aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c7
-rw-r--r--src/ap/ap_config.c10
-rw-r--r--src/ap/beacon.c16
-rw-r--r--src/ap/ctrl_iface_ap.c2
-rw-r--r--src/ap/drv_callbacks.c22
-rw-r--r--src/ap/hostapd.c7
-rw-r--r--src/ap/hostapd.h8
-rw-r--r--src/ap/hw_features.c103
-rw-r--r--src/ap/hw_features.h5
-rw-r--r--src/ap/ieee802_11.c20
-rw-r--r--src/ap/ieee802_11.h6
-rw-r--r--src/ap/ieee802_11_ht.c174
-rw-r--r--src/ap/sta_info.c4
-rw-r--r--src/ap/sta_info.h1
-rw-r--r--src/ap/wpa_auth.c2
-rw-r--r--src/ap/wpa_auth_ie.c2
-rw-r--r--src/common/ieee802_11_defs.h1
-rw-r--r--src/common/qca-vendor-attr.h28
-rw-r--r--src/common/qca-vendor.h13
-rw-r--r--src/drivers/driver.h14
-rw-r--r--src/drivers/driver_nl80211.c62
-rw-r--r--src/drivers/driver_test.c2
-rw-r--r--src/drivers/nl80211_copy.h42
-rw-r--r--src/p2p/p2p.c22
-rw-r--r--src/utils/trace.c8
-rw-r--r--src/wps/http_server.c8
-rw-r--r--src/wps/httpread.c1
-rw-r--r--src/wps/wps_upnp_ssdp.c4
-rw-r--r--src/wps/wps_upnp_web.c20
-rw-r--r--wpa_supplicant/bss.c3
-rw-r--r--wpa_supplicant/config_file.c12
-rw-r--r--wpa_supplicant/events.c8
-rw-r--r--wpa_supplicant/p2p_supplicant.c9
33 files changed, 562 insertions, 84 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 5f842810..caf51a94 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2445,8 +2445,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
line);
return 1;
-#endif /* CONFIG_ACS */
+#else /* CONFIG_ACS */
conf->channel = 0;
+#endif /* CONFIG_ACS */
} else
conf->channel = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
@@ -3074,8 +3075,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
char *end; \
\
conf->_val = strtod(pos, &end); \
- if (*end || conf->_val < 0.0d || \
- conf->_val > 1.0d) { \
+ if (*end || conf->_val < 0.0 || \
+ conf->_val > 1.0) { \
wpa_printf(MSG_ERROR, \
"Line %d: Invalid value '%s'", \
line, pos); \
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 0a143d39..9680817b 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -174,11 +174,11 @@ struct hostapd_config * hostapd_config_defaults(void)
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 56df3182..27525dc6 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -645,7 +645,7 @@ void handle_probe_req(struct hostapd_data *hapd,
* 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 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
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 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
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, &params);
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 97609334..ccbbab5b 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -405,6 +405,7 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"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 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
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 a8c24ebd..fb095efb 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 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
#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 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
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 614a5bf4..391d7746 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 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
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 090544d5..bd85c54a 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -327,6 +327,9 @@ struct hostapd_iface {
/* 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 @@ struct hostapd_iface {
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 d47a366b..b3618345 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 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
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 @@ static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
}
}
- /* 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 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
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 @@ static void ieee80211n_check_scan(struct hostapd_iface *iface)
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 ieee80211n_scan_channels_5g(struct hostapd_iface *iface,
}
+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(&params, 0, sizeof(params));
+ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ ieee80211n_scan_channels_2g4(iface, &params);
+ else
+ ieee80211n_scan_channels_5g(iface, &params);
+
+ ret = hostapd_driver_scan(iface->bss[0], &params);
+ 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 @@ static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
ieee80211n_scan_channels_2g4(iface, &params);
else
ieee80211n_scan_channels_5g(iface, &params);
- if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
- wpa_printf(MSG_ERROR, "Failed to request a scan of "
- "neighboring BSSes");
- os_free(params.freqs);
+
+ ret = hostapd_driver_scan(iface->bss[0], &params);
+ 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 783ae5e1..0f67ab8e 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -23,6 +23,7 @@ int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
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 @@ static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
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 14fb5675..ca8db8fb 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -62,7 +62,6 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
*pos++ = num;
- count = 0;
for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
i++) {
count++;
@@ -105,7 +104,6 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*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 @@ static void handle_auth(struct hostapd_data *hapd,
}
#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 @@ static void handle_assoc(struct hostapd_data *hapd,
#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 @@ static void handle_assoc(struct hostapd_data *hapd,
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 @@ static int handle_action(struct hostapd_data *hapd,
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 @@ static int handle_action(struct hostapd_data *hapd,
#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 809b4ca6..cf0d3f2b 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,11 +14,14 @@ struct hostapd_data;
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 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
#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 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
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 1d64748f..c0a7cd41 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 @@ int hostapd_ht_operation_update(struct hostapd_iface *iface)
}
+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 @@ u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
}
+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 @@ static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
__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 @@ void hostapd_get_ht_capab(struct hostapd_data *hapd,
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 f5417de0..60f07682 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -206,6 +206,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
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 2dbdeb18..03db98f6 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -54,6 +54,7 @@ struct sta_info {
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 77e78584..d2126103 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1421,7 +1421,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
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 e957c6e9..1e4defcf 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -675,7 +675,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
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 cb70130d..8fe2e4a6 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -646,6 +646,7 @@ struct ieee80211_vht_operation {
#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 00000000..6f51803e
--- /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 0e292e67..1bc981b0 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -51,25 +51,18 @@ enum qca_nl80211_vendor_subcmds {
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 13bf7183..00565a7b 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -868,6 +868,11 @@ struct wpa_driver_ap_params {
* osen - Whether OSEN security is enabled
*/
int osen;
+
+ /**
+ * freq - Channel parameters for dynamic bandwidth changes
+ */
+ struct hostapd_freq_params *freq;
};
/**
@@ -921,7 +926,8 @@ struct wpa_driver_capa {
#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 @@ struct wpa_driver_ops {
* @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 @@ struct wpa_driver_ops {
* 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 @@ struct wpa_driver_ops {
* 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 1300703e..b0c8a35f 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 @@ struct i802_bss {
u8 addr[ETH_ALEN];
int freq;
+ int bandwidth;
int if_dynamic;
void *ctx;
@@ -385,8 +387,8 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
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 enum chan_width convert2width(int width)
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 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info,
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 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
* 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 @@ static int wpa_driver_nl80211_set_ap(void *priv,
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 @@ nla_put_failure:
}
-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 @@ static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
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 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
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 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
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 wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
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 have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
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 1b13d3d2..3608b522 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1906,7 +1906,7 @@ static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
/* 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 1ba9d626..406010d4 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1579,6 +1579,10 @@ enum nl80211_commands {
* @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 @@ enum nl80211_attrs {
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 @@ enum nl80211_band_attr {
* 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 @@ enum nl80211_frequency_attr {
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 @@ enum nl80211_dfs_regions {
* 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 @@ enum nl80211_ap_sme_features {
* 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 @@ enum nl80211_feature_flags {
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 bcc7e644..b30ea56f 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -4210,7 +4210,7 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
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 @@ p2p_get_peer_found(struct p2p_data *p2p, const u8 *addr, int next)
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 @@ static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p,
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 94440f2f..6044f5f7 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -18,11 +18,9 @@ static struct dl_list active_references =
#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 06c8bee2..ac088c42 100644
--- a/src/wps/http_server.c
+++ b/src/wps/http_server.c
@@ -244,7 +244,13 @@ struct http_server * http_server_init(struct in_addr *addr, int port,
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 b51d9757..6d2d11c4 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -617,7 +617,6 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
* 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 416961cc..098571ce 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -134,6 +134,8 @@ next_advertisement(struct upnp_wps_device_sm *sm,
*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 @@ static void ssdp_parse_msearch(struct upnp_wps_device_sm *sm,
&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 54c3658a..b1cf571d 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -179,15 +179,12 @@ static const char *wps_device_xml_postfix =
/* 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 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
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 @@ static void web_connection_parse_get(struct upnp_wps_device_sm *sm,
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 @@ web_process_get_device_info(struct upnp_wps_device_sm *sm,
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 @@ web_process_put_message(struct upnp_wps_device_sm *sm, char *data,
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
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 482fc64f..f99a8a71 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -674,7 +674,8 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
wpa_s->last_scan_res_size = siz;
}
- wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
+ if (wpa_s->last_scan_res)
+ wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
}
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8d59f496..38429467 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -352,8 +352,8 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
FILE *f;
char buf[512], *pos;
int errors = 0, line = 0;
- struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
- struct wpa_cred *cred, *cred_tail = NULL, *cred_head = NULL;
+ struct wpa_ssid *ssid, *tail, *head;
+ struct wpa_cred *cred, *cred_tail, *cred_head;
struct wpa_config *config;
int id = 0;
int cred_id = 0;
@@ -369,8 +369,12 @@ struct wpa_config * wpa_config_read(const char *name, struct wpa_config *cfgp)
"structure");
return NULL;
}
- head = config->ssid;
- cred_head = config->cred;
+ tail = head = config->ssid;
+ while (tail && tail->next)
+ tail = tail->next;
+ cred_tail = cred_head = config->cred;
+ while (cred_tail && cred_tail->next)
+ cred_tail = cred_tail->next;
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7eedd837..9b7323bb 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3366,6 +3366,14 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
}
#endif /* CONFIG_P2P */
+ if (wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ /*
+ * Indicate disconnection to keep ctrl_iface events
+ * consistent.
+ */
+ wpa_supplicant_event_disassoc(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING, 1);
+ }
wpa_supplicant_mark_disassoc(wpa_s);
radio_remove_works(wpa_s, NULL, 0);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 49b2cd28..522d277a 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -6781,7 +6781,7 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
{
struct wpa_ssid *ssid = wpa_s->current_ssid;
struct wpa_ssid *persistent;
- struct psk_list_entry *p;
+ struct psk_list_entry *p, *last;
if (psk_len != sizeof(p->psk))
return;
@@ -6841,10 +6841,9 @@ void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
}
os_memcpy(p->psk, psk, psk_len);
- if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS) {
- struct psk_list_entry *last;
- last = dl_list_last(&persistent->psk_list,
- struct psk_list_entry, list);
+ if (dl_list_len(&persistent->psk_list) > P2P_MAX_STORED_CLIENTS &&
+ (last = dl_list_last(&persistent->psk_list,
+ struct psk_list_entry, list))) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Remove oldest PSK entry for "
MACSTR " (p2p=%u) to make room for a new one",
MAC2STR(last->addr), last->p2p);