util.c 56.7 KB
Newer Older
Johannes Berg's avatar
Johannes Berg committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * Copyright 2002-2005, Instant802 Networks, Inc.
 * Copyright 2005-2006, Devicescape Software, Inc.
 * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
 * Copyright 2007	Johannes Berg <johannes@sipsolutions.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * utilities for mac80211
 */

#include <net/mac80211.h>
#include <linux/netdevice.h>
16
#include <linux/export.h>
Johannes Berg's avatar
Johannes Berg committed
17
18
19
20
21
22
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/bitmap.h>
23
#include <linux/crc32.h>
24
#include <net/net_namespace.h>
Johannes Berg's avatar
Johannes Berg committed
25
#include <net/cfg80211.h>
26
#include <net/rtnetlink.h>
Johannes Berg's avatar
Johannes Berg committed
27
28

#include "ieee80211_i.h"
29
#include "driver-ops.h"
Johannes Berg's avatar
Johannes Berg committed
30
#include "rate.h"
31
#include "mesh.h"
Johannes Berg's avatar
Johannes Berg committed
32
#include "wme.h"
33
#include "led.h"
Johannes Berg's avatar
Johannes Berg committed
34
#include "wep.h"
Johannes Berg's avatar
Johannes Berg committed
35
36
37
38

/* privid for wiphys to determine whether they belong to us or not */
void *mac80211_wiphy_privid = &mac80211_wiphy_privid;

39
40
41
42
43
44
45
46
47
struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy)
{
	struct ieee80211_local *local;
	BUG_ON(!wiphy);

	local = wiphy_priv(wiphy);
	return &local->hw;
}
EXPORT_SYMBOL(wiphy_to_ieee80211_hw);
Johannes Berg's avatar
Johannes Berg committed
48

49
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
50
			enum nl80211_iftype type)
Johannes Berg's avatar
Johannes Berg committed
51
{
52
	__le16 fc = hdr->frame_control;
Johannes Berg's avatar
Johannes Berg committed
53

54
55
	 /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
	if (len < 16)
Johannes Berg's avatar
Johannes Berg committed
56
57
		return NULL;

58
	if (ieee80211_is_data(fc)) {
59
60
		if (len < 24) /* drop incorrect hdr len (data) */
			return NULL;
61
62

		if (ieee80211_has_a4(fc))
Johannes Berg's avatar
Johannes Berg committed
63
			return NULL;
64
65
66
		if (ieee80211_has_tods(fc))
			return hdr->addr1;
		if (ieee80211_has_fromds(fc))
Johannes Berg's avatar
Johannes Berg committed
67
			return hdr->addr2;
68
69
70
71
72

		return hdr->addr3;
	}

	if (ieee80211_is_mgmt(fc)) {
73
74
		if (len < 24) /* drop incorrect hdr len (mgmt) */
			return NULL;
Johannes Berg's avatar
Johannes Berg committed
75
		return hdr->addr3;
76
77
78
79
	}

	if (ieee80211_is_ctl(fc)) {
		if(ieee80211_is_pspoll(fc))
Johannes Berg's avatar
Johannes Berg committed
80
			return hdr->addr1;
81
82

		if (ieee80211_is_back_req(fc)) {
83
			switch (type) {
84
			case NL80211_IFTYPE_STATION:
85
				return hdr->addr2;
86
87
			case NL80211_IFTYPE_AP:
			case NL80211_IFTYPE_AP_VLAN:
88
89
				return hdr->addr1;
			default:
90
				break; /* fall through to the return */
91
92
			}
		}
Johannes Berg's avatar
Johannes Berg committed
93
94
95
96
97
	}

	return NULL;
}

98
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
Johannes Berg's avatar
Johannes Berg committed
99
{
100
	struct sk_buff *skb;
101
102
	struct ieee80211_hdr *hdr;

103
	skb_queue_walk(&tx->skbs, skb) {
104
105
		hdr = (struct ieee80211_hdr *) skb->data;
		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
106
	}
Johannes Berg's avatar
Johannes Berg committed
107
108
}

109
int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
Johannes Berg's avatar
Johannes Berg committed
110
111
112
113
114
115
116
117
118
119
120
121
122
			     int rate, int erp, int short_preamble)
{
	int dur;

	/* calculate duration (in microseconds, rounded up to next higher
	 * integer if it includes a fractional microsecond) to send frame of
	 * len bytes (does not include FCS) at the given rate. Duration will
	 * also include SIFS.
	 *
	 * rate is in 100 kbps, so divident is multiplied by 10 in the
	 * DIV_ROUND_UP() operations.
	 */

123
	if (band == IEEE80211_BAND_5GHZ || erp) {
Johannes Berg's avatar
Johannes Berg committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
		/*
		 * OFDM:
		 *
		 * N_DBPS = DATARATE x 4
		 * N_SYM = Ceiling((16+8xLENGTH+6) / N_DBPS)
		 *	(16 = SIGNAL time, 6 = tail bits)
		 * TXTIME = T_PREAMBLE + T_SIGNAL + T_SYM x N_SYM + Signal Ext
		 *
		 * T_SYM = 4 usec
		 * 802.11a - 17.5.2: aSIFSTime = 16 usec
		 * 802.11g - 19.8.4: aSIFSTime = 10 usec +
		 *	signal ext = 6 usec
		 */
		dur = 16; /* SIFS + signal ext */
		dur += 16; /* 17.3.2.3: T_PREAMBLE = 16 usec */
		dur += 4; /* 17.3.2.3: T_SIGNAL = 4 usec */
		dur += 4 * DIV_ROUND_UP((16 + 8 * (len + 4) + 6) * 10,
					4 * rate); /* T_SYM x N_SYM */
	} else {
		/*
		 * 802.11b or 802.11g with 802.11b compatibility:
		 * 18.3.4: TXTIME = PreambleLength + PLCPHeaderTime +
		 * Ceiling(((LENGTH+PBCC)x8)/DATARATE). PBCC=0.
		 *
		 * 802.11 (DS): 15.3.3, 802.11b: 18.3.4
		 * aSIFSTime = 10 usec
		 * aPreambleLength = 144 usec or 72 usec with short preamble
		 * aPLCPHeaderLength = 48 usec or 24 usec with short preamble
		 */
		dur = 10; /* aSIFSTime = 10 usec */
		dur += short_preamble ? (72 + 24) : (144 + 48);

		dur += DIV_ROUND_UP(8 * (len + 4) * 10, rate);
	}

	return dur;
}

