Blame view

net/wireless/util.c 45.4 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
8318d78a4   Johannes Berg   cfg80211 API for ...
2
3
4
  /*
   * Wireless utility functions
   *
d32365537   Johannes Berg   cfg80211: clean u...
5
   * Copyright 2007-2009	Johannes Berg <johannes@sipsolutions.net>
2740f0cf8   Johannes Berg   cfg80211: add Int...
6
   * Copyright 2013-2014  Intel Mobile Communications GmbH
8318d78a4   Johannes Berg   cfg80211 API for ...
7
   */
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
8
  #include <linux/export.h>
d32365537   Johannes Berg   cfg80211: clean u...
9
  #include <linux/bitops.h>
e31a16d6f   Zhu Yi   wireless: move so...
10
  #include <linux/etherdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
d32365537   Johannes Berg   cfg80211: clean u...
12
  #include <net/cfg80211.h>
e31a16d6f   Zhu Yi   wireless: move so...
13
  #include <net/ip.h>
b156579b1   Dave Täht   wireless: Treat I...
14
  #include <net/dsfield.h>
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
15
  #include <linux/if_vlan.h>
960d97f95   Simon Wunderlich   cfg80211: add MPL...
16
  #include <linux/mpls.h>
4c8dea638   Johannes Berg   cfg80211: validat...
17
  #include <linux/gcd.h>
8318d78a4   Johannes Berg   cfg80211 API for ...
18
  #include "core.h"
e35e4d28b   Hila Gonen   cfg80211: add wra...
19
  #include "rdev-ops.h"
8318d78a4   Johannes Berg   cfg80211 API for ...
20

bd8152527   Johannes Berg   wireless: impleme...
21
22
  struct ieee80211_rate *
  ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
881d948c2   Johannes Berg   wireless: restric...
23
  			    u32 basic_rates, int bitrate)
bd8152527   Johannes Berg   wireless: impleme...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  {
  	struct ieee80211_rate *result = &sband->bitrates[0];
  	int i;
  
  	for (i = 0; i < sband->n_bitrates; i++) {
  		if (!(basic_rates & BIT(i)))
  			continue;
  		if (sband->bitrates[i].bitrate > bitrate)
  			continue;
  		result = &sband->bitrates[i];
  	}
  
  	return result;
  }
  EXPORT_SYMBOL(ieee80211_get_response_rate);
74608aca4   Simon Wunderlich   cfg80211/mac80211...
39
40
  u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
  			      enum nl80211_bss_scan_width scan_width)
b422c6cd7   Ashok Nagarajan   {cfg,mac}80211: m...
41
42
43
44
45
46
47
48
  {
  	struct ieee80211_rate *bitrates;
  	u32 mandatory_rates = 0;
  	enum ieee80211_rate_flags mandatory_flag;
  	int i;
  
  	if (WARN_ON(!sband))
  		return 1;
57fbcce37   Johannes Berg   cfg80211: remove ...
49
  	if (sband->band == NL80211_BAND_2GHZ) {
74608aca4   Simon Wunderlich   cfg80211/mac80211...
50
51
52
53
54
55
  		if (scan_width == NL80211_BSS_CHAN_WIDTH_5 ||
  		    scan_width == NL80211_BSS_CHAN_WIDTH_10)
  			mandatory_flag = IEEE80211_RATE_MANDATORY_G;
  		else
  			mandatory_flag = IEEE80211_RATE_MANDATORY_B;
  	} else {
b422c6cd7   Ashok Nagarajan   {cfg,mac}80211: m...
56
  		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
74608aca4   Simon Wunderlich   cfg80211/mac80211...
57
  	}
b422c6cd7   Ashok Nagarajan   {cfg,mac}80211: m...
58
59
60
61
62
63
64
65
  
  	bitrates = sband->bitrates;
  	for (i = 0; i < sband->n_bitrates; i++)
  		if (bitrates[i].flags & mandatory_flag)
  			mandatory_rates |= BIT(i);
  	return mandatory_rates;
  }
  EXPORT_SYMBOL(ieee80211_mandatory_rates);
57fbcce37   Johannes Berg   cfg80211: remove ...
66
  int ieee80211_channel_to_frequency(int chan, enum nl80211_band band)
8318d78a4   Johannes Berg   cfg80211 API for ...
67
  {
59eb21a65   Bruno Randolf   cfg80211: Extend ...
68
69
  	/* see 802.11 17.3.8.3.2 and Annex J
  	 * there are overlapping channel numbers in 5GHz and 2GHz bands */
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
70
71
72
  	if (chan <= 0)
  		return 0; /* not supported */
  	switch (band) {
57fbcce37   Johannes Berg   cfg80211: remove ...
73
  	case NL80211_BAND_2GHZ:
59eb21a65   Bruno Randolf   cfg80211: Extend ...
74
75
76
77
  		if (chan == 14)
  			return 2484;
  		else if (chan < 14)
  			return 2407 + chan * 5;
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
78
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
79
  	case NL80211_BAND_5GHZ:
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
80
81
  		if (chan >= 182 && chan <= 196)
  			return 4000 + chan * 5;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
82
  		else
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
83
84
  			return 5000 + chan * 5;
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
85
  	case NL80211_BAND_60GHZ:
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
86
87
88
89
90
  		if (chan < 5)
  			return 56160 + chan * 2160;
  		break;
  	default:
  		;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
91
  	}
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
92
  	return 0; /* not supported */
8318d78a4   Johannes Berg   cfg80211 API for ...
93
94
95
96
97
  }
  EXPORT_SYMBOL(ieee80211_channel_to_frequency);
  
  int ieee80211_frequency_to_channel(int freq)
  {
59eb21a65   Bruno Randolf   cfg80211: Extend ...
98
  	/* see 802.11 17.3.8.3.2 and Annex J */
8318d78a4   Johannes Berg   cfg80211 API for ...
99
100
  	if (freq == 2484)
  		return 14;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
101
  	else if (freq < 2484)
8318d78a4   Johannes Berg   cfg80211 API for ...
102
  		return (freq - 2407) / 5;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
103
104
  	else if (freq >= 4910 && freq <= 4980)
  		return (freq - 4000) / 5;
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
105
  	else if (freq <= 45000) /* DMG band lower limit */
59eb21a65   Bruno Randolf   cfg80211: Extend ...
106
  		return (freq - 5000) / 5;
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
107
108
109
110
  	else if (freq >= 58320 && freq <= 64800)
  		return (freq - 56160) / 2160;
  	else
  		return 0;
8318d78a4   Johannes Berg   cfg80211 API for ...
111
112
  }
  EXPORT_SYMBOL(ieee80211_frequency_to_channel);
543b921b4   Arend Van Spriel   cfg80211: get rid...
113
  struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, int freq)
906c730a2   Johannes Berg   wireless: add wip...
114
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
115
  	enum nl80211_band band;
906c730a2   Johannes Berg   wireless: add wip...
116
117
  	struct ieee80211_supported_band *sband;
  	int i;
57fbcce37   Johannes Berg   cfg80211: remove ...
118
  	for (band = 0; band < NUM_NL80211_BANDS; band++) {
906c730a2   Johannes Berg   wireless: add wip...
119
120
121
122
123
124
125
126
127
128
129
130
131
  		sband = wiphy->bands[band];
  
  		if (!sband)
  			continue;
  
  		for (i = 0; i < sband->n_channels; i++) {
  			if (sband->channels[i].center_freq == freq)
  				return &sband->channels[i];
  		}
  	}
  
  	return NULL;
  }
543b921b4   Arend Van Spriel   cfg80211: get rid...
132
  EXPORT_SYMBOL(ieee80211_get_channel);
906c730a2   Johannes Berg   wireless: add wip...
133

343884c87   Arend Van Spriel   cfg80211: only pa...
134
  static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
8318d78a4   Johannes Berg   cfg80211 API for ...
135
136
  {
  	int i, want;
343884c87   Arend Van Spriel   cfg80211: only pa...
137
  	switch (sband->band) {
57fbcce37   Johannes Berg   cfg80211: remove ...
138
  	case NL80211_BAND_5GHZ:
8318d78a4   Johannes Berg   cfg80211 API for ...
139
140
141
142
143
144
145
146
147
148
149
150
  		want = 3;
  		for (i = 0; i < sband->n_bitrates; i++) {
  			if (sband->bitrates[i].bitrate == 60 ||
  			    sband->bitrates[i].bitrate == 120 ||
  			    sband->bitrates[i].bitrate == 240) {
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_MANDATORY_A;
  				want--;
  			}
  		}
  		WARN_ON(want);
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
151
  	case NL80211_BAND_2GHZ:
8318d78a4   Johannes Berg   cfg80211 API for ...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  		want = 7;
  		for (i = 0; i < sband->n_bitrates; i++) {
  			if (sband->bitrates[i].bitrate == 10) {
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_MANDATORY_B |
  					IEEE80211_RATE_MANDATORY_G;
  				want--;
  			}
  
  			if (sband->bitrates[i].bitrate == 20 ||
  			    sband->bitrates[i].bitrate == 55 ||
  			    sband->bitrates[i].bitrate == 110 ||
  			    sband->bitrates[i].bitrate == 60 ||
  			    sband->bitrates[i].bitrate == 120 ||
  			    sband->bitrates[i].bitrate == 240) {
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_MANDATORY_G;
  				want--;
  			}
aac09fbf8   Johannes Berg   wireless: fix ERP...
171
172
173
174
  			if (sband->bitrates[i].bitrate != 10 &&
  			    sband->bitrates[i].bitrate != 20 &&
  			    sband->bitrates[i].bitrate != 55 &&
  			    sband->bitrates[i].bitrate != 110)
8318d78a4   Johannes Berg   cfg80211 API for ...
175
176
177
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_ERP_G;
  		}
406f2388c   Ivo van Doorn   wireless: Fix WAR...
178
  		WARN_ON(want != 0 && want != 3 && want != 6);
8318d78a4   Johannes Berg   cfg80211 API for ...
179
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
180
  	case NL80211_BAND_60GHZ:
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
181
182
183
184
  		/* check for mandatory HT MCS 1..4 */
  		WARN_ON(!sband->ht_cap.ht_supported);
  		WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e);
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
185
  	case NUM_NL80211_BANDS:
343884c87   Arend Van Spriel   cfg80211: only pa...
186
  	default:
8318d78a4   Johannes Berg   cfg80211 API for ...
187
188
189
190
191
192
193
  		WARN_ON(1);
  		break;
  	}
  }
  
  void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
194
  	enum nl80211_band band;
8318d78a4   Johannes Berg   cfg80211 API for ...
195

57fbcce37   Johannes Berg   cfg80211: remove ...
196
  	for (band = 0; band < NUM_NL80211_BANDS; band++)
8318d78a4   Johannes Berg   cfg80211 API for ...
197
  		if (wiphy->bands[band])
343884c87   Arend Van Spriel   cfg80211: only pa...
198
  			set_mandatory_flags_band(wiphy->bands[band]);
8318d78a4   Johannes Berg   cfg80211 API for ...
199
  }
