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 Original line Diff line number Diff line
@@ -242,7 +242,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
			//TODO
			//TODO
			break;
			break;
		case BCM43xx_LED_ASSOC:
		case BCM43xx_LED_ASSOC:
			if (bcm->softmac->associated)
			if (bcm->softmac->associnfo.associated)
				turn_on = 1;
				turn_on = 1;
			break;
			break;
#ifdef CONFIG_BCM43XX_DEBUG
#ifdef CONFIG_BCM43XX_DEBUG
+1 −1
Original line number Original line 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;
	unsigned long flags;


	wstats = &bcm->stats.wstats;
	wstats = &bcm->stats.wstats;
	if (!mac->associated) {
	if (!mac->associnfo.associated) {
		wstats->miss.beacon = 0;
		wstats->miss.beacon = 0;
//		bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
//		bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here?
		wstats->discard.retries = 0;
		wstats->discard.retries = 0;
+16 −19
Original line number Original line Diff line number Diff line
@@ -63,13 +63,11 @@ struct ieee80211softmac_wpa {


/*
/*
 * Information about association
 * 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 ieee80211softmac_assoc_info {

	struct mutex mutex;

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


	/* Scan retries remaining */
	/* Scan retries remaining */
	int scan_retry;
	int scan_retry;
@@ -230,10 +229,8 @@ struct ieee80211softmac_device {
	/* this lock protects this structure */
	/* this lock protects this structure */
	spinlock_t lock;
	spinlock_t lock;


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


	struct ieee80211softmac_scaninfo *scaninfo;
	struct ieee80211softmac_scaninfo *scaninfo;
	struct ieee80211softmac_assoc_info associnfo;
	struct ieee80211softmac_assoc_info associnfo;
@@ -295,7 +292,7 @@ static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device
{
{
	struct ieee80211softmac_txrates *txrates = &mac->txrates;
	struct ieee80211softmac_txrates *txrates = &mac->txrates;


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


	/* We are associated, sending unicast frame */
	/* We are associated, sending unicast frame */
+27 −29
Original line number Original line 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");
	dprintk(KERN_INFO PFX "sent association request!\n");


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


	n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid);
	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");
	dprintk(KERN_INFO PFX "assoc request timed out!\n");
	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
	ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n);
out:
	mutex_unlock(&mac->associnfo.mutex);
}
}


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


	netif_carrier_off(mac->dev);
	netif_carrier_off(mac->dev);


	mac->associated = 0;
	mac->associnfo.associated = 0;
	mac->associnfo.bssvalid = 0;
	mac->associnfo.bssvalid = 0;
	mac->associnfo.associating = 0;
	mac->associnfo.associating = 0;
	ieee80211softmac_init_bss(mac);
	ieee80211softmac_init_bss(mac);
@@ -107,7 +105,7 @@ ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reas
{
{
	struct ieee80211softmac_network *found;
	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);
		found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid);
		if (found)
		if (found)
			ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
			ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason);
@@ -196,17 +194,18 @@ ieee80211softmac_assoc_work(void *d)
	int bssvalid;
	int bssvalid;
	unsigned long flags;
	unsigned long flags;


	mutex_lock(&mac->associnfo.mutex);

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

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


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


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


			/* We know of no such network. Let's scan. 
			/* We know of no such network. Let's scan. 
			 * NB: this also happens if we had no memory to copy the network info...
			 * 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);
			ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL);
			if (ieee80211softmac_start_scan(mac))
			if (ieee80211softmac_start_scan(mac))
				dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
				dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n");
			return;
			goto out;
		} else {
		} else {
			spin_lock_irqsave(&mac->lock, flags);
			mac->associnfo.associating = 0;
			mac->associnfo.associating = 0;
			mac->associated = 0;
			mac->associnfo.associated = 0;
			spin_unlock_irqrestore(&mac->lock, flags);


			dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
			dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n");
			/* reset the retry counter for the next user request since we
			/* reset the retry counter for the next user request since we
			 * break out and don't reschedule ourselves after this point. */
			 * break out and don't reschedule ourselves after this point. */
			mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
			mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT;
			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL);
			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;
			mac->associnfo.assoc_wait = 1;
			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
			ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL);
		}
		}
		return;
		goto out;
	}
	}
	if (!found->authenticated && !found->authenticating) {
	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,
@@ -321,11 +316,14 @@ ieee80211softmac_assoc_work(void *d)
			mac->associnfo.assoc_wait = 0;
			mac->associnfo.assoc_wait = 0;
			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
			ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found);
		}
		}
		return;
		goto out;
	}
	}
	/* finally! now we can start associating */
	/* finally! now we can start associating */
	mac->associnfo.assoc_wait = 0;
	mac->associnfo.assoc_wait = 0;
	ieee80211softmac_assoc(mac, found);
	ieee80211softmac_assoc(mac, found);

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


/* call this to do whatever is necessary when we're associated */
/* 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;
	mac->bssinfo.supported_rates = net->supported_rates;
	ieee80211softmac_recalc_txrates(mac);
	ieee80211softmac_recalc_txrates(mac);


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


	mac->associnfo.short_preamble_available =
	mac->associnfo.short_preamble_available =
		(cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0;
		(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);
			dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status);
			mac->associnfo.associating = 0;
			mac->associnfo.associating = 0;
			mac->associnfo.bssvalid = 0;
			mac->associnfo.bssvalid = 0;
			mac->associated = 0;
			mac->associnfo.associated = 0;
			ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
			ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network);
	}
	}
	
	
+7 −2
Original line number Original line Diff line number Diff line
@@ -475,8 +475,13 @@ int ieee80211softmac_handle_beacon(struct net_device *dev,
{
{
	struct ieee80211softmac_device *mac = ieee80211_priv(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);
			ieee80211softmac_process_erp(mac, network->erp_value);
	}


	return 0;
	return 0;
}
}
Loading