From: Joan Lledó <[email protected]>

ioctls `SIOCADDRT` and `SIOCDELRT` translate between BSD and lwip routing, but 
`pfinet_getroutes` didn't. That caused inconsistencies in the caller
---
 lwip/pfinet-ops.c | 153 ++++++++++++++++++++++++++++------------------
 1 file changed, 94 insertions(+), 59 deletions(-)

diff --git a/lwip/pfinet-ops.c b/lwip/pfinet-ops.c
index 271f2ac5..9775369f 100644
--- a/lwip/pfinet-ops.c
+++ b/lwip/pfinet-ops.c
@@ -32,6 +32,7 @@
 #include <net/route.h>
 
 #include <lwip-util.h>
+#include <stdlib.h>
 #include <netif/hurdethif.h>
 
 /*
@@ -118,6 +119,72 @@ lwip_S_pfinet_siocgifconf (io_t port,
 /* pfinet_getroutes must return up to 255 routes */
 #define MAX_ROUTES     255
 
+static void
+add_route(ifrtreq_t *rtable, char *devname, uint32_t dest, uint32_t netmask, 
uint32_t gw) {
+  strncpy (rtable->ifname, devname, IF_NAMESIZE - 1);
+  rtable->ifname[IF_NAMESIZE-1] = 0;
+  rtable->rt_dest = dest;
+  rtable->rt_mask = netmask;
+  rtable->rt_gateway = gw;
+}
+
+static uint32_t get_routes(ifrtreq_t *rtable) {
+  ifrtreq_t *rtable_it;
+  struct netif *netif;
+  char *devname;
+  uint32_t addr, netmask, gw, count;
+
+  rtable_it = rtable;
+  count = 0;
+
+  /* Add the default route if any
+   * e.g. `0.0.0.0/0 via 192.168.1.1` */
+  if (netif_default != NULL) {
+    inquire_device (netif_default, 0, 0, 0, 0, &gw, 0, 0);
+
+    if (gw != INADDR_ANY && gw != INADDR_NONE) {
+      devname = netif_get_state (netif_default)->devname;
+      add_route(rtable_it++, devname, INADDR_ANY, INADDR_ANY, gw);
+      count++;
+    }
+  }
+
+  /* Add subnet routes
+   * e.g. `192.168.1.0/24 dev eth0` */
+  NETIF_FOREACH (netif)
+  {
+    inquire_device (netif, &addr, &netmask, 0, 0, &gw, 0, 0);
+
+    if(addr != INADDR_ANY && addr != INADDR_NONE
+      && netmask != INADDR_ANY && netmask != INADDR_NONE) {
+      devname = netif_get_state (netif)->devname;
+      add_route(rtable_it++, devname, addr & netmask, netmask, INADDR_NONE);
+      count++;
+      }
+
+    if (count == MAX_ROUTES)
+      break;
+  }
+
+  return count;
+}
+
+/*
+ * Return the routing table as a series of ifrtreq_t structs
+ * in routes, but don't return more than `requested_amount` number of them.
+ * If `requested_amount` is -1, we get up to `MAX_ROUTES`.
+ *
+ * Here we must translate from lwip internal routing into standard
+ * BSD routing, which is what the caller expects.
+ *
+ * We support only two route types:
+ *  -  For all interfaces having a valid IP address and mask:
+ *     - Return a subnet route
+ *     - e.g. `192.168.1.0/24 dev eth0`
+ *   - If the default interface has a gateway set
+ *     - Return a default gateway
+ *     - e.g. `0.0.0.0/0 via 192.168.1.1`
+ */
 kern_return_t
 lwip_S_pfinet_getroutes (io_t port,
                         vm_size_t requested_amount,
@@ -125,80 +192,48 @@ lwip_S_pfinet_getroutes (io_t port,
                         mach_msg_type_number_t *len,
                         boolean_t *dealloc_data)
 {
-  struct netif *netif;
-  uint32_t addr, netmask, gw, available_count, count_to_return;
-  uint8_t i;
   ifrtreq_t *rtable;
-  char *devname;
+  size_t buflen;
+  uint32_t available_count, count_to_return;
 
   if (dealloc_data)
     *dealloc_data = FALSE;
 
-  available_count = 0;
-  NETIF_FOREACH (netif)
-  {
-    available_count++;
-  }
+  rtable = calloc (MAX_ROUTES, sizeof (ifrtreq_t));
+
+  available_count = get_routes (rtable);
 
   if (requested_amount == (vm_size_t) - 1)
-    {
-      /* All available */
-      count_to_return = available_count;
-    }
+  {
+    /* All available */
+    count_to_return = available_count;
+  }
   else
     /* Minimum of requested and available */
-    count_to_return =
-      requested_amount > available_count ? available_count : requested_amount;
+    count_to_return = requested_amount > available_count ? available_count : 
requested_amount;
 
-  if (count_to_return > MAX_ROUTES)
-    count_to_return = MAX_ROUTES;
+  buflen = count_to_return * sizeof (ifrtreq_t);
 
-  /* If the user requested 0 or there are 0 available, do nothing */
-  if (count_to_return > 0)
-    {
-      /* Possibly allocate a new buffer. */
-      if (*len < count_to_return * sizeof (ifrtreq_t))
-       {
-         rtable =
-           (ifrtreq_t *) mmap (0, count_to_return * sizeof (ifrtreq_t),
-                               PROT_READ | PROT_WRITE, MAP_ANON, 0, 0);
-         if (dealloc_data)
-           *dealloc_data = TRUE;
-       }
-      else
-       rtable = (ifrtreq_t *) * routes;
+  /* Possibly allocate a new buffer. */
+  if (*len < buflen)
+  {
+    *routes = mmap (0, buflen,PROT_READ | PROT_WRITE,
+        MAP_ANON, 0, 0);
 
-      if (rtable == MAP_FAILED)
-       {
-         *len = 0;
-         return ENOMEM;
-       }
+    if (*routes == MAP_FAILED)
+    {
+      *len = 0;
+      return ENOMEM;
+    }
 
-      /* Clear the output buffer */
-      memset (rtable, 0, count_to_return * sizeof (ifrtreq_t));
-
-      /* Get the routes */
-      i = 0;
-      NETIF_FOREACH (netif)
-      {
-       if (i == count_to_return)
-         break;
-
-       devname = netif_get_state (netif)->devname;
-       inquire_device (netif, &addr, &netmask, 0, 0, &gw, 0, 0);
-       strncpy (rtable[i].ifname, devname, IF_NAMESIZE);
-       rtable[i].ifname[IF_NAMESIZE-1] = '\0';
-       rtable[i].rt_dest = addr & netmask;
-       rtable[i].rt_mask = netmask;
-       rtable[i].rt_gateway = gw;
-
-       i++;
-      }
+    if (dealloc_data)
+      *dealloc_data = TRUE;
+  }
 
-      *routes = (char *) rtable;
-    }
+  memcpy(*routes, rtable, buflen);
+  *len = buflen;
 
-  *len = count_to_return * sizeof (ifrtreq_t);
+  free (rtable);
 
   return 0;
 }
-- 
2.50.1


Reply via email to