08645126d   Johannes Berg   cfg80211: impleme...
200

38ba3c57a   Jouni Malinen   cfg80211: Validat...
201
202
203
204
205
206
207
208
  bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
  {
  	int i;
  	for (i = 0; i < wiphy->n_cipher_suites; i++)
  		if (cipher == wiphy->cipher_suites[i])
  			return true;
  	return false;
  }
fffd0934b   Johannes Berg   cfg80211: rework ...
209
210
  int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
  				   struct key_params *params, int key_idx,
e31b82136   Johannes Berg   cfg80211/mac80211...
211
  				   bool pairwise, const u8 *mac_addr)
08645126d   Johannes Berg   cfg80211: impleme...
212
  {
e9c8f8d3a   Johannes Berg   cfg80211: validat...
213
  	if (key_idx < 0 || key_idx > 5)
08645126d   Johannes Berg   cfg80211: impleme...
214
  		return -EINVAL;
e31b82136   Johannes Berg   cfg80211/mac80211...
215
216
217
218
219
  	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
  		return -EINVAL;
  
  	if (pairwise && !mac_addr)
  		return -EINVAL;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
220
221
222
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_TKIP:
  	case WLAN_CIPHER_SUITE_CCMP:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
223
224
225
  	case WLAN_CIPHER_SUITE_CCMP_256:
  	case WLAN_CIPHER_SUITE_GCMP:
  	case WLAN_CIPHER_SUITE_GCMP_256:
37720569c   Jouni Malinen   cfg80211: Fix BIP...
226
227
228
229
230
231
232
233
234
235
  		/* Disallow pairwise keys with non-zero index unless it's WEP
  		 * or a vendor specific cipher (because current deployments use
  		 * pairwise WEP keys with non-zero indices and for vendor
  		 * specific ciphers this should be validated in the driver or
  		 * hardware level - but 802.11i clearly specifies to use zero)
  		 */
  		if (pairwise && key_idx)
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_AES_CMAC:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
236
237
238
  	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
  	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
37720569c   Jouni Malinen   cfg80211: Fix BIP...
239
240
241
  		/* Disallow BIP (group-only) cipher as pairwise cipher */
  		if (pairwise)
  			return -EINVAL;
e9c8f8d3a   Johannes Berg   cfg80211: validat...
242
243
  		if (key_idx < 4)
  			return -EINVAL;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
244
  		break;
e9c8f8d3a   Johannes Berg   cfg80211: validat...
245
246
247
248
  	case WLAN_CIPHER_SUITE_WEP40:
  	case WLAN_CIPHER_SUITE_WEP104:
  		if (key_idx > 3)
  			return -EINVAL;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
249
250
251
  	default:
  		break;
  	}
08645126d   Johannes Berg   cfg80211: impleme...
252

08645126d   Johannes Berg   cfg80211: impleme...
253
254
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_WEP40:
8fc0fee09   Johannes Berg   cfg80211: use key...
255
  		if (params->key_len != WLAN_KEY_LEN_WEP40)
08645126d   Johannes Berg   cfg80211: impleme...
256
257
258
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_TKIP:
8fc0fee09   Johannes Berg   cfg80211: use key...
259
  		if (params->key_len != WLAN_KEY_LEN_TKIP)
08645126d   Johannes Berg   cfg80211: impleme...
260
261
262
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_CCMP:
8fc0fee09   Johannes Berg   cfg80211: use key...
263
  		if (params->key_len != WLAN_KEY_LEN_CCMP)
08645126d   Johannes Berg   cfg80211: impleme...
264
265
  			return -EINVAL;
  		break;
cfcf1682c   Jouni Malinen   cfg80211: Add new...
266
267
268
269
270
271
272
273
274
275
276
277
  	case WLAN_CIPHER_SUITE_CCMP_256:
  		if (params->key_len != WLAN_KEY_LEN_CCMP_256)
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_GCMP:
  		if (params->key_len != WLAN_KEY_LEN_GCMP)
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_GCMP_256:
  		if (params->key_len != WLAN_KEY_LEN_GCMP_256)
  			return -EINVAL;
  		break;
08645126d   Johannes Berg   cfg80211: impleme...
278
  	case WLAN_CIPHER_SUITE_WEP104:
8fc0fee09   Johannes Berg   cfg80211: use key...
279
  		if (params->key_len != WLAN_KEY_LEN_WEP104)
08645126d   Johannes Berg   cfg80211: impleme...
280
281
282
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_AES_CMAC:
8fc0fee09   Johannes Berg   cfg80211: use key...
283
  		if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
08645126d   Johannes Berg   cfg80211: impleme...
284
285
  			return -EINVAL;
  		break;
cfcf1682c   Jouni Malinen   cfg80211: Add new...
286
287
288
289
290
291
292
293
294
295
296
297
  	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  		if (params->key_len != WLAN_KEY_LEN_BIP_CMAC_256)
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
  		if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_128)
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
  		if (params->key_len != WLAN_KEY_LEN_BIP_GMAC_256)
  			return -EINVAL;
  		break;
08645126d   Johannes Berg   cfg80211: impleme...
298
  	default:
7d64b7cc1   Johannes Berg   cfg80211: allow v...
299
300
301
302
303
304
305
306
  		/*
  		 * We don't know anything about this algorithm,
  		 * allow using it -- but the driver must check
  		 * all parameters! We still check below whether
  		 * or not the driver supports this algorithm,
  		 * of course.
  		 */
  		break;
08645126d   Johannes Berg   cfg80211: impleme...
307
  	}
9f26a9522   Jouni Malinen   nl80211: Validate...
308
309
310
311
312
313
314
315
  	if (params->seq) {
  		switch (params->cipher) {
  		case WLAN_CIPHER_SUITE_WEP40:
  		case WLAN_CIPHER_SUITE_WEP104:
  			/* These ciphers do not use key sequence */
  			return -EINVAL;
  		case WLAN_CIPHER_SUITE_TKIP:
  		case WLAN_CIPHER_SUITE_CCMP:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
316
317
318
  		case WLAN_CIPHER_SUITE_CCMP_256:
  		case WLAN_CIPHER_SUITE_GCMP:
  		case WLAN_CIPHER_SUITE_GCMP_256:
9f26a9522   Jouni Malinen   nl80211: Validate...
319
  		case WLAN_CIPHER_SUITE_AES_CMAC:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
320
321
322
  		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
  		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
9f26a9522   Jouni Malinen   nl80211: Validate...
323
324
325
326
327
  			if (params->seq_len != 6)
  				return -EINVAL;
  			break;
  		}
  	}
38ba3c57a   Jouni Malinen   cfg80211: Validat...
328
  	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
fffd0934b   Johannes Berg   cfg80211: rework ...
329
  		return -EINVAL;
08645126d   Johannes Berg   cfg80211: impleme...
330
331
  	return 0;
  }
e31a16d6f   Zhu Yi   wireless: move so...
332

633adf1ad   Johannes Berg   cfg80211: mark ie...
333
  unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
e31a16d6f   Zhu Yi   wireless: move so...
334
335
336
337
338
339
  {
  	unsigned int hdrlen = 24;
  
  	if (ieee80211_is_data(fc)) {
  		if (ieee80211_has_a4(fc))
  			hdrlen = 30;
d0dd2de0d   Andriy Tkachuk   mac80211: Account...
340
  		if (ieee80211_is_data_qos(fc)) {
e31a16d6f   Zhu Yi   wireless: move so...
341
  			hdrlen += IEEE80211_QOS_CTL_LEN;
d0dd2de0d   Andriy Tkachuk   mac80211: Account...
342
343
344
  			if (ieee80211_has_order(fc))
  				hdrlen += IEEE80211_HT_CTL_LEN;
  		}
e31a16d6f   Zhu Yi   wireless: move so...
345
346
  		goto out;
  	}
fb142f4bb   Fred Chou   mac80211: correct...
347
348
349
350
351
  	if (ieee80211_is_mgmt(fc)) {
  		if (ieee80211_has_order(fc))
  			hdrlen += IEEE80211_HT_CTL_LEN;
  		goto out;
  	}
e31a16d6f   Zhu Yi   wireless: move so...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  	if (ieee80211_is_ctl(fc)) {
  		/*
  		 * ACK and CTS are 10 bytes, all others 16. To see how
  		 * to get this condition consider
  		 *   subtype mask:   0b0000000011110000 (0x00F0)
  		 *   ACK subtype:    0b0000000011010000 (0x00D0)
  		 *   CTS subtype:    0b0000000011000000 (0x00C0)
  		 *   bits that matter:         ^^^      (0x00E0)
  		 *   value of those: 0b0000000011000000 (0x00C0)
  		 */
  		if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
  			hdrlen = 10;
  		else
  			hdrlen = 16;
  	}
  out:
  	return hdrlen;
  }
  EXPORT_SYMBOL(ieee80211_hdrlen);
  
  unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
  {
  	const struct ieee80211_hdr *hdr =
  			(const struct ieee80211_hdr *)skb->data;
  	unsigned int hdrlen;
  
  	if (unlikely(skb->len < 10))
  		return 0;
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
  	if (unlikely(hdrlen > skb->len))
  		return 0;
  	return hdrlen;
  }
  EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
2d1c304cb   Felix Fietkau   cfg80211: add fun...
386
  static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
e31a16d6f   Zhu Yi   wireless: move so...
387
  {
2d1c304cb   Felix Fietkau   cfg80211: add fun...
388
  	int ae = flags & MESH_FLAGS_AE;
7dd111e8e   Johannes Berg   wireless: drop in...
389
  	/* 802.11-2012, 8.2.4.7.3 */
e31a16d6f   Zhu Yi   wireless: move so...
390
  	switch (ae) {
7dd111e8e   Johannes Berg   wireless: drop in...
391
  	default:
e31a16d6f   Zhu Yi   wireless: move so...
392
393
  	case 0:
  		return 6;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
394
  	case MESH_FLAGS_AE_A4:
e31a16d6f   Zhu Yi   wireless: move so...
395
  		return 12;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
396
  	case MESH_FLAGS_AE_A5_A6:
e31a16d6f   Zhu Yi   wireless: move so...
397
  		return 18;
e31a16d6f   Zhu Yi   wireless: move so...
398
399
  	}
  }
2d1c304cb   Felix Fietkau   cfg80211: add fun...
400
401
402
403
404
  
  unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
  {
  	return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
  }
9b395bc3b   Johannes Berg   mac80211: verify ...
405
  EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
e31a16d6f   Zhu Yi   wireless: move so...
406

7f6990c83   Johannes Berg   cfg80211: let iee...
407
408
  int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
  				  const u8 *addr, enum nl80211_iftype iftype)
e31a16d6f   Zhu Yi   wireless: move so...
409
410
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
2d1c304cb   Felix Fietkau   cfg80211: add fun...
411
412
413
414
415
416
417
  	struct {
  		u8 hdr[ETH_ALEN] __aligned(2);
  		__be16 proto;
  	} payload;
  	struct ethhdr tmp;
  	u16 hdrlen;
  	u8 mesh_flags = 0;
