Commit cb74c432 authored by Joseph Jezak's avatar Joseph Jezak Committed by Jeff Garzik

[PATCH] SoftMAC: Prevent multiple authentication attempts on the same network

This patch addresses the "No queue exists" messages commonly seen during
authentication and associating.  These appear due to scheduling multiple
authentication attempts on the same network.  To prevent this, I added a
flag to stop multiple authentication attempts by the association layer.
I also added a check to the wx handler to see if we're connecting to a
different network than the one already in progress.  This scenario was
causing multiple requests on the same network because the network BSSID
was not being updated despite the fact that the ESSID changed.
Signed-off-by: default avatarJoseph Jezak <josejx@gentoo.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 43592194
...@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info { ...@@ -104,6 +104,7 @@ struct ieee80211softmac_assoc_info {
*/ */
u8 static_essid:1, u8 static_essid:1,
associating:1, associating:1,
assoc_wait:1,
bssvalid:1, bssvalid:1,
bssfixed:1; bssfixed:1;
......
...@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft ...@@ -47,9 +47,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
dprintk(KERN_INFO PFX "sent association request!\n"); dprintk(KERN_INFO PFX "sent association request!\n");
/* Change the state to associating */
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 1;
mac->associated = 0; /* just to make sure */ mac->associated = 0; /* just to make sure */
/* Set a timer for timeout */ /* Set a timer for timeout */
...@@ -203,6 +201,10 @@ ieee80211softmac_assoc_work(void *d) ...@@ -203,6 +201,10 @@ ieee80211softmac_assoc_work(void *d)
if (mac->associated) if (mac->associated)
ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); 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 */ /* try to find the requested network in our list, if we found one already */
if (bssvalid || mac->associnfo.bssfixed) if (bssvalid || mac->associnfo.bssfixed)
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
...@@ -295,19 +297,32 @@ ieee80211softmac_assoc_work(void *d) ...@@ -295,19 +297,32 @@ ieee80211softmac_assoc_work(void *d)
memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1); 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. */ /* 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, NULL, GFP_KERNEL);
}
return;
}
if (!found->authenticated && !found->authenticating) {
/* This relies on the fact that _auth_req only queues the work, /* This relies on the fact that _auth_req only queues the work,
* otherwise adding the notification would be racy. */ * otherwise adding the notification would be racy. */
if (!ieee80211softmac_auth_req(mac, found)) { if (!ieee80211softmac_auth_req(mac, found)) {
dprintk(KERN_INFO PFX "cannot associate without being authenticated, requested authentication\n"); if(!mac->associnfo.assoc_wait) {
ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); 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, NULL, GFP_KERNEL);
}
} else { } else {
printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); 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); ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
} }
return; return;
} }
/* finally! now we can start associating */ /* finally! now we can start associating */
mac->associnfo.assoc_wait = 0;
ieee80211softmac_assoc(mac, found); ieee80211softmac_assoc(mac, found);
} }
......
...@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, ...@@ -36,8 +36,9 @@ ieee80211softmac_auth_req(struct ieee80211softmac_device *mac,
struct ieee80211softmac_auth_queue_item *auth; struct ieee80211softmac_auth_queue_item *auth;
unsigned long flags; unsigned long flags;
if (net->authenticating) if (net->authenticating || net->authenticated)
return 0; return 0;
net->authenticating = 1;
/* Add the network if it's not already added */ /* Add the network if it's not already added */
ieee80211softmac_add_network(mac, net); ieee80211softmac_add_network(mac, net);
...@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data) ...@@ -92,7 +93,6 @@ ieee80211softmac_auth_queue(void *data)
return; return;
} }
net->authenticated = 0; net->authenticated = 0;
net->authenticating = 1;
/* add a timeout call so we eventually give up waiting for an auth reply */ /* add a timeout call so we eventually give up waiting for an auth reply */
schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT); schedule_delayed_work(&auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT);
auth->retry--; auth->retry--;
......
...@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev, ...@@ -70,12 +70,44 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
char *extra) char *extra)
{ {
struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); struct ieee80211softmac_device *sm = ieee80211_priv(net_dev);
struct ieee80211softmac_network *n;
struct ieee80211softmac_auth_queue_item *authptr;
int length = 0; int length = 0;
unsigned long flags; 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 && extra)) {
/* Get the associating network */
n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
if(n && n->essid.len == (data->essid.length - 1) &&
!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); spin_lock_irqsave(&sm->lock, flags);
sm->associnfo.static_essid = 0; sm->associnfo.static_essid = 0;
sm->associnfo.assoc_wait = 0;
if (data->essid.flags && data->essid.length && extra /*required?*/) { if (data->essid.flags && data->essid.length && extra /*required?*/) {
length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE); length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment