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);
diff --git a/src/common/dhcp.h b/src/common/dhcp.h
new file mode 100644
index 0000000..f2ef61e
--- /dev/null
+++ b/src/common/dhcp.h
@@ -0,0 +1,257 @@
+/*
+ * DHCP definitions
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#define DHCP_SERVER_PORT 67
+#define DHCP_CLIENT_PORT 68
+
+struct dhcp_data {
+ 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];
+} STRUCT_PACKED;
+
+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 DHCP_MAGIC 0x63825363
+
+/*
+ * IANA DHCP/BOOTP registry
+ * http://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
+*/
+enum dhcp_options {
+ DHCP_OPT_PAD = 0,
+ DHCP_OPT_SUBNET_MASK = 1,
+ DHCP_OPT_TIME_OFFSET = 2,
+ DHCP_OPT_ROUTER = 3,
+ DHCP_OPT_TIME_SERVER = 4,
+ DHCP_OPT_NAME_SERVER = 5,
+ DHCP_OPT_DOMAIN_NAME_SERVER = 6,
+ DHCP_OPT_LOG_SERVER = 7,
+ DHCP_OPT_QUOTES_SERVER = 8,
+ DHCP_OPT_LPR_SERVER = 9,
+ DHCP_OPT_IMPRESS_SERVER = 10,
+ DHCP_OPT_RLP_SERVER = 11,
+ DHCP_OPT_HOSTNAME = 12,
+ DHCP_OPT_BOOT_FILE_SIZE = 13,
+ DHCP_OPT_MERIT_DUMP_FILE = 14,
+ DHCP_OPT_DOMAIN_NAME = 15,
+ DHCP_OPT_SWAP_SERVER = 16,
+ DHCP_OPT_ROOT_PATH = 17,
+ DHCP_OPT_EXTENSION_PATH = 18,
+ DHCP_OPT_FORWARD = 19,
+ DHCP_OPT_SRC_RTE = 20,
+ DHCP_OPT_POLICY_FILTER = 21,
+ DHCP_OPT_MAX_DG_ASSEMBLY = 22,
+ DHCP_OPT_DEFAULT_IP_TTL = 23,
+ DHCP_OPT_MTU_TIMEOUT = 24,
+ DHCP_OPT_MTU_PLATEAU = 25,
+ DHCP_OPT_MTU_INTERFACE = 26,
+ DHCP_OPT_ALL_SUBNETS_LOCAL = 27,
+ DHCP_OPT_BROADCAST_ADDRESS = 28,
+ DHCP_OPT_MASK_DISCOVERY = 29,
+ DHCP_OPT_MASK_SUPPLIER = 30,
+ DHCP_OPT_ROUTER_DISCOVERY = 31,
+ DHCP_OPT_ROUTER_SOLICITATION_ADDRESS = 32,
+ DHCP_OPT_STATIC_ROUTE = 33,
+ DHCP_OPT_TRAILERS = 34,
+ DHCP_OPT_ARP_TIMEOUT = 35,
+ DHCP_OPT_ETHERNET = 36,
+ DHCP_OPT_TCP_DEFAULT_TTL = 37,
+ DHCP_OPT_TCP_KEEPALIVE_INTERVAL = 38,
+ DHCP_OPT_TCP_KEEPALIVE_GARBAGE = 39,
+ DHCP_OPT_NIS_DOMAIN = 40,
+ DHCP_OPT_NIS_SERVERS = 41,
+ DHCP_OPT_NTP_SERVERS = 42,
+ DHCP_OPT_VENDOR_SPECIFIC = 43,
+ DHCP_OPT_NETBIOS_NAME_SERVER = 44,
+ DHCP_OPT_NETBIOS_DISTRIBUTION_SERVER = 45,
+ DHCP_OPT_NETBIOS_NODE_TYPE = 46,
+ DHCP_OPT_NETBIOS_SCOPE = 47,
+ DHCP_OPT_FONT_SERVER = 48,
+ DHCP_OPT_DISPLAY_MANAGER = 49,
+ DHCP_OPT_REQUESTED_IP_ADDRESS = 50,
+ DHCP_OPT_IP_ADDRESS_LEASE_TIME = 51,
+ DHCP_OPT_OVERLOAD = 52,
+ DHCP_OPT_MSG_TYPE = 53,
+ DHCP_OPT_SERVER_ID = 54,
+ DHCP_OPT_PARAMETER_REQ_LIST = 55,
+ DHCP_OPT_MESSAGE = 56,
+ DHCP_OPT_MAX_MESSAGE_SIZE = 57,
+ DHCP_OPT_RENEWAL_TIME = 58,
+ DHCP_OPT_REBINDING_TIME = 59,
+ DHCP_OPT_VENDOR_CLASS_ID = 60,
+ DHCP_OPT_CLIENT_ID = 61,
+ DHCP_OPT_NETWARE_IP_DOMAIN = 62,
+ DHCP_OPT_NETWARE_IP_OPTION = 63,
+ DHCP_OPT_NIS_V3_DOMAIN = 64,
+ DHCP_OPT_NIS_V3_SERVERS = 65,
+ DHCP_OPT_TFTP_SERVER_NAME = 66,
+ DHCP_OPT_BOOT_FILE_NAME = 67,
+ DHCP_OPT_HOME_AGENT_ADDRESSES = 68,
+ DHCP_OPT_SMTP_SERVER = 69,
+ DHCP_OPT_POP3_SERVER = 70,
+ DHCP_OPT_NNTP_SERVER = 71,
+ DHCP_OPT_WWW_SERVER = 72,
+ DHCP_OPT_FINGER_SERVER = 73,
+ DHCP_OPT_IRC_SERVER = 74,
+ DHCP_OPT_STREETTALK_SERVER = 75,
+ DHCP_OPT_STDA_SERVER = 76,
+ DHCP_OPT_USER_CLASS = 77,
+ DHCP_OPT_DIRECTORY_AGENT = 78,
+ DHCP_OPT_SERVICE_SCOPE = 79,
+ DHCP_OPT_RAPID_COMMIT = 80,
+ DHCP_OPT_CLIENT_FQDN = 81,
+ DHCP_OPT_RELAY_AGENT_INFO = 82,
+ DHCP_OPT_ISNS = 83,
+ DHCP_OPT_NDS_SERVERS = 85,
+ DHCP_OPT_NDS_TREE_NAME = 86,
+ DHCP_OPT_NDS_CONTEXT = 87,
+ DHCP_OPT_BCMCS_CONTROLLER_DOMAIN_NAME_LIST = 88,
+ DHCP_OPT_BCMCS_CONTROLLER_IPV4_ADDRESS = 89,
+ DHCP_OPT_AUTHENTICATION = 90,
+ DHCP_OPT_CLIENT_LAST_TRANSACTION_TIME = 91,
+ DHCP_OPT_ASSOCIATED_IP = 92,
+ DHCP_OPT_CLIENT_SYSYEM = 93,
+ DHCP_OPT_CLIENT_NDI = 94,
+ DHCP_OPT_LDAP = 95,
+ DHCP_OPT_UUID_GUID = 97,
+ DHCP_OPT_USER_AUTH = 98,
+ DHCP_OPT_GEOCONF_CIVIC = 99,
+ DHCP_OPT_PCODE = 100,
+ DHCP_OPT_TCODE = 101,
+ DHCP_OPT_NETINFO_ADDRESS = 112,
+ DHCP_OPT_NETINFO_TAG = 113,
+ DHCP_OPT_URL = 114,
+ DHCP_OPT_AUTO_CONFIG = 116,
+ DHCP_OPT_NAME_SERVICE_SEARCH = 117,
+ DHCP_OPT_SUBNET_SELECTION = 118,
+ DHCP_OPT_DOMAIN_SEARCH = 119,
+ DHCP_OPT_SIP_SERVERS_DCP = 120,
+ DHCP_OPT_CLASSLESS_STATIC_ROUTE = 121,
+ DHCP_OPT_CCC = 122,
+ DHCP_OPT_GEOCONF = 123,
+ DHCP_OPT_V_I_VENDOR_CLASS = 124,
+ DHCP_OPT_V_I_VENDOR_SPECIFIC_INFO = 125,
+ DHCP_OPT_PANA_AGENT = 136,
+ DHCP_OPT_V4_LOST = 137,
+ DHCP_OPT_CAPWAP_AC_V4 = 138,
+ DHCP_OPT_IPV4_ADDRESS_MOS = 139,
+ DHCP_OPT_IPV4_FQDN_MOS = 140,
+ DHCP_OPT_SIP_UA_CONF = 141,
+ DHCP_OPT_IPV4_ADDRESS_ANDSF = 142,
+ DHCP_OPT_GEOLOC = 144,
+ DHCP_OPT_FORCERENEW_NONCE_CAPABLE = 145,
+ DHCP_OPT_RDNSS_SELECTION = 146,
+ DHCP_OPT_TFTP_SERVER_ADDRESS = 150,
+ DHCP_OPT_STATUS_CODE = 151,
+ DHCP_OPT_BASE_TIME = 152,
+ DHCP_OPT_START_TIME_OF_STATE = 153,
+ DHCP_OPT_QUERY_START_TIME = 154,
+ DHCP_OPT_QUERY_END_TIME = 155,
+ DHCP_OPT_STATE = 156,
+ DHCP_OPT_DATA_SOURCE = 157,
+ DHCP_OPT_V4_PCP_SERVER = 158,
+ DHCP_OPT_V4_PORTPARAMS = 159,
+ DHCP_OPT_CAPTIVE_PORTAL = 160,
+ DHCP_OPT_CONF_FILE = 209,
+ DHCP_OPT_PATH_PREFIX = 210,
+ DHCP_OPT_REBOOT_TIME = 211,
+ DHCP_OPT_6RD = 212,
+ DHCP_OPT_V4_ACCESS_DOMAIN = 213,
+ DHCP_OPT_SUBNET_ALLOCATION = 220,
+ DHCP_OPT_VSS = 221,
+ DHCP_OPT_END = 255
+};
+
+enum dhcp_message_types {
+ DHCPDISCOVER = 1,
+ DHCPOFFER = 2,
+ DHCPREQUEST = 3,
+ DHCPDECLINE = 4,
+ DHCPACK = 5,
+ DHCPNAK = 6,
+ DHCPRELEASE = 7,
+ DHCPINFORM = 8,
+ DHCPFORCERENEW = 9,
+ DHCPLEASEQUERY = 10,
+ DHCPLEASEUNASSIGNED = 11,
+ DHCPLEASEUNKNOWN = 12,
+ DHCPLEASEACTIVE = 13,
+ DHCPBULKLEASEQUERY = 14,
+ DHCPLEASEQUERYDONE = 15,
+ DHCPACTIVELEASEQUERY = 16,
+ DHCPLEASEQUERYSTATUS = 17,
+ DHCPTLS = 18,
+};
+
+enum dhcp_relay_agent_suboptions {
+ DHCP_RELAY_OPT_AGENT_CIRCUIT_ID = 1,
+ DHCP_RELAY_OPT_AGENT_REMOTE_ID = 2,
+ DHCP_RELAY_OPT_DOCSIS_DEVICE_CLASS = 4,
+ DHCP_RELAY_OPT_LINK_SELECTION = 5,
+ DHCP_RELAY_OPT_SUBSCRIBE_ID = 6,
+ DHCP_RELAY_OPT_RADIUS_ATTRIBUTES = 7,
+ DHCP_RELAY_OPT_AUTHENTICATION = 8,
+ DHCP_RELAY_OPT_VEDOR_SPECIFIC = 9,
+ DHCP_RELAY_OPT_RELAY_AGENT_FLAGS = 10,
+ DHCP_RELAY_OPT_SERVER_ID_OVERRIDE = 11,
+ DHCP_RELAY_OPT_RELAY_AGENT_ID = 12,
+ DHCP_RELAY_OPT_ACCESS_TECHNOLOGY_TYPE = 13,
+ DHCP_RELAY_OPT_ACCESS_NETWORK_NAME = 14,
+ DHCP_RELAY_OPT_ACCESS_POINT_NAME = 15,
+ DHCP_RELAY_OPT_ACCESS_POINT_BSSID = 16,
+ DHCP_RELAY_OPT_OPERATOR_ID = 17,
+ DHCP_RELAY_OPT_OPERATOR_REALM = 18,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION = 151,
+ DHCP_RELAY_OPT_DHCPV4_VIRTUAL_SUBNET_SELECTION_CONTROL = 152,
+};
+
+enum access_technology_types {
+ ACCESS_TECHNOLOGY_VIRTUAL = 1,
+ ACCESS_TECHNOLOGY_PPP = 2,
+ ACCESS_TECHNOLOGY_ETHERNET = 3,
+ ACCESS_TECHNOLOGY_WLAN = 4,
+ ACCESS_TECHNOLOGY_WIMAX = 5,
+};
+
+#endif /* DHCP_H */
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index ef4b59d..7a96f96 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -388,8 +388,10 @@
/* fall through */
case VHT_CHANWIDTH_80MHZ:
data->bandwidth = 80;
- if ((vht_oper_chwidth == 1 && center_segment1) ||
- (vht_oper_chwidth == 3 && !center_segment1) ||
+ if ((vht_oper_chwidth == VHT_CHANWIDTH_80MHZ &&
+ center_segment1) ||
+ (vht_oper_chwidth == VHT_CHANWIDTH_80P80MHZ &&
+ !center_segment1) ||
!sec_channel_offset)
return -1;
if (!center_segment0) {
@@ -467,3 +469,88 @@
else
htcaps->ht_capabilities_info |= msk;
}
+
+
+#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;
+}
+
+
+int ieee80211ac_cap_check(u32 hw, u32 conf)
+{
+#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;
+}
+
+#endif /* CONFIG_IEEE80211AC */
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 234b7bf..9cddbd5 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -37,5 +37,6 @@
int center_segment1, u32 vht_caps);
void set_disable_ht40(struct ieee80211_ht_capabilities *htcaps,
int disabled);
+int ieee80211ac_cap_check(u32 hw, u32 conf);
#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 55eaa82..15f6d42 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1960,4 +1960,53 @@
NR_CHAN_WIDTH_80P80 = 4,
};
+struct ieee80211_he_capabilities {
+ u8 he_mac_capab_info[5];
+ u8 he_phy_capab_info[9];
+ u16 he_txrx_mcs_support;
+ /* possibly followed by Tx Rx MCS NSS descriptor */
+ u8 variable[];
+ /* PPE Thresholds (optional) */
+} STRUCT_PACKED;
+
+struct ieee80211_he_operation {
+ u32 he_oper_params;
+ u8 he_mcs_nss_set[3];
+ u8 vht_op_info_chwidth;
+ u8 vht_op_info_chan_center_freq_seg0_idx;
+ u8 vht_op_info_chan_center_freq_seg1_idx;
+} STRUCT_PACKED;
+
+/* HE Capabilities Information defines */
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB_IDX 3
+#define HE_PHYCAP_SU_BEAMFORMER_CAPAB ((u8) BIT(7))
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB_IDX 4
+#define HE_PHYCAP_SU_BEAMFORMEE_CAPAB ((u8) BIT(0))
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB_IDX 4
+#define HE_PHYCAP_MU_BEAMFORMER_CAPAB ((u8) BIT(1))
+
+/* HE Operation defines */
+#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(0) | BIT(1) | \
+ BIT(2) | BIT(3) | \
+ BIT(4) | BIT(5)))
+#define HE_OPERATION_DFLT_PE_DURATION_MASK ((u32) (BIT(6) | BIT(7) | \
+ BIT(8)))
+#define HE_OPERATION_DFLT_PE_DURATION_OFFSET 6
+#define HE_OPERATION_TWT_REQUIRED ((u32) BIT(9))
+#define HE_OPERATION_RTS_THRESHOLD_MASK ((u32) (BIT(10) | BIT(11) | \
+ BIT(12) | BIT(13) | \
+ BIT(14) | BIT(15) | \
+ BIT(16) | BIT(17) | \
+ BIT(18) | BIT(19)))
+#define HE_OPERATION_RTS_THRESHOLD_OFFSET 10
+#define HE_OPERATION_PARTIAL_BSS_COLOR ((u32) BIT(20))
+#define HE_OPERATION_MAX_BSSID_INDICATOR_MASK ((u32) (BIT(21) | BIT(22) | \
+ BIT(23) | BIT(24) | \
+ BIT(25) | BIT(26) | \
+ BIT(27) | BIT(28)))
+#define HE_OPERATION_MAX_BSSID_INDICATOR_OFFSET 21
+#define HE_OPERATION_TX_BSSID_INDICATOR ((u32) BIT(29))
+#define HE_OPERATION_BSS_COLOR_DISABLED ((u32) BIT(30))
+#define HE_OPERATION_BSS_DUAL_BEACON ((u32) BIT(31))
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 25800d4..934f09d 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,6 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2017, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -233,6 +233,10 @@
* in the host driver. The different TDLS configurations are defined
* by the attributes in enum qca_wlan_vendor_attr_tdls_configuration.
*
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES: Query device IEEE 802.11ax HE
+ * capabilities. The response uses the attributes defined in
+ * enum qca_wlan_vendor_attr_get_he_capabilities.
+ *
* @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: Abort an ongoing vendor scan that was
* started with QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN. This command
* carries the scan cookie of the corresponding scan request. The scan
@@ -267,6 +271,23 @@
* @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET: Get the NUD statistics. These
* statistics are represented by the enum qca_attr_nud_stats_get
* attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS: Sub-command to fetch
+ * the BSS transition status, whether accept or reject, for a list of
+ * candidate BSSIDs provided by the userspace. This uses the vendor
+ * attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO. The userspace shall specify
+ * the attributes QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON and an
+ * array of QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO in the request. In the response
+ * the driver shall specify array of
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID and
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS pairs nested in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL: Set the trace level for a
+ * specific QCA module. The trace levels are represented by
+ * enum qca_attr_trace_level attributes.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -385,13 +406,15 @@
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_GET_SELECTED_SECTOR = 141,
QCA_NL80211_VENDOR_SUBCMD_DMG_RF_SET_SELECTED_SECTOR = 142,
QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143,
- /* 144 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES = 144,
QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145,
QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146,
QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS = 147,
QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148,
QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149,
QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150,
+ QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS = 151,
+ QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL = 152,
};
@@ -534,6 +557,22 @@
*/
QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM = 34,
QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO = 35,
+ /* Unsigned 8-bit value representing MBO transition reason code as
+ * provided by the AP used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS. This is
+ * specified by the userspace in the request to the driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON = 36,
+ /* Array of nested attributes, BSSID and status code, used by subcommand
+ * QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, where each
+ * entry is taken from enum qca_wlan_vendor_attr_btm_candidate_info.
+ * The userspace space specifies the list/array of candidate BSSIDs in
+ * the order of preference in the request. The driver specifies the
+ * status code, for each BSSID in the list, in the response. The
+ * acceptable candidates are listed in the order preferred by the
+ * driver.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO = 37,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
@@ -3304,4 +3343,83 @@
QCA_ATTR_NUD_STATS_GET_LAST - 1,
};
+enum qca_wlan_btm_candidate_status {
+ QCA_STATUS_ACCEPT = 0,
+ QCA_STATUS_REJECT_EXCESSIVE_FRAME_LOSS_EXPECTED = 1,
+ QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED = 2,
+ QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY = 3,
+ QCA_STATUS_REJECT_LOW_RSSI = 4,
+ QCA_STATUS_REJECT_HIGH_INTERFERENCE = 5,
+ QCA_STATUS_REJECT_UNKNOWN = 6,
+};
+
+enum qca_wlan_vendor_attr_btm_candidate_info {
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_INVALID = 0,
+
+ /* 6-byte MAC address representing the BSSID of transition candidate */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID = 1,
+ /* Unsigned 32-bit value from enum qca_wlan_btm_candidate_status
+ * returned by the driver. It says whether the BSSID provided in
+ * QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID is acceptable by
+ * the driver, if not it specifies the reason for rejection.
+ * Note that the user-space can overwrite the transition reject reason
+ * codes provided by driver based on more information.
+ */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX =
+ QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_AFTER_LAST - 1,
+};
+
+enum qca_attr_trace_level {
+ QCA_ATTR_TRACE_LEVEL_INVALID = 0,
+ /*
+ * Nested array of the following attributes:
+ * QCA_ATTR_TRACE_LEVEL_MODULE,
+ * QCA_ATTR_TRACE_LEVEL_MASK.
+ */
+ QCA_ATTR_TRACE_LEVEL_PARAM = 1,
+ /*
+ * Specific QCA host driver module. Please refer to the QCA host
+ * driver implementation to get the specific module ID.
+ */
+ QCA_ATTR_TRACE_LEVEL_MODULE = 2,
+ /* Different trace level masks represented in the QCA host driver. */
+ QCA_ATTR_TRACE_LEVEL_MASK = 3,
+
+ /* keep last */
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST,
+ QCA_ATTR_TRACE_LEVEL_MAX =
+ QCA_ATTR_TRACE_LEVEL_AFTER_LAST - 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_get_he_capabilities - IEEE 802.11ax HE capabilities
+ */
+enum qca_wlan_vendor_attr_get_he_capabilities {
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0,
+ /* Whether HE capabilities is supported
+ * (u8 attribute: 0 = not supported, 1 = supported) */
+ QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED = 1,
+ /* HE PHY capabilities, array of 3 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PHY_CAPAB = 2,
+ /* HE MAC capabilities (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_MAC_CAPAB = 3,
+ /* HE MCS map (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_HE_MCS = 4,
+ /* Number of SS (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_NUM_SS = 5,
+ /* RU count (u32 attribute) */
+ QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK = 6,
+ /* PPE threshold data, array of 8 u32 values */
+ QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD = 7,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX =
+ QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 79f001b..fd167d6 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -194,12 +194,12 @@
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
-#ifdef CONFIG_SUITEB192
+#if defined(CONFIG_SUITEB192) || defined(CONFIG_FILS)
if (wpa_key_mgmt_sha384(akmp))
sha384_prf(pmk, pmk_len, label, data, sizeof(data),
tmp, ptk_len);
else
-#endif /* CONFIG_SUITEB192 */
+#endif /* CONFIG_SUITEB192 || CONFIG_FILS */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
@@ -1104,10 +1104,10 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.3
*/
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
{
u8 buf[1 + SSID_MAX_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
@@ -1124,7 +1124,7 @@
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
*/
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
- return;
+ return -1;
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
@@ -1137,8 +1137,9 @@
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
- r0_key_data, sizeof(r0_key_data));
+ if (sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+ r0_key_data, sizeof(r0_key_data)) < 0)
+ return -1;
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
/*
@@ -1149,8 +1150,10 @@
addr[1] = r0_key_data + PMK_LEN;
len[1] = 16;
- sha256_vector(2, addr, len, hash);
+ if (sha256_vector(2, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+ return 0;
}
@@ -1159,8 +1162,8 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name)
{
u8 hash[32];
const u8 *addr[4];
@@ -1179,8 +1182,10 @@
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
- sha256_vector(4, addr, len, hash);
+ if (sha256_vector(4, addr, len, hash) < 0)
+ return -1;
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+ return 0;
}
@@ -1189,9 +1194,9 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name)
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name)
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
@@ -1203,9 +1208,12 @@
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+ if (sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf,
+ pmk_r1, PMK_LEN) < 0)
+ return -1;
- wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+ return wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id,
+ pmk_r1_name);
}
@@ -1245,7 +1253,9 @@
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
+ if (sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf,
+ tmp, ptk_len) < 0)
+ return -1;
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -1264,7 +1274,8 @@
addr[5] = sta_addr;
len[5] = ETH_ALEN;
- sha256_vector(6, addr, len, hash);
+ if (sha256_vector(6, addr, len, hash) < 0)
+ return -1;
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
os_memcpy(ptk->kck, tmp, ptk->kck_len);
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 4e465f5..a84cc9b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -358,15 +358,15 @@
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
-void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
- const u8 *ssid, size_t ssid_len,
- const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
- const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
-void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
- const u8 *s1kh_id, u8 *pmk_r1_name);
-void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
- const u8 *r1kh_id, const u8 *s1kh_id,
- u8 *pmk_r1, u8 *pmk_r1_name);
+int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+ const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+int wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+ const u8 *s1kh_id, u8 *pmk_r1_name);
+int wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+ const u8 *r1kh_id, const u8 *s1kh_id,
+ u8 *pmk_r1, u8 *pmk_r1_name);
int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 766a3fa..4649eab 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -300,6 +300,10 @@
/* PMKSA cache entry removed; parameters: <BSSID> <network_id> */
#define PMKSA_CACHE_REMOVED "PMKSA-CACHE-REMOVED "
+/* FILS HLP Container receive; parameters: dst=<addr> src=<addr> frame=<hexdump>
+ */
+#define FILS_HLP_RX "FILS-HLP-RX "
+
/* BSS command information masks */
#define WPA_BSS_MASK_ALL 0xFFFDFFFF
diff --git a/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
index fb91ab4..0fa06d9 100644
--- a/src/crypto/crypto_module_tests.c
+++ b/src/crypto/crypto_module_tests.c
@@ -17,6 +17,7 @@
#include "crypto/crypto.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
static int test_siv(void)
@@ -1295,13 +1296,14 @@
};
static const struct hmac_test {
- u8 key[80];
+ u8 key[150];
size_t key_len;
- u8 data[128];
+ u8 data[160];
size_t data_len;
- u8 hash[32];
+ u8 hash[32]; /* HMAC-SHA-256 */
+ u8 hash384[48]; /* HMAC-SHA-384 */
} hmac_tests[] = {
- /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt; RFC 4231 */
{
{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
@@ -1316,7 +1318,8 @@
0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
- }
+ },
+ { }
},
{
{
@@ -1333,7 +1336,8 @@
0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
- }
+ },
+ { }
},
{
{
@@ -1351,7 +1355,8 @@
0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
- }
+ },
+ { }
},
{
{
@@ -1368,9 +1373,34 @@
0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 1 */
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 20,
+ "Hi There",
+ 8,
+ {
+ 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53,
+ 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b,
+ 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7,
+ 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7
+ },
+ {
+ 0xaf, 0xd0, 0x39, 0x44, 0xd8, 0x48, 0x95, 0x62,
+ 0x6b, 0x08, 0x25, 0xf4, 0xab, 0x46, 0x90, 0x7f,
+ 0x15, 0xf9, 0xda, 0xdb, 0xe4, 0x10, 0x1e, 0xc6,
+ 0x82, 0xaa, 0x03, 0x4c, 0x7c, 0xeb, 0xc5, 0x9c,
+ 0xfa, 0xea, 0x9e, 0xa9, 0x07, 0x6e, 0xde, 0x7f,
+ 0x4a, 0xf1, 0x52, 0xe8, 0xb2, 0xfa, 0x9c, 0xb6
}
},
- {
+ { /* RFC 4231 - Test Case 2 */
"Jefe",
4,
"what do ya want for nothing?",
@@ -1380,6 +1410,14 @@
0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ },
+ {
+ 0xaf, 0x45, 0xd2, 0xe3, 0x76, 0x48, 0x40, 0x31,
+ 0x61, 0x7f, 0x78, 0xd2, 0xb5, 0x8a, 0x6b, 0x1b,
+ 0x9c, 0x7e, 0xf4, 0x64, 0xf5, 0xa0, 0x1b, 0x47,
+ 0xe4, 0x2e, 0xc3, 0x73, 0x63, 0x22, 0x44, 0x5e,
+ 0x8e, 0x22, 0x40, 0xca, 0x5e, 0x69, 0xe2, 0xc7,
+ 0x8b, 0x32, 0x39, 0xec, 0xfa, 0xb2, 0x16, 0x49
}
},
{
@@ -1405,6 +1443,39 @@
0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 3 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 20,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46,
+ 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7,
+ 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22,
+ 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe
+ },
+ {
+ 0x88, 0x06, 0x26, 0x08, 0xd3, 0xe6, 0xad, 0x8a,
+ 0x0a, 0xa2, 0xac, 0xe0, 0x14, 0xc8, 0xa8, 0x6f,
+ 0x0a, 0xa6, 0x35, 0xd9, 0x47, 0xac, 0x9f, 0xeb,
+ 0xe8, 0x3e, 0xf4, 0xe5, 0x59, 0x66, 0x14, 0x4b,
+ 0x2a, 0x5a, 0xb3, 0x9d, 0xc1, 0x38, 0x14, 0xb9,
+ 0x4e, 0x3a, 0xb6, 0xe1, 0x01, 0xa3, 0x4f, 0x27
}
},
{
@@ -1431,6 +1502,40 @@
0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 4 */
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ 25,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e,
+ 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a,
+ 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07,
+ 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b
+ },
+ {
+ 0x3e, 0x8a, 0x69, 0xb7, 0x78, 0x3c, 0x25, 0x85,
+ 0x19, 0x33, 0xab, 0x62, 0x90, 0xaf, 0x6c, 0xa7,
+ 0x7a, 0x99, 0x81, 0x48, 0x08, 0x50, 0x00, 0x9c,
+ 0xc5, 0x57, 0x7c, 0x6e, 0x1f, 0x57, 0x3b, 0x4e,
+ 0x68, 0x01, 0xdd, 0x23, 0xc4, 0xa7, 0xd6, 0x79,
+ 0xcc, 0xf8, 0xa3, 0x86, 0xc6, 0x74, 0xcf, 0xfb
}
},
{
@@ -1448,7 +1553,8 @@
0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
- }
+ },
+ { }
},
{
{
@@ -1471,6 +1577,45 @@
0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 6 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f,
+ 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f,
+ 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14,
+ 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54
+ },
+ {
+ 0x4e, 0xce, 0x08, 0x44, 0x85, 0x81, 0x3e, 0x90,
+ 0x88, 0xd2, 0xc6, 0x3a, 0x04, 0x1b, 0xc5, 0xb4,
+ 0x4f, 0x9e, 0xf1, 0x01, 0x2a, 0x2b, 0x58, 0x8f,
+ 0x3c, 0xd1, 0x1f, 0x05, 0x03, 0x3a, 0xc4, 0xc6,
+ 0x0c, 0x2e, 0xf6, 0xab, 0x40, 0x30, 0xfe, 0x82,
+ 0x96, 0x24, 0x8d, 0xf1, 0x63, 0xf4, 0x49, 0x52
}
},
{
@@ -1495,6 +1640,45 @@
0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ },
+ { }
+ },
+ { /* RFC 4231 - Test Case 7 */
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa
+ },
+ 131,
+ "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
+ 152,
+ {
+ 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb,
+ 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44,
+ 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93,
+ 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2
+ },
+ {
+ 0x66, 0x17, 0x17, 0x8e, 0x94, 0x1f, 0x02, 0x0d,
+ 0x35, 0x1e, 0x2f, 0x25, 0x4e, 0x8f, 0xd3, 0x2c,
+ 0x60, 0x24, 0x20, 0xfe, 0xb0, 0xb8, 0xfb, 0x9a,
+ 0xdc, 0xce, 0xbb, 0x82, 0x46, 0x1e, 0x99, 0xc5,
+ 0xa6, 0x78, 0xcc, 0x31, 0xe7, 0x99, 0x17, 0x6d,
+ 0x38, 0x60, 0xe6, 0x11, 0x0c, 0x46, 0x52, 0x3e
}
}
};
@@ -1609,6 +1793,96 @@
}
+static int test_sha384(void)
+{
+#ifdef CONFIG_SHA384
+ unsigned int i;
+ u8 hash[48];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+ const char *data = "hello";
+ const u8 hash_res[] = {
+ 0x59, 0xe1, 0x74, 0x87, 0x77, 0x44, 0x8c, 0x69,
+ 0xde, 0x6b, 0x80, 0x0d, 0x7a, 0x33, 0xbb, 0xfb,
+ 0x9f, 0xf1, 0xb4, 0x63, 0xe4, 0x43, 0x54, 0xc3,
+ 0x55, 0x3b, 0xcd, 0xb9, 0xc6, 0x66, 0xfa, 0x90,
+ 0x12, 0x5a, 0x3c, 0x79, 0xf9, 0x03, 0x97, 0xbd,
+ 0xf5, 0xf6, 0xa1, 0x3d, 0xe8, 0x28, 0x68, 0x4f
+ };
+
+ addr[0] = (const u8 *) data;
+ len[0] = 5;
+ if (sha384_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 1: OK");
+ }
+
+ addr[0] = (const u8 *) data;
+ len[0] = 4;
+ addr[1] = (const u8 *) data + 4;
+ len[1] = 1;
+ if (sha384_vector(2, addr, len, hash) < 0 ||
+ os_memcmp(hash, hash_res, 48) != 0) {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: FAIL");
+ errors++;
+ } else {
+ wpa_printf(MSG_INFO, "SHA384 test case 2: OK");
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ const struct hmac_test *t = &hmac_tests[i];
+
+ if (t->hash384[0] == 0 && t->hash384[1] == 0 &&
+ t->hash384[2] == 0 && t->hash384[3] == 0)
+ continue;
+ wpa_printf(MSG_INFO, "HMAC-SHA384 test case %d:", i + 1);
+
+ if (hmac_sha384(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha384_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha384_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash384, 48) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA384 test cases passed");
+ return errors;
+#else /* CONFIG_SHA384 */
+ return 0;
+#endif /* CONFIG_SHA384 */
+}
+
+
static int test_fips186_2_prf(void)
{
/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
@@ -1754,6 +2028,7 @@
test_md5() ||
test_sha1() ||
test_sha256() ||
+ test_sha384() ||
test_fips186_2_prf() ||
test_ms_funcs())
ret = -1;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 02cb391..5f7896c 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -383,6 +383,8 @@
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
@@ -397,6 +399,8 @@
AES_KEY actx;
int res;
+ if (TEST_FAIL())
+ return -1;
if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
return -1;
res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
@@ -1027,7 +1031,7 @@
const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
- len, mac, 32);
+ len, mac, 48);
}
diff --git a/src/crypto/sha384.c b/src/crypto/sha384.c
new file mode 100644
index 0000000..ee136ce
--- /dev/null
+++ b/src/crypto/sha384.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-384 hash implementation and interface functions
+ * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha384_vector - HMAC-SHA384 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[128]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[48];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return -1;
+ }
+
+ /* if key is longer than 128 bytes reset it to key = SHA384(key) */
+ if (key_len > 128) {
+ if (sha384_vector(1, &key, &key_len, tk) < 0)
+ return -1;
+ key = tk;
+ key_len = 48;
+ }
+
+ /* the HMAC_SHA384 transform looks like:
+ *
+ * SHA384(K XOR opad, SHA384(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 128 times
+ * opad is the byte 0x5c repeated 128 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ if (sha384_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
+
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 128; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA384 */
+ _addr[0] = k_pad;
+ _len[0] = 128;
+ _addr[1] = mac;
+ _len[1] = SHA384_MAC_LEN;
+ return sha384_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha384 - HMAC-SHA384 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (48 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 92688a3..7b3a6bd 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -136,6 +136,29 @@
unsigned int dfs_cac_ms;
};
+#define HE_MAX_NUM_SS 8
+#define HE_MAX_PHY_CAPAB_SIZE 3
+
+/**
+ * struct he_ppe_threshold - IEEE 802.11ax HE PPE Threshold
+ */
+struct he_ppe_threshold {
+ u32 numss_m1;
+ u32 ru_count;
+ u32 ppet16_ppet8_ru3_ru0[HE_MAX_NUM_SS];
+};
+
+/**
+ * struct he_capabilities - IEEE 802.11ax HE capabilities
+ */
+struct he_capabilities {
+ u8 he_supported;
+ u32 phy_cap[HE_MAX_PHY_CAPAB_SIZE];
+ u32 mac_cap;
+ u32 mcs;
+ struct he_ppe_threshold ppet;
+};
+
#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
#define HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN BIT(1)
@@ -194,6 +217,11 @@
u8 vht_mcs_set[8];
unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+
+ /**
+ * he_capab - HE (IEEE 802.11ax) capabilities
+ */
+ struct he_capabilities he_capab;
};
@@ -495,6 +523,36 @@
*/
unsigned int duration_mandatory:1;
+ /**
+ * relative_rssi_set - Whether relative RSSI parameters are set
+ */
+ unsigned int relative_rssi_set:1;
+
+ /**
+ * relative_rssi - Relative RSSI for reporting better BSSs
+ *
+ * Amount of RSSI by which a BSS should be better than the current
+ * connected BSS to report the new BSS to user space.
+ */
+ s8 relative_rssi;
+
+ /**
+ * relative_adjust_band - Band to which RSSI should be adjusted
+ *
+ * The relative_adjust_rssi should be added to the band specified
+ * by relative_adjust_band.
+ */
+ enum set_band relative_adjust_band;
+
+ /**
+ * relative_adjust_rssi - RSSI to be added to relative_adjust_band
+ *
+ * An amount of relative_band_rssi should be added to the BSSs that
+ * belong to the band specified by relative_adjust_band while comparing
+ * with other bands for BSS reporting.
+ */
+ s8 relative_adjust_rssi;
+
/*
* NOTE: Whenever adding new parameters here, please make sure
* wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -1393,6 +1451,14 @@
#define WPA_DRIVER_FLAGS_BEACON_RATE_HT 0x0000100000000000ULL
/** Driver supports Beacon frame TX rate configuration (VHT rates) */
#define WPA_DRIVER_FLAGS_BEACON_RATE_VHT 0x0000200000000000ULL
+/** Driver supports mgmt_tx with random TX address in non-connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA 0x0000400000000000ULL
+/** Driver supports mgmt_tx with random TX addr in connected state */
+#define WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED 0x0000800000000000ULL
+/** Driver supports better BSS reporting with sched_scan in connected mode */
+#define WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI 0x0001000000000000ULL
+/** Driver supports HE capabilities */
+#define WPA_DRIVER_FLAGS_HE_CAPABILITIES 0x0002000000000000ULL
u64 flags;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
@@ -2785,6 +2851,9 @@
* transmitted on that channel; alternatively the frame may be sent on
* the current operational channel (if in associated state in station
* mode or while operating as an AP.)
+ *
+ * If @src differs from the device MAC address, use of a random
+ * transmitter address is requested for this message exchange.
*/
int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
@@ -4638,6 +4707,11 @@
* than explicit rejection response from the AP.
*/
int timed_out;
+
+ /**
+ * timeout_reason - Reason for the timeout
+ */
+ const char *timeout_reason;
} assoc_reject;
struct timeout_event {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 27e22c6..e9107b3 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6881,6 +6881,14 @@
os_memcpy(hdr->addr2, src, ETH_ALEN);
os_memcpy(hdr->addr3, bssid, ETH_ALEN);
+ if (os_memcmp(bss->addr, src, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Use random TA " MACSTR,
+ MAC2STR(src));
+ os_memcpy(bss->rand_addr, src, ETH_ALEN);
+ } else {
+ os_memset(bss->rand_addr, 0, ETH_ALEN);
+ }
+
if (is_ap_interface(drv->nlmode) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
(int) freq == bss->freq || drv->device_ap_sme ||
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 94b8bdf..bdc79c5 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -78,6 +78,7 @@
struct nl80211_wiphy_data *wiphy_data;
struct dl_list wiphy_list;
+ u8 rand_addr[ETH_ALEN];
};
struct wpa_driver_nl80211_data {
@@ -160,6 +161,7 @@
unsigned int scan_vendor_cmd_avail:1;
unsigned int connect_reassoc:1;
unsigned int set_wifi_conf_vendor_cmd_avail:1;
+ unsigned int he_capab_vendor_cmd_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
@@ -208,6 +210,8 @@
* (NL80211_CMD_VENDOR). 0 if no pending scan request.
*/
int last_scan_cmd;
+
+ struct he_capabilities he_capab;
};
struct nl_msg;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 3d85316..7064ce1 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -389,6 +389,15 @@
ext_feature_isset(ext_features, len,
NL80211_EXT_FEATURE_SET_SCAN_DWELL))
capa->rrm_flags |= WPA_DRIVER_FLAGS_SUPPORT_BEACON_REPORT;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED))
+ capa->flags |= WPA_DRIVER_FLAGS_MGMT_TX_RANDOM_TA_CONNECTED;
+ if (ext_feature_isset(ext_features, len,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI))
+ capa->flags |= WPA_DRIVER_FLAGS_SCHED_SCAN_RELATIVE_RSSI;
}
@@ -735,6 +744,9 @@
case QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION:
drv->set_wifi_conf_vendor_cmd_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES:
+ drv->he_capab_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -904,6 +916,100 @@
}
+static int qca_nl80211_he_capab_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct he_capabilities *he_capab = arg;
+ struct nlattr *nl_vend;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX + 1];
+ size_t len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb[NL80211_ATTR_VENDOR_DATA])
+ return NL_SKIP;
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]) {
+ u8 he_supported;
+
+ he_supported = nla_get_u8(
+ tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED]);
+ wpa_printf(MSG_DEBUG, "nl80211: HE capabilities supported: %u",
+ he_supported);
+ he_capab->he_supported = he_supported;
+ if (!he_supported)
+ return NL_SKIP;
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]);
+
+ if (len > sizeof(he_capab->phy_cap))
+ len = sizeof(he_capab->phy_cap);
+ os_memcpy(he_capab->phy_cap,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PHY_CAPAB]),
+ len);
+ }
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB])
+ he_capab->mac_cap =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_MAC_CAPAB]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS])
+ he_capab->mcs =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_HE_MCS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS])
+ he_capab->ppet.numss_m1 =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_NUM_SS]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK])
+ he_capab->ppet.ru_count =
+ nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK]);
+
+ if (tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]) {
+ len = nla_len(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]);
+
+ if (len > sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0))
+ len = sizeof(he_capab->ppet.ppet16_ppet8_ru3_ru0);
+ os_memcpy(he_capab->ppet.ppet16_ppet8_ru3_ru0,
+ nla_data(tb_vendor[QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD]),
+ len);
+ }
+
+ return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_he_capab(struct wpa_driver_nl80211_data *drv)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ if (!drv->he_capab_vendor_cmd_avail)
+ return;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES)) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, qca_nl80211_he_capab_handler,
+ &drv->he_capab);
+ if (!ret && drv->he_capab.he_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_HE_CAPABILITIES;
+}
+
+
struct features_info {
u8 *flags;
size_t flags_len;
@@ -1075,6 +1181,7 @@
#ifdef CONFIG_DRIVER_NL80211_QCA
qca_nl80211_check_dfs_capa(drv);
qca_nl80211_get_features(drv);
+ qca_nl80211_check_he_capab(drv);
/*
* To enable offchannel simultaneous support in wpa_supplicant, the
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index c18fc22..ed2cbe4 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -279,6 +279,7 @@
struct nlattr *addr, struct nlattr *req_ie,
struct nlattr *resp_ie,
struct nlattr *timed_out,
+ struct nlattr *timeout_reason,
struct nlattr *authorized,
struct nlattr *key_replay_ctr,
struct nlattr *ptk_kck,
@@ -338,6 +339,24 @@
}
event.assoc_reject.status_code = status_code;
event.assoc_reject.timed_out = timed_out != NULL;
+ if (timed_out && timeout_reason) {
+ enum nl80211_timeout_reason reason;
+
+ reason = nla_get_u32(timeout_reason);
+ switch (reason) {
+ case NL80211_TIMEOUT_SCAN:
+ event.assoc_reject.timeout_reason = "scan";
+ break;
+ case NL80211_TIMEOUT_AUTH:
+ event.assoc_reject.timeout_reason = "auth";
+ break;
+ case NL80211_TIMEOUT_ASSOC:
+ event.assoc_reject.timeout_reason = "assoc";
+ break;
+ default:
+ break;
+ }
+ }
wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
return;
}
@@ -860,6 +879,8 @@
MAC2STR(data + 4 + ETH_ALEN));
if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
+ (is_zero_ether_addr(bss->rand_addr) ||
+ os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) &&
os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
"for foreign address", bss->ifname);
@@ -1724,7 +1745,7 @@
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
- NULL,
+ NULL, NULL,
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
@@ -2244,6 +2265,7 @@
tb[NL80211_ATTR_REQ_IE],
tb[NL80211_ATTR_RESP_IE],
tb[NL80211_ATTR_TIMED_OUT],
+ tb[NL80211_ATTR_TIMEOUT_REASON],
NULL, NULL, NULL, NULL, NULL);
break;
case NL80211_CMD_CH_SWITCH_NOTIFY:
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index b577531..4417721 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -562,6 +562,39 @@
nla_nest_end(msg, match_sets);
}
+ if (params->relative_rssi_set) {
+ struct nl80211_bss_select_rssi_adjust rssi_adjust;
+
+ os_memset(&rssi_adjust, 0, sizeof(rssi_adjust));
+ wpa_printf(MSG_DEBUG, "nl80211: Relative RSSI: %d",
+ params->relative_rssi);
+ if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ params->relative_rssi))
+ goto fail;
+
+ if (params->relative_adjust_rssi) {
+ int pref_band_set = 1;
+
+ switch (params->relative_adjust_band) {
+ case WPA_SETBAND_5G:
+ rssi_adjust.band = NL80211_BAND_5GHZ;
+ break;
+ case WPA_SETBAND_2G:
+ rssi_adjust.band = NL80211_BAND_2GHZ;
+ break;
+ default:
+ pref_band_set = 0;
+ break;
+ }
+ rssi_adjust.delta = params->relative_adjust_rssi;
+
+ if (pref_band_set &&
+ nla_put(msg, NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+ sizeof(rssi_adjust), &rssi_adjust))
+ goto fail;
+ }
+ }
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
/* TODO: if we get an error here, we should fall back to normal scan */
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 174f4b3..d6c62ee 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -1772,7 +1772,9 @@
*
* @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
* Notification Element based on association request when used with
- * %NL80211_CMD_NEW_STATION; u8 attribute.
+ * %NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when
+ * %NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS);
+ * u8 attribute.
*
* @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
* %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
@@ -1982,6 +1984,24 @@
* @NL80211_ATTR_BSSID: The BSSID of the AP. Note that %NL80211_ATTR_MAC is also
* used in various commands/events for specifying the BSSID.
*
+ * @NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI: Relative RSSI threshold by which
+ * other BSSs has to be better or slightly worse than the current
+ * connected BSS so that they get reported to user space.
+ * This will give an opportunity to userspace to consider connecting to
+ * other matching BSSs which have better or slightly worse RSSI than
+ * the current connected BSS by using an offloaded operation to avoid
+ * unnecessary wakeups.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST: When present the RSSI level for BSSs in
+ * the specified band is to be adjusted before doing
+ * %NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI based comparision to figure out
+ * better BSSs. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
+ *
+ * @NL80211_ATTR_TIMEOUT_REASON: The reason for which an operation timed out.
+ * u32 attribute with an &enum nl80211_timeout_reason value. This is used,
+ * e.g., with %NL80211_CMD_CONNECT event.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2388,6 +2408,11 @@
NL80211_ATTR_BSSID,
+ NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI,
+ NL80211_ATTR_SCHED_SCAN_RSSI_ADJUST,
+
+ NL80211_ATTR_TIMEOUT_REASON,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -3080,6 +3105,13 @@
* how this API was implemented in the past. Also, due to the same problem,
* the only way to create a matchset with only an RSSI filter (with this
* attribute) is if there's only a single matchset with the RSSI attribute.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI: Flag indicating whether
+ * %NL80211_SCHED_SCAN_MATCH_ATTR_RSSI to be used as absolute RSSI or
+ * relative to current bss's RSSI.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST: When present the RSSI level for
+ * BSS-es in the specified band is to be adjusted before doing
+ * RSSI-based BSS selection. The attribute value is a packed structure
+ * value as specified by &struct nl80211_bss_select_rssi_adjust.
* @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
* attribute number currently defined
* @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
@@ -3089,6 +3121,8 @@
NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RELATIVE_RSSI,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI_ADJUST,
/* keep last */
__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
@@ -4699,6 +4733,13 @@
* configuration (AP/mesh) with VHT rates.
* @NL80211_EXT_FEATURE_FILS_STA: This driver supports Fast Initial Link Setup
* with user space SME (NL80211_CMD_AUTHENTICATE) in station mode.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA: This driver supports randomized TA
+ * in @NL80211_CMD_FRAME while not associated.
+ * @NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED: This driver supports
+ * randomized TA in @NL80211_CMD_FRAME while associated.
+ * @NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI: The driver supports sched_scan
+ * for reporting BSSs with better RSSI than the current connected BSS
+ * (%NL80211_ATTR_SCHED_SCAN_RELATIVE_RSSI).
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
@@ -4714,6 +4755,9 @@
NL80211_EXT_FEATURE_BEACON_RATE_HT,
NL80211_EXT_FEATURE_BEACON_RATE_VHT,
NL80211_EXT_FEATURE_FILS_STA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA,
+ NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA_CONNECTED,
+ NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,
@@ -4753,6 +4797,21 @@
};
/**
+ * enum nl80211_timeout_reason - timeout reasons
+ *
+ * @NL80211_TIMEOUT_UNSPECIFIED: Timeout reason unspecified.
+ * @NL80211_TIMEOUT_SCAN: Scan (AP discovery) timed out.
+ * @NL80211_TIMEOUT_AUTH: Authentication timed out.
+ * @NL80211_TIMEOUT_ASSOC: Association timed out.
+ */
+enum nl80211_timeout_reason {
+ NL80211_TIMEOUT_UNSPECIFIED,
+ NL80211_TIMEOUT_SCAN,
+ NL80211_TIMEOUT_AUTH,
+ NL80211_TIMEOUT_ASSOC,
+};
+
+/**
* enum nl80211_scan_flags - scan request control flags
*
* Scan request control flags are used to control the handling
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 1c6116a..bc90c7a 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -489,7 +489,7 @@
u8 *emsk = NULL;
size_t emsk_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
char *realm;
size_t realm_len, nai_buf_len;
struct eap_erp_key *erp = NULL;
@@ -526,7 +526,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
len, sizeof(len),
EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -550,9 +550,11 @@
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
@@ -2244,6 +2246,7 @@
config->pending_req_passphrase++;
break;
case WPA_CTRL_REQ_SIM:
+ config->pending_req_sim++;
txt = msg;
break;
case WPA_CTRL_REQ_EXT_CERT_CHECK:
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 0bac62d..4188817 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -48,6 +48,7 @@
struct wpabuf *id_msgs;
int prev_id;
int result_ind, use_result_ind;
+ int use_pseudonym;
u8 eap_method;
u8 *network_name;
size_t network_name_len;
@@ -101,7 +102,8 @@
data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -350,7 +352,8 @@
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -405,7 +408,9 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index f980072..16521c3 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -628,6 +628,15 @@
int pending_req_passphrase;
/**
+ * pending_req_sim - Pending SIM request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_sim;
+
+ /**
* pending_req_otp - Whether there is a pending OTP request
*
* This field should not be set in configuration step. It is only used
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 964ebe7..e4b0c10 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -484,7 +484,8 @@
if (*resp == NULL && config &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
} else if (*resp == NULL)
@@ -1677,6 +1678,10 @@
static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
os_free(data->key_block_p);
data->key_block_p = NULL;
wpabuf_free(data->pending_phase2_req);
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index efeddb8..2ff6076 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -726,7 +726,8 @@
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp || config->pending_req_new_password)) {
+ config->pending_req_otp || config->pending_req_new_password ||
+ config->pending_req_sim)) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
}
@@ -1163,6 +1164,10 @@
static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
wpabuf_free(data->pending_resp);
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index b97c95d..95ecdf7 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -46,6 +46,7 @@
CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE
} state;
int result_ind, use_result_ind;
+ int use_pseudonym;
};
@@ -115,7 +116,8 @@
NULL;
}
- if (config && config->anonymous_identity) {
+ data->use_pseudonym = !sm->init_phase2;
+ if (config && config->anonymous_identity && data->use_pseudonym) {
data->pseudonym = os_malloc(config->anonymous_identity_len);
if (data->pseudonym) {
os_memcpy(data->pseudonym, config->anonymous_identity,
@@ -372,7 +374,8 @@
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
- eap_set_anon_id(sm, NULL, 0);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -427,7 +430,9 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
- eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
+ if (data->use_pseudonym)
+ eap_set_anon_id(sm, data->pseudonym,
+ data->pseudonym_len);
}
if (attr->next_reauth_id) {
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e4bc22f..3354b2d 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -458,7 +458,7 @@
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
- config->pending_req_otp)) {
+ config->pending_req_otp || config->pending_req_sim)) {
return 0;
}
@@ -1280,7 +1280,8 @@
} else if (config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password) {
+ config->pending_req_new_password ||
+ config->pending_req_sim) {
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = wpabuf_dup(in_decrypted);
}
@@ -1317,7 +1318,8 @@
(config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
- config->pending_req_new_password)) {
+ config->pending_req_new_password ||
+ config->pending_req_sim)) {
/*
* Use empty buffer to force implicit request
* processing when EAP request is re-processed after
@@ -1648,6 +1650,10 @@
static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
+
+ if (data->phase2_priv && data->phase2_method &&
+ data->phase2_method->deinit_for_reauth)
+ data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
wpabuf_free(data->pending_resp);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 08cc171..1b571cf 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -415,7 +415,7 @@
u8 *emsk = NULL;
size_t emsk_len = 0;
u8 EMSKname[EAP_EMSK_NAME_LEN];
- u8 len[2];
+ u8 len[2], ctx[3];
const char *domain;
size_t domain_len, nai_buf_len;
struct eap_server_erp_key *erp = NULL;
@@ -452,7 +452,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
- WPA_PUT_BE16(len, 8);
+ WPA_PUT_BE16(len, EAP_EMSK_NAME_LEN);
if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
"EMSK", len, sizeof(len),
EMSKname, EAP_EMSK_NAME_LEN) < 0) {
@@ -476,9 +476,11 @@
erp->rRK_len = emsk_len;
wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+ ctx[0] = EAP_ERP_CS_HMAC_SHA256_128;
+ WPA_PUT_BE16(&ctx[1], erp->rRK_len);
if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
- "EAP Re-authentication Integrity Key@ietf.org",
- len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+ "Re-authentication Integrity Key@ietf.org",
+ ctx, sizeof(ctx), erp->rIK, erp->rRK_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
goto fail;
}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 0dc7ea6..e727005 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -250,6 +250,8 @@
if (sm->eapTriggerStart)
send_start = 1;
+ if (sm->ctx->preauth)
+ send_start = 1;
sm->eapTriggerStart = FALSE;
if (send_start) {
@@ -2155,16 +2157,14 @@
}
+#ifdef CONFIG_EAP_PROXY
int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
{
-#ifdef CONFIG_EAP_PROXY
if (sm->eap_proxy == NULL)
return -1;
return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
-#else /* CONFIG_EAP_PROXY */
- return -1;
-#endif /* CONFIG_EAP_PROXY */
}
+#endif /* CONFIG_EAP_PROXY */
void eapol_sm_erp_flush(struct eapol_sm *sm)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 65dd1a3..14d6279 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3034,6 +3034,8 @@
p2p->ssid_set = 0;
p2ps_prov_free(p2p);
p2p_reset_pending_pd(p2p);
+ p2p->override_pref_op_class = 0;
+ p2p->override_pref_channel = 0;
}
@@ -5522,6 +5524,14 @@
}
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan)
+{
+ p2p->override_pref_op_class = op_class;
+ p2p->override_pref_channel = chan;
+}
+
+
struct wpabuf * p2p_build_probe_resp_template(struct p2p_data *p2p,
unsigned int freq)
{
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7b18dcf..70d3a90 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -2373,6 +2373,8 @@
void p2p_set_own_pref_freq_list(struct p2p_data *p2p,
const unsigned int *pref_freq_list,
unsigned int size);
+void p2p_set_override_pref_op_chan(struct p2p_data *p2p, u8 op_class,
+ u8 chan);
/**
* p2p_group_get_common_freqs - Get the group common frequencies
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 9f0b3f3..65ab4b8 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -315,7 +315,12 @@
group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
- if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
+ if (p2p->override_pref_op_class) {
+ p2p_dbg(p2p, "Override operating channel preference");
+ p2p_buf_add_operating_channel(buf, p2p->cfg->country,
+ p2p->override_pref_op_class,
+ p2p->override_pref_channel);
+ } else if (peer && peer->go_state == REMOTE_GO && !p2p->num_pref_freq) {
p2p_dbg(p2p, "Omit Operating Channel attribute");
} else {
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -562,26 +567,11 @@
* also supported by the peer device.
*/
for (i = 0; i < size && !found; i++) {
- /*
- * Make sure that the common frequency is:
- * 1. Supported by peer
- * 2. Allowed for P2P use.
- */
+ /* Make sure that the common frequency is supported by peer. */
oper_freq = freq_list[i];
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz", oper_freq);
- continue;
- }
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen due to earlier check */
for (j = 0; j < msg->channel_list_len; j++) {
if (op_channel != msg->channel_list[j])
@@ -602,8 +592,7 @@
oper_freq);
} else {
p2p_dbg(p2p,
- "None of our preferred channels are supported by peer!. Use: %d MHz for oper_channel",
- dev->oper_freq);
+ "None of our preferred channels are supported by peer!");
}
}
@@ -629,29 +618,9 @@
msg->pref_freq_list[2 * j + 1]);
if (freq_list[i] != oper_freq)
continue;
-
- /*
- * Make sure that the found frequency is:
- * 1. Supported
- * 2. Allowed for P2P use.
- */
if (p2p_freq_to_channel(oper_freq, &op_class,
- &op_channel) < 0) {
- p2p_dbg(p2p, "Unsupported frequency %u MHz",
- oper_freq);
- continue;
- }
-
- if (!p2p_channels_includes(&p2p->cfg->channels,
- op_class, op_channel) &&
- (go ||
- !p2p_channels_includes(&p2p->cfg->cli_channels,
- op_class, op_channel))) {
- p2p_dbg(p2p,
- "Freq %u MHz (oper_class %u channel %u) not allowed for P2P",
- oper_freq, op_class, op_channel);
- break;
- }
+ &op_channel) < 0)
+ continue; /* cannot happen */
p2p->op_reg_class = op_class;
p2p->op_channel = op_channel;
os_memcpy(&p2p->channels, &p2p->cfg->channels,
@@ -666,9 +635,7 @@
"Freq %d MHz is a common preferred channel for both peer and local, use it as operating channel",
oper_freq);
} else {
- p2p_dbg(p2p,
- "No common preferred channels found! Use: %d MHz for oper_channel",
- dev->oper_freq);
+ p2p_dbg(p2p, "No common preferred channels found!");
}
}
@@ -679,6 +646,8 @@
unsigned int freq_list[P2P_MAX_PREF_CHANNELS], size;
unsigned int i;
u8 op_class, op_channel;
+ char txt[100], *pos, *end;
+ int res;
/*
* Use the preferred channel list from the driver only if there is no
@@ -694,6 +663,39 @@
if (p2p->cfg->get_pref_freq_list(p2p->cfg->cb_ctx, go, &size,
freq_list))
return;
+ /* Filter out frequencies that are not acceptable for P2P use */
+ i = 0;
+ while (i < size) {
+ if (p2p_freq_to_channel(freq_list[i], &op_class,
+ &op_channel) < 0 ||
+ (!p2p_channels_includes(&p2p->cfg->channels,
+ op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels,
+ op_class, op_channel)))) {
+ p2p_dbg(p2p,
+ "Ignore local driver frequency preference %u MHz since it is not acceptable for P2P use (go=%d)",
+ freq_list[i], go);
+ if (size - i - 1 > 0)
+ os_memmove(&freq_list[i], &freq_list[i + 1], size - i - 1);
+ size--;
+ continue;
+ }
+
+ /* Preferred frequency is acceptable for P2P use */
+ i++;
+ }
+
+ pos = txt;
+ end = pos + sizeof(txt);
+ for (i = 0; i < size; i++) {
+ res = os_snprintf(pos, end - pos, " %u", freq_list[i]);
+ if (os_snprintf_error(end - pos, res))
+ break;
+ pos += res;
+ }
+ *pos = '\0';
+ p2p_dbg(p2p, "Local driver frequency preference (size=%u):%s",
+ size, txt);
/*
* Check if peer's preference of operating channel is in
@@ -703,20 +705,14 @@
if (freq_list[i] == (unsigned int) dev->oper_freq)
break;
}
- if (i != size) {
+ if (i != size &&
+ p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) == 0) {
/* Peer operating channel preference matches our preference */
- if (p2p_freq_to_channel(freq_list[i], &op_class, &op_channel) <
- 0) {
- p2p_dbg(p2p,
- "Peer operating channel preference is unsupported frequency %u MHz",
- freq_list[i]);
- } else {
- p2p->op_reg_class = op_class;
- p2p->op_channel = op_channel;
- os_memcpy(&p2p->channels, &p2p->cfg->channels,
- sizeof(struct p2p_channels));
- return;
- }
+ p2p->op_reg_class = op_class;
+ p2p->op_channel = op_channel;
+ os_memcpy(&p2p->channels, &p2p->cfg->channels,
+ sizeof(struct p2p_channels));
+ return;
}
p2p_dbg(p2p,
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 47524d4..ce69932 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -553,6 +553,10 @@
unsigned int pref_freq_list[P2P_MAX_PREF_CHANNELS];
unsigned int num_pref_freq;
+
+ /* Override option for preferred operating channel in GO Negotiation */
+ u8 override_pref_op_class;
+ u8 override_pref_channel;
};
/**
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index 1004b32..3f9e53d 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -1559,7 +1559,7 @@
ieee802_1x_cp_connect_authenticated(kay->cp);
ieee802_1x_cp_sm_step(kay->cp);
wpa_printf(MSG_WARNING, "KaY:The Key server advise no MACsec");
- participant->to_use_sak = TRUE;
+ participant->to_use_sak = FALSE;
return 0;
}
@@ -2361,9 +2361,9 @@
&participant->rxsc_list,
struct receive_sc, list) {
if (sci_equal(&rxsc->sci, &peer->sci)) {
- secy_delete_receive_sc(kay, rxsc);
ieee802_1x_kay_deinit_receive_sc(
participant, rxsc);
+ secy_delete_receive_sc(kay, rxsc);
}
}
dl_list_del(&peer->list);
@@ -2378,6 +2378,12 @@
participant->advised_capability =
MACSEC_CAP_NOT_IMPLEMENTED;
participant->to_use_sak = FALSE;
+ participant->ltx = FALSE;
+ participant->lrx = FALSE;
+ participant->otx = FALSE;
+ participant->orx = FALSE;
+ participant->is_key_server = FALSE;
+ participant->is_elected = FALSE;
kay->authenticated = TRUE;
kay->secured = FALSE;
kay->failed = FALSE;
@@ -2422,7 +2428,8 @@
participant->new_sak = FALSE;
}
- if (participant->retry_count < MAX_RETRY_CNT) {
+ if (participant->retry_count < MAX_RETRY_CNT ||
+ participant->mode == PSK) {
ieee802_1x_participant_send_mkpdu(participant);
participant->retry_count++;
}
@@ -2822,7 +2829,7 @@
if (!principal)
return -1;
- if (principal->retry_count < MAX_RETRY_CNT) {
+ if (principal->retry_count < MAX_RETRY_CNT || principal->mode == PSK) {
ieee802_1x_participant_send_mkpdu(principal);
principal->retry_count++;
}
@@ -3362,6 +3369,7 @@
participant->mka_life = MKA_LIFE_TIME / 1000 + time(NULL) +
usecs / 1000000;
}
+ participant->mode = mode;
return participant;
@@ -3424,11 +3432,11 @@
while (!dl_list_empty(&participant->rxsc_list)) {
rxsc = dl_list_entry(participant->rxsc_list.next,
struct receive_sc, list);
- secy_delete_receive_sc(kay, rxsc);
ieee802_1x_kay_deinit_receive_sc(participant, rxsc);
+ secy_delete_receive_sc(kay, rxsc);
}
- secy_delete_transmit_sc(kay, participant->txsc);
ieee802_1x_kay_deinit_transmit_sc(participant, participant->txsc);
+ secy_delete_transmit_sc(kay, participant->txsc);
os_memset(&participant->cak, 0, sizeof(participant->cak));
os_memset(&participant->kek, 0, sizeof(participant->kek));
diff --git a/src/pae/ieee802_1x_kay_i.h b/src/pae/ieee802_1x_kay_i.h
index 0c4bb8e..bc522d8 100644
--- a/src/pae/ieee802_1x_kay_i.h
+++ b/src/pae/ieee802_1x_kay_i.h
@@ -93,6 +93,7 @@
Boolean active;
Boolean participant;
Boolean retain;
+ enum mka_created_mode mode;
enum { DEFAULT, DISABLED, ON_OPER_UP, ALWAYS } activate;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 696ea04..1349873 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -288,7 +288,7 @@
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
int res, pmk_len;
- if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (wpa_key_mgmt_sha384(sm->key_mgmt))
pmk_len = PMK_LEN_SUITE_B_192;
else
pmk_len = PMK_LEN;
@@ -1393,7 +1393,8 @@
int maxkeylen;
struct wpa_eapol_ie_parse ie;
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+ wpa_hexdump_key(MSG_DEBUG, "RSN: msg 1/2 key data",
+ keydata, keydatalen);
if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
return -1;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
@@ -3439,6 +3440,8 @@
sm->fils_nonce, sm->fils_anonce, NULL, 0,
sm->pmk, &sm->pmk_len);
os_memset(rmsk, 0, sizeof(rmsk));
+ if (res)
+ return -1;
if (!sm->fils_erp_pmkid_set) {
wpa_printf(MSG_DEBUG, "FILS: PMKID not available");
@@ -3564,6 +3567,71 @@
}
+static void fils_process_hlp_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
+{
+ const u8 *pos, *end;
+
+ wpa_hexdump(MSG_MSGDUMP, "FILS: HLP response", resp, len);
+ if (len < 2 * ETH_ALEN)
+ return;
+ pos = resp + 2 * ETH_ALEN;
+ end = resp + len;
+ if (end - pos >= 6 &&
+ os_memcmp(pos, "\xaa\xaa\x03\x00\x00\x00", 6) == 0)
+ pos += 6; /* Remove SNAP/LLC header */
+ wpa_sm_fils_hlp_rx(sm, resp, resp + ETH_ALEN, pos, end - pos);
+}
+
+
+static void fils_process_hlp_container(struct wpa_sm *sm, const u8 *pos,
+ size_t len)
+{
+ const u8 *end = pos + len;
+ u8 *tmp, *tmp_pos;
+
+ /* 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_resp(sm, tmp, tmp_pos - tmp);
+ }
+
+ os_free(tmp);
+}
+
+
int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
{
const struct ieee80211_mgmt *mgmt;
@@ -3705,7 +3773,8 @@
/* TK is not needed anymore in supplicant */
os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
- /* TODO: FILS HLP Container */
+ /* FILS HLP Container */
+ fils_process_hlp_container(sm, ie_start, end - ie_start);
/* TODO: FILS IP Address Assignment */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index f0eeec8..bde8c78 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -79,6 +79,8 @@
const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
+ void (*fils_hlp_rx)(void *ctx, const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len);
};
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 491fc98..ab54a18 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -365,6 +365,15 @@
return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
}
+static inline void wpa_sm_fils_hlp_rx(struct wpa_sm *sm,
+ const u8 *dst, const u8 *src,
+ const u8 *pkt, size_t pkt_len)
+{
+ if (sm->ctx->fils_hlp_rx)
+ sm->ctx->fils_hlp_rx(sm->ctx->ctx, dst, src, pkt, pkt_len);
+}
+
+
int wpa_eapol_key_send(struct wpa_sm *sm, struct wpa_ptk *ptk,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index 59ba4d1..062e6fe 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -52,7 +52,7 @@
eloop_terminate();
return;
}
- wpabuf_put_str(resp, "User input completed");
+ wpabuf_put_str(resp, "HTTP/1.1\r\n\r\nUser input completed");
if (done) {
eloop_cancel_timeout(browser_timeout, NULL, NULL);
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 97af16f..04ee6d1 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -45,16 +45,16 @@
/**
* eloop_event_handler - eloop generic event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_event_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_timeout_handler - eloop timeout event callback type
* @eloop_ctx: Registered callback context data (eloop_data)
- * @sock_ctx: Registered callback context data (user_data)
+ * @user_ctx: Registered callback context data (user_data)
*/
-typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+typedef void (*eloop_timeout_handler)(void *eloop_ctx, void *user_ctx);
/**
* eloop_signal_handler - eloop signal event callback type