e31a16d6f   Zhu Yi   wireless: move so...
418
419
420
421
422
  
  	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
  		return -1;
  
  	hdrlen = ieee80211_hdrlen(hdr->frame_control);
2d1c304cb   Felix Fietkau   cfg80211: add fun...
423
424
  	if (skb->len < hdrlen + 8)
  		return -1;
e31a16d6f   Zhu Yi   wireless: move so...
425
426
427
428
429
430
431
432
433
434
  
  	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
  	 * header
  	 * IEEE 802.11 address fields:
  	 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
  	 *   0     0   DA    SA    BSSID n/a
  	 *   0     1   DA    BSSID SA    n/a
  	 *   1     0   BSSID SA    DA    n/a
  	 *   1     1   RA    TA    DA    SA
  	 */
2d1c304cb   Felix Fietkau   cfg80211: add fun...
435
436
437
438
439
  	memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
  	memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
  
  	if (iftype == NL80211_IFTYPE_MESH_POINT)
  		skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
e31a16d6f   Zhu Yi   wireless: move so...
440

5667c86ac   Rajkumar Manoharan   mac80211: strictl...
441
  	mesh_flags &= MESH_FLAGS_AE;
e31a16d6f   Zhu Yi   wireless: move so...
442
443
444
445
  	switch (hdr->frame_control &
  		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
  	case cpu_to_le16(IEEE80211_FCTL_TODS):
  		if (unlikely(iftype != NL80211_IFTYPE_AP &&
074ac8df9   Johannes Berg   cfg80211/nl80211:...
446
447
  			     iftype != NL80211_IFTYPE_AP_VLAN &&
  			     iftype != NL80211_IFTYPE_P2P_GO))
e31a16d6f   Zhu Yi   wireless: move so...
448
449
450
451
  			return -1;
  		break;
  	case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
  		if (unlikely(iftype != NL80211_IFTYPE_WDS &&
f14543ee4   Felix Fietkau   mac80211: impleme...
452
453
454
  			     iftype != NL80211_IFTYPE_MESH_POINT &&
  			     iftype != NL80211_IFTYPE_AP_VLAN &&
  			     iftype != NL80211_IFTYPE_STATION))
e31a16d6f   Zhu Yi   wireless: move so...
455
456
  			return -1;
  		if (iftype == NL80211_IFTYPE_MESH_POINT) {
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
457
  			if (mesh_flags == MESH_FLAGS_AE_A4)
e3cf8b3f7   Zhu Yi   mac80211: support...
458
  				return -1;
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
459
  			if (mesh_flags == MESH_FLAGS_AE_A5_A6) {
e3cf8b3f7   Zhu Yi   mac80211: support...
460
461
  				skb_copy_bits(skb, hdrlen +
  					offsetof(struct ieee80211s_hdr, eaddr1),
2d1c304cb   Felix Fietkau   cfg80211: add fun...
462
  					tmp.h_dest, 2 * ETH_ALEN);
e31a16d6f   Zhu Yi   wireless: move so...
463
  			}
2d1c304cb   Felix Fietkau   cfg80211: add fun...
464
  			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
e31a16d6f   Zhu Yi   wireless: move so...
465
466
467
  		}
  		break;
  	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
3c5772a52   Javier Cardona   mac80211: Use 3-a...
468
  		if ((iftype != NL80211_IFTYPE_STATION &&
074ac8df9   Johannes Berg   cfg80211/nl80211:...
469
470
  		     iftype != NL80211_IFTYPE_P2P_CLIENT &&
  		     iftype != NL80211_IFTYPE_MESH_POINT) ||
2d1c304cb   Felix Fietkau   cfg80211: add fun...
471
472
  		    (is_multicast_ether_addr(tmp.h_dest) &&
  		     ether_addr_equal(tmp.h_source, addr)))
e31a16d6f   Zhu Yi   wireless: move so...
473
  			return -1;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
474
  		if (iftype == NL80211_IFTYPE_MESH_POINT) {
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
475
  			if (mesh_flags == MESH_FLAGS_AE_A5_A6)
7dd111e8e   Johannes Berg   wireless: drop in...
476
  				return -1;
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
477
  			if (mesh_flags == MESH_FLAGS_AE_A4)
e3cf8b3f7   Zhu Yi   mac80211: support...
478
479
  				skb_copy_bits(skb, hdrlen +
  					offsetof(struct ieee80211s_hdr, eaddr1),
2d1c304cb   Felix Fietkau   cfg80211: add fun...
480
481
  					tmp.h_source, ETH_ALEN);
  			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
3c5772a52   Javier Cardona   mac80211: Use 3-a...
482
  		}
e31a16d6f   Zhu Yi   wireless: move so...
483
484
  		break;
  	case cpu_to_le16(0):
941c93cd0   Arik Nemtsov   mac80211: data pa...
485
  		if (iftype != NL80211_IFTYPE_ADHOC &&
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
486
487
  		    iftype != NL80211_IFTYPE_STATION &&
  		    iftype != NL80211_IFTYPE_OCB)
941c93cd0   Arik Nemtsov   mac80211: data pa...
488
  				return -1;
e31a16d6f   Zhu Yi   wireless: move so...
489
490
  		break;
  	}
2d1c304cb   Felix Fietkau   cfg80211: add fun...
491
492
  	skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
  	tmp.h_proto = payload.proto;
e31a16d6f   Zhu Yi   wireless: move so...
493

2d1c304cb   Felix Fietkau   cfg80211: add fun...
494
495
496
497
  	if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
  		    tmp.h_proto != htons(ETH_P_AARP) &&
  		    tmp.h_proto != htons(ETH_P_IPX)) ||
  		   ether_addr_equal(payload.hdr, bridge_tunnel_header)))
e31a16d6f   Zhu Yi   wireless: move so...
498
499
  		/* remove RFC1042 or Bridge-Tunnel encapsulation and
  		 * replace EtherType */
2d1c304cb   Felix Fietkau   cfg80211: add fun...
500
501
  		hdrlen += ETH_ALEN + 2;
  	else
c041778c9   Felix Fietkau   cfg80211: fix pro...
502
  		tmp.h_proto = htons(skb->len - hdrlen);
2d1c304cb   Felix Fietkau   cfg80211: add fun...
503
504
  
  	pskb_pull(skb, hdrlen);
e31a16d6f   Zhu Yi   wireless: move so...
505

2d1c304cb   Felix Fietkau   cfg80211: add fun...
506
  	if (!ehdr)
d58ff3512   Johannes Berg   networking: make ...
507
  		ehdr = skb_push(skb, sizeof(struct ethhdr));
2d1c304cb   Felix Fietkau   cfg80211: add fun...
508
  	memcpy(ehdr, &tmp, sizeof(tmp));
e31a16d6f   Zhu Yi   wireless: move so...
509
510
  	return 0;
  }
7f6990c83   Johannes Berg   cfg80211: let iee...
511
  EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
e31a16d6f   Zhu Yi   wireless: move so...
512

eaf85ca7f   Zhu Yi   wireless: add iee...
513
  int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
c1e5f4714   Johannes Berg   cfg80211: constif...
514
515
  			     enum nl80211_iftype iftype,
  			     const u8 *bssid, bool qos)
e31a16d6f   Zhu Yi   wireless: move so...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  {
  	struct ieee80211_hdr hdr;
  	u16 hdrlen, ethertype;
  	__le16 fc;
  	const u8 *encaps_data;
  	int encaps_len, skip_header_bytes;
  	int nh_pos, h_pos;
  	int head_need;
  
  	if (unlikely(skb->len < ETH_HLEN))
  		return -EINVAL;
  
  	nh_pos = skb_network_header(skb) - skb->data;
  	h_pos = skb_transport_header(skb) - skb->data;
  
  	/* convert Ethernet header to proper 802.11 header (based on
  	 * operation mode) */
  	ethertype = (skb->data[12] << 8) | skb->data[13];
  	fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
  
  	switch (iftype) {
  	case NL80211_IFTYPE_AP:
  	case NL80211_IFTYPE_AP_VLAN:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
539
  	case NL80211_IFTYPE_P2P_GO:
e31a16d6f   Zhu Yi   wireless: move so...
540
541
542
543
544
545
546
547
  		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
  		/* DA BSSID SA */
  		memcpy(hdr.addr1, skb->data, ETH_ALEN);
  		memcpy(hdr.addr2, addr, ETH_ALEN);
  		memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
  		hdrlen = 24;
  		break;
  	case NL80211_IFTYPE_STATION:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
548
  	case NL80211_IFTYPE_P2P_CLIENT:
e31a16d6f   Zhu Yi   wireless: move so...
549
550
551
552
553
554
555
  		fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
  		/* BSSID SA DA */
  		memcpy(hdr.addr1, bssid, ETH_ALEN);
  		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
  		memcpy(hdr.addr3, skb->data, ETH_ALEN);
  		hdrlen = 24;
  		break;
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
556
  	case NL80211_IFTYPE_OCB:
e31a16d6f   Zhu Yi   wireless: move so...
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
  	case NL80211_IFTYPE_ADHOC:
  		/* DA SA BSSID */
  		memcpy(hdr.addr1, skb->data, ETH_ALEN);
  		memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
  		memcpy(hdr.addr3, bssid, ETH_ALEN);
  		hdrlen = 24;
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	if (qos) {
  		fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
  		hdrlen += 2;
  	}
  
  	hdr.frame_control = fc;
  	hdr.duration_id = 0;
  	hdr.seq_ctrl = 0;
  
  	skip_header_bytes = ETH_HLEN;
  	if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
  		encaps_data = bridge_tunnel_header;
  		encaps_len = sizeof(bridge_tunnel_header);
  		skip_header_bytes -= 2;
e5c5d22e8   Simon Horman   net: add ETH_P_80...
582
  	} else if (ethertype >= ETH_P_802_3_MIN) {
e31a16d6f   Zhu Yi   wireless: move so...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  		encaps_data = rfc1042_header;
  		encaps_len = sizeof(rfc1042_header);
  		skip_header_bytes -= 2;
  	} else {
  		encaps_data = NULL;
  		encaps_len = 0;
  	}
  
  	skb_pull(skb, skip_header_bytes);
  	nh_pos -= skip_header_bytes;
  	h_pos -= skip_header_bytes;
  
  	head_need = hdrlen + encaps_len - skb_headroom(skb);
  
  	if (head_need > 0 || skb_cloned(skb)) {
  		head_need = max(head_need, 0);
  		if (head_need)
  			skb_orphan(skb);
24616152b   Joe Perches   wireless: Remove ...
601
  		if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
e31a16d6f   Zhu Yi   wireless: move so...
602
  			return -ENOMEM;
e31a16d6f   Zhu Yi   wireless: move so...
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  	}
  
  	if (encaps_data) {
  		memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
  		nh_pos += encaps_len;
  		h_pos += encaps_len;
  	}
  
  	memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
  
  	nh_pos += hdrlen;
  	h_pos += hdrlen;
  
  	/* Update skb pointers to various headers since this modified frame
  	 * is going to go through Linux networking code that may potentially
  	 * need things like pointer to IP header. */
3ef523aee   Zhang Shengju   wireless: use res...
619
  	skb_reset_mac_header(skb);
e31a16d6f   Zhu Yi   wireless: move so...
620
621
622
623
624
625
  	skb_set_network_header(skb, nh_pos);
  	skb_set_transport_header(skb, h_pos);
  
  	return 0;
  }
  EXPORT_SYMBOL(ieee80211_data_from_8023);
