diff options
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 105 | ||||
-rw-r--r-- | net/mac80211/debugfs_netdev.c | 38 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 86 | ||||
-rw-r--r-- | net/mac80211/iface.c | 28 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 1332 | ||||
-rw-r--r-- | net/mac80211/rx.c | 29 | ||||
-rw-r--r-- | net/mac80211/scan.c | 23 |
7 files changed, 750 insertions, 891 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e6d8860f26f..7cfc14e4ca0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *wiphy, static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_auth_request *req) { - struct ieee80211_sub_if_data *sdata; - const u8 *ssid; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - switch (req->auth_type) { - case NL80211_AUTHTYPE_OPEN_SYSTEM: - sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN; - break; - case NL80211_AUTHTYPE_SHARED_KEY: - sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY; - break; - case NL80211_AUTHTYPE_FT: - sdata->u.mgd.auth_alg = WLAN_AUTH_FT; - break; - case NL80211_AUTHTYPE_NETWORK_EAP: - sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP; - break; - default: - return -EOPNOTSUPP; - } - - memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); - if (!ssid) - return -EINVAL; - sdata->u.mgd.ssid_len = *(ssid + 1); - memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); - - kfree(sdata->u.mgd.sme_auth_ie); - sdata->u.mgd.sme_auth_ie = NULL; - sdata->u.mgd.sme_auth_ie_len = 0; - if (req->ie) { - sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL); - if (sdata->u.mgd.sme_auth_ie == NULL) - return -ENOMEM; - memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len); - sdata->u.mgd.sme_auth_ie_len = req->ie_len; - } - - sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_assoc_request *req) { - struct ieee80211_sub_if_data *sdata; - int ret, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || - !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) - return -ENOLINK; /* not authenticated */ - - sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N; - - for (i = 0; i < req->crypto.n_ciphers_pairwise; i++) - if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP || - req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) - sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; - - sdata->local->oper_channel = req->bss->channel; - ieee80211_hw_config(sdata->local, 0); - - ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); - if (ret && ret != -EALREADY) - return ret; - - if (req->use_mfp) { - sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED; - sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED; - } else { - sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED; - sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; - } - - if (req->prev_bssid) { - sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN); - } else - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - - if (req->crypto.control_port) - sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; - else - sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; - - sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE; - ieee80211_sta_req_auth(sdata); - return 0; + return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_deauth_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_deauthenticate(sdata, req->reason_code); + return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_disassoc_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* TODO: req->ie, req->peer_addr */ - return ieee80211_sta_disassociate(sdata, req->reason_code); + return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req); } static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 4c541f0f325..e9ec6cae2d3 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); /* STA attributes */ -IEEE80211_IF_FILE(state, u.mgd.state, DEC); IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); -IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC); -IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE); IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); -IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE); -IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC); -IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC); -IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC); -IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC); - -static ssize_t ieee80211_if_fmt_flags( - const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) -{ - return scnprintf(buf, buflen, "%s%s%s%s%s\n", - sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", - sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); -} -__IEEE80211_IF_FILE(flags); /* AP attributes */ IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); @@ -180,18 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(force_unicast_rateidx, sta); DEBUGFS_ADD(max_ratectrl_rateidx, sta); - DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); - DEBUGFS_ADD(prev_bssid, sta); - DEBUGFS_ADD(ssid_len, sta); DEBUGFS_ADD(aid, sta); DEBUGFS_ADD(capab, sta); - DEBUGFS_ADD(extra_ie_len, sta); - DEBUGFS_ADD(auth_tries, sta); - DEBUGFS_ADD(assoc_tries, sta); - DEBUGFS_ADD(auth_alg, sta); - DEBUGFS_ADD(auth_transaction, sta); - DEBUGFS_ADD(flags, sta); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) @@ -311,18 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(force_unicast_rateidx, sta); DEBUGFS_DEL(max_ratectrl_rateidx, sta); - DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); - DEBUGFS_DEL(prev_bssid, sta); - DEBUGFS_DEL(ssid_len, sta); DEBUGFS_DEL(aid, sta); DEBUGFS_DEL(capab, sta); - DEBUGFS_DEL(extra_ie_len, sta); - DEBUGFS_DEL(auth_tries, sta); - DEBUGFS_DEL(assoc_tries, sta); - DEBUGFS_DEL(auth_alg, sta); - DEBUGFS_DEL(auth_transaction, sta); - DEBUGFS_DEL(flags, sta); } static void del_ap_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d0354b16d24..2e92bbd9b2d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -227,11 +227,32 @@ struct mesh_preq_queue { u8 flags; }; +enum ieee80211_mgd_state { + IEEE80211_MGD_STATE_IDLE, + IEEE80211_MGD_STATE_PROBE, + IEEE80211_MGD_STATE_AUTH, + IEEE80211_MGD_STATE_ASSOC, +}; + +struct ieee80211_mgd_work { + struct list_head list; + struct ieee80211_bss *bss; + int ie_len; + u8 prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + u8 ssid_len; + unsigned long timeout; + enum ieee80211_mgd_state state; + u16 auth_alg, auth_transaction; + + int tries; + + /* must be last */ + u8 ie[0]; /* for auth or assoc frame, not probe */ +}; + /* flags used in struct ieee80211_if_managed.flags */ enum ieee80211_sta_flags { - IEEE80211_STA_PREV_BSSID_SET = BIT(0), - IEEE80211_STA_AUTHENTICATED = BIT(1), - IEEE80211_STA_ASSOCIATED = BIT(2), IEEE80211_STA_PROBEREQ_POLL = BIT(3), IEEE80211_STA_CONTROL_PORT = BIT(4), IEEE80211_STA_WMM_ENABLED = BIT(5), @@ -243,8 +264,6 @@ enum ieee80211_sta_flags { /* flags for MLME request */ enum ieee80211_sta_request { IEEE80211_STA_REQ_SCAN, - IEEE80211_STA_REQ_AUTH, - IEEE80211_STA_REQ_RUN, }; struct ieee80211_if_managed { @@ -254,35 +273,17 @@ struct ieee80211_if_managed { struct work_struct chswitch_work; struct work_struct beacon_loss_work; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + struct mutex mtx; + struct ieee80211_bss *associated; + struct list_head work_list; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - - enum { - IEEE80211_STA_MLME_DISABLED, - IEEE80211_STA_MLME_DIRECT_PROBE, - IEEE80211_STA_MLME_AUTHENTICATE, - IEEE80211_STA_MLME_ASSOCIATE, - IEEE80211_STA_MLME_ASSOCIATED, - } state; + u8 bssid[ETH_ALEN]; u16 aid; u16 capab; - u8 *extra_ie; /* to be added to the end of AssocReq */ - size_t extra_ie_len; - - /* The last AssocReq/Resp IEs */ - u8 *assocreq_ies, *assocresp_ies; - size_t assocreq_ies_len, assocresp_ies_len; struct sk_buff_head skb_queue; - int assoc_scan_tries; /* number of scans done pre-association */ - int direct_probe_tries; /* retries for direct probes */ - int auth_tries; /* retries for auth req */ - int assoc_tries; /* retries for assoc req */ - unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ @@ -292,9 +293,6 @@ struct ieee80211_if_managed { unsigned int flags; - int auth_alg; /* currently used IEEE 802.11 authentication algorithm */ - int auth_transaction; - u32 beacon_crc; enum { @@ -304,10 +302,6 @@ struct ieee80211_if_managed { } mfp; /* management frame protection */ int wmm_last_param_set; - - /* Extra IE data for management frames */ - u8 *sme_auth_ie; - size_t sme_auth_ie_len; }; enum ieee80211_ibss_request { @@ -466,18 +460,9 @@ struct ieee80211_sub_if_data { union { struct { struct dentry *drop_unencrypted; - struct dentry *state; struct dentry *bssid; - struct dentry *prev_bssid; - struct dentry *ssid_len; struct dentry *aid; struct dentry *capab; - struct dentry *extra_ie_len; - struct dentry *auth_tries; - struct dentry *assoc_tries; - struct dentry *auth_alg; - struct dentry *auth_transaction; - struct dentry *flags; struct dentry *force_unicast_rateidx; struct dentry *max_ratectrl_rateidx; } sta; @@ -928,11 +913,16 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* STA code */ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata); +int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_auth_request *req); +int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_assoc_request *req); +int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + struct cfg80211_deauth_request *req); +int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + struct cfg80211_disassoc_request *req); ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata); -int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); -int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); void ieee80211_send_pspoll(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency); @@ -966,8 +956,6 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, void ieee80211_scan_cancel(struct ieee80211_local *local); ieee80211_rx_result ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); -int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, - const char *ie, size_t len); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -983,8 +971,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); void ieee80211_rx_bss_put(struct ieee80211_local *local, struct ieee80211_bss *bss); -void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid, - int freq, u8 *ssid, u8 ssid_len); /* interface handling */ int ieee80211_if_add(struct ieee80211_local *local, const char *name, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index b87bf425f85..4839a2d97a3 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev) ieee80211_configure_filter(local); netif_addr_unlock_bh(local->mdev); break; - case NL80211_IFTYPE_STATION: - sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - /* fall through */ default: conf.vif = &sdata->vif; conf.type = sdata->vif.type; @@ -366,18 +363,6 @@ static int ieee80211_stop(struct net_device *dev) rcu_read_unlock(); /* - * Announce that we are leaving the network, in case we are a - * station interface type. This must be done before removing - * all stations associated with sta_info_flush, otherwise STA - * information will be gone and no announce being done. - */ - if (sdata->vif.type == NL80211_IFTYPE_STATION) { - if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED) - ieee80211_sta_deauthenticate(sdata, - WLAN_REASON_DEAUTH_LEAVING); - } - - /* * Remove all stations associated with this interface. * * This must be done before calling ops->remove_interface() @@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev) netif_addr_unlock_bh(local->mdev); break; case NL80211_IFTYPE_STATION: - memset(sdata->u.mgd.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.mgd.chswitch_timer); del_timer_sync(&sdata->u.mgd.timer); /* @@ -485,10 +469,6 @@ static int ieee80211_stop(struct net_device *dev) */ synchronize_rcu(); skb_queue_purge(&sdata->u.mgd.skb_queue); - - kfree(sdata->u.mgd.extra_ie); - sdata->u.mgd.extra_ie = NULL; - sdata->u.mgd.extra_ie_len = 0; /* fall through */ case NL80211_IFTYPE_ADHOC: if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { @@ -650,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev) kfree_skb(sdata->u.ibss.presp); break; case NL80211_IFTYPE_STATION: - kfree(sdata->u.mgd.extra_ie); - kfree(sdata->u.mgd.assocreq_ies); - kfree(sdata->u.mgd.assocresp_ies); - kfree(sdata->u.mgd.sme_auth_ie); - break; case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: @@ -937,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) continue; /* do not count disabled managed interfaces */ if (sdata->vif.type == NL80211_IFTYPE_STATION && - sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED) + !sdata->u.mgd.associated && + list_empty(&sdata->u.mgd.work_list)) continue; /* do not count unused IBSS interfaces */ if (sdata->vif.type == NL80211_IFTYPE_ADHOC && diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 29575eea3ed..108e8c9c60f 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -27,20 +27,51 @@ #include "rate.h" #include "led.h" -#define IEEE80211_ASSOC_SCANS_MAX_TRIES 2 #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) #define IEEE80211_PROBE_WAIT (HZ / 5) -#define IEEE80211_PROBE_IDLE_TIME (60 * HZ) -#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) #define TMR_RUNNING_TIMER 0 #define TMR_RUNNING_CHANSW 1 +/* + * All cfg80211 functions have to be called outside a locked + * section so that they can acquire a lock themselves... This + * is much simpler than queuing up things in cfg80211, but we + * do need some indirection for that here. + */ +enum rx_mgmt_action { + /* no action required */ + RX_MGMT_NONE, + + /* caller must call cfg80211_send_rx_auth() */ + RX_MGMT_CFG80211_AUTH, + + /* caller must call cfg80211_send_rx_assoc() */ + RX_MGMT_CFG80211_ASSOC, + + /* caller must call cfg80211_send_deauth() */ + RX_MGMT_CFG80211_DEAUTH, + + /* caller must call cfg80211_send_disassoc() */ + RX_MGMT_CFG80211_DISASSOC, + + /* caller must call cfg80211_auth_timeout() & free work */ + RX_MGMT_CFG80211_AUTH_TO, + + /* caller must call cfg80211_assoc_timeout() & free work */ + RX_MGMT_CFG80211_ASSOC_TO, +}; + /* utils */ +static inline void ASSERT_MGD_MTX(struct ieee80211_if_managed *ifmgd) +{ + WARN_ON(!mutex_is_locked(&ifmgd->mtx)); +} + static int ecw2cw(int ecw) { return (1 << ecw) - 1; @@ -74,11 +105,10 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss, */ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, struct ieee80211_ht_info *hti, - u16 ap_ht_cap_flags) + const u8 *bssid, u16 ap_ht_cap_flags) { struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct sta_info *sta; u32 changed = 0; u16 ht_opmode; @@ -127,12 +157,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, 0); rcu_read_lock(); - - sta = sta_info_get(local, ifmgd->bssid); + sta = sta_info_get(local, bssid); if (sta) rate_control_rate_update(local, sband, sta, IEEE80211_RC_HT_CHANGED); - rcu_read_unlock(); } @@ -155,7 +183,8 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, /* frame sending functions */ -static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) +static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; @@ -165,14 +194,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) const u8 *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; - struct ieee80211_bss *bss; int wmm = 0; struct ieee80211_supported_band *sband; u32 rates = 0; skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + ifmgd->extra_ie_len + - ifmgd->ssid_len); + sizeof(*mgmt) + 200 + wk->ie_len + + wk->ssid_len); if (!skb) { printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " "frame\n", sdata->dev->name); @@ -191,45 +219,35 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_used) - wmm = 1; + if (wk->bss->cbss.capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (wk->bss->wmm_used) + wmm = 1; - /* get all rates supported by the device and the AP as - * some APs don't like getting a superset of their rates - * in the association request (e.g. D-Link DAP 1353 in - * b-only mode) */ - rates_len = ieee80211_compatible_rates(bss, sband, &rates); + /* get all rates supported by the device and the AP as + * some APs don't like getting a superset of their rates + * in the association request (e.g. D-Link DAP 1353 in + * b-only mode) */ + rates_len = ieee80211_compatible_rates(wk->bss, sband, &rates); - if ((bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && - (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) - capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; - - ieee80211_rx_bss_put(local, bss); - } else { - rates = ~0; - rates_len = sband->n_bitrates; - } + if ((wk->bss->cbss.capability & WLAN_CAPABILITY_SPECTRUM_MGMT) && + (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)) + capab |= WLAN_CAPABILITY_SPECTRUM_MGMT; mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, wk->bss->cbss.bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, wk->bss->cbss.bssid, ETH_ALEN); - if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) { + if (!is_zero_ether_addr(wk->prev_bssid)) { skb_put(skb, 10); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_REASSOC_REQ); mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); mgmt->u.reassoc_req.listen_interval = cpu_to_le16(local->hw.conf.listen_interval); - memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid, + memcpy(mgmt->u.reassoc_req.current_ap, wk->prev_bssid, ETH_ALEN); } else { skb_put(skb, 4); @@ -241,10 +259,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } /* SSID */ - ies = pos = skb_put(skb, 2 + ifmgd->ssid_len); + ies = pos = skb_put(skb, 2 + wk->ssid_len); *pos++ = WLAN_EID_SSID; - *pos++ = ifmgd->ssid_len; - memcpy(pos, ifmgd->ssid, ifmgd->ssid_len); + *pos++ = wk->ssid_len; + memcpy(pos, wk->ssid, wk->ssid_len); /* add all rates which were marked to be used above */ supp_rates_len = rates_len; @@ -299,9 +317,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) } } - if (ifmgd->extra_ie) { - pos = skb_put(skb, ifmgd->extra_ie_len); - memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len); + if (wk->ie_len && wk->ie) { + pos = skb_put(skb, wk->ie_len); + memcpy(pos, wk->ie, wk->ie_len); } if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) { @@ -326,7 +344,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) */ if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) && sband->ht_cap.ht_supported && - (ht_ie = ieee80211_bss_get_ie(&bss->cbss, WLAN_EID_HT_INFORMATION)) && + (ht_ie = ieee80211_bss_get_ie(&wk->bss->cbss, WLAN_EID_HT_INFORMATION)) && ht_ie[1] >= sizeof(struct ieee80211_ht_info) && (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))) { struct ieee80211_ht_info *ht_info = @@ -363,18 +381,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); } - kfree(ifmgd->assocreq_ies); - ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies; - ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL); - if (ifmgd->assocreq_ies) - memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len); - ieee80211_tx_skb(sdata, skb, 0); } static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, - u16 stype, u16 reason) + const u8 *bssid, u16 stype, u16 reason) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -391,9 +403,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); memset(mgmt, 0, 24); - memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->da, bssid, ETH_ALEN); memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN); + memcpy(mgmt->bssid, bssid, ETH_ALEN); mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype); skb_put(skb, 2); /* u.deauth.reason_code == u.disassoc.reason_code */ @@ -477,28 +489,26 @@ static void ieee80211_chswitch_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work); - struct ieee80211_bss *bss; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; if (!netif_running(sdata->dev)) return; - bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (!bss) - goto exit; + mutex_lock(&ifmgd->mtx); + if (!ifmgd->associated) + goto out; sdata->local->oper_channel = sdata->local->csa_channel; + ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); + /* XXX: shouldn't really modify cfg80211-owned data! */ - if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL)) - bss->cbss.channel = sdata->local->oper_channel; + ifmgd->associated->cbss.channel = sdata->local->oper_channel; - ieee80211_rx_bss_put(sdata->local, bss); -exit: - ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; ieee80211_wake_queues_by_reason(&sdata->local->hw, IEEE80211_QUEUE_STOP_REASON_CSA); + out: + ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED; + mutex_unlock(&ifmgd->mtx); } static void ieee80211_chswitch_timer(unsigned long data) @@ -523,7 +533,9 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num); - if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED) + ASSERT_MGD_MTX(ifmgd); + + if (!ifmgd->associated) return; if (sdata->local->sw_scanning || sdata->local->hw_scanning) @@ -634,7 +646,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) } if (count == 1 && found->u.mgd.powersave && - (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) && + found->u.mgd.associated && list_empty(&found->u.mgd.work_list) && !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) { s32 beaconint_us; @@ -789,9 +801,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; -#endif u32 changed = 0; bool use_protection; bool use_short_preamble; @@ -808,42 +817,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); if (use_protection != bss_conf->use_cts_prot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", - sdata->dev->name, - use_protection ? "enabled" : "disabled", - ifmgd->bssid); - } -#endif bss_conf->use_cts_prot = use_protection; changed |= BSS_CHANGED_ERP_CTS_PROT; } if (use_short_preamble != bss_conf->use_short_preamble) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_preamble ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_preamble = use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } if (use_short_slot != bss_conf->use_short_slot) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s slot time" - " (BSSID=%pM)\n", - sdata->dev->name, - use_short_slot ? "short" : "long", - ifmgd->bssid); - } -#endif bss_conf->use_short_slot = use_short_slot; changed |= BSS_CHANGED_ERP_SLOT; } @@ -852,32 +835,23 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, + struct ieee80211_bss *bss, u32 bss_info_changed) { - struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - - struct ieee80211_bss *bss; bss_info_changed |= BSS_CHANGED_ASSOC; - ifmgd->flags |= IEEE80211_STA_ASSOCIATED; + /* set timing information */ + sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; + sdata->vif.bss_conf.timestamp = bss->cbss.tsf; + sdata->vif.bss_conf.dtim_period = bss->dtim_period; - bss = ieee80211_rx_bss_get(local, ifmgd->bssid, - conf->channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); - if (bss) { - /* set timing information */ - sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval; - sdata->vif.bss_conf.timestamp = bss->cbss.tsf; - sdata->vif.bss_conf.dtim_period = bss->dtim_period; + bss_info_changed |= BSS_CHANGED_BEACON_INT; + bss_info_changed |= ieee80211_handle_bss_capability(sdata, + bss->cbss.capability, bss->has_erp_value, bss->erp_value); - bss_info_changed |= BSS_CHANGED_BEACON_INT; - bss_info_changed |= ieee80211_handle_bss_capability(sdata, - bss->cbss.capability, bss->has_erp_value, bss->erp_value); - - ieee80211_rx_bss_put(local, bss); - } + sdata->u.mgd.associated = bss; + memcpy(sdata->u.mgd.bssid, bss->cbss.bssid, ETH_ALEN); ieee80211_led_assoc(local, 1); @@ -905,152 +879,133 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, netif_carrier_on(sdata->dev); } -static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->direct_probe_tries++; - if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); + sdata->dev->name, wk->bss->cbss.bssid); /* * Most likely AP is not in the range so remove the - * bss information associated to the AP + * bss struct for that AP. */ - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_DIRECT_PROBE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", - sdata->dev->name, ifmgd->bssid, - ifmgd->direct_probe_tries); + printk(KERN_DEBUG "%s: direct probe to AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, + wk->tries); - ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; - - /* Direct probe is sent to broadcast address as some APs + /* + * Direct probe is sent to broadcast address as some APs * will not answer to direct packet in unassociated state. */ - ieee80211_send_probe_req(sdata, NULL, - ifmgd->ssid, ifmgd->ssid_len, NULL, 0); + ieee80211_send_probe_req(sdata, NULL, wk->ssid, wk->ssid_len, NULL, 0); + + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata) +static enum rx_mgmt_action __must_check +ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, + struct ieee80211_mgd_work *wk) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_local *local = sdata->local; - ifmgd->auth_tries++; - if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { + wk->tries++; + if (wk->tries > IEEE80211_AUTH_MAX_TRIES) { printk(KERN_DEBUG "%s: authentication with AP %pM" " timed out\n", - sdata->dev->name, ifmgd->bssid); - ifmgd->state = IEEE80211_STA_MLME_DISABLED; - ieee80211_recalc_idle(local); - cfg80211_send_auth_timeout(sdata->dev, ifmgd->bssid, - GFP_KERNEL); - ieee80211_rx_bss_remove(sdata, ifmgd->bssid, - sdata->local->hw.conf.channel->center_freq, - ifmgd->ssid, ifmgd->ssid_len); + sdata->dev->name, wk->bss->cbss.bssid); + + /* + * Most likely AP is not in the range so remove the + * bss struct for that AP. + */ + cfg80211_unlink_bss(local->hw.wiphy, &wk->bss->cbss); /* * We might have a pending scan which had no chance to run yet - * due to state == IEEE80211_STA_MLME_AUTHENTICATE. - * Hence, queue the STAs work again + * due to work needing to be done. Hence, queue the STAs work + * again for that. */ queue_work(local->hw.workqueue, &ifmgd->work); - return; + return RX_MGMT_CFG80211_AUTH_TO; } - ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP %pM\n", - sdata->dev->name, ifmgd->bssid); + printk(KERN_DEBUG "%s: authenticate with AP %pM (try %d)\n", + sdata->dev->name, wk->bss->cbss.bssid, wk->tries); + + ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, + wk->bss->cbss.bssid, 0); + wk->auth_transaction = 2; - ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ifmgd->sme_auth_ie, - ifmgd->sme_auth_ie_len, ifmgd->bssid, 0); - ifmgd->auth_transaction = 2; + wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; + mod_timer(&ifmgd->timer, wk->timeout); - mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT); + return RX_MGMT_NONE; } -/* - * The disassoc 'reason' argument can be either our own reason - * if self disconnected or a reason code from the AP. - */ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, - bool deauth, bool self_disconnected, - u16 reason) + const u8 *bssid, bool deauth) { struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; |