Skip to content

Commit

Permalink
[PATCH] softmac: Fix WX and association related races
Browse files Browse the repository at this point in the history
This fixes some race conditions in the WirelessExtension
handling and association handling code.

Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Michael Buesch authored and John W. Linville committed Oct 17, 2006
1 parent 3693ec6 commit 7c28ad2
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 79 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/bcm43xx/bcm43xx_leds.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
//TODO
break;
case BCM43xx_LED_ASSOC:
if (bcm->softmac->associated)
if (bcm->softmac->associnfo.associated)
turn_on = 1;
break;
#ifdef CONFIG_BCM43XX_DEBUG
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/wireless/bcm43xx/bcm43xx_wx.c
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
unsigned long flags;

wstats = &bcm->stats.wstats;
if (!mac->associated) {
if (!mac->associnfo.associated) {
wstats->miss.beacon = 0;
// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
wstats->discard.retries = 0;
Expand Down
35 changes: 16 additions & 19 deletions include/net/ieee80211softmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,11 @@ struct ieee80211softmac_wpa {

/*
* Information about association
*
* Do we need a lock for this?
* We only ever use this structure inlined
* into our global struct. I've used its lock,
* but maybe we need a local one here?
*/
struct ieee80211softmac_assoc_info {

struct mutex mutex;

/*
* This is the requested ESSID. It is written
* only by the WX handlers.
Expand Down Expand Up @@ -99,12 +97,13 @@ struct ieee80211softmac_assoc_info {
*
* bssfixed is used for SIOCSIWAP.
*/
u8 static_essid:1,
short_preamble_available:1,
associating:1,
assoc_wait:1,
bssvalid:1,
bssfixed:1;
u8 static_essid;
u8 short_preamble_available;
u8 associating;
u8 associated;
u8 assoc_wait;
u8 bssvalid;
u8 bssfixed;

/* Scan retries remaining */
int scan_retry;
Expand Down Expand Up @@ -229,12 +228,10 @@ struct ieee80211softmac_device {
/* private stuff follows */
/* this lock protects this structure */
spinlock_t lock;

/* couple of flags */
u8 scanning:1, /* protects scanning from being done multiple times at once */
associated:1,
running:1;


u8 running; /* SoftMAC started? */
u8 scanning;

struct ieee80211softmac_scaninfo *scaninfo;
struct ieee80211softmac_assoc_info associnfo;
struct ieee80211softmac_bss_info bssinfo;
Expand All @@ -250,7 +247,7 @@ struct ieee80211softmac_device {

/* we need to keep a list of network structs we copied */
struct list_head network_list;

/* This must be the last item so that it points to the data
* allocated beyond this structure by alloc_ieee80211 */
u8 priv[0];
Expand Down Expand Up @@ -295,7 +292,7 @@ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device
{
struct ieee80211softmac_txrates *txrates = &mac->txrates;

if (!mac->associated)
if (!mac->associnfo.associated)
return txrates->mgt_mcast_rate;

/* We are associated, sending unicast frame */
Expand Down
56 changes: 27 additions & 29 deletions net/ieee80211/softmac/ieee80211softmac_assoc.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
dprintk(KERN_INFO PFX "sent association request!\n");

spin_lock_irqsave(&mac->lock, flags);
mac->associated = 0; /* just to make sure */
mac->associnfo.associated = 0; /* just to make sure */

/* Set a timer for timeout */
/* FIXME: make timeout configurable */
Expand All @@ -62,24 +62,22 @@ 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);
mutex_lock(&mac->associnfo.mutex);
/* we might race against ieee80211softmac_handle_assoc_response,
* so make sure only one of us does something */
if (!mac->associnfo.associating) {
spin_unlock_irqrestore(&mac->lock, flags);
return;
}
if (!mac->associnfo.associating)
goto out;
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associated = 0;
mac->associnfo.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");
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
out:
mutex_unlock(&mac->associnfo.mutex);
}

void
Expand All @@ -93,7 +91,7 @@ ieee80211softmac_disassoc(struct ieee80211softmac_device *mac)

netif_carrier_off(mac->dev);

mac->associated = 0;
mac->associnfo.associated = 0;
mac->associnfo.bssvalid = 0;
mac->associnfo.associating = 0;
ieee80211softmac_init_bss(mac);
Expand All @@ -107,7 +105,7 @@ ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reas
{
struct ieee80211softmac_network *found;

if (mac->associnfo.bssvalid && mac->associated) {
if (mac->associnfo.bssvalid && mac->associnfo.associated) {
found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
if (found)
ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
Expand Down Expand Up @@ -196,17 +194,18 @@ ieee80211softmac_assoc_work(void *d)
int bssvalid;
unsigned long flags;

mutex_lock(&mac->associnfo.mutex);

if (!mac->associnfo.associating)
goto out;

/* ieee80211_disassoc might clear this */
bssvalid = mac->associnfo.bssvalid;

/* meh */
if (mac->associated)
if (mac->associnfo.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);
Expand Down Expand Up @@ -260,10 +259,8 @@ ieee80211softmac_assoc_work(void *d)

if (!found) {
if (mac->associnfo.scan_retry > 0) {
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.scan_retry--;
spin_unlock_irqrestore(&mac->lock, flags);


/* We know of no such network. Let's scan.
* NB: this also happens if we had no memory to copy the network info...
* Maybe we can hope to have more memory after scanning finishes ;)
Expand All @@ -272,19 +269,17 @@ ieee80211softmac_assoc_work(void *d)
ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
if (ieee80211softmac_start_scan(mac))
dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
return;
goto out;
} else {
spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 0;
mac->associated = 0;
spin_unlock_irqrestore(&mac->lock, flags);
mac->associnfo.associated = 0;

dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
/* reset the retry counter for the next user request since we
* break out and don't reschedule ourselves after this point. */
mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
return;
goto out;
}
}

Expand All @@ -297,15 +292,15 @@ ieee80211softmac_assoc_work(void *d)
/* copy the ESSID for displaying it */
mac->associnfo.associate_essid.len = found->essid.len;
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->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;
goto out;
}
if (!found->authenticated && !found->authenticating) {
/* This relies on the fact that _auth_req only queues the work,
Expand All @@ -321,11 +316,14 @@ ieee80211softmac_assoc_work(void *d)
mac->associnfo.assoc_wait = 0;
ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
}
return;
goto out;
}
/* finally! now we can start associating */
mac->associnfo.assoc_wait = 0;
ieee80211softmac_assoc(mac, found);

out:
mutex_unlock(&mac->associnfo.mutex);
}

/* call this to do whatever is necessary when we're associated */
Expand All @@ -341,7 +339,7 @@ ieee80211softmac_associated(struct ieee80211softmac_device *mac,
mac->bssinfo.supported_rates = net->supported_rates;
ieee80211softmac_recalc_txrates(mac);

mac->associated = 1;
mac->associnfo.associated = 1;

mac->associnfo.short_preamble_available =
(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
Expand Down Expand Up @@ -421,7 +419,7 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
mac->associnfo.associating = 0;
mac->associnfo.bssvalid = 0;
mac->associated = 0;
mac->associnfo.associated = 0;
ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
}

Expand Down
9 changes: 7 additions & 2 deletions net/ieee80211/softmac/ieee80211softmac_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,8 +475,13 @@ int ieee80211softmac_handle_beacon(struct net_device *dev,
{
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);
/* This might race, but we don't really care and it's not worth
* adding heavyweight locking in this fastpath.
*/
if (mac->associnfo.associated) {
if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0)
ieee80211softmac_process_erp(mac, network->erp_value);
}

return 0;
}
Expand Down
1 change: 1 addition & 0 deletions net/ieee80211/softmac/ieee80211softmac_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct net_device *alloc_ieee80211softmac(int sizeof_priv)
INIT_LIST_HEAD(&softmac->network_list);
INIT_LIST_HEAD(&softmac->events);

mutex_init(&softmac->associnfo.mutex);
INIT_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work, softmac);
INIT_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout, softmac);
softmac->start_scan = ieee80211softmac_start_scan_implementation;
Expand Down
Loading

0 comments on commit 7c28ad2

Please sign in to comment.