2b67f944f   Felix Fietkau   cfg80211: reuse e...
626
627
628
629
630
631
  static void
  __frame_add_frag(struct sk_buff *skb, struct page *page,
  		 void *ptr, int len, int size)
  {
  	struct skb_shared_info *sh = skb_shinfo(skb);
  	int page_offset;
6d061f9f6   Joonsoo Kim   mm/page_ref: use ...
632
  	page_ref_inc(page);
2b67f944f   Felix Fietkau   cfg80211: reuse e...
633
634
635
636
637
638
639
640
641
  	page_offset = ptr - page_address(page);
  	skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
  }
  
  static void
  __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
  			    int offset, int len)
  {
  	struct skb_shared_info *sh = skb_shinfo(skb);
aa1702dd1   Matthias Kaehlcke   cfg80211: Fix arr...
642
  	const skb_frag_t *frag = &sh->frags[0];
2b67f944f   Felix Fietkau   cfg80211: reuse e...
643
644
645
646
647
648
649
650
651
652
653
654
  	struct page *frag_page;
  	void *frag_ptr;
  	int frag_len, frag_size;
  	int head_size = skb->len - skb->data_len;
  	int cur_len;
  
  	frag_page = virt_to_head_page(skb->head);
  	frag_ptr = skb->data;
  	frag_size = head_size;
  
  	while (offset >= frag_size) {
  		offset -= frag_size;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
655
656
657
  		frag_page = skb_frag_page(frag);
  		frag_ptr = skb_frag_address(frag);
  		frag_size = skb_frag_size(frag);
aa1702dd1   Matthias Kaehlcke   cfg80211: Fix arr...
658
  		frag++;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
659
660
661
662
663
664
665
666
667
668
669
  	}
  
  	frag_ptr += offset;
  	frag_len = frag_size - offset;
  
  	cur_len = min(len, frag_len);
  
  	__frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
  	len -= cur_len;
  
  	while (len > 0) {
2b67f944f   Felix Fietkau   cfg80211: reuse e...
670
671
672
673
674
  		frag_len = skb_frag_size(frag);
  		cur_len = min(len, frag_len);
  		__frame_add_frag(frame, skb_frag_page(frag),
  				 skb_frag_address(frag), cur_len, frag_len);
  		len -= cur_len;
aa1702dd1   Matthias Kaehlcke   cfg80211: Fix arr...
675
  		frag++;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
676
677
  	}
  }
230fd28a9   Felix Fietkau   cfg80211: add sup...
678
679
  static struct sk_buff *
  __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
2b67f944f   Felix Fietkau   cfg80211: reuse e...
680
  		       int offset, int len, bool reuse_frag)
230fd28a9   Felix Fietkau   cfg80211: add sup...
681
682
  {
  	struct sk_buff *frame;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
683
  	int cur_len = len;
230fd28a9   Felix Fietkau   cfg80211: add sup...
684
685
686
687
688
  
  	if (skb->len - offset < len)
  		return NULL;
  
  	/*
2b67f944f   Felix Fietkau   cfg80211: reuse e...
689
690
691
692
693
694
695
696
  	 * When reusing framents, copy some data to the head to simplify
  	 * ethernet header handling and speed up protocol header processing
  	 * in the stack later.
  	 */
  	if (reuse_frag)
  		cur_len = min_t(int, len, 32);
  
  	/*
230fd28a9   Felix Fietkau   cfg80211: add sup...
697
698
699
  	 * Allocate and reserve two bytes more for payload
  	 * alignment since sizeof(struct ethhdr) is 14.
  	 */
2b67f944f   Felix Fietkau   cfg80211: reuse e...
700
  	frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
16a910a67   Gregory Greenman   cfg80211: handle ...
701
702
  	if (!frame)
  		return NULL;
230fd28a9   Felix Fietkau   cfg80211: add sup...
703
704
  
  	skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
2b67f944f   Felix Fietkau   cfg80211: reuse e...
705
706
707
708
709
710
711
712
  	skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
  
  	len -= cur_len;
  	if (!len)
  		return frame;
  
  	offset += cur_len;
  	__ieee80211_amsdu_copy_frag(skb, frame, offset, len);
230fd28a9   Felix Fietkau   cfg80211: add sup...
713
714
715
  
  	return frame;
  }
eaf85ca7f   Zhu Yi   wireless: add iee...
716
717
718
  
  void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
  			      const u8 *addr, enum nl80211_iftype iftype,
8b3becadc   Yogesh Ashok Powar   cfg80211: make st...
719
  			      const unsigned int extra_headroom,
8b935ee2e   Johannes Berg   cfg80211: add abi...
720
  			      const u8 *check_da, const u8 *check_sa)
eaf85ca7f   Zhu Yi   wireless: add iee...
721
  {
230fd28a9   Felix Fietkau   cfg80211: add sup...
722
  	unsigned int hlen = ALIGN(extra_headroom, 4);
eaf85ca7f   Zhu Yi   wireless: add iee...
723
724
725
  	struct sk_buff *frame = NULL;
  	u16 ethertype;
  	u8 *payload;
7f6990c83   Johannes Berg   cfg80211: let iee...
726
  	int offset = 0, remaining;
230fd28a9   Felix Fietkau   cfg80211: add sup...
727
  	struct ethhdr eth;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
728
  	bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
2bf0ccc70   Felix Fietkau   cfg80211: fix fau...
729
  	bool reuse_skb = false;
230fd28a9   Felix Fietkau   cfg80211: add sup...
730
  	bool last = false;
88665f5a7   Felix Fietkau   mac80211: move A-...
731

230fd28a9   Felix Fietkau   cfg80211: add sup...
732
733
734
  	while (!last) {
  		unsigned int subframe_len;
  		int len;
eaf85ca7f   Zhu Yi   wireless: add iee...
735
  		u8 padding;
eaf85ca7f   Zhu Yi   wireless: add iee...
736

230fd28a9   Felix Fietkau   cfg80211: add sup...
737
738
739
  		skb_copy_bits(skb, offset, &eth, sizeof(eth));
  		len = ntohs(eth.h_proto);
  		subframe_len = sizeof(struct ethhdr) + len;
eaf85ca7f   Zhu Yi   wireless: add iee...
740
  		padding = (4 - subframe_len) & 0x3;
230fd28a9   Felix Fietkau   cfg80211: add sup...
741

eaf85ca7f   Zhu Yi   wireless: add iee...
742
  		/* the last MSDU has no padding */
230fd28a9   Felix Fietkau   cfg80211: add sup...
743
  		remaining = skb->len - offset;
eaf85ca7f   Zhu Yi   wireless: add iee...
744
745
  		if (subframe_len > remaining)
  			goto purge;
230fd28a9   Felix Fietkau   cfg80211: add sup...
746
  		offset += sizeof(struct ethhdr);
230fd28a9   Felix Fietkau   cfg80211: add sup...
747
  		last = remaining <= subframe_len + padding;
8b935ee2e   Johannes Berg   cfg80211: add abi...
748
749
750
751
752
753
754
755
756
757
  
  		/* FIXME: should we really accept multicast DA? */
  		if ((check_da && !is_multicast_ether_addr(eth.h_dest) &&
  		     !ether_addr_equal(check_da, eth.h_dest)) ||
  		    (check_sa && !ether_addr_equal(check_sa, eth.h_source))) {
  			offset += len + padding;
  			continue;
  		}
  
  		/* reuse skb for the last subframe */
2b67f944f   Felix Fietkau   cfg80211: reuse e...
758
  		if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
230fd28a9   Felix Fietkau   cfg80211: add sup...
759
  			skb_pull(skb, offset);
eaf85ca7f   Zhu Yi   wireless: add iee...
760
  			frame = skb;
230fd28a9   Felix Fietkau   cfg80211: add sup...
761
762
  			reuse_skb = true;
  		} else {
2b67f944f   Felix Fietkau   cfg80211: reuse e...
763
764
  			frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
  						       reuse_frag);
eaf85ca7f   Zhu Yi   wireless: add iee...
765
766
  			if (!frame)
  				goto purge;
230fd28a9   Felix Fietkau   cfg80211: add sup...
767
  			offset += len + padding;
eaf85ca7f   Zhu Yi   wireless: add iee...
768
769
770
771
772
773
774
775
  		}
  
  		skb_reset_network_header(frame);
  		frame->dev = skb->dev;
  		frame->priority = skb->priority;
  
  		payload = frame->data;
  		ethertype = (payload[6] << 8) | payload[7];
ac422d3cc   Joe Perches   wireless: Convert...
776
  		if (likely((ether_addr_equal(payload, rfc1042_header) &&
eaf85ca7f   Zhu Yi   wireless: add iee...
777
  			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
ac422d3cc   Joe Perches   wireless: Convert...
778
  			   ether_addr_equal(payload, bridge_tunnel_header))) {
230fd28a9   Felix Fietkau   cfg80211: add sup...
779
780
  			eth.h_proto = htons(ethertype);
  			skb_pull(frame, ETH_ALEN + 2);
eaf85ca7f   Zhu Yi   wireless: add iee...
781
  		}
230fd28a9   Felix Fietkau   cfg80211: add sup...
782
783
  
  		memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
eaf85ca7f   Zhu Yi   wireless: add iee...
784
785
  		__skb_queue_tail(list, frame);
  	}
230fd28a9   Felix Fietkau   cfg80211: add sup...
786
787
  	if (!reuse_skb)
  		dev_kfree_skb(skb);
eaf85ca7f   Zhu Yi   wireless: add iee...
788
789
790
791
  	return;
  
   purge:
  	__skb_queue_purge(list);
eaf85ca7f   Zhu Yi   wireless: add iee...
792
793
794
  	dev_kfree_skb(skb);
  }
  EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
e31a16d6f   Zhu Yi   wireless: move so...
795
  /* Given a data frame determine the 802.1p/1d tag to use. */
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
796
797
  unsigned int cfg80211_classify8021d(struct sk_buff *skb,
  				    struct cfg80211_qos_map *qos_map)
e31a16d6f   Zhu Yi   wireless: move so...
798
799
  {
  	unsigned int dscp;
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
800
  	unsigned char vlan_priority;
e31a16d6f   Zhu Yi   wireless: move so...
801
802
803
804
805
806
807
808
  
  	/* skb->priority values from 256->263 are magic values to
  	 * directly indicate a specific 802.1d priority.  This is used
  	 * to allow 802.1d priority to be passed directly in from VLAN
  	 * tags, etc.
  	 */
  	if (skb->priority >= 256 && skb->priority <= 263)
  		return skb->priority - 256;
df8a39def   Jiri Pirko   net: rename vlan_...
809
810
  	if (skb_vlan_tag_present(skb)) {
  		vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK)
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
811
812
813
814
  			>> VLAN_PRIO_SHIFT;
  		if (vlan_priority > 0)
  			return vlan_priority;
  	}
