Cumulative patch from commit 3b208346ec56342fda736e62601df485ed002493
3b20834 ctrl_iface: BSS command to skip info items if parsing fails
a9c52e8 HS 2.0R2: No longer use HTTP_RAW_POST_DATA
04c18fa curl: Don't free memory for subjectAltName before calling callback
5a8e48f mesh: Use MESH_CAP_* macros for mesh capability
d70a8ab mesh: Ignore crowded peer
a151b0e mesh: Select pairwise and group cipher based on network profile
3b6deac mesh: Avoid use of hardcoded cipher
f868d56 mesh: Clean up AMPE element encoding and parsing
4367eec mesh: Do not use RX MGTK as RX IGTK
a4eec3c mesh: Use variable length MGTK for RX
fccba2c mesh: Generate a separate TX IGTK if PMF is enabled
696f792 mesh: Support variable length TX MGTK
b02f4d0 mesh: Add variable length MTK support
846201d mesh: Coding style cleanup for MTK derivation
0f76d82 mesh: Fix MTK derivation to use AKM suite selector
f5ba692 mesh: Coding style cleanup for AEK derivation
a59c5e9 mesh: Fix AEK derivation to use AKM suite selector
18aca1a mesh: Use ieee80211w profile parameter
b8b499e mesh: Use WPA_NONCE_LEN macro
bb4e19e hostapd: Skip hostapd ACL check for drivers supporting ACL offload
00ec535 WPS: Fix memory leak with wps_ie in wpa_bss_is_wps_candidate()
d1296da Reserve QCA vendor specific nl80211 command 121
fae7b37 WPS: Do not expire probable BSSes for WPS connection
52a6c9c Add a QCA vendor command to configure AP parameters
31d3692 hostapd: Add comment about '-i' parameter in hostapd.conf
40f6282 hostapd: Accept interface names as a command line parameter
cc27c8e hostapd: Fix early init failure path
976dfb3 FST: Make fst_global_deinit() more robust
7a69fad mesh: Sync max peer links with kernel
f7cb6e9 Update PKCS#11 references in template wpa_supplicant.conf
c3d7fb7 OpenSSL: Initialise PKCS#11 engine even if found with ENGINE_by_id()
fdc1188 nl80211: Fix use-after-free in qca_nl80211_get_features()
8359472 hostapd Make GAS Address3 field selection behavior configurable
6996ff7 hostapd: Fix Public Action frame TX status processing for wildcard BSSID
78a3632 hostapd: Fix Public Action frame addressing (BSSID field)
c86bef2 wpa_supplicant: Make GAS Address3 field selection behavior configurable
a5a187b nl80211: Add TEST_FAIL() to command generation and set_mode
ee854ff mesh: Remove extra newline from the end of an error message
331f077 mesh: Allow 160 MHz channel to be configured
92a515b nl80211: Update drv->assoc_freq on mesh join
d2cc8bb mesh: Remove unreachable code
cc9a257 nl80211: Use extended capabilities per interface type
c6edea0 Sync with mac80211-next.git include/uapi/linux/nl80211.h
9a5160f Report connection timeouts in CTRL-EVENT-ASSOC-REJECT
dad0129 mesh: Support simple SAE group negotiation case
b4c738e mesh: Fix error path handling for RSN (MGTK init)
f4b4ddf D-Bus: Remove unused wpas_dbus_signal_p2p_group_started() parameter
4fe50bb D-Bus: Indicate whether created group is persistent or not
62fc8e6 mesh: Fix MESH_INTERFACE_ADD error path cleanup
9c10be3 mesh: Fix error path handling in init OOM cases
7012e25 Remove dead code from wpas_sched_scan_plans_set()
8e909fa Improve reattach scan OOM failure handling
f37d8a4 Indicate scan failure event on parameter cloning failure
9356823 wpaspy: Fix potentially referencing non existing attribute
Change-Id: I656be560523c206195a5bf8649e73d8aa70bd8f9
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index b263eb0..0ae9a6e 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -41,6 +41,10 @@
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
unsigned int security;
+ enum mfp_options ieee80211w;
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ unsigned int mgmt_group_cipher;
int dot11MeshMaxRetries;
int dot11MeshRetryTimeout; /* msec */
int dot11MeshConfirmTimeout; /* msec */
@@ -504,6 +508,7 @@
u16 gas_comeback_delay;
int gas_frag_limit;
+ int gas_address3;
u8 qos_map_set[16 + 2 * 21];
unsigned int qos_map_set_len;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index dca6b8b..532b72f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -675,6 +675,36 @@
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
{
+ const u8 *bssid;
+ const u8 wildcard_bssid[ETH_ALEN] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+ return 0;
+ bssid = hapd->own_addr;
+ if (!is_multicast_ether_addr(dst) &&
+ len > 0 && data[0] == WLAN_ACTION_PUBLIC) {
+ struct sta_info *sta;
+
+ /*
+ * Public Action frames to a STA that is not a member of the BSS
+ * shall use wildcard BSSID value.
+ */
+ sta = ap_get_sta(hapd, dst);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC))
+ bssid = wildcard_bssid;
+ }
+ return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+ hapd->own_addr, bssid, data, len, 0);
+}
+
+
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len)
+{
if (hapd->driver == NULL || hapd->driver->send_action == NULL)
return 0;
return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
@@ -750,6 +780,20 @@
}
+void hostapd_get_ext_capa(struct hostapd_iface *iface)
+{
+ struct hostapd_data *hapd = iface->bss[0];
+
+ if (!hapd->driver || !hapd->driver->get_ext_capab)
+ return;
+
+ hapd->driver->get_ext_capab(hapd->drv_priv, WPA_IF_AP_BSS,
+ &iface->extended_capa,
+ &iface->extended_capa_mask,
+ &iface->extended_capa_len);
+}
+
+
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 6ea1dab..6406d13 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -99,6 +99,10 @@
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len);
+int hostapd_drv_send_action_addr3_ap(struct hostapd_data *hapd,
+ unsigned int freq,
+ unsigned int wait, const u8 *dst,
+ const u8 *data, size_t len);
int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg);
int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
@@ -124,6 +128,8 @@
int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
u8 qos_map_set_len);
+void hostapd_get_ext_capa(struct hostapd_iface *iface);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3ab5bf3..3552b3e 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -116,8 +116,15 @@
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
- res = hostapd_check_acl(hapd, addr, NULL);
- if (res != HOSTAPD_ACL_ACCEPT) {
+ /*
+ * ACL configurations to the drivers (implementing AP SME and ACL
+ * offload) without hostapd's knowledge, can result in a disconnection
+ * though the driver accepts the connection. Skip the hostapd check for
+ * ACL if the driver supports ACL offload to avoid potentially
+ * conflicting ACL rules.
+ */
+ if (hapd->iface->drv_max_acl_mac_addrs == 0 &&
+ hostapd_check_acl(hapd, addr, NULL) != HOSTAPD_ACL_ACCEPT) {
wpa_printf(MSG_INFO, "STA " MACSTR " not allowed to connect",
MAC2STR(addr));
reason = WLAN_REASON_UNSPECIFIED;
@@ -916,11 +923,24 @@
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
+ struct hostapd_data *orig_hapd = hapd;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
- if (hapd == NULL || hapd == HAPD_BROADCAST)
+ if (!hapd)
return;
+ if (hapd == HAPD_BROADCAST) {
+ if (stype != WLAN_FC_STYPE_ACTION || len <= 25 ||
+ buf[24] != WLAN_ACTION_PUBLIC)
+ return;
+ hapd = get_hapd_bssid(orig_hapd->iface, hdr->addr2);
+ if (!hapd || hapd == HAPD_BROADCAST)
+ return;
+ /*
+ * Allow processing of TX status for a Public Action frame that
+ * used wildcard BBSID.
+ */
+ }
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
}
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 179dc7a..6ce178d 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -1166,7 +1166,8 @@
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
- struct anqp_query_info *qi, int prot)
+ struct anqp_query_info *qi, int prot,
+ int std_addr3)
{
struct wpabuf *buf, *tx_buf;
@@ -1227,15 +1228,22 @@
return;
if (prot)
convert_to_protected_dual(tx_buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
const u8 *pos = data;
const u8 *end = data + len;
@@ -1287,8 +1295,15 @@
wpabuf_put_le16(buf, 0); /* Query Response Length */
if (prot)
convert_to_protected_dual(buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(buf), wpabuf_len(buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd,
+ hapd->iface->freq, 0,
+ sa, wpabuf_head(buf),
+ wpabuf_len(buf));
wpabuf_free(buf);
return;
}
@@ -1338,13 +1353,15 @@
pos += elen;
}
- gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot);
+ gas_serv_req_local_processing(hapd, sa, dialog_token, &qi, prot,
+ std_addr3);
}
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
const u8 *sa,
- const u8 *data, size_t len, int prot)
+ const u8 *data, size_t len, int prot,
+ int std_addr3)
{
struct gas_dialog_info *dialog;
struct wpabuf *buf, *tx_buf;
@@ -1420,8 +1437,14 @@
send_resp:
if (prot)
convert_to_protected_dual(tx_buf);
- hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
- wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+ if (std_addr3)
+ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
+ else
+ hostapd_drv_send_action_addr3_ap(hapd, hapd->iface->freq, 0, sa,
+ wpabuf_head(tx_buf),
+ wpabuf_len(tx_buf));
wpabuf_free(tx_buf);
}
@@ -1432,7 +1455,7 @@
struct hostapd_data *hapd = ctx;
const struct ieee80211_mgmt *mgmt;
const u8 *sa, *data;
- int prot;
+ int prot, std_addr3;
mgmt = (const struct ieee80211_mgmt *) buf;
if (len < IEEE80211_HDRLEN + 2)
@@ -1447,14 +1470,22 @@
*/
prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL;
sa = mgmt->sa;
+ if (hapd->conf->gas_address3 == 1)
+ std_addr3 = 1;
+ else if (hapd->conf->gas_address3 == 2)
+ std_addr3 = 0;
+ else
+ std_addr3 = is_broadcast_ether_addr(mgmt->bssid);
len -= IEEE80211_HDRLEN + 1;
data = buf + IEEE80211_HDRLEN + 1;
switch (data[0]) {
case WLAN_PA_GAS_INITIAL_REQ:
- gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
case WLAN_PA_GAS_COMEBACK_REQ:
- gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot);
+ gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1, prot,
+ std_addr3);
break;
}
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 42c1aaa..30f57f4 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -206,10 +206,12 @@
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
- char *ifname)
+ const char *ifname)
{
int i;
+ if (!ifname)
+ return;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
0, NULL, 0, NULL, 0)) {
@@ -2005,6 +2007,8 @@
static void hostapd_bss_deinit(struct hostapd_data *hapd)
{
+ if (!hapd)
+ return;
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
hapd->conf->iface);
hostapd_bss_deinit_no_free(hapd);
@@ -2039,8 +2043,11 @@
}
#endif /* CONFIG_FST */
- for (j = iface->num_bss - 1; j >= 0; j--)
+ for (j = iface->num_bss - 1; j >= 0; j--) {
+ if (!iface->bss)
+ break;
hostapd_bss_deinit(iface->bss[j]);
+ }
}
@@ -2049,6 +2056,8 @@
size_t j;
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
for (j = 0; j < iface->num_bss; j++) {
+ if (!iface->bss)
+ break;
wpa_printf(MSG_DEBUG, "%s: free hapd %p",
__func__, iface->bss[j]);
os_free(iface->bss[j]);
@@ -2849,8 +2858,8 @@
void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s)
{
wpa_printf(MSG_INFO, "%s: interface state %s->%s",
- iface->conf->bss[0]->iface, hostapd_state_text(iface->state),
- hostapd_state_text(s));
+ iface->conf ? iface->conf->bss[0]->iface : "N/A",
+ hostapd_state_text(iface->state), hostapd_state_text(s));
iface->state = s;
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 4dba8cb..195679e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -53,6 +53,7 @@
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
+ int eloop_initialized;
};
enum hostapd_chan_status {
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 781afa2..f6fca67 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -518,6 +518,9 @@
if (sae_check_big_sync(sta))
return;
sta->sae->sync++;
+ wpa_printf(MSG_DEBUG, "SAE: Auth SAE retransmit timer for " MACSTR
+ " (sync=%d state=%d)",
+ MAC2STR(sta->addr), sta->sae->sync, sta->sae->state);
switch (sta->sae->state) {
case SAE_COMMITTED:
@@ -724,6 +727,44 @@
}
+static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ struct sae_data *sae = sta->sae;
+ int i, *groups = hapd->conf->sae_groups;
+
+ if (sae->state != SAE_COMMITTED)
+ return;
+
+ wpa_printf(MSG_DEBUG, "SAE: Previously selected group: %d", sae->group);
+
+ for (i = 0; groups && groups[i] > 0; i++) {
+ if (sae->group == groups[i])
+ break;
+ }
+
+ if (!groups || groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Previously selected group not found from the current configuration");
+ return;
+ }
+
+ for (;;) {
+ i++;
+ if (groups[i] <= 0) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: No alternative group enabled");
+ return;
+ }
+
+ if (sae_set_group(sae, groups[i]) < 0)
+ continue;
+
+ break;
+ }
+ wpa_printf(MSG_DEBUG, "SAE: Selected new group: %d", groups[i]);
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -811,6 +852,16 @@
return;
}
+ if ((hapd->conf->mesh & MESH_ENABLED) &&
+ status_code ==
+ WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
+ sta->sae->tmp) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Peer did not accept our SAE group");
+ sae_pick_next_group(hapd, sta);
+ goto remove_sta;
+ }
+
if (status_code != WLAN_STATUS_SUCCESS)
goto remove_sta;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index c49402d..5d4d0c8 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -12,6 +12,7 @@
#ifdef CONFIG_MESH
/* needed for mesh_plink_state enum */
#include "common/defs.h"
+#include "common/wpa_common.h"
#endif /* CONFIG_MESH */
#include "list.h"
@@ -81,11 +82,19 @@
u16 my_lid;
u16 mpm_close_reason;
int mpm_retries;
- u8 my_nonce[32];
- u8 peer_nonce[32];
+ u8 my_nonce[WPA_NONCE_LEN];
+ u8 peer_nonce[WPA_NONCE_LEN];
u8 aek[32]; /* SHA256 digest length */
- u8 mtk[16];
- u8 mgtk[16];
+ u8 mtk[WPA_TK_MAX_LEN];
+ size_t mtk_len;
+ u8 mgtk_rsc[6];
+ u8 mgtk_key_id;
+ u8 mgtk[WPA_TK_MAX_LEN];
+ size_t mgtk_len;
+ u8 igtk_rsc[6];
+ u8 igtk[WPA_TK_MAX_LEN];
+ size_t igtk_len;
+ u16 igtk_key_id;
u8 sae_auth_retry;
#endif /* CONFIG_MESH */