aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2022-08-29 10:30:04 +0000
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2022-08-29 23:01:17 +0200
commit574bc98f0f236939c6ef5bc1fc61c919ee8b5d47 (patch)
tree308c207b2db56a9f8a644a389dd9187f065a9362
parent5adb4b834b1eba82b7f3eca6324bed0355cae0af (diff)
downloadhurd-574bc98f0f236939c6ef5bc1fc61c919ee8b5d47.tar.gz
hurd-574bc98f0f236939c6ef5bc1fc61c919ee8b5d47.tar.bz2
hurd-574bc98f0f236939c6ef5bc1fc61c919ee8b5d47.zip
pfinet: Add SIOCADDRT and SIOCDELRT equivalent iioctls
Using a new client side <net/route.h> I was able to clean up the existing options.c in pfinet and add two new ioctls for adding/deleting network routes. /* move to bits/ioctl.h */ 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; }; Message-Id: <20220829102952.369798-1-damien@zamaudio.com>
-rw-r--r--hurd/iioctl.defs17
-rw-r--r--hurd/ioctl_types.h15
-rw-r--r--pfinet/iioctl-ops.c266
-rw-r--r--pfinet/options.c120
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);