]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Resubscribe to nl80211 events on global nl_event socket
authorJouni Malinen <j@w1.fi>
Sun, 22 Feb 2015 16:03:42 +0000 (18:03 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 22 Feb 2015 16:03:42 +0000 (18:03 +0200)
This allows wpa_supplicant to recover from some of the cases where
cfg80211 is unloaded and reloaded without restarting wpa_supplicant. The
netlink socket used for nl80211 events (global->nl_event) seemed to end
up in otherwise functionality state, but with all the event memberships
lost when cfg80211 gets reloaded.

There does not seem to be any clear way of determining when this has
happened, so it looks simplest to just try to re-subscribe to all the
events whenever an interface is re-enabled or added.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/drivers/driver_nl80211.c

index 2c4c0b365d93123effa30cedbf8f9130503de6bf..2dce242a3170ff34a08a4e68e460f50f0c86a832 100644 (file)
@@ -164,6 +164,7 @@ static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
 
 
 static void nl80211_global_deinit(void *priv);
+static void nl80211_check_global(struct nl80211_global *global);
 
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
 static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
@@ -864,6 +865,7 @@ static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
                return 1;
 
        if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
+               nl80211_check_global(drv->global);
                wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
                           "interface");
                wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
@@ -1481,6 +1483,33 @@ err:
 }
 
 
+static void nl80211_check_global(struct nl80211_global *global)
+{
+       struct nl_handle *handle;
+       const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
+       int ret;
+       unsigned int i;
+
+       /*
+        * Try to re-add memberships to handle case of cfg80211 getting reloaded
+        * and all registration having been cleared.
+        */
+       handle = (void *) (((intptr_t) global->nl_event) ^
+                          ELOOP_SOCKET_INVALID);
+
+       for (i = 0; groups[i]; i++) {
+               ret = nl_get_multicast_id(global, "nl80211", groups[i]);
+               if (ret >= 0)
+                       ret = nl_socket_add_membership(handle, ret);
+               if (ret < 0) {
+                       wpa_printf(MSG_INFO,
+                                  "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
+                                  groups[i], ret, strerror(-ret));
+               }
+       }
+}
+
+
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
        wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -1674,6 +1703,7 @@ static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
        }
 
        if (drv->global) {
+               nl80211_check_global(drv->global);
                dl_list_add(&drv->global->interfaces, &drv->list);
                drv->in_interface_list = 1;
        }