e31a16d6f   Zhu Yi   wireless: move so...
815
816
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
b156579b1   Dave Täht   wireless: Treat I...
817
818
819
820
  		dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
  		break;
  	case htons(ETH_P_IPV6):
  		dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc;
e31a16d6f   Zhu Yi   wireless: move so...
821
  		break;
960d97f95   Simon Wunderlich   cfg80211: add MPL...
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
  	case htons(ETH_P_MPLS_UC):
  	case htons(ETH_P_MPLS_MC): {
  		struct mpls_label mpls_tmp, *mpls;
  
  		mpls = skb_header_pointer(skb, sizeof(struct ethhdr),
  					  sizeof(*mpls), &mpls_tmp);
  		if (!mpls)
  			return 0;
  
  		return (ntohl(mpls->entry) & MPLS_LS_TC_MASK)
  			>> MPLS_LS_TC_SHIFT;
  	}
  	case htons(ETH_P_80221):
  		/* 802.21 is always network control traffic */
  		return 7;
e31a16d6f   Zhu Yi   wireless: move so...
837
838
839
  	default:
  		return 0;
  	}
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
840
841
842
843
844
845
846
847
848
849
850
851
852
853
  	if (qos_map) {
  		unsigned int i, tmp_dscp = dscp >> 2;
  
  		for (i = 0; i < qos_map->num_des; i++) {
  			if (tmp_dscp == qos_map->dscp_exception[i].dscp)
  				return qos_map->dscp_exception[i].up;
  		}
  
  		for (i = 0; i < 8; i++) {
  			if (tmp_dscp >= qos_map->up[i].low &&
  			    tmp_dscp <= qos_map->up[i].high)
  				return i;
  		}
  	}
e31a16d6f   Zhu Yi   wireless: move so...
854
855
856
  	return dscp >> 5;
  }
  EXPORT_SYMBOL(cfg80211_classify8021d);
517357c68   Johannes Berg   cfg80211: assimil...
857
858
859
  
  const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
  {
9caf03640   Johannes Berg   cfg80211: fix BSS...
860
861
862
863
  	const struct cfg80211_bss_ies *ies;
  
  	ies = rcu_dereference(bss->ies);
  	if (!ies)
517357c68   Johannes Berg   cfg80211: assimil...
864
  		return NULL;
9caf03640   Johannes Berg   cfg80211: fix BSS...
865
866
  
  	return cfg80211_find_ie(ie, ies->data, ies->len);
517357c68   Johannes Berg   cfg80211: assimil...
867
868
  }
  EXPORT_SYMBOL(ieee80211_bss_get_ie);
fffd0934b   Johannes Berg   cfg80211: rework ...
869
870
871
  
  void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
872
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
fffd0934b   Johannes Berg   cfg80211: rework ...
873
874
875
876
877
  	struct net_device *dev = wdev->netdev;
  	int i;
  
  	if (!wdev->connect_keys)
  		return;
b8676221f   David Spinadel   cfg80211: Add sup...
878
  	for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) {
fffd0934b   Johannes Berg   cfg80211: rework ...
879
880
  		if (!wdev->connect_keys->params[i].cipher)
  			continue;
e35e4d28b   Hila Gonen   cfg80211: add wra...
881
882
  		if (rdev_add_key(rdev, dev, i, false, NULL,
  				 &wdev->connect_keys->params[i])) {
e9c0268f0   Joe Perches   net/wireless: Use...
883
884
  			netdev_err(dev, "failed to set key %d
  ", i);
1e056665e   Zhu Yi   cfg80211: avoid s...
885
886
  			continue;
  		}
d4f299786   Johannes Berg   cfg80211: combine...
887
888
889
890
891
892
  		if (wdev->connect_keys->def == i &&
  		    rdev_set_default_key(rdev, dev, i, true, true)) {
  			netdev_err(dev, "failed to set defkey %d
  ", i);
  			continue;
  		}
fffd0934b   Johannes Berg   cfg80211: rework ...
893
  	}
b47f610bd   Johannes Berg   cfg80211: clear c...
894
  	kzfree(wdev->connect_keys);
fffd0934b   Johannes Berg   cfg80211: rework ...
895
896
  	wdev->connect_keys = NULL;
  }
3d54d2551   Johannes Berg   cfg80211: clean u...
897

1f6fc43e6   Daniel Drake   cfg80211: process...
898
  void cfg80211_process_wdev_events(struct wireless_dev *wdev)
3d54d2551   Johannes Berg   cfg80211: clean u...
899
900
901
  {
  	struct cfg80211_event *ev;
  	unsigned long flags;
3d54d2551   Johannes Berg   cfg80211: clean u...
902
903
904
905
906
907
908
909
910
911
912
  
  	spin_lock_irqsave(&wdev->event_lock, flags);
  	while (!list_empty(&wdev->event_list)) {
  		ev = list_first_entry(&wdev->event_list,
  				      struct cfg80211_event, list);
  		list_del(&ev->list);
  		spin_unlock_irqrestore(&wdev->event_lock, flags);
  
  		wdev_lock(wdev);
  		switch (ev->type) {
  		case EVENT_CONNECT_RESULT:
3d54d2551   Johannes Berg   cfg80211: clean u...
913
  			__cfg80211_connect_result(
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
914
915
916
  				wdev->netdev,
  				&ev->cr,
  				ev->cr.status == WLAN_STATUS_SUCCESS);
3d54d2551   Johannes Berg   cfg80211: clean u...
917
918
  			break;
  		case EVENT_ROAMED:
29ce6ecbb   Avraham Stern   cfg80211: unify c...
919
  			__cfg80211_roamed(wdev, &ev->rm);
3d54d2551   Johannes Berg   cfg80211: clean u...
920
921
922
923
  			break;
  		case EVENT_DISCONNECTED:
  			__cfg80211_disconnected(wdev->netdev,
  						ev->dc.ie, ev->dc.ie_len,
80279fb7b   Johannes Berg   cfg80211: properl...
924
925
  						ev->dc.reason,
  						!ev->dc.locally_generated);
3d54d2551   Johannes Berg   cfg80211: clean u...
926
927
  			break;
  		case EVENT_IBSS_JOINED:
fe94f3a4f   Antonio Quartulli   cfg80211: fix cha...
928
929
  			__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
  					       ev->ij.channel);
3d54d2551   Johannes Berg   cfg80211: clean u...
930
  			break;
f04c22033   Michal Kazior   cfg80211: export ...
931
932
933
  		case EVENT_STOPPED:
  			__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
  			break;
3d54d2551   Johannes Berg   cfg80211: clean u...
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  		}
  		wdev_unlock(wdev);
  
  		kfree(ev);
  
  		spin_lock_irqsave(&wdev->event_lock, flags);
  	}
  	spin_unlock_irqrestore(&wdev->event_lock, flags);
  }
  
  void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
  {
  	struct wireless_dev *wdev;
  
  	ASSERT_RTNL();
3d54d2551   Johannes Berg   cfg80211: clean u...
949

53873f134   Johannes Berg   cfg80211: make wd...
950
  	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
3d54d2551   Johannes Berg   cfg80211: clean u...
951
  		cfg80211_process_wdev_events(wdev);
3d54d2551   Johannes Berg   cfg80211: clean u...
952
953
954
955
  }
  
  int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
  			  struct net_device *dev, enum nl80211_iftype ntype,
818a986e4   Johannes Berg   cfg80211: move ad...
956
  			  struct vif_params *params)
3d54d2551   Johannes Berg   cfg80211: clean u...
957
958
959
  {
  	int err;
  	enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
73fb08e24   Zhao, Gang   cfg80211: remove ...
960
  	ASSERT_RTNL();
3d54d2551   Johannes Berg   cfg80211: clean u...
961
962
963
964
  
  	/* don't support changing VLANs, you just re-create them */
  	if (otype == NL80211_IFTYPE_AP_VLAN)
  		return -EOPNOTSUPP;
cb3b7d876   Ayala Beker   cfg80211: add sta...
965
966
967
  	/* cannot change into P2P device or NAN */
  	if (ntype == NL80211_IFTYPE_P2P_DEVICE ||
  	    ntype == NL80211_IFTYPE_NAN)
98104fded   Johannes Berg   cfg80211: add P2P...
968
  		return -EOPNOTSUPP;
3d54d2551   Johannes Berg   cfg80211: clean u...
969
970
971
  	if (!rdev->ops->change_virtual_intf ||
  	    !(rdev->wiphy.interface_modes & (1 << ntype)))
  		return -EOPNOTSUPP;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
972
  	/* if it's part of a bridge, reject changing type to station/ibss */
f350a0a87   Jiri Pirko   bridge: use rx_ha...
973
  	if ((dev->priv_flags & IFF_BRIDGE_PORT) &&
074ac8df9   Johannes Berg   cfg80211/nl80211:...
974
975
976
  	    (ntype == NL80211_IFTYPE_ADHOC ||
  	     ntype == NL80211_IFTYPE_STATION ||
  	     ntype == NL80211_IFTYPE_P2P_CLIENT))
ad4bb6f88   Johannes Berg   cfg80211: disallo...
977
  		return -EBUSY;
6cbfb1bb6   Michal Kazior   cfg80211: ignore ...
978
  	if (ntype != otype) {
9bc383de3   Johannes Berg   cfg80211: introdu...
979
  		dev->ieee80211_ptr->use_4addr = false;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
980
  		dev->ieee80211_ptr->mesh_id_up_len = 0;
194ff52d4   Johannes Berg   cfg80211/mac80211...
981
  		wdev_lock(dev->ieee80211_ptr);
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
982
  		rdev_set_qos_map(rdev, dev, NULL);
194ff52d4   Johannes Berg   cfg80211/mac80211...
983
  		wdev_unlock(dev->ieee80211_ptr);
9bc383de3   Johannes Berg   cfg80211: introdu...
984

3d54d2551   Johannes Berg   cfg80211: clean u...
985
  		switch (otype) {
ac800140c   Michal Kazior   cfg80211: .stop_a...
986
  		case NL80211_IFTYPE_AP:
7c8d5e03a   Ilan Peer   cfg80211: send st...
987
  			cfg80211_stop_ap(rdev, dev, true);
ac800140c   Michal Kazior   cfg80211: .stop_a...
988
  			break;
3d54d2551   Johannes Berg   cfg80211: clean u...
989
990
991
992
  		case NL80211_IFTYPE_ADHOC:
  			cfg80211_leave_ibss(rdev, dev, false);
  			break;
  		case NL80211_IFTYPE_STATION:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
993
  		case NL80211_IFTYPE_P2P_CLIENT:
83739b03d   Johannes Berg   cfg80211: remove ...
994
  			wdev_lock(dev->ieee80211_ptr);
3d54d2551   Johannes Berg   cfg80211: clean u...
995
996
  			cfg80211_disconnect(rdev, dev,
  					    WLAN_REASON_DEAUTH_LEAVING, true);
83739b03d   Johannes Berg   cfg80211: remove ...
997
  			wdev_unlock(dev->ieee80211_ptr);
3d54d2551   Johannes Berg   cfg80211: clean u...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  			break;
  		case NL80211_IFTYPE_MESH_POINT:
  			/* mesh should be handled? */
  			break;
  		default:
  			break;
  		}
  
  		cfg80211_process_rdev_events(rdev);
  	}
818a986e4   Johannes Berg   cfg80211: move ad...
1008
  	err = rdev_change_virtual_intf(rdev, dev, ntype, params);
3d54d2551   Johannes Berg   cfg80211: clean u...
1009
1010
  
  	WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
9bc383de3   Johannes Berg   cfg80211: introdu...
1011
1012
  	if (!err && params && params->use_4addr != -1)
  		dev->ieee80211_ptr->use_4addr = params->use_4addr;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1013
1014
1015
1016
1017
1018
1019
  	if (!err) {
  		dev->priv_flags &= ~IFF_DONT_BRIDGE;
  		switch (ntype) {
  		case NL80211_IFTYPE_STATION:
  			if (dev->ieee80211_ptr->use_4addr)
  				break;
  			/* fall through */
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
1020
  		case NL80211_IFTYPE_OCB:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1021
  		case NL80211_IFTYPE_P2P_CLIENT:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1022
1023
1024
  		case NL80211_IFTYPE_ADHOC:
  			dev->priv_flags |= IFF_DONT_BRIDGE;
  			break;
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1025
  		case NL80211_IFTYPE_P2P_GO:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
  		case NL80211_IFTYPE_AP:
  		case NL80211_IFTYPE_AP_VLAN:
  		case NL80211_IFTYPE_WDS:
  		case NL80211_IFTYPE_MESH_POINT:
  			/* bridging OK */
  			break;
  		case NL80211_IFTYPE_MONITOR:
  			/* monitor can't bridge anyway */
  			break;
  		case NL80211_IFTYPE_UNSPECIFIED:
2e161f78e   Johannes Berg   cfg80211/mac80211...
1036
  		case NUM_NL80211_IFTYPES:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1037
1038
  			/* not happening */
  			break;
98104fded   Johannes Berg   cfg80211: add P2P...
1039
  		case NL80211_IFTYPE_P2P_DEVICE:
cb3b7d876   Ayala Beker   cfg80211: add sta...
1040
  		case NL80211_IFTYPE_NAN:
98104fded   Johannes Berg   cfg80211: add P2P...
1041
1042
  			WARN_ON(1);
  			break;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1043
1044
  		}
  	}
dbbae26af   Michal Kazior   cfg80211: track m...
1045
1046
1047
1048
  	if (!err && ntype != otype && netif_running(dev)) {
  		cfg80211_update_iface_num(rdev, ntype, 1);
  		cfg80211_update_iface_num(rdev, otype, -1);
  	}
3d54d2551   Johannes Berg   cfg80211: clean u...
1049
1050
  	return err;
  }
