SUNRPC: pass buffer size to svc_addsock()
[safe/jmp/linux-2.6] / net / wireless / scan.c
index 009d128..2a00e36 100644 (file)
@@ -56,17 +56,32 @@ static void bss_release(struct kref *ref)
        struct cfg80211_internal_bss *bss;
 
        bss = container_of(ref, struct cfg80211_internal_bss, ref);
+       if (bss->pub.free_priv)
+               bss->pub.free_priv(&bss->pub);
        kfree(bss);
 }
 
 /* must hold dev->bss_lock! */
+void cfg80211_bss_age(struct cfg80211_registered_device *dev,
+                      unsigned long age_secs)
+{
+       struct cfg80211_internal_bss *bss;
+       unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
+
+       list_for_each_entry(bss, &dev->bss_list, list) {
+               bss->ts -= age_jiffies;
+       }
+}
+
+/* must hold dev->bss_lock! */
 void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 {
        struct cfg80211_internal_bss *bss, *tmp;
        bool expired = false;
 
        list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
-               if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
+               if (bss->hold ||
+                   !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE))
                        continue;
                list_del(&bss->list);
                rb_erase(&bss->rbn, &dev->bss_tree);
@@ -114,9 +129,12 @@ static bool is_bss(struct cfg80211_bss *a,
 {
        const u8 *ssidie;
 
-       if (compare_ether_addr(a->bssid, bssid))
+       if (bssid && compare_ether_addr(a->bssid, bssid))
                return false;
 
+       if (!ssid)
+               return true;
+
        ssidie = find_ie(WLAN_EID_SSID,
                         a->information_elements,
                         a->len_information_elements);
@@ -197,7 +215,8 @@ static int cmp_bss(struct cfg80211_bss *a,
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
                                      const u8 *bssid,
-                                     const u8 *ssid, size_t ssid_len)
+                                     const u8 *ssid, size_t ssid_len,
+                                     u16 capa_mask, u16 capa_val)
 {
        struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
        struct cfg80211_internal_bss *bss, *res = NULL;
@@ -205,6 +224,8 @@ struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
        spin_lock_bh(&dev->bss_lock);
 
        list_for_each_entry(bss, &dev->bss_list, list) {
+               if ((bss->pub.capability & capa_mask) != capa_val)
+                       continue;
                if (channel && bss->pub.channel != channel)
                        continue;
                if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
@@ -350,7 +371,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
-               found->pub.signal_type = res->pub.signal_type;
                found->pub.capability = res->pub.capability;
                found->ts = res->ts;
                kref_put(&res->ref, bss_release);
@@ -372,8 +392,7 @@ struct cfg80211_bss *
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
-                         s32 signal, enum cfg80211_signal_type sigtype,
-                         gfp_t gfp)
+                         s32 signal, gfp_t gfp)
 {
        struct cfg80211_internal_bss *res;
        size_t ielen = len - offsetof(struct ieee80211_mgmt,
@@ -381,7 +400,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        bool overwrite;
        size_t privsz = wiphy->bss_priv_size;
 
-       if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&
+       if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
                    (signal < 0 || signal > 100)))
                return NULL;
 
@@ -395,7 +414,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 
        memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
        res->pub.channel = channel;
-       res->pub.signal_type = sigtype;
        res->pub.signal = signal;
        res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
        res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
@@ -413,6 +431,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        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;
 }
@@ -430,6 +451,51 @@ void cfg80211_put_bss(struct cfg80211_bss *pub)
 }
 EXPORT_SYMBOL(cfg80211_put_bss);
 
+void cfg80211_unlink_bss(struct wiphy *wiphy, struct cfg80211_bss *pub)
+{
+       struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
+       struct cfg80211_internal_bss *bss;
+
+       if (WARN_ON(!pub))
+               return;
+
+       bss = container_of(pub, struct cfg80211_internal_bss, pub);
+
+       spin_lock_bh(&dev->bss_lock);
+
+       list_del(&bss->list);
+       rb_erase(&bss->rbn, &dev->bss_tree);
+
+       spin_unlock_bh(&dev->bss_lock);
+
+       kref_put(&bss->ref, bss_release);
+}
+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,
@@ -555,16 +621,25 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
        }
 }
 
+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
+{
+       unsigned long end = jiffies;
+
+       if (end >= start)
+               return jiffies_to_msecs(end - start);
+
+       return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
+}
 
 static char *
-ieee80211_bss(struct iw_request_info *info,
-                     struct cfg80211_internal_bss *bss,
-                     char *current_ev, char *end_buf)
+ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
+             struct cfg80211_internal_bss *bss, char *current_ev,
+             char *end_buf)
 {
        struct iw_event iwe;
        u8 *buf, *cfg, *p;
        u8 *ie = bss->pub.information_elements;
-       int rem = bss->pub.len_information_elements, i;
+       int rem = bss->pub.len_information_elements, i, sig;
        bool ismesh = false;
 
        memset(&iwe, 0, sizeof(iwe));
@@ -588,19 +663,28 @@ ieee80211_bss(struct iw_request_info *info,
        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
-       if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {
+       if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVQUAL;
                iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
                                     IW_QUAL_NOISE_INVALID |
-                                    IW_QUAL_QUAL_INVALID;
-               switch (bss->pub.signal_type) {
+                                    IW_QUAL_QUAL_UPDATED;
+               switch (wiphy->signal_type) {
                case CFG80211_SIGNAL_TYPE_MBM:
-                       iwe.u.qual.level = bss->pub.signal / 100;
+                       sig = bss->pub.signal / 100;
+                       iwe.u.qual.level = sig;
                        iwe.u.qual.updated |= IW_QUAL_DBM;
+                       if (sig < -110)         /* rather bad */
+                               sig = -110;
+                       else if (sig > -40)     /* perfect */
+                               sig = -40;
+                       /* will give a range of 0 .. 70 */
+                       iwe.u.qual.qual = sig + 110;
                        break;
                case CFG80211_SIGNAL_TYPE_UNSPEC:
                        iwe.u.qual.level = bss->pub.signal;
+                       /* will give range 0 .. 100 */
+                       iwe.u.qual.qual = bss->pub.signal;
                        break;
                default:
                        /* not reached */
@@ -734,8 +818,8 @@ ieee80211_bss(struct iw_request_info *info,
                                                  &iwe, buf);
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, " Last beacon: %dms ago",
-                       jiffies_to_msecs(jiffies - bss->ts));
+               sprintf(buf, " Last beacon: %ums ago",
+                       elapsed_jiffies_msecs(bss->ts));
                iwe.u.data.length = strlen(buf);
                current_ev = iwe_stream_add_point(info, current_ev,
                                                  end_buf, &iwe, buf);
@@ -764,8 +848,8 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
                        spin_unlock_bh(&dev->bss_lock);
                        return -E2BIG;
                }
-               current_ev = ieee80211_bss(info, bss,
-                                                  current_ev, end_buf);
+               current_ev = ieee80211_bss(&dev->wiphy, info, bss,
+                                          current_ev, end_buf);
        }
        spin_unlock_bh(&dev->bss_lock);
        return current_ev - buf;