Blame view

net/mac80211/util.c 42 KB
c2d1560ad   Johannes Berg   [MAC80211]: intro...
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>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
16
  #include <linux/export.h>
c2d1560ad   Johannes Berg   [MAC80211]: intro...
17
18
19
20
21
  #include <linux/types.h>
  #include <linux/slab.h>
  #include <linux/skbuff.h>
  #include <linux/etherdevice.h>
  #include <linux/if_arp.h>
c2d1560ad   Johannes Berg   [MAC80211]: intro...
22
  #include <linux/bitmap.h>
dd76986b0   Johannes Berg   cfg80211/mac80211...
23
  #include <linux/crc32.h>
881d966b4   Eric W. Biederman   [NET]: Make the d...
24
  #include <net/net_namespace.h>
c2d1560ad   Johannes Berg   [MAC80211]: intro...
25
  #include <net/cfg80211.h>
dabeb344f   Johannes Berg   mac80211: provide...
26
  #include <net/rtnetlink.h>
c2d1560ad   Johannes Berg   [MAC80211]: intro...
27
28
  
  #include "ieee80211_i.h"
244879813   Johannes Berg   mac80211: add dri...
29
  #include "driver-ops.h"
2c8dccc77   Johannes Berg   mac80211: rename ...
30
  #include "rate.h"
ee3858551   Luis Carlos Cobo   mac80211: mesh da...
31
  #include "mesh.h"
c2d1560ad   Johannes Berg   [MAC80211]: intro...
32
  #include "wme.h"
f2753ddba   Johannes Berg   mac80211: add har...
33
  #include "led.h"
fffd0934b   Johannes Berg   cfg80211: rework ...
34
  #include "wep.h"
c2d1560ad   Johannes Berg   [MAC80211]: intro...
35
36
37
  
  /* privid for wiphys to determine whether they belong to us or not */
  void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
9a95371aa   Luis R. Rodriguez   mac80211: allow m...
38
39
40
41
42
43
44
45
46
  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);
c2d1560ad   Johannes Berg   [MAC80211]: intro...
47

713647169   Ron Rindjunsky   mac80211: A-MPDU ...
48
  u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
05c914fe3   Johannes Berg   mac80211: use nl8...
49
  			enum nl80211_iftype type)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
50
  {
a494bb1ca   Harvey Harrison   mac80211: use new...
51
  	__le16 fc = hdr->frame_control;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
52

98f0b0a3a   Ron Rindjunsky   mac80211: pass in...
53
54
  	 /* drop ACK/CTS frames and incorrect hdr len (ctrl) */
  	if (len < 16)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
55
  		return NULL;
a494bb1ca   Harvey Harrison   mac80211: use new...
56
  	if (ieee80211_is_data(fc)) {
98f0b0a3a   Ron Rindjunsky   mac80211: pass in...
57
58
  		if (len < 24) /* drop incorrect hdr len (data) */
  			return NULL;
a494bb1ca   Harvey Harrison   mac80211: use new...
59
60
  
  		if (ieee80211_has_a4(fc))
c2d1560ad   Johannes Berg   [MAC80211]: intro...
61
  			return NULL;
a494bb1ca   Harvey Harrison   mac80211: use new...
62
63
64
  		if (ieee80211_has_tods(fc))
  			return hdr->addr1;
  		if (ieee80211_has_fromds(fc))
c2d1560ad   Johannes Berg   [MAC80211]: intro...
65
  			return hdr->addr2;
a494bb1ca   Harvey Harrison   mac80211: use new...
66
67
68
69
70
  
  		return hdr->addr3;
  	}
  
  	if (ieee80211_is_mgmt(fc)) {
98f0b0a3a   Ron Rindjunsky   mac80211: pass in...
71
72
  		if (len < 24) /* drop incorrect hdr len (mgmt) */
  			return NULL;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
73
  		return hdr->addr3;
a494bb1ca   Harvey Harrison   mac80211: use new...
74
75
76
77
  	}
  
  	if (ieee80211_is_ctl(fc)) {
  		if(ieee80211_is_pspoll(fc))
c2d1560ad   Johannes Berg   [MAC80211]: intro...
78
  			return hdr->addr1;
a494bb1ca   Harvey Harrison   mac80211: use new...
79
80
  
  		if (ieee80211_is_back_req(fc)) {
713647169   Ron Rindjunsky   mac80211: A-MPDU ...
81
  			switch (type) {
05c914fe3   Johannes Berg   mac80211: use nl8...
82
  			case NL80211_IFTYPE_STATION:
713647169   Ron Rindjunsky   mac80211: A-MPDU ...
83
  				return hdr->addr2;
05c914fe3   Johannes Berg   mac80211: use nl8...
84
85
  			case NL80211_IFTYPE_AP:
  			case NL80211_IFTYPE_AP_VLAN:
713647169   Ron Rindjunsky   mac80211: A-MPDU ...
86
87
  				return hdr->addr1;
  			default:
a494bb1ca   Harvey Harrison   mac80211: use new...
88
  				break; /* fall through to the return */
713647169   Ron Rindjunsky   mac80211: A-MPDU ...
89
90
  			}
  		}
c2d1560ad   Johannes Berg   [MAC80211]: intro...
91
92
93
94
  	}
  
  	return NULL;
  }
5cf121c3c   Johannes Berg   mac80211: split i...
95
  void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
96
  {
252b86c43   Johannes Berg   mac80211: use skb...
97
  	struct sk_buff *skb;
2de8e0d99   Johannes Berg   mac80211: rewrite...
98
  	struct ieee80211_hdr *hdr;
252b86c43   Johannes Berg   mac80211: use skb...
99
  	skb_queue_walk(&tx->skbs, skb) {
2de8e0d99   Johannes Berg   mac80211: rewrite...
100
101
  		hdr = (struct ieee80211_hdr *) skb->data;
  		hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
252b86c43   Johannes Berg   mac80211: use skb...
102
  	}
c2d1560ad   Johannes Berg   [MAC80211]: intro...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  }
  
  int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
  			     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.
  	 */
8318d78a4   Johannes Berg   cfg80211 API for ...
118
  	if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) {
c2d1560ad   Johannes Berg   [MAC80211]: intro...
119
120
121
122
123
124
125
126
127
128
129
130
131
  		/*
  		 * 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
  		 */
c2d1560ad   Johannes Berg   [MAC80211]: intro...
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
  		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 */
32bfd35d4   Johannes Berg   mac80211: dont us...
158
159
  __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw,
  					struct ieee80211_vif *vif,
8318d78a4   Johannes Berg   cfg80211 API for ...
160
161
  					size_t frame_len,
  					struct ieee80211_rate *rate)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
162
163
  {
  	struct ieee80211_local *local = hw_to_local(hw);
25d834e16   Johannes Berg   mac80211: fix vir...
164
  	struct ieee80211_sub_if_data *sdata;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
165
166
  	u16 dur;
  	int erp;
25d834e16   Johannes Berg   mac80211: fix vir...
167
  	bool short_preamble = false;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
168

8318d78a4   Johannes Berg   cfg80211 API for ...
169
  	erp = 0;
25d834e16   Johannes Berg   mac80211: fix vir...
170
171
  	if (vif) {
  		sdata = vif_to_sdata(vif);
bda3933a8   Johannes Berg   mac80211: move bs...
172
  		short_preamble = sdata->vif.bss_conf.use_short_preamble;
25d834e16   Johannes Berg   mac80211: fix vir...
173
174
175
  		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
  			erp = rate->flags & IEEE80211_RATE_ERP_G;
  	}
8318d78a4   Johannes Berg   cfg80211 API for ...
176
177
  
  	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp,
25d834e16   Johannes Berg   mac80211: fix vir...
178
  				       short_preamble);
c2d1560ad   Johannes Berg   [MAC80211]: intro...
179
180
181
182
  
  	return cpu_to_le16(dur);
  }
  EXPORT_SYMBOL(ieee80211_generic_frame_duration);
32bfd35d4   Johannes Berg   mac80211: dont us...
183
184
  __le16 ieee80211_rts_duration(struct ieee80211_hw *hw,
  			      struct ieee80211_vif *vif, size_t frame_len,
e039fa4a4   Johannes Berg   mac80211: move TX...
185
  			      const struct ieee80211_tx_info *frame_txctl)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
186
187
188
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct ieee80211_rate *rate;
25d834e16   Johannes Berg   mac80211: fix vir...
189
  	struct ieee80211_sub_if_data *sdata;
471b3efdf   Johannes Berg   mac80211: add uni...
190
  	bool short_preamble;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
191
192
  	int erp;
  	u16 dur;
2e92e6f2c   Johannes Berg   mac80211: use rat...
193
194
195
  	struct ieee80211_supported_band *sband;
  
  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
c2d1560ad   Johannes Berg   [MAC80211]: intro...
196

25d834e16   Johannes Berg   mac80211: fix vir...
197
  	short_preamble = false;
7e9ed1887   Daniel Drake   [MAC80211]: impro...
198

e039fa4a4   Johannes Berg   mac80211: move TX...
199
  	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
8318d78a4   Johannes Berg   cfg80211 API for ...
200
201
  
  	erp = 0;
