Source-Changes-HG archive

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

[src/trunk]: src/external/bsd/wpa/dist/src/drivers wpa: If route socket overf...



details:   https://anonhg.NetBSD.org/src/rev/2d602e3a8a4e
branches:  trunk
changeset: 958345:2d602e3a8a4e
user:      roy <roy%NetBSD.org@localhost>
date:      Fri Jan 01 14:57:14 2021 +0000

description:
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.

diffstat:

 external/bsd/wpa/dist/src/drivers/driver_bsd.c |  112 ++++++++++++++++++++++++-
 1 files changed, 110 insertions(+), 2 deletions(-)

diffs (150 lines):

diff -r 7561e3829b58 -r 2d602e3a8a4e external/bsd/wpa/dist/src/drivers/driver_bsd.c
--- a/external/bsd/wpa/dist/src/drivers/driver_bsd.c    Fri Jan 01 14:51:44 2021 +0000
+++ b/external/bsd/wpa/dist/src/drivers/driver_bsd.c    Fri Jan 01 14:57:14 2021 +0000
@@ -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 @@
        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 @@
                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 @@
        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));



Home | Main Index | Thread Index | Old Index