cregit-Linux how code gets into the kernel

Release 4.11 net/wireless/scan.c

Directory: net/wireless
/*
 * 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

PersonTokensPropCommitsCommitProp
Johannes Berg7969.30%375.00%
Amitkumar Karwar3530.70%125.00%
Total114100.00%4100.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

PersonTokensPropCommitsCommitProp
Johannes Berg5996.72%266.67%
Zhao, Gang23.28%133.33%
Total61100.00%3100.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

PersonTokensPropCommitsCommitProp
Johannes Berg9097.83%266.67%
Zhao, Gang22.17%133.33%
Total92100.00%3100.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

PersonTokensPropCommitsCommitProp
Johannes Berg8667.19%466.67%
Amitkumar Karwar3829.69%116.67%
Zhao, Gang43.12%116.67%
Total128100.00%6100.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

PersonTokensPropCommitsCommitProp
Sam Leffler7984.04%125.00%
Johannes Berg1010.64%250.00%
Zhao, Gang55.32%125.00%
Total94100.00%4100.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

PersonTokensPropCommitsCommitProp
Johannes Berg122100.00%1100.00%
Total122100.00%1100.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

PersonTokensPropCommitsCommitProp
Johannes Berg19780.74%1071.43%
Sam Leffler3413.93%17.14%
Avraham Stern62.46%17.14%
Christian Lamparter52.05%17.14%
Arend Van Spriel20.82%17.14%
Total244100.00%14100.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

PersonTokensPropCommitsCommitProp
Johannes Berg40100.00%3100.00%
Total40100.00%3100.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

PersonTokensPropCommitsCommitProp
Johannes Berg4570.31%342.86%
Avraham Stern812.50%114.29%
Beni Lev69.38%114.29%
Alban Browaeys34.69%114.29%
Zhao, Gang23.12%114.29%
Total64100.00%7100.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

PersonTokensPropCommitsCommitProp
Sam Leffler5450.47%116.67%
Luciano Coelho4239.25%116.67%
Johannes Berg54.67%233.33%
Jukka Rissanen32.80%116.67%
Arend Van Spriel32.80%116.67%
Total107100.00%6100.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

PersonTokensPropCommitsCommitProp
Luciano Coelho3175.61%125.00%
Beni Lev512.20%125.00%
Jukka Rissanen37.32%125.00%
Zhao, Gang24.88%125.00%
Total41100.00%4100.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

PersonTokensPropCommitsCommitProp
Luciano Coelho2468.57%240.00%
Eliad Peller514.29%120.00%
Beni Lev514.29%120.00%
Zhao, Gang12.86%120.00%
Total35100.00%5100.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

PersonTokensPropCommitsCommitProp
Eliad Peller1780.95%133.33%
Luciano Coelho29.52%133.33%
Johannes Berg29.52%133.33%
Total21100.00%3100.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

PersonTokensPropCommitsCommitProp
Luciano Coelho7673.08%342.86%
Jukka Rissanen2120.19%114.29%
Jesper Juhl43.85%114.29%
Johannes Berg21.92%114.29%
Hila Gonen10.96%114.29%
Total104100.00%7100.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

PersonTokensPropCommitsCommitProp
Dan J Williams4270.00%133.33%
Johannes Berg1423.33%133.33%
Zhao, Gang46.67%133.33%
Total60100.00%3100.00%


void cfg80211_bss_expire(struct cfg80211_registered_device *rdev) { __cfg80211_bss_expire(rdev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE); }

Contributors

PersonTokensPropCommitsCommitProp
Johannes Berg1578.95%133.33%
Zhao, Gang210.53%133.33%
Sam Leffler210.53%133.33%
Total19100.00%3100.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

PersonTokensPropCommitsCommitProp
Luciano Coelho8061.54%125.00%
Johannes Berg4937.69%250.00%
Bob Copeland10.77%125.00%
Total130100.00%4100.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

PersonTokensPropCommitsCommitProp
Luciano Coelho5247.71%250.00%
Eliad Peller4238.53%125.00%
Emmanuel Grumbach1513.76%125.00%
Total109100.00%4100.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

PersonTokensPropCommitsCommitProp
Johannes Berg12498.41%480.00%
Joe Perches21.59%120.00%
Total126100.00%5100.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

PersonTokensPropCommitsCommitProp
Johannes Berg38577.00%562.50%
Dmitry Tarnyagin9819.60%112.50%
Javier Cardona91.80%112.50%
Emmanuel Grumbach81.60%112.50%
Total500100.00%8100.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

PersonTokensPropCommitsCommitProp
Dedy Lansky13898.57%150.00%
Johannes Berg21.43%150.00%
Total140100.00%2100.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

PersonTokensPropCommitsCommitProp
Johannes Berg18468.91%660.00%
Dedy Lansky5420.22%110.00%
Beni Lev238.61%110.00%
Zhao, Gang62.25%220.00%
Total267100.00%10100.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

PersonTokensPropCommitsCommitProp
Johannes Berg14697.99%375.00%
Zhao, Gang32.01%125.00%
Total149100.00%4100.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