25d834e16   Johannes Berg   mac80211: fix vir...
202
203
  	if (vif) {
  		sdata = vif_to_sdata(vif);
bda3933a8   Johannes Berg   mac80211: move bs...
204
  		short_preamble = sdata->vif.bss_conf.use_short_preamble;
25d834e16   Johannes Berg   mac80211: fix vir...
205
206
207
  		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
  			erp = rate->flags & IEEE80211_RATE_ERP_G;
  	}
c2d1560ad   Johannes Berg   [MAC80211]: intro...
208
209
  
  	/* CTS duration */
8318d78a4   Johannes Berg   cfg80211 API for ...
210
  	dur = ieee80211_frame_duration(local, 10, rate->bitrate,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
211
212
  				       erp, short_preamble);
  	/* Data frame duration */
8318d78a4   Johannes Berg   cfg80211 API for ...
213
  	dur += ieee80211_frame_duration(local, frame_len, rate->bitrate,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
214
215
  					erp, short_preamble);
  	/* ACK duration */
8318d78a4   Johannes Berg   cfg80211 API for ...
216
  	dur += ieee80211_frame_duration(local, 10, rate->bitrate,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
217
218
219
220
221
  					erp, short_preamble);
  
  	return cpu_to_le16(dur);
  }
  EXPORT_SYMBOL(ieee80211_rts_duration);
32bfd35d4   Johannes Berg   mac80211: dont us...
222
223
  __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw,
  				    struct ieee80211_vif *vif,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
224
  				    size_t frame_len,
e039fa4a4   Johannes Berg   mac80211: move TX...
225
  				    const struct ieee80211_tx_info *frame_txctl)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
226
227
228
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct ieee80211_rate *rate;
25d834e16   Johannes Berg   mac80211: fix vir...
229
  	struct ieee80211_sub_if_data *sdata;
471b3efdf   Johannes Berg   mac80211: add uni...
230
  	bool short_preamble;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
231
232
  	int erp;
  	u16 dur;
2e92e6f2c   Johannes Berg   mac80211: use rat...
233
234
235
  	struct ieee80211_supported_band *sband;
  
  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
c2d1560ad   Johannes Berg   [MAC80211]: intro...
236

25d834e16   Johannes Berg   mac80211: fix vir...
237
  	short_preamble = false;
7e9ed1887   Daniel Drake   [MAC80211]: impro...
238

e039fa4a4   Johannes Berg   mac80211: move TX...
239
  	rate = &sband->bitrates[frame_txctl->control.rts_cts_rate_idx];
8318d78a4   Johannes Berg   cfg80211 API for ...
240
  	erp = 0;
25d834e16   Johannes Berg   mac80211: fix vir...
241
242
  	if (vif) {
  		sdata = vif_to_sdata(vif);
bda3933a8   Johannes Berg   mac80211: move bs...
243
  		short_preamble = sdata->vif.bss_conf.use_short_preamble;
25d834e16   Johannes Berg   mac80211: fix vir...
244
245
246
  		if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)
  			erp = rate->flags & IEEE80211_RATE_ERP_G;
  	}
c2d1560ad   Johannes Berg   [MAC80211]: intro...
247
248
  
  	/* Data frame duration */
8318d78a4   Johannes Berg   cfg80211 API for ...
249
  	dur = ieee80211_frame_duration(local, frame_len, rate->bitrate,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
250
  				       erp, short_preamble);
e039fa4a4   Johannes Berg   mac80211: move TX...
251
  	if (!(frame_txctl->flags & IEEE80211_TX_CTL_NO_ACK)) {
c2d1560ad   Johannes Berg   [MAC80211]: intro...
252
  		/* ACK duration */
8318d78a4   Johannes Berg   cfg80211 API for ...
253
  		dur += ieee80211_frame_duration(local, 10, rate->bitrate,
c2d1560ad   Johannes Berg   [MAC80211]: intro...
254
255
256
257
258
259
  						erp, short_preamble);
  	}
  
  	return cpu_to_le16(dur);
  }
  EXPORT_SYMBOL(ieee80211_ctstoself_duration);
ce7c9111a   Kalle Valo   mac80211: track m...
260
261
  static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
  				   enum queue_stop_reason reason)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
262
263
  {
  	struct ieee80211_local *local = hw_to_local(hw);
cf0277e71   Johannes Berg   mac80211: fix skb...
264
  	struct ieee80211_sub_if_data *sdata;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
265

b5878a2dc   Johannes Berg   mac80211: enhance...
266
  	trace_wake_queue(local, queue, reason);
e4e72fb4d   Johannes Berg   mac80211/iwlwifi:...
267
268
  	if (WARN_ON(queue >= hw->queues))
  		return;
ce7c9111a   Kalle Valo   mac80211: track m...
269

96f5e66e8   Johannes Berg   mac80211: fix agg...
270
271
272
273
274
  	__clear_bit(reason, &local->queue_stop_reasons[queue]);
  
  	if (local->queue_stop_reasons[queue] != 0)
  		/* someone still has this queue stopped */
  		return;
7236fe29f   Johannes Berg   mac80211: move ne...
275
276
  	if (skb_queue_empty(&local->pending[queue])) {
  		rcu_read_lock();
5b714c6a3   Johannes Berg   mac80211: fix off...
277
278
279
  		list_for_each_entry_rcu(sdata, &local->interfaces, list) {
  			if (test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
  				continue;
2337db8db   Johannes Berg   mac80211: use sub...
280
  			netif_wake_subqueue(sdata->dev, queue);
5b714c6a3   Johannes Berg   mac80211: fix off...
281
  		}
7236fe29f   Johannes Berg   mac80211: move ne...
282
283
  		rcu_read_unlock();
  	} else
3b8d81e02   Johannes Berg   mac80211: remove ...
284
  		tasklet_schedule(&local->tx_pending_tasklet);
c2d1560ad   Johannes Berg   [MAC80211]: intro...
285
  }
ce7c9111a   Kalle Valo   mac80211: track m...
286

96f5e66e8   Johannes Berg   mac80211: fix agg...
287
288
  void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
  				    enum queue_stop_reason reason)
ce7c9111a   Kalle Valo   mac80211: track m...
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  {
  	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);
  }
c2d1560ad   Johannes Berg   [MAC80211]: intro...
303
  EXPORT_SYMBOL(ieee80211_wake_queue);
ce7c9111a   Kalle Valo   mac80211: track m...
304
305
  static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
  				   enum queue_stop_reason reason)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
306
307
  {
  	struct ieee80211_local *local = hw_to_local(hw);
cf0277e71   Johannes Berg   mac80211: fix skb...
308
  	struct ieee80211_sub_if_data *sdata;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
309

b5878a2dc   Johannes Berg   mac80211: enhance...
310
  	trace_stop_queue(local, queue, reason);
e4e72fb4d   Johannes Berg   mac80211/iwlwifi:...
311
312
  	if (WARN_ON(queue >= hw->queues))
  		return;
96f5e66e8   Johannes Berg   mac80211: fix agg...
313

2a577d987   Johannes Berg   mac80211: rework ...
314
  	__set_bit(reason, &local->queue_stop_reasons[queue]);
cf0277e71   Johannes Berg   mac80211: fix skb...
315
316
317
  
  	rcu_read_lock();
  	list_for_each_entry_rcu(sdata, &local->interfaces, list)
2337db8db   Johannes Berg   mac80211: use sub...
318
  		netif_stop_subqueue(sdata->dev, queue);
cf0277e71   Johannes Berg   mac80211: fix skb...
319
  	rcu_read_unlock();
c2d1560ad   Johannes Berg   [MAC80211]: intro...
320
  }
ce7c9111a   Kalle Valo   mac80211: track m...
321

96f5e66e8   Johannes Berg   mac80211: fix agg...
322
323
  void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
  				    enum queue_stop_reason reason)
ce7c9111a   Kalle Valo   mac80211: track m...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
  {
  	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);
  }
c2d1560ad   Johannes Berg   [MAC80211]: intro...
338
  EXPORT_SYMBOL(ieee80211_stop_queue);
8f77f3849   Johannes Berg   mac80211: do not ...
339
340
341
342
343
344
  void ieee80211_add_pending_skb(struct ieee80211_local *local,
  			       struct sk_buff *skb)
  {
  	struct ieee80211_hw *hw = &local->hw;
  	unsigned long flags;
  	int queue = skb_get_queue_mapping(skb);
a7bc376c8   Johannes Berg   mac80211: verify ...
345
346
347
  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  
  	if (WARN_ON(!info->control.vif)) {
0819663d1   Roel Kluin   mac80211: use kfr...
348
  		kfree_skb(skb);
a7bc376c8   Johannes Berg   mac80211: verify ...
349
350
  		return;
  	}
8f77f3849   Johannes Berg   mac80211: do not ...
351
352
353
  
  	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
  	__ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
3b8d81e02   Johannes Berg   mac80211: remove ...
354
  	__skb_queue_tail(&local->pending[queue], skb);
8f77f3849   Johannes Berg   mac80211: do not ...
355
356
357
  	__ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
  	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
  }
b0b97a8ad   Johannes Berg   mac80211: remove ...
358
359
360
  void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
  				   struct sk_buff_head *skbs,
  				   void (*fn)(void *data), void *data)
