Wednesday, December 12, 2018

Re: security/wpa_supplicant: Reassoc on NWID change

Hi Edd, Raf, Mikolaj, ports@

I just updated my proposed patch with Mikolaj's suggestion of also
listening to RTM_IFINFO instead of just RTM_80211INFO. The patch is
attached below the signature.

It makes reassociation over suspend/resume work (if I resume in the
same spot I suspended in, haven't checked going out of range). What's
noteworthy is that it takes a while (in the area of 10 - 15 seconds)
for wpa_supplicant to re-establish a connection.

As for Edd's report that moving out of range with the device on doesn't
cause re-association (did I understand that correctly?), I think the
output of `route monitor` and `ifconfig $dev scan` before and after
loss of signal (and going into range of the other AP) might be
interesting to see if there's another routing message that we have to
consider.

Maybe the attached patch also helps Edd's situation. As always, I'm
grateful for testing and feedback.

--
Gregor

Index: patches/patch-src_drivers_driver_openbsd_c
===================================================================
RCS file: /home/cvs/ports/security/wpa_supplicant/patches/patch-src_drivers_driver_openbsd_c,v
retrieving revision 1.5
diff -u -p -r1.5 patch-src_drivers_driver_openbsd_c
--- patches/patch-src_drivers_driver_openbsd_c 17 May 2016 08:29:27 -0000 1.5
+++ patches/patch-src_drivers_driver_openbsd_c 12 Dec 2018 20:18:19 -0000
@@ -1,24 +1,151 @@
$OpenBSD: patch-src_drivers_driver_openbsd_c,v 1.5 2016/05/17 08:29:27 dcoppa Exp $

-Fix includes
+Fix includes and react to NWID changes and suspend/resume.

---- src/drivers/driver_openbsd.c.orig Sun Sep 27 21:02:05 2015
-+++ src/drivers/driver_openbsd.c Mon Sep 28 09:51:53 2015
-@@ -9,13 +9,14 @@
+Index: src/drivers/driver_openbsd.c
+--- src/drivers/driver_openbsd.c.orig
++++ src/drivers/driver_openbsd.c
+@@ -9,19 +9,34 @@
#include "includes.h"
#include <sys/ioctl.h>
-
+
+#include "common.h"
+#include "driver.h"
++#include "eloop.h"
+
++#include <sys/socket.h>
#include <net/if.h>
+#include <net/if_var.h>
++#include <net/route.h>
#include <net80211/ieee80211.h>
#include <net80211/ieee80211_crypto.h>
#include <net80211/ieee80211_ioctl.h>
--
+
-#include "common.h"
-#include "driver.h"
-
++#define RTM_READSZ 2048
+
struct openbsd_driver_data {
- char ifname[IFNAMSIZ + 1];
+- char ifname[IFNAMSIZ + 1];
+ void *ctx;
+
+- int sock; /* open socket for 802.11 ioctls */
++ char ifname[IFNAMSIZ + 1];
++ int ifindex; /* Ifindex of the configured interface */
++
++ int sock; /* open socket for 802.11 ioctls */
++ int rtsock; /* routing socket for interface state messages */
++
++ /* These fields are used to track the last seen (and associated) access point
++ to determine whether we should kick off an association event */
++ int nwid_len; /* Length of last seen SSID (as per routing message) */
++ char nwid[IEEE80211_NWID_LEN]; /* Last seen SSID (as per routing message) */
++ char addr[IEEE80211_ADDR_LEN]; /* Last seen BSSID (as per routing message) */
+ };
+
+
+@@ -90,6 +105,71 @@ wpa_driver_openbsd_set_key(const char *ifname, void *p
+ return 0;
+ }
+
++static void
++wpa_driver_openbsd_event_receive(int sock, void *global, void *sock_ctx)
++{
++ struct openbsd_driver_data *drv = sock_ctx;
++ struct rt_msghdr *rtm;
++ struct if_ieee80211_data *ifie;
++ char *rtmmsg;
++ ssize_t n;
++
++ rtmmsg = os_zalloc(RTM_READSZ);
++ if (rtmmsg == NULL) {
++ wpa_printf(MSG_ERROR, "Can't allocate space for routing message");
++ return;
++ }
++
++ do {
++ n = read(sock, rtmmsg, RTM_READSZ);
++ } while (n == -1 && errno == EINTR);
++
++ if (n == -1)
++ goto done;
++
++ rtm = (struct rt_msghdr *)rtmmsg;
++
++ if ((size_t)n < sizeof(rtm->rtm_msglen) ||
++ n < rtm->rtm_msglen ||
++ rtm->rtm_version != RTM_VERSION)
++ goto done;
++
++ if (rtm->rtm_index != drv->ifindex)
++ goto done;
++
++ if (rtm->rtm_type == RTM_80211INFO) {
++ printf("RTM_80211INFO received\n");
++ ifie = &((struct if_ieee80211_msghdr *)rtm)->ifim_ifie;
++
++ if ((ifie->ifie_nwid_len != drv->nwid_len) ||
++ (os_memcmp(drv->nwid, ifie->ifie_nwid, ifie->ifie_nwid_len) != 0) ||
++ (os_memcmp(drv->addr, ifie->ifie_addr, IEEE80211_ADDR_LEN) != 0)) {
++ os_memcpy(drv->addr, ifie->ifie_addr, IEEE80211_ADDR_LEN);
++
++ os_memcpy(drv->nwid, ifie->ifie_nwid, ifie->ifie_nwid_len);
++ drv->nwid_len = ifie->ifie_nwid_len;
++
++ /* Emit ASSOC event */
++ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
++ }
++ } else if (rtm->rtm_type == RTM_IFINFO) {
++ /* This is here so we can react to suspend/resume.
++
++ This is a bit rough, sometimes there are two or more IFINFOs notifying
++ us that the device just got "up" again. It doesn't seem to hurt to
++ issue multiple EVENT_ASSOC in those cases though.
++ */
++
++ if (rtm->rtm_flags & RTF_UP) {
++ /* Emit ASSOC event */
++ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
++ }
++ }
++
++done:
++ os_free(rtmmsg);
++}
++
+ static void *
+ wpa_driver_openbsd_init(void *ctx, const char *ifname)
+ {
+@@ -103,9 +183,21 @@ wpa_driver_openbsd_init(void *ctx, const char *ifname)
+ if (drv->sock < 0)
+ goto fail;
+
++ drv->rtsock = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
++ if (drv->rtsock < 0)
++ goto fail;
++
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
++ drv->ifindex = if_nametoindex(drv->ifname);
++ if (drv->ifindex == 0) /* No interface with that name */
++ goto fail;
++
++ drv->nwid_len = wpa_driver_openbsd_get_ssid(drv, drv->nwid);
++ wpa_driver_openbsd_get_bssid(drv, drv->addr);
++
++ eloop_register_read_sock(drv->rtsock, wpa_driver_openbsd_event_receive, NULL, drv);
+ return drv;
+
+ fail:
+@@ -119,7 +211,11 @@ wpa_driver_openbsd_deinit(void *priv)
+ {
+ struct openbsd_driver_data *drv = priv;
+
++ eloop_unregister_read_sock(drv->rtsock);
++
+ close(drv->sock);
++ close(drv->rtsock);
++
+ os_free(drv);
+ }

No comments:

Post a Comment