Merge branch 'linux-linaro-lsk-v4.4' into linux-linaro-lsk-v4.4-android
authorAlex Shi <alex.shi@linaro.org>
Tue, 6 Dec 2016 05:01:29 +0000 (13:01 +0800)
committerAlex Shi <alex.shi@linaro.org>
Tue, 6 Dec 2016 05:01:29 +0000 (13:01 +0800)
Conflicts:
keep low scan freq in android in net/wireless/scan.c

1  2 
net/wireless/scan.c

diff --combined net/wireless/scan.c
index 30f967665e84c72d3521304ddfef4767c8db17cf,8dde12a11725877104d040bf04251be80781eb32..6e7b86ca2abd6cbc0f72de95513307d980347769
   * also linked into the probe response struct.
   */
  
 -#define IEEE80211_SCAN_RESULT_EXPIRE  (30 * HZ)
+ /*
+  * Limit the number of BSS entries stored in mac80211. Each one is
+  * a bit over 4k at most, so this limits to roughly 4-5M of memory.
+  * If somebody wants to really attack this though, they'd likely
+  * use small beacons, and only one type of frame, limiting each of
+  * the entries to a much smaller size (in order to generate more
+  * entries in total, so overhead is bigger.)
+  */
+ static int bss_entries_limit = 1000;
+ module_param(bss_entries_limit, int, 0644);
+ MODULE_PARM_DESC(bss_entries_limit,
+                  "limit to number of scan BSS entries (per wiphy, default 1000)");
 +#define IEEE80211_SCAN_RESULT_EXPIRE  (7 * HZ)
  
  static void bss_free(struct cfg80211_internal_bss *bss)
  {
@@@ -136,6 -149,10 +149,10 @@@ static bool __cfg80211_unlink_bss(struc
  
        list_del_init(&bss->list);
        rb_erase(&bss->rbn, &rdev->bss_tree);
+       rdev->bss_entries--;
+       WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
+                 "rdev bss entries[%d]/list[empty:%d] corruption\n",
+                 rdev->bss_entries, list_empty(&rdev->bss_list));
        bss_ref_put(rdev, bss);
        return true;
  }
@@@ -162,6 -179,40 +179,40 @@@ static void __cfg80211_bss_expire(struc
                rdev->bss_generation++;
  }
  
+ static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
+ {
+       struct cfg80211_internal_bss *bss, *oldest = NULL;
+       bool ret;
+       lockdep_assert_held(&rdev->bss_lock);
+       list_for_each_entry(bss, &rdev->bss_list, list) {
+               if (atomic_read(&bss->hold))
+                       continue;
+               if (!list_empty(&bss->hidden_list) &&
+                   !bss->pub.hidden_beacon_bss)
+                       continue;
+               if (oldest && time_before(oldest->ts, bss->ts))
+                       continue;
+               oldest = bss;
+       }
+       if (WARN_ON(!oldest))
+               return false;
+       /*
+        * The callers make sure to increase rdev->bss_generation if anything
+        * gets removed (and a new entry added), so there's no need to also do
+        * it here.
+        */
+       ret = __cfg80211_unlink_bss(rdev, oldest);
+       WARN_ON(!ret);
+       return ret;
+ }
  void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
                           bool send_message)
  {
@@@ -687,6 -738,7 +738,7 @@@ static bool cfg80211_combine_bsses(stru
        const u8 *ie;
        int i, ssidlen;
        u8 fold = 0;
+       u32 n_entries = 0;
  
        ies = rcu_access_pointer(new->pub.beacon_ies);
        if (WARN_ON(!ies))
        /* This is the bad part ... */
  
        list_for_each_entry(bss, &rdev->bss_list, list) {
+               /*
+                * we're iterating all the entries anyway, so take the
+                * opportunity to validate the list length accounting
+                */
+               n_entries++;
                if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
                        continue;
                if (bss->pub.channel != new->pub.channel)
                                   new->pub.beacon_ies);
        }
  
+       WARN_ONCE(n_entries != rdev->bss_entries,
+                 "rdev bss entries[%d]/list[len:%d] corruption\n",
+                 rdev->bss_entries, n_entries);
        return true;
  }
  
@@@ -890,7 -952,14 +952,14 @@@ cfg80211_bss_update(struct cfg80211_reg
                        }
                }
  
+               if (rdev->bss_entries >= bss_entries_limit &&
+                   !cfg80211_bss_expire_oldest(rdev)) {
+                       kfree(new);
+                       goto drop;
+               }
                list_add_tail(&new->list, &rdev->bss_list);
+               rdev->bss_entries++;
                rb_insert_bss(rdev, new);
                found = new;
        }