8f77f3849   Johannes Berg   mac80211: do not ...
361
362
363
364
  {
  	struct ieee80211_hw *hw = &local->hw;
  	struct sk_buff *skb;
  	unsigned long flags;
b0b97a8ad   Johannes Berg   mac80211: remove ...
365
  	int queue, i;
8f77f3849   Johannes Berg   mac80211: do not ...
366
367
368
369
370
371
372
  
  	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
  	for (i = 0; i < hw->queues; i++)
  		__ieee80211_stop_queue(hw, i,
  			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
  
  	while ((skb = skb_dequeue(skbs))) {
a7bc376c8   Johannes Berg   mac80211: verify ...
373
374
375
  		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
  
  		if (WARN_ON(!info->control.vif)) {
0819663d1   Roel Kluin   mac80211: use kfr...
376
  			kfree_skb(skb);
a7bc376c8   Johannes Berg   mac80211: verify ...
377
378
  			continue;
  		}
8f77f3849   Johannes Berg   mac80211: do not ...
379
  		queue = skb_get_queue_mapping(skb);
3b8d81e02   Johannes Berg   mac80211: remove ...
380
  		__skb_queue_tail(&local->pending[queue], skb);
8f77f3849   Johannes Berg   mac80211: do not ...
381
  	}
50a9432da   Johannes Berg   mac80211: fix pow...
382
383
  	if (fn)
  		fn(data);
3b8d81e02   Johannes Berg   mac80211: remove ...
384
  	for (i = 0; i < hw->queues; i++)
8f77f3849   Johannes Berg   mac80211: do not ...
385
386
  		__ieee80211_wake_queue(hw, i,
  			IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
8f77f3849   Johannes Berg   mac80211: do not ...
387
  	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
8f77f3849   Johannes Berg   mac80211: do not ...
388
  }
b0b97a8ad   Johannes Berg   mac80211: remove ...
389
390
  void ieee80211_add_pending_skbs(struct ieee80211_local *local,
  				struct sk_buff_head *skbs)
50a9432da   Johannes Berg   mac80211: fix pow...
391
  {
b0b97a8ad   Johannes Berg   mac80211: remove ...
392
  	ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
50a9432da   Johannes Berg   mac80211: fix pow...
393
  }
ce7c9111a   Kalle Valo   mac80211: track m...
394
395
  void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
  				    enum queue_stop_reason reason)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
396
  {
ce7c9111a   Kalle Valo   mac80211: track m...
397
398
  	struct ieee80211_local *local = hw_to_local(hw);
  	unsigned long flags;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
399
  	int i;
ce7c9111a   Kalle Valo   mac80211: track m...
400
  	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
96f5e66e8   Johannes Berg   mac80211: fix agg...
401
  	for (i = 0; i < hw->queues; i++)
ce7c9111a   Kalle Valo   mac80211: track m...
402
403
404
405
406
407
408
409
410
  		__ieee80211_stop_queue(hw, i, reason);
  
  	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
  }
  
  void ieee80211_stop_queues(struct ieee80211_hw *hw)
  {
  	ieee80211_stop_queues_by_reason(hw,
  					IEEE80211_QUEUE_STOP_REASON_DRIVER);
c2d1560ad   Johannes Berg   [MAC80211]: intro...
411
412
  }
  EXPORT_SYMBOL(ieee80211_stop_queues);
92ab85354   Tomas Winkler   mac80211: add iee...
413
414
415
  int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
3b8d81e02   Johannes Berg   mac80211: remove ...
416
417
  	unsigned long flags;
  	int ret;
96f5e66e8   Johannes Berg   mac80211: fix agg...
418

e4e72fb4d   Johannes Berg   mac80211/iwlwifi:...
419
420
  	if (WARN_ON(queue >= hw->queues))
  		return true;
96f5e66e8   Johannes Berg   mac80211: fix agg...
421

3b8d81e02   Johannes Berg   mac80211: remove ...
422
423
424
425
  	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
  	ret = !!local->queue_stop_reasons[queue];
  	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
  	return ret;
92ab85354   Tomas Winkler   mac80211: add iee...
426
427
  }
  EXPORT_SYMBOL(ieee80211_queue_stopped);
ce7c9111a   Kalle Valo   mac80211: track m...
428
429
  void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
  				     enum queue_stop_reason reason)
c2d1560ad   Johannes Berg   [MAC80211]: intro...
430
  {
ce7c9111a   Kalle Valo   mac80211: track m...
431
432
  	struct ieee80211_local *local = hw_to_local(hw);
  	unsigned long flags;
c2d1560ad   Johannes Berg   [MAC80211]: intro...
433
  	int i;
ce7c9111a   Kalle Valo   mac80211: track m...
434
  	spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
e4e72fb4d   Johannes Berg   mac80211/iwlwifi:...
435
  	for (i = 0; i < hw->queues; i++)
ce7c9111a   Kalle Valo   mac80211: track m...
436
437
438
439
440
441
442
443
  		__ieee80211_wake_queue(hw, i, reason);
  
  	spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
  }
  
  void ieee80211_wake_queues(struct ieee80211_hw *hw)
  {
  	ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER);
c2d1560ad   Johannes Berg   [MAC80211]: intro...
444
445
  }
  EXPORT_SYMBOL(ieee80211_wake_queues);
dabeb344f   Johannes Berg   mac80211: provide...
446

32bfd35d4   Johannes Berg   mac80211: dont us...
447
448
449
450
451
  void ieee80211_iterate_active_interfaces(
  	struct ieee80211_hw *hw,
  	void (*iterator)(void *data, u8 *mac,
  			 struct ieee80211_vif *vif),
  	void *data)
dabeb344f   Johannes Berg   mac80211: provide...
452
453
454
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct ieee80211_sub_if_data *sdata;
c771c9d8d   Johannes Berg   mac80211: add int...
455
  	mutex_lock(&local->iflist_mtx);
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
456
457
458
  
  	list_for_each_entry(sdata, &local->interfaces, list) {
  		switch (sdata->vif.type) {
05c914fe3   Johannes Berg   mac80211: use nl8...
459
460
  		case NL80211_IFTYPE_MONITOR:
  		case NL80211_IFTYPE_AP_VLAN:
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
461
  			continue;
2ca27bcff   Johannes Berg   mac80211: add p2p...
462
  		default:
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
463
464
  			break;
  		}
9607e6b66   Johannes Berg   mac80211: add iee...
465
  		if (ieee80211_sdata_running(sdata))
47846c9b0   Johannes Berg   mac80211: reduce ...
466
  			iterator(data, sdata->vif.addr,
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
467
468
  				 &sdata->vif);
  	}
c771c9d8d   Johannes Berg   mac80211: add int...
469
  	mutex_unlock(&local->iflist_mtx);
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
470
471
472
473
474
475
476
477
478
479
480
  }
  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
  
  void ieee80211_iterate_active_interfaces_atomic(
  	struct ieee80211_hw *hw,
  	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;
e38bad476   Johannes Berg   mac80211: make ie...
481
  	rcu_read_lock();
dabeb344f   Johannes Berg   mac80211: provide...
482

e38bad476   Johannes Berg   mac80211: make ie...
483
  	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
51fb61e76   Johannes Berg   mac80211: move in...
484
  		switch (sdata->vif.type) {
05c914fe3   Johannes Berg   mac80211: use nl8...
485
486
  		case NL80211_IFTYPE_MONITOR:
  		case NL80211_IFTYPE_AP_VLAN:
dabeb344f   Johannes Berg   mac80211: provide...
487
  			continue;
2ca27bcff   Johannes Berg   mac80211: add p2p...
488
  		default:
dabeb344f   Johannes Berg   mac80211: provide...
489
490
  			break;
  		}
9607e6b66   Johannes Berg   mac80211: add iee...
491
  		if (ieee80211_sdata_running(sdata))
47846c9b0   Johannes Berg   mac80211: reduce ...
492
  			iterator(data, sdata->vif.addr,
32bfd35d4   Johannes Berg   mac80211: dont us...
493
  				 &sdata->vif);
dabeb344f   Johannes Berg   mac80211: provide...
494
  	}
e38bad476   Johannes Berg   mac80211: make ie...
495
496
  
  	rcu_read_unlock();
dabeb344f   Johannes Berg   mac80211: provide...
497
  }
2f561feb3   Ivo van Doorn   mac80211: Add RTN...
498
  EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
37ffc8da8   Johannes Berg   mac80211: move IE...
499

