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; 56351611Scy#ifdef CONFIG_MACSEC 57351611Scy if (wconf->eapol_version > 2) 58351611Scy wconf->eapol_version = 2; 59351611Scy#endif /* CONFIG_MACSEC */ 60214501Srpaulo wconf->wmm_enabled = conf->wmm_enabled; 61214501Srpaulo wconf->wmm_uapsd = conf->wmm_uapsd; 62252726Srpaulo wconf->disable_pmksa_caching = conf->disable_pmksa_caching; 63346981Scy#ifdef CONFIG_OCV 64346981Scy wconf->ocv = conf->ocv; 65346981Scy#endif /* CONFIG_OCV */ 66214501Srpaulo wconf->okc = conf->okc; 67214501Srpaulo#ifdef CONFIG_IEEE80211W 68214501Srpaulo wconf->ieee80211w = conf->ieee80211w; 69281806Srpaulo wconf->group_mgmt_cipher = conf->group_mgmt_cipher; 70346981Scy wconf->sae_require_mfp = conf->sae_require_mfp; 71214501Srpaulo#endif /* CONFIG_IEEE80211W */ 72346981Scy#ifdef CONFIG_IEEE80211R_AP 73214501Srpaulo wconf->ssid_len = conf->ssid.ssid_len; 74289549Srpaulo if (wconf->ssid_len > SSID_MAX_LEN) 75289549Srpaulo wconf->ssid_len = SSID_MAX_LEN; 76214501Srpaulo os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); 77214501Srpaulo os_memcpy(wconf->mobility_domain, conf->mobility_domain, 78214501Srpaulo MOBILITY_DOMAIN_ID_LEN); 79214501Srpaulo if (conf->nas_identifier && 80214501Srpaulo os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { 81214501Srpaulo wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); 82214501Srpaulo os_memcpy(wconf->r0_key_holder, conf->nas_identifier, 83214501Srpaulo wconf->r0_key_holder_len); 84214501Srpaulo } 85214501Srpaulo os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); 86214501Srpaulo wconf->r0_key_lifetime = conf->r0_key_lifetime; 87346981Scy wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime; 88214501Srpaulo wconf->reassociation_deadline = conf->reassociation_deadline; 89346981Scy wconf->rkh_pos_timeout = conf->rkh_pos_timeout; 90346981Scy wconf->rkh_neg_timeout = conf->rkh_neg_timeout; 91346981Scy wconf->rkh_pull_timeout = conf->rkh_pull_timeout; 92346981Scy wconf->rkh_pull_retries = conf->rkh_pull_retries; 93346981Scy wconf->r0kh_list = &conf->r0kh_list; 94346981Scy wconf->r1kh_list = &conf->r1kh_list; 95214501Srpaulo wconf->pmk_r1_push = conf->pmk_r1_push; 96252726Srpaulo wconf->ft_over_ds = conf->ft_over_ds; 97346981Scy wconf->ft_psk_generate_local = conf->ft_psk_generate_local; 98346981Scy#endif /* CONFIG_IEEE80211R_AP */ 99252726Srpaulo#ifdef CONFIG_HS20 100252726Srpaulo wconf->disable_gtk = conf->disable_dgaf; 101281806Srpaulo if (conf->osen) { 102281806Srpaulo wconf->disable_gtk = 1; 103281806Srpaulo wconf->wpa = WPA_PROTO_OSEN; 104281806Srpaulo wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; 105281806Srpaulo wconf->wpa_pairwise = 0; 106281806Srpaulo wconf->wpa_group = WPA_CIPHER_CCMP; 107281806Srpaulo wconf->rsn_pairwise = WPA_CIPHER_CCMP; 108281806Srpaulo wconf->rsn_preauth = 0; 109281806Srpaulo wconf->disable_pmksa_caching = 1; 110281806Srpaulo#ifdef CONFIG_IEEE80211W 111281806Srpaulo wconf->ieee80211w = 1; 112281806Srpaulo#endif /* CONFIG_IEEE80211W */ 113281806Srpaulo } 114252726Srpaulo#endif /* CONFIG_HS20 */ 115281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 116281806Srpaulo wconf->corrupt_gtk_rekey_mic_probability = 117281806Srpaulo iconf->corrupt_gtk_rekey_mic_probability; 118289549Srpaulo if (conf->own_ie_override && 119289549Srpaulo wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) { 120289549Srpaulo wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override); 121289549Srpaulo os_memcpy(wconf->own_ie_override, 122289549Srpaulo wpabuf_head(conf->own_ie_override), 123289549Srpaulo wconf->own_ie_override_len); 124289549Srpaulo } 125281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 126281806Srpaulo#ifdef CONFIG_P2P 127281806Srpaulo os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); 128281806Srpaulo os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4); 129281806Srpaulo os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4); 130281806Srpaulo os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4); 131281806Srpaulo#endif /* CONFIG_P2P */ 132346981Scy#ifdef CONFIG_FILS 133346981Scy wconf->fils_cache_id_set = conf->fils_cache_id_set; 134346981Scy os_memcpy(wconf->fils_cache_id, conf->fils_cache_id, 135346981Scy FILS_CACHE_ID_LEN); 136346981Scy#endif /* CONFIG_FILS */ 137214501Srpaulo} 138214501Srpaulo 139214501Srpaulo 140214501Srpaulostatic void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, 141214501Srpaulo logger_level level, const char *txt) 142214501Srpaulo{ 143214501Srpaulo#ifndef CONFIG_NO_HOSTAPD_LOGGER 144214501Srpaulo struct hostapd_data *hapd = ctx; 145214501Srpaulo int hlevel; 146214501Srpaulo 147214501Srpaulo switch (level) { 148214501Srpaulo case LOGGER_WARNING: 149214501Srpaulo hlevel = HOSTAPD_LEVEL_WARNING; 150214501Srpaulo break; 151214501Srpaulo case LOGGER_INFO: 152214501Srpaulo hlevel = HOSTAPD_LEVEL_INFO; 153214501Srpaulo break; 154214501Srpaulo case LOGGER_DEBUG: 155214501Srpaulo default: 156214501Srpaulo hlevel = HOSTAPD_LEVEL_DEBUG; 157214501Srpaulo break; 158214501Srpaulo } 159214501Srpaulo 160214501Srpaulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); 161214501Srpaulo#endif /* CONFIG_NO_HOSTAPD_LOGGER */ 162214501Srpaulo} 163214501Srpaulo 164214501Srpaulo 165214501Srpaulostatic void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, 166214501Srpaulo u16 reason) 167214501Srpaulo{ 168214501Srpaulo struct hostapd_data *hapd = ctx; 169214501Srpaulo wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " 170214501Srpaulo "STA " MACSTR " reason %d", 171214501Srpaulo __func__, MAC2STR(addr), reason); 172214501Srpaulo ap_sta_disconnect(hapd, NULL, addr, reason); 173214501Srpaulo} 174214501Srpaulo 175214501Srpaulo 176252726Srpaulostatic int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) 177214501Srpaulo{ 178214501Srpaulo struct hostapd_data *hapd = ctx; 179252726Srpaulo return michael_mic_failure(hapd, addr, 0); 180214501Srpaulo} 181214501Srpaulo 182214501Srpaulo 183289549Srpaulostatic void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr) 184289549Srpaulo{ 185289549Srpaulo struct hostapd_data *hapd = ctx; 186289549Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, 187289549Srpaulo MAC2STR(addr)); 188289549Srpaulo} 189289549Srpaulo 190289549Srpaulo 191214501Srpaulostatic void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, 192214501Srpaulo wpa_eapol_variable var, int value) 193214501Srpaulo{ 194214501Srpaulo struct hostapd_data *hapd = ctx; 195214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 196214501Srpaulo if (sta == NULL) 197214501Srpaulo return; 198214501Srpaulo switch (var) { 199214501Srpaulo case WPA_EAPOL_portEnabled: 200214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, value); 201214501Srpaulo break; 202214501Srpaulo case WPA_EAPOL_portValid: 203214501Srpaulo ieee802_1x_notify_port_valid(sta->eapol_sm, value); 204214501Srpaulo break; 205214501Srpaulo case WPA_EAPOL_authorized: 206214501Srpaulo ieee802_1x_set_sta_authorized(hapd, sta, value); 207214501Srpaulo break; 208214501Srpaulo case WPA_EAPOL_portControl_Auto: 209214501Srpaulo if (sta->eapol_sm) 210214501Srpaulo sta->eapol_sm->portControl = Auto; 211214501Srpaulo break; 212214501Srpaulo case WPA_EAPOL_keyRun: 213214501Srpaulo if (sta->eapol_sm) 214214501Srpaulo sta->eapol_sm->keyRun = value ? TRUE : FALSE; 215214501Srpaulo break; 216214501Srpaulo case WPA_EAPOL_keyAvailable: 217214501Srpaulo if (sta->eapol_sm) 218214501Srpaulo sta->eapol_sm->eap_if->eapKeyAvailable = 219214501Srpaulo value ? TRUE : FALSE; 220214501Srpaulo break; 221214501Srpaulo case WPA_EAPOL_keyDone: 222214501Srpaulo if (sta->eapol_sm) 223214501Srpaulo sta->eapol_sm->keyDone = value ? TRUE : FALSE; 224214501Srpaulo break; 225214501Srpaulo case WPA_EAPOL_inc_EapolFramesTx: 226214501Srpaulo if (sta->eapol_sm) 227214501Srpaulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 228214501Srpaulo break; 229214501Srpaulo } 230214501Srpaulo} 231214501Srpaulo 232214501Srpaulo 233214501Srpaulostatic int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, 234214501Srpaulo wpa_eapol_variable var) 235214501Srpaulo{ 236214501Srpaulo struct hostapd_data *hapd = ctx; 237214501Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 238214501Srpaulo if (sta == NULL || sta->eapol_sm == NULL) 239214501Srpaulo return -1; 240214501Srpaulo switch (var) { 241214501Srpaulo case WPA_EAPOL_keyRun: 242214501Srpaulo return sta->eapol_sm->keyRun; 243214501Srpaulo case WPA_EAPOL_keyAvailable: 244214501Srpaulo return sta->eapol_sm->eap_if->eapKeyAvailable; 245214501Srpaulo default: 246214501Srpaulo return -1; 247214501Srpaulo } 248214501Srpaulo} 249214501Srpaulo 250214501Srpaulo 251214501Srpaulostatic const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, 252281806Srpaulo const u8 *p2p_dev_addr, 253346981Scy const u8 *prev_psk, size_t *psk_len, 254346981Scy int *vlan_id) 255214501Srpaulo{ 256214501Srpaulo struct hostapd_data *hapd = ctx; 257252726Srpaulo struct sta_info *sta = ap_get_sta(hapd, addr); 258281806Srpaulo const u8 *psk; 259281806Srpaulo 260346981Scy if (vlan_id) 261346981Scy *vlan_id = 0; 262346981Scy if (psk_len) 263346981Scy *psk_len = PMK_LEN; 264346981Scy 265281806Srpaulo#ifdef CONFIG_SAE 266281806Srpaulo if (sta && sta->auth_alg == WLAN_AUTH_SAE) { 267281806Srpaulo if (!sta->sae || prev_psk) 268281806Srpaulo return NULL; 269281806Srpaulo return sta->sae->pmk; 270281806Srpaulo } 271346981Scy if (sta && wpa_auth_uses_sae(sta->wpa_sm)) { 272346981Scy wpa_printf(MSG_DEBUG, 273346981Scy "No PSK for STA trying to use SAE with PMKSA caching"); 274346981Scy return NULL; 275346981Scy } 276281806Srpaulo#endif /* CONFIG_SAE */ 277281806Srpaulo 278346981Scy#ifdef CONFIG_OWE 279346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 280346981Scy sta && sta->owe_pmk) { 281346981Scy if (psk_len) 282346981Scy *psk_len = sta->owe_pmk_len; 283346981Scy return sta->owe_pmk; 284346981Scy } 285346981Scy if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) { 286346981Scy struct rsn_pmksa_cache_entry *sa; 287346981Scy 288346981Scy sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 289346981Scy if (sa && sa->akmp == WPA_KEY_MGMT_OWE) { 290346981Scy if (psk_len) 291346981Scy *psk_len = sa->pmk_len; 292346981Scy return sa->pmk; 293346981Scy } 294346981Scy } 295346981Scy#endif /* CONFIG_OWE */ 296346981Scy 297346981Scy psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk, 298346981Scy vlan_id); 299252726Srpaulo /* 300252726Srpaulo * This is about to iterate over all psks, prev_psk gives the last 301252726Srpaulo * returned psk which should not be returned again. 302252726Srpaulo * logic list (all hostapd_get_psk; all sta->psk) 303252726Srpaulo */ 304252726Srpaulo if (sta && sta->psk && !psk) { 305252726Srpaulo struct hostapd_sta_wpa_psk_short *pos; 306346981Scy 307346981Scy if (vlan_id) 308346981Scy *vlan_id = 0; 309252726Srpaulo psk = sta->psk->psk; 310252726Srpaulo for (pos = sta->psk; pos; pos = pos->next) { 311337817Scy if (pos->is_passphrase) { 312337817Scy pbkdf2_sha1(pos->passphrase, 313337817Scy hapd->conf->ssid.ssid, 314337817Scy hapd->conf->ssid.ssid_len, 4096, 315337817Scy pos->psk, PMK_LEN); 316337817Scy pos->is_passphrase = 0; 317337817Scy } 318252726Srpaulo if (pos->psk == prev_psk) { 319252726Srpaulo psk = pos->next ? pos->next->psk : NULL; 320252726Srpaulo break; 321252726Srpaulo } 322252726Srpaulo } 323252726Srpaulo } 324252726Srpaulo return psk; 325214501Srpaulo} 326214501Srpaulo 327214501Srpaulo 328214501Srpaulostatic int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, 329214501Srpaulo size_t *len) 330214501Srpaulo{ 331214501Srpaulo struct hostapd_data *hapd = ctx; 332214501Srpaulo const u8 *key; 333214501Srpaulo size_t keylen; 334214501Srpaulo struct sta_info *sta; 335214501Srpaulo 336214501Srpaulo sta = ap_get_sta(hapd, addr); 337281806Srpaulo if (sta == NULL) { 338281806Srpaulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA"); 339214501Srpaulo return -1; 340281806Srpaulo } 341214501Srpaulo 342214501Srpaulo key = ieee802_1x_get_key(sta->eapol_sm, &keylen); 343281806Srpaulo if (key == NULL) { 344281806Srpaulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p", 345281806Srpaulo sta->eapol_sm); 346214501Srpaulo return -1; 347281806Srpaulo } 348214501Srpaulo 349214501Srpaulo if (keylen > *len) 350214501Srpaulo keylen = *len; 351214501Srpaulo os_memcpy(msk, key, keylen); 352214501Srpaulo *len = keylen; 353214501Srpaulo 354214501Srpaulo return 0; 355214501Srpaulo} 356214501Srpaulo 357214501Srpaulo 358214501Srpaulostatic int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 359214501Srpaulo const u8 *addr, int idx, u8 *key, 360214501Srpaulo size_t key_len) 361214501Srpaulo{ 362214501Srpaulo struct hostapd_data *hapd = ctx; 363214501Srpaulo const char *ifname = hapd->conf->iface; 364214501Srpaulo 365214501Srpaulo if (vlan_id > 0) { 366214501Srpaulo ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); 367214501Srpaulo if (ifname == NULL) 368214501Srpaulo return -1; 369214501Srpaulo } 370214501Srpaulo 371346981Scy#ifdef CONFIG_TESTING_OPTIONS 372346981Scy if (addr && !is_broadcast_ether_addr(addr)) { 373346981Scy struct sta_info *sta; 374346981Scy 375346981Scy sta = ap_get_sta(hapd, addr); 376346981Scy if (sta) { 377346981Scy sta->last_tk_alg = alg; 378346981Scy sta->last_tk_key_idx = idx; 379346981Scy if (key) 380346981Scy os_memcpy(sta->last_tk, key, key_len); 381346981Scy sta->last_tk_len = key_len; 382346981Scy } 383346981Scy#ifdef CONFIG_IEEE80211W 384346981Scy } else if (alg == WPA_ALG_IGTK || 385346981Scy alg == WPA_ALG_BIP_GMAC_128 || 386346981Scy alg == WPA_ALG_BIP_GMAC_256 || 387346981Scy alg == WPA_ALG_BIP_CMAC_256) { 388346981Scy hapd->last_igtk_alg = alg; 389346981Scy hapd->last_igtk_key_idx = idx; 390346981Scy if (key) 391346981Scy os_memcpy(hapd->last_igtk, key, key_len); 392346981Scy hapd->last_igtk_len = key_len; 393346981Scy#endif /* CONFIG_IEEE80211W */ 394346981Scy } else { 395346981Scy hapd->last_gtk_alg = alg; 396346981Scy hapd->last_gtk_key_idx = idx; 397346981Scy if (key) 398346981Scy os_memcpy(hapd->last_gtk, key, key_len); 399346981Scy hapd->last_gtk_len = key_len; 400346981Scy } 401346981Scy#endif /* CONFIG_TESTING_OPTIONS */ 402252726Srpaulo return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, 403252726Srpaulo key, key_len); 404214501Srpaulo} 405214501Srpaulo 406214501Srpaulo 407214501Srpaulostatic int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, 408214501Srpaulo u8 *seq) 409214501Srpaulo{ 410214501Srpaulo struct hostapd_data *hapd = ctx; 411214501Srpaulo return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); 412214501Srpaulo} 413214501Srpaulo 414214501Srpaulo 415214501Srpaulostatic int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, 416214501Srpaulo const u8 *data, size_t data_len, 417214501Srpaulo int encrypt) 418214501Srpaulo{ 419214501Srpaulo struct hostapd_data *hapd = ctx; 420252726Srpaulo struct sta_info *sta; 421252726Srpaulo u32 flags = 0; 422252726Srpaulo 423281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 424281806Srpaulo if (hapd->ext_eapol_frame_io) { 425281806Srpaulo size_t hex_len = 2 * data_len + 1; 426281806Srpaulo char *hex = os_malloc(hex_len); 427281806Srpaulo 428281806Srpaulo if (hex == NULL) 429281806Srpaulo return -1; 430281806Srpaulo wpa_snprintf_hex(hex, hex_len, data, data_len); 431281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 432281806Srpaulo MAC2STR(addr), hex); 433281806Srpaulo os_free(hex); 434281806Srpaulo return 0; 435281806Srpaulo } 436281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 437281806Srpaulo 438252726Srpaulo sta = ap_get_sta(hapd, addr); 439252726Srpaulo if (sta) 440252726Srpaulo flags = hostapd_sta_flags_to_drv(sta->flags); 441252726Srpaulo 442252726Srpaulo return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, 443252726Srpaulo encrypt, flags); 444214501Srpaulo} 445214501Srpaulo 446214501Srpaulo 447214501Srpaulostatic int hostapd_wpa_auth_for_each_sta( 448214501Srpaulo void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), 449214501Srpaulo void *cb_ctx) 450214501Srpaulo{ 451214501Srpaulo struct hostapd_data *hapd = ctx; 452214501Srpaulo struct sta_info *sta; 453214501Srpaulo 454214501Srpaulo for (sta = hapd->sta_list; sta; sta = sta->next) { 455214501Srpaulo if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) 456214501Srpaulo return 1; 457214501Srpaulo } 458214501Srpaulo return 0; 459214501Srpaulo} 460214501Srpaulo 461214501Srpaulo 462214501Srpaulostruct wpa_auth_iface_iter_data { 463214501Srpaulo int (*cb)(struct wpa_authenticator *sm, void *ctx); 464214501Srpaulo void *cb_ctx; 465214501Srpaulo}; 466214501Srpaulo 467214501Srpaulostatic int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) 468214501Srpaulo{ 469214501Srpaulo struct wpa_auth_iface_iter_data *data = ctx; 470214501Srpaulo size_t i; 471214501Srpaulo for (i = 0; i < iface->num_bss; i++) { 472214501Srpaulo if (iface->bss[i]->wpa_auth && 473214501Srpaulo data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) 474214501Srpaulo return 1; 475214501Srpaulo } 476214501Srpaulo return 0; 477214501Srpaulo} 478214501Srpaulo 479214501Srpaulo 480214501Srpaulostatic int hostapd_wpa_auth_for_each_auth( 481214501Srpaulo void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), 482214501Srpaulo void *cb_ctx) 483214501Srpaulo{ 484214501Srpaulo struct hostapd_data *hapd = ctx; 485214501Srpaulo struct wpa_auth_iface_iter_data data; 486252726Srpaulo if (hapd->iface->interfaces == NULL || 487252726Srpaulo hapd->iface->interfaces->for_each_interface == NULL) 488214501Srpaulo return -1; 489214501Srpaulo data.cb = cb; 490214501Srpaulo data.cb_ctx = cb_ctx; 491252726Srpaulo return hapd->iface->interfaces->for_each_interface( 492252726Srpaulo hapd->iface->interfaces, wpa_auth_iface_iter, &data); 493214501Srpaulo} 494214501Srpaulo 495214501Srpaulo 496346981Scy#ifdef CONFIG_IEEE80211R_AP 497214501Srpaulo 498346981Scystruct wpa_ft_rrb_rx_later_data { 499346981Scy struct dl_list list; 500346981Scy u8 addr[ETH_ALEN]; 501346981Scy size_t data_len; 502346981Scy /* followed by data_len octets of data */ 503346981Scy}; 504346981Scy 505346981Scystatic void hostapd_wpa_ft_rrb_rx_later(void *eloop_ctx, void *timeout_ctx) 506346981Scy{ 507346981Scy struct hostapd_data *hapd = eloop_ctx; 508346981Scy struct wpa_ft_rrb_rx_later_data *data, *n; 509346981Scy 510346981Scy dl_list_for_each_safe(data, n, &hapd->l2_queue, 511346981Scy struct wpa_ft_rrb_rx_later_data, list) { 512346981Scy if (hapd->wpa_auth) { 513346981Scy wpa_ft_rrb_rx(hapd->wpa_auth, data->addr, 514346981Scy (const u8 *) (data + 1), 515346981Scy data->data_len); 516346981Scy } 517346981Scy dl_list_del(&data->list); 518346981Scy os_free(data); 519346981Scy } 520346981Scy} 521346981Scy 522346981Scy 523214501Srpaulostruct wpa_auth_ft_iface_iter_data { 524214501Srpaulo struct hostapd_data *src_hapd; 525214501Srpaulo const u8 *dst; 526214501Srpaulo const u8 *data; 527214501Srpaulo size_t data_len; 528214501Srpaulo}; 529214501Srpaulo 530214501Srpaulo 531214501Srpaulostatic int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) 532214501Srpaulo{ 533214501Srpaulo struct wpa_auth_ft_iface_iter_data *idata = ctx; 534346981Scy struct wpa_ft_rrb_rx_later_data *data; 535214501Srpaulo struct hostapd_data *hapd; 536214501Srpaulo size_t j; 537214501Srpaulo 538214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 539214501Srpaulo hapd = iface->bss[j]; 540346981Scy if (hapd == idata->src_hapd || 541346981Scy !hapd->wpa_auth || 542346981Scy os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0) 543214501Srpaulo continue; 544346981Scy 545346981Scy wpa_printf(MSG_DEBUG, 546346981Scy "FT: Send RRB data directly to locally managed BSS " 547346981Scy MACSTR "@%s -> " MACSTR "@%s", 548346981Scy MAC2STR(idata->src_hapd->own_addr), 549346981Scy idata->src_hapd->conf->iface, 550346981Scy MAC2STR(hapd->own_addr), hapd->conf->iface); 551346981Scy 552346981Scy /* Defer wpa_ft_rrb_rx() until next eloop step as this is 553346981Scy * when it would be triggered when reading from a socket. 554346981Scy * This avoids 555346981Scy * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 556346981Scy * that is calling hapd0:recv handler from within 557346981Scy * hapd0:send directly. 558346981Scy */ 559346981Scy data = os_zalloc(sizeof(*data) + idata->data_len); 560346981Scy if (!data) 561214501Srpaulo return 1; 562346981Scy 563346981Scy os_memcpy(data->addr, idata->src_hapd->own_addr, ETH_ALEN); 564346981Scy os_memcpy(data + 1, idata->data, idata->data_len); 565346981Scy data->data_len = idata->data_len; 566346981Scy 567346981Scy dl_list_add(&hapd->l2_queue, &data->list); 568346981Scy 569346981Scy if (!eloop_is_timeout_registered(hostapd_wpa_ft_rrb_rx_later, 570346981Scy hapd, NULL)) 571346981Scy eloop_register_timeout(0, 0, 572346981Scy hostapd_wpa_ft_rrb_rx_later, 573346981Scy hapd, NULL); 574346981Scy 575346981Scy return 1; 576214501Srpaulo } 577214501Srpaulo 578214501Srpaulo return 0; 579214501Srpaulo} 580214501Srpaulo 581346981Scy#endif /* CONFIG_IEEE80211R_AP */ 582214501Srpaulo 583214501Srpaulo 584214501Srpaulostatic int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, 585214501Srpaulo const u8 *data, size_t data_len) 586214501Srpaulo{ 587214501Srpaulo struct hostapd_data *hapd = ctx; 588252726Srpaulo struct l2_ethhdr *buf; 589252726Srpaulo int ret; 590214501Srpaulo 591281806Srpaulo#ifdef CONFIG_TESTING_OPTIONS 592281806Srpaulo if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) { 593281806Srpaulo size_t hex_len = 2 * data_len + 1; 594281806Srpaulo char *hex = os_malloc(hex_len); 595281806Srpaulo 596281806Srpaulo if (hex == NULL) 597281806Srpaulo return -1; 598281806Srpaulo wpa_snprintf_hex(hex, hex_len, data, data_len); 599281806Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 600281806Srpaulo MAC2STR(dst), hex); 601281806Srpaulo os_free(hex); 602281806Srpaulo return 0; 603281806Srpaulo } 604281806Srpaulo#endif /* CONFIG_TESTING_OPTIONS */ 605281806Srpaulo 606346981Scy#ifdef CONFIG_IEEE80211R_AP 607252726Srpaulo if (proto == ETH_P_RRB && hapd->iface->interfaces && 608252726Srpaulo hapd->iface->interfaces->for_each_interface) { 609214501Srpaulo int res; 610214501Srpaulo struct wpa_auth_ft_iface_iter_data idata; 611214501Srpaulo idata.src_hapd = hapd; 612214501Srpaulo idata.dst = dst; 613214501Srpaulo idata.data = data; 614214501Srpaulo idata.data_len = data_len; 615252726Srpaulo res = hapd->iface->interfaces->for_each_interface( 616252726Srpaulo hapd->iface->interfaces, hostapd_wpa_auth_ft_iter, 617252726Srpaulo &idata); 618214501Srpaulo if (res == 1) 619214501Srpaulo return data_len; 620214501Srpaulo } 621346981Scy#endif /* CONFIG_IEEE80211R_AP */ 622214501Srpaulo 623214501Srpaulo if (hapd->driver && hapd->driver->send_ether) 624214501Srpaulo return hapd->driver->send_ether(hapd->drv_priv, dst, 625214501Srpaulo hapd->own_addr, proto, 626214501Srpaulo data, data_len); 627214501Srpaulo if (hapd->l2 == NULL) 628214501Srpaulo return -1; 629252726Srpaulo 630252726Srpaulo buf = os_malloc(sizeof(*buf) + data_len); 631252726Srpaulo if (buf == NULL) 632252726Srpaulo return -1; 633252726Srpaulo os_memcpy(buf->h_dest, dst, ETH_ALEN); 634252726Srpaulo os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN); 635252726Srpaulo buf->h_proto = host_to_be16(proto); 636252726Srpaulo os_memcpy(buf + 1, data, data_len); 637252726Srpaulo ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, 638252726Srpaulo sizeof(*buf) + data_len); 639252726Srpaulo os_free(buf); 640252726Srpaulo return ret; 641214501Srpaulo} 642214501Srpaulo 643214501Srpaulo 644346981Scy#ifdef CONFIG_ETH_P_OUI 645346981Scystatic struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd, 646346981Scy u8 oui_suffix) 647346981Scy{ 648346981Scy switch (oui_suffix) { 649346981Scy#ifdef CONFIG_IEEE80211R_AP 650346981Scy case FT_PACKET_R0KH_R1KH_PULL: 651346981Scy return hapd->oui_pull; 652346981Scy case FT_PACKET_R0KH_R1KH_RESP: 653346981Scy return hapd->oui_resp; 654346981Scy case FT_PACKET_R0KH_R1KH_PUSH: 655346981Scy return hapd->oui_push; 656346981Scy case FT_PACKET_R0KH_R1KH_SEQ_REQ: 657346981Scy return hapd->oui_sreq; 658346981Scy case FT_PACKET_R0KH_R1KH_SEQ_RESP: 659346981Scy return hapd->oui_sresp; 660346981Scy#endif /* CONFIG_IEEE80211R_AP */ 661346981Scy default: 662346981Scy return NULL; 663346981Scy } 664346981Scy} 665346981Scy#endif /* CONFIG_ETH_P_OUI */ 666214501Srpaulo 667346981Scy 668346981Scy#ifdef CONFIG_IEEE80211R_AP 669346981Scy 670346981Scystruct oui_deliver_later_data { 671346981Scy struct dl_list list; 672346981Scy u8 src_addr[ETH_ALEN]; 673346981Scy u8 dst_addr[ETH_ALEN]; 674346981Scy size_t data_len; 675346981Scy u8 oui_suffix; 676346981Scy /* followed by data_len octets of data */ 677346981Scy}; 678346981Scy 679346981Scystatic void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx) 680346981Scy{ 681346981Scy struct hostapd_data *hapd = eloop_ctx; 682346981Scy struct oui_deliver_later_data *data, *n; 683346981Scy struct eth_p_oui_ctx *oui_ctx; 684346981Scy 685346981Scy dl_list_for_each_safe(data, n, &hapd->l2_oui_queue, 686346981Scy struct oui_deliver_later_data, list) { 687346981Scy oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix); 688346981Scy if (hapd->wpa_auth && oui_ctx) { 689346981Scy eth_p_oui_deliver(oui_ctx, data->src_addr, 690346981Scy data->dst_addr, 691346981Scy (const u8 *) (data + 1), 692346981Scy data->data_len); 693346981Scy } 694346981Scy dl_list_del(&data->list); 695346981Scy os_free(data); 696346981Scy } 697346981Scy} 698346981Scy 699346981Scy 700346981Scystruct wpa_auth_oui_iface_iter_data { 701346981Scy struct hostapd_data *src_hapd; 702346981Scy const u8 *dst_addr; 703346981Scy const u8 *data; 704346981Scy size_t data_len; 705346981Scy u8 oui_suffix; 706346981Scy}; 707346981Scy 708346981Scystatic int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) 709346981Scy{ 710346981Scy struct wpa_auth_oui_iface_iter_data *idata = ctx; 711346981Scy struct oui_deliver_later_data *data; 712346981Scy struct hostapd_data *hapd; 713346981Scy size_t j; 714346981Scy 715346981Scy for (j = 0; j < iface->num_bss; j++) { 716346981Scy hapd = iface->bss[j]; 717346981Scy if (hapd == idata->src_hapd) 718346981Scy continue; 719346981Scy if (!is_multicast_ether_addr(idata->dst_addr) && 720346981Scy os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0) 721346981Scy continue; 722346981Scy 723346981Scy /* defer eth_p_oui_deliver until next eloop step as this is 724346981Scy * when it would be triggerd from reading from sock 725346981Scy * This avoids 726346981Scy * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 727346981Scy * that is calling hapd0:recv handler from within 728346981Scy * hapd0:send directly. 729346981Scy */ 730346981Scy data = os_zalloc(sizeof(*data) + idata->data_len); 731346981Scy if (!data) 732346981Scy return 1; 733346981Scy 734346981Scy os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN); 735346981Scy os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN); 736346981Scy os_memcpy(data + 1, idata->data, idata->data_len); 737346981Scy data->data_len = idata->data_len; 738346981Scy data->oui_suffix = idata->oui_suffix; 739346981Scy 740346981Scy dl_list_add(&hapd->l2_oui_queue, &data->list); 741346981Scy 742346981Scy if (!eloop_is_timeout_registered(hostapd_oui_deliver_later, 743346981Scy hapd, NULL)) 744346981Scy eloop_register_timeout(0, 0, 745346981Scy hostapd_oui_deliver_later, 746346981Scy hapd, NULL); 747346981Scy 748346981Scy return 1; 749346981Scy } 750346981Scy 751346981Scy return 0; 752346981Scy} 753346981Scy 754346981Scy#endif /* CONFIG_IEEE80211R_AP */ 755346981Scy 756346981Scy 757346981Scystatic int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix, 758346981Scy const u8 *data, size_t data_len) 759346981Scy{ 760346981Scy#ifdef CONFIG_ETH_P_OUI 761346981Scy struct hostapd_data *hapd = ctx; 762346981Scy struct eth_p_oui_ctx *oui_ctx; 763346981Scy 764346981Scy#ifdef CONFIG_IEEE80211R_AP 765346981Scy if (hapd->iface->interfaces && 766346981Scy hapd->iface->interfaces->for_each_interface) { 767346981Scy struct wpa_auth_oui_iface_iter_data idata; 768346981Scy int res; 769346981Scy 770346981Scy idata.src_hapd = hapd; 771346981Scy idata.dst_addr = dst; 772346981Scy idata.data = data; 773346981Scy idata.data_len = data_len; 774346981Scy idata.oui_suffix = oui_suffix; 775346981Scy res = hapd->iface->interfaces->for_each_interface( 776346981Scy hapd->iface->interfaces, hostapd_wpa_auth_oui_iter, 777346981Scy &idata); 778346981Scy if (res == 1) 779346981Scy return data_len; 780346981Scy } 781346981Scy#endif /* CONFIG_IEEE80211R_AP */ 782346981Scy 783346981Scy oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix); 784346981Scy if (!oui_ctx) 785346981Scy return -1; 786346981Scy 787346981Scy return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len); 788346981Scy#else /* CONFIG_ETH_P_OUI */ 789346981Scy return -1; 790346981Scy#endif /* CONFIG_ETH_P_OUI */ 791346981Scy} 792346981Scy 793346981Scy 794346981Scystatic int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci) 795346981Scy{ 796346981Scy struct hostapd_data *hapd = ctx; 797346981Scy 798346981Scy return hostapd_drv_channel_info(hapd, ci); 799346981Scy} 800346981Scy 801346981Scy 802346981Scystatic int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id) 803346981Scy{ 804346981Scy#ifndef CONFIG_NO_VLAN 805346981Scy struct hostapd_data *hapd = ctx; 806346981Scy struct sta_info *sta; 807346981Scy struct vlan_description vlan_desc; 808346981Scy 809346981Scy sta = ap_get_sta(hapd, addr); 810346981Scy if (!sta) 811346981Scy return -1; 812346981Scy 813346981Scy os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 814346981Scy vlan_desc.notempty = 1; 815346981Scy vlan_desc.untagged = vlan_id; 816346981Scy if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 817346981Scy wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file", 818346981Scy vlan_id); 819346981Scy return -1; 820346981Scy } 821346981Scy 822346981Scy if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { 823346981Scy wpa_printf(MSG_INFO, 824346981Scy "Failed to assign VLAN ID %d from wpa_psk_file to " 825346981Scy MACSTR, vlan_id, MAC2STR(sta->addr)); 826346981Scy return -1; 827346981Scy } 828346981Scy 829346981Scy wpa_printf(MSG_INFO, 830346981Scy "Assigned VLAN ID %d from wpa_psk_file to " MACSTR, 831346981Scy vlan_id, MAC2STR(sta->addr)); 832346981Scy if ((sta->flags & WLAN_STA_ASSOC) && 833346981Scy ap_sta_bind_vlan(hapd, sta) < 0) 834346981Scy return -1; 835346981Scy#endif /* CONFIG_NO_VLAN */ 836346981Scy 837346981Scy return 0; 838346981Scy} 839346981Scy 840346981Scy 841346981Scy#ifdef CONFIG_OCV 842346981Scystatic int hostapd_get_sta_tx_params(void *ctx, const u8 *addr, 843346981Scy int ap_max_chanwidth, int ap_seg1_idx, 844346981Scy int *bandwidth, int *seg1_idx) 845346981Scy{ 846346981Scy struct hostapd_data *hapd = ctx; 847346981Scy struct sta_info *sta; 848346981Scy 849346981Scy sta = ap_get_sta(hapd, addr); 850346981Scy if (!sta) { 851346981Scy hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO, 852346981Scy "Failed to get STA info to validate received OCI"); 853346981Scy return -1; 854346981Scy } 855346981Scy 856346981Scy return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth, 857346981Scy seg1_idx); 858346981Scy} 859346981Scy#endif /* CONFIG_OCV */ 860346981Scy 861346981Scy 862346981Scy#ifdef CONFIG_IEEE80211R_AP 863346981Scy 864214501Srpaulostatic int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, 865214501Srpaulo const u8 *data, size_t data_len) 866214501Srpaulo{ 867214501Srpaulo struct hostapd_data *hapd = ctx; 868214501Srpaulo int res; 869214501Srpaulo struct ieee80211_mgmt *m; 870214501Srpaulo size_t mlen; 871214501Srpaulo struct sta_info *sta; 872214501Srpaulo 873214501Srpaulo sta = ap_get_sta(hapd, dst); 874214501Srpaulo if (sta == NULL || sta->wpa_sm == NULL) 875214501Srpaulo return -1; 876214501Srpaulo 877214501Srpaulo m = os_zalloc(sizeof(*m) + data_len); 878214501Srpaulo if (m == NULL) 879214501Srpaulo return -1; 880214501Srpaulo mlen = ((u8 *) &m->u - (u8 *) m) + data_len; 881214501Srpaulo m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 882214501Srpaulo WLAN_FC_STYPE_ACTION); 883214501Srpaulo os_memcpy(m->da, dst, ETH_ALEN); 884214501Srpaulo os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); 885214501Srpaulo os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); 886214501Srpaulo os_memcpy(&m->u, data, data_len); 887214501Srpaulo 888252726Srpaulo res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); 889214501Srpaulo os_free(m); 890214501Srpaulo return res; 891214501Srpaulo} 892214501Srpaulo 893214501Srpaulo 894214501Srpaulostatic struct wpa_state_machine * 895214501Srpaulohostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) 896214501Srpaulo{ 897214501Srpaulo struct hostapd_data *hapd = ctx; 898214501Srpaulo struct sta_info *sta; 899214501Srpaulo 900346981Scy wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR 901346981Scy " based on WPA authenticator callback", 902346981Scy MAC2STR(sta_addr)); 903252726Srpaulo if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) 904252726Srpaulo return NULL; 905252726Srpaulo 906214501Srpaulo sta = ap_sta_add(hapd, sta_addr); 907214501Srpaulo if (sta == NULL) 908214501Srpaulo return NULL; 909346981Scy if (hapd->driver && hapd->driver->add_sta_node) 910346981Scy sta->added_unassoc = 1; 911346981Scy sta->ft_over_ds = 1; 912214501Srpaulo if (sta->wpa_sm) { 913214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 914214501Srpaulo return sta->wpa_sm; 915214501Srpaulo } 916214501Srpaulo 917281806Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); 918214501Srpaulo if (sta->wpa_sm == NULL) { 919214501Srpaulo ap_free_sta(hapd, sta); 920214501Srpaulo return NULL; 921214501Srpaulo } 922214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 923214501Srpaulo 924214501Srpaulo return sta->wpa_sm; 925214501Srpaulo} 926214501Srpaulo 927214501Srpaulo 928346981Scystatic int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, 929346981Scy struct vlan_description *vlan) 930346981Scy{ 931346981Scy struct hostapd_data *hapd = ctx; 932346981Scy struct sta_info *sta; 933346981Scy 934346981Scy sta = ap_get_sta(hapd, sta_addr); 935346981Scy if (!sta || !sta->wpa_sm) 936346981Scy return -1; 937346981Scy 938346981Scy if (vlan->notempty && 939346981Scy !hostapd_vlan_valid(hapd->conf->vlan, vlan)) { 940346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 941346981Scy HOSTAPD_LEVEL_INFO, 942346981Scy "Invalid VLAN %d%s received from FT", 943346981Scy vlan->untagged, vlan->tagged[0] ? "+" : ""); 944346981Scy return -1; 945346981Scy } 946346981Scy 947346981Scy if (ap_sta_set_vlan(hapd, sta, vlan) < 0) 948346981Scy return -1; 949346981Scy /* Configure wpa_group for GTK but ignore error due to driver not 950346981Scy * knowing this STA. */ 951346981Scy ap_sta_bind_vlan(hapd, sta); 952346981Scy 953346981Scy if (sta->vlan_id) 954346981Scy hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 955346981Scy HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 956346981Scy 957346981Scy return 0; 958346981Scy} 959346981Scy 960346981Scy 961346981Scystatic int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr, 962346981Scy struct vlan_description *vlan) 963346981Scy{ 964346981Scy struct hostapd_data *hapd = ctx; 965346981Scy struct sta_info *sta; 966346981Scy 967346981Scy sta = ap_get_sta(hapd, sta_addr); 968346981Scy if (!sta) 969346981Scy return -1; 970346981Scy 971346981Scy if (sta->vlan_desc) 972346981Scy *vlan = *sta->vlan_desc; 973346981Scy else 974346981Scy os_memset(vlan, 0, sizeof(*vlan)); 975346981Scy 976346981Scy return 0; 977346981Scy} 978346981Scy 979346981Scy 980346981Scystatic int 981346981Scyhostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr, 982346981Scy const u8 *identity, size_t identity_len) 983346981Scy{ 984346981Scy struct hostapd_data *hapd = ctx; 985346981Scy struct sta_info *sta; 986346981Scy 987346981Scy sta = ap_get_sta(hapd, sta_addr); 988346981Scy if (!sta) 989346981Scy return -1; 990346981Scy 991346981Scy os_free(sta->identity); 992346981Scy sta->identity = NULL; 993346981Scy 994346981Scy if (sta->eapol_sm) { 995346981Scy os_free(sta->eapol_sm->identity); 996346981Scy sta->eapol_sm->identity = NULL; 997346981Scy sta->eapol_sm->identity_len = 0; 998346981Scy } 999346981Scy 1000346981Scy if (!identity_len) 1001346981Scy return 0; 1002346981Scy 1003346981Scy /* sta->identity is NULL terminated */ 1004346981Scy sta->identity = os_zalloc(identity_len + 1); 1005346981Scy if (!sta->identity) 1006346981Scy return -1; 1007346981Scy os_memcpy(sta->identity, identity, identity_len); 1008346981Scy 1009346981Scy if (sta->eapol_sm) { 1010346981Scy sta->eapol_sm->identity = os_zalloc(identity_len); 1011346981Scy if (!sta->eapol_sm->identity) 1012346981Scy return -1; 1013346981Scy os_memcpy(sta->eapol_sm->identity, identity, identity_len); 1014346981Scy sta->eapol_sm->identity_len = identity_len; 1015346981Scy } 1016346981Scy 1017346981Scy return 0; 1018346981Scy} 1019346981Scy 1020346981Scy 1021346981Scystatic size_t 1022346981Scyhostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf) 1023346981Scy{ 1024346981Scy struct hostapd_data *hapd = ctx; 1025346981Scy struct sta_info *sta; 1026346981Scy size_t len; 1027346981Scy char *identity; 1028346981Scy 1029346981Scy sta = ap_get_sta(hapd, sta_addr); 1030346981Scy if (!sta) 1031346981Scy return 0; 1032346981Scy 1033346981Scy *buf = ieee802_1x_get_identity(sta->eapol_sm, &len); 1034346981Scy if (*buf && len) 1035346981Scy return len; 1036346981Scy 1037346981Scy if (!sta->identity) { 1038346981Scy *buf = NULL; 1039346981Scy return 0; 1040346981Scy } 1041346981Scy 1042346981Scy identity = sta->identity; 1043346981Scy len = os_strlen(identity); 1044346981Scy *buf = (u8 *) identity; 1045346981Scy 1046346981Scy return len; 1047346981Scy} 1048346981Scy 1049346981Scy 1050346981Scystatic int 1051346981Scyhostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr, 1052346981Scy const u8 *radius_cui, size_t radius_cui_len) 1053346981Scy{ 1054346981Scy struct hostapd_data *hapd = ctx; 1055346981Scy struct sta_info *sta; 1056346981Scy 1057346981Scy sta = ap_get_sta(hapd, sta_addr); 1058346981Scy if (!sta) 1059346981Scy return -1; 1060346981Scy 1061346981Scy os_free(sta->radius_cui); 1062346981Scy sta->radius_cui = NULL; 1063346981Scy 1064346981Scy if (sta->eapol_sm) { 1065346981Scy wpabuf_free(sta->eapol_sm->radius_cui); 1066346981Scy sta->eapol_sm->radius_cui = NULL; 1067346981Scy } 1068346981Scy 1069346981Scy if (!radius_cui) 1070346981Scy return 0; 1071346981Scy 1072346981Scy /* sta->radius_cui is NULL terminated */ 1073346981Scy sta->radius_cui = os_zalloc(radius_cui_len + 1); 1074346981Scy if (!sta->radius_cui) 1075346981Scy return -1; 1076346981Scy os_memcpy(sta->radius_cui, radius_cui, radius_cui_len); 1077346981Scy 1078346981Scy if (sta->eapol_sm) { 1079346981Scy sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui, 1080346981Scy radius_cui_len); 1081346981Scy if (!sta->eapol_sm->radius_cui) 1082346981Scy return -1; 1083346981Scy } 1084346981Scy 1085346981Scy return 0; 1086346981Scy} 1087346981Scy 1088346981Scy 1089346981Scystatic size_t 1090346981Scyhostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf) 1091346981Scy{ 1092346981Scy struct hostapd_data *hapd = ctx; 1093346981Scy struct sta_info *sta; 1094346981Scy struct wpabuf *b; 1095346981Scy size_t len; 1096346981Scy char *radius_cui; 1097346981Scy 1098346981Scy sta = ap_get_sta(hapd, sta_addr); 1099346981Scy if (!sta) 1100346981Scy return 0; 1101346981Scy 1102346981Scy b = ieee802_1x_get_radius_cui(sta->eapol_sm); 1103346981Scy if (b) { 1104346981Scy len = wpabuf_len(b); 1105346981Scy *buf = wpabuf_head(b); 1106346981Scy return len; 1107346981Scy } 1108346981Scy 1109346981Scy if (!sta->radius_cui) { 1110346981Scy *buf = NULL; 1111346981Scy return 0; 1112346981Scy } 1113346981Scy 1114346981Scy radius_cui = sta->radius_cui; 1115346981Scy len = os_strlen(radius_cui); 1116346981Scy *buf = (u8 *) radius_cui; 1117346981Scy 1118346981Scy return len; 1119346981Scy} 1120346981Scy 1121346981Scy 1122346981Scystatic void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr, 1123346981Scy int session_timeout) 1124346981Scy{ 1125346981Scy struct hostapd_data *hapd = ctx; 1126346981Scy struct sta_info *sta; 1127346981Scy 1128346981Scy sta = ap_get_sta(hapd, sta_addr); 1129346981Scy if (!sta) 1130346981Scy return; 1131346981Scy 1132346981Scy if (session_timeout) { 1133346981Scy os_get_reltime(&sta->session_timeout); 1134346981Scy sta->session_timeout.sec += session_timeout; 1135346981Scy sta->session_timeout_set = 1; 1136346981Scy ap_sta_session_timeout(hapd, sta, session_timeout); 1137346981Scy } else { 1138346981Scy sta->session_timeout_set = 0; 1139346981Scy ap_sta_no_session_timeout(hapd, sta); 1140346981Scy } 1141346981Scy} 1142346981Scy 1143346981Scy 1144346981Scystatic int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr) 1145346981Scy{ 1146346981Scy struct hostapd_data *hapd = ctx; 1147346981Scy struct sta_info *sta; 1148346981Scy struct os_reltime now, remaining; 1149346981Scy 1150346981Scy sta = ap_get_sta(hapd, sta_addr); 1151346981Scy if (!sta || !sta->session_timeout_set) 1152346981Scy return 0; 1153346981Scy 1154346981Scy os_get_reltime(&now); 1155346981Scy if (os_reltime_before(&sta->session_timeout, &now)) { 1156346981Scy /* already expired, return >0 as timeout was set */ 1157346981Scy return 1; 1158346981Scy } 1159346981Scy 1160346981Scy os_reltime_sub(&sta->session_timeout, &now, &remaining); 1161346981Scy 1162346981Scy return (remaining.sec > 0) ? remaining.sec : 1; 1163346981Scy} 1164346981Scy 1165346981Scy 1166214501Srpaulostatic void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, 1167214501Srpaulo size_t len) 1168214501Srpaulo{ 1169214501Srpaulo struct hostapd_data *hapd = ctx; 1170252726Srpaulo struct l2_ethhdr *ethhdr; 1171252726Srpaulo if (len < sizeof(*ethhdr)) 1172252726Srpaulo return; 1173252726Srpaulo ethhdr = (struct l2_ethhdr *) buf; 1174252726Srpaulo wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 1175252726Srpaulo MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest)); 1176337817Scy if (!is_multicast_ether_addr(ethhdr->h_dest) && 1177337817Scy os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0) 1178337817Scy return; 1179252726Srpaulo wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), 1180252726Srpaulo len - sizeof(*ethhdr)); 1181214501Srpaulo} 1182214501Srpaulo 1183252726Srpaulo 1184346981Scystatic void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr, 1185346981Scy const u8 *dst_addr, u8 oui_suffix, 1186346981Scy const u8 *buf, size_t len) 1187346981Scy{ 1188346981Scy struct hostapd_data *hapd = ctx; 1189346981Scy 1190346981Scy wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 1191346981Scy MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr)); 1192346981Scy if (!is_multicast_ether_addr(dst_addr) && 1193346981Scy os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0) 1194346981Scy return; 1195346981Scy wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf, 1196346981Scy len); 1197346981Scy} 1198346981Scy 1199346981Scy 1200252726Srpaulostatic int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr, 1201252726Srpaulo u8 *tspec_ie, size_t tspec_ielen) 1202252726Srpaulo{ 1203252726Srpaulo struct hostapd_data *hapd = ctx; 1204252726Srpaulo return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen); 1205252726Srpaulo} 1206252726Srpaulo 1207214501Srpaulo 1208214501Srpaulo 1209346981Scystatic int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd, 1210346981Scy const char *ft_iface) 1211346981Scy{ 1212346981Scy hapd->oui_pull = eth_p_oui_register(hapd, ft_iface, 1213346981Scy FT_PACKET_R0KH_R1KH_PULL, 1214346981Scy hostapd_rrb_oui_receive, hapd); 1215346981Scy if (!hapd->oui_pull) 1216346981Scy return -1; 1217346981Scy 1218346981Scy hapd->oui_resp = eth_p_oui_register(hapd, ft_iface, 1219346981Scy FT_PACKET_R0KH_R1KH_RESP, 1220346981Scy hostapd_rrb_oui_receive, hapd); 1221346981Scy if (!hapd->oui_resp) 1222346981Scy return -1; 1223346981Scy 1224346981Scy hapd->oui_push = eth_p_oui_register(hapd, ft_iface, 1225346981Scy FT_PACKET_R0KH_R1KH_PUSH, 1226346981Scy hostapd_rrb_oui_receive, hapd); 1227346981Scy if (!hapd->oui_push) 1228346981Scy return -1; 1229346981Scy 1230346981Scy hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface, 1231346981Scy FT_PACKET_R0KH_R1KH_SEQ_REQ, 1232346981Scy hostapd_rrb_oui_receive, hapd); 1233346981Scy if (!hapd->oui_sreq) 1234346981Scy return -1; 1235346981Scy 1236346981Scy hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface, 1237346981Scy FT_PACKET_R0KH_R1KH_SEQ_RESP, 1238346981Scy hostapd_rrb_oui_receive, hapd); 1239346981Scy if (!hapd->oui_sresp) 1240346981Scy return -1; 1241346981Scy 1242346981Scy return 0; 1243346981Scy} 1244346981Scy 1245346981Scy 1246346981Scystatic void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd) 1247346981Scy{ 1248346981Scy eth_p_oui_unregister(hapd->oui_pull); 1249346981Scy hapd->oui_pull = NULL; 1250346981Scy eth_p_oui_unregister(hapd->oui_resp); 1251346981Scy hapd->oui_resp = NULL; 1252346981Scy eth_p_oui_unregister(hapd->oui_push); 1253346981Scy hapd->oui_push = NULL; 1254346981Scy eth_p_oui_unregister(hapd->oui_sreq); 1255346981Scy hapd->oui_sreq = NULL; 1256346981Scy eth_p_oui_unregister(hapd->oui_sresp); 1257346981Scy hapd->oui_sresp = NULL; 1258346981Scy} 1259346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1260346981Scy 1261346981Scy 1262214501Srpauloint hostapd_setup_wpa(struct hostapd_data *hapd) 1263214501Srpaulo{ 1264214501Srpaulo struct wpa_auth_config _conf; 1265346981Scy static const struct wpa_auth_callbacks cb = { 1266346981Scy .logger = hostapd_wpa_auth_logger, 1267346981Scy .disconnect = hostapd_wpa_auth_disconnect, 1268346981Scy .mic_failure_report = hostapd_wpa_auth_mic_failure_report, 1269346981Scy .psk_failure_report = hostapd_wpa_auth_psk_failure_report, 1270346981Scy .set_eapol = hostapd_wpa_auth_set_eapol, 1271346981Scy .get_eapol = hostapd_wpa_auth_get_eapol, 1272346981Scy .get_psk = hostapd_wpa_auth_get_psk, 1273346981Scy .get_msk = hostapd_wpa_auth_get_msk, 1274346981Scy .set_key = hostapd_wpa_auth_set_key, 1275346981Scy .get_seqnum = hostapd_wpa_auth_get_seqnum, 1276346981Scy .send_eapol = hostapd_wpa_auth_send_eapol, 1277346981Scy .for_each_sta = hostapd_wpa_auth_for_each_sta, 1278346981Scy .for_each_auth = hostapd_wpa_auth_for_each_auth, 1279346981Scy .send_ether = hostapd_wpa_auth_send_ether, 1280346981Scy .send_oui = hostapd_wpa_auth_send_oui, 1281346981Scy .channel_info = hostapd_channel_info, 1282346981Scy .update_vlan = hostapd_wpa_auth_update_vlan, 1283346981Scy#ifdef CONFIG_OCV 1284346981Scy .get_sta_tx_params = hostapd_get_sta_tx_params, 1285346981Scy#endif /* CONFIG_OCV */ 1286346981Scy#ifdef CONFIG_IEEE80211R_AP 1287346981Scy .send_ft_action = hostapd_wpa_auth_send_ft_action, 1288346981Scy .add_sta = hostapd_wpa_auth_add_sta, 1289346981Scy .add_tspec = hostapd_wpa_auth_add_tspec, 1290346981Scy .set_vlan = hostapd_wpa_auth_set_vlan, 1291346981Scy .get_vlan = hostapd_wpa_auth_get_vlan, 1292346981Scy .set_identity = hostapd_wpa_auth_set_identity, 1293346981Scy .get_identity = hostapd_wpa_auth_get_identity, 1294346981Scy .set_radius_cui = hostapd_wpa_auth_set_radius_cui, 1295346981Scy .get_radius_cui = hostapd_wpa_auth_get_radius_cui, 1296346981Scy .set_session_timeout = hostapd_wpa_auth_set_session_timeout, 1297346981Scy .get_session_timeout = hostapd_wpa_auth_get_session_timeout, 1298346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1299346981Scy }; 1300214501Srpaulo const u8 *wpa_ie; 1301214501Srpaulo size_t wpa_ie_len; 1302214501Srpaulo 1303281806Srpaulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); 1304252726Srpaulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) 1305252726Srpaulo _conf.tx_status = 1; 1306252726Srpaulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) 1307252726Srpaulo _conf.ap_mlme = 1; 1308346981Scy hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); 1309214501Srpaulo if (hapd->wpa_auth == NULL) { 1310214501Srpaulo wpa_printf(MSG_ERROR, "WPA initialization failed."); 1311214501Srpaulo return -1; 1312214501Srpaulo } 1313214501Srpaulo 1314214501Srpaulo if (hostapd_set_privacy(hapd, 1)) { 1315214501Srpaulo wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " 1316214501Srpaulo "for interface %s", hapd->conf->iface); 1317214501Srpaulo return -1; 1318214501Srpaulo } 1319214501Srpaulo 1320214501Srpaulo wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); 1321214501Srpaulo if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { 1322214501Srpaulo wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " 1323214501Srpaulo "the kernel driver."); 1324214501Srpaulo return -1; 1325214501Srpaulo } 1326214501Srpaulo 1327214501Srpaulo if (rsn_preauth_iface_init(hapd)) { 1328214501Srpaulo wpa_printf(MSG_ERROR, "Initialization of RSN " 1329214501Srpaulo "pre-authentication failed."); 1330214501Srpaulo return -1; 1331214501Srpaulo } 1332214501Srpaulo 1333346981Scy#ifdef CONFIG_IEEE80211R_AP 1334337817Scy if (!hostapd_drv_none(hapd) && 1335289549Srpaulo wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { 1336346981Scy const char *ft_iface; 1337346981Scy 1338346981Scy ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge : 1339346981Scy hapd->conf->iface; 1340346981Scy hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, 1341252726Srpaulo hostapd_rrb_receive, hapd, 1); 1342214501Srpaulo if (hapd->l2 == NULL && 1343214501Srpaulo (hapd->driver == NULL || 1344214501Srpaulo hapd->driver->send_ether == NULL)) { 1345214501Srpaulo wpa_printf(MSG_ERROR, "Failed to open l2_packet " 1346214501Srpaulo "interface"); 1347214501Srpaulo return -1; 1348214501Srpaulo } 1349346981Scy 1350346981Scy if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) { 1351346981Scy wpa_printf(MSG_ERROR, 1352346981Scy "Failed to open ETH_P_OUI interface"); 1353346981Scy return -1; 1354346981Scy } 1355214501Srpaulo } 1356346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1357214501Srpaulo 1358214501Srpaulo return 0; 1359214501Srpaulo 1360214501Srpaulo} 1361214501Srpaulo 1362214501Srpaulo 1363214501Srpaulovoid hostapd_reconfig_wpa(struct hostapd_data *hapd) 1364214501Srpaulo{ 1365214501Srpaulo struct wpa_auth_config wpa_auth_conf; 1366281806Srpaulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf); 1367214501Srpaulo wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); 1368214501Srpaulo} 1369214501Srpaulo 1370214501Srpaulo 1371214501Srpaulovoid hostapd_deinit_wpa(struct hostapd_data *hapd) 1372214501Srpaulo{ 1373252726Srpaulo ieee80211_tkip_countermeasures_deinit(hapd); 1374214501Srpaulo rsn_preauth_iface_deinit(hapd); 1375214501Srpaulo if (hapd->wpa_auth) { 1376214501Srpaulo wpa_deinit(hapd->wpa_auth); 1377214501Srpaulo hapd->wpa_auth = NULL; 1378214501Srpaulo 1379337817Scy if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) { 1380214501Srpaulo wpa_printf(MSG_DEBUG, "Could not disable " 1381214501Srpaulo "PrivacyInvoked for interface %s", 1382214501Srpaulo hapd->conf->iface); 1383214501Srpaulo } 1384214501Srpaulo 1385337817Scy if (hapd->drv_priv && 1386337817Scy hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { 1387214501Srpaulo wpa_printf(MSG_DEBUG, "Could not remove generic " 1388214501Srpaulo "information element from interface %s", 1389214501Srpaulo hapd->conf->iface); 1390214501Srpaulo } 1391214501Srpaulo } 1392214501Srpaulo ieee802_1x_deinit(hapd); 1393214501Srpaulo 1394346981Scy#ifdef CONFIG_IEEE80211R_AP 1395346981Scy eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX); 1396346981Scy hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */ 1397346981Scy eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX); 1398346981Scy hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */ 1399214501Srpaulo l2_packet_deinit(hapd->l2); 1400281806Srpaulo hapd->l2 = NULL; 1401346981Scy hostapd_wpa_unregister_ft_oui(hapd); 1402346981Scy#endif /* CONFIG_IEEE80211R_AP */ 1403214501Srpaulo} 1404