From 04030e8c0dcef6c2423eee1419e13e0ba738c4bb Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 15 May 2020 21:23:50 +0300 Subject: [PATCH] nl80211: Remove AP mode interface from bridge for STA-mode-scan 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 --- src/drivers/driver_nl80211.c | 37 ++++++++++++++++++++++++++++++ src/drivers/driver_nl80211.h | 2 ++ src/drivers/driver_nl80211_event.c | 7 ++---- src/drivers/driver_nl80211_scan.c | 7 ++---- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 0bedf0630..bb0768c1c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -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) { diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 660f49879..895f9d72e 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -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, diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 1152312a8..6a2de1f3c 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -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: diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c index 17e8b2c2e..dc91a2901 100644 --- a/src/drivers/driver_nl80211_scan.c +++ b/src/drivers/driver_nl80211_scan.c @@ -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);