/* Exported duration function for driver use */
163
164
__le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
					struct ieee80211_vif *vif,
165
					enum ieee80211_band band,
166
167
					size_t frame_len,
					struct ieee80211_rate *rate)
Johannes Berg's avatar
Johannes Berg committed
168
{
169
	struct ieee80211_sub_if_data *sdata;
Johannes Berg's avatar
Johannes Berg committed
170
171
	u16 dur;
	int erp;
172
	bool short_preamble = false;
Johannes Berg's avatar
Johannes Berg committed
173

174
	erp = 0;
175
176
	if (vif) {
		sdata = vif_to_sdata(vif);
177
		short_preamble = sdata->vif.bss_conf.use_short_preamble;
178
179
180
		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
			erp = rate->flags & IEEE80211_RATE_ERP_G;
	}
181

182
	dur = ieee80211_frame_duration(band, frame_len, rate->bitrate, erp,
183
				       short_preamble);
Johannes Berg's avatar
Johannes Berg committed
184
185
186
187
188

	return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_generic_frame_duration);

189
190
__le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
			      struct ieee80211_vif *vif, size_t frame_len,
191
			      const struct ieee80211_tx_info *frame_txctl)
Johannes Berg's avatar
Johannes Berg committed
192
193
194
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_rate *rate;
195
	struct ieee80211_sub_if_data *sdata;
196
	bool short_preamble;
Johannes Berg's avatar
Johannes Berg committed
197
198
	int erp;
	u16 dur;
199
200
	struct ieee80211_supported_band *sband;

201
	sband = local->hw.wiphy->bands[frame_txctl->band];
Johannes Berg's avatar
Johannes Berg committed
202

203
	short_preamble = false;
204

205
	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
206
207

	erp = 0;
208
209
	if (vif) {
		sdata = vif_to_sdata(vif);
210
		short_preamble = sdata->vif.bss_conf.use_short_preamble;
211
212
213
		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
			erp = rate->flags & IEEE80211_RATE_ERP_G;
	}
Johannes Berg's avatar
Johannes Berg committed
214
215

	/* CTS duration */
216
	dur = ieee80211_frame_duration(sband->band, 10, rate->bitrate,
Johannes Berg's avatar
Johannes Berg committed
217
218
				       erp, short_preamble);
	/* Data frame duration */
219
	dur += ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
Johannes Berg's avatar
Johannes Berg committed
220
221
					erp, short_preamble);
	/* ACK duration */
222
	dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
Johannes Berg's avatar
Johannes Berg committed
223
224
225
226
227
228
					erp, short_preamble);

	return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_rts_duration);

229
230
__le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
				    struct ieee80211_vif *vif,
Johannes Berg's avatar
Johannes Berg committed
231
				    size_t frame_len,
232
				    const struct ieee80211_tx_info *frame_txctl)
Johannes Berg's avatar
Johannes Berg committed
233
234
235
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_rate *rate;
236
	struct ieee80211_sub_if_data *sdata;
237
	bool short_preamble;
Johannes Berg's avatar
Johannes Berg committed
238
239
	int erp;
	u16 dur;
240
241
	struct ieee80211_supported_band *sband;

242
	sband = local->hw.wiphy->bands[frame_txctl->band];
Johannes Berg's avatar
Johannes Berg committed
243

244
	short_preamble = false;
245

246
	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
247
	erp = 0;
248
249
	if (vif) {
		sdata = vif_to_sdata(vif);
250
		short_preamble = sdata->vif.bss_conf.use_short_preamble;
251
252
253
		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
			erp = rate->flags & IEEE80211_RATE_ERP_G;
	}
Johannes Berg's avatar
Johannes Berg committed
254
255

	/* Data frame duration */
256
	dur = ieee80211_frame_duration(sband->band, frame_len, rate->bitrate,
Johannes Berg's avatar
Johannes Berg committed
257
				       erp, short_preamble);
258
	if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
Johannes Berg's avatar
Johannes Berg committed
259
		/* ACK duration */
