1214501Srpaulo/* 2214501Srpaulo * wpa_supplicant - IBSS RSN 3281806Srpaulo * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12281806Srpaulo#include "common/wpa_ctrl.h" 13281806Srpaulo#include "utils/eloop.h" 14214501Srpaulo#include "l2_packet/l2_packet.h" 15214501Srpaulo#include "rsn_supp/wpa.h" 16214501Srpaulo#include "rsn_supp/wpa_ie.h" 17214501Srpaulo#include "ap/wpa_auth.h" 18214501Srpaulo#include "wpa_supplicant_i.h" 19214501Srpaulo#include "driver_i.h" 20281806Srpaulo#include "common/ieee802_11_defs.h" 21214501Srpaulo#include "ibss_rsn.h" 22214501Srpaulo 23214501Srpaulo 24281806Srpaulostatic void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx); 25281806Srpaulo 26281806Srpaulo 27252726Srpaulostatic struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, 28252726Srpaulo const u8 *addr) 29252726Srpaulo{ 30252726Srpaulo struct ibss_rsn_peer *peer; 31252726Srpaulo 32252726Srpaulo for (peer = ibss_rsn->peers; peer; peer = peer->next) 33252726Srpaulo if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) 34252726Srpaulo break; 35252726Srpaulo return peer; 36252726Srpaulo} 37252726Srpaulo 38252726Srpaulo 39214501Srpaulostatic void ibss_rsn_free(struct ibss_rsn_peer *peer) 40214501Srpaulo{ 41281806Srpaulo eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL); 42214501Srpaulo wpa_auth_sta_deinit(peer->auth); 43214501Srpaulo wpa_sm_deinit(peer->supp); 44214501Srpaulo os_free(peer); 45214501Srpaulo} 46214501Srpaulo 47214501Srpaulo 48214501Srpaulostatic void supp_set_state(void *ctx, enum wpa_states state) 49214501Srpaulo{ 50214501Srpaulo struct ibss_rsn_peer *peer = ctx; 51214501Srpaulo peer->supp_state = state; 52214501Srpaulo} 53214501Srpaulo 54214501Srpaulo 55252726Srpaulostatic enum wpa_states supp_get_state(void *ctx) 56252726Srpaulo{ 57252726Srpaulo struct ibss_rsn_peer *peer = ctx; 58252726Srpaulo return peer->supp_state; 59252726Srpaulo} 60252726Srpaulo 61252726Srpaulo 62214501Srpaulostatic int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, 63214501Srpaulo size_t len) 64214501Srpaulo{ 65214501Srpaulo struct ibss_rsn_peer *peer = ctx; 66214501Srpaulo struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; 67214501Srpaulo 68214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " 69214501Srpaulo "len=%lu)", 70214501Srpaulo __func__, MAC2STR(dest), proto, (unsigned long) len); 71214501Srpaulo 72214501Srpaulo if (wpa_s->l2) 73214501Srpaulo return l2_packet_send(wpa_s->l2, dest, proto, buf, len); 74214501Srpaulo 75281806Srpaulo return -1; 76214501Srpaulo} 77214501Srpaulo 78214501Srpaulo 79214501Srpaulostatic u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, 80214501Srpaulo u16 data_len, size_t *msg_len, void **data_pos) 81214501Srpaulo{ 82214501Srpaulo struct ieee802_1x_hdr *hdr; 83214501Srpaulo 84214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", 85214501Srpaulo __func__, type, data_len); 86214501Srpaulo 87214501Srpaulo *msg_len = sizeof(*hdr) + data_len; 88214501Srpaulo hdr = os_malloc(*msg_len); 89214501Srpaulo if (hdr == NULL) 90214501Srpaulo return NULL; 91214501Srpaulo 92214501Srpaulo hdr->version = 2; 93214501Srpaulo hdr->type = type; 94214501Srpaulo hdr->length = host_to_be16(data_len); 95214501Srpaulo 96214501Srpaulo if (data) 97214501Srpaulo os_memcpy(hdr + 1, data, data_len); 98214501Srpaulo else 99214501Srpaulo os_memset(hdr + 1, 0, data_len); 100214501Srpaulo 101214501Srpaulo if (data_pos) 102214501Srpaulo *data_pos = hdr + 1; 103214501Srpaulo 104214501Srpaulo return (u8 *) hdr; 105214501Srpaulo} 106214501Srpaulo 107214501Srpaulo 108214501Srpaulostatic int supp_get_beacon_ie(void *ctx) 109214501Srpaulo{ 110214501Srpaulo struct ibss_rsn_peer *peer = ctx; 111214501Srpaulo 112214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); 113214501Srpaulo /* TODO: get correct RSN IE */ 114214501Srpaulo return wpa_sm_set_ap_rsn_ie(peer->supp, 115214501Srpaulo (u8 *) "\x30\x14\x01\x00" 116214501Srpaulo "\x00\x0f\xac\x04" 117214501Srpaulo "\x01\x00\x00\x0f\xac\x04" 118214501Srpaulo "\x01\x00\x00\x0f\xac\x02" 119214501Srpaulo "\x00\x00", 22); 120214501Srpaulo} 121214501Srpaulo 122214501Srpaulo 123281806Srpaulostatic void ibss_check_rsn_completed(struct ibss_rsn_peer *peer) 124281806Srpaulo{ 125281806Srpaulo struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; 126281806Srpaulo 127281806Srpaulo if ((peer->authentication_status & 128281806Srpaulo (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) != 129281806Srpaulo (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) 130281806Srpaulo return; 131281806Srpaulo if (peer->authentication_status & IBSS_RSN_REPORTED_PTK) 132281806Srpaulo return; 133281806Srpaulo peer->authentication_status |= IBSS_RSN_REPORTED_PTK; 134281806Srpaulo wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR, 135281806Srpaulo MAC2STR(peer->addr)); 136281806Srpaulo} 137281806Srpaulo 138281806Srpaulo 139214501Srpaulostatic int supp_set_key(void *ctx, enum wpa_alg alg, 140214501Srpaulo const u8 *addr, int key_idx, int set_tx, 141214501Srpaulo const u8 *seq, size_t seq_len, 142214501Srpaulo const u8 *key, size_t key_len) 143214501Srpaulo{ 144214501Srpaulo struct ibss_rsn_peer *peer = ctx; 145214501Srpaulo 146214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " 147214501Srpaulo "set_tx=%d)", 148214501Srpaulo __func__, alg, MAC2STR(addr), key_idx, set_tx); 149214501Srpaulo wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); 150214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len); 151214501Srpaulo 152214501Srpaulo if (key_idx == 0) { 153281806Srpaulo peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP; 154281806Srpaulo ibss_check_rsn_completed(peer); 155214501Srpaulo /* 156214501Srpaulo * In IBSS RSN, the pairwise key from the 4-way handshake 157214501Srpaulo * initiated by the peer with highest MAC address is used. 158214501Srpaulo */ 159214501Srpaulo if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr, 160214501Srpaulo ETH_ALEN) > 0) { 161214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK"); 162214501Srpaulo return 0; 163214501Srpaulo } 164214501Srpaulo } 165214501Srpaulo 166252726Srpaulo if (is_broadcast_ether_addr(addr)) 167252726Srpaulo addr = peer->addr; 168214501Srpaulo return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, 169214501Srpaulo set_tx, seq, seq_len, key, key_len); 170214501Srpaulo} 171214501Srpaulo 172214501Srpaulo 173214501Srpaulostatic void * supp_get_network_ctx(void *ctx) 174214501Srpaulo{ 175214501Srpaulo struct ibss_rsn_peer *peer = ctx; 176214501Srpaulo return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s); 177214501Srpaulo} 178214501Srpaulo 179214501Srpaulo 180214501Srpaulostatic int supp_mlme_setprotection(void *ctx, const u8 *addr, 181214501Srpaulo int protection_type, int key_type) 182214501Srpaulo{ 183214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " 184214501Srpaulo "key_type=%d)", 185214501Srpaulo __func__, MAC2STR(addr), protection_type, key_type); 186214501Srpaulo return 0; 187214501Srpaulo} 188214501Srpaulo 189214501Srpaulo 190214501Srpaulostatic void supp_cancel_auth_timeout(void *ctx) 191214501Srpaulo{ 192214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); 193214501Srpaulo} 194214501Srpaulo 195214501Srpaulo 196351611Scystatic void supp_deauthenticate(void * ctx, u16 reason_code) 197214501Srpaulo{ 198252726Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); 199252726Srpaulo} 200252726Srpaulo 201252726Srpaulo 202252726Srpaulostatic int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, 203252726Srpaulo const u8 *psk) 204252726Srpaulo{ 205214501Srpaulo struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); 206214501Srpaulo if (ctx == NULL) 207214501Srpaulo return -1; 208214501Srpaulo 209214501Srpaulo ctx->ctx = peer; 210214501Srpaulo ctx->msg_ctx = peer->ibss_rsn->wpa_s; 211214501Srpaulo ctx->set_state = supp_set_state; 212252726Srpaulo ctx->get_state = supp_get_state; 213214501Srpaulo ctx->ether_send = supp_ether_send; 214214501Srpaulo ctx->get_beacon_ie = supp_get_beacon_ie; 215214501Srpaulo ctx->alloc_eapol = supp_alloc_eapol; 216214501Srpaulo ctx->set_key = supp_set_key; 217214501Srpaulo ctx->get_network_ctx = supp_get_network_ctx; 218214501Srpaulo ctx->mlme_setprotection = supp_mlme_setprotection; 219214501Srpaulo ctx->cancel_auth_timeout = supp_cancel_auth_timeout; 220252726Srpaulo ctx->deauthenticate = supp_deauthenticate; 221214501Srpaulo peer->supp = wpa_sm_init(ctx); 222214501Srpaulo if (peer->supp == NULL) { 223214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); 224337817Scy os_free(ctx); 225214501Srpaulo return -1; 226214501Srpaulo } 227214501Srpaulo 228214501Srpaulo wpa_sm_set_own_addr(peer->supp, own_addr); 229214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); 230214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); 231214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); 232214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); 233214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); 234337817Scy wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL, NULL); 235214501Srpaulo 236214501Srpaulo peer->supp_ie_len = sizeof(peer->supp_ie); 237214501Srpaulo if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, 238214501Srpaulo &peer->supp_ie_len) < 0) { 239214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" 240214501Srpaulo " failed"); 241214501Srpaulo return -1; 242214501Srpaulo } 243214501Srpaulo 244214501Srpaulo wpa_sm_notify_assoc(peer->supp, peer->addr); 245214501Srpaulo 246214501Srpaulo return 0; 247214501Srpaulo} 248214501Srpaulo 249214501Srpaulo 250214501Srpaulostatic void auth_logger(void *ctx, const u8 *addr, logger_level level, 251214501Srpaulo const char *txt) 252214501Srpaulo{ 253214501Srpaulo if (addr) 254214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", 255214501Srpaulo MAC2STR(addr), txt); 256214501Srpaulo else 257214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s", txt); 258214501Srpaulo} 259214501Srpaulo 260214501Srpaulo 261281806Srpaulostatic const u8 * auth_get_psk(void *ctx, const u8 *addr, 262346981Scy const u8 *p2p_dev_addr, const u8 *prev_psk, 263346981Scy size_t *psk_len, int *vlan_id) 264214501Srpaulo{ 265214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 266346981Scy 267346981Scy if (psk_len) 268346981Scy *psk_len = PMK_LEN; 269346981Scy if (vlan_id) 270346981Scy *vlan_id = 0; 271214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", 272214501Srpaulo __func__, MAC2STR(addr), prev_psk); 273214501Srpaulo if (prev_psk) 274214501Srpaulo return NULL; 275214501Srpaulo return ibss_rsn->psk; 276214501Srpaulo} 277214501Srpaulo 278214501Srpaulo 279214501Srpaulostatic int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, 280214501Srpaulo size_t data_len, int encrypt) 281214501Srpaulo{ 282214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 283214501Srpaulo struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; 284214501Srpaulo 285214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " 286214501Srpaulo "encrypt=%d)", 287214501Srpaulo __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); 288214501Srpaulo 289214501Srpaulo if (wpa_s->l2) 290214501Srpaulo return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, 291214501Srpaulo data_len); 292214501Srpaulo 293281806Srpaulo return -1; 294214501Srpaulo} 295214501Srpaulo 296214501Srpaulo 297214501Srpaulostatic int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 298214501Srpaulo const u8 *addr, int idx, u8 *key, size_t key_len) 299214501Srpaulo{ 300214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 301214501Srpaulo u8 seq[6]; 302214501Srpaulo 303214501Srpaulo os_memset(seq, 0, sizeof(seq)); 304214501Srpaulo 305214501Srpaulo if (addr) { 306214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR 307214501Srpaulo " key_idx=%d)", 308214501Srpaulo __func__, alg, MAC2STR(addr), idx); 309214501Srpaulo } else { 310214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", 311214501Srpaulo __func__, alg, idx); 312214501Srpaulo } 313214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); 314214501Srpaulo 315214501Srpaulo if (idx == 0) { 316281806Srpaulo if (addr) { 317281806Srpaulo struct ibss_rsn_peer *peer; 318281806Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, addr); 319281806Srpaulo if (peer) { 320281806Srpaulo peer->authentication_status |= 321281806Srpaulo IBSS_RSN_SET_PTK_AUTH; 322281806Srpaulo ibss_check_rsn_completed(peer); 323281806Srpaulo } 324281806Srpaulo } 325214501Srpaulo /* 326214501Srpaulo * In IBSS RSN, the pairwise key from the 4-way handshake 327214501Srpaulo * initiated by the peer with highest MAC address is used. 328214501Srpaulo */ 329214501Srpaulo if (addr == NULL || 330214501Srpaulo os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) { 331214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK"); 332214501Srpaulo return 0; 333214501Srpaulo } 334214501Srpaulo } 335214501Srpaulo 336214501Srpaulo return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, 337214501Srpaulo 1, seq, 6, key, key_len); 338214501Srpaulo} 339214501Srpaulo 340214501Srpaulo 341281806Srpaulostatic void ibss_rsn_disconnect(void *ctx, const u8 *addr, u16 reason) 342281806Srpaulo{ 343281806Srpaulo struct ibss_rsn *ibss_rsn = ctx; 344281806Srpaulo wpa_drv_sta_deauth(ibss_rsn->wpa_s, addr, reason); 345281806Srpaulo} 346281806Srpaulo 347281806Srpaulo 348252726Srpaulostatic int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm, 349252726Srpaulo void *ctx), 350252726Srpaulo void *cb_ctx) 351252726Srpaulo{ 352252726Srpaulo struct ibss_rsn *ibss_rsn = ctx; 353252726Srpaulo struct ibss_rsn_peer *peer; 354252726Srpaulo 355252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: for_each_sta"); 356252726Srpaulo 357252726Srpaulo for (peer = ibss_rsn->peers; peer; peer = peer->next) { 358252726Srpaulo if (peer->auth && cb(peer->auth, cb_ctx)) 359252726Srpaulo return 1; 360252726Srpaulo } 361252726Srpaulo 362252726Srpaulo return 0; 363252726Srpaulo} 364252726Srpaulo 365252726Srpaulo 366252726Srpaulostatic void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn, 367252726Srpaulo struct ibss_rsn_peer *peer, int authorized) 368252726Srpaulo{ 369252726Srpaulo int res; 370252726Srpaulo 371252726Srpaulo if (authorized) { 372252726Srpaulo res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, 373252726Srpaulo WPA_STA_AUTHORIZED, 374252726Srpaulo WPA_STA_AUTHORIZED, ~0); 375252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port", 376252726Srpaulo MAC2STR(peer->addr)); 377252726Srpaulo } else { 378252726Srpaulo res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, 379252726Srpaulo 0, 0, ~WPA_STA_AUTHORIZED); 380252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port", 381252726Srpaulo MAC2STR(peer->addr)); 382252726Srpaulo } 383252726Srpaulo 384252726Srpaulo if (res && errno != ENOENT) { 385252726Srpaulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags " 386252726Srpaulo "for kernel driver (errno=%d)", 387252726Srpaulo MAC2STR(peer->addr), errno); 388252726Srpaulo } 389252726Srpaulo} 390252726Srpaulo 391252726Srpaulo 392252726Srpaulostatic void auth_set_eapol(void *ctx, const u8 *addr, 393252726Srpaulo wpa_eapol_variable var, int value) 394252726Srpaulo{ 395252726Srpaulo struct ibss_rsn *ibss_rsn = ctx; 396252726Srpaulo struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr); 397252726Srpaulo 398252726Srpaulo if (peer == NULL) 399252726Srpaulo return; 400252726Srpaulo 401252726Srpaulo switch (var) { 402252726Srpaulo case WPA_EAPOL_authorized: 403252726Srpaulo ibss_set_sta_authorized(ibss_rsn, peer, value); 404252726Srpaulo break; 405252726Srpaulo default: 406252726Srpaulo /* do not handle any other event */ 407252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var); 408252726Srpaulo break; 409252726Srpaulo } 410252726Srpaulo} 411252726Srpaulo 412252726Srpaulo 413214501Srpaulostatic int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, 414337817Scy const u8 *own_addr, struct wpa_ssid *ssid) 415214501Srpaulo{ 416214501Srpaulo struct wpa_auth_config conf; 417346981Scy static const struct wpa_auth_callbacks cb = { 418346981Scy .logger = auth_logger, 419346981Scy .set_eapol = auth_set_eapol, 420346981Scy .send_eapol = auth_send_eapol, 421346981Scy .get_psk = auth_get_psk, 422346981Scy .set_key = auth_set_key, 423346981Scy .for_each_sta = auth_for_each_sta, 424346981Scy .disconnect = ibss_rsn_disconnect, 425346981Scy }; 426214501Srpaulo 427214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); 428214501Srpaulo 429214501Srpaulo os_memset(&conf, 0, sizeof(conf)); 430214501Srpaulo conf.wpa = 2; 431214501Srpaulo conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; 432214501Srpaulo conf.wpa_pairwise = WPA_CIPHER_CCMP; 433214501Srpaulo conf.rsn_pairwise = WPA_CIPHER_CCMP; 434214501Srpaulo conf.wpa_group = WPA_CIPHER_CCMP; 435214501Srpaulo conf.eapol_version = 2; 436337817Scy conf.wpa_group_rekey = ssid->group_rekey ? ssid->group_rekey : 600; 437346981Scy conf.wpa_group_update_count = 4; 438346981Scy conf.wpa_pairwise_update_count = 4; 439214501Srpaulo 440346981Scy ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb, ibss_rsn); 441214501Srpaulo if (ibss_rsn->auth_group == NULL) { 442214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); 443214501Srpaulo return -1; 444214501Srpaulo } 445214501Srpaulo 446252726Srpaulo wpa_init_keys(ibss_rsn->auth_group); 447252726Srpaulo 448214501Srpaulo return 0; 449214501Srpaulo} 450214501Srpaulo 451214501Srpaulo 452214501Srpaulostatic int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, 453214501Srpaulo struct ibss_rsn_peer *peer) 454214501Srpaulo{ 455281806Srpaulo peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr, NULL); 456214501Srpaulo if (peer->auth == NULL) { 457214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); 458214501Srpaulo return -1; 459214501Srpaulo } 460214501Srpaulo 461214501Srpaulo /* TODO: get peer RSN IE with Probe Request */ 462346981Scy if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, 0, 463214501Srpaulo (u8 *) "\x30\x14\x01\x00" 464214501Srpaulo "\x00\x0f\xac\x04" 465214501Srpaulo "\x01\x00\x00\x0f\xac\x04" 466214501Srpaulo "\x01\x00\x00\x0f\xac\x02" 467346981Scy "\x00\x00", 22, NULL, 0, NULL, 0) != 468214501Srpaulo WPA_IE_OK) { 469214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); 470214501Srpaulo return -1; 471214501Srpaulo } 472214501Srpaulo 473214501Srpaulo if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) 474214501Srpaulo return -1; 475214501Srpaulo 476214501Srpaulo if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) 477214501Srpaulo return -1; 478214501Srpaulo 479214501Srpaulo return 0; 480214501Srpaulo} 481214501Srpaulo 482214501Srpaulo 483281806Srpaulostatic int ibss_rsn_send_auth(struct ibss_rsn *ibss_rsn, const u8 *da, int seq) 484214501Srpaulo{ 485281806Srpaulo struct ieee80211_mgmt auth; 486281806Srpaulo const size_t auth_length = IEEE80211_HDRLEN + sizeof(auth.u.auth); 487281806Srpaulo struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; 488214501Srpaulo 489281806Srpaulo if (wpa_s->driver->send_frame == NULL) 490252726Srpaulo return -1; 491252726Srpaulo 492281806Srpaulo os_memset(&auth, 0, sizeof(auth)); 493281806Srpaulo 494281806Srpaulo auth.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 495281806Srpaulo WLAN_FC_STYPE_AUTH); 496281806Srpaulo os_memcpy(auth.da, da, ETH_ALEN); 497281806Srpaulo os_memcpy(auth.sa, wpa_s->own_addr, ETH_ALEN); 498281806Srpaulo os_memcpy(auth.bssid, wpa_s->bssid, ETH_ALEN); 499281806Srpaulo 500281806Srpaulo auth.u.auth.auth_alg = host_to_le16(WLAN_AUTH_OPEN); 501281806Srpaulo auth.u.auth.auth_transaction = host_to_le16(seq); 502281806Srpaulo auth.u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS); 503281806Srpaulo 504281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS TX Auth frame (SEQ %d) to " MACSTR, 505281806Srpaulo seq, MAC2STR(da)); 506281806Srpaulo 507281806Srpaulo return wpa_s->driver->send_frame(wpa_s->drv_priv, (u8 *) &auth, 508281806Srpaulo auth_length, 0); 509281806Srpaulo} 510281806Srpaulo 511281806Srpaulo 512281806Srpaulostatic int ibss_rsn_is_auth_started(struct ibss_rsn_peer * peer) 513281806Srpaulo{ 514281806Srpaulo return peer->authentication_status & 515281806Srpaulo (IBSS_RSN_AUTH_BY_US | IBSS_RSN_AUTH_EAPOL_BY_US); 516281806Srpaulo} 517281806Srpaulo 518281806Srpaulo 519281806Srpaulostatic struct ibss_rsn_peer * 520281806Srpauloibss_rsn_peer_init(struct ibss_rsn *ibss_rsn, const u8 *addr) 521281806Srpaulo{ 522281806Srpaulo struct ibss_rsn_peer *peer; 523281806Srpaulo if (ibss_rsn == NULL) 524281806Srpaulo return NULL; 525281806Srpaulo 526281806Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, addr); 527281806Srpaulo if (peer) { 528281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Supplicant for peer "MACSTR 529281806Srpaulo " already running", MAC2STR(addr)); 530281806Srpaulo return peer; 531252726Srpaulo } 532252726Srpaulo 533281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Supplicant for peer "MACSTR, 534281806Srpaulo MAC2STR(addr)); 535214501Srpaulo 536214501Srpaulo peer = os_zalloc(sizeof(*peer)); 537281806Srpaulo if (peer == NULL) { 538281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: Could not allocate memory."); 539281806Srpaulo return NULL; 540281806Srpaulo } 541214501Srpaulo 542214501Srpaulo peer->ibss_rsn = ibss_rsn; 543214501Srpaulo os_memcpy(peer->addr, addr, ETH_ALEN); 544281806Srpaulo peer->authentication_status = IBSS_RSN_AUTH_NOT_AUTHENTICATED; 545214501Srpaulo 546281806Srpaulo if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, 547281806Srpaulo ibss_rsn->psk) < 0) { 548214501Srpaulo ibss_rsn_free(peer); 549281806Srpaulo return NULL; 550281806Srpaulo } 551281806Srpaulo 552281806Srpaulo peer->next = ibss_rsn->peers; 553281806Srpaulo ibss_rsn->peers = peer; 554281806Srpaulo 555281806Srpaulo return peer; 556281806Srpaulo} 557281806Srpaulo 558281806Srpaulo 559281806Srpaulostatic void ibss_rsn_auth_timeout(void *eloop_ctx, void *timeout_ctx) 560281806Srpaulo{ 561281806Srpaulo struct ibss_rsn_peer *peer = eloop_ctx; 562281806Srpaulo 563281806Srpaulo /* 564281806Srpaulo * Assume peer does not support Authentication exchange or the frame was 565281806Srpaulo * lost somewhere - start EAPOL Authenticator. 566281806Srpaulo */ 567281806Srpaulo wpa_printf(MSG_DEBUG, 568281806Srpaulo "RSN: Timeout on waiting Authentication frame response from " 569281806Srpaulo MACSTR " - start authenticator", MAC2STR(peer->addr)); 570281806Srpaulo 571281806Srpaulo peer->authentication_status |= IBSS_RSN_AUTH_BY_US; 572281806Srpaulo ibss_rsn_auth_init(peer->ibss_rsn, peer); 573281806Srpaulo} 574281806Srpaulo 575281806Srpaulo 576281806Srpauloint ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) 577281806Srpaulo{ 578281806Srpaulo struct ibss_rsn_peer *peer; 579281806Srpaulo int res; 580281806Srpaulo 581289549Srpaulo if (!ibss_rsn) 582289549Srpaulo return -1; 583289549Srpaulo 584281806Srpaulo /* if the peer already exists, exit immediately */ 585281806Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, addr); 586281806Srpaulo if (peer) 587281806Srpaulo return 0; 588281806Srpaulo 589281806Srpaulo peer = ibss_rsn_peer_init(ibss_rsn, addr); 590281806Srpaulo if (peer == NULL) 591214501Srpaulo return -1; 592281806Srpaulo 593281806Srpaulo /* Open Authentication: send first Authentication frame */ 594281806Srpaulo res = ibss_rsn_send_auth(ibss_rsn, addr, 1); 595281806Srpaulo if (res) { 596281806Srpaulo /* 597281806Srpaulo * The driver may not support Authentication frame exchange in 598281806Srpaulo * IBSS. Ignore authentication and go through EAPOL exchange. 599281806Srpaulo */ 600281806Srpaulo peer->authentication_status |= IBSS_RSN_AUTH_BY_US; 601281806Srpaulo return ibss_rsn_auth_init(ibss_rsn, peer); 602281806Srpaulo } else { 603281806Srpaulo os_get_reltime(&peer->own_auth_tx); 604281806Srpaulo eloop_register_timeout(1, 0, ibss_rsn_auth_timeout, peer, NULL); 605214501Srpaulo } 606214501Srpaulo 607281806Srpaulo return 0; 608281806Srpaulo} 609281806Srpaulo 610281806Srpaulo 611281806Srpaulostatic int ibss_rsn_peer_authenticated(struct ibss_rsn *ibss_rsn, 612281806Srpaulo struct ibss_rsn_peer *peer, int reason) 613281806Srpaulo{ 614281806Srpaulo int already_started; 615281806Srpaulo 616281806Srpaulo if (ibss_rsn == NULL || peer == NULL) 617214501Srpaulo return -1; 618281806Srpaulo 619281806Srpaulo already_started = ibss_rsn_is_auth_started(peer); 620281806Srpaulo peer->authentication_status |= reason; 621281806Srpaulo 622281806Srpaulo if (already_started) { 623281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator already " 624281806Srpaulo "started for peer " MACSTR, MAC2STR(peer->addr)); 625281806Srpaulo return 0; 626214501Srpaulo } 627214501Srpaulo 628281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator " 629281806Srpaulo "for now-authenticated peer " MACSTR, MAC2STR(peer->addr)); 630214501Srpaulo 631281806Srpaulo return ibss_rsn_auth_init(ibss_rsn, peer); 632214501Srpaulo} 633214501Srpaulo 634214501Srpaulo 635252726Srpaulovoid ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) 636252726Srpaulo{ 637252726Srpaulo struct ibss_rsn_peer *peer, *prev; 638252726Srpaulo 639252726Srpaulo if (ibss_rsn == NULL) 640252726Srpaulo return; 641252726Srpaulo 642252726Srpaulo if (peermac == NULL) { 643252726Srpaulo /* remove all peers */ 644252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__); 645252726Srpaulo peer = ibss_rsn->peers; 646252726Srpaulo while (peer) { 647252726Srpaulo prev = peer; 648252726Srpaulo peer = peer->next; 649252726Srpaulo ibss_rsn_free(prev); 650252726Srpaulo ibss_rsn->peers = peer; 651252726Srpaulo } 652252726Srpaulo } else { 653252726Srpaulo /* remove specific peer */ 654252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR, 655252726Srpaulo __func__, MAC2STR(peermac)); 656252726Srpaulo 657252726Srpaulo for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; 658252726Srpaulo prev = peer, peer = peer->next) { 659252726Srpaulo if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { 660252726Srpaulo if (prev == NULL) 661252726Srpaulo ibss_rsn->peers = peer->next; 662252726Srpaulo else 663252726Srpaulo prev->next = peer->next; 664252726Srpaulo ibss_rsn_free(peer); 665252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Successfully " 666252726Srpaulo "removed a specific peer", 667252726Srpaulo __func__); 668252726Srpaulo break; 669252726Srpaulo } 670252726Srpaulo } 671252726Srpaulo } 672252726Srpaulo} 673252726Srpaulo 674252726Srpaulo 675337817Scystruct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s, 676337817Scy struct wpa_ssid *ssid) 677214501Srpaulo{ 678214501Srpaulo struct ibss_rsn *ibss_rsn; 679214501Srpaulo 680214501Srpaulo ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); 681214501Srpaulo if (ibss_rsn == NULL) 682214501Srpaulo return NULL; 683214501Srpaulo ibss_rsn->wpa_s = wpa_s; 684214501Srpaulo 685337817Scy if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr, ssid) < 0) { 686214501Srpaulo ibss_rsn_deinit(ibss_rsn); 687214501Srpaulo return NULL; 688214501Srpaulo } 689214501Srpaulo 690214501Srpaulo return ibss_rsn; 691214501Srpaulo} 692214501Srpaulo 693214501Srpaulo 694214501Srpaulovoid ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) 695214501Srpaulo{ 696214501Srpaulo struct ibss_rsn_peer *peer, *prev; 697214501Srpaulo 698214501Srpaulo if (ibss_rsn == NULL) 699214501Srpaulo return; 700214501Srpaulo 701214501Srpaulo peer = ibss_rsn->peers; 702214501Srpaulo while (peer) { 703214501Srpaulo prev = peer; 704214501Srpaulo peer = peer->next; 705214501Srpaulo ibss_rsn_free(prev); 706214501Srpaulo } 707214501Srpaulo 708289549Srpaulo if (ibss_rsn->auth_group) 709289549Srpaulo wpa_deinit(ibss_rsn->auth_group); 710214501Srpaulo os_free(ibss_rsn); 711214501Srpaulo 712214501Srpaulo} 713214501Srpaulo 714214501Srpaulo 715214501Srpaulostatic int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) 716214501Srpaulo{ 717214501Srpaulo const struct ieee802_1x_hdr *hdr; 718214501Srpaulo const struct wpa_eapol_key *key; 719214501Srpaulo u16 key_info; 720214501Srpaulo size_t plen; 721214501Srpaulo 722214501Srpaulo /* TODO: Support other EAPOL packets than just EAPOL-Key */ 723214501Srpaulo 724214501Srpaulo if (len < sizeof(*hdr) + sizeof(*key)) 725214501Srpaulo return -1; 726214501Srpaulo 727214501Srpaulo hdr = (const struct ieee802_1x_hdr *) buf; 728214501Srpaulo key = (const struct wpa_eapol_key *) (hdr + 1); 729214501Srpaulo plen = be_to_host16(hdr->length); 730214501Srpaulo 731214501Srpaulo if (hdr->version < EAPOL_VERSION) { 732214501Srpaulo /* TODO: backwards compatibility */ 733214501Srpaulo } 734214501Srpaulo if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { 735214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, " 736214501Srpaulo "not a Key frame", hdr->type); 737214501Srpaulo return -1; 738214501Srpaulo } 739214501Srpaulo if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { 740214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu " 741214501Srpaulo "invalid (frame size %lu)", 742214501Srpaulo (unsigned long) plen, (unsigned long) len); 743214501Srpaulo return -1; 744214501Srpaulo } 745214501Srpaulo 746214501Srpaulo if (key->type != EAPOL_KEY_TYPE_RSN) { 747214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, " 748214501Srpaulo "discarded", key->type); 749214501Srpaulo return -1; 750214501Srpaulo } 751214501Srpaulo 752214501Srpaulo key_info = WPA_GET_BE16(key->key_info); 753214501Srpaulo 754214501Srpaulo return !!(key_info & WPA_KEY_INFO_ACK); 755214501Srpaulo} 756214501Srpaulo 757214501Srpaulo 758214501Srpaulostatic int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, 759214501Srpaulo struct ibss_rsn_peer *peer, 760214501Srpaulo const u8 *buf, size_t len) 761214501Srpaulo{ 762214501Srpaulo int supp; 763214501Srpaulo u8 *tmp; 764214501Srpaulo 765214501Srpaulo supp = ibss_rsn_eapol_dst_supp(buf, len); 766214501Srpaulo if (supp < 0) 767214501Srpaulo return -1; 768214501Srpaulo 769346981Scy tmp = os_memdup(buf, len); 770214501Srpaulo if (tmp == NULL) 771214501Srpaulo return -1; 772214501Srpaulo if (supp) { 773281806Srpaulo peer->authentication_status |= IBSS_RSN_AUTH_EAPOL_BY_PEER; 774281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant from " 775281806Srpaulo MACSTR, MAC2STR(peer->addr)); 776214501Srpaulo wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); 777214501Srpaulo } else { 778281806Srpaulo if (ibss_rsn_is_auth_started(peer) == 0) { 779281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS EAPOL for " 780281806Srpaulo "Authenticator dropped as " MACSTR " is not " 781281806Srpaulo "authenticated", MAC2STR(peer->addr)); 782281806Srpaulo os_free(tmp); 783281806Srpaulo return -1; 784281806Srpaulo } 785281806Srpaulo 786281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator " 787281806Srpaulo "from "MACSTR, MAC2STR(peer->addr)); 788214501Srpaulo wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); 789214501Srpaulo } 790214501Srpaulo os_free(tmp); 791214501Srpaulo 792214501Srpaulo return 1; 793214501Srpaulo} 794214501Srpaulo 795214501Srpaulo 796214501Srpauloint ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, 797214501Srpaulo const u8 *buf, size_t len) 798214501Srpaulo{ 799214501Srpaulo struct ibss_rsn_peer *peer; 800214501Srpaulo 801252726Srpaulo if (ibss_rsn == NULL) 802252726Srpaulo return -1; 803214501Srpaulo 804252726Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, src_addr); 805252726Srpaulo if (peer) 806252726Srpaulo return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); 807252726Srpaulo 808214501Srpaulo if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { 809214501Srpaulo /* 810214501Srpaulo * Create new IBSS peer based on an EAPOL message from the peer 811214501Srpaulo * Authenticator. 812214501Srpaulo */ 813281806Srpaulo peer = ibss_rsn_peer_init(ibss_rsn, src_addr); 814281806Srpaulo if (peer == NULL) 815214501Srpaulo return -1; 816281806Srpaulo 817281806Srpaulo /* assume the peer is authenticated already */ 818281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Not using IBSS Auth for peer " 819281806Srpaulo MACSTR, MAC2STR(src_addr)); 820281806Srpaulo ibss_rsn_peer_authenticated(ibss_rsn, peer, 821281806Srpaulo IBSS_RSN_AUTH_EAPOL_BY_US); 822281806Srpaulo 823214501Srpaulo return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, 824214501Srpaulo buf, len); 825214501Srpaulo } 826214501Srpaulo 827214501Srpaulo return 0; 828214501Srpaulo} 829214501Srpaulo 830214501Srpaulovoid ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) 831214501Srpaulo{ 832252726Srpaulo if (ibss_rsn == NULL) 833252726Srpaulo return; 834214501Srpaulo os_memcpy(ibss_rsn->psk, psk, PMK_LEN); 835214501Srpaulo} 836281806Srpaulo 837281806Srpaulo 838281806Srpaulostatic void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn, 839281806Srpaulo struct ibss_rsn_peer *peer, 840281806Srpaulo const u8* addr) 841281806Srpaulo{ 842281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 1) from " MACSTR, 843281806Srpaulo MAC2STR(addr)); 844281806Srpaulo 845281806Srpaulo if (peer && 846346981Scy peer->authentication_status & (IBSS_RSN_SET_PTK_SUPP | 847346981Scy IBSS_RSN_SET_PTK_AUTH)) { 848346981Scy /* Clear the TK for this pair to allow recovery from the case 849346981Scy * where the peer STA has restarted and lost its key while we 850346981Scy * still have a pairwise key configured. */ 851346981Scy wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer " 852346981Scy MACSTR, MAC2STR(addr)); 853346981Scy wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0, 854346981Scy NULL, 0, NULL, 0); 855346981Scy } 856346981Scy 857346981Scy if (peer && 858281806Srpaulo peer->authentication_status & IBSS_RSN_AUTH_EAPOL_BY_PEER) { 859281806Srpaulo if (peer->own_auth_tx.sec) { 860281806Srpaulo struct os_reltime now, diff; 861281806Srpaulo os_get_reltime(&now); 862281806Srpaulo os_reltime_sub(&now, &peer->own_auth_tx, &diff); 863281806Srpaulo if (diff.sec == 0 && diff.usec < 500000) { 864281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: Skip IBSS reinit since only %u usec from own Auth frame TX", 865281806Srpaulo (int) diff.usec); 866281806Srpaulo goto skip_reinit; 867281806Srpaulo } 868281806Srpaulo } 869281806Srpaulo /* 870281806Srpaulo * A peer sent us an Authentication frame even though it already 871281806Srpaulo * started an EAPOL session. We should reinit state machines 872281806Srpaulo * here, but it's much more complicated than just deleting and 873281806Srpaulo * recreating the state machine 874281806Srpaulo */ 875281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Reinitializing station " 876281806Srpaulo MACSTR, MAC2STR(addr)); 877281806Srpaulo 878281806Srpaulo ibss_rsn_stop(ibss_rsn, addr); 879281806Srpaulo peer = NULL; 880281806Srpaulo } 881281806Srpaulo 882281806Srpaulo if (!peer) { 883281806Srpaulo peer = ibss_rsn_peer_init(ibss_rsn, addr); 884281806Srpaulo if (!peer) 885281806Srpaulo return; 886281806Srpaulo 887281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Auth started by peer " MACSTR, 888281806Srpaulo MAC2STR(addr)); 889281806Srpaulo } 890281806Srpaulo 891281806Srpauloskip_reinit: 892281806Srpaulo /* reply with an Authentication frame now, before sending an EAPOL */ 893281806Srpaulo ibss_rsn_send_auth(ibss_rsn, addr, 2); 894281806Srpaulo /* no need to start another AUTH challenge in the other way.. */ 895281806Srpaulo ibss_rsn_peer_authenticated(ibss_rsn, peer, IBSS_RSN_AUTH_EAPOL_BY_US); 896281806Srpaulo} 897281806Srpaulo 898281806Srpaulo 899281806Srpaulovoid ibss_rsn_handle_auth(struct ibss_rsn *ibss_rsn, const u8 *auth_frame, 900281806Srpaulo size_t len) 901281806Srpaulo{ 902281806Srpaulo const struct ieee80211_mgmt *header; 903281806Srpaulo struct ibss_rsn_peer *peer; 904281806Srpaulo size_t auth_length; 905281806Srpaulo 906281806Srpaulo header = (const struct ieee80211_mgmt *) auth_frame; 907281806Srpaulo auth_length = IEEE80211_HDRLEN + sizeof(header->u.auth); 908281806Srpaulo 909281806Srpaulo if (ibss_rsn == NULL || len < auth_length) 910281806Srpaulo return; 911281806Srpaulo 912281806Srpaulo if (le_to_host16(header->u.auth.auth_alg) != WLAN_AUTH_OPEN || 913281806Srpaulo le_to_host16(header->u.auth.status_code) != WLAN_STATUS_SUCCESS) 914281806Srpaulo return; 915281806Srpaulo 916281806Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, header->sa); 917281806Srpaulo 918281806Srpaulo switch (le_to_host16(header->u.auth.auth_transaction)) { 919281806Srpaulo case 1: 920281806Srpaulo ibss_rsn_handle_auth_1_of_2(ibss_rsn, peer, header->sa); 921281806Srpaulo break; 922281806Srpaulo case 2: 923281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX Auth frame (SEQ 2) from " 924281806Srpaulo MACSTR, MAC2STR(header->sa)); 925281806Srpaulo if (!peer) { 926281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: Received Auth seq 2 from " 927281806Srpaulo "unknown STA " MACSTR, MAC2STR(header->sa)); 928281806Srpaulo break; 929281806Srpaulo } 930281806Srpaulo 931281806Srpaulo /* authentication has been completed */ 932281806Srpaulo eloop_cancel_timeout(ibss_rsn_auth_timeout, peer, NULL); 933281806Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Auth completed with " MACSTR, 934281806Srpaulo MAC2STR(header->sa)); 935281806Srpaulo ibss_rsn_peer_authenticated(ibss_rsn, peer, 936281806Srpaulo IBSS_RSN_AUTH_BY_US); 937281806Srpaulo break; 938281806Srpaulo } 939281806Srpaulo} 940