42935ecaf   Luis R. Rodriguez   mac80211: redefin...
500
501
502
503
504
505
506
507
508
  /*
   * 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)
  {
ceb99fe07   Johannes Berg   mac80211: fix resume
509
510
511
512
  	if (WARN(local->suspended && !local->resuming,
  		 "queueing ieee80211 work while going to suspend
  "))
  		return false;
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
  
  	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);
dd76986b0   Johannes Berg   cfg80211/mac80211...
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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
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
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
  u32 ieee802_11_parse_elems_crc(u8 *start, size_t len,
  			       struct ieee802_11_elems *elems,
  			       u64 filter, u32 crc)
  {
  	size_t left = len;
  	u8 *pos = start;
  	bool calc_crc = filter != 0;
  
  	memset(elems, 0, sizeof(*elems));
  	elems->ie_start = start;
  	elems->total_len = len;
  
  	while (left >= 2) {
  		u8 id, elen;
  
  		id = *pos++;
  		elen = *pos++;
  		left -= 2;
  
  		if (elen > left)
  			break;
  
  		if (calc_crc && id < 64 && (filter & (1ULL << id)))
  			crc = crc32_be(crc, pos - 2, elen + 2);
  
  		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_FH_PARAMS:
  			elems->fh_params = pos;
  			elems->fh_params_len = elen;
  			break;
  		case WLAN_EID_DS_PARAMS:
  			elems->ds_params = pos;
  			elems->ds_params_len = elen;
  			break;
  		case WLAN_EID_CF_PARAMS:
  			elems->cf_params = pos;
  			elems->cf_params_len = elen;
  			break;
  		case WLAN_EID_TIM:
  			if (elen >= sizeof(struct ieee80211_tim_ie)) {
  				elems->tim = (void *)pos;
  				elems->tim_len = elen;
  			}
  			break;
  		case WLAN_EID_IBSS_PARAMS:
  			elems->ibss_params = pos;
  			elems->ibss_params_len = elen;
  			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);
  
  				if (pos[3] == 1) {
  					/* OUI Type 1 - WPA IE */
  					elems->wpa = pos;
  					elems->wpa_len = elen;
  				} else if (elen >= 5 && pos[3] == 2) {
  					/* 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:
  			elems->erp_info = pos;
  			elems->erp_info_len = elen;
  			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;
  			break;
  		case WLAN_EID_HT_INFORMATION:
  			if (elen >= sizeof(struct ieee80211_ht_info))
  				elems->ht_info_elem = (void *)pos;
  			break;
  		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;
  			break;
  		case WLAN_EID_PEER_MGMT:
  			elems->peering = pos;
  			elems->peering_len = elen;
  			break;
  		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;
  			break;
  		case WLAN_EID_CHANNEL_SWITCH:
  			elems->ch_switch_elem = pos;
  			elems->ch_switch_elem_len = elen;
  			break;
  		case WLAN_EID_QUIET:
  			if (!elems->quiet_elem) {
  				elems->quiet_elem = pos;
  				elems->quiet_elem_len = elen;
  			}
  			elems->num_of_quiet_elem++;
  			break;
  		case WLAN_EID_COUNTRY:
  			elems->country_elem = pos;
  			elems->country_elem_len = elen;
  			break;
  		case WLAN_EID_PWR_CONSTRAINT:
  			elems->pwr_constr_elem = pos;
  			elems->pwr_constr_elem_len = elen;
  			break;
  		case WLAN_EID_TIMEOUT_INTERVAL:
  			elems->timeout_int = pos;
  			elems->timeout_int_len = elen;
  			break;
  		default:
  			break;
  		}
  
  		left -= elen;
  		pos += elen;
  	}
  
  	return crc;
  }
37ffc8da8   Johannes Berg   mac80211: move IE...
705
706
707
  void ieee802_11_parse_elems(u8 *start, size_t len,
  			    struct ieee802_11_elems *elems)
  {
d91f36db5   Johannes Berg   mac80211: impleme...
708
709
  	ieee802_11_parse_elems_crc(start, len, elems, 0, 0);
  }
5825fe100   Johannes Berg   mac80211: initial...
710
711
712
713
  void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
  {
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_tx_queue_params qparam;
aa837e1d6   Johannes Berg   mac80211: set def...
714
715
716
  	int queue;
  	bool use_11b;
  	int aCWmin, aCWmax;
5825fe100   Johannes Berg   mac80211: initial...
717
718
719
720
721
  
  	if (!local->ops->conf_tx)
  		return;
  
  	memset(&qparam, 0, sizeof(qparam));
aa837e1d6   Johannes Berg   mac80211: set def...
722
723
  	use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
  		 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
5825fe100   Johannes Berg   mac80211: initial...
724

aa837e1d6   Johannes Berg   mac80211: set def...
725
726
727
728
729
730
731
732
733
734
  	for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
  		/* Set defaults according to 802.11-2007 Table 7-37 */
  		aCWmax = 1023;
  		if (use_11b)
  			aCWmin = 31;
  		else
  			aCWmin = 15;
  
  		switch (queue) {
  		case 3: /* AC_BK */
7ba10a8ef   Johannes Berg   mac80211: fix tra...
735
736
  			qparam.cw_max = aCWmax;
  			qparam.cw_min = aCWmin;
aa837e1d6   Johannes Berg   mac80211: set def...
737
738
739
740
741
  			qparam.txop = 0;
  			qparam.aifs = 7;
  			break;
  		default: /* never happens but let's not leave undefined */
  		case 2: /* AC_BE */
7ba10a8ef   Johannes Berg   mac80211: fix tra...
742
743
  			qparam.cw_max = aCWmax;
  			qparam.cw_min = aCWmin;
aa837e1d6   Johannes Berg   mac80211: set def...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
  			qparam.txop = 0;
  			qparam.aifs = 3;
  			break;
  		case 1: /* 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 0: /* 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;
  		}
5825fe100   Johannes Berg   mac80211: initial...
766

ab13315af   Kalle Valo   mac80211: add U-A...
767
  		qparam.uapsd = false;
f6f3def32   Eliad Peller   mac80211: save tx...
768
769
  		sdata->tx_conf[queue] = qparam;
  		drv_conf_tx(local, sdata, queue, &qparam);
aa837e1d6   Johannes Berg   mac80211: set def...
770
  	}
e1b3ec1a2   Stanislaw Gruszka   mac80211: explici...
771
772
773
  
  	/* after reinitialize QoS TX queues setting to default,
  	 * disable QoS at all */
d97349797   Sujith   mac80211: Don't s...
774
775
776
777
778
779
  
  	if (sdata->vif.type != NL80211_IFTYPE_MONITOR) {
  		sdata->vif.bss_conf.qos =
  			sdata->vif.type != NL80211_IFTYPE_STATION;
  		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS);
  	}
5825fe100   Johannes Berg   mac80211: initial...
780
  }
e50db65c0   Johannes Berg   mac80211: move fr...
781

469002983   Johannes Berg   mac80211: split I...
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
  				  const size_t supp_rates_len,
  				  const u8 *supp_rates)
  {
  	struct ieee80211_local *local = sdata->local;
  	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;
  
  	if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
  	    have_higher_than_11mbit)
  		sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
  	else
  		sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
  
  	ieee80211_set_wmm_default(sdata);
  }
881d948c2   Johannes Berg   wireless: restric...
802
  u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
96dd22ac0   Johannes Berg   mac80211: inform ...
803
804
805
806
  			      enum ieee80211_band band)
  {
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_rate *bitrates;
881d948c2   Johannes Berg   wireless: restric...
807
  	u32 mandatory_rates;
96dd22ac0   Johannes Berg   mac80211: inform ...
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
  	enum ieee80211_rate_flags mandatory_flag;
  	int i;
  
  	sband = local->hw.wiphy->bands[band];
  	if (!sband) {
  		WARN_ON(1);
  		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  	}
  
  	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;
  }
469002983   Johannes Berg   mac80211: split I...
829
830
831
  
  void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
  			 u16 transaction, u16 auth_alg,
fffd0934b   Johannes Berg   cfg80211: rework ...
832
833
  			 u8 *extra, size_t extra_len, const u8 *bssid,
  			 const u8 *key, u8 key_len, u8 key_idx)
469002983   Johannes Berg   mac80211: split I...
834
835
836
837
  {
  	struct ieee80211_local *local = sdata->local;
  	struct sk_buff *skb;
  	struct ieee80211_mgmt *mgmt;
fffd0934b   Johannes Berg   cfg80211: rework ...
838
  	int err;
469002983   Johannes Berg   mac80211: split I...
839
840
  
  	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
65fc73ac4   Jouni Malinen   nl80211: Remove N...
841
  			    sizeof(*mgmt) + 6 + extra_len);
d15b84590   Joe Perches   mac80211: Remove ...
842
  	if (!skb)
469002983   Johannes Berg   mac80211: split I...
843
  		return;
d15b84590   Joe Perches   mac80211: Remove ...
844

469002983   Johannes Berg   mac80211: split I...
845
846
847
848
849
850
  	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);
469002983   Johannes Berg   mac80211: split I...
851
  	memcpy(mgmt->da, bssid, ETH_ALEN);
47846c9b0   Johannes Berg   mac80211: reduce ...
852
  	memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
469002983   Johannes Berg   mac80211: split I...
853
854
855
856
857
858
  	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);
  	mgmt->u.auth.status_code = cpu_to_le16(0);
  	if (extra)
  		memcpy(skb_put(skb, extra_len), extra, extra_len);
469002983   Johannes Berg   mac80211: split I...
859

fffd0934b   Johannes Berg   cfg80211: rework ...
860
861
862
863
864
  	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);
  	}
62ae67be3   Johannes Berg   mac80211: remove ...
865
866
  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
  	ieee80211_tx_skb(sdata, skb);
469002983   Johannes Berg   mac80211: split I...
867
  }
de95a54b1   Johannes Berg   mac80211: pass al...
868
  int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