260
		dur += ieee80211_frame_duration(sband->band, 10, rate->bitrate,
Johannes Berg's avatar
Johannes Berg committed
261
262
263
264
265
266
267
						erp, short_preamble);
	}

	return cpu_to_le16(dur);
}
EXPORT_SYMBOL(ieee80211_ctstoself_duration);

268
269
270
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
{
	struct ieee80211_sub_if_data *sdata;
271
272
273
274
	int n_acs = IEEE80211_NUM_ACS;

	if (local->hw.queues < IEEE80211_NUM_ACS)
		n_acs = 1;
275
276
277
278

	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
		int ac;

279
280
281
		if (!sdata->dev)
			continue;

282
283
284
285
286
287
288
		if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
			continue;

		if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE &&
		    local->queue_stop_reasons[sdata->vif.cab_queue] != 0)
			continue;

289
		for (ac = 0; ac < n_acs; ac++) {
290
291
292
293
294
295
296
297
298
299
300
			int ac_queue = sdata->vif.hw_queue[ac];

			if (ac_queue == queue ||
			    (sdata->vif.cab_queue == queue &&
			     local->queue_stop_reasons[ac_queue] == 0 &&
			     skb_queue_empty(&local->pending[ac_queue])))
				netif_wake_subqueue(sdata->dev, ac);
		}
	}
}

301
302
static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
				   enum queue_stop_reason reason)
Johannes Berg's avatar
Johannes Berg committed
303
304
305
{
	struct ieee80211_local *local = hw_to_local(hw);

Johannes Berg's avatar
Johannes Berg committed
306
307
	trace_wake_queue(local, queue, reason);

308
309
	if (WARN_ON(queue >= hw->queues))
		return;
310

311
312
313
	if (!test_bit(reason, &local->queue_stop_reasons[queue]))
		return;

314
315
316
317
318
319
	__clear_bit(reason, &local->queue_stop_reasons[queue]);

	if (local->queue_stop_reasons[queue] != 0)
		/* someone still has this queue stopped */
		return;

320
321
	if (skb_queue_empty(&local->pending[queue])) {
		rcu_read_lock();
322
		ieee80211_propagate_queue_wake(local, queue);
323
324
		rcu_read_unlock();
	} else
Johannes Berg's avatar
Johannes Berg committed
325
		tasklet_schedule(&local->tx_pending_tasklet);
Johannes Berg's avatar
Johannes Berg committed
326
}
327

328
329
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
				    enum queue_stop_reason reason)
330
331
332
333
334
335
336
337
338
339
340
341
342
343
{
	struct ieee80211_local *local = hw_to_local(hw);
	unsigned long flags;

	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
	__ieee80211_wake_queue(hw, queue, reason);
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
{
	ieee80211_wake_queue_by_reason(hw, queue,
				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
Johannes Berg's avatar
Johannes Berg committed
344
345
EXPORT_SYMBOL(ieee80211_wake_queue);

346
347
static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
				   enum queue_stop_reason reason)
Johannes Berg's avatar
Johannes Berg committed
348
349
{
	struct ieee80211_local *local = hw_to_local(hw);
350
	struct ieee80211_sub_if_data *sdata;
351
	int n_acs = IEEE80211_NUM_ACS;
Johannes Berg's avatar
Johannes Berg committed
352

Johannes Berg's avatar
Johannes Berg committed
353
354
	trace_stop_queue(local, queue, reason);

355
356
	if (WARN_ON(queue >= hw->queues))
		return;
357

358
359
360
	if (test_bit(reason, &local->queue_stop_reasons[queue]))
		return;

361
	__set_bit(reason, &local->queue_stop_reasons[queue]);
362

363
364
365
	if (local->hw.queues < IEEE80211_NUM_ACS)
		n_acs = 1;

366
	rcu_read_lock();
367
368
369
	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
		int ac;

370
371
372
		if (!sdata->dev)
			continue;

373
		for (ac = 0; ac < n_acs; ac++) {
374
375
376
377
378
			if (sdata->vif.hw_queue[ac] == queue ||
			    sdata->vif.cab_queue == queue)
				netif_stop_subqueue(sdata->dev, ac);
		}
	}
379
	rcu_read_unlock();
Johannes Berg's avatar
Johannes Berg committed
380
}
381

382
383
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
				    enum queue_stop_reason reason)
