Module Name:    src
Committed By:   roy
Date:           Fri Jan  1 14:57:14 UTC 2021

Modified Files:
        src/external/bsd/wpa/dist/src/drivers: driver_bsd.c

Log Message:
wpa: If route socket overflows, sync drivers to system interfaces

Messages such as RTM_IFNFO or RTM_IFANNOUNCE could have been lost.
As such, sync the state of our internal driver to the state of the
system interfaces as reported by getifaddrs(2).

This change requires the routing socket be placed in non-blocking
mode. While here, set the routing and inet sockets to close on exec.


To generate a diff of this commit:
cvs rdiff -u -r1.37 -r1.38 src/external/bsd/wpa/dist/src/drivers/driver_bsd.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/bsd/wpa/dist/src/drivers/driver_bsd.c
diff -u src/external/bsd/wpa/dist/src/drivers/driver_bsd.c:1.37 src/external/bsd/wpa/dist/src/drivers/driver_bsd.c:1.38
--- src/external/bsd/wpa/dist/src/drivers/driver_bsd.c:1.37	Tue Jul 21 10:34:16 2020
+++ src/external/bsd/wpa/dist/src/drivers/driver_bsd.c	Fri Jan  1 14:57:14 2021
@@ -16,7 +16,9 @@
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_common.h"
 
+#include <ifaddrs.h>
 #include <net/if.h>
+#include <net/if_dl.h>
 #include <net/if_media.h>
 
 #ifdef __NetBSD__
@@ -615,6 +617,108 @@ bsd_set_opt_ie(void *priv, const u8 *ie,
 	return 0;
 }
 
+#ifdef SO_RERROR
+static void
+bsd_route_overflow(int sock, void *ctx, struct bsd_driver_global *global)
+{
+	char event_buf[2048]; /* max size of a single route(4) msg */
+	int n;
+	struct ifaddrs *ifaddrs, *ifa;
+	struct bsd_driver_data *drv;
+	struct sockaddr_dl *sdl;
+	union wpa_event_data event;
+
+	/* We need to match the system state, so drain the route
+	 * socket to avoid stale messages. */
+	do {
+		n = read(sock, event_buf, sizeof(event_buf));
+	} while (n != -1 || errno == ENOBUFS);
+
+	if (getifaddrs(&ifaddrs) == -1) {
+		wpa_printf(MSG_ERROR, "%s getifaddrs() failed: %s",
+			   __func__, strerror(errno));
+			   return;
+	}
+
+	/* add or update existing interfaces */
+	for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+		if (ifa->ifa_addr == NULL ||
+		    ifa->ifa_addr->sa_family != AF_LINK)
+			continue;
+		sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
+		drv = bsd_get_drvname(global, ifa->ifa_name);
+		if (drv != NULL &&
+		    (drv->ifindex != sdl->sdl_index || drv->if_removed)) {
+			wpa_printf(MSG_DEBUG,
+			    "RTM_IFANNOUNCE: Interface '%s' added",
+			    drv->ifname);
+			drv->ifindex = sdl->sdl_index;
+			drv->if_removed = 0;
+			event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+			os_strlcpy(event.interface_status.ifname, ifa->ifa_name,
+			    sizeof(event.interface_status.ifname));
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+					     &event);
+		}
+		if (drv == NULL &&
+		    (drv = bsd_get_drvindex(global, sdl->sdl_index)) != NULL) {
+			/* Driver name is invalid */
+			wpa_printf(MSG_DEBUG,
+			    "RTM_IFANNOUNCE: Interface '%s' removed",
+			    drv->ifname);
+			drv->if_removed = 1;
+			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+			os_strlcpy(event.interface_status.ifname, drv->ifname,
+			    sizeof(event.interface_status.ifname));
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+					     &event);
+		}
+	}
+
+	/* punt missing interfaces and update flags */
+	dl_list_for_each(drv, &global->ifaces, struct bsd_driver_data, list) {
+		for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+			if (ifa->ifa_addr == NULL ||
+			    ifa->ifa_addr->sa_family != AF_LINK)
+				continue;
+			sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
+			if (os_strcmp(drv->ifname, ifa->ifa_name) == 0)
+				break;
+		}
+		if (ifa == NULL && !drv->if_removed) {
+			wpa_printf(MSG_DEBUG,
+			    "RTM_IFANNOUNCE: Interface '%s' removed",
+			    drv->ifname);
+			drv->if_removed = 1;
+			event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+			os_strlcpy(event.interface_status.ifname, drv->ifname,
+			    sizeof(event.interface_status.ifname));
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS,
+					     &event);
+		}
+		if (ifa == NULL)
+			continue;
+
+		if ((ifa->ifa_flags & IFF_UP) == 0 &&
+		    (drv->flags & IFF_UP) != 0) {
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED,
+					     NULL);
+		} else if ((ifa->ifa_flags & IFF_UP) != 0 &&
+		    (drv->flags & IFF_UP) == 0) {
+			wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' UP",
+				   drv->ifname);
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
+		drv->flags = ifa->ifa_flags;
+	}
+
+	freeifaddrs(ifaddrs);
+}
+#endif
+
 static void
 bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
 {
@@ -635,6 +739,10 @@ bsd_wireless_event_receive(int sock, voi
 		if (errno != EINTR && errno != EAGAIN)
 			wpa_printf(MSG_ERROR, "%s read() failed: %s",
 				   __func__, strerror(errno));
+#ifdef SO_RERROR
+		if (errno == ENOBUFS)
+			bsd_route_overflow(sock, ctx, sock_ctx);
+#endif
 		return;
 	}
 
@@ -1560,14 +1668,14 @@ bsd_global_init(void *ctx)
 	global->ctx = ctx;
 	dl_list_init(&global->ifaces);
 
-	global->sock = socket(PF_INET, SOCK_DGRAM, 0);
+	global->sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
 	if (global->sock < 0) {
 		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
 			   strerror(errno));
 		goto fail1;
 	}
 
-	global->route = socket(PF_ROUTE, SOCK_RAW, 0);
+	global->route = socket(PF_ROUTE, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
 	if (global->route < 0) {
 		wpa_printf(MSG_ERROR, "socket[PF_ROUTE,SOCK_RAW]: %s",
 			   strerror(errno));

Reply via email to