scan.c 36.2 KB
Newer Older
1
2
3
4
5
6
/*
 * cfg80211 scan result handling
 *
 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
 */
#include <linux/kernel.h>
7
#include <linux/slab.h>
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>
15
#include <net/cfg80211-wext.h>
16
17
18
#include <net/iw_handler.h>
#include "core.h"
#include "nl80211.h"
19
#include "wext-compat.h"
20
#include "rdev-ops.h"
21

22
#define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
23

24
25
26
27
28
static void bss_release(struct kref *ref)
{
	struct cfg80211_internal_bss *bss;

	bss = container_of(ref, struct cfg80211_internal_bss, ref);
29
30
31
32

	if (WARN_ON(atomic_read(&bss->hold)))
		return;

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
	if (bss->pub.free_priv)
		bss->pub.free_priv(&bss->pub);

	if (bss->beacon_ies_allocated)
		kfree(bss->pub.beacon_ies);
	if (bss->proberesp_ies_allocated)
		kfree(bss->pub.proberesp_ies);

	kfree(bss);
}

/* must hold dev->bss_lock! */
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);
}

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* must hold dev->bss_lock! */
static void __cfg80211_bss_expire(struct cfg80211_registered_device *dev,
				  unsigned long expire_time)
{
	struct cfg80211_internal_bss *bss, *tmp;
	bool expired = false;

	list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) {
		if (atomic_read(&bss->hold))
			continue;
		if (!time_after(expire_time, bss->ts))
			continue;

		__cfg80211_unlink_bss(dev, bss);
		expired = true;
	}

	if (expired)
		dev->bss_generation++;
}

74
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak)
75
{
Johannes Berg's avatar
Johannes Berg committed
76
	struct cfg80211_scan_request *request;
Johannes Berg's avatar
Johannes Berg committed
77
	struct wireless_dev *wdev;
Johannes Berg's avatar
Johannes Berg committed
78
#ifdef CONFIG_CFG80211_WEXT
79
80
81
	union iwreq_data wrqu;
#endif

82
83
	ASSERT_RDEV_LOCK(rdev);

Johannes Berg's avatar
Johannes Berg committed
84
85
	request = rdev->scan_req;

86
87
88
	if (!request)
		return;

Johannes Berg's avatar
Johannes Berg committed
89
	wdev = request->wdev;
90

91
92
93
94
95
	/*
	 * This must be before sending the other events!
	 * Otherwise, wpa_supplicant gets completely confused with
	 * wext events.
	 */
Johannes Berg's avatar
Johannes Berg committed
96
97
	if (wdev->netdev)
		cfg80211_sme_scan_done(wdev->netdev);
98

99
	if (request->aborted) {
Johannes Berg's avatar
Johannes Berg committed
100
		nl80211_send_scan_aborted(rdev, wdev);
101
102
103
104
105
106
107
	} else {
		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);
		}
Johannes Berg's avatar
Johannes Berg committed
108
		nl80211_send_scan_done(rdev, wdev);
109
	}
110

Johannes Berg's avatar
Johannes Berg committed
111
#ifdef CONFIG_CFG80211_WEXT
Johannes Berg's avatar
Johannes Berg committed
112
	if (wdev->netdev && !request->aborted) {
113
114
		memset(&wrqu, 0, sizeof(wrqu));

Johannes Berg's avatar
Johannes Berg committed
115
		wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL);
116
117
118
	}
#endif

Johannes Berg's avatar
Johannes Berg committed
119
120
	if (wdev->netdev)
		dev_put(wdev->netdev);
121

122
	rdev->scan_req = NULL;
123
124
125
126
127
128
129
130
131
132
133

	/*
	 * 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);
134
}
Johannes Berg's avatar
Johannes Berg committed
135

136
137
138
139
140
141
142
143
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);
144
	___cfg80211_scan_done(rdev, false);
145
146
147
	cfg80211_unlock_rdev(rdev);
}

Johannes Berg's avatar
Johannes Berg committed
148
149
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
{
150
	trace_cfg80211_scan_done(request, aborted);
Johannes Berg's avatar
Johannes Berg committed
151
152
153
	WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);

	request->aborted = aborted;
154
	queue_work(cfg80211_wq, &wiphy_to_dev(request->wiphy)->scan_done_wk);
Johannes Berg's avatar
Johannes Berg committed
155
}
156
157
EXPORT_SYMBOL(cfg80211_scan_done);

158
159
160
void __cfg80211_sched_scan_results(struct work_struct *wk)
{
	struct cfg80211_registered_device *rdev;
161
	struct cfg80211_sched_scan_request *request;
162
163
164
165

	rdev = container_of(wk, struct cfg80211_registered_device,
			    sched_scan_results_wk);

166
167
	request = rdev->sched_scan_req;

168
	mutex_lock(&rdev->sched_scan_mtx);
169
170

	/* we don't have sched_scan_req anymore if the scan is stopping */