384
385
386
387
388
389
390
391
392
393
394
395
396
397
{
	struct ieee80211_local *local = hw_to_local(hw);
	unsigned long flags;

	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
	__ieee80211_stop_queue(hw, queue, reason);
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
{
	ieee80211_stop_queue_by_reason(hw, queue,
				       IEEE80211_QUEUE_STOP_REASON_DRIVER);
}
Johannes Berg's avatar
Johannes Berg committed
398
399
EXPORT_SYMBOL(ieee80211_stop_queue);

400
401
402
403
404
void ieee80211_add_pending_skb(struct ieee80211_local *local,
			       struct sk_buff *skb)
{
	struct ieee80211_hw *hw = &local->hw;
	unsigned long flags;
405
	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
406
	int queue = info->hw_queue;
407
408

	if (WARN_ON(!info->control.vif)) {
409
		ieee80211_free_txskb(&local->hw, skb);
410
411
		return;
	}
412
413
414

	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
	__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
Johannes Berg's avatar
Johannes Berg committed
415
	__skb_queue_tail(&local->pending[queue], skb);
416
417
418
419
	__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

420
421
422
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
				   struct sk_buff_head *skbs,
				   void (*fn)(void *data), void *data)
423
424
425
426
{
	struct ieee80211_hw *hw = &local->hw;
	struct sk_buff *skb;
	unsigned long flags;
427
	int queue, i;
428
429
430

	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
	while ((skb = skb_dequeue(skbs))) {
431
432
433
		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);

		if (WARN_ON(!info->control.vif)) {
434
			ieee80211_free_txskb(&local->hw, skb);
435
436
437
			continue;
		}

438
		queue = info->hw_queue;
439
440
441
442

		__ieee80211_stop_queue(hw, queue,
				IEEE80211_QUEUE_STOP_REASON_SKB_ADD);

Johannes Berg's avatar
Johannes Berg committed
443
		__skb_queue_tail(&local->pending[queue], skb);
444
445
	}

446
447
448
	if (fn)
		fn(data);

Johannes Berg's avatar
Johannes Berg committed
449
	for (i = 0; i < hw->queues; i++)
450
451
452
453
454
		__ieee80211_wake_queue(hw, i,
			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

455
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
456
457
				     unsigned long queues,
				     enum queue_stop_reason reason)
Johannes Berg's avatar
Johannes Berg committed
458
{
459
460
	struct ieee80211_local *local = hw_to_local(hw);
	unsigned long flags;
Johannes Berg's avatar
Johannes Berg committed
461
462
	int i;

463
464
	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);

465
	for_each_set_bit(i, &queues, hw->queues)
466
467
468
469
470
471
472
		__ieee80211_stop_queue(hw, i, reason);

	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

void ieee80211_stop_queues(struct ieee80211_hw *hw)
{
473
	ieee80211_stop_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
474
					IEEE80211_QUEUE_STOP_REASON_DRIVER);
Johannes Berg's avatar
Johannes Berg committed
475
476
477
}
EXPORT_SYMBOL(ieee80211_stop_queues);

478
479
480
int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
{
	struct ieee80211_local *local = hw_to_local(hw);
Johannes Berg's avatar
Johannes Berg committed
481
482
	unsigned long flags;
	int ret;
483

484
485
	if (WARN_ON(queue >= hw->queues))
		return true;
486

Johannes Berg's avatar
Johannes Berg committed
487
	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
488
489
	ret = test_bit(IEEE80211_QUEUE_STOP_REASON_DRIVER,
		       &local->queue_stop_reasons[queue]);
Johannes Berg's avatar
Johannes Berg committed
490
491
	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
	return ret;
492
493
494
}
EXPORT_SYMBOL(ieee80211_queue_stopped);

495
void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
496
				     unsigned long queues,
497
				     enum queue_stop_reason reason)
Johannes Berg's avatar
Johannes Berg committed
498
{
499
500
	struct ieee80211_local *local = hw_to_local(hw);
	unsigned long flags;
Johannes Berg's avatar
Johannes Berg committed
501
502
	int i;

503
504
	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);

505
	for_each_set_bit(i, &queues, hw->queues)
506
507
508
509
510
511
512
		__ieee80211_wake_queue(hw, i, reason);

	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
}

void ieee80211_wake_queues(struct ieee80211_hw *hw)
{
513
514
	ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
					IEEE80211_QUEUE_STOP_REASON_DRIVER);
Johannes Berg's avatar
Johannes Berg committed
515
516
}
EXPORT_SYMBOL(ieee80211_wake_queues);
517

518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
void ieee80211_flush_queues(struct ieee80211_local *local,
			    struct ieee80211_sub_if_data *sdata)
{
	u32 queues;

	if (!local->ops->flush)
		return;

	if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
		int ac;

		queues = 0;

		for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
			queues |= BIT(sdata->vif.hw_queue[ac]);
		if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
			queues |= BIT(sdata->vif.cab_queue);
	} else {
		/* all queues */
		queues = BIT(local->hw.queues) - 1;
	}

540
541
542
	ieee80211_stop_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
					IEEE80211_QUEUE_STOP_REASON_FLUSH);

543
	drv_flush(local, queues, false);
544
545
546

	ieee80211_wake_queues_by_reason(&local->hw, IEEE80211_MAX_QUEUE_MAP,
					IEEE80211_QUEUE_STOP_REASON_FLUSH);
547
548
}

549
void ieee80211_iterate_active_interfaces(
550
	struct ieee80211_hw *hw, u32 iter_flags,
551
552
553
	void (*iterator)(void *data, u8 *mac,
			 struct ieee80211_vif *vif),
	void *data)
554
555
556
557
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_sub_if_data *sdata;

558
	mutex_lock(&local->iflist_mtx);
559
560
561

	list_for_each_entry(sdata, &local->interfaces, list) {
		switch (sdata->vif.type) {
562
563
		case NL80211_IFTYPE_MONITOR:
		case NL80211_IFTYPE_AP_VLAN:
564
			continue;
565
		default:
566
567
			break;
		}
568
569
570
		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
			continue;
571
		if (ieee80211_sdata_running(sdata))
572
			iterator(data, sdata->vif.addr,
573
574
575
				 &sdata->vif);
	}

576
577
	sdata = rcu_dereference_protected(local->monitor_sdata,
					  lockdep_is_held(&local->iflist_mtx));
578
579
580
	if (sdata &&
	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))
