bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] pfinet: Add SIOCADDRT and SIOCDELRT equivalent iioctls


From: Damien Zammit
Subject: [PATCH] pfinet: Add SIOCADDRT and SIOCDELRT equivalent iioctls
Date: Sat, 27 Aug 2022 03:14:13 +0000

This adds support for ioctls for adding and removing routes in pfinet.

Tested to still access network, but there seems to be a mismatch between
<net/route.h> and <linux/route.h>, I can only make it compile
using the linux header.

---
 hurd/iioctl.defs    |  17 ++-
 hurd/ioctl_types.h  |   2 +
 pfinet/iioctl-ops.c | 266 ++++++++++++++++++++++++++++++++++++++++++++
 pfinet/options.c    | 107 +++---------------
 4 files changed, 301 insertions(+), 91 deletions(-)

diff --git a/hurd/iioctl.defs b/hurd/iioctl.defs
index dfa89033f..cd3378cd7 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 whole struct rtentry from <net/route.h>. */
+type rtentry_t = struct[84] of char;   /* sizeof(struct rtentry) is 84. */
+
 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: rtentry_t);
+
+/* 11 SIOCDELRT */
+routine iioctl_siocdelrt (
+       reqport: io_t;
+       ifnam: ifname_t;
+       route: rtentry_t);

 /* 12 SIOCSIFADDR */
 routine iioctl_siocsifaddr (
diff --git a/hurd/ioctl_types.h b/hurd/ioctl_types.h
index 8baa36040..6a52fb817 100644
--- a/hurd/ioctl_types.h
+++ b/hurd/ioctl_types.h
@@ -30,4 +30,6 @@ typedef struct winsize winsize_t;
 typedef struct sockaddr sockaddr_t;
 typedef char ifname_t[16];

+#include <linux/route.h>
+typedef struct rtentry rtentry_t;
 #endif /* hurd/ioctl_types.h */
diff --git a/pfinet/iioctl-ops.c b/pfinet/iioctl-ops.c
index 191c65913..7a7bb9217 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>
@@ -35,6 +40,9 @@
 #include <sys/ioctl.h>
 #include <net/if.h>
 #include <net/sock.h>
+#include <net/route.h>
+#include <net/ip_fib.h>
+#include <net/addrconf.h>

 extern struct notifier_block *netdev_chain;

@@ -64,6 +72,214 @@ struct device *get_dev (const char *name)
   return dev;
 }

+static uint32_t
+get_gateway(struct device *dev)
+{
+  uint32_t gateway = 0;
+  struct rt_key key = { 0 };
+  struct fib_result res;
+
+  /* Get gateway */
+  gateway = INADDR_NONE;
+  key.oif = dev->ifindex;
+  if (! main_table->tb_lookup (main_table, &key, &res)
+      && FIB_RES_GW(res) != INADDR_ANY)
+    gateway = FIB_RES_GW (res);
+  return 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.
+ */
+static error_t
+delete_gateway(struct device *dev, struct sockaddr_in *dst, struct sockaddr_in 
*gw)
+{
+  error_t err;
+  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;
+
+  /* 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->sin_addr.s_addr;
+  rta.rta_gw = &gw->sin_addr.s_addr;
+  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, struct sockaddr_in *dst, struct sockaddr_in 
*gw)
+{
+  error_t err;
+  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;
+
+  /* Add a gateway  */
+  rta.rta_oif = &dev->ifindex;
+  rta.rta_dst = &dst->sin_addr.s_addr;
+  rta.rta_gw = &gw->sin_addr.s_addr;
+  req.nlh.nlmsg_type = RTM_NEWROUTE;
+  req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_APPEND;
+  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, struct sockaddr_in *dst)
+{
+  error_t err;
+  struct kern_rta rta;
+  struct
+  {
+    struct nlmsghdr nlh;
+    struct rtmsg rtm;
+  } req;
+  struct fib_table *tb;
+
+  if (!dev->name)
+    return ENODEV;
+
+  /* Simulate the SIOCADDRT behavior.  */
+  memset (&req.rtm, 0, sizeof req.rtm);
+  memset (&rta, 0, sizeof rta);
+  req.nlh.nlmsg_type = RTM_NEWROUTE;
+
+  /* Append this routing for addr.  By this way we can always send
+     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;
+  return err;
+}
+
+static error_t
+delete_static_route(struct device *dev, struct sockaddr_in *dst)
+{
+  error_t err;
+  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);
+
+  /* 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;
+  rta.rta_dst = &dst->sin_addr.s_addr;
+  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, struct rtentry *route)
+{
+  error_t err;
+  struct sockaddr_in *dst = (struct sockaddr_in *)&route->rt_dst;
+  struct sockaddr_in *gw = (struct sockaddr_in *)&route->rt_gateway;
+
+  if (!dst)
+    return EINVAL;
+
+  if (route->rt_flags & RTF_GATEWAY)
+    err = add_gateway(dev, dst, gw);
+  else
+    err = add_static_route(dev, dst);
+
+  return err;
+}
+
+error_t
+delete_route (struct device *dev, struct rtentry *route)
+{
+  error_t err;
+  struct sockaddr_in *dst = (struct sockaddr_in *)&route->rt_dst;
+  struct sockaddr_in *gw = (struct sockaddr_in *)&route->rt_gateway;
+
+  if (!dst)
+    return EINVAL;
+
+  if (route->rt_flags & RTF_GATEWAY)
+    err = delete_gateway(dev, dst, gw);
+  else
+    err = delete_static_route(dev, dst);
+
+  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 rtentry 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 rtentry 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 ae44759dc..6de0b580a 100644
--- a/pfinet/options.c
+++ b/pfinet/options.c
@@ -60,6 +60,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 rtentry *route);
+extern error_t delete_route (struct device *dev, struct rtentry *route);
+
 #ifdef CONFIG_IPV6
 static struct rt6_info * ipv6_get_dflt_router (void);
 #endif
@@ -504,65 +508,32 @@ 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.  */
-      {
-       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);
+      /* Set the default gateway. */

-       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;
+      {
+       struct rtentry route = {0}; /* hardcoded dst/gw 0.0.0.0 */
+       route.rt_flags = RTF_GATEWAY;

        if (!gw4_in)
          {
            /* Delete any existing default route on configured devices  */
-           for (in = h->interfaces; in < h->interfaces + h->num_interfaces;
-                in++)
+           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 = delete_route (in->device, &route);
+               if (err)
                  {
-                   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;
+                   pthread_mutex_unlock (&global_lock);
+                   FAIL (err, 17, 0, "cannot delete default gateway");
                  }
              }
          }
        else
          {
            /* 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));
+           err = add_route (gw4_in->device, &route);
            if (err)
              {
-               pthread_mutex_unlock (&global_lock);
+               pthread_mutex_unlock (&global_lock);
                FAIL (err, 17, 0, "cannot set default gateway");
              }
          }
@@ -592,55 +563,11 @@ 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 rtentry route = {0}; // hardcoded 0.0.0.0 dst address

-         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);
--
2.34.1





reply via email to

[Prev in Thread] Current Thread [Next in Thread]