1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * wpa_supplicant - TDLS 3f05cddf9SRui Paulo * Copyright (c) 2010-2011, Atheros Communications 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "utils/includes.h" 10f05cddf9SRui Paulo 11f05cddf9SRui Paulo #include "utils/common.h" 12f05cddf9SRui Paulo #include "utils/eloop.h" 13f05cddf9SRui Paulo #include "utils/os.h" 14f05cddf9SRui Paulo #include "common/ieee802_11_defs.h" 15*325151a3SRui Paulo #include "common/ieee802_11_common.h" 16f05cddf9SRui Paulo #include "crypto/sha256.h" 17f05cddf9SRui Paulo #include "crypto/crypto.h" 18f05cddf9SRui Paulo #include "crypto/aes_wrap.h" 19f05cddf9SRui Paulo #include "rsn_supp/wpa.h" 20f05cddf9SRui Paulo #include "rsn_supp/wpa_ie.h" 21f05cddf9SRui Paulo #include "rsn_supp/wpa_i.h" 22f05cddf9SRui Paulo #include "drivers/driver.h" 23f05cddf9SRui Paulo #include "l2_packet/l2_packet.h" 24f05cddf9SRui Paulo 25f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 26f05cddf9SRui Paulo #define TDLS_TESTING_LONG_FRAME BIT(0) 27f05cddf9SRui Paulo #define TDLS_TESTING_ALT_RSN_IE BIT(1) 28f05cddf9SRui Paulo #define TDLS_TESTING_DIFF_BSSID BIT(2) 29f05cddf9SRui Paulo #define TDLS_TESTING_SHORT_LIFETIME BIT(3) 30f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) 31f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) 32f05cddf9SRui Paulo #define TDLS_TESTING_LONG_LIFETIME BIT(6) 33f05cddf9SRui Paulo #define TDLS_TESTING_CONCURRENT_INIT BIT(7) 34f05cddf9SRui Paulo #define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8) 35f05cddf9SRui Paulo #define TDLS_TESTING_DECLINE_RESP BIT(9) 36f05cddf9SRui Paulo #define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10) 375b9c547cSRui Paulo #define TDLS_TESTING_WRONG_MIC BIT(11) 38f05cddf9SRui Paulo unsigned int tdls_testing = 0; 39f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 40f05cddf9SRui Paulo 41f05cddf9SRui Paulo #define TPK_LIFETIME 43200 /* 12 hours */ 425b9c547cSRui Paulo #define TPK_M1_RETRY_COUNT 3 435b9c547cSRui Paulo #define TPK_M1_TIMEOUT 5000 /* in milliseconds */ 445b9c547cSRui Paulo #define TPK_M2_RETRY_COUNT 10 455b9c547cSRui Paulo #define TPK_M2_TIMEOUT 500 /* in milliseconds */ 46f05cddf9SRui Paulo 47f05cddf9SRui Paulo #define TDLS_MIC_LEN 16 48f05cddf9SRui Paulo 49f05cddf9SRui Paulo #define TDLS_TIMEOUT_LEN 4 50f05cddf9SRui Paulo 51f05cddf9SRui Paulo struct wpa_tdls_ftie { 52f05cddf9SRui Paulo u8 ie_type; /* FTIE */ 53f05cddf9SRui Paulo u8 ie_len; 54f05cddf9SRui Paulo u8 mic_ctrl[2]; 55f05cddf9SRui Paulo u8 mic[TDLS_MIC_LEN]; 56f05cddf9SRui Paulo u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ 57f05cddf9SRui Paulo u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ 58f05cddf9SRui Paulo /* followed by optional elements */ 59f05cddf9SRui Paulo } STRUCT_PACKED; 60f05cddf9SRui Paulo 61f05cddf9SRui Paulo struct wpa_tdls_timeoutie { 62f05cddf9SRui Paulo u8 ie_type; /* Timeout IE */ 63f05cddf9SRui Paulo u8 ie_len; 64f05cddf9SRui Paulo u8 interval_type; 65f05cddf9SRui Paulo u8 value[TDLS_TIMEOUT_LEN]; 66f05cddf9SRui Paulo } STRUCT_PACKED; 67f05cddf9SRui Paulo 68f05cddf9SRui Paulo struct wpa_tdls_lnkid { 69f05cddf9SRui Paulo u8 ie_type; /* Link Identifier IE */ 70f05cddf9SRui Paulo u8 ie_len; 71f05cddf9SRui Paulo u8 bssid[ETH_ALEN]; 72f05cddf9SRui Paulo u8 init_sta[ETH_ALEN]; 73f05cddf9SRui Paulo u8 resp_sta[ETH_ALEN]; 74f05cddf9SRui Paulo } STRUCT_PACKED; 75f05cddf9SRui Paulo 76f05cddf9SRui Paulo /* TDLS frame headers as per IEEE Std 802.11z-2010 */ 77f05cddf9SRui Paulo struct wpa_tdls_frame { 78f05cddf9SRui Paulo u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ 79f05cddf9SRui Paulo u8 category; /* Category */ 80f05cddf9SRui Paulo u8 action; /* Action (enum tdls_frame_type) */ 81f05cddf9SRui Paulo } STRUCT_PACKED; 82f05cddf9SRui Paulo 83f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs); 84f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); 85f05cddf9SRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); 865b9c547cSRui Paulo static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, 875b9c547cSRui Paulo struct wpa_tdls_peer *peer); 885b9c547cSRui Paulo static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, 895b9c547cSRui Paulo u16 reason_code); 90f05cddf9SRui Paulo 91f05cddf9SRui Paulo 92f05cddf9SRui Paulo #define TDLS_MAX_IE_LEN 80 93f05cddf9SRui Paulo #define IEEE80211_MAX_SUPP_RATES 32 94f05cddf9SRui Paulo 95f05cddf9SRui Paulo struct wpa_tdls_peer { 96f05cddf9SRui Paulo struct wpa_tdls_peer *next; 975b9c547cSRui Paulo unsigned int reconfig_key:1; 98f05cddf9SRui Paulo int initiator; /* whether this end was initiator for TDLS setup */ 99f05cddf9SRui Paulo u8 addr[ETH_ALEN]; /* other end MAC address */ 100f05cddf9SRui Paulo u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ 101f05cddf9SRui Paulo u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ 102f05cddf9SRui Paulo u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ 103f05cddf9SRui Paulo size_t rsnie_i_len; 104f05cddf9SRui Paulo u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ 105f05cddf9SRui Paulo size_t rsnie_p_len; 106f05cddf9SRui Paulo u32 lifetime; 107f05cddf9SRui Paulo int cipher; /* Selected cipher (WPA_CIPHER_*) */ 108f05cddf9SRui Paulo u8 dtoken; 109f05cddf9SRui Paulo 110f05cddf9SRui Paulo struct tpk { 111f05cddf9SRui Paulo u8 kck[16]; /* TPK-KCK */ 112f05cddf9SRui Paulo u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ 113f05cddf9SRui Paulo } tpk; 114f05cddf9SRui Paulo int tpk_set; 115f05cddf9SRui Paulo int tpk_success; 1165b9c547cSRui Paulo int tpk_in_progress; 117f05cddf9SRui Paulo 118f05cddf9SRui Paulo struct tpk_timer { 119f05cddf9SRui Paulo u8 dest[ETH_ALEN]; 120f05cddf9SRui Paulo int count; /* Retry Count */ 121f05cddf9SRui Paulo int timer; /* Timeout in milliseconds */ 122f05cddf9SRui Paulo u8 action_code; /* TDLS frame type */ 123f05cddf9SRui Paulo u8 dialog_token; 124f05cddf9SRui Paulo u16 status_code; 1255b9c547cSRui Paulo u32 peer_capab; 126f05cddf9SRui Paulo int buf_len; /* length of TPK message for retransmission */ 127f05cddf9SRui Paulo u8 *buf; /* buffer for TPK message */ 128f05cddf9SRui Paulo } sm_tmr; 129f05cddf9SRui Paulo 130f05cddf9SRui Paulo u16 capability; 131f05cddf9SRui Paulo 132f05cddf9SRui Paulo u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 133f05cddf9SRui Paulo size_t supp_rates_len; 1345b9c547cSRui Paulo 1355b9c547cSRui Paulo struct ieee80211_ht_capabilities *ht_capabilities; 1365b9c547cSRui Paulo struct ieee80211_vht_capabilities *vht_capabilities; 1375b9c547cSRui Paulo 1385b9c547cSRui Paulo u8 qos_info; 1395b9c547cSRui Paulo 1405b9c547cSRui Paulo u16 aid; 1415b9c547cSRui Paulo 1425b9c547cSRui Paulo u8 *ext_capab; 1435b9c547cSRui Paulo size_t ext_capab_len; 1445b9c547cSRui Paulo 1455b9c547cSRui Paulo u8 *supp_channels; 1465b9c547cSRui Paulo size_t supp_channels_len; 1475b9c547cSRui Paulo 1485b9c547cSRui Paulo u8 *supp_oper_classes; 1495b9c547cSRui Paulo size_t supp_oper_classes_len; 1505b9c547cSRui Paulo 1515b9c547cSRui Paulo u8 wmm_capable; 1525b9c547cSRui Paulo 1535b9c547cSRui Paulo /* channel switch currently enabled */ 1545b9c547cSRui Paulo int chan_switch_enabled; 155f05cddf9SRui Paulo }; 156f05cddf9SRui Paulo 157f05cddf9SRui Paulo 158f05cddf9SRui Paulo static int wpa_tdls_get_privacy(struct wpa_sm *sm) 159f05cddf9SRui Paulo { 160f05cddf9SRui Paulo /* 161f05cddf9SRui Paulo * Get info needed from supplicant to check if the current BSS supports 162f05cddf9SRui Paulo * security. Other than OPEN mode, rest are considered secured 163f05cddf9SRui Paulo * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. 164f05cddf9SRui Paulo */ 165f05cddf9SRui Paulo return sm->pairwise_cipher != WPA_CIPHER_NONE; 166f05cddf9SRui Paulo } 167f05cddf9SRui Paulo 168f05cddf9SRui Paulo 169f05cddf9SRui Paulo static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) 170f05cddf9SRui Paulo { 171f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 172f05cddf9SRui Paulo return pos + ie_len; 173f05cddf9SRui Paulo } 174f05cddf9SRui Paulo 175f05cddf9SRui Paulo 176f05cddf9SRui Paulo static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 177f05cddf9SRui Paulo { 178f05cddf9SRui Paulo if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, 179f05cddf9SRui Paulo 0, 0, NULL, 0, NULL, 0) < 0) { 180f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " 181f05cddf9SRui Paulo "the driver"); 182f05cddf9SRui Paulo return -1; 183f05cddf9SRui Paulo } 184f05cddf9SRui Paulo 185f05cddf9SRui Paulo return 0; 186f05cddf9SRui Paulo } 187f05cddf9SRui Paulo 188f05cddf9SRui Paulo 189f05cddf9SRui Paulo static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 190f05cddf9SRui Paulo { 191f05cddf9SRui Paulo u8 key_len; 192f05cddf9SRui Paulo u8 rsc[6]; 193f05cddf9SRui Paulo enum wpa_alg alg; 194f05cddf9SRui Paulo 195f05cddf9SRui Paulo os_memset(rsc, 0, 6); 196f05cddf9SRui Paulo 197f05cddf9SRui Paulo switch (peer->cipher) { 198f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 199f05cddf9SRui Paulo alg = WPA_ALG_CCMP; 200f05cddf9SRui Paulo key_len = 16; 201f05cddf9SRui Paulo break; 202f05cddf9SRui Paulo case WPA_CIPHER_NONE: 203f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " 204f05cddf9SRui Paulo "NONE - do not use pairwise keys"); 205f05cddf9SRui Paulo return -1; 206f05cddf9SRui Paulo default: 207f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", 208f05cddf9SRui Paulo sm->pairwise_cipher); 209f05cddf9SRui Paulo return -1; 210f05cddf9SRui Paulo } 211f05cddf9SRui Paulo 212f05cddf9SRui Paulo if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, 213f05cddf9SRui Paulo rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { 214f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " 215f05cddf9SRui Paulo "driver"); 216f05cddf9SRui Paulo return -1; 217f05cddf9SRui Paulo } 218f05cddf9SRui Paulo return 0; 219f05cddf9SRui Paulo } 220f05cddf9SRui Paulo 221f05cddf9SRui Paulo 222f05cddf9SRui Paulo static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, 223f05cddf9SRui Paulo u8 action_code, u8 dialog_token, 2245b9c547cSRui Paulo u16 status_code, u32 peer_capab, 2255b9c547cSRui Paulo int initiator, const u8 *buf, size_t len) 226f05cddf9SRui Paulo { 227f05cddf9SRui Paulo return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, 2285b9c547cSRui Paulo status_code, peer_capab, initiator, buf, 2295b9c547cSRui Paulo len); 230f05cddf9SRui Paulo } 231f05cddf9SRui Paulo 232f05cddf9SRui Paulo 233f05cddf9SRui Paulo static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, 2345b9c547cSRui Paulo u8 dialog_token, u16 status_code, u32 peer_capab, 2355b9c547cSRui Paulo int initiator, const u8 *msg, size_t msg_len) 236f05cddf9SRui Paulo { 237f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 238f05cddf9SRui Paulo 239f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " 2405b9c547cSRui Paulo "dialog_token=%u status_code=%u peer_capab=%u initiator=%d " 2415b9c547cSRui Paulo "msg_len=%u", 242f05cddf9SRui Paulo MAC2STR(dest), action_code, dialog_token, status_code, 2435b9c547cSRui Paulo peer_capab, initiator, (unsigned int) msg_len); 244f05cddf9SRui Paulo 245f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, 2465b9c547cSRui Paulo status_code, peer_capab, initiator, msg, 2475b9c547cSRui Paulo msg_len)) { 248f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to send message " 249f05cddf9SRui Paulo "(action_code=%u)", action_code); 250f05cddf9SRui Paulo return -1; 251f05cddf9SRui Paulo } 252f05cddf9SRui Paulo 253f05cddf9SRui Paulo if (action_code == WLAN_TDLS_SETUP_CONFIRM || 254f05cddf9SRui Paulo action_code == WLAN_TDLS_TEARDOWN || 255f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_REQUEST || 256f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_RESPONSE) 257f05cddf9SRui Paulo return 0; /* No retries */ 258f05cddf9SRui Paulo 259f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 260f05cddf9SRui Paulo if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) 261f05cddf9SRui Paulo break; 262f05cddf9SRui Paulo } 263f05cddf9SRui Paulo 264f05cddf9SRui Paulo if (peer == NULL) { 265f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 266f05cddf9SRui Paulo "retry " MACSTR, MAC2STR(dest)); 267f05cddf9SRui Paulo return 0; 268f05cddf9SRui Paulo } 269f05cddf9SRui Paulo 270f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 271f05cddf9SRui Paulo 2725b9c547cSRui Paulo if (action_code == WLAN_TDLS_SETUP_RESPONSE) { 2735b9c547cSRui Paulo peer->sm_tmr.count = TPK_M2_RETRY_COUNT; 2745b9c547cSRui Paulo peer->sm_tmr.timer = TPK_M2_TIMEOUT; 2755b9c547cSRui Paulo } else { 2765b9c547cSRui Paulo peer->sm_tmr.count = TPK_M1_RETRY_COUNT; 2775b9c547cSRui Paulo peer->sm_tmr.timer = TPK_M1_TIMEOUT; 2785b9c547cSRui Paulo } 279f05cddf9SRui Paulo 280f05cddf9SRui Paulo /* Copy message to resend on timeout */ 281f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); 282f05cddf9SRui Paulo peer->sm_tmr.action_code = action_code; 283f05cddf9SRui Paulo peer->sm_tmr.dialog_token = dialog_token; 284f05cddf9SRui Paulo peer->sm_tmr.status_code = status_code; 2855b9c547cSRui Paulo peer->sm_tmr.peer_capab = peer_capab; 286f05cddf9SRui Paulo peer->sm_tmr.buf_len = msg_len; 287f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 288f05cddf9SRui Paulo peer->sm_tmr.buf = os_malloc(msg_len); 289f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) 290f05cddf9SRui Paulo return -1; 291f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.buf, msg, msg_len); 292f05cddf9SRui Paulo 293f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " 294f05cddf9SRui Paulo "(action_code=%u)", action_code); 2955b9c547cSRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 2965b9c547cSRui Paulo (peer->sm_tmr.timer % 1000) * 1000, 297f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 298f05cddf9SRui Paulo return 0; 299f05cddf9SRui Paulo } 300f05cddf9SRui Paulo 301f05cddf9SRui Paulo 302f05cddf9SRui Paulo static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 3035b9c547cSRui Paulo u16 reason_code) 304f05cddf9SRui Paulo { 305f05cddf9SRui Paulo int ret; 306f05cddf9SRui Paulo 307f05cddf9SRui Paulo ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code); 308f05cddf9SRui Paulo /* disable the link after teardown was sent */ 3095b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 310f05cddf9SRui Paulo 311f05cddf9SRui Paulo return ret; 312f05cddf9SRui Paulo } 313f05cddf9SRui Paulo 314f05cddf9SRui Paulo 315f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) 316f05cddf9SRui Paulo { 317f05cddf9SRui Paulo 318f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 319f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 320f05cddf9SRui Paulo 321f05cddf9SRui Paulo if (peer->sm_tmr.count) { 322f05cddf9SRui Paulo peer->sm_tmr.count--; 323f05cddf9SRui Paulo 324f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " 325f05cddf9SRui Paulo "(action_code=%u)", 326f05cddf9SRui Paulo peer->sm_tmr.action_code); 327f05cddf9SRui Paulo 328f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) { 329f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No retry buffer available " 330f05cddf9SRui Paulo "for action_code=%u", 331f05cddf9SRui Paulo peer->sm_tmr.action_code); 332f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, 333f05cddf9SRui Paulo peer); 334f05cddf9SRui Paulo return; 335f05cddf9SRui Paulo } 336f05cddf9SRui Paulo 337f05cddf9SRui Paulo /* resend TPK Handshake Message to Peer */ 338f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, 339f05cddf9SRui Paulo peer->sm_tmr.action_code, 340f05cddf9SRui Paulo peer->sm_tmr.dialog_token, 341f05cddf9SRui Paulo peer->sm_tmr.status_code, 3425b9c547cSRui Paulo peer->sm_tmr.peer_capab, 3435b9c547cSRui Paulo peer->initiator, 344f05cddf9SRui Paulo peer->sm_tmr.buf, 345f05cddf9SRui Paulo peer->sm_tmr.buf_len)) { 346f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to retry " 347f05cddf9SRui Paulo "transmission"); 348f05cddf9SRui Paulo } 349f05cddf9SRui Paulo 350f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 3515b9c547cSRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 3525b9c547cSRui Paulo (peer->sm_tmr.timer % 1000) * 1000, 353f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 354f05cddf9SRui Paulo } else { 355f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 356f05cddf9SRui Paulo 357f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request"); 358f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 3595b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 360f05cddf9SRui Paulo } 361f05cddf9SRui Paulo } 362f05cddf9SRui Paulo 363f05cddf9SRui Paulo 364f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, 365f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 366f05cddf9SRui Paulo u8 action_code) 367f05cddf9SRui Paulo { 368f05cddf9SRui Paulo if (action_code == peer->sm_tmr.action_code) { 369f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " 370f05cddf9SRui Paulo "action_code=%u", action_code); 371f05cddf9SRui Paulo 372f05cddf9SRui Paulo /* Cancel Timeout registered */ 373f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 374f05cddf9SRui Paulo 375f05cddf9SRui Paulo /* free all resources meant for retry */ 376f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 377f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 378f05cddf9SRui Paulo 379f05cddf9SRui Paulo peer->sm_tmr.count = 0; 380f05cddf9SRui Paulo peer->sm_tmr.timer = 0; 381f05cddf9SRui Paulo peer->sm_tmr.buf_len = 0; 382f05cddf9SRui Paulo peer->sm_tmr.action_code = 0xff; 383f05cddf9SRui Paulo } else { 384f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " 385f05cddf9SRui Paulo "(Unknown action_code=%u)", action_code); 386f05cddf9SRui Paulo } 387f05cddf9SRui Paulo } 388f05cddf9SRui Paulo 389f05cddf9SRui Paulo 390f05cddf9SRui Paulo static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, 391f05cddf9SRui Paulo const u8 *own_addr, const u8 *bssid) 392f05cddf9SRui Paulo { 393f05cddf9SRui Paulo u8 key_input[SHA256_MAC_LEN]; 394f05cddf9SRui Paulo const u8 *nonce[2]; 395f05cddf9SRui Paulo size_t len[2]; 396f05cddf9SRui Paulo u8 data[3 * ETH_ALEN]; 397f05cddf9SRui Paulo 398f05cddf9SRui Paulo /* IEEE Std 802.11z-2010 8.5.9.1: 399f05cddf9SRui Paulo * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) 400f05cddf9SRui Paulo */ 401f05cddf9SRui Paulo len[0] = WPA_NONCE_LEN; 402f05cddf9SRui Paulo len[1] = WPA_NONCE_LEN; 403f05cddf9SRui Paulo if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { 404f05cddf9SRui Paulo nonce[0] = peer->inonce; 405f05cddf9SRui Paulo nonce[1] = peer->rnonce; 406f05cddf9SRui Paulo } else { 407f05cddf9SRui Paulo nonce[0] = peer->rnonce; 408f05cddf9SRui Paulo nonce[1] = peer->inonce; 409f05cddf9SRui Paulo } 410f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); 411f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); 412f05cddf9SRui Paulo sha256_vector(2, nonce, len, key_input); 413f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", 414f05cddf9SRui Paulo key_input, SHA256_MAC_LEN); 415f05cddf9SRui Paulo 416f05cddf9SRui Paulo /* 417f05cddf9SRui Paulo * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", 418f05cddf9SRui Paulo * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) 419f05cddf9SRui Paulo * TODO: is N_KEY really included in KDF Context and if so, in which 420f05cddf9SRui Paulo * presentation format (little endian 16-bit?) is it used? It gets 421f05cddf9SRui Paulo * added by the KDF anyway.. 422f05cddf9SRui Paulo */ 423f05cddf9SRui Paulo 424f05cddf9SRui Paulo if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { 425f05cddf9SRui Paulo os_memcpy(data, own_addr, ETH_ALEN); 426f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); 427f05cddf9SRui Paulo } else { 428f05cddf9SRui Paulo os_memcpy(data, peer->addr, ETH_ALEN); 429f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); 430f05cddf9SRui Paulo } 431f05cddf9SRui Paulo os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); 432f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); 433f05cddf9SRui Paulo 434f05cddf9SRui Paulo sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), 435f05cddf9SRui Paulo (u8 *) &peer->tpk, sizeof(peer->tpk)); 436f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", 437f05cddf9SRui Paulo peer->tpk.kck, sizeof(peer->tpk.kck)); 438f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", 439f05cddf9SRui Paulo peer->tpk.tk, sizeof(peer->tpk.tk)); 440f05cddf9SRui Paulo peer->tpk_set = 1; 441f05cddf9SRui Paulo } 442f05cddf9SRui Paulo 443f05cddf9SRui Paulo 444f05cddf9SRui Paulo /** 445f05cddf9SRui Paulo * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC 446f05cddf9SRui Paulo * @kck: TPK-KCK 447f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 448f05cddf9SRui Paulo * @rsnie: Pointer to the beginning of RSN IE used for handshake 449f05cddf9SRui Paulo * @timeoutie: Pointer to the beginning of Timeout IE used for handshake 450f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 451f05cddf9SRui Paulo * @mic: Pointer for writing MIC 452f05cddf9SRui Paulo * 453f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 454f05cddf9SRui Paulo */ 455f05cddf9SRui Paulo static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, 456f05cddf9SRui Paulo const u8 *rsnie, const u8 *timeoutie, 457f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 458f05cddf9SRui Paulo { 459f05cddf9SRui Paulo u8 *buf, *pos; 460f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 461f05cddf9SRui Paulo const struct wpa_tdls_lnkid *_lnkid; 462f05cddf9SRui Paulo int ret; 463f05cddf9SRui Paulo int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + 464f05cddf9SRui Paulo 2 + timeoutie[1] + 2 + ftie[1]; 465f05cddf9SRui Paulo buf = os_zalloc(len); 466f05cddf9SRui Paulo if (!buf) { 467f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 468f05cddf9SRui Paulo return -1; 469f05cddf9SRui Paulo } 470f05cddf9SRui Paulo 471f05cddf9SRui Paulo pos = buf; 472f05cddf9SRui Paulo _lnkid = (const struct wpa_tdls_lnkid *) lnkid; 473f05cddf9SRui Paulo /* 1) TDLS initiator STA MAC address */ 474f05cddf9SRui Paulo os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); 475f05cddf9SRui Paulo pos += ETH_ALEN; 476f05cddf9SRui Paulo /* 2) TDLS responder STA MAC address */ 477f05cddf9SRui Paulo os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); 478f05cddf9SRui Paulo pos += ETH_ALEN; 479f05cddf9SRui Paulo /* 3) Transaction Sequence number */ 480f05cddf9SRui Paulo *pos++ = trans_seq; 481f05cddf9SRui Paulo /* 4) Link Identifier IE */ 482f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 483f05cddf9SRui Paulo pos += 2 + lnkid[1]; 484f05cddf9SRui Paulo /* 5) RSN IE */ 485f05cddf9SRui Paulo os_memcpy(pos, rsnie, 2 + rsnie[1]); 486f05cddf9SRui Paulo pos += 2 + rsnie[1]; 487f05cddf9SRui Paulo /* 6) Timeout Interval IE */ 488f05cddf9SRui Paulo os_memcpy(pos, timeoutie, 2 + timeoutie[1]); 489f05cddf9SRui Paulo pos += 2 + timeoutie[1]; 490f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 491f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 492f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 493f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 494f05cddf9SRui Paulo pos += 2 + ftie[1]; 495f05cddf9SRui Paulo 496f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 497f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 498f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 499f05cddf9SRui Paulo os_free(buf); 500f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 501f05cddf9SRui Paulo return ret; 502f05cddf9SRui Paulo } 503f05cddf9SRui Paulo 504f05cddf9SRui Paulo 505f05cddf9SRui Paulo /** 506f05cddf9SRui Paulo * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame 507f05cddf9SRui Paulo * @kck: TPK-KCK 508f05cddf9SRui Paulo * @trans_seq: Transaction Sequence Number (4 - Teardown) 509f05cddf9SRui Paulo * @rcode: Reason code for Teardown 510f05cddf9SRui Paulo * @dtoken: Dialog Token used for that particular link 511f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 512f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 513f05cddf9SRui Paulo * @mic: Pointer for writing MIC 514f05cddf9SRui Paulo * 515f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 516f05cddf9SRui Paulo */ 517f05cddf9SRui Paulo static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, 518f05cddf9SRui Paulo u8 dtoken, const u8 *lnkid, 519f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 520f05cddf9SRui Paulo { 521f05cddf9SRui Paulo u8 *buf, *pos; 522f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 523f05cddf9SRui Paulo int ret; 524f05cddf9SRui Paulo int len; 525f05cddf9SRui Paulo 526f05cddf9SRui Paulo if (lnkid == NULL) 527f05cddf9SRui Paulo return -1; 528f05cddf9SRui Paulo 529f05cddf9SRui Paulo len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + 530f05cddf9SRui Paulo sizeof(trans_seq) + 2 + ftie[1]; 531f05cddf9SRui Paulo 532f05cddf9SRui Paulo buf = os_zalloc(len); 533f05cddf9SRui Paulo if (!buf) { 534f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 535f05cddf9SRui Paulo return -1; 536f05cddf9SRui Paulo } 537f05cddf9SRui Paulo 538f05cddf9SRui Paulo pos = buf; 539f05cddf9SRui Paulo /* 1) Link Identifier IE */ 540f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 541f05cddf9SRui Paulo pos += 2 + lnkid[1]; 542f05cddf9SRui Paulo /* 2) Reason Code */ 543f05cddf9SRui Paulo WPA_PUT_LE16(pos, rcode); 544f05cddf9SRui Paulo pos += sizeof(rcode); 545f05cddf9SRui Paulo /* 3) Dialog token */ 546f05cddf9SRui Paulo *pos++ = dtoken; 547f05cddf9SRui Paulo /* 4) Transaction Sequence number */ 548f05cddf9SRui Paulo *pos++ = trans_seq; 549f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 550f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 551f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 552f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 553f05cddf9SRui Paulo pos += 2 + ftie[1]; 554f05cddf9SRui Paulo 555f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 556f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 557f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 558f05cddf9SRui Paulo os_free(buf); 559f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 560f05cddf9SRui Paulo return ret; 561f05cddf9SRui Paulo } 562f05cddf9SRui Paulo 563f05cddf9SRui Paulo 564f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, 565f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 566f05cddf9SRui Paulo const u8 *lnkid, const u8 *timeoutie, 567f05cddf9SRui Paulo const struct wpa_tdls_ftie *ftie) 568f05cddf9SRui Paulo { 569f05cddf9SRui Paulo u8 mic[16]; 570f05cddf9SRui Paulo 571f05cddf9SRui Paulo if (peer->tpk_set) { 572f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, 573f05cddf9SRui Paulo peer->rsnie_p, timeoutie, (u8 *) ftie, 574f05cddf9SRui Paulo mic); 5755b9c547cSRui Paulo if (os_memcmp_const(mic, ftie->mic, 16) != 0) { 576f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " 577f05cddf9SRui Paulo "dropping packet"); 578f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", 579f05cddf9SRui Paulo ftie->mic, 16); 580f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", 581f05cddf9SRui Paulo mic, 16); 582f05cddf9SRui Paulo return -1; 583f05cddf9SRui Paulo } 584f05cddf9SRui Paulo } else { 585f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " 586f05cddf9SRui Paulo "TPK not set - dropping packet"); 587f05cddf9SRui Paulo return -1; 588f05cddf9SRui Paulo } 589f05cddf9SRui Paulo return 0; 590f05cddf9SRui Paulo } 591f05cddf9SRui Paulo 592f05cddf9SRui Paulo 593f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic_teardown( 594f05cddf9SRui Paulo u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, 595f05cddf9SRui Paulo const u8 *lnkid, const struct wpa_tdls_ftie *ftie) 596f05cddf9SRui Paulo { 597f05cddf9SRui Paulo u8 mic[16]; 598f05cddf9SRui Paulo 599f05cddf9SRui Paulo if (peer->tpk_set) { 600f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, 601f05cddf9SRui Paulo dtoken, lnkid, (u8 *) ftie, mic); 6025b9c547cSRui Paulo if (os_memcmp_const(mic, ftie->mic, 16) != 0) { 603f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " 604f05cddf9SRui Paulo "dropping packet"); 605f05cddf9SRui Paulo return -1; 606f05cddf9SRui Paulo } 607f05cddf9SRui Paulo } else { 608f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " 609f05cddf9SRui Paulo "MIC, TPK not set - dropping packet"); 610f05cddf9SRui Paulo return -1; 611f05cddf9SRui Paulo } 612f05cddf9SRui Paulo return 0; 613f05cddf9SRui Paulo } 614f05cddf9SRui Paulo 615f05cddf9SRui Paulo 616f05cddf9SRui Paulo static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) 617f05cddf9SRui Paulo { 618f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 619f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 620f05cddf9SRui Paulo 621f05cddf9SRui Paulo /* 622f05cddf9SRui Paulo * On TPK lifetime expiration, we have an option of either tearing down 623f05cddf9SRui Paulo * the direct link or trying to re-initiate it. The selection of what 624f05cddf9SRui Paulo * to do is not strictly speaking controlled by our role in the expired 625f05cddf9SRui Paulo * link, but for now, use that to select whether to renew or tear down 626f05cddf9SRui Paulo * the link. 627f05cddf9SRui Paulo */ 628f05cddf9SRui Paulo 629f05cddf9SRui Paulo if (peer->initiator) { 630f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 631f05cddf9SRui Paulo " - try to renew", MAC2STR(peer->addr)); 632f05cddf9SRui Paulo wpa_tdls_start(sm, peer->addr); 633f05cddf9SRui Paulo } else { 634f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 635f05cddf9SRui Paulo " - tear down", MAC2STR(peer->addr)); 636f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 6375b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 638f05cddf9SRui Paulo } 639f05cddf9SRui Paulo } 640f05cddf9SRui Paulo 641f05cddf9SRui Paulo 6425b9c547cSRui Paulo static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm, 6435b9c547cSRui Paulo struct wpa_tdls_peer *peer) 6445b9c547cSRui Paulo { 6455b9c547cSRui Paulo struct wpa_tdls_peer *cur, *prev; 6465b9c547cSRui Paulo 6475b9c547cSRui Paulo cur = sm->tdls; 6485b9c547cSRui Paulo prev = NULL; 6495b9c547cSRui Paulo while (cur && cur != peer) { 6505b9c547cSRui Paulo prev = cur; 6515b9c547cSRui Paulo cur = cur->next; 6525b9c547cSRui Paulo } 6535b9c547cSRui Paulo 6545b9c547cSRui Paulo if (cur != peer) { 6555b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR 6565b9c547cSRui Paulo " to remove it from the list", 6575b9c547cSRui Paulo MAC2STR(peer->addr)); 6585b9c547cSRui Paulo return; 6595b9c547cSRui Paulo } 6605b9c547cSRui Paulo 6615b9c547cSRui Paulo if (prev) 6625b9c547cSRui Paulo prev->next = peer->next; 6635b9c547cSRui Paulo else 6645b9c547cSRui Paulo sm->tdls = peer->next; 6655b9c547cSRui Paulo } 6665b9c547cSRui Paulo 6675b9c547cSRui Paulo 6685b9c547cSRui Paulo static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 669f05cddf9SRui Paulo { 670f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, 671f05cddf9SRui Paulo MAC2STR(peer->addr)); 672f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 673f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 6745b9c547cSRui Paulo peer->reconfig_key = 0; 675f05cddf9SRui Paulo peer->initiator = 0; 6765b9c547cSRui Paulo peer->tpk_in_progress = 0; 677f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 678f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 6795b9c547cSRui Paulo os_free(peer->ht_capabilities); 6805b9c547cSRui Paulo peer->ht_capabilities = NULL; 6815b9c547cSRui Paulo os_free(peer->vht_capabilities); 6825b9c547cSRui Paulo peer->vht_capabilities = NULL; 6835b9c547cSRui Paulo os_free(peer->ext_capab); 6845b9c547cSRui Paulo peer->ext_capab = NULL; 6855b9c547cSRui Paulo os_free(peer->supp_channels); 6865b9c547cSRui Paulo peer->supp_channels = NULL; 6875b9c547cSRui Paulo os_free(peer->supp_oper_classes); 6885b9c547cSRui Paulo peer->supp_oper_classes = NULL; 689f05cddf9SRui Paulo peer->rsnie_i_len = peer->rsnie_p_len = 0; 690f05cddf9SRui Paulo peer->cipher = 0; 6915b9c547cSRui Paulo peer->qos_info = 0; 6925b9c547cSRui Paulo peer->wmm_capable = 0; 693f05cddf9SRui Paulo peer->tpk_set = peer->tpk_success = 0; 6945b9c547cSRui Paulo peer->chan_switch_enabled = 0; 695f05cddf9SRui Paulo os_memset(&peer->tpk, 0, sizeof(peer->tpk)); 696f05cddf9SRui Paulo os_memset(peer->inonce, 0, WPA_NONCE_LEN); 697f05cddf9SRui Paulo os_memset(peer->rnonce, 0, WPA_NONCE_LEN); 698f05cddf9SRui Paulo } 699f05cddf9SRui Paulo 700f05cddf9SRui Paulo 7015b9c547cSRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 7025b9c547cSRui Paulo { 7035b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 7045b9c547cSRui Paulo wpa_tdls_peer_remove_from_list(sm, peer); 7055b9c547cSRui Paulo os_free(peer); 7065b9c547cSRui Paulo } 7075b9c547cSRui Paulo 7085b9c547cSRui Paulo 709f05cddf9SRui Paulo static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 710f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid) 711f05cddf9SRui Paulo { 712f05cddf9SRui Paulo lnkid->ie_type = WLAN_EID_LINK_ID; 713f05cddf9SRui Paulo lnkid->ie_len = 3 * ETH_ALEN; 714f05cddf9SRui Paulo os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); 715f05cddf9SRui Paulo if (peer->initiator) { 716f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); 717f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); 718f05cddf9SRui Paulo } else { 719f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); 720f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); 721f05cddf9SRui Paulo } 722f05cddf9SRui Paulo } 723f05cddf9SRui Paulo 724f05cddf9SRui Paulo 7255b9c547cSRui Paulo static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, 7265b9c547cSRui Paulo u16 reason_code) 727f05cddf9SRui Paulo { 728f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 729f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 730f05cddf9SRui Paulo struct wpa_tdls_lnkid lnkid; 731f05cddf9SRui Paulo u8 dialog_token; 732f05cddf9SRui Paulo u8 *rbuf, *pos; 733f05cddf9SRui Paulo int ielen; 734f05cddf9SRui Paulo 735f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 736f05cddf9SRui Paulo return -1; 737f05cddf9SRui Paulo 738f05cddf9SRui Paulo /* Find the node and free from the list */ 739f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 740f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 741f05cddf9SRui Paulo break; 742f05cddf9SRui Paulo } 743f05cddf9SRui Paulo 744f05cddf9SRui Paulo if (peer == NULL) { 745f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 746f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(addr)); 747f05cddf9SRui Paulo return 0; 748f05cddf9SRui Paulo } 749f05cddf9SRui Paulo 7505b9c547cSRui Paulo /* Cancel active channel switch before teardown */ 7515b9c547cSRui Paulo if (peer->chan_switch_enabled) { 7525b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR 7535b9c547cSRui Paulo " to base channel", MAC2STR(addr)); 7545b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 7555b9c547cSRui Paulo } 7565b9c547cSRui Paulo 757f05cddf9SRui Paulo dialog_token = peer->dtoken; 758f05cddf9SRui Paulo 759f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR, 760f05cddf9SRui Paulo MAC2STR(addr)); 761f05cddf9SRui Paulo 762f05cddf9SRui Paulo ielen = 0; 763f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { 764f05cddf9SRui Paulo /* To add FTIE for Teardown request and compute MIC */ 765f05cddf9SRui Paulo ielen += sizeof(*ftie); 766f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 767f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 768f05cddf9SRui Paulo ielen += 170; 769f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 770f05cddf9SRui Paulo } 771f05cddf9SRui Paulo 772f05cddf9SRui Paulo rbuf = os_zalloc(ielen + 1); 773f05cddf9SRui Paulo if (rbuf == NULL) 774f05cddf9SRui Paulo return -1; 775f05cddf9SRui Paulo pos = rbuf; 776f05cddf9SRui Paulo 777f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 778f05cddf9SRui Paulo goto skip_ies; 779f05cddf9SRui Paulo 780f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 781f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 782f05cddf9SRui Paulo /* Using the recent nonce which should be for CONFIRM frame */ 783f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 784f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 785f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 786f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 787f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 788f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 789f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 790f05cddf9SRui Paulo "FTIE"); 791f05cddf9SRui Paulo ftie->ie_len += 170; 792f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 793f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 794f05cddf9SRui Paulo pos += 168; 795f05cddf9SRui Paulo } 796f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 797f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", 798f05cddf9SRui Paulo (u8 *) ftie, pos - (u8 *) ftie); 799f05cddf9SRui Paulo 800f05cddf9SRui Paulo /* compute MIC before sending */ 801f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, &lnkid); 802f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, 803f05cddf9SRui Paulo dialog_token, (u8 *) &lnkid, (u8 *) ftie, 804f05cddf9SRui Paulo ftie->mic); 805f05cddf9SRui Paulo 806f05cddf9SRui Paulo skip_ies: 807f05cddf9SRui Paulo /* TODO: register for a Timeout handler, if Teardown is not received at 808f05cddf9SRui Paulo * the other end, then try again another time */ 809f05cddf9SRui Paulo 810f05cddf9SRui Paulo /* request driver to send Teardown using this FTIE */ 811f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, 8125b9c547cSRui Paulo reason_code, 0, peer->initiator, rbuf, pos - rbuf); 813f05cddf9SRui Paulo os_free(rbuf); 814f05cddf9SRui Paulo 815f05cddf9SRui Paulo return 0; 816f05cddf9SRui Paulo } 817f05cddf9SRui Paulo 818f05cddf9SRui Paulo 819f05cddf9SRui Paulo int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) 820f05cddf9SRui Paulo { 821f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 822f05cddf9SRui Paulo 823f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 824f05cddf9SRui Paulo return -1; 825f05cddf9SRui Paulo 826f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 827f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 828f05cddf9SRui Paulo break; 829f05cddf9SRui Paulo } 830f05cddf9SRui Paulo 831f05cddf9SRui Paulo if (peer == NULL) { 832f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR 833f05cddf9SRui Paulo " for link Teardown", MAC2STR(addr)); 834f05cddf9SRui Paulo return -1; 835f05cddf9SRui Paulo } 836f05cddf9SRui Paulo 837f05cddf9SRui Paulo if (!peer->tpk_success) { 838f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 839f05cddf9SRui Paulo " not connected - cannot Teardown link", MAC2STR(addr)); 840f05cddf9SRui Paulo return -1; 841f05cddf9SRui Paulo } 842f05cddf9SRui Paulo 8435b9c547cSRui Paulo return wpa_tdls_do_teardown(sm, peer, reason_code); 844f05cddf9SRui Paulo } 845f05cddf9SRui Paulo 846f05cddf9SRui Paulo 8475b9c547cSRui Paulo static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, 8485b9c547cSRui Paulo struct wpa_tdls_peer *peer) 8495b9c547cSRui Paulo { 8505b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 8515b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 8525b9c547cSRui Paulo } 8535b9c547cSRui Paulo 8545b9c547cSRui Paulo 8555b9c547cSRui Paulo void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr) 856f05cddf9SRui Paulo { 857f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 858f05cddf9SRui Paulo 859f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 860f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 861f05cddf9SRui Paulo break; 862f05cddf9SRui Paulo } 863f05cddf9SRui Paulo 8645b9c547cSRui Paulo if (!peer || !peer->tpk_success) { 8655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 8665b9c547cSRui Paulo " not connected - cannot teardown unreachable link", 8675b9c547cSRui Paulo MAC2STR(addr)); 8685b9c547cSRui Paulo return; 869f05cddf9SRui Paulo } 8705b9c547cSRui Paulo 8715b9c547cSRui Paulo if (wpa_tdls_is_external_setup(sm)) { 8725b9c547cSRui Paulo /* 8735b9c547cSRui Paulo * Get us on the base channel, disable the link, send a 8745b9c547cSRui Paulo * teardown packet through the AP, and then reset link data. 8755b9c547cSRui Paulo */ 8765b9c547cSRui Paulo if (peer->chan_switch_enabled) 8775b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 8785b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr); 8795b9c547cSRui Paulo wpa_tdls_send_teardown(sm, addr, 8805b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE); 8815b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 8825b9c547cSRui Paulo } else { 8835b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 8845b9c547cSRui Paulo } 8855b9c547cSRui Paulo } 8865b9c547cSRui Paulo 8875b9c547cSRui Paulo 8885b9c547cSRui Paulo const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr) 8895b9c547cSRui Paulo { 8905b9c547cSRui Paulo struct wpa_tdls_peer *peer; 8915b9c547cSRui Paulo 8925b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 8935b9c547cSRui Paulo return "disabled"; 8945b9c547cSRui Paulo 8955b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 8965b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 8975b9c547cSRui Paulo break; 8985b9c547cSRui Paulo } 8995b9c547cSRui Paulo 9005b9c547cSRui Paulo if (peer == NULL) 9015b9c547cSRui Paulo return "peer does not exist"; 9025b9c547cSRui Paulo 9035b9c547cSRui Paulo if (!peer->tpk_success) 9045b9c547cSRui Paulo return "peer not connected"; 9055b9c547cSRui Paulo 9065b9c547cSRui Paulo return "connected"; 907f05cddf9SRui Paulo } 908f05cddf9SRui Paulo 909f05cddf9SRui Paulo 910f05cddf9SRui Paulo static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, 911f05cddf9SRui Paulo const u8 *buf, size_t len) 912f05cddf9SRui Paulo { 913f05cddf9SRui Paulo struct wpa_tdls_peer *peer = NULL; 914f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 915f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 916f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 917f05cddf9SRui Paulo u16 reason_code; 918f05cddf9SRui Paulo const u8 *pos; 919f05cddf9SRui Paulo int ielen; 920f05cddf9SRui Paulo 921f05cddf9SRui Paulo /* Find the node and free from the list */ 922f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 923f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 924f05cddf9SRui Paulo break; 925f05cddf9SRui Paulo } 926f05cddf9SRui Paulo 927f05cddf9SRui Paulo if (peer == NULL) { 928f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 929f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(src_addr)); 930f05cddf9SRui Paulo return 0; 931f05cddf9SRui Paulo } 932f05cddf9SRui Paulo 933f05cddf9SRui Paulo pos = buf; 934f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 935f05cddf9SRui Paulo 936f05cddf9SRui Paulo reason_code = WPA_GET_LE16(pos); 937f05cddf9SRui Paulo pos += 2; 938f05cddf9SRui Paulo 939f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR 940f05cddf9SRui Paulo " (reason code %u)", MAC2STR(src_addr), reason_code); 941f05cddf9SRui Paulo 942f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 9435b9c547cSRui Paulo 9445b9c547cSRui Paulo /* 9455b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 9465b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 9475b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 9485b9c547cSRui Paulo */ 9495b9c547cSRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) 9505b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 9515b9c547cSRui Paulo "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround"); 952f05cddf9SRui Paulo 953f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 954f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " 955f05cddf9SRui Paulo "Teardown"); 956f05cddf9SRui Paulo return -1; 957f05cddf9SRui Paulo } 958f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 959f05cddf9SRui Paulo 960f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 961f05cddf9SRui Paulo goto skip_ftie; 962f05cddf9SRui Paulo 963f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 964f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); 965f05cddf9SRui Paulo return -1; 966f05cddf9SRui Paulo } 967f05cddf9SRui Paulo 968f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 969f05cddf9SRui Paulo 970f05cddf9SRui Paulo /* Process MIC check to see if TDLS Teardown is right */ 971f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, 972f05cddf9SRui Paulo peer->dtoken, peer, 973f05cddf9SRui Paulo (u8 *) lnkid, ftie) < 0) { 974f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " 975f05cddf9SRui Paulo "Teardown Request from " MACSTR, MAC2STR(src_addr)); 976f05cddf9SRui Paulo return -1; 977f05cddf9SRui Paulo } 978f05cddf9SRui Paulo 979f05cddf9SRui Paulo skip_ftie: 980f05cddf9SRui Paulo /* 981f05cddf9SRui Paulo * Request the driver to disable the direct link and clear associated 982f05cddf9SRui Paulo * keys. 983f05cddf9SRui Paulo */ 9845b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 985f05cddf9SRui Paulo return 0; 986f05cddf9SRui Paulo } 987f05cddf9SRui Paulo 988f05cddf9SRui Paulo 989f05cddf9SRui Paulo /** 990f05cddf9SRui Paulo * wpa_tdls_send_error - To send suitable TDLS status response with 991f05cddf9SRui Paulo * appropriate status code mentioning reason for error/failure. 992f05cddf9SRui Paulo * @dst - MAC addr of Peer station 993f05cddf9SRui Paulo * @tdls_action - TDLS frame type for which error code is sent 9945b9c547cSRui Paulo * @initiator - was this end the initiator of the connection 995f05cddf9SRui Paulo * @status - status code mentioning reason 996f05cddf9SRui Paulo */ 997f05cddf9SRui Paulo 998f05cddf9SRui Paulo static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, 9995b9c547cSRui Paulo u8 tdls_action, u8 dialog_token, int initiator, 10005b9c547cSRui Paulo u16 status) 1001f05cddf9SRui Paulo { 1002f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR 1003f05cddf9SRui Paulo " (action=%u status=%u)", 1004f05cddf9SRui Paulo MAC2STR(dst), tdls_action, status); 1005f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, 10065b9c547cSRui Paulo 0, initiator, NULL, 0); 1007f05cddf9SRui Paulo } 1008f05cddf9SRui Paulo 1009f05cddf9SRui Paulo 1010f05cddf9SRui Paulo static struct wpa_tdls_peer * 10115b9c547cSRui Paulo wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing) 1012f05cddf9SRui Paulo { 1013f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1014f05cddf9SRui Paulo 10155b9c547cSRui Paulo if (existing) 10165b9c547cSRui Paulo *existing = 0; 10175b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 10185b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) { 10195b9c547cSRui Paulo if (existing) 10205b9c547cSRui Paulo *existing = 1; 10215b9c547cSRui Paulo return peer; /* re-use existing entry */ 10225b9c547cSRui Paulo } 10235b9c547cSRui Paulo } 10245b9c547cSRui Paulo 1025f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR, 1026f05cddf9SRui Paulo MAC2STR(addr)); 1027f05cddf9SRui Paulo 1028f05cddf9SRui Paulo peer = os_zalloc(sizeof(*peer)); 1029f05cddf9SRui Paulo if (peer == NULL) 1030f05cddf9SRui Paulo return NULL; 1031f05cddf9SRui Paulo 1032f05cddf9SRui Paulo os_memcpy(peer->addr, addr, ETH_ALEN); 1033f05cddf9SRui Paulo peer->next = sm->tdls; 1034f05cddf9SRui Paulo sm->tdls = peer; 1035f05cddf9SRui Paulo 1036f05cddf9SRui Paulo return peer; 1037f05cddf9SRui Paulo } 1038f05cddf9SRui Paulo 1039f05cddf9SRui Paulo 1040f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, 1041f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 1042f05cddf9SRui Paulo { 1043f05cddf9SRui Paulo size_t buf_len; 1044f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1045f05cddf9SRui Paulo u16 rsn_capab; 1046f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1047f05cddf9SRui Paulo u8 *rbuf, *pos, *count_pos; 1048f05cddf9SRui Paulo u16 count; 1049f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 10505b9c547cSRui Paulo int status; 1051f05cddf9SRui Paulo 1052f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1053f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No security used on the link"); 1054f05cddf9SRui Paulo peer->rsnie_i_len = 0; 1055f05cddf9SRui Paulo goto skip_rsnie; 1056f05cddf9SRui Paulo } 1057f05cddf9SRui Paulo 1058f05cddf9SRui Paulo /* 1059f05cddf9SRui Paulo * TPK Handshake Message 1: 1060f05cddf9SRui Paulo * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, 1061f05cddf9SRui Paulo * Timeout Interval IE)) 1062f05cddf9SRui Paulo */ 1063f05cddf9SRui Paulo 1064f05cddf9SRui Paulo /* Filling RSN IE */ 1065f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_i; 1066f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 1067f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 1068f05cddf9SRui Paulo 1069f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 1070f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 1071f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1072f05cddf9SRui Paulo count_pos = pos; 1073f05cddf9SRui Paulo pos += 2; 1074f05cddf9SRui Paulo 1075f05cddf9SRui Paulo count = 0; 1076f05cddf9SRui Paulo 1077f05cddf9SRui Paulo /* 1078f05cddf9SRui Paulo * AES-CCMP is the default Encryption preferred for TDLS, so 1079f05cddf9SRui Paulo * RSN IE is filled only with CCMP CIPHER 1080f05cddf9SRui Paulo * Note: TKIP is not used to encrypt TDLS link. 1081f05cddf9SRui Paulo * 1082f05cddf9SRui Paulo * Regardless of the cipher used on the AP connection, select CCMP 1083f05cddf9SRui Paulo * here. 1084f05cddf9SRui Paulo */ 1085f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1086f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1087f05cddf9SRui Paulo count++; 1088f05cddf9SRui Paulo 1089f05cddf9SRui Paulo WPA_PUT_LE16(count_pos, count); 1090f05cddf9SRui Paulo 1091f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 1092f05cddf9SRui Paulo pos += 2; 1093f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 1094f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1095f05cddf9SRui Paulo 1096f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1097f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 1098f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1099f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 1100f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " 1101f05cddf9SRui Paulo "testing"); 1102f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1103f05cddf9SRui Paulo } 1104f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1105f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 1106f05cddf9SRui Paulo pos += 2; 1107f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1108f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 1109f05cddf9SRui Paulo /* Number of PMKIDs */ 1110f05cddf9SRui Paulo *pos++ = 0x00; 1111f05cddf9SRui Paulo *pos++ = 0x00; 1112f05cddf9SRui Paulo } 1113f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1114f05cddf9SRui Paulo 1115f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_i) - 2; 1116f05cddf9SRui Paulo peer->rsnie_i_len = pos - peer->rsnie_i; 1117f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 1118f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 1119f05cddf9SRui Paulo 1120f05cddf9SRui Paulo skip_rsnie: 1121f05cddf9SRui Paulo buf_len = 0; 1122f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) 1123f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1124f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1125f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1126f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && 1127f05cddf9SRui Paulo (tdls_testing & TDLS_TESTING_LONG_FRAME)) 1128f05cddf9SRui Paulo buf_len += 170; 1129f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) 1130f05cddf9SRui Paulo buf_len += sizeof(struct wpa_tdls_lnkid); 1131f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1132f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1133f05cddf9SRui Paulo if (rbuf == NULL) { 1134f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1135f05cddf9SRui Paulo return -1; 1136f05cddf9SRui Paulo } 1137f05cddf9SRui Paulo pos = rbuf; 1138f05cddf9SRui Paulo 1139f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1140f05cddf9SRui Paulo goto skip_ies; 1141f05cddf9SRui Paulo 1142f05cddf9SRui Paulo /* Initiator RSN IE */ 1143f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); 1144f05cddf9SRui Paulo 1145f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1146f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1147f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1148f05cddf9SRui Paulo 1149f05cddf9SRui Paulo if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { 1150f05cddf9SRui Paulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 1151f05cddf9SRui Paulo "TDLS: Failed to get random data for initiator Nonce"); 1152f05cddf9SRui Paulo os_free(rbuf); 1153f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1154f05cddf9SRui Paulo return -1; 1155f05cddf9SRui Paulo } 1156f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", 1157f05cddf9SRui Paulo peer->inonce, WPA_NONCE_LEN); 1158f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1159f05cddf9SRui Paulo 1160f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", 1161f05cddf9SRui Paulo (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); 1162f05cddf9SRui Paulo 1163f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1164f05cddf9SRui Paulo 1165f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1166f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1167f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1168f05cddf9SRui Paulo "FTIE"); 1169f05cddf9SRui Paulo ftie->ie_len += 170; 1170f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1171f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1172f05cddf9SRui Paulo pos += 168; 1173f05cddf9SRui Paulo } 1174f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1175f05cddf9SRui Paulo 1176f05cddf9SRui Paulo /* Lifetime */ 1177f05cddf9SRui Paulo peer->lifetime = TPK_LIFETIME; 1178f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1179f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { 1180f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " 1181f05cddf9SRui Paulo "lifetime"); 1182f05cddf9SRui Paulo peer->lifetime = 301; 1183f05cddf9SRui Paulo } 1184f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { 1185f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " 1186f05cddf9SRui Paulo "lifetime"); 1187f05cddf9SRui Paulo peer->lifetime = 0xffffffff; 1188f05cddf9SRui Paulo } 1189f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1190f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1191f05cddf9SRui Paulo sizeof(timeoutie), peer->lifetime); 1192f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); 1193f05cddf9SRui Paulo 1194f05cddf9SRui Paulo skip_ies: 1195f05cddf9SRui Paulo 1196f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1197f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { 1198f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " 1199f05cddf9SRui Paulo "Link Identifier"); 1200f05cddf9SRui Paulo struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; 1201f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, l); 1202f05cddf9SRui Paulo l->bssid[5] ^= 0x01; 1203f05cddf9SRui Paulo pos += sizeof(*l); 1204f05cddf9SRui Paulo } 1205f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1206f05cddf9SRui Paulo 1207f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " 1208f05cddf9SRui Paulo "Handshake Message 1 (peer " MACSTR ")", 1209f05cddf9SRui Paulo MAC2STR(peer->addr)); 1210f05cddf9SRui Paulo 12115b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 12125b9c547cSRui Paulo 1, 0, 0, peer->initiator, rbuf, pos - rbuf); 1213f05cddf9SRui Paulo os_free(rbuf); 1214f05cddf9SRui Paulo 12155b9c547cSRui Paulo return status; 1216f05cddf9SRui Paulo } 1217f05cddf9SRui Paulo 1218f05cddf9SRui Paulo 1219f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, 1220f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1221f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1222f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1223f05cddf9SRui Paulo { 1224f05cddf9SRui Paulo u8 *rbuf, *pos; 1225f05cddf9SRui Paulo size_t buf_len; 1226f05cddf9SRui Paulo u32 lifetime; 1227f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1228f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 12295b9c547cSRui Paulo int status; 1230f05cddf9SRui Paulo 1231f05cddf9SRui Paulo buf_len = 0; 1232f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1233f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1234f05cddf9SRui Paulo * Lifetime */ 1235f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1236f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1237f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1238f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1239f05cddf9SRui Paulo buf_len += 170; 1240f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1241f05cddf9SRui Paulo } 1242f05cddf9SRui Paulo 1243f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1244f05cddf9SRui Paulo if (rbuf == NULL) 1245f05cddf9SRui Paulo return -1; 1246f05cddf9SRui Paulo pos = rbuf; 1247f05cddf9SRui Paulo 1248f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1249f05cddf9SRui Paulo goto skip_ies; 1250f05cddf9SRui Paulo 1251f05cddf9SRui Paulo /* Peer RSN IE */ 1252f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1253f05cddf9SRui Paulo 1254f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1255f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1256f05cddf9SRui Paulo /* TODO: ftie->mic_control to set 2-RESPONSE */ 1257f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1258f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1259f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1260f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", 1261f05cddf9SRui Paulo (u8 *) ftie, sizeof(*ftie)); 1262f05cddf9SRui Paulo 1263f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1264f05cddf9SRui Paulo 1265f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1266f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1267f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1268f05cddf9SRui Paulo "FTIE"); 1269f05cddf9SRui Paulo ftie->ie_len += 170; 1270f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1271f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1272f05cddf9SRui Paulo pos += 168; 1273f05cddf9SRui Paulo } 1274f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1275f05cddf9SRui Paulo 1276f05cddf9SRui Paulo /* Lifetime */ 1277f05cddf9SRui Paulo lifetime = peer->lifetime; 1278f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1279f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { 1280f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1281f05cddf9SRui Paulo "lifetime in response"); 1282f05cddf9SRui Paulo lifetime++; 1283f05cddf9SRui Paulo } 1284f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1285f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1286f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1287f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", 1288f05cddf9SRui Paulo lifetime); 1289f05cddf9SRui Paulo 1290f05cddf9SRui Paulo /* compute MIC before sending */ 1291f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, 1292f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 12935b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 12945b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_MIC) { 12955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); 12965b9c547cSRui Paulo ftie->mic[0] ^= 0x01; 12975b9c547cSRui Paulo } 12985b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1299f05cddf9SRui Paulo 1300f05cddf9SRui Paulo skip_ies: 13015b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, 13025b9c547cSRui Paulo dtoken, 0, 0, peer->initiator, rbuf, 13035b9c547cSRui Paulo pos - rbuf); 1304f05cddf9SRui Paulo os_free(rbuf); 1305f05cddf9SRui Paulo 13065b9c547cSRui Paulo return status; 1307f05cddf9SRui Paulo } 1308f05cddf9SRui Paulo 1309f05cddf9SRui Paulo 1310f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, 1311f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1312f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1313f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1314f05cddf9SRui Paulo { 1315f05cddf9SRui Paulo u8 *rbuf, *pos; 1316f05cddf9SRui Paulo size_t buf_len; 1317f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1318f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1319f05cddf9SRui Paulo u32 lifetime; 13205b9c547cSRui Paulo int status; 13215b9c547cSRui Paulo u32 peer_capab = 0; 1322f05cddf9SRui Paulo 1323f05cddf9SRui Paulo buf_len = 0; 1324f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1325f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1326f05cddf9SRui Paulo * Lifetime */ 1327f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1328f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1329f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1330f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1331f05cddf9SRui Paulo buf_len += 170; 1332f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1333f05cddf9SRui Paulo } 1334f05cddf9SRui Paulo 1335f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1336f05cddf9SRui Paulo if (rbuf == NULL) 1337f05cddf9SRui Paulo return -1; 1338f05cddf9SRui Paulo pos = rbuf; 1339f05cddf9SRui Paulo 1340f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1341f05cddf9SRui Paulo goto skip_ies; 1342f05cddf9SRui Paulo 1343f05cddf9SRui Paulo /* Peer RSN IE */ 1344f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1345f05cddf9SRui Paulo 1346f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1347f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1348f05cddf9SRui Paulo /*TODO: ftie->mic_control to set 3-CONFIRM */ 1349f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1350f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1351f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1352f05cddf9SRui Paulo 1353f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1354f05cddf9SRui Paulo 1355f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1356f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1357f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1358f05cddf9SRui Paulo "FTIE"); 1359f05cddf9SRui Paulo ftie->ie_len += 170; 1360f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1361f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1362f05cddf9SRui Paulo pos += 168; 1363f05cddf9SRui Paulo } 1364f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1365f05cddf9SRui Paulo 1366f05cddf9SRui Paulo /* Lifetime */ 1367f05cddf9SRui Paulo lifetime = peer->lifetime; 1368f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1369f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { 1370f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1371f05cddf9SRui Paulo "lifetime in confirm"); 1372f05cddf9SRui Paulo lifetime++; 1373f05cddf9SRui Paulo } 1374f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1375f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1376f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1377f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", 1378f05cddf9SRui Paulo lifetime); 1379f05cddf9SRui Paulo 1380f05cddf9SRui Paulo /* compute MIC before sending */ 1381f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, 1382f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 13835b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 13845b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_MIC) { 13855b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); 13865b9c547cSRui Paulo ftie->mic[0] ^= 0x01; 13875b9c547cSRui Paulo } 13885b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1389f05cddf9SRui Paulo 1390f05cddf9SRui Paulo skip_ies: 13915b9c547cSRui Paulo 13925b9c547cSRui Paulo if (peer->vht_capabilities) 13935b9c547cSRui Paulo peer_capab |= TDLS_PEER_VHT; 13945b9c547cSRui Paulo if (peer->ht_capabilities) 13955b9c547cSRui Paulo peer_capab |= TDLS_PEER_HT; 13965b9c547cSRui Paulo if (peer->wmm_capable) 13975b9c547cSRui Paulo peer_capab |= TDLS_PEER_WMM; 13985b9c547cSRui Paulo 13995b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, 14005b9c547cSRui Paulo dtoken, 0, peer_capab, peer->initiator, 1401f05cddf9SRui Paulo rbuf, pos - rbuf); 1402f05cddf9SRui Paulo os_free(rbuf); 1403f05cddf9SRui Paulo 14045b9c547cSRui Paulo return status; 1405f05cddf9SRui Paulo } 1406f05cddf9SRui Paulo 1407f05cddf9SRui Paulo 1408f05cddf9SRui Paulo static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, 1409f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 1410f05cddf9SRui Paulo u8 dialog_token) 1411f05cddf9SRui Paulo { 14125b9c547cSRui Paulo size_t buf_len = 0; 14135b9c547cSRui Paulo struct wpa_tdls_timeoutie timeoutie; 14145b9c547cSRui Paulo u16 rsn_capab; 14155b9c547cSRui Paulo u8 *rbuf, *pos, *count_pos; 14165b9c547cSRui Paulo u16 count; 14175b9c547cSRui Paulo struct rsn_ie_hdr *hdr; 14185b9c547cSRui Paulo int status; 14195b9c547cSRui Paulo 1420f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response " 1421f05cddf9SRui Paulo "(peer " MACSTR ")", MAC2STR(peer->addr)); 14225b9c547cSRui Paulo if (!wpa_tdls_get_privacy(sm)) 14235b9c547cSRui Paulo goto skip_rsn_ies; 1424f05cddf9SRui Paulo 14255b9c547cSRui Paulo /* Filling RSN IE */ 14265b9c547cSRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_i; 14275b9c547cSRui Paulo hdr->elem_id = WLAN_EID_RSN; 14285b9c547cSRui Paulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 14295b9c547cSRui Paulo pos = (u8 *) (hdr + 1); 14305b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 14315b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 14325b9c547cSRui Paulo count_pos = pos; 14335b9c547cSRui Paulo pos += 2; 14345b9c547cSRui Paulo count = 0; 14355b9c547cSRui Paulo 14365b9c547cSRui Paulo /* 14375b9c547cSRui Paulo * AES-CCMP is the default encryption preferred for TDLS, so 14385b9c547cSRui Paulo * RSN IE is filled only with CCMP cipher suite. 14395b9c547cSRui Paulo * Note: TKIP is not used to encrypt TDLS link. 14405b9c547cSRui Paulo * 14415b9c547cSRui Paulo * Regardless of the cipher used on the AP connection, select CCMP 14425b9c547cSRui Paulo * here. 14435b9c547cSRui Paulo */ 14445b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 14455b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 14465b9c547cSRui Paulo count++; 14475b9c547cSRui Paulo WPA_PUT_LE16(count_pos, count); 14485b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 14495b9c547cSRui Paulo pos += 2; 14505b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 14515b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 14525b9c547cSRui Paulo 14535b9c547cSRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 14545b9c547cSRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 14555b9c547cSRui Paulo WPA_PUT_LE16(pos, rsn_capab); 14565b9c547cSRui Paulo pos += 2; 14575b9c547cSRui Paulo hdr->len = (pos - (u8 *) hdr) - 2; 14585b9c547cSRui Paulo peer->rsnie_i_len = pos - peer->rsnie_i; 14595b9c547cSRui Paulo 14605b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response", 14615b9c547cSRui Paulo (u8 *) hdr, hdr->len + 2); 14625b9c547cSRui Paulo skip_rsn_ies: 14635b9c547cSRui Paulo buf_len = 0; 14645b9c547cSRui Paulo if (wpa_tdls_get_privacy(sm)) { 14655b9c547cSRui Paulo /* Peer RSN IE, Lifetime */ 14665b9c547cSRui Paulo buf_len += peer->rsnie_i_len + 14675b9c547cSRui Paulo sizeof(struct wpa_tdls_timeoutie); 14685b9c547cSRui Paulo } 14695b9c547cSRui Paulo rbuf = os_zalloc(buf_len + 1); 14705b9c547cSRui Paulo if (rbuf == NULL) { 14715b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 14725b9c547cSRui Paulo return -1; 14735b9c547cSRui Paulo } 14745b9c547cSRui Paulo pos = rbuf; 14755b9c547cSRui Paulo 14765b9c547cSRui Paulo if (!wpa_tdls_get_privacy(sm)) 14775b9c547cSRui Paulo goto skip_ies; 14785b9c547cSRui Paulo /* Initiator RSN IE */ 14795b9c547cSRui Paulo pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); 14805b9c547cSRui Paulo /* Lifetime */ 14815b9c547cSRui Paulo peer->lifetime = TPK_LIFETIME; 14825b9c547cSRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 14835b9c547cSRui Paulo sizeof(timeoutie), peer->lifetime); 14845b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); 14855b9c547cSRui Paulo skip_ies: 14865b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, 14875b9c547cSRui Paulo dialog_token, 0, 0, 0, rbuf, pos - rbuf); 14885b9c547cSRui Paulo os_free(rbuf); 14895b9c547cSRui Paulo 14905b9c547cSRui Paulo return status; 1491f05cddf9SRui Paulo } 1492f05cddf9SRui Paulo 1493f05cddf9SRui Paulo 1494f05cddf9SRui Paulo static int 1495f05cddf9SRui Paulo wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, 1496f05cddf9SRui Paulo const u8 *buf, size_t len) 1497f05cddf9SRui Paulo { 1498f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1499f05cddf9SRui Paulo const struct wpa_tdls_lnkid *lnkid; 1500f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1501f05cddf9SRui Paulo size_t min_req_len = sizeof(struct wpa_tdls_frame) + 1502f05cddf9SRui Paulo 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); 1503f05cddf9SRui Paulo u8 dialog_token; 1504f05cddf9SRui Paulo 1505f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR, 1506f05cddf9SRui Paulo MAC2STR(addr)); 1507f05cddf9SRui Paulo 1508f05cddf9SRui Paulo if (len < min_req_len) { 1509f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: " 1510f05cddf9SRui Paulo "%d", (int) len); 1511f05cddf9SRui Paulo return -1; 1512f05cddf9SRui Paulo } 1513f05cddf9SRui Paulo 1514f05cddf9SRui Paulo dialog_token = buf[sizeof(struct wpa_tdls_frame)]; 1515f05cddf9SRui Paulo 15165b9c547cSRui Paulo /* 15175b9c547cSRui Paulo * Some APs will tack on a weird IE to the end of a TDLS 15185b9c547cSRui Paulo * discovery request packet. This needn't fail the response, 15195b9c547cSRui Paulo * since the required IE are verified separately. 15205b9c547cSRui Paulo */ 1521f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1, 1522f05cddf9SRui Paulo len - (sizeof(struct wpa_tdls_frame) + 1), 15235b9c547cSRui Paulo &kde) < 0) { 15245b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 15255b9c547cSRui Paulo "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround"); 15265b9c547cSRui Paulo } 1527f05cddf9SRui Paulo 1528f05cddf9SRui Paulo if (!kde.lnkid) { 1529f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery " 1530f05cddf9SRui Paulo "Request"); 1531f05cddf9SRui Paulo return -1; 1532f05cddf9SRui Paulo } 1533f05cddf9SRui Paulo 1534f05cddf9SRui Paulo lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; 1535f05cddf9SRui Paulo 1536f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1537f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " 1538f05cddf9SRui Paulo " BSS " MACSTR, MAC2STR(lnkid->bssid)); 1539f05cddf9SRui Paulo return -1; 1540f05cddf9SRui Paulo } 1541f05cddf9SRui Paulo 15425b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, addr, NULL); 1543f05cddf9SRui Paulo if (peer == NULL) 1544f05cddf9SRui Paulo return -1; 1545f05cddf9SRui Paulo 1546f05cddf9SRui Paulo return wpa_tdls_send_discovery_response(sm, peer, dialog_token); 1547f05cddf9SRui Paulo } 1548f05cddf9SRui Paulo 1549f05cddf9SRui Paulo 1550f05cddf9SRui Paulo int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) 1551f05cddf9SRui Paulo { 1552f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 1553f05cddf9SRui Paulo return -1; 1554f05cddf9SRui Paulo 1555f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " 1556f05cddf9SRui Paulo MACSTR, MAC2STR(addr)); 1557f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, 15585b9c547cSRui Paulo 1, 0, 0, 1, NULL, 0); 1559f05cddf9SRui Paulo } 1560f05cddf9SRui Paulo 1561f05cddf9SRui Paulo 1562f05cddf9SRui Paulo static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, 1563f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 1564f05cddf9SRui Paulo { 1565f05cddf9SRui Paulo if (!kde->supp_rates) { 1566f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported rates received"); 1567f05cddf9SRui Paulo return -1; 1568f05cddf9SRui Paulo } 15695b9c547cSRui Paulo peer->supp_rates_len = merge_byte_arrays( 15705b9c547cSRui Paulo peer->supp_rates, sizeof(peer->supp_rates), 15715b9c547cSRui Paulo kde->supp_rates + 2, kde->supp_rates_len - 2, 15725b9c547cSRui Paulo kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL, 15735b9c547cSRui Paulo kde->ext_supp_rates_len - 2); 15745b9c547cSRui Paulo return 0; 1575f05cddf9SRui Paulo } 1576f05cddf9SRui Paulo 15775b9c547cSRui Paulo 15785b9c547cSRui Paulo static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde, 15795b9c547cSRui Paulo struct wpa_tdls_peer *peer) 15805b9c547cSRui Paulo { 1581*325151a3SRui Paulo if (!kde->ht_capabilities) { 15825b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities " 15835b9c547cSRui Paulo "received"); 1584f05cddf9SRui Paulo return 0; 1585f05cddf9SRui Paulo } 1586f05cddf9SRui Paulo 15875b9c547cSRui Paulo if (!peer->ht_capabilities) { 15885b9c547cSRui Paulo peer->ht_capabilities = 15895b9c547cSRui Paulo os_zalloc(sizeof(struct ieee80211_ht_capabilities)); 15905b9c547cSRui Paulo if (peer->ht_capabilities == NULL) 15915b9c547cSRui Paulo return -1; 15925b9c547cSRui Paulo } 15935b9c547cSRui Paulo 15945b9c547cSRui Paulo os_memcpy(peer->ht_capabilities, kde->ht_capabilities, 15955b9c547cSRui Paulo sizeof(struct ieee80211_ht_capabilities)); 15965b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities", 15975b9c547cSRui Paulo (u8 *) peer->ht_capabilities, 15985b9c547cSRui Paulo sizeof(struct ieee80211_ht_capabilities)); 15995b9c547cSRui Paulo 16005b9c547cSRui Paulo return 0; 16015b9c547cSRui Paulo } 16025b9c547cSRui Paulo 16035b9c547cSRui Paulo 16045b9c547cSRui Paulo static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde, 16055b9c547cSRui Paulo struct wpa_tdls_peer *peer) 16065b9c547cSRui Paulo { 1607*325151a3SRui Paulo if (!kde->vht_capabilities) { 16085b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities " 16095b9c547cSRui Paulo "received"); 16105b9c547cSRui Paulo return 0; 16115b9c547cSRui Paulo } 16125b9c547cSRui Paulo 16135b9c547cSRui Paulo if (!peer->vht_capabilities) { 16145b9c547cSRui Paulo peer->vht_capabilities = 16155b9c547cSRui Paulo os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 16165b9c547cSRui Paulo if (peer->vht_capabilities == NULL) 16175b9c547cSRui Paulo return -1; 16185b9c547cSRui Paulo } 16195b9c547cSRui Paulo 16205b9c547cSRui Paulo os_memcpy(peer->vht_capabilities, kde->vht_capabilities, 16215b9c547cSRui Paulo sizeof(struct ieee80211_vht_capabilities)); 16225b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities", 16235b9c547cSRui Paulo (u8 *) peer->vht_capabilities, 16245b9c547cSRui Paulo sizeof(struct ieee80211_vht_capabilities)); 16255b9c547cSRui Paulo 16265b9c547cSRui Paulo return 0; 16275b9c547cSRui Paulo } 16285b9c547cSRui Paulo 16295b9c547cSRui Paulo 16305b9c547cSRui Paulo static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, 16315b9c547cSRui Paulo struct wpa_tdls_peer *peer) 16325b9c547cSRui Paulo { 16335b9c547cSRui Paulo if (!kde->ext_capab) { 16345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities " 16355b9c547cSRui Paulo "received"); 16365b9c547cSRui Paulo return 0; 16375b9c547cSRui Paulo } 16385b9c547cSRui Paulo 16395b9c547cSRui Paulo if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) { 16405b9c547cSRui Paulo /* Need to allocate buffer to fit the new information */ 16415b9c547cSRui Paulo os_free(peer->ext_capab); 16425b9c547cSRui Paulo peer->ext_capab = os_zalloc(kde->ext_capab_len - 2); 16435b9c547cSRui Paulo if (peer->ext_capab == NULL) 16445b9c547cSRui Paulo return -1; 16455b9c547cSRui Paulo } 16465b9c547cSRui Paulo 16475b9c547cSRui Paulo peer->ext_capab_len = kde->ext_capab_len - 2; 16485b9c547cSRui Paulo os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len); 16495b9c547cSRui Paulo 16505b9c547cSRui Paulo return 0; 16515b9c547cSRui Paulo } 16525b9c547cSRui Paulo 16535b9c547cSRui Paulo 16545b9c547cSRui Paulo static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde, 16555b9c547cSRui Paulo struct wpa_tdls_peer *peer) 16565b9c547cSRui Paulo { 16575b9c547cSRui Paulo struct wmm_information_element *wmm; 16585b9c547cSRui Paulo 16595b9c547cSRui Paulo if (!kde->wmm) { 16605b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received"); 16615b9c547cSRui Paulo return 0; 16625b9c547cSRui Paulo } 16635b9c547cSRui Paulo 16645b9c547cSRui Paulo if (kde->wmm_len < sizeof(struct wmm_information_element)) { 16655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received"); 16665b9c547cSRui Paulo return -1; 16675b9c547cSRui Paulo } 16685b9c547cSRui Paulo 16695b9c547cSRui Paulo wmm = (struct wmm_information_element *) kde->wmm; 16705b9c547cSRui Paulo peer->qos_info = wmm->qos_info; 16715b9c547cSRui Paulo 16725b9c547cSRui Paulo peer->wmm_capable = 1; 16735b9c547cSRui Paulo 16745b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info); 16755b9c547cSRui Paulo return 0; 16765b9c547cSRui Paulo } 16775b9c547cSRui Paulo 16785b9c547cSRui Paulo 16795b9c547cSRui Paulo static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, 16805b9c547cSRui Paulo struct wpa_tdls_peer *peer) 16815b9c547cSRui Paulo { 16825b9c547cSRui Paulo if (!kde->supp_channels) { 16835b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported channels received"); 16845b9c547cSRui Paulo return 0; 16855b9c547cSRui Paulo } 16865b9c547cSRui Paulo 16875b9c547cSRui Paulo if (!peer->supp_channels || 16885b9c547cSRui Paulo peer->supp_channels_len < kde->supp_channels_len) { 16895b9c547cSRui Paulo os_free(peer->supp_channels); 16905b9c547cSRui Paulo peer->supp_channels = os_zalloc(kde->supp_channels_len); 16915b9c547cSRui Paulo if (peer->supp_channels == NULL) 16925b9c547cSRui Paulo return -1; 16935b9c547cSRui Paulo } 16945b9c547cSRui Paulo 16955b9c547cSRui Paulo peer->supp_channels_len = kde->supp_channels_len; 16965b9c547cSRui Paulo 16975b9c547cSRui Paulo os_memcpy(peer->supp_channels, kde->supp_channels, 16985b9c547cSRui Paulo peer->supp_channels_len); 16995b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels", 17005b9c547cSRui Paulo (u8 *) peer->supp_channels, peer->supp_channels_len); 17015b9c547cSRui Paulo return 0; 17025b9c547cSRui Paulo } 17035b9c547cSRui Paulo 17045b9c547cSRui Paulo 17055b9c547cSRui Paulo static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, 17065b9c547cSRui Paulo struct wpa_tdls_peer *peer) 17075b9c547cSRui Paulo { 17085b9c547cSRui Paulo if (!kde->supp_oper_classes) { 17095b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received"); 17105b9c547cSRui Paulo return 0; 17115b9c547cSRui Paulo } 17125b9c547cSRui Paulo 17135b9c547cSRui Paulo if (!peer->supp_oper_classes || 17145b9c547cSRui Paulo peer->supp_oper_classes_len < kde->supp_oper_classes_len) { 17155b9c547cSRui Paulo os_free(peer->supp_oper_classes); 17165b9c547cSRui Paulo peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len); 17175b9c547cSRui Paulo if (peer->supp_oper_classes == NULL) 17185b9c547cSRui Paulo return -1; 17195b9c547cSRui Paulo } 17205b9c547cSRui Paulo 17215b9c547cSRui Paulo peer->supp_oper_classes_len = kde->supp_oper_classes_len; 17225b9c547cSRui Paulo os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes, 17235b9c547cSRui Paulo peer->supp_oper_classes_len); 17245b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes", 17255b9c547cSRui Paulo (u8 *) peer->supp_oper_classes, 17265b9c547cSRui Paulo peer->supp_oper_classes_len); 17275b9c547cSRui Paulo return 0; 17285b9c547cSRui Paulo } 17295b9c547cSRui Paulo 17305b9c547cSRui Paulo 17315b9c547cSRui Paulo static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 17325b9c547cSRui Paulo int add) 17335b9c547cSRui Paulo { 17345b9c547cSRui Paulo return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid, 17355b9c547cSRui Paulo peer->capability, 17365b9c547cSRui Paulo peer->supp_rates, peer->supp_rates_len, 17375b9c547cSRui Paulo peer->ht_capabilities, 17385b9c547cSRui Paulo peer->vht_capabilities, 17395b9c547cSRui Paulo peer->qos_info, peer->wmm_capable, 17405b9c547cSRui Paulo peer->ext_capab, peer->ext_capab_len, 17415b9c547cSRui Paulo peer->supp_channels, 17425b9c547cSRui Paulo peer->supp_channels_len, 17435b9c547cSRui Paulo peer->supp_oper_classes, 17445b9c547cSRui Paulo peer->supp_oper_classes_len); 17455b9c547cSRui Paulo } 17465b9c547cSRui Paulo 1747f05cddf9SRui Paulo 1748f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, 1749f05cddf9SRui Paulo const u8 *buf, size_t len) 1750f05cddf9SRui Paulo { 1751f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1752f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1753f05cddf9SRui Paulo struct wpa_ie_data ie; 1754f05cddf9SRui Paulo int cipher; 1755f05cddf9SRui Paulo const u8 *cpos; 1756f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie = NULL; 1757f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 1758f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 1759f05cddf9SRui Paulo u32 lifetime = 0; 1760f05cddf9SRui Paulo #if 0 1761f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 1762f05cddf9SRui Paulo u8 *pos; 1763f05cddf9SRui Paulo u16 rsn_capab; 1764f05cddf9SRui Paulo u16 rsn_ver; 1765f05cddf9SRui Paulo #endif 1766f05cddf9SRui Paulo u8 dtoken; 1767f05cddf9SRui Paulo u16 ielen; 1768f05cddf9SRui Paulo u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1769f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 1770f05cddf9SRui Paulo int existing_peer = 0; 1771f05cddf9SRui Paulo 1772f05cddf9SRui Paulo if (len < 3 + 3) 1773f05cddf9SRui Paulo return -1; 1774f05cddf9SRui Paulo 1775f05cddf9SRui Paulo cpos = buf; 1776f05cddf9SRui Paulo cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 1777f05cddf9SRui Paulo 1778f05cddf9SRui Paulo /* driver had already verified the frame format */ 1779f05cddf9SRui Paulo dtoken = *cpos++; /* dialog token */ 1780f05cddf9SRui Paulo 1781f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); 1782f05cddf9SRui Paulo 17835b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer); 1784f05cddf9SRui Paulo if (peer == NULL) 1785f05cddf9SRui Paulo goto error; 17865b9c547cSRui Paulo 17875b9c547cSRui Paulo /* If found, use existing entry instead of adding a new one; 17885b9c547cSRui Paulo * how to handle the case where both ends initiate at the 17895b9c547cSRui Paulo * same time? */ 17905b9c547cSRui Paulo if (existing_peer) { 17915b9c547cSRui Paulo if (peer->tpk_success) { 17925b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " 17935b9c547cSRui Paulo "direct link is enabled - tear down the " 17945b9c547cSRui Paulo "old link first"); 17955b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 17965b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 17975b9c547cSRui Paulo } else if (peer->initiator) { 17985b9c547cSRui Paulo /* 17995b9c547cSRui Paulo * An entry is already present, so check if we already 18005b9c547cSRui Paulo * sent a TDLS Setup Request. If so, compare MAC 18015b9c547cSRui Paulo * addresses and let the STA with the lower MAC address 18025b9c547cSRui Paulo * continue as the initiator. The other negotiation is 18035b9c547cSRui Paulo * terminated. 18045b9c547cSRui Paulo */ 18055b9c547cSRui Paulo if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { 18065b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard request " 18075b9c547cSRui Paulo "from peer with higher address " 18085b9c547cSRui Paulo MACSTR, MAC2STR(src_addr)); 18095b9c547cSRui Paulo return -1; 18105b9c547cSRui Paulo } else { 18115b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Accept request " 18125b9c547cSRui Paulo "from peer with lower address " 18135b9c547cSRui Paulo MACSTR " (terminate previously " 18145b9c547cSRui Paulo "initiated negotiation", 18155b9c547cSRui Paulo MAC2STR(src_addr)); 18165b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, 18175b9c547cSRui Paulo peer->addr); 18185b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 18195b9c547cSRui Paulo } 18205b9c547cSRui Paulo } 1821f05cddf9SRui Paulo } 1822f05cddf9SRui Paulo 1823f05cddf9SRui Paulo /* capability information */ 1824f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(cpos); 1825f05cddf9SRui Paulo cpos += 2; 1826f05cddf9SRui Paulo 1827f05cddf9SRui Paulo ielen = len - (cpos - buf); /* start of IE in buf */ 18285b9c547cSRui Paulo 18295b9c547cSRui Paulo /* 18305b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 18315b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 18325b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 18335b9c547cSRui Paulo */ 18345b9c547cSRui Paulo if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) 18355b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 18365b9c547cSRui Paulo "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround"); 1837f05cddf9SRui Paulo 1838f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 1839f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 1840f05cddf9SRui Paulo "TPK M1"); 1841f05cddf9SRui Paulo goto error; 1842f05cddf9SRui Paulo } 1843f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", 1844f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 1845f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 1846f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1847f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); 18485b9c547cSRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1849f05cddf9SRui Paulo goto error; 1850f05cddf9SRui Paulo } 1851f05cddf9SRui Paulo 1852f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, 1853f05cddf9SRui Paulo MAC2STR(src_addr)); 1854f05cddf9SRui Paulo 1855f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 1856f05cddf9SRui Paulo goto error; 1857f05cddf9SRui Paulo 18585b9c547cSRui Paulo if (copy_peer_ht_capab(&kde, peer) < 0) 18595b9c547cSRui Paulo goto error; 18605b9c547cSRui Paulo 18615b9c547cSRui Paulo if (copy_peer_vht_capab(&kde, peer) < 0) 18625b9c547cSRui Paulo goto error; 18635b9c547cSRui Paulo 18645b9c547cSRui Paulo if (copy_peer_ext_capab(&kde, peer) < 0) 18655b9c547cSRui Paulo goto error; 18665b9c547cSRui Paulo 18675b9c547cSRui Paulo if (copy_peer_supp_channels(&kde, peer) < 0) 18685b9c547cSRui Paulo goto error; 18695b9c547cSRui Paulo 18705b9c547cSRui Paulo if (copy_peer_supp_oper_classes(&kde, peer) < 0) 18715b9c547cSRui Paulo goto error; 18725b9c547cSRui Paulo 18735b9c547cSRui Paulo peer->qos_info = kde.qosinfo; 18745b9c547cSRui Paulo 18755b9c547cSRui Paulo /* Overwrite with the qos_info obtained in WMM IE */ 18765b9c547cSRui Paulo if (copy_peer_wmm_capab(&kde, peer) < 0) 18775b9c547cSRui Paulo goto error; 18785b9c547cSRui Paulo 18795b9c547cSRui Paulo peer->aid = kde.aid; 18805b9c547cSRui Paulo 1881f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1882f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 18835b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, src_addr, NULL); 1884f05cddf9SRui Paulo if (peer == NULL) 1885f05cddf9SRui Paulo goto error; 1886f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " 1887f05cddf9SRui Paulo "TDLS setup - send own request"); 1888f05cddf9SRui Paulo peer->initiator = 1; 18895b9c547cSRui Paulo wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, 18905b9c547cSRui Paulo NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0); 1891f05cddf9SRui Paulo wpa_tdls_send_tpk_m1(sm, peer); 1892f05cddf9SRui Paulo } 1893f05cddf9SRui Paulo 1894f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 1895f05cddf9SRui Paulo tdls_prohibited) { 1896f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 1897f05cddf9SRui Paulo "on TDLS"); 1898f05cddf9SRui Paulo tdls_prohibited = 0; 1899f05cddf9SRui Paulo } 1900f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1901f05cddf9SRui Paulo 1902f05cddf9SRui Paulo if (tdls_prohibited) { 1903f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); 1904f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1905f05cddf9SRui Paulo goto error; 1906f05cddf9SRui Paulo } 1907f05cddf9SRui Paulo 1908f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1909f05cddf9SRui Paulo if (kde.rsn_ie) { 1910f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " 1911f05cddf9SRui Paulo "security is disabled"); 1912f05cddf9SRui Paulo status = WLAN_STATUS_SECURITY_DISABLED; 1913f05cddf9SRui Paulo goto error; 1914f05cddf9SRui Paulo } 1915f05cddf9SRui Paulo goto skip_rsn; 1916f05cddf9SRui Paulo } 1917f05cddf9SRui Paulo 1918f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 1919f05cddf9SRui Paulo kde.rsn_ie == NULL) { 1920f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); 1921f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 1922f05cddf9SRui Paulo goto error; 1923f05cddf9SRui Paulo } 1924f05cddf9SRui Paulo 1925f05cddf9SRui Paulo if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { 1926f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " 1927f05cddf9SRui Paulo "TPK M1"); 1928f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1929f05cddf9SRui Paulo goto error; 1930f05cddf9SRui Paulo } 1931f05cddf9SRui Paulo 1932f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 1933f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); 1934f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1935f05cddf9SRui Paulo goto error; 1936f05cddf9SRui Paulo } 1937f05cddf9SRui Paulo 1938f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 1939f05cddf9SRui Paulo if (cipher & WPA_CIPHER_CCMP) { 1940f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 1941f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 1942f05cddf9SRui Paulo } else { 1943f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); 1944f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1945f05cddf9SRui Paulo goto error; 1946f05cddf9SRui Paulo } 1947f05cddf9SRui Paulo 1948f05cddf9SRui Paulo if ((ie.capabilities & 1949f05cddf9SRui Paulo (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != 1950f05cddf9SRui Paulo WPA_CAPABILITY_PEERKEY_ENABLED) { 1951f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " 1952f05cddf9SRui Paulo "TPK M1"); 1953f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; 1954f05cddf9SRui Paulo goto error; 1955f05cddf9SRui Paulo } 1956f05cddf9SRui Paulo 1957f05cddf9SRui Paulo /* Lifetime */ 1958f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 1959f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); 1960f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1961f05cddf9SRui Paulo goto error; 1962f05cddf9SRui Paulo } 1963f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 1964f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 1965f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); 1966f05cddf9SRui Paulo if (lifetime < 300) { 1967f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); 1968f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1969f05cddf9SRui Paulo goto error; 1970f05cddf9SRui Paulo } 1971f05cddf9SRui Paulo 1972f05cddf9SRui Paulo skip_rsn: 1973f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1974f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 1975f05cddf9SRui Paulo if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) { 1976f05cddf9SRui Paulo /* 1977f05cddf9SRui Paulo * The request frame from us is going to win, so do not 1978f05cddf9SRui Paulo * replace information based on this request frame from 1979f05cddf9SRui Paulo * the peer. 1980f05cddf9SRui Paulo */ 1981f05cddf9SRui Paulo goto skip_rsn_check; 1982f05cddf9SRui Paulo } 1983f05cddf9SRui Paulo } 1984f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1985f05cddf9SRui Paulo 1986f05cddf9SRui Paulo peer->initiator = 0; /* Need to check */ 1987f05cddf9SRui Paulo peer->dtoken = dtoken; 1988f05cddf9SRui Paulo 1989f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1990f05cddf9SRui Paulo peer->rsnie_i_len = 0; 1991f05cddf9SRui Paulo peer->rsnie_p_len = 0; 1992f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 1993f05cddf9SRui Paulo goto skip_rsn_check; 1994f05cddf9SRui Paulo } 1995f05cddf9SRui Paulo 1996f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 1997f05cddf9SRui Paulo os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); 1998f05cddf9SRui Paulo peer->rsnie_i_len = kde.rsn_ie_len; 1999f05cddf9SRui Paulo peer->cipher = cipher; 2000f05cddf9SRui Paulo 20015b9c547cSRui Paulo if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) { 20025b9c547cSRui Paulo /* 20035b9c547cSRui Paulo * There is no point in updating the RNonce for every obtained 20045b9c547cSRui Paulo * TPK M1 frame (e.g., retransmission due to timeout) with the 20055b9c547cSRui Paulo * same INonce (SNonce in FTIE). However, if the TPK M1 is 20065b9c547cSRui Paulo * retransmitted with a different INonce, update the RNonce 20075b9c547cSRui Paulo * since this is for a new TDLS session. 20085b9c547cSRui Paulo */ 20095b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 20105b9c547cSRui Paulo "TDLS: New TPK M1 INonce - generate new RNonce"); 20115b9c547cSRui Paulo os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN); 2012f05cddf9SRui Paulo if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { 2013f05cddf9SRui Paulo wpa_msg(sm->ctx->ctx, MSG_WARNING, 2014f05cddf9SRui Paulo "TDLS: Failed to get random data for responder nonce"); 2015f05cddf9SRui Paulo goto error; 2016f05cddf9SRui Paulo } 20175b9c547cSRui Paulo } 2018f05cddf9SRui Paulo 2019f05cddf9SRui Paulo #if 0 2020f05cddf9SRui Paulo /* get version info from RSNIE received from Peer */ 2021f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) kde.rsn_ie; 2022f05cddf9SRui Paulo rsn_ver = WPA_GET_LE16(hdr->version); 2023f05cddf9SRui Paulo 2024f05cddf9SRui Paulo /* use min(peer's version, out version) */ 2025f05cddf9SRui Paulo if (rsn_ver > RSN_VERSION) 2026f05cddf9SRui Paulo rsn_ver = RSN_VERSION; 2027f05cddf9SRui Paulo 2028f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_p; 2029f05cddf9SRui Paulo 2030f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 2031f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, rsn_ver); 2032f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 2033f05cddf9SRui Paulo 2034f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 2035f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2036f05cddf9SRui Paulo /* Include only the selected cipher in pairwise cipher suite */ 2037f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 2038f05cddf9SRui Paulo pos += 2; 2039f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) 2040f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 2041f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2042f05cddf9SRui Paulo 2043f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 2044f05cddf9SRui Paulo pos += 2; 2045f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 2046f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2047f05cddf9SRui Paulo 2048f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 2049f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 2050f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 2051f05cddf9SRui Paulo pos += 2; 2052f05cddf9SRui Paulo 2053f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_p) - 2; 2054f05cddf9SRui Paulo peer->rsnie_p_len = pos - peer->rsnie_p; 2055f05cddf9SRui Paulo #endif 2056f05cddf9SRui Paulo 2057f05cddf9SRui Paulo /* temp fix: validation of RSNIE later */ 2058f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); 2059f05cddf9SRui Paulo peer->rsnie_p_len = peer->rsnie_i_len; 2060f05cddf9SRui Paulo 2061f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 2062f05cddf9SRui Paulo peer->rsnie_p, peer->rsnie_p_len); 2063f05cddf9SRui Paulo 2064f05cddf9SRui Paulo peer->lifetime = lifetime; 2065f05cddf9SRui Paulo 2066f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 2067f05cddf9SRui Paulo 2068f05cddf9SRui Paulo skip_rsn_check: 20695b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 20705b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) 20715b9c547cSRui Paulo goto skip_add_peer; 20725b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 20735b9c547cSRui Paulo 20745b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 20755b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 1) < 0) 20765b9c547cSRui Paulo goto error; 20775b9c547cSRui Paulo 20785b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 20795b9c547cSRui Paulo skip_add_peer: 20805b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 20815b9c547cSRui Paulo peer->tpk_in_progress = 1; 2082f05cddf9SRui Paulo 2083f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); 2084f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { 20855b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2086f05cddf9SRui Paulo goto error; 2087f05cddf9SRui Paulo } 2088f05cddf9SRui Paulo 2089f05cddf9SRui Paulo return 0; 2090f05cddf9SRui Paulo 2091f05cddf9SRui Paulo error: 20925b9c547cSRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, 2093f05cddf9SRui Paulo status); 20945b9c547cSRui Paulo if (peer) 20955b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 2096f05cddf9SRui Paulo return -1; 2097f05cddf9SRui Paulo } 2098f05cddf9SRui Paulo 2099f05cddf9SRui Paulo 21005b9c547cSRui Paulo static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 2101f05cddf9SRui Paulo { 2102f05cddf9SRui Paulo peer->tpk_success = 1; 21035b9c547cSRui Paulo peer->tpk_in_progress = 0; 2104f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 2105f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 2106f05cddf9SRui Paulo u32 lifetime = peer->lifetime; 2107f05cddf9SRui Paulo /* 2108f05cddf9SRui Paulo * Start the initiator process a bit earlier to avoid race 2109f05cddf9SRui Paulo * condition with the responder sending teardown request. 2110f05cddf9SRui Paulo */ 2111f05cddf9SRui Paulo if (lifetime > 3 && peer->initiator) 2112f05cddf9SRui Paulo lifetime -= 3; 2113f05cddf9SRui Paulo eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, 2114f05cddf9SRui Paulo sm, peer); 2115f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2116f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { 2117f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " 2118f05cddf9SRui Paulo "expiration"); 2119f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 2120f05cddf9SRui Paulo } 2121f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2122f05cddf9SRui Paulo } 2123f05cddf9SRui Paulo 21245b9c547cSRui Paulo if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { 21255b9c547cSRui Paulo wpa_printf(MSG_INFO, "TDLS: Could not configure key to the " 21265b9c547cSRui Paulo "driver"); 21275b9c547cSRui Paulo return -1; 21285b9c547cSRui Paulo } 21295b9c547cSRui Paulo peer->reconfig_key = 0; 2130f05cddf9SRui Paulo 21315b9c547cSRui Paulo return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); 2132f05cddf9SRui Paulo } 2133f05cddf9SRui Paulo 2134f05cddf9SRui Paulo 2135f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, 2136f05cddf9SRui Paulo const u8 *buf, size_t len) 2137f05cddf9SRui Paulo { 2138f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2139f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 2140f05cddf9SRui Paulo struct wpa_ie_data ie; 2141f05cddf9SRui Paulo int cipher; 2142f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 2143f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 2144f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 2145f05cddf9SRui Paulo u32 lifetime; 2146f05cddf9SRui Paulo u8 dtoken; 2147f05cddf9SRui Paulo int ielen; 2148f05cddf9SRui Paulo u16 status; 2149f05cddf9SRui Paulo const u8 *pos; 21505b9c547cSRui Paulo int ret = 0; 2151f05cddf9SRui Paulo 2152f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " 2153f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 2154f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2155f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 2156f05cddf9SRui Paulo break; 2157f05cddf9SRui Paulo } 2158f05cddf9SRui Paulo if (peer == NULL) { 2159f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 2160f05cddf9SRui Paulo "TPK M2: " MACSTR, MAC2STR(src_addr)); 2161f05cddf9SRui Paulo return -1; 2162f05cddf9SRui Paulo } 21635b9c547cSRui Paulo if (!peer->initiator) { 21645b9c547cSRui Paulo /* 21655b9c547cSRui Paulo * This may happen if both devices try to initiate TDLS at the 21665b9c547cSRui Paulo * same time and we accept the TPK M1 from the peer in 21675b9c547cSRui Paulo * wpa_tdls_process_tpk_m1() and clear our previous state. 21685b9c547cSRui Paulo */ 21695b9c547cSRui Paulo wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so " 21705b9c547cSRui Paulo "ignore TPK M2 from " MACSTR, MAC2STR(src_addr)); 21715b9c547cSRui Paulo return -1; 21725b9c547cSRui Paulo } 2173f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); 2174f05cddf9SRui Paulo 21755b9c547cSRui Paulo if (len < 3 + 2 + 1) { 21765b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2177f05cddf9SRui Paulo return -1; 21785b9c547cSRui Paulo } 21795b9c547cSRui Paulo 2180f05cddf9SRui Paulo pos = buf; 2181f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 2182f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 2183f05cddf9SRui Paulo pos += 2 /* status code */; 2184f05cddf9SRui Paulo 2185f05cddf9SRui Paulo if (status != WLAN_STATUS_SUCCESS) { 2186f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", 2187f05cddf9SRui Paulo status); 21885b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2189f05cddf9SRui Paulo return -1; 2190f05cddf9SRui Paulo } 2191f05cddf9SRui Paulo 2192f05cddf9SRui Paulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2193f05cddf9SRui Paulo 2194f05cddf9SRui Paulo /* TODO: need to verify dialog token matches here or in kernel */ 2195f05cddf9SRui Paulo dtoken = *pos++; /* dialog token */ 2196f05cddf9SRui Paulo 2197f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); 2198f05cddf9SRui Paulo 21995b9c547cSRui Paulo if (len < 3 + 2 + 1 + 2) { 22005b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2201f05cddf9SRui Paulo return -1; 22025b9c547cSRui Paulo } 2203f05cddf9SRui Paulo 2204f05cddf9SRui Paulo /* capability information */ 2205f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(pos); 2206f05cddf9SRui Paulo pos += 2; 2207f05cddf9SRui Paulo 2208f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 22095b9c547cSRui Paulo 22105b9c547cSRui Paulo /* 22115b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 22125b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 22135b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 22145b9c547cSRui Paulo */ 22155b9c547cSRui Paulo if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) 22165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 22175b9c547cSRui Paulo "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround"); 2218f05cddf9SRui Paulo 2219f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2220f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { 2221f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); 2222f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 2223f05cddf9SRui Paulo goto error; 2224f05cddf9SRui Paulo } 2225f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2226f05cddf9SRui Paulo 2227f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 2228f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 2229f05cddf9SRui Paulo "TPK M2"); 2230f05cddf9SRui Paulo goto error; 2231f05cddf9SRui Paulo } 2232f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", 2233f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 2234f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 2235f05cddf9SRui Paulo 2236f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 2237f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); 2238f05cddf9SRui Paulo status = WLAN_STATUS_NOT_IN_SAME_BSS; 2239f05cddf9SRui Paulo goto error; 2240f05cddf9SRui Paulo } 2241f05cddf9SRui Paulo 2242f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 2243f05cddf9SRui Paulo goto error; 2244f05cddf9SRui Paulo 22455b9c547cSRui Paulo if (copy_peer_ht_capab(&kde, peer) < 0) 22465b9c547cSRui Paulo goto error; 22475b9c547cSRui Paulo 22485b9c547cSRui Paulo if (copy_peer_vht_capab(&kde, peer) < 0) 22495b9c547cSRui Paulo goto error; 22505b9c547cSRui Paulo 22515b9c547cSRui Paulo if (copy_peer_ext_capab(&kde, peer) < 0) 22525b9c547cSRui Paulo goto error; 22535b9c547cSRui Paulo 22545b9c547cSRui Paulo if (copy_peer_supp_channels(&kde, peer) < 0) 22555b9c547cSRui Paulo goto error; 22565b9c547cSRui Paulo 22575b9c547cSRui Paulo if (copy_peer_supp_oper_classes(&kde, peer) < 0) 22585b9c547cSRui Paulo goto error; 22595b9c547cSRui Paulo 22605b9c547cSRui Paulo peer->qos_info = kde.qosinfo; 22615b9c547cSRui Paulo 22625b9c547cSRui Paulo /* Overwrite with the qos_info obtained in WMM IE */ 22635b9c547cSRui Paulo if (copy_peer_wmm_capab(&kde, peer) < 0) 22645b9c547cSRui Paulo goto error; 22655b9c547cSRui Paulo 22665b9c547cSRui Paulo peer->aid = kde.aid; 22675b9c547cSRui Paulo 2268f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 2269f05cddf9SRui Paulo peer->rsnie_p_len = 0; 2270f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 2271f05cddf9SRui Paulo goto skip_rsn; 2272f05cddf9SRui Paulo } 2273f05cddf9SRui Paulo 2274f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 2275f05cddf9SRui Paulo kde.rsn_ie == NULL) { 2276f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); 2277f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 2278f05cddf9SRui Paulo goto error; 2279f05cddf9SRui Paulo } 2280f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 2281f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2282f05cddf9SRui Paulo 22835b9c547cSRui Paulo if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { 22845b9c547cSRui Paulo wpa_printf(MSG_INFO, 22855b9c547cSRui Paulo "TDLS: Too long Responder RSN IE in TPK M2"); 22865b9c547cSRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 22875b9c547cSRui Paulo goto error; 22885b9c547cSRui Paulo } 22895b9c547cSRui Paulo 2290f05cddf9SRui Paulo /* 2291f05cddf9SRui Paulo * FIX: bitwise comparison of RSN IE is not the correct way of 2292f05cddf9SRui Paulo * validation this. It can be different, but certain fields must 2293f05cddf9SRui Paulo * match. Since we list only a single pairwise cipher in TPK M1, the 2294f05cddf9SRui Paulo * memcmp is likely to work in most cases, though. 2295f05cddf9SRui Paulo */ 2296f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_i_len || 2297f05cddf9SRui Paulo os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { 2298f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " 2299f05cddf9SRui Paulo "not match with RSN IE used in TPK M1"); 2300f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", 2301f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 2302f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 2303f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2304f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 2305f05cddf9SRui Paulo goto error; 2306f05cddf9SRui Paulo } 2307f05cddf9SRui Paulo 2308f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 2309f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); 2310f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 2311f05cddf9SRui Paulo goto error; 2312f05cddf9SRui Paulo } 2313f05cddf9SRui Paulo 2314f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 2315f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) { 2316f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 2317f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 2318f05cddf9SRui Paulo } else { 2319f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); 2320f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 2321f05cddf9SRui Paulo goto error; 2322f05cddf9SRui Paulo } 2323f05cddf9SRui Paulo 2324f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", 2325f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 2326f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 2327f05cddf9SRui Paulo 2328f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 2329f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " 2330f05cddf9SRui Paulo "not match with FTIE SNonce used in TPK M1"); 2331f05cddf9SRui Paulo /* Silently discard the frame */ 2332f05cddf9SRui Paulo return -1; 2333f05cddf9SRui Paulo } 2334f05cddf9SRui Paulo 2335f05cddf9SRui Paulo /* Responder Nonce and RSN IE */ 2336f05cddf9SRui Paulo os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); 2337f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); 2338f05cddf9SRui Paulo peer->rsnie_p_len = kde.rsn_ie_len; 2339f05cddf9SRui Paulo peer->cipher = cipher; 2340f05cddf9SRui Paulo 2341f05cddf9SRui Paulo /* Lifetime */ 2342f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 2343f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); 2344f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 2345f05cddf9SRui Paulo goto error; 2346f05cddf9SRui Paulo } 2347f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 2348f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 2349f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", 2350f05cddf9SRui Paulo lifetime); 2351f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 2352f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 2353f05cddf9SRui Paulo "TPK M2 (expected %u)", lifetime, peer->lifetime); 2354f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 2355f05cddf9SRui Paulo goto error; 2356f05cddf9SRui Paulo } 2357f05cddf9SRui Paulo 2358f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 2359f05cddf9SRui Paulo 2360f05cddf9SRui Paulo /* Process MIC check to see if TPK M2 is right */ 2361f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, 2362f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 2363f05cddf9SRui Paulo /* Discard the frame */ 2364f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 23655b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2366f05cddf9SRui Paulo return -1; 2367f05cddf9SRui Paulo } 2368f05cddf9SRui Paulo 23695b9c547cSRui Paulo if (wpa_tdls_set_key(sm, peer) < 0) { 23705b9c547cSRui Paulo /* 23715b9c547cSRui Paulo * Some drivers may not be able to config the key prior to full 23725b9c547cSRui Paulo * STA entry having been configured. 23735b9c547cSRui Paulo */ 23745b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " 23755b9c547cSRui Paulo "STA entry is complete"); 23765b9c547cSRui Paulo peer->reconfig_key = 1; 23775b9c547cSRui Paulo } 2378f05cddf9SRui Paulo 2379f05cddf9SRui Paulo skip_rsn: 2380f05cddf9SRui Paulo peer->dtoken = dtoken; 2381f05cddf9SRui Paulo 23825b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 23835b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 0) < 0) 23845b9c547cSRui Paulo goto error; 23855b9c547cSRui Paulo 2386f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " 2387f05cddf9SRui Paulo "TPK Handshake Message 3"); 23885b9c547cSRui Paulo if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) 23895b9c547cSRui Paulo goto error; 2390f05cddf9SRui Paulo 23915b9c547cSRui Paulo if (!peer->tpk_success) { 23925b9c547cSRui Paulo /* 23935b9c547cSRui Paulo * Enable Link only when tpk_success is 0, signifying that this 23945b9c547cSRui Paulo * processing of TPK M2 frame is not because of a retransmission 23955b9c547cSRui Paulo * during TDLS setup handshake. 23965b9c547cSRui Paulo */ 23975b9c547cSRui Paulo ret = wpa_tdls_enable_link(sm, peer); 23985b9c547cSRui Paulo if (ret < 0) { 23995b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); 24005b9c547cSRui Paulo wpa_tdls_do_teardown( 24015b9c547cSRui Paulo sm, peer, 24025b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 24035b9c547cSRui Paulo } 24045b9c547cSRui Paulo } 24055b9c547cSRui Paulo return ret; 2406f05cddf9SRui Paulo 2407f05cddf9SRui Paulo error: 24085b9c547cSRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1, 2409f05cddf9SRui Paulo status); 24105b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2411f05cddf9SRui Paulo return -1; 2412f05cddf9SRui Paulo } 2413f05cddf9SRui Paulo 2414f05cddf9SRui Paulo 2415f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, 2416f05cddf9SRui Paulo const u8 *buf, size_t len) 2417f05cddf9SRui Paulo { 2418f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2419f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 2420f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 2421f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 2422f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 2423f05cddf9SRui Paulo int ielen; 2424f05cddf9SRui Paulo u16 status; 2425f05cddf9SRui Paulo const u8 *pos; 2426f05cddf9SRui Paulo u32 lifetime; 24275b9c547cSRui Paulo int ret = 0; 2428f05cddf9SRui Paulo 2429f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " 2430f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 2431f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2432f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 2433f05cddf9SRui Paulo break; 2434f05cddf9SRui Paulo } 2435f05cddf9SRui Paulo if (peer == NULL) { 2436f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 2437f05cddf9SRui Paulo "TPK M3: " MACSTR, MAC2STR(src_addr)); 2438f05cddf9SRui Paulo return -1; 2439f05cddf9SRui Paulo } 2440f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); 2441f05cddf9SRui Paulo 2442f05cddf9SRui Paulo if (len < 3 + 3) 24435b9c547cSRui Paulo goto error; 2444f05cddf9SRui Paulo pos = buf; 2445f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 2446f05cddf9SRui Paulo 2447f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 2448f05cddf9SRui Paulo 2449f05cddf9SRui Paulo if (status != 0) { 2450f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", 2451f05cddf9SRui Paulo status); 24525b9c547cSRui Paulo goto error; 2453f05cddf9SRui Paulo } 2454f05cddf9SRui Paulo pos += 2 /* status code */ + 1 /* dialog token */; 2455f05cddf9SRui Paulo 2456f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 24575b9c547cSRui Paulo 24585b9c547cSRui Paulo /* 24595b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 24605b9c547cSRui Paulo * explicitly checked below. Some APs piggy-back broken IEs to the end 24615b9c547cSRui Paulo * of a TDLS Confirm packet, which will fail the link if we don't ignore 24625b9c547cSRui Paulo * this error. 24635b9c547cSRui Paulo */ 2464f05cddf9SRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { 24655b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 24665b9c547cSRui Paulo "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround"); 2467f05cddf9SRui Paulo } 2468f05cddf9SRui Paulo 2469f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 2470f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3"); 24715b9c547cSRui Paulo goto error; 2472f05cddf9SRui Paulo } 2473f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", 2474f05cddf9SRui Paulo (u8 *) kde.lnkid, kde.lnkid_len); 2475f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 2476f05cddf9SRui Paulo 2477f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 2478f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); 24795b9c547cSRui Paulo goto error; 2480f05cddf9SRui Paulo } 2481f05cddf9SRui Paulo 2482f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 2483f05cddf9SRui Paulo goto skip_rsn; 2484f05cddf9SRui Paulo 2485f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 2486f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); 24875b9c547cSRui Paulo goto error; 2488f05cddf9SRui Paulo } 2489f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", 2490f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 2491f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 2492f05cddf9SRui Paulo 2493f05cddf9SRui Paulo if (kde.rsn_ie == NULL) { 2494f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); 24955b9c547cSRui Paulo goto error; 2496f05cddf9SRui Paulo } 2497f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", 2498f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2499f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_p_len || 2500f05cddf9SRui Paulo os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) { 2501f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match " 2502f05cddf9SRui Paulo "with the one sent in TPK M2"); 25035b9c547cSRui Paulo goto error; 2504f05cddf9SRui Paulo } 2505f05cddf9SRui Paulo 2506f05cddf9SRui Paulo if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) { 2507f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does " 2508f05cddf9SRui Paulo "not match with FTIE ANonce used in TPK M2"); 25095b9c547cSRui Paulo goto error; 2510f05cddf9SRui Paulo } 2511f05cddf9SRui Paulo 2512f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 2513f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not " 2514f05cddf9SRui Paulo "match with FTIE SNonce used in TPK M1"); 25155b9c547cSRui Paulo goto error; 2516f05cddf9SRui Paulo } 2517f05cddf9SRui Paulo 2518f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 2519f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); 25205b9c547cSRui Paulo goto error; 2521f05cddf9SRui Paulo } 2522f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 2523f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", 2524f05cddf9SRui Paulo (u8 *) timeoutie, sizeof(*timeoutie)); 2525f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 2526f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", 2527f05cddf9SRui Paulo lifetime); 2528f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 2529f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 2530f05cddf9SRui Paulo "TPK M3 (expected %u)", lifetime, peer->lifetime); 25315b9c547cSRui Paulo goto error; 2532f05cddf9SRui Paulo } 2533f05cddf9SRui Paulo 2534f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, 2535f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 2536f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 25375b9c547cSRui Paulo goto error; 2538f05cddf9SRui Paulo } 2539f05cddf9SRui Paulo 25405b9c547cSRui Paulo if (wpa_tdls_set_key(sm, peer) < 0) { 25415b9c547cSRui Paulo /* 25425b9c547cSRui Paulo * Some drivers may not be able to config the key prior to full 25435b9c547cSRui Paulo * STA entry having been configured. 25445b9c547cSRui Paulo */ 25455b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " 25465b9c547cSRui Paulo "STA entry is complete"); 25475b9c547cSRui Paulo peer->reconfig_key = 1; 25485b9c547cSRui Paulo } 2549f05cddf9SRui Paulo 2550f05cddf9SRui Paulo skip_rsn: 25515b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 25525b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 0) < 0) 25535b9c547cSRui Paulo goto error; 2554f05cddf9SRui Paulo 25555b9c547cSRui Paulo if (!peer->tpk_success) { 25565b9c547cSRui Paulo /* 25575b9c547cSRui Paulo * Enable Link only when tpk_success is 0, signifying that this 25585b9c547cSRui Paulo * processing of TPK M3 frame is not because of a retransmission 25595b9c547cSRui Paulo * during TDLS setup handshake. 25605b9c547cSRui Paulo */ 25615b9c547cSRui Paulo ret = wpa_tdls_enable_link(sm, peer); 25625b9c547cSRui Paulo if (ret < 0) { 25635b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); 25645b9c547cSRui Paulo goto error; 25655b9c547cSRui Paulo } 25665b9c547cSRui Paulo } 25675b9c547cSRui Paulo return ret; 25685b9c547cSRui Paulo error: 25695b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 25705b9c547cSRui Paulo return -1; 2571f05cddf9SRui Paulo } 2572f05cddf9SRui Paulo 2573f05cddf9SRui Paulo 2574f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) 2575f05cddf9SRui Paulo { 2576f05cddf9SRui Paulo struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; 2577f05cddf9SRui Paulo 2578f05cddf9SRui Paulo os_memset(lifetime, 0, ie_len); 2579f05cddf9SRui Paulo lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; 2580f05cddf9SRui Paulo lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; 2581f05cddf9SRui Paulo lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; 2582f05cddf9SRui Paulo WPA_PUT_LE32(lifetime->value, tsecs); 2583f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 2584f05cddf9SRui Paulo return pos + ie_len; 2585f05cddf9SRui Paulo } 2586f05cddf9SRui Paulo 2587f05cddf9SRui Paulo 2588f05cddf9SRui Paulo /** 2589f05cddf9SRui Paulo * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) 2590f05cddf9SRui Paulo * @sm: Pointer to WPA state machine data from wpa_sm_init() 2591f05cddf9SRui Paulo * @peer: MAC address of the peer STA 2592f05cddf9SRui Paulo * Returns: 0 on success, or -1 on failure 2593f05cddf9SRui Paulo * 2594f05cddf9SRui Paulo * Send TPK Handshake Message 1 info to driver to start TDLS 2595f05cddf9SRui Paulo * handshake with the peer. 2596f05cddf9SRui Paulo */ 2597f05cddf9SRui Paulo int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) 2598f05cddf9SRui Paulo { 2599f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2600f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 2601f05cddf9SRui Paulo 2602f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2603f05cddf9SRui Paulo return -1; 2604f05cddf9SRui Paulo 2605f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2606f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 2607f05cddf9SRui Paulo tdls_prohibited) { 2608f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 2609f05cddf9SRui Paulo "on TDLS"); 2610f05cddf9SRui Paulo tdls_prohibited = 0; 2611f05cddf9SRui Paulo } 2612f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2613f05cddf9SRui Paulo 2614f05cddf9SRui Paulo if (tdls_prohibited) { 2615f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " 2616f05cddf9SRui Paulo "reject request to start setup"); 2617f05cddf9SRui Paulo return -1; 2618f05cddf9SRui Paulo } 2619f05cddf9SRui Paulo 26205b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, addr, NULL); 2621f05cddf9SRui Paulo if (peer == NULL) 2622f05cddf9SRui Paulo return -1; 26235b9c547cSRui Paulo 26245b9c547cSRui Paulo if (peer->tpk_in_progress) { 26255b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer"); 26265b9c547cSRui Paulo return 0; 2627f05cddf9SRui Paulo } 2628f05cddf9SRui Paulo 2629f05cddf9SRui Paulo peer->initiator = 1; 2630f05cddf9SRui Paulo 2631f05cddf9SRui Paulo /* add the peer to the driver as a "setup in progress" peer */ 26325b9c547cSRui Paulo if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, 26335b9c547cSRui Paulo NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) { 26345b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 26355b9c547cSRui Paulo return -1; 26365b9c547cSRui Paulo } 26375b9c547cSRui Paulo 26385b9c547cSRui Paulo peer->tpk_in_progress = 1; 2639f05cddf9SRui Paulo 2640f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m1(sm, peer) < 0) { 26415b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2642f05cddf9SRui Paulo return -1; 2643f05cddf9SRui Paulo } 2644f05cddf9SRui Paulo 2645f05cddf9SRui Paulo return 0; 2646f05cddf9SRui Paulo } 2647f05cddf9SRui Paulo 2648f05cddf9SRui Paulo 26495b9c547cSRui Paulo void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) 2650f05cddf9SRui Paulo { 2651f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2652f05cddf9SRui Paulo 2653f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 26545b9c547cSRui Paulo return; 2655f05cddf9SRui Paulo 2656f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2657f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2658f05cddf9SRui Paulo break; 2659f05cddf9SRui Paulo } 2660f05cddf9SRui Paulo 2661f05cddf9SRui Paulo if (peer == NULL || !peer->tpk_success) 26625b9c547cSRui Paulo return; 2663f05cddf9SRui Paulo 2664f05cddf9SRui Paulo if (sm->tdls_external_setup) { 2665f05cddf9SRui Paulo /* 2666f05cddf9SRui Paulo * Disable previous link to allow renegotiation to be completed 2667f05cddf9SRui Paulo * on AP path. 2668f05cddf9SRui Paulo */ 26695b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, 26705b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 2671f05cddf9SRui Paulo } 2672f05cddf9SRui Paulo } 2673f05cddf9SRui Paulo 2674f05cddf9SRui Paulo 2675f05cddf9SRui Paulo /** 2676f05cddf9SRui Paulo * wpa_supplicant_rx_tdls - Receive TDLS data frame 2677f05cddf9SRui Paulo * 2678f05cddf9SRui Paulo * This function is called to receive TDLS (ethertype = 0x890d) data frames. 2679f05cddf9SRui Paulo */ 2680f05cddf9SRui Paulo static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, 2681f05cddf9SRui Paulo const u8 *buf, size_t len) 2682f05cddf9SRui Paulo { 2683f05cddf9SRui Paulo struct wpa_sm *sm = ctx; 2684f05cddf9SRui Paulo struct wpa_tdls_frame *tf; 2685f05cddf9SRui Paulo 2686f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", 2687f05cddf9SRui Paulo buf, len); 2688f05cddf9SRui Paulo 2689f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) { 2690f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " 2691f05cddf9SRui Paulo "or unsupported by driver"); 2692f05cddf9SRui Paulo return; 2693f05cddf9SRui Paulo } 2694f05cddf9SRui Paulo 2695f05cddf9SRui Paulo if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { 2696f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); 2697f05cddf9SRui Paulo return; 2698f05cddf9SRui Paulo } 2699f05cddf9SRui Paulo 2700f05cddf9SRui Paulo if (len < sizeof(*tf)) { 2701f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); 2702f05cddf9SRui Paulo return; 2703f05cddf9SRui Paulo } 2704f05cddf9SRui Paulo 2705f05cddf9SRui Paulo /* Check to make sure its a valid encapsulated TDLS frame */ 2706f05cddf9SRui Paulo tf = (struct wpa_tdls_frame *) buf; 2707f05cddf9SRui Paulo if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || 2708f05cddf9SRui Paulo tf->category != WLAN_ACTION_TDLS) { 2709f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " 2710f05cddf9SRui Paulo "category=%u action=%u", 2711f05cddf9SRui Paulo tf->payloadtype, tf->category, tf->action); 2712f05cddf9SRui Paulo return; 2713f05cddf9SRui Paulo } 2714f05cddf9SRui Paulo 2715f05cddf9SRui Paulo switch (tf->action) { 2716f05cddf9SRui Paulo case WLAN_TDLS_SETUP_REQUEST: 2717f05cddf9SRui Paulo wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); 2718f05cddf9SRui Paulo break; 2719f05cddf9SRui Paulo case WLAN_TDLS_SETUP_RESPONSE: 2720f05cddf9SRui Paulo wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); 2721f05cddf9SRui Paulo break; 2722f05cddf9SRui Paulo case WLAN_TDLS_SETUP_CONFIRM: 2723f05cddf9SRui Paulo wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); 2724f05cddf9SRui Paulo break; 2725f05cddf9SRui Paulo case WLAN_TDLS_TEARDOWN: 2726f05cddf9SRui Paulo wpa_tdls_recv_teardown(sm, src_addr, buf, len); 2727f05cddf9SRui Paulo break; 2728f05cddf9SRui Paulo case WLAN_TDLS_DISCOVERY_REQUEST: 2729f05cddf9SRui Paulo wpa_tdls_process_discovery_request(sm, src_addr, buf, len); 2730f05cddf9SRui Paulo break; 2731f05cddf9SRui Paulo default: 2732f05cddf9SRui Paulo /* Kernel code will process remaining frames */ 2733f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", 2734f05cddf9SRui Paulo tf->action); 2735f05cddf9SRui Paulo break; 2736f05cddf9SRui Paulo } 2737f05cddf9SRui Paulo } 2738f05cddf9SRui Paulo 2739f05cddf9SRui Paulo 2740f05cddf9SRui Paulo /** 2741f05cddf9SRui Paulo * wpa_tdls_init - Initialize driver interface parameters for TDLS 2742f05cddf9SRui Paulo * @wpa_s: Pointer to wpa_supplicant data 2743f05cddf9SRui Paulo * Returns: 0 on success, -1 on failure 2744f05cddf9SRui Paulo * 2745f05cddf9SRui Paulo * This function is called to initialize driver interface parameters for TDLS. 2746f05cddf9SRui Paulo * wpa_drv_init() must have been called before this function to initialize the 2747f05cddf9SRui Paulo * driver interface. 2748f05cddf9SRui Paulo */ 2749f05cddf9SRui Paulo int wpa_tdls_init(struct wpa_sm *sm) 2750f05cddf9SRui Paulo { 2751f05cddf9SRui Paulo if (sm == NULL) 2752f05cddf9SRui Paulo return -1; 2753f05cddf9SRui Paulo 2754f05cddf9SRui Paulo sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : 2755f05cddf9SRui Paulo sm->ifname, 2756f05cddf9SRui Paulo sm->own_addr, 2757f05cddf9SRui Paulo ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, 2758f05cddf9SRui Paulo sm, 0); 2759f05cddf9SRui Paulo if (sm->l2_tdls == NULL) { 2760f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " 2761f05cddf9SRui Paulo "connection"); 2762f05cddf9SRui Paulo return -1; 2763f05cddf9SRui Paulo } 2764f05cddf9SRui Paulo 2765f05cddf9SRui Paulo /* 2766f05cddf9SRui Paulo * Drivers that support TDLS but don't implement the get_capa callback 2767f05cddf9SRui Paulo * are assumed to perform everything internally 2768f05cddf9SRui Paulo */ 2769f05cddf9SRui Paulo if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, 27705b9c547cSRui Paulo &sm->tdls_external_setup, 27715b9c547cSRui Paulo &sm->tdls_chan_switch) < 0) { 2772f05cddf9SRui Paulo sm->tdls_supported = 1; 2773f05cddf9SRui Paulo sm->tdls_external_setup = 0; 2774f05cddf9SRui Paulo } 2775f05cddf9SRui Paulo 2776f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " 2777f05cddf9SRui Paulo "driver", sm->tdls_supported ? "" : " not"); 2778f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup", 2779f05cddf9SRui Paulo sm->tdls_external_setup ? "external" : "internal"); 27805b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching", 27815b9c547cSRui Paulo sm->tdls_chan_switch ? "supports" : "does not support"); 2782f05cddf9SRui Paulo 2783f05cddf9SRui Paulo return 0; 2784f05cddf9SRui Paulo } 2785f05cddf9SRui Paulo 2786f05cddf9SRui Paulo 27875b9c547cSRui Paulo void wpa_tdls_teardown_peers(struct wpa_sm *sm) 27885b9c547cSRui Paulo { 27895b9c547cSRui Paulo struct wpa_tdls_peer *peer, *tmp; 27905b9c547cSRui Paulo 27915b9c547cSRui Paulo if (!sm) 27925b9c547cSRui Paulo return; 27935b9c547cSRui Paulo peer = sm->tdls; 27945b9c547cSRui Paulo 27955b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Tear down peers"); 27965b9c547cSRui Paulo 27975b9c547cSRui Paulo while (peer) { 27985b9c547cSRui Paulo tmp = peer->next; 27995b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR, 28005b9c547cSRui Paulo MAC2STR(peer->addr)); 28015b9c547cSRui Paulo if (sm->tdls_external_setup) 28025b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, 28035b9c547cSRui Paulo WLAN_REASON_DEAUTH_LEAVING); 28045b9c547cSRui Paulo else 28055b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); 28065b9c547cSRui Paulo 28075b9c547cSRui Paulo peer = tmp; 28085b9c547cSRui Paulo } 28095b9c547cSRui Paulo } 28105b9c547cSRui Paulo 28115b9c547cSRui Paulo 2812f05cddf9SRui Paulo static void wpa_tdls_remove_peers(struct wpa_sm *sm) 2813f05cddf9SRui Paulo { 2814f05cddf9SRui Paulo struct wpa_tdls_peer *peer, *tmp; 2815f05cddf9SRui Paulo 2816f05cddf9SRui Paulo peer = sm->tdls; 2817f05cddf9SRui Paulo 2818f05cddf9SRui Paulo while (peer) { 2819f05cddf9SRui Paulo int res; 2820f05cddf9SRui Paulo tmp = peer->next; 2821f05cddf9SRui Paulo res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2822f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", 2823f05cddf9SRui Paulo MAC2STR(peer->addr), res); 2824f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 2825f05cddf9SRui Paulo peer = tmp; 2826f05cddf9SRui Paulo } 2827f05cddf9SRui Paulo } 2828f05cddf9SRui Paulo 2829f05cddf9SRui Paulo 2830f05cddf9SRui Paulo /** 2831f05cddf9SRui Paulo * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS 2832f05cddf9SRui Paulo * 2833f05cddf9SRui Paulo * This function is called to recover driver interface parameters for TDLS 2834f05cddf9SRui Paulo * and frees resources allocated for it. 2835f05cddf9SRui Paulo */ 2836f05cddf9SRui Paulo void wpa_tdls_deinit(struct wpa_sm *sm) 2837f05cddf9SRui Paulo { 2838f05cddf9SRui Paulo if (sm == NULL) 2839f05cddf9SRui Paulo return; 2840f05cddf9SRui Paulo 2841f05cddf9SRui Paulo if (sm->l2_tdls) 2842f05cddf9SRui Paulo l2_packet_deinit(sm->l2_tdls); 2843f05cddf9SRui Paulo sm->l2_tdls = NULL; 2844f05cddf9SRui Paulo 2845f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2846f05cddf9SRui Paulo } 2847f05cddf9SRui Paulo 2848f05cddf9SRui Paulo 2849f05cddf9SRui Paulo void wpa_tdls_assoc(struct wpa_sm *sm) 2850f05cddf9SRui Paulo { 2851f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); 2852f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2853f05cddf9SRui Paulo } 2854f05cddf9SRui Paulo 2855f05cddf9SRui Paulo 2856f05cddf9SRui Paulo void wpa_tdls_disassoc(struct wpa_sm *sm) 2857f05cddf9SRui Paulo { 2858f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); 2859f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2860f05cddf9SRui Paulo } 2861f05cddf9SRui Paulo 2862f05cddf9SRui Paulo 2863*325151a3SRui Paulo static int wpa_tdls_prohibited(struct ieee802_11_elems *elems) 2864f05cddf9SRui Paulo { 2865f05cddf9SRui Paulo /* bit 38 - TDLS Prohibited */ 28665b9c547cSRui Paulo return !!(elems->ext_capab[2 + 4] & 0x40); 28675b9c547cSRui Paulo } 28685b9c547cSRui Paulo 28695b9c547cSRui Paulo 2870*325151a3SRui Paulo static int wpa_tdls_chan_switch_prohibited(struct ieee802_11_elems *elems) 28715b9c547cSRui Paulo { 28725b9c547cSRui Paulo /* bit 39 - TDLS Channel Switch Prohibited */ 28735b9c547cSRui Paulo return !!(elems->ext_capab[2 + 4] & 0x80); 2874f05cddf9SRui Paulo } 2875f05cddf9SRui Paulo 2876f05cddf9SRui Paulo 2877f05cddf9SRui Paulo void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2878f05cddf9SRui Paulo { 2879*325151a3SRui Paulo struct ieee802_11_elems elems; 28805b9c547cSRui Paulo 28815b9c547cSRui Paulo sm->tdls_prohibited = 0; 28825b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 0; 28835b9c547cSRui Paulo 2884*325151a3SRui Paulo if (ies == NULL || 2885*325151a3SRui Paulo ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed || 28865b9c547cSRui Paulo elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) 28875b9c547cSRui Paulo return; 28885b9c547cSRui Paulo 28895b9c547cSRui Paulo sm->tdls_prohibited = wpa_tdls_prohibited(&elems); 2890f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", 2891f05cddf9SRui Paulo sm->tdls_prohibited ? "prohibited" : "allowed"); 28925b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 28935b9c547cSRui Paulo wpa_tdls_chan_switch_prohibited(&elems); 28945b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS", 28955b9c547cSRui Paulo sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed"); 2896f05cddf9SRui Paulo } 2897f05cddf9SRui Paulo 2898f05cddf9SRui Paulo 2899f05cddf9SRui Paulo void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2900f05cddf9SRui Paulo { 2901*325151a3SRui Paulo struct ieee802_11_elems elems; 29025b9c547cSRui Paulo 2903*325151a3SRui Paulo if (ies == NULL || 2904*325151a3SRui Paulo ieee802_11_parse_elems(ies, len, &elems, 0) == ParseFailed || 29055b9c547cSRui Paulo elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) 29065b9c547cSRui Paulo return; 29075b9c547cSRui Paulo 29085b9c547cSRui Paulo if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) { 2909f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " 2910f05cddf9SRui Paulo "(Re)Association Response IEs"); 2911f05cddf9SRui Paulo sm->tdls_prohibited = 1; 2912f05cddf9SRui Paulo } 29135b9c547cSRui Paulo 29145b9c547cSRui Paulo if (!sm->tdls_chan_switch_prohibited && 29155b9c547cSRui Paulo wpa_tdls_chan_switch_prohibited(&elems)) { 29165b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 29175b9c547cSRui Paulo "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs"); 29185b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 1; 29195b9c547cSRui Paulo } 2920f05cddf9SRui Paulo } 2921f05cddf9SRui Paulo 2922f05cddf9SRui Paulo 2923f05cddf9SRui Paulo void wpa_tdls_enable(struct wpa_sm *sm, int enabled) 2924f05cddf9SRui Paulo { 2925f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); 2926f05cddf9SRui Paulo sm->tdls_disabled = !enabled; 2927f05cddf9SRui Paulo } 2928f05cddf9SRui Paulo 2929f05cddf9SRui Paulo 2930f05cddf9SRui Paulo int wpa_tdls_is_external_setup(struct wpa_sm *sm) 2931f05cddf9SRui Paulo { 2932f05cddf9SRui Paulo return sm->tdls_external_setup; 2933f05cddf9SRui Paulo } 29345b9c547cSRui Paulo 29355b9c547cSRui Paulo 29365b9c547cSRui Paulo int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, 29375b9c547cSRui Paulo u8 oper_class, 29385b9c547cSRui Paulo struct hostapd_freq_params *freq_params) 29395b9c547cSRui Paulo { 29405b9c547cSRui Paulo struct wpa_tdls_peer *peer; 29415b9c547cSRui Paulo int ret; 29425b9c547cSRui Paulo 29435b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 29445b9c547cSRui Paulo return -1; 29455b9c547cSRui Paulo 29465b9c547cSRui Paulo if (!sm->tdls_chan_switch) { 29475b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 29485b9c547cSRui Paulo "TDLS: Channel switching not supported by the driver"); 29495b9c547cSRui Paulo return -1; 29505b9c547cSRui Paulo } 29515b9c547cSRui Paulo 29525b9c547cSRui Paulo if (sm->tdls_chan_switch_prohibited) { 29535b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 29545b9c547cSRui Paulo "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel"); 29555b9c547cSRui Paulo return -1; 29565b9c547cSRui Paulo } 29575b9c547cSRui Paulo 29585b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 29595b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 29605b9c547cSRui Paulo break; 29615b9c547cSRui Paulo } 29625b9c547cSRui Paulo 29635b9c547cSRui Paulo if (peer == NULL || !peer->tpk_success) { 29645b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR 29655b9c547cSRui Paulo " not found for channel switching", MAC2STR(addr)); 29665b9c547cSRui Paulo return -1; 29675b9c547cSRui Paulo } 29685b9c547cSRui Paulo 29695b9c547cSRui Paulo if (peer->chan_switch_enabled) { 29705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 29715b9c547cSRui Paulo " already has channel switching enabled", 29725b9c547cSRui Paulo MAC2STR(addr)); 29735b9c547cSRui Paulo return 0; 29745b9c547cSRui Paulo } 29755b9c547cSRui Paulo 29765b9c547cSRui Paulo ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr, 29775b9c547cSRui Paulo oper_class, freq_params); 29785b9c547cSRui Paulo if (!ret) 29795b9c547cSRui Paulo peer->chan_switch_enabled = 1; 29805b9c547cSRui Paulo 29815b9c547cSRui Paulo return ret; 29825b9c547cSRui Paulo } 29835b9c547cSRui Paulo 29845b9c547cSRui Paulo 29855b9c547cSRui Paulo int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr) 29865b9c547cSRui Paulo { 29875b9c547cSRui Paulo struct wpa_tdls_peer *peer; 29885b9c547cSRui Paulo 29895b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 29905b9c547cSRui Paulo return -1; 29915b9c547cSRui Paulo 29925b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 29935b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 29945b9c547cSRui Paulo break; 29955b9c547cSRui Paulo } 29965b9c547cSRui Paulo 29975b9c547cSRui Paulo if (!peer || !peer->chan_switch_enabled) { 29985b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for " 29995b9c547cSRui Paulo MACSTR, MAC2STR(addr)); 30005b9c547cSRui Paulo return -1; 30015b9c547cSRui Paulo } 30025b9c547cSRui Paulo 30035b9c547cSRui Paulo /* ignore the return value */ 30045b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 30055b9c547cSRui Paulo 30065b9c547cSRui Paulo peer->chan_switch_enabled = 0; 30075b9c547cSRui Paulo return 0; 30085b9c547cSRui Paulo } 3009