Blame view
net/wireless/scan.c
33.1 KB
2a5193119 cfg80211/nl80211:... |
1 2 3 4 5 6 |
/* * cfg80211 scan result handling * * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> */ #include <linux/kernel.h> |
5a0e3ad6a include cleanup: ... |
7 |
#include <linux/slab.h> |
2a5193119 cfg80211/nl80211:... |
8 9 10 11 12 13 14 |
#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> |
262eb9b22 cfg80211: split w... |
15 |
#include <net/cfg80211-wext.h> |
2a5193119 cfg80211/nl80211:... |
16 17 18 |
#include <net/iw_handler.h> #include "core.h" #include "nl80211.h" |
a9a11622c cfg80211: self-co... |
19 |
#include "wext-compat.h" |
2a5193119 cfg80211/nl80211:... |
20 |
|
09f97e0fc cfg80211: increas... |
21 |
#define IEEE80211_SCAN_RESULT_EXPIRE (15 * HZ) |
2a5193119 cfg80211/nl80211:... |
22 |
|
01a0ac417 cfg80211: check l... |
23 |
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) |
2a5193119 cfg80211/nl80211:... |
24 |
{ |
667503ddc cfg80211: fix loc... |
25 |
struct cfg80211_scan_request *request; |
2a5193119 cfg80211/nl80211:... |
26 |
struct net_device *dev; |
3d23e349d wext: refactor |
27 |
#ifdef CONFIG_CFG80211_WEXT |
2a5193119 cfg80211/nl80211:... |
28 29 |
union iwreq_data wrqu; #endif |
01a0ac417 cfg80211: check l... |
30 |
ASSERT_RDEV_LOCK(rdev); |
667503ddc cfg80211: fix loc... |
31 |
request = rdev->scan_req; |
01a0ac417 cfg80211: check l... |
32 33 |
if (!request) return; |
463d01832 cfg80211: make aw... |
34 |
dev = request->dev; |
2a5193119 cfg80211/nl80211:... |
35 |
|
6829c878e cfg80211: emulate... |
36 37 38 39 40 41 |
/* * This must be before sending the other events! * Otherwise, wpa_supplicant gets completely confused with * wext events. */ cfg80211_sme_scan_done(dev); |
667503ddc cfg80211: fix loc... |
42 |
if (request->aborted) |
36e6fea84 cfg80211: check f... |
43 |
nl80211_send_scan_aborted(rdev, dev); |
2a5193119 cfg80211/nl80211:... |
44 |
else |
36e6fea84 cfg80211: check f... |
45 |
nl80211_send_scan_done(rdev, dev); |
2a5193119 cfg80211/nl80211:... |
46 |
|
3d23e349d wext: refactor |
47 |
#ifdef CONFIG_CFG80211_WEXT |
667503ddc cfg80211: fix loc... |
48 |
if (!request->aborted) { |
2a5193119 cfg80211/nl80211:... |
49 50 51 52 53 54 55 |
memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); } #endif dev_put(dev); |
36e6fea84 cfg80211: check f... |
56 |
rdev->scan_req = NULL; |
01a0ac417 cfg80211: check l... |
57 58 59 60 61 62 63 64 65 66 67 |
/* * OK. If this is invoked with "leak" then we can't * free this ... but we've cleaned it up anyway. The * driver failed to call the scan_done callback, so * all bets are off, it might still be trying to use * the scan request or not ... if it accesses the dev * in there (it shouldn't anyway) then it may crash. */ if (!leak) kfree(request); |
2a5193119 cfg80211/nl80211:... |
68 |
} |
667503ddc cfg80211: fix loc... |
69 |
|
36e6fea84 cfg80211: check f... |
70 71 72 73 74 75 76 77 |
void __cfg80211_scan_done(struct work_struct *wk) { struct cfg80211_registered_device *rdev; rdev = container_of(wk, struct cfg80211_registered_device, scan_done_wk); cfg80211_lock_rdev(rdev); |
01a0ac417 cfg80211: check l... |
78 |
___cfg80211_scan_done(rdev, false); |
36e6fea84 cfg80211: check f... |
79 80 |
cfg80211_unlock_rdev(rdev); } |
667503ddc cfg80211: fix loc... |
81 82 |
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) { |
667503ddc cfg80211: fix loc... |
83 84 85 |
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); request->aborted = aborted; |
e60d7443e wireless : use a ... |
86 |
queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk); |
667503ddc cfg80211: fix loc... |
87 |
} |
2a5193119 cfg80211/nl80211:... |
88 |
EXPORT_SYMBOL(cfg80211_scan_done); |
807f8a8c3 cfg80211/nl80211:... |
89 90 91 92 93 94 |
void __cfg80211_sched_scan_results(struct work_struct *wk) { struct cfg80211_registered_device *rdev; rdev = container_of(wk, struct cfg80211_registered_device, sched_scan_results_wk); |
c10841ca7 cfg80211: fix dea... |
95 |
mutex_lock(&rdev->sched_scan_mtx); |
807f8a8c3 cfg80211/nl80211:... |
96 97 98 99 100 |
/* we don't have sched_scan_req anymore if the scan is stopping */ if (rdev->sched_scan_req) nl80211_send_sched_scan_results(rdev, rdev->sched_scan_req->dev); |
c10841ca7 cfg80211: fix dea... |
101 |
mutex_unlock(&rdev->sched_scan_mtx); |
807f8a8c3 cfg80211/nl80211:... |
102 103 104 105 106 107 108 109 110 111 |
} void cfg80211_sched_scan_results(struct wiphy *wiphy) { /* ignore if we're not scanning */ if (wiphy_to_dev(wiphy)->sched_scan_req) queue_work(cfg80211_wq, &wiphy_to_dev(wiphy)->sched_scan_results_wk); } EXPORT_SYMBOL(cfg80211_sched_scan_results); |
85a9994a0 cfg80211/mac80211... |
112 |
void cfg80211_sched_scan_stopped(struct wiphy *wiphy) |
807f8a8c3 cfg80211/nl80211:... |
113 |
{ |
85a9994a0 cfg80211/mac80211... |
114 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
807f8a8c3 cfg80211/nl80211:... |
115 |
|
c10841ca7 cfg80211: fix dea... |
116 |
mutex_lock(&rdev->sched_scan_mtx); |
807f8a8c3 cfg80211/nl80211:... |
117 |
__cfg80211_stop_sched_scan(rdev, true); |
c10841ca7 cfg80211: fix dea... |
118 |
mutex_unlock(&rdev->sched_scan_mtx); |
807f8a8c3 cfg80211/nl80211:... |
119 |
} |
807f8a8c3 cfg80211/nl80211:... |
120 121 122 123 124 |
EXPORT_SYMBOL(cfg80211_sched_scan_stopped); int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev, bool driver_initiated) { |
807f8a8c3 cfg80211/nl80211:... |
125 |
struct net_device *dev; |
c10841ca7 cfg80211: fix dea... |
126 |
lockdep_assert_held(&rdev->sched_scan_mtx); |
807f8a8c3 cfg80211/nl80211:... |
127 128 |
if (!rdev->sched_scan_req) |
1a84ff756 cfg80211: return ... |
129 |
return -ENOENT; |
807f8a8c3 cfg80211/nl80211:... |
130 131 |
dev = rdev->sched_scan_req->dev; |
85a9994a0 cfg80211/mac80211... |
132 |
if (!driver_initiated) { |
3b4670ffe net, wireless: Do... |
133 |
int err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev); |
85a9994a0 cfg80211/mac80211... |
134 135 136 |
if (err) return err; } |
807f8a8c3 cfg80211/nl80211:... |
137 138 139 140 141 |
nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED); kfree(rdev->sched_scan_req); rdev->sched_scan_req = NULL; |
3b4670ffe net, wireless: Do... |
142 |
return 0; |
807f8a8c3 cfg80211/nl80211:... |
143 |
} |
2a5193119 cfg80211/nl80211:... |
144 145 146 147 148 |
static void bss_release(struct kref *ref) { struct cfg80211_internal_bss *bss; bss = container_of(ref, struct cfg80211_internal_bss, ref); |
78c1c7e10 cfg80211: free_pr... |
149 150 |
if (bss->pub.free_priv) bss->pub.free_priv(&bss->pub); |
cd1658f59 cfg80211: do not ... |
151 |
|
34a6eddba cfg80211: Store I... |
152 153 154 155 |
if (bss->beacon_ies_allocated) kfree(bss->pub.beacon_ies); if (bss->proberesp_ies_allocated) kfree(bss->pub.proberesp_ies); |
cd1658f59 cfg80211: do not ... |
156 |
|
19957bb39 cfg80211: keep tr... |
157 |
BUG_ON(atomic_read(&bss->hold)); |
2a5193119 cfg80211/nl80211:... |
158 159 160 161 |
kfree(bss); } /* must hold dev->bss_lock! */ |
cb3a8eec0 cfg80211: age sca... |
162 163 164 165 166 167 168 169 170 171 172 173 |
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! */ |
2b78ac9bf cfg80211: fix BSS... |
174 175 176 177 178 179 180 181 182 |
static void __cfg80211_unlink_bss(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *bss) { list_del_init(&bss->list); rb_erase(&bss->rbn, &dev->bss_tree); kref_put(&bss->ref, bss_release); } /* must hold dev->bss_lock! */ |
2a5193119 cfg80211/nl80211:... |
183 184 185 186 187 188 |
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) { |
19957bb39 cfg80211: keep tr... |
189 190 191 |
if (atomic_read(&bss->hold)) continue; if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) |
2a5193119 cfg80211/nl80211:... |
192 |
continue; |
2b78ac9bf cfg80211: fix BSS... |
193 |
__cfg80211_unlink_bss(dev, bss); |
2a5193119 cfg80211/nl80211:... |
194 195 196 197 198 199 |
expired = true; } if (expired) dev->bss_generation++; } |
c21dbf921 cfg80211: export ... |
200 |
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) |
2a5193119 cfg80211/nl80211:... |
201 |
{ |
c21dbf921 cfg80211: export ... |
202 |
while (len > 2 && ies[0] != eid) { |
2a5193119 cfg80211/nl80211:... |
203 204 205 206 207 208 209 210 211 |
len -= ies[1] + 2; ies += ies[1] + 2; } if (len < 2) return NULL; if (len < 2 + ies[1]) return NULL; return ies; } |
c21dbf921 cfg80211: export ... |
212 |
EXPORT_SYMBOL(cfg80211_find_ie); |
2a5193119 cfg80211/nl80211:... |
213 |
|
0c28ec587 cfg80211: add cfg... |
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type, const u8 *ies, int len) { struct ieee80211_vendor_ie *ie; const u8 *pos = ies, *end = ies + len; int ie_oui; while (pos < end) { pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos, end - pos); if (!pos) return NULL; if (end - pos < sizeof(*ie)) return NULL; ie = (struct ieee80211_vendor_ie *)pos; ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2]; if (ie_oui == oui && ie->oui_type == oui_type) return pos; pos += 2 + ie->len; } return NULL; } EXPORT_SYMBOL(cfg80211_find_vendor_ie); |
2a5193119 cfg80211/nl80211:... |
240 241 |
static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) { |
c21dbf921 cfg80211: export ... |
242 243 |
const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); |
2a5193119 cfg80211/nl80211:... |
244 |
|
3b6ef6334 cfg80211: fix cmp... |
245 |
/* equal if both missing */ |
2a5193119 cfg80211/nl80211:... |
246 247 |
if (!ie1 && !ie2) return 0; |
3b6ef6334 cfg80211: fix cmp... |
248 249 |
/* sort missing IE before (left of) present IE */ if (!ie1) |
2a5193119 cfg80211/nl80211:... |
250 |
return -1; |
3b6ef6334 cfg80211: fix cmp... |
251 252 |
if (!ie2) return 1; |
2a5193119 cfg80211/nl80211:... |
253 |
|
3b6ef6334 cfg80211: fix cmp... |
254 255 |
/* sort by length first, then by contents */ if (ie1[1] != ie2[1]) |
2a5193119 cfg80211/nl80211:... |
256 |
return ie2[1] - ie1[1]; |
3b6ef6334 cfg80211: fix cmp... |
257 |
return memcmp(ie1 + 2, ie2 + 2, ie1[1]); |
2a5193119 cfg80211/nl80211:... |
258 259 260 261 262 263 264 |
} static bool is_bss(struct cfg80211_bss *a, const u8 *bssid, const u8 *ssid, size_t ssid_len) { const u8 *ssidie; |
79420f09e cfg80211: add mor... |
265 |
if (bssid && compare_ether_addr(a->bssid, bssid)) |
2a5193119 cfg80211/nl80211:... |
266 |
return false; |
79420f09e cfg80211: add mor... |
267 268 |
if (!ssid) return true; |
c21dbf921 cfg80211: export ... |
269 270 271 |
ssidie = cfg80211_find_ie(WLAN_EID_SSID, a->information_elements, a->len_information_elements); |
2a5193119 cfg80211/nl80211:... |
272 273 274 275 276 277 |
if (!ssidie) return false; if (ssidie[1] != ssid_len) return false; return memcmp(ssidie + 2, ssid, ssid_len) == 0; } |
333ba7325 cfg80211: don't d... |
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
static bool is_mesh_bss(struct cfg80211_bss *a) { const u8 *ie; if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) return false; ie = cfg80211_find_ie(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements); if (!ie) return false; ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, a->information_elements, a->len_information_elements); if (!ie) return false; return true; } |
2a5193119 cfg80211/nl80211:... |
299 300 301 302 303 |
static bool is_mesh(struct cfg80211_bss *a, const u8 *meshid, size_t meshidlen, const u8 *meshcfg) { const u8 *ie; |
333ba7325 cfg80211: don't d... |
304 |
if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) |
2a5193119 cfg80211/nl80211:... |
305 |
return false; |
c21dbf921 cfg80211: export ... |
306 307 308 |
ie = cfg80211_find_ie(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements); |
2a5193119 cfg80211/nl80211:... |
309 310 311 312 313 314 |
if (!ie) return false; if (ie[1] != meshidlen) return false; if (memcmp(ie + 2, meshid, meshidlen)) return false; |
c21dbf921 cfg80211: export ... |
315 316 317 |
ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, a->information_elements, a->len_information_elements); |
cd3468bad cfg80211: add two... |
318 319 |
if (!ie) return false; |
136cfa286 mac80211: use a s... |
320 |
if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) |
2a5193119 cfg80211/nl80211:... |
321 322 323 324 325 326 327 |
return false; /* * Ignore mesh capability (last two bytes of the IE) when * comparing since that may differ between stations taking * part in the same mesh. */ |
136cfa286 mac80211: use a s... |
328 329 |
return memcmp(ie + 2, meshcfg, sizeof(struct ieee80211_meshconf_ie) - 2) == 0; |
2a5193119 cfg80211/nl80211:... |
330 |
} |
dd9dfb9f9 cfg80211: merge i... |
331 332 |
static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b) |
2a5193119 cfg80211/nl80211:... |
333 334 335 336 337 |
{ int r; if (a->channel != b->channel) return b->channel->center_freq - a->channel->center_freq; |
333ba7325 cfg80211: don't d... |
338 |
if (is_mesh_bss(a) && is_mesh_bss(b)) { |
2a5193119 cfg80211/nl80211:... |
339 340 341 342 343 344 345 346 347 348 349 350 351 |
r = cmp_ies(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements, b->information_elements, b->len_information_elements); if (r) return r; return cmp_ies(WLAN_EID_MESH_CONFIG, a->information_elements, a->len_information_elements, b->information_elements, b->len_information_elements); } |
dd9dfb9f9 cfg80211: merge i... |
352 353 354 355 356 357 358 359 360 |
return memcmp(a->bssid, b->bssid, ETH_ALEN); } static int cmp_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) { int r; r = cmp_bss_core(a, b); |
0a35d36d6 cfg80211: Use cap... |
361 362 |
if (r) return r; |
2a5193119 cfg80211/nl80211:... |
363 364 365 366 367 368 |
return cmp_ies(WLAN_EID_SSID, a->information_elements, a->len_information_elements, b->information_elements, b->len_information_elements); } |
dd9dfb9f9 cfg80211: merge i... |
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b) { const u8 *ie1; const u8 *ie2; int i; int r; r = cmp_bss_core(a, b); if (r) return r; ie1 = cfg80211_find_ie(WLAN_EID_SSID, a->information_elements, a->len_information_elements); ie2 = cfg80211_find_ie(WLAN_EID_SSID, b->information_elements, b->len_information_elements); /* Key comparator must use same algorithm in any rb-tree * search function (order is important), otherwise ordering * of items in the tree is broken and search gives incorrect * results. This code uses same order as cmp_ies() does. */ /* sort missing IE before (left of) present IE */ if (!ie1) return -1; if (!ie2) return 1; /* zero-size SSID is used as an indication of the hidden bss */ if (!ie2[1]) return 0; /* sort by length first, then by contents */ if (ie1[1] != ie2[1]) return ie2[1] - ie1[1]; /* zeroed SSID ie is another indication of a hidden bss */ for (i = 0; i < ie2[1]; i++) if (ie2[i + 2]) return -1; return 0; } |
2a5193119 cfg80211/nl80211:... |
414 415 416 |
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *bssid, |
79420f09e cfg80211: add mor... |
417 418 |
const u8 *ssid, size_t ssid_len, u16 capa_mask, u16 capa_val) |
2a5193119 cfg80211/nl80211:... |
419 420 421 |
{ struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); struct cfg80211_internal_bss *bss, *res = NULL; |
ccb6c1360 cfg80211: don't g... |
422 |
unsigned long now = jiffies; |
2a5193119 cfg80211/nl80211:... |
423 424 425 426 |
spin_lock_bh(&dev->bss_lock); list_for_each_entry(bss, &dev->bss_list, list) { |
79420f09e cfg80211: add mor... |
427 428 |
if ((bss->pub.capability & capa_mask) != capa_val) continue; |
2a5193119 cfg80211/nl80211:... |
429 430 |
if (channel && bss->pub.channel != channel) continue; |
ccb6c1360 cfg80211: don't g... |
431 432 433 434 |
/* Don't get expired BSS structs */ if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) && !atomic_read(&bss->hold)) continue; |
2a5193119 cfg80211/nl80211:... |
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 |
if (is_bss(&bss->pub, bssid, ssid, ssid_len)) { res = bss; kref_get(&res->ref); break; } } spin_unlock_bh(&dev->bss_lock); if (!res) return NULL; return &res->pub; } EXPORT_SYMBOL(cfg80211_get_bss); struct cfg80211_bss *cfg80211_get_mesh(struct wiphy *wiphy, struct ieee80211_channel *channel, const u8 *meshid, size_t meshidlen, const u8 *meshcfg) { struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy); struct cfg80211_internal_bss *bss, *res = NULL; spin_lock_bh(&dev->bss_lock); list_for_each_entry(bss, &dev->bss_list, list) { if (channel && bss->pub.channel != channel) continue; if (is_mesh(&bss->pub, meshid, meshidlen, meshcfg)) { res = bss; kref_get(&res->ref); break; } } spin_unlock_bh(&dev->bss_lock); if (!res) return NULL; return &res->pub; } EXPORT_SYMBOL(cfg80211_get_mesh); static void rb_insert_bss(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *bss) { struct rb_node **p = &dev->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); 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, &dev->bss_tree); } static struct cfg80211_internal_bss * rb_find_bss(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *res) { struct rb_node *n = dev->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); if (r == 0) return bss; else if (r < 0) n = n->rb_left; else n = n->rb_right; } return NULL; } static struct cfg80211_internal_bss * |
dd9dfb9f9 cfg80211: merge i... |
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
rb_find_hidden_bss(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *res) { struct rb_node *n = dev->bss_tree.rb_node; struct cfg80211_internal_bss *bss; int r; while (n) { bss = rb_entry(n, struct cfg80211_internal_bss, rbn); r = cmp_hidden_bss(&res->pub, &bss->pub); if (r == 0) return bss; else if (r < 0) n = n->rb_left; else n = n->rb_right; } return NULL; } static void copy_hidden_ies(struct cfg80211_internal_bss *res, struct cfg80211_internal_bss *hidden) { if (unlikely(res->pub.beacon_ies)) return; if (WARN_ON(!hidden->pub.beacon_ies)) return; res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC); if (unlikely(!res->pub.beacon_ies)) return; res->beacon_ies_allocated = true; res->pub.len_beacon_ies = hidden->pub.len_beacon_ies; memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies, res->pub.len_beacon_ies); } static struct cfg80211_internal_bss * |
2a5193119 cfg80211/nl80211:... |
572 |
cfg80211_bss_update(struct cfg80211_registered_device *dev, |
34a6eddba cfg80211: Store I... |
573 |
struct cfg80211_internal_bss *res) |
2a5193119 cfg80211/nl80211:... |
574 575 |
{ struct cfg80211_internal_bss *found = NULL; |
2a5193119 cfg80211/nl80211:... |
576 577 578 579 580 581 582 583 584 585 586 |
/* * The reference to "res" is donated to this function. */ if (WARN_ON(!res->pub.channel)) { kref_put(&res->ref, bss_release); return NULL; } res->ts = jiffies; |
2a5193119 cfg80211/nl80211:... |
587 588 589 |
spin_lock_bh(&dev->bss_lock); found = rb_find_bss(dev, res); |
cd1658f59 cfg80211: do not ... |
590 |
if (found) { |
2a5193119 cfg80211/nl80211:... |
591 592 593 |
found->pub.beacon_interval = res->pub.beacon_interval; found->pub.tsf = res->pub.tsf; found->pub.signal = res->pub.signal; |
2a5193119 cfg80211/nl80211:... |
594 595 |
found->pub.capability = res->pub.capability; found->ts = res->ts; |
cd1658f59 cfg80211: do not ... |
596 |
|
34a6eddba cfg80211: Store I... |
597 598 |
/* Update IEs */ if (res->pub.proberesp_ies) { |
cd1658f59 cfg80211: do not ... |
599 |
size_t used = dev->wiphy.bss_priv_size + sizeof(*res); |
34a6eddba cfg80211: Store I... |
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
size_t ielen = res->pub.len_proberesp_ies; if (found->pub.proberesp_ies && !found->proberesp_ies_allocated && ksize(found) >= used + ielen) { memcpy(found->pub.proberesp_ies, res->pub.proberesp_ies, ielen); found->pub.len_proberesp_ies = ielen; } else { u8 *ies = found->pub.proberesp_ies; if (found->proberesp_ies_allocated) ies = krealloc(ies, ielen, GFP_ATOMIC); else ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { memcpy(ies, res->pub.proberesp_ies, ielen); found->proberesp_ies_allocated = true; found->pub.proberesp_ies = ies; found->pub.len_proberesp_ies = ielen; } } |
cd1658f59 cfg80211: do not ... |
624 |
|
34a6eddba cfg80211: Store I... |
625 626 627 628 629 630 631 632 633 |
/* Override possible earlier Beacon frame IEs */ found->pub.information_elements = found->pub.proberesp_ies; found->pub.len_information_elements = found->pub.len_proberesp_ies; } if (res->pub.beacon_ies) { size_t used = dev->wiphy.bss_priv_size + sizeof(*res); size_t ielen = res->pub.len_beacon_ies; |
01123e233 cfg80211: update ... |
634 635 636 |
bool information_elements_is_beacon_ies = (found->pub.information_elements == found->pub.beacon_ies); |
34a6eddba cfg80211: Store I... |
637 638 639 640 641 642 643 |
if (found->pub.beacon_ies && !found->beacon_ies_allocated && ksize(found) >= used + ielen) { memcpy(found->pub.beacon_ies, res->pub.beacon_ies, ielen); found->pub.len_beacon_ies = ielen; |
cd1658f59 cfg80211: do not ... |
644 |
} else { |
34a6eddba cfg80211: Store I... |
645 |
u8 *ies = found->pub.beacon_ies; |
cd1658f59 cfg80211: do not ... |
646 |
|
34a6eddba cfg80211: Store I... |
647 |
if (found->beacon_ies_allocated) |
273de92c8 cfg80211: Remove ... |
648 649 |
ies = krealloc(ies, ielen, GFP_ATOMIC); else |
cd1658f59 cfg80211: do not ... |
650 651 652 |
ies = kmalloc(ielen, GFP_ATOMIC); if (ies) { |
34a6eddba cfg80211: Store I... |
653 654 655 656 657 |
memcpy(ies, res->pub.beacon_ies, ielen); found->beacon_ies_allocated = true; found->pub.beacon_ies = ies; found->pub.len_beacon_ies = ielen; |
cd1658f59 cfg80211: do not ... |
658 659 |
} } |
01123e233 cfg80211: update ... |
660 661 662 663 664 665 666 667 |
/* Override IEs if they were from a beacon before */ if (information_elements_is_beacon_ies) { found->pub.information_elements = found->pub.beacon_ies; found->pub.len_information_elements = found->pub.len_beacon_ies; } |
cd1658f59 cfg80211: do not ... |
668 |
} |
2a5193119 cfg80211/nl80211:... |
669 670 |
kref_put(&res->ref, bss_release); } else { |
dd9dfb9f9 cfg80211: merge i... |
671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
struct cfg80211_internal_bss *hidden; /* First check if the beacon is a probe response from * a hidden bss. If so, copy beacon ies (with nullified * ssid) into the probe response bss entry (with real ssid). * It is required basically for PSM implementation * (probe responses do not contain tim ie) */ /* TODO: The code is not trying to update existing probe * response bss entries when beacon ies are * getting changed. */ hidden = rb_find_hidden_bss(dev, res); if (hidden) copy_hidden_ies(res, hidden); |
2a5193119 cfg80211/nl80211:... |
685 686 687 688 689 690 691 692 693 694 695 696 |
/* this "consumes" the reference */ list_add_tail(&res->list, &dev->bss_list); rb_insert_bss(dev, res); found = res; } dev->bss_generation++; spin_unlock_bh(&dev->bss_lock); kref_get(&found->ref); return found; } |
06aa7afaa cfg80211: add cfg... |
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 |
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; |
22fe88d3d cfg80211: Fix sig... |
712 |
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && |
06aa7afaa cfg80211: add cfg... |
713 714 715 716 717 718 719 720 721 722 723 724 725 |
(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; |
34a6eddba cfg80211: Store I... |
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 |
/* * Since we do not know here whether the IEs are from a Beacon or Probe * Response frame, we need to pick one of the options and only use it * with the driver that does not provide the full Beacon/Probe Response * frame. Use Beacon frame pointer to avoid indicating that this should * override the information_elements pointer should we have received an * earlier indication of Probe Response data. * * The initial buffer for the IEs is allocated with the BSS entry and * is located after the private area. */ res->pub.beacon_ies = (u8 *)res + sizeof(*res) + privsz; memcpy(res->pub.beacon_ies, ie, ielen); res->pub.len_beacon_ies = ielen; res->pub.information_elements = res->pub.beacon_ies; res->pub.len_information_elements = res->pub.len_beacon_ies; |
06aa7afaa cfg80211: add cfg... |
742 743 |
kref_init(&res->ref); |
34a6eddba cfg80211: Store I... |
744 |
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
06aa7afaa cfg80211: add cfg... |
745 746 747 748 749 750 751 752 753 754 |
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); |
2a5193119 cfg80211/nl80211:... |
755 756 757 758 |
struct cfg80211_bss * cfg80211_inform_bss_frame(struct wiphy *wiphy, struct ieee80211_channel *channel, struct ieee80211_mgmt *mgmt, size_t len, |
77965c970 cfg80211: clean u... |
759 |
s32 signal, gfp_t gfp) |
2a5193119 cfg80211/nl80211:... |
760 761 762 763 |
{ struct cfg80211_internal_bss *res; size_t ielen = len - offsetof(struct ieee80211_mgmt, u.probe_resp.variable); |
bef9bacc4 cfg80211:: fix po... |
764 765 766 767 768 769 770 |
size_t privsz; if (WARN_ON(!mgmt)) return NULL; if (WARN_ON(!wiphy)) return NULL; |
2a5193119 cfg80211/nl80211:... |
771 |
|
22fe88d3d cfg80211: Fix sig... |
772 |
if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC && |
2a5193119 cfg80211/nl80211:... |
773 774 |
(signal < 0 || signal > 100))) return NULL; |
bef9bacc4 cfg80211:: fix po... |
775 |
if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable))) |
2a5193119 cfg80211/nl80211:... |
776 |
return NULL; |
bef9bacc4 cfg80211:: fix po... |
777 |
privsz = wiphy->bss_priv_size; |
2a5193119 cfg80211/nl80211:... |
778 779 780 781 782 783 |
res = kzalloc(sizeof(*res) + privsz + ielen, gfp); if (!res) return NULL; memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN); res->pub.channel = channel; |
2a5193119 cfg80211/nl80211:... |
784 785 786 787 |
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); res->pub.capability = le16_to_cpu(mgmt->u.probe_resp.capab_info); |
34a6eddba cfg80211: Store I... |
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 |
/* * The initial buffer for the IEs is allocated with the BSS entry and * is located after the private area. */ if (ieee80211_is_probe_resp(mgmt->frame_control)) { res->pub.proberesp_ies = (u8 *) res + sizeof(*res) + privsz; memcpy(res->pub.proberesp_ies, mgmt->u.probe_resp.variable, ielen); res->pub.len_proberesp_ies = ielen; res->pub.information_elements = res->pub.proberesp_ies; res->pub.len_information_elements = res->pub.len_proberesp_ies; } else { res->pub.beacon_ies = (u8 *) res + sizeof(*res) + privsz; memcpy(res->pub.beacon_ies, mgmt->u.beacon.variable, ielen); res->pub.len_beacon_ies = ielen; res->pub.information_elements = res->pub.beacon_ies; res->pub.len_information_elements = res->pub.len_beacon_ies; } |
2a5193119 cfg80211/nl80211:... |
806 807 |
kref_init(&res->ref); |
34a6eddba cfg80211: Store I... |
808 |
res = cfg80211_bss_update(wiphy_to_dev(wiphy), res); |
2a5193119 cfg80211/nl80211:... |
809 810 |
if (!res) return NULL; |
e38f8a7a8 cfg80211: Add AP ... |
811 812 |
if (res->pub.capability & WLAN_CAPABILITY_ESS) regulatory_hint_found_beacon(wiphy, channel, gfp); |
2a5193119 cfg80211/nl80211:... |
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 |
/* cfg80211_bss_update gives us a referenced result */ return &res->pub; } EXPORT_SYMBOL(cfg80211_inform_bss_frame); void cfg80211_put_bss(struct cfg80211_bss *pub) { struct cfg80211_internal_bss *bss; if (!pub) return; bss = container_of(pub, struct cfg80211_internal_bss, pub); kref_put(&bss->ref, bss_release); } EXPORT_SYMBOL(cfg80211_put_bss); |
d491af19d cfg80211: allow u... |
829 830 831 832 833 834 835 836 837 838 839 |
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); |
3207390a8 cfg80211: fix BSS... |
840 |
if (!list_empty(&bss->list)) { |
2b78ac9bf cfg80211: fix BSS... |
841 |
__cfg80211_unlink_bss(dev, bss); |
3207390a8 cfg80211: fix BSS... |
842 |
dev->bss_generation++; |
3207390a8 cfg80211: fix BSS... |
843 |
} |
d491af19d cfg80211: allow u... |
844 |
spin_unlock_bh(&dev->bss_lock); |
d491af19d cfg80211: allow u... |
845 846 |
} EXPORT_SYMBOL(cfg80211_unlink_bss); |
3d23e349d wext: refactor |
847 |
#ifdef CONFIG_CFG80211_WEXT |
2a5193119 cfg80211/nl80211:... |
848 849 850 851 852 853 854 |
int cfg80211_wext_siwscan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct cfg80211_registered_device *rdev; struct wiphy *wiphy; struct iw_scan_req *wreq = NULL; |
65486c8b3 cfg80211: fix err... |
855 |
struct cfg80211_scan_request *creq = NULL; |
2a5193119 cfg80211/nl80211:... |
856 857 858 859 860 |
int i, err, n_channels = 0; enum ieee80211_band band; if (!netif_running(dev)) return -ENETDOWN; |
b2e3abdc7 cfg80211: allow s... |
861 862 |
if (wrqu->data.length == sizeof(struct iw_scan_req)) wreq = (struct iw_scan_req *)extra; |
463d01832 cfg80211: make aw... |
863 |
rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
2a5193119 cfg80211/nl80211:... |
864 865 866 867 868 869 870 871 872 873 |
if (IS_ERR(rdev)) return PTR_ERR(rdev); if (rdev->scan_req) { err = -EBUSY; goto out; } wiphy = &rdev->wiphy; |
b2e3abdc7 cfg80211: allow s... |
874 875 876 877 878 879 880 881 |
/* Determine number of channels, needed to allocate creq */ if (wreq && wreq->num_channels) n_channels = wreq->num_channels; else { for (band = 0; band < IEEE80211_NUM_BANDS; band++) if (wiphy->bands[band]) n_channels += wiphy->bands[band]->n_channels; } |
2a5193119 cfg80211/nl80211:... |
882 883 884 885 886 887 888 889 890 891 |
creq = kzalloc(sizeof(*creq) + sizeof(struct cfg80211_ssid) + n_channels * sizeof(void *), GFP_ATOMIC); if (!creq) { err = -ENOMEM; goto out; } creq->wiphy = wiphy; |
463d01832 cfg80211: make aw... |
892 |
creq->dev = dev; |
5ba63533b cfg80211: fix ali... |
893 894 |
/* SSIDs come after channels */ creq->ssids = (void *)&creq->channels[n_channels]; |
2a5193119 cfg80211/nl80211:... |
895 896 |
creq->n_channels = n_channels; creq->n_ssids = 1; |
b2e3abdc7 cfg80211: allow s... |
897 |
/* translate "Scan on frequencies" request */ |
2a5193119 cfg80211/nl80211:... |
898 899 900 |
i = 0; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { int j; |
584991dcc cfg80211: validat... |
901 |
|
2a5193119 cfg80211/nl80211:... |
902 903 |
if (!wiphy->bands[band]) continue; |
584991dcc cfg80211: validat... |
904 |
|
2a5193119 cfg80211/nl80211:... |
905 |
for (j = 0; j < wiphy->bands[band]->n_channels; j++) { |
584991dcc cfg80211: validat... |
906 907 908 909 |
/* ignore disabled channels */ if (wiphy->bands[band]->channels[j].flags & IEEE80211_CHAN_DISABLED) continue; |
b2e3abdc7 cfg80211: allow s... |
910 911 912 913 914 915 916 917 918 |
/* If we have a wireless request structure and the * wireless request specifies frequencies, then search * for the matching hardware channel. */ if (wreq && wreq->num_channels) { int k; int wiphy_freq = wiphy->bands[band]->channels[j].center_freq; for (k = 0; k < wreq->num_channels; k++) { |
a4e7b730f cfg80211: use cfg... |
919 |
int wext_freq = cfg80211_wext_freq(wiphy, &wreq->channel_list[k]); |
b2e3abdc7 cfg80211: allow s... |
920 921 922 923 924 925 926 |
if (wext_freq == wiphy_freq) goto wext_freq_found; } goto wext_freq_not_found; } wext_freq_found: |
2a5193119 cfg80211/nl80211:... |
927 928 |
creq->channels[i] = &wiphy->bands[band]->channels[j]; i++; |
b2e3abdc7 cfg80211: allow s... |
929 |
wext_freq_not_found: ; |
2a5193119 cfg80211/nl80211:... |
930 931 |
} } |
8862dc5f2 cfg80211: minimal... |
932 933 934 935 936 |
/* No channels found? */ if (!i) { err = -EINVAL; goto out; } |
2a5193119 cfg80211/nl80211:... |
937 |
|
b2e3abdc7 cfg80211: allow s... |
938 939 |
/* Set real number of channels specified in creq->channels[] */ creq->n_channels = i; |
2a5193119 cfg80211/nl80211:... |
940 |
|
b2e3abdc7 cfg80211: allow s... |
941 942 |
/* translate "Scan for SSID" request */ if (wreq) { |
2a5193119 cfg80211/nl80211:... |
943 |
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { |
65486c8b3 cfg80211: fix err... |
944 945 946 947 |
if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) { err = -EINVAL; goto out; } |
2a5193119 cfg80211/nl80211:... |
948 949 950 951 952 953 |
memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); creq->ssids[0].ssid_len = wreq->essid_len; } if (wreq->scan_type == IW_SCAN_TYPE_PASSIVE) creq->n_ssids = 0; } |
34850ab25 cfg80211: allow u... |
954 |
for (i = 0; i < IEEE80211_NUM_BANDS; i++) |
a401d2bb3 cfg80211: fix sca... |
955 956 |
if (wiphy->bands[i]) creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; |
34850ab25 cfg80211: allow u... |
957 |
|
2a5193119 cfg80211/nl80211:... |
958 959 960 961 |
rdev->scan_req = creq; err = rdev->ops->scan(wiphy, dev, creq); if (err) { rdev->scan_req = NULL; |
65486c8b3 cfg80211: fix err... |
962 |
/* creq will be freed below */ |
463d01832 cfg80211: make aw... |
963 |
} else { |
a538e2d5a cfg80211: issue n... |
964 |
nl80211_send_scan_start(rdev, dev); |
65486c8b3 cfg80211: fix err... |
965 966 |
/* creq now owned by driver */ creq = NULL; |
463d01832 cfg80211: make aw... |
967 968 |
dev_hold(dev); } |
2a5193119 cfg80211/nl80211:... |
969 |
out: |
65486c8b3 cfg80211: fix err... |
970 |
kfree(creq); |
4d0c8aead cfg80211: properl... |
971 |
cfg80211_unlock_rdev(rdev); |
2a5193119 cfg80211/nl80211:... |
972 973 |
return err; } |
ba44cb722 cfg80211: mark al... |
974 |
EXPORT_SYMBOL_GPL(cfg80211_wext_siwscan); |
2a5193119 cfg80211/nl80211:... |
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 |
static void ieee80211_scan_add_ies(struct iw_request_info *info, struct cfg80211_bss *bss, char **current_ev, char *end_buf) { u8 *pos, *end, *next; struct iw_event iwe; if (!bss->information_elements || !bss->len_information_elements) return; /* * If needed, fragment the IEs buffer (at IE boundaries) into short * enough fragments to fit into IW_GENERIC_IE_MAX octet messages. */ pos = bss->information_elements; end = pos + bss->len_information_elements; while (end - pos > IW_GENERIC_IE_MAX) { next = pos + 2 + pos[1]; while (next + 2 + next[1] - pos < IW_GENERIC_IE_MAX) next = next + 2 + next[1]; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = next - pos; *current_ev = iwe_stream_add_point(info, *current_ev, end_buf, &iwe, pos); pos = next; } if (end > pos) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVGENIE; iwe.u.data.length = end - pos; *current_ev = iwe_stream_add_point(info, *current_ev, end_buf, &iwe, pos); } } |
cb3a8eec0 cfg80211: age sca... |
1016 1017 1018 1019 1020 1021 1022 1023 1024 |
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); } |
2a5193119 cfg80211/nl80211:... |
1025 1026 |
static char * |
77965c970 cfg80211: clean u... |
1027 1028 1029 |
ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info, struct cfg80211_internal_bss *bss, char *current_ev, char *end_buf) |
2a5193119 cfg80211/nl80211:... |
1030 1031 1032 1033 |
{ struct iw_event iwe; u8 *buf, *cfg, *p; u8 *ie = bss->pub.information_elements; |
a77b85524 cfg80211/mac80211... |
1034 |
int rem = bss->pub.len_information_elements, i, sig; |
2a5193119 cfg80211/nl80211:... |
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 |
bool ismesh = false; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bss->pub.bssid, ETH_ALEN); current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = ieee80211_frequency_to_channel(bss->pub.channel->center_freq); iwe.u.freq.e = 0; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = bss->pub.channel->center_freq; iwe.u.freq.e = 6; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); |
77965c970 cfg80211: clean u... |
1057 |
if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) { |
2a5193119 cfg80211/nl80211:... |
1058 1059 1060 1061 |
memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVQUAL; iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED | IW_QUAL_NOISE_INVALID | |
a77b85524 cfg80211/mac80211... |
1062 |
IW_QUAL_QUAL_UPDATED; |
77965c970 cfg80211: clean u... |
1063 |
switch (wiphy->signal_type) { |
2a5193119 cfg80211/nl80211:... |
1064 |
case CFG80211_SIGNAL_TYPE_MBM: |
a77b85524 cfg80211/mac80211... |
1065 1066 |
sig = bss->pub.signal / 100; iwe.u.qual.level = sig; |
2a5193119 cfg80211/nl80211:... |
1067 |
iwe.u.qual.updated |= IW_QUAL_DBM; |
a77b85524 cfg80211/mac80211... |
1068 1069 1070 1071 1072 1073 |
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; |
2a5193119 cfg80211/nl80211:... |
1074 1075 1076 |
break; case CFG80211_SIGNAL_TYPE_UNSPEC: iwe.u.qual.level = bss->pub.signal; |
a77b85524 cfg80211/mac80211... |
1077 1078 |
/* will give range 0 .. 100 */ iwe.u.qual.qual = bss->pub.signal; |
2a5193119 cfg80211/nl80211:... |
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 |
break; default: /* not reached */ break; } current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); } memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWENCODE; if (bss->pub.capability & WLAN_CAPABILITY_PRIVACY) iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; else iwe.u.data.flags = IW_ENCODE_DISABLED; iwe.u.data.length = 0; current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ""); while (rem >= 2) { /* invalid data */ if (ie[1] > rem - 2) break; switch (ie[0]) { case WLAN_EID_SSID: memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ie + 2); break; case WLAN_EID_MESH_ID: memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; iwe.u.data.length = ie[1]; iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, ie + 2); break; case WLAN_EID_MESH_CONFIG: ismesh = true; |
136cfa286 mac80211: use a s... |
1122 |
if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) |
2a5193119 cfg80211/nl80211:... |
1123 1124 1125 1126 1127 1128 1129 |
break; buf = kmalloc(50, GFP_ATOMIC); if (!buf) break; cfg = ie + 2; memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; |
76aa5e704 mac80211: update ... |
1130 1131 |
sprintf(buf, "Mesh Network Path Selection Protocol ID: " "0x%02X", cfg[0]); |
2a5193119 cfg80211/nl80211:... |
1132 1133 1134 1135 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); |
76aa5e704 mac80211: update ... |
1136 1137 |
sprintf(buf, "Path Selection Metric ID: 0x%02X", cfg[1]); |
2a5193119 cfg80211/nl80211:... |
1138 1139 1140 1141 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); |
76aa5e704 mac80211: update ... |
1142 1143 |
sprintf(buf, "Congestion Control Mode ID: 0x%02X", cfg[2]); |
2a5193119 cfg80211/nl80211:... |
1144 1145 1146 1147 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); |
76aa5e704 mac80211: update ... |
1148 |
sprintf(buf, "Synchronization ID: 0x%02X", cfg[3]); |
2a5193119 cfg80211/nl80211:... |
1149 1150 1151 1152 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); |
76aa5e704 mac80211: update ... |
1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 |
sprintf(buf, "Authentication ID: 0x%02X", cfg[4]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); sprintf(buf, "Formation Info: 0x%02X", cfg[5]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); sprintf(buf, "Capabilities: 0x%02X", cfg[6]); |
2a5193119 cfg80211/nl80211:... |
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); kfree(buf); break; case WLAN_EID_SUPP_RATES: case WLAN_EID_EXT_SUPP_RATES: /* display all supported rates in readable format */ p = current_ev + iwe_stream_lcp_len(info); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWRATE; /* Those two flags are ignored... */ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; for (i = 0; i < ie[1]; i++) { iwe.u.bitrate.value = ((ie[i + 2] & 0x7f) * 500000); p = iwe_stream_add_value(info, current_ev, p, end_buf, &iwe, IW_EV_PARAM_LEN); } current_ev = p; break; } rem -= ie[1] + 2; ie += ie[1] + 2; } |
f64f9e719 net: Move && and ... |
1192 1193 |
if (bss->pub.capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) || ismesh) { |
2a5193119 cfg80211/nl80211:... |
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 |
memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; if (ismesh) iwe.u.mode = IW_MODE_MESH; else if (bss->pub.capability & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe, IW_EV_UINT_LEN); } buf = kmalloc(30, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->pub.tsf)); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; |
cb3a8eec0 cfg80211: age sca... |
1216 1217 |
sprintf(buf, " Last beacon: %ums ago", elapsed_jiffies_msecs(bss->ts)); |
2a5193119 cfg80211/nl80211:... |
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 |
iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(info, current_ev, end_buf, &iwe, buf); kfree(buf); } ieee80211_scan_add_ies(info, &bss->pub, ¤t_ev, end_buf); return current_ev; } static int ieee80211_scan_results(struct cfg80211_registered_device *dev, struct iw_request_info *info, char *buf, size_t len) { char *current_ev = buf; char *end_buf = buf + len; struct cfg80211_internal_bss *bss; spin_lock_bh(&dev->bss_lock); cfg80211_bss_expire(dev); list_for_each_entry(bss, &dev->bss_list, list) { if (buf + len - current_ev <= IW_EV_ADDR_LEN) { spin_unlock_bh(&dev->bss_lock); return -E2BIG; } |
77965c970 cfg80211: clean u... |
1246 1247 |
current_ev = ieee80211_bss(&dev->wiphy, info, bss, current_ev, end_buf); |
2a5193119 cfg80211/nl80211:... |
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 |
} spin_unlock_bh(&dev->bss_lock); return current_ev - buf; } int cfg80211_wext_giwscan(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { struct cfg80211_registered_device *rdev; int res; if (!netif_running(dev)) return -ENETDOWN; |
463d01832 cfg80211: make aw... |
1263 |
rdev = cfg80211_get_dev_from_ifindex(dev_net(dev), dev->ifindex); |
2a5193119 cfg80211/nl80211:... |
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 |
if (IS_ERR(rdev)) return PTR_ERR(rdev); if (rdev->scan_req) { res = -EAGAIN; goto out; } res = ieee80211_scan_results(rdev, info, extra, data->length); data->length = 0; if (res >= 0) { data->length = res; res = 0; } out: |
4d0c8aead cfg80211: properl... |
1281 |
cfg80211_unlock_rdev(rdev); |
2a5193119 cfg80211/nl80211:... |
1282 1283 |
return res; } |
ba44cb722 cfg80211: mark al... |
1284 |
EXPORT_SYMBOL_GPL(cfg80211_wext_giwscan); |
2a5193119 cfg80211/nl80211:... |
1285 |
#endif |