1e28a4053SRui Paulo /* 2e28a4053SRui Paulo * hostapd / WPA authenticator glue code 35b9c547cSRui Paulo * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> 4e28a4053SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7e28a4053SRui Paulo */ 8e28a4053SRui Paulo 9e28a4053SRui Paulo #include "utils/includes.h" 10e28a4053SRui Paulo 11e28a4053SRui Paulo #include "utils/common.h" 1285732ac8SCy Schubert #include "utils/eloop.h" 1385732ac8SCy Schubert #include "utils/list.h" 14e28a4053SRui Paulo #include "common/ieee802_11_defs.h" 155b9c547cSRui Paulo #include "common/sae.h" 16325151a3SRui Paulo #include "common/wpa_ctrl.h" 17780fb4a2SCy Schubert #include "crypto/sha1.h" 18e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm.h" 19e28a4053SRui Paulo #include "eapol_auth/eapol_auth_sm_i.h" 20e28a4053SRui Paulo #include "eap_server/eap.h" 21e28a4053SRui Paulo #include "l2_packet/l2_packet.h" 2285732ac8SCy Schubert #include "eth_p_oui.h" 23e28a4053SRui Paulo #include "hostapd.h" 24e28a4053SRui Paulo #include "ieee802_1x.h" 25e28a4053SRui Paulo #include "preauth_auth.h" 26e28a4053SRui Paulo #include "sta_info.h" 27e28a4053SRui Paulo #include "tkip_countermeasures.h" 28e28a4053SRui Paulo #include "ap_drv_ops.h" 29e28a4053SRui Paulo #include "ap_config.h" 304bc52338SCy Schubert #include "ieee802_11.h" 3185732ac8SCy Schubert #include "pmksa_cache_auth.h" 32e28a4053SRui Paulo #include "wpa_auth.h" 33f05cddf9SRui Paulo #include "wpa_auth_glue.h" 34e28a4053SRui Paulo 35e28a4053SRui Paulo 36e28a4053SRui Paulo static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, 375b9c547cSRui Paulo struct hostapd_config *iconf, 38e28a4053SRui Paulo struct wpa_auth_config *wconf) 39e28a4053SRui Paulo { 40f05cddf9SRui Paulo os_memset(wconf, 0, sizeof(*wconf)); 41e28a4053SRui Paulo wconf->wpa = conf->wpa; 42e28a4053SRui Paulo wconf->wpa_key_mgmt = conf->wpa_key_mgmt; 43e28a4053SRui Paulo wconf->wpa_pairwise = conf->wpa_pairwise; 44e28a4053SRui Paulo wconf->wpa_group = conf->wpa_group; 45e28a4053SRui Paulo wconf->wpa_group_rekey = conf->wpa_group_rekey; 46e28a4053SRui Paulo wconf->wpa_strict_rekey = conf->wpa_strict_rekey; 47e28a4053SRui Paulo wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey; 48e28a4053SRui Paulo wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey; 4985732ac8SCy Schubert wconf->wpa_group_update_count = conf->wpa_group_update_count; 5085732ac8SCy Schubert wconf->wpa_disable_eapol_key_retries = 5185732ac8SCy Schubert conf->wpa_disable_eapol_key_retries; 5285732ac8SCy Schubert wconf->wpa_pairwise_update_count = conf->wpa_pairwise_update_count; 53e28a4053SRui Paulo wconf->rsn_pairwise = conf->rsn_pairwise; 54e28a4053SRui Paulo wconf->rsn_preauth = conf->rsn_preauth; 55e28a4053SRui Paulo wconf->eapol_version = conf->eapol_version; 56*206b73d0SCy Schubert #ifdef CONFIG_MACSEC 57*206b73d0SCy Schubert if (wconf->eapol_version > 2) 58*206b73d0SCy Schubert wconf->eapol_version = 2; 59*206b73d0SCy Schubert #endif /* CONFIG_MACSEC */ 60e28a4053SRui Paulo wconf->wmm_enabled = conf->wmm_enabled; 61e28a4053SRui Paulo wconf->wmm_uapsd = conf->wmm_uapsd; 62f05cddf9SRui Paulo wconf->disable_pmksa_caching = conf->disable_pmksa_caching; 634bc52338SCy Schubert #ifdef CONFIG_OCV 644bc52338SCy Schubert wconf->ocv = conf->ocv; 654bc52338SCy Schubert #endif /* CONFIG_OCV */ 66e28a4053SRui Paulo wconf->okc = conf->okc; 67e28a4053SRui Paulo #ifdef CONFIG_IEEE80211W 68e28a4053SRui Paulo wconf->ieee80211w = conf->ieee80211w; 695b9c547cSRui Paulo wconf->group_mgmt_cipher = conf->group_mgmt_cipher; 7085732ac8SCy Schubert wconf->sae_require_mfp = conf->sae_require_mfp; 71e28a4053SRui Paulo #endif /* CONFIG_IEEE80211W */ 7285732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 73e28a4053SRui Paulo wconf->ssid_len = conf->ssid.ssid_len; 74325151a3SRui Paulo if (wconf->ssid_len > SSID_MAX_LEN) 75325151a3SRui Paulo wconf->ssid_len = SSID_MAX_LEN; 76e28a4053SRui Paulo os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len); 77e28a4053SRui Paulo os_memcpy(wconf->mobility_domain, conf->mobility_domain, 78e28a4053SRui Paulo MOBILITY_DOMAIN_ID_LEN); 79e28a4053SRui Paulo if (conf->nas_identifier && 80e28a4053SRui Paulo os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) { 81e28a4053SRui Paulo wconf->r0_key_holder_len = os_strlen(conf->nas_identifier); 82e28a4053SRui Paulo os_memcpy(wconf->r0_key_holder, conf->nas_identifier, 83e28a4053SRui Paulo wconf->r0_key_holder_len); 84e28a4053SRui Paulo } 85e28a4053SRui Paulo os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN); 86e28a4053SRui Paulo wconf->r0_key_lifetime = conf->r0_key_lifetime; 8785732ac8SCy Schubert wconf->r1_max_key_lifetime = conf->r1_max_key_lifetime; 88e28a4053SRui Paulo wconf->reassociation_deadline = conf->reassociation_deadline; 8985732ac8SCy Schubert wconf->rkh_pos_timeout = conf->rkh_pos_timeout; 9085732ac8SCy Schubert wconf->rkh_neg_timeout = conf->rkh_neg_timeout; 9185732ac8SCy Schubert wconf->rkh_pull_timeout = conf->rkh_pull_timeout; 9285732ac8SCy Schubert wconf->rkh_pull_retries = conf->rkh_pull_retries; 9385732ac8SCy Schubert wconf->r0kh_list = &conf->r0kh_list; 9485732ac8SCy Schubert wconf->r1kh_list = &conf->r1kh_list; 95e28a4053SRui Paulo wconf->pmk_r1_push = conf->pmk_r1_push; 96f05cddf9SRui Paulo wconf->ft_over_ds = conf->ft_over_ds; 9785732ac8SCy Schubert wconf->ft_psk_generate_local = conf->ft_psk_generate_local; 9885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 99f05cddf9SRui Paulo #ifdef CONFIG_HS20 100f05cddf9SRui Paulo wconf->disable_gtk = conf->disable_dgaf; 1015b9c547cSRui Paulo if (conf->osen) { 1025b9c547cSRui Paulo wconf->disable_gtk = 1; 1035b9c547cSRui Paulo wconf->wpa = WPA_PROTO_OSEN; 1045b9c547cSRui Paulo wconf->wpa_key_mgmt = WPA_KEY_MGMT_OSEN; 1055b9c547cSRui Paulo wconf->wpa_pairwise = 0; 1065b9c547cSRui Paulo wconf->wpa_group = WPA_CIPHER_CCMP; 1075b9c547cSRui Paulo wconf->rsn_pairwise = WPA_CIPHER_CCMP; 1085b9c547cSRui Paulo wconf->rsn_preauth = 0; 1095b9c547cSRui Paulo wconf->disable_pmksa_caching = 1; 1105b9c547cSRui Paulo #ifdef CONFIG_IEEE80211W 1115b9c547cSRui Paulo wconf->ieee80211w = 1; 1125b9c547cSRui Paulo #endif /* CONFIG_IEEE80211W */ 1135b9c547cSRui Paulo } 114f05cddf9SRui Paulo #endif /* CONFIG_HS20 */ 1155b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 1165b9c547cSRui Paulo wconf->corrupt_gtk_rekey_mic_probability = 1175b9c547cSRui Paulo iconf->corrupt_gtk_rekey_mic_probability; 118325151a3SRui Paulo if (conf->own_ie_override && 119325151a3SRui Paulo wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) { 120325151a3SRui Paulo wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override); 121325151a3SRui Paulo os_memcpy(wconf->own_ie_override, 122325151a3SRui Paulo wpabuf_head(conf->own_ie_override), 123325151a3SRui Paulo wconf->own_ie_override_len); 124325151a3SRui Paulo } 1255b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 1265b9c547cSRui Paulo #ifdef CONFIG_P2P 1275b9c547cSRui Paulo os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4); 1285b9c547cSRui Paulo os_memcpy(wconf->ip_addr_mask, conf->ip_addr_mask, 4); 1295b9c547cSRui Paulo os_memcpy(wconf->ip_addr_start, conf->ip_addr_start, 4); 1305b9c547cSRui Paulo os_memcpy(wconf->ip_addr_end, conf->ip_addr_end, 4); 1315b9c547cSRui Paulo #endif /* CONFIG_P2P */ 13285732ac8SCy Schubert #ifdef CONFIG_FILS 13385732ac8SCy Schubert wconf->fils_cache_id_set = conf->fils_cache_id_set; 13485732ac8SCy Schubert os_memcpy(wconf->fils_cache_id, conf->fils_cache_id, 13585732ac8SCy Schubert FILS_CACHE_ID_LEN); 13685732ac8SCy Schubert #endif /* CONFIG_FILS */ 137e28a4053SRui Paulo } 138e28a4053SRui Paulo 139e28a4053SRui Paulo 140e28a4053SRui Paulo static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr, 141e28a4053SRui Paulo logger_level level, const char *txt) 142e28a4053SRui Paulo { 143e28a4053SRui Paulo #ifndef CONFIG_NO_HOSTAPD_LOGGER 144e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 145e28a4053SRui Paulo int hlevel; 146e28a4053SRui Paulo 147e28a4053SRui Paulo switch (level) { 148e28a4053SRui Paulo case LOGGER_WARNING: 149e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_WARNING; 150e28a4053SRui Paulo break; 151e28a4053SRui Paulo case LOGGER_INFO: 152e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_INFO; 153e28a4053SRui Paulo break; 154e28a4053SRui Paulo case LOGGER_DEBUG: 155e28a4053SRui Paulo default: 156e28a4053SRui Paulo hlevel = HOSTAPD_LEVEL_DEBUG; 157e28a4053SRui Paulo break; 158e28a4053SRui Paulo } 159e28a4053SRui Paulo 160e28a4053SRui Paulo hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt); 161e28a4053SRui Paulo #endif /* CONFIG_NO_HOSTAPD_LOGGER */ 162e28a4053SRui Paulo } 163e28a4053SRui Paulo 164e28a4053SRui Paulo 165e28a4053SRui Paulo static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr, 166e28a4053SRui Paulo u16 reason) 167e28a4053SRui Paulo { 168e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 169e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: " 170e28a4053SRui Paulo "STA " MACSTR " reason %d", 171e28a4053SRui Paulo __func__, MAC2STR(addr), reason); 172e28a4053SRui Paulo ap_sta_disconnect(hapd, NULL, addr, reason); 173e28a4053SRui Paulo } 174e28a4053SRui Paulo 175e28a4053SRui Paulo 176f05cddf9SRui Paulo static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr) 177e28a4053SRui Paulo { 178e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 179f05cddf9SRui Paulo return michael_mic_failure(hapd, addr, 0); 180e28a4053SRui Paulo } 181e28a4053SRui Paulo 182e28a4053SRui Paulo 183325151a3SRui Paulo static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr) 184325151a3SRui Paulo { 185325151a3SRui Paulo struct hostapd_data *hapd = ctx; 186325151a3SRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR, 187325151a3SRui Paulo MAC2STR(addr)); 188325151a3SRui Paulo } 189325151a3SRui Paulo 190325151a3SRui Paulo 191e28a4053SRui Paulo static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr, 192e28a4053SRui Paulo wpa_eapol_variable var, int value) 193e28a4053SRui Paulo { 194e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 195e28a4053SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 196e28a4053SRui Paulo if (sta == NULL) 197e28a4053SRui Paulo return; 198e28a4053SRui Paulo switch (var) { 199e28a4053SRui Paulo case WPA_EAPOL_portEnabled: 200e28a4053SRui Paulo ieee802_1x_notify_port_enabled(sta->eapol_sm, value); 201e28a4053SRui Paulo break; 202e28a4053SRui Paulo case WPA_EAPOL_portValid: 203e28a4053SRui Paulo ieee802_1x_notify_port_valid(sta->eapol_sm, value); 204e28a4053SRui Paulo break; 205e28a4053SRui Paulo case WPA_EAPOL_authorized: 206e28a4053SRui Paulo ieee802_1x_set_sta_authorized(hapd, sta, value); 207e28a4053SRui Paulo break; 208e28a4053SRui Paulo case WPA_EAPOL_portControl_Auto: 209e28a4053SRui Paulo if (sta->eapol_sm) 210e28a4053SRui Paulo sta->eapol_sm->portControl = Auto; 211e28a4053SRui Paulo break; 212e28a4053SRui Paulo case WPA_EAPOL_keyRun: 213e28a4053SRui Paulo if (sta->eapol_sm) 214e28a4053SRui Paulo sta->eapol_sm->keyRun = value ? TRUE : FALSE; 215e28a4053SRui Paulo break; 216e28a4053SRui Paulo case WPA_EAPOL_keyAvailable: 217e28a4053SRui Paulo if (sta->eapol_sm) 218e28a4053SRui Paulo sta->eapol_sm->eap_if->eapKeyAvailable = 219e28a4053SRui Paulo value ? TRUE : FALSE; 220e28a4053SRui Paulo break; 221e28a4053SRui Paulo case WPA_EAPOL_keyDone: 222e28a4053SRui Paulo if (sta->eapol_sm) 223e28a4053SRui Paulo sta->eapol_sm->keyDone = value ? TRUE : FALSE; 224e28a4053SRui Paulo break; 225e28a4053SRui Paulo case WPA_EAPOL_inc_EapolFramesTx: 226e28a4053SRui Paulo if (sta->eapol_sm) 227e28a4053SRui Paulo sta->eapol_sm->dot1xAuthEapolFramesTx++; 228e28a4053SRui Paulo break; 229e28a4053SRui Paulo } 230e28a4053SRui Paulo } 231e28a4053SRui Paulo 232e28a4053SRui Paulo 233e28a4053SRui Paulo static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr, 234e28a4053SRui Paulo wpa_eapol_variable var) 235e28a4053SRui Paulo { 236e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 237e28a4053SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 238e28a4053SRui Paulo if (sta == NULL || sta->eapol_sm == NULL) 239e28a4053SRui Paulo return -1; 240e28a4053SRui Paulo switch (var) { 241e28a4053SRui Paulo case WPA_EAPOL_keyRun: 242e28a4053SRui Paulo return sta->eapol_sm->keyRun; 243e28a4053SRui Paulo case WPA_EAPOL_keyAvailable: 244e28a4053SRui Paulo return sta->eapol_sm->eap_if->eapKeyAvailable; 245e28a4053SRui Paulo default: 246e28a4053SRui Paulo return -1; 247e28a4053SRui Paulo } 248e28a4053SRui Paulo } 249e28a4053SRui Paulo 250e28a4053SRui Paulo 251e28a4053SRui Paulo static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr, 2525b9c547cSRui Paulo const u8 *p2p_dev_addr, 2534bc52338SCy Schubert const u8 *prev_psk, size_t *psk_len, 2544bc52338SCy Schubert int *vlan_id) 255e28a4053SRui Paulo { 256e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 257f05cddf9SRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 2585b9c547cSRui Paulo const u8 *psk; 2595b9c547cSRui Paulo 2604bc52338SCy Schubert if (vlan_id) 2614bc52338SCy Schubert *vlan_id = 0; 26285732ac8SCy Schubert if (psk_len) 26385732ac8SCy Schubert *psk_len = PMK_LEN; 26485732ac8SCy Schubert 2655b9c547cSRui Paulo #ifdef CONFIG_SAE 2665b9c547cSRui Paulo if (sta && sta->auth_alg == WLAN_AUTH_SAE) { 2675b9c547cSRui Paulo if (!sta->sae || prev_psk) 2685b9c547cSRui Paulo return NULL; 2695b9c547cSRui Paulo return sta->sae->pmk; 2705b9c547cSRui Paulo } 27185732ac8SCy Schubert if (sta && wpa_auth_uses_sae(sta->wpa_sm)) { 27285732ac8SCy Schubert wpa_printf(MSG_DEBUG, 27385732ac8SCy Schubert "No PSK for STA trying to use SAE with PMKSA caching"); 27485732ac8SCy Schubert return NULL; 27585732ac8SCy Schubert } 2765b9c547cSRui Paulo #endif /* CONFIG_SAE */ 2775b9c547cSRui Paulo 27885732ac8SCy Schubert #ifdef CONFIG_OWE 27985732ac8SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && 28085732ac8SCy Schubert sta && sta->owe_pmk) { 28185732ac8SCy Schubert if (psk_len) 28285732ac8SCy Schubert *psk_len = sta->owe_pmk_len; 28385732ac8SCy Schubert return sta->owe_pmk; 28485732ac8SCy Schubert } 28585732ac8SCy Schubert if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) && sta) { 28685732ac8SCy Schubert struct rsn_pmksa_cache_entry *sa; 28785732ac8SCy Schubert 28885732ac8SCy Schubert sa = wpa_auth_sta_get_pmksa(sta->wpa_sm); 28985732ac8SCy Schubert if (sa && sa->akmp == WPA_KEY_MGMT_OWE) { 29085732ac8SCy Schubert if (psk_len) 29185732ac8SCy Schubert *psk_len = sa->pmk_len; 29285732ac8SCy Schubert return sa->pmk; 29385732ac8SCy Schubert } 29485732ac8SCy Schubert } 29585732ac8SCy Schubert #endif /* CONFIG_OWE */ 29685732ac8SCy Schubert 2974bc52338SCy Schubert psk = hostapd_get_psk(hapd->conf, addr, p2p_dev_addr, prev_psk, 2984bc52338SCy Schubert vlan_id); 299f05cddf9SRui Paulo /* 300f05cddf9SRui Paulo * This is about to iterate over all psks, prev_psk gives the last 301f05cddf9SRui Paulo * returned psk which should not be returned again. 302f05cddf9SRui Paulo * logic list (all hostapd_get_psk; all sta->psk) 303f05cddf9SRui Paulo */ 304f05cddf9SRui Paulo if (sta && sta->psk && !psk) { 305f05cddf9SRui Paulo struct hostapd_sta_wpa_psk_short *pos; 3064bc52338SCy Schubert 3074bc52338SCy Schubert if (vlan_id) 3084bc52338SCy Schubert *vlan_id = 0; 309f05cddf9SRui Paulo psk = sta->psk->psk; 310f05cddf9SRui Paulo for (pos = sta->psk; pos; pos = pos->next) { 311780fb4a2SCy Schubert if (pos->is_passphrase) { 312780fb4a2SCy Schubert pbkdf2_sha1(pos->passphrase, 313780fb4a2SCy Schubert hapd->conf->ssid.ssid, 314780fb4a2SCy Schubert hapd->conf->ssid.ssid_len, 4096, 315780fb4a2SCy Schubert pos->psk, PMK_LEN); 316780fb4a2SCy Schubert pos->is_passphrase = 0; 317780fb4a2SCy Schubert } 318f05cddf9SRui Paulo if (pos->psk == prev_psk) { 319f05cddf9SRui Paulo psk = pos->next ? pos->next->psk : NULL; 320f05cddf9SRui Paulo break; 321f05cddf9SRui Paulo } 322f05cddf9SRui Paulo } 323f05cddf9SRui Paulo } 324f05cddf9SRui Paulo return psk; 325e28a4053SRui Paulo } 326e28a4053SRui Paulo 327e28a4053SRui Paulo 328e28a4053SRui Paulo static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, 329e28a4053SRui Paulo size_t *len) 330e28a4053SRui Paulo { 331e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 332e28a4053SRui Paulo const u8 *key; 333e28a4053SRui Paulo size_t keylen; 334e28a4053SRui Paulo struct sta_info *sta; 335e28a4053SRui Paulo 336e28a4053SRui Paulo sta = ap_get_sta(hapd, addr); 3375b9c547cSRui Paulo if (sta == NULL) { 3385b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA"); 339e28a4053SRui Paulo return -1; 3405b9c547cSRui Paulo } 341e28a4053SRui Paulo 342e28a4053SRui Paulo key = ieee802_1x_get_key(sta->eapol_sm, &keylen); 3435b9c547cSRui Paulo if (key == NULL) { 3445b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p", 3455b9c547cSRui Paulo sta->eapol_sm); 346e28a4053SRui Paulo return -1; 3475b9c547cSRui Paulo } 348e28a4053SRui Paulo 349e28a4053SRui Paulo if (keylen > *len) 350e28a4053SRui Paulo keylen = *len; 351e28a4053SRui Paulo os_memcpy(msk, key, keylen); 352e28a4053SRui Paulo *len = keylen; 353e28a4053SRui Paulo 354e28a4053SRui Paulo return 0; 355e28a4053SRui Paulo } 356e28a4053SRui Paulo 357e28a4053SRui Paulo 358e28a4053SRui Paulo static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 359e28a4053SRui Paulo const u8 *addr, int idx, u8 *key, 360e28a4053SRui Paulo size_t key_len) 361e28a4053SRui Paulo { 362e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 363e28a4053SRui Paulo const char *ifname = hapd->conf->iface; 364e28a4053SRui Paulo 365e28a4053SRui Paulo if (vlan_id > 0) { 366e28a4053SRui Paulo ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id); 367e28a4053SRui Paulo if (ifname == NULL) 368e28a4053SRui Paulo return -1; 369e28a4053SRui Paulo } 370e28a4053SRui Paulo 37185732ac8SCy Schubert #ifdef CONFIG_TESTING_OPTIONS 37285732ac8SCy Schubert if (addr && !is_broadcast_ether_addr(addr)) { 37385732ac8SCy Schubert struct sta_info *sta; 37485732ac8SCy Schubert 37585732ac8SCy Schubert sta = ap_get_sta(hapd, addr); 37685732ac8SCy Schubert if (sta) { 37785732ac8SCy Schubert sta->last_tk_alg = alg; 37885732ac8SCy Schubert sta->last_tk_key_idx = idx; 37985732ac8SCy Schubert if (key) 38085732ac8SCy Schubert os_memcpy(sta->last_tk, key, key_len); 38185732ac8SCy Schubert sta->last_tk_len = key_len; 38285732ac8SCy Schubert } 38385732ac8SCy Schubert #ifdef CONFIG_IEEE80211W 38485732ac8SCy Schubert } else if (alg == WPA_ALG_IGTK || 38585732ac8SCy Schubert alg == WPA_ALG_BIP_GMAC_128 || 38685732ac8SCy Schubert alg == WPA_ALG_BIP_GMAC_256 || 38785732ac8SCy Schubert alg == WPA_ALG_BIP_CMAC_256) { 38885732ac8SCy Schubert hapd->last_igtk_alg = alg; 38985732ac8SCy Schubert hapd->last_igtk_key_idx = idx; 39085732ac8SCy Schubert if (key) 39185732ac8SCy Schubert os_memcpy(hapd->last_igtk, key, key_len); 39285732ac8SCy Schubert hapd->last_igtk_len = key_len; 39385732ac8SCy Schubert #endif /* CONFIG_IEEE80211W */ 39485732ac8SCy Schubert } else { 39585732ac8SCy Schubert hapd->last_gtk_alg = alg; 39685732ac8SCy Schubert hapd->last_gtk_key_idx = idx; 39785732ac8SCy Schubert if (key) 39885732ac8SCy Schubert os_memcpy(hapd->last_gtk, key, key_len); 39985732ac8SCy Schubert hapd->last_gtk_len = key_len; 40085732ac8SCy Schubert } 40185732ac8SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */ 402f05cddf9SRui Paulo return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0, 403e28a4053SRui Paulo key, key_len); 404e28a4053SRui Paulo } 405e28a4053SRui Paulo 406e28a4053SRui Paulo 407e28a4053SRui Paulo static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx, 408e28a4053SRui Paulo u8 *seq) 409e28a4053SRui Paulo { 410e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 411e28a4053SRui Paulo return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq); 412e28a4053SRui Paulo } 413e28a4053SRui Paulo 414e28a4053SRui Paulo 415e28a4053SRui Paulo static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr, 416e28a4053SRui Paulo const u8 *data, size_t data_len, 417e28a4053SRui Paulo int encrypt) 418e28a4053SRui Paulo { 419e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 420f05cddf9SRui Paulo struct sta_info *sta; 421f05cddf9SRui Paulo u32 flags = 0; 422f05cddf9SRui Paulo 4235b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 4245b9c547cSRui Paulo if (hapd->ext_eapol_frame_io) { 4255b9c547cSRui Paulo size_t hex_len = 2 * data_len + 1; 4265b9c547cSRui Paulo char *hex = os_malloc(hex_len); 4275b9c547cSRui Paulo 4285b9c547cSRui Paulo if (hex == NULL) 4295b9c547cSRui Paulo return -1; 4305b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, data, data_len); 4315b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 4325b9c547cSRui Paulo MAC2STR(addr), hex); 4335b9c547cSRui Paulo os_free(hex); 4345b9c547cSRui Paulo return 0; 4355b9c547cSRui Paulo } 4365b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 4375b9c547cSRui Paulo 438f05cddf9SRui Paulo sta = ap_get_sta(hapd, addr); 439f05cddf9SRui Paulo if (sta) 440f05cddf9SRui Paulo flags = hostapd_sta_flags_to_drv(sta->flags); 441f05cddf9SRui Paulo 442f05cddf9SRui Paulo return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len, 443f05cddf9SRui Paulo encrypt, flags); 444e28a4053SRui Paulo } 445e28a4053SRui Paulo 446e28a4053SRui Paulo 447e28a4053SRui Paulo static int hostapd_wpa_auth_for_each_sta( 448e28a4053SRui Paulo void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx), 449e28a4053SRui Paulo void *cb_ctx) 450e28a4053SRui Paulo { 451e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 452e28a4053SRui Paulo struct sta_info *sta; 453e28a4053SRui Paulo 454e28a4053SRui Paulo for (sta = hapd->sta_list; sta; sta = sta->next) { 455e28a4053SRui Paulo if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx)) 456e28a4053SRui Paulo return 1; 457e28a4053SRui Paulo } 458e28a4053SRui Paulo return 0; 459e28a4053SRui Paulo } 460e28a4053SRui Paulo 461e28a4053SRui Paulo 462e28a4053SRui Paulo struct wpa_auth_iface_iter_data { 463e28a4053SRui Paulo int (*cb)(struct wpa_authenticator *sm, void *ctx); 464e28a4053SRui Paulo void *cb_ctx; 465e28a4053SRui Paulo }; 466e28a4053SRui Paulo 467e28a4053SRui Paulo static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx) 468e28a4053SRui Paulo { 469e28a4053SRui Paulo struct wpa_auth_iface_iter_data *data = ctx; 470e28a4053SRui Paulo size_t i; 471e28a4053SRui Paulo for (i = 0; i < iface->num_bss; i++) { 472e28a4053SRui Paulo if (iface->bss[i]->wpa_auth && 473e28a4053SRui Paulo data->cb(iface->bss[i]->wpa_auth, data->cb_ctx)) 474e28a4053SRui Paulo return 1; 475e28a4053SRui Paulo } 476e28a4053SRui Paulo return 0; 477e28a4053SRui Paulo } 478e28a4053SRui Paulo 479e28a4053SRui Paulo 480e28a4053SRui Paulo static int hostapd_wpa_auth_for_each_auth( 481e28a4053SRui Paulo void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx), 482e28a4053SRui Paulo void *cb_ctx) 483e28a4053SRui Paulo { 484e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 485e28a4053SRui Paulo struct wpa_auth_iface_iter_data data; 486f05cddf9SRui Paulo if (hapd->iface->interfaces == NULL || 487f05cddf9SRui Paulo hapd->iface->interfaces->for_each_interface == NULL) 488e28a4053SRui Paulo return -1; 489e28a4053SRui Paulo data.cb = cb; 490e28a4053SRui Paulo data.cb_ctx = cb_ctx; 491f05cddf9SRui Paulo return hapd->iface->interfaces->for_each_interface( 492f05cddf9SRui Paulo hapd->iface->interfaces, wpa_auth_iface_iter, &data); 493e28a4053SRui Paulo } 494e28a4053SRui Paulo 495e28a4053SRui Paulo 49685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 49785732ac8SCy Schubert 49885732ac8SCy Schubert struct wpa_ft_rrb_rx_later_data { 49985732ac8SCy Schubert struct dl_list list; 50085732ac8SCy Schubert u8 addr[ETH_ALEN]; 50185732ac8SCy Schubert size_t data_len; 50285732ac8SCy Schubert /* followed by data_len octets of data */ 50385732ac8SCy Schubert }; 50485732ac8SCy Schubert 50585732ac8SCy Schubert static void hostapd_wpa_ft_rrb_rx_later(void *eloop_ctx, void *timeout_ctx) 50685732ac8SCy Schubert { 50785732ac8SCy Schubert struct hostapd_data *hapd = eloop_ctx; 50885732ac8SCy Schubert struct wpa_ft_rrb_rx_later_data *data, *n; 50985732ac8SCy Schubert 51085732ac8SCy Schubert dl_list_for_each_safe(data, n, &hapd->l2_queue, 51185732ac8SCy Schubert struct wpa_ft_rrb_rx_later_data, list) { 51285732ac8SCy Schubert if (hapd->wpa_auth) { 51385732ac8SCy Schubert wpa_ft_rrb_rx(hapd->wpa_auth, data->addr, 51485732ac8SCy Schubert (const u8 *) (data + 1), 51585732ac8SCy Schubert data->data_len); 51685732ac8SCy Schubert } 51785732ac8SCy Schubert dl_list_del(&data->list); 51885732ac8SCy Schubert os_free(data); 51985732ac8SCy Schubert } 52085732ac8SCy Schubert } 52185732ac8SCy Schubert 522e28a4053SRui Paulo 523e28a4053SRui Paulo struct wpa_auth_ft_iface_iter_data { 524e28a4053SRui Paulo struct hostapd_data *src_hapd; 525e28a4053SRui Paulo const u8 *dst; 526e28a4053SRui Paulo const u8 *data; 527e28a4053SRui Paulo size_t data_len; 528e28a4053SRui Paulo }; 529e28a4053SRui Paulo 530e28a4053SRui Paulo 531e28a4053SRui Paulo static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx) 532e28a4053SRui Paulo { 533e28a4053SRui Paulo struct wpa_auth_ft_iface_iter_data *idata = ctx; 53485732ac8SCy Schubert struct wpa_ft_rrb_rx_later_data *data; 535e28a4053SRui Paulo struct hostapd_data *hapd; 536e28a4053SRui Paulo size_t j; 537e28a4053SRui Paulo 538e28a4053SRui Paulo for (j = 0; j < iface->num_bss; j++) { 539e28a4053SRui Paulo hapd = iface->bss[j]; 54085732ac8SCy Schubert if (hapd == idata->src_hapd || 54185732ac8SCy Schubert !hapd->wpa_auth || 54285732ac8SCy Schubert os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) != 0) 543e28a4053SRui Paulo continue; 54485732ac8SCy Schubert 54585732ac8SCy Schubert wpa_printf(MSG_DEBUG, 54685732ac8SCy Schubert "FT: Send RRB data directly to locally managed BSS " 54785732ac8SCy Schubert MACSTR "@%s -> " MACSTR "@%s", 548e28a4053SRui Paulo MAC2STR(idata->src_hapd->own_addr), 549e28a4053SRui Paulo idata->src_hapd->conf->iface, 550e28a4053SRui Paulo MAC2STR(hapd->own_addr), hapd->conf->iface); 55185732ac8SCy Schubert 55285732ac8SCy Schubert /* Defer wpa_ft_rrb_rx() until next eloop step as this is 55385732ac8SCy Schubert * when it would be triggered when reading from a socket. 55485732ac8SCy Schubert * This avoids 55585732ac8SCy Schubert * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 55685732ac8SCy Schubert * that is calling hapd0:recv handler from within 55785732ac8SCy Schubert * hapd0:send directly. 55885732ac8SCy Schubert */ 55985732ac8SCy Schubert data = os_zalloc(sizeof(*data) + idata->data_len); 56085732ac8SCy Schubert if (!data) 561e28a4053SRui Paulo return 1; 56285732ac8SCy Schubert 56385732ac8SCy Schubert os_memcpy(data->addr, idata->src_hapd->own_addr, ETH_ALEN); 56485732ac8SCy Schubert os_memcpy(data + 1, idata->data, idata->data_len); 56585732ac8SCy Schubert data->data_len = idata->data_len; 56685732ac8SCy Schubert 56785732ac8SCy Schubert dl_list_add(&hapd->l2_queue, &data->list); 56885732ac8SCy Schubert 56985732ac8SCy Schubert if (!eloop_is_timeout_registered(hostapd_wpa_ft_rrb_rx_later, 57085732ac8SCy Schubert hapd, NULL)) 57185732ac8SCy Schubert eloop_register_timeout(0, 0, 57285732ac8SCy Schubert hostapd_wpa_ft_rrb_rx_later, 57385732ac8SCy Schubert hapd, NULL); 57485732ac8SCy Schubert 57585732ac8SCy Schubert return 1; 576e28a4053SRui Paulo } 577e28a4053SRui Paulo 578e28a4053SRui Paulo return 0; 579e28a4053SRui Paulo } 580e28a4053SRui Paulo 58185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 582e28a4053SRui Paulo 583e28a4053SRui Paulo 584e28a4053SRui Paulo static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto, 585e28a4053SRui Paulo const u8 *data, size_t data_len) 586e28a4053SRui Paulo { 587e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 588f05cddf9SRui Paulo struct l2_ethhdr *buf; 589f05cddf9SRui Paulo int ret; 590e28a4053SRui Paulo 5915b9c547cSRui Paulo #ifdef CONFIG_TESTING_OPTIONS 5925b9c547cSRui Paulo if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) { 5935b9c547cSRui Paulo size_t hex_len = 2 * data_len + 1; 5945b9c547cSRui Paulo char *hex = os_malloc(hex_len); 5955b9c547cSRui Paulo 5965b9c547cSRui Paulo if (hex == NULL) 5975b9c547cSRui Paulo return -1; 5985b9c547cSRui Paulo wpa_snprintf_hex(hex, hex_len, data, data_len); 5995b9c547cSRui Paulo wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s", 6005b9c547cSRui Paulo MAC2STR(dst), hex); 6015b9c547cSRui Paulo os_free(hex); 6025b9c547cSRui Paulo return 0; 6035b9c547cSRui Paulo } 6045b9c547cSRui Paulo #endif /* CONFIG_TESTING_OPTIONS */ 6055b9c547cSRui Paulo 60685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 607f05cddf9SRui Paulo if (proto == ETH_P_RRB && hapd->iface->interfaces && 608f05cddf9SRui Paulo hapd->iface->interfaces->for_each_interface) { 609e28a4053SRui Paulo int res; 610e28a4053SRui Paulo struct wpa_auth_ft_iface_iter_data idata; 611e28a4053SRui Paulo idata.src_hapd = hapd; 612e28a4053SRui Paulo idata.dst = dst; 613e28a4053SRui Paulo idata.data = data; 614e28a4053SRui Paulo idata.data_len = data_len; 615f05cddf9SRui Paulo res = hapd->iface->interfaces->for_each_interface( 616f05cddf9SRui Paulo hapd->iface->interfaces, hostapd_wpa_auth_ft_iter, 617e28a4053SRui Paulo &idata); 618e28a4053SRui Paulo if (res == 1) 619e28a4053SRui Paulo return data_len; 620e28a4053SRui Paulo } 62185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 622e28a4053SRui Paulo 623e28a4053SRui Paulo if (hapd->driver && hapd->driver->send_ether) 624e28a4053SRui Paulo return hapd->driver->send_ether(hapd->drv_priv, dst, 625e28a4053SRui Paulo hapd->own_addr, proto, 626e28a4053SRui Paulo data, data_len); 627e28a4053SRui Paulo if (hapd->l2 == NULL) 628e28a4053SRui Paulo return -1; 629f05cddf9SRui Paulo 630f05cddf9SRui Paulo buf = os_malloc(sizeof(*buf) + data_len); 631f05cddf9SRui Paulo if (buf == NULL) 632f05cddf9SRui Paulo return -1; 633f05cddf9SRui Paulo os_memcpy(buf->h_dest, dst, ETH_ALEN); 634f05cddf9SRui Paulo os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN); 635f05cddf9SRui Paulo buf->h_proto = host_to_be16(proto); 636f05cddf9SRui Paulo os_memcpy(buf + 1, data, data_len); 637f05cddf9SRui Paulo ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf, 638f05cddf9SRui Paulo sizeof(*buf) + data_len); 639f05cddf9SRui Paulo os_free(buf); 640f05cddf9SRui Paulo return ret; 641e28a4053SRui Paulo } 642e28a4053SRui Paulo 643e28a4053SRui Paulo 64485732ac8SCy Schubert #ifdef CONFIG_ETH_P_OUI 64585732ac8SCy Schubert static struct eth_p_oui_ctx * hostapd_wpa_get_oui(struct hostapd_data *hapd, 64685732ac8SCy Schubert u8 oui_suffix) 64785732ac8SCy Schubert { 64885732ac8SCy Schubert switch (oui_suffix) { 64985732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 65085732ac8SCy Schubert case FT_PACKET_R0KH_R1KH_PULL: 65185732ac8SCy Schubert return hapd->oui_pull; 65285732ac8SCy Schubert case FT_PACKET_R0KH_R1KH_RESP: 65385732ac8SCy Schubert return hapd->oui_resp; 65485732ac8SCy Schubert case FT_PACKET_R0KH_R1KH_PUSH: 65585732ac8SCy Schubert return hapd->oui_push; 65685732ac8SCy Schubert case FT_PACKET_R0KH_R1KH_SEQ_REQ: 65785732ac8SCy Schubert return hapd->oui_sreq; 65885732ac8SCy Schubert case FT_PACKET_R0KH_R1KH_SEQ_RESP: 65985732ac8SCy Schubert return hapd->oui_sresp; 66085732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 66185732ac8SCy Schubert default: 66285732ac8SCy Schubert return NULL; 66385732ac8SCy Schubert } 66485732ac8SCy Schubert } 66585732ac8SCy Schubert #endif /* CONFIG_ETH_P_OUI */ 66685732ac8SCy Schubert 66785732ac8SCy Schubert 66885732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 66985732ac8SCy Schubert 67085732ac8SCy Schubert struct oui_deliver_later_data { 67185732ac8SCy Schubert struct dl_list list; 67285732ac8SCy Schubert u8 src_addr[ETH_ALEN]; 67385732ac8SCy Schubert u8 dst_addr[ETH_ALEN]; 67485732ac8SCy Schubert size_t data_len; 67585732ac8SCy Schubert u8 oui_suffix; 67685732ac8SCy Schubert /* followed by data_len octets of data */ 67785732ac8SCy Schubert }; 67885732ac8SCy Schubert 67985732ac8SCy Schubert static void hostapd_oui_deliver_later(void *eloop_ctx, void *timeout_ctx) 68085732ac8SCy Schubert { 68185732ac8SCy Schubert struct hostapd_data *hapd = eloop_ctx; 68285732ac8SCy Schubert struct oui_deliver_later_data *data, *n; 68385732ac8SCy Schubert struct eth_p_oui_ctx *oui_ctx; 68485732ac8SCy Schubert 68585732ac8SCy Schubert dl_list_for_each_safe(data, n, &hapd->l2_oui_queue, 68685732ac8SCy Schubert struct oui_deliver_later_data, list) { 68785732ac8SCy Schubert oui_ctx = hostapd_wpa_get_oui(hapd, data->oui_suffix); 68885732ac8SCy Schubert if (hapd->wpa_auth && oui_ctx) { 68985732ac8SCy Schubert eth_p_oui_deliver(oui_ctx, data->src_addr, 69085732ac8SCy Schubert data->dst_addr, 69185732ac8SCy Schubert (const u8 *) (data + 1), 69285732ac8SCy Schubert data->data_len); 69385732ac8SCy Schubert } 69485732ac8SCy Schubert dl_list_del(&data->list); 69585732ac8SCy Schubert os_free(data); 69685732ac8SCy Schubert } 69785732ac8SCy Schubert } 69885732ac8SCy Schubert 69985732ac8SCy Schubert 70085732ac8SCy Schubert struct wpa_auth_oui_iface_iter_data { 70185732ac8SCy Schubert struct hostapd_data *src_hapd; 70285732ac8SCy Schubert const u8 *dst_addr; 70385732ac8SCy Schubert const u8 *data; 70485732ac8SCy Schubert size_t data_len; 70585732ac8SCy Schubert u8 oui_suffix; 70685732ac8SCy Schubert }; 70785732ac8SCy Schubert 70885732ac8SCy Schubert static int hostapd_wpa_auth_oui_iter(struct hostapd_iface *iface, void *ctx) 70985732ac8SCy Schubert { 71085732ac8SCy Schubert struct wpa_auth_oui_iface_iter_data *idata = ctx; 71185732ac8SCy Schubert struct oui_deliver_later_data *data; 71285732ac8SCy Schubert struct hostapd_data *hapd; 71385732ac8SCy Schubert size_t j; 71485732ac8SCy Schubert 71585732ac8SCy Schubert for (j = 0; j < iface->num_bss; j++) { 71685732ac8SCy Schubert hapd = iface->bss[j]; 71785732ac8SCy Schubert if (hapd == idata->src_hapd) 71885732ac8SCy Schubert continue; 71985732ac8SCy Schubert if (!is_multicast_ether_addr(idata->dst_addr) && 72085732ac8SCy Schubert os_memcmp(hapd->own_addr, idata->dst_addr, ETH_ALEN) != 0) 72185732ac8SCy Schubert continue; 72285732ac8SCy Schubert 72385732ac8SCy Schubert /* defer eth_p_oui_deliver until next eloop step as this is 72485732ac8SCy Schubert * when it would be triggerd from reading from sock 72585732ac8SCy Schubert * This avoids 72685732ac8SCy Schubert * hapd0:send -> hapd1:recv -> hapd1:send -> hapd0:recv, 72785732ac8SCy Schubert * that is calling hapd0:recv handler from within 72885732ac8SCy Schubert * hapd0:send directly. 72985732ac8SCy Schubert */ 73085732ac8SCy Schubert data = os_zalloc(sizeof(*data) + idata->data_len); 73185732ac8SCy Schubert if (!data) 73285732ac8SCy Schubert return 1; 73385732ac8SCy Schubert 73485732ac8SCy Schubert os_memcpy(data->src_addr, idata->src_hapd->own_addr, ETH_ALEN); 73585732ac8SCy Schubert os_memcpy(data->dst_addr, idata->dst_addr, ETH_ALEN); 73685732ac8SCy Schubert os_memcpy(data + 1, idata->data, idata->data_len); 73785732ac8SCy Schubert data->data_len = idata->data_len; 73885732ac8SCy Schubert data->oui_suffix = idata->oui_suffix; 73985732ac8SCy Schubert 74085732ac8SCy Schubert dl_list_add(&hapd->l2_oui_queue, &data->list); 74185732ac8SCy Schubert 74285732ac8SCy Schubert if (!eloop_is_timeout_registered(hostapd_oui_deliver_later, 74385732ac8SCy Schubert hapd, NULL)) 74485732ac8SCy Schubert eloop_register_timeout(0, 0, 74585732ac8SCy Schubert hostapd_oui_deliver_later, 74685732ac8SCy Schubert hapd, NULL); 74785732ac8SCy Schubert 74885732ac8SCy Schubert return 1; 74985732ac8SCy Schubert } 75085732ac8SCy Schubert 75185732ac8SCy Schubert return 0; 75285732ac8SCy Schubert } 75385732ac8SCy Schubert 75485732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 75585732ac8SCy Schubert 75685732ac8SCy Schubert 75785732ac8SCy Schubert static int hostapd_wpa_auth_send_oui(void *ctx, const u8 *dst, u8 oui_suffix, 75885732ac8SCy Schubert const u8 *data, size_t data_len) 75985732ac8SCy Schubert { 76085732ac8SCy Schubert #ifdef CONFIG_ETH_P_OUI 76185732ac8SCy Schubert struct hostapd_data *hapd = ctx; 76285732ac8SCy Schubert struct eth_p_oui_ctx *oui_ctx; 76385732ac8SCy Schubert 76485732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 76585732ac8SCy Schubert if (hapd->iface->interfaces && 76685732ac8SCy Schubert hapd->iface->interfaces->for_each_interface) { 76785732ac8SCy Schubert struct wpa_auth_oui_iface_iter_data idata; 76885732ac8SCy Schubert int res; 76985732ac8SCy Schubert 77085732ac8SCy Schubert idata.src_hapd = hapd; 77185732ac8SCy Schubert idata.dst_addr = dst; 77285732ac8SCy Schubert idata.data = data; 77385732ac8SCy Schubert idata.data_len = data_len; 77485732ac8SCy Schubert idata.oui_suffix = oui_suffix; 77585732ac8SCy Schubert res = hapd->iface->interfaces->for_each_interface( 77685732ac8SCy Schubert hapd->iface->interfaces, hostapd_wpa_auth_oui_iter, 77785732ac8SCy Schubert &idata); 77885732ac8SCy Schubert if (res == 1) 77985732ac8SCy Schubert return data_len; 78085732ac8SCy Schubert } 78185732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 78285732ac8SCy Schubert 78385732ac8SCy Schubert oui_ctx = hostapd_wpa_get_oui(hapd, oui_suffix); 78485732ac8SCy Schubert if (!oui_ctx) 78585732ac8SCy Schubert return -1; 78685732ac8SCy Schubert 78785732ac8SCy Schubert return eth_p_oui_send(oui_ctx, hapd->own_addr, dst, data, data_len); 78885732ac8SCy Schubert #else /* CONFIG_ETH_P_OUI */ 78985732ac8SCy Schubert return -1; 79085732ac8SCy Schubert #endif /* CONFIG_ETH_P_OUI */ 79185732ac8SCy Schubert } 79285732ac8SCy Schubert 79385732ac8SCy Schubert 7944bc52338SCy Schubert static int hostapd_channel_info(void *ctx, struct wpa_channel_info *ci) 7954bc52338SCy Schubert { 7964bc52338SCy Schubert struct hostapd_data *hapd = ctx; 7974bc52338SCy Schubert 7984bc52338SCy Schubert return hostapd_drv_channel_info(hapd, ci); 7994bc52338SCy Schubert } 8004bc52338SCy Schubert 8014bc52338SCy Schubert 8024bc52338SCy Schubert static int hostapd_wpa_auth_update_vlan(void *ctx, const u8 *addr, int vlan_id) 8034bc52338SCy Schubert { 8044bc52338SCy Schubert #ifndef CONFIG_NO_VLAN 8054bc52338SCy Schubert struct hostapd_data *hapd = ctx; 8064bc52338SCy Schubert struct sta_info *sta; 8074bc52338SCy Schubert struct vlan_description vlan_desc; 8084bc52338SCy Schubert 8094bc52338SCy Schubert sta = ap_get_sta(hapd, addr); 8104bc52338SCy Schubert if (!sta) 8114bc52338SCy Schubert return -1; 8124bc52338SCy Schubert 8134bc52338SCy Schubert os_memset(&vlan_desc, 0, sizeof(vlan_desc)); 8144bc52338SCy Schubert vlan_desc.notempty = 1; 8154bc52338SCy Schubert vlan_desc.untagged = vlan_id; 8164bc52338SCy Schubert if (!hostapd_vlan_valid(hapd->conf->vlan, &vlan_desc)) { 8174bc52338SCy Schubert wpa_printf(MSG_INFO, "Invalid VLAN ID %d in wpa_psk_file", 8184bc52338SCy Schubert vlan_id); 8194bc52338SCy Schubert return -1; 8204bc52338SCy Schubert } 8214bc52338SCy Schubert 8224bc52338SCy Schubert if (ap_sta_set_vlan(hapd, sta, &vlan_desc) < 0) { 8234bc52338SCy Schubert wpa_printf(MSG_INFO, 8244bc52338SCy Schubert "Failed to assign VLAN ID %d from wpa_psk_file to " 8254bc52338SCy Schubert MACSTR, vlan_id, MAC2STR(sta->addr)); 8264bc52338SCy Schubert return -1; 8274bc52338SCy Schubert } 8284bc52338SCy Schubert 8294bc52338SCy Schubert wpa_printf(MSG_INFO, 8304bc52338SCy Schubert "Assigned VLAN ID %d from wpa_psk_file to " MACSTR, 8314bc52338SCy Schubert vlan_id, MAC2STR(sta->addr)); 8324bc52338SCy Schubert if ((sta->flags & WLAN_STA_ASSOC) && 8334bc52338SCy Schubert ap_sta_bind_vlan(hapd, sta) < 0) 8344bc52338SCy Schubert return -1; 8354bc52338SCy Schubert #endif /* CONFIG_NO_VLAN */ 8364bc52338SCy Schubert 8374bc52338SCy Schubert return 0; 8384bc52338SCy Schubert } 8394bc52338SCy Schubert 8404bc52338SCy Schubert 8414bc52338SCy Schubert #ifdef CONFIG_OCV 8424bc52338SCy Schubert static int hostapd_get_sta_tx_params(void *ctx, const u8 *addr, 8434bc52338SCy Schubert int ap_max_chanwidth, int ap_seg1_idx, 8444bc52338SCy Schubert int *bandwidth, int *seg1_idx) 8454bc52338SCy Schubert { 8464bc52338SCy Schubert struct hostapd_data *hapd = ctx; 8474bc52338SCy Schubert struct sta_info *sta; 8484bc52338SCy Schubert 8494bc52338SCy Schubert sta = ap_get_sta(hapd, addr); 8504bc52338SCy Schubert if (!sta) { 8514bc52338SCy Schubert hostapd_wpa_auth_logger(hapd, addr, LOGGER_INFO, 8524bc52338SCy Schubert "Failed to get STA info to validate received OCI"); 8534bc52338SCy Schubert return -1; 8544bc52338SCy Schubert } 8554bc52338SCy Schubert 8564bc52338SCy Schubert return get_tx_parameters(sta, ap_max_chanwidth, ap_seg1_idx, bandwidth, 8574bc52338SCy Schubert seg1_idx); 8584bc52338SCy Schubert } 8594bc52338SCy Schubert #endif /* CONFIG_OCV */ 8604bc52338SCy Schubert 8614bc52338SCy Schubert 86285732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 863e28a4053SRui Paulo 864e28a4053SRui Paulo static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, 865e28a4053SRui Paulo const u8 *data, size_t data_len) 866e28a4053SRui Paulo { 867e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 868e28a4053SRui Paulo int res; 869e28a4053SRui Paulo struct ieee80211_mgmt *m; 870e28a4053SRui Paulo size_t mlen; 871e28a4053SRui Paulo struct sta_info *sta; 872e28a4053SRui Paulo 873e28a4053SRui Paulo sta = ap_get_sta(hapd, dst); 874e28a4053SRui Paulo if (sta == NULL || sta->wpa_sm == NULL) 875e28a4053SRui Paulo return -1; 876e28a4053SRui Paulo 877e28a4053SRui Paulo m = os_zalloc(sizeof(*m) + data_len); 878e28a4053SRui Paulo if (m == NULL) 879e28a4053SRui Paulo return -1; 880e28a4053SRui Paulo mlen = ((u8 *) &m->u - (u8 *) m) + data_len; 881e28a4053SRui Paulo m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 882e28a4053SRui Paulo WLAN_FC_STYPE_ACTION); 883e28a4053SRui Paulo os_memcpy(m->da, dst, ETH_ALEN); 884e28a4053SRui Paulo os_memcpy(m->sa, hapd->own_addr, ETH_ALEN); 885e28a4053SRui Paulo os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN); 886e28a4053SRui Paulo os_memcpy(&m->u, data, data_len); 887e28a4053SRui Paulo 888f05cddf9SRui Paulo res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0); 889e28a4053SRui Paulo os_free(m); 890e28a4053SRui Paulo return res; 891e28a4053SRui Paulo } 892e28a4053SRui Paulo 893e28a4053SRui Paulo 894e28a4053SRui Paulo static struct wpa_state_machine * 895e28a4053SRui Paulo hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) 896e28a4053SRui Paulo { 897e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 898e28a4053SRui Paulo struct sta_info *sta; 899e28a4053SRui Paulo 9004bc52338SCy Schubert wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR 9014bc52338SCy Schubert " based on WPA authenticator callback", 9024bc52338SCy Schubert MAC2STR(sta_addr)); 903f05cddf9SRui Paulo if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) 904f05cddf9SRui Paulo return NULL; 905f05cddf9SRui Paulo 906e28a4053SRui Paulo sta = ap_sta_add(hapd, sta_addr); 907e28a4053SRui Paulo if (sta == NULL) 908e28a4053SRui Paulo return NULL; 9094bc52338SCy Schubert if (hapd->driver && hapd->driver->add_sta_node) 9104bc52338SCy Schubert sta->added_unassoc = 1; 9114bc52338SCy Schubert sta->ft_over_ds = 1; 912e28a4053SRui Paulo if (sta->wpa_sm) { 913e28a4053SRui Paulo sta->auth_alg = WLAN_AUTH_FT; 914e28a4053SRui Paulo return sta->wpa_sm; 915e28a4053SRui Paulo } 916e28a4053SRui Paulo 9175b9c547cSRui Paulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr, NULL); 918e28a4053SRui Paulo if (sta->wpa_sm == NULL) { 919e28a4053SRui Paulo ap_free_sta(hapd, sta); 920e28a4053SRui Paulo return NULL; 921e28a4053SRui Paulo } 922e28a4053SRui Paulo sta->auth_alg = WLAN_AUTH_FT; 923e28a4053SRui Paulo 924e28a4053SRui Paulo return sta->wpa_sm; 925e28a4053SRui Paulo } 926e28a4053SRui Paulo 927e28a4053SRui Paulo 92885732ac8SCy Schubert static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, 92985732ac8SCy Schubert struct vlan_description *vlan) 93085732ac8SCy Schubert { 93185732ac8SCy Schubert struct hostapd_data *hapd = ctx; 93285732ac8SCy Schubert struct sta_info *sta; 93385732ac8SCy Schubert 93485732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 93585732ac8SCy Schubert if (!sta || !sta->wpa_sm) 93685732ac8SCy Schubert return -1; 93785732ac8SCy Schubert 93885732ac8SCy Schubert if (vlan->notempty && 93985732ac8SCy Schubert !hostapd_vlan_valid(hapd->conf->vlan, vlan)) { 94085732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 94185732ac8SCy Schubert HOSTAPD_LEVEL_INFO, 94285732ac8SCy Schubert "Invalid VLAN %d%s received from FT", 94385732ac8SCy Schubert vlan->untagged, vlan->tagged[0] ? "+" : ""); 94485732ac8SCy Schubert return -1; 94585732ac8SCy Schubert } 94685732ac8SCy Schubert 94785732ac8SCy Schubert if (ap_sta_set_vlan(hapd, sta, vlan) < 0) 94885732ac8SCy Schubert return -1; 94985732ac8SCy Schubert /* Configure wpa_group for GTK but ignore error due to driver not 95085732ac8SCy Schubert * knowing this STA. */ 95185732ac8SCy Schubert ap_sta_bind_vlan(hapd, sta); 95285732ac8SCy Schubert 95385732ac8SCy Schubert if (sta->vlan_id) 95485732ac8SCy Schubert hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 95585732ac8SCy Schubert HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 95685732ac8SCy Schubert 95785732ac8SCy Schubert return 0; 95885732ac8SCy Schubert } 95985732ac8SCy Schubert 96085732ac8SCy Schubert 96185732ac8SCy Schubert static int hostapd_wpa_auth_get_vlan(void *ctx, const u8 *sta_addr, 96285732ac8SCy Schubert struct vlan_description *vlan) 96385732ac8SCy Schubert { 96485732ac8SCy Schubert struct hostapd_data *hapd = ctx; 96585732ac8SCy Schubert struct sta_info *sta; 96685732ac8SCy Schubert 96785732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 96885732ac8SCy Schubert if (!sta) 96985732ac8SCy Schubert return -1; 97085732ac8SCy Schubert 97185732ac8SCy Schubert if (sta->vlan_desc) 97285732ac8SCy Schubert *vlan = *sta->vlan_desc; 97385732ac8SCy Schubert else 97485732ac8SCy Schubert os_memset(vlan, 0, sizeof(*vlan)); 97585732ac8SCy Schubert 97685732ac8SCy Schubert return 0; 97785732ac8SCy Schubert } 97885732ac8SCy Schubert 97985732ac8SCy Schubert 98085732ac8SCy Schubert static int 98185732ac8SCy Schubert hostapd_wpa_auth_set_identity(void *ctx, const u8 *sta_addr, 98285732ac8SCy Schubert const u8 *identity, size_t identity_len) 98385732ac8SCy Schubert { 98485732ac8SCy Schubert struct hostapd_data *hapd = ctx; 98585732ac8SCy Schubert struct sta_info *sta; 98685732ac8SCy Schubert 98785732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 98885732ac8SCy Schubert if (!sta) 98985732ac8SCy Schubert return -1; 99085732ac8SCy Schubert 99185732ac8SCy Schubert os_free(sta->identity); 99285732ac8SCy Schubert sta->identity = NULL; 99385732ac8SCy Schubert 99485732ac8SCy Schubert if (sta->eapol_sm) { 99585732ac8SCy Schubert os_free(sta->eapol_sm->identity); 99685732ac8SCy Schubert sta->eapol_sm->identity = NULL; 99785732ac8SCy Schubert sta->eapol_sm->identity_len = 0; 99885732ac8SCy Schubert } 99985732ac8SCy Schubert 100085732ac8SCy Schubert if (!identity_len) 100185732ac8SCy Schubert return 0; 100285732ac8SCy Schubert 100385732ac8SCy Schubert /* sta->identity is NULL terminated */ 100485732ac8SCy Schubert sta->identity = os_zalloc(identity_len + 1); 100585732ac8SCy Schubert if (!sta->identity) 100685732ac8SCy Schubert return -1; 100785732ac8SCy Schubert os_memcpy(sta->identity, identity, identity_len); 100885732ac8SCy Schubert 100985732ac8SCy Schubert if (sta->eapol_sm) { 101085732ac8SCy Schubert sta->eapol_sm->identity = os_zalloc(identity_len); 101185732ac8SCy Schubert if (!sta->eapol_sm->identity) 101285732ac8SCy Schubert return -1; 101385732ac8SCy Schubert os_memcpy(sta->eapol_sm->identity, identity, identity_len); 101485732ac8SCy Schubert sta->eapol_sm->identity_len = identity_len; 101585732ac8SCy Schubert } 101685732ac8SCy Schubert 101785732ac8SCy Schubert return 0; 101885732ac8SCy Schubert } 101985732ac8SCy Schubert 102085732ac8SCy Schubert 102185732ac8SCy Schubert static size_t 102285732ac8SCy Schubert hostapd_wpa_auth_get_identity(void *ctx, const u8 *sta_addr, const u8 **buf) 102385732ac8SCy Schubert { 102485732ac8SCy Schubert struct hostapd_data *hapd = ctx; 102585732ac8SCy Schubert struct sta_info *sta; 102685732ac8SCy Schubert size_t len; 102785732ac8SCy Schubert char *identity; 102885732ac8SCy Schubert 102985732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 103085732ac8SCy Schubert if (!sta) 103185732ac8SCy Schubert return 0; 103285732ac8SCy Schubert 103385732ac8SCy Schubert *buf = ieee802_1x_get_identity(sta->eapol_sm, &len); 103485732ac8SCy Schubert if (*buf && len) 103585732ac8SCy Schubert return len; 103685732ac8SCy Schubert 103785732ac8SCy Schubert if (!sta->identity) { 103885732ac8SCy Schubert *buf = NULL; 103985732ac8SCy Schubert return 0; 104085732ac8SCy Schubert } 104185732ac8SCy Schubert 104285732ac8SCy Schubert identity = sta->identity; 104385732ac8SCy Schubert len = os_strlen(identity); 104485732ac8SCy Schubert *buf = (u8 *) identity; 104585732ac8SCy Schubert 104685732ac8SCy Schubert return len; 104785732ac8SCy Schubert } 104885732ac8SCy Schubert 104985732ac8SCy Schubert 105085732ac8SCy Schubert static int 105185732ac8SCy Schubert hostapd_wpa_auth_set_radius_cui(void *ctx, const u8 *sta_addr, 105285732ac8SCy Schubert const u8 *radius_cui, size_t radius_cui_len) 105385732ac8SCy Schubert { 105485732ac8SCy Schubert struct hostapd_data *hapd = ctx; 105585732ac8SCy Schubert struct sta_info *sta; 105685732ac8SCy Schubert 105785732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 105885732ac8SCy Schubert if (!sta) 105985732ac8SCy Schubert return -1; 106085732ac8SCy Schubert 106185732ac8SCy Schubert os_free(sta->radius_cui); 106285732ac8SCy Schubert sta->radius_cui = NULL; 106385732ac8SCy Schubert 106485732ac8SCy Schubert if (sta->eapol_sm) { 106585732ac8SCy Schubert wpabuf_free(sta->eapol_sm->radius_cui); 106685732ac8SCy Schubert sta->eapol_sm->radius_cui = NULL; 106785732ac8SCy Schubert } 106885732ac8SCy Schubert 106985732ac8SCy Schubert if (!radius_cui) 107085732ac8SCy Schubert return 0; 107185732ac8SCy Schubert 107285732ac8SCy Schubert /* sta->radius_cui is NULL terminated */ 107385732ac8SCy Schubert sta->radius_cui = os_zalloc(radius_cui_len + 1); 107485732ac8SCy Schubert if (!sta->radius_cui) 107585732ac8SCy Schubert return -1; 107685732ac8SCy Schubert os_memcpy(sta->radius_cui, radius_cui, radius_cui_len); 107785732ac8SCy Schubert 107885732ac8SCy Schubert if (sta->eapol_sm) { 107985732ac8SCy Schubert sta->eapol_sm->radius_cui = wpabuf_alloc_copy(radius_cui, 108085732ac8SCy Schubert radius_cui_len); 108185732ac8SCy Schubert if (!sta->eapol_sm->radius_cui) 108285732ac8SCy Schubert return -1; 108385732ac8SCy Schubert } 108485732ac8SCy Schubert 108585732ac8SCy Schubert return 0; 108685732ac8SCy Schubert } 108785732ac8SCy Schubert 108885732ac8SCy Schubert 108985732ac8SCy Schubert static size_t 109085732ac8SCy Schubert hostapd_wpa_auth_get_radius_cui(void *ctx, const u8 *sta_addr, const u8 **buf) 109185732ac8SCy Schubert { 109285732ac8SCy Schubert struct hostapd_data *hapd = ctx; 109385732ac8SCy Schubert struct sta_info *sta; 109485732ac8SCy Schubert struct wpabuf *b; 109585732ac8SCy Schubert size_t len; 109685732ac8SCy Schubert char *radius_cui; 109785732ac8SCy Schubert 109885732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 109985732ac8SCy Schubert if (!sta) 110085732ac8SCy Schubert return 0; 110185732ac8SCy Schubert 110285732ac8SCy Schubert b = ieee802_1x_get_radius_cui(sta->eapol_sm); 110385732ac8SCy Schubert if (b) { 110485732ac8SCy Schubert len = wpabuf_len(b); 110585732ac8SCy Schubert *buf = wpabuf_head(b); 110685732ac8SCy Schubert return len; 110785732ac8SCy Schubert } 110885732ac8SCy Schubert 110985732ac8SCy Schubert if (!sta->radius_cui) { 111085732ac8SCy Schubert *buf = NULL; 111185732ac8SCy Schubert return 0; 111285732ac8SCy Schubert } 111385732ac8SCy Schubert 111485732ac8SCy Schubert radius_cui = sta->radius_cui; 111585732ac8SCy Schubert len = os_strlen(radius_cui); 111685732ac8SCy Schubert *buf = (u8 *) radius_cui; 111785732ac8SCy Schubert 111885732ac8SCy Schubert return len; 111985732ac8SCy Schubert } 112085732ac8SCy Schubert 112185732ac8SCy Schubert 112285732ac8SCy Schubert static void hostapd_wpa_auth_set_session_timeout(void *ctx, const u8 *sta_addr, 112385732ac8SCy Schubert int session_timeout) 112485732ac8SCy Schubert { 112585732ac8SCy Schubert struct hostapd_data *hapd = ctx; 112685732ac8SCy Schubert struct sta_info *sta; 112785732ac8SCy Schubert 112885732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 112985732ac8SCy Schubert if (!sta) 113085732ac8SCy Schubert return; 113185732ac8SCy Schubert 113285732ac8SCy Schubert if (session_timeout) { 113385732ac8SCy Schubert os_get_reltime(&sta->session_timeout); 113485732ac8SCy Schubert sta->session_timeout.sec += session_timeout; 113585732ac8SCy Schubert sta->session_timeout_set = 1; 113685732ac8SCy Schubert ap_sta_session_timeout(hapd, sta, session_timeout); 113785732ac8SCy Schubert } else { 113885732ac8SCy Schubert sta->session_timeout_set = 0; 113985732ac8SCy Schubert ap_sta_no_session_timeout(hapd, sta); 114085732ac8SCy Schubert } 114185732ac8SCy Schubert } 114285732ac8SCy Schubert 114385732ac8SCy Schubert 114485732ac8SCy Schubert static int hostapd_wpa_auth_get_session_timeout(void *ctx, const u8 *sta_addr) 114585732ac8SCy Schubert { 114685732ac8SCy Schubert struct hostapd_data *hapd = ctx; 114785732ac8SCy Schubert struct sta_info *sta; 114885732ac8SCy Schubert struct os_reltime now, remaining; 114985732ac8SCy Schubert 115085732ac8SCy Schubert sta = ap_get_sta(hapd, sta_addr); 115185732ac8SCy Schubert if (!sta || !sta->session_timeout_set) 115285732ac8SCy Schubert return 0; 115385732ac8SCy Schubert 115485732ac8SCy Schubert os_get_reltime(&now); 115585732ac8SCy Schubert if (os_reltime_before(&sta->session_timeout, &now)) { 115685732ac8SCy Schubert /* already expired, return >0 as timeout was set */ 115785732ac8SCy Schubert return 1; 115885732ac8SCy Schubert } 115985732ac8SCy Schubert 116085732ac8SCy Schubert os_reltime_sub(&sta->session_timeout, &now, &remaining); 116185732ac8SCy Schubert 116285732ac8SCy Schubert return (remaining.sec > 0) ? remaining.sec : 1; 116385732ac8SCy Schubert } 116485732ac8SCy Schubert 116585732ac8SCy Schubert 1166e28a4053SRui Paulo static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf, 1167e28a4053SRui Paulo size_t len) 1168e28a4053SRui Paulo { 1169e28a4053SRui Paulo struct hostapd_data *hapd = ctx; 1170f05cddf9SRui Paulo struct l2_ethhdr *ethhdr; 1171f05cddf9SRui Paulo if (len < sizeof(*ethhdr)) 1172f05cddf9SRui Paulo return; 1173f05cddf9SRui Paulo ethhdr = (struct l2_ethhdr *) buf; 1174f05cddf9SRui Paulo wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 1175f05cddf9SRui Paulo MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest)); 1176780fb4a2SCy Schubert if (!is_multicast_ether_addr(ethhdr->h_dest) && 1177780fb4a2SCy Schubert os_memcmp(hapd->own_addr, ethhdr->h_dest, ETH_ALEN) != 0) 1178780fb4a2SCy Schubert return; 1179f05cddf9SRui Paulo wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr), 1180f05cddf9SRui Paulo len - sizeof(*ethhdr)); 1181f05cddf9SRui Paulo } 1182f05cddf9SRui Paulo 1183f05cddf9SRui Paulo 118485732ac8SCy Schubert static void hostapd_rrb_oui_receive(void *ctx, const u8 *src_addr, 118585732ac8SCy Schubert const u8 *dst_addr, u8 oui_suffix, 118685732ac8SCy Schubert const u8 *buf, size_t len) 118785732ac8SCy Schubert { 118885732ac8SCy Schubert struct hostapd_data *hapd = ctx; 118985732ac8SCy Schubert 119085732ac8SCy Schubert wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> " 119185732ac8SCy Schubert MACSTR, MAC2STR(src_addr), MAC2STR(dst_addr)); 119285732ac8SCy Schubert if (!is_multicast_ether_addr(dst_addr) && 119385732ac8SCy Schubert os_memcmp(hapd->own_addr, dst_addr, ETH_ALEN) != 0) 119485732ac8SCy Schubert return; 119585732ac8SCy Schubert wpa_ft_rrb_oui_rx(hapd->wpa_auth, src_addr, dst_addr, oui_suffix, buf, 119685732ac8SCy Schubert len); 119785732ac8SCy Schubert } 119885732ac8SCy Schubert 119985732ac8SCy Schubert 1200f05cddf9SRui Paulo static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr, 1201f05cddf9SRui Paulo u8 *tspec_ie, size_t tspec_ielen) 1202f05cddf9SRui Paulo { 1203f05cddf9SRui Paulo struct hostapd_data *hapd = ctx; 1204f05cddf9SRui Paulo return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen); 1205e28a4053SRui Paulo } 1206e28a4053SRui Paulo 120785732ac8SCy Schubert 120885732ac8SCy Schubert 120985732ac8SCy Schubert static int hostapd_wpa_register_ft_oui(struct hostapd_data *hapd, 121085732ac8SCy Schubert const char *ft_iface) 121185732ac8SCy Schubert { 121285732ac8SCy Schubert hapd->oui_pull = eth_p_oui_register(hapd, ft_iface, 121385732ac8SCy Schubert FT_PACKET_R0KH_R1KH_PULL, 121485732ac8SCy Schubert hostapd_rrb_oui_receive, hapd); 121585732ac8SCy Schubert if (!hapd->oui_pull) 121685732ac8SCy Schubert return -1; 121785732ac8SCy Schubert 121885732ac8SCy Schubert hapd->oui_resp = eth_p_oui_register(hapd, ft_iface, 121985732ac8SCy Schubert FT_PACKET_R0KH_R1KH_RESP, 122085732ac8SCy Schubert hostapd_rrb_oui_receive, hapd); 122185732ac8SCy Schubert if (!hapd->oui_resp) 122285732ac8SCy Schubert return -1; 122385732ac8SCy Schubert 122485732ac8SCy Schubert hapd->oui_push = eth_p_oui_register(hapd, ft_iface, 122585732ac8SCy Schubert FT_PACKET_R0KH_R1KH_PUSH, 122685732ac8SCy Schubert hostapd_rrb_oui_receive, hapd); 122785732ac8SCy Schubert if (!hapd->oui_push) 122885732ac8SCy Schubert return -1; 122985732ac8SCy Schubert 123085732ac8SCy Schubert hapd->oui_sreq = eth_p_oui_register(hapd, ft_iface, 123185732ac8SCy Schubert FT_PACKET_R0KH_R1KH_SEQ_REQ, 123285732ac8SCy Schubert hostapd_rrb_oui_receive, hapd); 123385732ac8SCy Schubert if (!hapd->oui_sreq) 123485732ac8SCy Schubert return -1; 123585732ac8SCy Schubert 123685732ac8SCy Schubert hapd->oui_sresp = eth_p_oui_register(hapd, ft_iface, 123785732ac8SCy Schubert FT_PACKET_R0KH_R1KH_SEQ_RESP, 123885732ac8SCy Schubert hostapd_rrb_oui_receive, hapd); 123985732ac8SCy Schubert if (!hapd->oui_sresp) 124085732ac8SCy Schubert return -1; 124185732ac8SCy Schubert 124285732ac8SCy Schubert return 0; 124385732ac8SCy Schubert } 124485732ac8SCy Schubert 124585732ac8SCy Schubert 124685732ac8SCy Schubert static void hostapd_wpa_unregister_ft_oui(struct hostapd_data *hapd) 124785732ac8SCy Schubert { 124885732ac8SCy Schubert eth_p_oui_unregister(hapd->oui_pull); 124985732ac8SCy Schubert hapd->oui_pull = NULL; 125085732ac8SCy Schubert eth_p_oui_unregister(hapd->oui_resp); 125185732ac8SCy Schubert hapd->oui_resp = NULL; 125285732ac8SCy Schubert eth_p_oui_unregister(hapd->oui_push); 125385732ac8SCy Schubert hapd->oui_push = NULL; 125485732ac8SCy Schubert eth_p_oui_unregister(hapd->oui_sreq); 125585732ac8SCy Schubert hapd->oui_sreq = NULL; 125685732ac8SCy Schubert eth_p_oui_unregister(hapd->oui_sresp); 125785732ac8SCy Schubert hapd->oui_sresp = NULL; 125885732ac8SCy Schubert } 125985732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 1260e28a4053SRui Paulo 1261e28a4053SRui Paulo 1262e28a4053SRui Paulo int hostapd_setup_wpa(struct hostapd_data *hapd) 1263e28a4053SRui Paulo { 1264e28a4053SRui Paulo struct wpa_auth_config _conf; 126585732ac8SCy Schubert static const struct wpa_auth_callbacks cb = { 126685732ac8SCy Schubert .logger = hostapd_wpa_auth_logger, 126785732ac8SCy Schubert .disconnect = hostapd_wpa_auth_disconnect, 126885732ac8SCy Schubert .mic_failure_report = hostapd_wpa_auth_mic_failure_report, 126985732ac8SCy Schubert .psk_failure_report = hostapd_wpa_auth_psk_failure_report, 127085732ac8SCy Schubert .set_eapol = hostapd_wpa_auth_set_eapol, 127185732ac8SCy Schubert .get_eapol = hostapd_wpa_auth_get_eapol, 127285732ac8SCy Schubert .get_psk = hostapd_wpa_auth_get_psk, 127385732ac8SCy Schubert .get_msk = hostapd_wpa_auth_get_msk, 127485732ac8SCy Schubert .set_key = hostapd_wpa_auth_set_key, 127585732ac8SCy Schubert .get_seqnum = hostapd_wpa_auth_get_seqnum, 127685732ac8SCy Schubert .send_eapol = hostapd_wpa_auth_send_eapol, 127785732ac8SCy Schubert .for_each_sta = hostapd_wpa_auth_for_each_sta, 127885732ac8SCy Schubert .for_each_auth = hostapd_wpa_auth_for_each_auth, 127985732ac8SCy Schubert .send_ether = hostapd_wpa_auth_send_ether, 128085732ac8SCy Schubert .send_oui = hostapd_wpa_auth_send_oui, 12814bc52338SCy Schubert .channel_info = hostapd_channel_info, 12824bc52338SCy Schubert .update_vlan = hostapd_wpa_auth_update_vlan, 12834bc52338SCy Schubert #ifdef CONFIG_OCV 12844bc52338SCy Schubert .get_sta_tx_params = hostapd_get_sta_tx_params, 12854bc52338SCy Schubert #endif /* CONFIG_OCV */ 128685732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 128785732ac8SCy Schubert .send_ft_action = hostapd_wpa_auth_send_ft_action, 128885732ac8SCy Schubert .add_sta = hostapd_wpa_auth_add_sta, 128985732ac8SCy Schubert .add_tspec = hostapd_wpa_auth_add_tspec, 129085732ac8SCy Schubert .set_vlan = hostapd_wpa_auth_set_vlan, 129185732ac8SCy Schubert .get_vlan = hostapd_wpa_auth_get_vlan, 129285732ac8SCy Schubert .set_identity = hostapd_wpa_auth_set_identity, 129385732ac8SCy Schubert .get_identity = hostapd_wpa_auth_get_identity, 129485732ac8SCy Schubert .set_radius_cui = hostapd_wpa_auth_set_radius_cui, 129585732ac8SCy Schubert .get_radius_cui = hostapd_wpa_auth_get_radius_cui, 129685732ac8SCy Schubert .set_session_timeout = hostapd_wpa_auth_set_session_timeout, 129785732ac8SCy Schubert .get_session_timeout = hostapd_wpa_auth_get_session_timeout, 129885732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 129985732ac8SCy Schubert }; 1300e28a4053SRui Paulo const u8 *wpa_ie; 1301e28a4053SRui Paulo size_t wpa_ie_len; 1302e28a4053SRui Paulo 13035b9c547cSRui Paulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &_conf); 1304f05cddf9SRui Paulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS) 1305f05cddf9SRui Paulo _conf.tx_status = 1; 1306f05cddf9SRui Paulo if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME) 1307f05cddf9SRui Paulo _conf.ap_mlme = 1; 130885732ac8SCy Schubert hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb, hapd); 1309e28a4053SRui Paulo if (hapd->wpa_auth == NULL) { 1310e28a4053SRui Paulo wpa_printf(MSG_ERROR, "WPA initialization failed."); 1311e28a4053SRui Paulo return -1; 1312e28a4053SRui Paulo } 1313e28a4053SRui Paulo 1314e28a4053SRui Paulo if (hostapd_set_privacy(hapd, 1)) { 1315e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked " 1316e28a4053SRui Paulo "for interface %s", hapd->conf->iface); 1317e28a4053SRui Paulo return -1; 1318e28a4053SRui Paulo } 1319e28a4053SRui Paulo 1320e28a4053SRui Paulo wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len); 1321e28a4053SRui Paulo if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) { 1322e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Failed to configure WPA IE for " 1323e28a4053SRui Paulo "the kernel driver."); 1324e28a4053SRui Paulo return -1; 1325e28a4053SRui Paulo } 1326e28a4053SRui Paulo 1327e28a4053SRui Paulo if (rsn_preauth_iface_init(hapd)) { 1328e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Initialization of RSN " 1329e28a4053SRui Paulo "pre-authentication failed."); 1330e28a4053SRui Paulo return -1; 1331e28a4053SRui Paulo } 1332e28a4053SRui Paulo 133385732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 1334780fb4a2SCy Schubert if (!hostapd_drv_none(hapd) && 1335325151a3SRui Paulo wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { 133685732ac8SCy Schubert const char *ft_iface; 133785732ac8SCy Schubert 133885732ac8SCy Schubert ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge : 133985732ac8SCy Schubert hapd->conf->iface; 134085732ac8SCy Schubert hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, 1341f05cddf9SRui Paulo hostapd_rrb_receive, hapd, 1); 1342e28a4053SRui Paulo if (hapd->l2 == NULL && 1343e28a4053SRui Paulo (hapd->driver == NULL || 1344e28a4053SRui Paulo hapd->driver->send_ether == NULL)) { 1345e28a4053SRui Paulo wpa_printf(MSG_ERROR, "Failed to open l2_packet " 1346e28a4053SRui Paulo "interface"); 1347e28a4053SRui Paulo return -1; 1348e28a4053SRui Paulo } 134985732ac8SCy Schubert 135085732ac8SCy Schubert if (hostapd_wpa_register_ft_oui(hapd, ft_iface)) { 135185732ac8SCy Schubert wpa_printf(MSG_ERROR, 135285732ac8SCy Schubert "Failed to open ETH_P_OUI interface"); 135385732ac8SCy Schubert return -1; 1354e28a4053SRui Paulo } 135585732ac8SCy Schubert } 135685732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 1357e28a4053SRui Paulo 1358e28a4053SRui Paulo return 0; 1359e28a4053SRui Paulo 1360e28a4053SRui Paulo } 1361e28a4053SRui Paulo 1362e28a4053SRui Paulo 1363e28a4053SRui Paulo void hostapd_reconfig_wpa(struct hostapd_data *hapd) 1364e28a4053SRui Paulo { 1365e28a4053SRui Paulo struct wpa_auth_config wpa_auth_conf; 13665b9c547cSRui Paulo hostapd_wpa_auth_conf(hapd->conf, hapd->iconf, &wpa_auth_conf); 1367e28a4053SRui Paulo wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf); 1368e28a4053SRui Paulo } 1369e28a4053SRui Paulo 1370e28a4053SRui Paulo 1371e28a4053SRui Paulo void hostapd_deinit_wpa(struct hostapd_data *hapd) 1372e28a4053SRui Paulo { 1373f05cddf9SRui Paulo ieee80211_tkip_countermeasures_deinit(hapd); 1374e28a4053SRui Paulo rsn_preauth_iface_deinit(hapd); 1375e28a4053SRui Paulo if (hapd->wpa_auth) { 1376e28a4053SRui Paulo wpa_deinit(hapd->wpa_auth); 1377e28a4053SRui Paulo hapd->wpa_auth = NULL; 1378e28a4053SRui Paulo 1379780fb4a2SCy Schubert if (hapd->drv_priv && hostapd_set_privacy(hapd, 0)) { 1380e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not disable " 1381e28a4053SRui Paulo "PrivacyInvoked for interface %s", 1382e28a4053SRui Paulo hapd->conf->iface); 1383e28a4053SRui Paulo } 1384e28a4053SRui Paulo 1385780fb4a2SCy Schubert if (hapd->drv_priv && 1386780fb4a2SCy Schubert hostapd_set_generic_elem(hapd, (u8 *) "", 0)) { 1387e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not remove generic " 1388e28a4053SRui Paulo "information element from interface %s", 1389e28a4053SRui Paulo hapd->conf->iface); 1390e28a4053SRui Paulo } 1391e28a4053SRui Paulo } 1392e28a4053SRui Paulo ieee802_1x_deinit(hapd); 1393e28a4053SRui Paulo 139485732ac8SCy Schubert #ifdef CONFIG_IEEE80211R_AP 139585732ac8SCy Schubert eloop_cancel_timeout(hostapd_wpa_ft_rrb_rx_later, hapd, ELOOP_ALL_CTX); 139685732ac8SCy Schubert hostapd_wpa_ft_rrb_rx_later(hapd, NULL); /* flush without delivering */ 139785732ac8SCy Schubert eloop_cancel_timeout(hostapd_oui_deliver_later, hapd, ELOOP_ALL_CTX); 139885732ac8SCy Schubert hostapd_oui_deliver_later(hapd, NULL); /* flush without delivering */ 1399e28a4053SRui Paulo l2_packet_deinit(hapd->l2); 14005b9c547cSRui Paulo hapd->l2 = NULL; 140185732ac8SCy Schubert hostapd_wpa_unregister_ft_oui(hapd); 140285732ac8SCy Schubert #endif /* CONFIG_IEEE80211R_AP */ 1403e28a4053SRui Paulo } 1404