ibss_rsn.c revision 252726
1214501Srpaulo/* 2214501Srpaulo * wpa_supplicant - IBSS RSN 3214501Srpaulo * Copyright (c) 2009, 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" 12214501Srpaulo#include "l2_packet/l2_packet.h" 13214501Srpaulo#include "rsn_supp/wpa.h" 14214501Srpaulo#include "rsn_supp/wpa_ie.h" 15214501Srpaulo#include "ap/wpa_auth.h" 16214501Srpaulo#include "wpa_supplicant_i.h" 17214501Srpaulo#include "driver_i.h" 18214501Srpaulo#include "ibss_rsn.h" 19214501Srpaulo 20214501Srpaulo 21252726Srpaulostatic struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, 22252726Srpaulo const u8 *addr) 23252726Srpaulo{ 24252726Srpaulo struct ibss_rsn_peer *peer; 25252726Srpaulo 26252726Srpaulo for (peer = ibss_rsn->peers; peer; peer = peer->next) 27252726Srpaulo if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) 28252726Srpaulo break; 29252726Srpaulo return peer; 30252726Srpaulo} 31252726Srpaulo 32252726Srpaulo 33214501Srpaulostatic void ibss_rsn_free(struct ibss_rsn_peer *peer) 34214501Srpaulo{ 35214501Srpaulo wpa_auth_sta_deinit(peer->auth); 36214501Srpaulo wpa_sm_deinit(peer->supp); 37214501Srpaulo os_free(peer); 38214501Srpaulo} 39214501Srpaulo 40214501Srpaulo 41214501Srpaulostatic void supp_set_state(void *ctx, enum wpa_states state) 42214501Srpaulo{ 43214501Srpaulo struct ibss_rsn_peer *peer = ctx; 44214501Srpaulo peer->supp_state = state; 45214501Srpaulo} 46214501Srpaulo 47214501Srpaulo 48252726Srpaulostatic enum wpa_states supp_get_state(void *ctx) 49252726Srpaulo{ 50252726Srpaulo struct ibss_rsn_peer *peer = ctx; 51252726Srpaulo return peer->supp_state; 52252726Srpaulo} 53252726Srpaulo 54252726Srpaulo 55214501Srpaulostatic int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, 56214501Srpaulo size_t len) 57214501Srpaulo{ 58214501Srpaulo struct ibss_rsn_peer *peer = ctx; 59214501Srpaulo struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; 60214501Srpaulo 61214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " 62214501Srpaulo "len=%lu)", 63214501Srpaulo __func__, MAC2STR(dest), proto, (unsigned long) len); 64214501Srpaulo 65214501Srpaulo if (wpa_s->l2) 66214501Srpaulo return l2_packet_send(wpa_s->l2, dest, proto, buf, len); 67214501Srpaulo 68214501Srpaulo return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); 69214501Srpaulo} 70214501Srpaulo 71214501Srpaulo 72214501Srpaulostatic u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, 73214501Srpaulo u16 data_len, size_t *msg_len, void **data_pos) 74214501Srpaulo{ 75214501Srpaulo struct ieee802_1x_hdr *hdr; 76214501Srpaulo 77214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", 78214501Srpaulo __func__, type, data_len); 79214501Srpaulo 80214501Srpaulo *msg_len = sizeof(*hdr) + data_len; 81214501Srpaulo hdr = os_malloc(*msg_len); 82214501Srpaulo if (hdr == NULL) 83214501Srpaulo return NULL; 84214501Srpaulo 85214501Srpaulo hdr->version = 2; 86214501Srpaulo hdr->type = type; 87214501Srpaulo hdr->length = host_to_be16(data_len); 88214501Srpaulo 89214501Srpaulo if (data) 90214501Srpaulo os_memcpy(hdr + 1, data, data_len); 91214501Srpaulo else 92214501Srpaulo os_memset(hdr + 1, 0, data_len); 93214501Srpaulo 94214501Srpaulo if (data_pos) 95214501Srpaulo *data_pos = hdr + 1; 96214501Srpaulo 97214501Srpaulo return (u8 *) hdr; 98214501Srpaulo} 99214501Srpaulo 100214501Srpaulo 101214501Srpaulostatic int supp_get_beacon_ie(void *ctx) 102214501Srpaulo{ 103214501Srpaulo struct ibss_rsn_peer *peer = ctx; 104214501Srpaulo 105214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); 106214501Srpaulo /* TODO: get correct RSN IE */ 107214501Srpaulo return wpa_sm_set_ap_rsn_ie(peer->supp, 108214501Srpaulo (u8 *) "\x30\x14\x01\x00" 109214501Srpaulo "\x00\x0f\xac\x04" 110214501Srpaulo "\x01\x00\x00\x0f\xac\x04" 111214501Srpaulo "\x01\x00\x00\x0f\xac\x02" 112214501Srpaulo "\x00\x00", 22); 113214501Srpaulo} 114214501Srpaulo 115214501Srpaulo 116214501Srpaulostatic int supp_set_key(void *ctx, enum wpa_alg alg, 117214501Srpaulo const u8 *addr, int key_idx, int set_tx, 118214501Srpaulo const u8 *seq, size_t seq_len, 119214501Srpaulo const u8 *key, size_t key_len) 120214501Srpaulo{ 121214501Srpaulo struct ibss_rsn_peer *peer = ctx; 122214501Srpaulo 123214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " 124214501Srpaulo "set_tx=%d)", 125214501Srpaulo __func__, alg, MAC2STR(addr), key_idx, set_tx); 126214501Srpaulo wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); 127214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len); 128214501Srpaulo 129214501Srpaulo if (key_idx == 0) { 130214501Srpaulo /* 131214501Srpaulo * In IBSS RSN, the pairwise key from the 4-way handshake 132214501Srpaulo * initiated by the peer with highest MAC address is used. 133214501Srpaulo */ 134214501Srpaulo if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr, 135214501Srpaulo ETH_ALEN) > 0) { 136214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK"); 137214501Srpaulo return 0; 138214501Srpaulo } 139214501Srpaulo } 140214501Srpaulo 141252726Srpaulo if (is_broadcast_ether_addr(addr)) 142252726Srpaulo addr = peer->addr; 143214501Srpaulo return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, 144214501Srpaulo set_tx, seq, seq_len, key, key_len); 145214501Srpaulo} 146214501Srpaulo 147214501Srpaulo 148214501Srpaulostatic void * supp_get_network_ctx(void *ctx) 149214501Srpaulo{ 150214501Srpaulo struct ibss_rsn_peer *peer = ctx; 151214501Srpaulo return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s); 152214501Srpaulo} 153214501Srpaulo 154214501Srpaulo 155214501Srpaulostatic int supp_mlme_setprotection(void *ctx, const u8 *addr, 156214501Srpaulo int protection_type, int key_type) 157214501Srpaulo{ 158214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " 159214501Srpaulo "key_type=%d)", 160214501Srpaulo __func__, MAC2STR(addr), protection_type, key_type); 161214501Srpaulo return 0; 162214501Srpaulo} 163214501Srpaulo 164214501Srpaulo 165214501Srpaulostatic void supp_cancel_auth_timeout(void *ctx) 166214501Srpaulo{ 167214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); 168214501Srpaulo} 169214501Srpaulo 170214501Srpaulo 171252726Srpaulostatic void supp_deauthenticate(void * ctx, int reason_code) 172214501Srpaulo{ 173252726Srpaulo wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); 174252726Srpaulo} 175252726Srpaulo 176252726Srpaulo 177252726Srpaulostatic int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, 178252726Srpaulo const u8 *psk) 179252726Srpaulo{ 180214501Srpaulo struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); 181214501Srpaulo if (ctx == NULL) 182214501Srpaulo return -1; 183214501Srpaulo 184214501Srpaulo ctx->ctx = peer; 185214501Srpaulo ctx->msg_ctx = peer->ibss_rsn->wpa_s; 186214501Srpaulo ctx->set_state = supp_set_state; 187252726Srpaulo ctx->get_state = supp_get_state; 188214501Srpaulo ctx->ether_send = supp_ether_send; 189214501Srpaulo ctx->get_beacon_ie = supp_get_beacon_ie; 190214501Srpaulo ctx->alloc_eapol = supp_alloc_eapol; 191214501Srpaulo ctx->set_key = supp_set_key; 192214501Srpaulo ctx->get_network_ctx = supp_get_network_ctx; 193214501Srpaulo ctx->mlme_setprotection = supp_mlme_setprotection; 194214501Srpaulo ctx->cancel_auth_timeout = supp_cancel_auth_timeout; 195252726Srpaulo ctx->deauthenticate = supp_deauthenticate; 196214501Srpaulo peer->supp = wpa_sm_init(ctx); 197214501Srpaulo if (peer->supp == NULL) { 198214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); 199214501Srpaulo return -1; 200214501Srpaulo } 201214501Srpaulo 202214501Srpaulo wpa_sm_set_own_addr(peer->supp, own_addr); 203214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); 204214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); 205214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); 206214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); 207214501Srpaulo wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); 208214501Srpaulo wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); 209214501Srpaulo 210214501Srpaulo peer->supp_ie_len = sizeof(peer->supp_ie); 211214501Srpaulo if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, 212214501Srpaulo &peer->supp_ie_len) < 0) { 213214501Srpaulo wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" 214214501Srpaulo " failed"); 215214501Srpaulo return -1; 216214501Srpaulo } 217214501Srpaulo 218214501Srpaulo wpa_sm_notify_assoc(peer->supp, peer->addr); 219214501Srpaulo 220214501Srpaulo return 0; 221214501Srpaulo} 222214501Srpaulo 223214501Srpaulo 224214501Srpaulostatic void auth_logger(void *ctx, const u8 *addr, logger_level level, 225214501Srpaulo const char *txt) 226214501Srpaulo{ 227214501Srpaulo if (addr) 228214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", 229214501Srpaulo MAC2STR(addr), txt); 230214501Srpaulo else 231214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s", txt); 232214501Srpaulo} 233214501Srpaulo 234214501Srpaulo 235214501Srpaulostatic const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) 236214501Srpaulo{ 237214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 238214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", 239214501Srpaulo __func__, MAC2STR(addr), prev_psk); 240214501Srpaulo if (prev_psk) 241214501Srpaulo return NULL; 242214501Srpaulo return ibss_rsn->psk; 243214501Srpaulo} 244214501Srpaulo 245214501Srpaulo 246214501Srpaulostatic int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, 247214501Srpaulo size_t data_len, int encrypt) 248214501Srpaulo{ 249214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 250214501Srpaulo struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; 251214501Srpaulo 252214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " 253214501Srpaulo "encrypt=%d)", 254214501Srpaulo __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); 255214501Srpaulo 256214501Srpaulo if (wpa_s->l2) 257214501Srpaulo return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, 258214501Srpaulo data_len); 259214501Srpaulo 260214501Srpaulo return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len); 261214501Srpaulo} 262214501Srpaulo 263214501Srpaulo 264214501Srpaulostatic int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 265214501Srpaulo const u8 *addr, int idx, u8 *key, size_t key_len) 266214501Srpaulo{ 267214501Srpaulo struct ibss_rsn *ibss_rsn = ctx; 268214501Srpaulo u8 seq[6]; 269214501Srpaulo 270214501Srpaulo os_memset(seq, 0, sizeof(seq)); 271214501Srpaulo 272214501Srpaulo if (addr) { 273214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR 274214501Srpaulo " key_idx=%d)", 275214501Srpaulo __func__, alg, MAC2STR(addr), idx); 276214501Srpaulo } else { 277214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", 278214501Srpaulo __func__, alg, idx); 279214501Srpaulo } 280214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); 281214501Srpaulo 282214501Srpaulo if (idx == 0) { 283214501Srpaulo /* 284214501Srpaulo * In IBSS RSN, the pairwise key from the 4-way handshake 285214501Srpaulo * initiated by the peer with highest MAC address is used. 286214501Srpaulo */ 287214501Srpaulo if (addr == NULL || 288214501Srpaulo os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) { 289214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK"); 290214501Srpaulo return 0; 291214501Srpaulo } 292214501Srpaulo } 293214501Srpaulo 294214501Srpaulo return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, 295214501Srpaulo 1, seq, 6, key, key_len); 296214501Srpaulo} 297214501Srpaulo 298214501Srpaulo 299252726Srpaulostatic int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm, 300252726Srpaulo void *ctx), 301252726Srpaulo void *cb_ctx) 302252726Srpaulo{ 303252726Srpaulo struct ibss_rsn *ibss_rsn = ctx; 304252726Srpaulo struct ibss_rsn_peer *peer; 305252726Srpaulo 306252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: for_each_sta"); 307252726Srpaulo 308252726Srpaulo for (peer = ibss_rsn->peers; peer; peer = peer->next) { 309252726Srpaulo if (peer->auth && cb(peer->auth, cb_ctx)) 310252726Srpaulo return 1; 311252726Srpaulo } 312252726Srpaulo 313252726Srpaulo return 0; 314252726Srpaulo} 315252726Srpaulo 316252726Srpaulo 317252726Srpaulostatic void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn, 318252726Srpaulo struct ibss_rsn_peer *peer, int authorized) 319252726Srpaulo{ 320252726Srpaulo int res; 321252726Srpaulo 322252726Srpaulo if (authorized) { 323252726Srpaulo res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, 324252726Srpaulo WPA_STA_AUTHORIZED, 325252726Srpaulo WPA_STA_AUTHORIZED, ~0); 326252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port", 327252726Srpaulo MAC2STR(peer->addr)); 328252726Srpaulo } else { 329252726Srpaulo res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, 330252726Srpaulo 0, 0, ~WPA_STA_AUTHORIZED); 331252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port", 332252726Srpaulo MAC2STR(peer->addr)); 333252726Srpaulo } 334252726Srpaulo 335252726Srpaulo if (res && errno != ENOENT) { 336252726Srpaulo wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags " 337252726Srpaulo "for kernel driver (errno=%d)", 338252726Srpaulo MAC2STR(peer->addr), errno); 339252726Srpaulo } 340252726Srpaulo} 341252726Srpaulo 342252726Srpaulo 343252726Srpaulostatic void auth_set_eapol(void *ctx, const u8 *addr, 344252726Srpaulo wpa_eapol_variable var, int value) 345252726Srpaulo{ 346252726Srpaulo struct ibss_rsn *ibss_rsn = ctx; 347252726Srpaulo struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr); 348252726Srpaulo 349252726Srpaulo if (peer == NULL) 350252726Srpaulo return; 351252726Srpaulo 352252726Srpaulo switch (var) { 353252726Srpaulo case WPA_EAPOL_authorized: 354252726Srpaulo ibss_set_sta_authorized(ibss_rsn, peer, value); 355252726Srpaulo break; 356252726Srpaulo default: 357252726Srpaulo /* do not handle any other event */ 358252726Srpaulo wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var); 359252726Srpaulo break; 360252726Srpaulo } 361252726Srpaulo} 362252726Srpaulo 363252726Srpaulo 364214501Srpaulostatic int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, 365214501Srpaulo const u8 *own_addr) 366214501Srpaulo{ 367214501Srpaulo struct wpa_auth_config conf; 368214501Srpaulo struct wpa_auth_callbacks cb; 369214501Srpaulo 370214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); 371214501Srpaulo 372214501Srpaulo os_memset(&conf, 0, sizeof(conf)); 373214501Srpaulo conf.wpa = 2; 374214501Srpaulo conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; 375214501Srpaulo conf.wpa_pairwise = WPA_CIPHER_CCMP; 376214501Srpaulo conf.rsn_pairwise = WPA_CIPHER_CCMP; 377214501Srpaulo conf.wpa_group = WPA_CIPHER_CCMP; 378214501Srpaulo conf.eapol_version = 2; 379252726Srpaulo conf.wpa_group_rekey = 600; 380214501Srpaulo 381214501Srpaulo os_memset(&cb, 0, sizeof(cb)); 382214501Srpaulo cb.ctx = ibss_rsn; 383214501Srpaulo cb.logger = auth_logger; 384252726Srpaulo cb.set_eapol = auth_set_eapol; 385214501Srpaulo cb.send_eapol = auth_send_eapol; 386214501Srpaulo cb.get_psk = auth_get_psk; 387214501Srpaulo cb.set_key = auth_set_key; 388252726Srpaulo cb.for_each_sta = auth_for_each_sta; 389214501Srpaulo 390214501Srpaulo ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); 391214501Srpaulo if (ibss_rsn->auth_group == NULL) { 392214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); 393214501Srpaulo return -1; 394214501Srpaulo } 395214501Srpaulo 396252726Srpaulo wpa_init_keys(ibss_rsn->auth_group); 397252726Srpaulo 398214501Srpaulo return 0; 399214501Srpaulo} 400214501Srpaulo 401214501Srpaulo 402214501Srpaulostatic int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, 403214501Srpaulo struct ibss_rsn_peer *peer) 404214501Srpaulo{ 405214501Srpaulo peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); 406214501Srpaulo if (peer->auth == NULL) { 407214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); 408214501Srpaulo return -1; 409214501Srpaulo } 410214501Srpaulo 411214501Srpaulo /* TODO: get peer RSN IE with Probe Request */ 412214501Srpaulo if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, 413214501Srpaulo (u8 *) "\x30\x14\x01\x00" 414214501Srpaulo "\x00\x0f\xac\x04" 415214501Srpaulo "\x01\x00\x00\x0f\xac\x04" 416214501Srpaulo "\x01\x00\x00\x0f\xac\x02" 417214501Srpaulo "\x00\x00", 22, NULL, 0) != 418214501Srpaulo WPA_IE_OK) { 419214501Srpaulo wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); 420214501Srpaulo return -1; 421214501Srpaulo } 422214501Srpaulo 423214501Srpaulo if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) 424214501Srpaulo return -1; 425214501Srpaulo 426214501Srpaulo if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) 427214501Srpaulo return -1; 428214501Srpaulo 429214501Srpaulo return 0; 430214501Srpaulo} 431214501Srpaulo 432214501Srpaulo 433214501Srpauloint ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) 434214501Srpaulo{ 435214501Srpaulo struct ibss_rsn_peer *peer; 436214501Srpaulo 437252726Srpaulo if (ibss_rsn == NULL) 438252726Srpaulo return -1; 439252726Srpaulo 440252726Srpaulo if (ibss_rsn_get_peer(ibss_rsn, addr)) { 441252726Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant " 442252726Srpaulo "for peer " MACSTR " already running", 443252726Srpaulo MAC2STR(addr)); 444252726Srpaulo return 0; 445252726Srpaulo } 446252726Srpaulo 447214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " 448214501Srpaulo "Supplicant for peer " MACSTR, MAC2STR(addr)); 449214501Srpaulo 450214501Srpaulo peer = os_zalloc(sizeof(*peer)); 451214501Srpaulo if (peer == NULL) 452214501Srpaulo return -1; 453214501Srpaulo 454214501Srpaulo peer->ibss_rsn = ibss_rsn; 455214501Srpaulo os_memcpy(peer->addr, addr, ETH_ALEN); 456214501Srpaulo 457214501Srpaulo if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) 458214501Srpaulo < 0) { 459214501Srpaulo ibss_rsn_free(peer); 460214501Srpaulo return -1; 461214501Srpaulo } 462214501Srpaulo 463214501Srpaulo if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { 464214501Srpaulo ibss_rsn_free(peer); 465214501Srpaulo return -1; 466214501Srpaulo } 467214501Srpaulo 468214501Srpaulo peer->next = ibss_rsn->peers; 469214501Srpaulo ibss_rsn->peers = peer; 470214501Srpaulo 471214501Srpaulo return 0; 472214501Srpaulo} 473214501Srpaulo 474214501Srpaulo 475252726Srpaulovoid ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) 476252726Srpaulo{ 477252726Srpaulo struct ibss_rsn_peer *peer, *prev; 478252726Srpaulo 479252726Srpaulo if (ibss_rsn == NULL) 480252726Srpaulo return; 481252726Srpaulo 482252726Srpaulo if (peermac == NULL) { 483252726Srpaulo /* remove all peers */ 484252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__); 485252726Srpaulo peer = ibss_rsn->peers; 486252726Srpaulo while (peer) { 487252726Srpaulo prev = peer; 488252726Srpaulo peer = peer->next; 489252726Srpaulo ibss_rsn_free(prev); 490252726Srpaulo ibss_rsn->peers = peer; 491252726Srpaulo } 492252726Srpaulo } else { 493252726Srpaulo /* remove specific peer */ 494252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR, 495252726Srpaulo __func__, MAC2STR(peermac)); 496252726Srpaulo 497252726Srpaulo for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; 498252726Srpaulo prev = peer, peer = peer->next) { 499252726Srpaulo if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { 500252726Srpaulo if (prev == NULL) 501252726Srpaulo ibss_rsn->peers = peer->next; 502252726Srpaulo else 503252726Srpaulo prev->next = peer->next; 504252726Srpaulo ibss_rsn_free(peer); 505252726Srpaulo wpa_printf(MSG_DEBUG, "%s: Successfully " 506252726Srpaulo "removed a specific peer", 507252726Srpaulo __func__); 508252726Srpaulo break; 509252726Srpaulo } 510252726Srpaulo } 511252726Srpaulo } 512252726Srpaulo} 513252726Srpaulo 514252726Srpaulo 515214501Srpaulostruct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) 516214501Srpaulo{ 517214501Srpaulo struct ibss_rsn *ibss_rsn; 518214501Srpaulo 519214501Srpaulo ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); 520214501Srpaulo if (ibss_rsn == NULL) 521214501Srpaulo return NULL; 522214501Srpaulo ibss_rsn->wpa_s = wpa_s; 523214501Srpaulo 524214501Srpaulo if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { 525214501Srpaulo ibss_rsn_deinit(ibss_rsn); 526214501Srpaulo return NULL; 527214501Srpaulo } 528214501Srpaulo 529214501Srpaulo return ibss_rsn; 530214501Srpaulo} 531214501Srpaulo 532214501Srpaulo 533214501Srpaulovoid ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) 534214501Srpaulo{ 535214501Srpaulo struct ibss_rsn_peer *peer, *prev; 536214501Srpaulo 537214501Srpaulo if (ibss_rsn == NULL) 538214501Srpaulo return; 539214501Srpaulo 540214501Srpaulo peer = ibss_rsn->peers; 541214501Srpaulo while (peer) { 542214501Srpaulo prev = peer; 543214501Srpaulo peer = peer->next; 544214501Srpaulo ibss_rsn_free(prev); 545214501Srpaulo } 546214501Srpaulo 547214501Srpaulo wpa_deinit(ibss_rsn->auth_group); 548214501Srpaulo os_free(ibss_rsn); 549214501Srpaulo 550214501Srpaulo} 551214501Srpaulo 552214501Srpaulo 553214501Srpaulostatic int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) 554214501Srpaulo{ 555214501Srpaulo const struct ieee802_1x_hdr *hdr; 556214501Srpaulo const struct wpa_eapol_key *key; 557214501Srpaulo u16 key_info; 558214501Srpaulo size_t plen; 559214501Srpaulo 560214501Srpaulo /* TODO: Support other EAPOL packets than just EAPOL-Key */ 561214501Srpaulo 562214501Srpaulo if (len < sizeof(*hdr) + sizeof(*key)) 563214501Srpaulo return -1; 564214501Srpaulo 565214501Srpaulo hdr = (const struct ieee802_1x_hdr *) buf; 566214501Srpaulo key = (const struct wpa_eapol_key *) (hdr + 1); 567214501Srpaulo plen = be_to_host16(hdr->length); 568214501Srpaulo 569214501Srpaulo if (hdr->version < EAPOL_VERSION) { 570214501Srpaulo /* TODO: backwards compatibility */ 571214501Srpaulo } 572214501Srpaulo if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { 573214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, " 574214501Srpaulo "not a Key frame", hdr->type); 575214501Srpaulo return -1; 576214501Srpaulo } 577214501Srpaulo if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { 578214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu " 579214501Srpaulo "invalid (frame size %lu)", 580214501Srpaulo (unsigned long) plen, (unsigned long) len); 581214501Srpaulo return -1; 582214501Srpaulo } 583214501Srpaulo 584214501Srpaulo if (key->type != EAPOL_KEY_TYPE_RSN) { 585214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, " 586214501Srpaulo "discarded", key->type); 587214501Srpaulo return -1; 588214501Srpaulo } 589214501Srpaulo 590214501Srpaulo key_info = WPA_GET_BE16(key->key_info); 591214501Srpaulo 592214501Srpaulo return !!(key_info & WPA_KEY_INFO_ACK); 593214501Srpaulo} 594214501Srpaulo 595214501Srpaulo 596214501Srpaulostatic int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, 597214501Srpaulo struct ibss_rsn_peer *peer, 598214501Srpaulo const u8 *buf, size_t len) 599214501Srpaulo{ 600214501Srpaulo int supp; 601214501Srpaulo u8 *tmp; 602214501Srpaulo 603214501Srpaulo supp = ibss_rsn_eapol_dst_supp(buf, len); 604214501Srpaulo if (supp < 0) 605214501Srpaulo return -1; 606214501Srpaulo 607214501Srpaulo tmp = os_malloc(len); 608214501Srpaulo if (tmp == NULL) 609214501Srpaulo return -1; 610214501Srpaulo os_memcpy(tmp, buf, len); 611214501Srpaulo if (supp) { 612214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant"); 613214501Srpaulo wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); 614214501Srpaulo } else { 615214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator"); 616214501Srpaulo wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); 617214501Srpaulo } 618214501Srpaulo os_free(tmp); 619214501Srpaulo 620214501Srpaulo return 1; 621214501Srpaulo} 622214501Srpaulo 623214501Srpaulo 624214501Srpauloint ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, 625214501Srpaulo const u8 *buf, size_t len) 626214501Srpaulo{ 627214501Srpaulo struct ibss_rsn_peer *peer; 628214501Srpaulo 629252726Srpaulo if (ibss_rsn == NULL) 630252726Srpaulo return -1; 631214501Srpaulo 632252726Srpaulo peer = ibss_rsn_get_peer(ibss_rsn, src_addr); 633252726Srpaulo if (peer) 634252726Srpaulo return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); 635252726Srpaulo 636214501Srpaulo if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { 637214501Srpaulo /* 638214501Srpaulo * Create new IBSS peer based on an EAPOL message from the peer 639214501Srpaulo * Authenticator. 640214501Srpaulo */ 641214501Srpaulo if (ibss_rsn_start(ibss_rsn, src_addr) < 0) 642214501Srpaulo return -1; 643214501Srpaulo return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, 644214501Srpaulo buf, len); 645214501Srpaulo } 646214501Srpaulo 647214501Srpaulo return 0; 648214501Srpaulo} 649214501Srpaulo 650214501Srpaulo 651214501Srpaulovoid ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) 652214501Srpaulo{ 653252726Srpaulo if (ibss_rsn == NULL) 654252726Srpaulo return; 655214501Srpaulo os_memcpy(ibss_rsn->psk, psk, PMK_LEN); 656214501Srpaulo} 657