bug-hurd
[Top][All Lists]
Advanced

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

[PATCH v3] pfinet: Add SIOCADDRT and SIOCDELRT equivalent iioctls


From: Damien Zammit
Subject: [PATCH v3] pfinet: Add SIOCADDRT and SIOCDELRT equivalent iioctls
Date: Mon, 29 Aug 2022 10:30:04 +0000

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.

#ifndef NET_ROUTE_H_
#define NET_ROUTE_H_

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define _IOT_ifrtreq _IOT (_IOTS(char), IFNAMSIZ, _IOTS(int), 10, 0, 0)

/* move to bits/ioctl.h */
#define SIOCADDRT _IOW('i', 10, struct ifrtreq)
#define SIOCDELRT _IOW('i', 11, struct ifrtreq)

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;
};

#endif

---
 hurd/iioctl.defs    |  17 ++-
 hurd/ioctl_types.h  |  15 +++
 pfinet/iioctl-ops.c | 280 ++++++++++++++++++++++++++++++++++++++++++++
 pfinet/options.c    | 122 ++++---------------
 4 files changed, 332 insertions(+), 102 deletions(-)

diff --git a/hurd/iioctl.defs b/hurd/iioctl.defs
index dfa89033f..6701d8ec7 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 8baa36040..1e22fe597 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 191c65913..3185c8141 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,226 @@ 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, 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  */
+  rta.rta_oif = &dev->ifindex;
+  rta.rta_dst = &dst;
+  rta.rta_gw = &gw;
+  req.nlh.nlmsg_type = RTM_NEWROUTE;
+  req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+  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 +388,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 ae44759dc..b945257be 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,65 +509,22 @@ 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);
+               pthread_mutex_unlock (&global_lock);
                FAIL (err, 17, 0, "cannot set default gateway");
              }
          }
@@ -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);
--
2.34.1





reply via email to

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