Cumulative patch from commit 905828fea4b95a6d48ce86e1b5272c25a618b3d8
905828f hostapd: Fix vht_capab 'Maximum A-MPDU Length Exponent' handling
89de64c ACS: Fix VHT80 segment picking
1f37483 DFS: Print error in case CAC fails
354c903 AP/GO interface teardown optimization
8bc4372 Use P2P_IE_VENDOR_TYPE more consistently
8714caa WPS: Parse Registrar Configuration Methods
6b9f7af nl80211: Extend the new vendor command for testing nl80211
3a94adb P2P: Do not start scan for P2P Device interfaces at driver init
aa10983 P2P: Do not initialize bgscan on P2P interfaces
819f096 nl80211: Fix RTM event handling for dynamic interfaces
54ac5aa config: Add bgscan option when saving global configuration
268043d bgscan: Do not initialize bgscan if disabled by user
adef894 nl80211: Add vendor command support
d0595b2 nl80211: Fix tearing down WDS STA interfaces
Change-Id: I6d49f445692b71a4cd324f517eba651518ee14bb
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index f58b091..60b7580 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -367,6 +367,19 @@
}
+static int acs_usable_vht80_chan(struct hostapd_channel_data *chan)
+{
+ const int allowed[] = { 36, 52, 100, 116, 132, 149 };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
+ if (chan->chan == allowed[i])
+ return 1;
+
+ return 0;
+}
+
+
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
@@ -541,6 +554,15 @@
continue;
}
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+ iface->conf->ieee80211ac &&
+ iface->conf->vht_oper_chwidth == 1 &&
+ !acs_usable_vht80_chan(chan)) {
+ wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80",
+ chan->chan);
+ continue;
+ }
+
factor = 0;
if (acs_usable_chan(chan))
factor = chan->interference_factor;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index b8b260a..5ba48c9 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -767,8 +767,10 @@
vht_enabled, sec_channel_offset,
vht_oper_chwidth, center_segment0,
center_segment1,
- iface->current_mode->vht_capab))
+ iface->current_mode->vht_capab)) {
+ wpa_printf(MSG_ERROR, "Can't set freq params");
return -1;
+ }
res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
if (!res)
diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c
index a959694..a7129f1 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -16,6 +16,7 @@
#include "wpa_auth.h"
#include "sta_info.h"
#include "ap_mlme.h"
+#include "hostapd.h"
#ifndef CONFIG_NO_HOSTAPD_LOGGER
@@ -80,7 +81,8 @@
HOSTAPD_LEVEL_DEBUG,
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
- mlme_deletekeys_request(hapd, sta);
+ if (!hapd->iface->driver_ap_teardown)
+ mlme_deletekeys_request(hapd, sta);
}
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 8c0cbab..c27cf3b 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -250,9 +250,8 @@
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = 4 + 3 + 1;
- WPA_PUT_BE24(pos, OUI_WFA);
- pos += 3;
- *pos++ = P2P_OUI_TYPE;
+ WPA_PUT_BE32(pos, P2P_IE_VENDOR_TYPE);
+ pos += 4;
*pos++ = P2P_ATTR_MINOR_REASON_CODE;
WPA_PUT_LE16(pos, 1);
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 2b8b90f..92eda21 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -608,19 +608,25 @@
hostapd_set_state(iface, HAPD_IFACE_DFS);
wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
- "freq=%d chan=%d sec_chan=%d",
+ "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d",
iface->freq,
- iface->conf->channel, iface->conf->secondary_channel);
- if (hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
- iface->freq,
- iface->conf->channel,
- iface->conf->ieee80211n,
- iface->conf->ieee80211ac,
- iface->conf->secondary_channel,
- iface->conf->vht_oper_chwidth,
- iface->conf->vht_oper_centr_freq_seg0_idx,
- iface->conf->vht_oper_centr_freq_seg1_idx)) {
- wpa_printf(MSG_DEBUG, "DFS start_dfs_cac() failed");
+ iface->conf->channel, iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+
+ res = hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
+ iface->freq,
+ iface->conf->channel,
+ iface->conf->ieee80211n,
+ iface->conf->ieee80211ac,
+ iface->conf->secondary_channel,
+ iface->conf->vht_oper_chwidth,
+ iface->conf->vht_oper_centr_freq_seg0_idx,
+ iface->conf->vht_oper_centr_freq_seg1_idx);
+
+ if (res) {
+ wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
return -1;
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ad1c2d0..6ba6f98 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -350,7 +350,7 @@
static void hostapd_clear_wep(struct hostapd_data *hapd)
{
- if (hapd->drv_priv) {
+ if (hapd->drv_priv && !hapd->iface->driver_ap_teardown) {
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
}
@@ -401,11 +401,15 @@
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
return 0;
- wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
- if (hostapd_flush(hapd)) {
- wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
- "kernel driver");
- ret = -1;
+ if (!hapd->iface->driver_ap_teardown) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "Flushing old station entries");
+
+ if (hostapd_flush(hapd)) {
+ wpa_msg(hapd->msg_ctx, MSG_WARNING,
+ "Could not connect to kernel driver");
+ ret = -1;
+ }
}
wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
@@ -1009,6 +1013,15 @@
struct hostapd_data *hapd = iface->bss[0];
size_t i;
+ /*
+ * It is possible that setup_interface() is called after the interface
+ * was disabled etc., in which case driver_ap_teardown is possibly set
+ * to 1. Clear it here so any other key/station deletion, which is not
+ * part of a teardown flow, would also call the relevant driver
+ * callbacks.
+ */
+ iface->driver_ap_teardown = 0;
+
if (!iface->phy[0]) {
const char *phy = hostapd_drv_get_radio_name(hapd);
if (phy) {
@@ -1627,7 +1640,11 @@
driver = hapd_iface->bss[0]->driver;
drv_priv = hapd_iface->bss[0]->drv_priv;
- /* whatever hostapd_interface_deinit does */
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
+ /* same as hostapd_interface_deinit without deinitializing ctrl-iface */
for (j = 0; j < hapd_iface->num_bss; j++) {
struct hostapd_data *hapd = hapd_iface->bss[j];
hostapd_free_stas(hapd);
@@ -1943,6 +1960,10 @@
return -1;
if (!os_strcmp(hapd_iface->conf->bss[0]->iface, buf)) {
wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hapd_iface->driver_ap_teardown =
+ !!(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
+
hostapd_interface_deinit_free(hapd_iface);
k = i;
while (k < (interfaces->count - 1)) {
@@ -1955,8 +1976,12 @@
}
for (j = 0; j < hapd_iface->conf->num_bss; j++) {
- if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf))
+ if (!os_strcmp(hapd_iface->conf->bss[j]->iface, buf)) {
+ hapd_iface->driver_ap_teardown =
+ !(hapd_iface->drv_flags &
+ WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
return hostapd_remove_bss(hapd_iface, j);
+ }
}
}
return -1;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 489ab16..be7df51 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -273,6 +273,12 @@
unsigned int wait_channel_update:1;
unsigned int cac_started:1;
+ /*
+ * When set, indicates that the driver will handle the AP
+ * teardown: delete global keys, station keys, and stations.
+ */
+ unsigned int driver_ap_teardown:1;
+
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index af1bc9b..28e92fd 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -764,7 +764,7 @@
VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
diff --git a/src/ap/p2p_hostapd.c b/src/ap/p2p_hostapd.c
index 795d313..9be640c 100644
--- a/src/ap/p2p_hostapd.c
+++ b/src/ap/p2p_hostapd.c
@@ -96,9 +96,8 @@
u8 bitmap;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 4 + 3 + 1;
- WPA_PUT_BE24(eid, OUI_WFA);
- eid += 3;
- *eid++ = P2P_OUI_TYPE;
+ WPA_PUT_BE32(eid, P2P_IE_VENDOR_TYPE);
+ eid += 4;
*eid++ = P2P_ATTR_MANAGEABILITY;
WPA_PUT_LE16(eid, 1);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f7af088..0b90e3b 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -156,7 +156,8 @@
if (sta->flags & WLAN_STA_WDS)
hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
- if (!(sta->flags & WLAN_STA_PREAUTH))
+ if (!hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);