diff options
-rw-r--r-- | hurd/iioctl.defs | 17 | ||||
-rw-r--r-- | hurd/ioctl_types.h | 15 | ||||
-rw-r--r-- | pfinet/iioctl-ops.c | 266 | ||||
-rw-r--r-- | pfinet/options.c | 120 |
4 files changed, 317 insertions, 101 deletions
diff --git a/hurd/iioctl.defs b/hurd/iioctl.defs index dfa89033..6701d8ec 100644 --- a/hurd/iioctl.defs +++ b/hurd/iioctl.defs @@ -40,9 +40,24 @@ type ifname_t = array[16] of char; /* IFNAMSIZ is 16. */ definition of _IOT_ifreq in <net/if.h>. */ type sockaddr_t = struct[16] of char; /* sizeof(struct sockaddr) is 16. */ +/* This is the struct srtentry from <net/route.h>. */ +type srtentry_t = struct[40] of char; /* sizeof(struct srtentry) is 40. */ + skip; skip; skip; skip; /* 0 1 2 3 unused */ skip; skip; skip; skip; /* 4 5 6 7 unused */ -skip; skip; skip; skip; /* 8 9 10 11 unused */ +skip; skip; /* 8 9 unused */ + +/* 10 SIOCADDRT */ +routine iioctl_siocaddrt ( + reqport: io_t; + ifnam: ifname_t; + route: srtentry_t); + +/* 11 SIOCDELRT */ +routine iioctl_siocdelrt ( + reqport: io_t; + ifnam: ifname_t; + route: srtentry_t); /* 12 SIOCSIFADDR */ routine iioctl_siocsifaddr ( diff --git a/hurd/ioctl_types.h b/hurd/ioctl_types.h index 8baa3604..1e22fe59 100644 --- a/hurd/ioctl_types.h +++ b/hurd/ioctl_types.h @@ -30,4 +30,19 @@ typedef struct winsize winsize_t; typedef struct sockaddr sockaddr_t; typedef char ifname_t[16]; +#include <stdint.h> +struct srtentry { + uint32_t rt_dest; + uint32_t rt_mask; + uint32_t rt_gateway; + int rt_flags; + int rt_metric; + int rt_mtu; + int rt_window; + int rt_irtt; + int rt_tos; + int rt_class; +}; + +typedef struct srtentry srtentry_t; #endif /* hurd/ioctl_types.h */ diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c index 191c6591..9d1c28fd 100644 --- a/pfinet/iioctl-ops.c +++ b/pfinet/iioctl-ops.c @@ -22,9 +22,14 @@ #include <linux/netdevice.h> #include <linux/notifier.h> +#include <linux/inetdevice.h> +#include <linux/ip.h> +#include <linux/route.h> +#include <linux/rtnetlink.h> #include "iioctl_S.h" #include <netinet/in.h> +#include <arpa/inet.h> #include <fcntl.h> #include <string.h> #include <unistd.h> @@ -32,9 +37,14 @@ #include <sys/mman.h> #include <hurd/fshelp.h> +#include <sys/socket.h> #include <sys/ioctl.h> #include <net/if.h> #include <net/sock.h> +#include <hurd/ioctl_types.h> +#include <net/route.h> +#include <net/ip_fib.h> +#include <net/addrconf.h> extern struct notifier_block *netdev_chain; @@ -64,6 +74,212 @@ struct device *get_dev (const char *name) return dev; } +/* This code is cobbled together from what + * the SIOCADDRT ioctl code does, and from the apparent functionality + * of the "netlink" layer from perusing a little. + */ +static error_t +delete_gateway(struct device *dev, in_addr_t dst, in_addr_t mask, in_addr_t gw) +{ + error_t err; + struct kern_rta rta; + struct + { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct fib_table *tb; + + if (bad_mask (mask, dst)) + return EINVAL; + + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); + + memset (&req.rtm, 0, sizeof req.rtm); + memset (&rta, 0, sizeof rta); + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_protocol = RTPROT_BOOT; + req.rtm.rtm_dst_len = inet_mask_len(mask); + + /* Delete any existing default route on configured device */ + req.nlh.nlmsg_type = RTM_DELROUTE; + req.nlh.nlmsg_flags = 0; + rta.rta_oif = &dev->ifindex; + rta.rta_dst = &dst; + rta.rta_gw = &gw; + tb = fib_get_table (req.rtm.rtm_table); + if (tb) + { + err = - (*tb->tb_delete) + (tb, &req.rtm, &rta, &req.nlh, 0); + if (err && err != ESRCH) + return err; + err = 0; + } + return err; +} + +static error_t +add_gateway(struct device *dev, in_addr_t dst, in_addr_t mask, in_addr_t gw) +{ + error_t err; + struct kern_rta rta; + struct + { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req = {0}; + struct fib_table *tb; + + if (bad_mask (mask, dst)) + return EINVAL; + + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); + + memset (&req.rtm, 0, sizeof req.rtm); + memset (&rta, 0, sizeof rta); + req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_protocol = RTPROT_BOOT; + req.rtm.rtm_dst_len = inet_mask_len(mask); + + /* Add a gateway */ + req.nlh.nlmsg_type = RTM_NEWROUTE; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; + rta.rta_oif = &dev->ifindex; + rta.rta_dst = &dst; + rta.rta_gw = &gw; + tb = fib_new_table (req.rtm.rtm_table); + err = (!tb ? ENOBUFS + : - (*tb->tb_insert) (tb, &req.rtm, &rta, &req.nlh, 0)); + return err; +} + +/* Setup a static route (required for e.g. DHCP) */ +static error_t +add_static_route(struct device *dev, in_addr_t dst, in_addr_t mask) +{ + error_t err; + struct kern_rta rta; + struct + { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct fib_table *tb; + + if (bad_mask (mask, dst)) + return EINVAL; + + if (!dev->name) + return ENODEV; + + /* Simulate the SIOCADDRT behavior. */ + memset (&req.rtm, 0, sizeof req.rtm); + memset (&rta, 0, sizeof rta); + + /* Append this routing for addr. By this way we can always send + dhcp messages (e.g dhcp renew). */ + req.nlh.nlmsg_type = RTM_NEWROUTE; + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_APPEND; + + req.rtm.rtm_protocol = RTPROT_BOOT; + req.rtm.rtm_scope = RT_SCOPE_LINK; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_dst_len = inet_mask_len(mask); + rta.rta_dst = &dst; + rta.rta_oif = &dev->ifindex; + + tb = fib_new_table (req.rtm.rtm_table); + if (tb) + err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); + else + err = ENOBUFS; + return err; +} + +static error_t +delete_static_route(struct device *dev, in_addr_t dst, in_addr_t mask) +{ + error_t err; + struct kern_rta rta; + struct + { + struct nlmsghdr nlh; + struct rtmsg rtm; + } req; + struct fib_table *tb; + + if (bad_mask (mask, dst)) + return EINVAL; + + req.nlh.nlmsg_pid = 0; + req.nlh.nlmsg_seq = 0; + req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); + + memset (&req.rtm, 0, sizeof req.rtm); + memset (&rta, 0, sizeof rta); + + /* Delete existing static route on configured device matching src/dst */ + req.nlh.nlmsg_type = RTM_DELROUTE; + req.nlh.nlmsg_flags = 0; + + req.rtm.rtm_protocol = RTPROT_BOOT; + req.rtm.rtm_scope = RT_SCOPE_LINK; + req.rtm.rtm_type = RTN_UNICAST; + req.rtm.rtm_dst_len = inet_mask_len(mask); + rta.rta_dst = &dst; + rta.rta_oif = &dev->ifindex; + + tb = fib_get_table (req.rtm.rtm_table); + if (tb) + { + err = - (*tb->tb_delete) + (tb, &req.rtm, &rta, &req.nlh, 0); + if (err && err != ESRCH) + return err; + err = 0; + } + return err; +} + +error_t +add_route (struct device *dev, const struct srtentry *r) +{ + error_t err; + + if (!r) + return EINVAL; + + if (r->rt_flags & RTF_GATEWAY) + err = add_gateway(dev, r->rt_dest, r->rt_mask, r->rt_gateway); + else + err = add_static_route(dev, r->rt_dest, r->rt_mask); + + return err; +} + +error_t +delete_route (struct device *dev, const struct srtentry *r) +{ + error_t err; + + if (!r) + return EINVAL; + + if (r->rt_flags & RTF_GATEWAY) + err = delete_gateway(dev, r->rt_dest, r->rt_mask, r->rt_gateway); + else + err = delete_static_route(dev, r->rt_dest, r->rt_mask); + + return err; +} + enum siocgif_type { ADDR, @@ -158,6 +374,56 @@ siocsifXaddr (struct sock_user *user, return err; } +/* 10 SIOCADDRT -- Add a network route */ +kern_return_t +S_iioctl_siocaddrt (struct sock_user *user, + const ifname_t ifnam, + const struct srtentry route) +{ + error_t err = 0; + struct device *dev; + + if (!user) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + + if (!dev) + err = ENODEV; + else if (user->sock->sk->family != AF_INET) + err = EINVAL; + else + err = add_route (dev, &route); + + pthread_mutex_unlock (&global_lock); + return err; +} + +/* 11 SIOCDELRT -- Delete a network route */ +kern_return_t +S_iioctl_siocdelrt (struct sock_user *user, + const ifname_t ifnam, + const struct srtentry route) +{ + error_t err = 0; + struct device *dev; + + if (!user) + return EOPNOTSUPP; + + dev = get_dev (ifnam); + + if (!dev) + err = ENODEV; + else if (user->sock->sk->family != AF_INET) + err = EINVAL; + else + err = delete_route (dev, &route); + + pthread_mutex_unlock (&global_lock); + return err; +} + /* 12 SIOCSIFADDR -- Set address of a network interface. */ SIOCSIF (addr, ADDR); diff --git a/pfinet/options.c b/pfinet/options.c index ae44759d..1e8c1c26 100644 --- a/pfinet/options.c +++ b/pfinet/options.c @@ -28,6 +28,7 @@ #include <error.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <hurd/ioctl_types.h> #include "pfinet.h" @@ -60,6 +61,10 @@ extern struct inet6_dev *ipv6_find_idev (struct device *dev); extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen); extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen); +/* iioctl.c */ +extern error_t add_route (struct device *dev, struct srtentry *r); +extern error_t delete_route (struct device *dev, struct srtentry *r); + #ifdef CONFIG_IPV6 static struct rt6_info * ipv6_get_dflt_router (void); #endif @@ -504,62 +509,19 @@ parse_opt (int opt, char *arg, struct argp_state *state) #endif /* CONFIG_IPV6 */ } - /* Set the default gateway. This code is cobbled together from what - the SIOCADDRT ioctl code does, and from the apparent functionality - of the "netlink" layer from perusing a little. */ + /* Set the default gateway. */ + { - struct kern_rta rta; - struct - { - struct nlmsghdr nlh; - struct rtmsg rtm; - } req; - struct fib_table *tb; - - req.nlh.nlmsg_pid = 0; - req.nlh.nlmsg_seq = 0; - req.nlh.nlmsg_len = NLMSG_LENGTH (sizeof req.rtm); - - memset (&req.rtm, 0, sizeof req.rtm); - memset (&rta, 0, sizeof rta); - req.rtm.rtm_scope = RT_SCOPE_UNIVERSE; - req.rtm.rtm_type = RTN_UNICAST; - req.rtm.rtm_protocol = RTPROT_STATIC; - - if (!gw4_in) - { - /* Delete any existing default route on configured devices */ - for (in = h->interfaces; in < h->interfaces + h->num_interfaces; - in++) - { - req.nlh.nlmsg_type = RTM_DELROUTE; - req.nlh.nlmsg_flags = 0; - rta.rta_oif = &in->device->ifindex; - tb = fib_get_table (req.rtm.rtm_table); - if (tb) - { - err = - (*tb->tb_delete) - (tb, &req.rtm, &rta, &req.nlh, 0); - if (err && err != ESRCH) - { - pthread_mutex_unlock (&global_lock); - FAIL (err, 17, 0, - "cannot remove old default gateway"); - } - err = 0; - } - } - } - else + struct srtentry route = {0}; + route.rt_flags = RTF_GATEWAY; + route.rt_mask = INADDR_ANY; + route.rt_dest = INADDR_ANY; + route.rt_gateway = h->curint->gateway; + + if (gw4_in) { - /* Add a default route, replacing any existing one. */ - rta.rta_oif = &gw4_in->device->ifindex; - rta.rta_gw = &gw4_in->gateway; - req.nlh.nlmsg_type = RTM_NEWROUTE; - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE; - tb = fib_new_table (req.rtm.rtm_table); - err = (!tb ? ENOBUFS - : - (*tb->tb_insert) (tb, &req.rtm, &rta, &req.nlh, 0)); + /* Add a default route */ + err = add_route (gw4_in->device, &route); if (err) { pthread_mutex_unlock (&global_lock); @@ -592,55 +554,13 @@ parse_opt (int opt, char *arg, struct argp_state *state) /* Setup the routing required for DHCP. */ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++) { - struct kern_rta rta; - struct - { - struct nlmsghdr nlh; - struct rtmsg rtm; - } req; - struct fib_table *tb; - struct rtentry route; - struct sockaddr_in *dst; - struct device *dev; - if (!in->device) continue; + struct srtentry route = {0}; + route.rt_flags = 0; + route.rt_dest = INADDR_ANY; - dst = (struct sockaddr_in *) &route.rt_dst; - if (!in->device->name) - { - pthread_mutex_unlock (&global_lock); - FAIL (ENODEV, 17, 0, "unknown device"); - } - dev = dev_get (in->device->name); - if (!dev) - { - pthread_mutex_unlock (&global_lock); - FAIL (ENODEV, 17, 0, "unknown device"); - } - - /* Simulate the SIOCADDRT behavior. */ - memset (&route, 0, sizeof (struct rtentry)); - memset (&req.rtm, 0, sizeof req.rtm); - memset (&rta, 0, sizeof rta); - req.nlh.nlmsg_type = RTM_NEWROUTE; - - /* Append this routing for 0.0.0.0. By this way we can send always - dhcp messages (e.g dhcp renew). */ - req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE - | NLM_F_APPEND; - req.rtm.rtm_protocol = RTPROT_BOOT; - req.rtm.rtm_scope = RT_SCOPE_LINK; - req.rtm.rtm_type = RTN_UNICAST; - rta.rta_dst = &dst->sin_addr.s_addr; - rta.rta_oif = &dev->ifindex; - - tb = fib_new_table (req.rtm.rtm_table); - if (tb) - err = tb->tb_insert (tb, &req.rtm, &rta, &req.nlh, NULL); - else - err = ENOBUFS; - + err = add_route (in->device, &route); if (err) { pthread_mutex_unlock (&global_lock); |