Release 4.11 net/wireless/scan.c
/*
* cfg80211 scan result handling
*
* Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright 2016 Intel Deutschland GmbH
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/nl80211.h>
#include <linux/etherdevice.h>
#include <net/arp.h>
#include <net/cfg80211.h>
#include <net/cfg80211-wext.h>
#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
#include "wext-compat.h"
#include "rdev-ops.h"
/**
* DOC: BSS tree/list structure
*
* At the top level, the BSS list is kept in both a list in each
* registered device (@bss_list) as well as an RB-tree for faster
* lookup. In the RB-tree, entries can be looked up using their
* channel, MESHID, MESHCONF (for MBSSes) or channel, BSSID, SSID
* for other BSSes.
*
* Due to the possibility of hidden SSIDs, there's a second level
* structure, the "hidden_list" and "hidden_beacon_bss" pointer.
* The hidden_list connects all BSSes belonging to a single AP
* that has a hidden SSID, and connects beacon and probe response
* entries. For a probe response entry for a hidden SSID, the
* hidden_beacon_bss pointer points to the BSS struct holding the
* beacon's information.
*
* Reference counting is done for all these references except for
* the hidden_list, so that a beacon BSS struct that is otherwise
* not referenced has one reference for being on the bss_list and
* one for each probe response entry that points to it using the
* hidden_beacon_bss pointer. When a BSS struct that has such a
* pointer is get/put, the refcount update is also propagated to
* the referenced struct, this ensure that it cannot get removed
* while somebody is using the probe response version.
*
* Note that the hidden_beacon_bss pointer never changes, due to
* the reference counting. Therefore, no locking is needed for
* it.
*
* Also note that the hidden_beacon_bss pointer is only relevant
* if the driver uses something other than the IEs, e.g. private
* data stored stored in the BSS struct, since the beacon IEs are
* also linked into the probe response struct.
*/
/*
* 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 (30 * HZ)
static void bss_free(struct cfg80211_internal_bss *bss)
{
struct cfg80211_bss_ies *ies;
if (WARN_ON(atomic_read(&bss->hold)))
return;
ies = (void *)rcu_access_pointer(bss->pub.beacon_ies);
if (ies && !bss->pub.hidden_beacon_bss)
kfree_rcu(ies, rcu_head);
ies = (void *)rcu_access_pointer(bss->pub.proberesp_ies);
if (ies)
kfree_rcu(ies, rcu_head);
/*
* This happens when the module is removed, it doesn't
* really matter any more save for completeness
*/
if (!list_empty(&bss->hidden_list))
list_del(&bss->hidden_list);
kfree(bss);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 79 | 69.30% | 3 | 75.00% |
Amitkumar Karwar | 35 | 30.70% | 1 | 25.00% |
Total | 114 | 100.00% | 4 | 100.00% |
static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&rdev->bss_lock);
bss->refcount++;
if (bss->pub.hidden_beacon_bss) {
bss = container_of(bss->pub.hidden_beacon_bss,
struct cfg80211_internal_bss,
pub);
bss->refcount++;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 59 | 96.72% | 2 | 66.67% |
Zhao, Gang | 2 | 3.28% | 1 | 33.33% |
Total | 61 | 100.00% | 3 | 100.00% |
static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&rdev->bss_lock);
if (bss->pub.hidden_beacon_bss) {
struct cfg80211_internal_bss *hbss;
hbss = container_of(bss->pub.hidden_beacon_bss,
struct cfg80211_internal_bss,
pub);
hbss->refcount--;
if (hbss->refcount == 0)
bss_free(hbss);
}
bss->refcount--;
if (bss->refcount == 0)
bss_free(bss);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 90 | 97.83% | 2 | 66.67% |
Zhao, Gang | 2 | 2.17% | 1 | 33.33% |
Total | 92 | 100.00% | 3 | 100.00% |
static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
lockdep_assert_held(&rdev->bss_lock);
if (!list_empty(&bss->hidden_list)) {
/*
* don't remove the beacon entry if it has
* probe responses associated with it
*/
if (!bss->pub.hidden_beacon_bss)
return false;
/*
* if it's a probe response entry break its
* link to the other entries in the group
*/
list_del_init(&bss->hidden_list);
}
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;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 86 | 67.19% | 4 | 66.67% |
Amitkumar Karwar | 38 | 29.69% | 1 | 16.67% |
Zhao, Gang | 4 | 3.12% | 1 | 16.67% |
Total | 128 | 100.00% | 6 | 100.00% |
static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
unsigned long expire_time)
{
struct cfg80211_internal_bss *bss, *tmp;
bool expired = false;
lockdep_assert_held(&rdev->bss_lock);
list_for_each_entry_safe(bss, tmp, &rdev->bss_list, list) {
if (atomic_read(&bss->hold))
continue;
if (!time_after(expire_time, bss->ts))
continue;
if (__cfg80211_unlink_bss(rdev, bss))
expired = true;
}
if (expired)
rdev->bss_generation++;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sam Leffler | 79 | 84.04% | 1 | 25.00% |
Johannes Berg | 10 | 10.64% | 2 | 50.00% |
Zhao, Gang | 5 | 5.32% | 1 | 25.00% |
Total | 94 | 100.00% | 4 | 100.00% |
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;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 122 | 100.00% | 1 | 100.00% |
Total | 122 | 100.00% | 1 | 100.00% |
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
bool send_message)
{
struct cfg80211_scan_request *request;
struct wireless_dev *wdev;
struct sk_buff *msg;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
ASSERT_RTNL();
if (rdev->scan_msg) {
nl80211_send_scan_msg(rdev, rdev->scan_msg);
rdev->scan_msg = NULL;
return;
}
request = rdev->scan_req;
if (!request)
return;
wdev = request->wdev;
/*
* This must be before sending the other events!
* Otherwise, wpa_supplicant gets completely confused with
* wext events.
*/
if (wdev->netdev)
cfg80211_sme_scan_done(wdev->netdev);
if (!request->info.aborted &&
request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock);
}
msg = nl80211_build_scan_msg(rdev, wdev, request->info.aborted);
#ifdef CONFIG_CFG80211_WEXT
if (wdev->netdev && !request->info.aborted) {
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
}
#endif
if (wdev->netdev)
dev_put(wdev->netdev);
rdev->scan_req = NULL;
kfree(request);
if (!send_message)
rdev->scan_msg = msg;
else
nl80211_send_scan_msg(rdev, msg);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 197 | 80.74% | 10 | 71.43% |
Sam Leffler | 34 | 13.93% | 1 | 7.14% |
Avraham Stern | 6 | 2.46% | 1 | 7.14% |
Christian Lamparter | 5 | 2.05% | 1 | 7.14% |
Arend Van Spriel | 2 | 0.82% | 1 | 7.14% |
Total | 244 | 100.00% | 14 | 100.00% |
void __cfg80211_scan_done(struct work_struct *wk)
{
struct cfg80211_registered_device *rdev;
rdev = container_of(wk, struct cfg80211_registered_device,
scan_done_wk);
rtnl_lock();
___cfg80211_scan_done(rdev, true);
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 40 | 100.00% | 3 | 100.00% |
Total | 40 | 100.00% | 3 | 100.00% |
void cfg80211_scan_done(struct cfg80211_scan_request *request,
struct cfg80211_scan_info *info)
{
trace_cfg80211_scan_done(request, info);
WARN_ON(request != wiphy_to_rdev(request->wiphy)->scan_req);
request->info = *info;
request->notified = true;
queue_work(cfg80211_wq, &wiphy_to_rdev(request->wiphy)->scan_done_wk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 45 | 70.31% | 3 | 42.86% |
Avraham Stern | 8 | 12.50% | 1 | 14.29% |
Beni Lev | 6 | 9.38% | 1 | 14.29% |
Alban Browaeys | 3 | 4.69% | 1 | 14.29% |
Zhao, Gang | 2 | 3.12% | 1 | 14.29% |
Total | 64 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(cfg80211_scan_done);
void __cfg80211_sched_scan_results(struct work_struct *wk)
{
struct cfg80211_registered_device *rdev;
struct cfg80211_sched_scan_request *request;
rdev = container_of(wk, struct cfg80211_registered_device,
sched_scan_results_wk);
rtnl_lock();
request = rtnl_dereference(rdev->sched_scan_req);
/* we don't have sched_scan_req anymore if the scan is stopping */
if (request) {
if (request->flags & NL80211_SCAN_FLAG_FLUSH) {
/* flush entries from previous scans */
spin_lock_bh(&rdev->bss_lock);
__cfg80211_bss_expire(rdev, request->scan_start);
spin_unlock_bh(&rdev->bss_lock);
request->scan_start = jiffies;
}
nl80211_send_sched_scan(rdev, request->dev,
NL80211_CMD_SCHED_SCAN_RESULTS);
}
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sam Leffler | 54 | 50.47% | 1 | 16.67% |
Luciano Coelho | 42 | 39.25% | 1 | 16.67% |
Johannes Berg | 5 | 4.67% | 2 | 33.33% |
Jukka Rissanen | 3 | 2.80% | 1 | 16.67% |
Arend Van Spriel | 3 | 2.80% | 1 | 16.67% |
Total | 107 | 100.00% | 6 | 100.00% |
void cfg80211_sched_scan_results(struct wiphy *wiphy)
{
trace_cfg80211_sched_scan_results(wiphy);
/* ignore if we're not scanning */
if (rcu_access_pointer(wiphy_to_rdev(wiphy)->sched_scan_req))
queue_work(cfg80211_wq,
&wiphy_to_rdev(wiphy)->sched_scan_results_wk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luciano Coelho | 31 | 75.61% | 1 | 25.00% |
Beni Lev | 5 | 12.20% | 1 | 25.00% |
Jukka Rissanen | 3 | 7.32% | 1 | 25.00% |
Zhao, Gang | 2 | 4.88% | 1 | 25.00% |
Total | 41 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(cfg80211_sched_scan_results);
void cfg80211_sched_scan_stopped_rtnl(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
ASSERT_RTNL();
trace_cfg80211_sched_scan_stopped(wiphy);
__cfg80211_stop_sched_scan(rdev, true);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luciano Coelho | 24 | 68.57% | 2 | 40.00% |
Eliad Peller | 5 | 14.29% | 1 | 20.00% |
Beni Lev | 5 | 14.29% | 1 | 20.00% |
Zhao, Gang | 1 | 2.86% | 1 | 20.00% |
Total | 35 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(cfg80211_sched_scan_stopped_rtnl);
void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
{
rtnl_lock();
cfg80211_sched_scan_stopped_rtnl(wiphy);
rtnl_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Eliad Peller | 17 | 80.95% | 1 | 33.33% |
Luciano Coelho | 2 | 9.52% | 1 | 33.33% |
Johannes Berg | 2 | 9.52% | 1 | 33.33% |
Total | 21 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
bool driver_initiated)
{
struct cfg80211_sched_scan_request *sched_scan_req;
struct net_device *dev;
ASSERT_RTNL();
if (!rdev->sched_scan_req)
return -ENOENT;
sched_scan_req = rtnl_dereference(rdev->sched_scan_req);
dev = sched_scan_req->dev;
if (!driver_initiated) {
int err = rdev_sched_scan_stop(rdev, dev);
if (err)
return err;
}
nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
RCU_INIT_POINTER(rdev->sched_scan_req, NULL);
kfree_rcu(sched_scan_req, rcu_head);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luciano Coelho | 76 | 73.08% | 3 | 42.86% |
Jukka Rissanen | 21 | 20.19% | 1 | 14.29% |
Jesper Juhl | 4 | 3.85% | 1 | 14.29% |
Johannes Berg | 2 | 1.92% | 1 | 14.29% |
Hila Gonen | 1 | 0.96% | 1 | 14.29% |
Total | 104 | 100.00% | 7 | 100.00% |
void cfg80211_bss_age(struct cfg80211_registered_device *rdev,
unsigned long age_secs)
{
struct cfg80211_internal_bss *bss;
unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &rdev->bss_list, list)
bss->ts -= age_jiffies;
spin_unlock_bh(&rdev->bss_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dan J Williams | 42 | 70.00% | 1 | 33.33% |
Johannes Berg | 14 | 23.33% | 1 | 33.33% |
Zhao, Gang | 4 | 6.67% | 1 | 33.33% |
Total | 60 | 100.00% | 3 | 100.00% |
void cfg80211_bss_expire(struct cfg80211_registered_device *rdev)
{
__cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 15 | 78.95% | 1 | 33.33% |
Zhao, Gang | 2 | 10.53% | 1 | 33.33% |
Sam Leffler | 2 | 10.53% | 1 | 33.33% |
Total | 19 | 100.00% | 3 | 100.00% |
const u8 *cfg80211_find_ie_match(u8 eid, const u8 *ies, int len,
const u8 *match, int match_len,
int match_offset)
{
/* match_offset can't be smaller than 2, unless match_len is
* zero, in which case match_offset must be zero as well.
*/
if (WARN_ON((match_len && match_offset < 2) ||
(!match_len && match_offset)))
return NULL;
while (len >= 2 && len >= ies[1] + 2) {
if ((ies[0] == eid) &&
(ies[1] + 2 >= match_offset + match_len) &&
!memcmp(ies + match_offset, match, match_len))
return ies;
len -= ies[1] + 2;
ies += ies[1] + 2;
}
return NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luciano Coelho | 80 | 61.54% | 1 | 25.00% |
Johannes Berg | 49 | 37.69% | 2 | 50.00% |
Bob Copeland | 1 | 0.77% | 1 | 25.00% |
Total | 130 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(cfg80211_find_ie_match);
const u8 *cfg80211_find_vendor_ie(unsigned int oui, int oui_type,
const u8 *ies, int len)
{
const u8 *ie;
u8 match[] = { oui >> 16, oui >> 8, oui, oui_type };
int match_len = (oui_type < 0) ? 3 : sizeof(match);
if (WARN_ON(oui_type > 0xff))
return NULL;
ie = cfg80211_find_ie_match(WLAN_EID_VENDOR_SPECIFIC, ies, len,
match, match_len, 2);
if (ie && (ie[1] < 4))
return NULL;
return ie;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Luciano Coelho | 52 | 47.71% | 2 | 50.00% |
Eliad Peller | 42 | 38.53% | 1 | 25.00% |
Emmanuel Grumbach | 15 | 13.76% | 1 | 25.00% |
Total | 109 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(cfg80211_find_vendor_ie);
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
const u8 *ssid, size_t ssid_len)
{
const struct cfg80211_bss_ies *ies;
const u8 *ssidie;
if (bssid && !ether_addr_equal(a->bssid, bssid))
return false;
if (!ssid)
return true;
ies = rcu_access_pointer(a->ies);
if (!ies)
return false;
ssidie = cfg80211_find_ie(WLAN_EID_SSID, ies->data, ies->len);
if (!ssidie)
return false;
if (ssidie[1] != ssid_len)
return false;
return memcmp(ssidie + 2, ssid, ssid_len) == 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 124 | 98.41% | 4 | 80.00% |
Joe Perches | 2 | 1.59% | 1 | 20.00% |
Total | 126 | 100.00% | 5 | 100.00% |
/**
* enum bss_compare_mode - BSS compare mode
* @BSS_CMP_REGULAR: regular compare mode (for insertion and normal find)
* @BSS_CMP_HIDE_ZLEN: find hidden SSID with zero-length mode
* @BSS_CMP_HIDE_NUL: find hidden SSID with NUL-ed out mode
*/
enum bss_compare_mode {
BSS_CMP_REGULAR,
BSS_CMP_HIDE_ZLEN,
BSS_CMP_HIDE_NUL,
};
static int cmp_bss(struct cfg80211_bss *a,
struct cfg80211_bss *b,
enum bss_compare_mode mode)
{
const struct cfg80211_bss_ies *a_ies, *b_ies;
const u8 *ie1 = NULL;
const u8 *ie2 = NULL;
int i, r;
if (a->channel != b->channel)
return b->channel->center_freq - a->channel->center_freq;
a_ies = rcu_access_pointer(a->ies);
if (!a_ies)
return -1;
b_ies = rcu_access_pointer(b->ies);
if (!b_ies)
return 1;
if (WLAN_CAPABILITY_IS_STA_BSS(a->capability))
ie1 = cfg80211_find_ie(WLAN_EID_MESH_ID,
a_ies->data, a_ies->len);
if (WLAN_CAPABILITY_IS_STA_BSS(b->capability))
ie2 = cfg80211_find_ie(WLAN_EID_MESH_ID,
b_ies->data, b_ies->len);
if (ie1 && ie2) {
int mesh_id_cmp;
if (ie1[1] == ie2[1])
mesh_id_cmp = memcmp(ie1 + 2, ie2 + 2, ie1[1]);
else
mesh_id_cmp = ie2[1] - ie1[1];
ie1 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
a_ies->data, a_ies->len);
ie2 = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
b_ies->data, b_ies->len);
if (ie1 && ie2) {
if (mesh_id_cmp)
return mesh_id_cmp;
if (ie1[1] != ie2[1])
return ie2[1] - ie1[1];
return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
}
}
r = memcmp(a->bssid, b->bssid, sizeof(a->bssid));
if (r)
return r;
ie1 = cfg80211_find_ie(WLAN_EID_SSID, a_ies->data, a_ies->len);
ie2 = cfg80211_find_ie(WLAN_EID_SSID, b_ies->data, b_ies->len);
if (!ie1 && !ie2)
return 0;
/*
* Note that with "hide_ssid", the function returns a match if
* the already-present BSS ("b") is a hidden SSID beacon for
* the new BSS ("a").
*/
/* sort missing IE before (left of) present IE */
if (!ie1)
return -1;
if (!ie2)
return 1;
switch (mode) {
case BSS_CMP_HIDE_ZLEN:
/*
* In ZLEN mode we assume the BSS entry we're
* looking for has a zero-length SSID. So if
* the one we're looking at right now has that,
* return 0. Otherwise, return the difference
* in length, but since we're looking for the
* 0-length it's really equivalent to returning
* the length of the one we're looking at.
*
* No content comparison is needed as we assume
* the content length is zero.
*/
return ie2[1];
case BSS_CMP_REGULAR:
default:
/* sort by length first, then by contents */
if (ie1[1] != ie2[1])
return ie2[1] - ie1[1];
return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
case BSS_CMP_HIDE_NUL:
if (ie1[1] != ie2[1])
return ie2[1] - ie1[1];
/* this is equivalent to memcmp(zeroes, ie2 + 2, len) */
for (i = 0; i < ie2[1]; i++)
if (ie2[i + 2])
return -1;
return 0;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 385 | 77.00% | 5 | 62.50% |
Dmitry Tarnyagin | 98 | 19.60% | 1 | 12.50% |
Javier Cardona | 9 | 1.80% | 1 | 12.50% |
Emmanuel Grumbach | 8 | 1.60% | 1 | 12.50% |
Total | 500 | 100.00% | 8 | 100.00% |
static bool cfg80211_bss_type_match(u16 capability,
enum nl80211_band band,
enum ieee80211_bss_type bss_type)
{
bool ret = true;
u16 mask, val;
if (bss_type == IEEE80211_BSS_TYPE_ANY)
return ret;
if (band == NL80211_BAND_60GHZ) {
mask = WLAN_CAPABILITY_DMG_TYPE_MASK;
switch (bss_type) {
case IEEE80211_BSS_TYPE_ESS:
val = WLAN_CAPABILITY_DMG_TYPE_AP;
break;
case IEEE80211_BSS_TYPE_PBSS:
val = WLAN_CAPABILITY_DMG_TYPE_PBSS;
break;
case IEEE80211_BSS_TYPE_IBSS:
val = WLAN_CAPABILITY_DMG_TYPE_IBSS;
break;
default:
return false;
}
} else {
mask = WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS;
switch (bss_type) {
case IEEE80211_BSS_TYPE_ESS:
val = WLAN_CAPABILITY_ESS;
break;
case IEEE80211_BSS_TYPE_IBSS:
val = WLAN_CAPABILITY_IBSS;
break;
case IEEE80211_BSS_TYPE_MBSS:
val = 0;
break;
default:
return false;
}
}
ret = ((capability & mask) == val);
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Dedy Lansky | 138 | 98.57% | 1 | 50.00% |
Johannes Berg | 2 | 1.43% | 1 | 50.00% |
Total | 140 | 100.00% | 2 | 100.00% |
/* Returned bss is reference counted and must be cleaned up appropriately. */
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
struct ieee80211_channel *channel,
const u8 *bssid,
const u8 *ssid, size_t ssid_len,
enum ieee80211_bss_type bss_type,
enum ieee80211_privacy privacy)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct cfg80211_internal_bss *bss, *res = NULL;
unsigned long now = jiffies;
int bss_privacy;
trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, bss_type,
privacy);
spin_lock_bh(&rdev->bss_lock);
list_for_each_entry(bss, &rdev->bss_list, list) {
if (!cfg80211_bss_type_match(bss->pub.capability,
bss->pub.channel->band, bss_type))
continue;
bss_privacy = (bss->pub.capability & WLAN_CAPABILITY_PRIVACY);
if ((privacy == IEEE80211_PRIVACY_ON && !bss_privacy) ||
(privacy == IEEE80211_PRIVACY_OFF && bss_privacy))
continue;
if (channel && bss->pub.channel != channel)
continue;
if (!is_valid_ether_addr(bss->pub.bssid))
continue;
/* Don't get expired BSS structs */
if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
!atomic_read(&bss->hold))
continue;
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) {
res = bss;
bss_ref_get(rdev, res);
break;
}
}
spin_unlock_bh(&rdev->bss_lock);
if (!res)
return NULL;
trace_cfg80211_return_bss(&res->pub);
return &res->pub;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 184 | 68.91% | 6 | 60.00% |
Dedy Lansky | 54 | 20.22% | 1 | 10.00% |
Beni Lev | 23 | 8.61% | 1 | 10.00% |
Zhao, Gang | 6 | 2.25% | 2 | 20.00% |
Total | 267 | 100.00% | 10 | 100.00% |
EXPORT_SYMBOL(cfg80211_get_bss);
static void rb_insert_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *bss)
{
struct rb_node **p = &rdev->bss_tree.rb_node;
struct rb_node *parent = NULL;
struct cfg80211_internal_bss *tbss;
int cmp;
while (*p) {
parent = *p;
tbss = rb_entry(parent, struct cfg80211_internal_bss, rbn);
cmp = cmp_bss(&bss->pub, &tbss->pub, BSS_CMP_REGULAR);
if (WARN_ON(!cmp)) {
/* will sort of leak this BSS */
return;
}
if (cmp < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
rb_link_node(&bss->rbn, parent, p);
rb_insert_color(&bss->rbn, &rdev->bss_tree);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Johannes Berg | 146 | 97.99% | 3 | 75.00% |
Zhao, Gang | 3 | 2.01% | 1 | 25.00% |
Total | 149 | 100.00% | 4 | 100.00% |
static struct cfg80211_internal_bss *
rb_find_bss(struct cfg80211_registered_device *rdev,
struct cfg80211_internal_bss *res,
enum bss_compare_mode mode)
{
struct rb_node *n = rdev->bss_tree.rb_node;
struct cfg80211_internal_bss *bss;
int r;
while (n) {
bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
r = cmp_bss(&res->pub, &bss->pub, mode);
if