1*f05cddf9SRui Paulo /* 2*f05cddf9SRui Paulo * wpa_supplicant - TDLS 3*f05cddf9SRui Paulo * Copyright (c) 2010-2011, Atheros Communications 4*f05cddf9SRui Paulo * 5*f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6*f05cddf9SRui Paulo * See README for more details. 7*f05cddf9SRui Paulo */ 8*f05cddf9SRui Paulo 9*f05cddf9SRui Paulo #include "utils/includes.h" 10*f05cddf9SRui Paulo 11*f05cddf9SRui Paulo #include "utils/common.h" 12*f05cddf9SRui Paulo #include "utils/eloop.h" 13*f05cddf9SRui Paulo #include "utils/os.h" 14*f05cddf9SRui Paulo #include "common/ieee802_11_defs.h" 15*f05cddf9SRui Paulo #include "crypto/sha256.h" 16*f05cddf9SRui Paulo #include "crypto/crypto.h" 17*f05cddf9SRui Paulo #include "crypto/aes_wrap.h" 18*f05cddf9SRui Paulo #include "rsn_supp/wpa.h" 19*f05cddf9SRui Paulo #include "rsn_supp/wpa_ie.h" 20*f05cddf9SRui Paulo #include "rsn_supp/wpa_i.h" 21*f05cddf9SRui Paulo #include "drivers/driver.h" 22*f05cddf9SRui Paulo #include "l2_packet/l2_packet.h" 23*f05cddf9SRui Paulo 24*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 25*f05cddf9SRui Paulo #define TDLS_TESTING_LONG_FRAME BIT(0) 26*f05cddf9SRui Paulo #define TDLS_TESTING_ALT_RSN_IE BIT(1) 27*f05cddf9SRui Paulo #define TDLS_TESTING_DIFF_BSSID BIT(2) 28*f05cddf9SRui Paulo #define TDLS_TESTING_SHORT_LIFETIME BIT(3) 29*f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_RESP BIT(4) 30*f05cddf9SRui Paulo #define TDLS_TESTING_WRONG_LIFETIME_CONF BIT(5) 31*f05cddf9SRui Paulo #define TDLS_TESTING_LONG_LIFETIME BIT(6) 32*f05cddf9SRui Paulo #define TDLS_TESTING_CONCURRENT_INIT BIT(7) 33*f05cddf9SRui Paulo #define TDLS_TESTING_NO_TPK_EXPIRATION BIT(8) 34*f05cddf9SRui Paulo #define TDLS_TESTING_DECLINE_RESP BIT(9) 35*f05cddf9SRui Paulo #define TDLS_TESTING_IGNORE_AP_PROHIBIT BIT(10) 36*f05cddf9SRui Paulo unsigned int tdls_testing = 0; 37*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 38*f05cddf9SRui Paulo 39*f05cddf9SRui Paulo #define TPK_LIFETIME 43200 /* 12 hours */ 40*f05cddf9SRui Paulo #define TPK_RETRY_COUNT 3 41*f05cddf9SRui Paulo #define TPK_TIMEOUT 5000 /* in milliseconds */ 42*f05cddf9SRui Paulo 43*f05cddf9SRui Paulo #define TDLS_MIC_LEN 16 44*f05cddf9SRui Paulo 45*f05cddf9SRui Paulo #define TDLS_TIMEOUT_LEN 4 46*f05cddf9SRui Paulo 47*f05cddf9SRui Paulo struct wpa_tdls_ftie { 48*f05cddf9SRui Paulo u8 ie_type; /* FTIE */ 49*f05cddf9SRui Paulo u8 ie_len; 50*f05cddf9SRui Paulo u8 mic_ctrl[2]; 51*f05cddf9SRui Paulo u8 mic[TDLS_MIC_LEN]; 52*f05cddf9SRui Paulo u8 Anonce[WPA_NONCE_LEN]; /* Responder Nonce in TDLS */ 53*f05cddf9SRui Paulo u8 Snonce[WPA_NONCE_LEN]; /* Initiator Nonce in TDLS */ 54*f05cddf9SRui Paulo /* followed by optional elements */ 55*f05cddf9SRui Paulo } STRUCT_PACKED; 56*f05cddf9SRui Paulo 57*f05cddf9SRui Paulo struct wpa_tdls_timeoutie { 58*f05cddf9SRui Paulo u8 ie_type; /* Timeout IE */ 59*f05cddf9SRui Paulo u8 ie_len; 60*f05cddf9SRui Paulo u8 interval_type; 61*f05cddf9SRui Paulo u8 value[TDLS_TIMEOUT_LEN]; 62*f05cddf9SRui Paulo } STRUCT_PACKED; 63*f05cddf9SRui Paulo 64*f05cddf9SRui Paulo struct wpa_tdls_lnkid { 65*f05cddf9SRui Paulo u8 ie_type; /* Link Identifier IE */ 66*f05cddf9SRui Paulo u8 ie_len; 67*f05cddf9SRui Paulo u8 bssid[ETH_ALEN]; 68*f05cddf9SRui Paulo u8 init_sta[ETH_ALEN]; 69*f05cddf9SRui Paulo u8 resp_sta[ETH_ALEN]; 70*f05cddf9SRui Paulo } STRUCT_PACKED; 71*f05cddf9SRui Paulo 72*f05cddf9SRui Paulo /* TDLS frame headers as per IEEE Std 802.11z-2010 */ 73*f05cddf9SRui Paulo struct wpa_tdls_frame { 74*f05cddf9SRui Paulo u8 payloadtype; /* IEEE80211_TDLS_RFTYPE */ 75*f05cddf9SRui Paulo u8 category; /* Category */ 76*f05cddf9SRui Paulo u8 action; /* Action (enum tdls_frame_type) */ 77*f05cddf9SRui Paulo } STRUCT_PACKED; 78*f05cddf9SRui Paulo 79*f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs); 80*f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx); 81*f05cddf9SRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer); 82*f05cddf9SRui Paulo 83*f05cddf9SRui Paulo 84*f05cddf9SRui Paulo #define TDLS_MAX_IE_LEN 80 85*f05cddf9SRui Paulo #define IEEE80211_MAX_SUPP_RATES 32 86*f05cddf9SRui Paulo 87*f05cddf9SRui Paulo struct wpa_tdls_peer { 88*f05cddf9SRui Paulo struct wpa_tdls_peer *next; 89*f05cddf9SRui Paulo int initiator; /* whether this end was initiator for TDLS setup */ 90*f05cddf9SRui Paulo u8 addr[ETH_ALEN]; /* other end MAC address */ 91*f05cddf9SRui Paulo u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */ 92*f05cddf9SRui Paulo u8 rnonce[WPA_NONCE_LEN]; /* Responder Nonce */ 93*f05cddf9SRui Paulo u8 rsnie_i[TDLS_MAX_IE_LEN]; /* Initiator RSN IE */ 94*f05cddf9SRui Paulo size_t rsnie_i_len; 95*f05cddf9SRui Paulo u8 rsnie_p[TDLS_MAX_IE_LEN]; /* Peer RSN IE */ 96*f05cddf9SRui Paulo size_t rsnie_p_len; 97*f05cddf9SRui Paulo u32 lifetime; 98*f05cddf9SRui Paulo int cipher; /* Selected cipher (WPA_CIPHER_*) */ 99*f05cddf9SRui Paulo u8 dtoken; 100*f05cddf9SRui Paulo 101*f05cddf9SRui Paulo struct tpk { 102*f05cddf9SRui Paulo u8 kck[16]; /* TPK-KCK */ 103*f05cddf9SRui Paulo u8 tk[16]; /* TPK-TK; assuming only CCMP will be used */ 104*f05cddf9SRui Paulo } tpk; 105*f05cddf9SRui Paulo int tpk_set; 106*f05cddf9SRui Paulo int tpk_success; 107*f05cddf9SRui Paulo 108*f05cddf9SRui Paulo struct tpk_timer { 109*f05cddf9SRui Paulo u8 dest[ETH_ALEN]; 110*f05cddf9SRui Paulo int count; /* Retry Count */ 111*f05cddf9SRui Paulo int timer; /* Timeout in milliseconds */ 112*f05cddf9SRui Paulo u8 action_code; /* TDLS frame type */ 113*f05cddf9SRui Paulo u8 dialog_token; 114*f05cddf9SRui Paulo u16 status_code; 115*f05cddf9SRui Paulo int buf_len; /* length of TPK message for retransmission */ 116*f05cddf9SRui Paulo u8 *buf; /* buffer for TPK message */ 117*f05cddf9SRui Paulo } sm_tmr; 118*f05cddf9SRui Paulo 119*f05cddf9SRui Paulo u16 capability; 120*f05cddf9SRui Paulo 121*f05cddf9SRui Paulo u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 122*f05cddf9SRui Paulo size_t supp_rates_len; 123*f05cddf9SRui Paulo }; 124*f05cddf9SRui Paulo 125*f05cddf9SRui Paulo 126*f05cddf9SRui Paulo static int wpa_tdls_get_privacy(struct wpa_sm *sm) 127*f05cddf9SRui Paulo { 128*f05cddf9SRui Paulo /* 129*f05cddf9SRui Paulo * Get info needed from supplicant to check if the current BSS supports 130*f05cddf9SRui Paulo * security. Other than OPEN mode, rest are considered secured 131*f05cddf9SRui Paulo * WEP/WPA/WPA2 hence TDLS frames are processed for TPK handshake. 132*f05cddf9SRui Paulo */ 133*f05cddf9SRui Paulo return sm->pairwise_cipher != WPA_CIPHER_NONE; 134*f05cddf9SRui Paulo } 135*f05cddf9SRui Paulo 136*f05cddf9SRui Paulo 137*f05cddf9SRui Paulo static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) 138*f05cddf9SRui Paulo { 139*f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 140*f05cddf9SRui Paulo return pos + ie_len; 141*f05cddf9SRui Paulo } 142*f05cddf9SRui Paulo 143*f05cddf9SRui Paulo 144*f05cddf9SRui Paulo static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 145*f05cddf9SRui Paulo { 146*f05cddf9SRui Paulo if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr, 147*f05cddf9SRui Paulo 0, 0, NULL, 0, NULL, 0) < 0) { 148*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from " 149*f05cddf9SRui Paulo "the driver"); 150*f05cddf9SRui Paulo return -1; 151*f05cddf9SRui Paulo } 152*f05cddf9SRui Paulo 153*f05cddf9SRui Paulo return 0; 154*f05cddf9SRui Paulo } 155*f05cddf9SRui Paulo 156*f05cddf9SRui Paulo 157*f05cddf9SRui Paulo static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 158*f05cddf9SRui Paulo { 159*f05cddf9SRui Paulo u8 key_len; 160*f05cddf9SRui Paulo u8 rsc[6]; 161*f05cddf9SRui Paulo enum wpa_alg alg; 162*f05cddf9SRui Paulo 163*f05cddf9SRui Paulo os_memset(rsc, 0, 6); 164*f05cddf9SRui Paulo 165*f05cddf9SRui Paulo switch (peer->cipher) { 166*f05cddf9SRui Paulo case WPA_CIPHER_CCMP: 167*f05cddf9SRui Paulo alg = WPA_ALG_CCMP; 168*f05cddf9SRui Paulo key_len = 16; 169*f05cddf9SRui Paulo break; 170*f05cddf9SRui Paulo case WPA_CIPHER_NONE: 171*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Pairwise Cipher Suite: " 172*f05cddf9SRui Paulo "NONE - do not use pairwise keys"); 173*f05cddf9SRui Paulo return -1; 174*f05cddf9SRui Paulo default: 175*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Unsupported pairwise cipher %d", 176*f05cddf9SRui Paulo sm->pairwise_cipher); 177*f05cddf9SRui Paulo return -1; 178*f05cddf9SRui Paulo } 179*f05cddf9SRui Paulo 180*f05cddf9SRui Paulo if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, 181*f05cddf9SRui Paulo rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) { 182*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the " 183*f05cddf9SRui Paulo "driver"); 184*f05cddf9SRui Paulo return -1; 185*f05cddf9SRui Paulo } 186*f05cddf9SRui Paulo return 0; 187*f05cddf9SRui Paulo } 188*f05cddf9SRui Paulo 189*f05cddf9SRui Paulo 190*f05cddf9SRui Paulo static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, 191*f05cddf9SRui Paulo u8 action_code, u8 dialog_token, 192*f05cddf9SRui Paulo u16 status_code, const u8 *buf, size_t len) 193*f05cddf9SRui Paulo { 194*f05cddf9SRui Paulo return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, 195*f05cddf9SRui Paulo status_code, buf, len); 196*f05cddf9SRui Paulo } 197*f05cddf9SRui Paulo 198*f05cddf9SRui Paulo 199*f05cddf9SRui Paulo static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, 200*f05cddf9SRui Paulo u8 dialog_token, u16 status_code, 201*f05cddf9SRui Paulo const u8 *msg, size_t msg_len) 202*f05cddf9SRui Paulo { 203*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 204*f05cddf9SRui Paulo 205*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " 206*f05cddf9SRui Paulo "dialog_token=%u status_code=%u msg_len=%u", 207*f05cddf9SRui Paulo MAC2STR(dest), action_code, dialog_token, status_code, 208*f05cddf9SRui Paulo (unsigned int) msg_len); 209*f05cddf9SRui Paulo 210*f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, 211*f05cddf9SRui Paulo status_code, msg, msg_len)) { 212*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to send message " 213*f05cddf9SRui Paulo "(action_code=%u)", action_code); 214*f05cddf9SRui Paulo return -1; 215*f05cddf9SRui Paulo } 216*f05cddf9SRui Paulo 217*f05cddf9SRui Paulo if (action_code == WLAN_TDLS_SETUP_CONFIRM || 218*f05cddf9SRui Paulo action_code == WLAN_TDLS_TEARDOWN || 219*f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_REQUEST || 220*f05cddf9SRui Paulo action_code == WLAN_TDLS_DISCOVERY_RESPONSE) 221*f05cddf9SRui Paulo return 0; /* No retries */ 222*f05cddf9SRui Paulo 223*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 224*f05cddf9SRui Paulo if (os_memcmp(peer->addr, dest, ETH_ALEN) == 0) 225*f05cddf9SRui Paulo break; 226*f05cddf9SRui Paulo } 227*f05cddf9SRui Paulo 228*f05cddf9SRui Paulo if (peer == NULL) { 229*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 230*f05cddf9SRui Paulo "retry " MACSTR, MAC2STR(dest)); 231*f05cddf9SRui Paulo return 0; 232*f05cddf9SRui Paulo } 233*f05cddf9SRui Paulo 234*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 235*f05cddf9SRui Paulo 236*f05cddf9SRui Paulo peer->sm_tmr.count = TPK_RETRY_COUNT; 237*f05cddf9SRui Paulo peer->sm_tmr.timer = TPK_TIMEOUT; 238*f05cddf9SRui Paulo 239*f05cddf9SRui Paulo /* Copy message to resend on timeout */ 240*f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN); 241*f05cddf9SRui Paulo peer->sm_tmr.action_code = action_code; 242*f05cddf9SRui Paulo peer->sm_tmr.dialog_token = dialog_token; 243*f05cddf9SRui Paulo peer->sm_tmr.status_code = status_code; 244*f05cddf9SRui Paulo peer->sm_tmr.buf_len = msg_len; 245*f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 246*f05cddf9SRui Paulo peer->sm_tmr.buf = os_malloc(msg_len); 247*f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) 248*f05cddf9SRui Paulo return -1; 249*f05cddf9SRui Paulo os_memcpy(peer->sm_tmr.buf, msg, msg_len); 250*f05cddf9SRui Paulo 251*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered " 252*f05cddf9SRui Paulo "(action_code=%u)", action_code); 253*f05cddf9SRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, 254*f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 255*f05cddf9SRui Paulo return 0; 256*f05cddf9SRui Paulo } 257*f05cddf9SRui Paulo 258*f05cddf9SRui Paulo 259*f05cddf9SRui Paulo static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 260*f05cddf9SRui Paulo u16 reason_code, int free_peer) 261*f05cddf9SRui Paulo { 262*f05cddf9SRui Paulo int ret; 263*f05cddf9SRui Paulo 264*f05cddf9SRui Paulo if (sm->tdls_external_setup) { 265*f05cddf9SRui Paulo ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code); 266*f05cddf9SRui Paulo 267*f05cddf9SRui Paulo /* disable the link after teardown was sent */ 268*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 269*f05cddf9SRui Paulo } else { 270*f05cddf9SRui Paulo ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); 271*f05cddf9SRui Paulo } 272*f05cddf9SRui Paulo 273*f05cddf9SRui Paulo if (sm->tdls_external_setup || free_peer) 274*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 275*f05cddf9SRui Paulo 276*f05cddf9SRui Paulo return ret; 277*f05cddf9SRui Paulo } 278*f05cddf9SRui Paulo 279*f05cddf9SRui Paulo 280*f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) 281*f05cddf9SRui Paulo { 282*f05cddf9SRui Paulo 283*f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 284*f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 285*f05cddf9SRui Paulo 286*f05cddf9SRui Paulo if (peer->sm_tmr.count) { 287*f05cddf9SRui Paulo peer->sm_tmr.count--; 288*f05cddf9SRui Paulo peer->sm_tmr.timer = TPK_TIMEOUT; 289*f05cddf9SRui Paulo 290*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Retrying sending of message " 291*f05cddf9SRui Paulo "(action_code=%u)", 292*f05cddf9SRui Paulo peer->sm_tmr.action_code); 293*f05cddf9SRui Paulo 294*f05cddf9SRui Paulo if (peer->sm_tmr.buf == NULL) { 295*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No retry buffer available " 296*f05cddf9SRui Paulo "for action_code=%u", 297*f05cddf9SRui Paulo peer->sm_tmr.action_code); 298*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, 299*f05cddf9SRui Paulo peer); 300*f05cddf9SRui Paulo return; 301*f05cddf9SRui Paulo } 302*f05cddf9SRui Paulo 303*f05cddf9SRui Paulo /* resend TPK Handshake Message to Peer */ 304*f05cddf9SRui Paulo if (wpa_tdls_send_tpk_msg(sm, peer->sm_tmr.dest, 305*f05cddf9SRui Paulo peer->sm_tmr.action_code, 306*f05cddf9SRui Paulo peer->sm_tmr.dialog_token, 307*f05cddf9SRui Paulo peer->sm_tmr.status_code, 308*f05cddf9SRui Paulo peer->sm_tmr.buf, 309*f05cddf9SRui Paulo peer->sm_tmr.buf_len)) { 310*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to retry " 311*f05cddf9SRui Paulo "transmission"); 312*f05cddf9SRui Paulo } 313*f05cddf9SRui Paulo 314*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 315*f05cddf9SRui Paulo eloop_register_timeout(peer->sm_tmr.timer / 1000, 0, 316*f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout, sm, peer); 317*f05cddf9SRui Paulo } else { 318*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 319*f05cddf9SRui Paulo 320*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request"); 321*f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 322*f05cddf9SRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1); 323*f05cddf9SRui Paulo } 324*f05cddf9SRui Paulo } 325*f05cddf9SRui Paulo 326*f05cddf9SRui Paulo 327*f05cddf9SRui Paulo static void wpa_tdls_tpk_retry_timeout_cancel(struct wpa_sm *sm, 328*f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 329*f05cddf9SRui Paulo u8 action_code) 330*f05cddf9SRui Paulo { 331*f05cddf9SRui Paulo if (action_code == peer->sm_tmr.action_code) { 332*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Retry timeout cancelled for " 333*f05cddf9SRui Paulo "action_code=%u", action_code); 334*f05cddf9SRui Paulo 335*f05cddf9SRui Paulo /* Cancel Timeout registered */ 336*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 337*f05cddf9SRui Paulo 338*f05cddf9SRui Paulo /* free all resources meant for retry */ 339*f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 340*f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 341*f05cddf9SRui Paulo 342*f05cddf9SRui Paulo peer->sm_tmr.count = 0; 343*f05cddf9SRui Paulo peer->sm_tmr.timer = 0; 344*f05cddf9SRui Paulo peer->sm_tmr.buf_len = 0; 345*f05cddf9SRui Paulo peer->sm_tmr.action_code = 0xff; 346*f05cddf9SRui Paulo } else { 347*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Error in cancelling retry timeout " 348*f05cddf9SRui Paulo "(Unknown action_code=%u)", action_code); 349*f05cddf9SRui Paulo } 350*f05cddf9SRui Paulo } 351*f05cddf9SRui Paulo 352*f05cddf9SRui Paulo 353*f05cddf9SRui Paulo static void wpa_tdls_generate_tpk(struct wpa_tdls_peer *peer, 354*f05cddf9SRui Paulo const u8 *own_addr, const u8 *bssid) 355*f05cddf9SRui Paulo { 356*f05cddf9SRui Paulo u8 key_input[SHA256_MAC_LEN]; 357*f05cddf9SRui Paulo const u8 *nonce[2]; 358*f05cddf9SRui Paulo size_t len[2]; 359*f05cddf9SRui Paulo u8 data[3 * ETH_ALEN]; 360*f05cddf9SRui Paulo 361*f05cddf9SRui Paulo /* IEEE Std 802.11z-2010 8.5.9.1: 362*f05cddf9SRui Paulo * TPK-Key-Input = SHA-256(min(SNonce, ANonce) || max(SNonce, ANonce)) 363*f05cddf9SRui Paulo */ 364*f05cddf9SRui Paulo len[0] = WPA_NONCE_LEN; 365*f05cddf9SRui Paulo len[1] = WPA_NONCE_LEN; 366*f05cddf9SRui Paulo if (os_memcmp(peer->inonce, peer->rnonce, WPA_NONCE_LEN) < 0) { 367*f05cddf9SRui Paulo nonce[0] = peer->inonce; 368*f05cddf9SRui Paulo nonce[1] = peer->rnonce; 369*f05cddf9SRui Paulo } else { 370*f05cddf9SRui Paulo nonce[0] = peer->rnonce; 371*f05cddf9SRui Paulo nonce[1] = peer->inonce; 372*f05cddf9SRui Paulo } 373*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: min(Nonce)", nonce[0], WPA_NONCE_LEN); 374*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: max(Nonce)", nonce[1], WPA_NONCE_LEN); 375*f05cddf9SRui Paulo sha256_vector(2, nonce, len, key_input); 376*f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-Key-Input", 377*f05cddf9SRui Paulo key_input, SHA256_MAC_LEN); 378*f05cddf9SRui Paulo 379*f05cddf9SRui Paulo /* 380*f05cddf9SRui Paulo * TPK-Key-Data = KDF-N_KEY(TPK-Key-Input, "TDLS PMK", 381*f05cddf9SRui Paulo * min(MAC_I, MAC_R) || max(MAC_I, MAC_R) || BSSID || N_KEY) 382*f05cddf9SRui Paulo * TODO: is N_KEY really included in KDF Context and if so, in which 383*f05cddf9SRui Paulo * presentation format (little endian 16-bit?) is it used? It gets 384*f05cddf9SRui Paulo * added by the KDF anyway.. 385*f05cddf9SRui Paulo */ 386*f05cddf9SRui Paulo 387*f05cddf9SRui Paulo if (os_memcmp(own_addr, peer->addr, ETH_ALEN) < 0) { 388*f05cddf9SRui Paulo os_memcpy(data, own_addr, ETH_ALEN); 389*f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, peer->addr, ETH_ALEN); 390*f05cddf9SRui Paulo } else { 391*f05cddf9SRui Paulo os_memcpy(data, peer->addr, ETH_ALEN); 392*f05cddf9SRui Paulo os_memcpy(data + ETH_ALEN, own_addr, ETH_ALEN); 393*f05cddf9SRui Paulo } 394*f05cddf9SRui Paulo os_memcpy(data + 2 * ETH_ALEN, bssid, ETH_ALEN); 395*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: KDF Context", data, sizeof(data)); 396*f05cddf9SRui Paulo 397*f05cddf9SRui Paulo sha256_prf(key_input, SHA256_MAC_LEN, "TDLS PMK", data, sizeof(data), 398*f05cddf9SRui Paulo (u8 *) &peer->tpk, sizeof(peer->tpk)); 399*f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-KCK", 400*f05cddf9SRui Paulo peer->tpk.kck, sizeof(peer->tpk.kck)); 401*f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: TPK-TK", 402*f05cddf9SRui Paulo peer->tpk.tk, sizeof(peer->tpk.tk)); 403*f05cddf9SRui Paulo peer->tpk_set = 1; 404*f05cddf9SRui Paulo } 405*f05cddf9SRui Paulo 406*f05cddf9SRui Paulo 407*f05cddf9SRui Paulo /** 408*f05cddf9SRui Paulo * wpa_tdls_ftie_mic - Calculate TDLS FTIE MIC 409*f05cddf9SRui Paulo * @kck: TPK-KCK 410*f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 411*f05cddf9SRui Paulo * @rsnie: Pointer to the beginning of RSN IE used for handshake 412*f05cddf9SRui Paulo * @timeoutie: Pointer to the beginning of Timeout IE used for handshake 413*f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 414*f05cddf9SRui Paulo * @mic: Pointer for writing MIC 415*f05cddf9SRui Paulo * 416*f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 417*f05cddf9SRui Paulo */ 418*f05cddf9SRui Paulo static int wpa_tdls_ftie_mic(const u8 *kck, u8 trans_seq, const u8 *lnkid, 419*f05cddf9SRui Paulo const u8 *rsnie, const u8 *timeoutie, 420*f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 421*f05cddf9SRui Paulo { 422*f05cddf9SRui Paulo u8 *buf, *pos; 423*f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 424*f05cddf9SRui Paulo const struct wpa_tdls_lnkid *_lnkid; 425*f05cddf9SRui Paulo int ret; 426*f05cddf9SRui Paulo int len = 2 * ETH_ALEN + 1 + 2 + lnkid[1] + 2 + rsnie[1] + 427*f05cddf9SRui Paulo 2 + timeoutie[1] + 2 + ftie[1]; 428*f05cddf9SRui Paulo buf = os_zalloc(len); 429*f05cddf9SRui Paulo if (!buf) { 430*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 431*f05cddf9SRui Paulo return -1; 432*f05cddf9SRui Paulo } 433*f05cddf9SRui Paulo 434*f05cddf9SRui Paulo pos = buf; 435*f05cddf9SRui Paulo _lnkid = (const struct wpa_tdls_lnkid *) lnkid; 436*f05cddf9SRui Paulo /* 1) TDLS initiator STA MAC address */ 437*f05cddf9SRui Paulo os_memcpy(pos, _lnkid->init_sta, ETH_ALEN); 438*f05cddf9SRui Paulo pos += ETH_ALEN; 439*f05cddf9SRui Paulo /* 2) TDLS responder STA MAC address */ 440*f05cddf9SRui Paulo os_memcpy(pos, _lnkid->resp_sta, ETH_ALEN); 441*f05cddf9SRui Paulo pos += ETH_ALEN; 442*f05cddf9SRui Paulo /* 3) Transaction Sequence number */ 443*f05cddf9SRui Paulo *pos++ = trans_seq; 444*f05cddf9SRui Paulo /* 4) Link Identifier IE */ 445*f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 446*f05cddf9SRui Paulo pos += 2 + lnkid[1]; 447*f05cddf9SRui Paulo /* 5) RSN IE */ 448*f05cddf9SRui Paulo os_memcpy(pos, rsnie, 2 + rsnie[1]); 449*f05cddf9SRui Paulo pos += 2 + rsnie[1]; 450*f05cddf9SRui Paulo /* 6) Timeout Interval IE */ 451*f05cddf9SRui Paulo os_memcpy(pos, timeoutie, 2 + timeoutie[1]); 452*f05cddf9SRui Paulo pos += 2 + timeoutie[1]; 453*f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 454*f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 455*f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 456*f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 457*f05cddf9SRui Paulo pos += 2 + ftie[1]; 458*f05cddf9SRui Paulo 459*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 460*f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 461*f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 462*f05cddf9SRui Paulo os_free(buf); 463*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 464*f05cddf9SRui Paulo return ret; 465*f05cddf9SRui Paulo } 466*f05cddf9SRui Paulo 467*f05cddf9SRui Paulo 468*f05cddf9SRui Paulo /** 469*f05cddf9SRui Paulo * wpa_tdls_key_mic_teardown - Calculate TDLS FTIE MIC for Teardown frame 470*f05cddf9SRui Paulo * @kck: TPK-KCK 471*f05cddf9SRui Paulo * @trans_seq: Transaction Sequence Number (4 - Teardown) 472*f05cddf9SRui Paulo * @rcode: Reason code for Teardown 473*f05cddf9SRui Paulo * @dtoken: Dialog Token used for that particular link 474*f05cddf9SRui Paulo * @lnkid: Pointer to the beginning of Link Identifier IE 475*f05cddf9SRui Paulo * @ftie: Pointer to the beginning of FT IE 476*f05cddf9SRui Paulo * @mic: Pointer for writing MIC 477*f05cddf9SRui Paulo * 478*f05cddf9SRui Paulo * Calculate MIC for TDLS frame. 479*f05cddf9SRui Paulo */ 480*f05cddf9SRui Paulo static int wpa_tdls_key_mic_teardown(const u8 *kck, u8 trans_seq, u16 rcode, 481*f05cddf9SRui Paulo u8 dtoken, const u8 *lnkid, 482*f05cddf9SRui Paulo const u8 *ftie, u8 *mic) 483*f05cddf9SRui Paulo { 484*f05cddf9SRui Paulo u8 *buf, *pos; 485*f05cddf9SRui Paulo struct wpa_tdls_ftie *_ftie; 486*f05cddf9SRui Paulo int ret; 487*f05cddf9SRui Paulo int len; 488*f05cddf9SRui Paulo 489*f05cddf9SRui Paulo if (lnkid == NULL) 490*f05cddf9SRui Paulo return -1; 491*f05cddf9SRui Paulo 492*f05cddf9SRui Paulo len = 2 + lnkid[1] + sizeof(rcode) + sizeof(dtoken) + 493*f05cddf9SRui Paulo sizeof(trans_seq) + 2 + ftie[1]; 494*f05cddf9SRui Paulo 495*f05cddf9SRui Paulo buf = os_zalloc(len); 496*f05cddf9SRui Paulo if (!buf) { 497*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: No memory for MIC calculation"); 498*f05cddf9SRui Paulo return -1; 499*f05cddf9SRui Paulo } 500*f05cddf9SRui Paulo 501*f05cddf9SRui Paulo pos = buf; 502*f05cddf9SRui Paulo /* 1) Link Identifier IE */ 503*f05cddf9SRui Paulo os_memcpy(pos, lnkid, 2 + lnkid[1]); 504*f05cddf9SRui Paulo pos += 2 + lnkid[1]; 505*f05cddf9SRui Paulo /* 2) Reason Code */ 506*f05cddf9SRui Paulo WPA_PUT_LE16(pos, rcode); 507*f05cddf9SRui Paulo pos += sizeof(rcode); 508*f05cddf9SRui Paulo /* 3) Dialog token */ 509*f05cddf9SRui Paulo *pos++ = dtoken; 510*f05cddf9SRui Paulo /* 4) Transaction Sequence number */ 511*f05cddf9SRui Paulo *pos++ = trans_seq; 512*f05cddf9SRui Paulo /* 7) FTIE, with the MIC field of the FTIE set to 0 */ 513*f05cddf9SRui Paulo os_memcpy(pos, ftie, 2 + ftie[1]); 514*f05cddf9SRui Paulo _ftie = (struct wpa_tdls_ftie *) pos; 515*f05cddf9SRui Paulo os_memset(_ftie->mic, 0, TDLS_MIC_LEN); 516*f05cddf9SRui Paulo pos += 2 + ftie[1]; 517*f05cddf9SRui Paulo 518*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Data for FTIE MIC", buf, pos - buf); 519*f05cddf9SRui Paulo wpa_hexdump_key(MSG_DEBUG, "TDLS: KCK", kck, 16); 520*f05cddf9SRui Paulo ret = omac1_aes_128(kck, buf, pos - buf, mic); 521*f05cddf9SRui Paulo os_free(buf); 522*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE MIC", mic, 16); 523*f05cddf9SRui Paulo return ret; 524*f05cddf9SRui Paulo } 525*f05cddf9SRui Paulo 526*f05cddf9SRui Paulo 527*f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, 528*f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 529*f05cddf9SRui Paulo const u8 *lnkid, const u8 *timeoutie, 530*f05cddf9SRui Paulo const struct wpa_tdls_ftie *ftie) 531*f05cddf9SRui Paulo { 532*f05cddf9SRui Paulo u8 mic[16]; 533*f05cddf9SRui Paulo 534*f05cddf9SRui Paulo if (peer->tpk_set) { 535*f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, 536*f05cddf9SRui Paulo peer->rsnie_p, timeoutie, (u8 *) ftie, 537*f05cddf9SRui Paulo mic); 538*f05cddf9SRui Paulo if (os_memcmp(mic, ftie->mic, 16) != 0) { 539*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " 540*f05cddf9SRui Paulo "dropping packet"); 541*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", 542*f05cddf9SRui Paulo ftie->mic, 16); 543*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Calculated MIC", 544*f05cddf9SRui Paulo mic, 16); 545*f05cddf9SRui Paulo return -1; 546*f05cddf9SRui Paulo } 547*f05cddf9SRui Paulo } else { 548*f05cddf9SRui Paulo wpa_printf(MSG_WARNING, "TDLS: Could not verify TDLS MIC, " 549*f05cddf9SRui Paulo "TPK not set - dropping packet"); 550*f05cddf9SRui Paulo return -1; 551*f05cddf9SRui Paulo } 552*f05cddf9SRui Paulo return 0; 553*f05cddf9SRui Paulo } 554*f05cddf9SRui Paulo 555*f05cddf9SRui Paulo 556*f05cddf9SRui Paulo static int wpa_supplicant_verify_tdls_mic_teardown( 557*f05cddf9SRui Paulo u8 trans_seq, u16 rcode, u8 dtoken, struct wpa_tdls_peer *peer, 558*f05cddf9SRui Paulo const u8 *lnkid, const struct wpa_tdls_ftie *ftie) 559*f05cddf9SRui Paulo { 560*f05cddf9SRui Paulo u8 mic[16]; 561*f05cddf9SRui Paulo 562*f05cddf9SRui Paulo if (peer->tpk_set) { 563*f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, 564*f05cddf9SRui Paulo dtoken, lnkid, (u8 *) ftie, mic); 565*f05cddf9SRui Paulo if (os_memcmp(mic, ftie->mic, 16) != 0) { 566*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " 567*f05cddf9SRui Paulo "dropping packet"); 568*f05cddf9SRui Paulo return -1; 569*f05cddf9SRui Paulo } 570*f05cddf9SRui Paulo } else { 571*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Could not verify TDLS Teardown " 572*f05cddf9SRui Paulo "MIC, TPK not set - dropping packet"); 573*f05cddf9SRui Paulo return -1; 574*f05cddf9SRui Paulo } 575*f05cddf9SRui Paulo return 0; 576*f05cddf9SRui Paulo } 577*f05cddf9SRui Paulo 578*f05cddf9SRui Paulo 579*f05cddf9SRui Paulo static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) 580*f05cddf9SRui Paulo { 581*f05cddf9SRui Paulo struct wpa_sm *sm = eloop_ctx; 582*f05cddf9SRui Paulo struct wpa_tdls_peer *peer = timeout_ctx; 583*f05cddf9SRui Paulo 584*f05cddf9SRui Paulo /* 585*f05cddf9SRui Paulo * On TPK lifetime expiration, we have an option of either tearing down 586*f05cddf9SRui Paulo * the direct link or trying to re-initiate it. The selection of what 587*f05cddf9SRui Paulo * to do is not strictly speaking controlled by our role in the expired 588*f05cddf9SRui Paulo * link, but for now, use that to select whether to renew or tear down 589*f05cddf9SRui Paulo * the link. 590*f05cddf9SRui Paulo */ 591*f05cddf9SRui Paulo 592*f05cddf9SRui Paulo if (peer->initiator) { 593*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 594*f05cddf9SRui Paulo " - try to renew", MAC2STR(peer->addr)); 595*f05cddf9SRui Paulo wpa_tdls_start(sm, peer->addr); 596*f05cddf9SRui Paulo } else { 597*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR 598*f05cddf9SRui Paulo " - tear down", MAC2STR(peer->addr)); 599*f05cddf9SRui Paulo wpa_tdls_do_teardown(sm, peer, 600*f05cddf9SRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1); 601*f05cddf9SRui Paulo } 602*f05cddf9SRui Paulo } 603*f05cddf9SRui Paulo 604*f05cddf9SRui Paulo 605*f05cddf9SRui Paulo static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 606*f05cddf9SRui Paulo { 607*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, 608*f05cddf9SRui Paulo MAC2STR(peer->addr)); 609*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 610*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer); 611*f05cddf9SRui Paulo peer->initiator = 0; 612*f05cddf9SRui Paulo os_free(peer->sm_tmr.buf); 613*f05cddf9SRui Paulo peer->sm_tmr.buf = NULL; 614*f05cddf9SRui Paulo peer->rsnie_i_len = peer->rsnie_p_len = 0; 615*f05cddf9SRui Paulo peer->cipher = 0; 616*f05cddf9SRui Paulo peer->tpk_set = peer->tpk_success = 0; 617*f05cddf9SRui Paulo os_memset(&peer->tpk, 0, sizeof(peer->tpk)); 618*f05cddf9SRui Paulo os_memset(peer->inonce, 0, WPA_NONCE_LEN); 619*f05cddf9SRui Paulo os_memset(peer->rnonce, 0, WPA_NONCE_LEN); 620*f05cddf9SRui Paulo } 621*f05cddf9SRui Paulo 622*f05cddf9SRui Paulo 623*f05cddf9SRui Paulo static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, 624*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid) 625*f05cddf9SRui Paulo { 626*f05cddf9SRui Paulo lnkid->ie_type = WLAN_EID_LINK_ID; 627*f05cddf9SRui Paulo lnkid->ie_len = 3 * ETH_ALEN; 628*f05cddf9SRui Paulo os_memcpy(lnkid->bssid, sm->bssid, ETH_ALEN); 629*f05cddf9SRui Paulo if (peer->initiator) { 630*f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, sm->own_addr, ETH_ALEN); 631*f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, peer->addr, ETH_ALEN); 632*f05cddf9SRui Paulo } else { 633*f05cddf9SRui Paulo os_memcpy(lnkid->init_sta, peer->addr, ETH_ALEN); 634*f05cddf9SRui Paulo os_memcpy(lnkid->resp_sta, sm->own_addr, ETH_ALEN); 635*f05cddf9SRui Paulo } 636*f05cddf9SRui Paulo } 637*f05cddf9SRui Paulo 638*f05cddf9SRui Paulo 639*f05cddf9SRui Paulo int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code) 640*f05cddf9SRui Paulo { 641*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 642*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 643*f05cddf9SRui Paulo struct wpa_tdls_lnkid lnkid; 644*f05cddf9SRui Paulo u8 dialog_token; 645*f05cddf9SRui Paulo u8 *rbuf, *pos; 646*f05cddf9SRui Paulo int ielen; 647*f05cddf9SRui Paulo 648*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 649*f05cddf9SRui Paulo return -1; 650*f05cddf9SRui Paulo 651*f05cddf9SRui Paulo /* Find the node and free from the list */ 652*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 653*f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 654*f05cddf9SRui Paulo break; 655*f05cddf9SRui Paulo } 656*f05cddf9SRui Paulo 657*f05cddf9SRui Paulo if (peer == NULL) { 658*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 659*f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(addr)); 660*f05cddf9SRui Paulo return 0; 661*f05cddf9SRui Paulo } 662*f05cddf9SRui Paulo 663*f05cddf9SRui Paulo dialog_token = peer->dtoken; 664*f05cddf9SRui Paulo 665*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR, 666*f05cddf9SRui Paulo MAC2STR(addr)); 667*f05cddf9SRui Paulo 668*f05cddf9SRui Paulo ielen = 0; 669*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && peer->tpk_set && peer->tpk_success) { 670*f05cddf9SRui Paulo /* To add FTIE for Teardown request and compute MIC */ 671*f05cddf9SRui Paulo ielen += sizeof(*ftie); 672*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 673*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 674*f05cddf9SRui Paulo ielen += 170; 675*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 676*f05cddf9SRui Paulo } 677*f05cddf9SRui Paulo 678*f05cddf9SRui Paulo rbuf = os_zalloc(ielen + 1); 679*f05cddf9SRui Paulo if (rbuf == NULL) 680*f05cddf9SRui Paulo return -1; 681*f05cddf9SRui Paulo pos = rbuf; 682*f05cddf9SRui Paulo 683*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 684*f05cddf9SRui Paulo goto skip_ies; 685*f05cddf9SRui Paulo 686*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 687*f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 688*f05cddf9SRui Paulo /* Using the recent nonce which should be for CONFIRM frame */ 689*f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 690*f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 691*f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 692*f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 693*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 694*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 695*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 696*f05cddf9SRui Paulo "FTIE"); 697*f05cddf9SRui Paulo ftie->ie_len += 170; 698*f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 699*f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 700*f05cddf9SRui Paulo pos += 168; 701*f05cddf9SRui Paulo } 702*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 703*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake", 704*f05cddf9SRui Paulo (u8 *) ftie, pos - (u8 *) ftie); 705*f05cddf9SRui Paulo 706*f05cddf9SRui Paulo /* compute MIC before sending */ 707*f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, &lnkid); 708*f05cddf9SRui Paulo wpa_tdls_key_mic_teardown(peer->tpk.kck, 4, reason_code, 709*f05cddf9SRui Paulo dialog_token, (u8 *) &lnkid, (u8 *) ftie, 710*f05cddf9SRui Paulo ftie->mic); 711*f05cddf9SRui Paulo 712*f05cddf9SRui Paulo skip_ies: 713*f05cddf9SRui Paulo /* TODO: register for a Timeout handler, if Teardown is not received at 714*f05cddf9SRui Paulo * the other end, then try again another time */ 715*f05cddf9SRui Paulo 716*f05cddf9SRui Paulo /* request driver to send Teardown using this FTIE */ 717*f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, 718*f05cddf9SRui Paulo WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, rbuf, 719*f05cddf9SRui Paulo pos - rbuf); 720*f05cddf9SRui Paulo os_free(rbuf); 721*f05cddf9SRui Paulo 722*f05cddf9SRui Paulo /* clear the Peerkey statemachine */ 723*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 724*f05cddf9SRui Paulo 725*f05cddf9SRui Paulo return 0; 726*f05cddf9SRui Paulo } 727*f05cddf9SRui Paulo 728*f05cddf9SRui Paulo 729*f05cddf9SRui Paulo int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code) 730*f05cddf9SRui Paulo { 731*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 732*f05cddf9SRui Paulo 733*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 734*f05cddf9SRui Paulo return -1; 735*f05cddf9SRui Paulo 736*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 737*f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 738*f05cddf9SRui Paulo break; 739*f05cddf9SRui Paulo } 740*f05cddf9SRui Paulo 741*f05cddf9SRui Paulo if (peer == NULL) { 742*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR 743*f05cddf9SRui Paulo " for link Teardown", MAC2STR(addr)); 744*f05cddf9SRui Paulo return -1; 745*f05cddf9SRui Paulo } 746*f05cddf9SRui Paulo 747*f05cddf9SRui Paulo if (!peer->tpk_success) { 748*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR 749*f05cddf9SRui Paulo " not connected - cannot Teardown link", MAC2STR(addr)); 750*f05cddf9SRui Paulo return -1; 751*f05cddf9SRui Paulo } 752*f05cddf9SRui Paulo 753*f05cddf9SRui Paulo return wpa_tdls_do_teardown(sm, peer, reason_code, 0); 754*f05cddf9SRui Paulo } 755*f05cddf9SRui Paulo 756*f05cddf9SRui Paulo 757*f05cddf9SRui Paulo void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr) 758*f05cddf9SRui Paulo { 759*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 760*f05cddf9SRui Paulo 761*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 762*f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 763*f05cddf9SRui Paulo break; 764*f05cddf9SRui Paulo } 765*f05cddf9SRui Paulo 766*f05cddf9SRui Paulo if (peer) { 767*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr); 768*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 769*f05cddf9SRui Paulo } 770*f05cddf9SRui Paulo } 771*f05cddf9SRui Paulo 772*f05cddf9SRui Paulo 773*f05cddf9SRui Paulo static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr, 774*f05cddf9SRui Paulo const u8 *buf, size_t len) 775*f05cddf9SRui Paulo { 776*f05cddf9SRui Paulo struct wpa_tdls_peer *peer = NULL; 777*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 778*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 779*f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 780*f05cddf9SRui Paulo u16 reason_code; 781*f05cddf9SRui Paulo const u8 *pos; 782*f05cddf9SRui Paulo int ielen; 783*f05cddf9SRui Paulo 784*f05cddf9SRui Paulo /* Find the node and free from the list */ 785*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 786*f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 787*f05cddf9SRui Paulo break; 788*f05cddf9SRui Paulo } 789*f05cddf9SRui Paulo 790*f05cddf9SRui Paulo if (peer == NULL) { 791*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching entry found for " 792*f05cddf9SRui Paulo "Teardown " MACSTR, MAC2STR(src_addr)); 793*f05cddf9SRui Paulo return 0; 794*f05cddf9SRui Paulo } 795*f05cddf9SRui Paulo 796*f05cddf9SRui Paulo pos = buf; 797*f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 798*f05cddf9SRui Paulo 799*f05cddf9SRui Paulo reason_code = WPA_GET_LE16(pos); 800*f05cddf9SRui Paulo pos += 2; 801*f05cddf9SRui Paulo 802*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown Request from " MACSTR 803*f05cddf9SRui Paulo " (reason code %u)", MAC2STR(src_addr), reason_code); 804*f05cddf9SRui Paulo 805*f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 806*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { 807*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in Teardown"); 808*f05cddf9SRui Paulo return -1; 809*f05cddf9SRui Paulo } 810*f05cddf9SRui Paulo 811*f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 812*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TDLS " 813*f05cddf9SRui Paulo "Teardown"); 814*f05cddf9SRui Paulo return -1; 815*f05cddf9SRui Paulo } 816*f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 817*f05cddf9SRui Paulo 818*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm) || !peer->tpk_set || !peer->tpk_success) 819*f05cddf9SRui Paulo goto skip_ftie; 820*f05cddf9SRui Paulo 821*f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 822*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TDLS Teardown"); 823*f05cddf9SRui Paulo return -1; 824*f05cddf9SRui Paulo } 825*f05cddf9SRui Paulo 826*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 827*f05cddf9SRui Paulo 828*f05cddf9SRui Paulo /* Process MIC check to see if TDLS Teardown is right */ 829*f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic_teardown(4, reason_code, 830*f05cddf9SRui Paulo peer->dtoken, peer, 831*f05cddf9SRui Paulo (u8 *) lnkid, ftie) < 0) { 832*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: MIC failure for TDLS " 833*f05cddf9SRui Paulo "Teardown Request from " MACSTR, MAC2STR(src_addr)); 834*f05cddf9SRui Paulo return -1; 835*f05cddf9SRui Paulo } 836*f05cddf9SRui Paulo 837*f05cddf9SRui Paulo skip_ftie: 838*f05cddf9SRui Paulo /* 839*f05cddf9SRui Paulo * Request the driver to disable the direct link and clear associated 840*f05cddf9SRui Paulo * keys. 841*f05cddf9SRui Paulo */ 842*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 843*f05cddf9SRui Paulo 844*f05cddf9SRui Paulo /* clear the Peerkey statemachine */ 845*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 846*f05cddf9SRui Paulo 847*f05cddf9SRui Paulo return 0; 848*f05cddf9SRui Paulo } 849*f05cddf9SRui Paulo 850*f05cddf9SRui Paulo 851*f05cddf9SRui Paulo /** 852*f05cddf9SRui Paulo * wpa_tdls_send_error - To send suitable TDLS status response with 853*f05cddf9SRui Paulo * appropriate status code mentioning reason for error/failure. 854*f05cddf9SRui Paulo * @dst - MAC addr of Peer station 855*f05cddf9SRui Paulo * @tdls_action - TDLS frame type for which error code is sent 856*f05cddf9SRui Paulo * @status - status code mentioning reason 857*f05cddf9SRui Paulo */ 858*f05cddf9SRui Paulo 859*f05cddf9SRui Paulo static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, 860*f05cddf9SRui Paulo u8 tdls_action, u8 dialog_token, u16 status) 861*f05cddf9SRui Paulo { 862*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR 863*f05cddf9SRui Paulo " (action=%u status=%u)", 864*f05cddf9SRui Paulo MAC2STR(dst), tdls_action, status); 865*f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, 866*f05cddf9SRui Paulo NULL, 0); 867*f05cddf9SRui Paulo } 868*f05cddf9SRui Paulo 869*f05cddf9SRui Paulo 870*f05cddf9SRui Paulo static struct wpa_tdls_peer * 871*f05cddf9SRui Paulo wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr) 872*f05cddf9SRui Paulo { 873*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 874*f05cddf9SRui Paulo 875*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR, 876*f05cddf9SRui Paulo MAC2STR(addr)); 877*f05cddf9SRui Paulo 878*f05cddf9SRui Paulo peer = os_zalloc(sizeof(*peer)); 879*f05cddf9SRui Paulo if (peer == NULL) 880*f05cddf9SRui Paulo return NULL; 881*f05cddf9SRui Paulo 882*f05cddf9SRui Paulo os_memcpy(peer->addr, addr, ETH_ALEN); 883*f05cddf9SRui Paulo peer->next = sm->tdls; 884*f05cddf9SRui Paulo sm->tdls = peer; 885*f05cddf9SRui Paulo 886*f05cddf9SRui Paulo return peer; 887*f05cddf9SRui Paulo } 888*f05cddf9SRui Paulo 889*f05cddf9SRui Paulo 890*f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm, 891*f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 892*f05cddf9SRui Paulo { 893*f05cddf9SRui Paulo size_t buf_len; 894*f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 895*f05cddf9SRui Paulo u16 rsn_capab; 896*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 897*f05cddf9SRui Paulo u8 *rbuf, *pos, *count_pos; 898*f05cddf9SRui Paulo u16 count; 899*f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 900*f05cddf9SRui Paulo 901*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 902*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No security used on the link"); 903*f05cddf9SRui Paulo peer->rsnie_i_len = 0; 904*f05cddf9SRui Paulo goto skip_rsnie; 905*f05cddf9SRui Paulo } 906*f05cddf9SRui Paulo 907*f05cddf9SRui Paulo /* 908*f05cddf9SRui Paulo * TPK Handshake Message 1: 909*f05cddf9SRui Paulo * FTIE: ANonce=0, SNonce=initiator nonce MIC=0, DataKDs=(RSNIE_I, 910*f05cddf9SRui Paulo * Timeout Interval IE)) 911*f05cddf9SRui Paulo */ 912*f05cddf9SRui Paulo 913*f05cddf9SRui Paulo /* Filling RSN IE */ 914*f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_i; 915*f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 916*f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, RSN_VERSION); 917*f05cddf9SRui Paulo 918*f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 919*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 920*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 921*f05cddf9SRui Paulo count_pos = pos; 922*f05cddf9SRui Paulo pos += 2; 923*f05cddf9SRui Paulo 924*f05cddf9SRui Paulo count = 0; 925*f05cddf9SRui Paulo 926*f05cddf9SRui Paulo /* 927*f05cddf9SRui Paulo * AES-CCMP is the default Encryption preferred for TDLS, so 928*f05cddf9SRui Paulo * RSN IE is filled only with CCMP CIPHER 929*f05cddf9SRui Paulo * Note: TKIP is not used to encrypt TDLS link. 930*f05cddf9SRui Paulo * 931*f05cddf9SRui Paulo * Regardless of the cipher used on the AP connection, select CCMP 932*f05cddf9SRui Paulo * here. 933*f05cddf9SRui Paulo */ 934*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 935*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 936*f05cddf9SRui Paulo count++; 937*f05cddf9SRui Paulo 938*f05cddf9SRui Paulo WPA_PUT_LE16(count_pos, count); 939*f05cddf9SRui Paulo 940*f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 941*f05cddf9SRui Paulo pos += 2; 942*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 943*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 944*f05cddf9SRui Paulo 945*f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 946*f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 947*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 948*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 949*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Use alternative RSN IE for " 950*f05cddf9SRui Paulo "testing"); 951*f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 952*f05cddf9SRui Paulo } 953*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 954*f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 955*f05cddf9SRui Paulo pos += 2; 956*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 957*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_ALT_RSN_IE) { 958*f05cddf9SRui Paulo /* Number of PMKIDs */ 959*f05cddf9SRui Paulo *pos++ = 0x00; 960*f05cddf9SRui Paulo *pos++ = 0x00; 961*f05cddf9SRui Paulo } 962*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 963*f05cddf9SRui Paulo 964*f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_i) - 2; 965*f05cddf9SRui Paulo peer->rsnie_i_len = pos - peer->rsnie_i; 966*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 967*f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 968*f05cddf9SRui Paulo 969*f05cddf9SRui Paulo skip_rsnie: 970*f05cddf9SRui Paulo buf_len = 0; 971*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) 972*f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 973*f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 974*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 975*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm) && 976*f05cddf9SRui Paulo (tdls_testing & TDLS_TESTING_LONG_FRAME)) 977*f05cddf9SRui Paulo buf_len += 170; 978*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) 979*f05cddf9SRui Paulo buf_len += sizeof(struct wpa_tdls_lnkid); 980*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 981*f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 982*f05cddf9SRui Paulo if (rbuf == NULL) { 983*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 984*f05cddf9SRui Paulo return -1; 985*f05cddf9SRui Paulo } 986*f05cddf9SRui Paulo pos = rbuf; 987*f05cddf9SRui Paulo 988*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 989*f05cddf9SRui Paulo goto skip_ies; 990*f05cddf9SRui Paulo 991*f05cddf9SRui Paulo /* Initiator RSN IE */ 992*f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); 993*f05cddf9SRui Paulo 994*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 995*f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 996*f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 997*f05cddf9SRui Paulo 998*f05cddf9SRui Paulo if (os_get_random(peer->inonce, WPA_NONCE_LEN)) { 999*f05cddf9SRui Paulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 1000*f05cddf9SRui Paulo "TDLS: Failed to get random data for initiator Nonce"); 1001*f05cddf9SRui Paulo os_free(rbuf); 1002*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1003*f05cddf9SRui Paulo return -1; 1004*f05cddf9SRui Paulo } 1005*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Initiator Nonce for TPK handshake", 1006*f05cddf9SRui Paulo peer->inonce, WPA_NONCE_LEN); 1007*f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1008*f05cddf9SRui Paulo 1009*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK Handshake M1", 1010*f05cddf9SRui Paulo (u8 *) ftie, sizeof(struct wpa_tdls_ftie)); 1011*f05cddf9SRui Paulo 1012*f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1013*f05cddf9SRui Paulo 1014*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1015*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1016*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1017*f05cddf9SRui Paulo "FTIE"); 1018*f05cddf9SRui Paulo ftie->ie_len += 170; 1019*f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1020*f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1021*f05cddf9SRui Paulo pos += 168; 1022*f05cddf9SRui Paulo } 1023*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1024*f05cddf9SRui Paulo 1025*f05cddf9SRui Paulo /* Lifetime */ 1026*f05cddf9SRui Paulo peer->lifetime = TPK_LIFETIME; 1027*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1028*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_SHORT_LIFETIME) { 1029*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use short TPK " 1030*f05cddf9SRui Paulo "lifetime"); 1031*f05cddf9SRui Paulo peer->lifetime = 301; 1032*f05cddf9SRui Paulo } 1033*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_LIFETIME) { 1034*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use long TPK " 1035*f05cddf9SRui Paulo "lifetime"); 1036*f05cddf9SRui Paulo peer->lifetime = 0xffffffff; 1037*f05cddf9SRui Paulo } 1038*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1039*f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1040*f05cddf9SRui Paulo sizeof(timeoutie), peer->lifetime); 1041*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); 1042*f05cddf9SRui Paulo 1043*f05cddf9SRui Paulo skip_ies: 1044*f05cddf9SRui Paulo 1045*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1046*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DIFF_BSSID) { 1047*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use incorrect BSSID in " 1048*f05cddf9SRui Paulo "Link Identifier"); 1049*f05cddf9SRui Paulo struct wpa_tdls_lnkid *l = (struct wpa_tdls_lnkid *) pos; 1050*f05cddf9SRui Paulo wpa_tdls_linkid(sm, peer, l); 1051*f05cddf9SRui Paulo l->bssid[5] ^= 0x01; 1052*f05cddf9SRui Paulo pos += sizeof(*l); 1053*f05cddf9SRui Paulo } 1054*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1055*f05cddf9SRui Paulo 1056*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Request / TPK " 1057*f05cddf9SRui Paulo "Handshake Message 1 (peer " MACSTR ")", 1058*f05cddf9SRui Paulo MAC2STR(peer->addr)); 1059*f05cddf9SRui Paulo 1060*f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0, 1061*f05cddf9SRui Paulo rbuf, pos - rbuf); 1062*f05cddf9SRui Paulo os_free(rbuf); 1063*f05cddf9SRui Paulo 1064*f05cddf9SRui Paulo return 0; 1065*f05cddf9SRui Paulo } 1066*f05cddf9SRui Paulo 1067*f05cddf9SRui Paulo 1068*f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, 1069*f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1070*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1071*f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1072*f05cddf9SRui Paulo { 1073*f05cddf9SRui Paulo u8 *rbuf, *pos; 1074*f05cddf9SRui Paulo size_t buf_len; 1075*f05cddf9SRui Paulo u32 lifetime; 1076*f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1077*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1078*f05cddf9SRui Paulo 1079*f05cddf9SRui Paulo buf_len = 0; 1080*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1081*f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1082*f05cddf9SRui Paulo * Lifetime */ 1083*f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1084*f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1085*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1086*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1087*f05cddf9SRui Paulo buf_len += 170; 1088*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1089*f05cddf9SRui Paulo } 1090*f05cddf9SRui Paulo 1091*f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1092*f05cddf9SRui Paulo if (rbuf == NULL) 1093*f05cddf9SRui Paulo return -1; 1094*f05cddf9SRui Paulo pos = rbuf; 1095*f05cddf9SRui Paulo 1096*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1097*f05cddf9SRui Paulo goto skip_ies; 1098*f05cddf9SRui Paulo 1099*f05cddf9SRui Paulo /* Peer RSN IE */ 1100*f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1101*f05cddf9SRui Paulo 1102*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1103*f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1104*f05cddf9SRui Paulo /* TODO: ftie->mic_control to set 2-RESPONSE */ 1105*f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1106*f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1107*f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1108*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TPK M2", 1109*f05cddf9SRui Paulo (u8 *) ftie, sizeof(*ftie)); 1110*f05cddf9SRui Paulo 1111*f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1112*f05cddf9SRui Paulo 1113*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1114*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1115*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1116*f05cddf9SRui Paulo "FTIE"); 1117*f05cddf9SRui Paulo ftie->ie_len += 170; 1118*f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1119*f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1120*f05cddf9SRui Paulo pos += 168; 1121*f05cddf9SRui Paulo } 1122*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1123*f05cddf9SRui Paulo 1124*f05cddf9SRui Paulo /* Lifetime */ 1125*f05cddf9SRui Paulo lifetime = peer->lifetime; 1126*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1127*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_RESP) { 1128*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1129*f05cddf9SRui Paulo "lifetime in response"); 1130*f05cddf9SRui Paulo lifetime++; 1131*f05cddf9SRui Paulo } 1132*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1133*f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1134*f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1135*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds from initiator", 1136*f05cddf9SRui Paulo lifetime); 1137*f05cddf9SRui Paulo 1138*f05cddf9SRui Paulo /* compute MIC before sending */ 1139*f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 2, (u8 *) lnkid, peer->rsnie_p, 1140*f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 1141*f05cddf9SRui Paulo 1142*f05cddf9SRui Paulo skip_ies: 1143*f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, 1144*f05cddf9SRui Paulo rbuf, pos - rbuf); 1145*f05cddf9SRui Paulo os_free(rbuf); 1146*f05cddf9SRui Paulo 1147*f05cddf9SRui Paulo return 0; 1148*f05cddf9SRui Paulo } 1149*f05cddf9SRui Paulo 1150*f05cddf9SRui Paulo 1151*f05cddf9SRui Paulo static int wpa_tdls_send_tpk_m3(struct wpa_sm *sm, 1152*f05cddf9SRui Paulo const unsigned char *src_addr, u8 dtoken, 1153*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid, 1154*f05cddf9SRui Paulo const struct wpa_tdls_peer *peer) 1155*f05cddf9SRui Paulo { 1156*f05cddf9SRui Paulo u8 *rbuf, *pos; 1157*f05cddf9SRui Paulo size_t buf_len; 1158*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1159*f05cddf9SRui Paulo struct wpa_tdls_timeoutie timeoutie; 1160*f05cddf9SRui Paulo u32 lifetime; 1161*f05cddf9SRui Paulo 1162*f05cddf9SRui Paulo buf_len = 0; 1163*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1164*f05cddf9SRui Paulo /* Peer RSN IE, FTIE(Initiator Nonce, Responder Nonce), 1165*f05cddf9SRui Paulo * Lifetime */ 1166*f05cddf9SRui Paulo buf_len += peer->rsnie_i_len + sizeof(struct wpa_tdls_ftie) + 1167*f05cddf9SRui Paulo sizeof(struct wpa_tdls_timeoutie); 1168*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1169*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) 1170*f05cddf9SRui Paulo buf_len += 170; 1171*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1172*f05cddf9SRui Paulo } 1173*f05cddf9SRui Paulo 1174*f05cddf9SRui Paulo rbuf = os_zalloc(buf_len + 1); 1175*f05cddf9SRui Paulo if (rbuf == NULL) 1176*f05cddf9SRui Paulo return -1; 1177*f05cddf9SRui Paulo pos = rbuf; 1178*f05cddf9SRui Paulo 1179*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1180*f05cddf9SRui Paulo goto skip_ies; 1181*f05cddf9SRui Paulo 1182*f05cddf9SRui Paulo /* Peer RSN IE */ 1183*f05cddf9SRui Paulo pos = wpa_add_ie(pos, peer->rsnie_p, peer->rsnie_p_len); 1184*f05cddf9SRui Paulo 1185*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) pos; 1186*f05cddf9SRui Paulo ftie->ie_type = WLAN_EID_FAST_BSS_TRANSITION; 1187*f05cddf9SRui Paulo /*TODO: ftie->mic_control to set 3-CONFIRM */ 1188*f05cddf9SRui Paulo os_memcpy(ftie->Anonce, peer->rnonce, WPA_NONCE_LEN); 1189*f05cddf9SRui Paulo os_memcpy(ftie->Snonce, peer->inonce, WPA_NONCE_LEN); 1190*f05cddf9SRui Paulo ftie->ie_len = sizeof(struct wpa_tdls_ftie) - 2; 1191*f05cddf9SRui Paulo 1192*f05cddf9SRui Paulo pos = (u8 *) (ftie + 1); 1193*f05cddf9SRui Paulo 1194*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1195*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_LONG_FRAME) { 1196*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - add extra subelem to " 1197*f05cddf9SRui Paulo "FTIE"); 1198*f05cddf9SRui Paulo ftie->ie_len += 170; 1199*f05cddf9SRui Paulo *pos++ = 255; /* FTIE subelem */ 1200*f05cddf9SRui Paulo *pos++ = 168; /* FTIE subelem length */ 1201*f05cddf9SRui Paulo pos += 168; 1202*f05cddf9SRui Paulo } 1203*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1204*f05cddf9SRui Paulo 1205*f05cddf9SRui Paulo /* Lifetime */ 1206*f05cddf9SRui Paulo lifetime = peer->lifetime; 1207*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1208*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_WRONG_LIFETIME_CONF) { 1209*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - use wrong TPK " 1210*f05cddf9SRui Paulo "lifetime in confirm"); 1211*f05cddf9SRui Paulo lifetime++; 1212*f05cddf9SRui Paulo } 1213*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1214*f05cddf9SRui Paulo pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, 1215*f05cddf9SRui Paulo sizeof(timeoutie), lifetime); 1216*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", 1217*f05cddf9SRui Paulo lifetime); 1218*f05cddf9SRui Paulo 1219*f05cddf9SRui Paulo /* compute MIC before sending */ 1220*f05cddf9SRui Paulo wpa_tdls_ftie_mic(peer->tpk.kck, 3, (u8 *) lnkid, peer->rsnie_p, 1221*f05cddf9SRui Paulo (u8 *) &timeoutie, (u8 *) ftie, ftie->mic); 1222*f05cddf9SRui Paulo 1223*f05cddf9SRui Paulo skip_ies: 1224*f05cddf9SRui Paulo wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 0, 1225*f05cddf9SRui Paulo rbuf, pos - rbuf); 1226*f05cddf9SRui Paulo os_free(rbuf); 1227*f05cddf9SRui Paulo 1228*f05cddf9SRui Paulo return 0; 1229*f05cddf9SRui Paulo } 1230*f05cddf9SRui Paulo 1231*f05cddf9SRui Paulo 1232*f05cddf9SRui Paulo static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, 1233*f05cddf9SRui Paulo struct wpa_tdls_peer *peer, 1234*f05cddf9SRui Paulo u8 dialog_token) 1235*f05cddf9SRui Paulo { 1236*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response " 1237*f05cddf9SRui Paulo "(peer " MACSTR ")", MAC2STR(peer->addr)); 1238*f05cddf9SRui Paulo 1239*f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, 1240*f05cddf9SRui Paulo dialog_token, 0, NULL, 0); 1241*f05cddf9SRui Paulo } 1242*f05cddf9SRui Paulo 1243*f05cddf9SRui Paulo 1244*f05cddf9SRui Paulo static int 1245*f05cddf9SRui Paulo wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, 1246*f05cddf9SRui Paulo const u8 *buf, size_t len) 1247*f05cddf9SRui Paulo { 1248*f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1249*f05cddf9SRui Paulo const struct wpa_tdls_lnkid *lnkid; 1250*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1251*f05cddf9SRui Paulo size_t min_req_len = sizeof(struct wpa_tdls_frame) + 1252*f05cddf9SRui Paulo 1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid); 1253*f05cddf9SRui Paulo u8 dialog_token; 1254*f05cddf9SRui Paulo 1255*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR, 1256*f05cddf9SRui Paulo MAC2STR(addr)); 1257*f05cddf9SRui Paulo 1258*f05cddf9SRui Paulo if (len < min_req_len) { 1259*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: " 1260*f05cddf9SRui Paulo "%d", (int) len); 1261*f05cddf9SRui Paulo return -1; 1262*f05cddf9SRui Paulo } 1263*f05cddf9SRui Paulo 1264*f05cddf9SRui Paulo dialog_token = buf[sizeof(struct wpa_tdls_frame)]; 1265*f05cddf9SRui Paulo 1266*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1, 1267*f05cddf9SRui Paulo len - (sizeof(struct wpa_tdls_frame) + 1), 1268*f05cddf9SRui Paulo &kde) < 0) 1269*f05cddf9SRui Paulo return -1; 1270*f05cddf9SRui Paulo 1271*f05cddf9SRui Paulo if (!kde.lnkid) { 1272*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery " 1273*f05cddf9SRui Paulo "Request"); 1274*f05cddf9SRui Paulo return -1; 1275*f05cddf9SRui Paulo } 1276*f05cddf9SRui Paulo 1277*f05cddf9SRui Paulo lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid; 1278*f05cddf9SRui Paulo 1279*f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1280*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different " 1281*f05cddf9SRui Paulo " BSS " MACSTR, MAC2STR(lnkid->bssid)); 1282*f05cddf9SRui Paulo return -1; 1283*f05cddf9SRui Paulo } 1284*f05cddf9SRui Paulo 1285*f05cddf9SRui Paulo peer = wpa_tdls_add_peer(sm, addr); 1286*f05cddf9SRui Paulo if (peer == NULL) 1287*f05cddf9SRui Paulo return -1; 1288*f05cddf9SRui Paulo 1289*f05cddf9SRui Paulo return wpa_tdls_send_discovery_response(sm, peer, dialog_token); 1290*f05cddf9SRui Paulo } 1291*f05cddf9SRui Paulo 1292*f05cddf9SRui Paulo 1293*f05cddf9SRui Paulo int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) 1294*f05cddf9SRui Paulo { 1295*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 1296*f05cddf9SRui Paulo return -1; 1297*f05cddf9SRui Paulo 1298*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " 1299*f05cddf9SRui Paulo MACSTR, MAC2STR(addr)); 1300*f05cddf9SRui Paulo return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, 1301*f05cddf9SRui Paulo 1, 0, NULL, 0); 1302*f05cddf9SRui Paulo } 1303*f05cddf9SRui Paulo 1304*f05cddf9SRui Paulo 1305*f05cddf9SRui Paulo static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde, 1306*f05cddf9SRui Paulo struct wpa_tdls_peer *peer) 1307*f05cddf9SRui Paulo { 1308*f05cddf9SRui Paulo if (!kde->supp_rates) { 1309*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: No supported rates received"); 1310*f05cddf9SRui Paulo return -1; 1311*f05cddf9SRui Paulo } 1312*f05cddf9SRui Paulo 1313*f05cddf9SRui Paulo peer->supp_rates_len = kde->supp_rates_len - 2; 1314*f05cddf9SRui Paulo if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES) 1315*f05cddf9SRui Paulo peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES; 1316*f05cddf9SRui Paulo os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len); 1317*f05cddf9SRui Paulo 1318*f05cddf9SRui Paulo if (kde->ext_supp_rates) { 1319*f05cddf9SRui Paulo int clen = kde->ext_supp_rates_len - 2; 1320*f05cddf9SRui Paulo if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES) 1321*f05cddf9SRui Paulo clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len; 1322*f05cddf9SRui Paulo os_memcpy(peer->supp_rates + peer->supp_rates_len, 1323*f05cddf9SRui Paulo kde->ext_supp_rates + 2, clen); 1324*f05cddf9SRui Paulo peer->supp_rates_len += clen; 1325*f05cddf9SRui Paulo } 1326*f05cddf9SRui Paulo 1327*f05cddf9SRui Paulo return 0; 1328*f05cddf9SRui Paulo } 1329*f05cddf9SRui Paulo 1330*f05cddf9SRui Paulo 1331*f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, 1332*f05cddf9SRui Paulo const u8 *buf, size_t len) 1333*f05cddf9SRui Paulo { 1334*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1335*f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1336*f05cddf9SRui Paulo struct wpa_ie_data ie; 1337*f05cddf9SRui Paulo int cipher; 1338*f05cddf9SRui Paulo const u8 *cpos; 1339*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie = NULL; 1340*f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 1341*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 1342*f05cddf9SRui Paulo u32 lifetime = 0; 1343*f05cddf9SRui Paulo #if 0 1344*f05cddf9SRui Paulo struct rsn_ie_hdr *hdr; 1345*f05cddf9SRui Paulo u8 *pos; 1346*f05cddf9SRui Paulo u16 rsn_capab; 1347*f05cddf9SRui Paulo u16 rsn_ver; 1348*f05cddf9SRui Paulo #endif 1349*f05cddf9SRui Paulo u8 dtoken; 1350*f05cddf9SRui Paulo u16 ielen; 1351*f05cddf9SRui Paulo u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1352*f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 1353*f05cddf9SRui Paulo int existing_peer = 0; 1354*f05cddf9SRui Paulo 1355*f05cddf9SRui Paulo if (len < 3 + 3) 1356*f05cddf9SRui Paulo return -1; 1357*f05cddf9SRui Paulo 1358*f05cddf9SRui Paulo cpos = buf; 1359*f05cddf9SRui Paulo cpos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 1360*f05cddf9SRui Paulo 1361*f05cddf9SRui Paulo /* driver had already verified the frame format */ 1362*f05cddf9SRui Paulo dtoken = *cpos++; /* dialog token */ 1363*f05cddf9SRui Paulo 1364*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken); 1365*f05cddf9SRui Paulo 1366*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 1367*f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) { 1368*f05cddf9SRui Paulo existing_peer = 1; 1369*f05cddf9SRui Paulo break; 1370*f05cddf9SRui Paulo } 1371*f05cddf9SRui Paulo } 1372*f05cddf9SRui Paulo 1373*f05cddf9SRui Paulo if (peer == NULL) { 1374*f05cddf9SRui Paulo peer = wpa_tdls_add_peer(sm, src_addr); 1375*f05cddf9SRui Paulo if (peer == NULL) 1376*f05cddf9SRui Paulo goto error; 1377*f05cddf9SRui Paulo } 1378*f05cddf9SRui Paulo 1379*f05cddf9SRui Paulo /* capability information */ 1380*f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(cpos); 1381*f05cddf9SRui Paulo cpos += 2; 1382*f05cddf9SRui Paulo 1383*f05cddf9SRui Paulo ielen = len - (cpos - buf); /* start of IE in buf */ 1384*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) { 1385*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M1"); 1386*f05cddf9SRui Paulo goto error; 1387*f05cddf9SRui Paulo } 1388*f05cddf9SRui Paulo 1389*f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 1390*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 1391*f05cddf9SRui Paulo "TPK M1"); 1392*f05cddf9SRui Paulo goto error; 1393*f05cddf9SRui Paulo } 1394*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M1", 1395*f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 1396*f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 1397*f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1398*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); 1399*f05cddf9SRui Paulo status = WLAN_STATUS_NOT_IN_SAME_BSS; 1400*f05cddf9SRui Paulo goto error; 1401*f05cddf9SRui Paulo } 1402*f05cddf9SRui Paulo 1403*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR, 1404*f05cddf9SRui Paulo MAC2STR(src_addr)); 1405*f05cddf9SRui Paulo 1406*f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 1407*f05cddf9SRui Paulo goto error; 1408*f05cddf9SRui Paulo 1409*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1410*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 1411*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 1412*f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 1413*f05cddf9SRui Paulo break; 1414*f05cddf9SRui Paulo } 1415*f05cddf9SRui Paulo if (peer == NULL) { 1416*f05cddf9SRui Paulo peer = wpa_tdls_add_peer(sm, src_addr); 1417*f05cddf9SRui Paulo if (peer == NULL) 1418*f05cddf9SRui Paulo goto error; 1419*f05cddf9SRui Paulo } 1420*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " 1421*f05cddf9SRui Paulo "TDLS setup - send own request"); 1422*f05cddf9SRui Paulo peer->initiator = 1; 1423*f05cddf9SRui Paulo wpa_tdls_send_tpk_m1(sm, peer); 1424*f05cddf9SRui Paulo } 1425*f05cddf9SRui Paulo 1426*f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 1427*f05cddf9SRui Paulo tdls_prohibited) { 1428*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 1429*f05cddf9SRui Paulo "on TDLS"); 1430*f05cddf9SRui Paulo tdls_prohibited = 0; 1431*f05cddf9SRui Paulo } 1432*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1433*f05cddf9SRui Paulo 1434*f05cddf9SRui Paulo if (tdls_prohibited) { 1435*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TDLS prohibited in this BSS"); 1436*f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1437*f05cddf9SRui Paulo goto error; 1438*f05cddf9SRui Paulo } 1439*f05cddf9SRui Paulo 1440*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1441*f05cddf9SRui Paulo if (kde.rsn_ie) { 1442*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M1 while " 1443*f05cddf9SRui Paulo "security is disabled"); 1444*f05cddf9SRui Paulo status = WLAN_STATUS_SECURITY_DISABLED; 1445*f05cddf9SRui Paulo goto error; 1446*f05cddf9SRui Paulo } 1447*f05cddf9SRui Paulo goto skip_rsn; 1448*f05cddf9SRui Paulo } 1449*f05cddf9SRui Paulo 1450*f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 1451*f05cddf9SRui Paulo kde.rsn_ie == NULL) { 1452*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M1"); 1453*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 1454*f05cddf9SRui Paulo goto error; 1455*f05cddf9SRui Paulo } 1456*f05cddf9SRui Paulo 1457*f05cddf9SRui Paulo if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { 1458*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too long Initiator RSN IE in " 1459*f05cddf9SRui Paulo "TPK M1"); 1460*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1461*f05cddf9SRui Paulo goto error; 1462*f05cddf9SRui Paulo } 1463*f05cddf9SRui Paulo 1464*f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 1465*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M1"); 1466*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1467*f05cddf9SRui Paulo goto error; 1468*f05cddf9SRui Paulo } 1469*f05cddf9SRui Paulo 1470*f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 1471*f05cddf9SRui Paulo if (cipher & WPA_CIPHER_CCMP) { 1472*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 1473*f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 1474*f05cddf9SRui Paulo } else { 1475*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M1"); 1476*f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1477*f05cddf9SRui Paulo goto error; 1478*f05cddf9SRui Paulo } 1479*f05cddf9SRui Paulo 1480*f05cddf9SRui Paulo if ((ie.capabilities & 1481*f05cddf9SRui Paulo (WPA_CAPABILITY_NO_PAIRWISE | WPA_CAPABILITY_PEERKEY_ENABLED)) != 1482*f05cddf9SRui Paulo WPA_CAPABILITY_PEERKEY_ENABLED) { 1483*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid RSN Capabilities in " 1484*f05cddf9SRui Paulo "TPK M1"); 1485*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSN_IE_CAPAB; 1486*f05cddf9SRui Paulo goto error; 1487*f05cddf9SRui Paulo } 1488*f05cddf9SRui Paulo 1489*f05cddf9SRui Paulo /* Lifetime */ 1490*f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 1491*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M1"); 1492*f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1493*f05cddf9SRui Paulo goto error; 1494*f05cddf9SRui Paulo } 1495*f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 1496*f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 1497*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", lifetime); 1498*f05cddf9SRui Paulo if (lifetime < 300) { 1499*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Too short TPK lifetime"); 1500*f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1501*f05cddf9SRui Paulo goto error; 1502*f05cddf9SRui Paulo } 1503*f05cddf9SRui Paulo 1504*f05cddf9SRui Paulo skip_rsn: 1505*f05cddf9SRui Paulo /* If found, use existing entry instead of adding a new one; 1506*f05cddf9SRui Paulo * how to handle the case where both ends initiate at the 1507*f05cddf9SRui Paulo * same time? */ 1508*f05cddf9SRui Paulo if (existing_peer) { 1509*f05cddf9SRui Paulo if (peer->tpk_success) { 1510*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " 1511*f05cddf9SRui Paulo "direct link is enabled - tear down the " 1512*f05cddf9SRui Paulo "old link first"); 1513*f05cddf9SRui Paulo #if 0 1514*f05cddf9SRui Paulo /* TODO: Disabling the link would be more proper 1515*f05cddf9SRui Paulo * operation here, but it seems to trigger a race with 1516*f05cddf9SRui Paulo * some drivers handling the new request frame. */ 1517*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 1518*f05cddf9SRui Paulo #else 1519*f05cddf9SRui Paulo if (sm->tdls_external_setup) 1520*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, 1521*f05cddf9SRui Paulo src_addr); 1522*f05cddf9SRui Paulo else 1523*f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 1524*f05cddf9SRui Paulo #endif 1525*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1526*f05cddf9SRui Paulo } 1527*f05cddf9SRui Paulo 1528*f05cddf9SRui Paulo /* 1529*f05cddf9SRui Paulo * An entry is already present, so check if we already sent a 1530*f05cddf9SRui Paulo * TDLS Setup Request. If so, compare MAC addresses and let the 1531*f05cddf9SRui Paulo * STA with the lower MAC address continue as the initiator. 1532*f05cddf9SRui Paulo * The other negotiation is terminated. 1533*f05cddf9SRui Paulo */ 1534*f05cddf9SRui Paulo if (peer->initiator) { 1535*f05cddf9SRui Paulo if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { 1536*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard request " 1537*f05cddf9SRui Paulo "from peer with higher address " 1538*f05cddf9SRui Paulo MACSTR, MAC2STR(src_addr)); 1539*f05cddf9SRui Paulo return -1; 1540*f05cddf9SRui Paulo } else { 1541*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Accept request " 1542*f05cddf9SRui Paulo "from peer with lower address " 1543*f05cddf9SRui Paulo MACSTR " (terminate previously " 1544*f05cddf9SRui Paulo "initiated negotiation", 1545*f05cddf9SRui Paulo MAC2STR(src_addr)); 1546*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1547*f05cddf9SRui Paulo } 1548*f05cddf9SRui Paulo } 1549*f05cddf9SRui Paulo } 1550*f05cddf9SRui Paulo 1551*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1552*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) { 1553*f05cddf9SRui Paulo if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) { 1554*f05cddf9SRui Paulo /* 1555*f05cddf9SRui Paulo * The request frame from us is going to win, so do not 1556*f05cddf9SRui Paulo * replace information based on this request frame from 1557*f05cddf9SRui Paulo * the peer. 1558*f05cddf9SRui Paulo */ 1559*f05cddf9SRui Paulo goto skip_rsn_check; 1560*f05cddf9SRui Paulo } 1561*f05cddf9SRui Paulo } 1562*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1563*f05cddf9SRui Paulo 1564*f05cddf9SRui Paulo peer->initiator = 0; /* Need to check */ 1565*f05cddf9SRui Paulo peer->dtoken = dtoken; 1566*f05cddf9SRui Paulo 1567*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1568*f05cddf9SRui Paulo peer->rsnie_i_len = 0; 1569*f05cddf9SRui Paulo peer->rsnie_p_len = 0; 1570*f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 1571*f05cddf9SRui Paulo goto skip_rsn_check; 1572*f05cddf9SRui Paulo } 1573*f05cddf9SRui Paulo 1574*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 1575*f05cddf9SRui Paulo os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN); 1576*f05cddf9SRui Paulo os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); 1577*f05cddf9SRui Paulo peer->rsnie_i_len = kde.rsn_ie_len; 1578*f05cddf9SRui Paulo peer->cipher = cipher; 1579*f05cddf9SRui Paulo 1580*f05cddf9SRui Paulo if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { 1581*f05cddf9SRui Paulo wpa_msg(sm->ctx->ctx, MSG_WARNING, 1582*f05cddf9SRui Paulo "TDLS: Failed to get random data for responder nonce"); 1583*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1584*f05cddf9SRui Paulo goto error; 1585*f05cddf9SRui Paulo } 1586*f05cddf9SRui Paulo 1587*f05cddf9SRui Paulo #if 0 1588*f05cddf9SRui Paulo /* get version info from RSNIE received from Peer */ 1589*f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) kde.rsn_ie; 1590*f05cddf9SRui Paulo rsn_ver = WPA_GET_LE16(hdr->version); 1591*f05cddf9SRui Paulo 1592*f05cddf9SRui Paulo /* use min(peer's version, out version) */ 1593*f05cddf9SRui Paulo if (rsn_ver > RSN_VERSION) 1594*f05cddf9SRui Paulo rsn_ver = RSN_VERSION; 1595*f05cddf9SRui Paulo 1596*f05cddf9SRui Paulo hdr = (struct rsn_ie_hdr *) peer->rsnie_p; 1597*f05cddf9SRui Paulo 1598*f05cddf9SRui Paulo hdr->elem_id = WLAN_EID_RSN; 1599*f05cddf9SRui Paulo WPA_PUT_LE16(hdr->version, rsn_ver); 1600*f05cddf9SRui Paulo pos = (u8 *) (hdr + 1); 1601*f05cddf9SRui Paulo 1602*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); 1603*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1604*f05cddf9SRui Paulo /* Include only the selected cipher in pairwise cipher suite */ 1605*f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 1606*f05cddf9SRui Paulo pos += 2; 1607*f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) 1608*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1609*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1610*f05cddf9SRui Paulo 1611*f05cddf9SRui Paulo WPA_PUT_LE16(pos, 1); 1612*f05cddf9SRui Paulo pos += 2; 1613*f05cddf9SRui Paulo RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); 1614*f05cddf9SRui Paulo pos += RSN_SELECTOR_LEN; 1615*f05cddf9SRui Paulo 1616*f05cddf9SRui Paulo rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; 1617*f05cddf9SRui Paulo rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; 1618*f05cddf9SRui Paulo WPA_PUT_LE16(pos, rsn_capab); 1619*f05cddf9SRui Paulo pos += 2; 1620*f05cddf9SRui Paulo 1621*f05cddf9SRui Paulo hdr->len = (pos - peer->rsnie_p) - 2; 1622*f05cddf9SRui Paulo peer->rsnie_p_len = pos - peer->rsnie_p; 1623*f05cddf9SRui Paulo #endif 1624*f05cddf9SRui Paulo 1625*f05cddf9SRui Paulo /* temp fix: validation of RSNIE later */ 1626*f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, peer->rsnie_i, peer->rsnie_i_len); 1627*f05cddf9SRui Paulo peer->rsnie_p_len = peer->rsnie_i_len; 1628*f05cddf9SRui Paulo 1629*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for TPK handshake", 1630*f05cddf9SRui Paulo peer->rsnie_p, peer->rsnie_p_len); 1631*f05cddf9SRui Paulo 1632*f05cddf9SRui Paulo peer->lifetime = lifetime; 1633*f05cddf9SRui Paulo 1634*f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 1635*f05cddf9SRui Paulo 1636*f05cddf9SRui Paulo skip_rsn_check: 1637*f05cddf9SRui Paulo /* add the peer to the driver as a "setup in progress" peer */ 1638*f05cddf9SRui Paulo wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0); 1639*f05cddf9SRui Paulo 1640*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); 1641*f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { 1642*f05cddf9SRui Paulo wpa_tdls_disable_link(sm, peer->addr); 1643*f05cddf9SRui Paulo goto error; 1644*f05cddf9SRui Paulo } 1645*f05cddf9SRui Paulo 1646*f05cddf9SRui Paulo return 0; 1647*f05cddf9SRui Paulo 1648*f05cddf9SRui Paulo error: 1649*f05cddf9SRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 1650*f05cddf9SRui Paulo status); 1651*f05cddf9SRui Paulo return -1; 1652*f05cddf9SRui Paulo } 1653*f05cddf9SRui Paulo 1654*f05cddf9SRui Paulo 1655*f05cddf9SRui Paulo static void wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) 1656*f05cddf9SRui Paulo { 1657*f05cddf9SRui Paulo peer->tpk_success = 1; 1658*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 1659*f05cddf9SRui Paulo if (wpa_tdls_get_privacy(sm)) { 1660*f05cddf9SRui Paulo u32 lifetime = peer->lifetime; 1661*f05cddf9SRui Paulo /* 1662*f05cddf9SRui Paulo * Start the initiator process a bit earlier to avoid race 1663*f05cddf9SRui Paulo * condition with the responder sending teardown request. 1664*f05cddf9SRui Paulo */ 1665*f05cddf9SRui Paulo if (lifetime > 3 && peer->initiator) 1666*f05cddf9SRui Paulo lifetime -= 3; 1667*f05cddf9SRui Paulo eloop_register_timeout(lifetime, 0, wpa_tdls_tpk_timeout, 1668*f05cddf9SRui Paulo sm, peer); 1669*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1670*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_NO_TPK_EXPIRATION) { 1671*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - disable TPK " 1672*f05cddf9SRui Paulo "expiration"); 1673*f05cddf9SRui Paulo eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer); 1674*f05cddf9SRui Paulo } 1675*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1676*f05cddf9SRui Paulo } 1677*f05cddf9SRui Paulo 1678*f05cddf9SRui Paulo /* add supported rates and capabilities to the TDLS peer */ 1679*f05cddf9SRui Paulo wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability, 1680*f05cddf9SRui Paulo peer->supp_rates, peer->supp_rates_len); 1681*f05cddf9SRui Paulo 1682*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr); 1683*f05cddf9SRui Paulo } 1684*f05cddf9SRui Paulo 1685*f05cddf9SRui Paulo 1686*f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, 1687*f05cddf9SRui Paulo const u8 *buf, size_t len) 1688*f05cddf9SRui Paulo { 1689*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1690*f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1691*f05cddf9SRui Paulo struct wpa_ie_data ie; 1692*f05cddf9SRui Paulo int cipher; 1693*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1694*f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 1695*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 1696*f05cddf9SRui Paulo u32 lifetime; 1697*f05cddf9SRui Paulo u8 dtoken; 1698*f05cddf9SRui Paulo int ielen; 1699*f05cddf9SRui Paulo u16 status; 1700*f05cddf9SRui Paulo const u8 *pos; 1701*f05cddf9SRui Paulo 1702*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Response / TPK M2 " 1703*f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 1704*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 1705*f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 1706*f05cddf9SRui Paulo break; 1707*f05cddf9SRui Paulo } 1708*f05cddf9SRui Paulo if (peer == NULL) { 1709*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 1710*f05cddf9SRui Paulo "TPK M2: " MACSTR, MAC2STR(src_addr)); 1711*f05cddf9SRui Paulo return -1; 1712*f05cddf9SRui Paulo } 1713*f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST); 1714*f05cddf9SRui Paulo 1715*f05cddf9SRui Paulo if (len < 3 + 2 + 1) 1716*f05cddf9SRui Paulo return -1; 1717*f05cddf9SRui Paulo pos = buf; 1718*f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 1719*f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 1720*f05cddf9SRui Paulo pos += 2 /* status code */; 1721*f05cddf9SRui Paulo 1722*f05cddf9SRui Paulo if (status != WLAN_STATUS_SUCCESS) { 1723*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u", 1724*f05cddf9SRui Paulo status); 1725*f05cddf9SRui Paulo if (sm->tdls_external_setup) 1726*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 1727*f05cddf9SRui Paulo return -1; 1728*f05cddf9SRui Paulo } 1729*f05cddf9SRui Paulo 1730*f05cddf9SRui Paulo status = WLAN_STATUS_UNSPECIFIED_FAILURE; 1731*f05cddf9SRui Paulo 1732*f05cddf9SRui Paulo /* TODO: need to verify dialog token matches here or in kernel */ 1733*f05cddf9SRui Paulo dtoken = *pos++; /* dialog token */ 1734*f05cddf9SRui Paulo 1735*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken); 1736*f05cddf9SRui Paulo 1737*f05cddf9SRui Paulo if (len < 3 + 2 + 1 + 2) 1738*f05cddf9SRui Paulo return -1; 1739*f05cddf9SRui Paulo 1740*f05cddf9SRui Paulo /* capability information */ 1741*f05cddf9SRui Paulo peer->capability = WPA_GET_LE16(pos); 1742*f05cddf9SRui Paulo pos += 2; 1743*f05cddf9SRui Paulo 1744*f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 1745*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) { 1746*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse IEs in TPK M2"); 1747*f05cddf9SRui Paulo goto error; 1748*f05cddf9SRui Paulo } 1749*f05cddf9SRui Paulo 1750*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 1751*f05cddf9SRui Paulo if (tdls_testing & TDLS_TESTING_DECLINE_RESP) { 1752*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - decline response"); 1753*f05cddf9SRui Paulo status = WLAN_STATUS_REQUEST_DECLINED; 1754*f05cddf9SRui Paulo goto error; 1755*f05cddf9SRui Paulo } 1756*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 1757*f05cddf9SRui Paulo 1758*f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 1759*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No valid Link Identifier IE in " 1760*f05cddf9SRui Paulo "TPK M2"); 1761*f05cddf9SRui Paulo goto error; 1762*f05cddf9SRui Paulo } 1763*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M2", 1764*f05cddf9SRui Paulo kde.lnkid, kde.lnkid_len); 1765*f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 1766*f05cddf9SRui Paulo 1767*f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1768*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M2 from different BSS"); 1769*f05cddf9SRui Paulo status = WLAN_STATUS_NOT_IN_SAME_BSS; 1770*f05cddf9SRui Paulo goto error; 1771*f05cddf9SRui Paulo } 1772*f05cddf9SRui Paulo 1773*f05cddf9SRui Paulo if (copy_supp_rates(&kde, peer) < 0) 1774*f05cddf9SRui Paulo goto error; 1775*f05cddf9SRui Paulo 1776*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) { 1777*f05cddf9SRui Paulo peer->rsnie_p_len = 0; 1778*f05cddf9SRui Paulo peer->cipher = WPA_CIPHER_NONE; 1779*f05cddf9SRui Paulo goto skip_rsn; 1780*f05cddf9SRui Paulo } 1781*f05cddf9SRui Paulo 1782*f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie) || 1783*f05cddf9SRui Paulo kde.rsn_ie == NULL) { 1784*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE or RSN IE in TPK M2"); 1785*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_PARAMETERS; 1786*f05cddf9SRui Paulo goto error; 1787*f05cddf9SRui Paulo } 1788*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 1789*f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 1790*f05cddf9SRui Paulo 1791*f05cddf9SRui Paulo /* 1792*f05cddf9SRui Paulo * FIX: bitwise comparison of RSN IE is not the correct way of 1793*f05cddf9SRui Paulo * validation this. It can be different, but certain fields must 1794*f05cddf9SRui Paulo * match. Since we list only a single pairwise cipher in TPK M1, the 1795*f05cddf9SRui Paulo * memcmp is likely to work in most cases, though. 1796*f05cddf9SRui Paulo */ 1797*f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_i_len || 1798*f05cddf9SRui Paulo os_memcmp(peer->rsnie_i, kde.rsn_ie, peer->rsnie_i_len) != 0) { 1799*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M2 does " 1800*f05cddf9SRui Paulo "not match with RSN IE used in TPK M1"); 1801*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Sent in TPK M1", 1802*f05cddf9SRui Paulo peer->rsnie_i, peer->rsnie_i_len); 1803*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", 1804*f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 1805*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1806*f05cddf9SRui Paulo goto error; 1807*f05cddf9SRui Paulo } 1808*f05cddf9SRui Paulo 1809*f05cddf9SRui Paulo if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 1810*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse RSN IE in TPK M2"); 1811*f05cddf9SRui Paulo status = WLAN_STATUS_INVALID_RSNIE; 1812*f05cddf9SRui Paulo goto error; 1813*f05cddf9SRui Paulo } 1814*f05cddf9SRui Paulo 1815*f05cddf9SRui Paulo cipher = ie.pairwise_cipher; 1816*f05cddf9SRui Paulo if (cipher == WPA_CIPHER_CCMP) { 1817*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Using CCMP for direct link"); 1818*f05cddf9SRui Paulo cipher = WPA_CIPHER_CCMP; 1819*f05cddf9SRui Paulo } else { 1820*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No acceptable cipher in TPK M2"); 1821*f05cddf9SRui Paulo status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 1822*f05cddf9SRui Paulo goto error; 1823*f05cddf9SRui Paulo } 1824*f05cddf9SRui Paulo 1825*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M2", 1826*f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 1827*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 1828*f05cddf9SRui Paulo 1829*f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 1830*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M2 does " 1831*f05cddf9SRui Paulo "not match with FTIE SNonce used in TPK M1"); 1832*f05cddf9SRui Paulo /* Silently discard the frame */ 1833*f05cddf9SRui Paulo return -1; 1834*f05cddf9SRui Paulo } 1835*f05cddf9SRui Paulo 1836*f05cddf9SRui Paulo /* Responder Nonce and RSN IE */ 1837*f05cddf9SRui Paulo os_memcpy(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN); 1838*f05cddf9SRui Paulo os_memcpy(peer->rsnie_p, kde.rsn_ie, kde.rsn_ie_len); 1839*f05cddf9SRui Paulo peer->rsnie_p_len = kde.rsn_ie_len; 1840*f05cddf9SRui Paulo peer->cipher = cipher; 1841*f05cddf9SRui Paulo 1842*f05cddf9SRui Paulo /* Lifetime */ 1843*f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 1844*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M2"); 1845*f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1846*f05cddf9SRui Paulo goto error; 1847*f05cddf9SRui Paulo } 1848*f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 1849*f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 1850*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M2", 1851*f05cddf9SRui Paulo lifetime); 1852*f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 1853*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 1854*f05cddf9SRui Paulo "TPK M2 (expected %u)", lifetime, peer->lifetime); 1855*f05cddf9SRui Paulo status = WLAN_STATUS_UNACCEPTABLE_LIFETIME; 1856*f05cddf9SRui Paulo goto error; 1857*f05cddf9SRui Paulo } 1858*f05cddf9SRui Paulo 1859*f05cddf9SRui Paulo wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); 1860*f05cddf9SRui Paulo 1861*f05cddf9SRui Paulo /* Process MIC check to see if TPK M2 is right */ 1862*f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(2, peer, (u8 *) lnkid, 1863*f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 1864*f05cddf9SRui Paulo /* Discard the frame */ 1865*f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 1866*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 1867*f05cddf9SRui Paulo if (sm->tdls_external_setup) 1868*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 1869*f05cddf9SRui Paulo return -1; 1870*f05cddf9SRui Paulo } 1871*f05cddf9SRui Paulo 1872*f05cddf9SRui Paulo wpa_tdls_set_key(sm, peer); 1873*f05cddf9SRui Paulo 1874*f05cddf9SRui Paulo skip_rsn: 1875*f05cddf9SRui Paulo peer->dtoken = dtoken; 1876*f05cddf9SRui Paulo 1877*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " 1878*f05cddf9SRui Paulo "TPK Handshake Message 3"); 1879*f05cddf9SRui Paulo wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer); 1880*f05cddf9SRui Paulo 1881*f05cddf9SRui Paulo wpa_tdls_enable_link(sm, peer); 1882*f05cddf9SRui Paulo 1883*f05cddf9SRui Paulo return 0; 1884*f05cddf9SRui Paulo 1885*f05cddf9SRui Paulo error: 1886*f05cddf9SRui Paulo wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1887*f05cddf9SRui Paulo status); 1888*f05cddf9SRui Paulo if (sm->tdls_external_setup) 1889*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 1890*f05cddf9SRui Paulo return -1; 1891*f05cddf9SRui Paulo } 1892*f05cddf9SRui Paulo 1893*f05cddf9SRui Paulo 1894*f05cddf9SRui Paulo static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, 1895*f05cddf9SRui Paulo const u8 *buf, size_t len) 1896*f05cddf9SRui Paulo { 1897*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 1898*f05cddf9SRui Paulo struct wpa_eapol_ie_parse kde; 1899*f05cddf9SRui Paulo struct wpa_tdls_ftie *ftie; 1900*f05cddf9SRui Paulo struct wpa_tdls_timeoutie *timeoutie; 1901*f05cddf9SRui Paulo struct wpa_tdls_lnkid *lnkid; 1902*f05cddf9SRui Paulo int ielen; 1903*f05cddf9SRui Paulo u16 status; 1904*f05cddf9SRui Paulo const u8 *pos; 1905*f05cddf9SRui Paulo u32 lifetime; 1906*f05cddf9SRui Paulo 1907*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Received TDLS Setup Confirm / TPK M3 " 1908*f05cddf9SRui Paulo "(Peer " MACSTR ")", MAC2STR(src_addr)); 1909*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 1910*f05cddf9SRui Paulo if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) 1911*f05cddf9SRui Paulo break; 1912*f05cddf9SRui Paulo } 1913*f05cddf9SRui Paulo if (peer == NULL) { 1914*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No matching peer found for " 1915*f05cddf9SRui Paulo "TPK M3: " MACSTR, MAC2STR(src_addr)); 1916*f05cddf9SRui Paulo return -1; 1917*f05cddf9SRui Paulo } 1918*f05cddf9SRui Paulo wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE); 1919*f05cddf9SRui Paulo 1920*f05cddf9SRui Paulo if (len < 3 + 3) 1921*f05cddf9SRui Paulo return -1; 1922*f05cddf9SRui Paulo pos = buf; 1923*f05cddf9SRui Paulo pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */; 1924*f05cddf9SRui Paulo 1925*f05cddf9SRui Paulo status = WPA_GET_LE16(pos); 1926*f05cddf9SRui Paulo 1927*f05cddf9SRui Paulo if (status != 0) { 1928*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u", 1929*f05cddf9SRui Paulo status); 1930*f05cddf9SRui Paulo if (sm->tdls_external_setup) 1931*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 1932*f05cddf9SRui Paulo return -1; 1933*f05cddf9SRui Paulo } 1934*f05cddf9SRui Paulo pos += 2 /* status code */ + 1 /* dialog token */; 1935*f05cddf9SRui Paulo 1936*f05cddf9SRui Paulo ielen = len - (pos - buf); /* start of IE in buf */ 1937*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { 1938*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3"); 1939*f05cddf9SRui Paulo return -1; 1940*f05cddf9SRui Paulo } 1941*f05cddf9SRui Paulo 1942*f05cddf9SRui Paulo if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { 1943*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3"); 1944*f05cddf9SRui Paulo return -1; 1945*f05cddf9SRui Paulo } 1946*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3", 1947*f05cddf9SRui Paulo (u8 *) kde.lnkid, kde.lnkid_len); 1948*f05cddf9SRui Paulo lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; 1949*f05cddf9SRui Paulo 1950*f05cddf9SRui Paulo if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { 1951*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS"); 1952*f05cddf9SRui Paulo return -1; 1953*f05cddf9SRui Paulo } 1954*f05cddf9SRui Paulo 1955*f05cddf9SRui Paulo if (!wpa_tdls_get_privacy(sm)) 1956*f05cddf9SRui Paulo goto skip_rsn; 1957*f05cddf9SRui Paulo 1958*f05cddf9SRui Paulo if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) { 1959*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3"); 1960*f05cddf9SRui Paulo return -1; 1961*f05cddf9SRui Paulo } 1962*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3", 1963*f05cddf9SRui Paulo kde.ftie, sizeof(*ftie)); 1964*f05cddf9SRui Paulo ftie = (struct wpa_tdls_ftie *) kde.ftie; 1965*f05cddf9SRui Paulo 1966*f05cddf9SRui Paulo if (kde.rsn_ie == NULL) { 1967*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3"); 1968*f05cddf9SRui Paulo return -1; 1969*f05cddf9SRui Paulo } 1970*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3", 1971*f05cddf9SRui Paulo kde.rsn_ie, kde.rsn_ie_len); 1972*f05cddf9SRui Paulo if (kde.rsn_ie_len != peer->rsnie_p_len || 1973*f05cddf9SRui Paulo os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) { 1974*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match " 1975*f05cddf9SRui Paulo "with the one sent in TPK M2"); 1976*f05cddf9SRui Paulo return -1; 1977*f05cddf9SRui Paulo } 1978*f05cddf9SRui Paulo 1979*f05cddf9SRui Paulo if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) { 1980*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does " 1981*f05cddf9SRui Paulo "not match with FTIE ANonce used in TPK M2"); 1982*f05cddf9SRui Paulo return -1; 1983*f05cddf9SRui Paulo } 1984*f05cddf9SRui Paulo 1985*f05cddf9SRui Paulo if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) { 1986*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not " 1987*f05cddf9SRui Paulo "match with FTIE SNonce used in TPK M1"); 1988*f05cddf9SRui Paulo return -1; 1989*f05cddf9SRui Paulo } 1990*f05cddf9SRui Paulo 1991*f05cddf9SRui Paulo if (kde.key_lifetime == NULL) { 1992*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3"); 1993*f05cddf9SRui Paulo return -1; 1994*f05cddf9SRui Paulo } 1995*f05cddf9SRui Paulo timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime; 1996*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3", 1997*f05cddf9SRui Paulo (u8 *) timeoutie, sizeof(*timeoutie)); 1998*f05cddf9SRui Paulo lifetime = WPA_GET_LE32(timeoutie->value); 1999*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds in TPK M3", 2000*f05cddf9SRui Paulo lifetime); 2001*f05cddf9SRui Paulo if (lifetime != peer->lifetime) { 2002*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in " 2003*f05cddf9SRui Paulo "TPK M3 (expected %u)", lifetime, peer->lifetime); 2004*f05cddf9SRui Paulo if (sm->tdls_external_setup) 2005*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr); 2006*f05cddf9SRui Paulo return -1; 2007*f05cddf9SRui Paulo } 2008*f05cddf9SRui Paulo 2009*f05cddf9SRui Paulo if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid, 2010*f05cddf9SRui Paulo (u8 *) timeoutie, ftie) < 0) { 2011*f05cddf9SRui Paulo wpa_tdls_del_key(sm, peer); 2012*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 2013*f05cddf9SRui Paulo return -1; 2014*f05cddf9SRui Paulo } 2015*f05cddf9SRui Paulo 2016*f05cddf9SRui Paulo if (wpa_tdls_set_key(sm, peer) < 0) 2017*f05cddf9SRui Paulo return -1; 2018*f05cddf9SRui Paulo 2019*f05cddf9SRui Paulo skip_rsn: 2020*f05cddf9SRui Paulo wpa_tdls_enable_link(sm, peer); 2021*f05cddf9SRui Paulo 2022*f05cddf9SRui Paulo return 0; 2023*f05cddf9SRui Paulo } 2024*f05cddf9SRui Paulo 2025*f05cddf9SRui Paulo 2026*f05cddf9SRui Paulo static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs) 2027*f05cddf9SRui Paulo { 2028*f05cddf9SRui Paulo struct wpa_tdls_timeoutie *lifetime = (struct wpa_tdls_timeoutie *) ie; 2029*f05cddf9SRui Paulo 2030*f05cddf9SRui Paulo os_memset(lifetime, 0, ie_len); 2031*f05cddf9SRui Paulo lifetime->ie_type = WLAN_EID_TIMEOUT_INTERVAL; 2032*f05cddf9SRui Paulo lifetime->ie_len = sizeof(struct wpa_tdls_timeoutie) - 2; 2033*f05cddf9SRui Paulo lifetime->interval_type = WLAN_TIMEOUT_KEY_LIFETIME; 2034*f05cddf9SRui Paulo WPA_PUT_LE32(lifetime->value, tsecs); 2035*f05cddf9SRui Paulo os_memcpy(pos, ie, ie_len); 2036*f05cddf9SRui Paulo return pos + ie_len; 2037*f05cddf9SRui Paulo } 2038*f05cddf9SRui Paulo 2039*f05cddf9SRui Paulo 2040*f05cddf9SRui Paulo /** 2041*f05cddf9SRui Paulo * wpa_tdls_start - Initiate TDLS handshake (send TPK Handshake Message 1) 2042*f05cddf9SRui Paulo * @sm: Pointer to WPA state machine data from wpa_sm_init() 2043*f05cddf9SRui Paulo * @peer: MAC address of the peer STA 2044*f05cddf9SRui Paulo * Returns: 0 on success, or -1 on failure 2045*f05cddf9SRui Paulo * 2046*f05cddf9SRui Paulo * Send TPK Handshake Message 1 info to driver to start TDLS 2047*f05cddf9SRui Paulo * handshake with the peer. 2048*f05cddf9SRui Paulo */ 2049*f05cddf9SRui Paulo int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) 2050*f05cddf9SRui Paulo { 2051*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2052*f05cddf9SRui Paulo int tdls_prohibited = sm->tdls_prohibited; 2053*f05cddf9SRui Paulo 2054*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2055*f05cddf9SRui Paulo return -1; 2056*f05cddf9SRui Paulo 2057*f05cddf9SRui Paulo #ifdef CONFIG_TDLS_TESTING 2058*f05cddf9SRui Paulo if ((tdls_testing & TDLS_TESTING_IGNORE_AP_PROHIBIT) && 2059*f05cddf9SRui Paulo tdls_prohibited) { 2060*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Testing - ignore AP prohibition " 2061*f05cddf9SRui Paulo "on TDLS"); 2062*f05cddf9SRui Paulo tdls_prohibited = 0; 2063*f05cddf9SRui Paulo } 2064*f05cddf9SRui Paulo #endif /* CONFIG_TDLS_TESTING */ 2065*f05cddf9SRui Paulo 2066*f05cddf9SRui Paulo if (tdls_prohibited) { 2067*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is prohibited in this BSS - " 2068*f05cddf9SRui Paulo "reject request to start setup"); 2069*f05cddf9SRui Paulo return -1; 2070*f05cddf9SRui Paulo } 2071*f05cddf9SRui Paulo 2072*f05cddf9SRui Paulo /* Find existing entry and if found, use that instead of adding 2073*f05cddf9SRui Paulo * a new one */ 2074*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2075*f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2076*f05cddf9SRui Paulo break; 2077*f05cddf9SRui Paulo } 2078*f05cddf9SRui Paulo 2079*f05cddf9SRui Paulo if (peer == NULL) { 2080*f05cddf9SRui Paulo peer = wpa_tdls_add_peer(sm, addr); 2081*f05cddf9SRui Paulo if (peer == NULL) 2082*f05cddf9SRui Paulo return -1; 2083*f05cddf9SRui Paulo } 2084*f05cddf9SRui Paulo 2085*f05cddf9SRui Paulo peer->initiator = 1; 2086*f05cddf9SRui Paulo 2087*f05cddf9SRui Paulo /* add the peer to the driver as a "setup in progress" peer */ 2088*f05cddf9SRui Paulo wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0); 2089*f05cddf9SRui Paulo 2090*f05cddf9SRui Paulo if (wpa_tdls_send_tpk_m1(sm, peer) < 0) { 2091*f05cddf9SRui Paulo wpa_tdls_disable_link(sm, peer->addr); 2092*f05cddf9SRui Paulo return -1; 2093*f05cddf9SRui Paulo } 2094*f05cddf9SRui Paulo 2095*f05cddf9SRui Paulo return 0; 2096*f05cddf9SRui Paulo } 2097*f05cddf9SRui Paulo 2098*f05cddf9SRui Paulo 2099*f05cddf9SRui Paulo int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr) 2100*f05cddf9SRui Paulo { 2101*f05cddf9SRui Paulo struct wpa_tdls_peer *peer; 2102*f05cddf9SRui Paulo 2103*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) 2104*f05cddf9SRui Paulo return -1; 2105*f05cddf9SRui Paulo 2106*f05cddf9SRui Paulo for (peer = sm->tdls; peer; peer = peer->next) { 2107*f05cddf9SRui Paulo if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0) 2108*f05cddf9SRui Paulo break; 2109*f05cddf9SRui Paulo } 2110*f05cddf9SRui Paulo 2111*f05cddf9SRui Paulo if (peer == NULL || !peer->tpk_success) 2112*f05cddf9SRui Paulo return -1; 2113*f05cddf9SRui Paulo 2114*f05cddf9SRui Paulo if (sm->tdls_external_setup) { 2115*f05cddf9SRui Paulo /* 2116*f05cddf9SRui Paulo * Disable previous link to allow renegotiation to be completed 2117*f05cddf9SRui Paulo * on AP path. 2118*f05cddf9SRui Paulo */ 2119*f05cddf9SRui Paulo wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2120*f05cddf9SRui Paulo } 2121*f05cddf9SRui Paulo 2122*f05cddf9SRui Paulo return wpa_tdls_start(sm, addr); 2123*f05cddf9SRui Paulo } 2124*f05cddf9SRui Paulo 2125*f05cddf9SRui Paulo 2126*f05cddf9SRui Paulo /** 2127*f05cddf9SRui Paulo * wpa_supplicant_rx_tdls - Receive TDLS data frame 2128*f05cddf9SRui Paulo * 2129*f05cddf9SRui Paulo * This function is called to receive TDLS (ethertype = 0x890d) data frames. 2130*f05cddf9SRui Paulo */ 2131*f05cddf9SRui Paulo static void wpa_supplicant_rx_tdls(void *ctx, const u8 *src_addr, 2132*f05cddf9SRui Paulo const u8 *buf, size_t len) 2133*f05cddf9SRui Paulo { 2134*f05cddf9SRui Paulo struct wpa_sm *sm = ctx; 2135*f05cddf9SRui Paulo struct wpa_tdls_frame *tf; 2136*f05cddf9SRui Paulo 2137*f05cddf9SRui Paulo wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation", 2138*f05cddf9SRui Paulo buf, len); 2139*f05cddf9SRui Paulo 2140*f05cddf9SRui Paulo if (sm->tdls_disabled || !sm->tdls_supported) { 2141*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled " 2142*f05cddf9SRui Paulo "or unsupported by driver"); 2143*f05cddf9SRui Paulo return; 2144*f05cddf9SRui Paulo } 2145*f05cddf9SRui Paulo 2146*f05cddf9SRui Paulo if (os_memcmp(src_addr, sm->own_addr, ETH_ALEN) == 0) { 2147*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Discard copy of own message"); 2148*f05cddf9SRui Paulo return; 2149*f05cddf9SRui Paulo } 2150*f05cddf9SRui Paulo 2151*f05cddf9SRui Paulo if (len < sizeof(*tf)) { 2152*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Drop too short frame"); 2153*f05cddf9SRui Paulo return; 2154*f05cddf9SRui Paulo } 2155*f05cddf9SRui Paulo 2156*f05cddf9SRui Paulo /* Check to make sure its a valid encapsulated TDLS frame */ 2157*f05cddf9SRui Paulo tf = (struct wpa_tdls_frame *) buf; 2158*f05cddf9SRui Paulo if (tf->payloadtype != 2 /* TDLS_RFTYPE */ || 2159*f05cddf9SRui Paulo tf->category != WLAN_ACTION_TDLS) { 2160*f05cddf9SRui Paulo wpa_printf(MSG_INFO, "TDLS: Invalid frame - payloadtype=%u " 2161*f05cddf9SRui Paulo "category=%u action=%u", 2162*f05cddf9SRui Paulo tf->payloadtype, tf->category, tf->action); 2163*f05cddf9SRui Paulo return; 2164*f05cddf9SRui Paulo } 2165*f05cddf9SRui Paulo 2166*f05cddf9SRui Paulo switch (tf->action) { 2167*f05cddf9SRui Paulo case WLAN_TDLS_SETUP_REQUEST: 2168*f05cddf9SRui Paulo wpa_tdls_process_tpk_m1(sm, src_addr, buf, len); 2169*f05cddf9SRui Paulo break; 2170*f05cddf9SRui Paulo case WLAN_TDLS_SETUP_RESPONSE: 2171*f05cddf9SRui Paulo wpa_tdls_process_tpk_m2(sm, src_addr, buf, len); 2172*f05cddf9SRui Paulo break; 2173*f05cddf9SRui Paulo case WLAN_TDLS_SETUP_CONFIRM: 2174*f05cddf9SRui Paulo wpa_tdls_process_tpk_m3(sm, src_addr, buf, len); 2175*f05cddf9SRui Paulo break; 2176*f05cddf9SRui Paulo case WLAN_TDLS_TEARDOWN: 2177*f05cddf9SRui Paulo wpa_tdls_recv_teardown(sm, src_addr, buf, len); 2178*f05cddf9SRui Paulo break; 2179*f05cddf9SRui Paulo case WLAN_TDLS_DISCOVERY_REQUEST: 2180*f05cddf9SRui Paulo wpa_tdls_process_discovery_request(sm, src_addr, buf, len); 2181*f05cddf9SRui Paulo break; 2182*f05cddf9SRui Paulo default: 2183*f05cddf9SRui Paulo /* Kernel code will process remaining frames */ 2184*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u", 2185*f05cddf9SRui Paulo tf->action); 2186*f05cddf9SRui Paulo break; 2187*f05cddf9SRui Paulo } 2188*f05cddf9SRui Paulo } 2189*f05cddf9SRui Paulo 2190*f05cddf9SRui Paulo 2191*f05cddf9SRui Paulo /** 2192*f05cddf9SRui Paulo * wpa_tdls_init - Initialize driver interface parameters for TDLS 2193*f05cddf9SRui Paulo * @wpa_s: Pointer to wpa_supplicant data 2194*f05cddf9SRui Paulo * Returns: 0 on success, -1 on failure 2195*f05cddf9SRui Paulo * 2196*f05cddf9SRui Paulo * This function is called to initialize driver interface parameters for TDLS. 2197*f05cddf9SRui Paulo * wpa_drv_init() must have been called before this function to initialize the 2198*f05cddf9SRui Paulo * driver interface. 2199*f05cddf9SRui Paulo */ 2200*f05cddf9SRui Paulo int wpa_tdls_init(struct wpa_sm *sm) 2201*f05cddf9SRui Paulo { 2202*f05cddf9SRui Paulo if (sm == NULL) 2203*f05cddf9SRui Paulo return -1; 2204*f05cddf9SRui Paulo 2205*f05cddf9SRui Paulo sm->l2_tdls = l2_packet_init(sm->bridge_ifname ? sm->bridge_ifname : 2206*f05cddf9SRui Paulo sm->ifname, 2207*f05cddf9SRui Paulo sm->own_addr, 2208*f05cddf9SRui Paulo ETH_P_80211_ENCAP, wpa_supplicant_rx_tdls, 2209*f05cddf9SRui Paulo sm, 0); 2210*f05cddf9SRui Paulo if (sm->l2_tdls == NULL) { 2211*f05cddf9SRui Paulo wpa_printf(MSG_ERROR, "TDLS: Failed to open l2_packet " 2212*f05cddf9SRui Paulo "connection"); 2213*f05cddf9SRui Paulo return -1; 2214*f05cddf9SRui Paulo } 2215*f05cddf9SRui Paulo 2216*f05cddf9SRui Paulo /* 2217*f05cddf9SRui Paulo * Drivers that support TDLS but don't implement the get_capa callback 2218*f05cddf9SRui Paulo * are assumed to perform everything internally 2219*f05cddf9SRui Paulo */ 2220*f05cddf9SRui Paulo if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported, 2221*f05cddf9SRui Paulo &sm->tdls_external_setup) < 0) { 2222*f05cddf9SRui Paulo sm->tdls_supported = 1; 2223*f05cddf9SRui Paulo sm->tdls_external_setup = 0; 2224*f05cddf9SRui Paulo } 2225*f05cddf9SRui Paulo 2226*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by " 2227*f05cddf9SRui Paulo "driver", sm->tdls_supported ? "" : " not"); 2228*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup", 2229*f05cddf9SRui Paulo sm->tdls_external_setup ? "external" : "internal"); 2230*f05cddf9SRui Paulo 2231*f05cddf9SRui Paulo return 0; 2232*f05cddf9SRui Paulo } 2233*f05cddf9SRui Paulo 2234*f05cddf9SRui Paulo 2235*f05cddf9SRui Paulo static void wpa_tdls_remove_peers(struct wpa_sm *sm) 2236*f05cddf9SRui Paulo { 2237*f05cddf9SRui Paulo struct wpa_tdls_peer *peer, *tmp; 2238*f05cddf9SRui Paulo 2239*f05cddf9SRui Paulo peer = sm->tdls; 2240*f05cddf9SRui Paulo sm->tdls = NULL; 2241*f05cddf9SRui Paulo 2242*f05cddf9SRui Paulo while (peer) { 2243*f05cddf9SRui Paulo int res; 2244*f05cddf9SRui Paulo tmp = peer->next; 2245*f05cddf9SRui Paulo res = wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); 2246*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", 2247*f05cddf9SRui Paulo MAC2STR(peer->addr), res); 2248*f05cddf9SRui Paulo wpa_tdls_peer_free(sm, peer); 2249*f05cddf9SRui Paulo os_free(peer); 2250*f05cddf9SRui Paulo peer = tmp; 2251*f05cddf9SRui Paulo } 2252*f05cddf9SRui Paulo } 2253*f05cddf9SRui Paulo 2254*f05cddf9SRui Paulo 2255*f05cddf9SRui Paulo /** 2256*f05cddf9SRui Paulo * wpa_tdls_deinit - Deinitialize driver interface parameters for TDLS 2257*f05cddf9SRui Paulo * 2258*f05cddf9SRui Paulo * This function is called to recover driver interface parameters for TDLS 2259*f05cddf9SRui Paulo * and frees resources allocated for it. 2260*f05cddf9SRui Paulo */ 2261*f05cddf9SRui Paulo void wpa_tdls_deinit(struct wpa_sm *sm) 2262*f05cddf9SRui Paulo { 2263*f05cddf9SRui Paulo if (sm == NULL) 2264*f05cddf9SRui Paulo return; 2265*f05cddf9SRui Paulo 2266*f05cddf9SRui Paulo if (sm->l2_tdls) 2267*f05cddf9SRui Paulo l2_packet_deinit(sm->l2_tdls); 2268*f05cddf9SRui Paulo sm->l2_tdls = NULL; 2269*f05cddf9SRui Paulo 2270*f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2271*f05cddf9SRui Paulo } 2272*f05cddf9SRui Paulo 2273*f05cddf9SRui Paulo 2274*f05cddf9SRui Paulo void wpa_tdls_assoc(struct wpa_sm *sm) 2275*f05cddf9SRui Paulo { 2276*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on association"); 2277*f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2278*f05cddf9SRui Paulo } 2279*f05cddf9SRui Paulo 2280*f05cddf9SRui Paulo 2281*f05cddf9SRui Paulo void wpa_tdls_disassoc(struct wpa_sm *sm) 2282*f05cddf9SRui Paulo { 2283*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: Remove peers on disassociation"); 2284*f05cddf9SRui Paulo wpa_tdls_remove_peers(sm); 2285*f05cddf9SRui Paulo } 2286*f05cddf9SRui Paulo 2287*f05cddf9SRui Paulo 2288*f05cddf9SRui Paulo static int wpa_tdls_prohibited(const u8 *ies, size_t len) 2289*f05cddf9SRui Paulo { 2290*f05cddf9SRui Paulo struct wpa_eapol_ie_parse elems; 2291*f05cddf9SRui Paulo 2292*f05cddf9SRui Paulo if (ies == NULL) 2293*f05cddf9SRui Paulo return 0; 2294*f05cddf9SRui Paulo 2295*f05cddf9SRui Paulo if (wpa_supplicant_parse_ies(ies, len, &elems) < 0) 2296*f05cddf9SRui Paulo return 0; 2297*f05cddf9SRui Paulo 2298*f05cddf9SRui Paulo if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5) 2299*f05cddf9SRui Paulo return 0; 2300*f05cddf9SRui Paulo 2301*f05cddf9SRui Paulo /* bit 38 - TDLS Prohibited */ 2302*f05cddf9SRui Paulo return !!(elems.ext_capab[2 + 4] & 0x40); 2303*f05cddf9SRui Paulo } 2304*f05cddf9SRui Paulo 2305*f05cddf9SRui Paulo 2306*f05cddf9SRui Paulo void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2307*f05cddf9SRui Paulo { 2308*f05cddf9SRui Paulo sm->tdls_prohibited = wpa_tdls_prohibited(ies, len); 2309*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS", 2310*f05cddf9SRui Paulo sm->tdls_prohibited ? "prohibited" : "allowed"); 2311*f05cddf9SRui Paulo } 2312*f05cddf9SRui Paulo 2313*f05cddf9SRui Paulo 2314*f05cddf9SRui Paulo void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len) 2315*f05cddf9SRui Paulo { 2316*f05cddf9SRui Paulo if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) { 2317*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on " 2318*f05cddf9SRui Paulo "(Re)Association Response IEs"); 2319*f05cddf9SRui Paulo sm->tdls_prohibited = 1; 2320*f05cddf9SRui Paulo } 2321*f05cddf9SRui Paulo } 2322*f05cddf9SRui Paulo 2323*f05cddf9SRui Paulo 2324*f05cddf9SRui Paulo void wpa_tdls_enable(struct wpa_sm *sm, int enabled) 2325*f05cddf9SRui Paulo { 2326*f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled"); 2327*f05cddf9SRui Paulo sm->tdls_disabled = !enabled; 2328*f05cddf9SRui Paulo } 2329*f05cddf9SRui Paulo 2330*f05cddf9SRui Paulo 2331*f05cddf9SRui Paulo int wpa_tdls_is_external_setup(struct wpa_sm *sm) 2332*f05cddf9SRui Paulo { 2333*f05cddf9SRui Paulo return sm->tdls_external_setup; 2334*f05cddf9SRui Paulo } 2335