summaryrefslogtreecommitdiffstats
path: root/net/ieee80211/softmac
diff options
context:
space:
mode:
Diffstat (limited to 'net/ieee80211/softmac')
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_assoc.c52
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_auth.c32
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_io.c20
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_module.c90
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_priv.h8
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c40
6 files changed, 187 insertions, 55 deletions
diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c
index 5e9a90651d0..589f6d2c548 100644
--- a/net/ieee80211/softmac/ieee80211softmac_assoc.c
+++ b/net/ieee80211/softmac/ieee80211softmac_assoc.c
@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
dprintk(KERN_INFO PFX "sent association request!\n");
- /* Change the state to associating */
spin_lock_irqsave(&mac->lock, flags);
- mac->associnfo.associating = 1;
mac->associated = 0; /* just to make sure */
/* Set a timer for timeout */
@@ -63,6 +61,7 @@ void
ieee80211softmac_assoc_timeout(void *d)
{
struct ieee80211softmac_device *mac = (struct ieee80211softmac_device *)d;
+ struct ieee80211softmac_network *n;
unsigned long flags;
spin_lock_irqsave(&mac->lock, flags);
@@ -75,11 +74,12 @@ ieee80211softmac_assoc_timeout(void *d)
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associated = 0;
+
+ n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
spin_unlock_irqrestore(&mac->lock, flags);
dprintk(KERN_INFO PFX "assoc request timed out!\n");
- /* FIXME: we need to know the network here. that requires a bit of restructuring */
- ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, NULL);
+ ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
}
void
@@ -96,7 +96,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)
mac->associated = 0;
mac->associnfo.bssvalid = 0;
mac->associnfo.associating = 0;
- ieee80211softmac_init_txrates(mac);
+ ieee80211softmac_init_bss(mac);
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL);
spin_unlock_irqrestore(&mac->lock, flags);
}
@@ -203,6 +203,10 @@ ieee80211softmac_assoc_work(void *d)
if (mac->associated)
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT);
+ spin_lock_irqsave(&mac->lock, flags);
+ mac->associnfo.associating = 1;
+ spin_unlock_irqrestore(&mac->lock, flags);
+
/* try to find the requested network in our list, if we found one already */
if (bssvalid || mac->associnfo.bssfixed)
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
@@ -295,19 +299,32 @@ ieee80211softmac_assoc_work(void *d)
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1);
/* we found a network! authenticate (if necessary) and associate to it. */
- if (!found->authenticated) {
+ if (found->authenticating) {
+ dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n");
+ if(!mac->associnfo.assoc_wait) {
+ mac->associnfo.assoc_wait = 1;
+ ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ }
+ return;
+ }
+ if (!found->authenticated && !found->authenticating) {
/* This relies on the fact that _auth_req only queues the work,
* otherwise adding the notification would be racy. */
if (!ieee80211softmac_auth_req(mac, found)) {
- dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n");
- ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ if(!mac->associnfo.assoc_wait) {
+ dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n");
+ mac->associnfo.assoc_wait = 1;
+ ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
+ }
} else {
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n");
+ mac->associnfo.assoc_wait = 0;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
}
return;
}
/* finally! now we can start associating */
+ mac->associnfo.assoc_wait = 0;
ieee80211softmac_assoc(mac, found);
}
@@ -317,11 +334,19 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
struct ieee80211_assoc_response * resp,
struct ieee80211softmac_network *net)
{
+ u16 cap = le16_to_cpu(resp->capability);
+ u8 erp_value = net->erp_value;
+
mac->associnfo.associating = 0;
- mac->associnfo.supported_rates = net->supported_rates;
+ mac->bssinfo.supported_rates = net->supported_rates;
ieee80211softmac_recalc_txrates(mac);
mac->associated = 1;
+
+ mac->associnfo.short_preamble_available =
+ (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
+ ieee80211softmac_process_erp(mac, erp_value);
+
if (mac->set_bssid_filter)
mac->set_bssid_filter(mac->dev, net->bssid);
memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN);
@@ -334,9 +359,9 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
int
ieee80211softmac_handle_assoc_response(struct net_device * dev,
struct ieee80211_assoc_response * resp,
- struct ieee80211_network * _ieee80211_network_do_not_use)
+ struct ieee80211_network * _ieee80211_network)
{
- /* NOTE: the network parameter has to be ignored by
+ /* NOTE: the network parameter has to be mostly ignored by
* this code because it is the ieee80211's pointer
* to the struct, not ours (we made a copy)
*/
@@ -368,6 +393,11 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
/* now that we know it was for us, we can cancel the timeout */
cancel_delayed_work(&mac->associnfo.timeout);
+ /* if the association response included an ERP IE, update our saved
+ * copy */
+ if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE)
+ network->erp_value = _ieee80211_network->erp_value;
+
switch (status) {
case 0:
dprintk(KERN_INFO PFX "associated!\n");
diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c
index 90b8484e509..4cef39e171d 100644
--- a/net/ieee80211/softmac/ieee80211softmac_auth.c
+++ b/net/ieee80211/softmac/ieee80211softmac_auth.c
@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_auth_queue_item *auth;
unsigned long flags;
- if (net->authenticating)
+ if (net->authenticating || net->authenticated)
return 0;
+ net->authenticating = 1;
/* Add the network if it's not already added */
ieee80211softmac_add_network(mac, net);
@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
return;
}
net->authenticated = 0;
- net->authenticating = 1;
/* add a timeout call so we eventually give up waiting for an auth reply */
schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
auth->retry--;
@@ -116,6 +116,16 @@ ieee80211softmac_auth_queue(void *data)
kfree(auth);
}
+/* Sends a response to an auth challenge (for shared key auth). */
+static void
+ieee80211softmac_auth_challenge_response(void *_aq)
+{
+ struct ieee80211softmac_auth_queue_item *aq = _aq;
+
+ /* Send our response */
+ ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
+}
+
/* Handle the auth response from the AP
* This should be registered with ieee80211 as handle_auth
*/
@@ -197,24 +207,30 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE:
/* Check to make sure we have a challenge IE */
data = (u8 *)auth->info_element;
- if(*data++ != MFIE_TYPE_CHALLENGE){
+ if (*data++ != MFIE_TYPE_CHALLENGE) {
printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n");
break;
}
/* Save the challenge */
spin_lock_irqsave(&mac->lock, flags);
net->challenge_len = *data++;
- if(net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
+ if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN)
net->challenge_len = WLAN_AUTH_CHALLENGE_LEN;
- if(net->challenge != NULL)
+ if (net->challenge != NULL)
kfree(net->challenge);
net->challenge = kmalloc(net->challenge_len, GFP_ATOMIC);
memcpy(net->challenge, data, net->challenge_len);
aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE;
- spin_unlock_irqrestore(&mac->lock, flags);
- /* Send our response */
- ieee80211softmac_send_mgt_frame(mac, aq->net, IEEE80211_STYPE_AUTH, aq->state);
+ /* We reuse the work struct from the auth request here.
+ * It is safe to do so as each one is per-request, and
+ * at this point (dealing with authentication response)
+ * we have obviously already sent the initial auth
+ * request. */
+ cancel_delayed_work(&aq->work);
+ INIT_WORK(&aq->work, &ieee80211softmac_auth_challenge_response, (void *)aq);
+ schedule_work(&aq->work);
+ spin_unlock_irqrestore(&mac->lock, flags);
return 0;
case IEEE80211SOFTMAC_AUTH_SHARED_PASS:
kfree(net->challenge);
diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c
index 09541611e48..82bfddbf33a 100644
--- a/net/ieee80211/softmac/ieee80211softmac_io.c
+++ b/net/ieee80211/softmac/ieee80211softmac_io.c
@@ -96,8 +96,7 @@ ieee80211softmac_alloc_mgt(u32 size)
if(size > IEEE80211_DATA_LEN)
return NULL;
/* Allocate the frame */
- data = kmalloc(size, GFP_ATOMIC);
- memset(data, 0, size);
+ data = kzalloc(size, GFP_ATOMIC);
return data;
}
@@ -229,6 +228,9 @@ ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt,
return 0;
ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid);
+ /* Fill in the capabilities */
+ (*pkt)->capability = ieee80211softmac_capabilities(mac, net);
+
/* Fill in Listen Interval (?) */
(*pkt)->listen_interval = cpu_to_le16(10);
@@ -465,3 +467,17 @@ ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
kfree(pkt);
return 0;
}
+
+/* Beacon handling */
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+ struct ieee80211_beacon *beacon,
+ struct ieee80211_network *network)
+{
+ struct ieee80211softmac_device *mac = ieee80211_priv(dev);
+
+ if (mac->associated && memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
+ ieee80211softmac_process_erp(mac, network->erp_value);
+
+ return 0;
+}
+
diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c
index 4b2e57d1241..addea1cf73a 100644
--- a/net/ieee80211/softmac/ieee80211softmac_module.c
+++ b/net/ieee80211/softmac/ieee80211softmac_module.c
@@ -44,6 +44,7 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response;
softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req;
softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc;
+ softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon;
softmac->scaninfo = NULL;
softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
@@ -178,21 +179,14 @@ int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo
return 0;
}
-/* Finds the highest rate which is:
- * 1. Present in ri (optionally a basic rate)
- * 2. Supported by the device
- * 3. Less than or equal to the user-defined rate
- */
-static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
+u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac,
struct ieee80211softmac_ratesinfo *ri, int basic_only)
{
u8 user_rate = mac->txrates.user_rate;
int i;
- if (ri->count == 0) {
- dprintk(KERN_ERR PFX "empty ratesinfo?\n");
+ if (ri->count == 0)
return IEEE80211_CCK_RATE_1MB;
- }
for (i = ri->count - 1; i >= 0; i--) {
u8 rate = ri->rates[i];
@@ -208,36 +202,61 @@ static u8 highest_supported_rate(struct ieee80211softmac_device *mac,
/* If we haven't found a suitable rate by now, just trust the user */
return user_rate;
}
+EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate);
+
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+ u8 erp_value)
+{
+ int use_protection;
+ int short_preamble;
+ u32 changes = 0;
+
+ /* Barker preamble mode */
+ short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0
+ && mac->associnfo.short_preamble_available) ? 1 : 0;
+
+ /* Protection needed? */
+ use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0;
+
+ if (mac->bssinfo.short_preamble != short_preamble) {
+ changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+ mac->bssinfo.short_preamble = short_preamble;
+ }
+
+ if (mac->bssinfo.use_protection != use_protection) {
+ changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+ mac->bssinfo.use_protection = use_protection;
+ }
+
+ if (mac->bssinfo_change && changes)
+ mac->bssinfo_change(mac->dev, changes);
+}
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac)
{
struct ieee80211softmac_txrates *txrates = &mac->txrates;
- struct ieee80211softmac_txrates oldrates;
u32 change = 0;
- if (mac->txrates_change)
- oldrates = mac->txrates;
-
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
- txrates->default_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 0);
+ txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0);
change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK;
txrates->default_fallback = lower_rate(mac, txrates->default_rate);
change |= IEEE80211SOFTMAC_TXRATECHG_MCAST;
- txrates->mcast_rate = highest_supported_rate(mac, &mac->associnfo.supported_rates, 1);
+ txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1);
if (mac->txrates_change)
- mac->txrates_change(mac->dev, change, &oldrates);
+ mac->txrates_change(mac->dev, change);
}
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac)
{
struct ieee80211_device *ieee = mac->ieee;
u32 change = 0;
struct ieee80211softmac_txrates *txrates = &mac->txrates;
- struct ieee80211softmac_txrates oldrates;
+ struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo;
/* TODO: We need some kind of state machine to lower the default rates
* if we loose too many packets.
@@ -245,8 +264,6 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
/* Change the default txrate to the highest possible value.
* The txrate machine will lower it, if it is too high.
*/
- if (mac->txrates_change)
- oldrates = mac->txrates;
/* FIXME: We don't correctly handle backing down to lower
rates, so 801.11g devices start off at 11M for now. People
can manually change it if they really need to, but 11M is
@@ -272,7 +289,23 @@ void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac)
change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST;
if (mac->txrates_change)
- mac->txrates_change(mac->dev, change, &oldrates);
+ mac->txrates_change(mac->dev, change);
+
+ change = 0;
+
+ bssinfo->supported_rates.count = 0;
+ memset(bssinfo->supported_rates.rates, 0,
+ sizeof(bssinfo->supported_rates.rates));
+ change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES;
+
+ bssinfo->short_preamble = 0;
+ change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE;
+
+ bssinfo->use_protection = 0;
+ change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION;
+
+ if (mac->bssinfo_change)
+ mac->bssinfo_change(mac->dev, change);
mac->running = 1;
}
@@ -282,7 +315,7 @@ void ieee80211softmac_start(struct net_device *dev)
struct ieee80211softmac_device *mac = ieee80211_priv(dev);
ieee80211softmac_start_check_rates(mac);
- ieee80211softmac_init_txrates(mac);
+ ieee80211softmac_init_bss(mac);
}
EXPORT_SYMBOL_GPL(ieee80211softmac_start);
@@ -335,7 +368,6 @@ u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rat
static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac,
int amount)
{
- struct ieee80211softmac_txrates oldrates;
u8 default_rate = mac->txrates.default_rate;
u8 default_fallback = mac->txrates.default_fallback;
u32 changes = 0;
@@ -348,8 +380,6 @@ printk("badness %d\n", mac->txrate_badness);
mac->txrate_badness += amount;
if (mac->txrate_badness <= -1000) {
/* Very small badness. Try a faster bitrate. */
- if (mac->txrates_change)
- memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
default_rate = raise_rate(mac, default_rate);
changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
default_fallback = get_fallback_rate(mac, default_rate);
@@ -358,8 +388,6 @@ printk("badness %d\n", mac->txrate_badness);
printk("Bitrate raised to %u\n", default_rate);
} else if (mac->txrate_badness >= 10000) {
/* Very high badness. Try a slower bitrate. */
- if (mac->txrates_change)
- memcpy(&oldrates, &mac->txrates, sizeof(oldrates));
default_rate = lower_rate(mac, default_rate);
changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT;
default_fallback = get_fallback_rate(mac, default_rate);
@@ -372,7 +400,7 @@ printk("Bitrate lowered to %u\n", default_rate);
mac->txrates.default_fallback = default_fallback;
if (changes && mac->txrates_change)
- mac->txrates_change(mac->dev, changes, &oldrates);
+ mac->txrates_change(mac->dev, changes);
}
void ieee80211softmac_fragment_lost(struct net_device *dev,
@@ -416,7 +444,11 @@ ieee80211softmac_create_network(struct ieee80211softmac_device *mac,
memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len);
softnet->supported_rates.count += net->rates_ex_len;
sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL);
-
+
+ /* we save the ERP value because it is needed at association time, and
+ * many AP's do not include an ERP IE in the association response. */
+ softnet->erp_value = net->erp_value;
+
softnet->capabilities = net->capability;
return softnet;
}
diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h
index fa1f8e3acfc..0642e090b8a 100644
--- a/net/ieee80211/softmac/ieee80211softmac_priv.h
+++ b/net/ieee80211/softmac/ieee80211softmac_priv.h
@@ -116,9 +116,11 @@ ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac,
struct ieee80211softmac_essid *essid);
/* Rates related */
+void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac,
+ u8 erp_value);
int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate);
u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta);
-void ieee80211softmac_init_txrates(struct ieee80211softmac_device *mac);
+void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac);
void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac);
static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) {
return ieee80211softmac_lower_rate_delta(mac, rate, 1);
@@ -133,6 +135,9 @@ static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate)
/*** prototypes from _io.c */
int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac,
void* ptrarg, u32 type, u32 arg);
+int ieee80211softmac_handle_beacon(struct net_device *dev,
+ struct ieee80211_beacon *beacon,
+ struct ieee80211_network *network);
/*** prototypes from _auth.c */
/* do these have to go into the public header? */
@@ -189,6 +194,7 @@ struct ieee80211softmac_network {
authenticated:1,
auth_desynced_once:1;
+ u8 erp_value; /* Saved ERP value */
u16 capabilities; /* Capabilities bitfield */
u8 challenge_len; /* Auth Challenge length */
char *challenge; /* Challenge Text */
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 0e65ff4e33f..2aa779d18f3 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -70,15 +70,47 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
char *extra)
{
struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
+ struct ieee80211softmac_network *n;
+ struct ieee80211softmac_auth_queue_item *authptr;
int length = 0;
unsigned long flags;
-
+
+ /* Check if we're already associating to this or another network
+ * If it's another network, cancel and start over with our new network
+ * If it's our network, ignore the change, we're already doing it!
+ */
+ if((sm->associnfo.associating || sm->associated) &&
+ (data->essid.flags && data->essid.length)) {
+ /* Get the associating network */
+ n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
+ if(n && n->essid.len == data->essid.length &&
+ !memcmp(n->essid.data, extra, n->essid.len)) {
+ dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
+ MAC_ARG(sm->associnfo.bssid));
+ return 0;
+ } else {
+ dprintk(KERN_INFO PFX "Canceling existing associate request!\n");
+ spin_lock_irqsave(&sm->lock,flags);
+ /* Cancel assoc work */
+ cancel_delayed_work(&sm->associnfo.work);
+ /* We don't have to do this, but it's a little cleaner */
+ list_for_each_entry(authptr, &sm->auth_queue, list)
+ cancel_delayed_work(&authptr->work);
+ sm->associnfo.bssvalid = 0;
+ sm->associnfo.bssfixed = 0;
+ spin_unlock_irqrestore(&sm->lock,flags);
+ flush_scheduled_work();
+ }
+ }
+
+
spin_lock_irqsave(&sm->lock, flags);
-
+
sm->associnfo.static_essid = 0;
+ sm->associnfo.assoc_wait = 0;
- if (data->essid.flags && data->essid.length && extra /*required?*/) {
- length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
+ if (data->essid.flags && data->essid.length) {
+ length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
if (length) {
memcpy(sm->associnfo.req_essid.data, extra, length);
sm->associnfo.static_essid = 1;