254416aae   John W. Linville   wireless: report ...
1051

0c1eca4e2   Johannes Berg   cfg80211: refacto...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  static u32 cfg80211_calculate_bitrate_ht(struct rate_info *rate)
  {
  	int modulation, streams, bitrate;
  
  	/* the formula below does only work for MCS values smaller than 32 */
  	if (WARN_ON_ONCE(rate->mcs >= 32))
  		return 0;
  
  	modulation = rate->mcs & 7;
  	streams = (rate->mcs >> 3) + 1;
  
  	bitrate = (rate->bw == RATE_INFO_BW_40) ? 13500000 : 6500000;
  
  	if (modulation < 4)
  		bitrate *= (modulation + 1);
  	else if (modulation == 4)
  		bitrate *= (modulation + 2);
  	else
  		bitrate *= (modulation + 3);
  
  	bitrate *= streams;
  
  	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
  		bitrate = (bitrate / 9) * 10;
  
  	/* do NOT round down here */
  	return (bitrate + 50000) / 100000;
  }
95ddc1fc4   Vladimir Kondratiev   cfg80211: bitrate...
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
  {
  	static const u32 __mcs2bitrate[] = {
  		/* control PHY */
  		[0] =   275,
  		/* SC PHY */
  		[1] =  3850,
  		[2] =  7700,
  		[3] =  9625,
  		[4] = 11550,
  		[5] = 12512, /* 1251.25 mbps */
  		[6] = 15400,
  		[7] = 19250,
  		[8] = 23100,
  		[9] = 25025,
  		[10] = 30800,
  		[11] = 38500,
  		[12] = 46200,
  		/* OFDM PHY */
  		[13] =  6930,
  		[14] =  8662, /* 866.25 mbps */
  		[15] = 13860,
  		[16] = 17325,
  		[17] = 20790,
  		[18] = 27720,
  		[19] = 34650,
  		[20] = 41580,
  		[21] = 45045,
  		[22] = 51975,
  		[23] = 62370,
  		[24] = 67568, /* 6756.75 mbps */
  		/* LP-SC PHY */
  		[25] =  6260,
  		[26] =  8340,
  		[27] = 11120,
  		[28] = 12510,
  		[29] = 16680,
  		[30] = 22240,
  		[31] = 25030,
  	};
  
  	if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate)))
  		return 0;
  
  	return __mcs2bitrate[rate->mcs];
  }
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
  {
  	static const u32 base[4][10] = {
  		{   6500000,
  		   13000000,
  		   19500000,
  		   26000000,
  		   39000000,
  		   52000000,
  		   58500000,
  		   65000000,
  		   78000000,
8fdd136f2   Pedersen, Thomas   cfg80211: add bit...
1138
1139
  		/* not in the spec, but some devices use this: */
  		   86500000,
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1140
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
  		},
  		{  13500000,
  		   27000000,
  		   40500000,
  		   54000000,
  		   81000000,
  		  108000000,
  		  121500000,
  		  135000000,
  		  162000000,
  		  180000000,
  		},
  		{  29300000,
  		   58500000,
  		   87800000,
  		  117000000,
  		  175500000,
  		  234000000,
  		  263300000,
  		  292500000,
  		  351000000,
  		  390000000,
  		},
  		{  58500000,
  		  117000000,
  		  175500000,
  		  234000000,
  		  351000000,
  		  468000000,
  		  526500000,
  		  585000000,
  		  702000000,
  		  780000000,
  		},
  	};
  	u32 bitrate;
  	int idx;
ca8fe2506   Johannes Berg   cfg80211: improve...
1177
1178
  	if (rate->mcs > 9)
  		goto warn;
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1179

b51f3beec   Johannes Berg   cfg80211: change ...
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
  	switch (rate->bw) {
  	case RATE_INFO_BW_160:
  		idx = 3;
  		break;
  	case RATE_INFO_BW_80:
  		idx = 2;
  		break;
  	case RATE_INFO_BW_40:
  		idx = 1;
  		break;
  	case RATE_INFO_BW_5:
  	case RATE_INFO_BW_10:
  	default:
ca8fe2506   Johannes Berg   cfg80211: improve...
1193
  		goto warn;
b51f3beec   Johannes Berg   cfg80211: change ...
1194
1195
1196
  	case RATE_INFO_BW_20:
  		idx = 0;
  	}
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1197
1198
1199
1200
1201
1202
1203
1204
1205
  
  	bitrate = base[idx][rate->mcs];
  	bitrate *= rate->nss;
  
  	if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
  		bitrate = (bitrate / 9) * 10;
  
  	/* do NOT round down here */
  	return (bitrate + 50000) / 100000;
ca8fe2506   Johannes Berg   cfg80211: improve...
1206
1207
1208
1209
1210
   warn:
  	WARN_ONCE(1, "invalid rate bw=%d, mcs=%d, nss=%d
  ",
  		  rate->bw, rate->mcs, rate->nss);
  	return 0;
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1211
  }
8eb41c8df   Vladimir Kondratiev   {nl,cfg}80211: su...
1212
  u32 cfg80211_calculate_bitrate(struct rate_info *rate)
254416aae   John W. Linville   wireless: report ...
1213
  {
0c1eca4e2   Johannes Berg   cfg80211: refacto...
1214
1215
  	if (rate->flags & RATE_INFO_FLAGS_MCS)
  		return cfg80211_calculate_bitrate_ht(rate);
95ddc1fc4   Vladimir Kondratiev   cfg80211: bitrate...
1216
1217
  	if (rate->flags & RATE_INFO_FLAGS_60G)
  		return cfg80211_calculate_bitrate_60g(rate);
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1218
1219
  	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
  		return cfg80211_calculate_bitrate_vht(rate);
254416aae   John W. Linville   wireless: report ...
1220

0c1eca4e2   Johannes Berg   cfg80211: refacto...
1221
  	return rate->legacy;
254416aae   John W. Linville   wireless: report ...
1222
  }
8097e1494   Thomas Pedersen   cfg80211: expose ...
1223
  EXPORT_SYMBOL(cfg80211_calculate_bitrate);
56d1893d9   Johannes Berg   cfg80211: restric...
1224

c216e6417   Arend van Spriel   cfg80211: change ...
1225
1226
1227
  int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
  			  enum ieee80211_p2p_attr_id attr,
  			  u8 *buf, unsigned int bufsize)
0ee453552   Johannes Berg   wireless: add uti...
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
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
1316
1317
1318
1319
1320
1321
1322
1323
  {
  	u8 *out = buf;
  	u16 attr_remaining = 0;
  	bool desired_attr = false;
  	u16 desired_len = 0;
  
  	while (len > 0) {
  		unsigned int iedatalen;
  		unsigned int copy;
  		const u8 *iedata;
  
  		if (len < 2)
  			return -EILSEQ;
  		iedatalen = ies[1];
  		if (iedatalen + 2 > len)
  			return -EILSEQ;
  
  		if (ies[0] != WLAN_EID_VENDOR_SPECIFIC)
  			goto cont;
  
  		if (iedatalen < 4)
  			goto cont;
  
  		iedata = ies + 2;
  
  		/* check WFA OUI, P2P subtype */
  		if (iedata[0] != 0x50 || iedata[1] != 0x6f ||
  		    iedata[2] != 0x9a || iedata[3] != 0x09)
  			goto cont;
  
  		iedatalen -= 4;
  		iedata += 4;
  
  		/* check attribute continuation into this IE */
  		copy = min_t(unsigned int, attr_remaining, iedatalen);
  		if (copy && desired_attr) {
  			desired_len += copy;
  			if (out) {
  				memcpy(out, iedata, min(bufsize, copy));
  				out += min(bufsize, copy);
  				bufsize -= min(bufsize, copy);
  			}
  
  
  			if (copy == attr_remaining)
  				return desired_len;
  		}
  
  		attr_remaining -= copy;
  		if (attr_remaining)
  			goto cont;
  
  		iedatalen -= copy;
  		iedata += copy;
  
  		while (iedatalen > 0) {
  			u16 attr_len;
  
  			/* P2P attribute ID & size must fit */
  			if (iedatalen < 3)
  				return -EILSEQ;
  			desired_attr = iedata[0] == attr;
  			attr_len = get_unaligned_le16(iedata + 1);
  			iedatalen -= 3;
  			iedata += 3;
  
  			copy = min_t(unsigned int, attr_len, iedatalen);
  
  			if (desired_attr) {
  				desired_len += copy;
  				if (out) {
  					memcpy(out, iedata, min(bufsize, copy));
  					out += min(bufsize, copy);
  					bufsize -= min(bufsize, copy);
  				}
  
  				if (copy == attr_len)
  					return desired_len;
  			}
  
  			iedata += copy;
  			iedatalen -= copy;
  			attr_remaining = attr_len - copy;
  		}
  
   cont:
  		len -= ies[1] + 2;
  		ies += ies[1] + 2;
  	}
  
  	if (attr_remaining && desired_attr)
  		return -EILSEQ;
  
  	return -ENOENT;
  }
  EXPORT_SYMBOL(cfg80211_get_p2p_attr);