4d36ec582   Johannes Berg   mac80211: split h...
869
  			     const u8 *ie, size_t ie_len,
651b52254   Jouni Malinen   mac80211: Add DS ...
870
871
  			     enum ieee80211_band band, u32 rate_mask,
  			     u8 channel)
de95a54b1   Johannes Berg   mac80211: pass al...
872
873
  {
  	struct ieee80211_supported_band *sband;
8e664fb3f   Johannes Berg   mac80211: split u...
874
875
876
  	u8 *pos;
  	size_t offset = 0, noffset;
  	int supp_rates_len, i;
8dcb20038   Jouni Malinen   mac80211: Filter ...
877
878
879
  	u8 rates[32];
  	int num_rates;
  	int ext_rates_len;
de95a54b1   Johannes Berg   mac80211: pass al...
880

4d36ec582   Johannes Berg   mac80211: split h...
881
  	sband = local->hw.wiphy->bands[band];
de95a54b1   Johannes Berg   mac80211: pass al...
882
883
  
  	pos = buffer;
8dcb20038   Jouni Malinen   mac80211: Filter ...
884
885
886
887
888
889
890
891
  	num_rates = 0;
  	for (i = 0; i < sband->n_bitrates; i++) {
  		if ((BIT(i) & rate_mask) == 0)
  			continue; /* skip rate */
  		rates[num_rates++] = (u8) (sband->bitrates[i].bitrate / 5);
  	}
  
  	supp_rates_len = min_t(int, num_rates, 8);
8e664fb3f   Johannes Berg   mac80211: split u...
892

de95a54b1   Johannes Berg   mac80211: pass al...
893
  	*pos++ = WLAN_EID_SUPP_RATES;
8e664fb3f   Johannes Berg   mac80211: split u...
894
  	*pos++ = supp_rates_len;
8dcb20038   Jouni Malinen   mac80211: Filter ...
895
896
  	memcpy(pos, rates, supp_rates_len);
  	pos += supp_rates_len;
8e664fb3f   Johannes Berg   mac80211: split u...
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
  
  	/* insert "request information" if in custom IEs */
  	if (ie && ie_len) {
  		static const u8 before_extrates[] = {
  			WLAN_EID_SSID,
  			WLAN_EID_SUPP_RATES,
  			WLAN_EID_REQUEST,
  		};
  		noffset = ieee80211_ie_split(ie, ie_len,
  					     before_extrates,
  					     ARRAY_SIZE(before_extrates),
  					     offset);
  		memcpy(pos, ie + offset, noffset - offset);
  		pos += noffset - offset;
  		offset = noffset;
  	}
8dcb20038   Jouni Malinen   mac80211: Filter ...
913
914
  	ext_rates_len = num_rates - supp_rates_len;
  	if (ext_rates_len > 0) {
8e664fb3f   Johannes Berg   mac80211: split u...
915
  		*pos++ = WLAN_EID_EXT_SUPP_RATES;
8dcb20038   Jouni Malinen   mac80211: Filter ...
916
917
918
  		*pos++ = ext_rates_len;
  		memcpy(pos, rates + supp_rates_len, ext_rates_len);
  		pos += ext_rates_len;
8e664fb3f   Johannes Berg   mac80211: split u...
919
  	}
651b52254   Jouni Malinen   mac80211: Add DS ...
920
921
922
923
924
  	if (channel && sband->band == IEEE80211_BAND_2GHZ) {
  		*pos++ = WLAN_EID_DS_PARAMS;
  		*pos++ = 1;
  		*pos++ = channel;
  	}
8e664fb3f   Johannes Berg   mac80211: split u...
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
  	/* insert custom IEs that go before HT */
  	if (ie && ie_len) {
  		static const u8 before_ht[] = {
  			WLAN_EID_SSID,
  			WLAN_EID_SUPP_RATES,
  			WLAN_EID_REQUEST,
  			WLAN_EID_EXT_SUPP_RATES,
  			WLAN_EID_DS_PARAMS,
  			WLAN_EID_SUPPORTED_REGULATORY_CLASSES,
  		};
  		noffset = ieee80211_ie_split(ie, ie_len,
  					     before_ht, ARRAY_SIZE(before_ht),
  					     offset);
  		memcpy(pos, ie + offset, noffset - offset);
  		pos += noffset - offset;
  		offset = noffset;
de95a54b1   Johannes Berg   mac80211: pass al...
941
  	}
42e7aa771   Alexander Simon   mac80211: Add HT ...
942
  	if (sband->ht_cap.ht_supported)
ef96a8420   Ben Greear   mac80211: Support...
943
944
  		pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap,
  						sband->ht_cap.cap);
5ef2d41af   Johannes Berg   mac80211: include...
945

de95a54b1   Johannes Berg   mac80211: pass al...
946
947
948
949
  	/*
  	 * If adding more here, adjust code in main.c
  	 * that calculates local->scan_ies_len.
  	 */
8e664fb3f   Johannes Berg   mac80211: split u...
950
951
952
953
954
  	/* add any remaining custom IEs */
  	if (ie && ie_len) {
  		noffset = ie_len;
  		memcpy(pos, ie + offset, noffset - offset);
  		pos += noffset - offset;
de95a54b1   Johannes Berg   mac80211: pass al...
955
956
957
958
  	}
  
  	return pos - buffer;
  }
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
959
  struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
85a237fe3   Johannes Berg   mac80211: impleme...
960
  					  u8 *dst, u32 ratemask,
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
961
  					  const u8 *ssid, size_t ssid_len,
a806c558e   Paul Stewart   mac80211: Drop DS...
962
963
  					  const u8 *ie, size_t ie_len,
  					  bool directed)
469002983   Johannes Berg   mac80211: split I...
964
965
  {
  	struct ieee80211_local *local = sdata->local;
469002983   Johannes Berg   mac80211: split I...
966
967
  	struct sk_buff *skb;
  	struct ieee80211_mgmt *mgmt;
7c12ce8b8   Kalle Valo   mac80211: use Pro...
968
969
  	size_t buf_len;
  	u8 *buf;
651b52254   Jouni Malinen   mac80211: Add DS ...
970
  	u8 chan;
7c12ce8b8   Kalle Valo   mac80211: use Pro...
971
972
973
  
  	/* FIXME: come up with a proper value */
  	buf = kmalloc(200 + ie_len, GFP_KERNEL);
d15b84590   Joe Perches   mac80211: Remove ...
974
  	if (!buf)
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
975
  		return NULL;
469002983   Johannes Berg   mac80211: split I...
976

a806c558e   Paul Stewart   mac80211: Drop DS...
977
978
979
980
981
982
983
984
985
986
  	/*
  	 * Do not send DS Channel parameter for directed probe requests
  	 * in order to maximize the chance that we get a response.  Some
  	 * badly-behaved APs don't respond when this parameter is included.
  	 */
  	if (directed)
  		chan = 0;
  	else
  		chan = ieee80211_frequency_to_channel(
  			local->hw.conf.channel->center_freq);
651b52254   Jouni Malinen   mac80211: Add DS ...
987

7c12ce8b8   Kalle Valo   mac80211: use Pro...
988
  	buf_len = ieee80211_build_preq_ies(local, buf, ie, ie_len,
8dcb20038   Jouni Malinen   mac80211: Filter ...
989
  					   local->hw.conf.channel->band,
85a237fe3   Johannes Berg   mac80211: impleme...
990
  					   ratemask, chan);
7c12ce8b8   Kalle Valo   mac80211: use Pro...
991
992
993
994
  
  	skb = ieee80211_probereq_get(&local->hw, &sdata->vif,
  				     ssid, ssid_len,
  				     buf, buf_len);
5b2bbf75a   Johannes Berg   mac80211: fix bug...
995
996
  	if (!skb)
  		goto out;
7c12ce8b8   Kalle Valo   mac80211: use Pro...
997

469002983   Johannes Berg   mac80211: split I...
998
  	if (dst) {
7c12ce8b8   Kalle Valo   mac80211: use Pro...
999
  		mgmt = (struct ieee80211_mgmt *) skb->data;
469002983   Johannes Berg   mac80211: split I...
1000
1001
  		memcpy(mgmt->da, dst, ETH_ALEN);
  		memcpy(mgmt->bssid, dst, ETH_ALEN);
469002983   Johannes Berg   mac80211: split I...
1002
  	}
469002983   Johannes Berg   mac80211: split I...
1003

62ae67be3   Johannes Berg   mac80211: remove ...
1004
  	IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
5b2bbf75a   Johannes Berg   mac80211: fix bug...
1005
1006
  
   out:
145b6d1a5   Ming Lei   mac80211: fix mem...
1007
  	kfree(buf);
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
1008
1009
1010
1011
1012
1013
  
  	return skb;
  }
  
  void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
  			      const u8 *ssid, size_t ssid_len,
a806c558e   Paul Stewart   mac80211: Drop DS...
1014
  			      const u8 *ie, size_t ie_len,
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
1015
  			      u32 ratemask, bool directed, bool no_cck)
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
1016
1017
  {
  	struct sk_buff *skb;
85a237fe3   Johannes Berg   mac80211: impleme...
1018
1019
  	skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
  					ie, ie_len, directed);
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
1020
1021
1022
1023
  	if (skb) {
  		if (no_cck)
  			IEEE80211_SKB_CB(skb)->flags |=
  				IEEE80211_TX_CTL_NO_CCK_RATE;
a619a4c0e   Juuso Oikarinen   mac80211: Add fun...
1024
  		ieee80211_tx_skb(sdata, skb);
aad14ceb4   Rajkumar Manoharan   mac80211: Send th...
1025
  	}
