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" 15f05cddf9SRui Paulo #include "crypto/sha256.h" 16f05cddf9SRui Paulo #include "crypto/crypto.h" 17f05cddf9SRui Paulo #include "crypto/aes_wrap.h" 18f05cddf9SRui Paulo #include "rsn_supp/wpa.h" 19f05cddf9SRui Paulo #include "rsn_supp/wpa_ie.h" 20f05cddf9SRui Paulo #include "rsn_supp/wpa_i.h" 21f05cddf9SRui Paulo #include "drivers/driver.h" 22f05cddf9SRui Paulo #include "l2_packet/l2_packet.h" 23f05cddf9SRui Paulo 24f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 25f05cddf9SRui Paulo #define TDLS_TESTING_LONG_FRAME BIT(0) 26f05cddf9SRui Paulo #define TDLS_TESTING_ALT_RSN_IE BIT(1) 27f05cddf9SRui Paulo #define TDLS_TESTING_DIFF_BSSID BIT(2) 28f05cddf9SRui Paulo #define TDLS_TESTING_SHORT_LIFETIME BIT(3) 29f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) 30f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) 31f05cddf9SRui Paulo #define TDLS_TESTING_LONG_LIFETIME BIT(6) 32f05cddf9SRui Paulo #define TDLS_TESTING_CONCURRENT_INIT BIT(7) 33f05cddf9SRui Paulo #define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8) 34f05cddf9SRui Paulo #define TDLS_TESTING_DECLINE_RESP BIT(9) 35f05cddf9SRui Paulo #define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10) 36*5b9c547cSRui Paulo #define TDLS_TESTING_WRONG_MIC BIT(11) 37f05cddf9SRui Paulo unsigned int tdls_testing = 0; 38f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 39f05cddf9SRui Paulo 40f05cddf9SRui Paulo #define TPK_LIFETIME 43200 /* 12 hours */ 41*5b9c547cSRui Paulo #define TPK_M1_RETRY_COUNT 3 42*5b9c547cSRui Paulo #define TPK_M1_TIMEOUT 5000 /* in milliseconds */ 43*5b9c547cSRui Paulo #define TPK_M2_RETRY_COUNT 10 44*5b9c547cSRui Paulo #define TPK_M2_TIMEOUT 500 /* in milliseconds */ 45f05cddf9SRui Paulo 46f05cddf9SRui Paulo #define TDLS_MIC_LEN 16 47f05cddf9SRui Paulo 48f05cddf9SRui Paulo #define TDLS_TIMEOUT_LEN 4 49f05cddf9SRui Paulo 50f05cddf9SRui Paulo struct wpa_tdls_ftie { 51f05cddf9SRui Paulo u8 ie_type; /* FTIE */ 52f05cddf9SRui Paulo u8 ie_len; 53f05cddf9SRui Paulo u8 mic_ctrl[2]; 54f05cddf9SRui Paulo u8 mic[TDLS_MIC_LEN]; 55f05cddf9SRui Paulo u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ 56f05cddf9SRui Paulo u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ 57f05cddf9SRui Paulo /* followed by optional elements */ 58f05cddf9SRui Paulo } STRUCT_PACKED; 59f05cddf9SRui Paulo 60f05cddf9SRui Paulo struct wpa_tdls_timeoutie { 61f05cddf9SRui Paulo u8 ie_type; /* Timeout IE */ 62f05cddf9SRui Paulo u8 ie_len; 63f05cddf9SRui Paulo u8 interval_type; 64f05cddf9SRui Paulo u8 value[TDLS_TIMEOUT_LEN]; 65f05cddf9SRui Paulo } STRUCT_PACKED; 66f05cddf9SRui Paulo 67f05cddf9SRui Paulo struct wpa_tdls_lnkid { 68f05cddf9SRui Paulo u8 ie_type; /* Link Identifier IE */ 69f05cddf9SRui Paulo u8 ie_len; 70f05cddf9SRui Paulo u8 bssid[ETH_ALEN]; 71f05cddf9SRui Paulo u8 init_sta[ETH_ALEN]; 72f05cddf9SRui Paulo u8 resp_sta[ETH_ALEN]; 73f05cddf9SRui Paulo } STRUCT_PACKED; 74f05cddf9SRui Paulo 75f05cddf9SRui Paulo /* TDLS frame headers as per IEEE Std 802.11z-2010 */ 76f05cddf9SRui Paulo struct wpa_tdls_frame { 77f05cddf9SRui Paulo u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ 78f05cddf9SRui Paulo u8 category; /* Category */ 79f05cddf9SRui Paulo u8 action; /* Action (enum tdls_frame_type) */ 80f05cddf9SRui Paulo } STRUCT_PACKED; 81f05cddf9SRui Paulo 82f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs); 83f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); 84f05cddf9SRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); 85*5b9c547cSRui Paulo static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, 86*5b9c547cSRui Paulo struct wpa_tdls_peer *peer); 87*5b9c547cSRui Paulo static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, 88*5b9c547cSRui Paulo u16 reason_code); 89f05cddf9SRui Paulo 90f05cddf9SRui Paulo 91f05cddf9SRui Paulo #define TDLS_MAX_IE_LEN 80 92f05cddf9SRui Paulo #define IEEE80211_MAX_SUPP_RATES 32 93f05cddf9SRui Paulo 94f05cddf9SRui Paulo struct wpa_tdls_peer { 95f05cddf9SRui Paulo struct wpa_tdls_peer *next; 96*5b9c547cSRui Paulo unsigned int reconfig_key:1; 97f05cddf9SRui Paulo int initiator; /* whether this end was initiator for TDLS setup */ 98f05cddf9SRui Paulo u8 addr[ETH_ALEN]; /* other end MAC address */ 99f05cddf9SRui Paulo u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ 100f05cddf9SRui Paulo u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ 101f05cddf9SRui Paulo u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ 102f05cddf9SRui Paulo size_t rsnie_i_len; 103f05cddf9SRui Paulo u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ 104f05cddf9SRui Paulo size_t rsnie_p_len; 105f05cddf9SRui Paulo u32 lifetime; 106f05cddf9SRui Paulo int cipher; /* Selected cipher (WPA_CIPHER_*) */ 107f05cddf9SRui Paulo u8 dtoken; 108f05cddf9SRui Paulo 109f05cddf9SRui Paulo struct tpk { 110f05cddf9SRui Paulo u8 kck[16]; /* TPK-KCK */ 111f05cddf9SRui Paulo u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ 112f05cddf9SRui Paulo } tpk; 113f05cddf9SRui Paulo int tpk_set; 114f05cddf9SRui Paulo int tpk_success; 115*5b9c547cSRui Paulo int tpk_in_progress; 116f05cddf9SRui Paulo 117f05cddf9SRui Paulo struct tpk_timer { 118f05cddf9SRui Paulo u8 dest[ETH_ALEN]; 119f05cddf9SRui Paulo int count; /* Retry Count */ 120f05cddf9SRui Paulo int timer; /* Timeout in milliseconds */ 121f05cddf9SRui Paulo u8 action_code; /* TDLS frame type */ 122f05cddf9SRui Paulo u8 dialog_token; 123f05cddf9SRui Paulo u16 status_code; 124*5b9c547cSRui Paulo u32 peer_capab; 125f05cddf9SRui Paulo int buf_len; /* length of TPK message for retransmission */ 126f05cddf9SRui Paulo u8 *buf; /* buffer for TPK message */ 127f05cddf9SRui Paulo } sm_tmr; 128f05cddf9SRui Paulo 129f05cddf9SRui Paulo u16 capability; 130f05cddf9SRui Paulo 131f05cddf9SRui Paulo u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 132f05cddf9SRui Paulo size_t supp_rates_len; 133*5b9c547cSRui Paulo 134*5b9c547cSRui Paulo struct ieee80211_ht_capabilities *ht_capabilities; 135*5b9c547cSRui Paulo struct ieee80211_vht_capabilities *vht_capabilities; 136*5b9c547cSRui Paulo 137*5b9c547cSRui Paulo u8 qos_info; 138*5b9c547cSRui Paulo 139*5b9c547cSRui Paulo u16 aid; 140*5b9c547cSRui Paulo 141*5b9c547cSRui Paulo u8 *ext_capab; 142*5b9c547cSRui Paulo size_t ext_capab_len; 143*5b9c547cSRui Paulo 144*5b9c547cSRui Paulo u8 *supp_channels; 145*5b9c547cSRui Paulo size_t supp_channels_len; 146*5b9c547cSRui Paulo 147*5b9c547cSRui Paulo u8 *supp_oper_classes; 148*5b9c547cSRui Paulo size_t supp_oper_classes_len; 149*5b9c547cSRui Paulo 150*5b9c547cSRui Paulo u8 wmm_capable; 151*5b9c547cSRui Paulo 152*5b9c547cSRui Paulo /* channel switch currently enabled */ 153*5b9c547cSRui Paulo int chan_switch_enabled; 154f05cddf9SRui Paulo }; 155f05cddf9SRui Paulo 156f05cddf9SRui Paulo 157f05cddf9SRui Paulo static int wpa_tdls_get_privacy(struct wpa_sm *sm) 158f05cddf9SRui Paulo { 159f05cddf9SRui Paulo /* 160f05cddf9SRui Paulo * Get info needed from supplicant to check if the current BSS supports 161f05cddf9SRui Paulo * security. Other than OPEN mode, rest are considered secured 162f05cddf9SRui Paulo * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. 163f05cddf9SRui Paulo */ 164f05cddf9SRui Paulo return sm->pairwise_cipher != WPA_CIPHER_NONE; 165f05cddf9SRui Paulo } 166f05cddf9SRui Paulo 167f05cddf9SRui Paulo 168f05cddf9SRui Paulo static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) 169f05cddf9SRui Paulo { 170f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 171f05cddf9SRui Paulo return pos + ie_len; 172f05cddf9SRui Paulo } 173f05cddf9SRui Paulo 174f05cddf9SRui Paulo 175f05cddf9SRui Paulo static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 176f05cddf9SRui Paulo { 177f05cddf9SRui Paulo if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, 178f05cddf9SRui Paulo 0, 0, NULL, 0, NULL, 0) < 0) { 179f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " 180f05cddf9SRui Paulo "the driver"); 181f05cddf9SRui Paulo return -1; 182f05cddf9SRui Paulo } 183f05cddf9SRui Paulo 184f05cddf9SRui Paulo return 0; 185f05cddf9SRui Paulo } 186f05cddf9SRui Paulo 187f05cddf9SRui Paulo 188f05cddf9SRui Paulo static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 189f05cddf9SRui Paulo { 190f05cddf9SRui Paulo u8 key_len; 191f05cddf9SRui Paulo u8 rsc[6]; 192f05cddf9SRui Paulo enum wpa_alg alg; 193f05cddf9SRui Paulo 194f05cddf9SRui Paulo os_memset(rsc, 0, 6); 195f05cddf9SRui Paulo 196f05cddf9SRui Paulo switch (peer->cipher) { 197f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 198f05cddf9SRui Paulo alg = WPA_ALG_CCMP; 199f05cddf9SRui Paulo key_len = 16; 200f05cddf9SRui Paulo break; 201f05cddf9SRui Paulo case WPA_CIPHER_NONE: 202f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " 203f05cddf9SRui Paulo "NONE - do not use pairwise keys"); 204f05cddf9SRui Paulo return -1; 205f05cddf9SRui Paulo default: 206f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", 207f05cddf9SRui Paulo sm->pairwise_cipher); 208f05cddf9SRui Paulo return -1; 209f05cddf9SRui Paulo } 210f05cddf9SRui Paulo 211f05cddf9SRui Paulo if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, 212f05cddf9SRui Paulo rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { 213f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " 214f05cddf9SRui Paulo "driver"); 215f05cddf9SRui Paulo return -1; 216f05cddf9SRui Paulo } 217f05cddf9SRui Paulo return 0; 218f05cddf9SRui Paulo } 219f05cddf9SRui Paulo 220f05cddf9SRui Paulo 221f05cddf9SRui Paulo static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, 222f05cddf9SRui Paulo u8 action_code, u8 dialog_token, 223*5b9c547cSRui Paulo u16 status_code, u32 peer_capab, 224*5b9c547cSRui Paulo int initiator, const u8 *buf, size_t len) 225f05cddf9SRui Paulo { 226f05cddf9SRui Paulo return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, 227*5b9c547cSRui Paulo status_code, peer_capab, initiator, buf, 228*5b9c547cSRui Paulo len); 229f05cddf9SRui Paulo } 230f05cddf9SRui Paulo 231f05cddf9SRui Paulo 232f05cddf9SRui Paulo static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, 233*5b9c547cSRui Paulo u8 dialog_token, u16 status_code, u32 peer_capab, 234*5b9c547cSRui Paulo int initiator, const u8 *msg, size_t msg_len) 235f05cddf9SRui Paulo { 236f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 237f05cddf9SRui Paulo 238f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " 239*5b9c547cSRui Paulo "dialog_token=%u status_code=%u peer_capab=%u initiator=%d " 240*5b9c547cSRui Paulo "msg_len=%u", 241f05cddf9SRui Paulo MAC2STR(dest), action_code, dialog_token, status_code, 242*5b9c547cSRui Paulo peer_capab, initiator, (unsigned int) msg_len); 243f05cddf9SRui Paulo 244f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, 245*5b9c547cSRui Paulo status_code, peer_capab, initiator, msg, 246*5b9c547cSRui Paulo msg_len)) { 247f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to send message " 248f05cddf9SRui Paulo "(action_code=%u)", action_code); 249f05cddf9SRui Paulo return -1; 250f05cddf9SRui Paulo } 251f05cddf9SRui Paulo 252f05cddf9SRui Paulo if (action_code == WLAN_TDLS_SETUP_CONFIRM || 253f05cddf9SRui Paulo action_code == WLAN_TDLS_TEARDOWN || 254f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_REQUEST || 255f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_RESPONSE) 256f05cddf9SRui Paulo return 0; /* No retries */ 257f05cddf9SRui Paulo 258f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 259f05cddf9SRui Paulo if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) 260f05cddf9SRui Paulo break; 261f05cddf9SRui Paulo } 262f05cddf9SRui Paulo 263f05cddf9SRui Paulo if (peer == NULL) { 264f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 265f05cddf9SRui Paulo "retry " MACSTR, MAC2STR(dest)); 266f05cddf9SRui Paulo return 0; 267f05cddf9SRui Paulo } 268f05cddf9SRui Paulo 269f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 270f05cddf9SRui Paulo 271*5b9c547cSRui Paulo if (action_code == WLAN_TDLS_SETUP_RESPONSE) { 272*5b9c547cSRui Paulo peer->sm_tmr.count = TPK_M2_RETRY_COUNT; 273*5b9c547cSRui Paulo peer->sm_tmr.timer = TPK_M2_TIMEOUT; 274*5b9c547cSRui Paulo } else { 275*5b9c547cSRui Paulo peer->sm_tmr.count = TPK_M1_RETRY_COUNT; 276*5b9c547cSRui Paulo peer->sm_tmr.timer = TPK_M1_TIMEOUT; 277*5b9c547cSRui Paulo } 278f05cddf9SRui Paulo 279f05cddf9SRui Paulo /* Copy message to resend on timeout */ 280f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); 281f05cddf9SRui Paulo peer->sm_tmr.action_code = action_code; 282f05cddf9SRui Paulo peer->sm_tmr.dialog_token = dialog_token; 283f05cddf9SRui Paulo peer->sm_tmr.status_code = status_code; 284*5b9c547cSRui Paulo peer->sm_tmr.peer_capab = peer_capab; 285f05cddf9SRui Paulo peer->sm_tmr.buf_len = msg_len; 286f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 287f05cddf9SRui Paulo peer->sm_tmr.buf = os_malloc(msg_len); 288f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) 289f05cddf9SRui Paulo return -1; 290f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.buf, msg, msg_len); 291f05cddf9SRui Paulo 292f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " 293f05cddf9SRui Paulo "(action_code=%u)", action_code); 294*5b9c547cSRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 295*5b9c547cSRui Paulo (peer->sm_tmr.timer % 1000) * 1000, 296f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 297f05cddf9SRui Paulo return 0; 298f05cddf9SRui Paulo } 299f05cddf9SRui Paulo 300f05cddf9SRui Paulo 301f05cddf9SRui Paulo static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 302*5b9c547cSRui Paulo u16 reason_code) 303f05cddf9SRui Paulo { 304f05cddf9SRui Paulo int ret; 305f05cddf9SRui Paulo 306f05cddf9SRui Paulo ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code); 307f05cddf9SRui Paulo /* disable the link after teardown was sent */ 308*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 309f05cddf9SRui Paulo 310f05cddf9SRui Paulo return ret; 311f05cddf9SRui Paulo } 312f05cddf9SRui Paulo 313f05cddf9SRui Paulo 314f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) 315f05cddf9SRui Paulo { 316f05cddf9SRui Paulo 317f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 318f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 319f05cddf9SRui Paulo 320f05cddf9SRui Paulo if (peer->sm_tmr.count) { 321f05cddf9SRui Paulo peer->sm_tmr.count--; 322f05cddf9SRui Paulo 323f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " 324f05cddf9SRui Paulo "(action_code=%u)", 325f05cddf9SRui Paulo peer->sm_tmr.action_code); 326f05cddf9SRui Paulo 327f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) { 328f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No retry buffer available " 329f05cddf9SRui Paulo "for action_code=%u", 330f05cddf9SRui Paulo peer->sm_tmr.action_code); 331f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, 332f05cddf9SRui Paulo peer); 333f05cddf9SRui Paulo return; 334f05cddf9SRui Paulo } 335f05cddf9SRui Paulo 336f05cddf9SRui Paulo /* resend TPK Handshake Message to Peer */ 337f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, 338f05cddf9SRui Paulo peer->sm_tmr.action_code, 339f05cddf9SRui Paulo peer->sm_tmr.dialog_token, 340f05cddf9SRui Paulo peer->sm_tmr.status_code, 341*5b9c547cSRui Paulo peer->sm_tmr.peer_capab, 342*5b9c547cSRui Paulo peer->initiator, 343f05cddf9SRui Paulo peer->sm_tmr.buf, 344f05cddf9SRui Paulo peer->sm_tmr.buf_len)) { 345f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to retry " 346f05cddf9SRui Paulo "transmission"); 347f05cddf9SRui Paulo } 348f05cddf9SRui Paulo 349f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 350*5b9c547cSRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 351*5b9c547cSRui Paulo (peer->sm_tmr.timer % 1000) * 1000, 352f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 353f05cddf9SRui Paulo } else { 354f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 355f05cddf9SRui Paulo 356f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request"); 357f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 358*5b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 359f05cddf9SRui Paulo } 360f05cddf9SRui Paulo } 361f05cddf9SRui Paulo 362f05cddf9SRui Paulo 363f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, 364f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 365f05cddf9SRui Paulo u8 action_code) 366f05cddf9SRui Paulo { 367f05cddf9SRui Paulo if (action_code == peer->sm_tmr.action_code) { 368f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " 369f05cddf9SRui Paulo "action_code=%u", action_code); 370f05cddf9SRui Paulo 371f05cddf9SRui Paulo /* Cancel Timeout registered */ 372f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 373f05cddf9SRui Paulo 374f05cddf9SRui Paulo /* free all resources meant for retry */ 375f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 376f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 377f05cddf9SRui Paulo 378f05cddf9SRui Paulo peer->sm_tmr.count = 0; 379f05cddf9SRui Paulo peer->sm_tmr.timer = 0; 380f05cddf9SRui Paulo peer->sm_tmr.buf_len = 0; 381f05cddf9SRui Paulo peer->sm_tmr.action_code = 0xff; 382f05cddf9SRui Paulo } else { 383f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " 384f05cddf9SRui Paulo "(Unknown action_code=%u)", action_code); 385f05cddf9SRui Paulo } 386f05cddf9SRui Paulo } 387f05cddf9SRui Paulo 388f05cddf9SRui Paulo 389f05cddf9SRui Paulo static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, 390f05cddf9SRui Paulo const u8 *own_addr, const u8 *bssid) 391f05cddf9SRui Paulo { 392f05cddf9SRui Paulo u8 key_input[SHA256_MAC_LEN]; 393f05cddf9SRui Paulo const u8 *nonce[2]; 394f05cddf9SRui Paulo size_t len[2]; 395f05cddf9SRui Paulo u8 data[3 * ETH_ALEN]; 396f05cddf9SRui Paulo 397f05cddf9SRui Paulo /* IEEE Std 802.11z-2010 8.5.9.1: 398f05cddf9SRui Paulo * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) 399f05cddf9SRui Paulo */ 400f05cddf9SRui Paulo len[0] = WPA_NONCE_LEN; 401f05cddf9SRui Paulo len[1] = WPA_NONCE_LEN; 402f05cddf9SRui Paulo if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { 403f05cddf9SRui Paulo nonce[0] = peer->inonce; 404f05cddf9SRui Paulo nonce[1] = peer->rnonce; 405f05cddf9SRui Paulo } else { 406f05cddf9SRui Paulo nonce[0] = peer->rnonce; 407f05cddf9SRui Paulo nonce[1] = peer->inonce; 408f05cddf9SRui Paulo } 409f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); 410f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); 411f05cddf9SRui Paulo sha256_vector(2, nonce, len, key_input); 412f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", 413f05cddf9SRui Paulo key_input, SHA256_MAC_LEN); 414f05cddf9SRui Paulo 415f05cddf9SRui Paulo /* 416f05cddf9SRui Paulo * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", 417f05cddf9SRui Paulo * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) 418f05cddf9SRui Paulo * TODO: is N_KEY really included in KDF Context and if so, in which 419f05cddf9SRui Paulo * presentation format (little endian 16-bit?) is it used? It gets 420f05cddf9SRui Paulo * added by the KDF anyway.. 421f05cddf9SRui Paulo */ 422f05cddf9SRui Paulo 423f05cddf9SRui Paulo if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { 424f05cddf9SRui Paulo os_memcpy(data, own_addr, ETH_ALEN); 425f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); 426f05cddf9SRui Paulo } else { 427f05cddf9SRui Paulo os_memcpy(data, peer->addr, ETH_ALEN); 428f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); 429f05cddf9SRui Paulo } 430f05cddf9SRui Paulo os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); 431f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); 432f05cddf9SRui Paulo 433f05cddf9SRui Paulo sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), 434f05cddf9SRui Paulo (u8 *) &peer->tpk, sizeof(peer->tpk)); 435f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", 436f05cddf9SRui Paulo peer->tpk.kck, sizeof(peer->tpk.kck)); 437f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", 438f05cddf9SRui Paulo peer->tpk.tk, sizeof(peer->tpk.tk)); 439f05cddf9SRui Paulo peer->tpk_set = 1; 440f05cddf9SRui Paulo } 441f05cddf9SRui Paulo 442f05cddf9SRui Paulo 443f05cddf9SRui Paulo /** 444f05cddf9SRui Paulo * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC 445f05cddf9SRui Paulo * @kck: TPK-KCK 446f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 447f05cddf9SRui Paulo * @rsnie: Pointer to the beginning of RSN IE used for handshake 448f05cddf9SRui Paulo * @timeoutie: Pointer to the beginning of Timeout IE used for handshake 449f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 450f05cddf9SRui Paulo * @mic: Pointer for writing MIC 451f05cddf9SRui Paulo * 452f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 453f05cddf9SRui Paulo */ 454f05cddf9SRui Paulo static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, 455f05cddf9SRui Paulo const u8 *rsnie, const u8 *timeoutie, 456f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 457f05cddf9SRui Paulo { 458f05cddf9SRui Paulo u8 *buf, *pos; 459f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 460f05cddf9SRui Paulo const struct wpa_tdls_lnkid *_lnkid; 461f05cddf9SRui Paulo int ret; 462f05cddf9SRui Paulo int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + 463f05cddf9SRui Paulo 2 + timeoutie[1] + 2 + ftie[1]; 464f05cddf9SRui Paulo buf = os_zalloc(len); 465f05cddf9SRui Paulo if (!buf) { 466f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 467f05cddf9SRui Paulo return -1; 468f05cddf9SRui Paulo } 469f05cddf9SRui Paulo 470f05cddf9SRui Paulo pos = buf; 471f05cddf9SRui Paulo _lnkid = (const struct wpa_tdls_lnkid *) lnkid; 472f05cddf9SRui Paulo /* 1) TDLS initiator STA MAC address */ 473f05cddf9SRui Paulo os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); 474f05cddf9SRui Paulo pos += ETH_ALEN; 475f05cddf9SRui Paulo /* 2) TDLS responder STA MAC address */ 476f05cddf9SRui Paulo os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); 477f05cddf9SRui Paulo pos += ETH_ALEN; 478f05cddf9SRui Paulo /* 3) Transaction Sequence number */ 479f05cddf9SRui Paulo *pos++ = trans_seq; 480f05cddf9SRui Paulo /* 4) Link Identifier IE */ 481f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 482f05cddf9SRui Paulo pos += 2 + lnkid[1]; 483f05cddf9SRui Paulo /* 5) RSN IE */ 484f05cddf9SRui Paulo os_memcpy(pos, rsnie, 2 + rsnie[1]); 485f05cddf9SRui Paulo pos += 2 + rsnie[1]; 486f05cddf9SRui Paulo /* 6) Timeout Interval IE */ 487f05cddf9SRui Paulo os_memcpy(pos, timeoutie, 2 + timeoutie[1]); 488f05cddf9SRui Paulo pos += 2 + timeoutie[1]; 489f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 490f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 491f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 492f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 493f05cddf9SRui Paulo pos += 2 + ftie[1]; 494f05cddf9SRui Paulo 495f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 496f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 497f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 498f05cddf9SRui Paulo os_free(buf); 499f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 500f05cddf9SRui Paulo return ret; 501f05cddf9SRui Paulo } 502f05cddf9SRui Paulo 503f05cddf9SRui Paulo 504f05cddf9SRui Paulo /** 505f05cddf9SRui Paulo * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame 506f05cddf9SRui Paulo * @kck: TPK-KCK 507f05cddf9SRui Paulo * @trans_seq: Transaction Sequence Number (4 - Teardown) 508f05cddf9SRui Paulo * @rcode: Reason code for Teardown 509f05cddf9SRui Paulo * @dtoken: Dialog Token used for that particular link 510f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 511f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 512f05cddf9SRui Paulo * @mic: Pointer for writing MIC 513f05cddf9SRui Paulo * 514f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 515f05cddf9SRui Paulo */ 516f05cddf9SRui Paulo static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, 517f05cddf9SRui Paulo u8 dtoken, const u8 *lnkid, 518f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 519f05cddf9SRui Paulo { 520f05cddf9SRui Paulo u8 *buf, *pos; 521f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 522f05cddf9SRui Paulo int ret; 523f05cddf9SRui Paulo int len; 524f05cddf9SRui Paulo 525f05cddf9SRui Paulo if (lnkid == NULL) 526f05cddf9SRui Paulo return -1; 527f05cddf9SRui Paulo 528f05cddf9SRui Paulo len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + 529f05cddf9SRui Paulo sizeof(trans_seq) + 2 + ftie[1]; 530f05cddf9SRui Paulo 531f05cddf9SRui Paulo buf = os_zalloc(len); 532f05cddf9SRui Paulo if (!buf) { 533f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 534f05cddf9SRui Paulo return -1; 535f05cddf9SRui Paulo } 536f05cddf9SRui Paulo 537f05cddf9SRui Paulo pos = buf; 538f05cddf9SRui Paulo /* 1) Link Identifier IE */ 539f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 540f05cddf9SRui Paulo pos += 2 + lnkid[1]; 541f05cddf9SRui Paulo /* 2) Reason Code */ 542f05cddf9SRui Paulo WPA_PUT_LE16(pos, rcode); 543f05cddf9SRui Paulo pos += sizeof(rcode); 544f05cddf9SRui Paulo /* 3) Dialog token */ 545f05cddf9SRui Paulo *pos++ = dtoken; 546f05cddf9SRui Paulo /* 4) Transaction Sequence number */ 547f05cddf9SRui Paulo *pos++ = trans_seq; 548f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 549f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 550f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 551f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 552f05cddf9SRui Paulo pos += 2 + ftie[1]; 553f05cddf9SRui Paulo 554f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 555f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 556f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 557f05cddf9SRui Paulo os_free(buf); 558f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 559f05cddf9SRui Paulo return ret; 560f05cddf9SRui Paulo } 561f05cddf9SRui Paulo 562f05cddf9SRui Paulo 563f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, 564f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 565f05cddf9SRui Paulo const u8 *lnkid, const u8 *timeoutie, 566f05cddf9SRui Paulo const struct wpa_tdls_ftie *ftie) 567f05cddf9SRui Paulo { 568f05cddf9SRui Paulo u8 mic[16]; 569f05cddf9SRui Paulo 570f05cddf9SRui Paulo if (peer->tpk_set) { 571f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, 572f05cddf9SRui Paulo peer->rsnie_p, timeoutie, (u8 *) ftie, 573f05cddf9SRui Paulo mic); 574*5b9c547cSRui Paulo if (os_memcmp_const(mic, ftie->mic, 16) != 0) { 575f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " 576f05cddf9SRui Paulo "dropping packet"); 577f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", 578f05cddf9SRui Paulo ftie->mic, 16); 579f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", 580f05cddf9SRui Paulo mic, 16); 581f05cddf9SRui Paulo return -1; 582f05cddf9SRui Paulo } 583f05cddf9SRui Paulo } else { 584f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " 585f05cddf9SRui Paulo "TPK not set - dropping packet"); 586f05cddf9SRui Paulo return -1; 587f05cddf9SRui Paulo } 588f05cddf9SRui Paulo return 0; 589f05cddf9SRui Paulo } 590f05cddf9SRui Paulo 591f05cddf9SRui Paulo 592f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic_teardown( 593f05cddf9SRui Paulo u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, 594f05cddf9SRui Paulo const u8 *lnkid, const struct wpa_tdls_ftie *ftie) 595f05cddf9SRui Paulo { 596f05cddf9SRui Paulo u8 mic[16]; 597f05cddf9SRui Paulo 598f05cddf9SRui Paulo if (peer->tpk_set) { 599f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, 600f05cddf9SRui Paulo dtoken, lnkid, (u8 *) ftie, mic); 601*5b9c547cSRui Paulo if (os_memcmp_const(mic, ftie->mic, 16) != 0) { 602f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " 603f05cddf9SRui Paulo "dropping packet"); 604f05cddf9SRui Paulo return -1; 605f05cddf9SRui Paulo } 606f05cddf9SRui Paulo } else { 607f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " 608f05cddf9SRui Paulo "MIC, TPK not set - dropping packet"); 609f05cddf9SRui Paulo return -1; 610f05cddf9SRui Paulo } 611f05cddf9SRui Paulo return 0; 612f05cddf9SRui Paulo } 613f05cddf9SRui Paulo 614f05cddf9SRui Paulo 615f05cddf9SRui Paulo static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) 616f05cddf9SRui Paulo { 617f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 618f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 619f05cddf9SRui Paulo 620f05cddf9SRui Paulo /* 621f05cddf9SRui Paulo * On TPK lifetime expiration, we have an option of either tearing down 622f05cddf9SRui Paulo * the direct link or trying to re-initiate it. The selection of what 623f05cddf9SRui Paulo * to do is not strictly speaking controlled by our role in the expired 624f05cddf9SRui Paulo * link, but for now, use that to select whether to renew or tear down 625f05cddf9SRui Paulo * the link. 626f05cddf9SRui Paulo */ 627f05cddf9SRui Paulo 628f05cddf9SRui Paulo if (peer->initiator) { 629f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 630f05cddf9SRui Paulo " - try to renew", MAC2STR(peer->addr)); 631f05cddf9SRui Paulo wpa_tdls_start(sm, peer->addr); 632f05cddf9SRui Paulo } else { 633f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 634f05cddf9SRui Paulo " - tear down", MAC2STR(peer->addr)); 635f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 636*5b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 637f05cddf9SRui Paulo } 638f05cddf9SRui Paulo } 639f05cddf9SRui Paulo 640f05cddf9SRui Paulo 641*5b9c547cSRui Paulo static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm, 642*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 643*5b9c547cSRui Paulo { 644*5b9c547cSRui Paulo struct wpa_tdls_peer *cur, *prev; 645*5b9c547cSRui Paulo 646*5b9c547cSRui Paulo cur = sm->tdls; 647*5b9c547cSRui Paulo prev = NULL; 648*5b9c547cSRui Paulo while (cur && cur != peer) { 649*5b9c547cSRui Paulo prev = cur; 650*5b9c547cSRui Paulo cur = cur->next; 651*5b9c547cSRui Paulo } 652*5b9c547cSRui Paulo 653*5b9c547cSRui Paulo if (cur != peer) { 654*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR 655*5b9c547cSRui Paulo " to remove it from the list", 656*5b9c547cSRui Paulo MAC2STR(peer->addr)); 657*5b9c547cSRui Paulo return; 658*5b9c547cSRui Paulo } 659*5b9c547cSRui Paulo 660*5b9c547cSRui Paulo if (prev) 661*5b9c547cSRui Paulo prev->next = peer->next; 662*5b9c547cSRui Paulo else 663*5b9c547cSRui Paulo sm->tdls = peer->next; 664*5b9c547cSRui Paulo } 665*5b9c547cSRui Paulo 666*5b9c547cSRui Paulo 667*5b9c547cSRui Paulo static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 668f05cddf9SRui Paulo { 669f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, 670f05cddf9SRui Paulo MAC2STR(peer->addr)); 671f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 672f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 673*5b9c547cSRui Paulo peer->reconfig_key = 0; 674f05cddf9SRui Paulo peer->initiator = 0; 675*5b9c547cSRui Paulo peer->tpk_in_progress = 0; 676f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 677f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 678*5b9c547cSRui Paulo os_free(peer->ht_capabilities); 679*5b9c547cSRui Paulo peer->ht_capabilities = NULL; 680*5b9c547cSRui Paulo os_free(peer->vht_capabilities); 681*5b9c547cSRui Paulo peer->vht_capabilities = NULL; 682*5b9c547cSRui Paulo os_free(peer->ext_capab); 683*5b9c547cSRui Paulo peer->ext_capab = NULL; 684*5b9c547cSRui Paulo os_free(peer->supp_channels); 685*5b9c547cSRui Paulo peer->supp_channels = NULL; 686*5b9c547cSRui Paulo os_free(peer->supp_oper_classes); 687*5b9c547cSRui Paulo peer->supp_oper_classes = NULL; 688f05cddf9SRui Paulo peer->rsnie_i_len = peer->rsnie_p_len = 0; 689f05cddf9SRui Paulo peer->cipher = 0; 690*5b9c547cSRui Paulo peer->qos_info = 0; 691*5b9c547cSRui Paulo peer->wmm_capable = 0; 692f05cddf9SRui Paulo peer->tpk_set = peer->tpk_success = 0; 693*5b9c547cSRui Paulo peer->chan_switch_enabled = 0; 694f05cddf9SRui Paulo os_memset(&peer->tpk, 0, sizeof(peer->tpk)); 695f05cddf9SRui Paulo os_memset(peer->inonce, 0, WPA_NONCE_LEN); 696f05cddf9SRui Paulo os_memset(peer->rnonce, 0, WPA_NONCE_LEN); 697f05cddf9SRui Paulo } 698f05cddf9SRui Paulo 699f05cddf9SRui Paulo 700*5b9c547cSRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 701*5b9c547cSRui Paulo { 702*5b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 703*5b9c547cSRui Paulo wpa_tdls_peer_remove_from_list(sm, peer); 704*5b9c547cSRui Paulo os_free(peer); 705*5b9c547cSRui Paulo } 706*5b9c547cSRui Paulo 707*5b9c547cSRui Paulo 708f05cddf9SRui Paulo static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 709f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid) 710f05cddf9SRui Paulo { 711f05cddf9SRui Paulo lnkid->ie_type = WLAN_EID_LINK_ID; 712f05cddf9SRui Paulo lnkid->ie_len = 3 * ETH_ALEN; 713f05cddf9SRui Paulo os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); 714f05cddf9SRui Paulo if (peer->initiator) { 715f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); 716f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); 717f05cddf9SRui Paulo } else { 718f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); 719f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); 720f05cddf9SRui Paulo } 721f05cddf9SRui Paulo } 722f05cddf9SRui Paulo 723f05cddf9SRui Paulo 724*5b9c547cSRui Paulo static int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, 725*5b9c547cSRui Paulo u16 reason_code) 726f05cddf9SRui Paulo { 727f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 728f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 729f05cddf9SRui Paulo struct wpa_tdls_lnkid lnkid; 730f05cddf9SRui Paulo u8 dialog_token; 731f05cddf9SRui Paulo u8 *rbuf, *pos; 732f05cddf9SRui Paulo int ielen; 733f05cddf9SRui Paulo 734f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 735f05cddf9SRui Paulo return -1; 736f05cddf9SRui Paulo 737f05cddf9SRui Paulo /* Find the node and free from the list */ 738f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 739f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 740f05cddf9SRui Paulo break; 741f05cddf9SRui Paulo } 742f05cddf9SRui Paulo 743f05cddf9SRui Paulo if (peer == NULL) { 744f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 745f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(addr)); 746f05cddf9SRui Paulo return 0; 747f05cddf9SRui Paulo } 748f05cddf9SRui Paulo 749*5b9c547cSRui Paulo /* Cancel active channel switch before teardown */ 750*5b9c547cSRui Paulo if (peer->chan_switch_enabled) { 751*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR 752*5b9c547cSRui Paulo " to base channel", MAC2STR(addr)); 753*5b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 754*5b9c547cSRui Paulo } 755*5b9c547cSRui Paulo 756f05cddf9SRui Paulo dialog_token = peer->dtoken; 757f05cddf9SRui Paulo 758f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR, 759f05cddf9SRui Paulo MAC2STR(addr)); 760f05cddf9SRui Paulo 761f05cddf9SRui Paulo ielen = 0; 762f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { 763f05cddf9SRui Paulo /* To add FTIE for Teardown request and compute MIC */ 764f05cddf9SRui Paulo ielen += sizeof(*ftie); 765f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 766f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 767f05cddf9SRui Paulo ielen += 170; 768f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 769f05cddf9SRui Paulo } 770f05cddf9SRui Paulo 771f05cddf9SRui Paulo rbuf = os_zalloc(ielen + 1); 772f05cddf9SRui Paulo if (rbuf == NULL) 773f05cddf9SRui Paulo return -1; 774f05cddf9SRui Paulo pos = rbuf; 775f05cddf9SRui Paulo 776f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 777f05cddf9SRui Paulo goto skip_ies; 778f05cddf9SRui Paulo 779f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 780f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 781f05cddf9SRui Paulo /* Using the recent nonce which should be for CONFIRM frame */ 782f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 783f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 784f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 785f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 786f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 787f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 788f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 789f05cddf9SRui Paulo "FTIE"); 790f05cddf9SRui Paulo ftie->ie_len += 170; 791f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 792f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 793f05cddf9SRui Paulo pos += 168; 794f05cddf9SRui Paulo } 795f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 796f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", 797f05cddf9SRui Paulo (u8 *) ftie, pos - (u8 *) ftie); 798f05cddf9SRui Paulo 799f05cddf9SRui Paulo /* compute MIC before sending */ 800f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, &lnkid); 801f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, 802f05cddf9SRui Paulo dialog_token, (u8 *) &lnkid, (u8 *) ftie, 803f05cddf9SRui Paulo ftie->mic); 804f05cddf9SRui Paulo 805f05cddf9SRui Paulo skip_ies: 806f05cddf9SRui Paulo /* TODO: register for a Timeout handler, if Teardown is not received at 807f05cddf9SRui Paulo * the other end, then try again another time */ 808f05cddf9SRui Paulo 809f05cddf9SRui Paulo /* request driver to send Teardown using this FTIE */ 810f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, 811*5b9c547cSRui Paulo reason_code, 0, peer->initiator, rbuf, pos - rbuf); 812f05cddf9SRui Paulo os_free(rbuf); 813f05cddf9SRui Paulo 814f05cddf9SRui Paulo return 0; 815f05cddf9SRui Paulo } 816f05cddf9SRui Paulo 817f05cddf9SRui Paulo 818f05cddf9SRui Paulo int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) 819f05cddf9SRui Paulo { 820f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 821f05cddf9SRui Paulo 822f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 823f05cddf9SRui Paulo return -1; 824f05cddf9SRui Paulo 825f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 826f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 827f05cddf9SRui Paulo break; 828f05cddf9SRui Paulo } 829f05cddf9SRui Paulo 830f05cddf9SRui Paulo if (peer == NULL) { 831f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR 832f05cddf9SRui Paulo " for link Teardown", MAC2STR(addr)); 833f05cddf9SRui Paulo return -1; 834f05cddf9SRui Paulo } 835f05cddf9SRui Paulo 836f05cddf9SRui Paulo if (!peer->tpk_success) { 837f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 838f05cddf9SRui Paulo " not connected - cannot Teardown link", MAC2STR(addr)); 839f05cddf9SRui Paulo return -1; 840f05cddf9SRui Paulo } 841f05cddf9SRui Paulo 842*5b9c547cSRui Paulo return wpa_tdls_do_teardown(sm, peer, reason_code); 843f05cddf9SRui Paulo } 844f05cddf9SRui Paulo 845f05cddf9SRui Paulo 846*5b9c547cSRui Paulo static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, 847*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 848*5b9c547cSRui Paulo { 849*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 850*5b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 851*5b9c547cSRui Paulo } 852*5b9c547cSRui Paulo 853*5b9c547cSRui Paulo 854*5b9c547cSRui Paulo void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr) 855f05cddf9SRui Paulo { 856f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 857f05cddf9SRui Paulo 858f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 859f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 860f05cddf9SRui Paulo break; 861f05cddf9SRui Paulo } 862f05cddf9SRui Paulo 863*5b9c547cSRui Paulo if (!peer || !peer->tpk_success) { 864*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 865*5b9c547cSRui Paulo " not connected - cannot teardown unreachable link", 866*5b9c547cSRui Paulo MAC2STR(addr)); 867*5b9c547cSRui Paulo return; 868f05cddf9SRui Paulo } 869*5b9c547cSRui Paulo 870*5b9c547cSRui Paulo if (wpa_tdls_is_external_setup(sm)) { 871*5b9c547cSRui Paulo /* 872*5b9c547cSRui Paulo * Get us on the base channel, disable the link, send a 873*5b9c547cSRui Paulo * teardown packet through the AP, and then reset link data. 874*5b9c547cSRui Paulo */ 875*5b9c547cSRui Paulo if (peer->chan_switch_enabled) 876*5b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 877*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr); 878*5b9c547cSRui Paulo wpa_tdls_send_teardown(sm, addr, 879*5b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE); 880*5b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 881*5b9c547cSRui Paulo } else { 882*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 883*5b9c547cSRui Paulo } 884*5b9c547cSRui Paulo } 885*5b9c547cSRui Paulo 886*5b9c547cSRui Paulo 887*5b9c547cSRui Paulo const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr) 888*5b9c547cSRui Paulo { 889*5b9c547cSRui Paulo struct wpa_tdls_peer *peer; 890*5b9c547cSRui Paulo 891*5b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 892*5b9c547cSRui Paulo return "disabled"; 893*5b9c547cSRui Paulo 894*5b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 895*5b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 896*5b9c547cSRui Paulo break; 897*5b9c547cSRui Paulo } 898*5b9c547cSRui Paulo 899*5b9c547cSRui Paulo if (peer == NULL) 900*5b9c547cSRui Paulo return "peer does not exist"; 901*5b9c547cSRui Paulo 902*5b9c547cSRui Paulo if (!peer->tpk_success) 903*5b9c547cSRui Paulo return "peer not connected"; 904*5b9c547cSRui Paulo 905*5b9c547cSRui Paulo return "connected"; 906f05cddf9SRui Paulo } 907f05cddf9SRui Paulo 908f05cddf9SRui Paulo 909f05cddf9SRui Paulo static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, 910f05cddf9SRui Paulo const u8 *buf, size_t len) 911f05cddf9SRui Paulo { 912f05cddf9SRui Paulo struct wpa_tdls_peer *peer = NULL; 913f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 914f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 915f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 916f05cddf9SRui Paulo u16 reason_code; 917f05cddf9SRui Paulo const u8 *pos; 918f05cddf9SRui Paulo int ielen; 919f05cddf9SRui Paulo 920f05cddf9SRui Paulo /* Find the node and free from the list */ 921f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 922f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 923f05cddf9SRui Paulo break; 924f05cddf9SRui Paulo } 925f05cddf9SRui Paulo 926f05cddf9SRui Paulo if (peer == NULL) { 927f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 928f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(src_addr)); 929f05cddf9SRui Paulo return 0; 930f05cddf9SRui Paulo } 931f05cddf9SRui Paulo 932f05cddf9SRui Paulo pos = buf; 933f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 934f05cddf9SRui Paulo 935f05cddf9SRui Paulo reason_code = WPA_GET_LE16(pos); 936f05cddf9SRui Paulo pos += 2; 937f05cddf9SRui Paulo 938f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR 939f05cddf9SRui Paulo " (reason code %u)", MAC2STR(src_addr), reason_code); 940f05cddf9SRui Paulo 941f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 942*5b9c547cSRui Paulo 943*5b9c547cSRui Paulo /* 944*5b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 945*5b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 946*5b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 947*5b9c547cSRui Paulo */ 948*5b9c547cSRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) 949*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 950*5b9c547cSRui Paulo "TDLS: Failed to parse IEs in Teardown - ignore as an interop workaround"); 951f05cddf9SRui Paulo 952f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 953f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " 954f05cddf9SRui Paulo "Teardown"); 955f05cddf9SRui Paulo return -1; 956f05cddf9SRui Paulo } 957f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 958f05cddf9SRui Paulo 959f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 960f05cddf9SRui Paulo goto skip_ftie; 961f05cddf9SRui Paulo 962f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 963f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); 964f05cddf9SRui Paulo return -1; 965f05cddf9SRui Paulo } 966f05cddf9SRui Paulo 967f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 968f05cddf9SRui Paulo 969f05cddf9SRui Paulo /* Process MIC check to see if TDLS Teardown is right */ 970f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, 971f05cddf9SRui Paulo peer->dtoken, peer, 972f05cddf9SRui Paulo (u8 *) lnkid, ftie) < 0) { 973f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " 974f05cddf9SRui Paulo "Teardown Request from " MACSTR, MAC2STR(src_addr)); 975f05cddf9SRui Paulo return -1; 976f05cddf9SRui Paulo } 977f05cddf9SRui Paulo 978f05cddf9SRui Paulo skip_ftie: 979f05cddf9SRui Paulo /* 980f05cddf9SRui Paulo * Request the driver to disable the direct link and clear associated 981f05cddf9SRui Paulo * keys. 982f05cddf9SRui Paulo */ 983*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 984f05cddf9SRui Paulo return 0; 985f05cddf9SRui Paulo } 986f05cddf9SRui Paulo 987f05cddf9SRui Paulo 988f05cddf9SRui Paulo /** 989f05cddf9SRui Paulo * wpa_tdls_send_error - To send suitable TDLS status response with 990f05cddf9SRui Paulo * appropriate status code mentioning reason for error/failure. 991f05cddf9SRui Paulo * @dst - MAC addr of Peer station 992f05cddf9SRui Paulo * @tdls_action - TDLS frame type for which error code is sent 993*5b9c547cSRui Paulo * @initiator - was this end the initiator of the connection 994f05cddf9SRui Paulo * @status - status code mentioning reason 995f05cddf9SRui Paulo */ 996f05cddf9SRui Paulo 997f05cddf9SRui Paulo static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, 998*5b9c547cSRui Paulo u8 tdls_action, u8 dialog_token, int initiator, 999*5b9c547cSRui Paulo u16 status) 1000f05cddf9SRui Paulo { 1001f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR 1002f05cddf9SRui Paulo " (action=%u status=%u)", 1003f05cddf9SRui Paulo MAC2STR(dst), tdls_action, status); 1004f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, 1005*5b9c547cSRui Paulo 0, initiator, NULL, 0); 1006f05cddf9SRui Paulo } 1007f05cddf9SRui Paulo 1008f05cddf9SRui Paulo 1009f05cddf9SRui Paulo static struct wpa_tdls_peer * 1010*5b9c547cSRui Paulo wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing) 1011f05cddf9SRui Paulo { 1012f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1013f05cddf9SRui Paulo 1014*5b9c547cSRui Paulo if (existing) 1015*5b9c547cSRui Paulo *existing = 0; 1016*5b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 1017*5b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) { 1018*5b9c547cSRui Paulo if (existing) 1019*5b9c547cSRui Paulo *existing = 1; 1020*5b9c547cSRui Paulo return peer; /* re-use existing entry */ 1021*5b9c547cSRui Paulo } 1022*5b9c547cSRui Paulo } 1023*5b9c547cSRui Paulo 1024f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR, 1025f05cddf9SRui Paulo MAC2STR(addr)); 1026f05cddf9SRui Paulo 1027f05cddf9SRui Paulo peer = os_zalloc(sizeof(*peer)); 1028f05cddf9SRui Paulo if (peer == NULL) 1029f05cddf9SRui Paulo return NULL; 1030f05cddf9SRui Paulo 1031f05cddf9SRui Paulo os_memcpy(peer->addr, addr, ETH_ALEN); 1032f05cddf9SRui Paulo peer->next = sm->tdls; 1033f05cddf9SRui Paulo sm->tdls = peer; 1034f05cddf9SRui Paulo 1035f05cddf9SRui Paulo return peer; 1036f05cddf9SRui Paulo } 1037f05cddf9SRui Paulo 1038f05cddf9SRui Paulo 1039f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, 1040f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 1041f05cddf9SRui Paulo { 1042f05cddf9SRui Paulo size_t buf_len; 1043f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1044f05cddf9SRui Paulo u16 rsn_capab; 1045f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1046f05cddf9SRui Paulo u8 *rbuf, *pos, *count_pos; 1047f05cddf9SRui Paulo u16 count; 1048f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 1049*5b9c547cSRui Paulo int status; 1050f05cddf9SRui Paulo 1051f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1052f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No security used on the link"); 1053f05cddf9SRui Paulo peer->rsnie_i_len = 0; 1054f05cddf9SRui Paulo goto skip_rsnie; 1055f05cddf9SRui Paulo } 1056f05cddf9SRui Paulo 1057f05cddf9SRui Paulo /* 1058f05cddf9SRui Paulo * TPK Handshake Message 1: 1059f05cddf9SRui Paulo * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, 1060f05cddf9SRui Paulo * Timeout Interval IE)) 1061f05cddf9SRui Paulo */ 1062f05cddf9SRui Paulo 1063f05cddf9SRui Paulo /* Filling RSN IE */ 1064f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_i; 1065f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 1066f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 1067f05cddf9SRui Paulo 1068f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 1069f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 1070f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1071f05cddf9SRui Paulo count_pos = pos; 1072f05cddf9SRui Paulo pos += 2; 1073f05cddf9SRui Paulo 1074f05cddf9SRui Paulo count = 0; 1075f05cddf9SRui Paulo 1076f05cddf9SRui Paulo /* 1077f05cddf9SRui Paulo * AES-CCMP is the default Encryption preferred for TDLS, so 1078f05cddf9SRui Paulo * RSN IE is filled only with CCMP CIPHER 1079f05cddf9SRui Paulo * Note: TKIP is not used to encrypt TDLS link. 1080f05cddf9SRui Paulo * 1081f05cddf9SRui Paulo * Regardless of the cipher used on the AP connection, select CCMP 1082f05cddf9SRui Paulo * here. 1083f05cddf9SRui Paulo */ 1084f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1085f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1086f05cddf9SRui Paulo count++; 1087f05cddf9SRui Paulo 1088f05cddf9SRui Paulo WPA_PUT_LE16(count_pos, count); 1089f05cddf9SRui Paulo 1090f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 1091f05cddf9SRui Paulo pos += 2; 1092f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 1093f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1094f05cddf9SRui Paulo 1095f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1096f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 1097f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1098f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 1099f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " 1100f05cddf9SRui Paulo "testing"); 1101f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1102f05cddf9SRui Paulo } 1103f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1104f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 1105f05cddf9SRui Paulo pos += 2; 1106f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1107f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 1108f05cddf9SRui Paulo /* Number of PMKIDs */ 1109f05cddf9SRui Paulo *pos++ = 0x00; 1110f05cddf9SRui Paulo *pos++ = 0x00; 1111f05cddf9SRui Paulo } 1112f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1113f05cddf9SRui Paulo 1114f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_i) - 2; 1115f05cddf9SRui Paulo peer->rsnie_i_len = pos - peer->rsnie_i; 1116f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 1117f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 1118f05cddf9SRui Paulo 1119f05cddf9SRui Paulo skip_rsnie: 1120f05cddf9SRui Paulo buf_len = 0; 1121f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) 1122f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1123f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1124f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1125f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && 1126f05cddf9SRui Paulo (tdls_testing & TDLS_TESTING_LONG_FRAME)) 1127f05cddf9SRui Paulo buf_len += 170; 1128f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) 1129f05cddf9SRui Paulo buf_len += sizeof(struct wpa_tdls_lnkid); 1130f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1131f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1132f05cddf9SRui Paulo if (rbuf == NULL) { 1133f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1134f05cddf9SRui Paulo return -1; 1135f05cddf9SRui Paulo } 1136f05cddf9SRui Paulo pos = rbuf; 1137f05cddf9SRui Paulo 1138f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1139f05cddf9SRui Paulo goto skip_ies; 1140f05cddf9SRui Paulo 1141f05cddf9SRui Paulo /* Initiator RSN IE */ 1142f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); 1143f05cddf9SRui Paulo 1144f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1145f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1146f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1147f05cddf9SRui Paulo 1148f05cddf9SRui Paulo if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { 1149f05cddf9SRui Paulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 1150f05cddf9SRui Paulo "TDLS: Failed to get random data for initiator Nonce"); 1151f05cddf9SRui Paulo os_free(rbuf); 1152f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1153f05cddf9SRui Paulo return -1; 1154f05cddf9SRui Paulo } 1155f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", 1156f05cddf9SRui Paulo peer->inonce, WPA_NONCE_LEN); 1157f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1158f05cddf9SRui Paulo 1159f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", 1160f05cddf9SRui Paulo (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); 1161f05cddf9SRui Paulo 1162f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1163f05cddf9SRui Paulo 1164f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1165f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1166f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1167f05cddf9SRui Paulo "FTIE"); 1168f05cddf9SRui Paulo ftie->ie_len += 170; 1169f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1170f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1171f05cddf9SRui Paulo pos += 168; 1172f05cddf9SRui Paulo } 1173f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1174f05cddf9SRui Paulo 1175f05cddf9SRui Paulo /* Lifetime */ 1176f05cddf9SRui Paulo peer->lifetime = TPK_LIFETIME; 1177f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1178f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { 1179f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " 1180f05cddf9SRui Paulo "lifetime"); 1181f05cddf9SRui Paulo peer->lifetime = 301; 1182f05cddf9SRui Paulo } 1183f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { 1184f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " 1185f05cddf9SRui Paulo "lifetime"); 1186f05cddf9SRui Paulo peer->lifetime = 0xffffffff; 1187f05cddf9SRui Paulo } 1188f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1189f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1190f05cddf9SRui Paulo sizeof(timeoutie), peer->lifetime); 1191f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); 1192f05cddf9SRui Paulo 1193f05cddf9SRui Paulo skip_ies: 1194f05cddf9SRui Paulo 1195f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1196f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { 1197f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " 1198f05cddf9SRui Paulo "Link Identifier"); 1199f05cddf9SRui Paulo struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; 1200f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, l); 1201f05cddf9SRui Paulo l->bssid[5] ^= 0x01; 1202f05cddf9SRui Paulo pos += sizeof(*l); 1203f05cddf9SRui Paulo } 1204f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1205f05cddf9SRui Paulo 1206f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " 1207f05cddf9SRui Paulo "Handshake Message 1 (peer " MACSTR ")", 1208f05cddf9SRui Paulo MAC2STR(peer->addr)); 1209f05cddf9SRui Paulo 1210*5b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1211*5b9c547cSRui Paulo 1, 0, 0, peer->initiator, rbuf, pos - rbuf); 1212f05cddf9SRui Paulo os_free(rbuf); 1213f05cddf9SRui Paulo 1214*5b9c547cSRui Paulo return status; 1215f05cddf9SRui Paulo } 1216f05cddf9SRui Paulo 1217f05cddf9SRui Paulo 1218f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, 1219f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1220f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1221f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1222f05cddf9SRui Paulo { 1223f05cddf9SRui Paulo u8 *rbuf, *pos; 1224f05cddf9SRui Paulo size_t buf_len; 1225f05cddf9SRui Paulo u32 lifetime; 1226f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1227f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1228*5b9c547cSRui Paulo int status; 1229f05cddf9SRui Paulo 1230f05cddf9SRui Paulo buf_len = 0; 1231f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1232f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1233f05cddf9SRui Paulo * Lifetime */ 1234f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1235f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1236f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1237f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1238f05cddf9SRui Paulo buf_len += 170; 1239f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1240f05cddf9SRui Paulo } 1241f05cddf9SRui Paulo 1242f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1243f05cddf9SRui Paulo if (rbuf == NULL) 1244f05cddf9SRui Paulo return -1; 1245f05cddf9SRui Paulo pos = rbuf; 1246f05cddf9SRui Paulo 1247f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1248f05cddf9SRui Paulo goto skip_ies; 1249f05cddf9SRui Paulo 1250f05cddf9SRui Paulo /* Peer RSN IE */ 1251f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1252f05cddf9SRui Paulo 1253f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1254f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1255f05cddf9SRui Paulo /* TODO: ftie->mic_control to set 2-RESPONSE */ 1256f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1257f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1258f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1259f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", 1260f05cddf9SRui Paulo (u8 *) ftie, sizeof(*ftie)); 1261f05cddf9SRui Paulo 1262f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1263f05cddf9SRui Paulo 1264f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1265f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1266f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1267f05cddf9SRui Paulo "FTIE"); 1268f05cddf9SRui Paulo ftie->ie_len += 170; 1269f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1270f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1271f05cddf9SRui Paulo pos += 168; 1272f05cddf9SRui Paulo } 1273f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1274f05cddf9SRui Paulo 1275f05cddf9SRui Paulo /* Lifetime */ 1276f05cddf9SRui Paulo lifetime = peer->lifetime; 1277f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1278f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { 1279f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1280f05cddf9SRui Paulo "lifetime in response"); 1281f05cddf9SRui Paulo lifetime++; 1282f05cddf9SRui Paulo } 1283f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1284f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1285f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1286f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", 1287f05cddf9SRui Paulo lifetime); 1288f05cddf9SRui Paulo 1289f05cddf9SRui Paulo /* compute MIC before sending */ 1290f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, 1291f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 1292*5b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 1293*5b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_MIC) { 1294*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); 1295*5b9c547cSRui Paulo ftie->mic[0] ^= 0x01; 1296*5b9c547cSRui Paulo } 1297*5b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1298f05cddf9SRui Paulo 1299f05cddf9SRui Paulo skip_ies: 1300*5b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, 1301*5b9c547cSRui Paulo dtoken, 0, 0, peer->initiator, rbuf, 1302*5b9c547cSRui Paulo pos - rbuf); 1303f05cddf9SRui Paulo os_free(rbuf); 1304f05cddf9SRui Paulo 1305*5b9c547cSRui Paulo return status; 1306f05cddf9SRui Paulo } 1307f05cddf9SRui Paulo 1308f05cddf9SRui Paulo 1309f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, 1310f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1311f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1312f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1313f05cddf9SRui Paulo { 1314f05cddf9SRui Paulo u8 *rbuf, *pos; 1315f05cddf9SRui Paulo size_t buf_len; 1316f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1317f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1318f05cddf9SRui Paulo u32 lifetime; 1319*5b9c547cSRui Paulo int status; 1320*5b9c547cSRui Paulo u32 peer_capab = 0; 1321f05cddf9SRui Paulo 1322f05cddf9SRui Paulo buf_len = 0; 1323f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1324f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1325f05cddf9SRui Paulo * Lifetime */ 1326f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1327f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1328f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1329f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1330f05cddf9SRui Paulo buf_len += 170; 1331f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1332f05cddf9SRui Paulo } 1333f05cddf9SRui Paulo 1334f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1335f05cddf9SRui Paulo if (rbuf == NULL) 1336f05cddf9SRui Paulo return -1; 1337f05cddf9SRui Paulo pos = rbuf; 1338f05cddf9SRui Paulo 1339f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1340f05cddf9SRui Paulo goto skip_ies; 1341f05cddf9SRui Paulo 1342f05cddf9SRui Paulo /* Peer RSN IE */ 1343f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1344f05cddf9SRui Paulo 1345f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1346f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1347f05cddf9SRui Paulo /*TODO: ftie->mic_control to set 3-CONFIRM */ 1348f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1349f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1350f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1351f05cddf9SRui Paulo 1352f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1353f05cddf9SRui Paulo 1354f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1355f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1356f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1357f05cddf9SRui Paulo "FTIE"); 1358f05cddf9SRui Paulo ftie->ie_len += 170; 1359f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1360f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1361f05cddf9SRui Paulo pos += 168; 1362f05cddf9SRui Paulo } 1363f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1364f05cddf9SRui Paulo 1365f05cddf9SRui Paulo /* Lifetime */ 1366f05cddf9SRui Paulo lifetime = peer->lifetime; 1367f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1368f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { 1369f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1370f05cddf9SRui Paulo "lifetime in confirm"); 1371f05cddf9SRui Paulo lifetime++; 1372f05cddf9SRui Paulo } 1373f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1374f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1375f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1376f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", 1377f05cddf9SRui Paulo lifetime); 1378f05cddf9SRui Paulo 1379f05cddf9SRui Paulo /* compute MIC before sending */ 1380f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, 1381f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 1382*5b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 1383*5b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_MIC) { 1384*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong MIC"); 1385*5b9c547cSRui Paulo ftie->mic[0] ^= 0x01; 1386*5b9c547cSRui Paulo } 1387*5b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1388f05cddf9SRui Paulo 1389f05cddf9SRui Paulo skip_ies: 1390*5b9c547cSRui Paulo 1391*5b9c547cSRui Paulo if (peer->vht_capabilities) 1392*5b9c547cSRui Paulo peer_capab |= TDLS_PEER_VHT; 1393*5b9c547cSRui Paulo if (peer->ht_capabilities) 1394*5b9c547cSRui Paulo peer_capab |= TDLS_PEER_HT; 1395*5b9c547cSRui Paulo if (peer->wmm_capable) 1396*5b9c547cSRui Paulo peer_capab |= TDLS_PEER_WMM; 1397*5b9c547cSRui Paulo 1398*5b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, 1399*5b9c547cSRui Paulo dtoken, 0, peer_capab, peer->initiator, 1400f05cddf9SRui Paulo rbuf, pos - rbuf); 1401f05cddf9SRui Paulo os_free(rbuf); 1402f05cddf9SRui Paulo 1403*5b9c547cSRui Paulo return status; 1404f05cddf9SRui Paulo } 1405f05cddf9SRui Paulo 1406f05cddf9SRui Paulo 1407f05cddf9SRui Paulo static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, 1408f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 1409f05cddf9SRui Paulo u8 dialog_token) 1410f05cddf9SRui Paulo { 1411*5b9c547cSRui Paulo size_t buf_len = 0; 1412*5b9c547cSRui Paulo struct wpa_tdls_timeoutie timeoutie; 1413*5b9c547cSRui Paulo u16 rsn_capab; 1414*5b9c547cSRui Paulo u8 *rbuf, *pos, *count_pos; 1415*5b9c547cSRui Paulo u16 count; 1416*5b9c547cSRui Paulo struct rsn_ie_hdr *hdr; 1417*5b9c547cSRui Paulo int status; 1418*5b9c547cSRui Paulo 1419f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response " 1420f05cddf9SRui Paulo "(peer " MACSTR ")", MAC2STR(peer->addr)); 1421*5b9c547cSRui Paulo if (!wpa_tdls_get_privacy(sm)) 1422*5b9c547cSRui Paulo goto skip_rsn_ies; 1423f05cddf9SRui Paulo 1424*5b9c547cSRui Paulo /* Filling RSN IE */ 1425*5b9c547cSRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_i; 1426*5b9c547cSRui Paulo hdr->elem_id = WLAN_EID_RSN; 1427*5b9c547cSRui Paulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 1428*5b9c547cSRui Paulo pos = (u8 *) (hdr + 1); 1429*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 1430*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 1431*5b9c547cSRui Paulo count_pos = pos; 1432*5b9c547cSRui Paulo pos += 2; 1433*5b9c547cSRui Paulo count = 0; 1434*5b9c547cSRui Paulo 1435*5b9c547cSRui Paulo /* 1436*5b9c547cSRui Paulo * AES-CCMP is the default encryption preferred for TDLS, so 1437*5b9c547cSRui Paulo * RSN IE is filled only with CCMP cipher suite. 1438*5b9c547cSRui Paulo * Note: TKIP is not used to encrypt TDLS link. 1439*5b9c547cSRui Paulo * 1440*5b9c547cSRui Paulo * Regardless of the cipher used on the AP connection, select CCMP 1441*5b9c547cSRui Paulo * here. 1442*5b9c547cSRui Paulo */ 1443*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1444*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 1445*5b9c547cSRui Paulo count++; 1446*5b9c547cSRui Paulo WPA_PUT_LE16(count_pos, count); 1447*5b9c547cSRui Paulo WPA_PUT_LE16(pos, 1); 1448*5b9c547cSRui Paulo pos += 2; 1449*5b9c547cSRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 1450*5b9c547cSRui Paulo pos += RSN_SELECTOR_LEN; 1451*5b9c547cSRui Paulo 1452*5b9c547cSRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1453*5b9c547cSRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 1454*5b9c547cSRui Paulo WPA_PUT_LE16(pos, rsn_capab); 1455*5b9c547cSRui Paulo pos += 2; 1456*5b9c547cSRui Paulo hdr->len = (pos - (u8 *) hdr) - 2; 1457*5b9c547cSRui Paulo peer->rsnie_i_len = pos - peer->rsnie_i; 1458*5b9c547cSRui Paulo 1459*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response", 1460*5b9c547cSRui Paulo (u8 *) hdr, hdr->len + 2); 1461*5b9c547cSRui Paulo skip_rsn_ies: 1462*5b9c547cSRui Paulo buf_len = 0; 1463*5b9c547cSRui Paulo if (wpa_tdls_get_privacy(sm)) { 1464*5b9c547cSRui Paulo /* Peer RSN IE, Lifetime */ 1465*5b9c547cSRui Paulo buf_len += peer->rsnie_i_len + 1466*5b9c547cSRui Paulo sizeof(struct wpa_tdls_timeoutie); 1467*5b9c547cSRui Paulo } 1468*5b9c547cSRui Paulo rbuf = os_zalloc(buf_len + 1); 1469*5b9c547cSRui Paulo if (rbuf == NULL) { 1470*5b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 1471*5b9c547cSRui Paulo return -1; 1472*5b9c547cSRui Paulo } 1473*5b9c547cSRui Paulo pos = rbuf; 1474*5b9c547cSRui Paulo 1475*5b9c547cSRui Paulo if (!wpa_tdls_get_privacy(sm)) 1476*5b9c547cSRui Paulo goto skip_ies; 1477*5b9c547cSRui Paulo /* Initiator RSN IE */ 1478*5b9c547cSRui Paulo pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); 1479*5b9c547cSRui Paulo /* Lifetime */ 1480*5b9c547cSRui Paulo peer->lifetime = TPK_LIFETIME; 1481*5b9c547cSRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1482*5b9c547cSRui Paulo sizeof(timeoutie), peer->lifetime); 1483*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); 1484*5b9c547cSRui Paulo skip_ies: 1485*5b9c547cSRui Paulo status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, 1486*5b9c547cSRui Paulo dialog_token, 0, 0, 0, rbuf, pos - rbuf); 1487*5b9c547cSRui Paulo os_free(rbuf); 1488*5b9c547cSRui Paulo 1489*5b9c547cSRui Paulo return status; 1490f05cddf9SRui Paulo } 1491f05cddf9SRui Paulo 1492f05cddf9SRui Paulo 1493f05cddf9SRui Paulo static int 1494f05cddf9SRui Paulo wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, 1495f05cddf9SRui Paulo const u8 *buf, size_t len) 1496f05cddf9SRui Paulo { 1497f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1498f05cddf9SRui Paulo const struct wpa_tdls_lnkid *lnkid; 1499f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1500f05cddf9SRui Paulo size_t min_req_len = sizeof(struct wpa_tdls_frame) + 1501f05cddf9SRui Paulo 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); 1502f05cddf9SRui Paulo u8 dialog_token; 1503f05cddf9SRui Paulo 1504f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR, 1505f05cddf9SRui Paulo MAC2STR(addr)); 1506f05cddf9SRui Paulo 1507f05cddf9SRui Paulo if (len < min_req_len) { 1508f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: " 1509f05cddf9SRui Paulo "%d", (int) len); 1510f05cddf9SRui Paulo return -1; 1511f05cddf9SRui Paulo } 1512f05cddf9SRui Paulo 1513f05cddf9SRui Paulo dialog_token = buf[sizeof(struct wpa_tdls_frame)]; 1514f05cddf9SRui Paulo 1515*5b9c547cSRui Paulo /* 1516*5b9c547cSRui Paulo * Some APs will tack on a weird IE to the end of a TDLS 1517*5b9c547cSRui Paulo * discovery request packet. This needn't fail the response, 1518*5b9c547cSRui Paulo * since the required IE are verified separately. 1519*5b9c547cSRui Paulo */ 1520f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1, 1521f05cddf9SRui Paulo len - (sizeof(struct wpa_tdls_frame) + 1), 1522*5b9c547cSRui Paulo &kde) < 0) { 1523*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 1524*5b9c547cSRui Paulo "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround"); 1525*5b9c547cSRui Paulo } 1526f05cddf9SRui Paulo 1527f05cddf9SRui Paulo if (!kde.lnkid) { 1528f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery " 1529f05cddf9SRui Paulo "Request"); 1530f05cddf9SRui Paulo return -1; 1531f05cddf9SRui Paulo } 1532f05cddf9SRui Paulo 1533f05cddf9SRui Paulo lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; 1534f05cddf9SRui Paulo 1535f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1536f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " 1537f05cddf9SRui Paulo " BSS " MACSTR, MAC2STR(lnkid->bssid)); 1538f05cddf9SRui Paulo return -1; 1539f05cddf9SRui Paulo } 1540f05cddf9SRui Paulo 1541*5b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, addr, NULL); 1542f05cddf9SRui Paulo if (peer == NULL) 1543f05cddf9SRui Paulo return -1; 1544f05cddf9SRui Paulo 1545f05cddf9SRui Paulo return wpa_tdls_send_discovery_response(sm, peer, dialog_token); 1546f05cddf9SRui Paulo } 1547f05cddf9SRui Paulo 1548f05cddf9SRui Paulo 1549f05cddf9SRui Paulo int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) 1550f05cddf9SRui Paulo { 1551f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 1552f05cddf9SRui Paulo return -1; 1553f05cddf9SRui Paulo 1554f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " 1555f05cddf9SRui Paulo MACSTR, MAC2STR(addr)); 1556f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, 1557*5b9c547cSRui Paulo 1, 0, 0, 1, NULL, 0); 1558f05cddf9SRui Paulo } 1559f05cddf9SRui Paulo 1560f05cddf9SRui Paulo 1561f05cddf9SRui Paulo static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, 1562f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 1563f05cddf9SRui Paulo { 1564f05cddf9SRui Paulo if (!kde->supp_rates) { 1565f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported rates received"); 1566f05cddf9SRui Paulo return -1; 1567f05cddf9SRui Paulo } 1568*5b9c547cSRui Paulo peer->supp_rates_len = merge_byte_arrays( 1569*5b9c547cSRui Paulo peer->supp_rates, sizeof(peer->supp_rates), 1570*5b9c547cSRui Paulo kde->supp_rates + 2, kde->supp_rates_len - 2, 1571*5b9c547cSRui Paulo kde->ext_supp_rates ? kde->ext_supp_rates + 2 : NULL, 1572*5b9c547cSRui Paulo kde->ext_supp_rates_len - 2); 1573*5b9c547cSRui Paulo return 0; 1574f05cddf9SRui Paulo } 1575f05cddf9SRui Paulo 1576*5b9c547cSRui Paulo 1577*5b9c547cSRui Paulo static int copy_peer_ht_capab(const struct wpa_eapol_ie_parse *kde, 1578*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1579*5b9c547cSRui Paulo { 1580*5b9c547cSRui Paulo if (!kde->ht_capabilities || 1581*5b9c547cSRui Paulo kde->ht_capabilities_len < 1582*5b9c547cSRui Paulo sizeof(struct ieee80211_ht_capabilities) ) { 1583*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported ht capabilities " 1584*5b9c547cSRui Paulo "received"); 1585f05cddf9SRui Paulo return 0; 1586f05cddf9SRui Paulo } 1587f05cddf9SRui Paulo 1588*5b9c547cSRui Paulo if (!peer->ht_capabilities) { 1589*5b9c547cSRui Paulo peer->ht_capabilities = 1590*5b9c547cSRui Paulo os_zalloc(sizeof(struct ieee80211_ht_capabilities)); 1591*5b9c547cSRui Paulo if (peer->ht_capabilities == NULL) 1592*5b9c547cSRui Paulo return -1; 1593*5b9c547cSRui Paulo } 1594*5b9c547cSRui Paulo 1595*5b9c547cSRui Paulo os_memcpy(peer->ht_capabilities, kde->ht_capabilities, 1596*5b9c547cSRui Paulo sizeof(struct ieee80211_ht_capabilities)); 1597*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer HT capabilities", 1598*5b9c547cSRui Paulo (u8 *) peer->ht_capabilities, 1599*5b9c547cSRui Paulo sizeof(struct ieee80211_ht_capabilities)); 1600*5b9c547cSRui Paulo 1601*5b9c547cSRui Paulo return 0; 1602*5b9c547cSRui Paulo } 1603*5b9c547cSRui Paulo 1604*5b9c547cSRui Paulo 1605*5b9c547cSRui Paulo static int copy_peer_vht_capab(const struct wpa_eapol_ie_parse *kde, 1606*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1607*5b9c547cSRui Paulo { 1608*5b9c547cSRui Paulo if (!kde->vht_capabilities || 1609*5b9c547cSRui Paulo kde->vht_capabilities_len < 1610*5b9c547cSRui Paulo sizeof(struct ieee80211_vht_capabilities) ) { 1611*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported vht capabilities " 1612*5b9c547cSRui Paulo "received"); 1613*5b9c547cSRui Paulo return 0; 1614*5b9c547cSRui Paulo } 1615*5b9c547cSRui Paulo 1616*5b9c547cSRui Paulo if (!peer->vht_capabilities) { 1617*5b9c547cSRui Paulo peer->vht_capabilities = 1618*5b9c547cSRui Paulo os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 1619*5b9c547cSRui Paulo if (peer->vht_capabilities == NULL) 1620*5b9c547cSRui Paulo return -1; 1621*5b9c547cSRui Paulo } 1622*5b9c547cSRui Paulo 1623*5b9c547cSRui Paulo os_memcpy(peer->vht_capabilities, kde->vht_capabilities, 1624*5b9c547cSRui Paulo sizeof(struct ieee80211_vht_capabilities)); 1625*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer VHT capabilities", 1626*5b9c547cSRui Paulo (u8 *) peer->vht_capabilities, 1627*5b9c547cSRui Paulo sizeof(struct ieee80211_vht_capabilities)); 1628*5b9c547cSRui Paulo 1629*5b9c547cSRui Paulo return 0; 1630*5b9c547cSRui Paulo } 1631*5b9c547cSRui Paulo 1632*5b9c547cSRui Paulo 1633*5b9c547cSRui Paulo static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, 1634*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1635*5b9c547cSRui Paulo { 1636*5b9c547cSRui Paulo if (!kde->ext_capab) { 1637*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No extended capabilities " 1638*5b9c547cSRui Paulo "received"); 1639*5b9c547cSRui Paulo return 0; 1640*5b9c547cSRui Paulo } 1641*5b9c547cSRui Paulo 1642*5b9c547cSRui Paulo if (!peer->ext_capab || peer->ext_capab_len < kde->ext_capab_len - 2) { 1643*5b9c547cSRui Paulo /* Need to allocate buffer to fit the new information */ 1644*5b9c547cSRui Paulo os_free(peer->ext_capab); 1645*5b9c547cSRui Paulo peer->ext_capab = os_zalloc(kde->ext_capab_len - 2); 1646*5b9c547cSRui Paulo if (peer->ext_capab == NULL) 1647*5b9c547cSRui Paulo return -1; 1648*5b9c547cSRui Paulo } 1649*5b9c547cSRui Paulo 1650*5b9c547cSRui Paulo peer->ext_capab_len = kde->ext_capab_len - 2; 1651*5b9c547cSRui Paulo os_memcpy(peer->ext_capab, kde->ext_capab + 2, peer->ext_capab_len); 1652*5b9c547cSRui Paulo 1653*5b9c547cSRui Paulo return 0; 1654*5b9c547cSRui Paulo } 1655*5b9c547cSRui Paulo 1656*5b9c547cSRui Paulo 1657*5b9c547cSRui Paulo static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde, 1658*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1659*5b9c547cSRui Paulo { 1660*5b9c547cSRui Paulo struct wmm_information_element *wmm; 1661*5b9c547cSRui Paulo 1662*5b9c547cSRui Paulo if (!kde->wmm) { 1663*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received"); 1664*5b9c547cSRui Paulo return 0; 1665*5b9c547cSRui Paulo } 1666*5b9c547cSRui Paulo 1667*5b9c547cSRui Paulo if (kde->wmm_len < sizeof(struct wmm_information_element)) { 1668*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received"); 1669*5b9c547cSRui Paulo return -1; 1670*5b9c547cSRui Paulo } 1671*5b9c547cSRui Paulo 1672*5b9c547cSRui Paulo wmm = (struct wmm_information_element *) kde->wmm; 1673*5b9c547cSRui Paulo peer->qos_info = wmm->qos_info; 1674*5b9c547cSRui Paulo 1675*5b9c547cSRui Paulo peer->wmm_capable = 1; 1676*5b9c547cSRui Paulo 1677*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info); 1678*5b9c547cSRui Paulo return 0; 1679*5b9c547cSRui Paulo } 1680*5b9c547cSRui Paulo 1681*5b9c547cSRui Paulo 1682*5b9c547cSRui Paulo static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, 1683*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1684*5b9c547cSRui Paulo { 1685*5b9c547cSRui Paulo if (!kde->supp_channels) { 1686*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported channels received"); 1687*5b9c547cSRui Paulo return 0; 1688*5b9c547cSRui Paulo } 1689*5b9c547cSRui Paulo 1690*5b9c547cSRui Paulo if (!peer->supp_channels || 1691*5b9c547cSRui Paulo peer->supp_channels_len < kde->supp_channels_len) { 1692*5b9c547cSRui Paulo os_free(peer->supp_channels); 1693*5b9c547cSRui Paulo peer->supp_channels = os_zalloc(kde->supp_channels_len); 1694*5b9c547cSRui Paulo if (peer->supp_channels == NULL) 1695*5b9c547cSRui Paulo return -1; 1696*5b9c547cSRui Paulo } 1697*5b9c547cSRui Paulo 1698*5b9c547cSRui Paulo peer->supp_channels_len = kde->supp_channels_len; 1699*5b9c547cSRui Paulo 1700*5b9c547cSRui Paulo os_memcpy(peer->supp_channels, kde->supp_channels, 1701*5b9c547cSRui Paulo peer->supp_channels_len); 1702*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Channels", 1703*5b9c547cSRui Paulo (u8 *) peer->supp_channels, peer->supp_channels_len); 1704*5b9c547cSRui Paulo return 0; 1705*5b9c547cSRui Paulo } 1706*5b9c547cSRui Paulo 1707*5b9c547cSRui Paulo 1708*5b9c547cSRui Paulo static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, 1709*5b9c547cSRui Paulo struct wpa_tdls_peer *peer) 1710*5b9c547cSRui Paulo { 1711*5b9c547cSRui Paulo if (!kde->supp_oper_classes) { 1712*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported operating classes received"); 1713*5b9c547cSRui Paulo return 0; 1714*5b9c547cSRui Paulo } 1715*5b9c547cSRui Paulo 1716*5b9c547cSRui Paulo if (!peer->supp_oper_classes || 1717*5b9c547cSRui Paulo peer->supp_oper_classes_len < kde->supp_oper_classes_len) { 1718*5b9c547cSRui Paulo os_free(peer->supp_oper_classes); 1719*5b9c547cSRui Paulo peer->supp_oper_classes = os_zalloc(kde->supp_oper_classes_len); 1720*5b9c547cSRui Paulo if (peer->supp_oper_classes == NULL) 1721*5b9c547cSRui Paulo return -1; 1722*5b9c547cSRui Paulo } 1723*5b9c547cSRui Paulo 1724*5b9c547cSRui Paulo peer->supp_oper_classes_len = kde->supp_oper_classes_len; 1725*5b9c547cSRui Paulo os_memcpy(peer->supp_oper_classes, kde->supp_oper_classes, 1726*5b9c547cSRui Paulo peer->supp_oper_classes_len); 1727*5b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Peer Supported Operating Classes", 1728*5b9c547cSRui Paulo (u8 *) peer->supp_oper_classes, 1729*5b9c547cSRui Paulo peer->supp_oper_classes_len); 1730*5b9c547cSRui Paulo return 0; 1731*5b9c547cSRui Paulo } 1732*5b9c547cSRui Paulo 1733*5b9c547cSRui Paulo 1734*5b9c547cSRui Paulo static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 1735*5b9c547cSRui Paulo int add) 1736*5b9c547cSRui Paulo { 1737*5b9c547cSRui Paulo return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid, 1738*5b9c547cSRui Paulo peer->capability, 1739*5b9c547cSRui Paulo peer->supp_rates, peer->supp_rates_len, 1740*5b9c547cSRui Paulo peer->ht_capabilities, 1741*5b9c547cSRui Paulo peer->vht_capabilities, 1742*5b9c547cSRui Paulo peer->qos_info, peer->wmm_capable, 1743*5b9c547cSRui Paulo peer->ext_capab, peer->ext_capab_len, 1744*5b9c547cSRui Paulo peer->supp_channels, 1745*5b9c547cSRui Paulo peer->supp_channels_len, 1746*5b9c547cSRui Paulo peer->supp_oper_classes, 1747*5b9c547cSRui Paulo peer->supp_oper_classes_len); 1748*5b9c547cSRui Paulo } 1749*5b9c547cSRui Paulo 1750f05cddf9SRui Paulo 1751f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, 1752f05cddf9SRui Paulo const u8 *buf, size_t len) 1753f05cddf9SRui Paulo { 1754f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1755f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1756f05cddf9SRui Paulo struct wpa_ie_data ie; 1757f05cddf9SRui Paulo int cipher; 1758f05cddf9SRui Paulo const u8 *cpos; 1759f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie = NULL; 1760f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 1761f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 1762f05cddf9SRui Paulo u32 lifetime = 0; 1763f05cddf9SRui Paulo #if 0 1764f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 1765f05cddf9SRui Paulo u8 *pos; 1766f05cddf9SRui Paulo u16 rsn_capab; 1767f05cddf9SRui Paulo u16 rsn_ver; 1768f05cddf9SRui Paulo #endif 1769f05cddf9SRui Paulo u8 dtoken; 1770f05cddf9SRui Paulo u16 ielen; 1771f05cddf9SRui Paulo u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1772f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 1773f05cddf9SRui Paulo int existing_peer = 0; 1774f05cddf9SRui Paulo 1775f05cddf9SRui Paulo if (len < 3 + 3) 1776f05cddf9SRui Paulo return -1; 1777f05cddf9SRui Paulo 1778f05cddf9SRui Paulo cpos = buf; 1779f05cddf9SRui Paulo cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 1780f05cddf9SRui Paulo 1781f05cddf9SRui Paulo /* driver had already verified the frame format */ 1782f05cddf9SRui Paulo dtoken = *cpos++; /* dialog token */ 1783f05cddf9SRui Paulo 1784f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); 1785f05cddf9SRui Paulo 1786*5b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, src_addr, &existing_peer); 1787f05cddf9SRui Paulo if (peer == NULL) 1788f05cddf9SRui Paulo goto error; 1789*5b9c547cSRui Paulo 1790*5b9c547cSRui Paulo /* If found, use existing entry instead of adding a new one; 1791*5b9c547cSRui Paulo * how to handle the case where both ends initiate at the 1792*5b9c547cSRui Paulo * same time? */ 1793*5b9c547cSRui Paulo if (existing_peer) { 1794*5b9c547cSRui Paulo if (peer->tpk_success) { 1795*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " 1796*5b9c547cSRui Paulo "direct link is enabled - tear down the " 1797*5b9c547cSRui Paulo "old link first"); 1798*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 1799*5b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 1800*5b9c547cSRui Paulo } else if (peer->initiator) { 1801*5b9c547cSRui Paulo /* 1802*5b9c547cSRui Paulo * An entry is already present, so check if we already 1803*5b9c547cSRui Paulo * sent a TDLS Setup Request. If so, compare MAC 1804*5b9c547cSRui Paulo * addresses and let the STA with the lower MAC address 1805*5b9c547cSRui Paulo * continue as the initiator. The other negotiation is 1806*5b9c547cSRui Paulo * terminated. 1807*5b9c547cSRui Paulo */ 1808*5b9c547cSRui Paulo if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { 1809*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard request " 1810*5b9c547cSRui Paulo "from peer with higher address " 1811*5b9c547cSRui Paulo MACSTR, MAC2STR(src_addr)); 1812*5b9c547cSRui Paulo return -1; 1813*5b9c547cSRui Paulo } else { 1814*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Accept request " 1815*5b9c547cSRui Paulo "from peer with lower address " 1816*5b9c547cSRui Paulo MACSTR " (terminate previously " 1817*5b9c547cSRui Paulo "initiated negotiation", 1818*5b9c547cSRui Paulo MAC2STR(src_addr)); 1819*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, 1820*5b9c547cSRui Paulo peer->addr); 1821*5b9c547cSRui Paulo wpa_tdls_peer_clear(sm, peer); 1822*5b9c547cSRui Paulo } 1823*5b9c547cSRui Paulo } 1824f05cddf9SRui Paulo } 1825f05cddf9SRui Paulo 1826f05cddf9SRui Paulo /* capability information */ 1827f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(cpos); 1828f05cddf9SRui Paulo cpos += 2; 1829f05cddf9SRui Paulo 1830f05cddf9SRui Paulo ielen = len - (cpos - buf); /* start of IE in buf */ 1831*5b9c547cSRui Paulo 1832*5b9c547cSRui Paulo /* 1833*5b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 1834*5b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 1835*5b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 1836*5b9c547cSRui Paulo */ 1837*5b9c547cSRui Paulo if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) 1838*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 1839*5b9c547cSRui Paulo "TDLS: Failed to parse IEs in TPK M1 - ignore as an interop workaround"); 1840f05cddf9SRui Paulo 1841f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 1842f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 1843f05cddf9SRui Paulo "TPK M1"); 1844f05cddf9SRui Paulo goto error; 1845f05cddf9SRui Paulo } 1846f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", 1847f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 1848f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 1849f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1850f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); 1851*5b9c547cSRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1852f05cddf9SRui Paulo goto error; 1853f05cddf9SRui Paulo } 1854f05cddf9SRui Paulo 1855f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, 1856f05cddf9SRui Paulo MAC2STR(src_addr)); 1857f05cddf9SRui Paulo 1858f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 1859f05cddf9SRui Paulo goto error; 1860f05cddf9SRui Paulo 1861*5b9c547cSRui Paulo if (copy_peer_ht_capab(&kde, peer) < 0) 1862*5b9c547cSRui Paulo goto error; 1863*5b9c547cSRui Paulo 1864*5b9c547cSRui Paulo if (copy_peer_vht_capab(&kde, peer) < 0) 1865*5b9c547cSRui Paulo goto error; 1866*5b9c547cSRui Paulo 1867*5b9c547cSRui Paulo if (copy_peer_ext_capab(&kde, peer) < 0) 1868*5b9c547cSRui Paulo goto error; 1869*5b9c547cSRui Paulo 1870*5b9c547cSRui Paulo if (copy_peer_supp_channels(&kde, peer) < 0) 1871*5b9c547cSRui Paulo goto error; 1872*5b9c547cSRui Paulo 1873*5b9c547cSRui Paulo if (copy_peer_supp_oper_classes(&kde, peer) < 0) 1874*5b9c547cSRui Paulo goto error; 1875*5b9c547cSRui Paulo 1876*5b9c547cSRui Paulo peer->qos_info = kde.qosinfo; 1877*5b9c547cSRui Paulo 1878*5b9c547cSRui Paulo /* Overwrite with the qos_info obtained in WMM IE */ 1879*5b9c547cSRui Paulo if (copy_peer_wmm_capab(&kde, peer) < 0) 1880*5b9c547cSRui Paulo goto error; 1881*5b9c547cSRui Paulo 1882*5b9c547cSRui Paulo peer->aid = kde.aid; 1883*5b9c547cSRui Paulo 1884f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1885f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 1886*5b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, src_addr, NULL); 1887f05cddf9SRui Paulo if (peer == NULL) 1888f05cddf9SRui Paulo goto error; 1889f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " 1890f05cddf9SRui Paulo "TDLS setup - send own request"); 1891f05cddf9SRui Paulo peer->initiator = 1; 1892*5b9c547cSRui Paulo wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, 1893*5b9c547cSRui Paulo NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0); 1894f05cddf9SRui Paulo wpa_tdls_send_tpk_m1(sm, peer); 1895f05cddf9SRui Paulo } 1896f05cddf9SRui Paulo 1897f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 1898f05cddf9SRui Paulo tdls_prohibited) { 1899f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 1900f05cddf9SRui Paulo "on TDLS"); 1901f05cddf9SRui Paulo tdls_prohibited = 0; 1902f05cddf9SRui Paulo } 1903f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1904f05cddf9SRui Paulo 1905f05cddf9SRui Paulo if (tdls_prohibited) { 1906f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); 1907f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1908f05cddf9SRui Paulo goto error; 1909f05cddf9SRui Paulo } 1910f05cddf9SRui Paulo 1911f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1912f05cddf9SRui Paulo if (kde.rsn_ie) { 1913f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " 1914f05cddf9SRui Paulo "security is disabled"); 1915f05cddf9SRui Paulo status = WLAN_STATUS_SECURITY_DISABLED; 1916f05cddf9SRui Paulo goto error; 1917f05cddf9SRui Paulo } 1918f05cddf9SRui Paulo goto skip_rsn; 1919f05cddf9SRui Paulo } 1920f05cddf9SRui Paulo 1921f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 1922f05cddf9SRui Paulo kde.rsn_ie == NULL) { 1923f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); 1924f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 1925f05cddf9SRui Paulo goto error; 1926f05cddf9SRui Paulo } 1927f05cddf9SRui Paulo 1928f05cddf9SRui Paulo if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { 1929f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " 1930f05cddf9SRui Paulo "TPK M1"); 1931f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1932f05cddf9SRui Paulo goto error; 1933f05cddf9SRui Paulo } 1934f05cddf9SRui Paulo 1935f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 1936f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); 1937f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1938f05cddf9SRui Paulo goto error; 1939f05cddf9SRui Paulo } 1940f05cddf9SRui Paulo 1941f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 1942f05cddf9SRui Paulo if (cipher & WPA_CIPHER_CCMP) { 1943f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 1944f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 1945f05cddf9SRui Paulo } else { 1946f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); 1947f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1948f05cddf9SRui Paulo goto error; 1949f05cddf9SRui Paulo } 1950f05cddf9SRui Paulo 1951f05cddf9SRui Paulo if ((ie.capabilities & 1952f05cddf9SRui Paulo (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != 1953f05cddf9SRui Paulo WPA_CAPABILITY_PEERKEY_ENABLED) { 1954f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " 1955f05cddf9SRui Paulo "TPK M1"); 1956f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; 1957f05cddf9SRui Paulo goto error; 1958f05cddf9SRui Paulo } 1959f05cddf9SRui Paulo 1960f05cddf9SRui Paulo /* Lifetime */ 1961f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 1962f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); 1963f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1964f05cddf9SRui Paulo goto error; 1965f05cddf9SRui Paulo } 1966f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 1967f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 1968f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); 1969f05cddf9SRui Paulo if (lifetime < 300) { 1970f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); 1971f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1972f05cddf9SRui Paulo goto error; 1973f05cddf9SRui Paulo } 1974f05cddf9SRui Paulo 1975f05cddf9SRui Paulo skip_rsn: 1976f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1977f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 1978f05cddf9SRui Paulo if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) { 1979f05cddf9SRui Paulo /* 1980f05cddf9SRui Paulo * The request frame from us is going to win, so do not 1981f05cddf9SRui Paulo * replace information based on this request frame from 1982f05cddf9SRui Paulo * the peer. 1983f05cddf9SRui Paulo */ 1984f05cddf9SRui Paulo goto skip_rsn_check; 1985f05cddf9SRui Paulo } 1986f05cddf9SRui Paulo } 1987f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1988f05cddf9SRui Paulo 1989f05cddf9SRui Paulo peer->initiator = 0; /* Need to check */ 1990f05cddf9SRui Paulo peer->dtoken = dtoken; 1991f05cddf9SRui Paulo 1992f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1993f05cddf9SRui Paulo peer->rsnie_i_len = 0; 1994f05cddf9SRui Paulo peer->rsnie_p_len = 0; 1995f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 1996f05cddf9SRui Paulo goto skip_rsn_check; 1997f05cddf9SRui Paulo } 1998f05cddf9SRui Paulo 1999f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 2000f05cddf9SRui Paulo os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); 2001f05cddf9SRui Paulo peer->rsnie_i_len = kde.rsn_ie_len; 2002f05cddf9SRui Paulo peer->cipher = cipher; 2003f05cddf9SRui Paulo 2004*5b9c547cSRui Paulo if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) { 2005*5b9c547cSRui Paulo /* 2006*5b9c547cSRui Paulo * There is no point in updating the RNonce for every obtained 2007*5b9c547cSRui Paulo * TPK M1 frame (e.g., retransmission due to timeout) with the 2008*5b9c547cSRui Paulo * same INonce (SNonce in FTIE). However, if the TPK M1 is 2009*5b9c547cSRui Paulo * retransmitted with a different INonce, update the RNonce 2010*5b9c547cSRui Paulo * since this is for a new TDLS session. 2011*5b9c547cSRui Paulo */ 2012*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2013*5b9c547cSRui Paulo "TDLS: New TPK M1 INonce - generate new RNonce"); 2014*5b9c547cSRui Paulo os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN); 2015f05cddf9SRui Paulo if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { 2016f05cddf9SRui Paulo wpa_msg(sm->ctx->ctx, MSG_WARNING, 2017f05cddf9SRui Paulo "TDLS: Failed to get random data for responder nonce"); 2018f05cddf9SRui Paulo goto error; 2019f05cddf9SRui Paulo } 2020*5b9c547cSRui Paulo } 2021f05cddf9SRui Paulo 2022f05cddf9SRui Paulo #if 0 2023f05cddf9SRui Paulo /* get version info from RSNIE received from Peer */ 2024f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) kde.rsn_ie; 2025f05cddf9SRui Paulo rsn_ver = WPA_GET_LE16(hdr->version); 2026f05cddf9SRui Paulo 2027f05cddf9SRui Paulo /* use min(peer's version, out version) */ 2028f05cddf9SRui Paulo if (rsn_ver > RSN_VERSION) 2029f05cddf9SRui Paulo rsn_ver = RSN_VERSION; 2030f05cddf9SRui Paulo 2031f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_p; 2032f05cddf9SRui Paulo 2033f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 2034f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, rsn_ver); 2035f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 2036f05cddf9SRui Paulo 2037f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 2038f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2039f05cddf9SRui Paulo /* Include only the selected cipher in pairwise cipher suite */ 2040f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 2041f05cddf9SRui Paulo pos += 2; 2042f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) 2043f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 2044f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2045f05cddf9SRui Paulo 2046f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 2047f05cddf9SRui Paulo pos += 2; 2048f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 2049f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 2050f05cddf9SRui Paulo 2051f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 2052f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 2053f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 2054f05cddf9SRui Paulo pos += 2; 2055f05cddf9SRui Paulo 2056f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_p) - 2; 2057f05cddf9SRui Paulo peer->rsnie_p_len = pos - peer->rsnie_p; 2058f05cddf9SRui Paulo #endif 2059f05cddf9SRui Paulo 2060f05cddf9SRui Paulo /* temp fix: validation of RSNIE later */ 2061f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); 2062f05cddf9SRui Paulo peer->rsnie_p_len = peer->rsnie_i_len; 2063f05cddf9SRui Paulo 2064f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 2065f05cddf9SRui Paulo peer->rsnie_p, peer->rsnie_p_len); 2066f05cddf9SRui Paulo 2067f05cddf9SRui Paulo peer->lifetime = lifetime; 2068f05cddf9SRui Paulo 2069f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 2070f05cddf9SRui Paulo 2071f05cddf9SRui Paulo skip_rsn_check: 2072*5b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 2073*5b9c547cSRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) 2074*5b9c547cSRui Paulo goto skip_add_peer; 2075*5b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2076*5b9c547cSRui Paulo 2077*5b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 2078*5b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 1) < 0) 2079*5b9c547cSRui Paulo goto error; 2080*5b9c547cSRui Paulo 2081*5b9c547cSRui Paulo #ifdef CONFIG_TDLS_TESTING 2082*5b9c547cSRui Paulo skip_add_peer: 2083*5b9c547cSRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2084*5b9c547cSRui Paulo peer->tpk_in_progress = 1; 2085f05cddf9SRui Paulo 2086f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); 2087f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { 2088*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2089f05cddf9SRui Paulo goto error; 2090f05cddf9SRui Paulo } 2091f05cddf9SRui Paulo 2092f05cddf9SRui Paulo return 0; 2093f05cddf9SRui Paulo 2094f05cddf9SRui Paulo error: 2095*5b9c547cSRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, 2096f05cddf9SRui Paulo status); 2097*5b9c547cSRui Paulo if (peer) 2098*5b9c547cSRui Paulo wpa_tdls_peer_free(sm, peer); 2099f05cddf9SRui Paulo return -1; 2100f05cddf9SRui Paulo } 2101f05cddf9SRui Paulo 2102f05cddf9SRui Paulo 2103*5b9c547cSRui Paulo static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 2104f05cddf9SRui Paulo { 2105f05cddf9SRui Paulo peer->tpk_success = 1; 2106*5b9c547cSRui Paulo peer->tpk_in_progress = 0; 2107f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 2108f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 2109f05cddf9SRui Paulo u32 lifetime = peer->lifetime; 2110f05cddf9SRui Paulo /* 2111f05cddf9SRui Paulo * Start the initiator process a bit earlier to avoid race 2112f05cddf9SRui Paulo * condition with the responder sending teardown request. 2113f05cddf9SRui Paulo */ 2114f05cddf9SRui Paulo if (lifetime > 3 && peer->initiator) 2115f05cddf9SRui Paulo lifetime -= 3; 2116f05cddf9SRui Paulo eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, 2117f05cddf9SRui Paulo sm, peer); 2118f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2119f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { 2120f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " 2121f05cddf9SRui Paulo "expiration"); 2122f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 2123f05cddf9SRui Paulo } 2124f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2125f05cddf9SRui Paulo } 2126f05cddf9SRui Paulo 2127*5b9c547cSRui Paulo if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { 2128*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "TDLS: Could not configure key to the " 2129*5b9c547cSRui Paulo "driver"); 2130*5b9c547cSRui Paulo return -1; 2131*5b9c547cSRui Paulo } 2132*5b9c547cSRui Paulo peer->reconfig_key = 0; 2133f05cddf9SRui Paulo 2134*5b9c547cSRui Paulo return wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); 2135f05cddf9SRui Paulo } 2136f05cddf9SRui Paulo 2137f05cddf9SRui Paulo 2138f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, 2139f05cddf9SRui Paulo const u8 *buf, size_t len) 2140f05cddf9SRui Paulo { 2141f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2142f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 2143f05cddf9SRui Paulo struct wpa_ie_data ie; 2144f05cddf9SRui Paulo int cipher; 2145f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 2146f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 2147f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 2148f05cddf9SRui Paulo u32 lifetime; 2149f05cddf9SRui Paulo u8 dtoken; 2150f05cddf9SRui Paulo int ielen; 2151f05cddf9SRui Paulo u16 status; 2152f05cddf9SRui Paulo const u8 *pos; 2153*5b9c547cSRui Paulo int ret = 0; 2154f05cddf9SRui Paulo 2155f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " 2156f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 2157f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2158f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 2159f05cddf9SRui Paulo break; 2160f05cddf9SRui Paulo } 2161f05cddf9SRui Paulo if (peer == NULL) { 2162f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 2163f05cddf9SRui Paulo "TPK M2: " MACSTR, MAC2STR(src_addr)); 2164f05cddf9SRui Paulo return -1; 2165f05cddf9SRui Paulo } 2166*5b9c547cSRui Paulo if (!peer->initiator) { 2167*5b9c547cSRui Paulo /* 2168*5b9c547cSRui Paulo * This may happen if both devices try to initiate TDLS at the 2169*5b9c547cSRui Paulo * same time and we accept the TPK M1 from the peer in 2170*5b9c547cSRui Paulo * wpa_tdls_process_tpk_m1() and clear our previous state. 2171*5b9c547cSRui Paulo */ 2172*5b9c547cSRui Paulo wpa_printf(MSG_INFO, "TDLS: We were not the initiator, so " 2173*5b9c547cSRui Paulo "ignore TPK M2 from " MACSTR, MAC2STR(src_addr)); 2174*5b9c547cSRui Paulo return -1; 2175*5b9c547cSRui Paulo } 2176f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); 2177f05cddf9SRui Paulo 2178*5b9c547cSRui Paulo if (len < 3 + 2 + 1) { 2179*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2180f05cddf9SRui Paulo return -1; 2181*5b9c547cSRui Paulo } 2182*5b9c547cSRui Paulo 2183f05cddf9SRui Paulo pos = buf; 2184f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 2185f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 2186f05cddf9SRui Paulo pos += 2 /* status code */; 2187f05cddf9SRui Paulo 2188f05cddf9SRui Paulo if (status != WLAN_STATUS_SUCCESS) { 2189f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", 2190f05cddf9SRui Paulo status); 2191*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2192f05cddf9SRui Paulo return -1; 2193f05cddf9SRui Paulo } 2194f05cddf9SRui Paulo 2195f05cddf9SRui Paulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 2196f05cddf9SRui Paulo 2197f05cddf9SRui Paulo /* TODO: need to verify dialog token matches here or in kernel */ 2198f05cddf9SRui Paulo dtoken = *pos++; /* dialog token */ 2199f05cddf9SRui Paulo 2200f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); 2201f05cddf9SRui Paulo 2202*5b9c547cSRui Paulo if (len < 3 + 2 + 1 + 2) { 2203*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2204f05cddf9SRui Paulo return -1; 2205*5b9c547cSRui Paulo } 2206f05cddf9SRui Paulo 2207f05cddf9SRui Paulo /* capability information */ 2208f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(pos); 2209f05cddf9SRui Paulo pos += 2; 2210f05cddf9SRui Paulo 2211f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 2212*5b9c547cSRui Paulo 2213*5b9c547cSRui Paulo /* 2214*5b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 2215*5b9c547cSRui Paulo * explicitly checked below. Some APs may add arbitrary padding to the 2216*5b9c547cSRui Paulo * end of short TDLS frames and that would look like invalid IEs. 2217*5b9c547cSRui Paulo */ 2218*5b9c547cSRui Paulo if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) 2219*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2220*5b9c547cSRui Paulo "TDLS: Failed to parse IEs in TPK M2 - ignore as an interop workaround"); 2221f05cddf9SRui Paulo 2222f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2223f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { 2224f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); 2225f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 2226f05cddf9SRui Paulo goto error; 2227f05cddf9SRui Paulo } 2228f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2229f05cddf9SRui Paulo 2230f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 2231f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 2232f05cddf9SRui Paulo "TPK M2"); 2233f05cddf9SRui Paulo goto error; 2234f05cddf9SRui Paulo } 2235f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", 2236f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 2237f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 2238f05cddf9SRui Paulo 2239f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 2240f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); 2241f05cddf9SRui Paulo status = WLAN_STATUS_NOT_IN_SAME_BSS; 2242f05cddf9SRui Paulo goto error; 2243f05cddf9SRui Paulo } 2244f05cddf9SRui Paulo 2245f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 2246f05cddf9SRui Paulo goto error; 2247f05cddf9SRui Paulo 2248*5b9c547cSRui Paulo if (copy_peer_ht_capab(&kde, peer) < 0) 2249*5b9c547cSRui Paulo goto error; 2250*5b9c547cSRui Paulo 2251*5b9c547cSRui Paulo if (copy_peer_vht_capab(&kde, peer) < 0) 2252*5b9c547cSRui Paulo goto error; 2253*5b9c547cSRui Paulo 2254*5b9c547cSRui Paulo if (copy_peer_ext_capab(&kde, peer) < 0) 2255*5b9c547cSRui Paulo goto error; 2256*5b9c547cSRui Paulo 2257*5b9c547cSRui Paulo if (copy_peer_supp_channels(&kde, peer) < 0) 2258*5b9c547cSRui Paulo goto error; 2259*5b9c547cSRui Paulo 2260*5b9c547cSRui Paulo if (copy_peer_supp_oper_classes(&kde, peer) < 0) 2261*5b9c547cSRui Paulo goto error; 2262*5b9c547cSRui Paulo 2263*5b9c547cSRui Paulo peer->qos_info = kde.qosinfo; 2264*5b9c547cSRui Paulo 2265*5b9c547cSRui Paulo /* Overwrite with the qos_info obtained in WMM IE */ 2266*5b9c547cSRui Paulo if (copy_peer_wmm_capab(&kde, peer) < 0) 2267*5b9c547cSRui Paulo goto error; 2268*5b9c547cSRui Paulo 2269*5b9c547cSRui Paulo peer->aid = kde.aid; 2270*5b9c547cSRui Paulo 2271f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 2272f05cddf9SRui Paulo peer->rsnie_p_len = 0; 2273f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 2274f05cddf9SRui Paulo goto skip_rsn; 2275f05cddf9SRui Paulo } 2276f05cddf9SRui Paulo 2277f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 2278f05cddf9SRui Paulo kde.rsn_ie == NULL) { 2279f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); 2280f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 2281f05cddf9SRui Paulo goto error; 2282f05cddf9SRui Paulo } 2283f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 2284f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2285f05cddf9SRui Paulo 2286*5b9c547cSRui Paulo if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { 2287*5b9c547cSRui Paulo wpa_printf(MSG_INFO, 2288*5b9c547cSRui Paulo "TDLS: Too long Responder RSN IE in TPK M2"); 2289*5b9c547cSRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 2290*5b9c547cSRui Paulo goto error; 2291*5b9c547cSRui Paulo } 2292*5b9c547cSRui Paulo 2293f05cddf9SRui Paulo /* 2294f05cddf9SRui Paulo * FIX: bitwise comparison of RSN IE is not the correct way of 2295f05cddf9SRui Paulo * validation this. It can be different, but certain fields must 2296f05cddf9SRui Paulo * match. Since we list only a single pairwise cipher in TPK M1, the 2297f05cddf9SRui Paulo * memcmp is likely to work in most cases, though. 2298f05cddf9SRui Paulo */ 2299f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_i_len || 2300f05cddf9SRui Paulo os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { 2301f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " 2302f05cddf9SRui Paulo "not match with RSN IE used in TPK M1"); 2303f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", 2304f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 2305f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 2306f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2307f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 2308f05cddf9SRui Paulo goto error; 2309f05cddf9SRui Paulo } 2310f05cddf9SRui Paulo 2311f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 2312f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); 2313f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 2314f05cddf9SRui Paulo goto error; 2315f05cddf9SRui Paulo } 2316f05cddf9SRui Paulo 2317f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 2318f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) { 2319f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 2320f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 2321f05cddf9SRui Paulo } else { 2322f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); 2323f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 2324f05cddf9SRui Paulo goto error; 2325f05cddf9SRui Paulo } 2326f05cddf9SRui Paulo 2327f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", 2328f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 2329f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 2330f05cddf9SRui Paulo 2331f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 2332f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " 2333f05cddf9SRui Paulo "not match with FTIE SNonce used in TPK M1"); 2334f05cddf9SRui Paulo /* Silently discard the frame */ 2335f05cddf9SRui Paulo return -1; 2336f05cddf9SRui Paulo } 2337f05cddf9SRui Paulo 2338f05cddf9SRui Paulo /* Responder Nonce and RSN IE */ 2339f05cddf9SRui Paulo os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); 2340f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); 2341f05cddf9SRui Paulo peer->rsnie_p_len = kde.rsn_ie_len; 2342f05cddf9SRui Paulo peer->cipher = cipher; 2343f05cddf9SRui Paulo 2344f05cddf9SRui Paulo /* Lifetime */ 2345f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 2346f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); 2347f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 2348f05cddf9SRui Paulo goto error; 2349f05cddf9SRui Paulo } 2350f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 2351f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 2352f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", 2353f05cddf9SRui Paulo lifetime); 2354f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 2355f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 2356f05cddf9SRui Paulo "TPK M2 (expected %u)", lifetime, peer->lifetime); 2357f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 2358f05cddf9SRui Paulo goto error; 2359f05cddf9SRui Paulo } 2360f05cddf9SRui Paulo 2361f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 2362f05cddf9SRui Paulo 2363f05cddf9SRui Paulo /* Process MIC check to see if TPK M2 is right */ 2364f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, 2365f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 2366f05cddf9SRui Paulo /* Discard the frame */ 2367f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 2368*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2369f05cddf9SRui Paulo return -1; 2370f05cddf9SRui Paulo } 2371f05cddf9SRui Paulo 2372*5b9c547cSRui Paulo if (wpa_tdls_set_key(sm, peer) < 0) { 2373*5b9c547cSRui Paulo /* 2374*5b9c547cSRui Paulo * Some drivers may not be able to config the key prior to full 2375*5b9c547cSRui Paulo * STA entry having been configured. 2376*5b9c547cSRui Paulo */ 2377*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " 2378*5b9c547cSRui Paulo "STA entry is complete"); 2379*5b9c547cSRui Paulo peer->reconfig_key = 1; 2380*5b9c547cSRui Paulo } 2381f05cddf9SRui Paulo 2382f05cddf9SRui Paulo skip_rsn: 2383f05cddf9SRui Paulo peer->dtoken = dtoken; 2384f05cddf9SRui Paulo 2385*5b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 2386*5b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 0) < 0) 2387*5b9c547cSRui Paulo goto error; 2388*5b9c547cSRui Paulo 2389f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " 2390f05cddf9SRui Paulo "TPK Handshake Message 3"); 2391*5b9c547cSRui Paulo if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) 2392*5b9c547cSRui Paulo goto error; 2393f05cddf9SRui Paulo 2394*5b9c547cSRui Paulo if (!peer->tpk_success) { 2395*5b9c547cSRui Paulo /* 2396*5b9c547cSRui Paulo * Enable Link only when tpk_success is 0, signifying that this 2397*5b9c547cSRui Paulo * processing of TPK M2 frame is not because of a retransmission 2398*5b9c547cSRui Paulo * during TDLS setup handshake. 2399*5b9c547cSRui Paulo */ 2400*5b9c547cSRui Paulo ret = wpa_tdls_enable_link(sm, peer); 2401*5b9c547cSRui Paulo if (ret < 0) { 2402*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); 2403*5b9c547cSRui Paulo wpa_tdls_do_teardown( 2404*5b9c547cSRui Paulo sm, peer, 2405*5b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 2406*5b9c547cSRui Paulo } 2407*5b9c547cSRui Paulo } 2408*5b9c547cSRui Paulo return ret; 2409f05cddf9SRui Paulo 2410f05cddf9SRui Paulo error: 2411*5b9c547cSRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1, 2412f05cddf9SRui Paulo status); 2413*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2414f05cddf9SRui Paulo return -1; 2415f05cddf9SRui Paulo } 2416f05cddf9SRui Paulo 2417f05cddf9SRui Paulo 2418f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, 2419f05cddf9SRui Paulo const u8 *buf, size_t len) 2420f05cddf9SRui Paulo { 2421f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2422f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 2423f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 2424f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 2425f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 2426f05cddf9SRui Paulo int ielen; 2427f05cddf9SRui Paulo u16 status; 2428f05cddf9SRui Paulo const u8 *pos; 2429f05cddf9SRui Paulo u32 lifetime; 2430*5b9c547cSRui Paulo int ret = 0; 2431f05cddf9SRui Paulo 2432f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " 2433f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 2434f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2435f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 2436f05cddf9SRui Paulo break; 2437f05cddf9SRui Paulo } 2438f05cddf9SRui Paulo if (peer == NULL) { 2439f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 2440f05cddf9SRui Paulo "TPK M3: " MACSTR, MAC2STR(src_addr)); 2441f05cddf9SRui Paulo return -1; 2442f05cddf9SRui Paulo } 2443f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); 2444f05cddf9SRui Paulo 2445f05cddf9SRui Paulo if (len < 3 + 3) 2446*5b9c547cSRui Paulo goto error; 2447f05cddf9SRui Paulo pos = buf; 2448f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 2449f05cddf9SRui Paulo 2450f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 2451f05cddf9SRui Paulo 2452f05cddf9SRui Paulo if (status != 0) { 2453f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", 2454f05cddf9SRui Paulo status); 2455*5b9c547cSRui Paulo goto error; 2456f05cddf9SRui Paulo } 2457f05cddf9SRui Paulo pos += 2 /* status code */ + 1 /* dialog token */; 2458f05cddf9SRui Paulo 2459f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 2460*5b9c547cSRui Paulo 2461*5b9c547cSRui Paulo /* 2462*5b9c547cSRui Paulo * Don't reject the message if failing to parse IEs. The IEs we need are 2463*5b9c547cSRui Paulo * explicitly checked below. Some APs piggy-back broken IEs to the end 2464*5b9c547cSRui Paulo * of a TDLS Confirm packet, which will fail the link if we don't ignore 2465*5b9c547cSRui Paulo * this error. 2466*5b9c547cSRui Paulo */ 2467f05cddf9SRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { 2468*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2469*5b9c547cSRui Paulo "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround"); 2470f05cddf9SRui Paulo } 2471f05cddf9SRui Paulo 2472f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 2473f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3"); 2474*5b9c547cSRui Paulo goto error; 2475f05cddf9SRui Paulo } 2476f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", 2477f05cddf9SRui Paulo (u8 *) kde.lnkid, kde.lnkid_len); 2478f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 2479f05cddf9SRui Paulo 2480f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 2481f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); 2482*5b9c547cSRui Paulo goto error; 2483f05cddf9SRui Paulo } 2484f05cddf9SRui Paulo 2485f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 2486f05cddf9SRui Paulo goto skip_rsn; 2487f05cddf9SRui Paulo 2488f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 2489f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); 2490*5b9c547cSRui Paulo goto error; 2491f05cddf9SRui Paulo } 2492f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", 2493f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 2494f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 2495f05cddf9SRui Paulo 2496f05cddf9SRui Paulo if (kde.rsn_ie == NULL) { 2497f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); 2498*5b9c547cSRui Paulo goto error; 2499f05cddf9SRui Paulo } 2500f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", 2501f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 2502f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_p_len || 2503f05cddf9SRui Paulo os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) { 2504f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match " 2505f05cddf9SRui Paulo "with the one sent in TPK M2"); 2506*5b9c547cSRui Paulo goto error; 2507f05cddf9SRui Paulo } 2508f05cddf9SRui Paulo 2509f05cddf9SRui Paulo if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) { 2510f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does " 2511f05cddf9SRui Paulo "not match with FTIE ANonce used in TPK M2"); 2512*5b9c547cSRui Paulo goto error; 2513f05cddf9SRui Paulo } 2514f05cddf9SRui Paulo 2515f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 2516f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not " 2517f05cddf9SRui Paulo "match with FTIE SNonce used in TPK M1"); 2518*5b9c547cSRui Paulo goto error; 2519f05cddf9SRui Paulo } 2520f05cddf9SRui Paulo 2521f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 2522f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); 2523*5b9c547cSRui Paulo goto error; 2524f05cddf9SRui Paulo } 2525f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 2526f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", 2527f05cddf9SRui Paulo (u8 *) timeoutie, sizeof(*timeoutie)); 2528f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 2529f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", 2530f05cddf9SRui Paulo lifetime); 2531f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 2532f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 2533f05cddf9SRui Paulo "TPK M3 (expected %u)", lifetime, peer->lifetime); 2534*5b9c547cSRui Paulo goto error; 2535f05cddf9SRui Paulo } 2536f05cddf9SRui Paulo 2537f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, 2538f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 2539f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 2540*5b9c547cSRui Paulo goto error; 2541f05cddf9SRui Paulo } 2542f05cddf9SRui Paulo 2543*5b9c547cSRui Paulo if (wpa_tdls_set_key(sm, peer) < 0) { 2544*5b9c547cSRui Paulo /* 2545*5b9c547cSRui Paulo * Some drivers may not be able to config the key prior to full 2546*5b9c547cSRui Paulo * STA entry having been configured. 2547*5b9c547cSRui Paulo */ 2548*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Try to configure TPK again after " 2549*5b9c547cSRui Paulo "STA entry is complete"); 2550*5b9c547cSRui Paulo peer->reconfig_key = 1; 2551*5b9c547cSRui Paulo } 2552f05cddf9SRui Paulo 2553f05cddf9SRui Paulo skip_rsn: 2554*5b9c547cSRui Paulo /* add supported rates, capabilities, and qos_info to the TDLS peer */ 2555*5b9c547cSRui Paulo if (wpa_tdls_addset_peer(sm, peer, 0) < 0) 2556*5b9c547cSRui Paulo goto error; 2557f05cddf9SRui Paulo 2558*5b9c547cSRui Paulo if (!peer->tpk_success) { 2559*5b9c547cSRui Paulo /* 2560*5b9c547cSRui Paulo * Enable Link only when tpk_success is 0, signifying that this 2561*5b9c547cSRui Paulo * processing of TPK M3 frame is not because of a retransmission 2562*5b9c547cSRui Paulo * during TDLS setup handshake. 2563*5b9c547cSRui Paulo */ 2564*5b9c547cSRui Paulo ret = wpa_tdls_enable_link(sm, peer); 2565*5b9c547cSRui Paulo if (ret < 0) { 2566*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); 2567*5b9c547cSRui Paulo goto error; 2568*5b9c547cSRui Paulo } 2569*5b9c547cSRui Paulo } 2570*5b9c547cSRui Paulo return ret; 2571*5b9c547cSRui Paulo error: 2572*5b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 2573*5b9c547cSRui Paulo return -1; 2574f05cddf9SRui Paulo } 2575f05cddf9SRui Paulo 2576f05cddf9SRui Paulo 2577f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) 2578f05cddf9SRui Paulo { 2579f05cddf9SRui Paulo struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; 2580f05cddf9SRui Paulo 2581f05cddf9SRui Paulo os_memset(lifetime, 0, ie_len); 2582f05cddf9SRui Paulo lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; 2583f05cddf9SRui Paulo lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; 2584f05cddf9SRui Paulo lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; 2585f05cddf9SRui Paulo WPA_PUT_LE32(lifetime->value, tsecs); 2586f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 2587f05cddf9SRui Paulo return pos + ie_len; 2588f05cddf9SRui Paulo } 2589f05cddf9SRui Paulo 2590f05cddf9SRui Paulo 2591f05cddf9SRui Paulo /** 2592f05cddf9SRui Paulo * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) 2593f05cddf9SRui Paulo * @sm: Pointer to WPA state machine data from wpa_sm_init() 2594f05cddf9SRui Paulo * @peer: MAC address of the peer STA 2595f05cddf9SRui Paulo * Returns: 0 on success, or -1 on failure 2596f05cddf9SRui Paulo * 2597f05cddf9SRui Paulo * Send TPK Handshake Message 1 info to driver to start TDLS 2598f05cddf9SRui Paulo * handshake with the peer. 2599f05cddf9SRui Paulo */ 2600f05cddf9SRui Paulo int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) 2601f05cddf9SRui Paulo { 2602f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2603f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 2604f05cddf9SRui Paulo 2605f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2606f05cddf9SRui Paulo return -1; 2607f05cddf9SRui Paulo 2608f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2609f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 2610f05cddf9SRui Paulo tdls_prohibited) { 2611f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 2612f05cddf9SRui Paulo "on TDLS"); 2613f05cddf9SRui Paulo tdls_prohibited = 0; 2614f05cddf9SRui Paulo } 2615f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2616f05cddf9SRui Paulo 2617f05cddf9SRui Paulo if (tdls_prohibited) { 2618f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " 2619f05cddf9SRui Paulo "reject request to start setup"); 2620f05cddf9SRui Paulo return -1; 2621f05cddf9SRui Paulo } 2622f05cddf9SRui Paulo 2623*5b9c547cSRui Paulo peer = wpa_tdls_add_peer(sm, addr, NULL); 2624f05cddf9SRui Paulo if (peer == NULL) 2625f05cddf9SRui Paulo return -1; 2626*5b9c547cSRui Paulo 2627*5b9c547cSRui Paulo if (peer->tpk_in_progress) { 2628*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer"); 2629*5b9c547cSRui Paulo return 0; 2630f05cddf9SRui Paulo } 2631f05cddf9SRui Paulo 2632f05cddf9SRui Paulo peer->initiator = 1; 2633f05cddf9SRui Paulo 2634f05cddf9SRui Paulo /* add the peer to the driver as a "setup in progress" peer */ 2635*5b9c547cSRui Paulo if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, 2636*5b9c547cSRui Paulo NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) { 2637*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2638*5b9c547cSRui Paulo return -1; 2639*5b9c547cSRui Paulo } 2640*5b9c547cSRui Paulo 2641*5b9c547cSRui Paulo peer->tpk_in_progress = 1; 2642f05cddf9SRui Paulo 2643f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m1(sm, peer) < 0) { 2644*5b9c547cSRui Paulo wpa_tdls_disable_peer_link(sm, peer); 2645f05cddf9SRui Paulo return -1; 2646f05cddf9SRui Paulo } 2647f05cddf9SRui Paulo 2648f05cddf9SRui Paulo return 0; 2649f05cddf9SRui Paulo } 2650f05cddf9SRui Paulo 2651f05cddf9SRui Paulo 2652*5b9c547cSRui Paulo void wpa_tdls_remove(struct wpa_sm *sm, const u8 *addr) 2653f05cddf9SRui Paulo { 2654f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2655f05cddf9SRui Paulo 2656f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2657*5b9c547cSRui Paulo return; 2658f05cddf9SRui Paulo 2659f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2660f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2661f05cddf9SRui Paulo break; 2662f05cddf9SRui Paulo } 2663f05cddf9SRui Paulo 2664f05cddf9SRui Paulo if (peer == NULL || !peer->tpk_success) 2665*5b9c547cSRui Paulo return; 2666f05cddf9SRui Paulo 2667f05cddf9SRui Paulo if (sm->tdls_external_setup) { 2668f05cddf9SRui Paulo /* 2669f05cddf9SRui Paulo * Disable previous link to allow renegotiation to be completed 2670f05cddf9SRui Paulo * on AP path. 2671f05cddf9SRui Paulo */ 2672*5b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, 2673*5b9c547cSRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); 2674f05cddf9SRui Paulo } 2675f05cddf9SRui Paulo } 2676f05cddf9SRui Paulo 2677f05cddf9SRui Paulo 2678f05cddf9SRui Paulo /** 2679f05cddf9SRui Paulo * wpa_supplicant_rx_tdls - Receive TDLS data frame 2680f05cddf9SRui Paulo * 2681f05cddf9SRui Paulo * This function is called to receive TDLS (ethertype = 0x890d) data frames. 2682f05cddf9SRui Paulo */ 2683f05cddf9SRui Paulo static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, 2684f05cddf9SRui Paulo const u8 *buf, size_t len) 2685f05cddf9SRui Paulo { 2686f05cddf9SRui Paulo struct wpa_sm *sm = ctx; 2687f05cddf9SRui Paulo struct wpa_tdls_frame *tf; 2688f05cddf9SRui Paulo 2689f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", 2690f05cddf9SRui Paulo buf, len); 2691f05cddf9SRui Paulo 2692f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) { 2693f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " 2694f05cddf9SRui Paulo "or unsupported by driver"); 2695f05cddf9SRui Paulo return; 2696f05cddf9SRui Paulo } 2697f05cddf9SRui Paulo 2698f05cddf9SRui Paulo if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { 2699f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); 2700f05cddf9SRui Paulo return; 2701f05cddf9SRui Paulo } 2702f05cddf9SRui Paulo 2703f05cddf9SRui Paulo if (len < sizeof(*tf)) { 2704f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); 2705f05cddf9SRui Paulo return; 2706f05cddf9SRui Paulo } 2707f05cddf9SRui Paulo 2708f05cddf9SRui Paulo /* Check to make sure its a valid encapsulated TDLS frame */ 2709f05cddf9SRui Paulo tf = (struct wpa_tdls_frame *) buf; 2710f05cddf9SRui Paulo if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || 2711f05cddf9SRui Paulo tf->category != WLAN_ACTION_TDLS) { 2712f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " 2713f05cddf9SRui Paulo "category=%u action=%u", 2714f05cddf9SRui Paulo tf->payloadtype, tf->category, tf->action); 2715f05cddf9SRui Paulo return; 2716f05cddf9SRui Paulo } 2717f05cddf9SRui Paulo 2718f05cddf9SRui Paulo switch (tf->action) { 2719f05cddf9SRui Paulo case WLAN_TDLS_SETUP_REQUEST: 2720f05cddf9SRui Paulo wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); 2721f05cddf9SRui Paulo break; 2722f05cddf9SRui Paulo case WLAN_TDLS_SETUP_RESPONSE: 2723f05cddf9SRui Paulo wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); 2724f05cddf9SRui Paulo break; 2725f05cddf9SRui Paulo case WLAN_TDLS_SETUP_CONFIRM: 2726f05cddf9SRui Paulo wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); 2727f05cddf9SRui Paulo break; 2728f05cddf9SRui Paulo case WLAN_TDLS_TEARDOWN: 2729f05cddf9SRui Paulo wpa_tdls_recv_teardown(sm, src_addr, buf, len); 2730f05cddf9SRui Paulo break; 2731f05cddf9SRui Paulo case WLAN_TDLS_DISCOVERY_REQUEST: 2732f05cddf9SRui Paulo wpa_tdls_process_discovery_request(sm, src_addr, buf, len); 2733f05cddf9SRui Paulo break; 2734f05cddf9SRui Paulo default: 2735f05cddf9SRui Paulo /* Kernel code will process remaining frames */ 2736f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", 2737f05cddf9SRui Paulo tf->action); 2738f05cddf9SRui Paulo break; 2739f05cddf9SRui Paulo } 2740f05cddf9SRui Paulo } 2741f05cddf9SRui Paulo 2742f05cddf9SRui Paulo 2743f05cddf9SRui Paulo /** 2744f05cddf9SRui Paulo * wpa_tdls_init - Initialize driver interface parameters for TDLS 2745f05cddf9SRui Paulo * @wpa_s: Pointer to wpa_supplicant data 2746f05cddf9SRui Paulo * Returns: 0 on success, -1 on failure 2747f05cddf9SRui Paulo * 2748f05cddf9SRui Paulo * This function is called to initialize driver interface parameters for TDLS. 2749f05cddf9SRui Paulo * wpa_drv_init() must have been called before this function to initialize the 2750f05cddf9SRui Paulo * driver interface. 2751f05cddf9SRui Paulo */ 2752f05cddf9SRui Paulo int wpa_tdls_init(struct wpa_sm *sm) 2753f05cddf9SRui Paulo { 2754f05cddf9SRui Paulo if (sm == NULL) 2755f05cddf9SRui Paulo return -1; 2756f05cddf9SRui Paulo 2757f05cddf9SRui Paulo sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : 2758f05cddf9SRui Paulo sm->ifname, 2759f05cddf9SRui Paulo sm->own_addr, 2760f05cddf9SRui Paulo ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, 2761f05cddf9SRui Paulo sm, 0); 2762f05cddf9SRui Paulo if (sm->l2_tdls == NULL) { 2763f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " 2764f05cddf9SRui Paulo "connection"); 2765f05cddf9SRui Paulo return -1; 2766f05cddf9SRui Paulo } 2767f05cddf9SRui Paulo 2768f05cddf9SRui Paulo /* 2769f05cddf9SRui Paulo * Drivers that support TDLS but don't implement the get_capa callback 2770f05cddf9SRui Paulo * are assumed to perform everything internally 2771f05cddf9SRui Paulo */ 2772f05cddf9SRui Paulo if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, 2773*5b9c547cSRui Paulo &sm->tdls_external_setup, 2774*5b9c547cSRui Paulo &sm->tdls_chan_switch) < 0) { 2775f05cddf9SRui Paulo sm->tdls_supported = 1; 2776f05cddf9SRui Paulo sm->tdls_external_setup = 0; 2777f05cddf9SRui Paulo } 2778f05cddf9SRui Paulo 2779f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " 2780f05cddf9SRui Paulo "driver", sm->tdls_supported ? "" : " not"); 2781f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup", 2782f05cddf9SRui Paulo sm->tdls_external_setup ? "external" : "internal"); 2783*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching", 2784*5b9c547cSRui Paulo sm->tdls_chan_switch ? "supports" : "does not support"); 2785f05cddf9SRui Paulo 2786f05cddf9SRui Paulo return 0; 2787f05cddf9SRui Paulo } 2788f05cddf9SRui Paulo 2789f05cddf9SRui Paulo 2790*5b9c547cSRui Paulo void wpa_tdls_teardown_peers(struct wpa_sm *sm) 2791*5b9c547cSRui Paulo { 2792*5b9c547cSRui Paulo struct wpa_tdls_peer *peer, *tmp; 2793*5b9c547cSRui Paulo 2794*5b9c547cSRui Paulo if (!sm) 2795*5b9c547cSRui Paulo return; 2796*5b9c547cSRui Paulo peer = sm->tdls; 2797*5b9c547cSRui Paulo 2798*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Tear down peers"); 2799*5b9c547cSRui Paulo 2800*5b9c547cSRui Paulo while (peer) { 2801*5b9c547cSRui Paulo tmp = peer->next; 2802*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR, 2803*5b9c547cSRui Paulo MAC2STR(peer->addr)); 2804*5b9c547cSRui Paulo if (sm->tdls_external_setup) 2805*5b9c547cSRui Paulo wpa_tdls_do_teardown(sm, peer, 2806*5b9c547cSRui Paulo WLAN_REASON_DEAUTH_LEAVING); 2807*5b9c547cSRui Paulo else 2808*5b9c547cSRui Paulo wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); 2809*5b9c547cSRui Paulo 2810*5b9c547cSRui Paulo peer = tmp; 2811*5b9c547cSRui Paulo } 2812*5b9c547cSRui Paulo } 2813*5b9c547cSRui Paulo 2814*5b9c547cSRui Paulo 2815f05cddf9SRui Paulo static void wpa_tdls_remove_peers(struct wpa_sm *sm) 2816f05cddf9SRui Paulo { 2817f05cddf9SRui Paulo struct wpa_tdls_peer *peer, *tmp; 2818f05cddf9SRui Paulo 2819f05cddf9SRui Paulo peer = sm->tdls; 2820f05cddf9SRui Paulo 2821f05cddf9SRui Paulo while (peer) { 2822f05cddf9SRui Paulo int res; 2823f05cddf9SRui Paulo tmp = peer->next; 2824f05cddf9SRui Paulo res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2825f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", 2826f05cddf9SRui Paulo MAC2STR(peer->addr), res); 2827f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 2828f05cddf9SRui Paulo peer = tmp; 2829f05cddf9SRui Paulo } 2830f05cddf9SRui Paulo } 2831f05cddf9SRui Paulo 2832f05cddf9SRui Paulo 2833f05cddf9SRui Paulo /** 2834f05cddf9SRui Paulo * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS 2835f05cddf9SRui Paulo * 2836f05cddf9SRui Paulo * This function is called to recover driver interface parameters for TDLS 2837f05cddf9SRui Paulo * and frees resources allocated for it. 2838f05cddf9SRui Paulo */ 2839f05cddf9SRui Paulo void wpa_tdls_deinit(struct wpa_sm *sm) 2840f05cddf9SRui Paulo { 2841f05cddf9SRui Paulo if (sm == NULL) 2842f05cddf9SRui Paulo return; 2843f05cddf9SRui Paulo 2844f05cddf9SRui Paulo if (sm->l2_tdls) 2845f05cddf9SRui Paulo l2_packet_deinit(sm->l2_tdls); 2846f05cddf9SRui Paulo sm->l2_tdls = NULL; 2847f05cddf9SRui Paulo 2848f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2849f05cddf9SRui Paulo } 2850f05cddf9SRui Paulo 2851f05cddf9SRui Paulo 2852f05cddf9SRui Paulo void wpa_tdls_assoc(struct wpa_sm *sm) 2853f05cddf9SRui Paulo { 2854f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); 2855f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2856f05cddf9SRui Paulo } 2857f05cddf9SRui Paulo 2858f05cddf9SRui Paulo 2859f05cddf9SRui Paulo void wpa_tdls_disassoc(struct wpa_sm *sm) 2860f05cddf9SRui Paulo { 2861f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); 2862f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2863f05cddf9SRui Paulo } 2864f05cddf9SRui Paulo 2865f05cddf9SRui Paulo 2866*5b9c547cSRui Paulo static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems) 2867f05cddf9SRui Paulo { 2868f05cddf9SRui Paulo /* bit 38 - TDLS Prohibited */ 2869*5b9c547cSRui Paulo return !!(elems->ext_capab[2 + 4] & 0x40); 2870*5b9c547cSRui Paulo } 2871*5b9c547cSRui Paulo 2872*5b9c547cSRui Paulo 2873*5b9c547cSRui Paulo static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems) 2874*5b9c547cSRui Paulo { 2875*5b9c547cSRui Paulo /* bit 39 - TDLS Channel Switch Prohibited */ 2876*5b9c547cSRui Paulo return !!(elems->ext_capab[2 + 4] & 0x80); 2877f05cddf9SRui Paulo } 2878f05cddf9SRui Paulo 2879f05cddf9SRui Paulo 2880f05cddf9SRui Paulo void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2881f05cddf9SRui Paulo { 2882*5b9c547cSRui Paulo struct wpa_eapol_ie_parse elems; 2883*5b9c547cSRui Paulo 2884*5b9c547cSRui Paulo sm->tdls_prohibited = 0; 2885*5b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 0; 2886*5b9c547cSRui Paulo 2887*5b9c547cSRui Paulo if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 || 2888*5b9c547cSRui Paulo elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) 2889*5b9c547cSRui Paulo return; 2890*5b9c547cSRui Paulo 2891*5b9c547cSRui Paulo sm->tdls_prohibited = wpa_tdls_prohibited(&elems); 2892f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", 2893f05cddf9SRui Paulo sm->tdls_prohibited ? "prohibited" : "allowed"); 2894*5b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 2895*5b9c547cSRui Paulo wpa_tdls_chan_switch_prohibited(&elems); 2896*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS", 2897*5b9c547cSRui Paulo sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed"); 2898f05cddf9SRui Paulo } 2899f05cddf9SRui Paulo 2900f05cddf9SRui Paulo 2901f05cddf9SRui Paulo void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2902f05cddf9SRui Paulo { 2903*5b9c547cSRui Paulo struct wpa_eapol_ie_parse elems; 2904*5b9c547cSRui Paulo 2905*5b9c547cSRui Paulo if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 || 2906*5b9c547cSRui Paulo elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) 2907*5b9c547cSRui Paulo return; 2908*5b9c547cSRui Paulo 2909*5b9c547cSRui Paulo if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) { 2910f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " 2911f05cddf9SRui Paulo "(Re)Association Response IEs"); 2912f05cddf9SRui Paulo sm->tdls_prohibited = 1; 2913f05cddf9SRui Paulo } 2914*5b9c547cSRui Paulo 2915*5b9c547cSRui Paulo if (!sm->tdls_chan_switch_prohibited && 2916*5b9c547cSRui Paulo wpa_tdls_chan_switch_prohibited(&elems)) { 2917*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2918*5b9c547cSRui Paulo "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs"); 2919*5b9c547cSRui Paulo sm->tdls_chan_switch_prohibited = 1; 2920*5b9c547cSRui Paulo } 2921f05cddf9SRui Paulo } 2922f05cddf9SRui Paulo 2923f05cddf9SRui Paulo 2924f05cddf9SRui Paulo void wpa_tdls_enable(struct wpa_sm *sm, int enabled) 2925f05cddf9SRui Paulo { 2926f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); 2927f05cddf9SRui Paulo sm->tdls_disabled = !enabled; 2928f05cddf9SRui Paulo } 2929f05cddf9SRui Paulo 2930f05cddf9SRui Paulo 2931f05cddf9SRui Paulo int wpa_tdls_is_external_setup(struct wpa_sm *sm) 2932f05cddf9SRui Paulo { 2933f05cddf9SRui Paulo return sm->tdls_external_setup; 2934f05cddf9SRui Paulo } 2935*5b9c547cSRui Paulo 2936*5b9c547cSRui Paulo 2937*5b9c547cSRui Paulo int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr, 2938*5b9c547cSRui Paulo u8 oper_class, 2939*5b9c547cSRui Paulo struct hostapd_freq_params *freq_params) 2940*5b9c547cSRui Paulo { 2941*5b9c547cSRui Paulo struct wpa_tdls_peer *peer; 2942*5b9c547cSRui Paulo int ret; 2943*5b9c547cSRui Paulo 2944*5b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2945*5b9c547cSRui Paulo return -1; 2946*5b9c547cSRui Paulo 2947*5b9c547cSRui Paulo if (!sm->tdls_chan_switch) { 2948*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2949*5b9c547cSRui Paulo "TDLS: Channel switching not supported by the driver"); 2950*5b9c547cSRui Paulo return -1; 2951*5b9c547cSRui Paulo } 2952*5b9c547cSRui Paulo 2953*5b9c547cSRui Paulo if (sm->tdls_chan_switch_prohibited) { 2954*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, 2955*5b9c547cSRui Paulo "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel"); 2956*5b9c547cSRui Paulo return -1; 2957*5b9c547cSRui Paulo } 2958*5b9c547cSRui Paulo 2959*5b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2960*5b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2961*5b9c547cSRui Paulo break; 2962*5b9c547cSRui Paulo } 2963*5b9c547cSRui Paulo 2964*5b9c547cSRui Paulo if (peer == NULL || !peer->tpk_success) { 2965*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR 2966*5b9c547cSRui Paulo " not found for channel switching", MAC2STR(addr)); 2967*5b9c547cSRui Paulo return -1; 2968*5b9c547cSRui Paulo } 2969*5b9c547cSRui Paulo 2970*5b9c547cSRui Paulo if (peer->chan_switch_enabled) { 2971*5b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 2972*5b9c547cSRui Paulo " already has channel switching enabled", 2973*5b9c547cSRui Paulo MAC2STR(addr)); 2974*5b9c547cSRui Paulo return 0; 2975*5b9c547cSRui Paulo } 2976*5b9c547cSRui Paulo 2977*5b9c547cSRui Paulo ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr, 2978*5b9c547cSRui Paulo oper_class, freq_params); 2979*5b9c547cSRui Paulo if (!ret) 2980*5b9c547cSRui Paulo peer->chan_switch_enabled = 1; 2981*5b9c547cSRui Paulo 2982*5b9c547cSRui Paulo return ret; 2983*5b9c547cSRui Paulo } 2984*5b9c547cSRui Paulo 2985*5b9c547cSRui Paulo 2986*5b9c547cSRui Paulo int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr) 2987*5b9c547cSRui Paulo { 2988*5b9c547cSRui Paulo struct wpa_tdls_peer *peer; 2989*5b9c547cSRui Paulo 2990*5b9c547cSRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2991*5b9c547cSRui Paulo return -1; 2992*5b9c547cSRui Paulo 2993*5b9c547cSRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2994*5b9c547cSRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2995*5b9c547cSRui Paulo break; 2996*5b9c547cSRui Paulo } 2997*5b9c547cSRui Paulo 2998*5b9c547cSRui Paulo if (!peer || !peer->chan_switch_enabled) { 2999*5b9c547cSRui Paulo wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for " 3000*5b9c547cSRui Paulo MACSTR, MAC2STR(addr)); 3001*5b9c547cSRui Paulo return -1; 3002*5b9c547cSRui Paulo } 3003*5b9c547cSRui Paulo 3004*5b9c547cSRui Paulo /* ignore the return value */ 3005*5b9c547cSRui Paulo wpa_sm_tdls_disable_channel_switch(sm, peer->addr); 3006*5b9c547cSRui Paulo 3007*5b9c547cSRui Paulo peer->chan_switch_enabled = 0; 3008*5b9c547cSRui Paulo return 0; 3009*5b9c547cSRui Paulo } 3010