171
172
173
174
175
176
177
178
179
180
181
	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 + msecs_to_jiffies(request->interval);
		}
		nl80211_send_sched_scan_results(rdev, request->dev);
	}
182

183
	mutex_unlock(&rdev->sched_scan_mtx);
184
185
186
187
}

void cfg80211_sched_scan_results(struct wiphy *wiphy)
{
188
	trace_cfg80211_sched_scan_results(wiphy);
189
190
191
192
193
194
195
	/* 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);

196
void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
197
{
198
	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
199

200
201
	trace_cfg80211_sched_scan_stopped(wiphy);

202
	mutex_lock(&rdev->sched_scan_mtx);
203
	__cfg80211_stop_sched_scan(rdev, true);
204
	mutex_unlock(&rdev->sched_scan_mtx);
205
206
207
208
209
210
211
212
}
EXPORT_SYMBOL(cfg80211_sched_scan_stopped);

int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
			       bool driver_initiated)
{
	struct net_device *dev;

213
	lockdep_assert_held(&rdev->sched_scan_mtx);
214
215

	if (!rdev->sched_scan_req)
216
		return -ENOENT;
217
218
219

	dev = rdev->sched_scan_req->dev;

220
	if (!driver_initiated) {
221
		int err = rdev_sched_scan_stop(rdev, dev);
222
223
224
		if (err)
			return err;
	}
225
226
227
228
229
230

	nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);

	kfree(rdev->sched_scan_req);
	rdev->sched_scan_req = NULL;

231
	return 0;
232
233
}

234
235
236
237
238
239
240
/* must hold dev->bss_lock! */
void cfg80211_bss_age(struct cfg80211_registered_device *dev,
                      unsigned long age_secs)
{
	struct cfg80211_internal_bss *bss;
	unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);

241
	list_for_each_entry(bss, &dev->bss_list, list)
242
243
244
		bss->ts -= age_jiffies;
}

245
246
void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
{
247
	__cfg80211_bss_expire(dev, jiffies - IEEE80211_SCAN_RESULT_EXPIRE);
248
249
}

250
const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
251
{
252
	while (len > 2 && ies[0] != eid) {
253
254
255
256
257
258
259
260
261
		len -= ies[1] + 2;
		ies += ies[1] + 2;
	}
	if (len < 2)
		return NULL;
	if (len < 2 + ies[1])
		return NULL;
	return ies;
}
262
EXPORT_SYMBOL(cfg80211_find_ie);
263

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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);

291
292
static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
{
293
294
	const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
	const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
295

Johannes Berg's avatar
Johannes Berg committed
296
	/* equal if both missing */
297
298
	if (!ie1 && !ie2)
		return 0;
Johannes Berg's avatar
Johannes Berg committed
299
300
	/* sort missing IE before (left of) present IE */
	if (!ie1)
301
		return -1;
Johannes Berg's avatar
Johannes Berg committed
302
303
	if (!ie2)
		return 1;
304

Johannes Berg's avatar
Johannes Berg committed
305
306
	/* sort by length first, then by contents */
	if (ie1[1] != ie2[1])
307
		return ie2[1] - ie1[1];
Johannes Berg's avatar
Johannes Berg committed
308
	return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
309
310
}

311
static bool is_bss(struct cfg80211_bss *a, const u8 *bssid,
312
313
314
315
		   const u8 *ssid, size_t ssid_len)
{
	const u8 *ssidie;

316
	if (bssid && !ether_addr_equal(a->bssid, bssid))
317
318
		return false;

319
320
321
	if (!ssid)
		return true;

322
323
324
	ssidie = cfg80211_find_ie(WLAN_EID_SSID,
				  a->information_elements,
				  a->len_information_elements);
325
326
327
328
329
330
331
	if (!ssidie)
		return false;
	if (ssidie[1] != ssid_len)
		return false;
	return memcmp(ssidie + 2, ssid, ssid_len) == 0;
}

332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
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;
}

354
355
356
357
358
359
static bool is_mesh(struct cfg80211_bss *a,
		    const u8 *meshid, size_t meshidlen,
		    const u8 *meshcfg)
{
	const u8 *ie;

360
	if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
361
362
		return false;

363
364
365
	ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
			      a->information_elements,
			      a->len_information_elements);
366
367
368
369
370
371
372
	if (!ie)
		return false;
	if (ie[1] != meshidlen)
		return false;
	if (memcmp(ie + 2, meshid, meshidlen))
		return false;

373
374
375
	ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
			      a->information_elements,
			      a->len_information_elements);
376
377
	if (!ie)
		return false;
378
	if (ie[1] != sizeof(struct ieee80211_meshconf_ie))
379
380
381
382
383
384
385
		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.
	 */
386
	return memcmp(ie + 2, meshcfg,
387
		      sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
388
389
}

390
static int cmp_bss_core(struct cfg80211_bss *a, struct cfg80211_bss *b)
391
392
393
394
395
396
{
	int r;

	if (a->channel != b->channel)
		return b->channel->center_freq - a->channel->center_freq;

397
	if (is_mesh_bss(a) && is_mesh_bss(b)) {
398
399
400
401
402
403
404
405
406
407
408
409
410
411
		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);
	}

412
413
414
415
416
	/*
	 * we can't use compare_ether_addr here since we need a < > operator.
	 * The binary return value of compare_ether_addr isn't enough
	 */
	return memcmp(a->bssid, b->bssid, sizeof(a->bssid));
417
418
419
420
421
422
423
424
}

static int cmp_bss(struct cfg80211_bss *a,
		   struct cfg80211_bss *b)
{
	int r;

	r = cmp_bss_core(a, b);
425
426
427
	if (r)
		return r;

428
429
430
431
432
433
434
	return cmp_ies(WLAN_EID_SSID,
		       a->information_elements,
		       a->len_information_elements,
		       b->information_elements,
		       b->len_information_elements);
}

435
static int cmp_hidden_bss(struct cfg80211_bss *a, struct cfg80211_bss *b)
436
437
438
439
440
441
442
443
444
445
446
{
	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,
447
448
			       a->information_elements,
			       a->len_information_elements);
449
	ie2 = cfg80211_find_ie(WLAN_EID_SSID,
450
451
			       b->information_elements,
			       b->len_information_elements);
452

Johannes Berg's avatar
Johannes Berg committed
453
454
	/*
	 * Key comparator must use same algorithm in any rb-tree
455
456
	 * search function (order is important), otherwise ordering
	 * of items in the tree is broken and search gives incorrect
Johannes Berg's avatar
Johannes Berg committed
457
458
459
460
461
462
	 * results. This code uses same order as cmp_ies() does.
	 *
	 * Note that due to the differring behaviour with hidden SSIDs
	 * this function only works when "b" is the tree element and
	 * "a" is the key we're looking for.
	 */
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477

	/* 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];

Johannes Berg's avatar
Johannes Berg committed
478
479
480
481
482
	/*
	 * zeroed SSID ie is another indication of a hidden bss;
	 * if it isn't zeroed just return the regular sort value
	 * to find the next candidate
	 */
483
484
	for (i = 0; i < ie2[1]; i++)
		if (ie2[i + 2])
Johannes Berg's avatar
Johannes Berg committed
485
			return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
486
487
488
489

	return 0;
}

490
491
492
struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
				      struct ieee80211_channel *channel,
				      const u8 *bssid,
493
494
				      const u8 *ssid, size_t ssid_len,
				      u16 capa_mask, u16 capa_val)
495
496
497
{
	struct cfg80211_registered_device *dev = wiphy_to_dev(wiphy);
	struct cfg80211_internal_bss *bss, *res = NULL;
498
	unsigned long now = jiffies;
499

500
501
502
	trace_cfg80211_get_bss(wiphy, channel, bssid, ssid, ssid_len, capa_mask,
			       capa_val);

503
504
505
	spin_lock_bh(&dev->bss_lock);

	list_for_each_entry(bss, &dev->bss_list, list) {
506
507
		if ((bss->pub.capability & capa_mask) != capa_val)
			continue;
508
509
		if (channel && bss->pub.channel != channel)
			continue;
510
511
512
513
		/* Don't get expired BSS structs */
		if (time_after(now, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE) &&
		    !atomic_read(&bss->hold))
			continue;
514
515
516
517
518
519
520
521
522
523
		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;
524
	trace_cfg80211_return_bss(&res->pub);
525
526
527
528
529
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
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
	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;
}

609
610
static struct cfg80211_internal_bss *
rb_find_hidden_bss(struct cfg80211_registered_device *dev,
611
		   struct cfg80211_internal_bss *res)
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
{
	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,
634
		struct cfg80211_internal_bss *hidden)
635
636
637
638
639
640
641
642
643
644
645
646
647
{
	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,
648
	       res->pub.len_beacon_ies);
649
650
}

651
652
static struct cfg80211_internal_bss *
cfg80211_bss_update(struct cfg80211_registered_device *dev,
653
		    struct cfg80211_internal_bss *res)
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
{
	struct cfg80211_internal_bss *found = NULL;

	/*
	 * 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;

	spin_lock_bh(&dev->bss_lock);

	found = rb_find_bss(dev, res);

672
	if (found) {
673
674
675
676
677
		found->pub.beacon_interval = res->pub.beacon_interval;
		found->pub.tsf = res->pub.tsf;
		found->pub.signal = res->pub.signal;
		found->pub.capability = res->pub.capability;
		found->ts = res->ts;
678

679
680
		/* Update IEs */
		if (res->pub.proberesp_ies) {
681
			size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
			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;
				}
			}
706

707
708
709
710
711
712
			/* Override possible earlier Beacon frame IEs */
			found->pub.information_elements =
				found->pub.proberesp_ies;
			found->pub.len_information_elements =
				found->pub.len_proberesp_ies;
		}
713

714
715
716
		if (res->pub.beacon_ies) {
			size_t used = dev->wiphy.bss_priv_size + sizeof(*res);
			size_t ielen = res->pub.len_beacon_ies;
717
718
719
			bool information_elements_is_beacon_ies =
				(found->pub.information_elements ==
				 found->pub.beacon_ies);
720
721
722
723
724
725
726

			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;
727
			} else {
728
				u8 *ies = found->pub.beacon_ies;
729

730
				if (found->beacon_ies_allocated)
731
732
					ies = krealloc(ies, ielen, GFP_ATOMIC);
				else
733
734
735
					ies = kmalloc(ielen, GFP_ATOMIC);

				if (ies) {
736
737
738
739
740
					memcpy(ies, res->pub.beacon_ies,
					       ielen);
					found->beacon_ies_allocated = true;
					found->pub.beacon_ies = ies;
					found->pub.len_beacon_ies = ielen;
741
742
				}
			}