581
582
		iterator(data, sdata->vif.addr, &sdata->vif);

583
	mutex_unlock(&local->iflist_mtx);
584
585
586
587
}
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);

void ieee80211_iterate_active_interfaces_atomic(
588
	struct ieee80211_hw *hw, u32 iter_flags,
589
590
591
592
593
594
595
	void (*iterator)(void *data, u8 *mac,
			 struct ieee80211_vif *vif),
	void *data)
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_sub_if_data *sdata;

596
	rcu_read_lock();
597

598
	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
599
		switch (sdata->vif.type) {
600
601
		case NL80211_IFTYPE_MONITOR:
		case NL80211_IFTYPE_AP_VLAN:
602
			continue;
603
		default:
604
605
			break;
		}
606
607
608
		if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
		    !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
			continue;
609
		if (ieee80211_sdata_running(sdata))
610
			iterator(data, sdata->vif.addr,
611
				 &sdata->vif);
612
	}
613

614
	sdata = rcu_dereference(local->monitor_sdata);
615
616
617
	if (sdata &&
	    (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
	     sdata->flags & IEEE80211_SDATA_IN_DRIVER))
618
619
		iterator(data, sdata->vif.addr, &sdata->vif);

620
	rcu_read_unlock();
621
}
622
EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
623

624
625
626
627
628
629
630
631
632
/*
 * Nothing should have been stuffed into the workqueue during
 * the suspend->resume cycle. If this WARN is seen then there
 * is a bug with either the driver suspend or something in
 * mac80211 stuffing into the workqueue which we haven't yet
 * cleared during mac80211's suspend cycle.
 */
static bool ieee80211_can_queue_work(struct ieee80211_local *local)
{
Johannes Berg's avatar
Johannes Berg committed
633
634
635
	if (WARN(local->suspended && !local->resuming,
		 "queueing ieee80211 work while going to suspend\n"))
		return false;
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663

	return true;
}

void ieee80211_queue_work(struct ieee80211_hw *hw, struct work_struct *work)
{
	struct ieee80211_local *local = hw_to_local(hw);

	if (!ieee80211_can_queue_work(local))
		return;

	queue_work(local->workqueue, work);
}
EXPORT_SYMBOL(ieee80211_queue_work);

void ieee80211_queue_delayed_work(struct ieee80211_hw *hw,
				  struct delayed_work *dwork,
				  unsigned long delay)
{
	struct ieee80211_local *local = hw_to_local(hw);

	if (!ieee80211_can_queue_work(local))
		return;

	queue_delayed_work(local->workqueue, dwork, delay);
}
EXPORT_SYMBOL(ieee80211_queue_delayed_work);

