1189251Ssam/* 2189251Ssam * WPA Supplicant - Client mode MLME 3189251Ssam * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * Copyright (c) 2004, Instant802 Networks, Inc. 5189251Ssam * Copyright (c) 2005-2006, Devicescape Software, Inc. 6189251Ssam * 7189251Ssam * This program is free software; you can redistribute it and/or modify 8189251Ssam * it under the terms of the GNU General Public License version 2 as 9189251Ssam * published by the Free Software Foundation. 10189251Ssam * 11189251Ssam * Alternatively, this software may be distributed under the terms of BSD 12189251Ssam * license. 13189251Ssam * 14189251Ssam * See README and COPYING for more details. 15189251Ssam */ 16189251Ssam 17189251Ssam#include "includes.h" 18189251Ssam 19189251Ssam#include "common.h" 20189251Ssam#include "eloop.h" 21189251Ssam#include "config_ssid.h" 22189251Ssam#include "wpa_supplicant_i.h" 23214734Srpaulo#include "notify.h" 24214734Srpaulo#include "driver_i.h" 25214734Srpaulo#include "rsn_supp/wpa.h" 26214734Srpaulo#include "common/ieee802_11_defs.h" 27214734Srpaulo#include "common/ieee802_11_common.h" 28189251Ssam#include "mlme.h" 29189251Ssam 30189251Ssam 31189251Ssam/* Timeouts and intervals in milliseconds */ 32189251Ssam#define IEEE80211_AUTH_TIMEOUT (200) 33189251Ssam#define IEEE80211_AUTH_MAX_TRIES 3 34189251Ssam#define IEEE80211_ASSOC_TIMEOUT (200) 35189251Ssam#define IEEE80211_ASSOC_MAX_TRIES 3 36189251Ssam#define IEEE80211_MONITORING_INTERVAL (2000) 37189251Ssam#define IEEE80211_PROBE_INTERVAL (60000) 38189251Ssam#define IEEE80211_RETRY_AUTH_INTERVAL (1000) 39189251Ssam#define IEEE80211_SCAN_INTERVAL (2000) 40189251Ssam#define IEEE80211_SCAN_INTERVAL_SLOW (15000) 41189251Ssam#define IEEE80211_IBSS_JOIN_TIMEOUT (20000) 42189251Ssam 43189251Ssam#define IEEE80211_PROBE_DELAY (33) 44189251Ssam#define IEEE80211_CHANNEL_TIME (33) 45189251Ssam#define IEEE80211_PASSIVE_CHANNEL_TIME (200) 46189251Ssam#define IEEE80211_SCAN_RESULT_EXPIRE (10000) 47189251Ssam#define IEEE80211_IBSS_MERGE_INTERVAL (30000) 48189251Ssam#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000) 49189251Ssam 50189251Ssam#define IEEE80211_IBSS_MAX_STA_ENTRIES 128 51189251Ssam 52189251Ssam 53189251Ssam#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) 54189251Ssam 55189251Ssam 56189251Ssamstruct ieee80211_sta_bss { 57189251Ssam struct ieee80211_sta_bss *next; 58189251Ssam struct ieee80211_sta_bss *hnext; 59189251Ssam 60189251Ssam u8 bssid[ETH_ALEN]; 61189251Ssam u8 ssid[MAX_SSID_LEN]; 62189251Ssam size_t ssid_len; 63189251Ssam u16 capability; /* host byte order */ 64189251Ssam int hw_mode; 65189251Ssam int channel; 66189251Ssam int freq; 67189251Ssam int rssi; 68189251Ssam u8 *ie; 69189251Ssam size_t ie_len; 70189251Ssam u8 *wpa_ie; 71189251Ssam size_t wpa_ie_len; 72189251Ssam u8 *rsn_ie; 73189251Ssam size_t rsn_ie_len; 74189251Ssam u8 *wmm_ie; 75189251Ssam size_t wmm_ie_len; 76189251Ssam u8 *mdie; 77189251Ssam size_t mdie_len; 78189251Ssam#define IEEE80211_MAX_SUPP_RATES 32 79189251Ssam u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; 80189251Ssam size_t supp_rates_len; 81189251Ssam int beacon_int; 82189251Ssam u64 timestamp; 83189251Ssam 84189251Ssam int probe_resp; 85189251Ssam struct os_time last_update; 86189251Ssam}; 87189251Ssam 88189251Ssam 89189251Ssamstatic void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, 90189251Ssam const u8 *dst, 91189251Ssam const u8 *ssid, size_t ssid_len); 92189251Ssamstatic struct ieee80211_sta_bss * 93189251Ssamieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid); 94189251Ssamstatic int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s); 95189251Ssamstatic int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s); 96189251Ssamstatic void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx); 97189251Ssamstatic void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx); 98214734Srpaulostatic void ieee80211_build_tspec(struct wpabuf *buf); 99214734Srpaulostatic int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, 100214734Srpaulo const u8 *ies, size_t ies_len); 101189251Ssam 102189251Ssam 103189251Ssamstatic int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s, 104214734Srpaulo enum hostapd_hw_mode phymode, int chan, 105189251Ssam int freq) 106189251Ssam{ 107189251Ssam size_t i; 108214734Srpaulo struct hostapd_hw_modes *mode; 109189251Ssam 110189251Ssam for (i = 0; i < wpa_s->mlme.num_modes; i++) { 111189251Ssam mode = &wpa_s->mlme.modes[i]; 112189251Ssam if (mode->mode == phymode) { 113189251Ssam wpa_s->mlme.curr_rates = mode->rates; 114189251Ssam wpa_s->mlme.num_curr_rates = mode->num_rates; 115189251Ssam break; 116189251Ssam } 117189251Ssam } 118189251Ssam 119189251Ssam return wpa_drv_set_channel(wpa_s, phymode, chan, freq); 120189251Ssam} 121189251Ssam 122189251Ssam 123189251Ssamstatic int ecw2cw(int ecw) 124189251Ssam{ 125189251Ssam int cw = 1; 126189251Ssam while (ecw > 0) { 127189251Ssam cw <<= 1; 128189251Ssam ecw--; 129189251Ssam } 130189251Ssam return cw - 1; 131189251Ssam} 132189251Ssam 133189251Ssam 134189251Ssamstatic void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s, 135214734Srpaulo const u8 *wmm_param, size_t wmm_param_len) 136189251Ssam{ 137189251Ssam size_t left; 138189251Ssam int count; 139214734Srpaulo const u8 *pos; 140214734Srpaulo u8 wmm_acm; 141189251Ssam 142189251Ssam if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) 143189251Ssam return; 144189251Ssam count = wmm_param[6] & 0x0f; 145189251Ssam if (count == wpa_s->mlme.wmm_last_param_set) 146189251Ssam return; 147189251Ssam wpa_s->mlme.wmm_last_param_set = count; 148189251Ssam 149189251Ssam pos = wmm_param + 8; 150189251Ssam left = wmm_param_len - 8; 151189251Ssam 152189251Ssam wmm_acm = 0; 153189251Ssam for (; left >= 4; left -= 4, pos += 4) { 154189251Ssam int aci = (pos[0] >> 5) & 0x03; 155189251Ssam int acm = (pos[0] >> 4) & 0x01; 156214734Srpaulo int aifs, cw_max, cw_min, burst_time; 157189251Ssam 158189251Ssam switch (aci) { 159214734Srpaulo case 1: /* AC_BK */ 160189251Ssam if (acm) 161214734Srpaulo wmm_acm |= BIT(1) | BIT(2); /* BK/- */ 162189251Ssam break; 163214734Srpaulo case 2: /* AC_VI */ 164189251Ssam if (acm) 165214734Srpaulo wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ 166189251Ssam break; 167214734Srpaulo case 3: /* AC_VO */ 168189251Ssam if (acm) 169214734Srpaulo wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ 170189251Ssam break; 171214734Srpaulo case 0: /* AC_BE */ 172189251Ssam default: 173189251Ssam if (acm) 174214734Srpaulo wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ 175189251Ssam break; 176189251Ssam } 177189251Ssam 178214734Srpaulo aifs = pos[0] & 0x0f; 179214734Srpaulo cw_max = ecw2cw((pos[1] & 0xf0) >> 4); 180214734Srpaulo cw_min = ecw2cw(pos[1] & 0x0f); 181189251Ssam /* TXOP is in units of 32 usec; burst_time in 0.1 ms */ 182214734Srpaulo burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100; 183214734Srpaulo wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d " 184214734Srpaulo "cWmin=%d cWmax=%d burst=%d", 185214734Srpaulo aci, acm, aifs, cw_min, cw_max, burst_time); 186214734Srpaulo /* TODO: driver configuration */ 187189251Ssam } 188189251Ssam} 189189251Ssam 190189251Ssam 191189251Ssamstatic void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc) 192189251Ssam{ 193189251Ssam if (wpa_s->mlme.associated == assoc && !assoc) 194189251Ssam return; 195189251Ssam 196189251Ssam wpa_s->mlme.associated = assoc; 197189251Ssam 198189251Ssam if (assoc) { 199189251Ssam union wpa_event_data data; 200189251Ssam os_memset(&data, 0, sizeof(data)); 201189251Ssam wpa_s->mlme.prev_bssid_set = 1; 202189251Ssam os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); 203189251Ssam data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies; 204189251Ssam data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len; 205189251Ssam data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies; 206189251Ssam data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len; 207214734Srpaulo data.assoc_info.freq = wpa_s->mlme.freq; 208189251Ssam wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); 209189251Ssam } else { 210189251Ssam wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); 211189251Ssam } 212189251Ssam os_get_time(&wpa_s->mlme.last_probe); 213189251Ssam} 214189251Ssam 215189251Ssam 216189251Ssamstatic int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf, 217189251Ssam size_t len) 218189251Ssam{ 219189251Ssam return wpa_drv_send_mlme(wpa_s, buf, len); 220189251Ssam} 221189251Ssam 222189251Ssam 223189251Ssamstatic void ieee80211_send_auth(struct wpa_supplicant *wpa_s, 224214734Srpaulo int transaction, const u8 *extra, 225214734Srpaulo size_t extra_len, int encrypt) 226189251Ssam{ 227189251Ssam u8 *buf; 228189251Ssam size_t len; 229189251Ssam struct ieee80211_mgmt *mgmt; 230189251Ssam 231189251Ssam buf = os_malloc(sizeof(*mgmt) + 6 + extra_len); 232189251Ssam if (buf == NULL) { 233189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " 234189251Ssam "auth frame"); 235189251Ssam return; 236189251Ssam } 237189251Ssam 238189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 239189251Ssam len = 24 + 6; 240189251Ssam os_memset(mgmt, 0, 24 + 6); 241189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 242189251Ssam WLAN_FC_STYPE_AUTH); 243189251Ssam if (encrypt) 244189251Ssam mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP); 245189251Ssam os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 246189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 247189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 248189251Ssam mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg); 249189251Ssam mgmt->u.auth.auth_transaction = host_to_le16(transaction); 250189251Ssam wpa_s->mlme.auth_transaction = transaction + 1; 251189251Ssam mgmt->u.auth.status_code = host_to_le16(0); 252189251Ssam if (extra) { 253189251Ssam os_memcpy(buf + len, extra, extra_len); 254189251Ssam len += extra_len; 255189251Ssam } 256189251Ssam 257189251Ssam ieee80211_sta_tx(wpa_s, buf, len); 258189251Ssam os_free(buf); 259189251Ssam} 260189251Ssam 261189251Ssam 262189251Ssamstatic void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms) 263189251Ssam{ 264189251Ssam eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); 265189251Ssam eloop_register_timeout(ms / 1000, 1000 * (ms % 1000), 266189251Ssam ieee80211_sta_timer, wpa_s, NULL); 267189251Ssam} 268189251Ssam 269189251Ssam 270189251Ssamstatic void ieee80211_authenticate(struct wpa_supplicant *wpa_s) 271189251Ssam{ 272189251Ssam u8 *extra; 273189251Ssam size_t extra_len; 274189251Ssam 275189251Ssam wpa_s->mlme.auth_tries++; 276189251Ssam if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) { 277189251Ssam wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR 278189251Ssam " timed out", MAC2STR(wpa_s->bssid)); 279189251Ssam return; 280189251Ssam } 281189251Ssam 282189251Ssam wpa_s->mlme.state = IEEE80211_AUTHENTICATE; 283189251Ssam wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR, 284189251Ssam MAC2STR(wpa_s->bssid)); 285189251Ssam 286189251Ssam extra = NULL; 287189251Ssam extra_len = 0; 288189251Ssam 289189251Ssam#ifdef CONFIG_IEEE80211R 290189251Ssam if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || 291189251Ssam wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && 292189251Ssam wpa_s->mlme.ft_ies) { 293189251Ssam struct ieee80211_sta_bss *bss; 294189251Ssam struct rsn_mdie *mdie = NULL; 295189251Ssam bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); 296189251Ssam if (bss && bss->mdie_len >= 2 + sizeof(*mdie)) 297189251Ssam mdie = (struct rsn_mdie *) (bss->mdie + 2); 298189251Ssam if (mdie && 299189251Ssam os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md, 300189251Ssam MOBILITY_DOMAIN_ID_LEN) == 0) { 301189251Ssam wpa_printf(MSG_DEBUG, "MLME: Trying to use FT " 302189251Ssam "over-the-air"); 303189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_FT; 304189251Ssam extra = wpa_s->mlme.ft_ies; 305189251Ssam extra_len = wpa_s->mlme.ft_ies_len; 306189251Ssam } 307189251Ssam } 308189251Ssam#endif /* CONFIG_IEEE80211R */ 309189251Ssam 310189251Ssam ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0); 311189251Ssam 312189251Ssam ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT); 313189251Ssam} 314189251Ssam 315189251Ssam 316189251Ssamstatic void ieee80211_send_assoc(struct wpa_supplicant *wpa_s) 317189251Ssam{ 318189251Ssam struct ieee80211_mgmt *mgmt; 319189251Ssam u8 *pos, *ies, *buf; 320189251Ssam int i, len; 321189251Ssam u16 capab; 322189251Ssam struct ieee80211_sta_bss *bss; 323189251Ssam int wmm = 0; 324189251Ssam size_t blen, buflen; 325189251Ssam 326189251Ssam if (wpa_s->mlme.curr_rates == NULL) { 327189251Ssam wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc"); 328189251Ssam return; 329189251Ssam } 330189251Ssam 331189251Ssam buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len + 332189251Ssam wpa_s->mlme.ssid_len; 333189251Ssam#ifdef CONFIG_IEEE80211R 334189251Ssam if (wpa_s->mlme.ft_ies) 335189251Ssam buflen += wpa_s->mlme.ft_ies_len; 336189251Ssam#endif /* CONFIG_IEEE80211R */ 337189251Ssam buf = os_malloc(buflen); 338189251Ssam if (buf == NULL) { 339189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " 340189251Ssam "assoc frame"); 341189251Ssam return; 342189251Ssam } 343189251Ssam blen = 0; 344189251Ssam 345189251Ssam capab = wpa_s->mlme.capab; 346214734Srpaulo if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) { 347189251Ssam capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | 348189251Ssam WLAN_CAPABILITY_SHORT_PREAMBLE; 349189251Ssam } 350189251Ssam bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); 351189251Ssam if (bss) { 352189251Ssam if (bss->capability & WLAN_CAPABILITY_PRIVACY) 353189251Ssam capab |= WLAN_CAPABILITY_PRIVACY; 354189251Ssam if (bss->wmm_ie) { 355189251Ssam wmm = 1; 356189251Ssam } 357189251Ssam } 358189251Ssam 359189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 360189251Ssam blen += 24; 361189251Ssam os_memset(mgmt, 0, 24); 362189251Ssam os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 363189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 364189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 365189251Ssam 366189251Ssam if (wpa_s->mlme.prev_bssid_set) { 367189251Ssam blen += 10; 368189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 369189251Ssam WLAN_FC_STYPE_REASSOC_REQ); 370189251Ssam mgmt->u.reassoc_req.capab_info = host_to_le16(capab); 371189251Ssam mgmt->u.reassoc_req.listen_interval = host_to_le16(1); 372189251Ssam os_memcpy(mgmt->u.reassoc_req.current_ap, 373189251Ssam wpa_s->mlme.prev_bssid, 374189251Ssam ETH_ALEN); 375189251Ssam } else { 376189251Ssam blen += 4; 377189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 378189251Ssam WLAN_FC_STYPE_ASSOC_REQ); 379189251Ssam mgmt->u.assoc_req.capab_info = host_to_le16(capab); 380189251Ssam mgmt->u.assoc_req.listen_interval = host_to_le16(1); 381189251Ssam } 382189251Ssam 383189251Ssam /* SSID */ 384189251Ssam ies = pos = buf + blen; 385189251Ssam blen += 2 + wpa_s->mlme.ssid_len; 386189251Ssam *pos++ = WLAN_EID_SSID; 387189251Ssam *pos++ = wpa_s->mlme.ssid_len; 388189251Ssam os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); 389189251Ssam 390189251Ssam len = wpa_s->mlme.num_curr_rates; 391189251Ssam if (len > 8) 392189251Ssam len = 8; 393189251Ssam pos = buf + blen; 394189251Ssam blen += len + 2; 395189251Ssam *pos++ = WLAN_EID_SUPP_RATES; 396189251Ssam *pos++ = len; 397214734Srpaulo for (i = 0; i < len; i++) 398214734Srpaulo *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5); 399189251Ssam 400189251Ssam if (wpa_s->mlme.num_curr_rates > len) { 401189251Ssam pos = buf + blen; 402189251Ssam blen += wpa_s->mlme.num_curr_rates - len + 2; 403189251Ssam *pos++ = WLAN_EID_EXT_SUPP_RATES; 404189251Ssam *pos++ = wpa_s->mlme.num_curr_rates - len; 405214734Srpaulo for (i = len; i < wpa_s->mlme.num_curr_rates; i++) 406214734Srpaulo *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5); 407189251Ssam } 408189251Ssam 409189251Ssam if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) { 410189251Ssam pos = buf + blen; 411189251Ssam blen += wpa_s->mlme.extra_ie_len; 412189251Ssam os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len); 413189251Ssam } 414189251Ssam 415189251Ssam#ifdef CONFIG_IEEE80211R 416189251Ssam if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || 417189251Ssam wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && 418189251Ssam wpa_s->mlme.auth_alg != WLAN_AUTH_FT && 419189251Ssam bss && bss->mdie && 420189251Ssam bss->mdie_len >= 2 + sizeof(struct rsn_mdie) && 421189251Ssam bss->mdie[1] >= sizeof(struct rsn_mdie)) { 422189251Ssam pos = buf + blen; 423189251Ssam blen += 2 + sizeof(struct rsn_mdie); 424189251Ssam *pos++ = WLAN_EID_MOBILITY_DOMAIN; 425189251Ssam *pos++ = sizeof(struct rsn_mdie); 426189251Ssam os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN); 427189251Ssam pos += MOBILITY_DOMAIN_ID_LEN; 428189251Ssam *pos++ = 0; /* FIX: copy from the target AP's MDIE */ 429189251Ssam } 430189251Ssam 431189251Ssam if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || 432189251Ssam wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && 433189251Ssam wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) { 434189251Ssam pos = buf + blen; 435189251Ssam os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len); 436189251Ssam pos += wpa_s->mlme.ft_ies_len; 437189251Ssam blen += wpa_s->mlme.ft_ies_len; 438189251Ssam } 439189251Ssam#endif /* CONFIG_IEEE80211R */ 440189251Ssam 441189251Ssam if (wmm && wpa_s->mlme.wmm_enabled) { 442189251Ssam pos = buf + blen; 443189251Ssam blen += 9; 444189251Ssam *pos++ = WLAN_EID_VENDOR_SPECIFIC; 445189251Ssam *pos++ = 7; /* len */ 446189251Ssam *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ 447189251Ssam *pos++ = 0x50; 448189251Ssam *pos++ = 0xf2; 449209158Srpaulo *pos++ = 2; /* WMM */ 450209158Srpaulo *pos++ = 0; /* WMM info */ 451209158Srpaulo *pos++ = 1; /* WMM ver */ 452189251Ssam *pos++ = 0; 453189251Ssam } 454189251Ssam 455189251Ssam os_free(wpa_s->mlme.assocreq_ies); 456189251Ssam wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies; 457189251Ssam wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len); 458189251Ssam if (wpa_s->mlme.assocreq_ies) { 459189251Ssam os_memcpy(wpa_s->mlme.assocreq_ies, ies, 460189251Ssam wpa_s->mlme.assocreq_ies_len); 461189251Ssam } 462189251Ssam 463189251Ssam ieee80211_sta_tx(wpa_s, buf, blen); 464189251Ssam os_free(buf); 465189251Ssam} 466189251Ssam 467189251Ssam 468189251Ssamstatic void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason) 469189251Ssam{ 470189251Ssam u8 *buf; 471189251Ssam size_t len; 472189251Ssam struct ieee80211_mgmt *mgmt; 473189251Ssam 474189251Ssam buf = os_zalloc(sizeof(*mgmt)); 475189251Ssam if (buf == NULL) { 476189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " 477189251Ssam "deauth frame"); 478189251Ssam return; 479189251Ssam } 480189251Ssam 481189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 482189251Ssam len = 24; 483189251Ssam os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 484189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 485189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 486189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 487189251Ssam WLAN_FC_STYPE_DEAUTH); 488189251Ssam len += 2; 489189251Ssam mgmt->u.deauth.reason_code = host_to_le16(reason); 490189251Ssam 491189251Ssam ieee80211_sta_tx(wpa_s, buf, len); 492189251Ssam os_free(buf); 493189251Ssam} 494189251Ssam 495189251Ssam 496189251Ssamstatic void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason) 497189251Ssam{ 498189251Ssam u8 *buf; 499189251Ssam size_t len; 500189251Ssam struct ieee80211_mgmt *mgmt; 501189251Ssam 502189251Ssam buf = os_zalloc(sizeof(*mgmt)); 503189251Ssam if (buf == NULL) { 504189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " 505189251Ssam "disassoc frame"); 506189251Ssam return; 507189251Ssam } 508189251Ssam 509189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 510189251Ssam len = 24; 511189251Ssam os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 512189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 513189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 514189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 515189251Ssam WLAN_FC_STYPE_DISASSOC); 516189251Ssam len += 2; 517189251Ssam mgmt->u.disassoc.reason_code = host_to_le16(reason); 518189251Ssam 519189251Ssam ieee80211_sta_tx(wpa_s, buf, len); 520189251Ssam os_free(buf); 521189251Ssam} 522189251Ssam 523189251Ssam 524189251Ssamstatic int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s) 525189251Ssam{ 526189251Ssam struct ieee80211_sta_bss *bss; 527189251Ssam int res = 0; 528189251Ssam 529189251Ssam if (wpa_s->mlme.mixed_cell || 530189251Ssam wpa_s->mlme.key_mgmt != KEY_MGMT_NONE) 531189251Ssam return 0; 532189251Ssam 533189251Ssam bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); 534189251Ssam if (bss == NULL) 535189251Ssam return 0; 536189251Ssam 537189251Ssam if (ieee80211_sta_wep_configured(wpa_s) != 538189251Ssam !!(bss->capability & WLAN_CAPABILITY_PRIVACY)) 539189251Ssam res = 1; 540189251Ssam 541189251Ssam return res; 542189251Ssam} 543189251Ssam 544189251Ssam 545189251Ssamstatic void ieee80211_associate(struct wpa_supplicant *wpa_s) 546189251Ssam{ 547189251Ssam wpa_s->mlme.assoc_tries++; 548189251Ssam if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { 549189251Ssam wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR 550189251Ssam " timed out", MAC2STR(wpa_s->bssid)); 551189251Ssam return; 552189251Ssam } 553189251Ssam 554189251Ssam wpa_s->mlme.state = IEEE80211_ASSOCIATE; 555189251Ssam wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR, 556189251Ssam MAC2STR(wpa_s->bssid)); 557189251Ssam if (ieee80211_privacy_mismatch(wpa_s)) { 558189251Ssam wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy " 559189251Ssam "configuration and mixed-cell disabled - abort " 560189251Ssam "association"); 561189251Ssam return; 562189251Ssam } 563189251Ssam 564189251Ssam ieee80211_send_assoc(wpa_s); 565189251Ssam 566189251Ssam ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT); 567189251Ssam} 568189251Ssam 569189251Ssam 570189251Ssamstatic void ieee80211_associated(struct wpa_supplicant *wpa_s) 571189251Ssam{ 572189251Ssam int disassoc; 573189251Ssam 574189251Ssam /* TODO: start monitoring current AP signal quality and number of 575189251Ssam * missed beacons. Scan other channels every now and then and search 576189251Ssam * for better APs. */ 577189251Ssam /* TODO: remove expired BSSes */ 578189251Ssam 579189251Ssam wpa_s->mlme.state = IEEE80211_ASSOCIATED; 580189251Ssam 581189251Ssam#if 0 /* FIX */ 582189251Ssam sta = sta_info_get(local, wpa_s->bssid); 583189251Ssam if (sta == NULL) { 584189251Ssam wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR, 585189251Ssam MAC2STR(wpa_s->bssid)); 586189251Ssam disassoc = 1; 587189251Ssam } else { 588189251Ssam disassoc = 0; 589189251Ssam if (time_after(jiffies, 590189251Ssam sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { 591189251Ssam if (wpa_s->mlme.probereq_poll) { 592189251Ssam wpa_printf(MSG_DEBUG "MLME: No ProbeResp from " 593189251Ssam "current AP " MACSTR " - assume " 594189251Ssam "out of range", 595189251Ssam MAC2STR(wpa_s->bssid)); 596189251Ssam disassoc = 1; 597189251Ssam } else { 598189251Ssam ieee80211_send_probe_req( 599189251Ssam wpa_s->bssid, 600189251Ssam wpa_s->mlme.scan_ssid, 601189251Ssam wpa_s->mlme.scan_ssid_len); 602189251Ssam wpa_s->mlme.probereq_poll = 1; 603189251Ssam } 604189251Ssam } else { 605189251Ssam wpa_s->mlme.probereq_poll = 0; 606189251Ssam if (time_after(jiffies, wpa_s->mlme.last_probe + 607189251Ssam IEEE80211_PROBE_INTERVAL)) { 608189251Ssam wpa_s->mlme.last_probe = jiffies; 609189251Ssam ieee80211_send_probe_req(wpa_s->bssid, 610189251Ssam wpa_s->mlme.ssid, 611189251Ssam wpa_s->mlme.ssid_len); 612189251Ssam } 613189251Ssam } 614189251Ssam sta_info_release(local, sta); 615189251Ssam } 616189251Ssam#else 617189251Ssam disassoc = 0; 618189251Ssam#endif 619189251Ssam if (disassoc) { 620189251Ssam wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); 621189251Ssam ieee80211_reschedule_timer(wpa_s, 622189251Ssam IEEE80211_MONITORING_INTERVAL + 623189251Ssam 30000); 624189251Ssam } else { 625189251Ssam ieee80211_reschedule_timer(wpa_s, 626189251Ssam IEEE80211_MONITORING_INTERVAL); 627189251Ssam } 628189251Ssam} 629189251Ssam 630189251Ssam 631189251Ssamstatic void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, 632189251Ssam const u8 *dst, 633189251Ssam const u8 *ssid, size_t ssid_len) 634189251Ssam{ 635189251Ssam u8 *buf; 636189251Ssam size_t len; 637189251Ssam struct ieee80211_mgmt *mgmt; 638189251Ssam u8 *pos, *supp_rates; 639189251Ssam u8 *esupp_rates = NULL; 640189251Ssam int i; 641189251Ssam 642189251Ssam buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len); 643189251Ssam if (buf == NULL) { 644189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " 645189251Ssam "probe request"); 646189251Ssam return; 647189251Ssam } 648189251Ssam 649189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 650189251Ssam len = 24; 651189251Ssam os_memset(mgmt, 0, 24); 652189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 653189251Ssam WLAN_FC_STYPE_PROBE_REQ); 654189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 655189251Ssam if (dst) { 656189251Ssam os_memcpy(mgmt->da, dst, ETH_ALEN); 657189251Ssam os_memcpy(mgmt->bssid, dst, ETH_ALEN); 658189251Ssam } else { 659189251Ssam os_memset(mgmt->da, 0xff, ETH_ALEN); 660189251Ssam os_memset(mgmt->bssid, 0xff, ETH_ALEN); 661189251Ssam } 662189251Ssam pos = buf + len; 663189251Ssam len += 2 + ssid_len; 664189251Ssam *pos++ = WLAN_EID_SSID; 665189251Ssam *pos++ = ssid_len; 666189251Ssam os_memcpy(pos, ssid, ssid_len); 667189251Ssam 668189251Ssam supp_rates = buf + len; 669189251Ssam len += 2; 670189251Ssam supp_rates[0] = WLAN_EID_SUPP_RATES; 671189251Ssam supp_rates[1] = 0; 672189251Ssam for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) { 673189251Ssam if (esupp_rates) { 674189251Ssam pos = buf + len; 675189251Ssam len++; 676189251Ssam esupp_rates[1]++; 677189251Ssam } else if (supp_rates[1] == 8) { 678189251Ssam esupp_rates = pos; 679189251Ssam esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; 680189251Ssam esupp_rates[1] = 1; 681189251Ssam pos = &esupp_rates[2]; 682189251Ssam len += 3; 683189251Ssam } else { 684189251Ssam pos = buf + len; 685189251Ssam len++; 686189251Ssam supp_rates[1]++; 687189251Ssam } 688214734Srpaulo *pos++ = wpa_s->mlme.curr_rates[i] / 5; 689189251Ssam } 690189251Ssam 691189251Ssam if (wpa_s->mlme.extra_probe_ie) { 692189251Ssam os_memcpy(pos, wpa_s->mlme.extra_probe_ie, 693189251Ssam wpa_s->mlme.extra_probe_ie_len); 694189251Ssam len += wpa_s->mlme.extra_probe_ie_len; 695189251Ssam } 696189251Ssam 697189251Ssam ieee80211_sta_tx(wpa_s, buf, len); 698189251Ssam os_free(buf); 699189251Ssam} 700189251Ssam 701189251Ssam 702189251Ssamstatic int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s) 703189251Ssam{ 704189251Ssam#if 0 /* FIX */ 705189251Ssam if (sdata == NULL || sdata->default_key == NULL || 706189251Ssam sdata->default_key->alg != ALG_WEP) 707189251Ssam return 0; 708189251Ssam return 1; 709189251Ssam#else 710189251Ssam return 0; 711189251Ssam#endif 712189251Ssam} 713189251Ssam 714189251Ssam 715189251Ssamstatic void ieee80211_auth_completed(struct wpa_supplicant *wpa_s) 716189251Ssam{ 717189251Ssam wpa_printf(MSG_DEBUG, "MLME: authenticated"); 718189251Ssam wpa_s->mlme.authenticated = 1; 719189251Ssam ieee80211_associate(wpa_s); 720189251Ssam} 721189251Ssam 722189251Ssam 723189251Ssamstatic void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s, 724189251Ssam struct ieee80211_mgmt *mgmt, 725189251Ssam size_t len, 726189251Ssam struct ieee80211_rx_status *rx_status) 727189251Ssam{ 728189251Ssam u8 *pos; 729189251Ssam struct ieee802_11_elems elems; 730189251Ssam 731189251Ssam wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge"); 732189251Ssam pos = mgmt->u.auth.variable; 733189251Ssam if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) 734189251Ssam == ParseFailed) { 735189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)"); 736189251Ssam return; 737189251Ssam } 738189251Ssam if (elems.challenge == NULL) { 739189251Ssam wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key " 740189251Ssam "auth frame"); 741189251Ssam return; 742189251Ssam } 743189251Ssam ieee80211_send_auth(wpa_s, 3, elems.challenge - 2, 744189251Ssam elems.challenge_len + 2, 1); 745189251Ssam} 746189251Ssam 747189251Ssam 748189251Ssamstatic void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s, 749189251Ssam struct ieee80211_mgmt *mgmt, 750189251Ssam size_t len, 751189251Ssam struct ieee80211_rx_status *rx_status) 752189251Ssam{ 753189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 754189251Ssam u16 auth_alg, auth_transaction, status_code; 755189251Ssam int adhoc; 756189251Ssam 757214734Srpaulo adhoc = ssid && ssid->mode == WPAS_MODE_IBSS; 758189251Ssam 759189251Ssam if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) { 760189251Ssam wpa_printf(MSG_DEBUG, "MLME: authentication frame received " 761189251Ssam "from " MACSTR ", but not in authenticate state - " 762189251Ssam "ignored", MAC2STR(mgmt->sa)); 763189251Ssam return; 764189251Ssam } 765189251Ssam 766189251Ssam if (len < 24 + 6) { 767189251Ssam wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication " 768189251Ssam "frame received from " MACSTR " - ignored", 769189251Ssam (unsigned long) len, MAC2STR(mgmt->sa)); 770189251Ssam return; 771189251Ssam } 772189251Ssam 773189251Ssam if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { 774189251Ssam wpa_printf(MSG_DEBUG, "MLME: authentication frame received " 775189251Ssam "from unknown AP (SA=" MACSTR " BSSID=" MACSTR 776189251Ssam ") - ignored", 777189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); 778189251Ssam return; 779189251Ssam } 780189251Ssam 781189251Ssam if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) { 782189251Ssam wpa_printf(MSG_DEBUG, "MLME: authentication frame received " 783189251Ssam "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR 784189251Ssam ") - ignored", 785189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); 786189251Ssam return; 787189251Ssam } 788189251Ssam 789189251Ssam auth_alg = le_to_host16(mgmt->u.auth.auth_alg); 790189251Ssam auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); 791189251Ssam status_code = le_to_host16(mgmt->u.auth.status_code); 792189251Ssam 793189251Ssam wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR 794189251Ssam " (alg=%d transaction=%d status=%d)", 795189251Ssam MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code); 796189251Ssam 797189251Ssam if (adhoc) { 798189251Ssam /* IEEE 802.11 standard does not require authentication in IBSS 799189251Ssam * networks and most implementations do not seem to use it. 800189251Ssam * However, try to reply to authentication attempts if someone 801189251Ssam * has actually implemented this. 802189251Ssam * TODO: Could implement shared key authentication. */ 803189251Ssam if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { 804189251Ssam wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS " 805189251Ssam "authentication frame (alg=%d " 806189251Ssam "transaction=%d)", 807189251Ssam auth_alg, auth_transaction); 808189251Ssam return; 809189251Ssam } 810189251Ssam ieee80211_send_auth(wpa_s, 2, NULL, 0, 0); 811189251Ssam } 812189251Ssam 813189251Ssam if (auth_alg != wpa_s->mlme.auth_alg || 814189251Ssam auth_transaction != wpa_s->mlme.auth_transaction) { 815189251Ssam wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame " 816189251Ssam "(alg=%d transaction=%d)", 817189251Ssam auth_alg, auth_transaction); 818189251Ssam return; 819189251Ssam } 820189251Ssam 821189251Ssam if (status_code != WLAN_STATUS_SUCCESS) { 822189251Ssam wpa_printf(MSG_DEBUG, "MLME: AP denied authentication " 823189251Ssam "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg, 824189251Ssam status_code); 825189251Ssam if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { 826189251Ssam const int num_algs = 3; 827189251Ssam u8 algs[num_algs]; 828189251Ssam int i, pos; 829189251Ssam algs[0] = algs[1] = algs[2] = 0xff; 830214734Srpaulo if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN) 831189251Ssam algs[0] = WLAN_AUTH_OPEN; 832214734Srpaulo if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED) 833189251Ssam algs[1] = WLAN_AUTH_SHARED_KEY; 834214734Srpaulo if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP) 835189251Ssam algs[2] = WLAN_AUTH_LEAP; 836189251Ssam if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN) 837189251Ssam pos = 0; 838189251Ssam else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY) 839189251Ssam pos = 1; 840189251Ssam else 841189251Ssam pos = 2; 842189251Ssam for (i = 0; i < num_algs; i++) { 843189251Ssam pos++; 844189251Ssam if (pos >= num_algs) 845189251Ssam pos = 0; 846189251Ssam if (algs[pos] == wpa_s->mlme.auth_alg || 847189251Ssam algs[pos] == 0xff) 848189251Ssam continue; 849189251Ssam if (algs[pos] == WLAN_AUTH_SHARED_KEY && 850189251Ssam !ieee80211_sta_wep_configured(wpa_s)) 851189251Ssam continue; 852189251Ssam wpa_s->mlme.auth_alg = algs[pos]; 853189251Ssam wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d " 854189251Ssam "for next try", 855189251Ssam wpa_s->mlme.auth_alg); 856189251Ssam break; 857189251Ssam } 858189251Ssam } 859189251Ssam return; 860189251Ssam } 861189251Ssam 862189251Ssam switch (wpa_s->mlme.auth_alg) { 863189251Ssam case WLAN_AUTH_OPEN: 864189251Ssam case WLAN_AUTH_LEAP: 865189251Ssam ieee80211_auth_completed(wpa_s); 866189251Ssam break; 867189251Ssam case WLAN_AUTH_SHARED_KEY: 868189251Ssam if (wpa_s->mlme.auth_transaction == 4) 869189251Ssam ieee80211_auth_completed(wpa_s); 870189251Ssam else 871189251Ssam ieee80211_auth_challenge(wpa_s, mgmt, len, 872189251Ssam rx_status); 873189251Ssam break; 874189251Ssam#ifdef CONFIG_IEEE80211R 875189251Ssam case WLAN_AUTH_FT: 876189251Ssam { 877189251Ssam union wpa_event_data data; 878214734Srpaulo struct wpabuf *ric = NULL; 879189251Ssam os_memset(&data, 0, sizeof(data)); 880189251Ssam data.ft_ies.ies = mgmt->u.auth.variable; 881189251Ssam data.ft_ies.ies_len = len - 882189251Ssam (mgmt->u.auth.variable - (u8 *) mgmt); 883189251Ssam os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN); 884214734Srpaulo if (os_strcmp(wpa_s->driver->name, "test") == 0 && 885214734Srpaulo wpa_s->mlme.wmm_enabled) { 886214734Srpaulo ric = wpabuf_alloc(200); 887214734Srpaulo if (ric) { 888214734Srpaulo /* Build simple RIC-Request: RDIE | TSPEC */ 889214734Srpaulo 890214734Srpaulo /* RIC Data (RDIE) */ 891214734Srpaulo wpabuf_put_u8(ric, WLAN_EID_RIC_DATA); 892214734Srpaulo wpabuf_put_u8(ric, 4); 893214734Srpaulo wpabuf_put_u8(ric, 0); /* RDIE Identifier */ 894214734Srpaulo wpabuf_put_u8(ric, 1); /* Resource Descriptor 895214734Srpaulo * Count */ 896214734Srpaulo wpabuf_put_le16(ric, 0); /* Status Code */ 897214734Srpaulo 898214734Srpaulo /* WMM TSPEC */ 899214734Srpaulo ieee80211_build_tspec(ric); 900214734Srpaulo 901214734Srpaulo data.ft_ies.ric_ies = wpabuf_head(ric); 902214734Srpaulo data.ft_ies.ric_ies_len = wpabuf_len(ric); 903214734Srpaulo } 904214734Srpaulo } 905214734Srpaulo 906189251Ssam wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); 907214734Srpaulo wpabuf_free(ric); 908189251Ssam ieee80211_auth_completed(wpa_s); 909189251Ssam break; 910189251Ssam } 911189251Ssam#endif /* CONFIG_IEEE80211R */ 912189251Ssam } 913189251Ssam} 914189251Ssam 915189251Ssam 916189251Ssamstatic void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s, 917189251Ssam struct ieee80211_mgmt *mgmt, 918189251Ssam size_t len, 919189251Ssam struct ieee80211_rx_status *rx_status) 920189251Ssam{ 921189251Ssam u16 reason_code; 922189251Ssam 923189251Ssam if (len < 24 + 2) { 924189251Ssam wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication " 925189251Ssam "frame received from " MACSTR " - ignored", 926189251Ssam (unsigned long) len, MAC2STR(mgmt->sa)); 927189251Ssam return; 928189251Ssam } 929189251Ssam 930189251Ssam if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { 931189251Ssam wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received " 932189251Ssam "from unknown AP (SA=" MACSTR " BSSID=" MACSTR 933189251Ssam ") - ignored", 934189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); 935189251Ssam return; 936189251Ssam } 937189251Ssam 938189251Ssam reason_code = le_to_host16(mgmt->u.deauth.reason_code); 939189251Ssam 940189251Ssam wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR 941189251Ssam " (reason=%d)", MAC2STR(mgmt->sa), reason_code); 942189251Ssam 943189251Ssam if (wpa_s->mlme.authenticated) 944189251Ssam wpa_printf(MSG_DEBUG, "MLME: deauthenticated"); 945189251Ssam 946189251Ssam if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE || 947189251Ssam wpa_s->mlme.state == IEEE80211_ASSOCIATE || 948189251Ssam wpa_s->mlme.state == IEEE80211_ASSOCIATED) { 949189251Ssam wpa_s->mlme.state = IEEE80211_AUTHENTICATE; 950189251Ssam ieee80211_reschedule_timer(wpa_s, 951189251Ssam IEEE80211_RETRY_AUTH_INTERVAL); 952189251Ssam } 953189251Ssam 954189251Ssam ieee80211_set_associated(wpa_s, 0); 955189251Ssam wpa_s->mlme.authenticated = 0; 956189251Ssam} 957189251Ssam 958189251Ssam 959189251Ssamstatic void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s, 960189251Ssam struct ieee80211_mgmt *mgmt, 961189251Ssam size_t len, 962189251Ssam struct ieee80211_rx_status *rx_status) 963189251Ssam{ 964189251Ssam u16 reason_code; 965189251Ssam 966189251Ssam if (len < 24 + 2) { 967189251Ssam wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation " 968189251Ssam "frame received from " MACSTR " - ignored", 969189251Ssam (unsigned long) len, MAC2STR(mgmt->sa)); 970189251Ssam return; 971189251Ssam } 972189251Ssam 973189251Ssam if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { 974189251Ssam wpa_printf(MSG_DEBUG, "MLME: disassociation frame received " 975189251Ssam "from unknown AP (SA=" MACSTR " BSSID=" MACSTR 976189251Ssam ") - ignored", 977189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); 978189251Ssam return; 979189251Ssam } 980189251Ssam 981189251Ssam reason_code = le_to_host16(mgmt->u.disassoc.reason_code); 982189251Ssam 983189251Ssam wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR 984189251Ssam " (reason=%d)", MAC2STR(mgmt->sa), reason_code); 985189251Ssam 986189251Ssam if (wpa_s->mlme.associated) 987189251Ssam wpa_printf(MSG_DEBUG, "MLME: disassociated"); 988189251Ssam 989189251Ssam if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) { 990189251Ssam wpa_s->mlme.state = IEEE80211_ASSOCIATE; 991189251Ssam ieee80211_reschedule_timer(wpa_s, 992189251Ssam IEEE80211_RETRY_AUTH_INTERVAL); 993189251Ssam } 994189251Ssam 995189251Ssam ieee80211_set_associated(wpa_s, 0); 996189251Ssam} 997189251Ssam 998189251Ssam 999214734Srpaulostatic void ieee80211_build_tspec(struct wpabuf *buf) 1000189251Ssam{ 1001214734Srpaulo struct wmm_tspec_element *tspec; 1002214734Srpaulo int tid, up; 1003189251Ssam 1004214734Srpaulo tspec = wpabuf_put(buf, sizeof(*tspec)); 1005214734Srpaulo tspec->eid = WLAN_EID_VENDOR_SPECIFIC; 1006214734Srpaulo tspec->length = sizeof(*tspec) - 2; 1007214734Srpaulo tspec->oui[0] = 0x00; 1008214734Srpaulo tspec->oui[1] = 0x50; 1009214734Srpaulo tspec->oui[2] = 0xf2; 1010214734Srpaulo tspec->oui_type = 2; 1011214734Srpaulo tspec->oui_subtype = 2; 1012214734Srpaulo tspec->version = 1; 1013214734Srpaulo 1014214734Srpaulo tid = 1; 1015214734Srpaulo up = 6; /* Voice */ 1016214734Srpaulo tspec->ts_info[0] = (tid << 1) | 1017214734Srpaulo (WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) | 1018214734Srpaulo BIT(7); 1019214734Srpaulo tspec->ts_info[1] = up << 3; 1020214734Srpaulo tspec->nominal_msdu_size = host_to_le16(1530); 1021214734Srpaulo tspec->mean_data_rate = host_to_le32(128000); /* bits per second */ 1022214734Srpaulo tspec->minimum_phy_rate = host_to_le32(6000000); 1023214734Srpaulo tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */ 1024189251Ssam} 1025189251Ssam 1026189251Ssam 1027214734Srpaulostatic void ieee80211_tx_addts(struct wpa_supplicant *wpa_s) 1028214734Srpaulo{ 1029214734Srpaulo struct wpabuf *buf; 1030214734Srpaulo struct ieee80211_mgmt *mgmt; 1031214734Srpaulo size_t alen; 1032214734Srpaulo 1033214734Srpaulo wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC"); 1034214734Srpaulo mgmt = NULL; 1035214734Srpaulo alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt; 1036214734Srpaulo 1037214734Srpaulo buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element)); 1038214734Srpaulo if (buf == NULL) 1039214734Srpaulo return; 1040214734Srpaulo 1041214734Srpaulo mgmt = wpabuf_put(buf, alen); 1042214734Srpaulo os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 1043214734Srpaulo os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 1044214734Srpaulo os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 1045214734Srpaulo mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1046214734Srpaulo WLAN_FC_STYPE_ACTION); 1047214734Srpaulo mgmt->u.action.category = WLAN_ACTION_WMM; 1048214734Srpaulo mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ; 1049214734Srpaulo mgmt->u.action.u.wmm_action.dialog_token = 1; 1050214734Srpaulo mgmt->u.action.u.wmm_action.status_code = 0; 1051214734Srpaulo 1052214734Srpaulo ieee80211_build_tspec(buf); 1053214734Srpaulo 1054214734Srpaulo ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf)); 1055214734Srpaulo wpabuf_free(buf); 1056214734Srpaulo} 1057214734Srpaulo 1058214734Srpaulo 1059189251Ssamstatic void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s, 1060189251Ssam struct ieee80211_mgmt *mgmt, 1061189251Ssam size_t len, 1062189251Ssam struct ieee80211_rx_status *rx_status, 1063189251Ssam int reassoc) 1064189251Ssam{ 1065189251Ssam u8 rates[32]; 1066189251Ssam size_t rates_len; 1067189251Ssam u16 capab_info, status_code, aid; 1068189251Ssam struct ieee802_11_elems elems; 1069189251Ssam u8 *pos; 1070189251Ssam 1071189251Ssam /* AssocResp and ReassocResp have identical structure, so process both 1072189251Ssam * of them in this function. */ 1073189251Ssam 1074189251Ssam if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) { 1075189251Ssam wpa_printf(MSG_DEBUG, "MLME: association frame received from " 1076189251Ssam MACSTR ", but not in associate state - ignored", 1077189251Ssam MAC2STR(mgmt->sa)); 1078189251Ssam return; 1079189251Ssam } 1080189251Ssam 1081189251Ssam if (len < 24 + 6) { 1082189251Ssam wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association " 1083189251Ssam "frame received from " MACSTR " - ignored", 1084189251Ssam (unsigned long) len, MAC2STR(mgmt->sa)); 1085189251Ssam return; 1086189251Ssam } 1087189251Ssam 1088189251Ssam if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { 1089189251Ssam wpa_printf(MSG_DEBUG, "MLME: association frame received from " 1090189251Ssam "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - " 1091189251Ssam "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); 1092189251Ssam return; 1093189251Ssam } 1094189251Ssam 1095189251Ssam capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info); 1096189251Ssam status_code = le_to_host16(mgmt->u.assoc_resp.status_code); 1097189251Ssam aid = le_to_host16(mgmt->u.assoc_resp.aid); 1098189251Ssam if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) 1099189251Ssam wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 " 1100189251Ssam "not set", aid); 1101189251Ssam aid &= ~(BIT(15) | BIT(14)); 1102189251Ssam 1103189251Ssam wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR 1104189251Ssam " (capab=0x%x status=%d aid=%d)", 1105189251Ssam reassoc ? "Rea" : "A", MAC2STR(mgmt->sa), 1106189251Ssam capab_info, status_code, aid); 1107189251Ssam 1108189251Ssam pos = mgmt->u.assoc_resp.variable; 1109189251Ssam if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) 1110189251Ssam == ParseFailed) { 1111189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp"); 1112189251Ssam return; 1113189251Ssam } 1114189251Ssam 1115189251Ssam if (status_code != WLAN_STATUS_SUCCESS) { 1116189251Ssam wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)", 1117189251Ssam status_code); 1118189251Ssam#ifdef CONFIG_IEEE80211W 1119189251Ssam if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && 1120189251Ssam elems.timeout_int && elems.timeout_int_len == 5 && 1121189251Ssam elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { 1122189251Ssam u32 tu, ms; 1123189251Ssam tu = WPA_GET_LE32(elems.timeout_int + 1); 1124189251Ssam ms = tu * 1024 / 1000; 1125189251Ssam wpa_printf(MSG_DEBUG, "MLME: AP rejected association " 1126189251Ssam "temporarily; comeback duration %u TU " 1127189251Ssam "(%u ms)", tu, ms); 1128189251Ssam if (ms > IEEE80211_ASSOC_TIMEOUT) { 1129189251Ssam wpa_printf(MSG_DEBUG, "MLME: Update timer " 1130189251Ssam "based on comeback duration"); 1131189251Ssam ieee80211_reschedule_timer(wpa_s, ms); 1132189251Ssam } 1133189251Ssam } 1134189251Ssam#endif /* CONFIG_IEEE80211W */ 1135189251Ssam return; 1136189251Ssam } 1137189251Ssam 1138189251Ssam if (elems.supp_rates == NULL) { 1139189251Ssam wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in " 1140189251Ssam "AssocResp"); 1141189251Ssam return; 1142189251Ssam } 1143189251Ssam 1144189251Ssam if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) { 1145189251Ssam if (!reassoc) { 1146189251Ssam wpa_printf(MSG_DEBUG, "MLME: AP tried to use " 1147189251Ssam "association, not reassociation, response " 1148189251Ssam "with FT"); 1149189251Ssam return; 1150189251Ssam } 1151189251Ssam if (wpa_ft_validate_reassoc_resp( 1152189251Ssam wpa_s->wpa, pos, len - (pos - (u8 *) mgmt), 1153189251Ssam mgmt->sa) < 0) { 1154189251Ssam wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc" 1155189251Ssam "Resp failed"); 1156189251Ssam return; 1157189251Ssam } 1158214734Srpaulo } else if (wpa_sm_set_ft_params(wpa_s->wpa, pos, 1159214734Srpaulo len - (pos - (u8 *) mgmt)) < 0) 1160189251Ssam return; 1161189251Ssam 1162189251Ssam wpa_printf(MSG_DEBUG, "MLME: associated"); 1163189251Ssam wpa_s->mlme.aid = aid; 1164189251Ssam wpa_s->mlme.ap_capab = capab_info; 1165189251Ssam 1166189251Ssam os_free(wpa_s->mlme.assocresp_ies); 1167189251Ssam wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt); 1168189251Ssam wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len); 1169189251Ssam if (wpa_s->mlme.assocresp_ies) { 1170189251Ssam os_memcpy(wpa_s->mlme.assocresp_ies, pos, 1171189251Ssam wpa_s->mlme.assocresp_ies_len); 1172189251Ssam } 1173189251Ssam 1174189251Ssam ieee80211_set_associated(wpa_s, 1); 1175189251Ssam 1176189251Ssam rates_len = elems.supp_rates_len; 1177189251Ssam if (rates_len > sizeof(rates)) 1178189251Ssam rates_len = sizeof(rates); 1179189251Ssam os_memcpy(rates, elems.supp_rates, rates_len); 1180189251Ssam if (elems.ext_supp_rates) { 1181189251Ssam size_t _len = elems.ext_supp_rates_len; 1182189251Ssam if (_len > sizeof(rates) - rates_len) 1183189251Ssam _len = sizeof(rates) - rates_len; 1184189251Ssam os_memcpy(rates + rates_len, elems.ext_supp_rates, _len); 1185189251Ssam rates_len += _len; 1186189251Ssam } 1187189251Ssam 1188189251Ssam if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) { 1189189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the " 1190189251Ssam "netstack"); 1191189251Ssam } 1192189251Ssam if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) < 1193189251Ssam 0) { 1194189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the " 1195189251Ssam "netstack"); 1196189251Ssam } 1197189251Ssam 1198189251Ssam /* Remove STA entry before adding a new one just in case to avoid 1199189251Ssam * problems with existing configuration (e.g., keys). */ 1200189251Ssam wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid); 1201189251Ssam if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) { 1202189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the " 1203189251Ssam "netstack"); 1204189251Ssam } 1205189251Ssam 1206214734Srpaulo if (elems.wmm && wpa_s->mlme.wmm_enabled) 1207209158Srpaulo ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len); 1208189251Ssam 1209189251Ssam ieee80211_associated(wpa_s); 1210214734Srpaulo 1211214734Srpaulo if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT && 1212214734Srpaulo os_strcmp(wpa_s->driver->name, "test") == 0 && 1213214734Srpaulo elems.wmm && wpa_s->mlme.wmm_enabled) { 1214214734Srpaulo /* Test WMM-AC - send ADDTS for WMM TSPEC */ 1215214734Srpaulo ieee80211_tx_addts(wpa_s); 1216214734Srpaulo } 1217189251Ssam} 1218189251Ssam 1219189251Ssam 1220189251Ssam/* Caller must hold local->sta_bss_lock */ 1221189251Ssamstatic void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s, 1222189251Ssam struct ieee80211_sta_bss *bss) 1223189251Ssam{ 1224189251Ssam bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; 1225189251Ssam wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss; 1226189251Ssam} 1227189251Ssam 1228189251Ssam 1229189251Ssam/* Caller must hold local->sta_bss_lock */ 1230189251Ssamstatic void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s, 1231189251Ssam struct ieee80211_sta_bss *bss) 1232189251Ssam{ 1233189251Ssam struct ieee80211_sta_bss *b, *prev = NULL; 1234189251Ssam b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; 1235189251Ssam while (b) { 1236189251Ssam if (b == bss) { 1237189251Ssam if (prev == NULL) { 1238189251Ssam wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] 1239189251Ssam = bss->hnext; 1240189251Ssam } else { 1241189251Ssam prev->hnext = bss->hnext; 1242189251Ssam } 1243189251Ssam break; 1244189251Ssam } 1245189251Ssam prev = b; 1246189251Ssam b = b->hnext; 1247189251Ssam } 1248189251Ssam} 1249189251Ssam 1250189251Ssam 1251189251Ssamstatic struct ieee80211_sta_bss * 1252189251Ssamieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid) 1253189251Ssam{ 1254189251Ssam struct ieee80211_sta_bss *bss; 1255189251Ssam 1256189251Ssam bss = os_zalloc(sizeof(*bss)); 1257189251Ssam if (bss == NULL) 1258189251Ssam return NULL; 1259189251Ssam os_memcpy(bss->bssid, bssid, ETH_ALEN); 1260189251Ssam 1261189251Ssam /* TODO: order by RSSI? */ 1262189251Ssam bss->next = wpa_s->mlme.sta_bss_list; 1263189251Ssam wpa_s->mlme.sta_bss_list = bss; 1264189251Ssam __ieee80211_bss_hash_add(wpa_s, bss); 1265189251Ssam return bss; 1266189251Ssam} 1267189251Ssam 1268189251Ssam 1269189251Ssamstatic struct ieee80211_sta_bss * 1270189251Ssamieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid) 1271189251Ssam{ 1272189251Ssam struct ieee80211_sta_bss *bss; 1273189251Ssam 1274189251Ssam bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)]; 1275189251Ssam while (bss) { 1276189251Ssam if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) 1277189251Ssam break; 1278189251Ssam bss = bss->hnext; 1279189251Ssam } 1280189251Ssam return bss; 1281189251Ssam} 1282189251Ssam 1283189251Ssam 1284189251Ssamstatic void ieee80211_bss_free(struct wpa_supplicant *wpa_s, 1285189251Ssam struct ieee80211_sta_bss *bss) 1286189251Ssam{ 1287189251Ssam __ieee80211_bss_hash_del(wpa_s, bss); 1288189251Ssam os_free(bss->ie); 1289189251Ssam os_free(bss->wpa_ie); 1290189251Ssam os_free(bss->rsn_ie); 1291189251Ssam os_free(bss->wmm_ie); 1292189251Ssam os_free(bss->mdie); 1293189251Ssam os_free(bss); 1294189251Ssam} 1295189251Ssam 1296189251Ssam 1297189251Ssamstatic void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s) 1298189251Ssam{ 1299189251Ssam struct ieee80211_sta_bss *bss, *prev; 1300189251Ssam 1301189251Ssam bss = wpa_s->mlme.sta_bss_list; 1302189251Ssam wpa_s->mlme.sta_bss_list = NULL; 1303189251Ssam while (bss) { 1304189251Ssam prev = bss; 1305189251Ssam bss = bss->next; 1306189251Ssam ieee80211_bss_free(wpa_s, prev); 1307189251Ssam } 1308189251Ssam} 1309189251Ssam 1310189251Ssam 1311189251Ssamstatic void ieee80211_bss_info(struct wpa_supplicant *wpa_s, 1312189251Ssam struct ieee80211_mgmt *mgmt, 1313189251Ssam size_t len, 1314189251Ssam struct ieee80211_rx_status *rx_status, 1315189251Ssam int beacon) 1316189251Ssam{ 1317189251Ssam struct ieee802_11_elems elems; 1318189251Ssam size_t baselen; 1319189251Ssam int channel, invalid = 0, clen; 1320189251Ssam struct ieee80211_sta_bss *bss; 1321189251Ssam u64 timestamp; 1322189251Ssam u8 *pos, *ie_pos; 1323189251Ssam size_t ie_len; 1324189251Ssam 1325189251Ssam if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN)) 1326189251Ssam return; /* ignore ProbeResp to foreign address */ 1327189251Ssam 1328189251Ssam#if 0 1329189251Ssam wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR, 1330189251Ssam beacon ? "Beacon" : "Probe Response", 1331189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->da)); 1332189251Ssam#endif 1333189251Ssam 1334189251Ssam baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; 1335189251Ssam if (baselen > len) 1336189251Ssam return; 1337189251Ssam 1338189251Ssam pos = mgmt->u.beacon.timestamp; 1339189251Ssam timestamp = WPA_GET_LE64(pos); 1340189251Ssam 1341189251Ssam#if 0 /* FIX */ 1342189251Ssam if (local->conf.mode == IW_MODE_ADHOC && beacon && 1343189251Ssam os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) { 1344189251Ssam#ifdef IEEE80211_IBSS_DEBUG 1345189251Ssam static unsigned long last_tsf_debug = 0; 1346189251Ssam u64 tsf; 1347189251Ssam if (local->hw->get_tsf) 1348189251Ssam tsf = local->hw->get_tsf(local->mdev); 1349189251Ssam else 1350189251Ssam tsf = -1LLU; 1351189251Ssam if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { 1352189251Ssam wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID=" 1353189251Ssam MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld " 1354189251Ssam "@%ld", 1355189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid), 1356189251Ssam tsf, timestamp, tsf - timestamp, jiffies); 1357189251Ssam last_tsf_debug = jiffies; 1358189251Ssam } 1359189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 1360189251Ssam } 1361189251Ssam#endif 1362189251Ssam 1363189251Ssam ie_pos = mgmt->u.beacon.variable; 1364189251Ssam ie_len = len - baselen; 1365189251Ssam if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed) 1366189251Ssam invalid = 1; 1367189251Ssam 1368189251Ssam#if 0 /* FIX */ 1369189251Ssam if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates && 1370189251Ssam os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 && 1371189251Ssam (sta = sta_info_get(local, mgmt->sa))) { 1372189251Ssam struct ieee80211_rate *rates; 1373189251Ssam size_t num_rates; 1374189251Ssam u32 supp_rates, prev_rates; 1375189251Ssam int i, j, oper_mode; 1376189251Ssam 1377189251Ssam rates = local->curr_rates; 1378189251Ssam num_rates = local->num_curr_rates; 1379189251Ssam oper_mode = wpa_s->mlme.sta_scanning ? 1380189251Ssam local->scan_oper_phymode : local->conf.phymode; 1381189251Ssam for (i = 0; i < local->hw->num_modes; i++) { 1382189251Ssam struct ieee80211_hw_modes *mode = &local->hw->modes[i]; 1383189251Ssam if (oper_mode == mode->mode) { 1384189251Ssam rates = mode->rates; 1385189251Ssam num_rates = mode->num_rates; 1386189251Ssam break; 1387189251Ssam } 1388189251Ssam } 1389189251Ssam 1390189251Ssam supp_rates = 0; 1391189251Ssam for (i = 0; i < elems.supp_rates_len + 1392189251Ssam elems.ext_supp_rates_len; i++) { 1393189251Ssam u8 rate = 0; 1394189251Ssam int own_rate; 1395189251Ssam if (i < elems.supp_rates_len) 1396189251Ssam rate = elems.supp_rates[i]; 1397189251Ssam else if (elems.ext_supp_rates) 1398189251Ssam rate = elems.ext_supp_rates 1399189251Ssam [i - elems.supp_rates_len]; 1400189251Ssam own_rate = 5 * (rate & 0x7f); 1401189251Ssam if (oper_mode == MODE_ATHEROS_TURBO) 1402189251Ssam own_rate *= 2; 1403189251Ssam for (j = 0; j < num_rates; j++) 1404189251Ssam if (rates[j].rate == own_rate) 1405189251Ssam supp_rates |= BIT(j); 1406189251Ssam } 1407189251Ssam 1408189251Ssam prev_rates = sta->supp_rates; 1409189251Ssam sta->supp_rates &= supp_rates; 1410189251Ssam if (sta->supp_rates == 0) { 1411189251Ssam /* No matching rates - this should not really happen. 1412189251Ssam * Make sure that at least one rate is marked 1413189251Ssam * supported to avoid issues with TX rate ctrl. */ 1414189251Ssam sta->supp_rates = wpa_s->mlme.supp_rates_bits; 1415189251Ssam } 1416189251Ssam if (sta->supp_rates != prev_rates) { 1417189251Ssam wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set " 1418189251Ssam "for " MACSTR " based on beacon info " 1419189251Ssam "(0x%x & 0x%x -> 0x%x)", 1420189251Ssam MAC2STR(sta->addr), prev_rates, 1421189251Ssam supp_rates, sta->supp_rates); 1422189251Ssam } 1423189251Ssam sta_info_release(local, sta); 1424189251Ssam } 1425189251Ssam#endif 1426189251Ssam 1427189251Ssam if (elems.ssid == NULL) 1428189251Ssam return; 1429189251Ssam 1430189251Ssam if (elems.ds_params && elems.ds_params_len == 1) 1431189251Ssam channel = elems.ds_params[0]; 1432189251Ssam else 1433189251Ssam channel = rx_status->channel; 1434189251Ssam 1435189251Ssam bss = ieee80211_bss_get(wpa_s, mgmt->bssid); 1436189251Ssam if (bss == NULL) { 1437189251Ssam bss = ieee80211_bss_add(wpa_s, mgmt->bssid); 1438189251Ssam if (bss == NULL) 1439189251Ssam return; 1440189251Ssam } else { 1441189251Ssam#if 0 1442189251Ssam /* TODO: order by RSSI? */ 1443189251Ssam spin_lock_bh(&local->sta_bss_lock); 1444189251Ssam list_move_tail(&bss->list, &local->sta_bss_list); 1445189251Ssam spin_unlock_bh(&local->sta_bss_lock); 1446189251Ssam#endif 1447189251Ssam } 1448189251Ssam 1449189251Ssam if (bss->probe_resp && beacon) { 1450189251Ssam /* Do not allow beacon to override data from Probe Response. */ 1451189251Ssam return; 1452189251Ssam } 1453189251Ssam 1454189251Ssam bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); 1455189251Ssam bss->capability = le_to_host16(mgmt->u.beacon.capab_info); 1456189251Ssam 1457189251Ssam if (bss->ie == NULL || bss->ie_len < ie_len) { 1458189251Ssam os_free(bss->ie); 1459189251Ssam bss->ie = os_malloc(ie_len); 1460189251Ssam } 1461189251Ssam if (bss->ie) { 1462189251Ssam os_memcpy(bss->ie, ie_pos, ie_len); 1463189251Ssam bss->ie_len = ie_len; 1464189251Ssam } 1465189251Ssam 1466189251Ssam if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) { 1467189251Ssam os_memcpy(bss->ssid, elems.ssid, elems.ssid_len); 1468189251Ssam bss->ssid_len = elems.ssid_len; 1469189251Ssam } 1470189251Ssam 1471189251Ssam bss->supp_rates_len = 0; 1472189251Ssam if (elems.supp_rates) { 1473189251Ssam clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 1474189251Ssam if (clen > elems.supp_rates_len) 1475189251Ssam clen = elems.supp_rates_len; 1476189251Ssam os_memcpy(&bss->supp_rates[bss->supp_rates_len], 1477189251Ssam elems.supp_rates, clen); 1478189251Ssam bss->supp_rates_len += clen; 1479189251Ssam } 1480189251Ssam if (elems.ext_supp_rates) { 1481189251Ssam clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; 1482189251Ssam if (clen > elems.ext_supp_rates_len) 1483189251Ssam clen = elems.ext_supp_rates_len; 1484189251Ssam os_memcpy(&bss->supp_rates[bss->supp_rates_len], 1485189251Ssam elems.ext_supp_rates, clen); 1486189251Ssam bss->supp_rates_len += clen; 1487189251Ssam } 1488189251Ssam 1489189251Ssam if (elems.wpa_ie && 1490189251Ssam (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len || 1491189251Ssam os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) { 1492189251Ssam os_free(bss->wpa_ie); 1493189251Ssam bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2); 1494189251Ssam if (bss->wpa_ie) { 1495189251Ssam os_memcpy(bss->wpa_ie, elems.wpa_ie - 2, 1496189251Ssam elems.wpa_ie_len + 2); 1497189251Ssam bss->wpa_ie_len = elems.wpa_ie_len + 2; 1498189251Ssam } else 1499189251Ssam bss->wpa_ie_len = 0; 1500189251Ssam } else if (!elems.wpa_ie && bss->wpa_ie) { 1501189251Ssam os_free(bss->wpa_ie); 1502189251Ssam bss->wpa_ie = NULL; 1503189251Ssam bss->wpa_ie_len = 0; 1504189251Ssam } 1505189251Ssam 1506189251Ssam if (elems.rsn_ie && 1507189251Ssam (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len || 1508189251Ssam os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) { 1509189251Ssam os_free(bss->rsn_ie); 1510189251Ssam bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2); 1511189251Ssam if (bss->rsn_ie) { 1512189251Ssam os_memcpy(bss->rsn_ie, elems.rsn_ie - 2, 1513189251Ssam elems.rsn_ie_len + 2); 1514189251Ssam bss->rsn_ie_len = elems.rsn_ie_len + 2; 1515189251Ssam } else 1516189251Ssam bss->rsn_ie_len = 0; 1517189251Ssam } else if (!elems.rsn_ie && bss->rsn_ie) { 1518189251Ssam os_free(bss->rsn_ie); 1519189251Ssam bss->rsn_ie = NULL; 1520189251Ssam bss->rsn_ie_len = 0; 1521189251Ssam } 1522189251Ssam 1523209158Srpaulo if (elems.wmm && 1524209158Srpaulo (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len || 1525209158Srpaulo os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) { 1526189251Ssam os_free(bss->wmm_ie); 1527209158Srpaulo bss->wmm_ie = os_malloc(elems.wmm_len + 2); 1528189251Ssam if (bss->wmm_ie) { 1529209158Srpaulo os_memcpy(bss->wmm_ie, elems.wmm - 2, 1530209158Srpaulo elems.wmm_len + 2); 1531209158Srpaulo bss->wmm_ie_len = elems.wmm_len + 2; 1532189251Ssam } else 1533189251Ssam bss->wmm_ie_len = 0; 1534209158Srpaulo } else if (!elems.wmm && bss->wmm_ie) { 1535189251Ssam os_free(bss->wmm_ie); 1536189251Ssam bss->wmm_ie = NULL; 1537189251Ssam bss->wmm_ie_len = 0; 1538189251Ssam } 1539189251Ssam 1540189251Ssam#ifdef CONFIG_IEEE80211R 1541189251Ssam if (elems.mdie && 1542189251Ssam (bss->mdie == NULL || bss->mdie_len != elems.mdie_len || 1543189251Ssam os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) { 1544189251Ssam os_free(bss->mdie); 1545189251Ssam bss->mdie = os_malloc(elems.mdie_len + 2); 1546189251Ssam if (bss->mdie) { 1547189251Ssam os_memcpy(bss->mdie, elems.mdie - 2, 1548189251Ssam elems.mdie_len + 2); 1549189251Ssam bss->mdie_len = elems.mdie_len + 2; 1550189251Ssam } else 1551189251Ssam bss->mdie_len = 0; 1552189251Ssam } else if (!elems.mdie && bss->mdie) { 1553189251Ssam os_free(bss->mdie); 1554189251Ssam bss->mdie = NULL; 1555189251Ssam bss->mdie_len = 0; 1556189251Ssam } 1557189251Ssam#endif /* CONFIG_IEEE80211R */ 1558189251Ssam 1559189251Ssam bss->hw_mode = wpa_s->mlme.phymode; 1560189251Ssam bss->channel = channel; 1561189251Ssam bss->freq = wpa_s->mlme.freq; 1562189251Ssam if (channel != wpa_s->mlme.channel && 1563214734Srpaulo (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G || 1564214734Srpaulo wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) && 1565189251Ssam channel >= 1 && channel <= 14) { 1566189251Ssam static const int freq_list[] = { 1567189251Ssam 2412, 2417, 2422, 2427, 2432, 2437, 2442, 1568189251Ssam 2447, 2452, 2457, 2462, 2467, 2472, 2484 1569189251Ssam }; 1570189251Ssam /* IEEE 802.11g/b mode can receive packets from neighboring 1571189251Ssam * channels, so map the channel into frequency. */ 1572189251Ssam bss->freq = freq_list[channel - 1]; 1573189251Ssam } 1574189251Ssam bss->timestamp = timestamp; 1575189251Ssam os_get_time(&bss->last_update); 1576189251Ssam bss->rssi = rx_status->ssi; 1577189251Ssam if (!beacon) 1578189251Ssam bss->probe_resp++; 1579189251Ssam} 1580189251Ssam 1581189251Ssam 1582189251Ssamstatic void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s, 1583189251Ssam struct ieee80211_mgmt *mgmt, 1584189251Ssam size_t len, 1585189251Ssam struct ieee80211_rx_status *rx_status) 1586189251Ssam{ 1587189251Ssam ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0); 1588189251Ssam} 1589189251Ssam 1590189251Ssam 1591189251Ssamstatic void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s, 1592189251Ssam struct ieee80211_mgmt *mgmt, 1593189251Ssam size_t len, 1594189251Ssam struct ieee80211_rx_status *rx_status) 1595189251Ssam{ 1596189251Ssam int use_protection; 1597189251Ssam size_t baselen; 1598189251Ssam struct ieee802_11_elems elems; 1599189251Ssam 1600189251Ssam ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1); 1601189251Ssam 1602189251Ssam if (!wpa_s->mlme.associated || 1603189251Ssam os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) 1604189251Ssam return; 1605189251Ssam 1606189251Ssam /* Process beacon from the current BSS */ 1607189251Ssam baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; 1608189251Ssam if (baselen > len) 1609189251Ssam return; 1610189251Ssam 1611189251Ssam if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, 1612189251Ssam &elems, 0) == ParseFailed) 1613189251Ssam return; 1614189251Ssam 1615189251Ssam use_protection = 0; 1616189251Ssam if (elems.erp_info && elems.erp_info_len >= 1) { 1617189251Ssam use_protection = 1618189251Ssam (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0; 1619189251Ssam } 1620189251Ssam 1621189251Ssam if (use_protection != !!wpa_s->mlme.use_protection) { 1622189251Ssam wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR 1623189251Ssam ")", 1624189251Ssam use_protection ? "enabled" : "disabled", 1625189251Ssam MAC2STR(wpa_s->bssid)); 1626189251Ssam wpa_s->mlme.use_protection = use_protection ? 1 : 0; 1627189251Ssam wpa_s->mlme.cts_protect_erp_frames = use_protection; 1628189251Ssam } 1629189251Ssam 1630209158Srpaulo if (elems.wmm && wpa_s->mlme.wmm_enabled) { 1631209158Srpaulo ieee80211_sta_wmm_params(wpa_s, elems.wmm, 1632209158Srpaulo elems.wmm_len); 1633189251Ssam } 1634189251Ssam} 1635189251Ssam 1636189251Ssam 1637189251Ssamstatic void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s, 1638189251Ssam struct ieee80211_mgmt *mgmt, 1639189251Ssam size_t len, 1640189251Ssam struct ieee80211_rx_status *rx_status) 1641189251Ssam{ 1642189251Ssam int tx_last_beacon, adhoc; 1643189251Ssam#if 0 /* FIX */ 1644189251Ssam struct ieee80211_mgmt *resp; 1645189251Ssam#endif 1646189251Ssam u8 *pos, *end; 1647189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 1648189251Ssam 1649214734Srpaulo adhoc = ssid && ssid->mode == WPAS_MODE_IBSS; 1650189251Ssam 1651189251Ssam if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED || 1652189251Ssam len < 24 + 2 || wpa_s->mlme.probe_resp == NULL) 1653189251Ssam return; 1654189251Ssam 1655189251Ssam#if 0 /* FIX */ 1656189251Ssam if (local->hw->tx_last_beacon) 1657189251Ssam tx_last_beacon = local->hw->tx_last_beacon(local->mdev); 1658189251Ssam else 1659189251Ssam#endif 1660189251Ssam tx_last_beacon = 1; 1661189251Ssam 1662189251Ssam#ifdef IEEE80211_IBSS_DEBUG 1663189251Ssam wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR 1664189251Ssam " BSSID=" MACSTR " (tx_last_beacon=%d)", 1665189251Ssam MAC2STR(mgmt->sa), MAC2STR(mgmt->da), 1666189251Ssam MAC2STR(mgmt->bssid), tx_last_beacon); 1667189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 1668189251Ssam 1669189251Ssam if (!tx_last_beacon) 1670189251Ssam return; 1671189251Ssam 1672189251Ssam if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 && 1673189251Ssam os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) 1674189251Ssam return; 1675189251Ssam 1676189251Ssam end = ((u8 *) mgmt) + len; 1677189251Ssam pos = mgmt->u.probe_req.variable; 1678189251Ssam if (pos[0] != WLAN_EID_SSID || 1679189251Ssam pos + 2 + pos[1] > end) { 1680189251Ssam wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from " 1681189251Ssam MACSTR, MAC2STR(mgmt->sa)); 1682189251Ssam return; 1683189251Ssam } 1684189251Ssam if (pos[1] != 0 && 1685189251Ssam (pos[1] != wpa_s->mlme.ssid_len || 1686189251Ssam os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0)) 1687189251Ssam { 1688189251Ssam /* Ignore ProbeReq for foreign SSID */ 1689189251Ssam return; 1690189251Ssam } 1691189251Ssam 1692189251Ssam#if 0 /* FIX */ 1693189251Ssam /* Reply with ProbeResp */ 1694189251Ssam skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC); 1695189251Ssam if (skb == NULL) 1696189251Ssam return; 1697189251Ssam 1698189251Ssam resp = (struct ieee80211_mgmt *) skb->data; 1699189251Ssam os_memcpy(resp->da, mgmt->sa, ETH_ALEN); 1700189251Ssam#ifdef IEEE80211_IBSS_DEBUG 1701189251Ssam wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR, 1702189251Ssam MAC2STR(resp->da)); 1703189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 1704189251Ssam ieee80211_sta_tx(wpa_s, skb, 0, 1); 1705189251Ssam#endif 1706189251Ssam} 1707189251Ssam 1708189251Ssam 1709189251Ssam#ifdef CONFIG_IEEE80211R 1710189251Ssamstatic void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s, 1711189251Ssam struct ieee80211_mgmt *mgmt, 1712189251Ssam size_t len, 1713189251Ssam struct ieee80211_rx_status *rx_status) 1714189251Ssam{ 1715189251Ssam union wpa_event_data data; 1716189251Ssam u16 status; 1717189251Ssam u8 *sta_addr, *target_ap_addr; 1718189251Ssam 1719189251Ssam if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) { 1720189251Ssam wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame"); 1721189251Ssam return; 1722189251Ssam } 1723189251Ssam 1724189251Ssam /* 1725189251Ssam * Only FT Action Response is needed for now since reservation 1726189251Ssam * protocol is not supported. 1727189251Ssam */ 1728189251Ssam if (mgmt->u.action.u.ft_action_resp.action != 2) { 1729189251Ssam wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d", 1730189251Ssam mgmt->u.action.u.ft_action_resp.action); 1731189251Ssam return; 1732189251Ssam } 1733189251Ssam 1734189251Ssam status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code); 1735189251Ssam sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr; 1736189251Ssam target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr; 1737189251Ssam wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR 1738189251Ssam " TargetAP " MACSTR " Status Code %d", 1739189251Ssam MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); 1740189251Ssam if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { 1741189251Ssam wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR 1742189251Ssam " in FT Action Response", MAC2STR(sta_addr)); 1743189251Ssam return; 1744189251Ssam } 1745189251Ssam 1746189251Ssam if (status) { 1747189251Ssam wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates " 1748189251Ssam "failure (status code %d)", status); 1749189251Ssam /* TODO: report error to FT code(?) */ 1750189251Ssam return; 1751189251Ssam } 1752189251Ssam 1753189251Ssam os_memset(&data, 0, sizeof(data)); 1754189251Ssam data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable; 1755189251Ssam data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable - 1756189251Ssam (u8 *) mgmt); 1757189251Ssam data.ft_ies.ft_action = 1; 1758189251Ssam os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN); 1759189251Ssam wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); 1760189251Ssam /* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed 1761189251Ssam * successfully */ 1762189251Ssam wpa_s->mlme.prev_bssid_set = 1; 1763189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_FT; 1764189251Ssam os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); 1765189251Ssam os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN); 1766189251Ssam ieee80211_associate(wpa_s); 1767189251Ssam} 1768189251Ssam#endif /* CONFIG_IEEE80211R */ 1769189251Ssam 1770189251Ssam 1771189251Ssam#ifdef CONFIG_IEEE80211W 1772189251Ssam 1773189251Ssam/* MLME-SAQuery.response */ 1774189251Ssamstatic int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s, 1775189251Ssam const u8 *addr, const u8 *trans_id) 1776189251Ssam{ 1777189251Ssam struct ieee80211_mgmt *mgmt; 1778189251Ssam int res; 1779189251Ssam size_t len; 1780189251Ssam 1781189251Ssam mgmt = os_zalloc(sizeof(*mgmt)); 1782189251Ssam if (mgmt == NULL) { 1783189251Ssam wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 1784189251Ssam "SA Query action frame"); 1785189251Ssam return -1; 1786189251Ssam } 1787189251Ssam 1788189251Ssam len = 24; 1789189251Ssam os_memcpy(mgmt->da, addr, ETH_ALEN); 1790189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 1791189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 1792189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 1793189251Ssam WLAN_FC_STYPE_ACTION); 1794189251Ssam mgmt->u.action.category = WLAN_ACTION_SA_QUERY; 1795189251Ssam mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE; 1796189251Ssam os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id, 1797189251Ssam WLAN_SA_QUERY_TR_ID_LEN); 1798189251Ssam len += 1 + sizeof(mgmt->u.action.u.sa_query_resp); 1799189251Ssam 1800189251Ssam res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len); 1801189251Ssam os_free(mgmt); 1802189251Ssam 1803189251Ssam return res; 1804189251Ssam} 1805189251Ssam 1806189251Ssam 1807189251Ssamstatic void ieee80211_rx_mgmt_sa_query_action( 1808189251Ssam struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, 1809189251Ssam struct ieee80211_rx_status *rx_status) 1810189251Ssam{ 1811189251Ssam if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) { 1812189251Ssam wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame"); 1813189251Ssam return; 1814189251Ssam } 1815189251Ssam 1816189251Ssam if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) { 1817189251Ssam wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d", 1818189251Ssam mgmt->u.action.u.sa_query_req.action); 1819189251Ssam return; 1820189251Ssam } 1821189251Ssam 1822189251Ssam if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { 1823189251Ssam wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown " 1824189251Ssam "source " MACSTR, MAC2STR(mgmt->sa)); 1825189251Ssam return; 1826189251Ssam } 1827189251Ssam 1828189251Ssam if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) { 1829189251Ssam wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during " 1830189251Ssam "association process"); 1831189251Ssam return; 1832189251Ssam } 1833189251Ssam 1834189251Ssam wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request"); 1835189251Ssam ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u. 1836189251Ssam sa_query_req.trans_id); 1837189251Ssam} 1838189251Ssam 1839189251Ssam#endif /* CONFIG_IEEE80211W */ 1840189251Ssam 1841189251Ssam 1842214734Srpaulostatic void dump_tspec(struct wmm_tspec_element *tspec) 1843214734Srpaulo{ 1844214734Srpaulo int up, psb, dir, tid; 1845214734Srpaulo u16 val; 1846214734Srpaulo 1847214734Srpaulo up = (tspec->ts_info[1] >> 3) & 0x07; 1848214734Srpaulo psb = (tspec->ts_info[1] >> 2) & 0x01; 1849214734Srpaulo dir = (tspec->ts_info[0] >> 5) & 0x03; 1850214734Srpaulo tid = (tspec->ts_info[0] >> 1) & 0x0f; 1851214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d", 1852214734Srpaulo up, psb, dir, tid); 1853214734Srpaulo val = le_to_host16(tspec->nominal_msdu_size); 1854214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s", 1855214734Srpaulo val & 0x7fff, val & 0x8000 ? " (fixed)" : ""); 1856214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps", 1857214734Srpaulo le_to_host32(tspec->mean_data_rate)); 1858214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps", 1859214734Srpaulo le_to_host32(tspec->minimum_phy_rate)); 1860214734Srpaulo val = le_to_host16(tspec->surplus_bandwidth_allowance); 1861214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u", 1862214734Srpaulo val >> 13, 10000 * (val & 0x1fff) / 0x2000); 1863214734Srpaulo val = le_to_host16(tspec->medium_time); 1864214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)", 1865214734Srpaulo val, 32 * val); 1866214734Srpaulo} 1867214734Srpaulo 1868214734Srpaulo 1869214734Srpaulostatic int is_wmm_tspec(const u8 *ie, size_t len) 1870214734Srpaulo{ 1871214734Srpaulo const struct wmm_tspec_element *tspec; 1872214734Srpaulo 1873214734Srpaulo if (len < sizeof(*tspec)) 1874214734Srpaulo return 0; 1875214734Srpaulo 1876214734Srpaulo tspec = (const struct wmm_tspec_element *) ie; 1877214734Srpaulo if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC || 1878214734Srpaulo tspec->length < sizeof(*tspec) - 2 || 1879214734Srpaulo tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 || 1880214734Srpaulo tspec->oui[2] != 0xf2 || tspec->oui_type != 2 || 1881214734Srpaulo tspec->oui_subtype != 2 || tspec->version != 1) 1882214734Srpaulo return 0; 1883214734Srpaulo 1884214734Srpaulo return 1; 1885214734Srpaulo} 1886214734Srpaulo 1887214734Srpaulo 1888214734Srpaulostatic void ieee80211_rx_addts_resp( 1889214734Srpaulo struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, 1890214734Srpaulo size_t var_len) 1891214734Srpaulo{ 1892214734Srpaulo struct wmm_tspec_element *tspec; 1893214734Srpaulo 1894214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response"); 1895214734Srpaulo wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)", 1896214734Srpaulo mgmt->u.action.u.wmm_action.variable, var_len); 1897214734Srpaulo if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len)) 1898214734Srpaulo return; 1899214734Srpaulo tspec = (struct wmm_tspec_element *) 1900214734Srpaulo mgmt->u.action.u.wmm_action.variable; 1901214734Srpaulo dump_tspec(tspec); 1902214734Srpaulo} 1903214734Srpaulo 1904214734Srpaulo 1905214734Srpaulostatic void ieee80211_rx_delts( 1906214734Srpaulo struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, 1907214734Srpaulo size_t var_len) 1908214734Srpaulo{ 1909214734Srpaulo struct wmm_tspec_element *tspec; 1910214734Srpaulo 1911214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Received DELTS"); 1912214734Srpaulo wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)", 1913214734Srpaulo mgmt->u.action.u.wmm_action.variable, var_len); 1914214734Srpaulo if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len)) 1915214734Srpaulo return; 1916214734Srpaulo tspec = (struct wmm_tspec_element *) 1917214734Srpaulo mgmt->u.action.u.wmm_action.variable; 1918214734Srpaulo dump_tspec(tspec); 1919214734Srpaulo} 1920214734Srpaulo 1921214734Srpaulo 1922214734Srpaulostatic void ieee80211_rx_mgmt_wmm_action( 1923214734Srpaulo struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, 1924214734Srpaulo struct ieee80211_rx_status *rx_status) 1925214734Srpaulo{ 1926214734Srpaulo size_t alen; 1927214734Srpaulo 1928214734Srpaulo alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt; 1929214734Srpaulo if (len < alen) { 1930214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short"); 1931214734Srpaulo return; 1932214734Srpaulo } 1933214734Srpaulo 1934214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, " 1935214734Srpaulo "Dialog Token %d, Status Code %d", 1936214734Srpaulo mgmt->u.action.u.wmm_action.action_code, 1937214734Srpaulo mgmt->u.action.u.wmm_action.dialog_token, 1938214734Srpaulo mgmt->u.action.u.wmm_action.status_code); 1939214734Srpaulo 1940214734Srpaulo switch (mgmt->u.action.u.wmm_action.action_code) { 1941214734Srpaulo case WMM_ACTION_CODE_ADDTS_RESP: 1942214734Srpaulo ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen); 1943214734Srpaulo break; 1944214734Srpaulo case WMM_ACTION_CODE_DELTS: 1945214734Srpaulo ieee80211_rx_delts(wpa_s, mgmt, len, len - alen); 1946214734Srpaulo break; 1947214734Srpaulo default: 1948214734Srpaulo wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d", 1949214734Srpaulo mgmt->u.action.u.wmm_action.action_code); 1950214734Srpaulo break; 1951214734Srpaulo } 1952214734Srpaulo} 1953214734Srpaulo 1954214734Srpaulo 1955189251Ssamstatic void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s, 1956189251Ssam struct ieee80211_mgmt *mgmt, 1957189251Ssam size_t len, 1958189251Ssam struct ieee80211_rx_status *rx_status) 1959189251Ssam{ 1960189251Ssam wpa_printf(MSG_DEBUG, "MLME: received Action frame"); 1961189251Ssam 1962189251Ssam if (len < 25) 1963189251Ssam return; 1964189251Ssam 1965189251Ssam switch (mgmt->u.action.category) { 1966189251Ssam#ifdef CONFIG_IEEE80211R 1967189251Ssam case WLAN_ACTION_FT: 1968189251Ssam ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status); 1969189251Ssam break; 1970189251Ssam#endif /* CONFIG_IEEE80211R */ 1971189251Ssam#ifdef CONFIG_IEEE80211W 1972189251Ssam case WLAN_ACTION_SA_QUERY: 1973189251Ssam ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status); 1974189251Ssam break; 1975189251Ssam#endif /* CONFIG_IEEE80211W */ 1976214734Srpaulo case WLAN_ACTION_WMM: 1977214734Srpaulo ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status); 1978214734Srpaulo break; 1979214734Srpaulo case WLAN_ACTION_PUBLIC: 1980214734Srpaulo if (wpa_s->mlme.public_action_cb) { 1981214734Srpaulo wpa_s->mlme.public_action_cb( 1982214734Srpaulo wpa_s->mlme.public_action_cb_ctx, 1983214734Srpaulo (u8 *) mgmt, len, rx_status->freq); 1984214734Srpaulo return; 1985214734Srpaulo } 1986214734Srpaulo break; 1987189251Ssam default: 1988189251Ssam wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d", 1989189251Ssam mgmt->u.action.category); 1990189251Ssam break; 1991189251Ssam } 1992189251Ssam} 1993189251Ssam 1994189251Ssam 1995189251Ssamstatic void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s, 1996189251Ssam const u8 *buf, size_t len, 1997189251Ssam struct ieee80211_rx_status *rx_status) 1998189251Ssam{ 1999189251Ssam struct ieee80211_mgmt *mgmt; 2000189251Ssam u16 fc; 2001189251Ssam 2002189251Ssam if (len < 24) 2003189251Ssam return; 2004189251Ssam 2005189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 2006189251Ssam fc = le_to_host16(mgmt->frame_control); 2007189251Ssam 2008189251Ssam switch (WLAN_FC_GET_STYPE(fc)) { 2009189251Ssam case WLAN_FC_STYPE_PROBE_REQ: 2010189251Ssam ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status); 2011189251Ssam break; 2012189251Ssam case WLAN_FC_STYPE_PROBE_RESP: 2013189251Ssam ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status); 2014189251Ssam break; 2015189251Ssam case WLAN_FC_STYPE_BEACON: 2016189251Ssam ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); 2017189251Ssam break; 2018189251Ssam case WLAN_FC_STYPE_AUTH: 2019189251Ssam ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status); 2020189251Ssam break; 2021189251Ssam case WLAN_FC_STYPE_ASSOC_RESP: 2022189251Ssam ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0); 2023189251Ssam break; 2024189251Ssam case WLAN_FC_STYPE_REASSOC_RESP: 2025189251Ssam ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1); 2026189251Ssam break; 2027189251Ssam case WLAN_FC_STYPE_DEAUTH: 2028189251Ssam ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status); 2029189251Ssam break; 2030189251Ssam case WLAN_FC_STYPE_DISASSOC: 2031189251Ssam ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status); 2032189251Ssam break; 2033189251Ssam case WLAN_FC_STYPE_ACTION: 2034189251Ssam ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status); 2035189251Ssam break; 2036189251Ssam default: 2037189251Ssam wpa_printf(MSG_DEBUG, "MLME: received unknown management " 2038189251Ssam "frame - stype=%d", WLAN_FC_GET_STYPE(fc)); 2039189251Ssam break; 2040189251Ssam } 2041189251Ssam} 2042189251Ssam 2043189251Ssam 2044189251Ssamstatic void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s, 2045189251Ssam const u8 *buf, size_t len, 2046189251Ssam struct ieee80211_rx_status *rx_status) 2047189251Ssam{ 2048189251Ssam struct ieee80211_mgmt *mgmt; 2049189251Ssam u16 fc; 2050189251Ssam 2051189251Ssam if (len < 24) 2052189251Ssam return; 2053189251Ssam 2054189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 2055189251Ssam fc = le_to_host16(mgmt->frame_control); 2056189251Ssam 2057189251Ssam if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) { 2058189251Ssam if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { 2059189251Ssam ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, 2060189251Ssam len, rx_status); 2061189251Ssam } else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) { 2062189251Ssam ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); 2063189251Ssam } 2064189251Ssam } 2065189251Ssam} 2066189251Ssam 2067189251Ssam 2068189251Ssamstatic int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s) 2069189251Ssam{ 2070189251Ssam int active = 0; 2071189251Ssam 2072189251Ssam#if 0 /* FIX */ 2073189251Ssam list_for_each(ptr, &local->sta_list) { 2074189251Ssam sta = list_entry(ptr, struct sta_info, list); 2075189251Ssam if (sta->dev == dev && 2076189251Ssam time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, 2077189251Ssam jiffies)) { 2078189251Ssam active++; 2079189251Ssam break; 2080189251Ssam } 2081189251Ssam } 2082189251Ssam#endif 2083189251Ssam 2084189251Ssam return active; 2085189251Ssam} 2086189251Ssam 2087189251Ssam 2088189251Ssamstatic void ieee80211_sta_expire(struct wpa_supplicant *wpa_s) 2089189251Ssam{ 2090189251Ssam#if 0 /* FIX */ 2091189251Ssam list_for_each_safe(ptr, n, &local->sta_list) { 2092189251Ssam sta = list_entry(ptr, struct sta_info, list); 2093189251Ssam if (time_after(jiffies, sta->last_rx + 2094189251Ssam IEEE80211_IBSS_INACTIVITY_LIMIT)) { 2095189251Ssam wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA " 2096189251Ssam MACSTR, MAC2STR(sta->addr)); 2097189251Ssam sta_info_free(local, sta, 1); 2098189251Ssam } 2099189251Ssam } 2100189251Ssam#endif 2101189251Ssam} 2102189251Ssam 2103189251Ssam 2104189251Ssamstatic void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s) 2105189251Ssam{ 2106214734Srpaulo struct wpa_driver_scan_params params; 2107214734Srpaulo 2108189251Ssam ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); 2109189251Ssam 2110189251Ssam ieee80211_sta_expire(wpa_s); 2111189251Ssam if (ieee80211_sta_active_ibss(wpa_s)) 2112189251Ssam return; 2113189251Ssam 2114189251Ssam wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for " 2115189251Ssam "other IBSS networks with same SSID (merge)"); 2116214734Srpaulo os_memset(¶ms, 0, sizeof(params)); 2117214734Srpaulo params.ssids[0].ssid = wpa_s->mlme.ssid; 2118214734Srpaulo params.ssids[0].ssid_len = wpa_s->mlme.ssid_len; 2119214734Srpaulo params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0; 2120214734Srpaulo ieee80211_sta_req_scan(wpa_s, ¶ms); 2121189251Ssam} 2122189251Ssam 2123189251Ssam 2124189251Ssamstatic void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx) 2125189251Ssam{ 2126189251Ssam struct wpa_supplicant *wpa_s = eloop_ctx; 2127189251Ssam 2128189251Ssam switch (wpa_s->mlme.state) { 2129189251Ssam case IEEE80211_DISABLED: 2130189251Ssam break; 2131189251Ssam case IEEE80211_AUTHENTICATE: 2132189251Ssam ieee80211_authenticate(wpa_s); 2133189251Ssam break; 2134189251Ssam case IEEE80211_ASSOCIATE: 2135189251Ssam ieee80211_associate(wpa_s); 2136189251Ssam break; 2137189251Ssam case IEEE80211_ASSOCIATED: 2138189251Ssam ieee80211_associated(wpa_s); 2139189251Ssam break; 2140189251Ssam case IEEE80211_IBSS_SEARCH: 2141189251Ssam ieee80211_sta_find_ibss(wpa_s); 2142189251Ssam break; 2143189251Ssam case IEEE80211_IBSS_JOINED: 2144189251Ssam ieee80211_sta_merge_ibss(wpa_s); 2145189251Ssam break; 2146189251Ssam default: 2147189251Ssam wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d", 2148189251Ssam wpa_s->mlme.state); 2149189251Ssam break; 2150189251Ssam } 2151189251Ssam 2152189251Ssam if (ieee80211_privacy_mismatch(wpa_s)) { 2153189251Ssam wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch " 2154189251Ssam "and mixed-cell disabled - disassociate"); 2155189251Ssam 2156189251Ssam ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED); 2157189251Ssam ieee80211_set_associated(wpa_s, 0); 2158189251Ssam } 2159189251Ssam} 2160189251Ssam 2161189251Ssam 2162189251Ssamstatic void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s) 2163189251Ssam{ 2164189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 2165214734Srpaulo if (ssid && ssid->mode != WPAS_MODE_INFRA) 2166189251Ssam return; 2167189251Ssam 2168189251Ssam#if 0 /* FIX */ 2169189251Ssam if (local->hw->reset_tsf) { 2170189251Ssam /* Reset own TSF to allow time synchronization work. */ 2171189251Ssam local->hw->reset_tsf(local->mdev); 2172189251Ssam } 2173189251Ssam#endif 2174189251Ssam 2175189251Ssam wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */ 2176189251Ssam 2177189251Ssam 2178214734Srpaulo if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN) 2179189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; 2180214734Srpaulo else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED) 2181189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY; 2182214734Srpaulo else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP) 2183189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP; 2184189251Ssam else 2185189251Ssam wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; 2186189251Ssam wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d", 2187189251Ssam wpa_s->mlme.auth_alg); 2188189251Ssam wpa_s->mlme.auth_transaction = -1; 2189189251Ssam wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0; 2190189251Ssam ieee80211_authenticate(wpa_s); 2191189251Ssam} 2192189251Ssam 2193189251Ssam 2194189251Ssamstatic int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s) 2195189251Ssam{ 2196189251Ssam#if 0 /* FIX */ 2197189251Ssam int m, c; 2198189251Ssam 2199189251Ssam for (m = 0; m < local->hw->num_modes; m++) { 2200189251Ssam struct ieee80211_hw_modes *mode = &local->hw->modes[m]; 2201189251Ssam if (mode->mode != local->conf.phymode) 2202189251Ssam continue; 2203189251Ssam for (c = 0; c < mode->num_channels; c++) { 2204189251Ssam struct ieee80211_channel *chan = &mode->channels[c]; 2205189251Ssam if (chan->flag & IEEE80211_CHAN_W_SCAN && 2206189251Ssam chan->chan == local->conf.channel) { 2207189251Ssam if (chan->flag & IEEE80211_CHAN_W_IBSS) 2208189251Ssam return 1; 2209189251Ssam break; 2210189251Ssam } 2211189251Ssam } 2212189251Ssam } 2213189251Ssam#endif 2214189251Ssam 2215189251Ssam return 0; 2216189251Ssam} 2217189251Ssam 2218189251Ssam 2219189251Ssamstatic int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s, 2220189251Ssam struct ieee80211_sta_bss *bss) 2221189251Ssam{ 2222214734Srpaulo int res = 0, rates, done = 0, bssid_changed; 2223189251Ssam struct ieee80211_mgmt *mgmt; 2224189251Ssam#if 0 /* FIX */ 2225189251Ssam struct ieee80211_tx_control control; 2226189251Ssam struct ieee80211_rate *rate; 2227189251Ssam struct rate_control_extra extra; 2228189251Ssam#endif 2229189251Ssam u8 *pos, *buf; 2230189251Ssam size_t len; 2231189251Ssam 2232189251Ssam /* Remove possible STA entries from other IBSS networks. */ 2233189251Ssam#if 0 /* FIX */ 2234189251Ssam sta_info_flush(local, NULL); 2235189251Ssam 2236189251Ssam if (local->hw->reset_tsf) { 2237189251Ssam /* Reset own TSF to allow time synchronization work. */ 2238189251Ssam local->hw->reset_tsf(local->mdev); 2239189251Ssam } 2240189251Ssam#endif 2241214734Srpaulo bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN); 2242189251Ssam os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN); 2243214734Srpaulo if (bssid_changed) 2244214734Srpaulo wpas_notify_bssid_changed(wpa_s); 2245189251Ssam 2246189251Ssam#if 0 /* FIX */ 2247189251Ssam local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; 2248189251Ssam 2249189251Ssam sdata->drop_unencrypted = bss->capability & 2250189251Ssam host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0; 2251189251Ssam#endif 2252189251Ssam 2253189251Ssam#if 0 /* FIX */ 2254189251Ssam os_memset(&rq, 0, sizeof(rq)); 2255189251Ssam rq.m = bss->freq * 100000; 2256189251Ssam rq.e = 1; 2257189251Ssam res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL); 2258189251Ssam#endif 2259189251Ssam 2260189251Ssam if (!ieee80211_ibss_allowed(wpa_s)) { 2261189251Ssam#if 0 /* FIX */ 2262189251Ssam wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d " 2263189251Ssam "(%d MHz)", local->conf.channel, 2264189251Ssam local->conf.freq); 2265189251Ssam#endif 2266189251Ssam return -1; 2267189251Ssam } 2268189251Ssam 2269189251Ssam /* Set beacon template based on scan results */ 2270189251Ssam buf = os_malloc(400); 2271189251Ssam len = 0; 2272189251Ssam do { 2273189251Ssam if (buf == NULL) 2274189251Ssam break; 2275189251Ssam 2276189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 2277189251Ssam len += 24 + sizeof(mgmt->u.beacon); 2278189251Ssam os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); 2279189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 2280189251Ssam WLAN_FC_STYPE_BEACON); 2281189251Ssam os_memset(mgmt->da, 0xff, ETH_ALEN); 2282189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 2283189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 2284189251Ssam#if 0 /* FIX */ 2285189251Ssam mgmt->u.beacon.beacon_int = 2286189251Ssam host_to_le16(local->conf.beacon_int); 2287189251Ssam#endif 2288189251Ssam mgmt->u.beacon.capab_info = host_to_le16(bss->capability); 2289189251Ssam 2290189251Ssam pos = buf + len; 2291189251Ssam len += 2 + wpa_s->mlme.ssid_len; 2292189251Ssam *pos++ = WLAN_EID_SSID; 2293189251Ssam *pos++ = wpa_s->mlme.ssid_len; 2294189251Ssam os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); 2295189251Ssam 2296189251Ssam rates = bss->supp_rates_len; 2297189251Ssam if (rates > 8) 2298189251Ssam rates = 8; 2299189251Ssam pos = buf + len; 2300189251Ssam len += 2 + rates; 2301189251Ssam *pos++ = WLAN_EID_SUPP_RATES; 2302189251Ssam *pos++ = rates; 2303189251Ssam os_memcpy(pos, bss->supp_rates, rates); 2304189251Ssam 2305189251Ssam pos = buf + len; 2306189251Ssam len += 2 + 1; 2307189251Ssam *pos++ = WLAN_EID_DS_PARAMS; 2308189251Ssam *pos++ = 1; 2309189251Ssam *pos++ = bss->channel; 2310189251Ssam 2311189251Ssam pos = buf + len; 2312189251Ssam len += 2 + 2; 2313189251Ssam *pos++ = WLAN_EID_IBSS_PARAMS; 2314189251Ssam *pos++ = 2; 2315189251Ssam /* FIX: set ATIM window based on scan results */ 2316189251Ssam *pos++ = 0; 2317189251Ssam *pos++ = 0; 2318189251Ssam 2319189251Ssam if (bss->supp_rates_len > 8) { 2320189251Ssam rates = bss->supp_rates_len - 8; 2321189251Ssam pos = buf + len; 2322189251Ssam len += 2 + rates; 2323189251Ssam *pos++ = WLAN_EID_EXT_SUPP_RATES; 2324189251Ssam *pos++ = rates; 2325189251Ssam os_memcpy(pos, &bss->supp_rates[8], rates); 2326189251Ssam } 2327189251Ssam 2328189251Ssam#if 0 /* FIX */ 2329189251Ssam os_memset(&control, 0, sizeof(control)); 2330189251Ssam control.pkt_type = PKT_PROBE_RESP; 2331189251Ssam os_memset(&extra, 0, sizeof(extra)); 2332189251Ssam extra.endidx = local->num_curr_rates; 2333189251Ssam rate = rate_control_get_rate(wpa_s, skb, &extra); 2334189251Ssam if (rate == NULL) { 2335189251Ssam wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX " 2336189251Ssam "rate for IBSS beacon"); 2337189251Ssam break; 2338189251Ssam } 2339189251Ssam control.tx_rate = (wpa_s->mlme.short_preamble && 2340189251Ssam (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? 2341189251Ssam rate->val2 : rate->val; 2342189251Ssam control.antenna_sel = local->conf.antenna_sel; 2343189251Ssam control.power_level = local->conf.power_level; 2344189251Ssam control.no_ack = 1; 2345189251Ssam control.retry_limit = 1; 2346189251Ssam control.rts_cts_duration = 0; 2347189251Ssam#endif 2348189251Ssam 2349189251Ssam#if 0 /* FIX */ 2350189251Ssam wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC); 2351189251Ssam if (wpa_s->mlme.probe_resp) { 2352189251Ssam mgmt = (struct ieee80211_mgmt *) 2353189251Ssam wpa_s->mlme.probe_resp->data; 2354189251Ssam mgmt->frame_control = 2355189251Ssam IEEE80211_FC(WLAN_FC_TYPE_MGMT, 2356189251Ssam WLAN_FC_STYPE_PROBE_RESP); 2357189251Ssam } else { 2358189251Ssam wpa_printf(MSG_DEBUG, "MLME: Could not allocate " 2359189251Ssam "ProbeResp template for IBSS"); 2360189251Ssam } 2361189251Ssam 2362189251Ssam if (local->hw->beacon_update && 2363189251Ssam local->hw->beacon_update(wpa_s, skb, &control) == 0) { 2364189251Ssam wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon " 2365189251Ssam "template based on scan results"); 2366189251Ssam skb = NULL; 2367189251Ssam } 2368189251Ssam 2369189251Ssam rates = 0; 2370189251Ssam for (i = 0; i < bss->supp_rates_len; i++) { 2371189251Ssam int rate = (bss->supp_rates[i] & 0x7f) * 5; 2372189251Ssam if (local->conf.phymode == MODE_ATHEROS_TURBO) 2373189251Ssam rate *= 2; 2374189251Ssam for (j = 0; j < local->num_curr_rates; j++) 2375214734Srpaulo if (local->curr_rates[j] == rate) 2376189251Ssam rates |= BIT(j); 2377189251Ssam } 2378189251Ssam wpa_s->mlme.supp_rates_bits = rates; 2379189251Ssam#endif 2380189251Ssam done = 1; 2381189251Ssam } while (0); 2382189251Ssam 2383189251Ssam os_free(buf); 2384189251Ssam if (!done) { 2385189251Ssam wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon " 2386189251Ssam "template"); 2387189251Ssam } 2388189251Ssam 2389189251Ssam wpa_s->mlme.state = IEEE80211_IBSS_JOINED; 2390189251Ssam ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); 2391189251Ssam 2392189251Ssam return res; 2393189251Ssam} 2394189251Ssam 2395189251Ssam 2396189251Ssam#if 0 /* FIX */ 2397189251Ssamstatic int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s) 2398189251Ssam{ 2399189251Ssam struct ieee80211_sta_bss *bss; 2400189251Ssam u8 bssid[ETH_ALEN], *pos; 2401189251Ssam int i; 2402189251Ssam 2403189251Ssam#if 0 2404189251Ssam /* Easier testing, use fixed BSSID. */ 2405189251Ssam os_memset(bssid, 0xfe, ETH_ALEN); 2406189251Ssam#else 2407189251Ssam /* Generate random, not broadcast, locally administered BSSID. Mix in 2408189251Ssam * own MAC address to make sure that devices that do not have proper 2409189251Ssam * random number generator get different BSSID. */ 2410189251Ssam os_get_random(bssid, ETH_ALEN); 2411189251Ssam for (i = 0; i < ETH_ALEN; i++) 2412189251Ssam bssid[i] ^= wpa_s->own_addr[i]; 2413189251Ssam bssid[0] &= ~0x01; 2414189251Ssam bssid[0] |= 0x02; 2415189251Ssam#endif 2416189251Ssam 2417189251Ssam wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID " 2418189251Ssam MACSTR "", MAC2STR(bssid)); 2419189251Ssam 2420189251Ssam bss = ieee80211_bss_add(wpa_s, bssid); 2421189251Ssam if (bss == NULL) 2422189251Ssam return -ENOMEM; 2423189251Ssam 2424189251Ssam#if 0 /* FIX */ 2425189251Ssam if (local->conf.beacon_int == 0) 2426189251Ssam local->conf.beacon_int = 100; 2427189251Ssam bss->beacon_int = local->conf.beacon_int; 2428189251Ssam bss->hw_mode = local->conf.phymode; 2429189251Ssam bss->channel = local->conf.channel; 2430189251Ssam bss->freq = local->conf.freq; 2431189251Ssam#endif 2432189251Ssam os_get_time(&bss->last_update); 2433189251Ssam bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS); 2434189251Ssam#if 0 /* FIX */ 2435189251Ssam if (sdata->default_key) { 2436189251Ssam bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY); 2437189251Ssam } else 2438189251Ssam sdata->drop_unencrypted = 0; 2439189251Ssam bss->supp_rates_len = local->num_curr_rates; 2440189251Ssam#endif 2441189251Ssam pos = bss->supp_rates; 2442189251Ssam#if 0 /* FIX */ 2443189251Ssam for (i = 0; i < local->num_curr_rates; i++) { 2444214734Srpaulo int rate = local->curr_rates[i]; 2445189251Ssam if (local->conf.phymode == MODE_ATHEROS_TURBO) 2446189251Ssam rate /= 2; 2447189251Ssam *pos++ = (u8) (rate / 5); 2448189251Ssam } 2449189251Ssam#endif 2450189251Ssam 2451189251Ssam return ieee80211_sta_join_ibss(wpa_s, bss); 2452189251Ssam} 2453189251Ssam#endif 2454189251Ssam 2455189251Ssam 2456189251Ssamstatic int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s) 2457189251Ssam{ 2458189251Ssam struct ieee80211_sta_bss *bss; 2459189251Ssam int found = 0; 2460189251Ssam u8 bssid[ETH_ALEN]; 2461189251Ssam int active_ibss; 2462189251Ssam struct os_time now; 2463189251Ssam 2464189251Ssam if (wpa_s->mlme.ssid_len == 0) 2465189251Ssam return -EINVAL; 2466189251Ssam 2467189251Ssam active_ibss = ieee80211_sta_active_ibss(wpa_s); 2468189251Ssam#ifdef IEEE80211_IBSS_DEBUG 2469189251Ssam wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)", 2470189251Ssam active_ibss); 2471189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 2472189251Ssam for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { 2473189251Ssam if (wpa_s->mlme.ssid_len != bss->ssid_len || 2474189251Ssam os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0 2475189251Ssam || !(bss->capability & WLAN_CAPABILITY_IBSS)) 2476189251Ssam continue; 2477189251Ssam#ifdef IEEE80211_IBSS_DEBUG 2478189251Ssam wpa_printf(MSG_DEBUG, " bssid=" MACSTR " found", 2479189251Ssam MAC2STR(bss->bssid)); 2480189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 2481189251Ssam os_memcpy(bssid, bss->bssid, ETH_ALEN); 2482189251Ssam found = 1; 2483189251Ssam if (active_ibss || 2484189251Ssam os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) 2485189251Ssam break; 2486189251Ssam } 2487189251Ssam 2488189251Ssam#ifdef IEEE80211_IBSS_DEBUG 2489189251Ssam wpa_printf(MSG_DEBUG, " sta_find_ibss: selected " MACSTR " current " 2490189251Ssam MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid)); 2491189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 2492189251Ssam if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 && 2493189251Ssam (bss = ieee80211_bss_get(wpa_s, bssid))) { 2494189251Ssam wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR 2495189251Ssam " based on configured SSID", 2496189251Ssam MAC2STR(bssid)); 2497189251Ssam return ieee80211_sta_join_ibss(wpa_s, bss); 2498189251Ssam } 2499189251Ssam#ifdef IEEE80211_IBSS_DEBUG 2500189251Ssam wpa_printf(MSG_DEBUG, " did not try to join ibss"); 2501189251Ssam#endif /* IEEE80211_IBSS_DEBUG */ 2502189251Ssam 2503189251Ssam /* Selected IBSS not found in current scan results - try to scan */ 2504189251Ssam os_get_time(&now); 2505189251Ssam#if 0 /* FIX */ 2506189251Ssam if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED && 2507189251Ssam !ieee80211_sta_active_ibss(wpa_s)) { 2508189251Ssam ieee80211_reschedule_timer(wpa_s, 2509189251Ssam IEEE80211_IBSS_MERGE_INTERVAL); 2510189251Ssam } else if (time_after(jiffies, wpa_s->mlme.last_scan_completed + 2511189251Ssam IEEE80211_SCAN_INTERVAL)) { 2512189251Ssam wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS " 2513189251Ssam "to join"); 2514189251Ssam return ieee80211_sta_req_scan(wpa_s->mlme.ssid, 2515189251Ssam wpa_s->mlme.ssid_len); 2516189251Ssam } else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) { 2517189251Ssam int interval = IEEE80211_SCAN_INTERVAL; 2518189251Ssam 2519189251Ssam if (time_after(jiffies, wpa_s->mlme.ibss_join_req + 2520189251Ssam IEEE80211_IBSS_JOIN_TIMEOUT)) { 2521189251Ssam if (wpa_s->mlme.create_ibss && 2522189251Ssam ieee80211_ibss_allowed(wpa_s)) 2523189251Ssam return ieee80211_sta_create_ibss(wpa_s); 2524189251Ssam if (wpa_s->mlme.create_ibss) { 2525189251Ssam wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed " 2526189251Ssam "on the configured channel %d " 2527189251Ssam "(%d MHz)", 2528189251Ssam local->conf.channel, 2529189251Ssam local->conf.freq); 2530189251Ssam } 2531189251Ssam 2532189251Ssam /* No IBSS found - decrease scan interval and continue 2533189251Ssam * scanning. */ 2534189251Ssam interval = IEEE80211_SCAN_INTERVAL_SLOW; 2535189251Ssam } 2536189251Ssam 2537189251Ssam wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; 2538189251Ssam ieee80211_reschedule_timer(wpa_s, interval); 2539189251Ssam return 0; 2540189251Ssam } 2541189251Ssam#endif 2542189251Ssam 2543189251Ssam return 0; 2544189251Ssam} 2545189251Ssam 2546189251Ssam 2547189251Ssamint ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid, 2548189251Ssam size_t *len) 2549189251Ssam{ 2550189251Ssam os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); 2551189251Ssam *len = wpa_s->mlme.ssid_len; 2552189251Ssam return 0; 2553189251Ssam} 2554189251Ssam 2555189251Ssam 2556189251Ssamint ieee80211_sta_associate(struct wpa_supplicant *wpa_s, 2557189251Ssam struct wpa_driver_associate_params *params) 2558189251Ssam{ 2559189251Ssam struct ieee80211_sta_bss *bss; 2560214734Srpaulo int bssid_changed; 2561189251Ssam 2562189251Ssam wpa_s->mlme.bssid_set = 0; 2563189251Ssam wpa_s->mlme.freq = params->freq; 2564189251Ssam if (params->bssid) { 2565214734Srpaulo bssid_changed = os_memcmp(wpa_s->bssid, params->bssid, 2566214734Srpaulo ETH_ALEN); 2567189251Ssam os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN); 2568214734Srpaulo if (bssid_changed) 2569214734Srpaulo wpas_notify_bssid_changed(wpa_s); 2570214734Srpaulo 2571189251Ssam if (!is_zero_ether_addr(params->bssid)) 2572189251Ssam wpa_s->mlme.bssid_set = 1; 2573189251Ssam bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); 2574189251Ssam if (bss) { 2575189251Ssam wpa_s->mlme.phymode = bss->hw_mode; 2576189251Ssam wpa_s->mlme.channel = bss->channel; 2577189251Ssam wpa_s->mlme.freq = bss->freq; 2578189251Ssam } 2579189251Ssam } 2580189251Ssam 2581189251Ssam#if 0 /* FIX */ 2582189251Ssam /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is 2583189251Ssam * not defined. */ 2584189251Ssam if (local->hw->conf_tx) { 2585189251Ssam struct ieee80211_tx_queue_params qparam; 2586189251Ssam int i; 2587189251Ssam 2588189251Ssam os_memset(&qparam, 0, sizeof(qparam)); 2589189251Ssam /* TODO: are these ok defaults for all hw_modes? */ 2590189251Ssam qparam.aifs = 2; 2591189251Ssam qparam.cw_min = 2592189251Ssam local->conf.phymode == MODE_IEEE80211B ? 31 : 15; 2593189251Ssam qparam.cw_max = 1023; 2594189251Ssam qparam.burst_time = 0; 2595189251Ssam for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) 2596189251Ssam { 2597189251Ssam local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0, 2598189251Ssam &qparam); 2599189251Ssam } 2600189251Ssam /* IBSS uses different parameters for Beacon sending */ 2601189251Ssam qparam.cw_min++; 2602189251Ssam qparam.cw_min *= 2; 2603189251Ssam qparam.cw_min--; 2604189251Ssam local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam); 2605189251Ssam } 2606189251Ssam#endif 2607189251Ssam 2608189251Ssam if (wpa_s->mlme.ssid_len != params->ssid_len || 2609189251Ssam os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0) 2610189251Ssam wpa_s->mlme.prev_bssid_set = 0; 2611189251Ssam os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len); 2612189251Ssam os_memset(wpa_s->mlme.ssid + params->ssid_len, 0, 2613189251Ssam MAX_SSID_LEN - params->ssid_len); 2614189251Ssam wpa_s->mlme.ssid_len = params->ssid_len; 2615189251Ssam wpa_s->mlme.ssid_set = 1; 2616189251Ssam 2617189251Ssam os_free(wpa_s->mlme.extra_ie); 2618189251Ssam if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { 2619189251Ssam wpa_s->mlme.extra_ie = NULL; 2620189251Ssam wpa_s->mlme.extra_ie_len = 0; 2621189251Ssam } else { 2622189251Ssam wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len); 2623189251Ssam if (wpa_s->mlme.extra_ie == NULL) { 2624189251Ssam wpa_s->mlme.extra_ie_len = 0; 2625189251Ssam return -1; 2626189251Ssam } 2627189251Ssam os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie, 2628189251Ssam params->wpa_ie_len); 2629189251Ssam wpa_s->mlme.extra_ie_len = params->wpa_ie_len; 2630189251Ssam } 2631189251Ssam 2632189251Ssam wpa_s->mlme.key_mgmt = params->key_mgmt_suite; 2633189251Ssam 2634189251Ssam ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, 2635189251Ssam wpa_s->mlme.channel, wpa_s->mlme.freq); 2636189251Ssam 2637214734Srpaulo if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) { 2638189251Ssam os_get_time(&wpa_s->mlme.ibss_join_req); 2639189251Ssam wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; 2640189251Ssam return ieee80211_sta_find_ibss(wpa_s); 2641189251Ssam } 2642189251Ssam 2643189251Ssam if (wpa_s->mlme.bssid_set) 2644189251Ssam ieee80211_sta_new_auth(wpa_s); 2645189251Ssam 2646189251Ssam return 0; 2647189251Ssam} 2648189251Ssam 2649189251Ssam 2650189251Ssamstatic void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s) 2651189251Ssam{ 2652189251Ssam wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel; 2653189251Ssam wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq; 2654189251Ssam wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode; 2655189251Ssam} 2656189251Ssam 2657189251Ssam 2658189251Ssamstatic int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s) 2659189251Ssam{ 2660189251Ssam wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel; 2661189251Ssam wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq; 2662189251Ssam wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode; 2663189251Ssam if (wpa_s->mlme.freq == 0) 2664189251Ssam return 0; 2665189251Ssam return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, 2666189251Ssam wpa_s->mlme.channel, 2667189251Ssam wpa_s->mlme.freq); 2668189251Ssam} 2669189251Ssam 2670189251Ssam 2671189251Ssamstatic int ieee80211_active_scan(struct wpa_supplicant *wpa_s) 2672189251Ssam{ 2673189251Ssam size_t m; 2674189251Ssam int c; 2675189251Ssam 2676189251Ssam for (m = 0; m < wpa_s->mlme.num_modes; m++) { 2677214734Srpaulo struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m]; 2678189251Ssam if ((int) mode->mode != (int) wpa_s->mlme.phymode) 2679189251Ssam continue; 2680189251Ssam for (c = 0; c < mode->num_channels; c++) { 2681214734Srpaulo struct hostapd_channel_data *chan = &mode->channels[c]; 2682214734Srpaulo if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && 2683189251Ssam chan->chan == wpa_s->mlme.channel) { 2684214734Srpaulo if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN)) 2685189251Ssam return 1; 2686189251Ssam break; 2687189251Ssam } 2688189251Ssam } 2689189251Ssam } 2690189251Ssam 2691189251Ssam return 0; 2692189251Ssam} 2693189251Ssam 2694189251Ssam 2695189251Ssamstatic void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx) 2696189251Ssam{ 2697189251Ssam struct wpa_supplicant *wpa_s = eloop_ctx; 2698214734Srpaulo struct hostapd_hw_modes *mode; 2699214734Srpaulo struct hostapd_channel_data *chan; 2700189251Ssam int skip = 0; 2701189251Ssam int timeout = 0; 2702189251Ssam struct wpa_ssid *ssid = wpa_s->current_ssid; 2703189251Ssam int adhoc; 2704189251Ssam 2705189251Ssam if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL) 2706189251Ssam return; 2707189251Ssam 2708189251Ssam adhoc = ssid && ssid->mode == 1; 2709189251Ssam 2710189251Ssam switch (wpa_s->mlme.scan_state) { 2711189251Ssam case SCAN_SET_CHANNEL: 2712189251Ssam mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]; 2713189251Ssam if (wpa_s->mlme.scan_hw_mode_idx >= 2714189251Ssam (int) wpa_s->mlme.num_modes || 2715189251Ssam (wpa_s->mlme.scan_hw_mode_idx + 1 == 2716189251Ssam (int) wpa_s->mlme.num_modes 2717189251Ssam && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) { 2718189251Ssam if (ieee80211_sta_restore_oper_chan(wpa_s)) { 2719189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to " 2720189251Ssam "restore operational channel after " 2721189251Ssam "scan"); 2722189251Ssam } 2723189251Ssam wpa_printf(MSG_DEBUG, "MLME: scan completed"); 2724189251Ssam wpa_s->mlme.sta_scanning = 0; 2725189251Ssam os_get_time(&wpa_s->mlme.last_scan_completed); 2726189251Ssam wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); 2727189251Ssam if (adhoc) { 2728189251Ssam if (!wpa_s->mlme.bssid_set || 2729189251Ssam (wpa_s->mlme.state == 2730189251Ssam IEEE80211_IBSS_JOINED && 2731189251Ssam !ieee80211_sta_active_ibss(wpa_s))) 2732189251Ssam ieee80211_sta_find_ibss(wpa_s); 2733189251Ssam } 2734189251Ssam return; 2735189251Ssam } 2736189251Ssam skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode)); 2737189251Ssam chan = &mode->channels[wpa_s->mlme.scan_channel_idx]; 2738214734Srpaulo if ((chan->flag & HOSTAPD_CHAN_DISABLED) || 2739214734Srpaulo (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) || 2740214734Srpaulo (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) && 2741214734Srpaulo mode->mode == HOSTAPD_MODE_IEEE80211B && 2742189251Ssam wpa_s->mlme.scan_skip_11b)) 2743189251Ssam skip = 1; 2744214734Srpaulo if (!skip && wpa_s->mlme.scan_freqs) { 2745214734Srpaulo int i, found = 0; 2746214734Srpaulo for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) { 2747214734Srpaulo if (wpa_s->mlme.scan_freqs[i] == chan->freq) { 2748214734Srpaulo found = 1; 2749214734Srpaulo break; 2750214734Srpaulo } 2751214734Srpaulo } 2752214734Srpaulo if (!found) 2753214734Srpaulo skip = 1; 2754214734Srpaulo } 2755189251Ssam 2756189251Ssam if (!skip) { 2757189251Ssam wpa_printf(MSG_MSGDUMP, 2758189251Ssam "MLME: scan channel %d (%d MHz)", 2759189251Ssam chan->chan, chan->freq); 2760189251Ssam 2761189251Ssam wpa_s->mlme.channel = chan->chan; 2762189251Ssam wpa_s->mlme.freq = chan->freq; 2763189251Ssam wpa_s->mlme.phymode = mode->mode; 2764189251Ssam if (ieee80211_sta_set_channel(wpa_s, mode->mode, 2765189251Ssam chan->chan, chan->freq)) 2766189251Ssam { 2767189251Ssam wpa_printf(MSG_DEBUG, "MLME: failed to set " 2768189251Ssam "channel %d (%d MHz) for scan", 2769189251Ssam chan->chan, chan->freq); 2770189251Ssam skip = 1; 2771189251Ssam } 2772189251Ssam } 2773189251Ssam 2774189251Ssam wpa_s->mlme.scan_channel_idx++; 2775189251Ssam if (wpa_s->mlme.scan_channel_idx >= 2776189251Ssam wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]. 2777189251Ssam num_channels) { 2778189251Ssam wpa_s->mlme.scan_hw_mode_idx++; 2779189251Ssam wpa_s->mlme.scan_channel_idx = 0; 2780189251Ssam } 2781189251Ssam 2782189251Ssam if (skip) { 2783189251Ssam timeout = 0; 2784189251Ssam break; 2785189251Ssam } 2786189251Ssam 2787189251Ssam timeout = IEEE80211_PROBE_DELAY; 2788189251Ssam wpa_s->mlme.scan_state = SCAN_SEND_PROBE; 2789189251Ssam break; 2790189251Ssam case SCAN_SEND_PROBE: 2791189251Ssam if (ieee80211_active_scan(wpa_s)) { 2792189251Ssam ieee80211_send_probe_req(wpa_s, NULL, 2793189251Ssam wpa_s->mlme.scan_ssid, 2794189251Ssam wpa_s->mlme.scan_ssid_len); 2795189251Ssam timeout = IEEE80211_CHANNEL_TIME; 2796189251Ssam } else { 2797189251Ssam timeout = IEEE80211_PASSIVE_CHANNEL_TIME; 2798189251Ssam } 2799189251Ssam wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; 2800189251Ssam break; 2801189251Ssam } 2802189251Ssam 2803189251Ssam eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000), 2804189251Ssam ieee80211_sta_scan_timer, wpa_s, NULL); 2805189251Ssam} 2806189251Ssam 2807189251Ssam 2808214734Srpauloint ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, 2809214734Srpaulo struct wpa_driver_scan_params *params) 2810189251Ssam{ 2811214734Srpaulo const u8 *ssid = params->ssids[0].ssid; 2812214734Srpaulo size_t ssid_len = params->ssids[0].ssid_len; 2813214734Srpaulo 2814189251Ssam if (ssid_len > MAX_SSID_LEN) 2815189251Ssam return -1; 2816189251Ssam 2817189251Ssam /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) 2818189251Ssam * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS 2819189251Ssam * BSSID: MACAddress 2820189251Ssam * SSID 2821189251Ssam * ScanType: ACTIVE, PASSIVE 2822189251Ssam * ProbeDelay: delay (in microseconds) to be used prior to transmitting 2823189251Ssam * a Probe frame during active scanning 2824189251Ssam * ChannelList 2825189251Ssam * MinChannelTime (>= ProbeDelay), in TU 2826189251Ssam * MaxChannelTime: (>= MinChannelTime), in TU 2827189251Ssam */ 2828189251Ssam 2829189251Ssam /* MLME-SCAN.confirm 2830189251Ssam * BSSDescriptionSet 2831189251Ssam * ResultCode: SUCCESS, INVALID_PARAMETERS 2832189251Ssam */ 2833189251Ssam 2834189251Ssam /* TODO: if assoc, move to power save mode for the duration of the 2835189251Ssam * scan */ 2836189251Ssam 2837189251Ssam if (wpa_s->mlme.sta_scanning) 2838189251Ssam return -1; 2839189251Ssam 2840189251Ssam wpa_printf(MSG_DEBUG, "MLME: starting scan"); 2841189251Ssam 2842214734Srpaulo ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies, 2843214734Srpaulo params->extra_ies_len); 2844214734Srpaulo 2845214734Srpaulo os_free(wpa_s->mlme.scan_freqs); 2846214734Srpaulo if (params->freqs) { 2847214734Srpaulo int i; 2848214734Srpaulo for (i = 0; params->freqs[i]; i++) 2849214734Srpaulo ; 2850214734Srpaulo wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int)); 2851214734Srpaulo if (wpa_s->mlme.scan_freqs) 2852214734Srpaulo os_memcpy(wpa_s->mlme.scan_freqs, params->freqs, 2853214734Srpaulo (i + 1) * sizeof(int)); 2854214734Srpaulo } else 2855214734Srpaulo wpa_s->mlme.scan_freqs = NULL; 2856214734Srpaulo 2857189251Ssam ieee80211_sta_save_oper_chan(wpa_s); 2858189251Ssam 2859189251Ssam wpa_s->mlme.sta_scanning = 1; 2860189251Ssam /* TODO: stop TX queue? */ 2861189251Ssam 2862189251Ssam if (ssid) { 2863189251Ssam wpa_s->mlme.scan_ssid_len = ssid_len; 2864189251Ssam os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len); 2865189251Ssam } else 2866189251Ssam wpa_s->mlme.scan_ssid_len = 0; 2867189251Ssam wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not 2868189251Ssam * supported */ 2869189251Ssam wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; 2870189251Ssam wpa_s->mlme.scan_hw_mode_idx = 0; 2871189251Ssam wpa_s->mlme.scan_channel_idx = 0; 2872189251Ssam eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL); 2873189251Ssam 2874189251Ssam return 0; 2875189251Ssam} 2876189251Ssam 2877189251Ssam 2878189251Ssamstruct wpa_scan_results * 2879189251Ssamieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s) 2880189251Ssam{ 2881189251Ssam size_t ap_num = 0; 2882189251Ssam struct wpa_scan_results *res; 2883189251Ssam struct wpa_scan_res *r; 2884189251Ssam struct ieee80211_sta_bss *bss; 2885189251Ssam 2886189251Ssam res = os_zalloc(sizeof(*res)); 2887189251Ssam for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) 2888189251Ssam ap_num++; 2889189251Ssam res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *)); 2890189251Ssam if (res->res == NULL) { 2891189251Ssam os_free(res); 2892189251Ssam return NULL; 2893189251Ssam } 2894189251Ssam 2895189251Ssam for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { 2896189251Ssam r = os_zalloc(sizeof(*r) + bss->ie_len); 2897189251Ssam if (r == NULL) 2898189251Ssam break; 2899189251Ssam os_memcpy(r->bssid, bss->bssid, ETH_ALEN); 2900189251Ssam r->freq = bss->freq; 2901189251Ssam r->beacon_int = bss->beacon_int; 2902189251Ssam r->caps = bss->capability; 2903189251Ssam r->level = bss->rssi; 2904189251Ssam r->tsf = bss->timestamp; 2905189251Ssam if (bss->ie) { 2906189251Ssam r->ie_len = bss->ie_len; 2907189251Ssam os_memcpy(r + 1, bss->ie, bss->ie_len); 2908189251Ssam } 2909189251Ssam 2910189251Ssam res->res[res->num++] = r; 2911189251Ssam } 2912189251Ssam 2913189251Ssam return res; 2914189251Ssam} 2915189251Ssam 2916189251Ssam 2917189251Ssam#if 0 /* FIX */ 2918189251Ssamstruct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s, 2919189251Ssam struct sk_buff *skb, u8 *bssid, 2920189251Ssam u8 *addr) 2921189251Ssam{ 2922189251Ssam struct ieee80211_local *local = dev->priv; 2923189251Ssam struct list_head *ptr; 2924189251Ssam struct sta_info *sta; 2925189251Ssam struct wpa_supplicant *sta_dev = NULL; 2926189251Ssam 2927189251Ssam /* TODO: Could consider removing the least recently used entry and 2928189251Ssam * allow new one to be added. */ 2929189251Ssam if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { 2930189251Ssam if (net_ratelimit()) { 2931189251Ssam wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS " 2932189251Ssam "STA entry " MACSTR, MAC2STR(addr)); 2933189251Ssam } 2934189251Ssam return NULL; 2935189251Ssam } 2936189251Ssam 2937189251Ssam spin_lock_bh(&local->sub_if_lock); 2938189251Ssam list_for_each(ptr, &local->sub_if_list) { 2939189251Ssam sdata = list_entry(ptr, struct ieee80211_sub_if_data, list); 2940189251Ssam if (sdata->type == IEEE80211_SUB_IF_TYPE_STA && 2941189251Ssam os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { 2942189251Ssam sta_dev = sdata->dev; 2943189251Ssam break; 2944189251Ssam } 2945189251Ssam } 2946189251Ssam spin_unlock_bh(&local->sub_if_lock); 2947189251Ssam 2948189251Ssam if (sta_dev == NULL) 2949189251Ssam return NULL; 2950189251Ssam 2951189251Ssam wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR 2952189251Ssam " (dev=%s)", MAC2STR(addr), sta_dev->name); 2953189251Ssam 2954189251Ssam sta = sta_info_add(wpa_s, addr); 2955189251Ssam if (sta == NULL) { 2956189251Ssam return NULL; 2957189251Ssam } 2958189251Ssam 2959189251Ssam sta->dev = sta_dev; 2960189251Ssam sta->supp_rates = wpa_s->mlme.supp_rates_bits; 2961189251Ssam 2962189251Ssam rate_control_rate_init(local, sta); 2963189251Ssam 2964189251Ssam return sta; /* caller will call sta_info_release() */ 2965189251Ssam} 2966189251Ssam#endif 2967189251Ssam 2968189251Ssam 2969189251Ssamint ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason) 2970189251Ssam{ 2971189251Ssam wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason); 2972189251Ssam 2973189251Ssam ieee80211_send_deauth(wpa_s, reason); 2974189251Ssam ieee80211_set_associated(wpa_s, 0); 2975189251Ssam return 0; 2976189251Ssam} 2977189251Ssam 2978189251Ssam 2979189251Ssamint ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason) 2980189251Ssam{ 2981189251Ssam wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason); 2982189251Ssam 2983189251Ssam if (!wpa_s->mlme.associated) 2984189251Ssam return -1; 2985189251Ssam 2986189251Ssam ieee80211_send_disassoc(wpa_s, reason); 2987189251Ssam ieee80211_set_associated(wpa_s, 0); 2988189251Ssam return 0; 2989189251Ssam} 2990189251Ssam 2991189251Ssam 2992189251Ssamvoid ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len, 2993189251Ssam struct ieee80211_rx_status *rx_status) 2994189251Ssam{ 2995189251Ssam struct ieee80211_mgmt *mgmt; 2996189251Ssam u16 fc; 2997189251Ssam const u8 *pos; 2998189251Ssam 2999189251Ssam /* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */ 3000189251Ssam 3001189251Ssam if (wpa_s->mlme.sta_scanning) { 3002189251Ssam ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status); 3003189251Ssam return; 3004189251Ssam } 3005189251Ssam 3006189251Ssam if (len < 24) 3007189251Ssam return; 3008189251Ssam 3009189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 3010189251Ssam fc = le_to_host16(mgmt->frame_control); 3011189251Ssam 3012189251Ssam if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) 3013189251Ssam ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status); 3014189251Ssam else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { 3015189251Ssam if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) != 3016189251Ssam WLAN_FC_FROMDS) 3017189251Ssam return; 3018189251Ssam /* mgmt->sa is actually BSSID for FromDS data frames */ 3019189251Ssam if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) 3020189251Ssam return; 3021189251Ssam /* Skip IEEE 802.11 and LLC headers */ 3022189251Ssam pos = buf + 24 + 6; 3023189251Ssam if (WPA_GET_BE16(pos) != ETH_P_EAPOL) 3024189251Ssam return; 3025189251Ssam pos += 2; 3026189251Ssam /* mgmt->bssid is actually BSSID for SA data frames */ 3027189251Ssam wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid, 3028189251Ssam pos, buf + len - pos); 3029189251Ssam } 3030189251Ssam} 3031189251Ssam 3032189251Ssam 3033214734Srpaulovoid ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features, 3034189251Ssam size_t num_hw_features) 3035189251Ssam{ 3036189251Ssam size_t i; 3037189251Ssam 3038189251Ssam if (hw_features == NULL) 3039189251Ssam return; 3040189251Ssam 3041189251Ssam for (i = 0; i < num_hw_features; i++) { 3042189251Ssam os_free(hw_features[i].channels); 3043189251Ssam os_free(hw_features[i].rates); 3044189251Ssam } 3045189251Ssam 3046189251Ssam os_free(hw_features); 3047189251Ssam} 3048189251Ssam 3049189251Ssam 3050189251Ssamint ieee80211_sta_init(struct wpa_supplicant *wpa_s) 3051189251Ssam{ 3052189251Ssam u16 num_modes, flags; 3053189251Ssam 3054189251Ssam wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, 3055189251Ssam &flags); 3056189251Ssam if (wpa_s->mlme.modes == NULL) { 3057189251Ssam wpa_printf(MSG_ERROR, "MLME: Failed to read supported " 3058189251Ssam "channels and rates from the driver"); 3059189251Ssam return -1; 3060189251Ssam } 3061189251Ssam 3062189251Ssam wpa_s->mlme.num_modes = num_modes; 3063189251Ssam 3064214734Srpaulo wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A; 3065214734Srpaulo wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B; 3066214734Srpaulo wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G; 3067189251Ssam 3068214734Srpaulo wpa_s->mlme.wmm_enabled = 1; 3069214734Srpaulo 3070189251Ssam return 0; 3071189251Ssam} 3072189251Ssam 3073189251Ssam 3074189251Ssamvoid ieee80211_sta_deinit(struct wpa_supplicant *wpa_s) 3075189251Ssam{ 3076189251Ssam eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); 3077189251Ssam eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL); 3078189251Ssam os_free(wpa_s->mlme.extra_ie); 3079189251Ssam wpa_s->mlme.extra_ie = NULL; 3080189251Ssam os_free(wpa_s->mlme.extra_probe_ie); 3081189251Ssam wpa_s->mlme.extra_probe_ie = NULL; 3082189251Ssam os_free(wpa_s->mlme.assocreq_ies); 3083189251Ssam wpa_s->mlme.assocreq_ies = NULL; 3084189251Ssam os_free(wpa_s->mlme.assocresp_ies); 3085189251Ssam wpa_s->mlme.assocresp_ies = NULL; 3086189251Ssam ieee80211_bss_list_deinit(wpa_s); 3087189251Ssam ieee80211_sta_free_hw_features(wpa_s->mlme.modes, 3088189251Ssam wpa_s->mlme.num_modes); 3089189251Ssam#ifdef CONFIG_IEEE80211R 3090189251Ssam os_free(wpa_s->mlme.ft_ies); 3091189251Ssam wpa_s->mlme.ft_ies = NULL; 3092189251Ssam wpa_s->mlme.ft_ies_len = 0; 3093189251Ssam#endif /* CONFIG_IEEE80211R */ 3094214734Srpaulo 3095214734Srpaulo os_free(wpa_s->mlme.scan_freqs); 3096214734Srpaulo wpa_s->mlme.scan_freqs = NULL; 3097189251Ssam} 3098189251Ssam 3099189251Ssam 3100189251Ssam#ifdef CONFIG_IEEE80211R 3101189251Ssam 3102189251Ssamint ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, 3103189251Ssam const u8 *ies, size_t ies_len) 3104189251Ssam{ 3105189251Ssam if (md == NULL) { 3106189251Ssam wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain"); 3107189251Ssam os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN); 3108189251Ssam } else { 3109189251Ssam wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR, 3110189251Ssam MAC2STR(md)); 3111189251Ssam os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN); 3112189251Ssam } 3113189251Ssam 3114189251Ssam wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len); 3115189251Ssam os_free(wpa_s->mlme.ft_ies); 3116189251Ssam wpa_s->mlme.ft_ies = os_malloc(ies_len); 3117189251Ssam if (wpa_s->mlme.ft_ies == NULL) 3118189251Ssam return -1; 3119189251Ssam os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len); 3120189251Ssam wpa_s->mlme.ft_ies_len = ies_len; 3121189251Ssam 3122189251Ssam return 0; 3123189251Ssam} 3124189251Ssam 3125189251Ssam 3126189251Ssamint ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, 3127189251Ssam const u8 *target_ap, 3128189251Ssam const u8 *ies, size_t ies_len) 3129189251Ssam{ 3130189251Ssam u8 *buf; 3131189251Ssam size_t len; 3132189251Ssam struct ieee80211_mgmt *mgmt; 3133189251Ssam int res; 3134189251Ssam 3135189251Ssam /* 3136189251Ssam * Action frame payload: 3137189251Ssam * Category[1] = 6 (Fast BSS Transition) 3138189251Ssam * Action[1] = 1 (Fast BSS Transition Request) 3139189251Ssam * STA Address 3140189251Ssam * Target AP Address 3141189251Ssam * FT IEs 3142189251Ssam */ 3143189251Ssam 3144189251Ssam buf = os_zalloc(sizeof(*mgmt) + ies_len); 3145189251Ssam if (buf == NULL) { 3146189251Ssam wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " 3147189251Ssam "FT action frame"); 3148189251Ssam return -1; 3149189251Ssam } 3150189251Ssam 3151189251Ssam mgmt = (struct ieee80211_mgmt *) buf; 3152189251Ssam len = 24; 3153189251Ssam os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); 3154189251Ssam os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); 3155189251Ssam os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); 3156189251Ssam mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, 3157189251Ssam WLAN_FC_STYPE_ACTION); 3158189251Ssam mgmt->u.action.category = WLAN_ACTION_FT; 3159189251Ssam mgmt->u.action.u.ft_action_req.action = action; 3160189251Ssam os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr, 3161189251Ssam ETH_ALEN); 3162189251Ssam os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap, 3163189251Ssam ETH_ALEN); 3164189251Ssam os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len); 3165189251Ssam len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len; 3166189251Ssam 3167189251Ssam wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d " 3168189251Ssam "Target AP=" MACSTR " body_len=%lu", 3169189251Ssam action, MAC2STR(target_ap), (unsigned long) ies_len); 3170189251Ssam 3171189251Ssam res = ieee80211_sta_tx(wpa_s, buf, len); 3172189251Ssam os_free(buf); 3173189251Ssam 3174189251Ssam return res; 3175189251Ssam} 3176189251Ssam 3177189251Ssam#endif /* CONFIG_IEEE80211R */ 3178189251Ssam 3179189251Ssam 3180214734Srpaulostatic int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, 3181214734Srpaulo const u8 *ies, size_t ies_len) 3182189251Ssam{ 3183189251Ssam os_free(wpa_s->mlme.extra_probe_ie); 3184189251Ssam wpa_s->mlme.extra_probe_ie = NULL; 3185189251Ssam wpa_s->mlme.extra_probe_ie_len = 0; 3186189251Ssam 3187189251Ssam if (ies == NULL) 3188189251Ssam return 0; 3189189251Ssam 3190189251Ssam wpa_s->mlme.extra_probe_ie = os_malloc(ies_len); 3191189251Ssam if (wpa_s->mlme.extra_probe_ie == NULL) 3192189251Ssam return -1; 3193189251Ssam 3194189251Ssam os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len); 3195189251Ssam wpa_s->mlme.extra_probe_ie_len = ies_len; 3196189251Ssam 3197189251Ssam return 0; 3198189251Ssam} 3199