Cumulative patch from commit 128f6a98b3d4d6ed103db759707309f451db9682
128f6a98b mka: Fix the order of operations in secure channel deletion
213eb1885 dbus: Set mode to mesh in bss properties when mesh is supported
21fda4ee7 RSN: Fix pre-authentication EAPOL-Start startPeriod configuration
3f23260da nl80211: Notify reason for connection timeout failure
ca1ab9db2 hostapd: Get vendor HE capabilities
7785c70bb QCA vendor command for fetching HE capabilities
d512f406f hostapd: Add IEEE 802.11ax HE IEs into Beacon/Probe Response frames
94380cb40 hostapd: Initial IEEE 802.11ax (HE) definitions
5972dc73c mesh: Use correct rate in VHT and HT mixed environment
84ea61cff mesh: Use correct rate in HT and legacy mixed environment
025c6a47f VHT: Remove a redundant check
a7a638c2c hw_features: Move VHT capabilities checks to common
e01cf2afc Define eapol_sm_get_eap_proxy_imsi() only with CONFIG_EAP_PROXY=y
a8e25deeb FT: Merge similar error paths to use common steps
c6c41f6ea FT: Support addition of RIC elements into Reassociation Request frame
ecbdc1a1f Mark RSN msg 1/2 key data debug dump as key material
834c5d681 FILS: Fix PMK length for initial connection with FILS SHA384 AKM
e491389eb FILS: Fix ifdef for PTK derivation with SHA384-based AKM
62944f7d2 Add HMAC-SHA384 with internal crypto
aeecd4eae OpenSSL: Fix hmac_sha384_vector() implementation
5db32adc9 browser-wpadebug: Send HTTP response with HTTP/1.1 header
79329ae0a P2P: Verify local driver preferred frequencies for P2P use cases
3a7819f0a P2P: Add P2P_SET override_pref_op_chan to allow overriding preference
c06fca04f Add wpa_supplicant SET get_pref_freq_list_override
b4d56efb1 Use throughput estimate-based BSS selection with larger SNR difference
142041487 Drop GREAT_SNR definition from 30 to 25 dB
364c064a4 FT: Check key derivation results explicitly in AP operations
b5562a1a6 FILS: Remove CRC32 dependency from build
5cf0930f9 testS: Additional BSS TM error case coverage
885bbd4de WNM: Remove unused code from BSS TM Req generation
e7ddd86a9 WNM: Use a common error path in ieee802_11_send_wnmsleep_resp()
d6d5970e2 WNM: Fix WNM-Sleep Mode Request parsing for WNM-Sleep element
8492cc79c PeerKey: Remove dead code related to STSL negotiation state
e37c0aa5d OSU server: Remove invalid options from documentation
0d6056703 WMM: Fix estimated medium time calculation for some corner cases
ae26d3021 Fix "IEEE 802.11: Ignored Action frame" debug message
4ead4c7ec WMM: Remove obsolete TODO comments
577e794eb Sync android.config with wpa_supplicant defconfig changes
784710b7f Add bgscan options to wpa_supplicant defconfig
212a8f487 Fix wpa_supplicant defconfig copy-paste description
57c3a605c Add support to sched scan to report relatively better BSSs
20c846d9e nl80211: sched_scan relative RSSI parameters
37e9f511e mka: Send MKPDUs forever if mode is PSK
76aa31838 EAP: Call deinit_for_reauth() for Phase 2 EAP methods
02156b98b EAP-AKA: Don't use anonymous identity in phase2
9e2afe10e EAP-SIM: Don't use anonymous identity in phase2
ed9b1c16d EAP peer: Cache decrypted requests for EAP-SIM/AKA/AKA'
5f11880f6 SME: Remove null ie param from CTRL-EVENT-AUTH-REJECT
4d70b2a4e RRM: Fix a memory leak in beacon request handling
401243b73 RRM: Fix range request overriding
fb81c0a3d RRM: Merge similar error returns to a single one
13b30052d RRM: Fix Range Request max age parsing
bd6ec7f7c Fix MAC ACL query freeing on deinit
b4fd1f0ed Allow PNO scan also in connection completed state
4c6f450ca Add radio_work_is_connect() helper
85b6b6b6e Serialize scan/p2p-scan if already scheduled on the same interface
fcb303a57 P2P: Clear driver scan cache after BSS_FLUSH
0d6dc6830 FILS: Clean up HLP resize check
1d9d21f37 GAS: Add support to randomize transmitter address
8331c9b31 nl80211: Add support for mgmt_tx with random TA
14fa723a9 Sync with mac80211-next.git include/uapi/linux/nl80211.h
65ab7eb1f GAS: Fix OSU Providers List response with invalid configuration
f3e157057 VHT: Fill VHT capability with hardware capability
4bb9b674c Add a log message when GTK rekeying failed
41f140d38 Add hostapd options wpa_group_update_count and wpa_pairwise_update_count
e54691106 mka: Some bug fixes for MACsec in PSK mode
7faf403f9 mka: Fix an incorrect update of participant->to_use_sak
00e0f0b01 hs20-osu-client: Hide a trivial compiler warning
276e93654 hw_features: Clean center freq for falling back HT40 channels
f47f93617 P2P: Override P2P_PEER group_capab with 0 if no matching BSS entry found
bcf66493c Fix estimated throughput based skip-roam case
84bb12aa6 FILS: Fix send_assoc_resp() HLP extension to cover sta == NULL
275cc9428 FILS: Stop processing if fils_rmsk_to_pmk() fails
caab23f19 Set EAPOL-Key Key Length field to 0 for group message 1/2 in RSN
b0fb2be77 Do not send GNonce in EAPOL-Key group message 1/2
3bbc47050 Fix EAPOL-Key Install bit in Group Key 1/2 with FT and FILS auth
db5e53cb0 mesh: Fix struct hostapd_data initialization
9b170991a mesh: Fix mesh interface removal fix
945604a35 Update wpaspy.py to be python3 compatible
4d6e79f86 Use defines in hostapd_set_freq_params()
0217b8d87 eloop: Fix comments mismatch eloop_event/timeout_handler definitions
09a97eb27 Update the copyright notice years for QCA vendor definitions
841e9a8c7 QCA vendor command to set the trace levels for the specific QCA module
d77f33041 FILS: Fix AES-SIV AAD for (Re)Association Request frame decryption
7a6c3de23 ERP: Use macro for EMSKname length instead of hardcoded integer value
bb3ea71a2 ERP: Fix rIK derivation
124ddfa19 FILS: Parse and report received FILS HLP Containers from response
91d91abf6 FILS: DHCP relay for HLP requests
54b04d6f3 FILS: Move HLP request handling into a separate file
5a9d50493 ProxyARP: Use more robust DHCP option parsing
e64c13feb Move DHCP definitions into a common file
70407ee5c Add QCA vendor definitions for BSS transition status
53d171440 AP: Check ACL upon association request for 802.11ad
4cc61c386 GAS: Set temporary session timeout bigger than gas_comeback_delay
Test: Wifi Suite
Change-Id: Id597d7cba5d2b3875f2dbbeb9a10fd5e69a6a7c2
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e417a12..9abcab7 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -13,6 +13,7 @@
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/eapol_common.h"
+#include "common/dhcp.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -55,6 +56,8 @@
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
+ bss->wpa_group_update_count = 4;
+ bss->wpa_pairwise_update_count = 4;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
@@ -100,6 +103,9 @@
#ifdef CONFIG_FILS
dl_list_init(&bss->fils_realms);
+ bss->fils_hlp_wait_time = 30;
+ bss->dhcp_server_port = DHCP_SERVER_PORT;
+ bss->dhcp_relay_port = DHCP_SERVER_PORT;
#endif /* CONFIG_FILS */
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 075261c..fdd5a1a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -330,6 +330,8 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
@@ -607,11 +609,34 @@
u8 fils_cache_id[FILS_CACHE_ID_LEN];
int fils_cache_id_set;
struct dl_list fils_realms; /* list of struct fils_realm */
+ struct hostapd_ip_addr dhcp_server;
+ int dhcp_rapid_commit_proxy;
+ unsigned int fils_hlp_wait_time;
+ u16 dhcp_server_port;
+ u16 dhcp_relay_port;
#endif /* CONFIG_FILS */
int multicast_to_unicast;
};
+/**
+ * struct he_phy_capabilities_info - HE PHY capabilities
+ */
+struct he_phy_capabilities_info {
+ Boolean he_su_beamformer;
+ Boolean he_su_beamformee;
+ Boolean he_mu_beamformer;
+};
+
+/**
+ * struct he_operation - HE operation
+ */
+struct he_operation {
+ u8 he_bss_color;
+ u8 he_default_pe_duration;
+ u8 he_twt_required;
+ u8 he_rts_threshold;
+};
/**
* struct hostapd_config - Per-radio interface configuration
@@ -725,6 +750,12 @@
struct wpabuf *lci;
struct wpabuf *civic;
int stationary_ap;
+
+ int ieee80211ax;
+#ifdef CONFIG_IEEE80211AX
+ struct he_phy_capabilities_info he_phy_capab;
+ struct he_operation he_op;
+#endif /* CONFIG_IEEE80211AX */
};
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 3788a97..c6bbda3 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -392,6 +392,13 @@
2 + sizeof(struct ieee80211_vht_operation);
}
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ buflen += 4 + sizeof (struct ieee80211_he_capabilities) +
+ 4 + sizeof (struct ieee80211_he_operation);
+ }
+#endif
+
buflen += hostapd_mbo_ie_len(hapd);
resp = os_zalloc(buflen);
@@ -500,6 +507,13 @@
pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ pos = hostapd_eid_vendor_he_capab(hapd, pos);
+ pos = hostapd_eid_vendor_he_operation(hapd, pos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
@@ -1040,6 +1054,13 @@
}
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tail_len += 4 + sizeof (struct ieee80211_he_capabilities) +
+ 4 + sizeof (struct ieee80211_he_operation);
+ }
+#endif
+
tail_len += hostapd_mbo_ie_len(hapd);
tailpos = tail = os_malloc(tail_len);
@@ -1171,6 +1192,13 @@
tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
+#ifdef CONFIG_IEEE80211AX
+ if (hapd->iconf->ieee80211ax) {
+ tailpos = hostapd_eid_vendor_he_capab(hapd, tailpos);
+ tailpos = hostapd_eid_vendor_he_operation(hapd, tailpos);
+ }
+#endif /* CONFIG_IEEE80211AX */
+
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index f0212fb..b9a36d7 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -7,10 +7,9 @@
*/
#include "utils/includes.h"
-#include <netinet/ip.h>
-#include <netinet/udp.h>
#include "utils/common.h"
+#include "common/dhcp.h"
#include "l2_packet/l2_packet.h"
#include "hostapd.h"
#include "sta_info.h"
@@ -18,29 +17,6 @@
#include "x_snoop.h"
#include "dhcp_snoop.h"
-struct bootp_pkt {
- struct iphdr iph;
- struct udphdr udph;
- u8 op;
- u8 htype;
- u8 hlen;
- u8 hops;
- be32 xid;
- be16 secs;
- be16 flags;
- be32 client_ip;
- be32 your_ip;
- be32 server_ip;
- be32 relay_ip;
- u8 hw_addr[16];
- u8 serv_name[64];
- u8 boot_file[128];
- u8 exten[312];
-} STRUCT_PACKED;
-
-#define DHCPACK 5
-static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
-
static const char * ipaddr_str(u32 addr)
{
@@ -74,24 +50,26 @@
if (tot_len > (unsigned int) (len - ETH_HLEN))
return;
- if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+ if (WPA_GET_BE32(b->exten) != DHCP_MAGIC)
return;
/* Parse DHCP options */
end = (const u8 *) b + tot_len;
pos = &b->exten[4];
- while (pos < end && *pos != 0xff) {
+ while (pos < end && *pos != DHCP_OPT_END) {
const u8 *opt = pos++;
- if (*opt == 0) /* padding */
+ if (*opt == DHCP_OPT_PAD)
continue;
+ if (pos >= end || 1 + *pos > end - pos)
+ break;
pos += *pos + 1;
if (pos >= end)
break;
switch (*opt) {
- case 1: /* subnet mask */
+ case DHCP_OPT_SUBNET_MASK:
if (opt[1] == 4)
subnet_mask = WPA_GET_BE32(&opt[2]);
if (subnet_mask == 0)
@@ -101,7 +79,7 @@
prefixlen--;
}
break;
- case 53: /* message type */
+ case DHCP_OPT_MSG_TYPE:
if (opt[1])
msgtype = opt[2];
break;
diff --git a/src/ap/fils_hlp.c b/src/ap/fils_hlp.c
new file mode 100644
index 0000000..40d9be1
--- /dev/null
+++ b/src/ap/fils_hlp.c
@@ -0,0 +1,636 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/dhcp.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ieee802_11.h"
+#include "fils_hlp.h"
+
+
+static be16 ip_checksum(const void *buf, size_t len)
+{
+ u32 sum = 0;
+ const u16 *pos;
+
+ for (pos = buf; len >= 2; len -= 2)
+ sum += ntohs(*pos++);
+ if (len)
+ sum += ntohs(*pos << 8);
+
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += sum >> 16;
+ return htons(~sum);
+}
+
+
+static int fils_dhcp_request(struct hostapd_data *hapd, struct sta_info *sta,
+ struct dhcp_data *dhcpoffer, u8 *dhcpofferend)
+{
+ u8 *pos, *end;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ ssize_t res;
+ const u8 *server_id = NULL;
+
+ if (!sta->hlp_dhcp_discover) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCPDISCOVER available");
+ return -1;
+ }
+
+ /* Convert to DHCPREQUEST, remove rapid commit option, replace requested
+ * IP address option with yiaddr. */
+ pos = wpabuf_mhead(sta->hlp_dhcp_discover);
+ end = pos + wpabuf_len(sta->hlp_dhcp_discover);
+ dhcp = (struct dhcp_data *) pos;
+ pos = (u8 *) (dhcp + 1);
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ *pos = DHCPREQUEST;
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ case DHCP_OPT_REQUESTED_IP_ADDRESS:
+ case DHCP_OPT_SERVER_ID:
+ /* Remove option */
+ pos -= 2;
+ os_memmove(pos, pos + 2 + olen, end - pos - 2 - olen);
+ end -= 2 + olen;
+ olen = 0;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos >= end || *pos != DHCP_OPT_END) {
+ wpa_printf(MSG_DEBUG, "FILS: Could not update DHCPDISCOVER");
+ return -1;
+ }
+ sta->hlp_dhcp_discover->used = pos - (u8 *) dhcp;
+
+ /* Copy Server ID option from DHCPOFFER to DHCPREQUEST */
+ pos = (u8 *) (dhcpoffer + 1);
+ end = dhcpofferend;
+ pos += 4; /* skip magic */
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_SERVER_ID:
+ server_id = pos - 2;
+ break;
+ }
+ pos += olen;
+ }
+
+ if (wpabuf_resize(&sta->hlp_dhcp_discover,
+ 6 + 1 + (server_id ? 2 + server_id[1] : 0)))
+ return -1;
+ if (server_id)
+ wpabuf_put_data(sta->hlp_dhcp_discover, server_id,
+ 2 + server_id[1]);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_REQUESTED_IP_ADDRESS);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, 4);
+ wpabuf_put_data(sta->hlp_dhcp_discover, &dhcpoffer->your_ip, 4);
+ wpabuf_put_u8(sta->hlp_dhcp_discover, DHCP_OPT_END);
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, wpabuf_head(sta->hlp_dhcp_discover),
+ wpabuf_len(sta->hlp_dhcp_discover), 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG,
+ "FILS: Acting as DHCP rapid commit proxy for %s:%d",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 1;
+ return 0;
+}
+
+
+static void fils_dhcp_handler(int sd, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = sock_ctx;
+ struct sta_info *sta;
+ u8 buf[1500], *pos, *end, *end_opt = NULL;
+ struct dhcp_data *dhcp;
+ struct sockaddr_in addr;
+ socklen_t addr_len;
+ ssize_t res;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct wpabuf *resp;
+ const u8 *rpos;
+ size_t left, len;
+
+ addr_len = sizeof(addr);
+ res = recvfrom(sd, buf, sizeof(buf), 0,
+ (struct sockaddr *) &addr, &addr_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "FILS: DHCP read failed: %s",
+ strerror(errno));
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "FILS: DHCP response from server %s:%d (len=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), (int) res);
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP - DHCP server response", buf, res);
+ if ((size_t) res < sizeof(*dhcp))
+ return;
+ dhcp = (struct dhcp_data *) buf;
+ if (dhcp->op != 2)
+ return; /* Not a BOOTREPLY */
+ if (dhcp->relay_ip != hapd->conf->own_ip_addr.u.v4.s_addr) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP response to unknown relay address 0x%x",
+ dhcp->relay_ip);
+ return;
+ }
+ dhcp->relay_ip = 0;
+ pos = (u8 *) (dhcp + 1);
+ end = &buf[res];
+
+ if (end - pos < 4 || WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic in response");
+ return;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options in response",
+ pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+ if (pos < end && *pos == DHCP_OPT_END)
+ end_opt = pos;
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - DHCP message type %u (rapid_commit=%d hw_addr="
+ MACSTR ")",
+ msgtype, rapid_commit, MAC2STR(dhcp->hw_addr));
+
+ sta = ap_get_sta(hapd, dhcp->hw_addr);
+ if (!sta || !sta->fils_pending_assoc_req) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No pending HLP DHCP exchange with hw_addr"
+ MACSTR, MAC2STR(dhcp->hw_addr));
+ return;
+ }
+
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPOFFER &&
+ !rapid_commit) {
+ /* Use hostapd to take care of 4-message exchange and convert
+ * the final DHCPACK to rapid commit version. */
+ if (fils_dhcp_request(hapd, sta, dhcp, end) == 0)
+ return;
+ /* failed, so send the server response as-is */
+ } else if (msgtype != DHCPACK) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No DHCPACK available from the server and cannot do rapid commit proxying");
+ }
+
+ pos = buf;
+ resp = wpabuf_alloc(2 * ETH_ALEN + 6 + 2 +
+ sizeof(*iph) + sizeof(*udph) + (end - pos) + 2);
+ if (!resp)
+ return;
+ wpabuf_put_data(resp, sta->addr, ETH_ALEN);
+ wpabuf_put_data(resp, hapd->own_addr, ETH_ALEN);
+ wpabuf_put_data(resp, "\xaa\xaa\x03\x00\x00\x00", 6);
+ wpabuf_put_be16(resp, ETH_P_IP);
+ iph = wpabuf_put(resp, sizeof(*iph));
+ iph->version = 4;
+ iph->ihl = sizeof(*iph) / 4;
+ iph->tot_len = htons(sizeof(*iph) + sizeof(*udph) + (end - pos));
+ iph->ttl = 1;
+ iph->saddr = hapd->conf->dhcp_server.u.v4.s_addr;
+ iph->daddr = dhcp->client_ip;
+ iph->check = ip_checksum(iph, sizeof(*iph));
+ udph = wpabuf_put(resp, sizeof(*udph));
+ udph->uh_sport = htons(DHCP_SERVER_PORT);
+ udph->uh_dport = htons(DHCP_CLIENT_PORT);
+ udph->len = htons(sizeof(*udph) + (end - pos));
+ udph->check = htons(0x0000); /* TODO: calculate checksum */
+ if (hapd->conf->dhcp_rapid_commit_proxy && msgtype == DHCPACK &&
+ !rapid_commit && sta->fils_dhcp_rapid_commit_proxy && end_opt) {
+ /* Add rapid commit option */
+ wpabuf_put_data(resp, pos, end_opt - pos);
+ wpabuf_put_u8(resp, DHCP_OPT_RAPID_COMMIT);
+ wpabuf_put_u8(resp, 0);
+ wpabuf_put_data(resp, end_opt, end - end_opt);
+ } else {
+ wpabuf_put_data(resp, pos, end - pos);
+ }
+ if (wpabuf_resize(&sta->fils_hlp_resp, wpabuf_len(resp) +
+ 2 * wpabuf_len(resp) / 255 + 100)) {
+ wpabuf_free(resp);
+ return;
+ }
+
+ rpos = wpabuf_head(resp);
+ left = wpabuf_len(resp);
+
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXTENSION); /* Element ID */
+ if (left <= 254)
+ len = 1 + left;
+ else
+ len = 255;
+ wpabuf_put_u8(sta->fils_hlp_resp, len); /* Length */
+ /* Element ID Extension */
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_EXT_FILS_HLP_CONTAINER);
+ /* Destination MAC Address, Source MAC Address, HLP Packet.
+ * HLP Packet is in MSDU format (i.e., including the LLC/SNAP header
+ * when LPD is used). */
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len - 1);
+ rpos += len - 1;
+ left -= len - 1;
+ while (left) {
+ wpabuf_put_u8(sta->fils_hlp_resp, WLAN_EID_FRAGMENT);
+ len = left > 255 ? 255 : left;
+ wpabuf_put_u8(sta->fils_hlp_resp, len);
+ wpabuf_put_data(sta->fils_hlp_resp, rpos, len);
+ rpos += len;
+ left -= len;
+ }
+ wpabuf_free(resp);
+ fils_hlp_finish_assoc(hapd, sta);
+}
+
+
+static int fils_process_hlp_dhcp(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *msg, size_t len)
+{
+ const struct dhcp_data *dhcp;
+ struct wpabuf *dhcp_buf;
+ struct dhcp_data *dhcp_msg;
+ u8 msgtype = 0;
+ int rapid_commit = 0;
+ const u8 *pos = msg, *end;
+ struct sockaddr_in addr;
+ ssize_t res;
+
+ if (len < sizeof(*dhcp))
+ return 0;
+ dhcp = (const struct dhcp_data *) pos;
+ end = pos + len;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request DHCP: op=%u htype=%u hlen=%u hops=%u xid=0x%x",
+ dhcp->op, dhcp->htype, dhcp->hlen, dhcp->hops,
+ ntohl(dhcp->xid));
+ pos += sizeof(*dhcp);
+ if (dhcp->op != 1)
+ return 0; /* Not a BOOTREQUEST */
+
+ if (end - pos < 4)
+ return 0;
+ if (WPA_GET_BE32(pos) != DHCP_MAGIC) {
+ wpa_printf(MSG_DEBUG, "FILS: HLP - no DHCP magic");
+ return 0;
+ }
+ pos += 4;
+
+ wpa_hexdump(MSG_DEBUG, "FILS: HLP - DHCP options", pos, end - pos);
+ while (pos < end && *pos != DHCP_OPT_END) {
+ u8 opt, olen;
+
+ opt = *pos++;
+ if (opt == DHCP_OPT_PAD)
+ continue;
+ if (pos >= end)
+ break;
+ olen = *pos++;
+ if (olen > end - pos)
+ break;
+
+ switch (opt) {
+ case DHCP_OPT_MSG_TYPE:
+ if (olen > 0)
+ msgtype = pos[0];
+ break;
+ case DHCP_OPT_RAPID_COMMIT:
+ rapid_commit = 1;
+ break;
+ }
+ pos += olen;
+ }
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP - DHCP message type %u", msgtype);
+ if (msgtype != DHCPDISCOVER)
+ return 0;
+
+ if (hapd->conf->dhcp_server.af != AF_INET ||
+ hapd->conf->dhcp_server.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no DHCPv4 server configured - drop request");
+ return 0;
+ }
+
+ if (hapd->conf->own_ip_addr.af != AF_INET ||
+ hapd->conf->own_ip_addr.u.v4.s_addr == 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP - no IPv4 own_ip_addr configured - drop request");
+ return 0;
+ }
+
+ if (hapd->dhcp_sock < 0) {
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to open DHCP socket: %s",
+ strerror(errno));
+ return 0;
+ }
+
+ if (hapd->conf->dhcp_relay_port) {
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr =
+ hapd->conf->own_ip_addr.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_relay_port);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr))) {
+ wpa_printf(MSG_ERROR,
+ "FILS: Failed to bind DHCP socket: %s",
+ strerror(errno));
+ close(s);
+ return 0;
+ }
+ }
+ if (eloop_register_sock(s, EVENT_TYPE_READ,
+ fils_dhcp_handler, NULL, hapd)) {
+ close(s);
+ return 0;
+ }
+
+ hapd->dhcp_sock = s;
+ }
+
+ dhcp_buf = wpabuf_alloc(len);
+ if (!dhcp_buf)
+ return 0;
+ dhcp_msg = wpabuf_put(dhcp_buf, len);
+ os_memcpy(dhcp_msg, msg, len);
+ dhcp_msg->relay_ip = hapd->conf->own_ip_addr.u.v4.s_addr;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = hapd->conf->dhcp_server.u.v4.s_addr;
+ addr.sin_port = htons(hapd->conf->dhcp_server_port);
+ res = sendto(hapd->dhcp_sock, dhcp_msg, len, 0,
+ (const struct sockaddr *) &addr, sizeof(addr));
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "FILS: DHCP sendto failed: %s",
+ strerror(errno));
+ wpabuf_free(dhcp_buf);
+ /* Close the socket to try to recover from error */
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP relayed DHCP request to server %s:%d (rapid_commit=%d)",
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+ rapid_commit);
+ if (hapd->conf->dhcp_rapid_commit_proxy && rapid_commit) {
+ /* Store a copy of the DHCPDISCOVER for rapid commit proxying
+ * purposes if the server does not support the rapid commit
+ * option. */
+ wpa_printf(MSG_DEBUG,
+ "FILS: Store DHCPDISCOVER for rapid commit proxy");
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = dhcp_buf;
+ } else {
+ wpabuf_free(dhcp_buf);
+ }
+
+ return 1;
+}
+
+
+static int fils_process_hlp_udp(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ const struct udphdr *udph;
+ u16 sport, dport, ulen;
+
+ if (len < sizeof(*iph) + sizeof(*udph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ udph = (const struct udphdr *) (iph + 1);
+ sport = ntohs(udph->uh_sport);
+ dport = ntohs(udph->uh_dport);
+ ulen = ntohs(udph->uh_ulen);
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request UDP: sport=%u dport=%u ulen=%u sum=0x%x",
+ sport, dport, ulen, ntohs(udph->uh_sum));
+ /* TODO: Check UDP checksum */
+ if (ulen < sizeof(*udph) || ulen > len - sizeof(*iph))
+ return 0;
+
+ if (dport == DHCP_SERVER_PORT && sport == DHCP_CLIENT_PORT) {
+ return fils_process_hlp_dhcp(hapd, sta, (const u8 *) (udph + 1),
+ ulen - sizeof(*udph));
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_ip(struct hostapd_data *hapd,
+ struct sta_info *sta, const u8 *dst,
+ const u8 *pos, size_t len)
+{
+ const struct iphdr *iph;
+ u16 tot_len;
+
+ if (len < sizeof(*iph))
+ return 0;
+ iph = (const struct iphdr *) pos;
+ if (ip_checksum(iph, sizeof(*iph)) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4 packet had invalid header checksum - dropped");
+ return 0;
+ }
+ tot_len = ntohs(iph->tot_len);
+ if (tot_len > len)
+ return 0;
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP request IPv4: saddr=%08x daddr=%08x protocol=%u",
+ iph->saddr, iph->daddr, iph->protocol);
+ switch (iph->protocol) {
+ case 17:
+ return fils_process_hlp_udp(hapd, sta, dst, pos, len);
+ }
+
+ return 0;
+}
+
+
+static int fils_process_hlp_req(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *pos, size_t len)
+{
+ const u8 *pkt, *end;
+
+ wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
+ " src=" MACSTR " len=%u)",
+ MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
+ (unsigned int) len);
+ if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Ignore HLP request with unexpected source address"
+ MACSTR, MAC2STR(pos + ETH_ALEN));
+ return 0;
+ }
+
+ end = pos + len;
+ pkt = pos + 2 * ETH_ALEN;
+ if (end - pkt >= 6 &&
+ os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pkt += 6; /* Remove SNAP/LLC header */
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+
+ if (end - pkt < 2)
+ return 0;
+
+ switch (WPA_GET_BE16(pkt)) {
+ case ETH_P_IP:
+ return fils_process_hlp_ip(hapd, sta, pos, pkt + 2,
+ end - pkt - 2);
+ }
+
+ return 0;
+}
+
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left)
+{
+ const u8 *end = pos + left;
+ u8 *tmp, *tmp_pos;
+ int ret = 0;
+
+ /* Old DHCPDISCOVER is not needed anymore, if it was still pending */
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
+ sta->fils_dhcp_rapid_commit_proxy = 0;
+
+ /* Check if there are any FILS HLP Container elements */
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos)
+ return 0;
+ if (pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 1 + 2 * ETH_ALEN &&
+ pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ pos += 2 + pos[1];
+ }
+ if (end - pos < 2)
+ return 0; /* No FILS HLP Container elements */
+
+ tmp = os_malloc(end - pos);
+ if (!tmp)
+ return 0;
+
+ while (end - pos >= 2) {
+ if (2 + pos[1] > end - pos ||
+ pos[0] != WLAN_EID_EXTENSION ||
+ pos[1] < 1 + 2 * ETH_ALEN ||
+ pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
+ break;
+ tmp_pos = tmp;
+ os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
+ tmp_pos += pos[1] - 1;
+ pos += 2 + pos[1];
+
+ /* Add possible fragments */
+ while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
+ 2 + pos[1] <= end - pos) {
+ os_memcpy(tmp_pos, pos + 2, pos[1]);
+ tmp_pos += pos[1];
+ pos += 2 + pos[1];
+ }
+
+ if (fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp) > 0)
+ ret = 1;
+ }
+
+ os_free(tmp);
+
+ return ret;
+}
+
+
+void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+ if (hapd->dhcp_sock >= 0) {
+ eloop_unregister_read_sock(hapd->dhcp_sock);
+ close(hapd->dhcp_sock);
+ hapd->dhcp_sock = -1;
+ }
+}
diff --git a/src/ap/fils_hlp.h b/src/ap/fils_hlp.h
new file mode 100644
index 0000000..e14a6bf
--- /dev/null
+++ b/src/ap/fils_hlp.h
@@ -0,0 +1,27 @@
+/*
+ * FILS HLP request processing
+ * Copyright (c) 2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef FILS_HLP_H
+#define FILS_HLP_H
+
+int fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *pos, int left);
+
+#ifdef CONFIG_FILS
+
+void fils_hlp_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_FILS */
+
+static inline void fils_hlp_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_FILS */
+
+#endif /* FILS_HLP_H */
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 3878ce6..96cd703 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -50,9 +50,12 @@
sta->flags |= WLAN_STA_GAS;
/*
* The default inactivity is 300 seconds. We don't need
- * it to be that long.
+ * it to be that long. Use five second timeout and increase this
+ * with the comeback_delay for testing cases.
*/
- ap_sta_session_timeout(hapd, sta, 5);
+ ap_sta_session_timeout(hapd, sta,
+ hapd->conf->gas_comeback_delay / 1024 +
+ 5);
} else {
ap_sta_replenish_timeout(hapd, sta, 5);
}
@@ -688,7 +691,7 @@
/* OSU Method List */
count = wpabuf_put(buf, 1);
- for (i = 0; p->method_list[i] >= 0; i++)
+ for (i = 0; p->method_list && p->method_list[i] >= 0; i++)
wpabuf_put_u8(buf, p->method_list[i]);
*count = i;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 26ebbb6..cf8a8cb 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -45,6 +45,7 @@
#include "ndisc_snoop.h"
#include "neighbor_db.h"
#include "rrm.h"
+#include "fils_hlp.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -344,6 +345,7 @@
#endif /* CONFIG_MESH */
hostapd_clean_rrm(hapd);
+ fils_hlp_deinit(hapd);
}
@@ -2002,10 +2004,12 @@
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
- hapd->driver = hapd->iconf->driver;
+ if (conf)
+ hapd->driver = conf->driver;
hapd->ctrl_sock = -1;
dl_list_init(&hapd->ctrl_dst);
dl_list_init(&hapd->nr_db);
+ hapd->dhcp_sock = -1;
return hapd;
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index bc0ac23..5ab623d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -303,6 +303,8 @@
u8 range_req_token;
unsigned int lci_req_active:1;
unsigned int range_req_active:1;
+
+ int dhcp_sock; /* UDP socket used with the DHCP server */
};
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index d66ff4b..2d6cef1 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -329,6 +329,8 @@
res = ieee80211n_allowed_ht40_channel_pair(iface);
if (!res) {
iface->conf->secondary_channel = 0;
+ iface->conf->vht_oper_centr_freq_seg0_idx = 0;
+ iface->conf->vht_oper_centr_freq_seg1_idx = 0;
res = 1;
wpa_printf(MSG_INFO, "Fallback to 20 MHz");
}
@@ -621,41 +623,6 @@
#ifdef CONFIG_IEEE80211AC
-
-static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
-{
- u32 req_cap = conf & cap;
-
- /*
- * Make sure we support all requested capabilities.
- * NOTE: We assume that 'cap' represents a capability mask,
- * not a discrete value.
- */
- if ((hw & req_cap) != req_cap) {
- wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
- name);
- return 0;
- }
- return 1;
-}
-
-
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
- unsigned int shift,
- const char *name)
-{
- u32 hw_max = hw & mask;
- u32 conf_val = conf & mask;
-
- if (conf_val > hw_max) {
- wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
- name, conf_val >> shift, hw_max >> shift);
- return 0;
- }
- return 1;
-}
-
-
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
struct hostapd_hw_modes *mode = iface->current_mode;
@@ -683,45 +650,7 @@
}
}
-#define VHT_CAP_CHECK(cap) \
- do { \
- if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
- return 0; \
- } while (0)
-
-#define VHT_CAP_CHECK_MAX(cap) \
- do { \
- if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
- #cap)) \
- return 0; \
- } while (0)
-
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
- VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
- VHT_CAP_CHECK(VHT_CAP_RXLDPC);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
- VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
- VHT_CAP_CHECK(VHT_CAP_TXSTBC);
- VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
- VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
- VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
- VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
- VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
- VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
- VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
- VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
-
-#undef VHT_CAP_CHECK
-#undef VHT_CAP_CHECK_MAX
-
- return 1;
+ return ieee80211ac_cap_check(hw, conf);
}
#endif /* CONFIG_IEEE80211AC */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index cceeee0..e1a6712 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -45,6 +45,7 @@
#include "mbo_ap.h"
#include "rrm.h"
#include "taxonomy.h"
+#include "fils_hlp.h"
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
@@ -1301,6 +1302,89 @@
#endif /* CONFIG_FILS */
+static int
+ieee802_11_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *msg, size_t len, u32 *session_timeout,
+ u32 *acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
+{
+ int res;
+
+ os_memset(vlan_id, 0, sizeof(*vlan_id));
+ res = hostapd_allowed_address(hapd, addr, msg, len,
+ session_timeout, acct_interim_interval,
+ vlan_id, psk, identity, radius_cui);
+
+ if (res == HOSTAPD_ACL_REJECT) {
+ wpa_printf(MSG_INFO,
+ "Station " MACSTR " not allowed to authenticate",
+ MAC2STR(addr));
+ return HOSTAPD_ACL_REJECT;
+ }
+
+ if (res == HOSTAPD_ACL_PENDING) {
+ wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+ " waiting for an external authentication",
+ MAC2STR(addr));
+ /* Authentication code will re-send the authentication frame
+ * after it has received (and cached) information from the
+ * external source. */
+ return HOSTAPD_ACL_PENDING;
+ }
+
+ return res;
+}
+
+
+static int
+ieee802_11_set_radius_info(struct hostapd_data *hapd, struct sta_info *sta,
+ int res, u32 session_timeout,
+ u32 acct_interim_interval,
+ struct vlan_description *vlan_id,
+ struct hostapd_sta_wpa_psk_short **psk,
+ char **identity, char **radius_cui)
+{
+ if (vlan_id->notempty &&
+ !hostapd_vlan_valid(hapd->conf->vlan, vlan_id)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN %d%s received from RADIUS server",
+ vlan_id->untagged,
+ vlan_id->tagged[0] ? "+" : "");
+ return -1;
+ }
+ if (ap_sta_set_vlan(hapd, sta, vlan_id) < 0)
+ return -1;
+ if (sta->vlan_id)
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+
+ hostapd_free_psk_list(sta->psk);
+ if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+ sta->psk = *psk;
+ *psk = NULL;
+ } else {
+ sta->psk = NULL;
+ }
+
+ sta->identity = *identity;
+ *identity = NULL;
+ sta->radius_cui = *radius_cui;
+ *radius_cui = NULL;
+
+ if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+ sta->acct_interim_interval = acct_interim_interval;
+ if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ ap_sta_session_timeout(hapd, sta, session_timeout);
+ else
+ ap_sta_no_session_timeout(hapd, sta);
+
+ return 0;
+}
+
+
static void handle_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
@@ -1319,8 +1403,6 @@
char *radius_cui = NULL;
u16 seq_ctrl;
- os_memset(&vlan_id, 0, sizeof(vlan_id));
-
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
(unsigned long) len);
@@ -1464,26 +1546,15 @@
}
}
- res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
- &session_timeout,
- &acct_interim_interval, &vlan_id,
- &psk, &identity, &radius_cui);
-
+ res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len, &session_timeout,
+ &acct_interim_interval, &vlan_id, &psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
- wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to authenticate",
- MAC2STR(mgmt->sa));
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- if (res == HOSTAPD_ACL_PENDING) {
- wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
- " waiting for an external authentication",
- MAC2STR(mgmt->sa));
- /* Authentication code will re-send the authentication frame
- * after it has received (and cached) information from the
- * external source. */
+ if (res == HOSTAPD_ACL_PENDING)
return;
- }
sta = ap_get_sta(hapd, mgmt->sa);
if (sta) {
@@ -1536,47 +1607,17 @@
sta->last_seq_ctrl = seq_ctrl;
sta->last_subtype = WLAN_FC_STYPE_AUTH;
- if (vlan_id.notempty &&
- !hostapd_vlan_valid(hapd->conf->vlan, &vlan_id)) {
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO,
- "Invalid VLAN %d%s received from RADIUS server",
- vlan_id.untagged,
- vlan_id.tagged[0] ? "+" : "");
+ res = ieee802_11_set_radius_info(
+ hapd, sta, res, session_timeout, acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui);
+ if (res) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- if (ap_sta_set_vlan(hapd, sta, &vlan_id) < 0) {
- resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
- goto fail;
- }
- if (sta->vlan_id)
- hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
- HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
-
- hostapd_free_psk_list(sta->psk);
- if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
- sta->psk = psk;
- psk = NULL;
- } else {
- sta->psk = NULL;
- }
-
- sta->identity = identity;
- identity = NULL;
- sta->radius_cui = radius_cui;
- radius_cui = NULL;
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
- if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
- sta->acct_interim_interval = acct_interim_interval;
- if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- ap_sta_session_timeout(hapd, sta, session_timeout);
- else
- ap_sta_no_session_timeout(hapd, sta);
-
/*
* If the driver supports full AP client state, add a station to the
* driver before sending authentication reply to make sure the driver
@@ -2225,11 +2266,22 @@
const u8 *ies, size_t ies_len)
{
int send_len;
- u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ u8 *buf;
+ size_t buflen;
struct ieee80211_mgmt *reply;
u8 *p;
+ u16 res = WLAN_STATUS_SUCCESS;
- os_memset(buf, 0, sizeof(buf));
+ buflen = sizeof(struct ieee80211_mgmt) + 1024;
+#ifdef CONFIG_FILS
+ if (sta && sta->fils_hlp_resp)
+ buflen += wpabuf_len(sta->fils_hlp_resp);
+#endif /* CONFIG_FILS */
+ buf = os_zalloc(buflen);
+ if (!buf) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
reply = (struct ieee80211_mgmt *) buf;
reply->frame_control =
IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -2257,7 +2309,7 @@
/* IEEE 802.11r: Mobility Domain Information, Fast BSS
* Transition Information, RSN, [RIC Response] */
p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
- buf + sizeof(buf) - p,
+ buf + buflen - p,
sta->auth_alg, ies, ies_len);
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -2359,10 +2411,10 @@
p = hostapd_eid_p2p_manage(hapd, p);
#endif /* CONFIG_P2P_MANAGER */
- p = hostapd_eid_mbo(hapd, p, buf + sizeof(buf) - p);
+ p = hostapd_eid_mbo(hapd, p, buf + buflen - p);
if (hapd->conf->assocresp_elements &&
- (size_t) (buf + sizeof(buf) - p) >=
+ (size_t) (buf + buflen - p) >=
wpabuf_len(hapd->conf->assocresp_elements)) {
os_memcpy(p, wpabuf_head(hapd->conf->assocresp_elements),
wpabuf_len(hapd->conf->assocresp_elements));
@@ -2380,8 +2432,10 @@
struct ieee802_11_elems elems;
if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) ==
- ParseFailed || !elems.fils_session)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ ParseFailed || !elems.fils_session) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
/* FILS Session */
*p++ = WLAN_EID_EXTENSION; /* Element ID */
@@ -2391,96 +2445,70 @@
send_len += 2 + 1 + FILS_SESSION_LEN;
send_len = fils_encrypt_assoc(sta->wpa_sm, buf, send_len,
- sizeof(buf));
- if (send_len < 0)
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ buflen, sta->fils_hlp_resp);
+ if (send_len < 0) {
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto done;
+ }
}
#endif /* CONFIG_FILS */
if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0) {
wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
strerror(errno));
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ res = WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- return WLAN_STATUS_SUCCESS;
+done:
+ os_free(buf);
+ return res;
}
#ifdef CONFIG_FILS
-static void fils_process_hlp_req(struct hostapd_data *hapd,
- struct sta_info *sta,
- const u8 *pos, size_t len)
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta)
{
- const u8 *pkt, *end;
+ u16 reply_res;
- wpa_printf(MSG_DEBUG, "FILS: HLP request from " MACSTR " (dst=" MACSTR
- " src=" MACSTR " len=%u)",
- MAC2STR(sta->addr), MAC2STR(pos), MAC2STR(pos + ETH_ALEN),
- (unsigned int) len);
- if (os_memcmp(sta->addr, pos + ETH_ALEN, ETH_ALEN) != 0) {
- wpa_printf(MSG_DEBUG,
- "FILS: Ignore HLP request with unexpected source address"
- MACSTR, MAC2STR(pos + ETH_ALEN));
+ wpa_printf(MSG_DEBUG, "FILS: Finish association with " MACSTR,
+ MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ if (!sta->fils_pending_assoc_req)
return;
- }
+ reply_res = send_assoc_resp(hapd, sta, sta->addr, WLAN_STATUS_SUCCESS,
+ sta->fils_pending_assoc_is_reassoc,
+ sta->fils_pending_assoc_req,
+ sta->fils_pending_assoc_req_len);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ wpabuf_free(sta->hlp_dhcp_discover);
+ sta->hlp_dhcp_discover = NULL;
- end = pos + len;
- pkt = pos + 2 * ETH_ALEN;
- if (end - pkt >= 6 &&
- os_memcmp(pkt, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
- pkt += 6; /* Remove SNAP/LLC header */
- wpa_hexdump(MSG_MSGDUMP, "FILS: HLP request packet", pkt, end - pkt);
+ /*
+ * Remove the station in case tranmission of a success response fails
+ * (the STA was added associated to the driver) or if the station was
+ * previously added unassociated.
+ */
+ if (reply_res != WLAN_STATUS_SUCCESS || sta->added_unassoc) {
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ sta->added_unassoc = 0;
+ }
}
-static void fils_process_hlp(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *pos, int left)
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data)
{
- const u8 *end = pos + left;
- u8 *tmp, *tmp_pos;
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
- /* Check if there are any FILS HLP Container elements */
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos)
- return;
- if (pos[0] == WLAN_EID_EXTENSION &&
- pos[1] >= 1 + 2 * ETH_ALEN &&
- pos[2] == WLAN_EID_EXT_FILS_HLP_CONTAINER)
- break;
- pos += 2 + pos[1];
- }
- if (end - pos < 2)
- return; /* No FILS HLP Container elements */
-
- tmp = os_malloc(end - pos);
- if (!tmp)
- return;
-
- while (end - pos >= 2) {
- if (2 + pos[1] > end - pos ||
- pos[0] != WLAN_EID_EXTENSION ||
- pos[1] < 1 + 2 * ETH_ALEN ||
- pos[2] != WLAN_EID_EXT_FILS_HLP_CONTAINER)
- break;
- tmp_pos = tmp;
- os_memcpy(tmp_pos, pos + 3, pos[1] - 1);
- tmp_pos += pos[1] - 1;
- pos += 2 + pos[1];
-
- /* Add possible fragments */
- while (end - pos >= 2 && pos[0] == WLAN_EID_FRAGMENT &&
- 2 + pos[1] <= end - pos) {
- os_memcpy(tmp_pos, pos + 2, pos[1]);
- tmp_pos += pos[1];
- pos += 2 + pos[1];
- }
-
- fils_process_hlp_req(hapd, sta, tmp, tmp_pos - tmp);
- }
-
- os_free(tmp);
+ wpa_printf(MSG_DEBUG,
+ "FILS: HLP response timeout - continue with association response for "
+ MACSTR, MAC2STR(sta->addr));
+ fils_hlp_finish_assoc(hapd, sta);
}
#endif /* CONFIG_FILS */
@@ -2496,6 +2524,12 @@
int left, i;
struct sta_info *sta;
u8 *tmp = NULL;
+ struct hostapd_sta_wpa_psk_short *psk = NULL;
+ char *identity = NULL;
+ char *radius_cui = NULL;
+#ifdef CONFIG_FILS
+ int delay_assoc = 0;
+#endif /* CONFIG_FILS */
if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
sizeof(mgmt->u.assoc_req))) {
@@ -2571,6 +2605,21 @@
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode ==
HOSTAPD_MODE_IEEE80211AD) {
+ int acl_res;
+ u32 session_timeout, acct_interim_interval;
+ struct vlan_description vlan_id;
+
+ acl_res = ieee802_11_allowed_address(
+ hapd, mgmt->sa, (const u8 *) mgmt, len,
+ &session_timeout, &acct_interim_interval,
+ &vlan_id, &psk, &identity, &radius_cui);
+ if (acl_res == HOSTAPD_ACL_REJECT) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (acl_res == HOSTAPD_ACL_PENDING)
+ return;
+
/* DMG/IEEE 802.11ad does not use authentication.
* Allocate sta entry upon association. */
sta = ap_sta_add(hapd, mgmt->sa);
@@ -2583,6 +2632,15 @@
goto fail;
}
+ acl_res = ieee802_11_set_radius_info(
+ hapd, sta, acl_res, session_timeout,
+ acct_interim_interval, &vlan_id, &psk,
+ &identity, &radius_cui);
+ if (acl_res) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -2760,11 +2818,17 @@
#ifdef CONFIG_FILS
if (sta->auth_alg == WLAN_AUTH_FILS_SK ||
sta->auth_alg == WLAN_AUTH_FILS_SK_PFS ||
- sta->auth_alg == WLAN_AUTH_FILS_PK)
- fils_process_hlp(hapd, sta, pos, left);
+ sta->auth_alg == WLAN_AUTH_FILS_PK) {
+ if (fils_process_hlp(hapd, sta, pos, left) > 0)
+ delay_assoc = 1;
+ }
#endif /* CONFIG_FILS */
fail:
+ os_free(identity);
+ os_free(radius_cui);
+ hostapd_free_psk_list(psk);
+
/*
* In case of a successful response, add the station to the driver.
* Otherwise, the kernel may ignore Data frames before we process the
@@ -2786,6 +2850,29 @@
if (resp == WLAN_STATUS_SUCCESS && sta && add_associated_sta(hapd, sta))
resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+#ifdef CONFIG_FILS
+ if (sta) {
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ os_free(sta->fils_pending_assoc_req);
+ sta->fils_pending_assoc_req = NULL;
+ sta->fils_pending_assoc_req_len = 0;
+ wpabuf_free(sta->fils_hlp_resp);
+ sta->fils_hlp_resp = NULL;
+ }
+ if (sta && delay_assoc && resp == WLAN_STATUS_SUCCESS) {
+ sta->fils_pending_assoc_req = tmp;
+ sta->fils_pending_assoc_req_len = left;
+ sta->fils_pending_assoc_is_reassoc = reassoc;
+ wpa_printf(MSG_DEBUG,
+ "FILS: Waiting for HLP processing before sending (Re)Association Response frame to "
+ MACSTR, MAC2STR(sta->addr));
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+ eloop_register_timeout(0, hapd->conf->fils_hlp_wait_time * 1024,
+ fils_hlp_timeout, hapd, sta);
+ return;
+ }
+#endif /* CONFIG_FILS */
+
reply_res = send_assoc_resp(hapd, sta, mgmt->sa, resp, reassoc, pos,
left);
os_free(tmp);
@@ -2975,7 +3062,7 @@
(sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
"frame (category=%u) from unassociated STA " MACSTR,
- MAC2STR(mgmt->sa), mgmt->u.action.category);
+ mgmt->u.action.category, MAC2STR(mgmt->sa));
return 0;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 46c92b7..ce3abcb 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -55,6 +55,8 @@
u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_wb_chsw_wrapper(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_txpower_envelope(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_he_operation(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
@@ -140,5 +142,7 @@
struct sta_info *sta, int success,
struct wpabuf *erp_resp,
const u8 *msk, size_t msk_len);
+void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
+void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index b890537..1e0358c 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -665,9 +665,11 @@
#ifndef CONFIG_NO_RADIUS
hostapd_acl_cache_free(hapd->acl_cache);
+ hapd->acl_cache = NULL;
#endif /* CONFIG_NO_RADIUS */
query = hapd->acl_queries;
+ hapd->acl_queries = NULL;
while (query) {
prev = query;
query = query->next;
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
new file mode 100644
index 0000000..7d6a84f
--- /dev/null
+++ b/src/ap/ieee802_11_he.c
@@ -0,0 +1,101 @@
+/*
+ * hostapd / IEEE 802.11ax HE
+ * Copyright (c) 2016-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/qca-vendor.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+#include "dfs.h"
+
+u8 * hostapd_eid_vendor_he_capab(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_capabilities *cap;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ /* For now, use a vendor specific element since the P802.11ax draft is
+ * still subject to changes and the contents of this element may change.
+ * This can be replaced with the actual element once P802.11ax is
+ * finalized. */
+ /* Vendor HE Capabilities element */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 /* The Vendor OUI, subtype */ +
+ sizeof(struct ieee80211_he_capabilities);
+
+ WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_CAPAB);
+ pos += 4;
+ cap = (struct ieee80211_he_capabilities *) pos;
+ os_memset(cap, 0, sizeof(*cap));
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMER_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_su_beamformee)
+ cap->he_phy_capab_info[HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX] |=
+ HE_PHYCAP_SU_BEAMFORMEE_CAPAB;
+
+ if (hapd->iface->conf->he_phy_capab.he_mu_beamformer)
+ cap->he_phy_capab_info[HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX] |=
+ HE_PHYCAP_MU_BEAMFORMER_CAPAB;
+
+ pos += sizeof(*cap);
+
+ return pos;
+}
+
+
+u8 * hostapd_eid_vendor_he_operation(struct hostapd_data *hapd, u8 *eid)
+{
+ struct ieee80211_he_operation *oper;
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ /* For now, use a vendor specific element since the P802.11ax draft is
+ * still subject to changes and the contents of this element may change.
+ * This can be replaced with the actual element once P802.11ax is
+ * finalized. */
+ /* Vendor HE Operation element */
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 4 /* The Vendor OUI, subtype */ +
+ sizeof(struct ieee80211_he_operation);
+
+ WPA_PUT_BE32(pos, (OUI_QCA << 8) | QCA_VENDOR_ELEM_HE_OPER);
+ pos += 4;
+ oper = (struct ieee80211_he_operation *) pos;
+ os_memset(oper, 0, sizeof(*oper));
+
+ if (hapd->iface->conf->he_op.he_bss_color)
+ oper->he_oper_params |= hapd->iface->conf->he_op.he_bss_color;
+
+ if (hapd->iface->conf->he_op.he_default_pe_duration)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_default_pe_duration <<
+ HE_OPERATION_DFLT_PE_DURATION_OFFSET);
+
+ if (hapd->iface->conf->he_op.he_twt_required)
+ oper->he_oper_params |= HE_OPERATION_TWT_REQUIRED;
+
+ if (hapd->iface->conf->he_op.he_rts_threshold)
+ oper->he_oper_params |=
+ (hapd->iface->conf->he_op.he_rts_threshold <<
+ HE_OPERATION_RTS_THRESHOLD_OFFSET);
+
+ pos += sizeof(*oper);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 5eb1060..146e447 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -340,8 +340,8 @@
* that did not specify a valid WMM IE in the (Re)Association Request
* frame.
*/
- if (!ht_capab ||
- !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
+ if (!ht_capab || !(sta->flags & WLAN_STA_WMM) ||
+ !hapd->iconf->ieee80211n || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index f30f63b..8d06620 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -334,7 +334,7 @@
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
- hapd->conf->disable_11ac ||
+ !hapd->iconf->ieee80211ac || hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
index efc1d7e..93e775b 100644
--- a/src/ap/peerkey_auth.c
+++ b/src/ap/peerkey_auth.c
@@ -19,17 +19,6 @@
#ifdef CONFIG_PEERKEY
-static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
-{
-#if 0
- struct wpa_authenticator *wpa_auth = eloop_ctx;
- struct wpa_stsl_negotiation *neg = timeout_ctx;
-#endif
-
- /* TODO: ? */
-}
-
-
struct wpa_stsl_search {
const u8 *addr;
struct wpa_state_machine *sm;
@@ -110,7 +99,6 @@
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
@@ -285,7 +273,6 @@
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
- /* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
@@ -365,32 +352,4 @@
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
}
-
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg)
-{
- struct wpa_stsl_negotiation *pos, *prev;
-
- if (wpa_auth == NULL)
- return -1;
- pos = wpa_auth->stsl_negotiations;
- prev = NULL;
- while (pos) {
- if (pos == neg) {
- if (prev)
- prev->next = pos->next;
- else
- wpa_auth->stsl_negotiations = pos->next;
-
- eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
- os_free(pos);
- return 0;
- }
- prev = pos;
- pos = pos->next;
- }
-
- return -1;
-}
-
#endif /* CONFIG_PEERKEY */
diff --git a/src/ap/rrm.c b/src/ap/rrm.c
index 28e8cc9..56ed29c 100644
--- a/src/ap/rrm.c
+++ b/src/ap/rrm.c
@@ -147,7 +147,7 @@
/* Subelements are arranged as IEs */
subelem = get_ie(buf + 4, len - 4, LCI_REQ_SUBELEM_MAX_AGE);
if (subelem && subelem[1] == 2)
- return *(u16 *) (subelem + 2);
+ return WPA_GET_LE16(subelem + 2);
return 0;
}
@@ -370,13 +370,7 @@
struct sta_info *sta = ap_get_sta(hapd, addr);
int ret;
- if (!sta) {
- wpa_printf(MSG_INFO,
- "Request LCI: Destination address is not in station list");
- return -1;
- }
-
- if (!(sta->flags & WLAN_STA_AUTHORIZED)) {
+ if (!sta || !(sta->flags & WLAN_STA_AUTHORIZED)) {
wpa_printf(MSG_INFO,
"Request LCI: Destination address is not connected");
return -1;
@@ -479,9 +473,8 @@
wpa_printf(MSG_DEBUG,
"Request range: Range request is already in process; overriding");
hapd->range_req_active = 0;
- eloop_register_timeout(HOSTAPD_RRM_REQUEST_TIMEOUT, 0,
- hostapd_range_rep_timeout_handler, hapd,
- NULL);
+ eloop_cancel_timeout(hostapd_range_rep_timeout_handler, hapd,
+ NULL);
}
/* Action + measurement type + token + reps + EID + len = 7 */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index b87ddea..af8c754 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -339,6 +339,13 @@
mbo_ap_sta_free(sta);
os_free(sta->supp_op_classes);
+#ifdef CONFIG_FILS
+ os_free(sta->fils_pending_assoc_req);
+ wpabuf_free(sta->fils_hlp_resp);
+ wpabuf_free(sta->hlp_dhcp_discover);
+ eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+#endif /* CONFIG_FILS */
+
os_free(sta);
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 0b44f7b..6f55403 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -225,6 +225,12 @@
#ifdef CONFIG_FILS
u8 fils_snonce[FILS_NONCE_LEN];
u8 fils_session[FILS_SESSION_LEN];
+ u8 *fils_pending_assoc_req;
+ size_t fils_pending_assoc_req_len;
+ unsigned int fils_pending_assoc_is_reassoc:1;
+ unsigned int fils_dhcp_rapid_commit_proxy:1;
+ struct wpabuf *fils_hlp_resp;
+ struct wpabuf *hlp_dhcp_discover;
#endif /* CONFIG_FILS */
};
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index 314e244..8054c5d 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -21,11 +21,6 @@
#include "wmm.h"
-/* TODO: maintain separate sequence and fragment numbers for each AC
- * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WMM stations are receiving a certain group */
-
-
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
u8 ret;
@@ -157,8 +152,9 @@
int wmm_process_tspec(struct wmm_tspec_element *tspec)
{
- int medium_time, pps, duration;
- int up, psb, dir, tid;
+ u64 medium_time;
+ unsigned int pps, duration;
+ unsigned int up, psb, dir, tid;
u16 val, surplus;
up = (tspec->ts_info[1] >> 3) & 0x07;
@@ -206,8 +202,9 @@
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
- medium_time = surplus * pps * duration / 0x2000;
- wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+ medium_time = (u64) surplus * pps * duration / 0x2000;
+ wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %lu",
+ (unsigned long) medium_time);
/*
* TODO: store list of granted (and still active) TSPECs and check
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 41d50ce..7c4fde0 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -95,8 +95,8 @@
if (mgmt == NULL) {
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
"WNM-Sleep Response action frame");
- os_free(wnmtfs_ie);
- return -1;
+ res = -1;
+ goto fail;
}
os_memcpy(mgmt->da, addr, ETH_ALEN);
os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
@@ -118,11 +118,8 @@
(int) gtk_elem_len);
#ifdef CONFIG_IEEE80211W
res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
- if (res < 0) {
- os_free(wnmtfs_ie);
- os_free(mgmt);
- return -1;
- }
+ if (res < 0)
+ goto fail;
igtk_elem_len = res;
pos += igtk_elem_len;
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
@@ -184,6 +181,7 @@
#undef MAX_GTK_SUBELEM_LEN
#undef MAX_IGTK_SUBELEM_LEN
+fail:
os_free(wnmtfs_ie);
os_free(mgmt);
return res;
@@ -207,7 +205,8 @@
u8 ie_len = pos[1];
if (pos + 2 + ie_len > frm + len)
break;
- if (*pos == WLAN_EID_WNMSLEEP)
+ if (*pos == WLAN_EID_WNMSLEEP &&
+ ie_len >= (int) sizeof(*wnmsleep_ie) - 2)
wnmsleep_ie = (struct wnm_sleep_element *) pos;
else if (*pos == WLAN_EID_TFS_REQ) {
if (!tfsreq_ie_start)
@@ -251,20 +250,14 @@
static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
const u8 *addr,
- u8 dialog_token,
- const char *url)
+ u8 dialog_token)
{
struct ieee80211_mgmt *mgmt;
- size_t url_len, len;
+ size_t len;
u8 *pos;
int res;
- if (url)
- url_len = os_strlen(url);
- else
- url_len = 0;
-
- mgmt = os_zalloc(sizeof(*mgmt) + (url_len ? 1 + url_len : 0));
+ mgmt = os_zalloc(sizeof(*mgmt));
if (mgmt == NULL)
return -1;
os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -279,11 +272,6 @@
mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
mgmt->u.action.u.bss_tm_req.validity_interval = 1;
pos = mgmt->u.action.u.bss_tm_req.variable;
- if (url) {
- *pos++ += url_len;
- os_memcpy(pos, url, url_len);
- pos += url_len;
- }
wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
@@ -326,7 +314,7 @@
wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
pos, end - pos);
- ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token, NULL);
+ ieee802_11_send_bss_trans_mgmt_request(hapd, addr, dialog_token);
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 69e3a5d..7b26c04 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -60,8 +60,6 @@
struct wpa_group *group);
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
-static const u32 dot11RSNAConfigGroupUpdateCount = 4;
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
static const u32 eapol_key_timeout_first = 100; /* ms */
static const u32 eapol_key_timeout_subseq = 1000; /* ms */
static const u32 eapol_key_timeout_first_group = 500; /* ms */
@@ -515,11 +513,6 @@
eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
-#ifdef CONFIG_PEERKEY
- while (wpa_auth->stsl_negotiations)
- wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
-#endif /* CONFIG_PEERKEY */
-
pmksa_cache_auth_deinit(wpa_auth->pmksa);
#ifdef CONFIG_IEEE80211R_AP
@@ -615,6 +608,7 @@
"start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
return 0;
}
#endif /* CONFIG_IEEE80211R_AP */
@@ -625,6 +619,7 @@
"FILS authentication already completed - do not start 4-way handshake");
/* Go to PTKINITDONE state to allow GTK rekeying */
sm->wpa_ptk_state = WPA_PTK_PTKINITDONE;
+ sm->Pair = TRUE;
return 0;
}
#endif /* CONFIG_FILS */
@@ -862,7 +857,8 @@
pmk_len = sm->pmk_len;
}
- wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
+ if (wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
== 0) {
@@ -1482,9 +1478,11 @@
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
- if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+ if ((key_info & WPA_KEY_INFO_SMK_MESSAGE) ||
+ (sm->wpa == WPA_VERSION_WPA2 && !pairwise))
WPA_PUT_BE16(key->key_length, 0);
+ else
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
/* FIX: STSL: what to use as key_replay_counter? */
for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
@@ -1619,7 +1617,7 @@
{
int timeout_ms;
int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
- int ctr;
+ u32 ctr;
if (sm == NULL)
return;
@@ -1636,7 +1634,7 @@
if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
sm->pending_1_of_4_timeout = 1;
wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
- "counter %d)", timeout_ms, ctr);
+ "counter %u)", timeout_ms, ctr);
eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
wpa_send_eapol_timeout, wpa_auth, sm);
}
@@ -1927,7 +1925,7 @@
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
unsigned int pmk_len;
- if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt))
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
@@ -1998,7 +1996,7 @@
sm->alt_snonce_valid = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2230,10 +2228,10 @@
* field to the FILS Session element (both inclusive).
*/
aad[4] = (const u8 *) &mgmt->u.assoc_req.capab_info;
- aad_len[4] = crypt - aad[0];
+ aad_len[4] = crypt - aad[4];
if (aes_siv_decrypt(sm->PTK.kek, sm->PTK.kek_len, crypt, end - crypt,
- 1, aad, aad_len, pos + (crypt - ie_start)) < 0) {
+ 5, aad, aad_len, pos + (crypt - ie_start)) < 0) {
wpa_printf(MSG_DEBUG,
"FILS: Invalid AES-SIV data in the frame");
return -1;
@@ -2274,7 +2272,8 @@
int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
- size_t current_len, size_t max_len)
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp)
{
u8 *end = buf + max_len;
u8 *pos = buf + current_len;
@@ -2334,7 +2333,9 @@
wpabuf_put_u8(plain, WLAN_EID_EXT_FILS_KEY_CONFIRM);
wpabuf_put_data(plain, sm->fils_key_auth_ap, sm->fils_key_auth_len);
- /* TODO: FILS HLP Container */
+ /* FILS HLP Container */
+ if (hlp)
+ wpabuf_put_buf(plain, hlp);
/* TODO: FILS IP Address Assignment */
@@ -2464,7 +2465,8 @@
pmk_len = sm->pmk_len;
}
- wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
+ if (wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK) < 0)
+ break;
if (mic_len &&
wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
@@ -2686,7 +2688,7 @@
sm->TimeoutEvt = FALSE;
sm->TimeoutCtr++;
- if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+ if (sm->TimeoutCtr > sm->wpa_auth->conf.wpa_pairwise_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -2981,11 +2983,12 @@
sm->EAPOLKeyPairwise)
SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKSTART: Retry limit %d reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKSTART: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKSTART);
@@ -3009,12 +3012,12 @@
sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
- (int) dot11RSNAConfigPairwiseUpdateCount) {
+ sm->wpa_auth->conf.wpa_pairwise_update_count) {
wpa_auth->dot11RSNA4WayHandshakeFailures++;
- wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
- "PTKINITNEGOTIATING: Retry limit %d "
- "reached",
- dot11RSNAConfigPairwiseUpdateCount);
+ wpa_auth_vlogger(
+ sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+ "PTKINITNEGOTIATING: Retry limit %u reached",
+ sm->wpa_auth->conf.wpa_pairwise_update_count);
SM_ENTER(WPA_PTK, DISCONNECT);
} else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
@@ -3049,7 +3052,7 @@
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
sm->GTimeoutCtr++;
- if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+ if (sm->GTimeoutCtr > sm->wpa_auth->conf.wpa_group_update_count) {
/* No point in sending the EAPOL-Key - we will disconnect
* immediately following this. */
return;
@@ -3099,7 +3102,7 @@
(wpa_mic_len(sm->wpa_key_mgmt) ? WPA_KEY_INFO_MIC : 0) |
WPA_KEY_INFO_ACK |
(!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
- rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+ rsc, NULL, kde, kde_len, gsm->GN, 1);
os_free(kde_buf);
}
@@ -3128,6 +3131,10 @@
sm->group->GKeyDoneStations--;
sm->GUpdateStationKeys = FALSE;
sm->Disconnect = TRUE;
+ wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ "group key handshake failed (%s) after %u tries",
+ sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN",
+ sm->wpa_auth->conf.wpa_group_update_count);
}
@@ -3147,7 +3154,7 @@
!sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
else if (sm->GTimeoutCtr >
- (int) dot11RSNAConfigGroupUpdateCount)
+ sm->wpa_auth->conf.wpa_group_update_count)
SM_ENTER(WPA_PTK_GROUP, KEYERROR);
else if (sm->TimeoutEvt)
SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
@@ -3607,8 +3614,8 @@
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
RSN_VERSION,
!!wpa_auth->conf.wpa_strict_rekey,
- dot11RSNAConfigGroupUpdateCount,
- dot11RSNAConfigPairwiseUpdateCount,
+ wpa_auth->conf.wpa_group_update_count,
+ wpa_auth->conf.wpa_pairwise_update_count,
wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
@@ -3768,7 +3775,7 @@
sm->wpa_auth->conf.disable_pmksa_caching)
return -1;
- if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ if (wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) {
if (pmk_len > PMK_LEN_SUITE_B_192)
pmk_len = PMK_LEN_SUITE_B_192;
} else if (pmk_len > PMK_LEN) {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a44b030..0920a16 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -144,6 +144,8 @@
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
+ u32 wpa_group_update_count;
+ u32 wpa_pairwise_update_count;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
@@ -247,7 +249,7 @@
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
WPA_INVALID_MDIE, WPA_INVALID_PROTO
};
-
+
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
@@ -361,7 +363,8 @@
const struct ieee80211_mgmt *mgmt, size_t frame_len,
u8 *pos, size_t left);
int fils_encrypt_assoc(struct wpa_state_machine *sm, u8 *buf,
- size_t current_len, size_t max_len);
+ size_t current_len, size_t max_len,
+ const struct wpabuf *hlp);
int fils_set_tk(struct wpa_state_machine *sm);
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 1fe3c2b..c267a17 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -392,16 +392,19 @@
return -1;
}
- wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
- r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+ if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+ r0kh, r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
if (!psk_local || !wpa_key_mgmt_ft_psk(sm->wpa_key_mgmt))
wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
sm->pairwise);
- wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, sm->pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, sm->pmk_r1_name) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
@@ -834,12 +837,12 @@
if (pmk == NULL)
break;
- wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
- r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
- wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
- pmk_r1, pmk_r1_name);
-
- if (os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
+ if (wpa_derive_pmk_r0(pmk, PMK_LEN, ssid, ssid_len, mdid, r0kh,
+ r0kh_len, sm->addr,
+ pmk_r0, pmk_r0_name) < 0 ||
+ wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+ pmk_r1, pmk_r1_name) < 0 ||
+ os_memcmp_const(pmk_r1_name, req_pmk_r1_name,
WPA_PMK_NAME_LEN) != 0)
continue;
@@ -958,9 +961,10 @@
wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
parse.rsn_pmkid, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1_name(parse.rsn_pmkid,
- sm->wpa_auth->conf.r1_key_holder, sm->addr,
- pmk_r1_name);
+ if (wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+ sm->wpa_auth->conf.r1_key_holder, sm->addr,
+ pmk_r1_name) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
pmk_r1_name, WPA_PMK_NAME_LEN);
@@ -1007,41 +1011,35 @@
buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
2 + FT_R1KH_ID_LEN + 200;
*resp_ies = os_zalloc(buflen);
- if (*resp_ies == NULL) {
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (*resp_ies == NULL)
+ goto fail;
pos = *resp_ies;
end = *resp_ies + buflen;
ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
ret = wpa_write_mdie(conf, pos, end - pos);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
- if (ret < 0) {
- os_free(*resp_ies);
- *resp_ies = NULL;
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
+ if (ret < 0)
+ goto fail;
pos += ret;
*resp_ies_len = pos - *resp_ies;
return WLAN_STATUS_SUCCESS;
+fail:
+ os_free(*resp_ies);
+ *resp_ies = NULL;
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
@@ -1483,8 +1481,11 @@
return -1;
}
- wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
- r.pmk_r1, r.pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+ r.pmk_r1, r.pmk_r1_name) < 0) {
+ os_memset(pmk_r0, 0, PMK_LEN);
+ return -1;
+ }
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
WPA_PMK_NAME_LEN);
@@ -1536,12 +1537,10 @@
{
struct ft_r0kh_r1kh_resp_frame *frame = ctx;
- if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0)
- return 0;
- if (os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
- FT_R0KH_R1KH_PULL_NONCE_LEN) != 0)
- return 0;
- if (sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
+ if (os_memcmp(frame->s1kh_id, sm->addr, ETH_ALEN) != 0 ||
+ os_memcmp(frame->nonce, sm->ft_pending_pull_nonce,
+ FT_R0KH_R1KH_PULL_NONCE_LEN) != 0 ||
+ sm->ft_pending_cb == NULL || sm->ft_pending_req_ies == NULL)
return 0;
wpa_printf(MSG_DEBUG, "FT: Response to a pending pull request for "
@@ -1825,10 +1824,10 @@
}
-static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
- struct wpa_ft_pmk_r0_sa *pmk_r0,
- struct ft_remote_r1kh *r1kh,
- const u8 *s1kh_id, int pairwise)
+static int wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+ struct wpa_ft_pmk_r0_sa *pmk_r0,
+ struct ft_remote_r1kh *r1kh,
+ const u8 *s1kh_id, int pairwise)
{
struct ft_r0kh_r1kh_push_frame frame, f;
struct os_time now;
@@ -1846,8 +1845,9 @@
os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
- wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
- s1kh_id, f.pmk_r1, f.pmk_r1_name);
+ if (wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+ s1kh_id, f.pmk_r1, f.pmk_r1_name) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
@@ -1863,9 +1863,10 @@
if (aes_wrap(r1kh->key, sizeof(r1kh->key),
(FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
plain, crypt) < 0)
- return;
+ return -1;
wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+ return 0;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 22518a1..394f77a 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -41,6 +41,8 @@
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+ wconf->wpa_group_update_count = conf->wpa_group_update_count;
+ wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 065a624..90318d8 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -14,13 +14,6 @@
struct wpa_group;
-struct wpa_stsl_negotiation {
- struct wpa_stsl_negotiation *next;
- u8 initiator[ETH_ALEN];
- u8 peer[ETH_ALEN];
-};
-
-
struct wpa_state_machine {
struct wpa_authenticator *wpa_auth;
struct wpa_group *group;
@@ -48,8 +41,8 @@
Boolean AuthenticationRequest;
Boolean ReAuthenticationRequest;
Boolean Disconnect;
- int TimeoutCtr;
- int GTimeoutCtr;
+ u32 TimeoutCtr;
+ u32 GTimeoutCtr;
Boolean TimeoutEvt;
Boolean EAPOLKeyReceived;
Boolean EAPOLKeyPairwise;
@@ -200,8 +193,6 @@
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
unsigned int dot11RSNA4WayHandshakeFailures;
- struct wpa_stsl_negotiation *stsl_negotiations;
-
struct wpa_auth_config conf;
const struct wpa_auth_callbacks *cb;
void *cb_ctx;
@@ -239,8 +230,6 @@
void *cb_ctx);
#ifdef CONFIG_PEERKEY
-int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
- struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *key_data, size_t key_data_len);