I had to add some code to linux-src (otherwise reimplement tons of structs).
--- hurd/pfinet.defs | 9 +++ pfinet/iioctl-ops.c | 1 + pfinet/linux-src/include/net/ip_fib.h | 2 + pfinet/linux-src/net/ipv4/fib_hash.c | 84 +++++++++++++++++++++++++++ pfinet/pfinet-ops.c | 84 ++++++++++++++++++++++++++- pfinet/pfinet.h | 5 +- pfinet/route.h | 26 +++++++++ 7 files changed, 207 insertions(+), 4 deletions(-) create mode 100644 pfinet/route.h diff --git a/hurd/pfinet.defs b/hurd/pfinet.defs index ec0b03e34..81f7c1945 100644 --- a/hurd/pfinet.defs +++ b/hurd/pfinet.defs @@ -37,3 +37,12 @@ routine pfinet_siocgifconf ( amount: vm_size_t; out buf: data_t, dealloc ); + +/* Return the routing table as a sequence of ifrtreq_t structs. + The maximum number of routes returned can be given in AMOUNT. + But if AMOUNT is -1, all routes will be returned up to MAX_ROUTES. */ +routine pfinet_getroutes ( + port: io_t; + amount: vm_size_t; + out routes: data_t, dealloc[] +); diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c index b128242bb..adf7bd82b 100644 --- a/pfinet/iioctl-ops.c +++ b/pfinet/iioctl-ops.c @@ -104,6 +104,7 @@ prepare_rt_req(struct rt_req *req, struct device *dev, in_addr_t dst, in_addr_t req->rtm.rtm_type = RTN_UNICAST; req->rtm.rtm_protocol = RTPROT_BOOT; req->rtm.rtm_dst_len = inet_mask_len(mask); + req->rtm.rtm_table = RT_TABLE_MAIN; return 0; } diff --git a/pfinet/linux-src/include/net/ip_fib.h b/pfinet/linux-src/include/net/ip_fib.h index 60338945f..faf13c649 100644 --- a/pfinet/linux-src/include/net/ip_fib.h +++ b/pfinet/linux-src/include/net/ip_fib.h @@ -17,6 +17,7 @@ #define _NET_IP_FIB_H #include <linux/config.h> +#include "route.h" struct kern_rta { @@ -223,6 +224,7 @@ extern u32 __fib_res_prefsrc(struct fib_result *res); /* Exported by fib_hash.c */ extern struct fib_table *fib_hash_init(int id); +int fn_hash_get_routes(struct fib_table *tb, ifrtreq_t *routes, int first, int count); #ifdef CONFIG_IP_MULTIPLE_TABLES /* Exported by fib_rules.c */ diff --git a/pfinet/linux-src/net/ipv4/fib_hash.c b/pfinet/linux-src/net/ipv4/fib_hash.c index 074a36876..ca25377c9 100644 --- a/pfinet/linux-src/net/ipv4/fib_hash.c +++ b/pfinet/linux-src/net/ipv4/fib_hash.c @@ -883,3 +883,87 @@ __initfunc(struct fib_table * fib_hash_init(int id)) memset(tb->tb_data, 0, sizeof(struct fn_hash)); return tb; } + +/* DZ: Could not fit this anywhere else, due to excessive struct defs in .c file */ + +static void +fib_node_get_route(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, ifrtreq_t *r) +{ + int len; + static unsigned type2flags[RTN_MAX+1] = { + 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0 + }; + unsigned flags = type2flags[type]; + + if (fi && fi->fib_nh->nh_gw) + flags |= RTF_GATEWAY; + if (mask == 0xFFFFFFFF) + flags |= RTF_HOST; + if (!dead) + flags |= RTF_UP; + + + if (fi && fi->fib_dev) + sprintf (r->ifname, "%s", fi->fib_dev->name); + else + { + r->ifname[0] = '*'; + r->ifname[1] = '\0'; + } + + r->rt_dest = prefix; + r->rt_flags = flags; + r->rt_mask = mask; + + if (fi) + { + r->rt_gateway = fi->fib_nh->nh_gw; + r->rt_metric = fi->fib_priority; + r->rt_mtu = fi->fib_mtu; + r->rt_window = fi->fib_window; + r->rt_irtt = fi->fib_rtt; + } +} + +int +fn_hash_get_routes(struct fib_table *tb, ifrtreq_t *routes, int first, int count) +{ + struct fn_hash *table = (struct fn_hash*)tb->tb_data; + struct fn_zone *fz; + int pos = 0; + int n = 0; + + for (fz=table->fn_zone_list; fz; fz = fz->fz_next) + { + int i; + struct fib_node *f; + int maxslot = fz->fz_divisor; + struct fib_node **fp = fz->fz_hash; + + if (fz->fz_nent == 0) + continue; + + if (pos + fz->fz_nent <= first) { + pos += fz->fz_nent; + continue; + } + + for (i=0; i < maxslot; i++, fp++) + { + for (f = *fp; f; f = f->fn_next) + { + if (++pos <= first) + continue; + fib_node_get_route(f->fn_type, + f->fn_state & FN_S_ZOMBIE, + FIB_INFO(f), + fz_prefix(f->fn_key, fz), + FZ_MASK(fz), routes); + routes++; + if (++n >= count) + return n; + } + } + } + return n; +} diff --git a/pfinet/pfinet-ops.c b/pfinet/pfinet-ops.c index 5db669783..621721898 100644 --- a/pfinet/pfinet-ops.c +++ b/pfinet/pfinet-ops.c @@ -22,6 +22,13 @@ #include <linux/netdevice.h> #include <linux/notifier.h> +#include <linux/inetdevice.h> +#include <linux/rtnetlink.h> +#include <linux/ip.h> +#include <net/route.h> +#include <net/sock.h> +#include <net/ip_fib.h> +#include <net/addrconf.h> #include "pfinet_S.h" #include <netinet/in.h> @@ -32,7 +39,8 @@ #include <sys/mman.h> #include <sys/ioctl.h> -#include <net/if.h> + +#define MAX_ROUTES 255 extern int dev_ifconf(char *arg); @@ -91,3 +99,77 @@ S_pfinet_siocgifconf (io_t port, pthread_mutex_unlock (&global_lock); return err; } + +int +get_routing_table(int start, int count, ifrtreq_t *routes) +{ + struct fib_table *tb; + + if (!routes) + return 0; + + if ((tb = fib_get_table(RT_TABLE_MAIN)) == NULL) + return 0; + + return fn_hash_get_routes(tb, routes, start, count); +} + + +/* Return the routing table as a series of ifrtreq_t structs + in routes, but don't return more then AMOUNT number of them. + If AMOUNT is -1, we get the full table. */ +error_t +S_pfinet_getroutes (io_t port, + vm_size_t amount, + data_t *routes, + mach_msg_type_number_t *len, + boolean_t *dealloc_data) +{ + error_t err = 0; + ifrtreq_t rs[MAX_ROUTES]; + int n; + ifrtreq_t *rtable; + + pthread_mutex_lock (&global_lock); + + if (dealloc_data) + *dealloc_data = FALSE; + + if (amount == (vm_size_t) -1) + { + /* Get all of them, and return the number we got. */ + n = get_routing_table (0, MAX_ROUTES, rs); + amount = n; + } + else + n = amount; + + if (amount > 0) + { + /* Possibly allocate a new buffer. */ + if (*len < amount * sizeof(ifrtreq_t)) + rtable = (ifrtreq_t *) mmap (0, amount * sizeof(ifrtreq_t), PROT_READ|PROT_WRITE, + MAP_ANON, 0, 0); + else + rtable = (ifrtreq_t *)*routes; + + memset(rtable, 0, n * sizeof(ifrtreq_t)); + n = get_routing_table (0, n, rtable); + } + + if (rtable == MAP_FAILED) + { + err = ENOMEM; + *len = 0; + if ((char *)rtable != *routes) + munmap (rtable, amount * sizeof(ifrtreq_t)); + } + else + { + *len = n * sizeof(ifrtreq_t); + *routes = (char *)rtable; + } + + pthread_mutex_unlock (&global_lock); + return err; +} diff --git a/pfinet/pfinet.h b/pfinet/pfinet.h index d08779bff..f8a1dd8dc 100644 --- a/pfinet/pfinet.h +++ b/pfinet/pfinet.h @@ -29,6 +29,7 @@ #include <sys/mman.h> #include <sys/socket.h> #include <pthread.h> +#include "route.h" extern pthread_mutex_t global_lock; extern pthread_mutex_t net_bh_lock; @@ -77,9 +78,7 @@ error_t make_sockaddr_port (struct socket *, int, void init_devices (void); void *net_bh_worker (void *); void init_time (void); -void ip_rt_add (short, u_long, u_long, u_long, struct device *, - u_short, u_long); -void ip_rt_del (u_long, struct device *); +int get_routing_table(int start, int count, ifrtreq_t *routes); struct sock; error_t tcp_tiocinq (struct sock *sk, mach_msg_type_number_t *amount); diff --git a/pfinet/route.h b/pfinet/route.h new file mode 100644 index 000000000..8cb1b8a3f --- /dev/null +++ b/pfinet/route.h @@ -0,0 +1,26 @@ +#ifndef ROUTE_H_ +#define ROUTE_H_ + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +typedef struct ifrtreq { + char ifname[IFNAMSIZ]; + in_addr_t rt_dest; + in_addr_t rt_mask; + in_addr_t rt_gateway; + int rt_flags; + int rt_metric; + int rt_mtu; + int rt_window; + int rt_irtt; + int rt_tos; + int rt_class; +} ifrtreq_t; + +#endif -- 2.34.1