wpa_auth_glue.c revision 346981
1214501Srpaulo/* 2214501Srpaulo * hostapd / WPA authenticator glue code 3281806Srpaulo * Copyright (c) 2002-2012, 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 "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12346981Scy#include "utils/eloop.h" 13346981Scy#include "utils/list.h" 14214501Srpaulo#include "common/ieee802_11_defs.h" 15281806Srpaulo#include "common/sae.h" 16289549Srpaulo#include "common/wpa_ctrl.h" 17337817Scy#include "crypto/sha1.h" 18214501Srpaulo#include "eapol_auth/eapol_auth_sm.h" 19214501Srpaulo#include "eapol_auth/eapol_auth_sm_i.h" 20214501Srpaulo#include "eap_server/eap.h" 21214501Srpaulo#include "l2_packet/l2_packet.h" 22346981Scy#include "eth_p_oui.h" 23214501Srpaulo#include "hostapd.h" 24214501Srpaulo#include "ieee802_1x.h" 25214501Srpaulo#include "preauth_auth.h" 26214501Srpaulo#include "sta_info.h" 27214501Srpaulo#include "tkip_countermeasures.h" 28214501Srpaulo#include "ap_drv_ops.h" 29214501Srpaulo#include "ap_config.h" 30346981Scy#include "ieee802_11.h" 31346981Scy#include "pmksa_cache_auth.h" 32214501Srpaulo#include "wpa_auth.h" 33252726Srpaulo#include "wpa_auth_glue.h" 34214501Srpaulo 35214501Srpaulo 36214501Srpaulostatic void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, 37281806Srpaulo struct hostapd_config *iconf, 38214501Srpaulo struct wpa_auth_config *wconf) 39214501Srpaulo{ 40252726Srpaulo os_memset(wconf, 0, sizeof(*wconf)); 41214501Srpaulo wconf->wpa = conf->wpa; 42214501Srpaulo wconf->wpa_key_mgmt = conf->wpa_key_mgmt; 43214501Srpaulo wconf->wpa_pairwise = conf->wpa_pairwise; 44214501Srpaulo wconf->wpa_group = conf->wpa_group; 45214501Srpaulo wconf->wpa_group_rekey = conf->wpa_group_rekey; 46214501Srpaulo wconf->wpa_strict_rekey = conf->wpa_strict_rekey; 47214501Srpaulo wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; 48214501Srpaulo wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; 49346981Scy wconf->wpa_group_update_count = conf->wpa_group_update_count; 50346981Scy wconf->wpa_disable_eapol_key_retries = 51346981Scy conf->wpa_disable_eapol_key_retries; 52346981Scy wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count; 53214501Srpaulo wconf->rsn_pairwise = conf->rsn_pairwise; 54214501Srpaulo wconf->rsn_preauth = conf->rsn_preauth; 55214501Srpaulo wconf->eapol_version = conf->eapol_version; 56214501Srpaulo wconf->wmm_enabled = conf->wmm_enabled; 57214501Srpaulo wconf->wmm_uapsd = conf->wmm_uapsd; 58252726Srpaulo wconf->disable_pmksa_caching = conf->disable_pmksa_caching; 59346981Scy#ifdef CONFIG_OCV 60346981Scy wconf->ocv = conf->ocv; 61346981Scy#endif /* CONFIG_OCV */ 62214501Srpaulo wconf->okc = conf->okc; 63214501Srpaulo#ifdef CONFIG_IEEE80211W 64214501Srpaulo wconf->ieee80211w = conf->ieee80211w; 65281806Srpaulo wconf->group_mgmt_cipher = conf->group_mgmt_cipher; 66346981Scy wconf->sae_require_mfp = conf->sae_require_mfp; 67214501Srpaulo#endif /* CONFIG_IEEE80211W */ 68346981Scy#ifdef CONFIG_IEEE80211R_AP 69214501Srpaulo wconf->ssid_len = conf->ssid.ssid_len; 70289549Srpaulo if (wconf->ssid_len > SSID_MAX_LEN) 71289549Srpaulo wconf->ssid_len = SSID_MAX_LEN; 72214501Srpaulo os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); 73214501Srpaulo os_memcpy(wconf->mobility_domain, conf->mobility_domain, 74214501Srpaulo MOBILITY_DOMAIN_ID_LEN); 75214501Srpaulo if (conf->nas_identifier && 76214501Srpaulo os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { 77214501Srpaulo wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); 78214501Srpaulo os_memcpy(wconf->r0_key_holder, conf->nas_identifier, 79214501Srpaulo wconf->r0_key_holder_len); 80214501Srpaulo } 81214501Srpaulo os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); 82214501Srpaulo wconf->r0_key_lifetime = conf->r0_key_lifetime; 83346981Scy wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime; 84214501Srpaulo wconf->reassociation_deadline = conf->reassociation_deadline; 85346981Scy wconf->rkh_pos_timeout = conf->rkh_pos_timeout; 86346981Scy wconf->rkh_neg_timeout = conf->rkh_neg_timeout; 87346981Scy wconf->rkh_pull_timeout = conf->rkh_pull_timeout; 88346981Scy wconf->rkh_pull_retries = conf->rkh_pull_retries; 89346981Scy wconf->r0kh_list = &conf->r0kh_list; 90346981Scy wconf->r1kh_list = &conf->r1kh_list; 91214501Srpaulo wconf->pmk_r1_push = conf->pmk_r1_push; 92252726Srpaulo wconf->ft_over_ds = conf->ft_over_ds; 93346981Scy wconf->ft_psk_generate_local = conf->ft_psk_generate_local; 94346981Scy#endif /* CONFIG_IEEE80211R_AP */ 95252726Srpaulo#ifdef CONFIG_HS20 96252726Srpaulo wconf->disable_gtk = conf->disable_dgaf; 97281806Srpaulo if (conf->osen) { 98281806Srpaulo wconf->disable_gtk = 1; 99281806Srpaulo wconf->wpa = WPA_PROTO_OSEN; 100281806Srpaulo wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; 101281806Srpaulo wconf->wpa_pairwise = 0; 102281806Srpaulo wconf->wpa_group = WPA_CIPHER_CCMP; 103281806Srpaulo wconf->rsn_pairwise = WPA_CIPHER_CCMP; 104281806Srpaulo wconf->rsn_preauth = 0; 105281806Srpaulo wconf->disable_pmksa_caching = 1; 106281806Srpaulo#ifdef CONFIG_IEEE80211W 107281806Srpaulo wconf->ieee80211w = 1; 108281806Srpaulo#endif /* CONFIG_IEEE80211W */ 109281806Srpaulo } 110252726Srpaulo#endif /* CONFIG_HS20 */ 111281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 112281806Srpaulo wconf->corrupt_gtk_rekey_mic_probability = 113281806Srpaulo iconf->corrupt_gtk_rekey_mic_probability; 114289549Srpaulo if (conf->own_ie_override && 115289549Srpaulo wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) { 116289549Srpaulo wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override); 117289549Srpaulo os_memcpy(wconf->own_ie_override, 118289549Srpaulo wpabuf_head(conf->own_ie_override), 119289549Srpaulo wconf->own_ie_override_len); 120289549Srpaulo } 121281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 122281806Srpaulo#ifdef CONFIG_P2P 123281806Srpaulo os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); 124281806Srpaulo os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4); 125281806Srpaulo os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4); 126281806Srpaulo os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4); 127281806Srpaulo#endif /* CONFIG_P2P */ 128346981Scy#ifdef CONFIG_FILS 129346981Scy wconf->fils_cache_id_set = conf->fils_cache_id_set; 130346981Scy os_memcpy(wconf->fils_cache_id, conf->fils_cache_id, 131346981Scy FILS_CACHE_ID_LEN); 132346981Scy#endif /* CONFIG_FILS */ 133214501Srpaulo} 134214501Srpaulo 135214501Srpaulo 136214501Srpaulostatic void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, 137214501Srpaulo logger_level level, const char *txt) 138214501Srpaulo{ 139214501Srpaulo#ifndef CONFIG_NO_HOSTAPD_LOGGER 140214501Srpaulo struct hostapd_data *hapd = ctx; 141214501Srpaulo int hlevel; 142214501Srpaulo 143214501Srpaulo switch (level) { 144214501Srpaulo case LOGGER_WARNING: 145214501Srpaulo hlevel = HOSTAPD_LEVEL_WARNING; 146214501Srpaulo break; 147214501Srpaulo case LOGGER_INFO: 148214501Srpaulo hlevel = HOSTAPD_LEVEL_INFO; 149214501Srpaulo break; 150214501Srpaulo case LOGGER_DEBUG: 151214501Srpaulo default: 152214501Srpaulo hlevel = HOSTAPD_LEVEL_DEBUG; 153214501Srpaulo break; 154214501Srpaulo } 155214501Srpaulo 156214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); 157214501Srpaulo#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 158214501Srpaulo} 159214501Srpaulo 160214501Srpaulo 161214501Srpaulostatic void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, 162214501Srpaulo u16 reason) 163214501Srpaulo{ 164214501Srpaulo struct hostapd_data *hapd = ctx; 165214501Srpaulo wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " 166214501Srpaulo "STA " MACSTR " reason %d", 167214501Srpaulo __func__, MAC2STR(addr), reason); 168214501Srpaulo ap_sta_disconnect(hapd, NULL, addr, reason); 169214501Srpaulo} 170214501Srpaulo 171214501Srpaulo 172252726Srpaulostatic int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) 173214501Srpaulo{ 174214501Srpaulo struct hostapd_data *hapd = ctx; 175252726Srpaulo return michael_mic_failure(hapd, addr, 0); 176214501Srpaulo} 177214501Srpaulo 178214501Srpaulo 179289549Srpaulostatic void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr) 180289549Srpaulo{ 181289549Srpaulo struct hostapd_data *hapd = ctx; 182289549Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, 183289549Srpaulo MAC2STR(addr)); 184289549Srpaulo} 185289549Srpaulo 186289549Srpaulo 187214501Srpaulostatic void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, 188214501Srpaulo wpa_eapol_variable var, int value) 189214501Srpaulo{ 190214501Srpaulo struct hostapd_data *hapd = ctx; 191214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 192214501Srpaulo if (sta == NULL) 193214501Srpaulo return; 194214501Srpaulo switch (var) { 195214501Srpaulo case WPA_EAPOL_portEnabled: 196214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, value); 197214501Srpaulo break; 198214501Srpaulo case WPA_EAPOL_portValid: 199214501Srpaulo ieee802_1x_notify_port_valid(sta->eapol_sm, value); 200214501Srpaulo break; 201214501Srpaulo case WPA_EAPOL_authorized: 202214501Srpaulo ieee802_1x_set_sta_authorized(hapd, sta, value); 203214501Srpaulo break; 204214501Srpaulo case WPA_EAPOL_portControl_Auto: 205214501Srpaulo if (sta->eapol_sm) 206214501Srpaulo sta->eapol_sm->portControl = Auto; 207214501Srpaulo break; 208214501Srpaulo case WPA_EAPOL_keyRun: 209214501Srpaulo if (sta->eapol_sm) 210214501Srpaulo sta->eapol_sm->keyRun = value ? TRUE : FALSE; 211214501Srpaulo break; 212214501Srpaulo case WPA_EAPOL_keyAvailable: 213214501Srpaulo if (sta->eapol_sm) 214214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = 215214501Srpaulo value ? TRUE : FALSE; 216214501Srpaulo break; 217214501Srpaulo case WPA_EAPOL_keyDone: 218214501Srpaulo if (sta->eapol_sm) 219214501Srpaulo sta->eapol_sm->keyDone = value ? TRUE : FALSE; 220214501Srpaulo break; 221214501Srpaulo case WPA_EAPOL_inc_EapolFramesTx: 222214501Srpaulo if (sta->eapol_sm) 223214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 224214501Srpaulo break; 225214501Srpaulo } 226214501Srpaulo} 227214501Srpaulo 228214501Srpaulo 229214501Srpaulostatic int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, 230214501Srpaulo wpa_eapol_variable var) 231214501Srpaulo{ 232214501Srpaulo struct hostapd_data *hapd = ctx; 233214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 234214501Srpaulo if (sta == NULL || sta->eapol_sm == NULL) 235214501Srpaulo return -1; 236214501Srpaulo switch (var) { 237214501Srpaulo case WPA_EAPOL_keyRun: 238214501Srpaulo return sta->eapol_sm->keyRun; 239214501Srpaulo case WPA_EAPOL_keyAvailable: 240214501Srpaulo return sta->eapol_sm->eap_if->eapKeyAvailable; 241214501Srpaulo default: 242214501Srpaulo return -1; 243214501Srpaulo } 244214501Srpaulo} 245214501Srpaulo 246214501Srpaulo 247214501Srpaulostatic const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, 248281806Srpaulo const u8 *p2p_dev_addr, 249346981Scy const u8 *prev_psk, size_t *psk_len, 250346981Scy int *vlan_id) 251214501Srpaulo{ 252214501Srpaulo struct hostapd_data *hapd = ctx; 253252726Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 254281806Srpaulo const u8 *psk; 255281806Srpaulo 256346981Scy if (vlan_id) 257346981Scy *vlan_id = 0; 258346981Scy if (psk_len) 259346981Scy *psk_len = PMK_LEN; 260346981Scy 261281806Srpaulo#ifdef CONFIG_SAE 262281806Srpaulo if (sta && sta->auth_alg == WLAN_AUTH_SAE) { 263281806Srpaulo if (!sta->sae || prev_psk) 264281806Srpaulo return NULL; 265281806Srpaulo return sta->sae->pmk; 266281806Srpaulo } 267346981Scy if (sta && wpa_auth_uses_sae(sta->wpa_sm)) { 268346981Scy wpa_printf(MSG_DEBUG, 269346981Scy "No PSK for STA trying to use SAE with PMKSA caching"); 270346981Scy return NULL; 271346981Scy } 272281806Srpaulo#endif /* CONFIG_SAE */ 273281806Srpaulo 274346981Scy#ifdef CONFIG_OWE 275346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 276346981Scy sta && sta->owe_pmk) { 277346981Scy if (psk_len) 278346981Scy *psk_len = sta->owe_pmk_len; 279346981Scy return sta->owe_pmk; 280346981Scy } 281346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) { 282346981Scy struct rsn_pmksa_cache_entry *sa; 283346981Scy 284346981Scy sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 285346981Scy if (sa && sa->akmp == WPA_KEY_MGMT_OWE) { 286346981Scy if (psk_len) 287346981Scy *psk_len = sa->pmk_len; 288346981Scy return sa->pmk; 289346981Scy } 290346981Scy } 291346981Scy#endif /* CONFIG_OWE */ 292346981Scy 293346981Scy psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk, 294346981Scy vlan_id); 295252726Srpaulo /* 296252726Srpaulo * This is about to iterate over all psks, prev_psk gives the last 297252726Srpaulo * returned psk which should not be returned again. 298252726Srpaulo * logic list (all hostapd_get_psk; all sta->psk) 299252726Srpaulo */ 300252726Srpaulo if (sta && sta->psk && !psk) { 301252726Srpaulo struct hostapd_sta_wpa_psk_short *pos; 302346981Scy 303346981Scy if (vlan_id) 304346981Scy *vlan_id = 0; 305252726Srpaulo psk = sta->psk->psk; 306252726Srpaulo for (pos = sta->psk; pos; pos = pos->next) { 307337817Scy if (pos->is_passphrase) { 308337817Scy pbkdf2_sha1(pos->passphrase, 309337817Scy hapd->conf->ssid.ssid, 310337817Scy hapd->conf->ssid.ssid_len, 4096, 311337817Scy pos->psk, PMK_LEN); 312337817Scy pos->is_passphrase = 0; 313337817Scy } 314252726Srpaulo if (pos->psk == prev_psk) { 315252726Srpaulo psk = pos->next ? pos->next->psk : NULL; 316252726Srpaulo break; 317252726Srpaulo } 318252726Srpaulo } 319252726Srpaulo } 320252726Srpaulo return psk; 321214501Srpaulo} 322214501Srpaulo 323214501Srpaulo 324214501Srpaulostatic int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, 325214501Srpaulo size_t *len) 326214501Srpaulo{ 327214501Srpaulo struct hostapd_data *hapd = ctx; 328214501Srpaulo const u8 *key; 329214501Srpaulo size_t keylen; 330214501Srpaulo struct sta_info *sta; 331214501Srpaulo 332214501Srpaulo sta = ap_get_sta(hapd, addr); 333281806Srpaulo if (sta == NULL) { 334281806Srpaulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA"); 335214501Srpaulo return -1; 336281806Srpaulo } 337214501Srpaulo 338214501Srpaulo key = ieee802_1x_get_key(sta->eapol_sm, &keylen); 339281806Srpaulo if (key == NULL) { 340281806Srpaulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p", 341281806Srpaulo sta->eapol_sm); 342214501Srpaulo return -1; 343281806Srpaulo } 344214501Srpaulo 345214501Srpaulo if (keylen > *len) 346214501Srpaulo keylen = *len; 347214501Srpaulo os_memcpy(msk, key, keylen); 348214501Srpaulo *len = keylen; 349214501Srpaulo 350214501Srpaulo return 0; 351214501Srpaulo} 352214501Srpaulo 353214501Srpaulo 354214501Srpaulostatic int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 355214501Srpaulo const u8 *addr, int idx, u8 *key, 356214501Srpaulo size_t key_len) 357214501Srpaulo{ 358214501Srpaulo struct hostapd_data *hapd = ctx; 359214501Srpaulo const char *ifname = hapd->conf->iface; 360214501Srpaulo 361214501Srpaulo if (vlan_id > 0) { 362214501Srpaulo ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); 363214501Srpaulo if (ifname == NULL) 364214501Srpaulo return -1; 365214501Srpaulo } 366214501Srpaulo 367346981Scy#ifdef CONFIG_TESTING_OPTIONS 368346981Scy if (addr && !is_broadcast_ether_addr(addr)) { 369346981Scy struct sta_info *sta; 370346981Scy 371346981Scy sta = ap_get_sta(hapd, addr); 372346981Scy if (sta) { 373346981Scy sta->last_tk_alg = alg; 374346981Scy sta->last_tk_key_idx = idx; 375346981Scy if (key) 376346981Scy os_memcpy(sta->last_tk, key, key_len); 377346981Scy sta->last_tk_len = key_len; 378346981Scy } 379346981Scy#ifdef CONFIG_IEEE80211W 380346981Scy } else if (alg == WPA_ALG_IGTK || 381346981Scy alg == WPA_ALG_BIP_GMAC_128 || 382346981Scy alg == WPA_ALG_BIP_GMAC_256 || 383346981Scy alg == WPA_ALG_BIP_CMAC_256) { 384346981Scy hapd->last_igtk_alg = alg; 385346981Scy hapd->last_igtk_key_idx = idx; 386346981Scy if (key) 387346981Scy os_memcpy(hapd->last_igtk, key, key_len); 388346981Scy hapd->last_igtk_len = key_len; 389346981Scy#endif /* CONFIG_IEEE80211W */ 390346981Scy } else { 391346981Scy hapd->last_gtk_alg = alg; 392346981Scy hapd->last_gtk_key_idx = idx; 393346981Scy if (key) 394346981Scy os_memcpy(hapd->last_gtk, key, key_len); 395346981Scy hapd->last_gtk_len = key_len; 396346981Scy } 397346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 398252726Srpaulo return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, 399252726Srpaulo key, key_len); 400214501Srpaulo} 401214501Srpaulo 402214501Srpaulo 403214501Srpaulostatic int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, 404214501Srpaulo u8 *seq) 405214501Srpaulo{ 406214501Srpaulo struct hostapd_data *hapd = ctx; 407214501Srpaulo return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); 408214501Srpaulo} 409214501Srpaulo 410214501Srpaulo 411214501Srpaulostatic int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, 412214501Srpaulo const u8 *data, size_t data_len, 413214501Srpaulo int encrypt) 414214501Srpaulo{ 415214501Srpaulo struct hostapd_data *hapd = ctx; 416252726Srpaulo struct sta_info *sta; 417252726Srpaulo u32 flags = 0; 418252726Srpaulo 419281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 420281806Srpaulo if (hapd->ext_eapol_frame_io) { 421281806Srpaulo size_t hex_len = 2 * data_len + 1; 422281806Srpaulo char *hex = os_malloc(hex_len); 423281806Srpaulo 424281806Srpaulo if (hex == NULL) 425281806Srpaulo return -1; 426281806Srpaulo wpa_snprintf_hex(hex, hex_len, data, data_len); 427281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 428281806Srpaulo MAC2STR(addr), hex); 429281806Srpaulo os_free(hex); 430281806Srpaulo return 0; 431281806Srpaulo } 432281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 433281806Srpaulo 434252726Srpaulo sta = ap_get_sta(hapd, addr); 435252726Srpaulo if (sta) 436252726Srpaulo flags = hostapd_sta_flags_to_drv(sta->flags); 437252726Srpaulo 438252726Srpaulo return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, 439252726Srpaulo encrypt, flags); 440214501Srpaulo} 441214501Srpaulo 442214501Srpaulo 443214501Srpaulostatic int hostapd_wpa_auth_for_each_sta( 444214501Srpaulo void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), 445214501Srpaulo void *cb_ctx) 446214501Srpaulo{ 447214501Srpaulo struct hostapd_data *hapd = ctx; 448214501Srpaulo struct sta_info *sta; 449214501Srpaulo 450214501Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 451214501Srpaulo if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) 452214501Srpaulo return 1; 453214501Srpaulo } 454214501Srpaulo return 0; 455214501Srpaulo} 456214501Srpaulo 457214501Srpaulo 458214501Srpaulostruct wpa_auth_iface_iter_data { 459214501Srpaulo int (*cb)(struct wpa_authenticator *sm, void *ctx); 460214501Srpaulo void *cb_ctx; 461214501Srpaulo}; 462214501Srpaulo 463214501Srpaulostatic int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) 464214501Srpaulo{ 465214501Srpaulo struct wpa_auth_iface_iter_data *data = ctx; 466214501Srpaulo size_t i; 467214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 468214501Srpaulo if (iface->bss[i]->wpa_auth && 469214501Srpaulo data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) 470214501Srpaulo return 1; 471214501Srpaulo } 472214501Srpaulo return 0; 473214501Srpaulo} 474214501Srpaulo 475214501Srpaulo 476214501Srpaulostatic int hostapd_wpa_auth_for_each_auth( 477214501Srpaulo void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), 478214501Srpaulo void *cb_ctx) 479214501Srpaulo{ 480214501Srpaulo struct hostapd_data *hapd = ctx; 481214501Srpaulo struct wpa_auth_iface_iter_data data; 482252726Srpaulo if (hapd->iface->interfaces == NULL || 483252726Srpaulo hapd->iface->interfaces->for_each_interface == NULL) 484214501Srpaulo return -1; 485214501Srpaulo data.cb = cb; 486214501Srpaulo data.cb_ctx = cb_ctx; 487252726Srpaulo return hapd->iface->interfaces->for_each_interface( 488252726Srpaulo hapd->iface->interfaces, wpa_auth_iface_iter, &data); 489214501Srpaulo} 490214501Srpaulo 491214501Srpaulo 492346981Scy#ifdef CONFIG_IEEE80211R_AP 493214501Srpaulo 494346981Scystruct wpa_ft_rrb_rx_later_data { 495346981Scy struct dl_list list; 496346981Scy u8 addr[ETH_ALEN]; 497346981Scy size_t data_len; 498346981Scy /* followed by data_len octets of data */ 499346981Scy}; 500346981Scy 501346981Scystatic void hostapd_wpa_ft_rrb_rx_later(void *eloop_ctx, void *timeout_ctx) 502346981Scy{ 503346981Scy struct hostapd_data *hapd = eloop_ctx; 504346981Scy struct wpa_ft_rrb_rx_later_data *data, *n; 505346981Scy 506346981Scy dl_list_for_each_safe(data, n, &hapd->l2_queue, 507346981Scy struct wpa_ft_rrb_rx_later_data, list) { 508346981Scy if (hapd->wpa_auth) { 509346981Scy wpa_ft_rrb_rx(hapd->wpa_auth, data->addr, 510346981Scy (const u8 *) (data + 1), 511346981Scy data->data_len); 512346981Scy } 513346981Scy dl_list_del(&data->list); 514346981Scy os_free(data); 515346981Scy } 516346981Scy} 517346981Scy 518346981Scy 519214501Srpaulostruct wpa_auth_ft_iface_iter_data { 520214501Srpaulo struct hostapd_data *src_hapd; 521214501Srpaulo const u8 *dst; 522214501Srpaulo const u8 *data; 523214501Srpaulo size_t data_len; 524214501Srpaulo}; 525214501Srpaulo 526214501Srpaulo 527214501Srpaulostatic int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) 528214501Srpaulo{ 529214501Srpaulo struct wpa_auth_ft_iface_iter_data *idata = ctx; 530346981Scy struct wpa_ft_rrb_rx_later_data *data; 531214501Srpaulo struct hostapd_data *hapd; 532214501Srpaulo size_t j; 533214501Srpaulo 534214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 535214501Srpaulo hapd = iface->bss[j]; 536346981Scy if (hapd == idata->src_hapd || 537346981Scy !hapd->wpa_auth || 538346981Scy os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0) 539214501Srpaulo continue; 540346981Scy 541346981Scy wpa_printf(MSG_DEBUG, 542346981Scy "FT: Send RRB data directly to locally managed BSS " 543346981Scy MACSTR "@%s -> " MACSTR "@%s", 544346981Scy MAC2STR(idata->src_hapd->own_addr), 545346981Scy idata->src_hapd->conf->iface, 546346981Scy MAC2STR(hapd->own_addr), hapd->conf->iface); 547346981Scy 548346981Scy /* Defer wpa_ft_rrb_rx() until next eloop step as this is 549346981Scy * when it would be triggered when reading from a socket. 550346981Scy * This avoids 551346981Scy * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 552346981Scy * that is calling hapd0:recv handler from within 553346981Scy * hapd0:send directly. 554346981Scy */ 555346981Scy data = os_zalloc(sizeof(*data) + idata->data_len); 556346981Scy if (!data) 557214501Srpaulo return 1; 558346981Scy 559346981Scy os_memcpy(data->addr, idata->src_hapd->own_addr, ETH_ALEN); 560346981Scy os_memcpy(data + 1, idata->data, idata->data_len); 561346981Scy data->data_len = idata->data_len; 562346981Scy 563346981Scy dl_list_add(&hapd->l2_queue, &data->list); 564346981Scy 565346981Scy if (!eloop_is_timeout_registered(hostapd_wpa_ft_rrb_rx_later, 566346981Scy hapd, NULL)) 567346981Scy eloop_register_timeout(0, 0, 568346981Scy hostapd_wpa_ft_rrb_rx_later, 569346981Scy hapd, NULL); 570346981Scy 571346981Scy return 1; 572214501Srpaulo } 573214501Srpaulo 574214501Srpaulo return 0; 575214501Srpaulo} 576214501Srpaulo 577346981Scy#endif /* CONFIG_IEEE80211R_AP */ 578214501Srpaulo 579214501Srpaulo 580214501Srpaulostatic int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, 581214501Srpaulo const u8 *data, size_t data_len) 582214501Srpaulo{ 583214501Srpaulo struct hostapd_data *hapd = ctx; 584252726Srpaulo struct l2_ethhdr *buf; 585252726Srpaulo int ret; 586214501Srpaulo 587281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 588281806Srpaulo if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) { 589281806Srpaulo size_t hex_len = 2 * data_len + 1; 590281806Srpaulo char *hex = os_malloc(hex_len); 591281806Srpaulo 592281806Srpaulo if (hex == NULL) 593281806Srpaulo return -1; 594281806Srpaulo wpa_snprintf_hex(hex, hex_len, data, data_len); 595281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 596281806Srpaulo MAC2STR(dst), hex); 597281806Srpaulo os_free(hex); 598281806Srpaulo return 0; 599281806Srpaulo } 600281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 601281806Srpaulo 602346981Scy#ifdef CONFIG_IEEE80211R_AP 603252726Srpaulo if (proto == ETH_P_RRB && hapd->iface->interfaces && 604252726Srpaulo hapd->iface->interfaces->for_each_interface) { 605214501Srpaulo int res; 606214501Srpaulo struct wpa_auth_ft_iface_iter_data idata; 607214501Srpaulo idata.src_hapd = hapd; 608214501Srpaulo idata.dst = dst; 609214501Srpaulo idata.data = data; 610214501Srpaulo idata.data_len = data_len; 611252726Srpaulo res = hapd->iface->interfaces->for_each_interface( 612252726Srpaulo hapd->iface->interfaces, hostapd_wpa_auth_ft_iter, 613252726Srpaulo &idata); 614214501Srpaulo if (res == 1) 615214501Srpaulo return data_len; 616214501Srpaulo } 617346981Scy#endif /* CONFIG_IEEE80211R_AP */ 618214501Srpaulo 619214501Srpaulo if (hapd->driver && hapd->driver->send_ether) 620214501Srpaulo return hapd->driver->send_ether(hapd->drv_priv, dst, 621214501Srpaulo hapd->own_addr, proto, 622214501Srpaulo data, data_len); 623214501Srpaulo if (hapd->l2 == NULL) 624214501Srpaulo return -1; 625252726Srpaulo 626252726Srpaulo buf = os_malloc(sizeof(*buf) + data_len); 627252726Srpaulo if (buf == NULL) 628252726Srpaulo return -1; 629252726Srpaulo os_memcpy(buf->h_dest, dst, ETH_ALEN); 630252726Srpaulo os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN); 631252726Srpaulo buf->h_proto = host_to_be16(proto); 632252726Srpaulo os_memcpy(buf + 1, data, data_len); 633252726Srpaulo ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, 634252726Srpaulo sizeof(*buf) + data_len); 635252726Srpaulo os_free(buf); 636252726Srpaulo return ret; 637214501Srpaulo} 638214501Srpaulo 639214501Srpaulo 640346981Scy#ifdef CONFIG_ETH_P_OUI 641346981Scystatic struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd, 642346981Scy u8 oui_suffix) 643346981Scy{ 644346981Scy switch (oui_suffix) { 645346981Scy#ifdef CONFIG_IEEE80211R_AP 646346981Scy case FT_PACKET_R0KH_R1KH_PULL: 647346981Scy return hapd->oui_pull; 648346981Scy case FT_PACKET_R0KH_R1KH_RESP: 649346981Scy return hapd->oui_resp; 650346981Scy case FT_PACKET_R0KH_R1KH_PUSH: 651346981Scy return hapd->oui_push; 652346981Scy case FT_PACKET_R0KH_R1KH_SEQ_REQ: 653346981Scy return hapd->oui_sreq; 654346981Scy case FT_PACKET_R0KH_R1KH_SEQ_RESP: 655346981Scy return hapd->oui_sresp; 656346981Scy#endif /* CONFIG_IEEE80211R_AP */ 657346981Scy default: 658346981Scy return NULL; 659346981Scy } 660346981Scy} 661346981Scy#endif /* CONFIG_ETH_P_OUI */ 662214501Srpaulo 663346981Scy 664346981Scy#ifdef CONFIG_IEEE80211R_AP 665346981Scy 666346981Scystruct oui_deliver_later_data { 667346981Scy struct dl_list list; 668346981Scy u8 src_addr[ETH_ALEN]; 669346981Scy u8 dst_addr[ETH_ALEN]; 670346981Scy size_t data_len; 671346981Scy u8 oui_suffix; 672346981Scy /* followed by data_len octets of data */ 673346981Scy}; 674346981Scy 675346981Scystatic void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx) 676346981Scy{ 677346981Scy struct hostapd_data *hapd = eloop_ctx; 678346981Scy struct oui_deliver_later_data *data, *n; 679346981Scy struct eth_p_oui_ctx *oui_ctx; 680346981Scy 681346981Scy dl_list_for_each_safe(data, n, &hapd->l2_oui_queue, 682346981Scy struct oui_deliver_later_data, list) { 683346981Scy oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix); 684346981Scy if (hapd->wpa_auth && oui_ctx) { 685346981Scy eth_p_oui_deliver(oui_ctx, data->src_addr, 686346981Scy data->dst_addr, 687346981Scy (const u8 *) (data + 1), 688346981Scy data->data_len); 689346981Scy } 690346981Scy dl_list_del(&data->list); 691346981Scy os_free(data); 692346981Scy } 693346981Scy} 694346981Scy 695346981Scy 696346981Scystruct wpa_auth_oui_iface_iter_data { 697346981Scy struct hostapd_data *src_hapd; 698346981Scy const u8 *dst_addr; 699346981Scy const u8 *data; 700346981Scy size_t data_len; 701346981Scy u8 oui_suffix; 702346981Scy}; 703346981Scy 704346981Scystatic int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) 705346981Scy{ 706346981Scy struct wpa_auth_oui_iface_iter_data *idata = ctx; 707346981Scy struct oui_deliver_later_data *data; 708346981Scy struct hostapd_data *hapd; 709346981Scy size_t j; 710346981Scy 711346981Scy for (j = 0; j < iface->num_bss; j++) { 712346981Scy hapd = iface->bss[j]; 713346981Scy if (hapd == idata->src_hapd) 714346981Scy continue; 715346981Scy if (!is_multicast_ether_addr(idata->dst_addr) && 716346981Scy os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0) 717346981Scy continue; 718346981Scy 719346981Scy /* defer eth_p_oui_deliver until next eloop step as this is 720346981Scy * when it would be triggerd from reading from sock 721346981Scy * This avoids 722346981Scy * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 723346981Scy * that is calling hapd0:recv handler from within 724346981Scy * hapd0:send directly. 725346981Scy */ 726346981Scy data = os_zalloc(sizeof(*data) + idata->data_len); 727346981Scy if (!data) 728346981Scy return 1; 729346981Scy 730346981Scy os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN); 731346981Scy os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN); 732346981Scy os_memcpy(data + 1, idata->data, idata->data_len); 733346981Scy data->data_len = idata->data_len; 734346981Scy data->oui_suffix = idata->oui_suffix; 735346981Scy 736346981Scy dl_list_add(&hapd->l2_oui_queue, &data->list); 737346981Scy 738346981Scy if (!eloop_is_timeout_registered(hostapd_oui_deliver_later, 739346981Scy hapd, NULL)) 740346981Scy eloop_register_timeout(0, 0, 741346981Scy hostapd_oui_deliver_later, 742346981Scy hapd, NULL); 743346981Scy 744346981Scy return 1; 745346981Scy } 746346981Scy 747346981Scy return 0; 748346981Scy} 749346981Scy 750346981Scy#endif /* CONFIG_IEEE80211R_AP */ 751346981Scy 752346981Scy 753346981Scystatic int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix, 754346981Scy const u8 *data, size_t data_len) 755346981Scy{ 756346981Scy#ifdef CONFIG_ETH_P_OUI 757346981Scy struct hostapd_data *hapd = ctx; 758346981Scy struct eth_p_oui_ctx *oui_ctx; 759346981Scy 760346981Scy#ifdef CONFIG_IEEE80211R_AP 761346981Scy if (hapd->iface->interfaces && 762346981Scy hapd->iface->interfaces->for_each_interface) { 763346981Scy struct wpa_auth_oui_iface_iter_data idata; 764346981Scy int res; 765346981Scy 766346981Scy idata.src_hapd = hapd; 767346981Scy idata.dst_addr = dst; 768346981Scy idata.data = data; 769346981Scy idata.data_len = data_len; 770346981Scy idata.oui_suffix = oui_suffix; 771346981Scy res = hapd->iface->interfaces->for_each_interface( 772346981Scy hapd->iface->interfaces, hostapd_wpa_auth_oui_iter, 773346981Scy &idata); 774346981Scy if (res == 1) 775346981Scy return data_len; 776346981Scy } 777346981Scy#endif /* CONFIG_IEEE80211R_AP */ 778346981Scy 779346981Scy oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix); 780346981Scy if (!oui_ctx) 781346981Scy return -1; 782346981Scy 783346981Scy return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len); 784346981Scy#else /* CONFIG_ETH_P_OUI */ 785346981Scy return -1; 786346981Scy#endif /* CONFIG_ETH_P_OUI */ 787346981Scy} 788346981Scy 789346981Scy 790346981Scystatic int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci) 791346981Scy{ 792346981Scy struct hostapd_data *hapd = ctx; 793346981Scy 794346981Scy return hostapd_drv_channel_info(hapd, ci); 795346981Scy} 796346981Scy 797346981Scy 798346981Scystatic int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id) 799346981Scy{ 800346981Scy#ifndef CONFIG_NO_VLAN 801346981Scy struct hostapd_data *hapd = ctx; 802346981Scy struct sta_info *sta; 803346981Scy struct vlan_description vlan_desc; 804346981Scy 805346981Scy sta = ap_get_sta(hapd, addr); 806346981Scy if (!sta) 807346981Scy return -1; 808346981Scy 809346981Scy os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 810346981Scy vlan_desc.notempty = 1; 811346981Scy vlan_desc.untagged = vlan_id; 812346981Scy if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 813346981Scy wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file", 814346981Scy vlan_id); 815346981Scy return -1; 816346981Scy } 817346981Scy 818346981Scy if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { 819346981Scy wpa_printf(MSG_INFO, 820346981Scy "Failed to assign VLAN ID %d from wpa_psk_file to " 821346981Scy MACSTR, vlan_id, MAC2STR(sta->addr)); 822346981Scy return -1; 823346981Scy } 824346981Scy 825346981Scy wpa_printf(MSG_INFO, 826346981Scy "Assigned VLAN ID %d from wpa_psk_file to " MACSTR, 827346981Scy vlan_id, MAC2STR(sta->addr)); 828346981Scy if ((sta->flags & WLAN_STA_ASSOC) && 829346981Scy ap_sta_bind_vlan(hapd, sta) < 0) 830346981Scy return -1; 831346981Scy#endif /* CONFIG_NO_VLAN */ 832346981Scy 833346981Scy return 0; 834346981Scy} 835346981Scy 836346981Scy 837346981Scy#ifdef CONFIG_OCV 838346981Scystatic int hostapd_get_sta_tx_params(void *ctx, const u8 *addr, 839346981Scy int ap_max_chanwidth, int ap_seg1_idx, 840346981Scy int *bandwidth, int *seg1_idx) 841346981Scy{ 842346981Scy struct hostapd_data *hapd = ctx; 843346981Scy struct sta_info *sta; 844346981Scy 845346981Scy sta = ap_get_sta(hapd, addr); 846346981Scy if (!sta) { 847346981Scy hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO, 848346981Scy "Failed to get STA info to validate received OCI"); 849346981Scy return -1; 850346981Scy } 851346981Scy 852346981Scy return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth, 853346981Scy seg1_idx); 854346981Scy} 855346981Scy#endif /* CONFIG_OCV */ 856346981Scy 857346981Scy 858346981Scy#ifdef CONFIG_IEEE80211R_AP 859346981Scy 860214501Srpaulostatic int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, 861214501Srpaulo const u8 *data, size_t data_len) 862214501Srpaulo{ 863214501Srpaulo struct hostapd_data *hapd = ctx; 864214501Srpaulo int res; 865214501Srpaulo struct ieee80211_mgmt *m; 866214501Srpaulo size_t mlen; 867214501Srpaulo struct sta_info *sta; 868214501Srpaulo 869214501Srpaulo sta = ap_get_sta(hapd, dst); 870214501Srpaulo if (sta == NULL || sta->wpa_sm == NULL) 871214501Srpaulo return -1; 872214501Srpaulo 873214501Srpaulo m = os_zalloc(sizeof(*m) + data_len); 874214501Srpaulo if (m == NULL) 875214501Srpaulo return -1; 876214501Srpaulo mlen = ((u8 *) &m->u - (u8 *) m) + data_len; 877214501Srpaulo m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 878214501Srpaulo WLAN_FC_STYPE_ACTION); 879214501Srpaulo os_memcpy(m->da, dst, ETH_ALEN); 880214501Srpaulo os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); 881214501Srpaulo os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); 882214501Srpaulo os_memcpy(&m->u, data, data_len); 883214501Srpaulo 884252726Srpaulo res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); 885214501Srpaulo os_free(m); 886214501Srpaulo return res; 887214501Srpaulo} 888214501Srpaulo 889214501Srpaulo 890214501Srpaulostatic struct wpa_state_machine * 891214501Srpaulohostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) 892214501Srpaulo{ 893214501Srpaulo struct hostapd_data *hapd = ctx; 894214501Srpaulo struct sta_info *sta; 895214501Srpaulo 896346981Scy wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR 897346981Scy " based on WPA authenticator callback", 898346981Scy MAC2STR(sta_addr)); 899252726Srpaulo if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) 900252726Srpaulo return NULL; 901252726Srpaulo 902214501Srpaulo sta = ap_sta_add(hapd, sta_addr); 903214501Srpaulo if (sta == NULL) 904214501Srpaulo return NULL; 905346981Scy if (hapd->driver && hapd->driver->add_sta_node) 906346981Scy sta->added_unassoc = 1; 907346981Scy sta->ft_over_ds = 1; 908214501Srpaulo if (sta->wpa_sm) { 909214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 910214501Srpaulo return sta->wpa_sm; 911214501Srpaulo } 912214501Srpaulo 913281806Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); 914214501Srpaulo if (sta->wpa_sm == NULL) { 915214501Srpaulo ap_free_sta(hapd, sta); 916214501Srpaulo return NULL; 917214501Srpaulo } 918214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 919214501Srpaulo 920214501Srpaulo return sta->wpa_sm; 921214501Srpaulo} 922214501Srpaulo 923214501Srpaulo 924346981Scystatic int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, 925346981Scy struct vlan_description *vlan) 926346981Scy{ 927346981Scy struct hostapd_data *hapd = ctx; 928346981Scy struct sta_info *sta; 929346981Scy 930346981Scy sta = ap_get_sta(hapd, sta_addr); 931346981Scy if (!sta || !sta->wpa_sm) 932346981Scy return -1; 933346981Scy 934346981Scy if (vlan->notempty && 935346981Scy !hostapd_vlan_valid(hapd->conf->vlan, vlan)) { 936346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 937346981Scy HOSTAPD_LEVEL_INFO, 938346981Scy "Invalid VLAN %d%s received from FT", 939346981Scy vlan->untagged, vlan->tagged[0] ? "+" : ""); 940346981Scy return -1; 941346981Scy } 942346981Scy 943346981Scy if (ap_sta_set_vlan(hapd, sta, vlan) < 0) 944346981Scy return -1; 945346981Scy /* Configure wpa_group for GTK but ignore error due to driver not 946346981Scy * knowing this STA. */ 947346981Scy ap_sta_bind_vlan(hapd, sta); 948346981Scy 949346981Scy if (sta->vlan_id) 950346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 951346981Scy HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 952346981Scy 953346981Scy return 0; 954346981Scy} 955346981Scy 956346981Scy 957346981Scystatic int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr, 958346981Scy struct vlan_description *vlan) 959346981Scy{ 960346981Scy struct hostapd_data *hapd = ctx; 961346981Scy struct sta_info *sta; 962346981Scy 963346981Scy sta = ap_get_sta(hapd, sta_addr); 964346981Scy if (!sta) 965346981Scy return -1; 966346981Scy 967346981Scy if (sta->vlan_desc) 968346981Scy *vlan = *sta->vlan_desc; 969346981Scy else 970346981Scy os_memset(vlan, 0, sizeof(*vlan)); 971346981Scy 972346981Scy return 0; 973346981Scy} 974346981Scy 975346981Scy 976346981Scystatic int 977346981Scyhostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr, 978346981Scy const u8 *identity, size_t identity_len) 979346981Scy{ 980346981Scy struct hostapd_data *hapd = ctx; 981346981Scy struct sta_info *sta; 982346981Scy 983346981Scy sta = ap_get_sta(hapd, sta_addr); 984346981Scy if (!sta) 985346981Scy return -1; 986346981Scy 987346981Scy os_free(sta->identity); 988346981Scy sta->identity = NULL; 989346981Scy 990346981Scy if (sta->eapol_sm) { 991346981Scy os_free(sta->eapol_sm->identity); 992346981Scy sta->eapol_sm->identity = NULL; 993346981Scy sta->eapol_sm->identity_len = 0; 994346981Scy } 995346981Scy 996346981Scy if (!identity_len) 997346981Scy return 0; 998346981Scy 999346981Scy /* sta->identity is NULL terminated */ 1000346981Scy sta->identity = os_zalloc(identity_len + 1); 1001346981Scy if (!sta->identity) 1002346981Scy return -1; 1003346981Scy os_memcpy(sta->identity, identity, identity_len); 1004346981Scy 1005346981Scy if (sta->eapol_sm) { 1006346981Scy sta->eapol_sm->identity = os_zalloc(identity_len); 1007346981Scy if (!sta->eapol_sm->identity) 1008346981Scy return -1; 1009346981Scy os_memcpy(sta->eapol_sm->identity, identity, identity_len); 1010346981Scy sta->eapol_sm->identity_len = identity_len; 1011346981Scy } 1012346981Scy 1013346981Scy return 0; 1014346981Scy} 1015346981Scy 1016346981Scy 1017346981Scystatic size_t 1018346981Scyhostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf) 1019346981Scy{ 1020346981Scy struct hostapd_data *hapd = ctx; 1021346981Scy struct sta_info *sta; 1022346981Scy size_t len; 1023346981Scy char *identity; 1024346981Scy 1025346981Scy sta = ap_get_sta(hapd, sta_addr); 1026346981Scy if (!sta) 1027346981Scy return 0; 1028346981Scy 1029346981Scy *buf = ieee802_1x_get_identity(sta->eapol_sm, &len); 1030346981Scy if (*buf && len) 1031346981Scy return len; 1032346981Scy 1033346981Scy if (!sta->identity) { 1034346981Scy *buf = NULL; 1035346981Scy return 0; 1036346981Scy } 1037346981Scy 1038346981Scy identity = sta->identity; 1039346981Scy len = os_strlen(identity); 1040346981Scy *buf = (u8 *) identity; 1041346981Scy 1042346981Scy return len; 1043346981Scy} 1044346981Scy 1045346981Scy 1046346981Scystatic int 1047346981Scyhostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr, 1048346981Scy const u8 *radius_cui, size_t radius_cui_len) 1049346981Scy{ 1050346981Scy struct hostapd_data *hapd = ctx; 1051346981Scy struct sta_info *sta; 1052346981Scy 1053346981Scy sta = ap_get_sta(hapd, sta_addr); 1054346981Scy if (!sta) 1055346981Scy return -1; 1056346981Scy 1057346981Scy os_free(sta->radius_cui); 1058346981Scy sta->radius_cui = NULL; 1059346981Scy 1060346981Scy if (sta->eapol_sm) { 1061346981Scy wpabuf_free(sta->eapol_sm->radius_cui); 1062346981Scy sta->eapol_sm->radius_cui = NULL; 1063346981Scy } 1064346981Scy 1065346981Scy if (!radius_cui) 1066346981Scy return 0; 1067346981Scy 1068346981Scy /* sta->radius_cui is NULL terminated */ 1069346981Scy sta->radius_cui = os_zalloc(radius_cui_len + 1); 1070346981Scy if (!sta->radius_cui) 1071346981Scy return -1; 1072346981Scy os_memcpy(sta->radius_cui, radius_cui, radius_cui_len); 1073346981Scy 1074346981Scy if (sta->eapol_sm) { 1075346981Scy sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui, 1076346981Scy radius_cui_len); 1077346981Scy if (!sta->eapol_sm->radius_cui) 1078346981Scy return -1; 1079346981Scy } 1080346981Scy 1081346981Scy return 0; 1082346981Scy} 1083346981Scy 1084346981Scy 1085346981Scystatic size_t 1086346981Scyhostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf) 1087346981Scy{ 1088346981Scy struct hostapd_data *hapd = ctx; 1089346981Scy struct sta_info *sta; 1090346981Scy struct wpabuf *b; 1091346981Scy size_t len; 1092346981Scy char *radius_cui; 1093346981Scy 1094346981Scy sta = ap_get_sta(hapd, sta_addr); 1095346981Scy if (!sta) 1096346981Scy return 0; 1097346981Scy 1098346981Scy b = ieee802_1x_get_radius_cui(sta->eapol_sm); 1099346981Scy if (b) { 1100346981Scy len = wpabuf_len(b); 1101346981Scy *buf = wpabuf_head(b); 1102346981Scy return len; 1103346981Scy } 1104346981Scy 1105346981Scy if (!sta->radius_cui) { 1106346981Scy *buf = NULL; 1107346981Scy return 0; 1108346981Scy } 1109346981Scy 1110346981Scy radius_cui = sta->radius_cui; 1111346981Scy len = os_strlen(radius_cui); 1112346981Scy *buf = (u8 *) radius_cui; 1113346981Scy 1114346981Scy return len; 1115346981Scy} 1116346981Scy 1117346981Scy 1118346981Scystatic void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr, 1119346981Scy int session_timeout) 1120346981Scy{ 1121346981Scy struct hostapd_data *hapd = ctx; 1122346981Scy struct sta_info *sta; 1123346981Scy 1124346981Scy sta = ap_get_sta(hapd, sta_addr); 1125346981Scy if (!sta) 1126346981Scy return; 1127346981Scy 1128346981Scy if (session_timeout) { 1129346981Scy os_get_reltime(&sta->session_timeout); 1130346981Scy sta->session_timeout.sec += session_timeout; 1131346981Scy sta->session_timeout_set = 1; 1132346981Scy ap_sta_session_timeout(hapd, sta, session_timeout); 1133346981Scy } else { 1134346981Scy sta->session_timeout_set = 0; 1135346981Scy ap_sta_no_session_timeout(hapd, sta); 1136346981Scy } 1137346981Scy} 1138346981Scy 1139346981Scy 1140346981Scystatic int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr) 1141346981Scy{ 1142346981Scy struct hostapd_data *hapd = ctx; 1143346981Scy struct sta_info *sta; 1144346981Scy struct os_reltime now, remaining; 1145346981Scy 1146346981Scy sta = ap_get_sta(hapd, sta_addr); 1147346981Scy if (!sta || !sta->session_timeout_set) 1148346981Scy return 0; 1149346981Scy 1150346981Scy os_get_reltime(&now); 1151346981Scy if (os_reltime_before(&sta->session_timeout, &now)) { 1152346981Scy /* already expired, return >0 as timeout was set */ 1153346981Scy return 1; 1154346981Scy } 1155346981Scy 1156346981Scy os_reltime_sub(&sta->session_timeout, &now, &remaining); 1157346981Scy 1158346981Scy return (remaining.sec > 0) ? remaining.sec : 1; 1159346981Scy} 1160346981Scy 1161346981Scy 1162214501Srpaulostatic void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, 1163214501Srpaulo size_t len) 1164214501Srpaulo{ 1165214501Srpaulo struct hostapd_data *hapd = ctx; 1166252726Srpaulo struct l2_ethhdr *ethhdr; 1167252726Srpaulo if (len < sizeof(*ethhdr)) 1168252726Srpaulo return; 1169252726Srpaulo ethhdr = (struct l2_ethhdr *) buf; 1170252726Srpaulo wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 1171252726Srpaulo MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest)); 1172337817Scy if (!is_multicast_ether_addr(ethhdr->h_dest) && 1173337817Scy os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0) 1174337817Scy return; 1175252726Srpaulo wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), 1176252726Srpaulo len - sizeof(*ethhdr)); 1177214501Srpaulo} 1178214501Srpaulo 1179252726Srpaulo 1180346981Scystatic void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr, 1181346981Scy const u8 *dst_addr, u8 oui_suffix, 1182346981Scy const u8 *buf, size_t len) 1183346981Scy{ 1184346981Scy struct hostapd_data *hapd = ctx; 1185346981Scy 1186346981Scy wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 1187346981Scy MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr)); 1188346981Scy if (!is_multicast_ether_addr(dst_addr) && 1189346981Scy os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0) 1190346981Scy return; 1191346981Scy wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf, 1192346981Scy len); 1193346981Scy} 1194346981Scy 1195346981Scy 1196252726Srpaulostatic int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr, 1197252726Srpaulo u8 *tspec_ie, size_t tspec_ielen) 1198252726Srpaulo{ 1199252726Srpaulo struct hostapd_data *hapd = ctx; 1200252726Srpaulo return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen); 1201252726Srpaulo} 1202252726Srpaulo 1203214501Srpaulo 1204214501Srpaulo 1205346981Scystatic int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd, 1206346981Scy const char *ft_iface) 1207346981Scy{ 1208346981Scy hapd->oui_pull = eth_p_oui_register(hapd, ft_iface, 1209346981Scy FT_PACKET_R0KH_R1KH_PULL, 1210346981Scy hostapd_rrb_oui_receive, hapd); 1211346981Scy if (!hapd->oui_pull) 1212346981Scy return -1; 1213346981Scy 1214346981Scy hapd->oui_resp = eth_p_oui_register(hapd, ft_iface, 1215346981Scy FT_PACKET_R0KH_R1KH_RESP, 1216346981Scy hostapd_rrb_oui_receive, hapd); 1217346981Scy if (!hapd->oui_resp) 1218346981Scy return -1; 1219346981Scy 1220346981Scy hapd->oui_push = eth_p_oui_register(hapd, ft_iface, 1221346981Scy FT_PACKET_R0KH_R1KH_PUSH, 1222346981Scy hostapd_rrb_oui_receive, hapd); 1223346981Scy if (!hapd->oui_push) 1224346981Scy return -1; 1225346981Scy 1226346981Scy hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface, 1227346981Scy FT_PACKET_R0KH_R1KH_SEQ_REQ, 1228346981Scy hostapd_rrb_oui_receive, hapd); 1229346981Scy if (!hapd->oui_sreq) 1230346981Scy return -1; 1231346981Scy 1232346981Scy hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface, 1233346981Scy FT_PACKET_R0KH_R1KH_SEQ_RESP, 1234346981Scy hostapd_rrb_oui_receive, hapd); 1235346981Scy if (!hapd->oui_sresp) 1236346981Scy return -1; 1237346981Scy 1238346981Scy return 0; 1239346981Scy} 1240346981Scy 1241346981Scy 1242346981Scystatic void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd) 1243346981Scy{ 1244346981Scy eth_p_oui_unregister(hapd->oui_pull); 1245346981Scy hapd->oui_pull = NULL; 1246346981Scy eth_p_oui_unregister(hapd->oui_resp); 1247346981Scy hapd->oui_resp = NULL; 1248346981Scy eth_p_oui_unregister(hapd->oui_push); 1249346981Scy hapd->oui_push = NULL; 1250346981Scy eth_p_oui_unregister(hapd->oui_sreq); 1251346981Scy hapd->oui_sreq = NULL; 1252346981Scy eth_p_oui_unregister(hapd->oui_sresp); 1253346981Scy hapd->oui_sresp = NULL; 1254346981Scy} 1255346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1256346981Scy 1257346981Scy 1258214501Srpauloint hostapd_setup_wpa(struct hostapd_data *hapd) 1259214501Srpaulo{ 1260214501Srpaulo struct wpa_auth_config _conf; 1261346981Scy static const struct wpa_auth_callbacks cb = { 1262346981Scy .logger = hostapd_wpa_auth_logger, 1263346981Scy .disconnect = hostapd_wpa_auth_disconnect, 1264346981Scy .mic_failure_report = hostapd_wpa_auth_mic_failure_report, 1265346981Scy .psk_failure_report = hostapd_wpa_auth_psk_failure_report, 1266346981Scy .set_eapol = hostapd_wpa_auth_set_eapol, 1267346981Scy .get_eapol = hostapd_wpa_auth_get_eapol, 1268346981Scy .get_psk = hostapd_wpa_auth_get_psk, 1269346981Scy .get_msk = hostapd_wpa_auth_get_msk, 1270346981Scy .set_key = hostapd_wpa_auth_set_key, 1271346981Scy .get_seqnum = hostapd_wpa_auth_get_seqnum, 1272346981Scy .send_eapol = hostapd_wpa_auth_send_eapol, 1273346981Scy .for_each_sta = hostapd_wpa_auth_for_each_sta, 1274346981Scy .for_each_auth = hostapd_wpa_auth_for_each_auth, 1275346981Scy .send_ether = hostapd_wpa_auth_send_ether, 1276346981Scy .send_oui = hostapd_wpa_auth_send_oui, 1277346981Scy .channel_info = hostapd_channel_info, 1278346981Scy .update_vlan = hostapd_wpa_auth_update_vlan, 1279346981Scy#ifdef CONFIG_OCV 1280346981Scy .get_sta_tx_params = hostapd_get_sta_tx_params, 1281346981Scy#endif /* CONFIG_OCV */ 1282346981Scy#ifdef CONFIG_IEEE80211R_AP 1283346981Scy .send_ft_action = hostapd_wpa_auth_send_ft_action, 1284346981Scy .add_sta = hostapd_wpa_auth_add_sta, 1285346981Scy .add_tspec = hostapd_wpa_auth_add_tspec, 1286346981Scy .set_vlan = hostapd_wpa_auth_set_vlan, 1287346981Scy .get_vlan = hostapd_wpa_auth_get_vlan, 1288346981Scy .set_identity = hostapd_wpa_auth_set_identity, 1289346981Scy .get_identity = hostapd_wpa_auth_get_identity, 1290346981Scy .set_radius_cui = hostapd_wpa_auth_set_radius_cui, 1291346981Scy .get_radius_cui = hostapd_wpa_auth_get_radius_cui, 1292346981Scy .set_session_timeout = hostapd_wpa_auth_set_session_timeout, 1293346981Scy .get_session_timeout = hostapd_wpa_auth_get_session_timeout, 1294346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1295346981Scy }; 1296214501Srpaulo const u8 *wpa_ie; 1297214501Srpaulo size_t wpa_ie_len; 1298214501Srpaulo 1299281806Srpaulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); 1300252726Srpaulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) 1301252726Srpaulo _conf.tx_status = 1; 1302252726Srpaulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) 1303252726Srpaulo _conf.ap_mlme = 1; 1304346981Scy hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); 1305214501Srpaulo if (hapd->wpa_auth == NULL) { 1306214501Srpaulo wpa_printf(MSG_ERROR, "WPA initialization failed."); 1307214501Srpaulo return -1; 1308214501Srpaulo } 1309214501Srpaulo 1310214501Srpaulo if (hostapd_set_privacy(hapd, 1)) { 1311214501Srpaulo wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " 1312214501Srpaulo "for interface %s", hapd->conf->iface); 1313214501Srpaulo return -1; 1314214501Srpaulo } 1315214501Srpaulo 1316214501Srpaulo wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); 1317214501Srpaulo if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { 1318214501Srpaulo wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " 1319214501Srpaulo "the kernel driver."); 1320214501Srpaulo return -1; 1321214501Srpaulo } 1322214501Srpaulo 1323214501Srpaulo if (rsn_preauth_iface_init(hapd)) { 1324214501Srpaulo wpa_printf(MSG_ERROR, "Initialization of RSN " 1325214501Srpaulo "pre-authentication failed."); 1326214501Srpaulo return -1; 1327214501Srpaulo } 1328214501Srpaulo 1329346981Scy#ifdef CONFIG_IEEE80211R_AP 1330337817Scy if (!hostapd_drv_none(hapd) && 1331289549Srpaulo wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { 1332346981Scy const char *ft_iface; 1333346981Scy 1334346981Scy ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge : 1335346981Scy hapd->conf->iface; 1336346981Scy hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, 1337252726Srpaulo hostapd_rrb_receive, hapd, 1); 1338214501Srpaulo if (hapd->l2 == NULL && 1339214501Srpaulo (hapd->driver == NULL || 1340214501Srpaulo hapd->driver->send_ether == NULL)) { 1341214501Srpaulo wpa_printf(MSG_ERROR, "Failed to open l2_packet " 1342214501Srpaulo "interface"); 1343214501Srpaulo return -1; 1344214501Srpaulo } 1345346981Scy 1346346981Scy if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) { 1347346981Scy wpa_printf(MSG_ERROR, 1348346981Scy "Failed to open ETH_P_OUI interface"); 1349346981Scy return -1; 1350346981Scy } 1351214501Srpaulo } 1352346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1353214501Srpaulo 1354214501Srpaulo return 0; 1355214501Srpaulo 1356214501Srpaulo} 1357214501Srpaulo 1358214501Srpaulo 1359214501Srpaulovoid hostapd_reconfig_wpa(struct hostapd_data *hapd) 1360214501Srpaulo{ 1361214501Srpaulo struct wpa_auth_config wpa_auth_conf; 1362281806Srpaulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf); 1363214501Srpaulo wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); 1364214501Srpaulo} 1365214501Srpaulo 1366214501Srpaulo 1367214501Srpaulovoid hostapd_deinit_wpa(struct hostapd_data *hapd) 1368214501Srpaulo{ 1369252726Srpaulo ieee80211_tkip_countermeasures_deinit(hapd); 1370214501Srpaulo rsn_preauth_iface_deinit(hapd); 1371214501Srpaulo if (hapd->wpa_auth) { 1372214501Srpaulo wpa_deinit(hapd->wpa_auth); 1373214501Srpaulo hapd->wpa_auth = NULL; 1374214501Srpaulo 1375337817Scy if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) { 1376214501Srpaulo wpa_printf(MSG_DEBUG, "Could not disable " 1377214501Srpaulo "PrivacyInvoked for interface %s", 1378214501Srpaulo hapd->conf->iface); 1379214501Srpaulo } 1380214501Srpaulo 1381337817Scy if (hapd->drv_priv && 1382337817Scy hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { 1383214501Srpaulo wpa_printf(MSG_DEBUG, "Could not remove generic " 1384214501Srpaulo "information element from interface %s", 1385214501Srpaulo hapd->conf->iface); 1386214501Srpaulo } 1387214501Srpaulo } 1388214501Srpaulo ieee802_1x_deinit(hapd); 1389214501Srpaulo 1390346981Scy#ifdef CONFIG_IEEE80211R_AP 1391346981Scy eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX); 1392346981Scy hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */ 1393346981Scy eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX); 1394346981Scy hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */ 1395214501Srpaulo l2_packet_deinit(hapd->l2); 1396281806Srpaulo hapd->l2 = NULL; 1397346981Scy hostapd_wpa_unregister_ft_oui(hapd); 1398346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1399214501Srpaulo} 1400