664
u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
665
666
667
668
			       struct ieee802_11_elems *elems,
			       u64 filter, u32 crc)
{
	size_t left = len;
669
	const u8 *pos = start;
670
	bool calc_crc = filter != 0;
671
	DECLARE_BITMAP(seen_elems, 256);
672
	const u8 *ie;
673

674
	bitmap_zero(seen_elems, 256);
675
676
677
678
679
680
	memset(elems, 0, sizeof(*elems));
	elems->ie_start = start;
	elems->total_len = len;

	while (left >= 2) {
		u8 id, elen;
681
		bool elem_parse_failed;
682
683
684
685
686

		id = *pos++;
		elen = *pos++;
		left -= 2;

687
688
		if (elen > left) {
			elems->parse_error = true;
689
			break;
690
691
		}

692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
		switch (id) {
		case WLAN_EID_SSID:
		case WLAN_EID_SUPP_RATES:
		case WLAN_EID_FH_PARAMS:
		case WLAN_EID_DS_PARAMS:
		case WLAN_EID_CF_PARAMS:
		case WLAN_EID_TIM:
		case WLAN_EID_IBSS_PARAMS:
		case WLAN_EID_CHALLENGE:
		case WLAN_EID_RSN:
		case WLAN_EID_ERP_INFO:
		case WLAN_EID_EXT_SUPP_RATES:
		case WLAN_EID_HT_CAPABILITY:
		case WLAN_EID_HT_OPERATION:
		case WLAN_EID_VHT_CAPABILITY:
		case WLAN_EID_VHT_OPERATION:
		case WLAN_EID_MESH_ID:
		case WLAN_EID_MESH_CONFIG:
		case WLAN_EID_PEER_MGMT:
		case WLAN_EID_PREQ:
		case WLAN_EID_PREP:
		case WLAN_EID_PERR:
		case WLAN_EID_RANN:
		case WLAN_EID_CHANNEL_SWITCH:
		case WLAN_EID_EXT_CHANSWITCH_ANN:
		case WLAN_EID_COUNTRY:
		case WLAN_EID_PWR_CONSTRAINT:
		case WLAN_EID_TIMEOUT_INTERVAL:
720
		case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
721
722
723
724
725
		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
		/*
		 * not listing WLAN_EID_CHANNEL_SWITCH_WRAPPER -- it seems possible
		 * that if the content gets bigger it might be needed more than once
		 */
726
727
728
729
730
731
732
			if (test_bit(id, seen_elems)) {
				elems->parse_error = true;
				left -= elen;
				pos += elen;
				continue;
			}
			break;
733
		}
734
735
736
737

		if (calc_crc && id < 64 && (filter & (1ULL << id)))
			crc = crc32_be(crc, pos - 2, elen + 2);

738
739
		elem_parse_failed = false;

740
741
742
743
744
745
746
747
748
749
		switch (id) {
		case WLAN_EID_SSID:
			elems->ssid = pos;
			elems->ssid_len = elen;
			break;
		case WLAN_EID_SUPP_RATES:
			elems->supp_rates = pos;
			elems->supp_rates_len = elen;
			break;
		case WLAN_EID_DS_PARAMS:
750
751
752
753
			if (elen >= 1)
				elems->ds_params = pos;
			else
				elem_parse_failed = true;
754
755
756
757
758
			break;
		case WLAN_EID_TIM:
			if (elen >= sizeof(struct ieee80211_tim_ie)) {
				elems->tim = (void *)pos;
				elems->tim_len = elen;
759
760
			} else
				elem_parse_failed = true;
761
762
763
764
765
766
767
768
769
770
771
772
773
			break;
		case WLAN_EID_CHALLENGE:
			elems->challenge = pos;
			elems->challenge_len = elen;
			break;
		case WLAN_EID_VENDOR_SPECIFIC:
			if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
			    pos[2] == 0xf2) {
				/* Microsoft OUI (00:50:F2) */

				if (calc_crc)
					crc = crc32_be(crc, pos - 2, elen + 2);

774
				if (elen >= 5 && pos[3] == 2) {
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
					/* OUI Type 2 - WMM IE */
					if (pos[4] == 0) {
						elems->wmm_info = pos;
						elems->wmm_info_len = elen;
					} else if (pos[4] == 1) {
						elems->wmm_param = pos;
						elems->wmm_param_len = elen;
					}
				}
			}
			break;
		case WLAN_EID_RSN:
			elems->rsn = pos;
			elems->rsn_len = elen;
			break;
		case WLAN_EID_ERP_INFO:
791
792
793
794
			if (elen >= 1)
				elems->erp_info = pos;
			else
				elem_parse_failed = true;
795
796
797
798
799
800
801
802
			break;
		case WLAN_EID_EXT_SUPP_RATES:
			elems->ext_supp_rates = pos;
			elems->ext_supp_rates_len = elen;
			break;
		case WLAN_EID_HT_CAPABILITY:
			if (elen >= sizeof(struct ieee80211_ht_cap))
				elems->ht_cap_elem = (void *)pos;
803
804
			else
				elem_parse_failed = true;
805
			break;
806
807
808
		case WLAN_EID_HT_OPERATION:
			if (elen >= sizeof(struct ieee80211_ht_operation))
				elems->ht_operation = (void *)pos;
809
810
			else
				elem_parse_failed = true;
811
			break;
Mahesh Palivela's avatar
Mahesh Palivela committed
812
813
814
815
816
817
818
819
820
821
822
823
		case WLAN_EID_VHT_CAPABILITY:
			if (elen >= sizeof(struct ieee80211_vht_cap))
				elems->vht_cap_elem = (void *)pos;
			else
				elem_parse_failed = true;
			break;
		case WLAN_EID_VHT_OPERATION:
			if (elen >= sizeof(struct ieee80211_vht_operation))
				elems->vht_operation = (void *)pos;
			else
				elem_parse_failed = true;
			break;
824
825
826
827
828
829
		case WLAN_EID_OPMODE_NOTIF:
			if (elen > 0)
				elems->opmode_notif = pos;
			else
				elem_parse_failed = true;
			break;
830
831
832
833
834
835
836
		case WLAN_EID_MESH_ID:
			elems->mesh_id = pos;
			elems->mesh_id_len = elen;
			break;
		case WLAN_EID_MESH_CONFIG:
			if (elen >= sizeof(struct ieee80211_meshconf_ie))
				elems->mesh_config = (void *)pos;
837
838
			else
				elem_parse_failed = true;
839
840
841
842
843
			break;
		case WLAN_EID_PEER_MGMT:
			elems->peering = pos;
			elems->peering_len = elen;
			break;
844
845
846
847
		case WLAN_EID_MESH_AWAKE_WINDOW:
			if (elen >= 2)
				elems->awake_window = (void *)pos;
			break;
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
		case WLAN_EID_PREQ:
			elems->preq = pos;
			elems->preq_len = elen;
			break;
		case WLAN_EID_PREP:
			elems->prep = pos;
			elems->prep_len = elen;
			break;
		case WLAN_EID_PERR:
			elems->perr = pos;
			elems->perr_len = elen;
			break;
		case WLAN_EID_RANN:
			if (elen >= sizeof(struct ieee80211_rann_ie))
				elems->rann = (void *)pos;
863
864
			else
				elem_parse_failed = true;
865
866
			break;
		case WLAN_EID_CHANNEL_SWITCH:
867
868
869
870
871
			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
				elem_parse_failed = true;
				break;
			}
			elems->ch_switch_ie = (void *)pos;
872
			break;
873
874
875
876
877
878
879
		case WLAN_EID_EXT_CHANSWITCH_ANN:
			if (elen != sizeof(struct ieee80211_ext_chansw_ie)) {
				elem_parse_failed = true;
				break;
			}
			elems->ext_chansw_ie = (void *)pos;
			break;
880
881
882
883
884
885
886
		case WLAN_EID_SECONDARY_CHANNEL_OFFSET:
			if (elen != sizeof(struct ieee80211_sec_chan_offs_ie)) {
				elem_parse_failed = true;
				break;
			}
			elems->sec_chan_offs = (void *)pos;
			break;
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
		case WLAN_EID_WIDE_BW_CHANNEL_SWITCH:
			if (!action ||
			    elen != sizeof(*elems->wide_bw_chansw_ie)) {
				elem_parse_failed = true;
				break;
			}
			elems->wide_bw_chansw_ie = (void *)pos;
			break;
		case WLAN_EID_CHANNEL_SWITCH_WRAPPER:
			if (action) {
				elem_parse_failed = true;
				break;
			}
			/*
			 * This is a bit tricky, but as we only care about
			 * the wide bandwidth channel switch element, so
			 * just parse it out manually.
			 */
			ie = cfg80211_find_ie(WLAN_EID_WIDE_BW_CHANNEL_SWITCH,
					      pos, elen);
			if (ie) {
				if (ie[1] == sizeof(*elems->wide_bw_chansw_ie))
					elems->wide_bw_chansw_ie =
						(void *)(ie + 2);
				else
					elem_parse_failed = true;
			}
			break;
915
916
917
918
919
		case WLAN_EID_COUNTRY:
			elems->country_elem = pos;
			elems->country_elem_len = elen;
			break;
		case WLAN_EID_PWR_CONSTRAINT:
920
921
922
923
			if (elen != 1) {
				elem_parse_failed = true;
				break;
			}
924
925
926
			elems->pwr_constr_elem = pos;
			break;
		case WLAN_EID_TIMEOUT_INTERVAL:
927
928
929
930
			if (elen >= sizeof(struct ieee80211_timeout_interval_ie))
				elems->timeout_int = (void *)pos;
			else
				elem_parse_failed = true;
931
932
933
934
935
			break;
		default:
			break;
		}

