Remove unused files which may make trouble during FreeBSD baseline updates. It also increased the compile-time of the library for nothing.
Update #3472. --- freebsd/contrib/wpa/src/rsn_supp/tdls.c | 3054 -------------------------- freebsd/contrib/wpa/wpa_supplicant/wnm_sta.c | 1168 ---------- libbsd.py | 2 - 3 files changed, 4224 deletions(-) delete mode 100644 freebsd/contrib/wpa/src/rsn_supp/tdls.c delete mode 100644 freebsd/contrib/wpa/wpa_supplicant/wnm_sta.c diff --git a/freebsd/contrib/wpa/src/rsn_supp/tdls.c b/freebsd/contrib/wpa/src/rsn_supp/tdls.c deleted file mode 100644 index 337fb80c1..000000000 --- a/freebsd/contrib/wpa/src/rsn_supp/tdls.c +++ /dev/null @@ -1,3054 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* - * wpa_supplicant - TDLS - * Copyright (c) 2010-2011, Atheros Communications - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "utils/eloop.h" -#include "utils/os.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "crypto/sha256.h" -#include "crypto/crypto.h" -#include "crypto/aes_wrap.h" -#include "rsn_supp/wpa.h" -#include "rsn_supp/wpa_ie.h" -#include "rsn_supp/wpa_i.h" -#include "drivers/driver.h" -#include "l2_packet/l2_packet.h" - -#if defined(__rtems__) && defined(CONFIG_TDLS) -#ifdef CONFIG_TDLS_TESTING -#define TDLS_TESTING_LONG_FRAME BIT(0) -#define TDLS_TESTING_ALT_RSN_IE BIT(1) -#define TDLS_TESTING_DIFF_BSSID BIT(2) -#define TDLS_TESTING_SHORT_LIFETIME BIT(3) -#define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) -#define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) -#define TDLS_TESTING_LONG_LIFETIME BIT(6) -#define TDLS_TESTING_CONCURRENT_INIT BIT(7) -#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_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 - -#define TDLS_TIMEOUT_LEN 4 - -struct wpa_tdls_ftie { - u8 ie_type; /* FTIE */ - u8 ie_len; - u8 mic_ctrl[2]; - u8 mic[TDLS_MIC_LEN]; - u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ - u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ - /* followed by optional elements */ -} STRUCT_PACKED; - -struct wpa_tdls_timeoutie { - u8 ie_type; /* Timeout IE */ - u8 ie_len; - u8 interval_type; - u8 value[TDLS_TIMEOUT_LEN]; -} STRUCT_PACKED; - -struct wpa_tdls_lnkid { - u8 ie_type; /* Link Identifier IE */ - u8 ie_len; - u8 bssid[ETH_ALEN]; - u8 init_sta[ETH_ALEN]; - u8 resp_sta[ETH_ALEN]; -} STRUCT_PACKED; - -/* TDLS frame headers as per IEEE Std 802.11z-2010 */ -struct wpa_tdls_frame { - u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ - u8 category; /* Category */ - u8 action; /* Action (enum tdls_frame_type) */ -} STRUCT_PACKED; - -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 -#define IEEE80211_MAX_SUPP_RATES 32 - -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 */ - u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ - u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ - size_t rsnie_i_len; - u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ - size_t rsnie_p_len; - u32 lifetime; - int cipher; /* Selected cipher (WPA_CIPHER_*) */ - u8 dtoken; - - struct tpk { - u8 kck[16]; /* TPK-KCK */ - u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ - } tpk; - int tpk_set; - int tk_set; /* TPK-TK configured to the driver */ - int tpk_success; - int tpk_in_progress; - - struct tpk_timer { - u8 dest[ETH_ALEN]; - int count; /* Retry Count */ - int timer; /* Timeout in milliseconds */ - 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; - - u16 capability; - - 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; -}; - - -static int wpa_tdls_get_privacy(struct wpa_sm *sm) -{ - /* - * Get info needed from supplicant to check if the current BSS supports - * security. Other than OPEN mode, rest are considered secured - * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. - */ - return sm->pairwise_cipher != WPA_CIPHER_NONE; -} - - -static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) -{ - os_memcpy(pos, ie, ie_len); - return pos + ie_len; -} - - -static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, - 0, 0, NULL, 0, NULL, 0) < 0) { - wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " - "the driver"); - return -1; - } - - return 0; -} - - -static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) -{ - u8 key_len; - u8 rsc[6]; - enum wpa_alg alg; - - if (peer->tk_set) { - /* - * This same TPK-TK has already been configured to the driver - * and this new configuration attempt (likely due to an - * unexpected retransmitted frame) would result in clearing - * the TX/RX sequence number which can break security, so must - * not allow that to happen. - */ - wpa_printf(MSG_INFO, "TDLS: TPK-TK for the peer " MACSTR - " has already been configured to the driver - do not reconfigure", - MAC2STR(peer->addr)); - return -1; - } - - os_memset(rsc, 0, 6); - - switch (peer->cipher) { - case WPA_CIPHER_CCMP: - alg = WPA_ALG_CCMP; - key_len = 16; - break; - case WPA_CIPHER_NONE: - wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " - "NONE - do not use pairwise keys"); - return -1; - default: - wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", - sm->pairwise_cipher); - return -1; - } - - wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR, - MAC2STR(peer->addr)); - if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, - rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { - wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " - "driver"); - return -1; - } - peer->tk_set = 1; - return 0; -} - - -static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, - u8 action_code, u8 dialog_token, - 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, 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, 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 peer_capab=%u initiator=%d " - "msg_len=%u", - MAC2STR(dest), action_code, dialog_token, status_code, - peer_capab, initiator, (unsigned int) msg_len); - - if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, - status_code, peer_capab, initiator, msg, - msg_len)) { - wpa_printf(MSG_INFO, "TDLS: Failed to send message " - "(action_code=%u)", action_code); - return -1; - } - - if (action_code == WLAN_TDLS_SETUP_CONFIRM || - action_code == WLAN_TDLS_TEARDOWN || - action_code == WLAN_TDLS_DISCOVERY_REQUEST || - action_code == WLAN_TDLS_DISCOVERY_RESPONSE) - return 0; /* No retries */ - - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "retry " MACSTR, MAC2STR(dest)); - return 0; - } - - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - - 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); - if (peer->sm_tmr.buf == NULL) - return -1; - os_memcpy(peer->sm_tmr.buf, msg, msg_len); - - wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " - "(action_code=%u)", action_code); - 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 ret; - - 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; -} - - -static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) -{ - - struct wpa_sm *sm = eloop_ctx; - struct wpa_tdls_peer *peer = timeout_ctx; - - if (peer->sm_tmr.count) { - peer->sm_tmr.count--; - - wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " - "(action_code=%u)", - peer->sm_tmr.action_code); - - if (peer->sm_tmr.buf == NULL) { - wpa_printf(MSG_INFO, "TDLS: No retry buffer available " - "for action_code=%u", - peer->sm_tmr.action_code); - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, - peer); - return; - } - - /* resend TPK Handshake Message to Peer */ - if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, - 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 " - "transmission"); - } - - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - 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); - } -} - - -static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, - struct wpa_tdls_peer *peer, - u8 action_code) -{ - if (action_code == peer->sm_tmr.action_code) { - wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " - "action_code=%u", action_code); - - /* Cancel Timeout registered */ - eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); - - /* free all resources meant for retry */ - os_free(peer->sm_tmr.buf); - peer->sm_tmr.buf = NULL; - - peer->sm_tmr.count = 0; - peer->sm_tmr.timer = 0; - peer->sm_tmr.buf_len = 0; - peer->sm_tmr.action_code = 0xff; - } else { - wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " - "(Unknown action_code=%u)", action_code); - } -} - - -static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, - const u8 *own_addr, const u8 *bssid) -{ - u8 key_input[SHA256_MAC_LEN]; - const u8 *nonce[2]; - size_t len[2]; - u8 data[3 * ETH_ALEN]; - - /* IEEE Std 802.11z-2010 8.5.9.1: - * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) - */ - len[0] = WPA_NONCE_LEN; - len[1] = WPA_NONCE_LEN; - if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { - nonce[0] = peer->inonce; - nonce[1] = peer->rnonce; - } else { - nonce[0] = peer->rnonce; - nonce[1] = peer->inonce; - } - wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); - wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); - sha256_vector(2, nonce, len, key_input); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", - key_input, SHA256_MAC_LEN); - - /* - * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", - * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) - * TODO: is N_KEY really included in KDF Context and if so, in which - * presentation format (little endian 16-bit?) is it used? It gets - * added by the KDF anyway.. - */ - - if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { - os_memcpy(data, own_addr, ETH_ALEN); - os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); - } else { - os_memcpy(data, peer->addr, ETH_ALEN); - os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); - } - os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); - wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); - - sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), - (u8 *) &peer->tpk, sizeof(peer->tpk)); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", - peer->tpk.kck, sizeof(peer->tpk.kck)); - wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", - peer->tpk.tk, sizeof(peer->tpk.tk)); - peer->tpk_set = 1; -} - - -/** - * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC - * @kck: TPK-KCK - * @lnkid: Pointer to the beginning of Link Identifier IE - * @rsnie: Pointer to the beginning of RSN IE used for handshake - * @timeoutie: Pointer to the beginning of Timeout IE used for handshake - * @ftie: Pointer to the beginning of FT IE - * @mic: Pointer for writing MIC - * - * Calculate MIC for TDLS frame. - */ -static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, - const u8 *rsnie, const u8 *timeoutie, - const u8 *ftie, u8 *mic) -{ - u8 *buf, *pos; - struct wpa_tdls_ftie *_ftie; - const struct wpa_tdls_lnkid *_lnkid; - int ret; - int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + - 2 + timeoutie[1] + 2 + ftie[1]; - buf = os_zalloc(len); - if (!buf) { - wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); - return -1; - } - - pos = buf; - _lnkid = (const struct wpa_tdls_lnkid *) lnkid; - /* 1) TDLS initiator STA MAC address */ - os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); - pos += ETH_ALEN; - /* 2) TDLS responder STA MAC address */ - os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); - pos += ETH_ALEN; - /* 3) Transaction Sequence number */ - *pos++ = trans_seq; - /* 4) Link Identifier IE */ - os_memcpy(pos, lnkid, 2 + lnkid[1]); - pos += 2 + lnkid[1]; - /* 5) RSN IE */ - os_memcpy(pos, rsnie, 2 + rsnie[1]); - pos += 2 + rsnie[1]; - /* 6) Timeout Interval IE */ - os_memcpy(pos, timeoutie, 2 + timeoutie[1]); - pos += 2 + timeoutie[1]; - /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); - _ftie = (struct wpa_tdls_ftie *) pos; - os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; - - wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); - wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); - ret = omac1_aes_128(kck, buf, pos - buf, mic); - os_free(buf); - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); - return ret; -} - - -/** - * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame - * @kck: TPK-KCK - * @trans_seq: Transaction Sequence Number (4 - Teardown) - * @rcode: Reason code for Teardown - * @dtoken: Dialog Token used for that particular link - * @lnkid: Pointer to the beginning of Link Identifier IE - * @ftie: Pointer to the beginning of FT IE - * @mic: Pointer for writing MIC - * - * Calculate MIC for TDLS frame. - */ -static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, - u8 dtoken, const u8 *lnkid, - const u8 *ftie, u8 *mic) -{ - u8 *buf, *pos; - struct wpa_tdls_ftie *_ftie; - int ret; - int len; - - if (lnkid == NULL) - return -1; - - len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + - sizeof(trans_seq) + 2 + ftie[1]; - - buf = os_zalloc(len); - if (!buf) { - wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); - return -1; - } - - pos = buf; - /* 1) Link Identifier IE */ - os_memcpy(pos, lnkid, 2 + lnkid[1]); - pos += 2 + lnkid[1]; - /* 2) Reason Code */ - WPA_PUT_LE16(pos, rcode); - pos += sizeof(rcode); - /* 3) Dialog token */ - *pos++ = dtoken; - /* 4) Transaction Sequence number */ - *pos++ = trans_seq; - /* 7) FTIE, with the MIC field of the FTIE set to 0 */ - os_memcpy(pos, ftie, 2 + ftie[1]); - _ftie = (struct wpa_tdls_ftie *) pos; - os_memset(_ftie->mic, 0, TDLS_MIC_LEN); - pos += 2 + ftie[1]; - - wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); - wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); - ret = omac1_aes_128(kck, buf, pos - buf, mic); - os_free(buf); - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); - return ret; -} - - -static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, - struct wpa_tdls_peer *peer, - const u8 *lnkid, const u8 *timeoutie, - const struct wpa_tdls_ftie *ftie) -{ - u8 mic[16]; - - if (peer->tpk_set) { - wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, - peer->rsnie_p, timeoutie, (u8 *) ftie, - mic); - 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", - ftie->mic, 16); - wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", - mic, 16); - return -1; - } - } else { - wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " - "TPK not set - dropping packet"); - return -1; - } - return 0; -} - - -static int wpa_supplicant_verify_tdls_mic_teardown( - u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, - const u8 *lnkid, const struct wpa_tdls_ftie *ftie) -{ - u8 mic[16]; - - if (peer->tpk_set) { - wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, - dtoken, lnkid, (u8 *) ftie, mic); - if (os_memcmp_const(mic, ftie->mic, 16) != 0) { - wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " - "dropping packet"); - return -1; - } - } else { - wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " - "MIC, TPK not set - dropping packet"); - return -1; - } - return 0; -} - - -static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_sm *sm = eloop_ctx; - struct wpa_tdls_peer *peer = timeout_ctx; - - /* - * On TPK lifetime expiration, we have an option of either tearing down - * the direct link or trying to re-initiate it. The selection of what - * to do is not strictly speaking controlled by our role in the expired - * link, but for now, use that to select whether to renew or tear down - * the link. - */ - - if (peer->initiator) { - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR - " - try to renew", MAC2STR(peer->addr)); - wpa_tdls_start(sm, peer->addr); - } else { - 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); - } -} - - -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->tk_set = 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) -{ - lnkid->ie_type = WLAN_EID_LINK_ID; - lnkid->ie_len = 3 * ETH_ALEN; - os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); - if (peer->initiator) { - os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); - os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); - } else { - os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); - os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); - } -} - - -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; - struct wpa_tdls_lnkid lnkid; - u8 dialog_token; - u8 *rbuf, *pos; - int ielen; - - if (sm->tdls_disabled || !sm->tdls_supported) - return -1; - - /* Find the node and free from the list */ - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "Teardown " MACSTR, MAC2STR(addr)); - 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, - MAC2STR(addr)); - - ielen = 0; - if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { - /* To add FTIE for Teardown request and compute MIC */ - ielen += sizeof(*ftie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - ielen += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(ielen + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) - goto skip_ies; - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /* Using the recent nonce which should be for CONFIRM frame */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - pos = (u8 *) (ftie + 1); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", - (u8 *) ftie, pos - (u8 *) ftie); - - /* compute MIC before sending */ - wpa_tdls_linkid(sm, peer, &lnkid); - wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, - dialog_token, (u8 *) &lnkid, (u8 *) ftie, - ftie->mic); - -skip_ies: - /* TODO: register for a Timeout handler, if Teardown is not received at - * the other end, then try again another time */ - - /* request driver to send Teardown using this FTIE */ - wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, - reason_code, 0, peer->initiator, rbuf, pos - rbuf); - os_free(rbuf); - - return 0; -} - - -int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) -{ - 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 == NULL) { - wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR - " for link Teardown", MAC2STR(addr)); - return -1; - } - - if (!peer->tpk_success) { - wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR - " not connected - cannot Teardown link", MAC2STR(addr)); - return -1; - } - - 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_unreachable_link(struct wpa_sm *sm, const u8 *addr) -{ - struct wpa_tdls_peer *peer; - - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - 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) -{ - struct wpa_tdls_peer *peer = NULL; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_lnkid *lnkid; - struct wpa_eapol_ie_parse kde; - u16 reason_code; - const u8 *pos; - int ielen; - - /* Find the node and free from the list */ - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching entry found for " - "Teardown " MACSTR, MAC2STR(src_addr)); - return 0; - } - - pos = buf; - pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - reason_code = WPA_GET_LE16(pos); - pos += 2; - - wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR - " (reason code %u)", MAC2STR(src_addr), reason_code); - - 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 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 " - "Teardown"); - return -1; - } - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) - goto skip_ftie; - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); - return -1; - } - - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - /* Process MIC check to see if TDLS Teardown is right */ - if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, - peer->dtoken, peer, - (u8 *) lnkid, ftie) < 0) { - wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " - "Teardown Request from " MACSTR, MAC2STR(src_addr)); - return -1; - } - -skip_ftie: - /* - * Request the driver to disable the direct link and clear associated - * keys. - */ - wpa_tdls_disable_peer_link(sm, peer); - return 0; -} - - -/** - * wpa_tdls_send_error - To send suitable TDLS status response with - * 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, 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, - 0, initiator, NULL, 0); -} - - -static struct wpa_tdls_peer * -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)); - - peer = os_zalloc(sizeof(*peer)); - if (peer == NULL) - return NULL; - - os_memcpy(peer->addr, addr, ETH_ALEN); - peer->next = sm->tdls; - sm->tdls = peer; - - return peer; -} - - -static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, - struct wpa_tdls_peer *peer) -{ - size_t buf_len; - struct wpa_tdls_timeoutie timeoutie; - u16 rsn_capab; - struct wpa_tdls_ftie *ftie; - 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"); - peer->rsnie_i_len = 0; - goto skip_rsnie; - } - - /* - * TPK Handshake Message 1: - * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, - * Timeout Interval IE)) - */ - - /* 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; - - /* - * AES-CCMP is the default Encryption preferred for TDLS, so - * RSN IE is filled only with CCMP CIPHER - * 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; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { - wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " - "testing"); - rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; - } -#endif /* CONFIG_TDLS_TESTING */ - WPA_PUT_LE16(pos, rsn_capab); - pos += 2; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { - /* Number of PMKIDs */ - *pos++ = 0x00; - *pos++ = 0x00; - } -#endif /* CONFIG_TDLS_TESTING */ - - hdr->len = (pos - peer->rsnie_i) - 2; - peer->rsnie_i_len = pos - peer->rsnie_i; - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", - peer->rsnie_i, peer->rsnie_i_len); - -skip_rsnie: - buf_len = 0; - if (wpa_tdls_get_privacy(sm)) - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (wpa_tdls_get_privacy(sm) && - (tdls_testing & TDLS_TESTING_LONG_FRAME)) - buf_len += 170; - if (tdls_testing & TDLS_TESTING_DIFF_BSSID) - buf_len += sizeof(struct wpa_tdls_lnkid); -#endif /* CONFIG_TDLS_TESTING */ - 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); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - - if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { - wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "TDLS: Failed to get random data for initiator Nonce"); - os_free(rbuf); - wpa_tdls_peer_free(sm, peer); - return -1; - } - peer->tk_set = 0; /* A new nonce results in a new TK */ - wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", - peer->inonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", - (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - peer->lifetime = TPK_LIFETIME; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " - "lifetime"); - peer->lifetime = 301; - } - if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " - "lifetime"); - peer->lifetime = 0xffffffff; - } -#endif /* CONFIG_TDLS_TESTING */ - 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: - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " - "Link Identifier"); - struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; - wpa_tdls_linkid(sm, peer, l); - l->bssid[5] ^= 0x01; - pos += sizeof(*l); - } -#endif /* CONFIG_TDLS_TESTING */ - - wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " - "Handshake Message 1 (peer " MACSTR ")", - MAC2STR(peer->addr)); - - status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, - 1, 0, 0, peer->initiator, rbuf, pos - rbuf); - os_free(rbuf); - - return status; -} - - -static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, - const unsigned char *src_addr, u8 dtoken, - struct wpa_tdls_lnkid *lnkid, - const struct wpa_tdls_peer *peer) -{ - u8 *rbuf, *pos; - size_t buf_len; - u32 lifetime; - struct wpa_tdls_timeoutie timeoutie; - struct wpa_tdls_ftie *ftie; - int status; - - buf_len = 0; - if (wpa_tdls_get_privacy(sm)) { - /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), - * Lifetime */ - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - buf_len += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(buf_len + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm)) - goto skip_ies; - - /* Peer RSN IE */ - pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /* TODO: ftie->mic_control to set 2-RESPONSE */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", - (u8 *) ftie, sizeof(*ftie)); - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - lifetime = peer->lifetime; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " - "lifetime in response"); - lifetime++; - } -#endif /* CONFIG_TDLS_TESTING */ - pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, - sizeof(timeoutie), lifetime); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", - lifetime); - - /* 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: - status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, - dtoken, 0, 0, peer->initiator, rbuf, - pos - rbuf); - os_free(rbuf); - - return status; -} - - -static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, - const unsigned char *src_addr, u8 dtoken, - struct wpa_tdls_lnkid *lnkid, - const struct wpa_tdls_peer *peer) -{ - u8 *rbuf, *pos; - size_t buf_len; - 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)) { - /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), - * Lifetime */ - buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + - sizeof(struct wpa_tdls_timeoutie); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) - buf_len += 170; -#endif /* CONFIG_TDLS_TESTING */ - } - - rbuf = os_zalloc(buf_len + 1); - if (rbuf == NULL) - return -1; - pos = rbuf; - - if (!wpa_tdls_get_privacy(sm)) - goto skip_ies; - - /* Peer RSN IE */ - pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); - - ftie = (struct wpa_tdls_ftie *) pos; - ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; - /*TODO: ftie->mic_control to set 3-CONFIRM */ - os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); - os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); - ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; - - pos = (u8 *) (ftie + 1); - -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_LONG_FRAME) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " - "FTIE"); - ftie->ie_len += 170; - *pos++ = 255; /* FTIE subelem */ - *pos++ = 168; /* FTIE subelem length */ - pos += 168; - } -#endif /* CONFIG_TDLS_TESTING */ - - /* Lifetime */ - lifetime = peer->lifetime; -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " - "lifetime in confirm"); - lifetime++; - } -#endif /* CONFIG_TDLS_TESTING */ - pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, - sizeof(timeoutie), lifetime); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", - lifetime); - - /* 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: - - 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 status; -} - - -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; - - /* - * 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; -} - - -static int -wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, - const u8 *buf, size_t len) -{ - struct wpa_eapol_ie_parse kde; - const struct wpa_tdls_lnkid *lnkid; - struct wpa_tdls_peer *peer; - size_t min_req_len = sizeof(struct wpa_tdls_frame) + - 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); - u8 dialog_token; - - wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR, - MAC2STR(addr)); - - if (len < min_req_len) { - wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: " - "%d", (int) len); - return -1; - } - - 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) { - 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 " - "Request"); - return -1; - } - - lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; - - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " - " BSS " MACSTR, MAC2STR(lnkid->bssid)); - return -1; - } - - peer = wpa_tdls_add_peer(sm, addr, NULL); - if (peer == NULL) - return -1; - - return wpa_tdls_send_discovery_response(sm, peer, dialog_token); -} - - -int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) -{ - if (sm->tdls_disabled || !sm->tdls_supported) - return -1; - - 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, 0, 1, NULL, 0); -} - - -static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, - struct wpa_tdls_peer *peer) -{ - if (!kde->supp_rates) { - 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) { - 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) { - 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; -} - - -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 tdls_nonce_set(const u8 *nonce) -{ - int i; - - for (i = 0; i < WPA_NONCE_LEN; i++) { - if (nonce[i]) - return 1; - } - - return 0; -} - - -static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_ie_data ie; - int cipher; - const u8 *cpos; - struct wpa_tdls_ftie *ftie = NULL; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - u32 lifetime = 0; -#if 0 - struct rsn_ie_hdr *hdr; - u8 *pos; - u16 rsn_capab; - u16 rsn_ver; -#endif - u8 dtoken; - u16 ielen; - u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; - int tdls_prohibited = sm->tdls_prohibited; - int existing_peer = 0; - - if (len < 3 + 3) - return -1; - - cpos = buf; - cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - /* driver had already verified the frame format */ - dtoken = *cpos++; /* dialog token */ - - wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); - - peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer); - 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 */ - peer->capability = WPA_GET_LE16(cpos); - cpos += 2; - - ielen = len - (cpos - 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 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 " - "TPK M1"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", - kde.lnkid, kde.lnkid_len); - 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_REQUEST_DECLINED; - goto error; - } - - wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, - MAC2STR(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) { - 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); - } - - if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && - tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " - "on TDLS"); - tdls_prohibited = 0; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (tdls_prohibited) { - wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); - status = WLAN_STATUS_REQUEST_DECLINED; - goto error; - } - - if (!wpa_tdls_get_privacy(sm)) { - if (kde.rsn_ie) { - wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " - "security is disabled"); - status = WLAN_STATUS_SECURITY_DISABLED; - goto error; - } - goto skip_rsn; - } - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || - kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto error; - } - - if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { - wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " - "TPK M1"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - cipher = ie.pairwise_cipher; - if (cipher & WPA_CIPHER_CCMP) { - wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); - cipher = WPA_CIPHER_CCMP; - } else { - wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - goto error; - } - - if ((ie.capabilities & - (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != - WPA_CAPABILITY_PEERKEY_ENABLED) { - wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " - "TPK M1"); - status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; - goto error; - } - - /* Lifetime */ - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); - if (lifetime < 300) { - wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - -skip_rsn: -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { - if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) { - /* - * The request frame from us is going to win, so do not - * replace information based on this request frame from - * the peer. - */ - goto skip_rsn_check; - } - } -#endif /* CONFIG_TDLS_TESTING */ - - peer->initiator = 0; /* Need to check */ - peer->dtoken = dtoken; - - if (!wpa_tdls_get_privacy(sm)) { - peer->rsnie_i_len = 0; - peer->rsnie_p_len = 0; - peer->cipher = WPA_CIPHER_NONE; - goto skip_rsn_check; - } - - ftie = (struct wpa_tdls_ftie *) kde.ftie; - 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_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0 || - !tdls_nonce_set(peer->inonce)) { - /* - * 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; - } - peer->tk_set = 0; /* A new nonce results in a new TK */ - } - -#if 0 - /* get version info from RSNIE received from Peer */ - hdr = (struct rsn_ie_hdr *) kde.rsn_ie; - rsn_ver = WPA_GET_LE16(hdr->version); - - /* use min(peer's version, out version) */ - if (rsn_ver > RSN_VERSION) - rsn_ver = RSN_VERSION; - - hdr = (struct rsn_ie_hdr *) peer->rsnie_p; - - hdr->elem_id = WLAN_EID_RSN; - WPA_PUT_LE16(hdr->version, rsn_ver); - pos = (u8 *) (hdr + 1); - - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); - pos += RSN_SELECTOR_LEN; - /* Include only the selected cipher in pairwise cipher suite */ - WPA_PUT_LE16(pos, 1); - pos += 2; - if (cipher == WPA_CIPHER_CCMP) - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); - pos += RSN_SELECTOR_LEN; - - 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 - peer->rsnie_p) - 2; - peer->rsnie_p_len = pos - peer->rsnie_p; -#endif - - /* temp fix: validation of RSNIE later */ - os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); - peer->rsnie_p_len = peer->rsnie_i_len; - - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", - peer->rsnie_p, peer->rsnie_p_len); - - peer->lifetime = lifetime; - - wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); - -skip_rsn_check: -#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_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, 0, - status); - if (peer) - wpa_tdls_peer_free(sm, peer); - return -1; -} - - -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; - /* - * Start the initiator process a bit earlier to avoid race - * condition with the responder sending teardown request. - */ - if (lifetime > 3 && peer->initiator) - lifetime -= 3; - eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, - sm, peer); -#ifdef CONFIG_TDLS_TESTING - if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " - "expiration"); - eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); - } -#endif /* CONFIG_TDLS_TESTING */ - } - - 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; - - return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); -} - - -static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_ie_data ie; - int cipher; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - u32 lifetime; - u8 dtoken; - 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)); - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) - break; - } - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching peer found for " - "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; - } - - if (peer->tpk_success) { - wpa_printf(MSG_INFO, "TDLS: Ignore incoming TPK M2 retry, from " - MACSTR " as TPK M3 was already sent", - MAC2STR(src_addr)); - return 0; - } - - wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); - - 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); - pos += 2 /* status code */; - - if (status != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", - status); - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } - - status = WLAN_STATUS_UNSPECIFIED_FAILURE; - - /* TODO: need to verify dialog token matches here or in kernel */ - dtoken = *pos++; /* dialog token */ - - wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); - - 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 */ - - /* - * 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) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); - status = WLAN_STATUS_REQUEST_DECLINED; - goto error; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { - wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " - "TPK M2"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", - kde.lnkid, kde.lnkid_len); - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); - status = WLAN_STATUS_NOT_IN_SAME_BSS; - goto error; - } - - 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; - goto skip_rsn; - } - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || - kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); - status = WLAN_STATUS_INVALID_PARAMETERS; - goto error; - } - 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 - * match. Since we list only a single pairwise cipher in TPK M1, the - * memcmp is likely to work in most cases, though. - */ - if (kde.rsn_ie_len != peer->rsnie_i_len || - os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { - wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " - "not match with RSN IE used in TPK M1"); - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", - peer->rsnie_i, peer->rsnie_i_len); - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", - kde.rsn_ie, kde.rsn_ie_len); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); - status = WLAN_STATUS_INVALID_RSNIE; - goto error; - } - - cipher = ie.pairwise_cipher; - if (cipher == WPA_CIPHER_CCMP) { - wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); - cipher = WPA_CIPHER_CCMP; - } else { - wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); - status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; - goto error; - } - - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", - kde.ftie, sizeof(*ftie)); - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { - wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " - "not match with FTIE SNonce used in TPK M1"); - /* Silently discard the frame */ - return -1; - } - - /* Responder Nonce and RSN IE */ - os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); - os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); - peer->rsnie_p_len = kde.rsn_ie_len; - peer->cipher = cipher; - - /* Lifetime */ - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", - lifetime); - if (lifetime != peer->lifetime) { - wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " - "TPK M2 (expected %u)", lifetime, peer->lifetime); - status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; - goto error; - } - - wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); - - /* Process MIC check to see if TPK M2 is right */ - if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { - /* Discard the frame */ - wpa_tdls_del_key(sm, peer); - wpa_tdls_disable_peer_link(sm, peer); - 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: - 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"); - if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) - goto error; - - 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, 1, - status); - wpa_tdls_disable_peer_link(sm, peer); - return -1; -} - - -static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_tdls_peer *peer; - struct wpa_eapol_ie_parse kde; - struct wpa_tdls_ftie *ftie; - struct wpa_tdls_timeoutie *timeoutie; - struct wpa_tdls_lnkid *lnkid; - int ielen; - 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)); - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) - break; - } - if (peer == NULL) { - wpa_printf(MSG_INFO, "TDLS: No matching peer found for " - "TPK M3: " MACSTR, MAC2STR(src_addr)); - return -1; - } - wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); - - if (len < 3 + 3) - goto error; - pos = buf; - pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; - - status = WPA_GET_LE16(pos); - - if (status != 0) { - wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", - status); - 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_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"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", - (u8 *) kde.lnkid, kde.lnkid_len); - lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; - - if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); - goto error; - } - - if (!wpa_tdls_get_privacy(sm)) - goto skip_rsn; - - if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { - wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", - kde.ftie, sizeof(*ftie)); - ftie = (struct wpa_tdls_ftie *) kde.ftie; - - if (kde.rsn_ie == NULL) { - wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); - goto error; - } - wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", - kde.rsn_ie, kde.rsn_ie_len); - if (kde.rsn_ie_len != peer->rsnie_p_len || - 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"); - 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"); - 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"); - goto error; - } - - if (kde.key_lifetime == NULL) { - wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); - goto error; - } - timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; - wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", - (u8 *) timeoutie, sizeof(*timeoutie)); - lifetime = WPA_GET_LE32(timeoutie->value); - wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", - lifetime); - if (lifetime != peer->lifetime) { - wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " - "TPK M3 (expected %u)", lifetime, peer->lifetime); - goto error; - } - - if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, - (u8 *) timeoutie, ftie) < 0) { - wpa_tdls_del_key(sm, peer); - goto error; - } - - 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: - /* add supported rates, capabilities, and qos_info to the TDLS peer */ - if (wpa_tdls_addset_peer(sm, peer, 0) < 0) - goto error; - - 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; -} - - -static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) -{ - struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; - - os_memset(lifetime, 0, ie_len); - lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; - lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; - lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; - WPA_PUT_LE32(lifetime->value, tsecs); - os_memcpy(pos, ie, ie_len); - return pos + ie_len; -} - - -/** - * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) - * @sm: Pointer to WPA state machine data from wpa_sm_init() - * @peer: MAC address of the peer STA - * Returns: 0 on success, or -1 on failure - * - * Send TPK Handshake Message 1 info to driver to start TDLS - * handshake with the peer. - */ -int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) -{ - struct wpa_tdls_peer *peer; - int tdls_prohibited = sm->tdls_prohibited; - - if (sm->tdls_disabled || !sm->tdls_supported) - return -1; - -#ifdef CONFIG_TDLS_TESTING - if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && - tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " - "on TDLS"); - tdls_prohibited = 0; - } -#endif /* CONFIG_TDLS_TESTING */ - - if (tdls_prohibited) { - wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " - "reject request to start setup"); - return -1; - } - - peer = wpa_tdls_add_peer(sm, addr, NULL); - 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 */ - 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_peer_link(sm, peer); - return -1; - } - - return 0; -} - - -void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) -{ - struct wpa_tdls_peer *peer; - - if (sm->tdls_disabled || !sm->tdls_supported) - return; - - for (peer = sm->tdls; peer; peer = peer->next) { - if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) - break; - } - - if (peer == NULL || !peer->tpk_success) - return; - - if (sm->tdls_external_setup) { - /* - * Disable previous link to allow renegotiation to be completed - * on AP path. - */ - wpa_tdls_do_teardown(sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); - } -} - - -/** - * wpa_supplicant_rx_tdls - Receive TDLS data frame - * - * This function is called to receive TDLS (ethertype = 0x890d) data frames. - */ -static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, - const u8 *buf, size_t len) -{ - struct wpa_sm *sm = ctx; - struct wpa_tdls_frame *tf; - - wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", - buf, len); - - if (sm->tdls_disabled || !sm->tdls_supported) { - wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " - "or unsupported by driver"); - return; - } - - if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { - wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); - return; - } - - if (len < sizeof(*tf)) { - wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); - return; - } - - /* Check to make sure its a valid encapsulated TDLS frame */ - tf = (struct wpa_tdls_frame *) buf; - if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || - tf->category != WLAN_ACTION_TDLS) { - wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " - "category=%u action=%u", - tf->payloadtype, tf->category, tf->action); - return; - } - - switch (tf->action) { - case WLAN_TDLS_SETUP_REQUEST: - wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); - break; - case WLAN_TDLS_SETUP_RESPONSE: - wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); - break; - case WLAN_TDLS_SETUP_CONFIRM: - wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); - break; - case WLAN_TDLS_TEARDOWN: - wpa_tdls_recv_teardown(sm, src_addr, buf, len); - break; - case WLAN_TDLS_DISCOVERY_REQUEST: - wpa_tdls_process_discovery_request(sm, src_addr, buf, len); - break; - default: - /* Kernel code will process remaining frames */ - wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", - tf->action); - break; - } -} - - -/** - * wpa_tdls_init - Initialize driver interface parameters for TDLS - * @wpa_s: Pointer to wpa_supplicant data - * Returns: 0 on success, -1 on failure - * - * This function is called to initialize driver interface parameters for TDLS. - * wpa_drv_init() must have been called before this function to initialize the - * driver interface. - */ -int wpa_tdls_init(struct wpa_sm *sm) -{ - if (sm == NULL) - return -1; - - sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : - sm->ifname, - sm->own_addr, - ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, - sm, 0); - if (sm->l2_tdls == NULL) { - wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " - "connection"); - return -1; - } - - /* - * Drivers that support TDLS but don't implement the get_capa callback - * are assumed to perform everything internally - */ - if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, - &sm->tdls_external_setup, - &sm->tdls_chan_switch) < 0) { - sm->tdls_supported = 1; - sm->tdls_external_setup = 0; - } - - wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " - "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; - - while (peer) { - int res; - tmp = peer->next; - res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); - wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", - MAC2STR(peer->addr), res); - wpa_tdls_peer_free(sm, peer); - peer = tmp; - } -} - - -/** - * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS - * - * This function is called to recover driver interface parameters for TDLS - * and frees resources allocated for it. - */ -void wpa_tdls_deinit(struct wpa_sm *sm) -{ - if (sm == NULL) - return; - - if (sm->l2_tdls) - l2_packet_deinit(sm->l2_tdls); - sm->l2_tdls = NULL; - - wpa_tdls_remove_peers(sm); -} - - -void wpa_tdls_assoc(struct wpa_sm *sm) -{ - wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); - wpa_tdls_remove_peers(sm); -} - - -void wpa_tdls_disassoc(struct wpa_sm *sm) -{ - wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); - wpa_tdls_remove_peers(sm); -} - - -static int wpa_tdls_prohibited(struct ieee802_11_elems *elems) -{ - /* bit 38 - TDLS Prohibited */ - return !!(elems->ext_capab[2 + 4] & 0x40); -} - - -static int wpa_tdls_chan_switch_prohibited(struct ieee802_11_elems *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) -{ - struct ieee802_11_elems elems; - - sm->tdls_prohibited = 0; - sm->tdls_chan_switch_prohibited = 0; - - if (ies == NULL || - ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed || - 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) -{ - struct ieee802_11_elems elems; - - if (ies == NULL || - ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed || - 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; - } -} - - -void wpa_tdls_enable(struct wpa_sm *sm, int enabled) -{ - wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); - sm->tdls_disabled = !enabled; -} - - -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; -} -#endif /* __rtems__ && CONFIG_TDLS */ diff --git a/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.c b/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.c deleted file mode 100644 index d38b06eb0..000000000 --- a/freebsd/contrib/wpa/wpa_supplicant/wnm_sta.c +++ /dev/null @@ -1,1168 +0,0 @@ -#include <machine/rtems-bsd-user-space.h> - -/* - * wpa_supplicant - WNM - * Copyright (c) 2011-2013, Qualcomm Atheros, Inc. - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "utils/includes.h" - -#include "utils/common.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "common/wpa_ctrl.h" -#include "rsn_supp/wpa.h" -#include "wpa_supplicant_i.h" -#include "driver_i.h" -#include "scan.h" -#include "ctrl_iface.h" -#include "bss.h" -#include "wnm_sta.h" -#include "hs20_supplicant.h" - -#define MAX_TFS_IE_LEN 1024 -#define WNM_MAX_NEIGHBOR_REPORT 10 - -#if defined(__rtems__) && defined(CONFIG_WNM) - -/* get the TFS IE from driver */ -static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf, - u16 *buf_len, enum wnm_oper oper) -{ - wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper); - - return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len); -} - - -/* set the TFS IE to driver */ -static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s, - const u8 *addr, u8 *buf, u16 *buf_len, - enum wnm_oper oper) -{ - wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper); - - return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len); -} - - -/* MLME-SLEEPMODE.request */ -int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s, - u8 action, u16 intval, struct wpabuf *tfs_req) -{ - struct ieee80211_mgmt *mgmt; - int res; - size_t len; - struct wnm_sleep_element *wnmsleep_ie; - u8 *wnmtfs_ie; - u8 wnmsleep_ie_len; - u16 wnmtfs_ie_len; /* possibly multiple IE(s) */ - enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD : - WNM_SLEEP_TFS_REQ_IE_NONE; - - wpa_printf(MSG_DEBUG, "WNM: Request to send WNM-Sleep Mode Request " - "action=%s to " MACSTR, - action == 0 ? "enter" : "exit", - MAC2STR(wpa_s->bssid)); - - /* WNM-Sleep Mode IE */ - wnmsleep_ie_len = sizeof(struct wnm_sleep_element); - wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element)); - if (wnmsleep_ie == NULL) - return -1; - wnmsleep_ie->eid = WLAN_EID_WNMSLEEP; - wnmsleep_ie->len = wnmsleep_ie_len - 2; - wnmsleep_ie->action_type = action; - wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT; - wnmsleep_ie->intval = host_to_le16(intval); - wpa_hexdump(MSG_DEBUG, "WNM: WNM-Sleep Mode element", - (u8 *) wnmsleep_ie, wnmsleep_ie_len); - - /* TFS IE(s) */ - if (tfs_req) { - wnmtfs_ie_len = wpabuf_len(tfs_req); - wnmtfs_ie = os_malloc(wnmtfs_ie_len); - if (wnmtfs_ie == NULL) { - os_free(wnmsleep_ie); - return -1; - } - os_memcpy(wnmtfs_ie, wpabuf_head(tfs_req), wnmtfs_ie_len); - } else { - wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN); - if (wnmtfs_ie == NULL) { - os_free(wnmsleep_ie); - return -1; - } - if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len, - tfs_oper)) { - wnmtfs_ie_len = 0; - os_free(wnmtfs_ie); - wnmtfs_ie = NULL; - } - } - wpa_hexdump(MSG_DEBUG, "WNM: TFS Request element", - (u8 *) wnmtfs_ie, wnmtfs_ie_len); - - mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len); - if (mgmt == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " - "WNM-Sleep Request action frame"); - os_free(wnmsleep_ie); - os_free(wnmtfs_ie); - return -1; - } - - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ; - mgmt->u.action.u.wnm_sleep_req.dialogtoken = 1; - os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie, - wnmsleep_ie_len); - /* copy TFS IE here */ - if (wnmtfs_ie_len > 0) { - os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable + - wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len); - } - - len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len + - wnmtfs_ie_len; - - res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, - wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); - if (res < 0) - wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request " - "(action=%d, intval=%d)", action, intval); - else - wpa_s->wnmsleep_used = 1; - - os_free(wnmsleep_ie); - os_free(wnmtfs_ie); - os_free(mgmt); - - return res; -} - - -static void wnm_sleep_mode_enter_success(struct wpa_supplicant *wpa_s, - u8 *tfsresp_ie_start, - u8 *tfsresp_ie_end) -{ - wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM, - wpa_s->bssid, NULL, NULL); - /* remove GTK/IGTK ?? */ - - /* set the TFS Resp IE(s) */ - if (tfsresp_ie_start && tfsresp_ie_end && - tfsresp_ie_end - tfsresp_ie_start >= 0) { - u16 tfsresp_ie_len; - tfsresp_ie_len = (tfsresp_ie_end + tfsresp_ie_end[1] + 2) - - tfsresp_ie_start; - wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found"); - /* pass the TFS Resp IE(s) to driver for processing */ - if (ieee80211_11_set_tfs_ie(wpa_s, wpa_s->bssid, - tfsresp_ie_start, - &tfsresp_ie_len, - WNM_SLEEP_TFS_RESP_IE_SET)) - wpa_printf(MSG_DEBUG, "WNM: Fail to set TFS Resp IE"); - } -} - - -static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s, - const u8 *frm, u16 key_len_total) -{ - u8 *ptr, *end; - u8 gtk_len; - - wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM, wpa_s->bssid, - NULL, NULL); - - /* Install GTK/IGTK */ - - /* point to key data field */ - ptr = (u8 *) frm + 1 + 2; - end = ptr + key_len_total; - wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", ptr, key_len_total); - - if (key_len_total && !wpa_sm_pmf_enabled(wpa_s->wpa)) { - wpa_msg(wpa_s, MSG_INFO, - "WNM: Ignore Key Data in WNM-Sleep Mode Response - PMF not enabled"); - return; - } - - while (ptr + 1 < end) { - if (ptr + 2 + ptr[1] > end) { - wpa_printf(MSG_DEBUG, "WNM: Invalid Key Data element " - "length"); - if (end > ptr) { - wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", - ptr, end - ptr); - } - break; - } - if (*ptr == WNM_SLEEP_SUBELEM_GTK) { - if (ptr[1] < 11 + 5) { - wpa_printf(MSG_DEBUG, "WNM: Too short GTK " - "subelem"); - break; - } - gtk_len = *(ptr + 4); - if (ptr[1] < 11 + gtk_len || - gtk_len < 5 || gtk_len > 32) { - wpa_printf(MSG_DEBUG, "WNM: Invalid GTK " - "subelem"); - break; - } - wpa_wnmsleep_install_key( - wpa_s->wpa, - WNM_SLEEP_SUBELEM_GTK, - ptr); - ptr += 13 + gtk_len; -#ifdef CONFIG_IEEE80211W - } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { - if (ptr[1] < 2 + 6 + WPA_IGTK_LEN) { - wpa_printf(MSG_DEBUG, "WNM: Too short IGTK " - "subelem"); - break; - } - wpa_wnmsleep_install_key(wpa_s->wpa, - WNM_SLEEP_SUBELEM_IGTK, ptr); - ptr += 10 + WPA_IGTK_LEN; -#endif /* CONFIG_IEEE80211W */ - } else - break; /* skip the loop */ - } -} - - -static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, - const u8 *frm, int len) -{ - /* - * Action [1] | Dialog Token [1] | Key Data Len [2] | Key Data | - * WNM-Sleep Mode IE | TFS Response IE - */ - u8 *pos = (u8 *) frm; /* point to payload after the action field */ - u16 key_len_total; - struct wnm_sleep_element *wnmsleep_ie = NULL; - /* multiple TFS Resp IE (assuming consecutive) */ - u8 *tfsresp_ie_start = NULL; - u8 *tfsresp_ie_end = NULL; - size_t left; - - if (!wpa_s->wnmsleep_used) { - wpa_printf(MSG_DEBUG, - "WNM: Ignore WNM-Sleep Mode Response frame since WNM-Sleep Mode operation has not been requested"); - return; - } - - if (len < 3) - return; - key_len_total = WPA_GET_LE16(frm + 1); - - wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d", - frm[0], key_len_total); - left = len - 3; - if (key_len_total > left) { - wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); - return; - } - pos += 3 + key_len_total; - while (pos - frm < len) { - u8 ie_len = *(pos + 1); - if (pos + 2 + ie_len > frm + len) { - wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); - break; - } - wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); - if (*pos == WLAN_EID_WNMSLEEP) - wnmsleep_ie = (struct wnm_sleep_element *) pos; - else if (*pos == WLAN_EID_TFS_RESP) { - if (!tfsresp_ie_start) - tfsresp_ie_start = pos; - tfsresp_ie_end = pos; - } else - wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos); - pos += ie_len + 2; - } - - if (!wnmsleep_ie) { - wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found"); - return; - } - - wpa_s->wnmsleep_used = 0; - - if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT || - wnmsleep_ie->status == WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) { - wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response " - "frame (action=%d, intval=%d)", - wnmsleep_ie->action_type, wnmsleep_ie->intval); - if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) { - wnm_sleep_mode_enter_success(wpa_s, tfsresp_ie_start, - tfsresp_ie_end); - } else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) { - wnm_sleep_mode_exit_success(wpa_s, frm, key_len_total); - } - } else { - wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame " - "(action=%d, intval=%d)", - wnmsleep_ie->action_type, wnmsleep_ie->intval); - if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER) - wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL, - wpa_s->bssid, NULL, NULL); - else if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) - wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL, - wpa_s->bssid, NULL, NULL); - } -} - - -void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) -{ - int i; - - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - os_free(wpa_s->wnm_neighbor_report_elements[i].meas_pilot); - os_free(wpa_s->wnm_neighbor_report_elements[i].mul_bssid); - } - - wpa_s->wnm_num_neighbor_report = 0; - os_free(wpa_s->wnm_neighbor_report_elements); - wpa_s->wnm_neighbor_report_elements = NULL; -} - - -static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, - u8 id, u8 elen, const u8 *pos) -{ - switch (id) { - case WNM_NEIGHBOR_TSF: - if (elen < 2 + 2) { - wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); - break; - } - rep->tsf_offset = WPA_GET_LE16(pos); - rep->beacon_int = WPA_GET_LE16(pos + 2); - rep->tsf_present = 1; - break; - case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: - if (elen < 2) { - wpa_printf(MSG_DEBUG, "WNM: Too short condensed " - "country string"); - break; - } - os_memcpy(rep->country, pos, 2); - rep->country_present = 1; - break; - case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: - if (elen < 1) { - wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " - "candidate"); - break; - } - rep->preference = pos[0]; - rep->preference_present = 1; - break; - case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: - rep->bss_term_tsf = WPA_GET_LE64(pos); - rep->bss_term_dur = WPA_GET_LE16(pos + 8); - rep->bss_term_present = 1; - break; - case WNM_NEIGHBOR_BEARING: - if (elen < 8) { - wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " - "bearing"); - break; - } - rep->bearing = WPA_GET_LE16(pos); - rep->distance = WPA_GET_LE32(pos + 2); - rep->rel_height = WPA_GET_LE16(pos + 2 + 4); - rep->bearing_present = 1; - break; - case WNM_NEIGHBOR_MEASUREMENT_PILOT: - if (elen < 1) { - wpa_printf(MSG_DEBUG, "WNM: Too short measurement " - "pilot"); - break; - } - os_free(rep->meas_pilot); - rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); - if (rep->meas_pilot == NULL) - break; - rep->meas_pilot->measurement_pilot = pos[0]; - rep->meas_pilot->subelem_len = elen - 1; - os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); - break; - case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: - if (elen < 5) { - wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " - "capabilities"); - break; - } - os_memcpy(rep->rm_capab, pos, 5); - rep->rm_capab_present = 1; - break; - case WNM_NEIGHBOR_MULTIPLE_BSSID: - if (elen < 1) { - wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); - break; - } - os_free(rep->mul_bssid); - rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); - if (rep->mul_bssid == NULL) - break; - rep->mul_bssid->max_bssid_indicator = pos[0]; - rep->mul_bssid->subelem_len = elen - 1; - os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); - break; - } -} - - -static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan) -{ - struct wpa_bss *bss = wpa_s->current_bss; - const char *country = NULL; - - if (bss) { - const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY); - - if (elem && elem[1] >= 2) - country = (const char *) (elem + 2); - } - - return ieee80211_chan_to_freq(country, op_class, chan); -} - - -static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s, - const u8 *pos, u8 len, - struct neighbor_report *rep) -{ - u8 left = len; - - if (left < 13) { - wpa_printf(MSG_DEBUG, "WNM: Too short neighbor report"); - return; - } - - os_memcpy(rep->bssid, pos, ETH_ALEN); - rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN); - rep->regulatory_class = *(pos + 10); - rep->channel_number = *(pos + 11); - rep->phy_type = *(pos + 12); - - pos += 13; - left -= 13; - - while (left >= 2) { - u8 id, elen; - - id = *pos++; - elen = *pos++; - wpa_printf(MSG_DEBUG, "WNM: Subelement id=%u len=%u", id, elen); - left -= 2; - if (elen > left) { - wpa_printf(MSG_DEBUG, - "WNM: Truncated neighbor report subelement"); - break; - } - wnm_parse_neighbor_report_elem(rep, id, elen, pos); - left -= elen; - pos += elen; - } - - rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class, - rep->channel_number); -} - - -static struct wpa_bss * -compare_scan_neighbor_results(struct wpa_supplicant *wpa_s) -{ - - u8 i; - struct wpa_bss *bss = wpa_s->current_bss; - struct wpa_bss *target; - - if (!bss) - return 0; - - wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", - MAC2STR(wpa_s->bssid), bss->level); - - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - struct neighbor_report *nei; - - nei = &wpa_s->wnm_neighbor_report_elements[i]; - if (nei->preference_present && nei->preference == 0) { - wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, - MAC2STR(nei->bssid)); - continue; - } - - target = wpa_bss_get_bssid(wpa_s, nei->bssid); - if (!target) { - wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR - " (pref %d) not found in scan results", - MAC2STR(nei->bssid), - nei->preference_present ? nei->preference : - -1); - continue; - } - - if (bss->ssid_len != target->ssid_len || - os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { - /* - * TODO: Could consider allowing transition to another - * ESS if PMF was enabled for the association. - */ - wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR - " (pref %d) in different ESS", - MAC2STR(nei->bssid), - nei->preference_present ? nei->preference : - -1); - continue; - } - - if (target->level < bss->level && target->level < -80) { - wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR - " (pref %d) does not have sufficient signal level (%d)", - MAC2STR(nei->bssid), - nei->preference_present ? nei->preference : - -1, - target->level); - continue; - } - - wpa_printf(MSG_DEBUG, - "WNM: Found an acceptable preferred transition candidate BSS " - MACSTR " (RSSI %d)", - MAC2STR(nei->bssid), target->level); - return target; - } - - return NULL; -} - - -static void wnm_send_bss_transition_mgmt_resp( - struct wpa_supplicant *wpa_s, u8 dialog_token, - enum bss_trans_mgmt_status_code status, u8 delay, - const u8 *target_bssid) -{ - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; - int res; - - wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response " - "to " MACSTR " dialog_token=%u status=%u delay=%d", - MAC2STR(wpa_s->bssid), dialog_token, status, delay); - if (!wpa_s->current_bss) { - wpa_printf(MSG_DEBUG, - "WNM: Current BSS not known - drop response"); - return; - } - - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_resp.action = WNM_BSS_TRANS_MGMT_RESP; - mgmt->u.action.u.bss_tm_resp.dialog_token = dialog_token; - mgmt->u.action.u.bss_tm_resp.status_code = status; - mgmt->u.action.u.bss_tm_resp.bss_termination_delay = delay; - pos = mgmt->u.action.u.bss_tm_resp.variable; - if (target_bssid) { - os_memcpy(pos, target_bssid, ETH_ALEN); - pos += ETH_ALEN; - } else if (status == WNM_BSS_TM_ACCEPT) { - /* - * P802.11-REVmc clarifies that the Target BSSID field is always - * present when status code is zero, so use a fake value here if - * no BSSID is yet known. - */ - os_memset(pos, 0, ETH_ALEN); - pos += ETH_ALEN; - } - - len = pos - (u8 *) &mgmt->u.action.category; - - res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, - wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); - if (res < 0) { - wpa_printf(MSG_DEBUG, - "WNM: Failed to send BSS Transition Management Response"); - } -} - - -int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail) -{ - struct wpa_bss *bss; - struct wpa_ssid *ssid = wpa_s->current_ssid; - enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED; - - if (!wpa_s->wnm_neighbor_report_elements) - return 0; - - if (os_reltime_before(&wpa_s->wnm_cand_valid_until, - &wpa_s->scan_trigger_time)) { - wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); - wnm_deallocate_memory(wpa_s); - return 0; - } - - if (!wpa_s->current_bss || - os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid, - ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it"); - return 0; - } - - /* Compare the Neighbor Report and scan results */ - bss = compare_scan_neighbor_results(wpa_s); - if (!bss) { - wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found"); - status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES; - goto send_bss_resp_fail; - } - - /* Associate to the network */ - /* Send the BSS Management Response - Accept */ - if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - WNM_BSS_TM_ACCEPT, - 0, bss->bssid); - } - - if (bss == wpa_s->current_bss) { - wpa_printf(MSG_DEBUG, - "WNM: Already associated with the preferred candidate"); - return 1; - } - - wpa_s->reassociate = 1; - wpa_supplicant_connect(wpa_s, bss, ssid); - wnm_deallocate_memory(wpa_s); - return 1; - -send_bss_resp_fail: - if (!reply_on_fail) - return 0; - - /* Send reject response for all the failures */ - - if (wpa_s->wnm_reply) { - wpa_s->wnm_reply = 0; - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - status, 0, NULL); - } - wnm_deallocate_memory(wpa_s); - - return 0; -} - - -static int cand_pref_compar(const void *a, const void *b) -{ - const struct neighbor_report *aa = a; - const struct neighbor_report *bb = b; - - if (!aa->preference_present && !bb->preference_present) - return 0; - if (!aa->preference_present) - return 1; - if (!bb->preference_present) - return -1; - if (bb->preference > aa->preference) - return 1; - if (bb->preference < aa->preference) - return -1; - return 0; -} - - -static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s) -{ - if (!wpa_s->wnm_neighbor_report_elements) - return; - qsort(wpa_s->wnm_neighbor_report_elements, - wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report), - cand_pref_compar); -} - - -static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s) -{ - unsigned int i; - - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List"); - if (!wpa_s->wnm_neighbor_report_elements) - return; - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - struct neighbor_report *nei; - - nei = &wpa_s->wnm_neighbor_report_elements[i]; - wpa_printf(MSG_DEBUG, "%u: " MACSTR - " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d", - i, MAC2STR(nei->bssid), nei->bssid_info, - nei->regulatory_class, - nei->channel_number, nei->phy_type, - nei->preference_present ? nei->preference : -1, - nei->freq); - } -} - - -static int chan_supported(struct wpa_supplicant *wpa_s, int freq) -{ - unsigned int i; - - for (i = 0; i < wpa_s->hw.num_modes; i++) { - struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i]; - int j; - - for (j = 0; j < mode->num_channels; j++) { - struct hostapd_channel_data *chan; - - chan = &mode->channels[j]; - if (chan->freq == freq && - !(chan->flag & HOSTAPD_CHAN_DISABLED)) - return 1; - } - } - - return 0; -} - - -static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s) -{ - int *freqs; - int num_freqs = 0; - unsigned int i; - - if (!wpa_s->wnm_neighbor_report_elements) - return; - - if (wpa_s->hw.modes == NULL) - return; - - os_free(wpa_s->next_scan_freqs); - wpa_s->next_scan_freqs = NULL; - - freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int)); - if (freqs == NULL) - return; - - for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { - struct neighbor_report *nei; - - nei = &wpa_s->wnm_neighbor_report_elements[i]; - if (nei->freq <= 0) { - wpa_printf(MSG_DEBUG, - "WNM: Unknown neighbor operating frequency for " - MACSTR " - scan all channels", - MAC2STR(nei->bssid)); - os_free(freqs); - return; - } - if (chan_supported(wpa_s, nei->freq)) - add_freq(freqs, &num_freqs, nei->freq); - } - - if (num_freqs == 0) { - os_free(freqs); - return; - } - - wpa_printf(MSG_DEBUG, - "WNM: Scan %d frequencies based on transition candidate list", - num_freqs); - wpa_s->next_scan_freqs = freqs; -} - - -static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, - const u8 *pos, const u8 *end, - int reply) -{ - unsigned int beacon_int; - u8 valid_int; - - if (pos + 5 > end) - return; - - if (wpa_s->current_bss) - beacon_int = wpa_s->current_bss->beacon_int; - else - beacon_int = 100; /* best guess */ - - wpa_s->wnm_dialog_token = pos[0]; - wpa_s->wnm_mode = pos[1]; - wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); - valid_int = pos[4]; - wpa_s->wnm_reply = reply; - - wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " - "dialog_token=%u request_mode=0x%x " - "disassoc_timer=%u validity_interval=%u", - wpa_s->wnm_dialog_token, wpa_s->wnm_mode, - wpa_s->wnm_dissoc_timer, valid_int); - - pos += 5; - - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { - if (pos + 12 > end) { - wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); - return; - } - os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); - pos += 12; /* BSS Termination Duration */ - } - - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { - char url[256]; - - if (pos + 1 > end || pos + 1 + pos[0] > end) { - wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " - "Management Request (URL)"); - return; - } - os_memcpy(url, pos + 1, pos[0]); - url[pos[0]] = '\0'; - pos += 1 + pos[0]; - - wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", - wpa_sm_pmf_enabled(wpa_s->wpa), - wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); - } - - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { - wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " - "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); - if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { - /* TODO: mark current BSS less preferred for - * selection */ - wpa_printf(MSG_DEBUG, "Trying to find another BSS"); - wpa_supplicant_req_scan(wpa_s, 0, 0); - } - } - - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { - unsigned int valid_ms; - - wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); - wnm_deallocate_memory(wpa_s); - wpa_s->wnm_neighbor_report_elements = os_calloc( - WNM_MAX_NEIGHBOR_REPORT, - sizeof(struct neighbor_report)); - if (wpa_s->wnm_neighbor_report_elements == NULL) - return; - - while (pos + 2 <= end && - wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) - { - u8 tag = *pos++; - u8 len = *pos++; - - wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", - tag); - if (pos + len > end) { - wpa_printf(MSG_DEBUG, "WNM: Truncated request"); - return; - } - if (tag == WLAN_EID_NEIGHBOR_REPORT) { - struct neighbor_report *rep; - rep = &wpa_s->wnm_neighbor_report_elements[ - wpa_s->wnm_num_neighbor_report]; - wnm_parse_neighbor_report(wpa_s, pos, len, rep); - } - - pos += len; - wpa_s->wnm_num_neighbor_report++; - } - wnm_sort_cand_list(wpa_s); - wnm_dump_cand_list(wpa_s); - valid_ms = valid_int * beacon_int * 128 / 125; - wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", - valid_ms); - os_get_reltime(&wpa_s->wnm_cand_valid_until); - wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; - wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; - wpa_s->wnm_cand_valid_until.sec += - wpa_s->wnm_cand_valid_until.usec / 1000000; - wpa_s->wnm_cand_valid_until.usec %= 1000000; - os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); - - if (wpa_s->last_scan_res_used > 0) { - struct os_reltime now; - - os_get_reltime(&now); - if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { - wpa_printf(MSG_DEBUG, - "WNM: Try to use recent scan results"); - if (wnm_scan_process(wpa_s, 0) > 0) - return; - wpa_printf(MSG_DEBUG, - "WNM: No match in previous scan results - try a new scan"); - } - } - - wnm_set_scan_freqs(wpa_s); - wpa_supplicant_req_scan(wpa_s, 0, 0); - } else if (reply) { - enum bss_trans_mgmt_status_code status; - if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) - status = WNM_BSS_TM_ACCEPT; - else { - wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); - status = WNM_BSS_TM_REJECT_UNSPECIFIED; - } - wnm_send_bss_transition_mgmt_resp(wpa_s, - wpa_s->wnm_dialog_token, - status, 0, NULL); - } -} - - -int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s, - u8 query_reason) -{ - u8 buf[1000], *pos; - struct ieee80211_mgmt *mgmt; - size_t len; - int ret; - - wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Query to " - MACSTR " query_reason=%u", - MAC2STR(wpa_s->bssid), query_reason); - - mgmt = (struct ieee80211_mgmt *) buf; - os_memset(&buf, 0, sizeof(buf)); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WNM; - mgmt->u.action.u.bss_tm_query.action = WNM_BSS_TRANS_MGMT_QUERY; - mgmt->u.action.u.bss_tm_query.dialog_token = 1; - mgmt->u.action.u.bss_tm_query.query_reason = query_reason; - pos = mgmt->u.action.u.bss_tm_query.variable; - - len = pos - (u8 *) &mgmt->u.action.category; - - ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid, - wpa_s->own_addr, wpa_s->bssid, - &mgmt->u.action.category, len, 0); - - return ret; -} - - -static void ieee802_11_rx_wnm_notif_req_wfa(struct wpa_supplicant *wpa_s, - const u8 *sa, const u8 *data, - int len) -{ - const u8 *pos, *end, *next; - u8 ie, ie_len; - - pos = data; - end = data + len; - - while (pos + 1 < end) { - ie = *pos++; - ie_len = *pos++; - wpa_printf(MSG_DEBUG, "WNM: WFA subelement %u len %u", - ie, ie_len); - if (ie_len > end - pos) { - wpa_printf(MSG_DEBUG, "WNM: Not enough room for " - "subelement"); - break; - } - next = pos + ie_len; - if (ie_len < 4) { - pos = next; - continue; - } - wpa_printf(MSG_DEBUG, "WNM: Subelement OUI %06x type %u", - WPA_GET_BE24(pos), pos[3]); - -#ifdef CONFIG_HS20 - if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 5 && - WPA_GET_BE24(pos) == OUI_WFA && - pos[3] == HS20_WNM_SUB_REM_NEEDED) { - /* Subscription Remediation subelement */ - const u8 *ie_end; - u8 url_len; - char *url; - u8 osu_method; - - wpa_printf(MSG_DEBUG, "WNM: Subscription Remediation " - "subelement"); - ie_end = pos + ie_len; - pos += 4; - url_len = *pos++; - if (url_len == 0) { - wpa_printf(MSG_DEBUG, "WNM: No Server URL included"); - url = NULL; - osu_method = 1; - } else { - if (pos + url_len + 1 > ie_end) { - wpa_printf(MSG_DEBUG, "WNM: Not enough room for Server URL (len=%u) and Server Method (left %d)", - url_len, - (int) (ie_end - pos)); - break; - } - url = os_malloc(url_len + 1); - if (url == NULL) - break; - os_memcpy(url, pos, url_len); - url[url_len] = '\0'; - osu_method = pos[url_len]; - } - hs20_rx_subscription_remediation(wpa_s, url, - osu_method); - os_free(url); - pos = next; - continue; - } - - if (ie == WLAN_EID_VENDOR_SPECIFIC && ie_len >= 8 && - WPA_GET_BE24(pos) == OUI_WFA && - pos[3] == HS20_WNM_DEAUTH_IMMINENT_NOTICE) { - const u8 *ie_end; - u8 url_len; - char *url; - u8 code; - u16 reauth_delay; - - ie_end = pos + ie_len; - pos += 4; - code = *pos++; - reauth_delay = WPA_GET_LE16(pos); - pos += 2; - url_len = *pos++; - wpa_printf(MSG_DEBUG, "WNM: HS 2.0 Deauthentication " - "Imminent - Reason Code %u " - "Re-Auth Delay %u URL Length %u", - code, reauth_delay, url_len); - if (pos + url_len > ie_end) - break; - url = os_malloc(url_len + 1); - if (url == NULL) - break; - os_memcpy(url, pos, url_len); - url[url_len] = '\0'; - hs20_rx_deauth_imminent_notice(wpa_s, code, - reauth_delay, url); - os_free(url); - pos = next; - continue; - } -#endif /* CONFIG_HS20 */ - - pos = next; - } -} - - -static void ieee802_11_rx_wnm_notif_req(struct wpa_supplicant *wpa_s, - const u8 *sa, const u8 *frm, int len) -{ - const u8 *pos, *end; - u8 dialog_token, type; - - /* Dialog Token [1] | Type [1] | Subelements */ - - if (len < 2 || sa == NULL) - return; - end = frm + len; - pos = frm; - dialog_token = *pos++; - type = *pos++; - - wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Received WNM-Notification Request " - "(dialog_token %u type %u sa " MACSTR ")", - dialog_token, type, MAC2STR(sa)); - wpa_hexdump(MSG_DEBUG, "WNM-Notification Request subelements", - pos, end - pos); - - if (wpa_s->wpa_state != WPA_COMPLETED || - os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) { - wpa_dbg(wpa_s, MSG_DEBUG, "WNM: WNM-Notification frame not " - "from our AP - ignore it"); - return; - } - - switch (type) { - case 1: - ieee802_11_rx_wnm_notif_req_wfa(wpa_s, sa, pos, end - pos); - break; - default: - wpa_dbg(wpa_s, MSG_DEBUG, "WNM: Ignore unknown " - "WNM-Notification type %u", type); - break; - } -} - - -void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s, - const struct ieee80211_mgmt *mgmt, size_t len) -{ - const u8 *pos, *end; - u8 act; - - if (len < IEEE80211_HDRLEN + 2) - return; - - pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; - act = *pos++; - end = ((const u8 *) mgmt) + len; - - wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR, - act, MAC2STR(mgmt->sa)); - if (wpa_s->wpa_state < WPA_ASSOCIATED || - os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "WNM: Ignore unexpected WNM Action " - "frame"); - return; - } - - switch (act) { - case WNM_BSS_TRANS_MGMT_REQ: - ieee802_11_rx_bss_trans_mgmt_req(wpa_s, pos, end, - !(mgmt->da[0] & 0x01)); - break; - case WNM_SLEEP_MODE_RESP: - ieee802_11_rx_wnmsleep_resp(wpa_s, pos, end - pos); - break; - case WNM_NOTIFICATION_REQ: - ieee802_11_rx_wnm_notif_req(wpa_s, mgmt->sa, pos, end - pos); - break; - default: - wpa_printf(MSG_ERROR, "WNM: Unknown request"); - break; - } -} -#endif /* __rtems__ && CONFIG_WNM */ diff --git a/libbsd.py b/libbsd.py index a8c6048aa..2429c0a94 100644 --- a/libbsd.py +++ b/libbsd.py @@ -4422,7 +4422,6 @@ class usr_sbin_wpa_supplicant(builder.Module): 'contrib/wpa/wpa_supplicant/offchannel.c', 'contrib/wpa/wpa_supplicant/scan.c', 'contrib/wpa/wpa_supplicant/wmm_ac.c', - 'contrib/wpa/wpa_supplicant/wnm_sta.c', 'contrib/wpa/wpa_supplicant/wpa_supplicant.c', 'contrib/wpa/wpa_supplicant/wpas_glue.c', 'contrib/wpa/wpa_supplicant/wps_supplicant.c', @@ -4468,7 +4467,6 @@ class usr_sbin_wpa_supplicant(builder.Module): 'contrib/wpa/src/rsn_supp/peerkey.c', 'contrib/wpa/src/rsn_supp/pmksa_cache.c', 'contrib/wpa/src/rsn_supp/preauth.c', - 'contrib/wpa/src/rsn_supp/tdls.c', 'contrib/wpa/src/rsn_supp/wpa.c', 'contrib/wpa/src/rsn_supp/wpa_ft.c', 'contrib/wpa/src/rsn_supp/wpa_ie.c', -- 2.13.7 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel