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,