936
937
938
		if (elem_parse_failed)
			elems->parse_error = true;
		else
939
			__set_bit(id, seen_elems);
940

941
942
943
944
		left -= elen;
		pos += elen;
	}

945
946
947
	if (left != 0)
		elems->parse_error = true;

948
949
950
	return crc;
}

951
952
void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
			       bool bss_notify)
953
954
955
{
	struct ieee80211_local *local = sdata->local;
	struct ieee80211_tx_queue_params qparam;
Johannes Berg's avatar
Johannes Berg committed
956
	struct ieee80211_chanctx_conf *chanctx_conf;
957
	int ac;
958
	bool use_11b, enable_qos;
959
	int aCWmin, aCWmax;
960
961
962
963

	if (!local->ops->conf_tx)
		return;

964
965
966
	if (local->hw.queues < IEEE80211_NUM_ACS)
		return;

967
968
	memset(&qparam, 0, sizeof(qparam));

Johannes Berg's avatar
Johannes Berg committed
969
970
971
	rcu_read_lock();
	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
	use_11b = (chanctx_conf &&
972
		   chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) &&
973
		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
Johannes Berg's avatar
Johannes Berg committed
974
	rcu_read_unlock();
975

976
977
978
979
980
981
982
	/*
	 * By default disable QoS in STA mode for old access points, which do
	 * not support 802.11e. New APs will provide proper queue parameters,
	 * that we will configure later.
	 */
	enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);

983
	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
984
985
986
987
988
989
990
		/* Set defaults according to 802.11-2007 Table 7-37 */
		aCWmax = 1023;
		if (use_11b)
			aCWmin = 31;
		else
			aCWmin = 15;

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
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
		if (enable_qos) {
			switch (ac) {
			case IEEE80211_AC_BK:
				qparam.cw_max = aCWmax;
				qparam.cw_min = aCWmin;
				qparam.txop = 0;
				qparam.aifs = 7;
				break;
			/* never happens but let's not leave undefined */
			default:
			case IEEE80211_AC_BE:
				qparam.cw_max = aCWmax;
				qparam.cw_min = aCWmin;
				qparam.txop = 0;
				qparam.aifs = 3;
				break;
			case IEEE80211_AC_VI:
				qparam.cw_max = aCWmin;
				qparam.cw_min = (aCWmin + 1) / 2 - 1;
				if (use_11b)
					qparam.txop = 6016/32;
				else
					qparam.txop = 3008/32;
				qparam.aifs = 2;
				break;
			case IEEE80211_AC_VO:
				qparam.cw_max = (aCWmin + 1) / 2 - 1;
				qparam.cw_min = (aCWmin + 1) / 4 - 1;
				if (use_11b)
					qparam.txop = 3264/32;
				else
					qparam.txop = 1504/32;
				qparam.aifs = 2;
				break;
			}
		} else {
			/* Confiure old 802.11b/g medium access rules. */
1028
1029
			qparam.cw_max = aCWmax;
			qparam.cw_min = aCWmin;
1030
1031
1032
			qparam.txop = 0;
			qparam.aifs = 2;
		}
1033

1034
1035
		qparam.uapsd = false;

1036
1037
		sdata->tx_conf[ac] = qparam;
		drv_conf_tx(local, sdata, ac, &qparam);
1038
	}
1039

1040
1041
	if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE) {
1042
		sdata->vif.bss_conf.qos = enable_qos;
1043
1044
1045
		if (bss_notify)
			ieee80211_bss_info_change_notify(sdata,
							 BSS_CHANGED_QOS);
1046
	}
