Commit 77fdaa12 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211: rework MLME for multiple authentications



Sit tight. This shakes up the world as you know
it. Let go of your spaghetti tongs, they will no
longer be required, the horrible statemachine in
net/mac80211/mlme.c is no more...

With the cfg80211 SME mac80211 now has much less
to keep track of, but, on the other hand, for FT
it needs to be able to keep track of at least one
authentication being in progress while associated.
So convert from a single state machine to having
small ones for all the different things we need to
do. For real FT it will still need work wrt. PS,
but this should be a good step.
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a7c1cfc9
......@@ -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,
......
......@@ -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)
......
......@@ -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,
......
......@@ -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;
......@@ -365,18 +362,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.
*
......@@ -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 &&
......
......@@ -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) {