469002983   Johannes Berg   mac80211: split I...
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  }
  
  u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
  			    struct ieee802_11_elems *elems,
  			    enum ieee80211_band band)
  {
  	struct ieee80211_supported_band *sband;
  	struct ieee80211_rate *bitrates;
  	size_t num_rates;
  	u32 supp_rates;
  	int i, j;
  	sband = local->hw.wiphy->bands[band];
  
  	if (!sband) {
  		WARN_ON(1);
  		sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  	}
  
  	bitrates = sband->bitrates;
  	num_rates = sband->n_bitrates;
  	supp_rates = 0;
  	for (i = 0; i < elems->supp_rates_len +
  		     elems->ext_supp_rates_len; i++) {
  		u8 rate = 0;
  		int own_rate;
  		if (i < elems->supp_rates_len)
  			rate = elems->supp_rates[i];
  		else if (elems->ext_supp_rates)
  			rate = elems->ext_supp_rates
  				[i - elems->supp_rates_len];
  		own_rate = 5 * (rate & 0x7f);
  		for (j = 0; j < num_rates; j++)
  			if (bitrates[j].bitrate == own_rate)
  				supp_rates |= BIT(j);
  	}
  	return supp_rates;
  }
f2753ddba   Johannes Berg   mac80211: add har...
1063

84f6a01ce   Johannes Berg   mac80211: fix con...
1064
1065
1066
  void ieee80211_stop_device(struct ieee80211_local *local)
  {
  	ieee80211_led_radio(local, false);
67408c8c7   Johannes Berg   mac80211: selecti...
1067
  	ieee80211_mod_tpt_led_trig(local, 0, IEEE80211_TPT_LEDTRIG_FL_RADIO);
84f6a01ce   Johannes Berg   mac80211: fix con...
1068
1069
  
  	cancel_work_sync(&local->reconfig_filter);
84f6a01ce   Johannes Berg   mac80211: fix con...
1070
1071
  
  	flush_workqueue(local->workqueue);
678f415fd   Lennert Buytenhek   mac80211: flush w...
1072
  	drv_stop(local);
84f6a01ce   Johannes Berg   mac80211: fix con...
1073
  }
f2753ddba   Johannes Berg   mac80211: add har...
1074
1075
1076
1077
  int ieee80211_reconfig(struct ieee80211_local *local)
  {
  	struct ieee80211_hw *hw = &local->hw;
  	struct ieee80211_sub_if_data *sdata;
f2753ddba   Johannes Berg   mac80211: add har...
1078
  	struct sta_info *sta;
2683d65bb   Eliad Peller   mac80211: reconfi...
1079
  	int res, i;
5bb644a0f   Johannes Berg   mac80211: cancel/...
1080

eecc48000   Johannes Berg   mac80211: add bas...
1081
  #ifdef CONFIG_PM
ceb99fe07   Johannes Berg   mac80211: fix resume
1082
1083
  	if (local->suspended)
  		local->resuming = true;
f2753ddba   Johannes Berg   mac80211: add har...
1084

eecc48000   Johannes Berg   mac80211: add bas...
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
  	if (local->wowlan) {
  		local->wowlan = false;
  		res = drv_resume(local);
  		if (res < 0) {
  			local->resuming = false;
  			return res;
  		}
  		if (res == 0)
  			goto wake_up;
  		WARN_ON(res > 1);
  		/*
  		 * res is 1, which means the driver requested
  		 * to go through a regular reset on wakeup.
  		 */
  	}
  #endif
94f9b97be   Johannes Berg   mac80211: be more...
1101
1102
1103
  	/* everything else happens only if HW was up & running */
  	if (!local->open_count)
  		goto wake_up;
f2753ddba   Johannes Berg   mac80211: add har...
1104

94f9b97be   Johannes Berg   mac80211: be more...
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
  	/*
  	 * Upon resume hardware can sometimes be goofy due to
  	 * various platform / driver / bus issues, so restarting
  	 * the device may at times not work immediately. Propagate
  	 * the error.
  	 */
  	res = drv_start(local);
  	if (res) {
  		WARN(local->suspended, "Hardware became unavailable "
  		     "upon resume. This could be a software issue "
  		     "prior to suspend or a hardware issue.
  ");
  		return res;
f2753ddba   Johannes Berg   mac80211: add har...
1118
  	}
7f2819756   Yogesh Ashok Powar   mac80211: Call dr...
1119
1120
1121
1122
1123
1124
1125
1126
  	/* setup fragmentation threshold */
  	drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
  
  	/* setup RTS threshold */
  	drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
  
  	/* reset coverage class */
  	drv_set_coverage_class(local, hw->wiphy->coverage_class);
94f9b97be   Johannes Berg   mac80211: be more...
1127
1128
1129
  	ieee80211_led_radio(local, true);
  	ieee80211_mod_tpt_led_trig(local,
  				   IEEE80211_TPT_LEDTRIG_FL_RADIO, 0);
f2753ddba   Johannes Berg   mac80211: add har...
1130
1131
1132
1133
  	/* add interfaces */
  	list_for_each_entry(sdata, &local->interfaces, list) {
  		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
  		    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
1ed32e4fc   Johannes Berg   mac80211: remove ...
1134
  		    ieee80211_sdata_running(sdata))
7b7eab6fc   Johannes Berg   mac80211: verify ...
1135
  			res = drv_add_interface(local, sdata);
f2753ddba   Johannes Berg   mac80211: add har...
1136
1137
1138
  	}
  
  	/* add STAs back */
34e895075   Johannes Berg   mac80211: allow s...
1139
1140
1141
  	mutex_lock(&local->sta_mtx);
  	list_for_each_entry(sta, &local->sta_list, list) {
  		if (sta->uploaded) {
5bb644a0f   Johannes Berg   mac80211: cancel/...
1142
  			sdata = sta->sdata;
f2753ddba   Johannes Berg   mac80211: add har...
1143
1144
1145
1146
  			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
  				sdata = container_of(sdata->bss,
  					     struct ieee80211_sub_if_data,
  					     u.ap);
34e895075   Johannes Berg   mac80211: allow s...
1147
  			WARN_ON(drv_sta_add(local, sdata, &sta->sta));
f2753ddba   Johannes Berg   mac80211: add har...
1148
  		}
f2753ddba   Johannes Berg   mac80211: add har...
1149
  	}
34e895075   Johannes Berg   mac80211: allow s...
1150
  	mutex_unlock(&local->sta_mtx);
f2753ddba   Johannes Berg   mac80211: add har...
1151

2683d65bb   Eliad Peller   mac80211: reconfi...
1152
  	/* reconfigure tx conf */
f6f3def32   Eliad Peller   mac80211: save tx...
1153
1154
1155
1156
1157
1158
1159
1160
1161
  	list_for_each_entry(sdata, &local->interfaces, list) {
  		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
  		    sdata->vif.type == NL80211_IFTYPE_MONITOR ||
  		    !ieee80211_sdata_running(sdata))
  			continue;
  
  		for (i = 0; i < hw->queues; i++)
  			drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
  	}
2683d65bb   Eliad Peller   mac80211: reconfi...
1162

f2753ddba   Johannes Berg   mac80211: add har...
1163
1164
  	/* reconfigure hardware */
  	ieee80211_hw_config(local, ~0);
f2753ddba   Johannes Berg   mac80211: add har...
1165
  	ieee80211_configure_filter(local);