1047
}
1048

1049
1050
1051
1052
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
				  const size_t supp_rates_len,
				  const u8 *supp_rates)
{
Johannes Berg's avatar
Johannes Berg committed
1053
	struct ieee80211_chanctx_conf *chanctx_conf;
1054
1055
1056
1057
1058
1059
1060
	int i, have_higher_than_11mbit = 0;

	/* cf. IEEE 802.11 9.2.12 */
	for (i = 0; i < supp_rates_len; i++)
		if ((supp_rates[i] & 0x7f) * 5 > 110)
			have_higher_than_11mbit = 1;

Johannes Berg's avatar
Johannes Berg committed
1061
1062
1063
1064
	rcu_read_lock();
	chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);

	if (chanctx_conf &&
1065
	    chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ &&
1066
1067
1068
1069
	    have_higher_than_11mbit)
		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
	else
		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
Johannes Berg's avatar
Johannes Berg committed
1070
	rcu_read_unlock();
1071

1072
	ieee80211_set_wmm_default(sdata, true);
1073
1074
}

1075
u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
1076
1077
1078
1079
			      enum ieee80211_band band)
{
	struct ieee80211_supported_band *sband;
	struct ieee80211_rate *bitrates;
1080
	u32 mandatory_rates;
1081
1082
1083
1084
	enum ieee80211_rate_flags mandatory_flag;
	int i;

	sband = local->hw.wiphy->bands[band];
1085
1086
	if (WARN_ON(!sband))
		return 1;
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

	if (band == IEEE80211_BAND_2GHZ)
		mandatory_flag = IEEE80211_RATE_MANDATORY_B;
	else
		mandatory_flag = IEEE80211_RATE_MANDATORY_A;

	bitrates = sband->bitrates;
	mandatory_rates = 0;
	for (i = 0; i < sband->n_bitrates; i++)
		if (bitrates[i].flags & mandatory_flag)
			mandatory_rates |= BIT(i);
	return mandatory_rates;
}
1100
1101

void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
1102
			 u16 transaction, u16 auth_alg, u16 status,
Johannes Berg's avatar
Johannes Berg committed
1103
			 const u8 *extra, size_t extra_len, const u8 *da,
1104
1105
			 const u8 *bssid, const u8 *key, u8 key_len, u8 key_idx,
			 u32 tx_flags)
1106
1107
1108
1109
{
	struct ieee80211_local *local = sdata->local;
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt;
Johannes Berg's avatar
Johannes Berg committed
1110
	int err;
1111
1112

	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
1113
			    sizeof(*mgmt) + 6 + extra_len);
1114
	if (!skb)
1115
		return;
1116

1117
1118
1119
1120
1121
1122
	skb_reserve(skb, local->hw.extra_tx_headroom);

	mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
	memset(mgmt, 0, 24 + 6);
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
					  IEEE80211_STYPE_AUTH);
1123
	memcpy(mgmt->da, da, ETH_ALEN);
1124
	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
1125
1126
1127
	memcpy(mgmt->bssid, bssid, ETH_ALEN);
	mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
	mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
1128
	mgmt->u.auth.status_code = cpu_to_le16(status);
1129
1130
1131
	if (extra)
		memcpy(skb_put(skb, extra_len), extra, extra_len);

Johannes Berg's avatar
Johannes Berg committed
1132
1133
1134
1135
1136
1137
	if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
		mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
		err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
		WARN_ON(err);
	}

1138
1139
	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
					tx_flags;
1140
	ieee80211_tx_skb(sdata, skb);
1141
1142
}

1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
				    const u8 *bssid, u16 stype, u16 reason,
				    bool send_frame, u8 *frame_buf)
{
	struct ieee80211_local *local = sdata->local;
	struct sk_buff *skb;
	struct ieee80211_mgmt *mgmt = (void *)frame_buf;

	/* build frame */
	mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
	mgmt->duration = 0; /* initialize only */
	mgmt->seq_ctrl = 0; /* initialize only */
	memcpy(mgmt->da, bssid, ETH_ALEN);
	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
	memcpy(mgmt->bssid, bssid, ETH_ALEN);
	/* u.deauth.reason_code == u.disassoc.reason_code */
	mgmt->u.deauth.reason_code = cpu_to_le16(reason);

	if (send_frame) {
		skb = dev_alloc_skb(local->hw.extra_tx_headroom +
				    IEEE80211_DEAUTH_FRAME_LEN);
		if (!skb)
			return;

		skb_reserve(skb, local->hw.extra_tx_headroom);

		/* copy in frame */
		memcpy(skb_put(skb, IEEE80211_DEAUTH_FRAME_LEN),
		       mgmt, IEEE80211_DEAUTH_FRAME_LEN);

		if (sdata->vif.type != NL80211_IFTYPE_STATION ||
		    !(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
			IEEE80211_SKB_CB(skb)->flags |=
				IEEE80211_TX_INTFL_DONT_ENCRYPT;

		ieee80211_tx_skb(sdata, skb);
	}
}

1182
int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1183
			     size_t buffer_len, const u8 *ie, size_t ie_len,
1184
1185
			     enum ieee80211_band band, u32 rate_mask,
			     u8 channel)