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);