Cumulative patch from commit c0333c8dd59b9e254d3fc725c984b1c0cd3d496a
c0333c8 Check rx_mgmt::frame more consistently against NULL
d6c6b1f Make sta NULL-check easier for static analyzers
0bceb8d Make dl_list_first() and dl_list_last() uses easier for static analyzers
5f693cb WPS HTTP: Remove unused assignment
ee4fefc Remove duplicated variable zeroing
4a9d0eb Make PMKID check easier for static analyzers
06df2aa Remove floating constant suffix 'd' from test coee
9670f87 ACS: Clean up ifdef CONFIG_ACS to avoid unreachable code
ece88f7 Make last_scan_res update easier for static analyzers
d06e9ac P2P: Verify operating channel validity for NFC connection handover
13a524a nl80211: Remove unnecessary wpa_driver_nl80211_set_freq() wrapper
e87ef75 nl80211: Add support for changing AP mode channel bandwidth
3057518 Sync with mac80211-next.git nl80211.h
5f0bca7 Retry initial 20/40 MHz co-ex scan if the driver is busy
587d60d Add AP mode support for HT 20/40 co-ex Action frame
9c47f6a hostapd: Extend support for HT 20/40 coexistence feature
196c9c7 Make channel parameters available in set_ap() driver operation
b7a6702 Indicate disconnection event on interface disabled
b89962b Fix wpa_config_read() with existing config block
27b4187 WPS: Print setsockopt() failure in debug log
52cb207 trace: Replace demangle.h with internal defines
0e80ea2 nl80211: Fix some coding style issues
a26582c Make qca-vendor.h independent of other header files
4a64d5a nl80211: Allocate QCA vendor subcmd for extended statistics
Change-Id: Ibabee77b2b87f04f99d6b1ca0f1ac741cb9222c0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 0a143d3..9680817 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -174,11 +174,11 @@
conf->ap_table_expiration_time = 60;
#ifdef CONFIG_TESTING_OPTIONS
- conf->ignore_probe_probability = 0.0d;
- conf->ignore_auth_probability = 0.0d;
- conf->ignore_assoc_probability = 0.0d;
- conf->ignore_reassoc_probability = 0.0d;
- conf->corrupt_gtk_rekey_mic_probability = 0.0d;
+ conf->ignore_probe_probability = 0.0;
+ conf->ignore_auth_probability = 0.0;
+ conf->ignore_assoc_probability = 0.0;
+ conf->ignore_reassoc_probability = 0.0;
+ conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_ACS
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 56df318..27525dc 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -645,7 +645,7 @@
* with AP configuration */
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->iconf->ignore_probe_probability > 0.0d &&
+ if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring probe request from " MACSTR,
@@ -951,6 +951,9 @@
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct wpa_driver_ap_params params;
+ struct hostapd_freq_params freq;
+ struct hostapd_iface *iface = hapd->iface;
+ struct hostapd_config *iconf = iface->conf;
struct wpabuf *beacon, *proberesp, *assocresp;
int res, ret = -1;
@@ -972,6 +975,17 @@
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
+ if (iface->current_mode &&
+ hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
+ iconf->channel, iconf->ieee80211n,
+ iconf->ieee80211ac,
+ iconf->secondary_channel,
+ iconf->vht_oper_chwidth,
+ iconf->vht_oper_centr_freq_seg0_idx,
+ iconf->vht_oper_centr_freq_seg1_idx,
+ iface->current_mode->vht_capab) == 0)
+ params.freq = &freq;
+
res = hostapd_drv_set_ap(hapd, ¶ms);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
if (res)
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9760933..ccbbab5 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -405,6 +405,7 @@
"num_sta_ht_no_gf=%d\n"
"num_sta_no_ht=%d\n"
"num_sta_ht_20_mhz=%d\n"
+ "num_sta_ht40_intolerant=%d\n"
"olbc_ht=%d\n"
"ht_op_mode=0x%x\n",
hostapd_state_text(iface->state),
@@ -417,6 +418,7 @@
iface->num_sta_ht_no_gf,
iface->num_sta_no_ht,
iface->num_sta_ht_20mhz,
+ iface->num_sta_ht40_intolerant,
iface->olbc_ht,
iface->ht_op_mode);
if (ret < 0 || (size_t) ret >= buflen - len)
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index a8c24eb..fb095ef 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -9,6 +9,7 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "radius/radius.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
@@ -30,6 +31,7 @@
#include "ap_config.h"
#include "hw_features.h"
#include "dfs.h"
+#include "beacon.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
@@ -121,6 +123,24 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities) &&
+ (hapd->iface->conf->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT)
+ ht40_intolerant_add(hapd->iface, sta);
+ }
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
+
#ifdef CONFIG_INTERWORKING
if (elems.ext_capab && elems.ext_capab_len > 4) {
if (elems.ext_capab[4] & 0x01)
@@ -981,6 +1001,8 @@
break;
#endif /* NEED_AP_MLME */
case EVENT_RX_MGMT:
+ if (!data->rx_mgmt.frame)
+ break;
#ifdef NEED_AP_MLME
if (hostapd_mgmt_rx(hapd, &data->rx_mgmt) > 0)
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 614a5bf..391d774 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -33,6 +33,7 @@
#include "p2p_hostapd.h"
#include "gas_serv.h"
#include "dfs.h"
+#include "ieee802_11.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -1352,6 +1353,12 @@
if (iface == NULL)
return;
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 090544d..bd85c54 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -327,6 +327,9 @@
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
+ /* Number of HT40 intolerant stations */
+ int num_sta_ht40_intolerant;
+
/* Overlapping BSS information */
int olbc_ht;
@@ -351,11 +354,16 @@
unsigned int dfs_cac_ms;
struct os_reltime dfs_cac_start;
+ /* Latched with the actual secondary channel information and will be
+ * used while juggling between HT20 and HT40 modes. */
+ int secondary_ch;
+
#ifdef CONFIG_ACS
unsigned int acs_num_completed_scans;
#endif /* CONFIG_ACS */
void (*scan_cb)(struct hostapd_iface *iface);
+ int num_ht40_scan_tries;
};
/* hostapd.c */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d47a366..b361834 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -19,6 +19,8 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "acs.h"
+#include "ieee802_11.h"
+#include "beacon.h"
#include "hw_features.h"
@@ -414,6 +416,7 @@
int pri = bss->freq;
int sec = pri;
int sec_chan, pri_chan;
+ struct ieee802_11_elems elems;
ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
@@ -445,7 +448,23 @@
}
}
- /* TODO: 40 MHz intolerant */
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+ 0);
+ if (elems.ht_capabilities &&
+ elems.ht_capabilities_len >=
+ sizeof(struct ieee80211_ht_capabilities)) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 0;
+ }
+ }
}
return 1;
@@ -475,6 +494,7 @@
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
wpa_scan_results_free(scan_res);
+ iface->secondary_ch = iface->conf->secondary_channel;
if (!oper40) {
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
"channel pri=%d sec=%d based on overlapping BSSes",
@@ -482,9 +502,21 @@
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX) {
+ /*
+ * TODO: Could consider scheduling another scan to check
+ * if channel width can be changed if no coex reports
+ * are received from associating stations.
+ */
+ }
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
+ if (!res) {
+ iface->conf->secondary_channel = 0;
+ wpa_printf(MSG_INFO, "Fallback to 20 MHz");
+ }
+
hostapd_setup_interface_complete(iface, !res);
}
@@ -570,9 +602,55 @@
}
+static void ap_ht40_scan_retry(void *eloop_data, void *user_data)
+{
+#define HT2040_COEX_SCAN_RETRY 15
+ struct hostapd_iface *iface = eloop_data;
+ struct wpa_driver_scan_params params;
+ int ret;
+
+ os_memset(¶ms, 0, sizeof(params));
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, ¶ms);
+ else
+ ieee80211n_scan_channels_5g(iface, ¶ms);
+
+ ret = hostapd_driver_scan(iface->bss[0], ¶ms);
+ iface->num_ht40_scan_tries++;
+ os_free(params.freqs);
+
+ if (ret == -EBUSY &&
+ iface->num_ht40_scan_tries < HT2040_COEX_SCAN_RETRY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again (attempt %d)",
+ ret, strerror(-ret), iface->num_ht40_scan_tries);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return;
+ }
+
+ if (ret == 0) {
+ iface->scan_cb = ieee80211n_check_scan;
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "Failed to request a scan in device, bringing up in HT20 mode");
+ iface->conf->secondary_channel = 0;
+ iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ hostapd_setup_interface_complete(iface, 0);
+}
+
+
+void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+}
+
+
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
+ int ret;
if (!iface->conf->secondary_channel)
return 0; /* HT40 not used */
@@ -585,13 +663,26 @@
ieee80211n_scan_channels_2g4(iface, ¶ms);
else
ieee80211n_scan_channels_5g(iface, ¶ms);
- if (hostapd_driver_scan(iface->bss[0], ¶ms) < 0) {
- wpa_printf(MSG_ERROR, "Failed to request a scan of "
- "neighboring BSSes");
- os_free(params.freqs);
+
+ ret = hostapd_driver_scan(iface->bss[0], ¶ms);
+ os_free(params.freqs);
+
+ if (ret == -EBUSY) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s) - try to scan again",
+ ret, strerror(-ret));
+ iface->num_ht40_scan_tries = 1;
+ eloop_cancel_timeout(ap_ht40_scan_retry, iface, NULL);
+ eloop_register_timeout(1, 0, ap_ht40_scan_retry, iface, NULL);
+ return 1;
+ }
+
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ "Failed to request a scan of neighboring BSSes ret=%d (%s)",
+ ret, strerror(-ret));
return -1;
}
- os_free(params.freqs);
iface->scan_cb = ieee80211n_check_scan;
return 1;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 783ae5e..0f67ab8 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -23,6 +23,7 @@
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
+void hostapd_stop_setup_timers(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
@@ -61,6 +62,10 @@
return 0;
}
+static inline void hostapd_stop_setup_timers(struct hostapd_iface *iface)
+{
+}
+
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 14fb567..ca8db8f 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -62,7 +62,6 @@
}
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
i++) {
count++;
@@ -105,7 +104,6 @@
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
i++) {
count++;
@@ -565,7 +563,7 @@
}
#ifdef CONFIG_TESTING_OPTIONS
- if (hapd->iconf->ignore_auth_probability > 0.0d &&
+ if (hapd->iconf->ignore_auth_probability > 0.0 &&
drand48() < hapd->iconf->ignore_auth_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring auth frame from " MACSTR,
@@ -1291,7 +1289,7 @@
#ifdef CONFIG_TESTING_OPTIONS
if (reassoc) {
- if (hapd->iconf->ignore_reassoc_probability > 0.0d &&
+ if (hapd->iconf->ignore_reassoc_probability > 0.0 &&
drand48() < hapd->iconf->ignore_reassoc_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring reassoc request from "
@@ -1299,7 +1297,7 @@
return;
}
} else {
- if (hapd->iconf->ignore_assoc_probability > 0.0d &&
+ if (hapd->iconf->ignore_assoc_probability > 0.0 &&
drand48() < hapd->iconf->ignore_assoc_probability) {
wpa_printf(MSG_INFO,
"TESTING: ignoring assoc request from "
@@ -1628,7 +1626,8 @@
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
- if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+ if (!sta ||
+ wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
len - IEEE80211_HDRLEN))
break;
return 1;
@@ -1647,6 +1646,15 @@
#endif /* CONFIG_WNM */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
+#ifdef CONFIG_IEEE80211N
+ if (mgmt->u.action.u.public_action.action ==
+ WLAN_PA_20_40_BSS_COEX) {
+ wpa_printf(MSG_DEBUG,
+ "HT20/40 coex mgmt frame received from STA "
+ MACSTR, MAC2STR(mgmt->sa));
+ hostapd_2040_coex_action(hapd, mgmt, len);
+ }
+#endif /* CONFIG_IEEE80211N */
if (hapd->public_action_cb) {
hapd->public_action_cb(hapd->public_action_cb_ctx,
(u8 *) mgmt, len,
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 809b4ca..cf0d3f2 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,11 +14,14 @@
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
+struct ieee80211_mgmt;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
u16 stype, int ok);
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
@@ -39,6 +42,7 @@
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
+void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
@@ -59,6 +63,8 @@
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 1d64748..c0a7cd4 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -10,12 +10,15 @@
#include "utils/includes.h"
#include "utils/common.h"
+#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
+#include "hw_features.h"
+#include "ap_drv_ops.h"
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
@@ -172,6 +175,117 @@
}
+static int is_40_allowed(struct hostapd_iface *iface, int channel)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ int pri = 2407 + 5 * channel;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return 1;
+
+ pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+
+ if (iface->conf->secondary_channel > 0)
+ sec_freq = pri_freq + 20;
+ else
+ sec_freq = pri_freq - 20;
+
+ affected_start = (pri_freq + sec_freq) / 2 - 25;
+ affected_end = (pri_freq + sec_freq) / 2 + 25;
+ if ((pri < affected_start || pri > affected_end))
+ return 1; /* not within affected channel range */
+
+ wpa_printf(MSG_ERROR, "40 MHz affected channel range: [%d,%d] MHz",
+ affected_start, affected_end);
+ wpa_printf(MSG_ERROR, "Neighboring BSS: freq=%d", pri);
+ return 0;
+}
+
+
+void hostapd_2040_coex_action(struct hostapd_data *hapd,
+ const struct ieee80211_mgmt *mgmt, size_t len)
+{
+ struct hostapd_iface *iface = hapd->iface;
+ struct ieee80211_2040_bss_coex_ie *bc_ie;
+ struct ieee80211_2040_intol_chan_report *ic_report;
+ int is_ht_allowed = 1;
+ int i;
+ const u8 *data = (const u8 *) &mgmt->u.action.u.public_action.action;
+ size_t hdr_len;
+
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
+ mgmt->u.action.u.public_action.action);
+
+ if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
+
+ hdr_len = data - (u8 *) mgmt;
+ if (hdr_len > len)
+ return;
+ data++;
+
+ bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0];
+ ic_report = (struct ieee80211_2040_intol_chan_report *)
+ (&data[0] + sizeof(*bc_ie));
+
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20 MHz BSS width request bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "40 MHz intolerant bit is set in BSS coexistence information field");
+ is_ht_allowed = 0;
+ }
+
+ if (ic_report &&
+ (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) {
+ /* Go through the channel report to find any BSS there in the
+ * affected channel range */
+ for (i = 0; i < ic_report->length - 1; i++) {
+ if (is_40_allowed(iface, ic_report->variable[i]))
+ continue;
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "20_40_INTOLERANT channel %d reported",
+ ic_report->variable[i]);
+ is_ht_allowed = 0;
+ break;
+ }
+ }
+
+ if (!is_ht_allowed &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ if (iface->conf->secondary_channel) {
+ hostapd_logger(hapd, mgmt->sa,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO,
+ "Switching to 20 MHz operation");
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+ if (!iface->num_sta_ht40_intolerant) {
+ unsigned int delay_time;
+ delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
+ NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ hapd->iface, NULL);
+ }
+ }
+}
+
+
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
@@ -200,6 +314,52 @@
}
+void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return;
+
+ wpa_printf(MSG_INFO, "HT: Forty MHz Intolerant is set by STA " MACSTR
+ " in Association Request", MAC2STR(sta->addr));
+
+ if (sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 1;
+ iface->num_sta_ht40_intolerant++;
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+
+ if (iface->conf->secondary_channel &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ iface->conf->secondary_channel = 0;
+ ieee802_11_set_beacons(iface);
+ }
+}
+
+
+void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta)
+{
+ if (!sta->ht40_intolerant_set)
+ return;
+
+ sta->ht40_intolerant_set = 0;
+ iface->num_sta_ht40_intolerant--;
+
+ if (iface->num_sta_ht40_intolerant == 0 &&
+ (iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
+ unsigned int delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
+ iface->conf->obss_interval;
+ wpa_printf(MSG_DEBUG,
+ "HT: Start 20->40 MHz transition timer (%d seconds)",
+ delay_time);
+ eloop_cancel_timeout(ap_ht2040_timeout, iface, NULL);
+ eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
+ iface, NULL);
+ }
+}
+
+
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
u16 ht_capab;
@@ -227,6 +387,9 @@
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
+
+ if (ht_capab & HT_CAP_INFO_40MHZ_INTOLERANT)
+ ht40_intolerant_add(hapd->iface, sta);
}
@@ -288,3 +451,14 @@
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
}
+
+
+void ap_ht2040_timeout(void *eloop_data, void *user_data)
+{
+ struct hostapd_iface *iface = eloop_data;
+
+ wpa_printf(MSG_INFO, "Switching to 40 MHz operation");
+
+ iface->conf->secondary_channel = iface->secondary_ch;
+ ieee802_11_set_beacons(iface);
+}
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f5417de..60f0768 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -206,6 +206,10 @@
hapd->iface->num_sta_ht_20mhz--;
}
+#ifdef CONFIG_IEEE80211N
+ ht40_intolerant_remove(hapd->iface, sta);
+#endif /* CONFIG_IEEE80211N */
+
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 2dbdeb1..03db98f 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -54,6 +54,7 @@
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
+ unsigned int ht40_intolerant_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
unsigned int qos_map_enabled:1;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 77e7858..d212610 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1421,7 +1421,7 @@
key->key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
- wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0d &&
+ wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
drand48() <
wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index e957c6e..1e4defc 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -675,7 +675,7 @@
break;
}
}
- if (sm->pmksa) {
+ if (sm->pmksa && pmkid) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index cb70130..8fe2e4a 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -646,6 +646,7 @@
#define ERP_INFO_USE_PROTECTION BIT(1)
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+#define OVERLAPPING_BSS_TRANS_DELAY_FACTOR 5
/* HT Capabilities Info field within HT Capabilities element */
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
diff --git a/src/common/qca-vendor-attr.h b/src/common/qca-vendor-attr.h
new file mode 100644
index 0000000..6f51803
--- /dev/null
+++ b/src/common/qca-vendor-attr.h
@@ -0,0 +1,28 @@
+/*
+ * Qualcomm Atheros vendor specific attribute definitions
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef QCA_VENDOR_ATTR_H
+#define QCA_VENDOR_ATTR_H
+
+/*
+ * This file defines some of the attributes used with Qualcomm Atheros OUI
+ * 00:13:74 in a way that is not suitable for qca-vendor.h, e.g., due to
+ * compiler dependencies.
+ */
+
+struct qca_avoid_freq_range {
+ u32 start_freq;
+ u32 end_freq;
+} __attribute__ ((packed));
+
+struct qca_avoid_freq_list {
+ u32 count;
+ struct qca_avoid_freq_range range[0];
+} __attribute__ ((packed));
+
+#endif /* QCA_VENDOR_ATTR_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0e292e6..1bc981b 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -51,25 +51,18 @@
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10,
QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11,
QCA_NL80211_VENDOR_SUBCMD_NAN = 12,
+ QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
};
-struct qca_avoid_freq_range {
- u32 start_freq;
- u32 end_freq;
-} STRUCT_PACKED;
-
-struct qca_avoid_freq_list {
- u32 count;
- struct qca_avoid_freq_range range[0];
-} STRUCT_PACKED;
-
enum qca_wlan_vendor_attr {
QCA_WLAN_VENDOR_ATTR_INVALID = 0,
/* used by QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY */
QCA_WLAN_VENDOR_ATTR_DFS = 1,
/* used by QCA_NL80211_VENDOR_SUBCMD_NAN */
QCA_WLAN_VENDOR_ATTR_NAN = 2,
+ /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */
+ QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 13bf718..00565a7 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -868,6 +868,11 @@
* osen - Whether OSEN security is enabled
*/
int osen;
+
+ /**
+ * freq - Channel parameters for dynamic bandwidth changes
+ */
+ struct hostapd_freq_params *freq;
};
/**
@@ -921,7 +926,8 @@
#define WPA_DRIVER_FLAGS_AP 0x00000040
/* Driver needs static WEP key setup after association has been completed */
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE 0x00000080
-/* unused: 0x00000100 */
+/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+#define WPA_DRIVER_FLAGS_HT_2040_COEX 0x00000100
/* Driver supports concurrent P2P operations */
#define WPA_DRIVER_FLAGS_P2P_CONCURRENT 0x00000200
/*
@@ -2164,7 +2170,7 @@
* @session_timeout: Session timeout for the station
* Returns: 0 on success, -1 on failure
*/
- int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
+ int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted,
u32 session_timeout);
/**
@@ -2228,7 +2234,7 @@
* Returns: 0 on success, -1 on failure
*/
int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
- const char *bridge_ifname, char *ifname_wds);
+ const char *bridge_ifname, char *ifname_wds);
/**
* send_action - Transmit an Action frame
@@ -2516,7 +2522,7 @@
* signal_poll - Get current connection information
* @priv: Private driver interface data
* @signal_info: Connection info structure
- */
+ */
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 1300703..b0c8a35 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -29,6 +29,7 @@
#include "eloop.h"
#include "utils/list.h"
#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "l2_packet/l2_packet.h"
@@ -235,6 +236,7 @@
u8 addr[ETH_ALEN];
int freq;
+ int bandwidth;
int if_dynamic;
void *ctx;
@@ -385,8 +387,8 @@
enum wpa_driver_if_type type,
const char *ifname);
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
- struct hostapd_freq_params *freq);
+static int nl80211_set_channel(struct i802_bss *bss,
+ struct hostapd_freq_params *freq, int set_chan);
static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
int ifindex, int disabled);
@@ -536,22 +538,22 @@
static int is_ap_interface(enum nl80211_iftype nlmode)
{
- return (nlmode == NL80211_IFTYPE_AP ||
- nlmode == NL80211_IFTYPE_P2P_GO);
+ return nlmode == NL80211_IFTYPE_AP ||
+ nlmode == NL80211_IFTYPE_P2P_GO;
}
static int is_sta_interface(enum nl80211_iftype nlmode)
{
- return (nlmode == NL80211_IFTYPE_STATION ||
- nlmode == NL80211_IFTYPE_P2P_CLIENT);
+ return nlmode == NL80211_IFTYPE_STATION ||
+ nlmode == NL80211_IFTYPE_P2P_CLIENT;
}
static int is_p2p_net_interface(enum nl80211_iftype nlmode)
{
- return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
- nlmode == NL80211_IFTYPE_P2P_GO);
+ return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+ nlmode == NL80211_IFTYPE_P2P_GO;
}
@@ -3656,6 +3658,9 @@
if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+ if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+ capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
}
@@ -4522,7 +4527,7 @@
* it isn't per interface ... maybe just dump the scan
* results periodically for OLBC?
*/
-// WLAN_FC_STYPE_BEACON,
+ /* WLAN_FC_STYPE_BEACON, */
};
unsigned int i;
@@ -7299,6 +7304,30 @@
nl80211_set_bss(bss, params->cts_protect, params->preamble,
params->short_slot_time, params->ht_opmode,
params->isolate, params->basic_rates);
+ if (beacon_set && params->freq &&
+ params->freq->bandwidth != bss->bandwidth) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Update BSS %s bandwidth: %d -> %d",
+ bss->ifname, bss->bandwidth,
+ params->freq->bandwidth);
+ ret = nl80211_set_channel(bss, params->freq, 1);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frequency set failed: %d (%s)",
+ ret, strerror(-ret));
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Frequency set succeeded for ht2040 coex");
+ bss->bandwidth = params->freq->bandwidth;
+ }
+ } else if (!beacon_set) {
+ /*
+ * cfg80211 updates the driver on frequence change in AP
+ * mode only at the point when beaconing is started, so
+ * set the initial value here.
+ */
+ bss->bandwidth = params->freq->bandwidth;
+ }
}
return ret;
nla_put_failure:
@@ -7363,8 +7392,8 @@
}
-static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
- struct hostapd_freq_params *freq)
+static int nl80211_set_channel(struct i802_bss *bss,
+ struct hostapd_freq_params *freq, int set_chan)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
@@ -7378,7 +7407,8 @@
if (!msg)
return -1;
- nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
+ nl80211_cmd(drv, msg, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+ NL80211_CMD_SET_WIPHY);
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (nl80211_put_freq_params(msg, freq) < 0)
@@ -7841,7 +7871,7 @@
return;
}
- if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len, NULL)) {
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
return;
}
@@ -8395,7 +8425,7 @@
return -1;
}
- if (wpa_driver_nl80211_set_freq(drv->first_bss, &freq)) {
+ if (nl80211_set_channel(drv->first_bss, &freq, 0)) {
if (old_mode != nlmode)
wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
nl80211_remove_monitor_interface(drv);
@@ -9121,7 +9151,7 @@
static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
struct i802_bss *bss = priv;
- return wpa_driver_nl80211_set_freq(bss, freq);
+ return nl80211_set_channel(bss, freq, 0);
}
@@ -9620,7 +9650,7 @@
static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
- const char *bridge_ifname, char *ifname_wds)
+ const char *bridge_ifname, char *ifname_wds)
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 1b13d3d..3608b52 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1906,7 +1906,7 @@
/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
- if (!drv->ibss)
+ if (bss == NULL || !drv->ibss)
return;
pos = buf;
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 1ba9d62..406010d 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1579,6 +1579,10 @@
* @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
* As specified in the &enum nl80211_tdls_peer_capability.
*
+ * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * creation then the new interface will be owned by the netlink socket
+ * that created it and will be destroyed when the socket is closed
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1914,6 +1918,8 @@
NL80211_ATTR_TDLS_PEER_CAPABILITY,
+ NL80211_ATTR_IFACE_SOCKET_OWNER,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2336,9 +2342,34 @@
* using this channel as the primary or any of the secondary channels
* isn't possible
* @NL80211_FREQUENCY_ATTR_DFS_CAC_TIME: DFS CAC time in milliseconds.
+ * @NL80211_FREQUENCY_ATTR_INDOOR_ONLY: Only indoor use is permitted on this
+ * channel. A channel that has the INDOOR_ONLY attribute can only be
+ * used when there is a clear assessment that the device is operating in
+ * an indoor surroundings, i.e., it is connected to AC power (and not
+ * through portable DC inverters) or is under the control of a master
+ * that is acting as an AP and is connected to AC power.
+ * @NL80211_FREQUENCY_ATTR_GO_CONCURRENT: GO operation is allowed on this
+ * channel if it's connected concurrently to a BSS on the same channel on
+ * the 2 GHz band or to a channel in the same UNII band (on the 5 GHz
+ * band), and IEEE80211_CHAN_RADAR is not set. Instantiating a GO on a
+ * channel that has the GO_CONCURRENT attribute set can be done when there
+ * is a clear assessment that the device is operating under the guidance of
+ * an authorized master, i.e., setting up a GO while the device is also
+ * connected to an AP with DFS and radar detection on the UNII band (it is
+ * up to user-space, i.e., wpa_supplicant to perform the required
+ * verifications)
+ * @NL80211_FREQUENCY_ATTR_NO_20MHZ: 20 MHz operation is not allowed
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_10MHZ: 10 MHz operation is not allowed
+ * on this channel in current regulatory domain.
* @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number
* currently defined
* @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use
+ *
+ * See https://apps.fcc.gov/eas/comments/GetPublishedDocument.html?id=327&tn=528122
+ * for more information on the FCC description of the relaxations allowed
+ * by NL80211_FREQUENCY_ATTR_INDOOR_ONLY and
+ * NL80211_FREQUENCY_ATTR_GO_CONCURRENT.
*/
enum nl80211_frequency_attr {
__NL80211_FREQUENCY_ATTR_INVALID,
@@ -2355,6 +2386,10 @@
NL80211_FREQUENCY_ATTR_NO_80MHZ,
NL80211_FREQUENCY_ATTR_NO_160MHZ,
NL80211_FREQUENCY_ATTR_DFS_CAC_TIME,
+ NL80211_FREQUENCY_ATTR_INDOOR_ONLY,
+ NL80211_FREQUENCY_ATTR_GO_CONCURRENT,
+ NL80211_FREQUENCY_ATTR_NO_20MHZ,
+ NL80211_FREQUENCY_ATTR_NO_10MHZ,
/* keep last */
__NL80211_FREQUENCY_ATTR_AFTER_LAST,
@@ -2573,10 +2608,13 @@
* present has been registered with the wireless core that
* has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
* supported feature.
+ * @NL80211_USER_REG_HINT_INDOOR: a user sent an hint indicating that the
+ * platform is operating in an indoor environment.
*/
enum nl80211_user_reg_hint_type {
NL80211_USER_REG_HINT_USER = 0,
NL80211_USER_REG_HINT_CELL_BASE = 1,
+ NL80211_USER_REG_HINT_INDOOR = 2,
};
/**
@@ -3891,6 +3929,9 @@
* interface. An active monitor interface behaves like a normal monitor
* interface, but gets added to the driver. It ensures that incoming
* unicast packets directed at the configured interface address get ACKed.
+ * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic
+ * channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the
+ * lifetime of a BSS.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
@@ -3911,6 +3952,7 @@
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
+ NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18,
};
/**
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index bcc7e64..b30ea56 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4210,7 +4210,7 @@
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
} while (dev->flags & P2P_DEV_PROBE_REQ_ONLY);
}
@@ -4222,7 +4222,7 @@
dev = dl_list_first(&dev->list,
struct p2p_device,
list);
- if (&dev->list == &p2p->devices)
+ if (!dev || &dev->list == &p2p->devices)
return NULL;
}
}
@@ -4463,12 +4463,24 @@
p2p_buf_add_device_info(buf, p2p, NULL);
if (p2p->num_groups > 0) {
+ int freq = p2p_group_get_freq(p2p->groups[0]);
role = P2P_GO_IN_A_GROUP;
- p2p_freq_to_channel(p2p_group_get_freq(p2p->groups[0]),
- &op_class, &channel);
+ if (p2p_freq_to_channel(freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown GO operating frequency %d MHz for NFC handover",
+ freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
} else if (client_freq > 0) {
role = P2P_CLIENT_IN_A_GROUP;
- p2p_freq_to_channel(client_freq, &op_class, &channel);
+ if (p2p_freq_to_channel(client_freq, &op_class, &channel) < 0) {
+ p2p_dbg(p2p,
+ "Unknown client operating frequency %d MHz for NFC handover",
+ client_freq);
+ wpabuf_free(buf);
+ return NULL;
+ }
}
p2p_buf_add_oob_go_neg_channel(buf, p2p->cfg->country, op_class,
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 94440f2..6044f5f 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -18,11 +18,9 @@
#ifdef WPA_TRACE_BFD
#include <bfd.h>
-#ifdef __linux__
-#include <demangle.h>
-#else /* __linux__ */
-#include <libiberty/demangle.h>
-#endif /* __linux__ */
+
+#define DMGL_PARAMS (1 << 0)
+#define DMGL_ANSI (1 << 1)
static char *prg_fname = NULL;
static bfd *cached_abfd = NULL;
diff --git a/src/wps/http_server.c b/src/wps/http_server.c
index 06c8bee..ac088c4 100644
--- a/src/wps/http_server.c
+++ b/src/wps/http_server.c
@@ -244,7 +244,13 @@
if (srv->fd < 0)
goto fail;
- setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ if (setsockopt(srv->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+ {
+ wpa_printf(MSG_DEBUG,
+ "HTTP: setsockopt(SO_REUSEADDR) failed: %s",
+ strerror(errno));
+ /* try to continue anyway */
+ }
if (fcntl(srv->fd, F_SETFL, O_NONBLOCK) < 0)
goto fail;
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index b51d975..6d2d11c 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -617,7 +617,6 @@
* We do NOT support trailers except to skip them --
* this is supported (generally) by the http spec.
*/
- bbp = h->body + h->body_nbytes;
for (;;) {
int c;
if (nread <= 0)
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 416961c..098571c 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -134,6 +134,8 @@
*islast = 0;
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (!iface)
+ return NULL;
uuid_bin2str(iface->wps->uuid, uuid_string, sizeof(uuid_string));
msg = wpabuf_alloc(800); /* more than big enough */
if (msg == NULL)
@@ -587,6 +589,8 @@
&sm->interfaces,
struct upnp_wps_device_interface,
list);
+ if (!iface)
+ continue;
data += os_strlen("uuid:");
uuid_bin2str(iface->wps->uuid, uuid_string,
sizeof(uuid_string));
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 54c3658..b1cf571 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -179,15 +179,12 @@
/* format_wps_device_xml -- produce content of "file" wps_device.xml
* (UPNP_WPS_DEVICE_XML_FILE)
*/
-static void format_wps_device_xml(struct upnp_wps_device_sm *sm,
+static void format_wps_device_xml(struct upnp_wps_device_interface *iface,
+ struct upnp_wps_device_sm *sm,
struct wpabuf *buf)
{
const char *s;
char uuid_string[80];
- struct upnp_wps_device_interface *iface;
-
- iface = dl_list_first(&sm->interfaces,
- struct upnp_wps_device_interface, list);
wpabuf_put_str(buf, wps_device_xml_prefix);
@@ -319,6 +316,10 @@
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (iface == NULL) {
+ http_request_deinit(hreq);
+ return;
+ }
/*
* It is not required that filenames be case insensitive but it is
@@ -391,7 +392,7 @@
switch (req) {
case GET_DEVICE_XML_FILE:
- format_wps_device_xml(sm, buf);
+ format_wps_device_xml(iface, sm, buf);
break;
case GET_SCPD_XML_FILE:
wpabuf_put_str(buf, wps_scpd_xml);
@@ -419,13 +420,14 @@
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
- peer = &iface->peer;
wpa_printf(MSG_DEBUG, "WPS UPnP: GetDeviceInfo");
- if (iface->ctx->ap_pin == NULL)
+ if (!iface || iface->ctx->ap_pin == NULL)
return HTTP_INTERNAL_SERVER_ERROR;
+ peer = &iface->peer;
+
/*
* Request for DeviceInfo, i.e., M1 TLVs. This is a start of WPS
* registration over UPnP with the AP acting as an Enrollee. It should
@@ -473,6 +475,8 @@
iface = dl_list_first(&sm->interfaces,
struct upnp_wps_device_interface, list);
+ if (!iface)
+ return HTTP_INTERNAL_SERVER_ERROR;
/*
* PutMessage is used by external UPnP-based Registrar to perform WPS