diff options
Diffstat (limited to 'contrib/wpa/wpa_supplicant/mlme.c')
-rw-r--r-- | contrib/wpa/wpa_supplicant/mlme.c | 3198 |
1 files changed, 0 insertions, 3198 deletions
diff --git a/contrib/wpa/wpa_supplicant/mlme.c b/contrib/wpa/wpa_supplicant/mlme.c deleted file mode 100644 index eb60ac5..0000000 --- a/contrib/wpa/wpa_supplicant/mlme.c +++ /dev/null @@ -1,3198 +0,0 @@ -/* - * WPA Supplicant - Client mode MLME - * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> - * Copyright (c) 2004, Instant802 Networks, Inc. - * Copyright (c) 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "eloop.h" -#include "config_ssid.h" -#include "wpa_supplicant_i.h" -#include "notify.h" -#include "driver_i.h" -#include "rsn_supp/wpa.h" -#include "common/ieee802_11_defs.h" -#include "common/ieee802_11_common.h" -#include "mlme.h" - - -/* Timeouts and intervals in milliseconds */ -#define IEEE80211_AUTH_TIMEOUT (200) -#define IEEE80211_AUTH_MAX_TRIES 3 -#define IEEE80211_ASSOC_TIMEOUT (200) -#define IEEE80211_ASSOC_MAX_TRIES 3 -#define IEEE80211_MONITORING_INTERVAL (2000) -#define IEEE80211_PROBE_INTERVAL (60000) -#define IEEE80211_RETRY_AUTH_INTERVAL (1000) -#define IEEE80211_SCAN_INTERVAL (2000) -#define IEEE80211_SCAN_INTERVAL_SLOW (15000) -#define IEEE80211_IBSS_JOIN_TIMEOUT (20000) - -#define IEEE80211_PROBE_DELAY (33) -#define IEEE80211_CHANNEL_TIME (33) -#define IEEE80211_PASSIVE_CHANNEL_TIME (200) -#define IEEE80211_SCAN_RESULT_EXPIRE (10000) -#define IEEE80211_IBSS_MERGE_INTERVAL (30000) -#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000) - -#define IEEE80211_IBSS_MAX_STA_ENTRIES 128 - - -#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4)) - - -struct ieee80211_sta_bss { - struct ieee80211_sta_bss *next; - struct ieee80211_sta_bss *hnext; - - u8 bssid[ETH_ALEN]; - u8 ssid[MAX_SSID_LEN]; - size_t ssid_len; - u16 capability; /* host byte order */ - int hw_mode; - int channel; - int freq; - int rssi; - u8 *ie; - size_t ie_len; - u8 *wpa_ie; - size_t wpa_ie_len; - u8 *rsn_ie; - size_t rsn_ie_len; - u8 *wmm_ie; - size_t wmm_ie_len; - u8 *mdie; - size_t mdie_len; -#define IEEE80211_MAX_SUPP_RATES 32 - u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; - size_t supp_rates_len; - int beacon_int; - u64 timestamp; - - int probe_resp; - struct os_time last_update; -}; - - -static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, - const u8 *dst, - const u8 *ssid, size_t ssid_len); -static struct ieee80211_sta_bss * -ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid); -static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s); -static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s); -static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx); -static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx); -static void ieee80211_build_tspec(struct wpabuf *buf); -static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, - const u8 *ies, size_t ies_len); - - -static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s, - enum hostapd_hw_mode phymode, int chan, - int freq) -{ - size_t i; - struct hostapd_hw_modes *mode; - - for (i = 0; i < wpa_s->mlme.num_modes; i++) { - mode = &wpa_s->mlme.modes[i]; - if (mode->mode == phymode) { - wpa_s->mlme.curr_rates = mode->rates; - wpa_s->mlme.num_curr_rates = mode->num_rates; - break; - } - } - - return wpa_drv_set_channel(wpa_s, phymode, chan, freq); -} - - -static int ecw2cw(int ecw) -{ - int cw = 1; - while (ecw > 0) { - cw <<= 1; - ecw--; - } - return cw - 1; -} - - -static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s, - const u8 *wmm_param, size_t wmm_param_len) -{ - size_t left; - int count; - const u8 *pos; - u8 wmm_acm; - - if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) - return; - count = wmm_param[6] & 0x0f; - if (count == wpa_s->mlme.wmm_last_param_set) - return; - wpa_s->mlme.wmm_last_param_set = count; - - pos = wmm_param + 8; - left = wmm_param_len - 8; - - wmm_acm = 0; - for (; left >= 4; left -= 4, pos += 4) { - int aci = (pos[0] >> 5) & 0x03; - int acm = (pos[0] >> 4) & 0x01; - int aifs, cw_max, cw_min, burst_time; - - switch (aci) { - case 1: /* AC_BK */ - if (acm) - wmm_acm |= BIT(1) | BIT(2); /* BK/- */ - break; - case 2: /* AC_VI */ - if (acm) - wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ - break; - case 3: /* AC_VO */ - if (acm) - wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ - break; - case 0: /* AC_BE */ - default: - if (acm) - wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ - break; - } - - aifs = pos[0] & 0x0f; - cw_max = ecw2cw((pos[1] & 0xf0) >> 4); - cw_min = ecw2cw(pos[1] & 0x0f); - /* TXOP is in units of 32 usec; burst_time in 0.1 ms */ - burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100; - wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d burst=%d", - aci, acm, aifs, cw_min, cw_max, burst_time); - /* TODO: driver configuration */ - } -} - - -static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc) -{ - if (wpa_s->mlme.associated == assoc && !assoc) - return; - - wpa_s->mlme.associated = assoc; - - if (assoc) { - union wpa_event_data data; - os_memset(&data, 0, sizeof(data)); - wpa_s->mlme.prev_bssid_set = 1; - os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); - data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies; - data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len; - data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies; - data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len; - data.assoc_info.freq = wpa_s->mlme.freq; - wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data); - } else { - wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); - } - os_get_time(&wpa_s->mlme.last_probe); -} - - -static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf, - size_t len) -{ - return wpa_drv_send_mlme(wpa_s, buf, len); -} - - -static void ieee80211_send_auth(struct wpa_supplicant *wpa_s, - int transaction, const u8 *extra, - size_t extra_len, int encrypt) -{ - u8 *buf; - size_t len; - struct ieee80211_mgmt *mgmt; - - buf = os_malloc(sizeof(*mgmt) + 6 + extra_len); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " - "auth frame"); - return; - } - - mgmt = (struct ieee80211_mgmt *) buf; - len = 24 + 6; - os_memset(mgmt, 0, 24 + 6); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_AUTH); - if (encrypt) - mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg); - mgmt->u.auth.auth_transaction = host_to_le16(transaction); - wpa_s->mlme.auth_transaction = transaction + 1; - mgmt->u.auth.status_code = host_to_le16(0); - if (extra) { - os_memcpy(buf + len, extra, extra_len); - len += extra_len; - } - - ieee80211_sta_tx(wpa_s, buf, len); - os_free(buf); -} - - -static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms) -{ - eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); - eloop_register_timeout(ms / 1000, 1000 * (ms % 1000), - ieee80211_sta_timer, wpa_s, NULL); -} - - -static void ieee80211_authenticate(struct wpa_supplicant *wpa_s) -{ - u8 *extra; - size_t extra_len; - - wpa_s->mlme.auth_tries++; - if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) { - wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR - " timed out", MAC2STR(wpa_s->bssid)); - return; - } - - wpa_s->mlme.state = IEEE80211_AUTHENTICATE; - wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR, - MAC2STR(wpa_s->bssid)); - - extra = NULL; - extra_len = 0; - -#ifdef CONFIG_IEEE80211R - if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || - wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && - wpa_s->mlme.ft_ies) { - struct ieee80211_sta_bss *bss; - struct rsn_mdie *mdie = NULL; - bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); - if (bss && bss->mdie_len >= 2 + sizeof(*mdie)) - mdie = (struct rsn_mdie *) (bss->mdie + 2); - if (mdie && - os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md, - MOBILITY_DOMAIN_ID_LEN) == 0) { - wpa_printf(MSG_DEBUG, "MLME: Trying to use FT " - "over-the-air"); - wpa_s->mlme.auth_alg = WLAN_AUTH_FT; - extra = wpa_s->mlme.ft_ies; - extra_len = wpa_s->mlme.ft_ies_len; - } - } -#endif /* CONFIG_IEEE80211R */ - - ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0); - - ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT); -} - - -static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s) -{ - struct ieee80211_mgmt *mgmt; - u8 *pos, *ies, *buf; - int i, len; - u16 capab; - struct ieee80211_sta_bss *bss; - int wmm = 0; - size_t blen, buflen; - - if (wpa_s->mlme.curr_rates == NULL) { - wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc"); - return; - } - - buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len + - wpa_s->mlme.ssid_len; -#ifdef CONFIG_IEEE80211R - if (wpa_s->mlme.ft_ies) - buflen += wpa_s->mlme.ft_ies_len; -#endif /* CONFIG_IEEE80211R */ - buf = os_malloc(buflen); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " - "assoc frame"); - return; - } - blen = 0; - - capab = wpa_s->mlme.capab; - if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) { - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | - WLAN_CAPABILITY_SHORT_PREAMBLE; - } - bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); - if (bss) { - if (bss->capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_ie) { - wmm = 1; - } - } - - mgmt = (struct ieee80211_mgmt *) buf; - blen += 24; - os_memset(mgmt, 0, 24); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - - if (wpa_s->mlme.prev_bssid_set) { - blen += 10; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = host_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = host_to_le16(1); - os_memcpy(mgmt->u.reassoc_req.current_ap, - wpa_s->mlme.prev_bssid, - ETH_ALEN); - } else { - blen += 4; - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = host_to_le16(capab); - mgmt->u.assoc_req.listen_interval = host_to_le16(1); - } - - /* SSID */ - ies = pos = buf + blen; - blen += 2 + wpa_s->mlme.ssid_len; - *pos++ = WLAN_EID_SSID; - *pos++ = wpa_s->mlme.ssid_len; - os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); - - len = wpa_s->mlme.num_curr_rates; - if (len > 8) - len = 8; - pos = buf + blen; - blen += len + 2; - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = len; - for (i = 0; i < len; i++) - *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5); - - if (wpa_s->mlme.num_curr_rates > len) { - pos = buf + blen; - blen += wpa_s->mlme.num_curr_rates - len + 2; - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = wpa_s->mlme.num_curr_rates - len; - for (i = len; i < wpa_s->mlme.num_curr_rates; i++) - *pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5); - } - - if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) { - pos = buf + blen; - blen += wpa_s->mlme.extra_ie_len; - os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len); - } - -#ifdef CONFIG_IEEE80211R - if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || - wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && - wpa_s->mlme.auth_alg != WLAN_AUTH_FT && - bss && bss->mdie && - bss->mdie_len >= 2 + sizeof(struct rsn_mdie) && - bss->mdie[1] >= sizeof(struct rsn_mdie)) { - pos = buf + blen; - blen += 2 + sizeof(struct rsn_mdie); - *pos++ = WLAN_EID_MOBILITY_DOMAIN; - *pos++ = sizeof(struct rsn_mdie); - os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN); - pos += MOBILITY_DOMAIN_ID_LEN; - *pos++ = 0; /* FIX: copy from the target AP's MDIE */ - } - - if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X || - wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) && - wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) { - pos = buf + blen; - os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len); - pos += wpa_s->mlme.ft_ies_len; - blen += wpa_s->mlme.ft_ies_len; - } -#endif /* CONFIG_IEEE80211R */ - - if (wmm && wpa_s->mlme.wmm_enabled) { - pos = buf + blen; - blen += 9; - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WMM */ - *pos++ = 0; /* WMM info */ - *pos++ = 1; /* WMM ver */ - *pos++ = 0; - } - - os_free(wpa_s->mlme.assocreq_ies); - wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies; - wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len); - if (wpa_s->mlme.assocreq_ies) { - os_memcpy(wpa_s->mlme.assocreq_ies, ies, - wpa_s->mlme.assocreq_ies_len); - } - - ieee80211_sta_tx(wpa_s, buf, blen); - os_free(buf); -} - - -static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason) -{ - u8 *buf; - size_t len; - struct ieee80211_mgmt *mgmt; - - buf = os_zalloc(sizeof(*mgmt)); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " - "deauth frame"); - return; - } - - mgmt = (struct ieee80211_mgmt *) buf; - len = 24; - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DEAUTH); - len += 2; - mgmt->u.deauth.reason_code = host_to_le16(reason); - - ieee80211_sta_tx(wpa_s, buf, len); - os_free(buf); -} - - -static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason) -{ - u8 *buf; - size_t len; - struct ieee80211_mgmt *mgmt; - - buf = os_zalloc(sizeof(*mgmt)); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " - "disassoc frame"); - return; - } - - mgmt = (struct ieee80211_mgmt *) buf; - len = 24; - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_DISASSOC); - len += 2; - mgmt->u.disassoc.reason_code = host_to_le16(reason); - - ieee80211_sta_tx(wpa_s, buf, len); - os_free(buf); -} - - -static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s) -{ - struct ieee80211_sta_bss *bss; - int res = 0; - - if (wpa_s->mlme.mixed_cell || - wpa_s->mlme.key_mgmt != KEY_MGMT_NONE) - return 0; - - bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); - if (bss == NULL) - return 0; - - if (ieee80211_sta_wep_configured(wpa_s) != - !!(bss->capability & WLAN_CAPABILITY_PRIVACY)) - res = 1; - - return res; -} - - -static void ieee80211_associate(struct wpa_supplicant *wpa_s) -{ - wpa_s->mlme.assoc_tries++; - if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR - " timed out", MAC2STR(wpa_s->bssid)); - return; - } - - wpa_s->mlme.state = IEEE80211_ASSOCIATE; - wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR, - MAC2STR(wpa_s->bssid)); - if (ieee80211_privacy_mismatch(wpa_s)) { - wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy " - "configuration and mixed-cell disabled - abort " - "association"); - return; - } - - ieee80211_send_assoc(wpa_s); - - ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT); -} - - -static void ieee80211_associated(struct wpa_supplicant *wpa_s) -{ - int disassoc; - - /* TODO: start monitoring current AP signal quality and number of - * missed beacons. Scan other channels every now and then and search - * for better APs. */ - /* TODO: remove expired BSSes */ - - wpa_s->mlme.state = IEEE80211_ASSOCIATED; - -#if 0 /* FIX */ - sta = sta_info_get(local, wpa_s->bssid); - if (sta == NULL) { - wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR, - MAC2STR(wpa_s->bssid)); - disassoc = 1; - } else { - disassoc = 0; - if (time_after(jiffies, - sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { - if (wpa_s->mlme.probereq_poll) { - wpa_printf(MSG_DEBUG "MLME: No ProbeResp from " - "current AP " MACSTR " - assume " - "out of range", - MAC2STR(wpa_s->bssid)); - disassoc = 1; - } else { - ieee80211_send_probe_req( - wpa_s->bssid, - wpa_s->mlme.scan_ssid, - wpa_s->mlme.scan_ssid_len); - wpa_s->mlme.probereq_poll = 1; - } - } else { - wpa_s->mlme.probereq_poll = 0; - if (time_after(jiffies, wpa_s->mlme.last_probe + - IEEE80211_PROBE_INTERVAL)) { - wpa_s->mlme.last_probe = jiffies; - ieee80211_send_probe_req(wpa_s->bssid, - wpa_s->mlme.ssid, - wpa_s->mlme.ssid_len); - } - } - sta_info_release(local, sta); - } -#else - disassoc = 0; -#endif - if (disassoc) { - wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL); - ieee80211_reschedule_timer(wpa_s, - IEEE80211_MONITORING_INTERVAL + - 30000); - } else { - ieee80211_reschedule_timer(wpa_s, - IEEE80211_MONITORING_INTERVAL); - } -} - - -static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s, - const u8 *dst, - const u8 *ssid, size_t ssid_len) -{ - u8 *buf; - size_t len; - struct ieee80211_mgmt *mgmt; - u8 *pos, *supp_rates; - u8 *esupp_rates = NULL; - int i; - - buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for " - "probe request"); - return; - } - - mgmt = (struct ieee80211_mgmt *) buf; - len = 24; - os_memset(mgmt, 0, 24); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_REQ); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - if (dst) { - os_memcpy(mgmt->da, dst, ETH_ALEN); - os_memcpy(mgmt->bssid, dst, ETH_ALEN); - } else { - os_memset(mgmt->da, 0xff, ETH_ALEN); - os_memset(mgmt->bssid, 0xff, ETH_ALEN); - } - pos = buf + len; - len += 2 + ssid_len; - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - os_memcpy(pos, ssid, ssid_len); - - supp_rates = buf + len; - len += 2; - supp_rates[0] = WLAN_EID_SUPP_RATES; - supp_rates[1] = 0; - for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) { - if (esupp_rates) { - pos = buf + len; - len++; - esupp_rates[1]++; - } else if (supp_rates[1] == 8) { - esupp_rates = pos; - esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; - esupp_rates[1] = 1; - pos = &esupp_rates[2]; - len += 3; - } else { - pos = buf + len; - len++; - supp_rates[1]++; - } - *pos++ = wpa_s->mlme.curr_rates[i] / 5; - } - - if (wpa_s->mlme.extra_probe_ie) { - os_memcpy(pos, wpa_s->mlme.extra_probe_ie, - wpa_s->mlme.extra_probe_ie_len); - len += wpa_s->mlme.extra_probe_ie_len; - } - - ieee80211_sta_tx(wpa_s, buf, len); - os_free(buf); -} - - -static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s) -{ -#if 0 /* FIX */ - if (sdata == NULL || sdata->default_key == NULL || - sdata->default_key->alg != ALG_WEP) - return 0; - return 1; -#else - return 0; -#endif -} - - -static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s) -{ - wpa_printf(MSG_DEBUG, "MLME: authenticated"); - wpa_s->mlme.authenticated = 1; - ieee80211_associate(wpa_s); -} - - -static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - u8 *pos; - struct ieee802_11_elems elems; - - wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge"); - pos = mgmt->u.auth.variable; - if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) - == ParseFailed) { - wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)"); - return; - } - if (elems.challenge == NULL) { - wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key " - "auth frame"); - return; - } - ieee80211_send_auth(wpa_s, 3, elems.challenge - 2, - elems.challenge_len + 2, 1); -} - - -static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct wpa_ssid *ssid = wpa_s->current_ssid; - u16 auth_alg, auth_transaction, status_code; - int adhoc; - - adhoc = ssid && ssid->mode == WPAS_MODE_IBSS; - - if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) { - wpa_printf(MSG_DEBUG, "MLME: authentication frame received " - "from " MACSTR ", but not in authenticate state - " - "ignored", MAC2STR(mgmt->sa)); - return; - } - - if (len < 24 + 6) { - wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication " - "frame received from " MACSTR " - ignored", - (unsigned long) len, MAC2STR(mgmt->sa)); - return; - } - - if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: authentication frame received " - "from unknown AP (SA=" MACSTR " BSSID=" MACSTR - ") - ignored", - MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); - return; - } - - if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: authentication frame received " - "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR - ") - ignored", - MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); - return; - } - - auth_alg = le_to_host16(mgmt->u.auth.auth_alg); - auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); - status_code = le_to_host16(mgmt->u.auth.status_code); - - wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR - " (alg=%d transaction=%d status=%d)", - MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code); - - if (adhoc) { - /* IEEE 802.11 standard does not require authentication in IBSS - * networks and most implementations do not seem to use it. - * However, try to reply to authentication attempts if someone - * has actually implemented this. - * TODO: Could implement shared key authentication. */ - if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { - wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS " - "authentication frame (alg=%d " - "transaction=%d)", - auth_alg, auth_transaction); - return; - } - ieee80211_send_auth(wpa_s, 2, NULL, 0, 0); - } - - if (auth_alg != wpa_s->mlme.auth_alg || - auth_transaction != wpa_s->mlme.auth_transaction) { - wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame " - "(alg=%d transaction=%d)", - auth_alg, auth_transaction); - return; - } - - if (status_code != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "MLME: AP denied authentication " - "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg, - status_code); - if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - const int num_algs = 3; - u8 algs[num_algs]; - int i, pos; - algs[0] = algs[1] = algs[2] = 0xff; - if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN) - algs[0] = WLAN_AUTH_OPEN; - if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED) - algs[1] = WLAN_AUTH_SHARED_KEY; - if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP) - algs[2] = WLAN_AUTH_LEAP; - if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN) - pos = 0; - else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY) - pos = 1; - else - pos = 2; - for (i = 0; i < num_algs; i++) { - pos++; - if (pos >= num_algs) - pos = 0; - if (algs[pos] == wpa_s->mlme.auth_alg || - algs[pos] == 0xff) - continue; - if (algs[pos] == WLAN_AUTH_SHARED_KEY && - !ieee80211_sta_wep_configured(wpa_s)) - continue; - wpa_s->mlme.auth_alg = algs[pos]; - wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d " - "for next try", - wpa_s->mlme.auth_alg); - break; - } - } - return; - } - - switch (wpa_s->mlme.auth_alg) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - ieee80211_auth_completed(wpa_s); - break; - case WLAN_AUTH_SHARED_KEY: - if (wpa_s->mlme.auth_transaction == 4) - ieee80211_auth_completed(wpa_s); - else - ieee80211_auth_challenge(wpa_s, mgmt, len, - rx_status); - break; -#ifdef CONFIG_IEEE80211R - case WLAN_AUTH_FT: - { - union wpa_event_data data; - struct wpabuf *ric = NULL; - os_memset(&data, 0, sizeof(data)); - data.ft_ies.ies = mgmt->u.auth.variable; - data.ft_ies.ies_len = len - - (mgmt->u.auth.variable - (u8 *) mgmt); - os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN); - if (os_strcmp(wpa_s->driver->name, "test") == 0 && - wpa_s->mlme.wmm_enabled) { - ric = wpabuf_alloc(200); - if (ric) { - /* Build simple RIC-Request: RDIE | TSPEC */ - - /* RIC Data (RDIE) */ - wpabuf_put_u8(ric, WLAN_EID_RIC_DATA); - wpabuf_put_u8(ric, 4); - wpabuf_put_u8(ric, 0); /* RDIE Identifier */ - wpabuf_put_u8(ric, 1); /* Resource Descriptor - * Count */ - wpabuf_put_le16(ric, 0); /* Status Code */ - - /* WMM TSPEC */ - ieee80211_build_tspec(ric); - - data.ft_ies.ric_ies = wpabuf_head(ric); - data.ft_ies.ric_ies_len = wpabuf_len(ric); - } - } - - wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); - wpabuf_free(ric); - ieee80211_auth_completed(wpa_s); - break; - } -#endif /* CONFIG_IEEE80211R */ - } -} - - -static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - u16 reason_code; - - if (len < 24 + 2) { - wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication " - "frame received from " MACSTR " - ignored", - (unsigned long) len, MAC2STR(mgmt->sa)); - return; - } - - if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received " - "from unknown AP (SA=" MACSTR " BSSID=" MACSTR - ") - ignored", - MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); - return; - } - - reason_code = le_to_host16(mgmt->u.deauth.reason_code); - - wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR - " (reason=%d)", MAC2STR(mgmt->sa), reason_code); - - if (wpa_s->mlme.authenticated) - wpa_printf(MSG_DEBUG, "MLME: deauthenticated"); - - if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE || - wpa_s->mlme.state == IEEE80211_ASSOCIATE || - wpa_s->mlme.state == IEEE80211_ASSOCIATED) { - wpa_s->mlme.state = IEEE80211_AUTHENTICATE; - ieee80211_reschedule_timer(wpa_s, - IEEE80211_RETRY_AUTH_INTERVAL); - } - - ieee80211_set_associated(wpa_s, 0); - wpa_s->mlme.authenticated = 0; -} - - -static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - u16 reason_code; - - if (len < 24 + 2) { - wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation " - "frame received from " MACSTR " - ignored", - (unsigned long) len, MAC2STR(mgmt->sa)); - return; - } - - if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: disassociation frame received " - "from unknown AP (SA=" MACSTR " BSSID=" MACSTR - ") - ignored", - MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); - return; - } - - reason_code = le_to_host16(mgmt->u.disassoc.reason_code); - - wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR - " (reason=%d)", MAC2STR(mgmt->sa), reason_code); - - if (wpa_s->mlme.associated) - wpa_printf(MSG_DEBUG, "MLME: disassociated"); - - if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) { - wpa_s->mlme.state = IEEE80211_ASSOCIATE; - ieee80211_reschedule_timer(wpa_s, - IEEE80211_RETRY_AUTH_INTERVAL); - } - - ieee80211_set_associated(wpa_s, 0); -} - - -static void ieee80211_build_tspec(struct wpabuf *buf) -{ - struct wmm_tspec_element *tspec; - int tid, up; - - tspec = wpabuf_put(buf, sizeof(*tspec)); - tspec->eid = WLAN_EID_VENDOR_SPECIFIC; - tspec->length = sizeof(*tspec) - 2; - tspec->oui[0] = 0x00; - tspec->oui[1] = 0x50; - tspec->oui[2] = 0xf2; - tspec->oui_type = 2; - tspec->oui_subtype = 2; - tspec->version = 1; - - tid = 1; - up = 6; /* Voice */ - tspec->ts_info[0] = (tid << 1) | - (WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) | - BIT(7); - tspec->ts_info[1] = up << 3; - tspec->nominal_msdu_size = host_to_le16(1530); - tspec->mean_data_rate = host_to_le32(128000); /* bits per second */ - tspec->minimum_phy_rate = host_to_le32(6000000); - tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */ -} - - -static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s) -{ - struct wpabuf *buf; - struct ieee80211_mgmt *mgmt; - size_t alen; - - wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC"); - mgmt = NULL; - alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt; - - buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element)); - if (buf == NULL) - return; - - mgmt = wpabuf_put(buf, alen); - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_WMM; - mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ; - mgmt->u.action.u.wmm_action.dialog_token = 1; - mgmt->u.action.u.wmm_action.status_code = 0; - - ieee80211_build_tspec(buf); - - ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf)); - wpabuf_free(buf); -} - - -static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status, - int reassoc) -{ - u8 rates[32]; - size_t rates_len; - u16 capab_info, status_code, aid; - struct ieee802_11_elems elems; - u8 *pos; - - /* AssocResp and ReassocResp have identical structure, so process both - * of them in this function. */ - - if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) { - wpa_printf(MSG_DEBUG, "MLME: association frame received from " - MACSTR ", but not in associate state - ignored", - MAC2STR(mgmt->sa)); - return; - } - - if (len < 24 + 6) { - wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association " - "frame received from " MACSTR " - ignored", - (unsigned long) len, MAC2STR(mgmt->sa)); - return; - } - - if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: association frame received from " - "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - " - "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid)); - return; - } - - capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info); - status_code = le_to_host16(mgmt->u.assoc_resp.status_code); - aid = le_to_host16(mgmt->u.assoc_resp.aid); - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 " - "not set", aid); - aid &= ~(BIT(15) | BIT(14)); - - wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR - " (capab=0x%x status=%d aid=%d)", - reassoc ? "Rea" : "A", MAC2STR(mgmt->sa), - capab_info, status_code, aid); - - pos = mgmt->u.assoc_resp.variable; - if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0) - == ParseFailed) { - wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp"); - return; - } - - if (status_code != WLAN_STATUS_SUCCESS) { - wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)", - status_code); -#ifdef CONFIG_IEEE80211W - if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY && - elems.timeout_int && elems.timeout_int_len == 5 && - elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) { - u32 tu, ms; - tu = WPA_GET_LE32(elems.timeout_int + 1); - ms = tu * 1024 / 1000; - wpa_printf(MSG_DEBUG, "MLME: AP rejected association " - "temporarily; comeback duration %u TU " - "(%u ms)", tu, ms); - if (ms > IEEE80211_ASSOC_TIMEOUT) { - wpa_printf(MSG_DEBUG, "MLME: Update timer " - "based on comeback duration"); - ieee80211_reschedule_timer(wpa_s, ms); - } - } -#endif /* CONFIG_IEEE80211W */ - return; - } - - if (elems.supp_rates == NULL) { - wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in " - "AssocResp"); - return; - } - - if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) { - if (!reassoc) { - wpa_printf(MSG_DEBUG, "MLME: AP tried to use " - "association, not reassociation, response " - "with FT"); - return; - } - if (wpa_ft_validate_reassoc_resp( - wpa_s->wpa, pos, len - (pos - (u8 *) mgmt), - mgmt->sa) < 0) { - wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc" - "Resp failed"); - return; - } - } else if (wpa_sm_set_ft_params(wpa_s->wpa, pos, - len - (pos - (u8 *) mgmt)) < 0) - return; - - wpa_printf(MSG_DEBUG, "MLME: associated"); - wpa_s->mlme.aid = aid; - wpa_s->mlme.ap_capab = capab_info; - - os_free(wpa_s->mlme.assocresp_ies); - wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt); - wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len); - if (wpa_s->mlme.assocresp_ies) { - os_memcpy(wpa_s->mlme.assocresp_ies, pos, - wpa_s->mlme.assocresp_ies_len); - } - - ieee80211_set_associated(wpa_s, 1); - - rates_len = elems.supp_rates_len; - if (rates_len > sizeof(rates)) - rates_len = sizeof(rates); - os_memcpy(rates, elems.supp_rates, rates_len); - if (elems.ext_supp_rates) { - size_t _len = elems.ext_supp_rates_len; - if (_len > sizeof(rates) - rates_len) - _len = sizeof(rates) - rates_len; - os_memcpy(rates + rates_len, elems.ext_supp_rates, _len); - rates_len += _len; - } - - if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) { - wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the " - "netstack"); - } - if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) < - 0) { - wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the " - "netstack"); - } - - /* Remove STA entry before adding a new one just in case to avoid - * problems with existing configuration (e.g., keys). */ - wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid); - if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) { - wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the " - "netstack"); - } - - if (elems.wmm && wpa_s->mlme.wmm_enabled) - ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len); - - ieee80211_associated(wpa_s); - - if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT && - os_strcmp(wpa_s->driver->name, "test") == 0 && - elems.wmm && wpa_s->mlme.wmm_enabled) { - /* Test WMM-AC - send ADDTS for WMM TSPEC */ - ieee80211_tx_addts(wpa_s); - } -} - - -/* Caller must hold local->sta_bss_lock */ -static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s, - struct ieee80211_sta_bss *bss) -{ - bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; - wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss; -} - - -/* Caller must hold local->sta_bss_lock */ -static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_sta_bss *b, *prev = NULL; - b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]; - while (b) { - if (b == bss) { - if (prev == NULL) { - wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] - = bss->hnext; - } else { - prev->hnext = bss->hnext; - } - break; - } - prev = b; - b = b->hnext; - } -} - - -static struct ieee80211_sta_bss * -ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid) -{ - struct ieee80211_sta_bss *bss; - - bss = os_zalloc(sizeof(*bss)); - if (bss == NULL) - return NULL; - os_memcpy(bss->bssid, bssid, ETH_ALEN); - - /* TODO: order by RSSI? */ - bss->next = wpa_s->mlme.sta_bss_list; - wpa_s->mlme.sta_bss_list = bss; - __ieee80211_bss_hash_add(wpa_s, bss); - return bss; -} - - -static struct ieee80211_sta_bss * -ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid) -{ - struct ieee80211_sta_bss *bss; - - bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)]; - while (bss) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) - break; - bss = bss->hnext; - } - return bss; -} - - -static void ieee80211_bss_free(struct wpa_supplicant *wpa_s, - struct ieee80211_sta_bss *bss) -{ - __ieee80211_bss_hash_del(wpa_s, bss); - os_free(bss->ie); - os_free(bss->wpa_ie); - os_free(bss->rsn_ie); - os_free(bss->wmm_ie); - os_free(bss->mdie); - os_free(bss); -} - - -static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s) -{ - struct ieee80211_sta_bss *bss, *prev; - - bss = wpa_s->mlme.sta_bss_list; - wpa_s->mlme.sta_bss_list = NULL; - while (bss) { - prev = bss; - bss = bss->next; - ieee80211_bss_free(wpa_s, prev); - } -} - - -static void ieee80211_bss_info(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status, - int beacon) -{ - struct ieee802_11_elems elems; - size_t baselen; - int channel, invalid = 0, clen; - struct ieee80211_sta_bss *bss; - u64 timestamp; - u8 *pos, *ie_pos; - size_t ie_len; - - if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN)) - return; /* ignore ProbeResp to foreign address */ - -#if 0 - wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR, - beacon ? "Beacon" : "Probe Response", - MAC2STR(mgmt->sa), MAC2STR(mgmt->da)); -#endif - - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - - pos = mgmt->u.beacon.timestamp; - timestamp = WPA_GET_LE64(pos); - -#if 0 /* FIX */ - if (local->conf.mode == IW_MODE_ADHOC && beacon && - os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) { -#ifdef IEEE80211_IBSS_DEBUG - static unsigned long last_tsf_debug = 0; - u64 tsf; - if (local->hw->get_tsf) - tsf = local->hw->get_tsf(local->mdev); - else - tsf = -1LLU; - if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID=" - MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld " - "@%ld", - MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid), - tsf, timestamp, tsf - timestamp, jiffies); - last_tsf_debug = jiffies; - } -#endif /* IEEE80211_IBSS_DEBUG */ - } -#endif - - ie_pos = mgmt->u.beacon.variable; - ie_len = len - baselen; - if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed) - invalid = 1; - -#if 0 /* FIX */ - if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates && - os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 && - (sta = sta_info_get(local, mgmt->sa))) { - struct ieee80211_rate *rates; - size_t num_rates; - u32 supp_rates, prev_rates; - int i, j, oper_mode; - - rates = local->curr_rates; - num_rates = local->num_curr_rates; - oper_mode = wpa_s->mlme.sta_scanning ? - local->scan_oper_phymode : local->conf.phymode; - for (i = 0; i < local->hw->num_modes; i++) { - struct ieee80211_hw_modes *mode = &local->hw->modes[i]; - if (oper_mode == mode->mode) { - rates = mode->rates; - num_rates = mode->num_rates; - break; - } - } - - supp_rates = 0; - for (i = 0; i < elems.supp_rates_len + - elems.ext_supp_rates_len; i++) { - u8 rate = 0; - int own_rate; - if (i < elems.supp_rates_len) - rate = elems.supp_rates[i]; - else if (elems.ext_supp_rates) - rate = elems.ext_supp_rates - [i - elems.supp_rates_len]; - own_rate = 5 * (rate & 0x7f); - if (oper_mode == MODE_ATHEROS_TURBO) - own_rate *= 2; - for (j = 0; j < num_rates; j++) - if (rates[j].rate == own_rate) - supp_rates |= BIT(j); - } - - prev_rates = sta->supp_rates; - sta->supp_rates &= supp_rates; - if (sta->supp_rates == 0) { - /* No matching rates - this should not really happen. - * Make sure that at least one rate is marked - * supported to avoid issues with TX rate ctrl. */ - sta->supp_rates = wpa_s->mlme.supp_rates_bits; - } - if (sta->supp_rates != prev_rates) { - wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set " - "for " MACSTR " based on beacon info " - "(0x%x & 0x%x -> 0x%x)", - MAC2STR(sta->addr), prev_rates, - supp_rates, sta->supp_rates); - } - sta_info_release(local, sta); - } -#endif - - if (elems.ssid == NULL) - return; - - if (elems.ds_params && elems.ds_params_len == 1) - channel = elems.ds_params[0]; - else - channel = rx_status->channel; - - bss = ieee80211_bss_get(wpa_s, mgmt->bssid); - if (bss == NULL) { - bss = ieee80211_bss_add(wpa_s, mgmt->bssid); - if (bss == NULL) - return; - } else { -#if 0 - /* TODO: order by RSSI? */ - spin_lock_bh(&local->sta_bss_lock); - list_move_tail(&bss->list, &local->sta_bss_list); - spin_unlock_bh(&local->sta_bss_lock); -#endif - } - - if (bss->probe_resp && beacon) { - /* Do not allow beacon to override data from Probe Response. */ - return; - } - - bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); - bss->capability = le_to_host16(mgmt->u.beacon.capab_info); - - if (bss->ie == NULL || bss->ie_len < ie_len) { - os_free(bss->ie); - bss->ie = os_malloc(ie_len); - } - if (bss->ie) { - os_memcpy(bss->ie, ie_pos, ie_len); - bss->ie_len = ie_len; - } - - if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) { - os_memcpy(bss->ssid, elems.ssid, elems.ssid_len); - bss->ssid_len = elems.ssid_len; - } - - bss->supp_rates_len = 0; - if (elems.supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.supp_rates_len) - clen = elems.supp_rates_len; - os_memcpy(&bss->supp_rates[bss->supp_rates_len], - elems.supp_rates, clen); - bss->supp_rates_len += clen; - } - if (elems.ext_supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.ext_supp_rates_len) - clen = elems.ext_supp_rates_len; - os_memcpy(&bss->supp_rates[bss->supp_rates_len], - elems.ext_supp_rates, clen); - bss->supp_rates_len += clen; - } - - if (elems.wpa_ie && - (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len || - os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) { - os_free(bss->wpa_ie); - bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2); - if (bss->wpa_ie) { - os_memcpy(bss->wpa_ie, elems.wpa_ie - 2, - elems.wpa_ie_len + 2); - bss->wpa_ie_len = elems.wpa_ie_len + 2; - } else - bss->wpa_ie_len = 0; - } else if (!elems.wpa_ie && bss->wpa_ie) { - os_free(bss->wpa_ie); - bss->wpa_ie = NULL; - bss->wpa_ie_len = 0; - } - - if (elems.rsn_ie && - (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len || - os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) { - os_free(bss->rsn_ie); - bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2); - if (bss->rsn_ie) { - os_memcpy(bss->rsn_ie, elems.rsn_ie - 2, - elems.rsn_ie_len + 2); - bss->rsn_ie_len = elems.rsn_ie_len + 2; - } else - bss->rsn_ie_len = 0; - } else if (!elems.rsn_ie && bss->rsn_ie) { - os_free(bss->rsn_ie); - bss->rsn_ie = NULL; - bss->rsn_ie_len = 0; - } - - if (elems.wmm && - (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len || - os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) { - os_free(bss->wmm_ie); - bss->wmm_ie = os_malloc(elems.wmm_len + 2); - if (bss->wmm_ie) { - os_memcpy(bss->wmm_ie, elems.wmm - 2, - elems.wmm_len + 2); - bss->wmm_ie_len = elems.wmm_len + 2; - } else - bss->wmm_ie_len = 0; - } else if (!elems.wmm && bss->wmm_ie) { - os_free(bss->wmm_ie); - bss->wmm_ie = NULL; - bss->wmm_ie_len = 0; - } - -#ifdef CONFIG_IEEE80211R - if (elems.mdie && - (bss->mdie == NULL || bss->mdie_len != elems.mdie_len || - os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) { - os_free(bss->mdie); - bss->mdie = os_malloc(elems.mdie_len + 2); - if (bss->mdie) { - os_memcpy(bss->mdie, elems.mdie - 2, - elems.mdie_len + 2); - bss->mdie_len = elems.mdie_len + 2; - } else - bss->mdie_len = 0; - } else if (!elems.mdie && bss->mdie) { - os_free(bss->mdie); - bss->mdie = NULL; - bss->mdie_len = 0; - } -#endif /* CONFIG_IEEE80211R */ - - bss->hw_mode = wpa_s->mlme.phymode; - bss->channel = channel; - bss->freq = wpa_s->mlme.freq; - if (channel != wpa_s->mlme.channel && - (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G || - wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) && - channel >= 1 && channel <= 14) { - static const int freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - /* IEEE 802.11g/b mode can receive packets from neighboring - * channels, so map the channel into frequency. */ - bss->freq = freq_list[channel - 1]; - } - bss->timestamp = timestamp; - os_get_time(&bss->last_update); - bss->rssi = rx_status->ssi; - if (!beacon) - bss->probe_resp++; -} - - -static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0); -} - - -static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - int use_protection; - size_t baselen; - struct ieee802_11_elems elems; - - ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1); - - if (!wpa_s->mlme.associated || - os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) - return; - - /* Process beacon from the current BSS */ - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - - if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, - &elems, 0) == ParseFailed) - return; - - use_protection = 0; - if (elems.erp_info && elems.erp_info_len >= 1) { - use_protection = - (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0; - } - - if (use_protection != !!wpa_s->mlme.use_protection) { - wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR - ")", - use_protection ? "enabled" : "disabled", - MAC2STR(wpa_s->bssid)); - wpa_s->mlme.use_protection = use_protection ? 1 : 0; - wpa_s->mlme.cts_protect_erp_frames = use_protection; - } - - if (elems.wmm && wpa_s->mlme.wmm_enabled) { - ieee80211_sta_wmm_params(wpa_s, elems.wmm, - elems.wmm_len); - } -} - - -static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - int tx_last_beacon, adhoc; -#if 0 /* FIX */ - struct ieee80211_mgmt *resp; -#endif - u8 *pos, *end; - struct wpa_ssid *ssid = wpa_s->current_ssid; - - adhoc = ssid && ssid->mode == WPAS_MODE_IBSS; - - if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED || - len < 24 + 2 || wpa_s->mlme.probe_resp == NULL) - return; - -#if 0 /* FIX */ - if (local->hw->tx_last_beacon) - tx_last_beacon = local->hw->tx_last_beacon(local->mdev); - else -#endif - tx_last_beacon = 1; - -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR - " BSSID=" MACSTR " (tx_last_beacon=%d)", - MAC2STR(mgmt->sa), MAC2STR(mgmt->da), - MAC2STR(mgmt->bssid), tx_last_beacon); -#endif /* IEEE80211_IBSS_DEBUG */ - - if (!tx_last_beacon) - return; - - if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 && - os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) - return; - - end = ((u8 *) mgmt) + len; - pos = mgmt->u.probe_req.variable; - if (pos[0] != WLAN_EID_SSID || - pos + 2 + pos[1] > end) { - wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from " - MACSTR, MAC2STR(mgmt->sa)); - return; - } - if (pos[1] != 0 && - (pos[1] != wpa_s->mlme.ssid_len || - os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0)) - { - /* Ignore ProbeReq for foreign SSID */ - return; - } - -#if 0 /* FIX */ - /* Reply with ProbeResp */ - skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC); - if (skb == NULL) - return; - - resp = (struct ieee80211_mgmt *) skb->data; - os_memcpy(resp->da, mgmt->sa, ETH_ALEN); -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR, - MAC2STR(resp->da)); -#endif /* IEEE80211_IBSS_DEBUG */ - ieee80211_sta_tx(wpa_s, skb, 0, 1); -#endif -} - - -#ifdef CONFIG_IEEE80211R -static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - union wpa_event_data data; - u16 status; - u8 *sta_addr, *target_ap_addr; - - if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) { - wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame"); - return; - } - - /* - * Only FT Action Response is needed for now since reservation - * protocol is not supported. - */ - if (mgmt->u.action.u.ft_action_resp.action != 2) { - wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d", - mgmt->u.action.u.ft_action_resp.action); - return; - } - - status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code); - sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr; - target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr; - wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR - " TargetAP " MACSTR " Status Code %d", - MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); - if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR - " in FT Action Response", MAC2STR(sta_addr)); - return; - } - - if (status) { - wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates " - "failure (status code %d)", status); - /* TODO: report error to FT code(?) */ - return; - } - - os_memset(&data, 0, sizeof(data)); - data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable; - data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable - - (u8 *) mgmt); - data.ft_ies.ft_action = 1; - os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN); - wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data); - /* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed - * successfully */ - wpa_s->mlme.prev_bssid_set = 1; - wpa_s->mlme.auth_alg = WLAN_AUTH_FT; - os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN); - os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN); - ieee80211_associate(wpa_s); -} -#endif /* CONFIG_IEEE80211R */ - - -#ifdef CONFIG_IEEE80211W - -/* MLME-SAQuery.response */ -static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s, - const u8 *addr, const u8 *trans_id) -{ - struct ieee80211_mgmt *mgmt; - int res; - size_t len; - - mgmt = os_zalloc(sizeof(*mgmt)); - if (mgmt == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " - "SA Query action frame"); - return -1; - } - - len = 24; - os_memcpy(mgmt->da, addr, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_SA_QUERY; - mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE; - os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id, - WLAN_SA_QUERY_TR_ID_LEN); - len += 1 + sizeof(mgmt->u.action.u.sa_query_resp); - - res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len); - os_free(mgmt); - - return res; -} - - -static void ieee80211_rx_mgmt_sa_query_action( - struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) -{ - if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) { - wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame"); - return; - } - - if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) { - wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d", - mgmt->u.action.u.sa_query_req.action); - return; - } - - if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) { - wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown " - "source " MACSTR, MAC2STR(mgmt->sa)); - return; - } - - if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) { - wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during " - "association process"); - return; - } - - wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request"); - ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u. - sa_query_req.trans_id); -} - -#endif /* CONFIG_IEEE80211W */ - - -static void dump_tspec(struct wmm_tspec_element *tspec) -{ - int up, psb, dir, tid; - u16 val; - - up = (tspec->ts_info[1] >> 3) & 0x07; - psb = (tspec->ts_info[1] >> 2) & 0x01; - dir = (tspec->ts_info[0] >> 5) & 0x03; - tid = (tspec->ts_info[0] >> 1) & 0x0f; - wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d", - up, psb, dir, tid); - val = le_to_host16(tspec->nominal_msdu_size); - wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s", - val & 0x7fff, val & 0x8000 ? " (fixed)" : ""); - wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps", - le_to_host32(tspec->mean_data_rate)); - wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps", - le_to_host32(tspec->minimum_phy_rate)); - val = le_to_host16(tspec->surplus_bandwidth_allowance); - wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u", - val >> 13, 10000 * (val & 0x1fff) / 0x2000); - val = le_to_host16(tspec->medium_time); - wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)", - val, 32 * val); -} - - -static int is_wmm_tspec(const u8 *ie, size_t len) -{ - const struct wmm_tspec_element *tspec; - - if (len < sizeof(*tspec)) - return 0; - - tspec = (const struct wmm_tspec_element *) ie; - if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC || - tspec->length < sizeof(*tspec) - 2 || - tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 || - tspec->oui[2] != 0xf2 || tspec->oui_type != 2 || - tspec->oui_subtype != 2 || tspec->version != 1) - return 0; - - return 1; -} - - -static void ieee80211_rx_addts_resp( - struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, - size_t var_len) -{ - struct wmm_tspec_element *tspec; - - wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response"); - wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)", - mgmt->u.action.u.wmm_action.variable, var_len); - if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len)) - return; - tspec = (struct wmm_tspec_element *) - mgmt->u.action.u.wmm_action.variable; - dump_tspec(tspec); -} - - -static void ieee80211_rx_delts( - struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, - size_t var_len) -{ - struct wmm_tspec_element *tspec; - - wpa_printf(MSG_DEBUG, "WMM: Received DELTS"); - wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)", - mgmt->u.action.u.wmm_action.variable, var_len); - if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len)) - return; - tspec = (struct wmm_tspec_element *) - mgmt->u.action.u.wmm_action.variable; - dump_tspec(tspec); -} - - -static void ieee80211_rx_mgmt_wmm_action( - struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len, - struct ieee80211_rx_status *rx_status) -{ - size_t alen; - - alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt; - if (len < alen) { - wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short"); - return; - } - - wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, " - "Dialog Token %d, Status Code %d", - mgmt->u.action.u.wmm_action.action_code, - mgmt->u.action.u.wmm_action.dialog_token, - mgmt->u.action.u.wmm_action.status_code); - - switch (mgmt->u.action.u.wmm_action.action_code) { - case WMM_ACTION_CODE_ADDTS_RESP: - ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen); - break; - case WMM_ACTION_CODE_DELTS: - ieee80211_rx_delts(wpa_s, mgmt, len, len - alen); - break; - default: - wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d", - mgmt->u.action.u.wmm_action.action_code); - break; - } -} - - -static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - wpa_printf(MSG_DEBUG, "MLME: received Action frame"); - - if (len < 25) - return; - - switch (mgmt->u.action.category) { -#ifdef CONFIG_IEEE80211R - case WLAN_ACTION_FT: - ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status); - break; -#endif /* CONFIG_IEEE80211R */ -#ifdef CONFIG_IEEE80211W - case WLAN_ACTION_SA_QUERY: - ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status); - break; -#endif /* CONFIG_IEEE80211W */ - case WLAN_ACTION_WMM: - ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status); - break; - case WLAN_ACTION_PUBLIC: - if (wpa_s->mlme.public_action_cb) { - wpa_s->mlme.public_action_cb( - wpa_s->mlme.public_action_cb_ctx, - (u8 *) mgmt, len, rx_status->freq); - return; - } - break; - default: - wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d", - mgmt->u.action.category); - break; - } -} - - -static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s, - const u8 *buf, size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_mgmt *mgmt; - u16 fc; - - if (len < 24) - return; - - mgmt = (struct ieee80211_mgmt *) buf; - fc = le_to_host16(mgmt->frame_control); - - switch (WLAN_FC_GET_STYPE(fc)) { - case WLAN_FC_STYPE_PROBE_REQ: - ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_AUTH: - ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_ASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0); - break; - case WLAN_FC_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1); - break; - case WLAN_FC_STYPE_DEAUTH: - ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_DISASSOC: - ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status); - break; - case WLAN_FC_STYPE_ACTION: - ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status); - break; - default: - wpa_printf(MSG_DEBUG, "MLME: received unknown management " - "frame - stype=%d", WLAN_FC_GET_STYPE(fc)); - break; - } -} - - -static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s, - const u8 *buf, size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_mgmt *mgmt; - u16 fc; - - if (len < 24) - return; - - mgmt = (struct ieee80211_mgmt *) buf; - fc = le_to_host16(mgmt->frame_control); - - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) { - if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) { - ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, - len, rx_status); - } else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) { - ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status); - } - } -} - - -static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s) -{ - int active = 0; - -#if 0 /* FIX */ - list_for_each(ptr, &local->sta_list) { - sta = list_entry(ptr, struct sta_info, list); - if (sta->dev == dev && - time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, - jiffies)) { - active++; - break; - } - } -#endif - - return active; -} - - -static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s) -{ -#if 0 /* FIX */ - list_for_each_safe(ptr, n, &local->sta_list) { - sta = list_entry(ptr, struct sta_info, list); - if (time_after(jiffies, sta->last_rx + - IEEE80211_IBSS_INACTIVITY_LIMIT)) { - wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA " - MACSTR, MAC2STR(sta->addr)); - sta_info_free(local, sta, 1); - } - } -#endif -} - - -static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s) -{ - struct wpa_driver_scan_params params; - - ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); - - ieee80211_sta_expire(wpa_s); - if (ieee80211_sta_active_ibss(wpa_s)) - return; - - wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for " - "other IBSS networks with same SSID (merge)"); - os_memset(¶ms, 0, sizeof(params)); - params.ssids[0].ssid = wpa_s->mlme.ssid; - params.ssids[0].ssid_len = wpa_s->mlme.ssid_len; - params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0; - ieee80211_sta_req_scan(wpa_s, ¶ms); -} - - -static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - - switch (wpa_s->mlme.state) { - case IEEE80211_DISABLED: - break; - case IEEE80211_AUTHENTICATE: - ieee80211_authenticate(wpa_s); - break; - case IEEE80211_ASSOCIATE: - ieee80211_associate(wpa_s); - break; - case IEEE80211_ASSOCIATED: - ieee80211_associated(wpa_s); - break; - case IEEE80211_IBSS_SEARCH: - ieee80211_sta_find_ibss(wpa_s); - break; - case IEEE80211_IBSS_JOINED: - ieee80211_sta_merge_ibss(wpa_s); - break; - default: - wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d", - wpa_s->mlme.state); - break; - } - - if (ieee80211_privacy_mismatch(wpa_s)) { - wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch " - "and mixed-cell disabled - disassociate"); - - ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED); - ieee80211_set_associated(wpa_s, 0); - } -} - - -static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s) -{ - struct wpa_ssid *ssid = wpa_s->current_ssid; - if (ssid && ssid->mode != WPAS_MODE_INFRA) - return; - -#if 0 /* FIX */ - if (local->hw->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->hw->reset_tsf(local->mdev); - } -#endif - - wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */ - - - if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN) - wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; - else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED) - wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY; - else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP) - wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP; - else - wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN; - wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d", - wpa_s->mlme.auth_alg); - wpa_s->mlme.auth_transaction = -1; - wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0; - ieee80211_authenticate(wpa_s); -} - - -static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s) -{ -#if 0 /* FIX */ - int m, c; - - for (m = 0; m < local->hw->num_modes; m++) { - struct ieee80211_hw_modes *mode = &local->hw->modes[m]; - if (mode->mode != local->conf.phymode) - continue; - for (c = 0; c < mode->num_channels; c++) { - struct ieee80211_channel *chan = &mode->channels[c]; - if (chan->flag & IEEE80211_CHAN_W_SCAN && - chan->chan == local->conf.channel) { - if (chan->flag & IEEE80211_CHAN_W_IBSS) - return 1; - break; - } - } - } -#endif - - return 0; -} - - -static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s, - struct ieee80211_sta_bss *bss) -{ - int res = 0, rates, done = 0, bssid_changed; - struct ieee80211_mgmt *mgmt; -#if 0 /* FIX */ - struct ieee80211_tx_control control; - struct ieee80211_rate *rate; - struct rate_control_extra extra; -#endif - u8 *pos, *buf; - size_t len; - - /* Remove possible STA entries from other IBSS networks. */ -#if 0 /* FIX */ - sta_info_flush(local, NULL); - - if (local->hw->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->hw->reset_tsf(local->mdev); - } -#endif - bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN); - os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN); - if (bssid_changed) - wpas_notify_bssid_changed(wpa_s); - -#if 0 /* FIX */ - local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; - - sdata->drop_unencrypted = bss->capability & - host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0; -#endif - -#if 0 /* FIX */ - os_memset(&rq, 0, sizeof(rq)); - rq.m = bss->freq * 100000; - rq.e = 1; - res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL); -#endif - - if (!ieee80211_ibss_allowed(wpa_s)) { -#if 0 /* FIX */ - wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d " - "(%d MHz)", local->conf.channel, - local->conf.freq); -#endif - return -1; - } - - /* Set beacon template based on scan results */ - buf = os_malloc(400); - len = 0; - do { - if (buf == NULL) - break; - - mgmt = (struct ieee80211_mgmt *) buf; - len += 24 + sizeof(mgmt->u.beacon); - os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_BEACON); - os_memset(mgmt->da, 0xff, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); -#if 0 /* FIX */ - mgmt->u.beacon.beacon_int = - host_to_le16(local->conf.beacon_int); -#endif - mgmt->u.beacon.capab_info = host_to_le16(bss->capability); - - pos = buf + len; - len += 2 + wpa_s->mlme.ssid_len; - *pos++ = WLAN_EID_SSID; - *pos++ = wpa_s->mlme.ssid_len; - os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); - - rates = bss->supp_rates_len; - if (rates > 8) - rates = 8; - pos = buf + len; - len += 2 + rates; - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = rates; - os_memcpy(pos, bss->supp_rates, rates); - - pos = buf + len; - len += 2 + 1; - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = bss->channel; - - pos = buf + len; - len += 2 + 2; - *pos++ = WLAN_EID_IBSS_PARAMS; - *pos++ = 2; - /* FIX: set ATIM window based on scan results */ - *pos++ = 0; - *pos++ = 0; - - if (bss->supp_rates_len > 8) { - rates = bss->supp_rates_len - 8; - pos = buf + len; - len += 2 + rates; - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates; - os_memcpy(pos, &bss->supp_rates[8], rates); - } - -#if 0 /* FIX */ - os_memset(&control, 0, sizeof(control)); - control.pkt_type = PKT_PROBE_RESP; - os_memset(&extra, 0, sizeof(extra)); - extra.endidx = local->num_curr_rates; - rate = rate_control_get_rate(wpa_s, skb, &extra); - if (rate == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX " - "rate for IBSS beacon"); - break; - } - control.tx_rate = (wpa_s->mlme.short_preamble && - (rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rate->val2 : rate->val; - control.antenna_sel = local->conf.antenna_sel; - control.power_level = local->conf.power_level; - control.no_ack = 1; - control.retry_limit = 1; - control.rts_cts_duration = 0; -#endif - -#if 0 /* FIX */ - wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC); - if (wpa_s->mlme.probe_resp) { - mgmt = (struct ieee80211_mgmt *) - wpa_s->mlme.probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_PROBE_RESP); - } else { - wpa_printf(MSG_DEBUG, "MLME: Could not allocate " - "ProbeResp template for IBSS"); - } - - if (local->hw->beacon_update && - local->hw->beacon_update(wpa_s, skb, &control) == 0) { - wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon " - "template based on scan results"); - skb = NULL; - } - - rates = 0; - for (i = 0; i < bss->supp_rates_len; i++) { - int rate = (bss->supp_rates[i] & 0x7f) * 5; - if (local->conf.phymode == MODE_ATHEROS_TURBO) - rate *= 2; - for (j = 0; j < local->num_curr_rates; j++) - if (local->curr_rates[j] == rate) - rates |= BIT(j); - } - wpa_s->mlme.supp_rates_bits = rates; -#endif - done = 1; - } while (0); - - os_free(buf); - if (!done) { - wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon " - "template"); - } - - wpa_s->mlme.state = IEEE80211_IBSS_JOINED; - ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL); - - return res; -} - - -#if 0 /* FIX */ -static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s) -{ - struct ieee80211_sta_bss *bss; - u8 bssid[ETH_ALEN], *pos; - int i; - -#if 0 - /* Easier testing, use fixed BSSID. */ - os_memset(bssid, 0xfe, ETH_ALEN); -#else - /* Generate random, not broadcast, locally administered BSSID. Mix in - * own MAC address to make sure that devices that do not have proper - * random number generator get different BSSID. */ - os_get_random(bssid, ETH_ALEN); - for (i = 0; i < ETH_ALEN; i++) - bssid[i] ^= wpa_s->own_addr[i]; - bssid[0] &= ~0x01; - bssid[0] |= 0x02; -#endif - - wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID " - MACSTR "", MAC2STR(bssid)); - - bss = ieee80211_bss_add(wpa_s, bssid); - if (bss == NULL) - return -ENOMEM; - -#if 0 /* FIX */ - if (local->conf.beacon_int == 0) - local->conf.beacon_int = 100; - bss->beacon_int = local->conf.beacon_int; - bss->hw_mode = local->conf.phymode; - bss->channel = local->conf.channel; - bss->freq = local->conf.freq; -#endif - os_get_time(&bss->last_update); - bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS); -#if 0 /* FIX */ - if (sdata->default_key) { - bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY); - } else - sdata->drop_unencrypted = 0; - bss->supp_rates_len = local->num_curr_rates; -#endif - pos = bss->supp_rates; -#if 0 /* FIX */ - for (i = 0; i < local->num_curr_rates; i++) { - int rate = local->curr_rates[i]; - if (local->conf.phymode == MODE_ATHEROS_TURBO) - rate /= 2; - *pos++ = (u8) (rate / 5); - } -#endif - - return ieee80211_sta_join_ibss(wpa_s, bss); -} -#endif - - -static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s) -{ - struct ieee80211_sta_bss *bss; - int found = 0; - u8 bssid[ETH_ALEN]; - int active_ibss; - struct os_time now; - - if (wpa_s->mlme.ssid_len == 0) - return -EINVAL; - - active_ibss = ieee80211_sta_active_ibss(wpa_s); -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)", - active_ibss); -#endif /* IEEE80211_IBSS_DEBUG */ - for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { - if (wpa_s->mlme.ssid_len != bss->ssid_len || - os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0 - || !(bss->capability & WLAN_CAPABILITY_IBSS)) - continue; -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, " bssid=" MACSTR " found", - MAC2STR(bss->bssid)); -#endif /* IEEE80211_IBSS_DEBUG */ - os_memcpy(bssid, bss->bssid, ETH_ALEN); - found = 1; - if (active_ibss || - os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) - break; - } - -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, " sta_find_ibss: selected " MACSTR " current " - MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid)); -#endif /* IEEE80211_IBSS_DEBUG */ - if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_bss_get(wpa_s, bssid))) { - wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR - " based on configured SSID", - MAC2STR(bssid)); - return ieee80211_sta_join_ibss(wpa_s, bss); - } -#ifdef IEEE80211_IBSS_DEBUG - wpa_printf(MSG_DEBUG, " did not try to join ibss"); -#endif /* IEEE80211_IBSS_DEBUG */ - - /* Selected IBSS not found in current scan results - try to scan */ - os_get_time(&now); -#if 0 /* FIX */ - if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED && - !ieee80211_sta_active_ibss(wpa_s)) { - ieee80211_reschedule_timer(wpa_s, - IEEE80211_IBSS_MERGE_INTERVAL); - } else if (time_after(jiffies, wpa_s->mlme.last_scan_completed + - IEEE80211_SCAN_INTERVAL)) { - wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS " - "to join"); - return ieee80211_sta_req_scan(wpa_s->mlme.ssid, - wpa_s->mlme.ssid_len); - } else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) { - int interval = IEEE80211_SCAN_INTERVAL; - - if (time_after(jiffies, wpa_s->mlme.ibss_join_req + - IEEE80211_IBSS_JOIN_TIMEOUT)) { - if (wpa_s->mlme.create_ibss && - ieee80211_ibss_allowed(wpa_s)) - return ieee80211_sta_create_ibss(wpa_s); - if (wpa_s->mlme.create_ibss) { - wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed " - "on the configured channel %d " - "(%d MHz)", - local->conf.channel, - local->conf.freq); - } - - /* No IBSS found - decrease scan interval and continue - * scanning. */ - interval = IEEE80211_SCAN_INTERVAL_SLOW; - } - - wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; - ieee80211_reschedule_timer(wpa_s, interval); - return 0; - } -#endif - - return 0; -} - - -int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid, - size_t *len) -{ - os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len); - *len = wpa_s->mlme.ssid_len; - return 0; -} - - -int ieee80211_sta_associate(struct wpa_supplicant *wpa_s, - struct wpa_driver_associate_params *params) -{ - struct ieee80211_sta_bss *bss; - int bssid_changed; - - wpa_s->mlme.bssid_set = 0; - wpa_s->mlme.freq = params->freq; - if (params->bssid) { - bssid_changed = os_memcmp(wpa_s->bssid, params->bssid, - ETH_ALEN); - os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN); - if (bssid_changed) - wpas_notify_bssid_changed(wpa_s); - - if (!is_zero_ether_addr(params->bssid)) - wpa_s->mlme.bssid_set = 1; - bss = ieee80211_bss_get(wpa_s, wpa_s->bssid); - if (bss) { - wpa_s->mlme.phymode = bss->hw_mode; - wpa_s->mlme.channel = bss->channel; - wpa_s->mlme.freq = bss->freq; - } - } - -#if 0 /* FIX */ - /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is - * not defined. */ - if (local->hw->conf_tx) { - struct ieee80211_tx_queue_params qparam; - int i; - - os_memset(&qparam, 0, sizeof(qparam)); - /* TODO: are these ok defaults for all hw_modes? */ - qparam.aifs = 2; - qparam.cw_min = - local->conf.phymode == MODE_IEEE80211B ? 31 : 15; - qparam.cw_max = 1023; - qparam.burst_time = 0; - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - { - local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - } - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam); - } -#endif - - if (wpa_s->mlme.ssid_len != params->ssid_len || - os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0) - wpa_s->mlme.prev_bssid_set = 0; - os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len); - os_memset(wpa_s->mlme.ssid + params->ssid_len, 0, - MAX_SSID_LEN - params->ssid_len); - wpa_s->mlme.ssid_len = params->ssid_len; - wpa_s->mlme.ssid_set = 1; - - os_free(wpa_s->mlme.extra_ie); - if (params->wpa_ie == NULL || params->wpa_ie_len == 0) { - wpa_s->mlme.extra_ie = NULL; - wpa_s->mlme.extra_ie_len = 0; - } else { - wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len); - if (wpa_s->mlme.extra_ie == NULL) { - wpa_s->mlme.extra_ie_len = 0; - return -1; - } - os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie, - params->wpa_ie_len); - wpa_s->mlme.extra_ie_len = params->wpa_ie_len; - } - - wpa_s->mlme.key_mgmt = params->key_mgmt_suite; - - ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, - wpa_s->mlme.channel, wpa_s->mlme.freq); - - if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) { - os_get_time(&wpa_s->mlme.ibss_join_req); - wpa_s->mlme.state = IEEE80211_IBSS_SEARCH; - return ieee80211_sta_find_ibss(wpa_s); - } - - if (wpa_s->mlme.bssid_set) - ieee80211_sta_new_auth(wpa_s); - - return 0; -} - - -static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s) -{ - wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel; - wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq; - wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode; -} - - -static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s) -{ - wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel; - wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq; - wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode; - if (wpa_s->mlme.freq == 0) - return 0; - return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode, - wpa_s->mlme.channel, - wpa_s->mlme.freq); -} - - -static int ieee80211_active_scan(struct wpa_supplicant *wpa_s) -{ - size_t m; - int c; - - for (m = 0; m < wpa_s->mlme.num_modes; m++) { - struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m]; - if ((int) mode->mode != (int) wpa_s->mlme.phymode) - continue; - for (c = 0; c < mode->num_channels; c++) { - struct hostapd_channel_data *chan = &mode->channels[c]; - if (!(chan->flag & HOSTAPD_CHAN_DISABLED) && - chan->chan == wpa_s->mlme.channel) { - if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN)) - return 1; - break; - } - } - } - - return 0; -} - - -static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx) -{ - struct wpa_supplicant *wpa_s = eloop_ctx; - struct hostapd_hw_modes *mode; - struct hostapd_channel_data *chan; - int skip = 0; - int timeout = 0; - struct wpa_ssid *ssid = wpa_s->current_ssid; - int adhoc; - - if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL) - return; - - adhoc = ssid && ssid->mode == 1; - - switch (wpa_s->mlme.scan_state) { - case SCAN_SET_CHANNEL: - mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]; - if (wpa_s->mlme.scan_hw_mode_idx >= - (int) wpa_s->mlme.num_modes || - (wpa_s->mlme.scan_hw_mode_idx + 1 == - (int) wpa_s->mlme.num_modes - && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) { - if (ieee80211_sta_restore_oper_chan(wpa_s)) { - wpa_printf(MSG_DEBUG, "MLME: failed to " - "restore operational channel after " - "scan"); - } - wpa_printf(MSG_DEBUG, "MLME: scan completed"); - wpa_s->mlme.sta_scanning = 0; - os_get_time(&wpa_s->mlme.last_scan_completed); - wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL); - if (adhoc) { - if (!wpa_s->mlme.bssid_set || - (wpa_s->mlme.state == - IEEE80211_IBSS_JOINED && - !ieee80211_sta_active_ibss(wpa_s))) - ieee80211_sta_find_ibss(wpa_s); - } - return; - } - skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode)); - chan = &mode->channels[wpa_s->mlme.scan_channel_idx]; - if ((chan->flag & HOSTAPD_CHAN_DISABLED) || - (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) || - (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) && - mode->mode == HOSTAPD_MODE_IEEE80211B && - wpa_s->mlme.scan_skip_11b)) - skip = 1; - if (!skip && wpa_s->mlme.scan_freqs) { - int i, found = 0; - for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) { - if (wpa_s->mlme.scan_freqs[i] == chan->freq) { - found = 1; - break; - } - } - if (!found) - skip = 1; - } - - if (!skip) { - wpa_printf(MSG_MSGDUMP, - "MLME: scan channel %d (%d MHz)", - chan->chan, chan->freq); - - wpa_s->mlme.channel = chan->chan; - wpa_s->mlme.freq = chan->freq; - wpa_s->mlme.phymode = mode->mode; - if (ieee80211_sta_set_channel(wpa_s, mode->mode, - chan->chan, chan->freq)) - { - wpa_printf(MSG_DEBUG, "MLME: failed to set " - "channel %d (%d MHz) for scan", - chan->chan, chan->freq); - skip = 1; - } - } - - wpa_s->mlme.scan_channel_idx++; - if (wpa_s->mlme.scan_channel_idx >= - wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx]. - num_channels) { - wpa_s->mlme.scan_hw_mode_idx++; - wpa_s->mlme.scan_channel_idx = 0; - } - - if (skip) { - timeout = 0; - break; - } - - timeout = IEEE80211_PROBE_DELAY; - wpa_s->mlme.scan_state = SCAN_SEND_PROBE; - break; - case SCAN_SEND_PROBE: - if (ieee80211_active_scan(wpa_s)) { - ieee80211_send_probe_req(wpa_s, NULL, - wpa_s->mlme.scan_ssid, - wpa_s->mlme.scan_ssid_len); - timeout = IEEE80211_CHANNEL_TIME; - } else { - timeout = IEEE80211_PASSIVE_CHANNEL_TIME; - } - wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; - break; - } - - eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000), - ieee80211_sta_scan_timer, wpa_s, NULL); -} - - -int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, - struct wpa_driver_scan_params *params) -{ - const u8 *ssid = params->ssids[0].ssid; - size_t ssid_len = params->ssids[0].ssid_len; - - if (ssid_len > MAX_SSID_LEN) - return -1; - - /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) - * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS - * BSSID: MACAddress - * SSID - * ScanType: ACTIVE, PASSIVE - * ProbeDelay: delay (in microseconds) to be used prior to transmitting - * a Probe frame during active scanning - * ChannelList - * MinChannelTime (>= ProbeDelay), in TU - * MaxChannelTime: (>= MinChannelTime), in TU - */ - - /* MLME-SCAN.confirm - * BSSDescriptionSet - * ResultCode: SUCCESS, INVALID_PARAMETERS - */ - - /* TODO: if assoc, move to power save mode for the duration of the - * scan */ - - if (wpa_s->mlme.sta_scanning) - return -1; - - wpa_printf(MSG_DEBUG, "MLME: starting scan"); - - ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies, - params->extra_ies_len); - - os_free(wpa_s->mlme.scan_freqs); - if (params->freqs) { - int i; - for (i = 0; params->freqs[i]; i++) - ; - wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int)); - if (wpa_s->mlme.scan_freqs) - os_memcpy(wpa_s->mlme.scan_freqs, params->freqs, - (i + 1) * sizeof(int)); - } else - wpa_s->mlme.scan_freqs = NULL; - - ieee80211_sta_save_oper_chan(wpa_s); - - wpa_s->mlme.sta_scanning = 1; - /* TODO: stop TX queue? */ - - if (ssid) { - wpa_s->mlme.scan_ssid_len = ssid_len; - os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len); - } else - wpa_s->mlme.scan_ssid_len = 0; - wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not - * supported */ - wpa_s->mlme.scan_state = SCAN_SET_CHANNEL; - wpa_s->mlme.scan_hw_mode_idx = 0; - wpa_s->mlme.scan_channel_idx = 0; - eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL); - - return 0; -} - - -struct wpa_scan_results * -ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s) -{ - size_t ap_num = 0; - struct wpa_scan_results *res; - struct wpa_scan_res *r; - struct ieee80211_sta_bss *bss; - - res = os_zalloc(sizeof(*res)); - for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) - ap_num++; - res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *)); - if (res->res == NULL) { - os_free(res); - return NULL; - } - - for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) { - r = os_zalloc(sizeof(*r) + bss->ie_len); - if (r == NULL) - break; - os_memcpy(r->bssid, bss->bssid, ETH_ALEN); - r->freq = bss->freq; - r->beacon_int = bss->beacon_int; - r->caps = bss->capability; - r->level = bss->rssi; - r->tsf = bss->timestamp; - if (bss->ie) { - r->ie_len = bss->ie_len; - os_memcpy(r + 1, bss->ie, bss->ie_len); - } - - res->res[res->num++] = r; - } - - return res; -} - - -#if 0 /* FIX */ -struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s, - struct sk_buff *skb, u8 *bssid, - u8 *addr) -{ - struct ieee80211_local *local = dev->priv; - struct list_head *ptr; - struct sta_info *sta; - struct wpa_supplicant *sta_dev = NULL; - - /* TODO: Could consider removing the least recently used entry and - * allow new one to be added. */ - if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - if (net_ratelimit()) { - wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS " - "STA entry " MACSTR, MAC2STR(addr)); - } - return NULL; - } - - spin_lock_bh(&local->sub_if_lock); - list_for_each(ptr, &local->sub_if_list) { - sdata = list_entry(ptr, struct ieee80211_sub_if_data, list); - if (sdata->type == IEEE80211_SUB_IF_TYPE_STA && - os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { - sta_dev = sdata->dev; - break; - } - } - spin_unlock_bh(&local->sub_if_lock); - - if (sta_dev == NULL) - return NULL; - - wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR - " (dev=%s)", MAC2STR(addr), sta_dev->name); - - sta = sta_info_add(wpa_s, addr); - if (sta == NULL) { - return NULL; - } - - sta->dev = sta_dev; - sta->supp_rates = wpa_s->mlme.supp_rates_bits; - - rate_control_rate_init(local, sta); - - return sta; /* caller will call sta_info_release() */ -} -#endif - - -int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason) -{ - wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason); - - ieee80211_send_deauth(wpa_s, reason); - ieee80211_set_associated(wpa_s, 0); - return 0; -} - - -int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason) -{ - wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason); - - if (!wpa_s->mlme.associated) - return -1; - - ieee80211_send_disassoc(wpa_s, reason); - ieee80211_set_associated(wpa_s, 0); - return 0; -} - - -void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_mgmt *mgmt; - u16 fc; - const u8 *pos; - - /* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */ - - if (wpa_s->mlme.sta_scanning) { - ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status); - return; - } - - if (len < 24) - return; - - mgmt = (struct ieee80211_mgmt *) buf; - fc = le_to_host16(mgmt->frame_control); - - if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) - ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status); - else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) { - if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) != - WLAN_FC_FROMDS) - return; - /* mgmt->sa is actually BSSID for FromDS data frames */ - if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) - return; - /* Skip IEEE 802.11 and LLC headers */ - pos = buf + 24 + 6; - if (WPA_GET_BE16(pos) != ETH_P_EAPOL) - return; - pos += 2; - /* mgmt->bssid is actually BSSID for SA data frames */ - wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid, - pos, buf + len - pos); - } -} - - -void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features, - size_t num_hw_features) -{ - size_t i; - - if (hw_features == NULL) - return; - - for (i = 0; i < num_hw_features; i++) { - os_free(hw_features[i].channels); - os_free(hw_features[i].rates); - } - - os_free(hw_features); -} - - -int ieee80211_sta_init(struct wpa_supplicant *wpa_s) -{ - u16 num_modes, flags; - - wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, - &flags); - if (wpa_s->mlme.modes == NULL) { - wpa_printf(MSG_ERROR, "MLME: Failed to read supported " - "channels and rates from the driver"); - return -1; - } - - wpa_s->mlme.num_modes = num_modes; - - wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A; - wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B; - wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G; - - wpa_s->mlme.wmm_enabled = 1; - - return 0; -} - - -void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s) -{ - eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL); - eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL); - os_free(wpa_s->mlme.extra_ie); - wpa_s->mlme.extra_ie = NULL; - os_free(wpa_s->mlme.extra_probe_ie); - wpa_s->mlme.extra_probe_ie = NULL; - os_free(wpa_s->mlme.assocreq_ies); - wpa_s->mlme.assocreq_ies = NULL; - os_free(wpa_s->mlme.assocresp_ies); - wpa_s->mlme.assocresp_ies = NULL; - ieee80211_bss_list_deinit(wpa_s); - ieee80211_sta_free_hw_features(wpa_s->mlme.modes, - wpa_s->mlme.num_modes); -#ifdef CONFIG_IEEE80211R - os_free(wpa_s->mlme.ft_ies); - wpa_s->mlme.ft_ies = NULL; - wpa_s->mlme.ft_ies_len = 0; -#endif /* CONFIG_IEEE80211R */ - - os_free(wpa_s->mlme.scan_freqs); - wpa_s->mlme.scan_freqs = NULL; -} - - -#ifdef CONFIG_IEEE80211R - -int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md, - const u8 *ies, size_t ies_len) -{ - if (md == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain"); - os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN); - } else { - wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR, - MAC2STR(md)); - os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN); - } - - wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len); - os_free(wpa_s->mlme.ft_ies); - wpa_s->mlme.ft_ies = os_malloc(ies_len); - if (wpa_s->mlme.ft_ies == NULL) - return -1; - os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len); - wpa_s->mlme.ft_ies_len = ies_len; - - return 0; -} - - -int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action, - const u8 *target_ap, - const u8 *ies, size_t ies_len) -{ - u8 *buf; - size_t len; - struct ieee80211_mgmt *mgmt; - int res; - - /* - * Action frame payload: - * Category[1] = 6 (Fast BSS Transition) - * Action[1] = 1 (Fast BSS Transition Request) - * STA Address - * Target AP Address - * FT IEs - */ - - buf = os_zalloc(sizeof(*mgmt) + ies_len); - if (buf == NULL) { - wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for " - "FT action frame"); - return -1; - } - - mgmt = (struct ieee80211_mgmt *) buf; - len = 24; - os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN); - os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN); - os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, - WLAN_FC_STYPE_ACTION); - mgmt->u.action.category = WLAN_ACTION_FT; - mgmt->u.action.u.ft_action_req.action = action; - os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr, - ETH_ALEN); - os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap, - ETH_ALEN); - os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len); - len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len; - - wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d " - "Target AP=" MACSTR " body_len=%lu", - action, MAC2STR(target_ap), (unsigned long) ies_len); - - res = ieee80211_sta_tx(wpa_s, buf, len); - os_free(buf); - - return res; -} - -#endif /* CONFIG_IEEE80211R */ - - -static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s, - const u8 *ies, size_t ies_len) -{ - os_free(wpa_s->mlme.extra_probe_ie); - wpa_s->mlme.extra_probe_ie = NULL; - wpa_s->mlme.extra_probe_ie_len = 0; - - if (ies == NULL) - return 0; - - wpa_s->mlme.extra_probe_ie = os_malloc(ies_len); - if (wpa_s->mlme.extra_probe_ie == NULL) - return -1; - - os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len); - wpa_s->mlme.extra_probe_ie_len = ies_len; - - return 0; -} |