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