29464ccc7   Johannes Berg   cfg80211: move IE...
1324
1325
1326
1327
1328
1329
1330
1331
1332
  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;
  }
8ac634486   Johannes Berg   cfg80211: handle ...
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
  static size_t skip_ie(const u8 *ies, size_t ielen, size_t pos)
  {
  	/* we assume a validly formed IEs buffer */
  	u8 len = ies[pos + 1];
  
  	pos += 2 + len;
  
  	/* the IE itself must have 255 bytes for fragments to follow */
  	if (len < 255)
  		return pos;
  
  	while (pos < ielen && ies[pos] == WLAN_EID_FRAGMENT) {
  		len = ies[pos + 1];
  		pos += 2 + len;
  	}
  
  	return pos;
  }
29464ccc7   Johannes Berg   cfg80211: move IE...
1351
1352
1353
1354
1355
1356
1357
1358
1359
  size_t ieee80211_ie_split_ric(const u8 *ies, size_t ielen,
  			      const u8 *ids, int n_ids,
  			      const u8 *after_ric, int n_after_ric,
  			      size_t offset)
  {
  	size_t pos = offset;
  
  	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) {
  		if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
8ac634486   Johannes Berg   cfg80211: handle ...
1360
  			pos = skip_ie(ies, ielen, pos);
29464ccc7   Johannes Berg   cfg80211: move IE...
1361
1362
1363
1364
  
  			while (pos < ielen &&
  			       !ieee80211_id_in_list(after_ric, n_after_ric,
  						     ies[pos]))
8ac634486   Johannes Berg   cfg80211: handle ...
1365
  				pos = skip_ie(ies, ielen, pos);
29464ccc7   Johannes Berg   cfg80211: move IE...
1366
  		} else {
8ac634486   Johannes Berg   cfg80211: handle ...
1367
  			pos = skip_ie(ies, ielen, pos);
29464ccc7   Johannes Berg   cfg80211: move IE...
1368
1369
1370
1371
1372
1373
  		}
  	}
  
  	return pos;
  }
  EXPORT_SYMBOL(ieee80211_ie_split_ric);
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1374
  bool ieee80211_operating_class_to_band(u8 operating_class,
57fbcce37   Johannes Berg   cfg80211: remove ...
1375
  				       enum nl80211_band *band)
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1376
1377
1378
1379
  {
  	switch (operating_class) {
  	case 112:
  	case 115 ... 127:
954a86ef4   Eliad Peller   cfg80211: add ope...
1380
  	case 128 ... 130:
57fbcce37   Johannes Berg   cfg80211: remove ...
1381
  		*band = NL80211_BAND_5GHZ;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1382
1383
1384
1385
1386
  		return true;
  	case 81:
  	case 82:
  	case 83:
  	case 84:
57fbcce37   Johannes Berg   cfg80211: remove ...
1387
  		*band = NL80211_BAND_2GHZ;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1388
  		return true;
55300a13d   Vladimir Kondratiev   cfg80211: add 60G...
1389
  	case 180:
57fbcce37   Johannes Berg   cfg80211: remove ...
1390
  		*band = NL80211_BAND_60GHZ;
55300a13d   Vladimir Kondratiev   cfg80211: add 60G...
1391
  		return true;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1392
1393
1394
1395
1396
  	}
  
  	return false;
  }
  EXPORT_SYMBOL(ieee80211_operating_class_to_band);
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
1397
1398
1399
1400
  bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
  					  u8 *op_class)
  {
  	u8 vht_opclass;
4fa55f6d2   Dan Carpenter   cfg80211: fix a t...
1401
  	u32 freq = chandef->center_freq1;
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
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
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
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
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
  
  	if (freq >= 2412 && freq <= 2472) {
  		if (chandef->width > NL80211_CHAN_WIDTH_40)
  			return false;
  
  		/* 2.407 GHz, channels 1..13 */
  		if (chandef->width == NL80211_CHAN_WIDTH_40) {
  			if (freq > chandef->chan->center_freq)
  				*op_class = 83; /* HT40+ */
  			else
  				*op_class = 84; /* HT40- */
  		} else {
  			*op_class = 81;
  		}
  
  		return true;
  	}
  
  	if (freq == 2484) {
  		if (chandef->width > NL80211_CHAN_WIDTH_40)
  			return false;
  
  		*op_class = 82; /* channel 14 */
  		return true;
  	}
  
  	switch (chandef->width) {
  	case NL80211_CHAN_WIDTH_80:
  		vht_opclass = 128;
  		break;
  	case NL80211_CHAN_WIDTH_160:
  		vht_opclass = 129;
  		break;
  	case NL80211_CHAN_WIDTH_80P80:
  		vht_opclass = 130;
  		break;
  	case NL80211_CHAN_WIDTH_10:
  	case NL80211_CHAN_WIDTH_5:
  		return false; /* unsupported for now */
  	default:
  		vht_opclass = 0;
  		break;
  	}
  
  	/* 5 GHz, channels 36..48 */
  	if (freq >= 5180 && freq <= 5240) {
  		if (vht_opclass) {
  			*op_class = vht_opclass;
  		} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
  			if (freq > chandef->chan->center_freq)
  				*op_class = 116;
  			else
  				*op_class = 117;
  		} else {
  			*op_class = 115;
  		}
  
  		return true;
  	}
  
  	/* 5 GHz, channels 52..64 */
  	if (freq >= 5260 && freq <= 5320) {
  		if (vht_opclass) {
  			*op_class = vht_opclass;
  		} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
  			if (freq > chandef->chan->center_freq)
  				*op_class = 119;
  			else
  				*op_class = 120;
  		} else {
  			*op_class = 118;
  		}
  
  		return true;
  	}
  
  	/* 5 GHz, channels 100..144 */
  	if (freq >= 5500 && freq <= 5720) {
  		if (vht_opclass) {
  			*op_class = vht_opclass;
  		} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
  			if (freq > chandef->chan->center_freq)
  				*op_class = 122;
  			else
  				*op_class = 123;
  		} else {
  			*op_class = 121;
  		}
  
  		return true;
  	}
  
  	/* 5 GHz, channels 149..169 */
  	if (freq >= 5745 && freq <= 5845) {
  		if (vht_opclass) {
  			*op_class = vht_opclass;
  		} else if (chandef->width == NL80211_CHAN_WIDTH_40) {
  			if (freq > chandef->chan->center_freq)
  				*op_class = 126;
  			else
  				*op_class = 127;
  		} else if (freq <= 5805) {
  			*op_class = 124;
  		} else {
  			*op_class = 125;
  		}
  
  		return true;
  	}
  
  	/* 56.16 GHz, channel 1..4 */
  	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
  		if (chandef->width >= NL80211_CHAN_WIDTH_40)
  			return false;
  
  		*op_class = 180;
  		return true;
  	}
  
  	/* not supported yet */
  	return false;
  }
  EXPORT_SYMBOL(ieee80211_chandef_to_operating_class);
4c8dea638   Johannes Berg   cfg80211: validat...
1525
1526
1527
  static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int,
  				       u32 *beacon_int_gcd,
  				       bool *beacon_int_different)
56d1893d9   Johannes Berg   cfg80211: restric...
1528
1529
  {
  	struct wireless_dev *wdev;
56d1893d9   Johannes Berg   cfg80211: restric...
1530

4c8dea638   Johannes Berg   cfg80211: validat...
1531
1532
  	*beacon_int_gcd = 0;
  	*beacon_int_different = false;
56d1893d9   Johannes Berg   cfg80211: restric...
1533

4c8dea638   Johannes Berg   cfg80211: validat...
1534
  	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
56d1893d9   Johannes Berg   cfg80211: restric...
1535
1536
  		if (!wdev->beacon_interval)
  			continue;
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1537

4c8dea638   Johannes Berg   cfg80211: validat...
1538
1539
  		if (!*beacon_int_gcd) {
  			*beacon_int_gcd = wdev->beacon_interval;
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1540
  			continue;
4c8dea638   Johannes Berg   cfg80211: validat...
1541
  		}
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1542

4c8dea638   Johannes Berg   cfg80211: validat...
1543
  		if (wdev->beacon_interval == *beacon_int_gcd)
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1544
  			continue;
4c8dea638   Johannes Berg   cfg80211: validat...
1545
1546
1547
  		*beacon_int_different = true;
  		*beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
  	}
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1548

4c8dea638   Johannes Berg   cfg80211: validat...
1549
1550
1551
1552
  	if (new_beacon_int && *beacon_int_gcd != new_beacon_int) {
  		if (*beacon_int_gcd)
  			*beacon_int_different = true;
  		*beacon_int_gcd = gcd(*beacon_int_gcd, new_beacon_int);
56d1893d9   Johannes Berg   cfg80211: restric...
1553
  	}
4c8dea638   Johannes Berg   cfg80211: validat...
1554
  }
56d1893d9   Johannes Berg   cfg80211: restric...
1555

4c8dea638   Johannes Berg   cfg80211: validat...
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
  int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
  				 enum nl80211_iftype iftype, u32 beacon_int)
  {
  	/*
  	 * This is just a basic pre-condition check; if interface combinations
  	 * are possible the driver must already be checking those with a call
  	 * to cfg80211_check_combinations(), in which case we'll validate more
  	 * through the cfg80211_calculate_bi_data() call and code in
  	 * cfg80211_iter_combinations().
  	 */
  
  	if (beacon_int < 10 || beacon_int > 10000)
  		return -EINVAL;
  
  	return 0;
56d1893d9   Johannes Berg   cfg80211: restric...
1571
  }
7527a782e   Johannes Berg   cfg80211: adverti...
1572

