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 <jouni@codeaurora.org>
This commit is contained in:
Jouni Malinen 2020-05-15 21:23:50 +03:00 committed by Jouni Malinen
parent 7adea21d2f
commit 04030e8c0d
4 changed files with 43 additions and 10 deletions

View 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)
{

View 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,

View 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:

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