1214501Srpaulo/* 2214501Srpaulo * hostapd / IEEE 802.11 Management 3214501Srpaulo * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo */ 14214501Srpaulo 15214501Srpaulo#include "utils/includes.h" 16214501Srpaulo 17214501Srpaulo#ifndef CONFIG_NATIVE_WINDOWS 18214501Srpaulo 19214501Srpaulo#include "utils/common.h" 20214501Srpaulo#include "utils/eloop.h" 21214501Srpaulo#include "crypto/crypto.h" 22214501Srpaulo#include "drivers/driver.h" 23214501Srpaulo#include "common/ieee802_11_defs.h" 24214501Srpaulo#include "common/ieee802_11_common.h" 25214501Srpaulo#include "common/wpa_ctrl.h" 26214501Srpaulo#include "radius/radius.h" 27214501Srpaulo#include "radius/radius_client.h" 28214501Srpaulo#include "wps/wps.h" 29214501Srpaulo#include "hostapd.h" 30214501Srpaulo#include "beacon.h" 31214501Srpaulo#include "ieee802_11_auth.h" 32214501Srpaulo#include "sta_info.h" 33214501Srpaulo#include "ieee802_1x.h" 34214501Srpaulo#include "wpa_auth.h" 35214501Srpaulo#include "wmm.h" 36214501Srpaulo#include "ap_list.h" 37214501Srpaulo#include "accounting.h" 38214501Srpaulo#include "ap_config.h" 39214501Srpaulo#include "ap_mlme.h" 40214501Srpaulo#include "ieee802_11.h" 41214501Srpaulo 42214501Srpaulo 43214501Srpaulou8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid) 44214501Srpaulo{ 45214501Srpaulo u8 *pos = eid; 46214501Srpaulo int i, num, count; 47214501Srpaulo 48214501Srpaulo if (hapd->iface->current_rates == NULL) 49214501Srpaulo return eid; 50214501Srpaulo 51214501Srpaulo *pos++ = WLAN_EID_SUPP_RATES; 52214501Srpaulo num = hapd->iface->num_rates; 53214501Srpaulo if (num > 8) { 54214501Srpaulo /* rest of the rates are encoded in Extended supported 55214501Srpaulo * rates element */ 56214501Srpaulo num = 8; 57214501Srpaulo } 58214501Srpaulo 59214501Srpaulo *pos++ = num; 60214501Srpaulo count = 0; 61214501Srpaulo for (i = 0, count = 0; i < hapd->iface->num_rates && count < num; 62214501Srpaulo i++) { 63214501Srpaulo count++; 64214501Srpaulo *pos = hapd->iface->current_rates[i].rate / 5; 65214501Srpaulo if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 66214501Srpaulo *pos |= 0x80; 67214501Srpaulo pos++; 68214501Srpaulo } 69214501Srpaulo 70214501Srpaulo return pos; 71214501Srpaulo} 72214501Srpaulo 73214501Srpaulo 74214501Srpaulou8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid) 75214501Srpaulo{ 76214501Srpaulo u8 *pos = eid; 77214501Srpaulo int i, num, count; 78214501Srpaulo 79214501Srpaulo if (hapd->iface->current_rates == NULL) 80214501Srpaulo return eid; 81214501Srpaulo 82214501Srpaulo num = hapd->iface->num_rates; 83214501Srpaulo if (num <= 8) 84214501Srpaulo return eid; 85214501Srpaulo num -= 8; 86214501Srpaulo 87214501Srpaulo *pos++ = WLAN_EID_EXT_SUPP_RATES; 88214501Srpaulo *pos++ = num; 89214501Srpaulo count = 0; 90214501Srpaulo for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8; 91214501Srpaulo i++) { 92214501Srpaulo count++; 93214501Srpaulo if (count <= 8) 94214501Srpaulo continue; /* already in SuppRates IE */ 95214501Srpaulo *pos = hapd->iface->current_rates[i].rate / 5; 96214501Srpaulo if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC) 97214501Srpaulo *pos |= 0x80; 98214501Srpaulo pos++; 99214501Srpaulo } 100214501Srpaulo 101214501Srpaulo return pos; 102214501Srpaulo} 103214501Srpaulo 104214501Srpaulo 105214501Srpaulou16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta, 106214501Srpaulo int probe) 107214501Srpaulo{ 108214501Srpaulo int capab = WLAN_CAPABILITY_ESS; 109214501Srpaulo int privacy; 110214501Srpaulo 111214501Srpaulo if (hapd->iface->num_sta_no_short_preamble == 0 && 112214501Srpaulo hapd->iconf->preamble == SHORT_PREAMBLE) 113214501Srpaulo capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; 114214501Srpaulo 115214501Srpaulo privacy = hapd->conf->ssid.wep.keys_set; 116214501Srpaulo 117214501Srpaulo if (hapd->conf->ieee802_1x && 118214501Srpaulo (hapd->conf->default_wep_key_len || 119214501Srpaulo hapd->conf->individual_wep_key_len)) 120214501Srpaulo privacy = 1; 121214501Srpaulo 122214501Srpaulo if (hapd->conf->wpa) 123214501Srpaulo privacy = 1; 124214501Srpaulo 125214501Srpaulo if (sta) { 126214501Srpaulo int policy, def_klen; 127214501Srpaulo if (probe && sta->ssid_probe) { 128214501Srpaulo policy = sta->ssid_probe->security_policy; 129214501Srpaulo def_klen = sta->ssid_probe->wep.default_len; 130214501Srpaulo } else { 131214501Srpaulo policy = sta->ssid->security_policy; 132214501Srpaulo def_klen = sta->ssid->wep.default_len; 133214501Srpaulo } 134214501Srpaulo privacy = policy != SECURITY_PLAINTEXT; 135214501Srpaulo if (policy == SECURITY_IEEE_802_1X && def_klen == 0) 136214501Srpaulo privacy = 0; 137214501Srpaulo } 138214501Srpaulo 139214501Srpaulo if (privacy) 140214501Srpaulo capab |= WLAN_CAPABILITY_PRIVACY; 141214501Srpaulo 142214501Srpaulo if (hapd->iface->current_mode && 143214501Srpaulo hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G && 144214501Srpaulo hapd->iface->num_sta_no_short_slot_time == 0) 145214501Srpaulo capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 146214501Srpaulo 147214501Srpaulo return capab; 148214501Srpaulo} 149214501Srpaulo 150214501Srpaulo 151214501Srpaulo#ifdef CONFIG_IEEE80211W 152214501Srpaulostatic u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, 153214501Srpaulo struct sta_info *sta, u8 *eid) 154214501Srpaulo{ 155214501Srpaulo u8 *pos = eid; 156214501Srpaulo u32 timeout, tu; 157214501Srpaulo struct os_time now, passed; 158214501Srpaulo 159214501Srpaulo *pos++ = WLAN_EID_TIMEOUT_INTERVAL; 160214501Srpaulo *pos++ = 5; 161214501Srpaulo *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; 162214501Srpaulo os_get_time(&now); 163214501Srpaulo os_time_sub(&now, &sta->sa_query_start, &passed); 164214501Srpaulo tu = (passed.sec * 1000000 + passed.usec) / 1024; 165214501Srpaulo if (hapd->conf->assoc_sa_query_max_timeout > tu) 166214501Srpaulo timeout = hapd->conf->assoc_sa_query_max_timeout - tu; 167214501Srpaulo else 168214501Srpaulo timeout = 0; 169214501Srpaulo if (timeout < hapd->conf->assoc_sa_query_max_timeout) 170214501Srpaulo timeout++; /* add some extra time for local timers */ 171214501Srpaulo WPA_PUT_LE32(pos, timeout); 172214501Srpaulo pos += 4; 173214501Srpaulo 174214501Srpaulo return pos; 175214501Srpaulo} 176214501Srpaulo#endif /* CONFIG_IEEE80211W */ 177214501Srpaulo 178214501Srpaulo 179214501Srpaulovoid ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) 180214501Srpaulo{ 181214501Srpaulo int i; 182214501Srpaulo if (len > HOSTAPD_MAX_SSID_LEN) 183214501Srpaulo len = HOSTAPD_MAX_SSID_LEN; 184214501Srpaulo for (i = 0; i < len; i++) { 185214501Srpaulo if (ssid[i] >= 32 && ssid[i] < 127) 186214501Srpaulo buf[i] = ssid[i]; 187214501Srpaulo else 188214501Srpaulo buf[i] = '.'; 189214501Srpaulo } 190214501Srpaulo buf[len] = '\0'; 191214501Srpaulo} 192214501Srpaulo 193214501Srpaulo 194214501Srpaulostatic u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, 195214501Srpaulo u16 auth_transaction, const u8 *challenge, 196214501Srpaulo int iswep) 197214501Srpaulo{ 198214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 199214501Srpaulo HOSTAPD_LEVEL_DEBUG, 200214501Srpaulo "authentication (shared key, transaction %d)", 201214501Srpaulo auth_transaction); 202214501Srpaulo 203214501Srpaulo if (auth_transaction == 1) { 204214501Srpaulo if (!sta->challenge) { 205214501Srpaulo /* Generate a pseudo-random challenge */ 206214501Srpaulo u8 key[8]; 207214501Srpaulo time_t now; 208214501Srpaulo int r; 209214501Srpaulo sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN); 210214501Srpaulo if (sta->challenge == NULL) 211214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 212214501Srpaulo 213214501Srpaulo now = time(NULL); 214214501Srpaulo r = random(); 215214501Srpaulo os_memcpy(key, &now, 4); 216214501Srpaulo os_memcpy(key + 4, &r, 4); 217214501Srpaulo rc4_skip(key, sizeof(key), 0, 218214501Srpaulo sta->challenge, WLAN_AUTH_CHALLENGE_LEN); 219214501Srpaulo } 220214501Srpaulo return 0; 221214501Srpaulo } 222214501Srpaulo 223214501Srpaulo if (auth_transaction != 3) 224214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 225214501Srpaulo 226214501Srpaulo /* Transaction 3 */ 227214501Srpaulo if (!iswep || !sta->challenge || !challenge || 228214501Srpaulo os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { 229214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 230214501Srpaulo HOSTAPD_LEVEL_INFO, 231214501Srpaulo "shared key authentication - invalid " 232214501Srpaulo "challenge-response"); 233214501Srpaulo return WLAN_STATUS_CHALLENGE_FAIL; 234214501Srpaulo } 235214501Srpaulo 236214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 237214501Srpaulo HOSTAPD_LEVEL_DEBUG, 238214501Srpaulo "authentication OK (shared key)"); 239214501Srpaulo#ifdef IEEE80211_REQUIRE_AUTH_ACK 240214501Srpaulo /* Station will be marked authenticated if it ACKs the 241214501Srpaulo * authentication reply. */ 242214501Srpaulo#else 243214501Srpaulo sta->flags |= WLAN_STA_AUTH; 244214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 245214501Srpaulo#endif 246214501Srpaulo os_free(sta->challenge); 247214501Srpaulo sta->challenge = NULL; 248214501Srpaulo 249214501Srpaulo return 0; 250214501Srpaulo} 251214501Srpaulo 252214501Srpaulo 253214501Srpaulostatic void send_auth_reply(struct hostapd_data *hapd, 254214501Srpaulo const u8 *dst, const u8 *bssid, 255214501Srpaulo u16 auth_alg, u16 auth_transaction, u16 resp, 256214501Srpaulo const u8 *ies, size_t ies_len) 257214501Srpaulo{ 258214501Srpaulo struct ieee80211_mgmt *reply; 259214501Srpaulo u8 *buf; 260214501Srpaulo size_t rlen; 261214501Srpaulo 262214501Srpaulo rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len; 263214501Srpaulo buf = os_zalloc(rlen); 264214501Srpaulo if (buf == NULL) 265214501Srpaulo return; 266214501Srpaulo 267214501Srpaulo reply = (struct ieee80211_mgmt *) buf; 268214501Srpaulo reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 269214501Srpaulo WLAN_FC_STYPE_AUTH); 270214501Srpaulo os_memcpy(reply->da, dst, ETH_ALEN); 271214501Srpaulo os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 272214501Srpaulo os_memcpy(reply->bssid, bssid, ETH_ALEN); 273214501Srpaulo 274214501Srpaulo reply->u.auth.auth_alg = host_to_le16(auth_alg); 275214501Srpaulo reply->u.auth.auth_transaction = host_to_le16(auth_transaction); 276214501Srpaulo reply->u.auth.status_code = host_to_le16(resp); 277214501Srpaulo 278214501Srpaulo if (ies && ies_len) 279214501Srpaulo os_memcpy(reply->u.auth.variable, ies, ies_len); 280214501Srpaulo 281214501Srpaulo wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR 282214501Srpaulo " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)", 283214501Srpaulo MAC2STR(dst), auth_alg, auth_transaction, 284214501Srpaulo resp, (unsigned long) ies_len); 285214501Srpaulo if (hapd->drv.send_mgmt_frame(hapd, reply, rlen) < 0) 286214501Srpaulo perror("send_auth_reply: send"); 287214501Srpaulo 288214501Srpaulo os_free(buf); 289214501Srpaulo} 290214501Srpaulo 291214501Srpaulo 292214501Srpaulo#ifdef CONFIG_IEEE80211R 293214501Srpaulostatic void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid, 294214501Srpaulo u16 auth_transaction, u16 status, 295214501Srpaulo const u8 *ies, size_t ies_len) 296214501Srpaulo{ 297214501Srpaulo struct hostapd_data *hapd = ctx; 298214501Srpaulo struct sta_info *sta; 299214501Srpaulo 300214501Srpaulo send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction, 301214501Srpaulo status, ies, ies_len); 302214501Srpaulo 303214501Srpaulo if (status != WLAN_STATUS_SUCCESS) 304214501Srpaulo return; 305214501Srpaulo 306214501Srpaulo sta = ap_get_sta(hapd, dst); 307214501Srpaulo if (sta == NULL) 308214501Srpaulo return; 309214501Srpaulo 310214501Srpaulo hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211, 311214501Srpaulo HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)"); 312214501Srpaulo sta->flags |= WLAN_STA_AUTH; 313214501Srpaulo mlme_authenticate_indication(hapd, sta); 314214501Srpaulo} 315214501Srpaulo#endif /* CONFIG_IEEE80211R */ 316214501Srpaulo 317214501Srpaulo 318214501Srpaulostatic void handle_auth(struct hostapd_data *hapd, 319214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 320214501Srpaulo{ 321214501Srpaulo u16 auth_alg, auth_transaction, status_code; 322214501Srpaulo u16 resp = WLAN_STATUS_SUCCESS; 323214501Srpaulo struct sta_info *sta = NULL; 324214501Srpaulo int res; 325214501Srpaulo u16 fc; 326214501Srpaulo const u8 *challenge = NULL; 327214501Srpaulo u32 session_timeout, acct_interim_interval; 328214501Srpaulo int vlan_id = 0; 329214501Srpaulo u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN]; 330214501Srpaulo size_t resp_ies_len = 0; 331214501Srpaulo 332214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 333214501Srpaulo printf("handle_auth - too short payload (len=%lu)\n", 334214501Srpaulo (unsigned long) len); 335214501Srpaulo return; 336214501Srpaulo } 337214501Srpaulo 338214501Srpaulo auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 339214501Srpaulo auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 340214501Srpaulo status_code = le_to_host16(mgmt->u.auth.status_code); 341214501Srpaulo fc = le_to_host16(mgmt->frame_control); 342214501Srpaulo 343214501Srpaulo if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + 344214501Srpaulo 2 + WLAN_AUTH_CHALLENGE_LEN && 345214501Srpaulo mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && 346214501Srpaulo mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) 347214501Srpaulo challenge = &mgmt->u.auth.variable[2]; 348214501Srpaulo 349214501Srpaulo wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d " 350214501Srpaulo "auth_transaction=%d status_code=%d wep=%d%s", 351214501Srpaulo MAC2STR(mgmt->sa), auth_alg, auth_transaction, 352214501Srpaulo status_code, !!(fc & WLAN_FC_ISWEP), 353214501Srpaulo challenge ? " challenge" : ""); 354214501Srpaulo 355214501Srpaulo if (hapd->tkip_countermeasures) { 356214501Srpaulo resp = WLAN_REASON_MICHAEL_MIC_FAILURE; 357214501Srpaulo goto fail; 358214501Srpaulo } 359214501Srpaulo 360214501Srpaulo if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) && 361214501Srpaulo auth_alg == WLAN_AUTH_OPEN) || 362214501Srpaulo#ifdef CONFIG_IEEE80211R 363214501Srpaulo (hapd->conf->wpa && 364214501Srpaulo (hapd->conf->wpa_key_mgmt & 365214501Srpaulo (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) && 366214501Srpaulo auth_alg == WLAN_AUTH_FT) || 367214501Srpaulo#endif /* CONFIG_IEEE80211R */ 368214501Srpaulo ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) && 369214501Srpaulo auth_alg == WLAN_AUTH_SHARED_KEY))) { 370214501Srpaulo printf("Unsupported authentication algorithm (%d)\n", 371214501Srpaulo auth_alg); 372214501Srpaulo resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; 373214501Srpaulo goto fail; 374214501Srpaulo } 375214501Srpaulo 376214501Srpaulo if (!(auth_transaction == 1 || 377214501Srpaulo (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { 378214501Srpaulo printf("Unknown authentication transaction number (%d)\n", 379214501Srpaulo auth_transaction); 380214501Srpaulo resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; 381214501Srpaulo goto fail; 382214501Srpaulo } 383214501Srpaulo 384214501Srpaulo if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { 385214501Srpaulo printf("Station " MACSTR " not allowed to authenticate.\n", 386214501Srpaulo MAC2STR(mgmt->sa)); 387214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 388214501Srpaulo goto fail; 389214501Srpaulo } 390214501Srpaulo 391214501Srpaulo res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, 392214501Srpaulo &session_timeout, 393214501Srpaulo &acct_interim_interval, &vlan_id); 394214501Srpaulo if (res == HOSTAPD_ACL_REJECT) { 395214501Srpaulo printf("Station " MACSTR " not allowed to authenticate.\n", 396214501Srpaulo MAC2STR(mgmt->sa)); 397214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 398214501Srpaulo goto fail; 399214501Srpaulo } 400214501Srpaulo if (res == HOSTAPD_ACL_PENDING) { 401214501Srpaulo wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR 402214501Srpaulo " waiting for an external authentication", 403214501Srpaulo MAC2STR(mgmt->sa)); 404214501Srpaulo /* Authentication code will re-send the authentication frame 405214501Srpaulo * after it has received (and cached) information from the 406214501Srpaulo * external source. */ 407214501Srpaulo return; 408214501Srpaulo } 409214501Srpaulo 410214501Srpaulo sta = ap_sta_add(hapd, mgmt->sa); 411214501Srpaulo if (!sta) { 412214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 413214501Srpaulo goto fail; 414214501Srpaulo } 415214501Srpaulo 416214501Srpaulo if (vlan_id > 0) { 417214501Srpaulo if (hostapd_get_vlan_id_ifname(hapd->conf->vlan, 418214501Srpaulo vlan_id) == NULL) { 419214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 420214501Srpaulo HOSTAPD_LEVEL_INFO, "Invalid VLAN ID " 421214501Srpaulo "%d received from RADIUS server", 422214501Srpaulo vlan_id); 423214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 424214501Srpaulo goto fail; 425214501Srpaulo } 426214501Srpaulo sta->vlan_id = vlan_id; 427214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS, 428214501Srpaulo HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id); 429214501Srpaulo } 430214501Srpaulo 431214501Srpaulo sta->flags &= ~WLAN_STA_PREAUTH; 432214501Srpaulo ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); 433214501Srpaulo 434214501Srpaulo if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval) 435214501Srpaulo sta->acct_interim_interval = acct_interim_interval; 436214501Srpaulo if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) 437214501Srpaulo ap_sta_session_timeout(hapd, sta, session_timeout); 438214501Srpaulo else 439214501Srpaulo ap_sta_no_session_timeout(hapd, sta); 440214501Srpaulo 441214501Srpaulo switch (auth_alg) { 442214501Srpaulo case WLAN_AUTH_OPEN: 443214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 444214501Srpaulo HOSTAPD_LEVEL_DEBUG, 445214501Srpaulo "authentication OK (open system)"); 446214501Srpaulo#ifdef IEEE80211_REQUIRE_AUTH_ACK 447214501Srpaulo /* Station will be marked authenticated if it ACKs the 448214501Srpaulo * authentication reply. */ 449214501Srpaulo#else 450214501Srpaulo sta->flags |= WLAN_STA_AUTH; 451214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH); 452214501Srpaulo sta->auth_alg = WLAN_AUTH_OPEN; 453214501Srpaulo mlme_authenticate_indication(hapd, sta); 454214501Srpaulo#endif 455214501Srpaulo break; 456214501Srpaulo case WLAN_AUTH_SHARED_KEY: 457214501Srpaulo resp = auth_shared_key(hapd, sta, auth_transaction, challenge, 458214501Srpaulo fc & WLAN_FC_ISWEP); 459214501Srpaulo sta->auth_alg = WLAN_AUTH_SHARED_KEY; 460214501Srpaulo mlme_authenticate_indication(hapd, sta); 461214501Srpaulo if (sta->challenge && auth_transaction == 1) { 462214501Srpaulo resp_ies[0] = WLAN_EID_CHALLENGE; 463214501Srpaulo resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN; 464214501Srpaulo os_memcpy(resp_ies + 2, sta->challenge, 465214501Srpaulo WLAN_AUTH_CHALLENGE_LEN); 466214501Srpaulo resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN; 467214501Srpaulo } 468214501Srpaulo break; 469214501Srpaulo#ifdef CONFIG_IEEE80211R 470214501Srpaulo case WLAN_AUTH_FT: 471214501Srpaulo sta->auth_alg = WLAN_AUTH_FT; 472214501Srpaulo if (sta->wpa_sm == NULL) 473214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 474214501Srpaulo sta->addr); 475214501Srpaulo if (sta->wpa_sm == NULL) { 476214501Srpaulo wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA " 477214501Srpaulo "state machine"); 478214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 479214501Srpaulo goto fail; 480214501Srpaulo } 481214501Srpaulo wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid, 482214501Srpaulo auth_transaction, mgmt->u.auth.variable, 483214501Srpaulo len - IEEE80211_HDRLEN - 484214501Srpaulo sizeof(mgmt->u.auth), 485214501Srpaulo handle_auth_ft_finish, hapd); 486214501Srpaulo /* handle_auth_ft_finish() callback will complete auth. */ 487214501Srpaulo return; 488214501Srpaulo#endif /* CONFIG_IEEE80211R */ 489214501Srpaulo } 490214501Srpaulo 491214501Srpaulo fail: 492214501Srpaulo send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg, 493214501Srpaulo auth_transaction + 1, resp, resp_ies, resp_ies_len); 494214501Srpaulo} 495214501Srpaulo 496214501Srpaulo 497214501Srpaulostatic int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta) 498214501Srpaulo{ 499214501Srpaulo int i, j = 32, aid; 500214501Srpaulo 501214501Srpaulo /* get a unique AID */ 502214501Srpaulo if (sta->aid > 0) { 503214501Srpaulo wpa_printf(MSG_DEBUG, " old AID %d", sta->aid); 504214501Srpaulo return 0; 505214501Srpaulo } 506214501Srpaulo 507214501Srpaulo for (i = 0; i < AID_WORDS; i++) { 508214501Srpaulo if (hapd->sta_aid[i] == (u32) -1) 509214501Srpaulo continue; 510214501Srpaulo for (j = 0; j < 32; j++) { 511214501Srpaulo if (!(hapd->sta_aid[i] & BIT(j))) 512214501Srpaulo break; 513214501Srpaulo } 514214501Srpaulo if (j < 32) 515214501Srpaulo break; 516214501Srpaulo } 517214501Srpaulo if (j == 32) 518214501Srpaulo return -1; 519214501Srpaulo aid = i * 32 + j + 1; 520214501Srpaulo if (aid > 2007) 521214501Srpaulo return -1; 522214501Srpaulo 523214501Srpaulo sta->aid = aid; 524214501Srpaulo hapd->sta_aid[i] |= BIT(j); 525214501Srpaulo wpa_printf(MSG_DEBUG, " new AID %d", sta->aid); 526214501Srpaulo return 0; 527214501Srpaulo} 528214501Srpaulo 529214501Srpaulo 530214501Srpaulostatic u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta, 531214501Srpaulo const u8 *ssid_ie, size_t ssid_ie_len) 532214501Srpaulo{ 533214501Srpaulo if (ssid_ie == NULL) 534214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 535214501Srpaulo 536214501Srpaulo if (ssid_ie_len != hapd->conf->ssid.ssid_len || 537214501Srpaulo os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) { 538214501Srpaulo char ssid_txt[33]; 539214501Srpaulo ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len); 540214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 541214501Srpaulo HOSTAPD_LEVEL_INFO, 542214501Srpaulo "Station tried to associate with unknown SSID " 543214501Srpaulo "'%s'", ssid_txt); 544214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 545214501Srpaulo } 546214501Srpaulo 547214501Srpaulo return WLAN_STATUS_SUCCESS; 548214501Srpaulo} 549214501Srpaulo 550214501Srpaulo 551214501Srpaulostatic u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta, 552214501Srpaulo const u8 *wmm_ie, size_t wmm_ie_len) 553214501Srpaulo{ 554214501Srpaulo sta->flags &= ~WLAN_STA_WMM; 555214501Srpaulo if (wmm_ie && hapd->conf->wmm_enabled) { 556214501Srpaulo if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) 557214501Srpaulo hostapd_logger(hapd, sta->addr, 558214501Srpaulo HOSTAPD_MODULE_WPA, 559214501Srpaulo HOSTAPD_LEVEL_DEBUG, 560214501Srpaulo "invalid WMM element in association " 561214501Srpaulo "request"); 562214501Srpaulo else 563214501Srpaulo sta->flags |= WLAN_STA_WMM; 564214501Srpaulo } 565214501Srpaulo return WLAN_STATUS_SUCCESS; 566214501Srpaulo} 567214501Srpaulo 568214501Srpaulo 569214501Srpaulostatic u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta, 570214501Srpaulo struct ieee802_11_elems *elems) 571214501Srpaulo{ 572214501Srpaulo if (!elems->supp_rates) { 573214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 574214501Srpaulo HOSTAPD_LEVEL_DEBUG, 575214501Srpaulo "No supported rates element in AssocReq"); 576214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 577214501Srpaulo } 578214501Srpaulo 579214501Srpaulo if (elems->supp_rates_len > sizeof(sta->supported_rates)) { 580214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 581214501Srpaulo HOSTAPD_LEVEL_DEBUG, 582214501Srpaulo "Invalid supported rates element length %d", 583214501Srpaulo elems->supp_rates_len); 584214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 585214501Srpaulo } 586214501Srpaulo 587214501Srpaulo os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); 588214501Srpaulo os_memcpy(sta->supported_rates, elems->supp_rates, 589214501Srpaulo elems->supp_rates_len); 590214501Srpaulo sta->supported_rates_len = elems->supp_rates_len; 591214501Srpaulo 592214501Srpaulo if (elems->ext_supp_rates) { 593214501Srpaulo if (elems->supp_rates_len + elems->ext_supp_rates_len > 594214501Srpaulo sizeof(sta->supported_rates)) { 595214501Srpaulo hostapd_logger(hapd, sta->addr, 596214501Srpaulo HOSTAPD_MODULE_IEEE80211, 597214501Srpaulo HOSTAPD_LEVEL_DEBUG, 598214501Srpaulo "Invalid supported rates element length" 599214501Srpaulo " %d+%d", elems->supp_rates_len, 600214501Srpaulo elems->ext_supp_rates_len); 601214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 602214501Srpaulo } 603214501Srpaulo 604214501Srpaulo os_memcpy(sta->supported_rates + elems->supp_rates_len, 605214501Srpaulo elems->ext_supp_rates, elems->ext_supp_rates_len); 606214501Srpaulo sta->supported_rates_len += elems->ext_supp_rates_len; 607214501Srpaulo } 608214501Srpaulo 609214501Srpaulo return WLAN_STATUS_SUCCESS; 610214501Srpaulo} 611214501Srpaulo 612214501Srpaulo 613214501Srpaulostatic u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta, 614214501Srpaulo const u8 *ies, size_t ies_len, int reassoc) 615214501Srpaulo{ 616214501Srpaulo struct ieee802_11_elems elems; 617214501Srpaulo u16 resp; 618214501Srpaulo const u8 *wpa_ie; 619214501Srpaulo size_t wpa_ie_len; 620214501Srpaulo 621214501Srpaulo if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) { 622214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 623214501Srpaulo HOSTAPD_LEVEL_INFO, "Station sent an invalid " 624214501Srpaulo "association request"); 625214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 626214501Srpaulo } 627214501Srpaulo 628214501Srpaulo resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len); 629214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 630214501Srpaulo return resp; 631214501Srpaulo resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len); 632214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 633214501Srpaulo return resp; 634214501Srpaulo resp = copy_supp_rates(hapd, sta, &elems); 635214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 636214501Srpaulo return resp; 637214501Srpaulo#ifdef CONFIG_IEEE80211N 638214501Srpaulo resp = copy_sta_ht_capab(sta, elems.ht_capabilities, 639214501Srpaulo elems.ht_capabilities_len); 640214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 641214501Srpaulo return resp; 642214501Srpaulo#endif /* CONFIG_IEEE80211N */ 643214501Srpaulo 644214501Srpaulo if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) { 645214501Srpaulo wpa_ie = elems.rsn_ie; 646214501Srpaulo wpa_ie_len = elems.rsn_ie_len; 647214501Srpaulo } else if ((hapd->conf->wpa & WPA_PROTO_WPA) && 648214501Srpaulo elems.wpa_ie) { 649214501Srpaulo wpa_ie = elems.wpa_ie; 650214501Srpaulo wpa_ie_len = elems.wpa_ie_len; 651214501Srpaulo } else { 652214501Srpaulo wpa_ie = NULL; 653214501Srpaulo wpa_ie_len = 0; 654214501Srpaulo } 655214501Srpaulo 656214501Srpaulo#ifdef CONFIG_WPS 657214501Srpaulo sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); 658214501Srpaulo if (hapd->conf->wps_state && elems.wps_ie) { 659214501Srpaulo wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association " 660214501Srpaulo "Request - assume WPS is used"); 661214501Srpaulo sta->flags |= WLAN_STA_WPS; 662214501Srpaulo wpabuf_free(sta->wps_ie); 663214501Srpaulo sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len, 664214501Srpaulo WPS_IE_VENDOR_TYPE); 665214501Srpaulo wpa_ie = NULL; 666214501Srpaulo wpa_ie_len = 0; 667214501Srpaulo } else if (hapd->conf->wps_state && wpa_ie == NULL) { 668214501Srpaulo wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in " 669214501Srpaulo "(Re)Association Request - possible WPS use"); 670214501Srpaulo sta->flags |= WLAN_STA_MAYBE_WPS; 671214501Srpaulo } else 672214501Srpaulo#endif /* CONFIG_WPS */ 673214501Srpaulo if (hapd->conf->wpa && wpa_ie == NULL) { 674214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 675214501Srpaulo HOSTAPD_LEVEL_INFO, 676214501Srpaulo "No WPA/RSN IE in association request"); 677214501Srpaulo return WLAN_STATUS_INVALID_IE; 678214501Srpaulo } 679214501Srpaulo 680214501Srpaulo if (hapd->conf->wpa && wpa_ie) { 681214501Srpaulo int res; 682214501Srpaulo wpa_ie -= 2; 683214501Srpaulo wpa_ie_len += 2; 684214501Srpaulo if (sta->wpa_sm == NULL) 685214501Srpaulo sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 686214501Srpaulo sta->addr); 687214501Srpaulo if (sta->wpa_sm == NULL) { 688214501Srpaulo wpa_printf(MSG_WARNING, "Failed to initialize WPA " 689214501Srpaulo "state machine"); 690214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 691214501Srpaulo } 692214501Srpaulo res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm, 693214501Srpaulo wpa_ie, wpa_ie_len, 694214501Srpaulo elems.mdie, elems.mdie_len); 695214501Srpaulo if (res == WPA_INVALID_GROUP) 696214501Srpaulo resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID; 697214501Srpaulo else if (res == WPA_INVALID_PAIRWISE) 698214501Srpaulo resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID; 699214501Srpaulo else if (res == WPA_INVALID_AKMP) 700214501Srpaulo resp = WLAN_STATUS_AKMP_NOT_VALID; 701214501Srpaulo else if (res == WPA_ALLOC_FAIL) 702214501Srpaulo resp = WLAN_STATUS_UNSPECIFIED_FAILURE; 703214501Srpaulo#ifdef CONFIG_IEEE80211W 704214501Srpaulo else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) 705214501Srpaulo resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 706214501Srpaulo else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) 707214501Srpaulo resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; 708214501Srpaulo#endif /* CONFIG_IEEE80211W */ 709214501Srpaulo else if (res == WPA_INVALID_MDIE) 710214501Srpaulo resp = WLAN_STATUS_INVALID_MDIE; 711214501Srpaulo else if (res != WPA_IE_OK) 712214501Srpaulo resp = WLAN_STATUS_INVALID_IE; 713214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 714214501Srpaulo return resp; 715214501Srpaulo#ifdef CONFIG_IEEE80211W 716214501Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 717214501Srpaulo sta->sa_query_count > 0) 718214501Srpaulo ap_check_sa_query_timeout(hapd, sta); 719214501Srpaulo if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && 720214501Srpaulo (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { 721214501Srpaulo /* 722214501Srpaulo * STA has already been associated with MFP and SA 723214501Srpaulo * Query timeout has not been reached. Reject the 724214501Srpaulo * association attempt temporarily and start SA Query, 725214501Srpaulo * if one is not pending. 726214501Srpaulo */ 727214501Srpaulo 728214501Srpaulo if (sta->sa_query_count == 0) 729214501Srpaulo ap_sta_start_sa_query(hapd, sta); 730214501Srpaulo 731214501Srpaulo return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; 732214501Srpaulo } 733214501Srpaulo 734214501Srpaulo if (wpa_auth_uses_mfp(sta->wpa_sm)) 735214501Srpaulo sta->flags |= WLAN_STA_MFP; 736214501Srpaulo else 737214501Srpaulo sta->flags &= ~WLAN_STA_MFP; 738214501Srpaulo#endif /* CONFIG_IEEE80211W */ 739214501Srpaulo 740214501Srpaulo#ifdef CONFIG_IEEE80211R 741214501Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) { 742214501Srpaulo if (!reassoc) { 743214501Srpaulo wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried " 744214501Srpaulo "to use association (not " 745214501Srpaulo "re-association) with FT auth_alg", 746214501Srpaulo MAC2STR(sta->addr)); 747214501Srpaulo return WLAN_STATUS_UNSPECIFIED_FAILURE; 748214501Srpaulo } 749214501Srpaulo 750214501Srpaulo resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies, 751214501Srpaulo ies_len); 752214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 753214501Srpaulo return resp; 754214501Srpaulo } 755214501Srpaulo#endif /* CONFIG_IEEE80211R */ 756214501Srpaulo 757214501Srpaulo#ifdef CONFIG_IEEE80211N 758214501Srpaulo if ((sta->flags & WLAN_STA_HT) && 759214501Srpaulo wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { 760214501Srpaulo hostapd_logger(hapd, sta->addr, 761214501Srpaulo HOSTAPD_MODULE_IEEE80211, 762214501Srpaulo HOSTAPD_LEVEL_INFO, 763214501Srpaulo "Station tried to use TKIP with HT " 764214501Srpaulo "association"); 765214501Srpaulo return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; 766214501Srpaulo } 767214501Srpaulo#endif /* CONFIG_IEEE80211N */ 768214501Srpaulo } else 769214501Srpaulo wpa_auth_sta_no_wpa(sta->wpa_sm); 770214501Srpaulo 771214501Srpaulo return WLAN_STATUS_SUCCESS; 772214501Srpaulo} 773214501Srpaulo 774214501Srpaulo 775214501Srpaulostatic void send_deauth(struct hostapd_data *hapd, const u8 *addr, 776214501Srpaulo u16 reason_code) 777214501Srpaulo{ 778214501Srpaulo int send_len; 779214501Srpaulo struct ieee80211_mgmt reply; 780214501Srpaulo 781214501Srpaulo os_memset(&reply, 0, sizeof(reply)); 782214501Srpaulo reply.frame_control = 783214501Srpaulo IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH); 784214501Srpaulo os_memcpy(reply.da, addr, ETH_ALEN); 785214501Srpaulo os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN); 786214501Srpaulo os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN); 787214501Srpaulo 788214501Srpaulo send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth); 789214501Srpaulo reply.u.deauth.reason_code = host_to_le16(reason_code); 790214501Srpaulo 791214501Srpaulo if (hapd->drv.send_mgmt_frame(hapd, &reply, send_len) < 0) 792214501Srpaulo wpa_printf(MSG_INFO, "Failed to send deauth: %s", 793214501Srpaulo strerror(errno)); 794214501Srpaulo} 795214501Srpaulo 796214501Srpaulo 797214501Srpaulostatic void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta, 798214501Srpaulo u16 status_code, int reassoc, const u8 *ies, 799214501Srpaulo size_t ies_len) 800214501Srpaulo{ 801214501Srpaulo int send_len; 802214501Srpaulo u8 buf[sizeof(struct ieee80211_mgmt) + 1024]; 803214501Srpaulo struct ieee80211_mgmt *reply; 804214501Srpaulo u8 *p; 805214501Srpaulo 806214501Srpaulo os_memset(buf, 0, sizeof(buf)); 807214501Srpaulo reply = (struct ieee80211_mgmt *) buf; 808214501Srpaulo reply->frame_control = 809214501Srpaulo IEEE80211_FC(WLAN_FC_TYPE_MGMT, 810214501Srpaulo (reassoc ? WLAN_FC_STYPE_REASSOC_RESP : 811214501Srpaulo WLAN_FC_STYPE_ASSOC_RESP)); 812214501Srpaulo os_memcpy(reply->da, sta->addr, ETH_ALEN); 813214501Srpaulo os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN); 814214501Srpaulo os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN); 815214501Srpaulo 816214501Srpaulo send_len = IEEE80211_HDRLEN; 817214501Srpaulo send_len += sizeof(reply->u.assoc_resp); 818214501Srpaulo reply->u.assoc_resp.capab_info = 819214501Srpaulo host_to_le16(hostapd_own_capab_info(hapd, sta, 0)); 820214501Srpaulo reply->u.assoc_resp.status_code = host_to_le16(status_code); 821214501Srpaulo reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0) 822214501Srpaulo | BIT(14) | BIT(15)); 823214501Srpaulo /* Supported rates */ 824214501Srpaulo p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable); 825214501Srpaulo /* Extended supported rates */ 826214501Srpaulo p = hostapd_eid_ext_supp_rates(hapd, p); 827214501Srpaulo 828214501Srpaulo#ifdef CONFIG_IEEE80211R 829214501Srpaulo if (status_code == WLAN_STATUS_SUCCESS) { 830214501Srpaulo /* IEEE 802.11r: Mobility Domain Information, Fast BSS 831214501Srpaulo * Transition Information, RSN, [RIC Response] */ 832214501Srpaulo p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p, 833214501Srpaulo buf + sizeof(buf) - p, 834214501Srpaulo sta->auth_alg, ies, ies_len); 835214501Srpaulo } 836214501Srpaulo#endif /* CONFIG_IEEE80211R */ 837214501Srpaulo 838214501Srpaulo#ifdef CONFIG_IEEE80211W 839214501Srpaulo if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY) 840214501Srpaulo p = hostapd_eid_assoc_comeback_time(hapd, sta, p); 841214501Srpaulo#endif /* CONFIG_IEEE80211W */ 842214501Srpaulo 843214501Srpaulo#ifdef CONFIG_IEEE80211N 844214501Srpaulo p = hostapd_eid_ht_capabilities(hapd, p); 845214501Srpaulo p = hostapd_eid_ht_operation(hapd, p); 846214501Srpaulo#endif /* CONFIG_IEEE80211N */ 847214501Srpaulo 848214501Srpaulo if (sta->flags & WLAN_STA_WMM) 849214501Srpaulo p = hostapd_eid_wmm(hapd, p); 850214501Srpaulo 851214501Srpaulo#ifdef CONFIG_WPS 852214501Srpaulo if (sta->flags & WLAN_STA_WPS) { 853214501Srpaulo struct wpabuf *wps = wps_build_assoc_resp_ie(); 854214501Srpaulo if (wps) { 855214501Srpaulo os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps)); 856214501Srpaulo p += wpabuf_len(wps); 857214501Srpaulo wpabuf_free(wps); 858214501Srpaulo } 859214501Srpaulo } 860214501Srpaulo#endif /* CONFIG_WPS */ 861214501Srpaulo 862214501Srpaulo send_len += p - reply->u.assoc_resp.variable; 863214501Srpaulo 864214501Srpaulo if (hapd->drv.send_mgmt_frame(hapd, reply, send_len) < 0) 865214501Srpaulo wpa_printf(MSG_INFO, "Failed to send assoc resp: %s", 866214501Srpaulo strerror(errno)); 867214501Srpaulo} 868214501Srpaulo 869214501Srpaulo 870214501Srpaulostatic void handle_assoc(struct hostapd_data *hapd, 871214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len, 872214501Srpaulo int reassoc) 873214501Srpaulo{ 874214501Srpaulo u16 capab_info, listen_interval; 875214501Srpaulo u16 resp = WLAN_STATUS_SUCCESS; 876214501Srpaulo const u8 *pos; 877214501Srpaulo int left, i; 878214501Srpaulo struct sta_info *sta; 879214501Srpaulo 880214501Srpaulo if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : 881214501Srpaulo sizeof(mgmt->u.assoc_req))) { 882214501Srpaulo printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)" 883214501Srpaulo "\n", reassoc, (unsigned long) len); 884214501Srpaulo return; 885214501Srpaulo } 886214501Srpaulo 887214501Srpaulo if (reassoc) { 888214501Srpaulo capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info); 889214501Srpaulo listen_interval = le_to_host16( 890214501Srpaulo mgmt->u.reassoc_req.listen_interval); 891214501Srpaulo wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR 892214501Srpaulo " capab_info=0x%02x listen_interval=%d current_ap=" 893214501Srpaulo MACSTR, 894214501Srpaulo MAC2STR(mgmt->sa), capab_info, listen_interval, 895214501Srpaulo MAC2STR(mgmt->u.reassoc_req.current_ap)); 896214501Srpaulo left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req)); 897214501Srpaulo pos = mgmt->u.reassoc_req.variable; 898214501Srpaulo } else { 899214501Srpaulo capab_info = le_to_host16(mgmt->u.assoc_req.capab_info); 900214501Srpaulo listen_interval = le_to_host16( 901214501Srpaulo mgmt->u.assoc_req.listen_interval); 902214501Srpaulo wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR 903214501Srpaulo " capab_info=0x%02x listen_interval=%d", 904214501Srpaulo MAC2STR(mgmt->sa), capab_info, listen_interval); 905214501Srpaulo left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req)); 906214501Srpaulo pos = mgmt->u.assoc_req.variable; 907214501Srpaulo } 908214501Srpaulo 909214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 910214501Srpaulo#ifdef CONFIG_IEEE80211R 911214501Srpaulo if (sta && sta->auth_alg == WLAN_AUTH_FT && 912214501Srpaulo (sta->flags & WLAN_STA_AUTH) == 0) { 913214501Srpaulo wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " 914214501Srpaulo "prior to authentication since it is using " 915214501Srpaulo "over-the-DS FT", MAC2STR(mgmt->sa)); 916214501Srpaulo } else 917214501Srpaulo#endif /* CONFIG_IEEE80211R */ 918214501Srpaulo if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) { 919214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 920214501Srpaulo HOSTAPD_LEVEL_INFO, "Station tried to " 921214501Srpaulo "associate before authentication " 922214501Srpaulo "(aid=%d flags=0x%x)", 923214501Srpaulo sta ? sta->aid : -1, 924214501Srpaulo sta ? sta->flags : 0); 925214501Srpaulo send_deauth(hapd, mgmt->sa, 926214501Srpaulo WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); 927214501Srpaulo return; 928214501Srpaulo } 929214501Srpaulo 930214501Srpaulo if (hapd->tkip_countermeasures) { 931214501Srpaulo resp = WLAN_REASON_MICHAEL_MIC_FAILURE; 932214501Srpaulo goto fail; 933214501Srpaulo } 934214501Srpaulo 935214501Srpaulo if (listen_interval > hapd->conf->max_listen_interval) { 936214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 937214501Srpaulo HOSTAPD_LEVEL_DEBUG, 938214501Srpaulo "Too large Listen Interval (%d)", 939214501Srpaulo listen_interval); 940214501Srpaulo resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE; 941214501Srpaulo goto fail; 942214501Srpaulo } 943214501Srpaulo 944214501Srpaulo /* followed by SSID and Supported rates; and HT capabilities if 802.11n 945214501Srpaulo * is used */ 946214501Srpaulo resp = check_assoc_ies(hapd, sta, pos, left, reassoc); 947214501Srpaulo if (resp != WLAN_STATUS_SUCCESS) 948214501Srpaulo goto fail; 949214501Srpaulo 950214501Srpaulo if (hostapd_get_aid(hapd, sta) < 0) { 951214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 952214501Srpaulo HOSTAPD_LEVEL_INFO, "No room for more AIDs"); 953214501Srpaulo resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; 954214501Srpaulo goto fail; 955214501Srpaulo } 956214501Srpaulo 957214501Srpaulo sta->capability = capab_info; 958214501Srpaulo sta->listen_interval = listen_interval; 959214501Srpaulo 960214501Srpaulo if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) 961214501Srpaulo sta->flags |= WLAN_STA_NONERP; 962214501Srpaulo for (i = 0; i < sta->supported_rates_len; i++) { 963214501Srpaulo if ((sta->supported_rates[i] & 0x7f) > 22) { 964214501Srpaulo sta->flags &= ~WLAN_STA_NONERP; 965214501Srpaulo break; 966214501Srpaulo } 967214501Srpaulo } 968214501Srpaulo if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) { 969214501Srpaulo sta->nonerp_set = 1; 970214501Srpaulo hapd->iface->num_sta_non_erp++; 971214501Srpaulo if (hapd->iface->num_sta_non_erp == 1) 972214501Srpaulo ieee802_11_set_beacons(hapd->iface); 973214501Srpaulo } 974214501Srpaulo 975214501Srpaulo if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) && 976214501Srpaulo !sta->no_short_slot_time_set) { 977214501Srpaulo sta->no_short_slot_time_set = 1; 978214501Srpaulo hapd->iface->num_sta_no_short_slot_time++; 979214501Srpaulo if (hapd->iface->current_mode->mode == 980214501Srpaulo HOSTAPD_MODE_IEEE80211G && 981214501Srpaulo hapd->iface->num_sta_no_short_slot_time == 1) 982214501Srpaulo ieee802_11_set_beacons(hapd->iface); 983214501Srpaulo } 984214501Srpaulo 985214501Srpaulo if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) 986214501Srpaulo sta->flags |= WLAN_STA_SHORT_PREAMBLE; 987214501Srpaulo else 988214501Srpaulo sta->flags &= ~WLAN_STA_SHORT_PREAMBLE; 989214501Srpaulo 990214501Srpaulo if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) && 991214501Srpaulo !sta->no_short_preamble_set) { 992214501Srpaulo sta->no_short_preamble_set = 1; 993214501Srpaulo hapd->iface->num_sta_no_short_preamble++; 994214501Srpaulo if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G 995214501Srpaulo && hapd->iface->num_sta_no_short_preamble == 1) 996214501Srpaulo ieee802_11_set_beacons(hapd->iface); 997214501Srpaulo } 998214501Srpaulo 999214501Srpaulo#ifdef CONFIG_IEEE80211N 1000214501Srpaulo update_ht_state(hapd, sta); 1001214501Srpaulo#endif /* CONFIG_IEEE80211N */ 1002214501Srpaulo 1003214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1004214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1005214501Srpaulo "association OK (aid %d)", sta->aid); 1006214501Srpaulo /* Station will be marked associated, after it acknowledges AssocResp 1007214501Srpaulo */ 1008214501Srpaulo 1009214501Srpaulo#ifdef CONFIG_IEEE80211W 1010214501Srpaulo if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { 1011214501Srpaulo wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " 1012214501Srpaulo "SA Query procedure", reassoc ? "re" : ""); 1013214501Srpaulo /* TODO: Send a protected Disassociate frame to the STA using 1014214501Srpaulo * the old key and Reason Code "Previous Authentication no 1015214501Srpaulo * longer valid". Make sure this is only sent protected since 1016214501Srpaulo * unprotected frame would be received by the STA that is now 1017214501Srpaulo * trying to associate. 1018214501Srpaulo */ 1019214501Srpaulo } 1020214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1021214501Srpaulo 1022214501Srpaulo if (reassoc) { 1023214501Srpaulo os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap, 1024214501Srpaulo ETH_ALEN); 1025214501Srpaulo } 1026214501Srpaulo 1027214501Srpaulo if (sta->last_assoc_req) 1028214501Srpaulo os_free(sta->last_assoc_req); 1029214501Srpaulo sta->last_assoc_req = os_malloc(len); 1030214501Srpaulo if (sta->last_assoc_req) 1031214501Srpaulo os_memcpy(sta->last_assoc_req, mgmt, len); 1032214501Srpaulo 1033214501Srpaulo /* Make sure that the previously registered inactivity timer will not 1034214501Srpaulo * remove the STA immediately. */ 1035214501Srpaulo sta->timeout_next = STA_NULLFUNC; 1036214501Srpaulo 1037214501Srpaulo fail: 1038214501Srpaulo send_assoc_resp(hapd, sta, resp, reassoc, pos, left); 1039214501Srpaulo} 1040214501Srpaulo 1041214501Srpaulo 1042214501Srpaulostatic void handle_disassoc(struct hostapd_data *hapd, 1043214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 1044214501Srpaulo{ 1045214501Srpaulo struct sta_info *sta; 1046214501Srpaulo 1047214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { 1048214501Srpaulo printf("handle_disassoc - too short payload (len=%lu)\n", 1049214501Srpaulo (unsigned long) len); 1050214501Srpaulo return; 1051214501Srpaulo } 1052214501Srpaulo 1053214501Srpaulo wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", 1054214501Srpaulo MAC2STR(mgmt->sa), 1055214501Srpaulo le_to_host16(mgmt->u.disassoc.reason_code)); 1056214501Srpaulo 1057214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1058214501Srpaulo if (sta == NULL) { 1059214501Srpaulo printf("Station " MACSTR " trying to disassociate, but it " 1060214501Srpaulo "is not associated.\n", MAC2STR(mgmt->sa)); 1061214501Srpaulo return; 1062214501Srpaulo } 1063214501Srpaulo 1064214501Srpaulo sta->flags &= ~WLAN_STA_ASSOC; 1065214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, 1066214501Srpaulo MAC2STR(sta->addr)); 1067214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC); 1068214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1069214501Srpaulo HOSTAPD_LEVEL_INFO, "disassociated"); 1070214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1071214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 1072214501Srpaulo /* Stop Accounting and IEEE 802.1X sessions, but leave the STA 1073214501Srpaulo * authenticated. */ 1074214501Srpaulo accounting_sta_stop(hapd, sta); 1075214501Srpaulo ieee802_1x_free_station(sta); 1076214501Srpaulo hapd->drv.sta_remove(hapd, sta->addr); 1077214501Srpaulo 1078214501Srpaulo if (sta->timeout_next == STA_NULLFUNC || 1079214501Srpaulo sta->timeout_next == STA_DISASSOC) { 1080214501Srpaulo sta->timeout_next = STA_DEAUTH; 1081214501Srpaulo eloop_cancel_timeout(ap_handle_timer, hapd, sta); 1082214501Srpaulo eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, 1083214501Srpaulo hapd, sta); 1084214501Srpaulo } 1085214501Srpaulo 1086214501Srpaulo mlme_disassociate_indication( 1087214501Srpaulo hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code)); 1088214501Srpaulo} 1089214501Srpaulo 1090214501Srpaulo 1091214501Srpaulostatic void handle_deauth(struct hostapd_data *hapd, 1092214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 1093214501Srpaulo{ 1094214501Srpaulo struct sta_info *sta; 1095214501Srpaulo 1096214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { 1097214501Srpaulo printf("handle_deauth - too short payload (len=%lu)\n", 1098214501Srpaulo (unsigned long) len); 1099214501Srpaulo return; 1100214501Srpaulo } 1101214501Srpaulo 1102214501Srpaulo wpa_printf(MSG_DEBUG, "deauthentication: STA=" MACSTR 1103214501Srpaulo " reason_code=%d", 1104214501Srpaulo MAC2STR(mgmt->sa), 1105214501Srpaulo le_to_host16(mgmt->u.deauth.reason_code)); 1106214501Srpaulo 1107214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1108214501Srpaulo if (sta == NULL) { 1109214501Srpaulo printf("Station " MACSTR " trying to deauthenticate, but it " 1110214501Srpaulo "is not authenticated.\n", MAC2STR(mgmt->sa)); 1111214501Srpaulo return; 1112214501Srpaulo } 1113214501Srpaulo 1114214501Srpaulo sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); 1115214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR, 1116214501Srpaulo MAC2STR(sta->addr)); 1117214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH); 1118214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1119214501Srpaulo HOSTAPD_LEVEL_DEBUG, "deauthenticated"); 1120214501Srpaulo mlme_deauthenticate_indication( 1121214501Srpaulo hapd, sta, le_to_host16(mgmt->u.deauth.reason_code)); 1122214501Srpaulo sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; 1123214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); 1124214501Srpaulo ap_free_sta(hapd, sta); 1125214501Srpaulo} 1126214501Srpaulo 1127214501Srpaulo 1128214501Srpaulostatic void handle_beacon(struct hostapd_data *hapd, 1129214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len, 1130214501Srpaulo struct hostapd_frame_info *fi) 1131214501Srpaulo{ 1132214501Srpaulo struct ieee802_11_elems elems; 1133214501Srpaulo 1134214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) { 1135214501Srpaulo printf("handle_beacon - too short payload (len=%lu)\n", 1136214501Srpaulo (unsigned long) len); 1137214501Srpaulo return; 1138214501Srpaulo } 1139214501Srpaulo 1140214501Srpaulo (void) ieee802_11_parse_elems(mgmt->u.beacon.variable, 1141214501Srpaulo len - (IEEE80211_HDRLEN + 1142214501Srpaulo sizeof(mgmt->u.beacon)), &elems, 1143214501Srpaulo 0); 1144214501Srpaulo 1145214501Srpaulo ap_list_process_beacon(hapd->iface, mgmt, &elems, fi); 1146214501Srpaulo} 1147214501Srpaulo 1148214501Srpaulo 1149214501Srpaulo#ifdef CONFIG_IEEE80211W 1150214501Srpaulo 1151214501Srpaulo/* MLME-SAQuery.request */ 1152214501Srpaulovoid ieee802_11_send_sa_query_req(struct hostapd_data *hapd, 1153214501Srpaulo const u8 *addr, const u8 *trans_id) 1154214501Srpaulo{ 1155214501Srpaulo struct ieee80211_mgmt mgmt; 1156214501Srpaulo u8 *end; 1157214501Srpaulo 1158214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to " 1159214501Srpaulo MACSTR, MAC2STR(addr)); 1160214501Srpaulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 1161214501Srpaulo trans_id, WLAN_SA_QUERY_TR_ID_LEN); 1162214501Srpaulo 1163214501Srpaulo os_memset(&mgmt, 0, sizeof(mgmt)); 1164214501Srpaulo mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1165214501Srpaulo WLAN_FC_STYPE_ACTION); 1166214501Srpaulo os_memcpy(mgmt.da, addr, ETH_ALEN); 1167214501Srpaulo os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN); 1168214501Srpaulo os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN); 1169214501Srpaulo mgmt.u.action.category = WLAN_ACTION_SA_QUERY; 1170214501Srpaulo mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; 1171214501Srpaulo os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, 1172214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN); 1173214501Srpaulo end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; 1174214501Srpaulo if (hapd->drv.send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt) < 0) 1175214501Srpaulo perror("ieee802_11_send_sa_query_req: send"); 1176214501Srpaulo} 1177214501Srpaulo 1178214501Srpaulo 1179214501Srpaulostatic void hostapd_sa_query_request(struct hostapd_data *hapd, 1180214501Srpaulo const struct ieee80211_mgmt *mgmt) 1181214501Srpaulo{ 1182214501Srpaulo struct sta_info *sta; 1183214501Srpaulo struct ieee80211_mgmt resp; 1184214501Srpaulo u8 *end; 1185214501Srpaulo 1186214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from " 1187214501Srpaulo MACSTR, MAC2STR(mgmt->sa)); 1188214501Srpaulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 1189214501Srpaulo mgmt->u.action.u.sa_query_resp.trans_id, 1190214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN); 1191214501Srpaulo 1192214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1193214501Srpaulo if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { 1194214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request " 1195214501Srpaulo "from unassociated STA " MACSTR, MAC2STR(mgmt->sa)); 1196214501Srpaulo return; 1197214501Srpaulo } 1198214501Srpaulo 1199214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to " 1200214501Srpaulo MACSTR, MAC2STR(mgmt->sa)); 1201214501Srpaulo 1202214501Srpaulo os_memset(&resp, 0, sizeof(resp)); 1203214501Srpaulo resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1204214501Srpaulo WLAN_FC_STYPE_ACTION); 1205214501Srpaulo os_memcpy(resp.da, mgmt->sa, ETH_ALEN); 1206214501Srpaulo os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN); 1207214501Srpaulo os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN); 1208214501Srpaulo resp.u.action.category = WLAN_ACTION_SA_QUERY; 1209214501Srpaulo resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE; 1210214501Srpaulo os_memcpy(resp.u.action.u.sa_query_req.trans_id, 1211214501Srpaulo mgmt->u.action.u.sa_query_req.trans_id, 1212214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN); 1213214501Srpaulo end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; 1214214501Srpaulo if (hapd->drv.send_mgmt_frame(hapd, &resp, end - (u8 *) &resp) < 0) 1215214501Srpaulo perror("hostapd_sa_query_request: send"); 1216214501Srpaulo} 1217214501Srpaulo 1218214501Srpaulo 1219214501Srpaulostatic void hostapd_sa_query_action(struct hostapd_data *hapd, 1220214501Srpaulo const struct ieee80211_mgmt *mgmt, 1221214501Srpaulo size_t len) 1222214501Srpaulo{ 1223214501Srpaulo struct sta_info *sta; 1224214501Srpaulo const u8 *end; 1225214501Srpaulo int i; 1226214501Srpaulo 1227214501Srpaulo end = mgmt->u.action.u.sa_query_resp.trans_id + 1228214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN; 1229214501Srpaulo if (((u8 *) mgmt) + len < end) { 1230214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " 1231214501Srpaulo "frame (len=%lu)", (unsigned long) len); 1232214501Srpaulo return; 1233214501Srpaulo } 1234214501Srpaulo 1235214501Srpaulo if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) { 1236214501Srpaulo hostapd_sa_query_request(hapd, mgmt); 1237214501Srpaulo return; 1238214501Srpaulo } 1239214501Srpaulo 1240214501Srpaulo if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { 1241214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " 1242214501Srpaulo "Action %d", mgmt->u.action.u.sa_query_resp.action); 1243214501Srpaulo return; 1244214501Srpaulo } 1245214501Srpaulo 1246214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from " 1247214501Srpaulo MACSTR, MAC2STR(mgmt->sa)); 1248214501Srpaulo wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID", 1249214501Srpaulo mgmt->u.action.u.sa_query_resp.trans_id, 1250214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN); 1251214501Srpaulo 1252214501Srpaulo /* MLME-SAQuery.confirm */ 1253214501Srpaulo 1254214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1255214501Srpaulo if (sta == NULL || sta->sa_query_trans_id == NULL) { 1256214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " 1257214501Srpaulo "pending SA Query request found"); 1258214501Srpaulo return; 1259214501Srpaulo } 1260214501Srpaulo 1261214501Srpaulo for (i = 0; i < sta->sa_query_count; i++) { 1262214501Srpaulo if (os_memcmp(sta->sa_query_trans_id + 1263214501Srpaulo i * WLAN_SA_QUERY_TR_ID_LEN, 1264214501Srpaulo mgmt->u.action.u.sa_query_resp.trans_id, 1265214501Srpaulo WLAN_SA_QUERY_TR_ID_LEN) == 0) 1266214501Srpaulo break; 1267214501Srpaulo } 1268214501Srpaulo 1269214501Srpaulo if (i >= sta->sa_query_count) { 1270214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " 1271214501Srpaulo "transaction identifier found"); 1272214501Srpaulo return; 1273214501Srpaulo } 1274214501Srpaulo 1275214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1276214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1277214501Srpaulo "Reply to pending SA Query received"); 1278214501Srpaulo ap_sta_stop_sa_query(hapd, sta); 1279214501Srpaulo} 1280214501Srpaulo 1281214501Srpaulo 1282214501Srpaulostatic int robust_action_frame(u8 category) 1283214501Srpaulo{ 1284214501Srpaulo return category != WLAN_ACTION_PUBLIC && 1285214501Srpaulo category != WLAN_ACTION_HT; 1286214501Srpaulo} 1287214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1288214501Srpaulo 1289214501Srpaulo 1290214501Srpaulostatic void handle_action(struct hostapd_data *hapd, 1291214501Srpaulo const struct ieee80211_mgmt *mgmt, size_t len) 1292214501Srpaulo{ 1293214501Srpaulo struct sta_info *sta; 1294214501Srpaulo 1295214501Srpaulo if (len < IEEE80211_HDRLEN + 1) { 1296214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 1297214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1298214501Srpaulo "handle_action - too short payload (len=%lu)", 1299214501Srpaulo (unsigned long) len); 1300214501Srpaulo return; 1301214501Srpaulo } 1302214501Srpaulo 1303214501Srpaulo sta = ap_get_sta(hapd, mgmt->sa); 1304214501Srpaulo#ifdef CONFIG_IEEE80211W 1305214501Srpaulo if (sta && (sta->flags & WLAN_STA_MFP) && 1306214501Srpaulo !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) && 1307214501Srpaulo robust_action_frame(mgmt->u.action.category))) { 1308214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 1309214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1310214501Srpaulo "Dropped unprotected Robust Action frame from " 1311214501Srpaulo "an MFP STA"); 1312214501Srpaulo return; 1313214501Srpaulo } 1314214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1315214501Srpaulo 1316214501Srpaulo switch (mgmt->u.action.category) { 1317214501Srpaulo#ifdef CONFIG_IEEE80211R 1318214501Srpaulo case WLAN_ACTION_FT: 1319214501Srpaulo { 1320214501Srpaulo if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) { 1321214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action " 1322214501Srpaulo "frame from unassociated STA " MACSTR, 1323214501Srpaulo MAC2STR(mgmt->sa)); 1324214501Srpaulo return; 1325214501Srpaulo } 1326214501Srpaulo 1327214501Srpaulo if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action, 1328214501Srpaulo len - IEEE80211_HDRLEN)) 1329214501Srpaulo break; 1330214501Srpaulo 1331214501Srpaulo return; 1332214501Srpaulo } 1333214501Srpaulo#endif /* CONFIG_IEEE80211R */ 1334214501Srpaulo case WLAN_ACTION_WMM: 1335214501Srpaulo hostapd_wmm_action(hapd, mgmt, len); 1336214501Srpaulo return; 1337214501Srpaulo#ifdef CONFIG_IEEE80211W 1338214501Srpaulo case WLAN_ACTION_SA_QUERY: 1339214501Srpaulo hostapd_sa_query_action(hapd, mgmt, len); 1340214501Srpaulo return; 1341214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1342214501Srpaulo case WLAN_ACTION_PUBLIC: 1343214501Srpaulo if (hapd->public_action_cb) { 1344214501Srpaulo hapd->public_action_cb(hapd->public_action_cb_ctx, 1345214501Srpaulo (u8 *) mgmt, len, 1346214501Srpaulo hapd->iface->freq); 1347214501Srpaulo return; 1348214501Srpaulo } 1349214501Srpaulo break; 1350214501Srpaulo } 1351214501Srpaulo 1352214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 1353214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1354214501Srpaulo "handle_action - unknown action category %d or invalid " 1355214501Srpaulo "frame", 1356214501Srpaulo mgmt->u.action.category); 1357214501Srpaulo if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) && 1358214501Srpaulo !(mgmt->sa[0] & 0x01)) { 1359214501Srpaulo struct ieee80211_mgmt *resp; 1360214501Srpaulo 1361214501Srpaulo /* 1362214501Srpaulo * IEEE 802.11-REVma/D9.0 - 7.3.1.11 1363214501Srpaulo * Return the Action frame to the source without change 1364214501Srpaulo * except that MSB of the Category set to 1. 1365214501Srpaulo */ 1366214501Srpaulo wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action " 1367214501Srpaulo "frame back to sender"); 1368214501Srpaulo resp = os_malloc(len); 1369214501Srpaulo if (resp == NULL) 1370214501Srpaulo return; 1371214501Srpaulo os_memcpy(resp, mgmt, len); 1372214501Srpaulo os_memcpy(resp->da, resp->sa, ETH_ALEN); 1373214501Srpaulo os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN); 1374214501Srpaulo os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN); 1375214501Srpaulo resp->u.action.category |= 0x80; 1376214501Srpaulo 1377214501Srpaulo hapd->drv.send_mgmt_frame(hapd, resp, len); 1378214501Srpaulo os_free(resp); 1379214501Srpaulo } 1380214501Srpaulo} 1381214501Srpaulo 1382214501Srpaulo 1383214501Srpaulo/** 1384214501Srpaulo * ieee802_11_mgmt - process incoming IEEE 802.11 management frames 1385214501Srpaulo * @hapd: hostapd BSS data structure (the BSS to which the management frame was 1386214501Srpaulo * sent to) 1387214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header) 1388214501Srpaulo * @len: length of frame data in octets 1389214501Srpaulo * @fi: meta data about received frame (signal level, etc.) 1390214501Srpaulo * 1391214501Srpaulo * Process all incoming IEEE 802.11 management frames. This will be called for 1392214501Srpaulo * each frame received from the kernel driver through wlan#ap interface. In 1393214501Srpaulo * addition, it can be called to re-inserted pending frames (e.g., when using 1394214501Srpaulo * external RADIUS server as an MAC ACL). 1395214501Srpaulo */ 1396214501Srpaulovoid ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, 1397214501Srpaulo struct hostapd_frame_info *fi) 1398214501Srpaulo{ 1399214501Srpaulo struct ieee80211_mgmt *mgmt; 1400214501Srpaulo int broadcast; 1401214501Srpaulo u16 fc, stype; 1402214501Srpaulo 1403214501Srpaulo mgmt = (struct ieee80211_mgmt *) buf; 1404214501Srpaulo fc = le_to_host16(mgmt->frame_control); 1405214501Srpaulo stype = WLAN_FC_GET_STYPE(fc); 1406214501Srpaulo 1407214501Srpaulo if (stype == WLAN_FC_STYPE_BEACON) { 1408214501Srpaulo handle_beacon(hapd, mgmt, len, fi); 1409214501Srpaulo return; 1410214501Srpaulo } 1411214501Srpaulo 1412214501Srpaulo broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff && 1413214501Srpaulo mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff && 1414214501Srpaulo mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff; 1415214501Srpaulo 1416214501Srpaulo if (!broadcast && 1417214501Srpaulo os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) { 1418214501Srpaulo printf("MGMT: BSSID=" MACSTR " not our address\n", 1419214501Srpaulo MAC2STR(mgmt->bssid)); 1420214501Srpaulo return; 1421214501Srpaulo } 1422214501Srpaulo 1423214501Srpaulo 1424214501Srpaulo if (stype == WLAN_FC_STYPE_PROBE_REQ) { 1425214501Srpaulo handle_probe_req(hapd, mgmt, len); 1426214501Srpaulo return; 1427214501Srpaulo } 1428214501Srpaulo 1429214501Srpaulo if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) { 1430214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 1431214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1432214501Srpaulo "MGMT: DA=" MACSTR " not our address", 1433214501Srpaulo MAC2STR(mgmt->da)); 1434214501Srpaulo return; 1435214501Srpaulo } 1436214501Srpaulo 1437214501Srpaulo switch (stype) { 1438214501Srpaulo case WLAN_FC_STYPE_AUTH: 1439214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::auth"); 1440214501Srpaulo handle_auth(hapd, mgmt, len); 1441214501Srpaulo break; 1442214501Srpaulo case WLAN_FC_STYPE_ASSOC_REQ: 1443214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); 1444214501Srpaulo handle_assoc(hapd, mgmt, len, 0); 1445214501Srpaulo break; 1446214501Srpaulo case WLAN_FC_STYPE_REASSOC_REQ: 1447214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); 1448214501Srpaulo handle_assoc(hapd, mgmt, len, 1); 1449214501Srpaulo break; 1450214501Srpaulo case WLAN_FC_STYPE_DISASSOC: 1451214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::disassoc"); 1452214501Srpaulo handle_disassoc(hapd, mgmt, len); 1453214501Srpaulo break; 1454214501Srpaulo case WLAN_FC_STYPE_DEAUTH: 1455214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::deauth"); 1456214501Srpaulo handle_deauth(hapd, mgmt, len); 1457214501Srpaulo break; 1458214501Srpaulo case WLAN_FC_STYPE_ACTION: 1459214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::action"); 1460214501Srpaulo handle_action(hapd, mgmt, len); 1461214501Srpaulo break; 1462214501Srpaulo default: 1463214501Srpaulo hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, 1464214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1465214501Srpaulo "unknown mgmt frame subtype %d", stype); 1466214501Srpaulo break; 1467214501Srpaulo } 1468214501Srpaulo} 1469214501Srpaulo 1470214501Srpaulo 1471214501Srpaulostatic void handle_auth_cb(struct hostapd_data *hapd, 1472214501Srpaulo const struct ieee80211_mgmt *mgmt, 1473214501Srpaulo size_t len, int ok) 1474214501Srpaulo{ 1475214501Srpaulo u16 auth_alg, auth_transaction, status_code; 1476214501Srpaulo struct sta_info *sta; 1477214501Srpaulo 1478214501Srpaulo if (!ok) { 1479214501Srpaulo hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 1480214501Srpaulo HOSTAPD_LEVEL_NOTICE, 1481214501Srpaulo "did not acknowledge authentication response"); 1482214501Srpaulo return; 1483214501Srpaulo } 1484214501Srpaulo 1485214501Srpaulo if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { 1486214501Srpaulo printf("handle_auth_cb - too short payload (len=%lu)\n", 1487214501Srpaulo (unsigned long) len); 1488214501Srpaulo return; 1489214501Srpaulo } 1490214501Srpaulo 1491214501Srpaulo auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 1492214501Srpaulo auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 1493214501Srpaulo status_code = le_to_host16(mgmt->u.auth.status_code); 1494214501Srpaulo 1495214501Srpaulo sta = ap_get_sta(hapd, mgmt->da); 1496214501Srpaulo if (!sta) { 1497214501Srpaulo printf("handle_auth_cb: STA " MACSTR " not found\n", 1498214501Srpaulo MAC2STR(mgmt->da)); 1499214501Srpaulo return; 1500214501Srpaulo } 1501214501Srpaulo 1502214501Srpaulo if (status_code == WLAN_STATUS_SUCCESS && 1503214501Srpaulo ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) || 1504214501Srpaulo (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) { 1505214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1506214501Srpaulo HOSTAPD_LEVEL_INFO, "authenticated"); 1507214501Srpaulo sta->flags |= WLAN_STA_AUTH; 1508214501Srpaulo } 1509214501Srpaulo} 1510214501Srpaulo 1511214501Srpaulo 1512214501Srpaulostatic void handle_assoc_cb(struct hostapd_data *hapd, 1513214501Srpaulo const struct ieee80211_mgmt *mgmt, 1514214501Srpaulo size_t len, int reassoc, int ok) 1515214501Srpaulo{ 1516214501Srpaulo u16 status; 1517214501Srpaulo struct sta_info *sta; 1518214501Srpaulo int new_assoc = 1; 1519214501Srpaulo struct ieee80211_ht_capabilities ht_cap; 1520214501Srpaulo 1521214501Srpaulo if (!ok) { 1522214501Srpaulo hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, 1523214501Srpaulo HOSTAPD_LEVEL_DEBUG, 1524214501Srpaulo "did not acknowledge association response"); 1525214501Srpaulo return; 1526214501Srpaulo } 1527214501Srpaulo 1528214501Srpaulo if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) : 1529214501Srpaulo sizeof(mgmt->u.assoc_resp))) { 1530214501Srpaulo printf("handle_assoc_cb(reassoc=%d) - too short payload " 1531214501Srpaulo "(len=%lu)\n", reassoc, (unsigned long) len); 1532214501Srpaulo return; 1533214501Srpaulo } 1534214501Srpaulo 1535214501Srpaulo if (reassoc) 1536214501Srpaulo status = le_to_host16(mgmt->u.reassoc_resp.status_code); 1537214501Srpaulo else 1538214501Srpaulo status = le_to_host16(mgmt->u.assoc_resp.status_code); 1539214501Srpaulo 1540214501Srpaulo sta = ap_get_sta(hapd, mgmt->da); 1541214501Srpaulo if (!sta) { 1542214501Srpaulo printf("handle_assoc_cb: STA " MACSTR " not found\n", 1543214501Srpaulo MAC2STR(mgmt->da)); 1544214501Srpaulo return; 1545214501Srpaulo } 1546214501Srpaulo 1547214501Srpaulo if (status != WLAN_STATUS_SUCCESS) 1548214501Srpaulo goto fail; 1549214501Srpaulo 1550214501Srpaulo /* Stop previous accounting session, if one is started, and allocate 1551214501Srpaulo * new session id for the new session. */ 1552214501Srpaulo accounting_sta_stop(hapd, sta); 1553214501Srpaulo 1554214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1555214501Srpaulo HOSTAPD_LEVEL_INFO, 1556214501Srpaulo "associated (aid %d)", 1557214501Srpaulo sta->aid); 1558214501Srpaulo 1559214501Srpaulo if (sta->flags & WLAN_STA_ASSOC) 1560214501Srpaulo new_assoc = 0; 1561214501Srpaulo sta->flags |= WLAN_STA_ASSOC; 1562214501Srpaulo if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) || 1563214501Srpaulo sta->auth_alg == WLAN_AUTH_FT) { 1564214501Srpaulo /* 1565214501Srpaulo * Open, static WEP, or FT protocol; no separate authorization 1566214501Srpaulo * step. 1567214501Srpaulo */ 1568214501Srpaulo sta->flags |= WLAN_STA_AUTHORIZED; 1569214501Srpaulo wpa_msg(hapd->msg_ctx, MSG_INFO, 1570214501Srpaulo AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr)); 1571214501Srpaulo } 1572214501Srpaulo 1573214501Srpaulo if (reassoc) 1574214501Srpaulo mlme_reassociate_indication(hapd, sta); 1575214501Srpaulo else 1576214501Srpaulo mlme_associate_indication(hapd, sta); 1577214501Srpaulo 1578214501Srpaulo#ifdef CONFIG_IEEE80211W 1579214501Srpaulo sta->sa_query_timed_out = 0; 1580214501Srpaulo#endif /* CONFIG_IEEE80211W */ 1581214501Srpaulo 1582214501Srpaulo /* 1583214501Srpaulo * Remove the STA entry in order to make sure the STA PS state gets 1584214501Srpaulo * cleared and configuration gets updated in case of reassociation back 1585214501Srpaulo * to the same AP. 1586214501Srpaulo */ 1587214501Srpaulo hapd->drv.sta_remove(hapd, sta->addr); 1588214501Srpaulo 1589214501Srpaulo#ifdef CONFIG_IEEE80211N 1590214501Srpaulo if (sta->flags & WLAN_STA_HT) 1591214501Srpaulo hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap); 1592214501Srpaulo#endif /* CONFIG_IEEE80211N */ 1593214501Srpaulo 1594214501Srpaulo if (hapd->drv.sta_add(hapd, sta->addr, sta->aid, sta->capability, 1595214501Srpaulo sta->supported_rates, sta->supported_rates_len, 1596214501Srpaulo sta->listen_interval, 1597214501Srpaulo sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) { 1598214501Srpaulo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, 1599214501Srpaulo HOSTAPD_LEVEL_NOTICE, 1600214501Srpaulo "Could not add STA to kernel driver"); 1601214501Srpaulo } 1602214501Srpaulo 1603214501Srpaulo if (sta->eapol_sm == NULL) { 1604214501Srpaulo /* 1605214501Srpaulo * This STA does not use RADIUS server for EAP authentication, 1606214501Srpaulo * so bind it to the selected VLAN interface now, since the 1607214501Srpaulo * interface selection is not going to change anymore. 1608214501Srpaulo */ 1609214501Srpaulo if (ap_sta_bind_vlan(hapd, sta, 0) < 0) 1610214501Srpaulo goto fail; 1611214501Srpaulo } else if (sta->vlan_id) { 1612214501Srpaulo /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ 1613214501Srpaulo if (ap_sta_bind_vlan(hapd, sta, 0) < 0) 1614214501Srpaulo goto fail; 1615214501Srpaulo } 1616214501Srpaulo 1617214501Srpaulo hapd->drv.set_sta_flags(hapd, sta); 1618214501Srpaulo 1619214501Srpaulo if (sta->auth_alg == WLAN_AUTH_FT) 1620214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); 1621214501Srpaulo else 1622214501Srpaulo wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC); 1623214501Srpaulo hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); 1624214501Srpaulo 1625214501Srpaulo ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); 1626214501Srpaulo 1627214501Srpaulo fail: 1628214501Srpaulo /* Copy of the association request is not needed anymore */ 1629214501Srpaulo if (sta->last_assoc_req) { 1630214501Srpaulo os_free(sta->last_assoc_req); 1631214501Srpaulo sta->last_assoc_req = NULL; 1632214501Srpaulo } 1633214501Srpaulo} 1634214501Srpaulo 1635214501Srpaulo 1636214501Srpaulo/** 1637214501Srpaulo * ieee802_11_mgmt_cb - Process management frame TX status callback 1638214501Srpaulo * @hapd: hostapd BSS data structure (the BSS from which the management frame 1639214501Srpaulo * was sent from) 1640214501Srpaulo * @buf: management frame data (starting from IEEE 802.11 header) 1641214501Srpaulo * @len: length of frame data in octets 1642214501Srpaulo * @stype: management frame subtype from frame control field 1643214501Srpaulo * @ok: Whether the frame was ACK'ed 1644214501Srpaulo */ 1645214501Srpaulovoid ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len, 1646214501Srpaulo u16 stype, int ok) 1647214501Srpaulo{ 1648214501Srpaulo const struct ieee80211_mgmt *mgmt; 1649214501Srpaulo mgmt = (const struct ieee80211_mgmt *) buf; 1650214501Srpaulo 1651214501Srpaulo switch (stype) { 1652214501Srpaulo case WLAN_FC_STYPE_AUTH: 1653214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::auth cb"); 1654214501Srpaulo handle_auth_cb(hapd, mgmt, len, ok); 1655214501Srpaulo break; 1656214501Srpaulo case WLAN_FC_STYPE_ASSOC_RESP: 1657214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb"); 1658214501Srpaulo handle_assoc_cb(hapd, mgmt, len, 0, ok); 1659214501Srpaulo break; 1660214501Srpaulo case WLAN_FC_STYPE_REASSOC_RESP: 1661214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb"); 1662214501Srpaulo handle_assoc_cb(hapd, mgmt, len, 1, ok); 1663214501Srpaulo break; 1664214501Srpaulo case WLAN_FC_STYPE_PROBE_RESP: 1665214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::proberesp cb"); 1666214501Srpaulo break; 1667214501Srpaulo case WLAN_FC_STYPE_DEAUTH: 1668214501Srpaulo /* ignore */ 1669214501Srpaulo break; 1670214501Srpaulo case WLAN_FC_STYPE_ACTION: 1671214501Srpaulo wpa_printf(MSG_DEBUG, "mgmt::action cb"); 1672214501Srpaulo break; 1673214501Srpaulo default: 1674214501Srpaulo printf("unknown mgmt cb frame subtype %d\n", stype); 1675214501Srpaulo break; 1676214501Srpaulo } 1677214501Srpaulo} 1678214501Srpaulo 1679214501Srpaulo 1680214501Srpauloint ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) 1681214501Srpaulo{ 1682214501Srpaulo /* TODO */ 1683214501Srpaulo return 0; 1684214501Srpaulo} 1685214501Srpaulo 1686214501Srpaulo 1687214501Srpauloint ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta, 1688214501Srpaulo char *buf, size_t buflen) 1689214501Srpaulo{ 1690214501Srpaulo /* TODO */ 1691214501Srpaulo return 0; 1692214501Srpaulo} 1693214501Srpaulo 1694214501Srpaulo 1695214501Srpaulovoid hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr, 1696214501Srpaulo const u8 *buf, size_t len, int ack) 1697214501Srpaulo{ 1698214501Srpaulo struct sta_info *sta; 1699214501Srpaulo struct hostapd_iface *iface = hapd->iface; 1700214501Srpaulo 1701214501Srpaulo sta = ap_get_sta(hapd, addr); 1702214501Srpaulo if (sta == NULL && iface->num_bss > 1) { 1703214501Srpaulo size_t j; 1704214501Srpaulo for (j = 0; j < iface->num_bss; j++) { 1705214501Srpaulo hapd = iface->bss[j]; 1706214501Srpaulo sta = ap_get_sta(hapd, addr); 1707214501Srpaulo if (sta) 1708214501Srpaulo break; 1709214501Srpaulo } 1710214501Srpaulo } 1711214501Srpaulo if (sta == NULL) 1712214501Srpaulo return; 1713214501Srpaulo if (sta->flags & WLAN_STA_PENDING_POLL) { 1714214501Srpaulo wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending " 1715214501Srpaulo "activity poll", MAC2STR(sta->addr), 1716214501Srpaulo ack ? "ACKed" : "did not ACK"); 1717214501Srpaulo if (ack) 1718214501Srpaulo sta->flags &= ~WLAN_STA_PENDING_POLL; 1719214501Srpaulo } 1720214501Srpaulo 1721214501Srpaulo ieee802_1x_tx_status(hapd, sta, buf, len, ack); 1722214501Srpaulo} 1723214501Srpaulo 1724214501Srpaulo 1725214501Srpaulovoid ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src, 1726214501Srpaulo int wds) 1727214501Srpaulo{ 1728214501Srpaulo struct sta_info *sta; 1729214501Srpaulo 1730214501Srpaulo sta = ap_get_sta(hapd, src); 1731214501Srpaulo if (sta && (sta->flags & WLAN_STA_ASSOC)) { 1732214501Srpaulo if (wds && !(sta->flags & WLAN_STA_WDS)) { 1733214501Srpaulo wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for " 1734214501Srpaulo "STA " MACSTR " (aid %u)", 1735214501Srpaulo MAC2STR(sta->addr), sta->aid); 1736214501Srpaulo sta->flags |= WLAN_STA_WDS; 1737214501Srpaulo hapd->drv.set_wds_sta(hapd, sta->addr, sta->aid, 1); 1738214501Srpaulo } 1739214501Srpaulo return; 1740214501Srpaulo } 1741214501Srpaulo 1742214501Srpaulo wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA " 1743214501Srpaulo MACSTR, MAC2STR(src)); 1744214501Srpaulo if (sta && (sta->flags & WLAN_STA_AUTH)) 1745214501Srpaulo hapd->drv.sta_disassoc( 1746214501Srpaulo hapd, src, 1747214501Srpaulo WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 1748214501Srpaulo else 1749214501Srpaulo hapd->drv.sta_deauth( 1750214501Srpaulo hapd, src, 1751214501Srpaulo WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); 1752214501Srpaulo} 1753214501Srpaulo 1754214501Srpaulo 1755214501Srpaulo#endif /* CONFIG_NATIVE_WINDOWS */ 1756