Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c28ad2d authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville
Browse files

[PATCH] softmac: Fix WX and association related races



This fixes some race conditions in the WirelessExtension
handling and association handling code.

Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3693ec67
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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;
+16 −19
Original line number Diff line number Diff line
@@ -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.
@@ -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;
@@ -230,10 +229,8 @@ struct ieee80211softmac_device {
	/* 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;
@@ -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 */
+27 −29
Original line number Diff line number Diff line
@@ -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 */
@@ -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
@@ -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);
@@ -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);
@@ -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);	
@@ -260,9 +259,7 @@ 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...
@@ -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;
		}
	}

@@ -305,7 +300,7 @@ ieee80211softmac_assoc_work(void *d)
			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,
@@ -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 */
@@ -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;
@@ -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);
	}
	
+7 −2
Original line number Diff line number Diff line
@@ -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)
	/* 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;
}
Loading