cfg80211: properly name driver locking
[pandora-kernel.git] / net / wireless / scan.c
index 1f260c4..1625faf 100644 (file)
@@ -28,14 +28,20 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
        if (!dev)
                goto out;
 
-       WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
-       wiphy_to_dev(request->wiphy)->scan_req = NULL;
+       /*
+        * This must be before sending the other events!
+        * Otherwise, wpa_supplicant gets completely confused with
+        * wext events.
+        */
+       cfg80211_sme_scan_done(dev);
 
        if (aborted)
                nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
        else
                nl80211_send_scan_done(wiphy_to_dev(request->wiphy), dev);
 
+       wiphy_to_dev(request->wiphy)->scan_req = NULL;
+
 #ifdef CONFIG_WIRELESS_EXT
        if (!aborted) {
                memset(&wrqu, 0, sizeof(wrqu));
@@ -62,6 +68,8 @@ static void bss_release(struct kref *ref)
        if (bss->ies_allocated)
                kfree(bss->pub.information_elements);
 
+       BUG_ON(atomic_read(&bss->hold));
+
        kfree(bss);
 }
 
@@ -84,8 +92,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
        bool expired = false;
 
        list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
-               if (bss->hold ||
-                   !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+               if (atomic_read(&bss->hold))
+                       continue;
+               if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
                        continue;
                list_del(&bss->list);
                rb_erase(&bss->rbn, &dev->bss_tree);
@@ -365,7 +374,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        found = rb_find_bss(dev, res);
 
        if (found) {
-               kref_get(&found->ref);
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
@@ -377,18 +385,16 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                        size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
                        size_t ielen = res->pub.len_information_elements;
 
-                       if (ksize(found) >= used + ielen) {
+                       if (!found->ies_allocated && ksize(found) >= used + ielen) {
                                memcpy(found->pub.information_elements,
                                       res->pub.information_elements, ielen);
                                found->pub.len_information_elements = ielen;
                        } else {
                                u8 *ies = found->pub.information_elements;
 
-                               if (found->ies_allocated) {
-                                       if (ksize(ies) < ielen)
-                                               ies = krealloc(ies, ielen,
-                                                              GFP_ATOMIC);
-                               } else
+                               if (found->ies_allocated)
+                                       ies = krealloc(ies, ielen, GFP_ATOMIC);
+                               else
                                        ies = kmalloc(ielen, GFP_ATOMIC);
 
                                if (ies) {
@@ -415,6 +421,55 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        return found;
 }
 
+struct cfg80211_bss*
+cfg80211_inform_bss(struct wiphy *wiphy,
+                   struct ieee80211_channel *channel,
+                   const u8 *bssid,
+                   u64 timestamp, u16 capability, u16 beacon_interval,
+                   const u8 *ie, size_t ielen,
+                   s32 signal, gfp_t gfp)
+{
+       struct cfg80211_internal_bss *res;
+       size_t privsz;
+
+       if (WARN_ON(!wiphy))
+               return NULL;
+
+       privsz = wiphy->bss_priv_size;
+
+       if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
+                       (signal < 0 || signal > 100)))
+               return NULL;
+
+       res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
+       if (!res)
+               return NULL;
+
+       memcpy(res->pub.bssid, bssid, ETH_ALEN);
+       res->pub.channel = channel;
+       res->pub.signal = signal;
+       res->pub.tsf = timestamp;
+       res->pub.beacon_interval = beacon_interval;
+       res->pub.capability = capability;
+       /* point to after the private area */
+       res->pub.information_elements = (u8 *)res + sizeof(*res) + privsz;
+       memcpy(res->pub.information_elements, ie, ielen);
+       res->pub.len_information_elements = ielen;
+
+       kref_init(&res->ref);
+
+       res = cfg80211_bss_update(wiphy_to_dev(wiphy), res, 0);
+       if (!res)
+               return NULL;
+
+       if (res->pub.capability & WLAN_CAPABILITY_ESS)
+               regulatory_hint_found_beacon(wiphy, channel, gfp);
+
+       /* cfg80211_bss_update gives us a referenced result */
+       return &res->pub;
+}
+EXPORT_SYMBOL(cfg80211_inform_bss);
+
 struct cfg80211_bss *
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
@@ -499,30 +554,6 @@ void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
 }
 EXPORT_SYMBOL(cfg80211_unlink_bss);
 
-void cfg80211_hold_bss(struct cfg80211_bss *pub)
-{
-       struct cfg80211_internal_bss *bss;
-
-       if (!pub)
-               return;
-
-       bss = container_of(pub, struct cfg80211_internal_bss, pub);
-       bss->hold = true;
-}
-EXPORT_SYMBOL(cfg80211_hold_bss);
-
-void cfg80211_unhold_bss(struct cfg80211_bss *pub)
-{
-       struct cfg80211_internal_bss *bss;
-
-       if (!pub)
-               return;
-
-       bss = container_of(pub, struct cfg80211_internal_bss, pub);
-       bss->hold = false;
-}
-EXPORT_SYMBOL(cfg80211_unhold_bss);
-
 #ifdef CONFIG_WIRELESS_EXT
 int cfg80211_wext_siwscan(struct net_device *dev,
                          struct iw_request_info *info,
@@ -600,12 +631,13 @@ int cfg80211_wext_siwscan(struct net_device *dev,
        if (err) {
                rdev->scan_req = NULL;
                kfree(creq);
-       }
+       } else
+               nl80211_send_scan_start(rdev, dev);
  out:
-       cfg80211_put_dev(rdev);
+       cfg80211_unlock_rdev(rdev);
        return err;
 }
-EXPORT_SYMBOL(cfg80211_wext_siwscan);
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan);
 
 static void ieee80211_scan_add_ies(struct iw_request_info *info,
                                   struct cfg80211_bss *bss,
@@ -911,8 +943,8 @@ int cfg80211_wext_giwscan(struct net_device *dev,
        }
 
  out:
-       cfg80211_put_dev(rdev);
+       cfg80211_unlock_rdev(rdev);
        return res;
 }
-EXPORT_SYMBOL(cfg80211_wext_giwscan);
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan);
 #endif