synchronize_rcu();
skb_queue_purge(&sdata->u.sta.skb_queue);
- if (!local->ops->hw_scan &&
- local->scan_dev == sdata->dev) {
- local->sta_scanning = 0;
- cancel_delayed_work(&local->scan_work);
+ if (local->scan_dev == sdata->dev) {
+ if (!local->ops->hw_scan) {
+ local->sta_sw_scanning = 0;
+ cancel_delayed_work(&local->scan_work);
+ } else
+ local->sta_hw_scanning = 0;
}
+
flush_workqueue(local->hw.workqueue);
sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
struct ieee80211_channel *chan;
int ret = 0;
- if (local->sta_scanning) {
+ if (local->sta_sw_scanning) {
chan = local->scan_channel;
mode = local->scan_hw_mode;
} else {
u32 supp_rates, prev_rates;
int i, j;
- mode = local->sta_scanning ?
+ mode = local->sta_sw_scanning ?
local->scan_hw_mode : local->oper_hw_mode;
+
+ if (local->sta_hw_scanning) {
+ /* search for the correct mode matches the beacon */
+ list_for_each_entry(mode, &local->modes_list, list)
+ if (mode->mode == rx_status->phymode)
+ break;
+
+ if (mode == NULL)
+ mode = local->oper_hw_mode;
+ }
rates = mode->rates;
num_rates = mode->num_rates;
}
-void ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
- struct ieee80211_rx_status *rx_status)
+ieee80211_txrx_result
+ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb,
+ struct ieee80211_rx_status *rx_status)
{
struct ieee80211_mgmt *mgmt;
u16 fc;
- if (skb->len < 24) {
- dev_kfree_skb(skb);
- return;
- }
+ if (skb->len < 2)
+ return TXRX_DROP;
mgmt = (struct ieee80211_mgmt *) skb->data;
fc = le16_to_cpu(mgmt->frame_control);
+ if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL)
+ return TXRX_CONTINUE;
+
+ if (skb->len < 24)
+ return TXRX_DROP;
+
if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) {
ieee80211_rx_mgmt_probe_resp(dev, mgmt,
skb->len, rx_status);
+ dev_kfree_skb(skb);
+ return TXRX_QUEUED;
} else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) {
ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len,
rx_status);
+ dev_kfree_skb(skb);
+ return TXRX_QUEUED;
}
}
-
- dev_kfree_skb(skb);
+ return TXRX_CONTINUE;
}
if (!netif_running(dev))
return;
- if (local->sta_scanning)
+ if (local->sta_sw_scanning || local->sta_hw_scanning)
return;
if (sdata->type != IEEE80211_IF_TYPE_STA &&
union iwreq_data wrqu;
local->last_scan_completed = jiffies;
- wmb();
- local->sta_scanning = 0;
+ memset(&wrqu, 0, sizeof(wrqu));
+ wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ if (local->sta_hw_scanning) {
+ local->sta_hw_scanning = 0;
+ goto done;
+ }
+
+ local->sta_sw_scanning = 0;
if (ieee80211_hw_config(local))
printk(KERN_DEBUG "%s: failed to restore operational "
"channel after scan\n", dev->name);
netif_tx_unlock_bh(local->mdev);
- memset(&wrqu, 0, sizeof(wrqu));
- wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
-
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
}
rcu_read_unlock();
+done:
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
int skip;
unsigned long next_delay = 0;
- if (!local->sta_scanning)
+ if (!local->sta_sw_scanning)
return;
switch (local->scan_state) {
break;
}
- if (local->sta_scanning)
+ if (local->sta_sw_scanning)
queue_delayed_work(local->hw.workqueue, &local->scan_work,
next_delay);
}
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- if (local->sta_scanning) {
+ if (local->sta_sw_scanning || local->sta_hw_scanning) {
if (local->scan_dev == dev)
return 0;
return -EBUSY;
if (local->ops->hw_scan) {
int rc = local->ops->hw_scan(local_to_hw(local),
- ssid, ssid_len);
+ ssid, ssid_len);
if (!rc) {
- local->sta_scanning = 1;
+ local->sta_hw_scanning = 1;
local->scan_dev = dev;
}
return rc;
}
- local->sta_scanning = 1;
+ local->sta_sw_scanning = 1;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (sdata->type != IEEE80211_IF_TYPE_STA)
return ieee80211_sta_start_scan(dev, ssid, ssid_len);
- if (local->sta_scanning) {
+ if (local->sta_sw_scanning || local->sta_hw_scanning) {
if (local->scan_dev == dev)
return 0;
return -EBUSY;
struct ieee80211_local *local = rx->local;
struct sk_buff *skb = rx->skb;
- if (unlikely(local->sta_scanning != 0)) {
- ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+ if (unlikely(local->sta_hw_scanning))
+ return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status);
+
+ if (unlikely(local->sta_sw_scanning)) {
+ /* drop all the other packets during a software scan anyway */
+ if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status)
+ != TXRX_QUEUED)
+ dev_kfree_skb(skb);
return TXRX_QUEUED;
}
goto end;
}
- if (unlikely(local->sta_scanning))
+ if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning))
rx.flags |= IEEE80211_TXRXD_RXIN_SCAN;
if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,