summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/rsn_supp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/src/rsn_supp')
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.c189
-rw-r--r--contrib/wpa/src/rsn_supp/peerkey.h13
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.c79
-rw-r--r--contrib/wpa/src/rsn_supp/pmksa_cache.h16
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.c54
-rw-r--r--contrib/wpa/src/rsn_supp/preauth.h6
-rw-r--r--contrib/wpa/src/rsn_supp/tdls.c1155
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.c842
-rw-r--r--contrib/wpa/src/rsn_supp/wpa.h83
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ft.c99
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_i.h84
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.c168
-rw-r--r--contrib/wpa/src/rsn_supp/wpa_ie.h16
13 files changed, 2032 insertions, 772 deletions
diff --git a/contrib/wpa/src/rsn_supp/peerkey.c b/contrib/wpa/src/rsn_supp/peerkey.c
index f2bac34..79764d9 100644
--- a/contrib/wpa/src/rsn_supp/peerkey.c
+++ b/contrib/wpa/src/rsn_supp/peerkey.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -65,6 +65,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
{
size_t rlen;
struct wpa_eapol_key *err;
+ struct wpa_eapol_key_192 *err192;
struct rsn_error_kde error;
u8 *rbuf, *pos;
size_t kde_len;
@@ -79,6 +80,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
(void *) &err);
if (rbuf == NULL)
return -1;
+ err192 = (struct wpa_eapol_key_192 *) err;
err->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -112,8 +114,8 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
"(mui %d error_type %d)", mui, error_type);
}
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, err->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+ ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
return 0;
}
@@ -126,6 +128,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
{
size_t rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *pos;
size_t kde_len;
u16 key_info;
@@ -140,6 +143,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
(void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -164,8 +168,8 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
+ ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
return 0;
}
@@ -217,23 +221,17 @@ static int wpa_supplicant_process_smk_m2(
return -1;
}
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- cipher = WPA_CIPHER_TKIP;
- } else {
+ cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+ sm->allowed_pairwise_cipher, 0);
+ if (cipher < 0) {
wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
STK_MUI_SMK, STK_ERR_CPHR_NS,
ver);
return -1;
}
+ wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+ wpa_cipher_txt(cipher));
/* TODO: find existing entry and if found, use that instead of adding
* a new one; how to handle the case where both ends initiate at the
@@ -246,11 +244,7 @@ static int wpa_supplicant_process_smk_m2(
os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peerkey->rsnie_i_len = kde.rsn_ie_len;
peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
- if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = ie.key_mgmt;
if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -294,14 +288,14 @@ static int wpa_supplicant_process_smk_m2(
* @mac_p: Peer MAC address
* @inonce: Initiator Nonce
* @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
*
* 8.5.1.4 Station to station (STK) key hierarchy
* SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
*/
static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
const u8 *inonce, const u8 *mac_i, u8 *smkid,
- int use_sha256)
+ int akmp)
{
char *title = "SMK Name";
const u8 *addr[5];
@@ -316,7 +310,7 @@ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
addr[4] = mac_i;
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
@@ -377,7 +371,7 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
mbuf, mlen, NULL);
}
@@ -432,8 +426,9 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
- ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+ wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+ peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+ msg->key_mic);
}
@@ -496,17 +491,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
peerkey->rsnie_p_len = kde->rsn_ie_len;
os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
- cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
- if (cipher & WPA_CIPHER_CCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_CCMP;
- } else if (cipher & WPA_CIPHER_GCMP) {
- wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
- peerkey->cipher = WPA_CIPHER_GCMP;
- } else if (cipher & WPA_CIPHER_TKIP) {
- wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
- peerkey->cipher = WPA_CIPHER_TKIP;
- } else {
+ cipher = wpa_pick_pairwise_cipher(ie.pairwise_cipher &
+ sm->allowed_pairwise_cipher, 0);
+ if (cipher < 0) {
wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
"unacceptable cipher", MAC2STR(kde->mac_addr));
wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
@@ -515,6 +502,9 @@ static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
/* TODO: abort negotiation */
return -1;
}
+ wpa_printf(MSG_DEBUG, "RSN: Using %s for PeerKey",
+ wpa_cipher_txt(cipher));
+ peerkey->cipher = cipher;
return 0;
}
@@ -527,7 +517,6 @@ static int wpa_supplicant_process_smk_m45(
struct wpa_peerkey *peerkey;
struct wpa_eapol_ie_parse kde;
u32 lifetime;
- struct os_time now;
if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
@@ -579,22 +568,20 @@ static int wpa_supplicant_process_smk_m45(
lifetime = WPA_GET_BE32(kde.lifetime);
wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
if (lifetime > 1000000000)
- lifetime = 1000000000; /* avoid overflowing expiration time */
+ lifetime = 1000000000; /* avoid overflowing eloop time */
peerkey->lifetime = lifetime;
- os_get_time(&now);
- peerkey->expiration = now.sec + lifetime;
eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
sm, peerkey);
if (peerkey->initiator) {
rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
peerkey->inonce, sm->own_addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
wpa_supplicant_send_stk_1_of_4(sm, peerkey);
} else {
rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
peerkey->inonce, peerkey->addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
}
wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
@@ -667,11 +654,11 @@ static int wpa_supplicant_process_smk_error(
static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
- const u8 *kde;
- size_t len, kde_buf_len;
+ size_t kde_buf_len;
struct wpa_ptk *stk;
u8 buf[8], *kde_buf, *pos;
be32 lifetime;
@@ -682,14 +669,13 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
/* RSN: msg 1/4 should contain SMKID for the selected SMK */
- kde = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
- if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 ||
+ ie.pmkid == NULL) {
wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
return;
}
- if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
ie.pmkid, PMKID_LEN);
return;
@@ -709,12 +695,11 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->pnonce, key->key_nonce,
- (u8 *) stk, sizeof(*stk),
- peerkey->use_sha256);
+ stk, peerkey->akmp, peerkey->cipher);
/* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
- os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
- os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+ os_memcpy(buf, &stk->tk[16], 8);
+ os_memcpy(&stk->tk[16], &stk->tk[24], 8);
+ os_memcpy(&stk->tk[24], buf, 8);
peerkey->tstk_set = 1;
kde_buf_len = peerkey->rsnie_p_len +
@@ -747,7 +732,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *kde)
{
u32 lifetime;
- struct os_time now;
if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
return;
@@ -766,8 +750,6 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
lifetime, peerkey->lifetime);
peerkey->lifetime = lifetime;
- os_get_time(&now);
- peerkey->expiration = now.sec + lifetime;
eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
sm, peerkey);
@@ -777,11 +759,10 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len;
wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
@@ -790,16 +771,14 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
* from the peer. It may also include Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 ||
kde.pmkid == NULL || kde.rsn_ie == NULL) {
wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
return;
}
- if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
kde.pmkid, PMKID_LEN);
return;
@@ -826,11 +805,11 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse kde;
- const u8 *keydata;
- size_t len, key_len;
+ size_t key_len;
const u8 *_key;
u8 key_buf[32], rsc[6];
@@ -841,10 +820,8 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
* Lifetime KDE. */
- keydata = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
- if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) {
wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
"STK 3/4");
return;
@@ -875,15 +852,15 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
WPA_GET_BE16(key->key_info),
- NULL, 0, &peerkey->stk))
+ &peerkey->stk))
return;
- _key = (u8 *) peerkey->stk.tk1;
+ _key = peerkey->stk.tk;
if (peerkey->cipher == WPA_CIPHER_TKIP) {
/* Swap Tx/Rx keys for Michael MIC */
os_memcpy(key_buf, _key, 16);
- os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
- os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+ os_memcpy(key_buf + 16, _key + 24, 8);
+ os_memcpy(key_buf + 24, _key + 16, 8);
_key = key_buf;
key_len = 32;
} else
@@ -892,10 +869,12 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
rsc, sizeof(rsc), _key, key_len) < 0) {
+ os_memset(key_buf, 0, sizeof(key_buf));
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
return;
}
+ os_memset(key_buf, 0, sizeof(key_buf));
}
@@ -911,7 +890,7 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+ rsc, sizeof(rsc), peerkey->stk.tk,
peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
@@ -932,27 +911,27 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
*/
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
int ok = 0;
if (peerkey->initiator && !peerkey->stk_set) {
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->inonce, key->key_nonce,
- (u8 *) &peerkey->stk, sizeof(peerkey->stk),
- peerkey->use_sha256);
+ &peerkey->stk, peerkey->akmp, peerkey->cipher);
peerkey->stk_set = 1;
}
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(peerkey->tstk.kck, peerkey->tstk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
} else {
@@ -961,14 +940,15 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
peerkey->stk_set = 1;
os_memcpy(&peerkey->stk, &peerkey->tstk,
sizeof(peerkey->stk));
+ os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
}
}
if (!ok && peerkey->stk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(peerkey->stk.kck, peerkey->stk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -1037,10 +1017,7 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
return -1;
peerkey->initiator = 1;
os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->key_mgmt))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = sm->key_mgmt;
/* SMK M1:
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
@@ -1107,8 +1084,8 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, req->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, req->key_mic);
peerkey->next = sm->peerkey;
sm->peerkey = peerkey;
@@ -1127,28 +1104,32 @@ void peerkey_deinit(struct wpa_sm *sm)
while (peerkey) {
prev = peerkey;
peerkey = peerkey->next;
- os_free(prev);
+ wpa_supplicant_peerkey_free(sm, prev);
}
sm->peerkey = NULL;
}
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver)
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len)
{
if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
(WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
/* 3/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_ACK) {
/* 1/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_SECURE) {
/* 4/4 STK 4-Way Handshake */
wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
} else {
/* 2/4 STK 4-Way Handshake */
- wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
+ wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver,
+ key_data, key_data_len);
}
}
diff --git a/contrib/wpa/src/rsn_supp/peerkey.h b/contrib/wpa/src/rsn_supp/peerkey.h
index b8845f7..6ccd948 100644
--- a/contrib/wpa/src/rsn_supp/peerkey.h
+++ b/contrib/wpa/src/rsn_supp/peerkey.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -24,11 +24,10 @@ struct wpa_peerkey {
int smk_complete;
u8 smkid[PMKID_LEN];
u32 lifetime;
- os_time_t expiration;
int cipher; /* Selected cipher (WPA_CIPHER_*) */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
int replay_counter_set;
- int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+ int akmp;
struct wpa_ptk stk, tstk;
int stk_set, tstk_set;
@@ -39,10 +38,11 @@ struct wpa_peerkey {
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len);
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver);
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len);
void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
struct wpa_eapol_key *key, size_t extra_len,
u16 key_info, u16 ver);
@@ -61,7 +61,8 @@ peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
static inline void
peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 key_info, u16 ver)
+ struct wpa_eapol_key *key, u16 key_info, u16 ver,
+ const u8 *key_data, size_t key_data_len)
{
}
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.c b/contrib/wpa/src/rsn_supp/pmksa_cache.c
index df67583..ef7b683 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.c
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -15,7 +15,7 @@
#include "wpa_i.h"
#include "pmksa_cache.h"
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
static const int pmksa_cache_max_entries = 32;
@@ -35,7 +35,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
- os_free(entry);
+ bin_clear_free(entry, sizeof(*entry));
}
@@ -53,9 +53,9 @@ static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
pmksa->pmksa = entry->next;
@@ -80,13 +80,13 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct rsn_pmksa_cache_entry *entry;
- struct os_time now;
+ struct os_reltime now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
- os_get_time(&now);
+ os_get_reltime(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
@@ -109,6 +109,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @network_ctx: Network configuration context for this PMK
@@ -122,22 +124,31 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
- struct os_time now;
+ struct os_reltime now;
if (pmk_len > PMK_LEN)
return NULL;
+ if (wpa_key_mgmt_suite_b(akmp) && !kck)
+ return NULL;
+
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
- os_get_time(&now);
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+ else if (wpa_key_mgmt_suite_b(akmp))
+ rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
+ else
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+ wpa_key_mgmt_sha256(akmp));
+ os_get_reltime(&now);
entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
@@ -152,9 +163,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
while (pos) {
if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
if (pos->pmk_len == pmk_len &&
- os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
- os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
- 0) {
+ os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 &&
+ os_memcmp_const(pos->pmkid, entry->pmkid,
+ PMKID_LEN) == 0) {
wpa_printf(MSG_DEBUG, "WPA: reusing previous "
"PMKSA entry");
os_free(entry);
@@ -164,17 +175,23 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
pmksa->pmksa = pos->next;
else
prev->next = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
- "the current AP");
- pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
/*
* If OKC is used, there may be other PMKSA cache
* entries based on the same PMK. These needs to be
* flushed so that a new entry can be created based on
- * the new PMK.
+ * the new PMK. Only clear other entries if they have a
+ * matching PMK and this PMK has been used successfully
+ * with the current AP, i.e., if opportunistic flag has
+ * been cleared in wpa_supplicant_key_neg_complete().
*/
- pmksa_cache_flush(pmksa, network_ctx);
+ wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+ "the current AP and any PMKSA cache entry "
+ "that was based on the old PMK");
+ if (!pos->opportunistic)
+ pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+ pos->pmk_len);
+ pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
break;
}
prev = pos;
@@ -235,15 +252,22 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
*/
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len)
{
struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
int removed = 0;
entry = pmksa->pmksa;
while (entry) {
- if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+ if ((entry->network_ctx == network_ctx ||
+ network_ctx == NULL) &&
+ (pmk == NULL ||
+ (pmk_len == entry->pmk_len &&
+ os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
"for " MACSTR, MAC2STR(entry->aa));
if (prev)
@@ -320,6 +344,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *new_entry;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+ NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp);
if (new_entry == NULL)
@@ -453,13 +478,13 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
int i, ret;
char *pos = buf;
struct rsn_pmksa_cache_entry *entry;
- struct os_time now;
+ struct os_reltime now;
- os_get_time(&now);
+ os_get_reltime(&now);
ret = os_snprintf(pos, buf + len - pos,
"Index / AA / PMKID / expiration (in seconds) / "
"opportunistic\n");
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
i = 0;
@@ -468,7 +493,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
i++;
ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
i, MAC2STR(entry->aa));
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
@@ -476,7 +501,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
(int) (entry->expiration - now.sec),
entry->opportunistic);
- if (ret < 0 || ret >= buf + len - pos)
+ if (os_snprintf_error(buf + len - pos, ret))
return pos - buf;
pos += ret;
entry = entry->next;
@@ -509,4 +534,4 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
return pmksa;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/rsn_supp/pmksa_cache.h b/contrib/wpa/src/rsn_supp/pmksa_cache.h
index f318c52..f8e040e 100644
--- a/contrib/wpa/src/rsn_supp/pmksa_cache.h
+++ b/contrib/wpa/src/rsn_supp/pmksa_cache.h
@@ -44,7 +44,7 @@ enum pmksa_free_reason {
PMKSA_EXPIRE,
};
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
@@ -57,6 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -66,13 +67,14 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
struct rsn_pmksa_cache_entry *
pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
void *network_ctx, const u8 *aa);
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+ const u8 *pmk, size_t pmk_len);
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
static inline struct rsn_pmksa_cache *
pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
- void *ctx, int reason),
+ void *ctx, enum pmksa_free_reason reason),
void *ctx, struct wpa_sm *sm)
{
return (void *) -1;
@@ -103,6 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
return NULL;
@@ -121,10 +124,11 @@ static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
}
static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
- void *network_ctx)
+ void *network_ctx,
+ const u8 *pmk, size_t pmk_len)
{
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa/src/rsn_supp/preauth.c b/contrib/wpa/src/rsn_supp/preauth.c
index ab61867..c6534af 100644
--- a/contrib/wpa/src/rsn_supp/preauth.c
+++ b/contrib/wpa/src/rsn_supp/preauth.c
@@ -1,6 +1,6 @@
/*
* RSN pre-authentication (supplicant)
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,7 +18,7 @@
#include "wpa_i.h"
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
#define PMKID_CANDIDATE_PRIO_SCAN 1000
@@ -70,13 +70,14 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
}
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
+ enum eapol_supp_result result,
void *ctx)
{
struct wpa_sm *sm = ctx;
u8 pmk[PMK_LEN];
- if (success) {
+ if (result == EAPOL_SUPP_RESULT_SUCCESS) {
int res, pmk_len;
pmk_len = PMK_LEN;
res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
@@ -93,6 +94,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
pmk, pmk_len);
sm->pmk_len = pmk_len;
pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+ NULL, 0,
sm->preauth_bssid, sm->own_addr,
sm->network_ctx,
WPA_KEY_MGMT_IEEE8021X);
@@ -100,13 +102,14 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: failed to get master session key from "
"pre-auth EAPOL state machines");
- success = 0;
+ result = EAPOL_SUPP_RESULT_FAILURE;
}
}
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
MACSTR " %s", MAC2STR(sm->preauth_bssid),
- success ? "completed successfully" : "failed");
+ result == EAPOL_SUPP_RESULT_SUCCESS ? "completed successfully" :
+ "failed");
rsn_preauth_deinit(sm);
rsn_preauth_candidate_process(sm);
@@ -169,6 +172,7 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
{
struct eapol_config eapol_conf;
struct eapol_ctx *ctx;
+ int ret;
if (sm->preauth_eapol)
return -1;
@@ -194,14 +198,16 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
"packet processing (bridge) for "
"pre-authentication");
- return -2;
+ ret = -2;
+ goto fail;
}
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
- return -4;
+ ret = -4;
+ goto fail;
}
ctx->ctx = sm->ctx->ctx;
ctx->msg_ctx = sm->ctx->ctx;
@@ -219,7 +225,8 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
os_free(ctx);
wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
"state machines for pre-authentication");
- return -3;
+ ret = -3;
+ goto fail;
}
os_memset(&eapol_conf, 0, sizeof(eapol_conf));
eapol_conf.accept_802_1x_keys = 0;
@@ -244,6 +251,15 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
rsn_preauth_timeout, sm, NULL);
return 0;
+
+fail:
+ if (sm->l2_preauth_br) {
+ l2_packet_deinit(sm->l2_preauth_br);
+ sm->l2_preauth_br = NULL;
+ }
+ l2_packet_deinit(sm->l2_preauth);
+ sm->l2_preauth = NULL;
+ return ret;
}
@@ -296,7 +312,9 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
sm->proto != WPA_PROTO_RSN ||
wpa_sm_get_state(sm) != WPA_COMPLETED ||
(sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
@@ -389,6 +407,18 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
dl_list_for_each(pos, &sm->pmksa_candidates,
struct rsn_pmksa_candidate, list) {
if (cand->priority <= pos->priority) {
+ if (!pos->list.prev) {
+ /*
+ * This cannot really happen in pracrice since
+ * pos was fetched from the list and the prev
+ * pointer must be set. It looks like clang
+ * static analyzer gets confused with the
+ * dl_list_del(&cand->list) call above and ends
+ * up assuming pos->list.prev could be NULL.
+ */
+ os_free(cand);
+ return;
+ }
dl_list_add(pos->list.prev, &cand->list);
cand = NULL;
break;
@@ -485,7 +515,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
if (sm->preauth_eapol) {
ret = os_snprintf(pos, end - pos, "Pre-authentication "
"EAPOL state machines:\n");
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
res = eapol_sm_get_status(sm->preauth_eapol,
@@ -508,4 +538,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
return sm->preauth_eapol != NULL;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa/src/rsn_supp/preauth.h b/contrib/wpa/src/rsn_supp/preauth.h
index 27d3112c..277f066 100644
--- a/contrib/wpa/src/rsn_supp/preauth.h
+++ b/contrib/wpa/src/rsn_supp/preauth.h
@@ -11,7 +11,7 @@
struct wpa_scan_results;
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+#ifdef IEEE8021X_EAPOL
void pmksa_candidate_free(struct wpa_sm *sm);
int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
@@ -27,7 +27,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int rsn_preauth_in_progress(struct wpa_sm *sm);
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#else /* IEEE8021X_EAPOL */
static inline void pmksa_candidate_free(struct wpa_sm *sm)
{
@@ -74,6 +74,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
return 0;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+#endif /* IEEE8021X_EAPOL */
#endif /* PREAUTH_H */
diff --git a/contrib/wpa/src/rsn_supp/tdls.c b/contrib/wpa/src/rsn_supp/tdls.c
index 7646ca8..c1d7749 100644
--- a/contrib/wpa/src/rsn_supp/tdls.c
+++ b/contrib/wpa/src/rsn_supp/tdls.c
@@ -33,12 +33,15 @@
#define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8)
#define TDLS_TESTING_DECLINE_RESP BIT(9)
#define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10)
+#define TDLS_TESTING_WRONG_MIC BIT(11)
unsigned int tdls_testing = 0;
#endif /* CONFIG_TDLS_TESTING */
#define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
#define TDLS_MIC_LEN 16
@@ -79,6 +82,10 @@ struct wpa_tdls_frame {
static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer);
+static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr,
+ u16 reason_code);
#define TDLS_MAX_IE_LEN 80
@@ -86,6 +93,7 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
struct wpa_tdls_peer {
struct wpa_tdls_peer *next;
+ unsigned int reconfig_key:1;
int initiator; /* whether this end was initiator for TDLS setup */
u8 addr[ETH_ALEN]; /* other end MAC address */
u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
@@ -104,6 +112,7 @@ struct wpa_tdls_peer {
} tpk;
int tpk_set;
int tpk_success;
+ int tpk_in_progress;
struct tpk_timer {
u8 dest[ETH_ALEN];
@@ -112,6 +121,7 @@ struct wpa_tdls_peer {
u8 action_code; /* TDLS frame type */
u8 dialog_token;
u16 status_code;
+ u32 peer_capab;
int buf_len; /* length of TPK message for retransmission */
u8 *buf; /* buffer for TPK message */
} sm_tmr;
@@ -120,6 +130,27 @@ struct wpa_tdls_peer {
u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
size_t supp_rates_len;
+
+ struct ieee80211_ht_capabilities *ht_capabilities;
+ struct ieee80211_vht_capabilities *vht_capabilities;
+
+ u8 qos_info;
+
+ u16 aid;
+
+ u8 *ext_capab;
+ size_t ext_capab_len;
+
+ u8 *supp_channels;
+ size_t supp_channels_len;
+
+ u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+
+ u8 wmm_capable;
+
+ /* channel switch currently enabled */
+ int chan_switch_enabled;
};
@@ -189,26 +220,30 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len)
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf, size_t len)
{
return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token,
- status_code, buf, len);
+ status_code, peer_capab, initiator, buf,
+ len);
}
static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
- u8 dialog_token, u16 status_code,
- const u8 *msg, size_t msg_len)
+ u8 dialog_token, u16 status_code, u32 peer_capab,
+ int initiator, const u8 *msg, size_t msg_len)
{
struct wpa_tdls_peer *peer;
wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u "
- "dialog_token=%u status_code=%u msg_len=%u",
+ "dialog_token=%u status_code=%u peer_capab=%u initiator=%d "
+ "msg_len=%u",
MAC2STR(dest), action_code, dialog_token, status_code,
- (unsigned int) msg_len);
+ peer_capab, initiator, (unsigned int) msg_len);
if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token,
- status_code, msg, msg_len)) {
+ status_code, peer_capab, initiator, msg,
+ msg_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to send message "
"(action_code=%u)", action_code);
return -1;
@@ -233,14 +268,20 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- peer->sm_tmr.count = TPK_RETRY_COUNT;
- peer->sm_tmr.timer = TPK_TIMEOUT;
+ if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+ peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+ } else {
+ peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+ peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+ }
/* Copy message to resend on timeout */
os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
peer->sm_tmr.action_code = action_code;
peer->sm_tmr.dialog_token = dialog_token;
peer->sm_tmr.status_code = status_code;
+ peer->sm_tmr.peer_capab = peer_capab;
peer->sm_tmr.buf_len = msg_len;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = os_malloc(msg_len);
@@ -250,28 +291,21 @@ static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code,
wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
"(action_code=%u)", action_code);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
return 0;
}
static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
- u16 reason_code, int free_peer)
+ u16 reason_code)
{
int ret;
- if (sm->tdls_external_setup) {
- ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
-
- /* disable the link after teardown was sent */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
- } else {
- ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
- }
-
- if (sm->tdls_external_setup || free_peer)
- wpa_tdls_peer_free(sm, peer);
+ ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+ /* disable the link after teardown was sent */
+ wpa_tdls_disable_peer_link(sm, peer);
return ret;
}
@@ -285,7 +319,6 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
if (peer->sm_tmr.count) {
peer->sm_tmr.count--;
- peer->sm_tmr.timer = TPK_TIMEOUT;
wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
"(action_code=%u)",
@@ -305,6 +338,8 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
peer->sm_tmr.action_code,
peer->sm_tmr.dialog_token,
peer->sm_tmr.status_code,
+ peer->sm_tmr.peer_capab,
+ peer->initiator,
peer->sm_tmr.buf,
peer->sm_tmr.buf_len)) {
wpa_printf(MSG_INFO, "TDLS: Failed to retry "
@@ -312,14 +347,15 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
}
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
- eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+ eloop_register_timeout(peer->sm_tmr.timer / 1000,
+ (peer->sm_tmr.timer % 1000) * 1000,
wpa_tdls_tpk_retry_timeout, sm, peer);
} else {
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
@@ -535,7 +571,7 @@ static int wpa_supplicant_verify_tdls_mic(u8 trans_seq,
wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid,
peer->rsnie_p, timeoutie, (u8 *) ftie,
mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - "
"dropping packet");
wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC",
@@ -562,7 +598,7 @@ static int wpa_supplicant_verify_tdls_mic_teardown(
if (peer->tpk_set) {
wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode,
dtoken, lnkid, (u8 *) ftie, mic);
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - "
"dropping packet");
return -1;
@@ -597,29 +633,78 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
" - tear down", MAC2STR(peer->addr));
wpa_tdls_do_teardown(sm, peer,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
}
-static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ struct wpa_tdls_peer *cur, *prev;
+
+ cur = sm->tdls;
+ prev = NULL;
+ while (cur && cur != peer) {
+ prev = cur;
+ cur = cur->next;
+ }
+
+ if (cur != peer) {
+ wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR
+ " to remove it from the list",
+ MAC2STR(peer->addr));
+ return;
+ }
+
+ if (prev)
+ prev->next = peer->next;
+ else
+ sm->tdls = peer->next;
+}
+
+
+static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
MAC2STR(peer->addr));
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
+ peer->reconfig_key = 0;
peer->initiator = 0;
+ peer->tpk_in_progress = 0;
os_free(peer->sm_tmr.buf);
peer->sm_tmr.buf = NULL;
+ os_free(peer->ht_capabilities);
+ peer->ht_capabilities = NULL;
+ os_free(peer->vht_capabilities);
+ peer->vht_capabilities = NULL;
+ os_free(peer->ext_capab);
+ peer->ext_capab = NULL;
+ os_free(peer->supp_channels);
+ peer->supp_channels = NULL;
+ os_free(peer->supp_oper_classes);
+ peer->supp_oper_classes = NULL;
peer->rsnie_i_len = peer->rsnie_p_len = 0;
peer->cipher = 0;
+ peer->qos_info = 0;
+ peer->wmm_capable = 0;
peer->tpk_set = peer->tpk_success = 0;
+ peer->chan_switch_enabled = 0;
os_memset(&peer->tpk, 0, sizeof(peer->tpk));
os_memset(peer->inonce, 0, WPA_NONCE_LEN);
os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
}
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+ wpa_tdls_peer_clear(sm, peer);
+ wpa_tdls_peer_remove_from_list(sm, peer);
+ os_free(peer);
+}
+
+
static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
struct wpa_tdls_lnkid *lnkid)
{
@@ -636,7 +721,8 @@ static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
}
-int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr,
+ u16 reason_code)
{
struct wpa_tdls_peer *peer;
struct wpa_tdls_ftie *ftie;
@@ -660,6 +746,13 @@ int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
return 0;
}
+ /* Cancel active channel switch before teardown */
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+ " to base channel", MAC2STR(addr));
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+ }
+
dialog_token = peer->dtoken;
wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -715,13 +808,9 @@ skip_ies:
/* request driver to send Teardown using this FTIE */
wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0,
- WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf,
- pos - rbuf);
+ reason_code, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
-
return 0;
}
@@ -750,11 +839,19 @@ int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
return -1;
}
- return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+ return wpa_tdls_do_teardown(sm, peer, reason_code);
+}
+
+
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+ struct wpa_tdls_peer *peer)
+{
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_free(sm, peer);
}
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
@@ -763,13 +860,52 @@ void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
break;
}
- if (peer) {
+ if (!peer || !peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " not connected - cannot teardown unreachable link",
+ MAC2STR(addr));
+ return;
+ }
+
+ if (wpa_tdls_is_external_setup(sm)) {
+ /*
+ * Get us on the base channel, disable the link, send a
+ * teardown packet through the AP, and then reset link data.
+ */
+ if (peer->chan_switch_enabled)
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+ wpa_tdls_send_teardown(sm, addr,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
wpa_tdls_peer_free(sm, peer);
+ } else {
+ wpa_tdls_disable_peer_link(sm, peer);
}
}
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return "disabled";
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL)
+ return "peer does not exist";
+
+ if (!peer->tpk_success)
+ return "peer not connected";
+
+ return "connected";
+}
+
+
static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -803,10 +939,15 @@ static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
" (reason code %u)", MAC2STR(src_addr), reason_code);
ielen = len - (pos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown");
- return -1;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround");
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS "
@@ -839,11 +980,7 @@ skip_ftie:
* Request the driver to disable the direct link and clear associated
* keys.
*/
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-
- /* clear the Peerkey statemachine */
- wpa_tdls_peer_free(sm, peer);
-
+ wpa_tdls_disable_peer_link(sm, peer);
return 0;
}
@@ -853,25 +990,37 @@ skip_ftie:
* appropriate status code mentioning reason for error/failure.
* @dst - MAC addr of Peer station
* @tdls_action - TDLS frame type for which error code is sent
+ * @initiator - was this end the initiator of the connection
* @status - status code mentioning reason
*/
static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst,
- u8 tdls_action, u8 dialog_token, u16 status)
+ u8 tdls_action, u8 dialog_token, int initiator,
+ u16 status)
{
wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR
" (action=%u status=%u)",
MAC2STR(dst), tdls_action, status);
return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status,
- NULL, 0);
+ 0, initiator, NULL, 0);
}
static struct wpa_tdls_peer *
-wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
{
struct wpa_tdls_peer *peer;
+ if (existing)
+ *existing = 0;
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) {
+ if (existing)
+ *existing = 1;
+ return peer; /* re-use existing entry */
+ }
+ }
+
wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
MAC2STR(addr));
@@ -897,6 +1046,7 @@ static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
u8 *rbuf, *pos, *count_pos;
u16 count;
struct rsn_ie_hdr *hdr;
+ int status;
if (!wpa_tdls_get_privacy(sm)) {
wpa_printf(MSG_DEBUG, "TDLS: No security used on the link");
@@ -1057,11 +1207,11 @@ skip_ies:
"Handshake Message 1 (peer " MACSTR ")",
MAC2STR(peer->addr));
- wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST,
+ 1, 0, 0, peer->initiator, rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1075,6 +1225,7 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
u32 lifetime;
struct wpa_tdls_timeoutie timeoutie;
struct wpa_tdls_ftie *ftie;
+ int status;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1138,13 +1289,20 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm,
/* compute MIC before sending */
wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_WRONG_MIC) {
+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC");
+ ftie->mic[0] ^= 0x01;
+ }
+#endif /* CONFIG_TDLS_TESTING */
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
- rbuf, pos - rbuf);
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE,
+ dtoken, 0, 0, peer->initiator, rbuf,
+ pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1158,6 +1316,8 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
struct wpa_tdls_ftie *ftie;
struct wpa_tdls_timeoutie timeoutie;
u32 lifetime;
+ int status;
+ u32 peer_capab = 0;
buf_len = 0;
if (wpa_tdls_get_privacy(sm)) {
@@ -1219,13 +1379,28 @@ static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm,
/* compute MIC before sending */
wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p,
(u8 *) &timeoutie, (u8 *) ftie, ftie->mic);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_WRONG_MIC) {
+ wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC");
+ ftie->mic[0] ^= 0x01;
+ }
+#endif /* CONFIG_TDLS_TESTING */
skip_ies:
- wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0,
- rbuf, pos - rbuf);
+
+ if (peer->vht_capabilities)
+ peer_capab |= TDLS_PEER_VHT;
+ if (peer->ht_capabilities)
+ peer_capab |= TDLS_PEER_HT;
+ if (peer->wmm_capable)
+ peer_capab |= TDLS_PEER_WMM;
+
+ status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM,
+ dtoken, 0, peer_capab, peer->initiator,
+ rbuf, pos - rbuf);
os_free(rbuf);
- return 0;
+ return status;
}
@@ -1233,11 +1408,85 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
struct wpa_tdls_peer *peer,
u8 dialog_token)
{
+ size_t buf_len = 0;
+ struct wpa_tdls_timeoutie timeoutie;
+ u16 rsn_capab;
+ u8 *rbuf, *pos, *count_pos;
+ u16 count;
+ struct rsn_ie_hdr *hdr;
+ int status;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
"(peer " MACSTR ")", MAC2STR(peer->addr));
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_rsn_ies;
+
+ /* Filling RSN IE */
+ hdr = (struct rsn_ie_hdr *) peer->rsnie_i;
+ hdr->elem_id = WLAN_EID_RSN;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+ pos += RSN_SELECTOR_LEN;
+ count_pos = pos;
+ pos += 2;
+ count = 0;
- return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
- dialog_token, 0, NULL, 0);
+ /*
+ * AES-CCMP is the default encryption preferred for TDLS, so
+ * RSN IE is filled only with CCMP cipher suite.
+ * Note: TKIP is not used to encrypt TDLS link.
+ *
+ * Regardless of the cipher used on the AP connection, select CCMP
+ * here.
+ */
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ WPA_PUT_LE16(count_pos, count);
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE);
+ pos += RSN_SELECTOR_LEN;
+
+ rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED;
+ rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2;
+ WPA_PUT_LE16(pos, rsn_capab);
+ pos += 2;
+ hdr->len = (pos - (u8 *) hdr) - 2;
+ peer->rsnie_i_len = pos - peer->rsnie_i;
+
+ wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response",
+ (u8 *) hdr, hdr->len + 2);
+skip_rsn_ies:
+ buf_len = 0;
+ if (wpa_tdls_get_privacy(sm)) {
+ /* Peer RSN IE, Lifetime */
+ buf_len += peer->rsnie_i_len +
+ sizeof(struct wpa_tdls_timeoutie);
+ }
+ rbuf = os_zalloc(buf_len + 1);
+ if (rbuf == NULL) {
+ wpa_tdls_peer_free(sm, peer);
+ return -1;
+ }
+ pos = rbuf;
+
+ if (!wpa_tdls_get_privacy(sm))
+ goto skip_ies;
+ /* Initiator RSN IE */
+ pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len);
+ /* Lifetime */
+ peer->lifetime = TPK_LIFETIME;
+ pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie,
+ sizeof(timeoutie), peer->lifetime);
+ wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime);
+skip_ies:
+ status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+ dialog_token, 0, 0, 0, rbuf, pos - rbuf);
+ os_free(rbuf);
+
+ return status;
}
@@ -1263,10 +1512,17 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+ /*
+ * Some APs will tack on a weird IE to the end of a TDLS
+ * discovery request packet. This needn't fail the response,
+ * since the required IE are verified separately.
+ */
if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
len - (sizeof(struct wpa_tdls_frame) + 1),
- &kde) < 0)
- return -1;
+ &kde) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround");
+ }
if (!kde.lnkid) {
wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
@@ -1282,7 +1538,7 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
return -1;
}
- peer = wpa_tdls_add_peer(sm, addr);
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
if (peer == NULL)
return -1;
@@ -1298,7 +1554,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
MACSTR, MAC2STR(addr));
return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
- 1, 0, NULL, 0);
+ 1, 0, 0, 1, NULL, 0);
}
@@ -1309,25 +1565,189 @@ static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
return -1;
}
+ peer->supp_rates_len = merge_byte_arrays(
+ peer->supp_rates, sizeof(peer->supp_rates),
+ kde->supp_rates + 2, kde->supp_rates_len - 2,
+ kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL,
+ kde->ext_supp_rates_len - 2);
+ return 0;
+}
+
+
+static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ht_capabilities ||
+ kde->ht_capabilities_len <
+ sizeof(struct ieee80211_ht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ht_capabilities) {
+ peer->ht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+ if (peer->ht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->ht_capabilities, kde->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities",
+ (u8 *) peer->ht_capabilities,
+ sizeof(struct ieee80211_ht_capabilities));
+
+ return 0;
+}
+
+
+static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->vht_capabilities ||
+ kde->vht_capabilities_len <
+ sizeof(struct ieee80211_vht_capabilities) ) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->vht_capabilities) {
+ peer->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (peer->vht_capabilities == NULL)
+ return -1;
+ }
+
+ os_memcpy(peer->vht_capabilities, kde->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities",
+ (u8 *) peer->vht_capabilities,
+ sizeof(struct ieee80211_vht_capabilities));
+
+ return 0;
+}
- peer->supp_rates_len = kde->supp_rates_len - 2;
- if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
- peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
- os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
- if (kde->ext_supp_rates) {
- int clen = kde->ext_supp_rates_len - 2;
- if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
- clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
- os_memcpy(peer->supp_rates + peer->supp_rates_len,
- kde->ext_supp_rates + 2, clen);
- peer->supp_rates_len += clen;
+static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->ext_capab) {
+ wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities "
+ "received");
+ return 0;
+ }
+
+ if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) {
+ /* Need to allocate buffer to fit the new information */
+ os_free(peer->ext_capab);
+ peer->ext_capab = os_zalloc(kde->ext_capab_len - 2);
+ if (peer->ext_capab == NULL)
+ return -1;
}
+ peer->ext_capab_len = kde->ext_capab_len - 2;
+ os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len);
+
return 0;
}
+static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ struct wmm_information_element *wmm;
+
+ if (!kde->wmm) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received");
+ return 0;
+ }
+
+ if (kde->wmm_len < sizeof(struct wmm_information_element)) {
+ wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received");
+ return -1;
+ }
+
+ wmm = (struct wmm_information_element *) kde->wmm;
+ peer->qos_info = wmm->qos_info;
+
+ peer->wmm_capable = 1;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info);
+ return 0;
+}
+
+
+static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->supp_channels) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported channels received");
+ return 0;
+ }
+
+ if (!peer->supp_channels ||
+ peer->supp_channels_len < kde->supp_channels_len) {
+ os_free(peer->supp_channels);
+ peer->supp_channels = os_zalloc(kde->supp_channels_len);
+ if (peer->supp_channels == NULL)
+ return -1;
+ }
+
+ peer->supp_channels_len = kde->supp_channels_len;
+
+ os_memcpy(peer->supp_channels, kde->supp_channels,
+ peer->supp_channels_len);
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels",
+ (u8 *) peer->supp_channels, peer->supp_channels_len);
+ return 0;
+}
+
+
+static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde,
+ struct wpa_tdls_peer *peer)
+{
+ if (!kde->supp_oper_classes) {
+ wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received");
+ return 0;
+ }
+
+ if (!peer->supp_oper_classes ||
+ peer->supp_oper_classes_len < kde->supp_oper_classes_len) {
+ os_free(peer->supp_oper_classes);
+ peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len);
+ if (peer->supp_oper_classes == NULL)
+ return -1;
+ }
+
+ peer->supp_oper_classes_len = kde->supp_oper_classes_len;
+ os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes,
+ peer->supp_oper_classes_len);
+ wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes",
+ (u8 *) peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+ return 0;
+}
+
+
+static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+ int add)
+{
+ return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid,
+ peer->capability,
+ peer->supp_rates, peer->supp_rates_len,
+ peer->ht_capabilities,
+ peer->vht_capabilities,
+ peer->qos_info, peer->wmm_capable,
+ peer->ext_capab, peer->ext_capab_len,
+ peer->supp_channels,
+ peer->supp_channels_len,
+ peer->supp_oper_classes,
+ peer->supp_oper_classes_len);
+}
+
+
static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
@@ -1363,17 +1783,44 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
- existing_peer = 1;
- break;
- }
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer);
+ if (peer == NULL)
+ goto error;
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
+ /* If found, use existing entry instead of adding a new one;
+ * how to handle the case where both ends initiate at the
+ * same time? */
+ if (existing_peer) {
+ if (peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
+ "direct link is enabled - tear down the "
+ "old link first");
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ } else if (peer->initiator) {
+ /*
+ * An entry is already present, so check if we already
+ * sent a TDLS Setup Request. If so, compare MAC
+ * addresses and let the STA with the lower MAC address
+ * continue as the initiator. The other negotiation is
+ * terminated.
+ */
+ if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Discard request "
+ "from peer with higher address "
+ MACSTR, MAC2STR(src_addr));
+ return -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "TDLS: Accept request "
+ "from peer with lower address "
+ MACSTR " (terminate previously "
+ "initiated negotiation",
+ MAC2STR(src_addr));
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+ peer->addr);
+ wpa_tdls_peer_clear(sm, peer);
+ }
+ }
}
/* capability information */
@@ -1381,10 +1828,15 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
cpos += 2;
ielen = len - (cpos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1");
- goto error;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround");
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in "
@@ -1396,7 +1848,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
lnkid = (struct wpa_tdls_lnkid *) kde.lnkid;
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS");
- status = WLAN_STATUS_NOT_IN_SAME_BSS;
+ status = WLAN_STATUS_REQUEST_DECLINED;
goto error;
}
@@ -1406,20 +1858,39 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_channels(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
+ /* Overwrite with the qos_info obtained in WMM IE */
+ if (copy_peer_wmm_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->aid = kde.aid;
+
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
- break;
- }
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, src_addr);
- if (peer == NULL)
- goto error;
- }
+ peer = wpa_tdls_add_peer(sm, src_addr, NULL);
+ if (peer == NULL)
+ goto error;
wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
"TDLS setup - send own request");
peer->initiator = 1;
+ wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0);
wpa_tdls_send_tpk_m1(sm, peer);
}
@@ -1502,52 +1973,6 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
}
skip_rsn:
- /* If found, use existing entry instead of adding a new one;
- * how to handle the case where both ends initiate at the
- * same time? */
- if (existing_peer) {
- if (peer->tpk_success) {
- wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
- "direct link is enabled - tear down the "
- "old link first");
-#if 0
- /* TODO: Disabling the link would be more proper
- * operation here, but it seems to trigger a race with
- * some drivers handling the new request frame. */
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
- src_addr);
- else
- wpa_tdls_del_key(sm, peer);
-#endif
- wpa_tdls_peer_free(sm, peer);
- }
-
- /*
- * An entry is already present, so check if we already sent a
- * TDLS Setup Request. If so, compare MAC addresses and let the
- * STA with the lower MAC address continue as the initiator.
- * The other negotiation is terminated.
- */
- if (peer->initiator) {
- if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
- wpa_printf(MSG_DEBUG, "TDLS: Discard request "
- "from peer with higher address "
- MACSTR, MAC2STR(src_addr));
- return -1;
- } else {
- wpa_printf(MSG_DEBUG, "TDLS: Accept request "
- "from peer with lower address "
- MACSTR " (terminate previously "
- "initiated negotiation",
- MAC2STR(src_addr));
- wpa_tdls_peer_free(sm, peer);
- }
- }
- }
-
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
@@ -1572,16 +1997,26 @@ skip_rsn:
}
ftie = (struct wpa_tdls_ftie *) kde.ftie;
- os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peer->rsnie_i_len = kde.rsn_ie_len;
peer->cipher = cipher;
- if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->ctx, MSG_WARNING,
- "TDLS: Failed to get random data for responder nonce");
- wpa_tdls_peer_free(sm, peer);
- goto error;
+ if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
+ /*
+ * There is no point in updating the RNonce for every obtained
+ * TPK M1 frame (e.g., retransmission due to timeout) with the
+ * same INonce (SNonce in FTIE). However, if the TPK M1 is
+ * retransmitted with a different INonce, update the RNonce
+ * since this is for a new TDLS session.
+ */
+ wpa_printf(MSG_DEBUG,
+ "TDLS: New TPK M1 INonce - generate new RNonce");
+ os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+ if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "TDLS: Failed to get random data for responder nonce");
+ goto error;
+ }
}
#if 0
@@ -1634,27 +2069,41 @@ skip_rsn:
wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
skip_rsn_check:
- /* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+#ifdef CONFIG_TDLS_TESTING
+ if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT)
+ goto skip_add_peer;
+#endif /* CONFIG_TDLS_TESTING */
+
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 1) < 0)
+ goto error;
+
+#ifdef CONFIG_TDLS_TESTING
+skip_add_peer:
+#endif /* CONFIG_TDLS_TESTING */
+ peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
goto error;
}
return 0;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0,
status);
+ if (peer)
+ wpa_tdls_peer_free(sm, peer);
return -1;
}
-static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
{
peer->tpk_success = 1;
+ peer->tpk_in_progress = 0;
eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
if (wpa_tdls_get_privacy(sm)) {
u32 lifetime = peer->lifetime;
@@ -1675,11 +2124,14 @@ static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
#endif /* CONFIG_TDLS_TESTING */
}
- /* add supported rates and capabilities to the TDLS peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
- peer->supp_rates, peer->supp_rates_len);
+ if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
+ wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
+ "driver");
+ return -1;
+ }
+ peer->reconfig_key = 0;
- wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
+ return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
}
@@ -1698,6 +2150,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
int ielen;
u16 status;
const u8 *pos;
+ int ret = 0;
wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 "
"(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1710,10 +2163,23 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
"TPK M2: " MACSTR, MAC2STR(src_addr));
return -1;
}
+ if (!peer->initiator) {
+ /*
+ * This may happen if both devices try to initiate TDLS at the
+ * same time and we accept the TPK M1 from the peer in
+ * wpa_tdls_process_tpk_m1() and clear our previous state.
+ */
+ wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so "
+ "ignore TPK M2 from " MACSTR, MAC2STR(src_addr));
+ return -1;
+ }
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
- if (len < 3 + 2 + 1)
+ if (len < 3 + 2 + 1) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
+
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
status = WPA_GET_LE16(pos);
@@ -1722,8 +2188,7 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (status != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1734,18 +2199,25 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
- if (len < 3 + 2 + 1 + 2)
+ if (len < 3 + 2 + 1 + 2) {
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
+ }
/* capability information */
peer->capability = WPA_GET_LE16(pos);
pos += 2;
ielen = len - (pos - buf); /* start of IE in buf */
- if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2");
- goto error;
- }
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs may add arbitrary padding to the
+ * end of short TDLS frames and that would look like invalid IEs.
+ */
+ if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0)
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround");
#ifdef CONFIG_TDLS_TESTING
if (tdls_testing & TDLS_TESTING_DECLINE_RESP) {
@@ -1773,6 +2245,29 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
if (copy_supp_rates(&kde, peer) < 0)
goto error;
+ if (copy_peer_ht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_vht_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_ext_capab(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_channels(&kde, peer) < 0)
+ goto error;
+
+ if (copy_peer_supp_oper_classes(&kde, peer) < 0)
+ goto error;
+
+ peer->qos_info = kde.qosinfo;
+
+ /* Overwrite with the qos_info obtained in WMM IE */
+ if (copy_peer_wmm_capab(&kde, peer) < 0)
+ goto error;
+
+ peer->aid = kde.aid;
+
if (!wpa_tdls_get_privacy(sm)) {
peer->rsnie_p_len = 0;
peer->cipher = WPA_CIPHER_NONE;
@@ -1788,6 +2283,13 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2",
kde.rsn_ie, kde.rsn_ie_len);
+ if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) {
+ wpa_printf(MSG_INFO,
+ "TDLS: Too long Responder RSN IE in TPK M2");
+ status = WLAN_STATUS_INVALID_RSNIE;
+ goto error;
+ }
+
/*
* FIX: bitwise comparison of RSN IE is not the correct way of
* validation this. It can be different, but certain fields must
@@ -1863,30 +2365,52 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr,
(u8 *) timeoutie, ftie) < 0) {
/* Discard the frame */
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
- wpa_tdls_set_key(sm, peer);
+ if (wpa_tdls_set_key(sm, peer) < 0) {
+ /*
+ * Some drivers may not be able to config the key prior to full
+ * STA entry having been configured.
+ */
+ wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+ "STA entry is complete");
+ peer->reconfig_key = 1;
+ }
skip_rsn:
peer->dtoken = dtoken;
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
+
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
"TPK Handshake Message 3");
- wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer);
-
- wpa_tdls_enable_link(sm, peer);
+ if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
+ goto error;
- return 0;
+ if (!peer->tpk_success) {
+ /*
+ * Enable Link only when tpk_success is 0, signifying that this
+ * processing of TPK M2 frame is not because of a retransmission
+ * during TDLS setup handshake.
+ */
+ ret = wpa_tdls_enable_link(sm, peer);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+ wpa_tdls_do_teardown(
+ sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ }
+ }
+ return ret;
error:
- wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
+ wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1,
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -1903,6 +2427,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
u16 status;
const u8 *pos;
u32 lifetime;
+ int ret = 0;
wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 "
"(Peer " MACSTR ")", MAC2STR(src_addr));
@@ -1918,7 +2443,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
if (len < 3 + 3)
- return -1;
+ goto error;
pos = buf;
pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
@@ -1927,21 +2452,26 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (status != 0) {
wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
status);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
pos += 2 /* status code */ + 1 /* dialog token */;
ielen = len - (pos - buf); /* start of IE in buf */
+
+ /*
+ * Don't reject the message if failing to parse IEs. The IEs we need are
+ * explicitly checked below. Some APs piggy-back broken IEs to the end
+ * of a TDLS Confirm packet, which will fail the link if we don't ignore
+ * this error.
+ */
if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
- wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
- return -1;
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround");
}
if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
(u8 *) kde.lnkid, kde.lnkid_len);
@@ -1949,7 +2479,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
- return -1;
+ goto error;
}
if (!wpa_tdls_get_privacy(sm))
@@ -1957,7 +2487,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
kde.ftie, sizeof(*ftie));
@@ -1965,7 +2495,7 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (kde.rsn_ie == NULL) {
wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
- return -1;
+ goto error;
}
wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
kde.rsn_ie, kde.rsn_ie_len);
@@ -1973,24 +2503,24 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
"with the one sent in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
"not match with FTIE ANonce used in TPK M2");
- return -1;
+ goto error;
}
if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
"match with FTIE SNonce used in TPK M1");
- return -1;
+ goto error;
}
if (kde.key_lifetime == NULL) {
wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
- return -1;
+ goto error;
}
timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
@@ -2001,25 +2531,46 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr,
if (lifetime != peer->lifetime) {
wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
"TPK M3 (expected %u)", lifetime, peer->lifetime);
- if (sm->tdls_external_setup)
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
- return -1;
+ goto error;
}
if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
(u8 *) timeoutie, ftie) < 0) {
wpa_tdls_del_key(sm, peer);
- wpa_tdls_peer_free(sm, peer);
- return -1;
+ goto error;
}
- if (wpa_tdls_set_key(sm, peer) < 0)
- return -1;
+ if (wpa_tdls_set_key(sm, peer) < 0) {
+ /*
+ * Some drivers may not be able to config the key prior to full
+ * STA entry having been configured.
+ */
+ wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after "
+ "STA entry is complete");
+ peer->reconfig_key = 1;
+ }
skip_rsn:
- wpa_tdls_enable_link(sm, peer);
+ /* add supported rates, capabilities, and qos_info to the TDLS peer */
+ if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+ goto error;
- return 0;
+ if (!peer->tpk_success) {
+ /*
+ * Enable Link only when tpk_success is 0, signifying that this
+ * processing of TPK M3 frame is not because of a retransmission
+ * during TDLS setup handshake.
+ */
+ ret = wpa_tdls_enable_link(sm, peer);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
+ goto error;
+ }
+ }
+ return ret;
+error:
+ wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+ return -1;
}
@@ -2069,26 +2620,28 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
return -1;
}
- /* Find existing entry and if found, use that instead of adding
- * a new one */
- for (peer = sm->tdls; peer; peer = peer->next) {
- if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
- break;
- }
+ peer = wpa_tdls_add_peer(sm, addr, NULL);
+ if (peer == NULL)
+ return -1;
- if (peer == NULL) {
- peer = wpa_tdls_add_peer(sm, addr);
- if (peer == NULL)
- return -1;
+ if (peer->tpk_in_progress) {
+ wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer");
+ return 0;
}
peer->initiator = 1;
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) {
+ wpa_tdls_disable_peer_link(sm, peer);
+ return -1;
+ }
+
+ peer->tpk_in_progress = 1;
if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
- wpa_tdls_disable_link(sm, peer->addr);
+ wpa_tdls_disable_peer_link(sm, peer);
return -1;
}
@@ -2096,12 +2649,12 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr)
}
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
if (sm->tdls_disabled || !sm->tdls_supported)
- return -1;
+ return;
for (peer = sm->tdls; peer; peer = peer->next) {
if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
@@ -2109,17 +2662,16 @@ int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr)
}
if (peer == NULL || !peer->tpk_success)
- return -1;
+ return;
if (sm->tdls_external_setup) {
/*
* Disable previous link to allow renegotiation to be completed
* on AP path.
*/
- wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
}
-
- return wpa_tdls_start(sm, addr);
}
@@ -2218,7 +2770,8 @@ int wpa_tdls_init(struct wpa_sm *sm)
* are assumed to perform everything internally
*/
if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
- &sm->tdls_external_setup) < 0) {
+ &sm->tdls_external_setup,
+ &sm->tdls_chan_switch) < 0) {
sm->tdls_supported = 1;
sm->tdls_external_setup = 0;
}
@@ -2227,17 +2780,43 @@ int wpa_tdls_init(struct wpa_sm *sm)
"driver", sm->tdls_supported ? "" : " not");
wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
sm->tdls_external_setup ? "external" : "internal");
+ wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching",
+ sm->tdls_chan_switch ? "supports" : "does not support");
return 0;
}
+void wpa_tdls_teardown_peers(struct wpa_sm *sm)
+{
+ struct wpa_tdls_peer *peer, *tmp;
+
+ if (!sm)
+ return;
+ peer = sm->tdls;
+
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
+
+ while (peer) {
+ tmp = peer->next;
+ wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
+ MAC2STR(peer->addr));
+ if (sm->tdls_external_setup)
+ wpa_tdls_do_teardown(sm, peer,
+ WLAN_REASON_DEAUTH_LEAVING);
+ else
+ wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+
+ peer = tmp;
+ }
+}
+
+
static void wpa_tdls_remove_peers(struct wpa_sm *sm)
{
struct wpa_tdls_peer *peer, *tmp;
peer = sm->tdls;
- sm->tdls = NULL;
while (peer) {
int res;
@@ -2246,7 +2825,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm)
wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
MAC2STR(peer->addr), res);
wpa_tdls_peer_free(sm, peer);
- os_free(peer);
peer = tmp;
}
}
@@ -2285,39 +2863,61 @@ void wpa_tdls_disassoc(struct wpa_sm *sm)
}
-static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems)
{
- struct wpa_eapol_ie_parse elems;
-
- if (ies == NULL)
- return 0;
+ /* bit 38 - TDLS Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x40);
+}
- if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
- return 0;
- if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
- return 0;
-
- /* bit 38 - TDLS Prohibited */
- return !!(elems.ext_capab[2 + 4] & 0x40);
+static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems)
+{
+ /* bit 39 - TDLS Channel Switch Prohibited */
+ return !!(elems->ext_capab[2 + 4] & 0x80);
}
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+ struct wpa_eapol_ie_parse elems;
+
+ sm->tdls_prohibited = 0;
+ sm->tdls_chan_switch_prohibited = 0;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
sm->tdls_prohibited ? "prohibited" : "allowed");
+ sm->tdls_chan_switch_prohibited =
+ wpa_tdls_chan_switch_prohibited(&elems);
+ wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS",
+ sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed");
}
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
{
- if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+ struct wpa_eapol_ie_parse elems;
+
+ if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+ elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+ return;
+
+ if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
"(Re)Association Response IEs");
sm->tdls_prohibited = 1;
}
+
+ if (!sm->tdls_chan_switch_prohibited &&
+ wpa_tdls_chan_switch_prohibited(&elems)) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs");
+ sm->tdls_chan_switch_prohibited = 1;
+ }
}
@@ -2332,3 +2932,78 @@ int wpa_tdls_is_external_setup(struct wpa_sm *sm)
{
return sm->tdls_external_setup;
}
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params)
+{
+ struct wpa_tdls_peer *peer;
+ int ret;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ if (!sm->tdls_chan_switch) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching not supported by the driver");
+ return -1;
+ }
+
+ if (sm->tdls_chan_switch_prohibited) {
+ wpa_printf(MSG_DEBUG,
+ "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+ return -1;
+ }
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (peer == NULL || !peer->tpk_success) {
+ wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+ " not found for channel switching", MAC2STR(addr));
+ return -1;
+ }
+
+ if (peer->chan_switch_enabled) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " already has channel switching enabled",
+ MAC2STR(addr));
+ return 0;
+ }
+
+ ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+ oper_class, freq_params);
+ if (!ret)
+ peer->chan_switch_enabled = 1;
+
+ return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ struct wpa_tdls_peer *peer;
+
+ if (sm->tdls_disabled || !sm->tdls_supported)
+ return -1;
+
+ for (peer = sm->tdls; peer; peer = peer->next) {
+ if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peer || !peer->chan_switch_enabled) {
+ wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+ MACSTR, MAC2STR(addr));
+ return -1;
+ }
+
+ /* ignore the return value */
+ wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+ peer->chan_switch_enabled = 0;
+ return 0;
+}
diff --git a/contrib/wpa/src/rsn_supp/wpa.c b/contrib/wpa/src/rsn_supp/wpa.c
index 9283aa79..127e246 100644
--- a/contrib/wpa/src/rsn_supp/wpa.c
+++ b/contrib/wpa/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,7 @@
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @kck: Key Confirmation Key (KCK, part of PTK)
+ * @kck_len: KCK length in octets
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
@@ -34,10 +35,12 @@
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
+
if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
/*
* Association event was not yet received; try to fetch
@@ -56,14 +59,15 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+ wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
+ key_mic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key "
- "version %d MIC", ver);
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
goto out;
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -84,12 +88,17 @@ out:
*/
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic;
- if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt))
+ ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
+ else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
+ wpa_key_mgmt_sha256(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -102,12 +111,16 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
return;
}
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (sm->ptk_set)
@@ -122,15 +135,39 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
+ if (!(key_info & WPA_KEY_INFO_MIC))
+ key_mic = NULL;
+ else
+ key_mic = reply192->key_mic; /* same offset in reply */
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
- reply->key_mic : NULL);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
+}
+
+
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set low order 256 bits of MSK for key management offload");
+ } else {
+#endif /* CONFIG_IEEE80211R */
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+ }
+#endif /* CONFIG_IEEE80211R */
}
@@ -158,7 +195,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (pmkid && sm->cur_pmksa &&
- os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -194,10 +231,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
+ wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
sm->pmk, pmk_len,
+ NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
@@ -231,7 +271,9 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
- !wpa_key_mgmt_ft(sm->key_mgmt)) {
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
+ {
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
@@ -273,9 +315,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
if (wpa_ie == NULL) {
@@ -317,19 +360,23 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + wpa_ie_len,
+ NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
return -1;
}
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
WPA_PUT_BE16(reply->key_info,
ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -338,47 +385,52 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24) {
+ WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
+ os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
+ } else {
+ WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+ os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ }
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
- return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+ return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
- sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->key_mgmt));
- return 0;
+ return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+ sm->own_addr, sm->bssid, sm->snonce,
+ key->key_nonce, ptk, sm->key_mgmt,
+ sm->pairwise_cipher);
}
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
struct wpa_ptk *ptk;
- u8 buf[8];
int res;
+ u8 *kde, *kde_buf = NULL;
+ size_t kde_len;
if (wpa_sm_get_network_ctx(sm) == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
@@ -392,20 +444,17 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
-#ifndef CONFIG_NO_WPA2
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
- const u8 *_buf = (const u8 *) (key + 1);
- size_t len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
- if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
+ key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", ie.pmkid, PMKID_LEN);
}
}
-#endif /* CONFIG_NO_WPA2 */
res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
if (res == -2) {
@@ -431,21 +480,49 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
* been verified when processing message 3/4. */
ptk = &sm->tptk;
wpa_derive_ptk(sm, src_addr, key, ptk);
- /* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
- os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
- os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+ if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
+ u8 buf[8];
+ /* Supplicant: swap tx/rx Mic keys */
+ os_memcpy(buf, &ptk->tk[16], 8);
+ os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
+ os_memcpy(&ptk->tk[24], buf, 8);
+ os_memset(buf, 0, sizeof(buf));
+ }
sm->tptk_set = 1;
+ kde = sm->assoc_wpa_ie;
+ kde_len = sm->assoc_wpa_ie_len;
+
+#ifdef CONFIG_P2P
+ if (sm->p2p) {
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
+ if (kde_buf) {
+ u8 *pos;
+ wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
+ "into EAPOL-Key 2/4");
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
+ }
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
- sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
- ptk))
+ kde, kde_len, ptk))
goto failed;
+ os_free(kde_buf);
os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
return;
failed:
+ os_free(kde_buf);
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -537,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
@@ -545,7 +622,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
}
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sm->ptk.tk, keylen) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set PTK to the "
"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -553,6 +630,9 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
return -1;
}
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -625,6 +705,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
@@ -634,8 +715,10 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
gd->alg, gd->gtk_len, gd->keyidx);
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return 0;
}
@@ -664,7 +747,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
const u8 *gtk, size_t gtk_len,
int key_info)
{
-#ifndef CONFIG_NO_WPA2
struct wpa_gtk_data gd;
/*
@@ -691,21 +773,21 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gtk_len, gtk_len,
- &gd.key_rsc_len, &gd.alg) ||
- wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
+ if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+ (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, gtk_len,
+ &gd.key_rsc_len, &gd.alg) ||
+ wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Failed to install GTK");
+ os_memset(&gd, 0, sizeof(gd));
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info & WPA_KEY_INFO_SECURE);
return 0;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -713,13 +795,15 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
#ifdef CONFIG_IEEE80211W
- if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+ if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
+ size_t len;
const struct wpa_igtk_kde *igtk;
u16 keyidx;
- if (ie->igtk_len != sizeof(*igtk))
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len)
return -1;
igtk = (const struct wpa_igtk_kde *) ie->igtk;
keyidx = WPA_GET_LE16(igtk->keyid);
@@ -727,15 +811,16 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
"pn %02x%02x%02x%02x%02x%02x",
keyidx, MAC2STR(igtk->pn));
wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
- igtk->igtk, WPA_IGTK_LEN);
+ igtk->igtk, len);
if (keyidx > 4095) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KeyID %d", keyidx);
return -1;
}
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
keyidx, 0, igtk->pn, sizeof(igtk->pn),
- igtk->igtk, WPA_IGTK_LEN) < 0) {
+ igtk->igtk, len) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to configure IGTK to the driver");
return -1;
@@ -868,7 +953,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
return -1;
}
- if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+ {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"FT: PMKR1Name mismatch in "
"FT 4-way handshake message 3/4");
@@ -988,49 +1074,49 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
* @key: Pointer to the EAPOL-Key frame header
* @ver: Version bits from EAPOL-Key Key Info
* @key_info: Key Info
- * @kde: KDEs to include the EAPOL-Key frame
- * @kde_len: Length of KDEs
* @ptk: PTK to use for keyed hash and encryption
* Returns: 0 on success, -1 on failure
*/
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
u16 ver, u16 key_info,
- const u8 *kde, size_t kde_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
-
- if (kde)
- wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply) + kde_len,
- &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, kde_len);
- if (kde)
- os_memcpy(reply + 1, kde, kde_len);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
@@ -1038,10 +1124,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
- u16 key_info, keylen, len;
- const u8 *pos;
+ u16 key_info, keylen;
struct wpa_eapol_ie_parse ie;
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
@@ -1050,10 +1136,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
key_info = WPA_GET_BE16(key->key_info);
- pos = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1067,7 +1151,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
- if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+ if (ie.igtk &&
+ wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) &&
+ ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN +
+ (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid IGTK KDE length %lu",
(unsigned long) ie.igtk_len);
@@ -1095,8 +1182,16 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+#ifdef CONFIG_P2P
+ if (ie.ip_addr_alloc) {
+ os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4);
+ wpa_hexdump(MSG_DEBUG, "P2P: IP address info",
+ sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr));
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
- NULL, 0, &sm->ptk)) {
+ &sm->ptk)) {
goto failed;
}
@@ -1118,7 +1213,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
- if (ie.gtk &&
+ if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
+ key_info & WPA_KEY_INFO_SECURE);
+ } else if (ie.gtk &&
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1132,8 +1230,21 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
- wpa_sm_set_rekey_offload(sm);
+ if (ie.gtk)
+ wpa_sm_set_rekey_offload(sm);
+
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ struct rsn_pmksa_cache_entry *sa;
+
+ sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+ sm->msg_3_of_4_ok = 1;
return;
failed:
@@ -1193,22 +1304,15 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- size_t keydatalen, int key_info,
- size_t extra_len, u16 ver,
- struct wpa_gtk_data *gd)
+ const u8 *key_data,
+ size_t key_data_len, u16 key_info,
+ u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
- u8 ek[32];
+ u16 gtk_len;
- gd->gtk_len = WPA_GET_BE16(key->key_length);
- maxkeylen = keydatalen;
- if (keydatalen > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "WPA: Truncated EAPOL-Key packet: "
- "key_data_length=%lu > extra_len=%lu",
- (unsigned long) keydatalen, (unsigned long) extra_len);
- return -1;
- }
+ gtk_len = WPA_GET_BE16(key->key_length);
+ maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1219,45 +1323,50 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
maxkeylen -= 8;
}
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ if (gtk_len > maxkeylen ||
+ wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
+ gd->gtk_len = gtk_len;
gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
WPA_KEY_INFO_KEY_INDEX_SHIFT;
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
- os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (keydatalen > sizeof(gd->gtk)) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
+ u8 ek[32];
+ if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: RC4 key data too long (%lu)",
- (unsigned long) keydatalen);
+ (unsigned long) key_data_len);
return -1;
}
- os_memcpy(gd->gtk, key + 1, keydatalen);
- if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ os_memcpy(gd->gtk, key_data, key_data_len);
+ if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
+ os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
+ os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- if (keydatalen % 8) {
+ if (maxkeylen % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported AES-WRAP len %lu",
- (unsigned long) keydatalen);
+ (unsigned long) maxkeylen);
return -1;
}
if (maxkeylen > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES-WRAP key data "
"too long (keydatalen=%lu maxkeylen=%lu)",
- (unsigned long) keydatalen,
+ (unsigned long) key_data_len,
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
- (const u8 *) (key + 1), gd->gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, maxkeylen / 8,
+ key_data, gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1278,32 +1387,41 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
int ver, u16 key_info)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
return 0;
}
@@ -1312,12 +1430,19 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ const u8 *key_data,
+ size_t key_data_len, u16 ver)
{
- u16 key_info, keydatalen;
+ u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
+ if (!sm->msg_3_of_4_ok) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Group Key Handshake started prior to completion of 4-way handshake");
+ goto failed;
+ }
+
os_memset(&gd, 0, sizeof(gd));
rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
@@ -1325,17 +1450,15 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
key_info = WPA_GET_BE16(key->key_info);
- keydatalen = WPA_GET_BE16(key->key_data_length);
- if (sm->proto == WPA_PROTO_RSN) {
- ret = wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
+ ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data,
+ key_data_len, key_info,
&gd);
} else {
- ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
- key_info, extra_len,
- ver, &gd);
+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data,
+ key_data_len,
+ key_info, ver, &gd);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1346,6 +1469,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
goto failed;
+ os_memset(&gd, 0, sizeof(gd));
if (rekey) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Group rekeying "
@@ -1353,34 +1477,37 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
-
- wpa_sm_set_rekey_offload(sm);
} else {
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
WPA_KEY_INFO_SECURE);
}
+
+ wpa_sm_set_rekey_offload(sm);
+
return;
failed:
+ os_memset(&gd, 0, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key *key,
+ struct wpa_eapol_key_192 *key,
u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
int ok = 0;
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1389,14 +1516,15 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
sm->tptk_set = 0;
sm->ptk_set = 1;
os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
}
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1421,12 +1549,11 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver)
+ struct wpa_eapol_key *key, u16 ver,
+ u8 *key_data, size_t *key_data_len)
{
- u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
if (!sm->ptk_set) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
@@ -1436,49 +1563,53 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
/* Decrypt key data here so that this operation does not need
* to be implemented separately for each message type. */
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
+ os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
return -1;
}
+ os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
+ sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt)) {
u8 *buf;
- if (keydatalen % 8) {
+ if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Unsupported AES-WRAP len %d",
- keydatalen);
+ "WPA: Unsupported AES-WRAP len %u",
+ (unsigned int) *key_data_len);
return -1;
}
- keydatalen -= 8; /* AES-WRAP adds 8 bytes */
- buf = os_malloc(keydatalen);
+ *key_data_len -= 8; /* AES-WRAP adds 8 bytes */
+ buf = os_malloc(*key_data_len);
if (buf == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
- (u8 *) (key + 1), buf)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, *key_data_len / 8,
+ key_data, buf)) {
os_free(buf);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
- os_memcpy(key + 1, buf, keydatalen);
+ os_memcpy(key_data, buf, *key_data_len);
os_free(buf);
- WPA_PUT_BE16(key->key_data_length, keydatalen);
+ WPA_PUT_BE16(key->key_data_length, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
return 0;
}
@@ -1498,7 +1629,9 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm)
static void wpa_eapol_key_dump(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ unsigned int key_data_len,
+ const u8 *mic, unsigned int mic_len)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
u16 key_info = WPA_GET_BE16(key->key_info);
@@ -1520,15 +1653,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
" key_length=%u key_data_length=%u",
- WPA_GET_BE16(key->key_length),
- WPA_GET_BE16(key->key_data_length));
+ WPA_GET_BE16(key->key_length), key_data_len);
wpa_hexdump(MSG_DEBUG, " replay_counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16);
wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8);
wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8);
- wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);
+ wpa_hexdump(MSG_DEBUG, " key_mic", mic, mic_len);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -1552,34 +1684,34 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
- size_t plen, data_len, extra_len;
- struct ieee802_1x_hdr *hdr;
+ size_t plen, data_len, key_data_len;
+ const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info, ver;
- u8 *tmp;
+ u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
+ u8 *key_data;
+ size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- if (len < sizeof(*hdr) + sizeof(*key)) {
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame too short to be a WPA "
"EAPOL-Key (len %lu, expecting at least %lu)",
(unsigned long) len,
- (unsigned long) sizeof(*hdr) + sizeof(*key));
+ (unsigned long) sizeof(*hdr) + keyhdrlen);
return 0;
}
- tmp = os_malloc(len);
- if (tmp == NULL)
- return -1;
- os_memcpy(tmp, buf, len);
-
- hdr = (struct ieee802_1x_hdr *) tmp;
- key = (struct wpa_eapol_key *) (hdr + 1);
+ hdr = (const struct ieee802_1x_hdr *) buf;
plen = be_to_host16(hdr->length);
data_len = plen + sizeof(*hdr);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1596,7 +1728,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
+ if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
"invalid (frame size %lu)",
@@ -1604,6 +1737,27 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ if (data_len < len) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+ (unsigned long) len - data_len);
+ }
+
+ /*
+ * Make a copy of the frame since we need to modify the buffer during
+ * MAC validation and Key Data decryption.
+ */
+ tmp = os_malloc(data_len);
+ if (tmp == NULL)
+ goto out;
+ os_memcpy(tmp, buf, data_len);
+ key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
+ key192 = (struct wpa_eapol_key_192 *)
+ (tmp + sizeof(struct ieee802_1x_hdr));
+ if (mic_len == 24)
+ key_data = (u8 *) (key192 + 1);
+ else
+ key_data = (u8 *) (key + 1);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1613,28 +1767,53 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- wpa_eapol_key_dump(sm, key);
- eapol_sm_notify_lower_layer_success(sm->eapol, 0);
- wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
- if (data_len < len) {
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: ignoring %lu bytes after the IEEE 802.1X data",
- (unsigned long) len - data_len);
+ if (mic_len == 24)
+ key_data_len = WPA_GET_BE16(key192->key_data_length);
+ else
+ key_data_len = WPA_GET_BE16(key->key_data_length);
+ wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+
+ if (key_data_len > plen - keyhdrlen) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+ "frame - key_data overflow (%u > %u)",
+ (unsigned int) key_data_len,
+ (unsigned int) (plen - keyhdrlen));
+ goto out;
}
+
+ eapol_sm_notify_lower_layer_success(sm->eapol, 0);
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "OSEN: Unsupported EAPOL-Key descriptor version %d",
+ ver);
+ goto out;
+ }
+
+ if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
+ ver);
+ goto out;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
@@ -1647,7 +1826,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
- if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -1656,6 +1837,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -1669,11 +1851,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Backwards compatibility: allow invalid "
"version for non-CCMP group keys");
+ } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
} else
goto out;
- }
- if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2", ver);
@@ -1743,31 +1928,21 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+ wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
goto out;
#ifdef CONFIG_PEERKEY
if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+ peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+ data_len))
goto out;
#endif /* CONFIG_PEERKEY */
- extra_len = data_len - sizeof(*hdr) - sizeof(*key);
-
- if (WPA_GET_BE16(key->key_data_length) > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
- "frame - key_data overflow (%d > %lu)",
- WPA_GET_BE16(key->key_data_length),
- (unsigned long) extra_len);
- goto out;
- }
- extra_len = WPA_GET_BE16(key->key_data_length);
-
- if (sm->proto == WPA_PROTO_RSN &&
+ if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+ if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ &key_data_len))
goto out;
- extra_len = WPA_GET_BE16(key->key_data_length);
}
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
@@ -1779,24 +1954,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if (peerkey) {
/* PeerKey 4-Way Handshake */
- peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+ peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, key, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+ key_data_len);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
- ver);
+ ver, key_data,
+ key_data_len);
}
} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
/* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
ver);
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
- extra_len, ver);
+ key_data, key_data_len,
+ ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic bit - "
@@ -1807,7 +1986,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
@@ -1817,7 +1996,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return (sm->proto == WPA_PROTO_RSN ?
+ return ((sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK:
@@ -1842,6 +2022,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
default:
return 0;
}
@@ -1899,7 +2083,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1926,7 +2110,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
- if (ret >= 0 && (size_t) ret < buflen)
+ if (!os_snprintf_error(buflen - len, ret))
len += ret;
return (int) len;
@@ -2024,6 +2208,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->assoc_wpa_ie);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ wpa_sm_drop_sa(sm);
os_free(sm->ctx);
peerkey_deinit(sm);
#ifdef CONFIG_IEEE80211R
@@ -2080,12 +2265,18 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
sm->ptk_set = 0;
+ os_memset(&sm->ptk, 0, sizeof(sm->ptk));
sm->tptk_set = 0;
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
}
#ifdef CONFIG_TDLS
wpa_tdls_assoc(sm);
#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_P2P
+ os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
+#endif /* CONFIG_P2P */
}
@@ -2098,6 +2289,9 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
+ eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+ eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+ peerkey_deinit(sm);
rsn_preauth_deinit(sm);
pmksa_cache_clear_current(sm);
if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
@@ -2105,6 +2299,11 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+
+ /* Keys are not needed in the WPA state machine anymore */
+ wpa_sm_drop_sa(sm);
+
+ sm->msg_3_of_4_ok = 0;
}
@@ -2113,10 +2312,12 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
*
* Configure the PMK for WPA state machine.
*/
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid)
{
if (sm == NULL)
return;
@@ -2129,6 +2330,12 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */
+
+ if (bssid) {
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+ bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ }
}
@@ -2208,6 +2415,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
} else
sm->ssid_len = 0;
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+ sm->p2p = config->p2p;
} else {
sm->network_ctx = NULL;
sm->peerkey_enabled = 0;
@@ -2217,6 +2425,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->eap_conf_ctx = NULL;
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
+ sm->p2p = 0;
}
}
@@ -2327,44 +2536,6 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
/**
- * wpa_sm_get_param - Get WPA state machine parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @param: Parameter field
- * Returns: Parameter value
- */
-unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
-{
- if (sm == NULL)
- return 0;
-
- switch (param) {
- case RSNA_PMK_LIFETIME:
- return sm->dot11RSNAConfigPMKLifetime;
- case RSNA_PMK_REAUTH_THRESHOLD:
- return sm->dot11RSNAConfigPMKReauthThreshold;
- case RSNA_SA_TIMEOUT:
- return sm->dot11RSNAConfigSATimeout;
- case WPA_PARAM_PROTO:
- return sm->proto;
- case WPA_PARAM_PAIRWISE:
- return sm->pairwise_cipher;
- case WPA_PARAM_GROUP:
- return sm->group_cipher;
- case WPA_PARAM_KEY_MGMT:
- return sm->key_mgmt;
-#ifdef CONFIG_IEEE80211W
- case WPA_PARAM_MGMT_GROUP:
- return sm->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
- case WPA_PARAM_RSN_ENABLED:
- return sm->rsn_enabled;
- default:
- return 0;
- }
-}
-
-
-/**
* wpa_sm_get_status - Get WPA state machine
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @buf: Buffer for status information
@@ -2389,7 +2560,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
wpa_cipher_txt(sm->pairwise_cipher),
wpa_cipher_txt(sm->group_cipher),
wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2402,7 +2573,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
ret = os_snprintf(pos, end - pos, "pmf=%d\n",
(rsn.capabilities &
WPA_CAPABILITY_MFPR) ? 2 : 1);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2412,6 +2583,21 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
}
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+ return 0;
+
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+ return 1;
+
+ return 0;
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2586,11 +2772,7 @@ int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
{
-#ifndef CONFIG_NO_WPA2
return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -2602,6 +2784,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+#ifdef CONFIG_IEEE80211R
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+#endif /* CONFIG_IEEE80211R */
}
@@ -2621,38 +2808,29 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
{
-#ifndef CONFIG_NO_WPA2
- pmksa_cache_flush(sm->pmksa, network_ctx);
-#endif /* CONFIG_NO_WPA2 */
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
}
#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
{
- struct wpa_gtk_data gd;
-#ifdef CONFIG_IEEE80211W
- struct wpa_igtk_kde igd;
- u16 keyidx;
-#endif /* CONFIG_IEEE80211W */
u16 keyinfo;
u8 keylen; /* plaintext key len */
u8 *key_rsc;
- os_memset(&gd, 0, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
- os_memset(&igd, 0, sizeof(igd));
-#endif /* CONFIG_IEEE80211W */
-
- keylen = wpa_cipher_key_len(sm->group_cipher);
- gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
- gd.alg = wpa_cipher_to_alg(sm->group_cipher);
- if (gd.alg == WPA_ALG_NONE) {
- wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
- return -1;
- }
-
if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+ struct wpa_gtk_data gd;
+
+ os_memset(&gd, 0, sizeof(gd));
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (gd.alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+ return -1;
+ }
+
key_rsc = buf + 5;
keyinfo = WPA_GET_LE16(buf + 2);
gd.gtk_len = keylen;
@@ -2670,27 +2848,37 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
gd.gtk, gd.gtk_len);
if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+ os_memset(&gd, 0, sizeof(gd));
wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
"WNM mode");
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+ struct wpa_igtk_kde igd;
+ u16 keyidx;
+
+ os_memset(&igd, 0, sizeof(igd));
+ keylen = wpa_cipher_key_len(sm->mgmt_group_cipher);
os_memcpy(igd.keyid, buf + 2, 2);
os_memcpy(igd.pn, buf + 4, 6);
keyidx = WPA_GET_LE16(igd.keyid);
- os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
+ os_memcpy(igd.igtk, buf + 10, keylen);
wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
- igd.igtk, WPA_IGTK_LEN);
- if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ igd.igtk, keylen);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
keyidx, 0, igd.pn, sizeof(igd.pn),
- igd.igtk, WPA_IGTK_LEN) < 0) {
+ igd.igtk, keylen) < 0) {
wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
"WNM mode");
+ os_memset(&igd, 0, sizeof(igd));
return -1;
}
+ os_memset(&igd, 0, sizeof(igd));
#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
@@ -2700,3 +2888,67 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
return 0;
}
#endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_peerkey *peerkey;
+
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peerkey)
+ return 0;
+
+ wpa_sm_rx_eapol(sm, src_addr, buf, len);
+
+ return 1;
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_P2P
+
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
+{
+ if (sm == NULL || WPA_GET_BE32(sm->p2p_ip_addr) == 0)
+ return -1;
+ os_memcpy(buf, sm->p2p_ip_addr, 3 * 4);
+ return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+ if (rx_replay_counter == NULL)
+ return;
+
+ os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+ wpa_printf(MSG_DEBUG, "Updated key replay counter");
+}
+
+
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+ const u8 *ptk_kck, size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len)
+{
+ if (ptk_kck && ptk_kck_len <= WPA_KCK_MAX_LEN) {
+ os_memcpy(sm->ptk.kck, ptk_kck, ptk_kck_len);
+ sm->ptk.kck_len = ptk_kck_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+ }
+ if (ptk_kek && ptk_kek_len <= WPA_KEK_MAX_LEN) {
+ os_memcpy(sm->ptk.kek, ptk_kek, ptk_kek_len);
+ sm->ptk.kek_len = ptk_kek_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+ }
+ sm->ptk_set = 1;
+}
diff --git a/contrib/wpa/src/rsn_supp/wpa.h b/contrib/wpa/src/rsn_supp/wpa.h
index 791974c..e163b70 100644
--- a/contrib/wpa/src/rsn_supp/wpa.h
+++ b/contrib/wpa/src/rsn_supp/wpa.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,10 +12,12 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
struct wpa_sm;
struct eapol_sm;
struct wpa_config_blob;
+struct hostapd_freq_params;
struct wpa_sm_ctx {
void *ctx; /* pointer to arbitrary upper level context */
@@ -50,17 +52,31 @@ struct wpa_sm_ctx {
int (*mark_authenticated)(void *ctx, const u8 *target_ap);
#ifdef CONFIG_TDLS
int (*tdls_get_capa)(void *ctx, int *tdls_supported,
- int *tdls_ext_setup);
+ int *tdls_ext_setup, int *tdls_chan_switch);
int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf, size_t len);
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf, size_t len);
int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
- int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+ int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid,
u16 capability, const u8 *supp_rates,
- size_t supp_rates_len);
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
+ size_t ext_capab_len, const u8 *supp_channels,
+ size_t supp_channels_len,
+ const u8 *supp_oper_classes,
+ size_t supp_oper_classes_len);
+ int (*tdls_enable_channel_switch)(
+ void *ctx, const u8 *addr, u8 oper_class,
+ const struct hostapd_freq_params *params);
+ int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
#endif /* CONFIG_TDLS */
- void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+ void (*set_rekey_offload)(void *ctx, const u8 *kek, size_t kek_len,
+ 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);
};
@@ -87,6 +103,7 @@ struct rsn_supp_config {
const u8 *ssid;
size_t ssid_len;
int wpa_ptk_rekey;
+ int p2p;
};
#ifndef CONFIG_NO_WPA
@@ -95,7 +112,8 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
void wpa_sm_deinit(struct wpa_sm *sm);
void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
void wpa_sm_notify_disassoc(struct wpa_sm *sm);
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid);
void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -113,11 +131,10 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
unsigned int value);
-unsigned int wpa_sm_get_param(struct wpa_sm *sm,
- enum wpa_sm_conf_params param);
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@@ -136,6 +153,13 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+ const u8 *ptk_kck, size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len);
+
#else /* CONFIG_NO_WPA */
static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -227,14 +251,13 @@ static inline int wpa_sm_set_param(struct wpa_sm *sm,
return -1;
}
-static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
- enum wpa_sm_conf_params param)
+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
+ size_t buflen, int verbose)
{
return 0;
}
-static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
- size_t buflen, int verbose)
+static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
{
return 0;
}
@@ -291,15 +314,33 @@ static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
{
}
+static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
+ const u8 *rx_replay_counter)
+{
+}
+
+static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+ const u8 *ptk_kek)
+{
+}
+
#endif /* CONFIG_NO_WPA */
#ifdef CONFIG_PEERKEY
int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len);
#else /* CONFIG_PEERKEY */
static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
{
return -1;
}
+
+static inline int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ return 0;
+}
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
@@ -310,6 +351,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len);
int wpa_ft_is_completed(struct wpa_sm *sm);
+void wpa_reset_ft_completed(struct wpa_sm *sm);
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr);
int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
@@ -341,6 +383,10 @@ static inline int wpa_ft_is_completed(struct wpa_sm *sm)
return 0;
}
+static inline void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+}
+
static inline int
wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *src_addr)
@@ -355,15 +401,20 @@ wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
+const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ struct hostapd_freq_params *freq_params);
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ft.c b/contrib/wpa/src/rsn_supp/wpa_ft.c
index 2df060c..06dea05 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ft.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,8 +19,7 @@
#ifdef CONFIG_IEEE80211R
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
@@ -43,13 +42,9 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+ sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
+ sm->key_mgmt, sm->pairwise_cipher);
}
@@ -134,6 +129,7 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
* @anonce: ANonce or %NULL if not yet available
* @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
* @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octets
* @target_ap: Target AP address
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
@@ -144,7 +140,8 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
*/
static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *anonce, const u8 *pmk_name,
- const u8 *kck, const u8 *target_ap,
+ const u8 *kck, size_t kck_len,
+ const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
const u8 *ap_mdie)
{
@@ -207,6 +204,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+ else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
else {
wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
sm->key_mgmt);
@@ -296,7 +295,7 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
/* Information element count */
ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
ric_ies_len);
- if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+ if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
@@ -331,7 +330,7 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -358,7 +357,7 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -374,7 +373,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *ric_ies, size_t ric_ies_len)
{
u8 *ft_ies;
- size_t ft_ies_len, ptk_len;
+ size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
@@ -400,8 +399,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
}
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+ if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
"enabled for this connection");
return -1;
@@ -441,7 +439,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -457,7 +456,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
"RSNIE");
return -1;
@@ -475,16 +475,14 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
- bssid, sm->pmk_r1_name,
- (u8 *) &sm->ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
+ sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+ return -1;
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
- sm->pmk_r1_name, sm->ptk.kck, bssid,
+ sm->pmk_r1_name,
+ sm->ptk.kck, sm->ptk.kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -526,14 +524,20 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
if (sm == NULL)
return 0;
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK)
+ if (!wpa_key_mgmt_ft(sm->key_mgmt))
return 0;
return sm->ft_completed;
}
+void wpa_reset_ft_completed(struct wpa_sm *sm)
+{
+ if (sm != NULL)
+ sm->ft_completed = 0;
+}
+
+
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
size_t gtk_elem_len)
{
@@ -557,7 +561,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
+ gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -589,6 +594,13 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
}
wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
+ if (sm->group_cipher == WPA_CIPHER_TKIP) {
+ /* Swap Tx/Rx keys for Michael MIC */
+ u8 tmp[8];
+ os_memcpy(tmp, gtk + 16, 8);
+ os_memcpy(gtk + 16, gtk + 24, 8);
+ os_memcpy(gtk + 24, tmp, 8);
+ }
if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
@@ -629,7 +641,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
return -1;
}
- if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+ igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -660,12 +673,11 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
unsigned int count;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
- if (sm->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
- sm->key_mgmt != WPA_KEY_MGMT_FT_PSK) {
+ if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
"enabled for this connection");
return -1;
@@ -714,7 +726,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
}
if (parse.r0kh_id_len != sm->r0kh_id_len ||
- os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+ os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0)
+ {
wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
"the current R0KH-ID");
wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
@@ -729,14 +742,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
+ if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
"ReassocResp");
return -1;
}
if (parse.rsn_pmkid == NULL ||
- os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+ os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN))
+ {
wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
"RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
return -1;
@@ -752,7 +766,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+ if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -762,7 +776,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
return -1;
}
- if (os_memcmp(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
@@ -788,9 +802,12 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
if (parse.ric) {
wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
parse.ric, parse.ric_len);
- /* TODO: parse response and inform driver about results */
+ /* TODO: parse response and inform driver about results when
+ * using wpa_supplicant SME */
}
+ wpa_printf(MSG_DEBUG, "FT: Completed successfully");
+
return 0;
}
@@ -818,7 +835,7 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/contrib/wpa/src/rsn_supp/wpa_i.h b/contrib/wpa/src/rsn_supp/wpa_i.h
index 9f9e641..965a9c1 100644
--- a/contrib/wpa/src/rsn_supp/wpa_i.h
+++ b/contrib/wpa/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
/*
* Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,6 +23,7 @@ struct wpa_sm {
size_t pmk_len;
struct wpa_ptk ptk, tptk;
int ptk_set, tptk_set;
+ unsigned int msg_3_of_4_ok:1;
u8 snonce[WPA_NONCE_LEN];
u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
int renew_snonce;
@@ -58,6 +59,7 @@ struct wpa_sm {
u8 ssid[32];
size_t ssid_len;
int wpa_ptk_rekey;
+ int p2p;
u8 own_addr[ETH_ALEN];
const char *ifname;
@@ -91,6 +93,7 @@ struct wpa_sm {
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
int tdls_prohibited;
+ int tdls_chan_switch_prohibited;
int tdls_disabled;
/* The driver supports TDLS */
@@ -101,6 +104,9 @@ struct wpa_sm {
* to it via tdls_mgmt.
*/
int tdls_external_setup;
+
+ /* The driver supports TDLS channel switching */
+ int tdls_chan_switch;
#endif /* CONFIG_TDLS */
#ifdef CONFIG_IEEE80211R
@@ -122,6 +128,10 @@ struct wpa_sm {
u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
size_t assoc_resp_ies_len;
#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_P2P
+ u8 p2p_ip_addr[3 * 4];
+#endif /* CONFIG_P2P */
};
@@ -245,30 +255,34 @@ static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
{
if (!sm->ctx->set_rekey_offload)
return;
- sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
- sm->ptk.kck, sm->rx_replay_counter);
+ sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, sm->ptk.kek_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->rx_replay_counter);
}
#ifdef CONFIG_TDLS
static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
int *tdls_supported,
- int *tdls_ext_setup)
+ int *tdls_ext_setup,
+ int *tdls_chan_switch)
{
if (sm->ctx->tdls_get_capa)
return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
- tdls_ext_setup);
+ tdls_ext_setup, tdls_chan_switch);
return -1;
}
static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
u8 action_code, u8 dialog_token,
- u16 status_code, const u8 *buf,
+ u16 status_code, u32 peer_capab,
+ int initiator, const u8 *buf,
size_t len)
{
if (sm->ctx->send_tdls_mgmt)
return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
dialog_token, status_code,
- buf, len);
+ peer_capab, initiator, buf,
+ len);
return -1;
}
@@ -282,18 +296,60 @@ static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
static inline int
wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
- u16 capability, const u8 *supp_rates,
- size_t supp_rates_len)
+ u16 aid, u16 capability, const u8 *supp_rates,
+ size_t supp_rates_len,
+ const struct ieee80211_ht_capabilities *ht_capab,
+ const struct ieee80211_vht_capabilities *vht_capab,
+ u8 qosinfo, int wmm, const u8 *ext_capab,
+ size_t ext_capab_len, const u8 *supp_channels,
+ size_t supp_channels_len, const u8 *supp_oper_classes,
+ size_t supp_oper_classes_len)
{
if (sm->ctx->tdls_peer_addset)
return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
- capability, supp_rates,
- supp_rates_len);
+ aid, capability, supp_rates,
+ supp_rates_len, ht_capab,
+ vht_capab, qosinfo, wmm,
+ ext_capab, ext_capab_len,
+ supp_channels,
+ supp_channels_len,
+ supp_oper_classes,
+ supp_oper_classes_len);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+ u8 oper_class,
+ const struct hostapd_freq_params *freq_params)
+{
+ if (sm->ctx->tdls_enable_channel_switch)
+ return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+ oper_class,
+ freq_params);
+ return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm->ctx->tdls_disable_channel_switch)
+ return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
return -1;
}
#endif /* CONFIG_TDLS */
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
+ const u8 *pmk, size_t pmk_len)
+{
+ if (!sm->proactive_key_caching)
+ return 0;
+ if (!sm->ctx->key_mgmt_set_pmk)
+ return -1;
+ return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
+}
+
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
@@ -304,12 +360,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
u16 ver, u16 key_info,
- const u8 *kde, size_t kde_len,
struct wpa_ptk *ptk);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len);
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.c b/contrib/wpa/src/rsn_supp/wpa_ie.c
index 3d75365..cb334df 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.c
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -107,7 +107,6 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int key_mgmt, int mgmt_group_cipher,
struct wpa_sm *sm)
{
-#ifndef CONFIG_NO_WPA2
u8 *pos;
struct rsn_ie_hdr *hdr;
u16 capab;
@@ -174,6 +173,10 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -202,7 +205,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
}
#ifdef CONFIG_IEEE80211W
- if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) {
if (!sm->cur_pmksa) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
@@ -210,7 +213,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
}
/* Management Group Cipher Suite */
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ mgmt_group_cipher));
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
@@ -220,12 +224,67 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
return pos - rsn_ie;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
+#ifdef CONFIG_HS20
+static int wpa_gen_wpa_ie_osen(u8 *wpa_ie, size_t wpa_ie_len,
+ int pairwise_cipher, int group_cipher,
+ int key_mgmt)
+{
+ u8 *pos, *len;
+ u32 suite;
+
+ if (wpa_ie_len < 2 + 4 + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN)
+ return -1;
+
+ pos = wpa_ie;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ len = pos++; /* to be filled */
+ WPA_PUT_BE24(pos, OUI_WFA);
+ pos += 3;
+ *pos++ = HS20_OSEN_OUI_TYPE;
+
+ /* Group Data Cipher Suite */
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+ if (suite == 0) {
+ wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+ group_cipher);
+ return -1;
+ }
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* Pairwise Cipher Suite Count and List */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
+ wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+ pairwise_cipher);
+ return -1;
+ }
+ RSN_SELECTOR_PUT(pos, suite);
+ pos += RSN_SELECTOR_LEN;
+
+ /* AKM Suite Count and List */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_OSEN);
+ pos += RSN_SELECTOR_LEN;
+
+ *len = pos - len - 1;
+
+ WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
+
+ return pos - wpa_ie;
+}
+#endif /* CONFIG_HS20 */
+
+
/**
* wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -241,6 +300,13 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
sm->group_cipher,
sm->key_mgmt, sm->mgmt_group_cipher,
sm);
+#ifdef CONFIG_HS20
+ else if (sm->proto == WPA_PROTO_OSEN)
+ return wpa_gen_wpa_ie_osen(wpa_ie, wpa_ie_len,
+ sm->pairwise_cipher,
+ sm->group_cipher,
+ sm->key_mgmt);
+#endif /* CONFIG_HS20 */
else
return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
sm->pairwise_cipher,
@@ -250,6 +316,42 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return 1;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+ return 0;
+}
+
+
+/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
* @end: Pointer to the end of the Key Data buffer
@@ -349,6 +451,25 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
}
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_P2P
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+#endif /* CONFIG_P2P */
+
return 0;
}
@@ -427,6 +548,31 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
ie->ext_supp_rates = pos;
ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP) {
+ ie->ht_capabilities = pos + 2;
+ ie->ht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP) {
+ ie->vht_capabilities = pos + 2;
+ ie->vht_capabilities_len = pos[1];
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
@@ -435,6 +581,14 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
ret = 0;
break;
}
+
+ ret = wpa_parse_vendor_specific(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
"Key Data IE", pos, 2 + pos[1]);
diff --git a/contrib/wpa/src/rsn_supp/wpa_ie.h b/contrib/wpa/src/rsn_supp/wpa_ie.h
index 5afdfe9..0fc42cc 100644
--- a/contrib/wpa/src/rsn_supp/wpa_ie.h
+++ b/contrib/wpa/src/rsn_supp/wpa_ie.h
@@ -49,6 +49,22 @@ struct wpa_eapol_ie_parse {
size_t supp_rates_len;
const u8 *ext_supp_rates;
size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ size_t ht_capabilities_len;
+ const u8 *vht_capabilities;
+ size_t vht_capabilities_len;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+#ifdef CONFIG_P2P
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+#endif /* CONFIG_P2P */
};
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
OpenPOWER on IntegriCloud