f2753ddba   Johannes Berg   mac80211: add har...
1166
1167
1168
  
  	/* Finally also reconfigure all the BSS information */
  	list_for_each_entry(sdata, &local->interfaces, list) {
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1169
  		u32 changed;
9607e6b66   Johannes Berg   mac80211: add iee...
1170
  		if (!ieee80211_sdata_running(sdata))
f2753ddba   Johannes Berg   mac80211: add har...
1171
  			continue;
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1172
1173
1174
1175
1176
1177
1178
1179
1180
  
  		/* common change flags for all interface types */
  		changed = BSS_CHANGED_ERP_CTS_PROT |
  			  BSS_CHANGED_ERP_PREAMBLE |
  			  BSS_CHANGED_ERP_SLOT |
  			  BSS_CHANGED_HT |
  			  BSS_CHANGED_BASIC_RATES |
  			  BSS_CHANGED_BEACON_INT |
  			  BSS_CHANGED_BSSID |
4ced3f74d   Johannes Berg   mac80211: move Qo...
1181
  			  BSS_CHANGED_CQM |
55de47f65   Eliad Peller   mac80211: set BSS...
1182
1183
  			  BSS_CHANGED_QOS |
  			  BSS_CHANGED_IDLE;
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1184

f2753ddba   Johannes Berg   mac80211: add har...
1185
1186
  		switch (sdata->vif.type) {
  		case NL80211_IFTYPE_STATION:
0d392e938   Eliad Peller   mac80211: configu...
1187
1188
  			changed |= BSS_CHANGED_ASSOC |
  				   BSS_CHANGED_ARP_FILTER;
a7b545f7f   Eliad Peller   mac80211: add mis...
1189
  			mutex_lock(&sdata->u.mgd.mtx);
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1190
  			ieee80211_bss_info_change_notify(sdata, changed);
a7b545f7f   Eliad Peller   mac80211: add mis...
1191
  			mutex_unlock(&sdata->u.mgd.mtx);
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1192
  			break;
f2753ddba   Johannes Berg   mac80211: add har...
1193
  		case NL80211_IFTYPE_ADHOC:
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1194
1195
  			changed |= BSS_CHANGED_IBSS;
  			/* fall through */
f2753ddba   Johannes Berg   mac80211: add har...
1196
  		case NL80211_IFTYPE_AP:
e7979ac78   Arik Nemtsov   mac80211: don't i...
1197
1198
1199
1200
  			changed |= BSS_CHANGED_SSID;
  
  			if (sdata->vif.type == NL80211_IFTYPE_AP)
  				changed |= BSS_CHANGED_AP_PROBE_RESP;
7827493b8   Arik Nemtsov   mac80211: add ssi...
1201
  			/* fall through */
f2753ddba   Johannes Berg   mac80211: add har...
1202
  		case NL80211_IFTYPE_MESH_POINT:
ac8dd506e   Johannes Berg   mac80211: fix BSS...
1203
1204
  			changed |= BSS_CHANGED_BEACON |
  				   BSS_CHANGED_BEACON_ENABLED;
2d0ddec5b   Johannes Berg   mac80211: unify c...
1205
  			ieee80211_bss_info_change_notify(sdata, changed);
f2753ddba   Johannes Berg   mac80211: add har...
1206
1207
1208
1209
1210
1211
1212
1213
  			break;
  		case NL80211_IFTYPE_WDS:
  			break;
  		case NL80211_IFTYPE_AP_VLAN:
  		case NL80211_IFTYPE_MONITOR:
  			/* ignore virtual */
  			break;
  		case NL80211_IFTYPE_UNSPECIFIED:
2e161f78e   Johannes Berg   cfg80211/mac80211...
1214
  		case NUM_NL80211_IFTYPES:
2ca27bcff   Johannes Berg   mac80211: add p2p...
1215
1216
  		case NL80211_IFTYPE_P2P_CLIENT:
  		case NL80211_IFTYPE_P2P_GO:
f2753ddba   Johannes Berg   mac80211: add har...
1217
1218
1219
1220
  			WARN_ON(1);
  			break;
  		}
  	}
8e1b23b9e   Eyal Shapira   mac80211: add rec...
1221
  	ieee80211_recalc_ps(local, -1);
2a419056c   Johannes Berg   mac80211: simplif...
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
  	/*
  	 * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
  	 * sessions can be established after a resume.
  	 *
  	 * Also tear down aggregation sessions since reconfiguring
  	 * them in a hardware restart scenario is not easily done
  	 * right now, and the hardware will have lost information
  	 * about the sessions, but we and the AP still think they
  	 * are active. This is really a workaround though.
  	 */
74e2bd1fa   Wey-Yi Guy   mac80211: tear do...
1232
  	if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
2a419056c   Johannes Berg   mac80211: simplif...
1233
1234
1235
  		mutex_lock(&local->sta_mtx);
  
  		list_for_each_entry(sta, &local->sta_list, list) {
53f73c09d   Johannes Berg   mac80211: avoid t...
1236
  			ieee80211_sta_tear_down_BA_sessions(sta, true);
c2c98fdeb   Johannes Berg   mac80211: optimis...
1237
  			clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
74e2bd1fa   Wey-Yi Guy   mac80211: tear do...
1238
  		}
2a419056c   Johannes Berg   mac80211: simplif...
1239
1240
  
  		mutex_unlock(&local->sta_mtx);
74e2bd1fa   Wey-Yi Guy   mac80211: tear do...
1241
  	}
74e2bd1fa   Wey-Yi Guy   mac80211: tear do...
1242

f2753ddba   Johannes Berg   mac80211: add har...
1243
1244
  	/* add back keys */
  	list_for_each_entry(sdata, &local->interfaces, list)
9607e6b66   Johannes Berg   mac80211: add iee...
1245
  		if (ieee80211_sdata_running(sdata))
f2753ddba   Johannes Berg   mac80211: add har...
1246
  			ieee80211_enable_keys(sdata);
eecc48000   Johannes Berg   mac80211: add bas...
1247
   wake_up:
f2753ddba   Johannes Berg   mac80211: add har...
1248
1249
  	ieee80211_wake_queues_by_reason(hw,
  			IEEE80211_QUEUE_STOP_REASON_SUSPEND);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1250
1251
1252
1253
  	/*
  	 * If this is for hw restart things are still running.
  	 * We may want to change that later, however.
  	 */
ceb99fe07   Johannes Berg   mac80211: fix resume
1254
  	if (!local->suspended)
5bb644a0f   Johannes Berg   mac80211: cancel/...
1255
1256
1257
  		return 0;
  
  #ifdef CONFIG_PM
ceb99fe07   Johannes Berg   mac80211: fix resume
1258
  	/* first set suspended false, then resuming */
5bb644a0f   Johannes Berg   mac80211: cancel/...
1259
  	local->suspended = false;
ceb99fe07   Johannes Berg   mac80211: fix resume
1260
1261
  	mb();
  	local->resuming = false;
5bb644a0f   Johannes Berg   mac80211: cancel/...
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
  
  	list_for_each_entry(sdata, &local->interfaces, list) {
  		switch(sdata->vif.type) {
  		case NL80211_IFTYPE_STATION:
  			ieee80211_sta_restart(sdata);
  			break;
  		case NL80211_IFTYPE_ADHOC:
  			ieee80211_ibss_restart(sdata);
  			break;
  		case NL80211_IFTYPE_MESH_POINT:
  			ieee80211_mesh_restart(sdata);
  			break;
  		default:
  			break;
  		}
  	}
26d59535a   Johannes Berg   mac80211: clean u...
1278
  	mod_timer(&local->sta_cleanup, jiffies + 1);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1279

34e895075   Johannes Berg   mac80211: allow s...
1280
  	mutex_lock(&local->sta_mtx);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1281
1282
  	list_for_each_entry(sta, &local->sta_list, list)
  		mesh_plink_restart(sta);
34e895075   Johannes Berg   mac80211: allow s...
1283
  	mutex_unlock(&local->sta_mtx);
5bb644a0f   Johannes Berg   mac80211: cancel/...
1284
1285
1286
  #else
  	WARN_ON(1);
  #endif
f2753ddba   Johannes Berg   mac80211: add har...
1287
1288
  	return 0;
  }
42935ecaf   Luis R. Rodriguez   mac80211: redefin...
1289

95acac61b   Johannes Berg   mac80211: allow d...
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
  void ieee80211_resume_disconnect(struct ieee80211_vif *vif)
  {
  	struct ieee80211_sub_if_data *sdata;
  	struct ieee80211_local *local;
  	struct ieee80211_key *key;
  
  	if (WARN_ON(!vif))
  		return;
  
  	sdata = vif_to_sdata(vif);
  	local = sdata->local;
  
  	if (WARN_ON(!local->resuming))
  		return;
  
  	if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
  		return;
  
  	sdata->flags |= IEEE80211_SDATA_DISCONNECT_RESUME;
  
  	mutex_lock(&local->key_mtx);
  	list_for_each_entry(key, &sdata->key_list, list)
  		key->flags |= KEY_FLAG_TAINTED;
  	mutex_unlock(&local->key_mtx);
  }
  EXPORT_SYMBOL_GPL(ieee80211_resume_disconnect);
0f78231bf   Johannes Berg   mac80211: enable ...
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
  static int check_mgd_smps(struct ieee80211_if_managed *ifmgd,
  			  enum ieee80211_smps_mode *smps_mode)
  {
  	if (ifmgd->associated) {
  		*smps_mode = ifmgd->ap_smps;
  
  		if (*smps_mode == IEEE80211_SMPS_AUTOMATIC) {
  			if (ifmgd->powersave)
  				*smps_mode = IEEE80211_SMPS_DYNAMIC;
  			else
  				*smps_mode = IEEE80211_SMPS_OFF;
  		}
  
  		return 1;
  	}
  
  	return 0;
  }
  
  /* must hold iflist_mtx */
025e6be22   Johannes Berg   mac80211: fix dea...
1336
  void ieee80211_recalc_smps(struct ieee80211_local *local)
