Commit d57336e3 authored by Daniel Drake's avatar Daniel Drake Committed by John W. Linville

[PATCH] softmac: make non-operational after being stopped

zd1211 with softmac and wpa_supplicant revealed an issue with softmac
and the use of workqueues. Some of the work functions actually
reschedule themselves, so this meant that there could still be
pending work after flush_scheduled_work() had been called during
ieee80211softmac_stop().

This patch introduces a "running" flag which is used to ensure that
rescheduling does not happen in this situation.

I also used this flag to ensure that softmac's hooks into ieee80211 are
non-operational once the stop operation has been started. This simply
makes softmac a little more robust, because I could crash it easily
by receiving frames in the short timeframe after shutting down softmac
and before turning off the ZD1211 radio. (ZD1211 is now fixed as well!)
Signed-off-by: default avatarDaniel Drake <dsd@gentoo.org>
Acked-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 995c9926
...@@ -204,7 +204,8 @@ struct ieee80211softmac_device { ...@@ -204,7 +204,8 @@ struct ieee80211softmac_device {
/* couple of flags */ /* couple of flags */
u8 scanning:1, /* protects scanning from being done multiple times at once */ u8 scanning:1, /* protects scanning from being done multiple times at once */
associated:1; associated:1,
running:1;
struct ieee80211softmac_scaninfo *scaninfo; struct ieee80211softmac_scaninfo *scaninfo;
struct ieee80211softmac_assoc_info associnfo; struct ieee80211softmac_assoc_info associnfo;
......
...@@ -51,11 +51,12 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft ...@@ -51,11 +51,12 @@ ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211soft
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
mac->associnfo.associating = 1; mac->associnfo.associating = 1;
mac->associated = 0; /* just to make sure */ mac->associated = 0; /* just to make sure */
spin_unlock_irqrestore(&mac->lock, flags);
/* Set a timer for timeout */ /* Set a timer for timeout */
/* FIXME: make timeout configurable */ /* FIXME: make timeout configurable */
if (likely(mac->running))
schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ); schedule_delayed_work(&mac->associnfo.timeout, 5 * HZ);
spin_unlock_irqrestore(&mac->lock, flags);
} }
void void
...@@ -320,6 +321,9 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev, ...@@ -320,6 +321,9 @@ ieee80211softmac_handle_assoc_response(struct net_device * dev,
struct ieee80211softmac_network *network = NULL; struct ieee80211softmac_network *network = NULL;
unsigned long flags; unsigned long flags;
if (unlikely(!mac->running))
return -ENODEV;
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
if (!mac->associnfo.associating) { if (!mac->associnfo.associating) {
...@@ -377,10 +381,16 @@ ieee80211softmac_handle_disassoc(struct net_device * dev, ...@@ -377,10 +381,16 @@ ieee80211softmac_handle_disassoc(struct net_device * dev,
{ {
struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_device *mac = ieee80211_priv(dev);
unsigned long flags; unsigned long flags;
if (unlikely(!mac->running))
return -ENODEV;
if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN)) if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN))
return 0; return 0;
if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN)) if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN))
return 0; return 0;
dprintk(KERN_INFO PFX "got disassoc frame\n"); dprintk(KERN_INFO PFX "got disassoc frame\n");
netif_carrier_off(dev); netif_carrier_off(dev);
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
...@@ -400,6 +410,9 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev, ...@@ -400,6 +410,9 @@ ieee80211softmac_handle_reassoc_req(struct net_device * dev,
struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_device *mac = ieee80211_priv(dev);
struct ieee80211softmac_network *network; struct ieee80211softmac_network *network;
if (unlikely(!mac->running))
return -ENODEV;
network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3); network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3);
if (!network) { if (!network) {
dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); dprintkl(KERN_INFO PFX "reassoc request from unknown network\n");
......
...@@ -86,6 +86,11 @@ ieee80211softmac_auth_queue(void *data) ...@@ -86,6 +86,11 @@ ieee80211softmac_auth_queue(void *data)
/* Lock and set flags */ /* Lock and set flags */
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
if (unlikely(!mac->running)) {
/* Prevent reschedule on workqueue flush */
spin_unlock_irqrestore(&mac->lock, flags);
return;
}
net->authenticated = 0; net->authenticated = 0;
net->authenticating = 1; 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 */
...@@ -124,6 +129,9 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) ...@@ -124,6 +129,9 @@ ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth)
unsigned long flags; unsigned long flags;
u8 * data; u8 * data;
if (unlikely(!mac->running))
return -ENODEV;
/* Find correct auth queue item */ /* Find correct auth queue item */
spin_lock_irqsave(&mac->lock, flags); spin_lock_irqsave(&mac->lock, flags);
list_for_each(list_ptr, &mac->auth_queue) { list_for_each(list_ptr, &mac->auth_queue) {
...@@ -336,6 +344,9 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de ...@@ -336,6 +344,9 @@ ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *de
struct ieee80211softmac_network *net = NULL; struct ieee80211softmac_network *net = NULL;
struct ieee80211softmac_device *mac = ieee80211_priv(dev); struct ieee80211softmac_device *mac = ieee80211_priv(dev);
if (unlikely(!mac->running))
return -ENODEV;
if (!deauth) { if (!deauth) {
dprintk("deauth without deauth packet. eek!\n"); dprintk("deauth without deauth packet. eek!\n");
return 0; return 0;
......
...@@ -89,6 +89,8 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) ...@@ -89,6 +89,8 @@ ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm)
ieee80211softmac_wait_for_scan(sm); ieee80211softmac_wait_for_scan(sm);
spin_lock_irqsave(&sm->lock, flags); spin_lock_irqsave(&sm->lock, flags);
sm->running = 0;
/* Free all pending assoc work items */ /* Free all pending assoc work items */
cancel_delayed_work(&sm->associnfo.work); cancel_delayed_work(&sm->associnfo.work);
...@@ -204,6 +206,8 @@ void ieee80211softmac_start(struct net_device *dev) ...@@ -204,6 +206,8 @@ void ieee80211softmac_start(struct net_device *dev)
assert(0); assert(0);
if (mac->txrates_change) if (mac->txrates_change)
mac->txrates_change(dev, change, &oldrates); mac->txrates_change(dev, change, &oldrates);
mac->running = 1;
} }
EXPORT_SYMBOL_GPL(ieee80211softmac_start); EXPORT_SYMBOL_GPL(ieee80211softmac_start);
......
...@@ -115,7 +115,15 @@ void ieee80211softmac_scan(void *d) ...@@ -115,7 +115,15 @@ void ieee80211softmac_scan(void *d)
// TODO: is this if correct, or should we do this only if scanning from assoc request? // TODO: is this if correct, or should we do this only if scanning from assoc request?
if (sm->associnfo.req_essid.len) if (sm->associnfo.req_essid.len)
ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0); ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0);
spin_lock_irqsave(&sm->lock, flags);
if (unlikely(!sm->running)) {
/* Prevent reschedule on workqueue flush */
spin_unlock_irqrestore(&sm->lock, flags);
break;
}
schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); schedule_delayed_work(&si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY);
spin_unlock_irqrestore(&sm->lock, flags);
return; return;
} else { } else {
dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel); dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel);
......
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