743
744
745
746
747
748
749
750

			/* 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;
			}
751
752
		}

753
754
		kref_put(&res->ref, bss_release);
	} else {
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
		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);

770
771
772
773
774
775
776
777
778
779
780
781
782
		/* 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;
}

783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
static struct ieee80211_channel *
cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
			 struct ieee80211_channel *channel)
{
	const u8 *tmp;
	u32 freq;
	int channel_number = -1;

	tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
	if (tmp && tmp[1] == 1) {
		channel_number = tmp[2];
	} else {
		tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
		if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
			struct ieee80211_ht_operation *htop = (void *)(tmp + 2);

			channel_number = htop->primary_chan;
		}
	}

	if (channel_number < 0)
		return channel;

	freq = ieee80211_channel_to_frequency(channel_number, channel->band);
	channel = ieee80211_get_channel(wiphy, freq);
	if (!channel)
		return NULL;
	if (channel->flags & IEEE80211_CHAN_DISABLED)
		return NULL;
	return channel;
}

815
816
817
struct cfg80211_bss*
cfg80211_inform_bss(struct wiphy *wiphy,
		    struct ieee80211_channel *channel,
818
819
		    const u8 *bssid, u64 tsf, u16 capability,
		    u16 beacon_interval, const u8 *ie, size_t ielen,
820
821
822
823
824
825
826
827
828
829
		    s32 signal, gfp_t gfp)
{
	struct cfg80211_internal_bss *res;
	size_t privsz;

	if (WARN_ON(!wiphy))
		return NULL;

	privsz = wiphy->bss_priv_size;

Sujith's avatar
Sujith committed
830
	if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
831
832
833
			(signal < 0 || signal > 100)))
		return NULL;

834
835
836
837
	channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel);
	if (!channel)
		return NULL;

838
839
840
841
842
843
844
	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;
845
	res->pub.tsf = tsf;
846
847
	res->pub.beacon_interval = beacon_interval;
	res->pub.capability = capability;
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
	/*
	 * 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;
864
865
866

	kref_init(&res->ref);

867
	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
868
869
870
871
872
873
	if (!res)
		return NULL;

	if (res->pub.capability & WLAN_CAPABILITY_ESS)
		regulatory_hint_found_beacon(wiphy, channel, gfp);

874
	trace_cfg80211_return_bss(&res->pub);
875
876
877
878
879
	/* cfg80211_bss_update gives us a referenced result */
	return &res->pub;
}
EXPORT_SYMBOL(cfg80211_inform_bss);

880
881
882
883
struct cfg80211_bss *
cfg80211_inform_bss_frame(struct wiphy *wiphy,
			  struct ieee80211_channel *channel,
			  struct ieee80211_mgmt *mgmt, size_t len,
Johannes Berg's avatar
Johannes Berg committed
884
			  s32 signal, gfp_t gfp)
885
886
887
888
{
	struct cfg80211_internal_bss *res;
	size_t ielen = len - offsetof(struct ieee80211_mgmt,
				      u.probe_resp.variable);
889
890
	size_t privsz;

891
892
893
	BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
			offsetof(struct ieee80211_mgmt, u.beacon.variable));

894
895
	trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);

896
897
898
899
900
	if (WARN_ON(!mgmt))
		return NULL;

	if (WARN_ON(!wiphy))
		return NULL;
901

Sujith's avatar
Sujith committed
902
	if (WARN_ON(wiphy->signal_type == CFG80211_SIGNAL_TYPE_UNSPEC &&
Hila Gonen's avatar
Hila Gonen committed
903
		    (signal < 0 || signal > 100)))
904
905
		return NULL;

906
	if (WARN_ON(len < offsetof(struct ieee80211_mgmt, u.probe_resp.variable)))
907
908
		return NULL;

909
910
	privsz = wiphy->bss_priv_size;

911
912
913
914
915
	channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
					   ielen, channel);
	if (!channel)
		return NULL;

916
917
918
919
920
921
922
923
924
925
	res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
	if (!res)
		return NULL;

	memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
	res->pub.channel = channel;
	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);
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
	/*
	 * 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;
	}
944
945
946

	kref_init(&res->ref);

947
	res = cfg80211_bss_update(wiphy_to_dev(wiphy), res);
948
949
950
	if (!res)
		return NULL;

951
952
953
	if (res->pub.capability & WLAN_CAPABILITY_ESS)
		regulatory_hint_found_beacon(wiphy, channel, gfp);

954
	trace_cfg80211_return_bss(&res->pub);
955
956
957
958
959
	/* cfg80211_bss_update gives us a referenced result */
	return &res->pub;
}
EXPORT_SYMBOL(cfg80211_inform_bss_frame);

960
961
962
963
964
965
966
967
968
969
970
971
void cfg80211_ref_bss(struct cfg80211_bss *pub)
{
	struct cfg80211_internal_bss *bss;

	if (!pub)
		return;

	bss = container_of(pub, struct cfg80211_internal_bss, pub);
	kref_get(&bss->ref);
}
EXPORT_SYMBOL(cfg80211_ref_bss);

972
973
974
975
976
977
978
979
980
981
982
983
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);

984
985
986
987
988
989
990
991
992
993
994
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);
995
	if (!list_empty(&bss->list)) {
996
		__cfg80211_unlink_bss(dev, bss);
997
998
		dev->bss_generation++;
	}
999
1000
	spin_unlock_bh(&dev->bss_lock);
}
For faster browsing, not all history is shown. View entire blame