65a124dd7   Michal Kazior   cfg80211: allow d...
1573
  int cfg80211_iter_combinations(struct wiphy *wiphy,
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1574
  			       struct iface_combination_params *params,
65a124dd7   Michal Kazior   cfg80211: allow d...
1575
1576
1577
  			       void (*iter)(const struct ieee80211_iface_combination *c,
  					    void *data),
  			       void *data)
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1578
  {
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1579
1580
  	const struct ieee80211_regdomain *regdom;
  	enum nl80211_dfs_regions region = 0;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1581
1582
1583
  	int i, j, iftype;
  	int num_interfaces = 0;
  	u32 used_iftypes = 0;
4c8dea638   Johannes Berg   cfg80211: validat...
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
  	u32 beacon_int_gcd;
  	bool beacon_int_different;
  
  	/*
  	 * This is a bit strange, since the iteration used to rely only on
  	 * the data given by the driver, but here it now relies on context,
  	 * in form of the currently operating interfaces.
  	 * This is OK for all current users, and saves us from having to
  	 * push the GCD calculations into all the drivers.
  	 * In the future, this should probably rely more on data that's in
  	 * cfg80211 already - the only thing not would appear to be any new
  	 * interfaces (while being brought up) and channel/radar data.
  	 */
  	cfg80211_calculate_bi_data(wiphy, params->new_beacon_int,
  				   &beacon_int_gcd, &beacon_int_different);
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1599

e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1600
  	if (params->radar_detect) {
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1601
1602
1603
1604
1605
1606
  		rcu_read_lock();
  		regdom = rcu_dereference(cfg80211_regdomain);
  		if (regdom)
  			region = regdom->dfs_region;
  		rcu_read_unlock();
  	}
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1607
  	for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1608
1609
  		num_interfaces += params->iftype_num[iftype];
  		if (params->iftype_num[iftype] > 0 &&
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
  		    !(wiphy->software_iftypes & BIT(iftype)))
  			used_iftypes |= BIT(iftype);
  	}
  
  	for (i = 0; i < wiphy->n_iface_combinations; i++) {
  		const struct ieee80211_iface_combination *c;
  		struct ieee80211_iface_limit *limits;
  		u32 all_iftypes = 0;
  
  		c = &wiphy->iface_combinations[i];
  
  		if (num_interfaces > c->max_interfaces)
  			continue;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1623
  		if (params->num_different_channels > c->num_different_channels)
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
  			continue;
  
  		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
  				 GFP_KERNEL);
  		if (!limits)
  			return -ENOMEM;
  
  		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
  			if (wiphy->software_iftypes & BIT(iftype))
  				continue;
  			for (j = 0; j < c->n_limits; j++) {
  				all_iftypes |= limits[j].types;
  				if (!(limits[j].types & BIT(iftype)))
  					continue;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1638
  				if (limits[j].max < params->iftype_num[iftype])
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1639
  					goto cont;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1640
  				limits[j].max -= params->iftype_num[iftype];
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1641
1642
  			}
  		}
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1643
1644
  		if (params->radar_detect !=
  			(c->radar_detect_widths & params->radar_detect))
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1645
  			goto cont;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1646
  		if (params->radar_detect && c->radar_detect_regions &&
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1647
1648
  		    !(c->radar_detect_regions & BIT(region)))
  			goto cont;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1649
1650
1651
1652
1653
1654
1655
  		/* Finally check that all iftypes that we're currently
  		 * using are actually part of this combination. If they
  		 * aren't then we can't use this combination and have
  		 * to continue to the next.
  		 */
  		if ((all_iftypes & used_iftypes) != used_iftypes)
  			goto cont;
4c8dea638   Johannes Berg   cfg80211: validat...
1656
  		if (beacon_int_gcd) {
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1657
  			if (c->beacon_int_min_gcd &&
4c8dea638   Johannes Berg   cfg80211: validat...
1658
  			    beacon_int_gcd < c->beacon_int_min_gcd)
0507a3ac6   Johannes Berg   cfg80211: fix bea...
1659
  				goto cont;
4c8dea638   Johannes Berg   cfg80211: validat...
1660
  			if (!c->beacon_int_min_gcd && beacon_int_different)
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1661
1662
  				goto cont;
  		}
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1663
1664
1665
  		/* This combination covered all interface types and
  		 * supported the requested numbers, so we're good.
  		 */
65a124dd7   Michal Kazior   cfg80211: allow d...
1666
1667
  
  		(*iter)(c, data);
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1668
1669
1670
   cont:
  		kfree(limits);
  	}
65a124dd7   Michal Kazior   cfg80211: allow d...
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
  	return 0;
  }
  EXPORT_SYMBOL(cfg80211_iter_combinations);
  
  static void
  cfg80211_iter_sum_ifcombs(const struct ieee80211_iface_combination *c,
  			  void *data)
  {
  	int *num = data;
  	(*num)++;
  }
  
  int cfg80211_check_combinations(struct wiphy *wiphy,
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1684
  				struct iface_combination_params *params)
65a124dd7   Michal Kazior   cfg80211: allow d...
1685
1686
  {
  	int err, num = 0;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1687
  	err = cfg80211_iter_combinations(wiphy, params,
65a124dd7   Michal Kazior   cfg80211: allow d...
1688
1689
1690
1691
1692
1693
1694
  					 cfg80211_iter_sum_ifcombs, &num);
  	if (err)
  		return err;
  	if (num == 0)
  		return -EBUSY;
  
  	return 0;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1695
1696
  }
  EXPORT_SYMBOL(cfg80211_check_combinations);
34850ab25   Johannes Berg   cfg80211: allow u...
1697
1698
1699
1700
1701
  int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
  			   const u8 *rates, unsigned int n_rates,
  			   u32 *mask)
  {
  	int i, j;
a401d2bb3   Johannes Berg   cfg80211: fix sca...
1702
1703
  	if (!sband)
  		return -EINVAL;
34850ab25   Johannes Berg   cfg80211: allow u...
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
  	if (n_rates == 0 || n_rates > NL80211_MAX_SUPP_RATES)
  		return -EINVAL;
  
  	*mask = 0;
  
  	for (i = 0; i < n_rates; i++) {
  		int rate = (rates[i] & 0x7f) * 5;
  		bool found = false;
  
  		for (j = 0; j < sband->n_bitrates; j++) {
  			if (sband->bitrates[j].bitrate == rate) {
  				found = true;
  				*mask |= BIT(j);
  				break;
  			}
  		}
  		if (!found)
  			return -EINVAL;
  	}
  
  	/*
  	 * mask must have at least one bit set here since we
  	 * didn't accept a 0-length rates array nor allowed
  	 * entries in the array that didn't exist
  	 */
  
  	return 0;
  }
11a2a357a   Johannes Berg   cfg80211: work ar...
1732

bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1733
1734
  unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
1735
  	enum nl80211_band band;
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1736
  	unsigned int n_channels = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1737
  	for (band = 0; band < NUM_NL80211_BANDS; band++)
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1738
1739
1740
1741
1742
1743
  		if (wiphy->bands[band])
  			n_channels += wiphy->bands[band]->n_channels;
  
  	return n_channels;
  }
  EXPORT_SYMBOL(ieee80211_get_num_supported_channels);
7406353d4   Antonio Quartulli   cfg80211: impleme...
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
  int cfg80211_get_station(struct net_device *dev, const u8 *mac_addr,
  			 struct station_info *sinfo)
  {
  	struct cfg80211_registered_device *rdev;
  	struct wireless_dev *wdev;
  
  	wdev = dev->ieee80211_ptr;
  	if (!wdev)
  		return -EOPNOTSUPP;
  
  	rdev = wiphy_to_rdev(wdev->wiphy);
  	if (!rdev->ops->get_station)
  		return -EOPNOTSUPP;
  
  	return rdev_get_station(rdev, dev, mac_addr, sinfo);
  }
  EXPORT_SYMBOL(cfg80211_get_station);
a442b761b   Ayala Beker   cfg80211: add add...
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
  void cfg80211_free_nan_func(struct cfg80211_nan_func *f)
  {
  	int i;
  
  	if (!f)
  		return;
  
  	kfree(f->serv_spec_info);
  	kfree(f->srf_bf);
  	kfree(f->srf_macs);
  	for (i = 0; i < f->num_rx_filters; i++)
  		kfree(f->rx_filters[i].filter);
  
  	for (i = 0; i < f->num_tx_filters; i++)
  		kfree(f->tx_filters[i].filter);
  
  	kfree(f->rx_filters);
  	kfree(f->tx_filters);
  	kfree(f);
  }
  EXPORT_SYMBOL(cfg80211_free_nan_func);
4787cfa08   Rafał Miłecki   cfg80211: move fu...
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
  bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
  				u32 center_freq_khz, u32 bw_khz)
  {
  	u32 start_freq_khz, end_freq_khz;
  
  	start_freq_khz = center_freq_khz - (bw_khz / 2);
  	end_freq_khz = center_freq_khz + (bw_khz / 2);
  
  	if (start_freq_khz >= freq_range->start_freq_khz &&
  	    end_freq_khz <= freq_range->end_freq_khz)
  		return true;
  
  	return false;
  }
11a2a357a   Johannes Berg   cfg80211: work ar...
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
  /* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
  /* Ethernet-II snap header (RFC1042 for most EtherTypes) */
  const unsigned char rfc1042_header[] __aligned(2) =
  	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
  EXPORT_SYMBOL(rfc1042_header);
  
  /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
  const unsigned char bridge_tunnel_header[] __aligned(2) =
  	{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
  EXPORT_SYMBOL(bridge_tunnel_header);
7101e4fa0   Nakul Kachhwaha   MLK-17362-01 Chan...
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
  
  bool cfg80211_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb)
  {
      const struct ethhdr *eth = (void *)skb->data;
      const struct {
          struct arphdr hdr;
          u8 ar_sha[ETH_ALEN];
          u8 ar_sip[4];
          u8 ar_tha[ETH_ALEN];
          u8 ar_tip[4];
      } __packed *arp;
      const struct ipv6hdr *ipv6;
      const struct icmp6hdr *icmpv6;
  
      switch (eth->h_proto) {
      case cpu_to_be16(ETH_P_ARP):
          /* can't say - but will probably be dropped later anyway */
          if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*arp)))
              return false;
  
          arp = (void *)(eth + 1);
  
          if ((arp->hdr.ar_op == cpu_to_be16(ARPOP_REPLY) ||
               arp->hdr.ar_op == cpu_to_be16(ARPOP_REQUEST)) &&
              !memcmp(arp->ar_sip, arp->ar_tip, sizeof(arp->ar_sip)))
              return true;
          break;
      case cpu_to_be16(ETH_P_IPV6):
          /* can't say - but will probably be dropped later anyway */
          if (!pskb_may_pull(skb, sizeof(*eth) + sizeof(*ipv6) +
                      sizeof(*icmpv6)))
              return false;
  
          ipv6 = (void *)(eth + 1);
          icmpv6 = (void *)(ipv6 + 1);
  
          if (icmpv6->icmp6_type == NDISC_NEIGHBOUR_ADVERTISEMENT &&
              !memcmp(&ipv6->saddr, &ipv6->daddr, sizeof(ipv6->saddr)))
              return true;
          break;
      default:
          /*
           * no need to support other protocols, proxy service isn't
           * specified for any others
           */
          break;
      }
  
      return false;
  }
  EXPORT_SYMBOL(cfg80211_is_gratuitous_arp_unsolicited_na);