]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Remove AP mode interface from bridge for STA-mode-scan
authorJouni Malinen <jouni@codeaurora.org>
Fri, 15 May 2020 18:23:50 +0000 (21:23 +0300)
committerJouni Malinen <j@w1.fi>
Fri, 15 May 2020 18:23:50 +0000 (21:23 +0300)
Linux bridging code does not allow a station mode WLAN interface in a
bridge and this prevents the AP mode scan workaround from working if the
AP interface is in a bridge and scanning can be only done by moving to
STA mode. Extend this workaround to remove the interface from the bridge
temporarily for the duration of the scan, i.e., for the same duration as
the interface needs to be moved into the station.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c
src/drivers/driver_nl80211_scan.c

index 0bedf063069c2303ed5e3041b1b54b33109a5508..bb0768c1cb3481e0b1a81b3520e57503fa8ee9bd 100644 (file)
@@ -6274,6 +6274,20 @@ static int wpa_driver_nl80211_set_mode_impl(
                        }
                }
 
+               if (i == 0 && was_ap && !is_ap_interface(nlmode) &&
+                   bss->brname[0] &&
+                   (bss->added_if_into_bridge || bss->already_in_bridge)) {
+                       wpa_printf(MSG_DEBUG,
+                                  "nl80211: Remove AP interface %s temporarily from the bridge %s to allow its mode to be set to STATION",
+                                  bss->ifname, bss->brname);
+                       if (linux_br_del_if(drv->global->ioctl_sock,
+                                           bss->brname, bss->ifname) < 0)
+                               wpa_printf(MSG_INFO,
+                                          "nl80211: Failed to remove interface %s from bridge %s: %s",
+                                          bss->ifname, bss->brname,
+                                          strerror(errno));
+               }
+
                /* Try to set the mode again while the interface is down */
                mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
                if (mode_switch_res == -EBUSY) {
@@ -6346,6 +6360,29 @@ done:
 }
 
 
+void nl80211_restore_ap_mode(struct i802_bss *bss)
+{
+       struct wpa_driver_nl80211_data *drv = bss->drv;
+       int was_ap = is_ap_interface(drv->nlmode);
+
+       wpa_driver_nl80211_set_mode(bss, drv->ap_scan_as_station);
+       if (!was_ap && is_ap_interface(drv->ap_scan_as_station) &&
+           bss->brname[0] &&
+           (bss->added_if_into_bridge || bss->already_in_bridge)) {
+               wpa_printf(MSG_DEBUG,
+                          "nl80211: Add AP interface %s back into the bridge %s",
+                          bss->ifname, bss->brname);
+               if (linux_br_add_if(drv->global->ioctl_sock, bss->brname,
+                                   bss->ifname) < 0) {
+                       wpa_printf(MSG_WARNING,
+                                  "nl80211: Failed to add interface %s into bridge %s: %s",
+                                  bss->ifname, bss->brname, strerror(errno));
+               }
+       }
+       drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+}
+
+
 int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
                                enum nl80211_iftype nlmode)
 {
index 660f49879bf4da8f775833bd02f702522ca056a1..895f9d72e6d56665984e135bcb5ffcf3e54f1d03 100644 (file)
@@ -275,6 +275,8 @@ int process_bss_event(struct nl_msg *msg, void *arg);
 
 const char * nl80211_iftype_str(enum nl80211_iftype mode);
 
+void nl80211_restore_ap_mode(struct i802_bss *bss);
+
 #ifdef ANDROID
 int android_nl_socket_set_nonblocking(struct nl_sock *handle);
 int android_pno_start(struct i802_bss *bss,
index 1152312a82232c94a827fa374fa11d1e0fd1db3b..6a2de1f3c21188d94de24e95a0bb47ddb39f1f3e 100644 (file)
@@ -2581,11 +2581,8 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd,
 
        if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
            (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-            cmd == NL80211_CMD_SCAN_ABORTED)) {
-               wpa_driver_nl80211_set_mode(drv->first_bss,
-                                           drv->ap_scan_as_station);
-               drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
-       }
+            cmd == NL80211_CMD_SCAN_ABORTED))
+               nl80211_restore_ap_mode(bss);
 
        switch (cmd) {
        case NL80211_CMD_TRIGGER_SCAN:
index 17e8b2c2eea4a5c8175146eb967a1d4ef28d6b50..dc91a2901aabe08728f8673b82133ad22e11158b 100644 (file)
@@ -166,11 +166,8 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
 
        wpa_printf(MSG_DEBUG, "nl80211: Failed to abort scan");
 
-       if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-               wpa_driver_nl80211_set_mode(drv->first_bss,
-                                           drv->ap_scan_as_station);
-               drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
-       }
+       if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED)
+               nl80211_restore_ap_mode(drv->first_bss);
 
        wpa_printf(MSG_DEBUG, "nl80211: Try to get scan results");
        wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);