0f78231bf   Johannes Berg   mac80211: enable ...
1337
1338
1339
1340
  {
  	struct ieee80211_sub_if_data *sdata;
  	enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_OFF;
  	int count = 0;
46a5ebaf0   Johannes Berg   cfg80211/mac80211...
1341
  	lockdep_assert_held(&local->iflist_mtx);
0f78231bf   Johannes Berg   mac80211: enable ...
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  
  	/*
  	 * This function could be improved to handle multiple
  	 * interfaces better, but right now it makes any
  	 * non-station interfaces force SM PS to be turned
  	 * off. If there are multiple station interfaces it
  	 * could also use the best possible mode, e.g. if
  	 * one is in static and the other in dynamic then
  	 * dynamic is ok.
  	 */
  
  	list_for_each_entry(sdata, &local->interfaces, list) {
26a58456b   Johannes Berg   mac80211: switch ...
1354
  		if (!ieee80211_sdata_running(sdata))
0f78231bf   Johannes Berg   mac80211: enable ...
1355
1356
1357
  			continue;
  		if (sdata->vif.type != NL80211_IFTYPE_STATION)
  			goto set;
025e6be22   Johannes Berg   mac80211: fix dea...
1358
1359
  
  		count += check_mgd_smps(&sdata->u.mgd, &smps_mode);
0f78231bf   Johannes Berg   mac80211: enable ...
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
  
  		if (count > 1) {
  			smps_mode = IEEE80211_SMPS_OFF;
  			break;
  		}
  	}
  
  	if (smps_mode == local->smps_mode)
  		return;
  
   set:
  	local->smps_mode = smps_mode;
  	/* changed flag is auto-detected for this */
  	ieee80211_hw_config(local, 0);
  }
8e664fb3f   Johannes Berg   mac80211: split u...
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
  
  static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id)
  {
  	int i;
  
  	for (i = 0; i < n_ids; i++)
  		if (ids[i] == id)
  			return true;
  	return false;
  }
  
  /**
   * ieee80211_ie_split - split an IE buffer according to ordering
   *
   * @ies: the IE buffer
   * @ielen: the length of the IE buffer
   * @ids: an array with element IDs that are allowed before
   *	the split
   * @n_ids: the size of the element ID array
   * @offset: offset where to start splitting in the buffer
   *
   * This function splits an IE buffer by updating the @offset
   * variable to point to the location where the buffer should be
   * split.
   *
   * It assumes that the given IE buffer is well-formed, this
   * has to be guaranteed by the caller!
   *
   * It also assumes that the IEs in the buffer are ordered
   * correctly, if not the result of using this function will not
   * be ordered correctly either, i.e. it does no reordering.
   *
   * The function returns the offset where the next part of the
   * buffer starts, which may be @ielen if the entire (remainder)
   * of the buffer should be used.
   */
  size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
  			  const u8 *ids, int n_ids, size_t offset)
  {
  	size_t pos = offset;
  
  	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos]))
  		pos += 2 + ies[pos + 1];
  
  	return pos;
  }
  
  size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset)
  {
  	size_t pos = offset;
  
  	while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC)
  		pos += 2 + ies[pos + 1];
  
  	return pos;
  }
615f7b9bb   Meenakshi Venkataraman   mac80211: add dri...
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
  
  static void _ieee80211_enable_rssi_reports(struct ieee80211_sub_if_data *sdata,
  					    int rssi_min_thold,
  					    int rssi_max_thold)
  {
  	trace_api_enable_rssi_reports(sdata, rssi_min_thold, rssi_max_thold);
  
  	if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
  		return;
  
  	/*
  	 * Scale up threshold values before storing it, as the RSSI averaging
  	 * algorithm uses a scaled up value as well. Change this scaling
  	 * factor if the RSSI averaging algorithm changes.
  	 */
  	sdata->u.mgd.rssi_min_thold = rssi_min_thold*16;
  	sdata->u.mgd.rssi_max_thold = rssi_max_thold*16;
  }
  
  void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
  				    int rssi_min_thold,
  				    int rssi_max_thold)
  {
  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  
  	WARN_ON(rssi_min_thold == rssi_max_thold ||
  		rssi_min_thold > rssi_max_thold);
  
  	_ieee80211_enable_rssi_reports(sdata, rssi_min_thold,
  				       rssi_max_thold);
  }
  EXPORT_SYMBOL(ieee80211_enable_rssi_reports);
  
  void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
  {
  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  
  	_ieee80211_enable_rssi_reports(sdata, 0, 0);
  }
  EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
768db3438   Arik Nemtsov   mac80211: standar...
1471

ef96a8420   Ben Greear   mac80211: Support...
1472
  u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
42e7aa771   Alexander Simon   mac80211: Add HT ...
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
  			      u16 cap)
  {
  	__le16 tmp;
  
  	*pos++ = WLAN_EID_HT_CAPABILITY;
  	*pos++ = sizeof(struct ieee80211_ht_cap);
  	memset(pos, 0, sizeof(struct ieee80211_ht_cap));
  
  	/* capability flags */
  	tmp = cpu_to_le16(cap);
  	memcpy(pos, &tmp, sizeof(u16));
  	pos += sizeof(u16);
  
  	/* AMPDU parameters */
ef96a8420   Ben Greear   mac80211: Support...
1487
1488
  	*pos++ = ht_cap->ampdu_factor |
  		 (ht_cap->ampdu_density <<
42e7aa771   Alexander Simon   mac80211: Add HT ...
1489
1490
1491
  			IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
  
  	/* MCS set */
ef96a8420   Ben Greear   mac80211: Support...
1492
1493
  	memcpy(pos, &ht_cap->mcs, sizeof(ht_cap->mcs));
  	pos += sizeof(ht_cap->mcs);
42e7aa771   Alexander Simon   mac80211: Add HT ...
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
  
  	/* extended capabilities */
  	pos += sizeof(__le16);
  
  	/* BF capabilities */
  	pos += sizeof(__le32);
  
  	/* antenna selection */
  	pos += sizeof(u8);
  
  	return pos;
  }
  
  u8 *ieee80211_ie_build_ht_info(u8 *pos,
  			       struct ieee80211_sta_ht_cap *ht_cap,
  			       struct ieee80211_channel *channel,
  			       enum nl80211_channel_type channel_type)
  {
  	struct ieee80211_ht_info *ht_info;
  	/* Build HT Information */
  	*pos++ = WLAN_EID_HT_INFORMATION;
  	*pos++ = sizeof(struct ieee80211_ht_info);
  	ht_info = (struct ieee80211_ht_info *)pos;
  	ht_info->control_chan =
  			ieee80211_frequency_to_channel(channel->center_freq);
  	switch (channel_type) {
  	case NL80211_CHAN_HT40MINUS:
  		ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
  		break;
  	case NL80211_CHAN_HT40PLUS:
  		ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
  		break;
  	case NL80211_CHAN_HT20:
  	default:
  		ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
  		break;
  	}
  	if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
  		ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
ff3cc5f40   Simon Wunderlich   mac80211: handle ...
1533
1534
1535
1536
1537
  
  	/*
  	 * Note: According to 802.11n-2009 9.13.3.1, HT Protection field and
  	 * RIFS Mode are reserved in IBSS mode, therefore keep them at 0
  	 */
42e7aa771   Alexander Simon   mac80211: Add HT ...
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
  	ht_info->operation_mode = 0x0000;
  	ht_info->stbc_param = 0x0000;
  
  	/* It seems that Basic MCS set and Supported MCS set
  	   are identical for the first 10 bytes */
  	memset(&ht_info->basic_set, 0, 16);
  	memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
  
  	return pos + sizeof(struct ieee80211_ht_info);
  }
  
  enum nl80211_channel_type
  ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
  {
  	enum nl80211_channel_type channel_type;
  
  	if (!ht_info)
  		return NL80211_CHAN_NO_HT;
  
  	switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
  	case IEEE80211_HT_PARAM_CHA_SEC_NONE:
  		channel_type = NL80211_CHAN_HT20;
  		break;
  	case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
  		channel_type = NL80211_CHAN_HT40PLUS;
  		break;
  	case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
  		channel_type = NL80211_CHAN_HT40MINUS;
  		break;
  	default:
  		channel_type = NL80211_CHAN_NO_HT;
  	}
  
  	return channel_type;
  }
768db3438   Arik Nemtsov   mac80211: standar...
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
  int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
  {
  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_supported_band *sband;
  	int rate;
  	u8 i, rates, *pos;
  
  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  	rates = sband->n_bitrates;
  	if (rates > 8)
  		rates = 8;
  
  	if (skb_tailroom(skb) < rates + 2)
  		return -ENOMEM;
  
  	pos = skb_put(skb, rates + 2);
  	*pos++ = WLAN_EID_SUPP_RATES;
  	*pos++ = rates;
  	for (i = 0; i < rates; i++) {
  		rate = sband->bitrates[i].bitrate;
  		*pos++ = (u8) (rate / 5);
  	}
  
  	return 0;
  }
  
  int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
  {
  	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
  	struct ieee80211_local *local = sdata->local;
  	struct ieee80211_supported_band *sband;
  	int rate;
  	u8 i, exrates, *pos;
  
  	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
  	exrates = sband->n_bitrates;
  	if (exrates > 8)
  		exrates -= 8;
  	else
  		exrates = 0;
  
  	if (skb_tailroom(skb) < exrates + 2)
  		return -ENOMEM;
  
  	if (exrates) {
  		pos = skb_put(skb, exrates + 2);
  		*pos++ = WLAN_EID_EXT_SUPP_RATES;
  		*pos++ = exrates;
  		for (i = 8; i < sband->n_bitrates; i++) {
  			rate = sband->bitrates[i].bitrate;
  			*pos++ = (u8) (rate / 5);
  		}
  	}
  	return 0;
  }