Blame view

net/wireless/util.c 52.8 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
c4cbaf797   Luca Coelho   cfg80211: Add sup...
7
   * Copyright 2017	Intel Deutschland GmbH
9166cc497   Johannes Berg   mac80211: impleme...
8
   * Copyright (C) 2018-2020 Intel Corporation
8318d78a4   Johannes Berg   cfg80211 API for ...
9
   */
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
10
  #include <linux/export.h>
d32365537   Johannes Berg   cfg80211: clean u...
11
  #include <linux/bitops.h>
e31a16d6f   Zhu Yi   wireless: move so...
12
  #include <linux/etherdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
b0aa75f0b   Johannes Berg   ieee80211: add ne...
14
  #include <linux/ieee80211.h>
d32365537   Johannes Berg   cfg80211: clean u...
15
  #include <net/cfg80211.h>
e31a16d6f   Zhu Yi   wireless: move so...
16
  #include <net/ip.h>
b156579b1   Dave Täht   wireless: Treat I...
17
  #include <net/dsfield.h>
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
18
  #include <linux/if_vlan.h>
960d97f95   Simon Wunderlich   cfg80211: add MPL...
19
  #include <linux/mpls.h>
4c8dea638   Johannes Berg   cfg80211: validat...
20
  #include <linux/gcd.h>
b0aa75f0b   Johannes Berg   ieee80211: add ne...
21
  #include <linux/bitfield.h>
1fc9b7253   Johannes Berg   cfg80211: prevent...
22
  #include <linux/nospec.h>
8318d78a4   Johannes Berg   cfg80211 API for ...
23
  #include "core.h"
e35e4d28b   Hila Gonen   cfg80211: add wra...
24
  #include "rdev-ops.h"
8318d78a4   Johannes Berg   cfg80211 API for ...
25

bd8152527   Johannes Berg   wireless: impleme...
26
27
  struct ieee80211_rate *
  ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
881d948c2   Johannes Berg   wireless: restric...
28
  			    u32 basic_rates, int bitrate)
bd8152527   Johannes Berg   wireless: impleme...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
  {
  	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...
44
45
  u32 ieee80211_mandatory_rates(struct ieee80211_supported_band *sband,
  			      enum nl80211_bss_scan_width scan_width)
b422c6cd7   Ashok Nagarajan   {cfg,mac}80211: m...
46
47
48
49
50
51
52
53
  {
  	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 ...
54
  	if (sband->band == NL80211_BAND_2GHZ) {
74608aca4   Simon Wunderlich   cfg80211/mac80211...
55
56
57
58
59
60
  		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...
61
  		mandatory_flag = IEEE80211_RATE_MANDATORY_A;
74608aca4   Simon Wunderlich   cfg80211/mac80211...
62
  	}
b422c6cd7   Ashok Nagarajan   {cfg,mac}80211: m...
63
64
65
66
67
68
69
70
  
  	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);
934f4c7dd   Thomas Pedersen   cfg80211: express...
71
  u32 ieee80211_channel_to_freq_khz(int chan, enum nl80211_band band)
8318d78a4   Johannes Berg   cfg80211 API for ...
72
  {
59eb21a65   Bruno Randolf   cfg80211: Extend ...
73
74
  	/* 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...
75
76
77
  	if (chan <= 0)
  		return 0; /* not supported */
  	switch (band) {
57fbcce37   Johannes Berg   cfg80211: remove ...
78
  	case NL80211_BAND_2GHZ:
59eb21a65   Bruno Randolf   cfg80211: Extend ...
79
  		if (chan == 14)
934f4c7dd   Thomas Pedersen   cfg80211: express...
80
  			return MHZ_TO_KHZ(2484);
59eb21a65   Bruno Randolf   cfg80211: Extend ...
81
  		else if (chan < 14)
934f4c7dd   Thomas Pedersen   cfg80211: express...
82
  			return MHZ_TO_KHZ(2407 + chan * 5);
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
83
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
84
  	case NL80211_BAND_5GHZ:
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
85
  		if (chan >= 182 && chan <= 196)
934f4c7dd   Thomas Pedersen   cfg80211: express...
86
  			return MHZ_TO_KHZ(4000 + chan * 5);
59eb21a65   Bruno Randolf   cfg80211: Extend ...
87
  		else
934f4c7dd   Thomas Pedersen   cfg80211: express...
88
  			return MHZ_TO_KHZ(5000 + chan * 5);
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
89
  		break;
fa1f1085b   Arend van Spriel   cfg80211: util: a...
90
  	case NL80211_BAND_6GHZ:
d1a1646c0   Arend Van Spriel   cfg80211: adapt t...
91
92
93
  		/* see 802.11ax D6.1 27.3.23.2 */
  		if (chan == 2)
  			return MHZ_TO_KHZ(5935);
c0de8776a   Johannes Berg   cfg80211: fix 6 G...
94
  		if (chan <= 233)
d1a1646c0   Arend Van Spriel   cfg80211: adapt t...
95
  			return MHZ_TO_KHZ(5950 + chan * 5);
fa1f1085b   Arend van Spriel   cfg80211: util: a...
96
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
97
  	case NL80211_BAND_60GHZ:
9cf0a0b4b   Alexei Avshalom Lazar   cfg80211: Add sup...
98
  		if (chan < 7)
934f4c7dd   Thomas Pedersen   cfg80211: express...
99
  			return MHZ_TO_KHZ(56160 + chan * 2160);
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
100
  		break;
df78a0c0b   Thomas Pedersen   nl80211: S1G band...
101
102
  	case NL80211_BAND_S1GHZ:
  		return 902000 + chan * 500;
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
103
104
  	default:
  		;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
105
  	}
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
106
  	return 0; /* not supported */
8318d78a4   Johannes Berg   cfg80211 API for ...
107
  }
934f4c7dd   Thomas Pedersen   cfg80211: express...
108
  EXPORT_SYMBOL(ieee80211_channel_to_freq_khz);
8318d78a4   Johannes Berg   cfg80211 API for ...
109

11b34737b   Thomas Pedersen   nl80211: support ...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
  enum nl80211_chan_width
  ieee80211_s1g_channel_width(const struct ieee80211_channel *chan)
  {
  	if (WARN_ON(!chan || chan->band != NL80211_BAND_S1GHZ))
  		return NL80211_CHAN_WIDTH_20_NOHT;
  
  	/*S1G defines a single allowed channel width per channel.
  	 * Extract that width here.
  	 */
  	if (chan->flags & IEEE80211_CHAN_1MHZ)
  		return NL80211_CHAN_WIDTH_1;
  	else if (chan->flags & IEEE80211_CHAN_2MHZ)
  		return NL80211_CHAN_WIDTH_2;
  	else if (chan->flags & IEEE80211_CHAN_4MHZ)
  		return NL80211_CHAN_WIDTH_4;
  	else if (chan->flags & IEEE80211_CHAN_8MHZ)
  		return NL80211_CHAN_WIDTH_8;
  	else if (chan->flags & IEEE80211_CHAN_16MHZ)
  		return NL80211_CHAN_WIDTH_16;
  
  	pr_err("unknown channel width for channel at %dKHz?
  ",
  	       ieee80211_channel_to_khz(chan));
  
  	return NL80211_CHAN_WIDTH_1;
  }
  EXPORT_SYMBOL(ieee80211_s1g_channel_width);
934f4c7dd   Thomas Pedersen   cfg80211: express...
137
  int ieee80211_freq_khz_to_channel(u32 freq)
8318d78a4   Johannes Berg   cfg80211 API for ...
138
  {
934f4c7dd   Thomas Pedersen   cfg80211: express...
139
140
  	/* TODO: just handle MHz for now */
  	freq = KHZ_TO_MHZ(freq);
59eb21a65   Bruno Randolf   cfg80211: Extend ...
141
  	/* see 802.11 17.3.8.3.2 and Annex J */
8318d78a4   Johannes Berg   cfg80211 API for ...
142
143
  	if (freq == 2484)
  		return 14;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
144
  	else if (freq < 2484)
8318d78a4   Johannes Berg   cfg80211 API for ...
145
  		return (freq - 2407) / 5;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
146
147
  	else if (freq >= 4910 && freq <= 4980)
  		return (freq - 4000) / 5;
2d9b55508   Amar Singhal   cfg80211: Adjust ...
148
  	else if (freq < 5925)
59eb21a65   Bruno Randolf   cfg80211: Extend ...
149
  		return (freq - 5000) / 5;
2d9b55508   Amar Singhal   cfg80211: Adjust ...
150
151
  	else if (freq == 5935)
  		return 2;
fa1f1085b   Arend van Spriel   cfg80211: util: a...
152
  	else if (freq <= 45000) /* DMG band lower limit */
2d9b55508   Amar Singhal   cfg80211: Adjust ...
153
154
  		/* see 802.11ax D6.1 27.3.22.2 */
  		return (freq - 5950) / 5;
9cf0a0b4b   Alexei Avshalom Lazar   cfg80211: Add sup...
155
  	else if (freq >= 58320 && freq <= 70200)
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
156
157
158
  		return (freq - 56160) / 2160;
  	else
  		return 0;
8318d78a4   Johannes Berg   cfg80211 API for ...
159
  }
934f4c7dd   Thomas Pedersen   cfg80211: express...
160
  EXPORT_SYMBOL(ieee80211_freq_khz_to_channel);
8318d78a4   Johannes Berg   cfg80211 API for ...
161

934f4c7dd   Thomas Pedersen   cfg80211: express...
162
163
  struct ieee80211_channel *ieee80211_get_channel_khz(struct wiphy *wiphy,
  						    u32 freq)
906c730a2   Johannes Berg   wireless: add wip...
164
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
165
  	enum nl80211_band band;
906c730a2   Johannes Berg   wireless: add wip...
166
167
  	struct ieee80211_supported_band *sband;
  	int i;
57fbcce37   Johannes Berg   cfg80211: remove ...
168
  	for (band = 0; band < NUM_NL80211_BANDS; band++) {
906c730a2   Johannes Berg   wireless: add wip...
169
170
171
172
173
174
  		sband = wiphy->bands[band];
  
  		if (!sband)
  			continue;
  
  		for (i = 0; i < sband->n_channels; i++) {
934f4c7dd   Thomas Pedersen   cfg80211: express...
175
176
177
178
  			struct ieee80211_channel *chan = &sband->channels[i];
  
  			if (ieee80211_channel_to_khz(chan) == freq)
  				return chan;
906c730a2   Johannes Berg   wireless: add wip...
179
180
181
182
183
  		}
  	}
  
  	return NULL;
  }
934f4c7dd   Thomas Pedersen   cfg80211: express...
184
  EXPORT_SYMBOL(ieee80211_get_channel_khz);
906c730a2   Johannes Berg   wireless: add wip...
185

343884c87   Arend Van Spriel   cfg80211: only pa...
186
  static void set_mandatory_flags_band(struct ieee80211_supported_band *sband)
8318d78a4   Johannes Berg   cfg80211 API for ...
187
188
  {
  	int i, want;
343884c87   Arend Van Spriel   cfg80211: only pa...
189
  	switch (sband->band) {
57fbcce37   Johannes Berg   cfg80211: remove ...
190
  	case NL80211_BAND_5GHZ:
62524a585   Arend van Spriel   cfg80211: apply s...
191
  	case NL80211_BAND_6GHZ:
8318d78a4   Johannes Berg   cfg80211 API for ...
192
193
194
195
196
197
198
199
200
201
202
203
  		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 ...
204
  	case NL80211_BAND_2GHZ:
8318d78a4   Johannes Berg   cfg80211 API for ...
205
206
  		want = 7;
  		for (i = 0; i < sband->n_bitrates; i++) {
1bd773c07   Richard Schütz   wireless: set cor...
207
208
209
210
211
  			switch (sband->bitrates[i].bitrate) {
  			case 10:
  			case 20:
  			case 55:
  			case 110:
8318d78a4   Johannes Berg   cfg80211 API for ...
212
213
214
215
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_MANDATORY_B |
  					IEEE80211_RATE_MANDATORY_G;
  				want--;
1bd773c07   Richard Schütz   wireless: set cor...
216
217
218
219
  				break;
  			case 60:
  			case 120:
  			case 240:
8318d78a4   Johannes Berg   cfg80211 API for ...
220
221
222
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_MANDATORY_G;
  				want--;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
223
  				fallthrough;
1bd773c07   Richard Schütz   wireless: set cor...
224
  			default:
8318d78a4   Johannes Berg   cfg80211 API for ...
225
226
  				sband->bitrates[i].flags |=
  					IEEE80211_RATE_ERP_G;
1bd773c07   Richard Schütz   wireless: set cor...
227
228
  				break;
  			}
8318d78a4   Johannes Berg   cfg80211 API for ...
229
  		}
1bd773c07   Richard Schütz   wireless: set cor...
230
  		WARN_ON(want != 0 && want != 3);
8318d78a4   Johannes Berg   cfg80211 API for ...
231
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
232
  	case NL80211_BAND_60GHZ:
3a0c52a6d   Vladimir Kondratiev   cfg80211: add 802...
233
234
235
236
  		/* 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;
df78a0c0b   Thomas Pedersen   nl80211: S1G band...
237
238
239
240
241
242
  	case NL80211_BAND_S1GHZ:
  		/* Figure 9-589bd: 3 means unsupported, so != 3 means at least
  		 * mandatory is ok.
  		 */
  		WARN_ON((sband->s1g_cap.nss_mcs[0] & 0x3) == 0x3);
  		break;
57fbcce37   Johannes Berg   cfg80211: remove ...
243
  	case NUM_NL80211_BANDS:
343884c87   Arend Van Spriel   cfg80211: only pa...
244
  	default:
8318d78a4   Johannes Berg   cfg80211 API for ...
245
246
247
248
249
250
251
  		WARN_ON(1);
  		break;
  	}
  }
  
  void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
252
  	enum nl80211_band band;
8318d78a4   Johannes Berg   cfg80211 API for ...
253

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

38ba3c57a   Jouni Malinen   cfg80211: Validat...
259
260
261
262
263
264
265
266
  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;
  }
05725b40b   Anant Thazhemadam   nl80211: validate...
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  static bool
  cfg80211_igtk_cipher_supported(struct cfg80211_registered_device *rdev)
  {
  	struct wiphy *wiphy = &rdev->wiphy;
  	int i;
  
  	for (i = 0; i < wiphy->n_cipher_suites; i++) {
  		switch (wiphy->cipher_suites[i]) {
  		case WLAN_CIPHER_SUITE_AES_CMAC:
  		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
  		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
  		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
  			return true;
  		}
  	}
  
  	return false;
  }
  
  bool cfg80211_valid_key_idx(struct cfg80211_registered_device *rdev,
  			    int key_idx, bool pairwise)
08645126d   Johannes Berg   cfg80211: impleme...
288
  {
05725b40b   Anant Thazhemadam   nl80211: validate...
289
  	int max_key_idx;
56be393fa   Jouni Malinen   cfg80211: Support...
290

05725b40b   Anant Thazhemadam   nl80211: validate...
291
292
293
294
295
296
  	if (pairwise)
  		max_key_idx = 3;
  	else if (wiphy_ext_feature_isset(&rdev->wiphy,
  					 NL80211_EXT_FEATURE_BEACON_PROTECTION) ||
  		 wiphy_ext_feature_isset(&rdev->wiphy,
  					 NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT))
56be393fa   Jouni Malinen   cfg80211: Support...
297
  		max_key_idx = 7;
05725b40b   Anant Thazhemadam   nl80211: validate...
298
299
300
301
  	else if (cfg80211_igtk_cipher_supported(rdev))
  		max_key_idx = 5;
  	else
  		max_key_idx = 3;
56be393fa   Jouni Malinen   cfg80211: Support...
302
  	if (key_idx < 0 || key_idx > max_key_idx)
05725b40b   Anant Thazhemadam   nl80211: validate...
303
304
305
306
307
308
309
310
311
312
  		return false;
  
  	return true;
  }
  
  int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
  				   struct key_params *params, int key_idx,
  				   bool pairwise, const u8 *mac_addr)
  {
  	if (!cfg80211_valid_key_idx(rdev, key_idx, pairwise))
08645126d   Johannes Berg   cfg80211: impleme...
313
  		return -EINVAL;
e31b82136   Johannes Berg   cfg80211/mac80211...
314
315
316
317
318
  	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...
319
320
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_TKIP:
b67fd72e8   Alexander Wetzel   cfg80211: Fix Ext...
321
322
323
324
325
  		/* Extended Key ID can only be used with CCMP/GCMP ciphers */
  		if ((pairwise && key_idx) ||
  		    params->mode != NL80211_KEY_RX_TX)
  			return -EINVAL;
  		break;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
326
  	case WLAN_CIPHER_SUITE_CCMP:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
327
328
329
  	case WLAN_CIPHER_SUITE_CCMP_256:
  	case WLAN_CIPHER_SUITE_GCMP:
  	case WLAN_CIPHER_SUITE_GCMP_256:
b67fd72e8   Alexander Wetzel   cfg80211: Fix Ext...
330
331
  		/* IEEE802.11-2016 allows only 0 and - when supporting
  		 * Extended Key ID - 1 as index for pairwise keys.
6cdd3979a   Alexander Wetzel   nl80211/cfg80211:...
332
333
334
335
  		 * @NL80211_KEY_NO_TX is only allowed for pairwise keys when
  		 * the driver supports Extended Key ID.
  		 * @NL80211_KEY_SET_TX can't be set when installing and
  		 * validating a key.
37720569c   Jouni Malinen   cfg80211: Fix BIP...
336
  		 */
b67fd72e8   Alexander Wetzel   cfg80211: Fix Ext...
337
338
339
340
341
342
  		if ((params->mode == NL80211_KEY_NO_TX && !pairwise) ||
  		    params->mode == NL80211_KEY_SET_TX)
  			return -EINVAL;
  		if (wiphy_ext_feature_isset(&rdev->wiphy,
  					    NL80211_EXT_FEATURE_EXT_KEY_ID)) {
  			if (pairwise && (key_idx < 0 || key_idx > 1))
6cdd3979a   Alexander Wetzel   nl80211/cfg80211:...
343
  				return -EINVAL;
b67fd72e8   Alexander Wetzel   cfg80211: Fix Ext...
344
  		} else if (pairwise && key_idx) {
37720569c   Jouni Malinen   cfg80211: Fix BIP...
345
  			return -EINVAL;
6cdd3979a   Alexander Wetzel   nl80211/cfg80211:...
346
  		}
37720569c   Jouni Malinen   cfg80211: Fix BIP...
347
348
  		break;
  	case WLAN_CIPHER_SUITE_AES_CMAC:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
349
350
351
  	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...
352
353
354
  		/* Disallow BIP (group-only) cipher as pairwise cipher */
  		if (pairwise)
  			return -EINVAL;
e9c8f8d3a   Johannes Berg   cfg80211: validat...
355
356
  		if (key_idx < 4)
  			return -EINVAL;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
357
  		break;
e9c8f8d3a   Johannes Berg   cfg80211: validat...
358
359
360
361
  	case WLAN_CIPHER_SUITE_WEP40:
  	case WLAN_CIPHER_SUITE_WEP104:
  		if (key_idx > 3)
  			return -EINVAL;
37720569c   Jouni Malinen   cfg80211: Fix BIP...
362
363
364
  	default:
  		break;
  	}
08645126d   Johannes Berg   cfg80211: impleme...
365

08645126d   Johannes Berg   cfg80211: impleme...
366
367
  	switch (params->cipher) {
  	case WLAN_CIPHER_SUITE_WEP40:
8fc0fee09   Johannes Berg   cfg80211: use key...
368
  		if (params->key_len != WLAN_KEY_LEN_WEP40)
08645126d   Johannes Berg   cfg80211: impleme...
369
370
371
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_TKIP:
8fc0fee09   Johannes Berg   cfg80211: use key...
372
  		if (params->key_len != WLAN_KEY_LEN_TKIP)
08645126d   Johannes Berg   cfg80211: impleme...
373
374
375
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_CCMP:
8fc0fee09   Johannes Berg   cfg80211: use key...
376
  		if (params->key_len != WLAN_KEY_LEN_CCMP)
08645126d   Johannes Berg   cfg80211: impleme...
377
378
  			return -EINVAL;
  		break;
cfcf1682c   Jouni Malinen   cfg80211: Add new...
379
380
381
382
383
384
385
386
387
388
389
390
  	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...
391
  	case WLAN_CIPHER_SUITE_WEP104:
8fc0fee09   Johannes Berg   cfg80211: use key...
392
  		if (params->key_len != WLAN_KEY_LEN_WEP104)
08645126d   Johannes Berg   cfg80211: impleme...
393
394
395
  			return -EINVAL;
  		break;
  	case WLAN_CIPHER_SUITE_AES_CMAC:
8fc0fee09   Johannes Berg   cfg80211: use key...
396
  		if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
08645126d   Johannes Berg   cfg80211: impleme...
397
398
  			return -EINVAL;
  		break;
cfcf1682c   Jouni Malinen   cfg80211: Add new...
399
400
401
402
403
404
405
406
407
408
409
410
  	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...
411
  	default:
7d64b7cc1   Johannes Berg   cfg80211: allow v...
412
413
414
415
416
417
418
419
  		/*
  		 * 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...
420
  	}
9f26a9522   Jouni Malinen   nl80211: Validate...
421
422
423
424
425
426
427
428
  	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...
429
430
431
  		case WLAN_CIPHER_SUITE_CCMP_256:
  		case WLAN_CIPHER_SUITE_GCMP:
  		case WLAN_CIPHER_SUITE_GCMP_256:
9f26a9522   Jouni Malinen   nl80211: Validate...
432
  		case WLAN_CIPHER_SUITE_AES_CMAC:
cfcf1682c   Jouni Malinen   cfg80211: Add new...
433
434
435
  		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...
436
437
438
439
440
  			if (params->seq_len != 6)
  				return -EINVAL;
  			break;
  		}
  	}
38ba3c57a   Jouni Malinen   cfg80211: Validat...
441
  	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
fffd0934b   Johannes Berg   cfg80211: rework ...
442
  		return -EINVAL;
08645126d   Johannes Berg   cfg80211: impleme...
443
444
  	return 0;
  }
e31a16d6f   Zhu Yi   wireless: move so...
445

633adf1ad   Johannes Berg   cfg80211: mark ie...
446
  unsigned int __attribute_const__ ieee80211_hdrlen(__le16 fc)
e31a16d6f   Zhu Yi   wireless: move so...
447
448
  {
  	unsigned int hdrlen = 24;
1d47f1198   Thomas Pedersen   nl80211: correctl...
449
450
451
452
  	if (ieee80211_is_ext(fc)) {
  		hdrlen = 4;
  		goto out;
  	}
e31a16d6f   Zhu Yi   wireless: move so...
453
454
455
  	if (ieee80211_is_data(fc)) {
  		if (ieee80211_has_a4(fc))
  			hdrlen = 30;
d0dd2de0d   Andriy Tkachuk   mac80211: Account...
456
  		if (ieee80211_is_data_qos(fc)) {
e31a16d6f   Zhu Yi   wireless: move so...
457
  			hdrlen += IEEE80211_QOS_CTL_LEN;
d0dd2de0d   Andriy Tkachuk   mac80211: Account...
458
459
460
  			if (ieee80211_has_order(fc))
  				hdrlen += IEEE80211_HT_CTL_LEN;
  		}
e31a16d6f   Zhu Yi   wireless: move so...
461
462
  		goto out;
  	}
fb142f4bb   Fred Chou   mac80211: correct...
463
464
465
466
467
  	if (ieee80211_is_mgmt(fc)) {
  		if (ieee80211_has_order(fc))
  			hdrlen += IEEE80211_HT_CTL_LEN;
  		goto out;
  	}
e31a16d6f   Zhu Yi   wireless: move so...
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  	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...
502
  static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
e31a16d6f   Zhu Yi   wireless: move so...
503
  {
2d1c304cb   Felix Fietkau   cfg80211: add fun...
504
  	int ae = flags & MESH_FLAGS_AE;
7dd111e8e   Johannes Berg   wireless: drop in...
505
  	/* 802.11-2012, 8.2.4.7.3 */
e31a16d6f   Zhu Yi   wireless: move so...
506
  	switch (ae) {
7dd111e8e   Johannes Berg   wireless: drop in...
507
  	default:
e31a16d6f   Zhu Yi   wireless: move so...
508
509
  	case 0:
  		return 6;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
510
  	case MESH_FLAGS_AE_A4:
e31a16d6f   Zhu Yi   wireless: move so...
511
  		return 12;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
512
  	case MESH_FLAGS_AE_A5_A6:
e31a16d6f   Zhu Yi   wireless: move so...
513
  		return 18;
e31a16d6f   Zhu Yi   wireless: move so...
514
515
  	}
  }
2d1c304cb   Felix Fietkau   cfg80211: add fun...
516
517
518
519
520
  
  unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
  {
  	return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
  }
9b395bc3b   Johannes Berg   mac80211: verify ...
521
  EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
e31a16d6f   Zhu Yi   wireless: move so...
522

7f6990c83   Johannes Berg   cfg80211: let iee...
523
  int ieee80211_data_to_8023_exthdr(struct sk_buff *skb, struct ethhdr *ehdr,
24bba078e   Felix Fietkau   mac80211: support...
524
525
  				  const u8 *addr, enum nl80211_iftype iftype,
  				  u8 data_offset)
e31a16d6f   Zhu Yi   wireless: move so...
526
527
  {
  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
2d1c304cb   Felix Fietkau   cfg80211: add fun...
528
529
530
531
532
533
534
  	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...
535
536
537
  
  	if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
  		return -1;
24bba078e   Felix Fietkau   mac80211: support...
538
  	hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset;
2d1c304cb   Felix Fietkau   cfg80211: add fun...
539
540
  	if (skb->len < hdrlen + 8)
  		return -1;
e31a16d6f   Zhu Yi   wireless: move so...
541
542
543
544
545
546
547
548
549
550
  
  	/* 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...
551
552
553
554
555
  	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...
556

5667c86ac   Rajkumar Manoharan   mac80211: strictl...
557
  	mesh_flags &= MESH_FLAGS_AE;
e31a16d6f   Zhu Yi   wireless: move so...
558
559
560
561
  	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:...
562
563
  			     iftype != NL80211_IFTYPE_AP_VLAN &&
  			     iftype != NL80211_IFTYPE_P2P_GO))
e31a16d6f   Zhu Yi   wireless: move so...
564
565
566
567
  			return -1;
  		break;
  	case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
  		if (unlikely(iftype != NL80211_IFTYPE_WDS &&
f14543ee4   Felix Fietkau   mac80211: impleme...
568
569
570
  			     iftype != NL80211_IFTYPE_MESH_POINT &&
  			     iftype != NL80211_IFTYPE_AP_VLAN &&
  			     iftype != NL80211_IFTYPE_STATION))
e31a16d6f   Zhu Yi   wireless: move so...
571
572
  			return -1;
  		if (iftype == NL80211_IFTYPE_MESH_POINT) {
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
573
  			if (mesh_flags == MESH_FLAGS_AE_A4)
e3cf8b3f7   Zhu Yi   mac80211: support...
574
  				return -1;
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
575
  			if (mesh_flags == MESH_FLAGS_AE_A5_A6) {
e3cf8b3f7   Zhu Yi   mac80211: support...
576
577
  				skb_copy_bits(skb, hdrlen +
  					offsetof(struct ieee80211s_hdr, eaddr1),
2d1c304cb   Felix Fietkau   cfg80211: add fun...
578
  					tmp.h_dest, 2 * ETH_ALEN);
e31a16d6f   Zhu Yi   wireless: move so...
579
  			}
2d1c304cb   Felix Fietkau   cfg80211: add fun...
580
  			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
e31a16d6f   Zhu Yi   wireless: move so...
581
582
583
  		}
  		break;
  	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
3c5772a52   Javier Cardona   mac80211: Use 3-a...
584
  		if ((iftype != NL80211_IFTYPE_STATION &&
074ac8df9   Johannes Berg   cfg80211/nl80211:...
585
586
  		     iftype != NL80211_IFTYPE_P2P_CLIENT &&
  		     iftype != NL80211_IFTYPE_MESH_POINT) ||
2d1c304cb   Felix Fietkau   cfg80211: add fun...
587
588
  		    (is_multicast_ether_addr(tmp.h_dest) &&
  		     ether_addr_equal(tmp.h_source, addr)))
e31a16d6f   Zhu Yi   wireless: move so...
589
  			return -1;
3c5772a52   Javier Cardona   mac80211: Use 3-a...
590
  		if (iftype == NL80211_IFTYPE_MESH_POINT) {
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
591
  			if (mesh_flags == MESH_FLAGS_AE_A5_A6)
7dd111e8e   Johannes Berg   wireless: drop in...
592
  				return -1;
5667c86ac   Rajkumar Manoharan   mac80211: strictl...
593
  			if (mesh_flags == MESH_FLAGS_AE_A4)
e3cf8b3f7   Zhu Yi   mac80211: support...
594
595
  				skb_copy_bits(skb, hdrlen +
  					offsetof(struct ieee80211s_hdr, eaddr1),
2d1c304cb   Felix Fietkau   cfg80211: add fun...
596
597
  					tmp.h_source, ETH_ALEN);
  			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
3c5772a52   Javier Cardona   mac80211: Use 3-a...
598
  		}
e31a16d6f   Zhu Yi   wireless: move so...
599
600
  		break;
  	case cpu_to_le16(0):
941c93cd0   Arik Nemtsov   mac80211: data pa...
601
  		if (iftype != NL80211_IFTYPE_ADHOC &&
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
602
603
  		    iftype != NL80211_IFTYPE_STATION &&
  		    iftype != NL80211_IFTYPE_OCB)
941c93cd0   Arik Nemtsov   mac80211: data pa...
604
  				return -1;
e31a16d6f   Zhu Yi   wireless: move so...
605
606
  		break;
  	}
2d1c304cb   Felix Fietkau   cfg80211: add fun...
607
608
  	skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
  	tmp.h_proto = payload.proto;
e31a16d6f   Zhu Yi   wireless: move so...
609

2d1c304cb   Felix Fietkau   cfg80211: add fun...
610
611
612
613
  	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...
614
615
  		/* remove RFC1042 or Bridge-Tunnel encapsulation and
  		 * replace EtherType */
2d1c304cb   Felix Fietkau   cfg80211: add fun...
616
617
  		hdrlen += ETH_ALEN + 2;
  	else
c041778c9   Felix Fietkau   cfg80211: fix pro...
618
  		tmp.h_proto = htons(skb->len - hdrlen);
2d1c304cb   Felix Fietkau   cfg80211: add fun...
619
620
  
  	pskb_pull(skb, hdrlen);
e31a16d6f   Zhu Yi   wireless: move so...
621

2d1c304cb   Felix Fietkau   cfg80211: add fun...
622
  	if (!ehdr)
d58ff3512   Johannes Berg   networking: make ...
623
  		ehdr = skb_push(skb, sizeof(struct ethhdr));
2d1c304cb   Felix Fietkau   cfg80211: add fun...
624
  	memcpy(ehdr, &tmp, sizeof(tmp));
e31a16d6f   Zhu Yi   wireless: move so...
625
626
  	return 0;
  }
7f6990c83   Johannes Berg   cfg80211: let iee...
627
  EXPORT_SYMBOL(ieee80211_data_to_8023_exthdr);
e31a16d6f   Zhu Yi   wireless: move so...
628

2b67f944f   Felix Fietkau   cfg80211: reuse e...
629
630
631
632
633
634
  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;
81c044fc3   Felix Fietkau   cfg80211: fix pag...
635
  	get_page(page);
2b67f944f   Felix Fietkau   cfg80211: reuse e...
636
637
638
639
640
641
642
643
644
  	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...
645
  	const skb_frag_t *frag = &sh->frags[0];
2b67f944f   Felix Fietkau   cfg80211: reuse e...
646
647
648
649
650
651
652
653
654
655
656
657
  	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...
658
659
660
  		frag_page = skb_frag_page(frag);
  		frag_ptr = skb_frag_address(frag);
  		frag_size = skb_frag_size(frag);
aa1702dd1   Matthias Kaehlcke   cfg80211: Fix arr...
661
  		frag++;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
662
663
664
665
666
667
668
669
670
671
672
  	}
  
  	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...
673
674
675
676
677
  		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...
678
  		frag++;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
679
680
  	}
  }
230fd28a9   Felix Fietkau   cfg80211: add sup...
681
682
  static struct sk_buff *
  __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
2b67f944f   Felix Fietkau   cfg80211: reuse e...
683
  		       int offset, int len, bool reuse_frag)
230fd28a9   Felix Fietkau   cfg80211: add sup...
684
685
  {
  	struct sk_buff *frame;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
686
  	int cur_len = len;
230fd28a9   Felix Fietkau   cfg80211: add sup...
687
688
689
690
691
  
  	if (skb->len - offset < len)
  		return NULL;
  
  	/*
2b67f944f   Felix Fietkau   cfg80211: reuse e...
692
693
694
695
696
697
698
699
  	 * 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...
700
701
702
  	 * Allocate and reserve two bytes more for payload
  	 * alignment since sizeof(struct ethhdr) is 14.
  	 */
2b67f944f   Felix Fietkau   cfg80211: reuse e...
703
  	frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
16a910a67   Gregory Greenman   cfg80211: handle ...
704
705
  	if (!frame)
  		return NULL;
230fd28a9   Felix Fietkau   cfg80211: add sup...
706
707
  
  	skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
2b67f944f   Felix Fietkau   cfg80211: reuse e...
708
709
710
711
712
713
714
715
  	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...
716
717
718
  
  	return frame;
  }
eaf85ca7f   Zhu Yi   wireless: add iee...
719
720
721
  
  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...
722
  			      const unsigned int extra_headroom,
8b935ee2e   Johannes Berg   cfg80211: add abi...
723
  			      const u8 *check_da, const u8 *check_sa)
eaf85ca7f   Zhu Yi   wireless: add iee...
724
  {
230fd28a9   Felix Fietkau   cfg80211: add sup...
725
  	unsigned int hlen = ALIGN(extra_headroom, 4);
eaf85ca7f   Zhu Yi   wireless: add iee...
726
727
728
  	struct sk_buff *frame = NULL;
  	u16 ethertype;
  	u8 *payload;
7f6990c83   Johannes Berg   cfg80211: let iee...
729
  	int offset = 0, remaining;
230fd28a9   Felix Fietkau   cfg80211: add sup...
730
  	struct ethhdr eth;
2b67f944f   Felix Fietkau   cfg80211: reuse e...
731
  	bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
2bf0ccc70   Felix Fietkau   cfg80211: fix fau...
732
  	bool reuse_skb = false;
230fd28a9   Felix Fietkau   cfg80211: add sup...
733
  	bool last = false;
88665f5a7   Felix Fietkau   mac80211: move A-...
734

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

230fd28a9   Felix Fietkau   cfg80211: add sup...
740
741
742
  		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...
743
  		padding = (4 - subframe_len) & 0x3;
230fd28a9   Felix Fietkau   cfg80211: add sup...
744

eaf85ca7f   Zhu Yi   wireless: add iee...
745
  		/* the last MSDU has no padding */
230fd28a9   Felix Fietkau   cfg80211: add sup...
746
  		remaining = skb->len - offset;
eaf85ca7f   Zhu Yi   wireless: add iee...
747
748
  		if (subframe_len > remaining)
  			goto purge;
230fd28a9   Felix Fietkau   cfg80211: add sup...
749
  		offset += sizeof(struct ethhdr);
230fd28a9   Felix Fietkau   cfg80211: add sup...
750
  		last = remaining <= subframe_len + padding;
8b935ee2e   Johannes Berg   cfg80211: add abi...
751
752
753
754
755
756
757
758
759
760
  
  		/* 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...
761
  		if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
230fd28a9   Felix Fietkau   cfg80211: add sup...
762
  			skb_pull(skb, offset);
eaf85ca7f   Zhu Yi   wireless: add iee...
763
  			frame = skb;
230fd28a9   Felix Fietkau   cfg80211: add sup...
764
765
  			reuse_skb = true;
  		} else {
2b67f944f   Felix Fietkau   cfg80211: reuse e...
766
767
  			frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
  						       reuse_frag);
eaf85ca7f   Zhu Yi   wireless: add iee...
768
769
  			if (!frame)
  				goto purge;
230fd28a9   Felix Fietkau   cfg80211: add sup...
770
  			offset += len + padding;
eaf85ca7f   Zhu Yi   wireless: add iee...
771
772
773
774
775
776
777
778
  		}
  
  		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...
779
  		if (likely((ether_addr_equal(payload, rfc1042_header) &&
eaf85ca7f   Zhu Yi   wireless: add iee...
780
  			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
ac422d3cc   Joe Perches   wireless: Convert...
781
  			   ether_addr_equal(payload, bridge_tunnel_header))) {
230fd28a9   Felix Fietkau   cfg80211: add sup...
782
783
  			eth.h_proto = htons(ethertype);
  			skb_pull(frame, ETH_ALEN + 2);
eaf85ca7f   Zhu Yi   wireless: add iee...
784
  		}
230fd28a9   Felix Fietkau   cfg80211: add sup...
785
786
  
  		memcpy(skb_push(frame, sizeof(eth)), &eth, sizeof(eth));
eaf85ca7f   Zhu Yi   wireless: add iee...
787
788
  		__skb_queue_tail(list, frame);
  	}
230fd28a9   Felix Fietkau   cfg80211: add sup...
789
790
  	if (!reuse_skb)
  		dev_kfree_skb(skb);
eaf85ca7f   Zhu Yi   wireless: add iee...
791
792
793
794
  	return;
  
   purge:
  	__skb_queue_purge(list);
eaf85ca7f   Zhu Yi   wireless: add iee...
795
796
797
  	dev_kfree_skb(skb);
  }
  EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
e31a16d6f   Zhu Yi   wireless: move so...
798
  /* Given a data frame determine the 802.1p/1d tag to use. */
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
799
800
  unsigned int cfg80211_classify8021d(struct sk_buff *skb,
  				    struct cfg80211_qos_map *qos_map)
e31a16d6f   Zhu Yi   wireless: move so...
801
802
  {
  	unsigned int dscp;
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
803
  	unsigned char vlan_priority;
1fc9b7253   Johannes Berg   cfg80211: prevent...
804
  	unsigned int ret;
e31a16d6f   Zhu Yi   wireless: move so...
805
806
807
808
809
810
  
  	/* 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.
  	 */
1fc9b7253   Johannes Berg   cfg80211: prevent...
811
812
813
814
  	if (skb->priority >= 256 && skb->priority <= 263) {
  		ret = skb->priority - 256;
  		goto out;
  	}
e31a16d6f   Zhu Yi   wireless: move so...
815

df8a39def   Jiri Pirko   net: rename vlan_...
816
817
  	if (skb_vlan_tag_present(skb)) {
  		vlan_priority = (skb_vlan_tag_get(skb) & VLAN_PRIO_MASK)
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
818
  			>> VLAN_PRIO_SHIFT;
1fc9b7253   Johannes Berg   cfg80211: prevent...
819
820
821
822
  		if (vlan_priority > 0) {
  			ret = vlan_priority;
  			goto out;
  		}
c6ca5e28b   cedric Voncken   cfg80211: vlan pr...
823
  	}
e31a16d6f   Zhu Yi   wireless: move so...
824
825
  	switch (skb->protocol) {
  	case htons(ETH_P_IP):
b156579b1   Dave Täht   wireless: Treat I...
826
827
828
829
  		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...
830
  		break;
960d97f95   Simon Wunderlich   cfg80211: add MPL...
831
832
833
834
835
836
837
838
  	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;
1fc9b7253   Johannes Berg   cfg80211: prevent...
839
  		ret = (ntohl(mpls->entry) & MPLS_LS_TC_MASK)
960d97f95   Simon Wunderlich   cfg80211: add MPL...
840
  			>> MPLS_LS_TC_SHIFT;
1fc9b7253   Johannes Berg   cfg80211: prevent...
841
  		goto out;
960d97f95   Simon Wunderlich   cfg80211: add MPL...
842
843
844
845
  	}
  	case htons(ETH_P_80221):
  		/* 802.21 is always network control traffic */
  		return 7;
e31a16d6f   Zhu Yi   wireless: move so...
846
847
848
  	default:
  		return 0;
  	}
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
849
850
851
852
  	if (qos_map) {
  		unsigned int i, tmp_dscp = dscp >> 2;
  
  		for (i = 0; i < qos_map->num_des; i++) {
1fc9b7253   Johannes Berg   cfg80211: prevent...
853
854
855
856
  			if (tmp_dscp == qos_map->dscp_exception[i].dscp) {
  				ret = qos_map->dscp_exception[i].up;
  				goto out;
  			}
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
857
858
859
860
  		}
  
  		for (i = 0; i < 8; i++) {
  			if (tmp_dscp >= qos_map->up[i].low &&
1fc9b7253   Johannes Berg   cfg80211: prevent...
861
862
863
864
  			    tmp_dscp <= qos_map->up[i].high) {
  				ret = i;
  				goto out;
  			}
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
865
866
  		}
  	}
1fc9b7253   Johannes Berg   cfg80211: prevent...
867
868
869
  	ret = dscp >> 5;
  out:
  	return array_index_nospec(ret, IEEE80211_NUM_TIDS);
e31a16d6f   Zhu Yi   wireless: move so...
870
871
  }
  EXPORT_SYMBOL(cfg80211_classify8021d);
517357c68   Johannes Berg   cfg80211: assimil...
872

49a68e0d8   Johannes Berg   cfg80211: add var...
873
  const struct element *ieee80211_bss_get_elem(struct cfg80211_bss *bss, u8 id)
517357c68   Johannes Berg   cfg80211: assimil...
874
  {
9caf03640   Johannes Berg   cfg80211: fix BSS...
875
876
877
878
  	const struct cfg80211_bss_ies *ies;
  
  	ies = rcu_dereference(bss->ies);
  	if (!ies)
517357c68   Johannes Berg   cfg80211: assimil...
879
  		return NULL;
9caf03640   Johannes Berg   cfg80211: fix BSS...
880

49a68e0d8   Johannes Berg   cfg80211: add var...
881
  	return cfg80211_find_elem(id, ies->data, ies->len);
517357c68   Johannes Berg   cfg80211: assimil...
882
  }
49a68e0d8   Johannes Berg   cfg80211: add var...
883
  EXPORT_SYMBOL(ieee80211_bss_get_elem);
fffd0934b   Johannes Berg   cfg80211: rework ...
884
885
886
  
  void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
  {
f26cbf401   Zhao, Gang   cfg80211: change ...
887
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
fffd0934b   Johannes Berg   cfg80211: rework ...
888
889
890
891
892
  	struct net_device *dev = wdev->netdev;
  	int i;
  
  	if (!wdev->connect_keys)
  		return;
b8676221f   David Spinadel   cfg80211: Add sup...
893
  	for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++) {
fffd0934b   Johannes Berg   cfg80211: rework ...
894
895
  		if (!wdev->connect_keys->params[i].cipher)
  			continue;
e35e4d28b   Hila Gonen   cfg80211: add wra...
896
897
  		if (rdev_add_key(rdev, dev, i, false, NULL,
  				 &wdev->connect_keys->params[i])) {
e9c0268f0   Joe Perches   net/wireless: Use...
898
899
  			netdev_err(dev, "failed to set key %d
  ", i);
1e056665e   Zhu Yi   cfg80211: avoid s...
900
901
  			continue;
  		}
d4f299786   Johannes Berg   cfg80211: combine...
902
903
904
905
906
907
  		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 ...
908
  	}
453431a54   Waiman Long   mm, treewide: ren...
909
  	kfree_sensitive(wdev->connect_keys);
fffd0934b   Johannes Berg   cfg80211: rework ...
910
911
  	wdev->connect_keys = NULL;
  }
3d54d2551   Johannes Berg   cfg80211: clean u...
912

1f6fc43e6   Daniel Drake   cfg80211: process...
913
  void cfg80211_process_wdev_events(struct wireless_dev *wdev)
3d54d2551   Johannes Berg   cfg80211: clean u...
914
915
916
  {
  	struct cfg80211_event *ev;
  	unsigned long flags;
3d54d2551   Johannes Berg   cfg80211: clean u...
917
918
919
920
921
922
923
924
925
926
927
  
  	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...
928
  			__cfg80211_connect_result(
5349a0f7b   Vidyullatha Kanchanapally   cfg80211: Use a s...
929
930
931
  				wdev->netdev,
  				&ev->cr,
  				ev->cr.status == WLAN_STATUS_SUCCESS);
3d54d2551   Johannes Berg   cfg80211: clean u...
932
933
  			break;
  		case EVENT_ROAMED:
29ce6ecbb   Avraham Stern   cfg80211: unify c...
934
  			__cfg80211_roamed(wdev, &ev->rm);
3d54d2551   Johannes Berg   cfg80211: clean u...
935
936
937
938
  			break;
  		case EVENT_DISCONNECTED:
  			__cfg80211_disconnected(wdev->netdev,
  						ev->dc.ie, ev->dc.ie_len,
80279fb7b   Johannes Berg   cfg80211: properl...
939
940
  						ev->dc.reason,
  						!ev->dc.locally_generated);
3d54d2551   Johannes Berg   cfg80211: clean u...
941
942
  			break;
  		case EVENT_IBSS_JOINED:
fe94f3a4f   Antonio Quartulli   cfg80211: fix cha...
943
944
  			__cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
  					       ev->ij.channel);
3d54d2551   Johannes Berg   cfg80211: clean u...
945
  			break;
f04c22033   Michal Kazior   cfg80211: export ...
946
947
948
  		case EVENT_STOPPED:
  			__cfg80211_leave(wiphy_to_rdev(wdev->wiphy), wdev);
  			break;
503c1fb98   Avraham Stern   cfg80211/nl80211:...
949
950
951
  		case EVENT_PORT_AUTHORIZED:
  			__cfg80211_port_authorized(wdev, ev->pa.bssid);
  			break;
3d54d2551   Johannes Berg   cfg80211: clean u...
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  		}
  		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...
967

53873f134   Johannes Berg   cfg80211: make wd...
968
  	list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
3d54d2551   Johannes Berg   cfg80211: clean u...
969
  		cfg80211_process_wdev_events(wdev);
3d54d2551   Johannes Berg   cfg80211: clean u...
970
971
972
973
  }
  
  int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
  			  struct net_device *dev, enum nl80211_iftype ntype,
818a986e4   Johannes Berg   cfg80211: move ad...
974
  			  struct vif_params *params)
3d54d2551   Johannes Berg   cfg80211: clean u...
975
976
977
  {
  	int err;
  	enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
73fb08e24   Zhao, Gang   cfg80211: remove ...
978
  	ASSERT_RTNL();
3d54d2551   Johannes Berg   cfg80211: clean u...
979
980
981
982
  
  	/* don't support changing VLANs, you just re-create them */
  	if (otype == NL80211_IFTYPE_AP_VLAN)
  		return -EOPNOTSUPP;
cb3b7d876   Ayala Beker   cfg80211: add sta...
983
984
985
  	/* cannot change into P2P device or NAN */
  	if (ntype == NL80211_IFTYPE_P2P_DEVICE ||
  	    ntype == NL80211_IFTYPE_NAN)
98104fded   Johannes Berg   cfg80211: add P2P...
986
  		return -EOPNOTSUPP;
3d54d2551   Johannes Berg   cfg80211: clean u...
987
988
989
  	if (!rdev->ops->change_virtual_intf ||
  	    !(rdev->wiphy.interface_modes & (1 << ntype)))
  		return -EOPNOTSUPP;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
990
  	/* if it's part of a bridge, reject changing type to station/ibss */
2e92a2d0e   Julian Wiedmann   net: use netif_is...
991
  	if (netif_is_bridge_port(dev) &&
074ac8df9   Johannes Berg   cfg80211/nl80211:...
992
993
994
  	    (ntype == NL80211_IFTYPE_ADHOC ||
  	     ntype == NL80211_IFTYPE_STATION ||
  	     ntype == NL80211_IFTYPE_P2P_CLIENT))
ad4bb6f88   Johannes Berg   cfg80211: disallo...
995
  		return -EBUSY;
6cbfb1bb6   Michal Kazior   cfg80211: ignore ...
996
  	if (ntype != otype) {
9bc383de3   Johannes Berg   cfg80211: introdu...
997
  		dev->ieee80211_ptr->use_4addr = false;
29cbe68c5   Johannes Berg   cfg80211/mac80211...
998
  		dev->ieee80211_ptr->mesh_id_up_len = 0;
194ff52d4   Johannes Berg   cfg80211/mac80211...
999
  		wdev_lock(dev->ieee80211_ptr);
fa9ffc745   Kyeyoon Park   cfg80211: Add sup...
1000
  		rdev_set_qos_map(rdev, dev, NULL);
194ff52d4   Johannes Berg   cfg80211/mac80211...
1001
  		wdev_unlock(dev->ieee80211_ptr);
9bc383de3   Johannes Berg   cfg80211: introdu...
1002

3d54d2551   Johannes Berg   cfg80211: clean u...
1003
  		switch (otype) {
ac800140c   Michal Kazior   cfg80211: .stop_a...
1004
  		case NL80211_IFTYPE_AP:
7c8d5e03a   Ilan Peer   cfg80211: send st...
1005
  			cfg80211_stop_ap(rdev, dev, true);
ac800140c   Michal Kazior   cfg80211: .stop_a...
1006
  			break;
3d54d2551   Johannes Berg   cfg80211: clean u...
1007
1008
1009
1010
  		case NL80211_IFTYPE_ADHOC:
  			cfg80211_leave_ibss(rdev, dev, false);
  			break;
  		case NL80211_IFTYPE_STATION:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1011
  		case NL80211_IFTYPE_P2P_CLIENT:
83739b03d   Johannes Berg   cfg80211: remove ...
1012
  			wdev_lock(dev->ieee80211_ptr);
3d54d2551   Johannes Berg   cfg80211: clean u...
1013
1014
  			cfg80211_disconnect(rdev, dev,
  					    WLAN_REASON_DEAUTH_LEAVING, true);
83739b03d   Johannes Berg   cfg80211: remove ...
1015
  			wdev_unlock(dev->ieee80211_ptr);
3d54d2551   Johannes Berg   cfg80211: clean u...
1016
1017
1018
1019
1020
1021
1022
1023
1024
  			break;
  		case NL80211_IFTYPE_MESH_POINT:
  			/* mesh should be handled? */
  			break;
  		default:
  			break;
  		}
  
  		cfg80211_process_rdev_events(rdev);
c1d3ad84e   Denis Kenzior   cfg80211: Purge f...
1025
  		cfg80211_mlme_purge_registrations(dev->ieee80211_ptr);
3d54d2551   Johannes Berg   cfg80211: clean u...
1026
  	}
818a986e4   Johannes Berg   cfg80211: move ad...
1027
  	err = rdev_change_virtual_intf(rdev, dev, ntype, params);
3d54d2551   Johannes Berg   cfg80211: clean u...
1028
1029
  
  	WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
9bc383de3   Johannes Berg   cfg80211: introdu...
1030
1031
  	if (!err && params && params->use_4addr != -1)
  		dev->ieee80211_ptr->use_4addr = params->use_4addr;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1032
1033
1034
1035
1036
1037
  	if (!err) {
  		dev->priv_flags &= ~IFF_DONT_BRIDGE;
  		switch (ntype) {
  		case NL80211_IFTYPE_STATION:
  			if (dev->ieee80211_ptr->use_4addr)
  				break;
df561f668   Gustavo A. R. Silva   treewide: Use fal...
1038
  			fallthrough;
6e0bd6c35   Rostislav Lisovy   cfg80211: 802.11p...
1039
  		case NL80211_IFTYPE_OCB:
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1040
  		case NL80211_IFTYPE_P2P_CLIENT:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1041
1042
1043
  		case NL80211_IFTYPE_ADHOC:
  			dev->priv_flags |= IFF_DONT_BRIDGE;
  			break;
074ac8df9   Johannes Berg   cfg80211/nl80211:...
1044
  		case NL80211_IFTYPE_P2P_GO:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
  		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...
1055
  		case NUM_NL80211_IFTYPES:
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1056
1057
  			/* not happening */
  			break;
98104fded   Johannes Berg   cfg80211: add P2P...
1058
  		case NL80211_IFTYPE_P2P_DEVICE:
cb3b7d876   Ayala Beker   cfg80211: add sta...
1059
  		case NL80211_IFTYPE_NAN:
98104fded   Johannes Berg   cfg80211: add P2P...
1060
1061
  			WARN_ON(1);
  			break;
ad4bb6f88   Johannes Berg   cfg80211: disallo...
1062
1063
  		}
  	}
dbbae26af   Michal Kazior   cfg80211: track m...
1064
1065
1066
1067
  	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...
1068
1069
  	return err;
  }
254416aae   John W. Linville   wireless: report ...
1070

0c1eca4e2   Johannes Berg   cfg80211: refacto...
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
  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;
  }
2a38075cd   Alexei Avshalom Lazar   nl80211: Add supp...
1099
  static u32 cfg80211_calculate_bitrate_dmg(struct rate_info *rate)
95ddc1fc4   Vladimir Kondratiev   cfg80211: bitrate...
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
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
  {
  	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];
  }
2a38075cd   Alexei Avshalom Lazar   nl80211: Add supp...
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  static u32 cfg80211_calculate_bitrate_edmg(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] = 13475,
  		[7] = 15400,
  		[8] = 19250,
  		[9] = 23100,
  		[10] = 25025,
  		[11] = 26950,
  		[12] = 30800,
  		[13] = 38500,
  		[14] = 46200,
  		[15] = 50050,
  		[16] = 53900,
  		[17] = 57750,
  		[18] = 69300,
  		[19] = 75075,
  		[20] = 80850,
  	};
  
  	if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate)))
  		return 0;
  
  	return __mcs2bitrate[rate->mcs] * rate->n_bonded_ch;
  }
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
  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...
1190
1191
  		/* not in the spec, but some devices use this: */
  		   86500000,
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
  		},
  		{  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...
1229
1230
  	if (rate->mcs > 9)
  		goto warn;
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1231

b51f3beec   Johannes Berg   cfg80211: change ...
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
  	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...
1245
  		goto warn;
b51f3beec   Johannes Berg   cfg80211: change ...
1246
1247
1248
  	case RATE_INFO_BW_20:
  		idx = 0;
  	}
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1249
1250
1251
1252
1253
1254
1255
1256
1257
  
  	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...
1258
1259
1260
1261
1262
   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:...
1263
  }
c4cbaf797   Luca Coelho   cfg80211: Add sup...
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
1324
  static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
  {
  #define SCALE 2048
  	u16 mcs_divisors[12] = {
  		34133, /* 16.666666... */
  		17067, /*  8.333333... */
  		11378, /*  5.555555... */
  		 8533, /*  4.166666... */
  		 5689, /*  2.777777... */
  		 4267, /*  2.083333... */
  		 3923, /*  1.851851... */
  		 3413, /*  1.666666... */
  		 2844, /*  1.388888... */
  		 2560, /*  1.250000... */
  		 2276, /*  1.111111... */
  		 2048, /*  1.000000... */
  	};
  	u32 rates_160M[3] = { 960777777, 907400000, 816666666 };
  	u32 rates_969[3] =  { 480388888, 453700000, 408333333 };
  	u32 rates_484[3] =  { 229411111, 216666666, 195000000 };
  	u32 rates_242[3] =  { 114711111, 108333333,  97500000 };
  	u32 rates_106[3] =  {  40000000,  37777777,  34000000 };
  	u32 rates_52[3]  =  {  18820000,  17777777,  16000000 };
  	u32 rates_26[3]  =  {   9411111,   8888888,   8000000 };
  	u64 tmp;
  	u32 result;
  
  	if (WARN_ON_ONCE(rate->mcs > 11))
  		return 0;
  
  	if (WARN_ON_ONCE(rate->he_gi > NL80211_RATE_INFO_HE_GI_3_2))
  		return 0;
  	if (WARN_ON_ONCE(rate->he_ru_alloc >
  			 NL80211_RATE_INFO_HE_RU_ALLOC_2x996))
  		return 0;
  	if (WARN_ON_ONCE(rate->nss < 1 || rate->nss > 8))
  		return 0;
  
  	if (rate->bw == RATE_INFO_BW_160)
  		result = rates_160M[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_80 ||
  		 (rate->bw == RATE_INFO_BW_HE_RU &&
  		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_996))
  		result = rates_969[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_40 ||
  		 (rate->bw == RATE_INFO_BW_HE_RU &&
  		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_484))
  		result = rates_484[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_20 ||
  		 (rate->bw == RATE_INFO_BW_HE_RU &&
  		  rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_242))
  		result = rates_242[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_HE_RU &&
  		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_106)
  		result = rates_106[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_HE_RU &&
  		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_52)
  		result = rates_52[rate->he_gi];
  	else if (rate->bw == RATE_INFO_BW_HE_RU &&
  		 rate->he_ru_alloc == NL80211_RATE_INFO_HE_RU_ALLOC_26)
  		result = rates_26[rate->he_gi];
344c9719c   Nathan Chancellor   cfg80211: Change ...
1325
1326
1327
1328
  	else {
  		WARN(1, "invalid HE MCS: bw:%d, ru:%d
  ",
  		     rate->bw, rate->he_ru_alloc);
c4cbaf797   Luca Coelho   cfg80211: Add sup...
1329
  		return 0;
344c9719c   Nathan Chancellor   cfg80211: Change ...
1330
  	}
c4cbaf797   Luca Coelho   cfg80211: Add sup...
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
  
  	/* now scale to the appropriate MCS */
  	tmp = result;
  	tmp *= SCALE;
  	do_div(tmp, mcs_divisors[rate->mcs]);
  	result = tmp;
  
  	/* and take NSS, DCM into account */
  	result = (result * rate->nss) / 8;
  	if (rate->he_dcm)
  		result /= 2;
25d16d124   John Crispin   mac80211: fix rat...
1342
  	return result / 10000;
c4cbaf797   Luca Coelho   cfg80211: Add sup...
1343
  }
8eb41c8df   Vladimir Kondratiev   {nl,cfg}80211: su...
1344
  u32 cfg80211_calculate_bitrate(struct rate_info *rate)
254416aae   John W. Linville   wireless: report ...
1345
  {
0c1eca4e2   Johannes Berg   cfg80211: refacto...
1346
1347
  	if (rate->flags & RATE_INFO_FLAGS_MCS)
  		return cfg80211_calculate_bitrate_ht(rate);
2a38075cd   Alexei Avshalom Lazar   nl80211: Add supp...
1348
1349
1350
1351
  	if (rate->flags & RATE_INFO_FLAGS_DMG)
  		return cfg80211_calculate_bitrate_dmg(rate);
  	if (rate->flags & RATE_INFO_FLAGS_EDMG)
  		return cfg80211_calculate_bitrate_edmg(rate);
db9c64cf8   Johannes Berg   nl80211/cfg80211:...
1352
1353
  	if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
  		return cfg80211_calculate_bitrate_vht(rate);
c4cbaf797   Luca Coelho   cfg80211: Add sup...
1354
1355
  	if (rate->flags & RATE_INFO_FLAGS_HE_MCS)
  		return cfg80211_calculate_bitrate_he(rate);
254416aae   John W. Linville   wireless: report ...
1356

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

c216e6417   Arend van Spriel   cfg80211: change ...
1361
1362
1363
  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...
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
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
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
  {
  	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);
2512b1b18   Liad Kaufman   mac80211: extend ...
1460
  static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id, bool id_ext)
29464ccc7   Johannes Berg   cfg80211: move IE...
1461
1462
  {
  	int i;
2512b1b18   Liad Kaufman   mac80211: extend ...
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
  	/* Make sure array values are legal */
  	if (WARN_ON(ids[n_ids - 1] == WLAN_EID_EXTENSION))
  		return false;
  
  	i = 0;
  	while (i < n_ids) {
  		if (ids[i] == WLAN_EID_EXTENSION) {
  			if (id_ext && (ids[i + 1] == id))
  				return true;
  
  			i += 2;
  			continue;
  		}
  
  		if (ids[i] == id && !id_ext)
29464ccc7   Johannes Berg   cfg80211: move IE...
1478
  			return true;
2512b1b18   Liad Kaufman   mac80211: extend ...
1479
1480
1481
  
  		i++;
  	}
29464ccc7   Johannes Berg   cfg80211: move IE...
1482
1483
  	return false;
  }
8ac634486   Johannes Berg   cfg80211: handle ...
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
  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...
1502
1503
1504
1505
1506
1507
  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;
2512b1b18   Liad Kaufman   mac80211: extend ...
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
  	while (pos < ielen) {
  		u8 ext = 0;
  
  		if (ies[pos] == WLAN_EID_EXTENSION)
  			ext = 2;
  		if ((pos + ext) >= ielen)
  			break;
  
  		if (!ieee80211_id_in_list(ids, n_ids, ies[pos + ext],
  					  ies[pos] == WLAN_EID_EXTENSION))
  			break;
29464ccc7   Johannes Berg   cfg80211: move IE...
1519
  		if (ies[pos] == WLAN_EID_RIC_DATA && n_after_ric) {
8ac634486   Johannes Berg   cfg80211: handle ...
1520
  			pos = skip_ie(ies, ielen, pos);
29464ccc7   Johannes Berg   cfg80211: move IE...
1521

2512b1b18   Liad Kaufman   mac80211: extend ...
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
  			while (pos < ielen) {
  				if (ies[pos] == WLAN_EID_EXTENSION)
  					ext = 2;
  				else
  					ext = 0;
  
  				if ((pos + ext) >= ielen)
  					break;
  
  				if (!ieee80211_id_in_list(after_ric,
  							  n_after_ric,
  							  ies[pos + ext],
  							  ext == 2))
  					pos = skip_ie(ies, ielen, pos);
312ca38dd   Jouni Malinen   cfg80211: Fix bus...
1536
1537
  				else
  					break;
2512b1b18   Liad Kaufman   mac80211: extend ...
1538
  			}
29464ccc7   Johannes Berg   cfg80211: move IE...
1539
  		} else {
8ac634486   Johannes Berg   cfg80211: handle ...
1540
  			pos = skip_ie(ies, ielen, pos);
29464ccc7   Johannes Berg   cfg80211: move IE...
1541
1542
1543
1544
1545
1546
  		}
  	}
  
  	return pos;
  }
  EXPORT_SYMBOL(ieee80211_ie_split_ric);
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1547
  bool ieee80211_operating_class_to_band(u8 operating_class,
57fbcce37   Johannes Berg   cfg80211: remove ...
1548
  				       enum nl80211_band *band)
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1549
1550
1551
1552
  {
  	switch (operating_class) {
  	case 112:
  	case 115 ... 127:
954a86ef4   Eliad Peller   cfg80211: add ope...
1553
  	case 128 ... 130:
57fbcce37   Johannes Berg   cfg80211: remove ...
1554
  		*band = NL80211_BAND_5GHZ;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1555
  		return true;
852f04620   Arend van Spriel   cfg80211: extend ...
1556
1557
1558
  	case 131 ... 135:
  		*band = NL80211_BAND_6GHZ;
  		return true;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1559
1560
1561
1562
  	case 81:
  	case 82:
  	case 83:
  	case 84:
57fbcce37   Johannes Berg   cfg80211: remove ...
1563
  		*band = NL80211_BAND_2GHZ;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1564
  		return true;
55300a13d   Vladimir Kondratiev   cfg80211: add 60G...
1565
  	case 180:
57fbcce37   Johannes Berg   cfg80211: remove ...
1566
  		*band = NL80211_BAND_60GHZ;
55300a13d   Vladimir Kondratiev   cfg80211: add 60G...
1567
  		return true;
1ce3e82b0   Johannes Berg   cfg80211: add iee...
1568
1569
1570
1571
1572
  	}
  
  	return false;
  }
  EXPORT_SYMBOL(ieee80211_operating_class_to_band);
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
1573
1574
1575
1576
  bool ieee80211_chandef_to_operating_class(struct cfg80211_chan_def *chandef,
  					  u8 *op_class)
  {
  	u8 vht_opclass;
8442938c3   Dan Carpenter   cfg80211: fix a t...
1577
  	u32 freq = chandef->center_freq1;
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
  
  	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) {
ec649fed6   Masashi Honma   nl80211: Disallow...
1597
1598
  		/* channel 14 is only for IEEE 802.11b */
  		if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
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
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
  			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 */
9cf0a0b4b   Alexei Avshalom Lazar   cfg80211: Add sup...
1690
  	if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) {
a38700dd4   Arik Nemtsov   cfg/mac80211: add...
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
  		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...
1702
1703
1704
  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...
1705
1706
  {
  	struct wireless_dev *wdev;
56d1893d9   Johannes Berg   cfg80211: restric...
1707

4c8dea638   Johannes Berg   cfg80211: validat...
1708
1709
  	*beacon_int_gcd = 0;
  	*beacon_int_different = false;
56d1893d9   Johannes Berg   cfg80211: restric...
1710

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

4c8dea638   Johannes Berg   cfg80211: validat...
1715
1716
  		if (!*beacon_int_gcd) {
  			*beacon_int_gcd = wdev->beacon_interval;
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1717
  			continue;
4c8dea638   Johannes Berg   cfg80211: validat...
1718
  		}
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1719

4c8dea638   Johannes Berg   cfg80211: validat...
1720
  		if (wdev->beacon_interval == *beacon_int_gcd)
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1721
  			continue;
4c8dea638   Johannes Berg   cfg80211: validat...
1722
1723
1724
  		*beacon_int_different = true;
  		*beacon_int_gcd = gcd(*beacon_int_gcd, wdev->beacon_interval);
  	}
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1725

4c8dea638   Johannes Berg   cfg80211: validat...
1726
1727
1728
1729
  	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...
1730
  	}
4c8dea638   Johannes Berg   cfg80211: validat...
1731
  }
56d1893d9   Johannes Berg   cfg80211: restric...
1732

4c8dea638   Johannes Berg   cfg80211: validat...
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
  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...
1748
  }
7527a782e   Johannes Berg   cfg80211: adverti...
1749

65a124dd7   Michal Kazior   cfg80211: allow d...
1750
  int cfg80211_iter_combinations(struct wiphy *wiphy,
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1751
  			       struct iface_combination_params *params,
65a124dd7   Michal Kazior   cfg80211: allow d...
1752
1753
1754
  			       void (*iter)(const struct ieee80211_iface_combination *c,
  					    void *data),
  			       void *data)
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1755
  {
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1756
1757
  	const struct ieee80211_regdomain *regdom;
  	enum nl80211_dfs_regions region = 0;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1758
1759
1760
  	int i, j, iftype;
  	int num_interfaces = 0;
  	u32 used_iftypes = 0;
4c8dea638   Johannes Berg   cfg80211: validat...
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
  	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...
1776

e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1777
  	if (params->radar_detect) {
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1778
1779
1780
1781
1782
1783
  		rcu_read_lock();
  		regdom = rcu_dereference(cfg80211_regdomain);
  		if (regdom)
  			region = regdom->dfs_region;
  		rcu_read_unlock();
  	}
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1784
  	for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1785
1786
  		num_interfaces += params->iftype_num[iftype];
  		if (params->iftype_num[iftype] > 0 &&
e6f405112   Manikanta Pubbisetty   {nl,mac}80211: fi...
1787
  		    !cfg80211_iftype_allowed(wiphy, iftype, 0, 1))
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
  			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...
1800
  		if (params->num_different_channels > c->num_different_channels)
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1801
1802
1803
1804
1805
1806
1807
1808
  			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++) {
e6f405112   Manikanta Pubbisetty   {nl,mac}80211: fi...
1809
  			if (cfg80211_iftype_allowed(wiphy, iftype, 0, 1))
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1810
1811
1812
1813
1814
  				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...
1815
  				if (limits[j].max < params->iftype_num[iftype])
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1816
  					goto cont;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1817
  				limits[j].max -= params->iftype_num[iftype];
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1818
1819
  			}
  		}
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1820
1821
  		if (params->radar_detect !=
  			(c->radar_detect_widths & params->radar_detect))
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1822
  			goto cont;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1823
  		if (params->radar_detect && c->radar_detect_regions &&
8c48b50a1   Felix Fietkau   cfg80211: allow r...
1824
1825
  		    !(c->radar_detect_regions & BIT(region)))
  			goto cont;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1826
1827
1828
1829
1830
1831
1832
  		/* 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...
1833
  		if (beacon_int_gcd) {
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1834
  			if (c->beacon_int_min_gcd &&
4c8dea638   Johannes Berg   cfg80211: validat...
1835
  			    beacon_int_gcd < c->beacon_int_min_gcd)
0507a3ac6   Johannes Berg   cfg80211: fix bea...
1836
  				goto cont;
4c8dea638   Johannes Berg   cfg80211: validat...
1837
  			if (!c->beacon_int_min_gcd && beacon_int_different)
0c317a02c   Purushottam Kushwaha   cfg80211: support...
1838
1839
  				goto cont;
  		}
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1840
1841
1842
  		/* This combination covered all interface types and
  		 * supported the requested numbers, so we're good.
  		 */
65a124dd7   Michal Kazior   cfg80211: allow d...
1843
1844
  
  		(*iter)(c, data);
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1845
1846
1847
   cont:
  		kfree(limits);
  	}
65a124dd7   Michal Kazior   cfg80211: allow d...
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
  	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...
1861
  				struct iface_combination_params *params)
65a124dd7   Michal Kazior   cfg80211: allow d...
1862
1863
  {
  	int err, num = 0;
e227300c8   Purushottam Kushwaha   cfg80211: pass st...
1864
  	err = cfg80211_iter_combinations(wiphy, params,
65a124dd7   Michal Kazior   cfg80211: allow d...
1865
1866
1867
1868
1869
1870
1871
  					 cfg80211_iter_sum_ifcombs, &num);
  	if (err)
  		return err;
  	if (num == 0)
  		return -EBUSY;
  
  	return 0;
cb2d956dd   Luciano Coelho   cfg80211: refacto...
1872
1873
  }
  EXPORT_SYMBOL(cfg80211_check_combinations);
34850ab25   Johannes Berg   cfg80211: allow u...
1874
1875
1876
1877
1878
  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...
1879
1880
  	if (!sband)
  		return -EINVAL;
34850ab25   Johannes Berg   cfg80211: allow u...
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
  	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...
1909

bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1910
1911
  unsigned int ieee80211_get_num_supported_channels(struct wiphy *wiphy)
  {
57fbcce37   Johannes Berg   cfg80211: remove ...
1912
  	enum nl80211_band band;
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1913
  	unsigned int n_channels = 0;
57fbcce37   Johannes Berg   cfg80211: remove ...
1914
  	for (band = 0; band < NUM_NL80211_BANDS; band++)
bdfbec2d2   Ilan Peer   cfg80211: Add a f...
1915
1916
1917
1918
1919
1920
  		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...
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
  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;
3c12d0486   Sven Eckelmann   cfg80211: initial...
1934
  	memset(sinfo, 0, sizeof(*sinfo));
7406353d4   Antonio Quartulli   cfg80211: impleme...
1935
1936
1937
  	return rdev_get_station(rdev, dev, mac_addr, sinfo);
  }
  EXPORT_SYMBOL(cfg80211_get_station);
a442b761b   Ayala Beker   cfg80211: add add...
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
  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...
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
  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;
  }
8689c051a   Arend van Spriel   cfg80211: dynamic...
1973
1974
  int cfg80211_sinfo_alloc_tid_stats(struct station_info *sinfo, gfp_t gfp)
  {
1d211d431   Johannes Berg   cfg80211: use bet...
1975
1976
1977
  	sinfo->pertid = kcalloc(IEEE80211_NUM_TIDS + 1,
  				sizeof(*(sinfo->pertid)),
  				gfp);
8689c051a   Arend van Spriel   cfg80211: dynamic...
1978
1979
1980
1981
1982
1983
  	if (!sinfo->pertid)
  		return -ENOMEM;
  
  	return 0;
  }
  EXPORT_SYMBOL(cfg80211_sinfo_alloc_tid_stats);
11a2a357a   Johannes Berg   cfg80211: work ar...
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
  /* 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);
30ca1aa53   Dedy Lansky   cfg80211/mac80211...
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
  
  /* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
  struct iapp_layer2_update {
  	u8 da[ETH_ALEN];	/* broadcast */
  	u8 sa[ETH_ALEN];	/* STA addr */
  	__be16 len;		/* 6 */
  	u8 dsap;		/* 0 */
  	u8 ssap;		/* 0 */
  	u8 control;
  	u8 xid_info[3];
  } __packed;
  
  void cfg80211_send_layer2_update(struct net_device *dev, const u8 *addr)
  {
  	struct iapp_layer2_update *msg;
  	struct sk_buff *skb;
  
  	/* Send Level 2 Update Frame to update forwarding tables in layer 2
  	 * bridge devices */
  
  	skb = dev_alloc_skb(sizeof(*msg));
  	if (!skb)
  		return;
  	msg = skb_put(skb, sizeof(*msg));
  
  	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
  	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
  
  	eth_broadcast_addr(msg->da);
  	ether_addr_copy(msg->sa, addr);
  	msg->len = htons(6);
  	msg->dsap = 0;
  	msg->ssap = 0x01;	/* NULL LSAP, CR Bit: Response */
  	msg->control = 0xaf;	/* XID response lsb.1111F101.
  				 * F=0 (no poll command; unsolicited frame) */
  	msg->xid_info[0] = 0x81;	/* XID format identifier */
  	msg->xid_info[1] = 1;	/* LLC types/classes: Type 1 LLC */
  	msg->xid_info[2] = 0;	/* XID sender's receive window size (RW) */
  
  	skb->dev = dev;
  	skb->protocol = eth_type_trans(skb, dev);
  	memset(skb->cb, 0, sizeof(skb->cb));
  	netif_rx_ni(skb);
  }
  EXPORT_SYMBOL(cfg80211_send_layer2_update);
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2039
2040
2041
  
  int ieee80211_get_vht_max_nss(struct ieee80211_vht_cap *cap,
  			      enum ieee80211_vht_chanwidth bw,
9166cc497   Johannes Berg   mac80211: impleme...
2042
2043
  			      int mcs, bool ext_nss_bw_capable,
  			      unsigned int max_vht_nss)
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2044
2045
  {
  	u16 map = le16_to_cpu(cap->supp_mcs.rx_mcs_map);
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2046
2047
2048
2049
2050
2051
  	int ext_nss_bw;
  	int supp_width;
  	int i, mcs_encoding;
  
  	if (map == 0xffff)
  		return 0;
9166cc497   Johannes Berg   mac80211: impleme...
2052
  	if (WARN_ON(mcs > 9 || max_vht_nss > 8))
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2053
2054
2055
2056
2057
2058
2059
  		return 0;
  	if (mcs <= 7)
  		mcs_encoding = 0;
  	else if (mcs == 8)
  		mcs_encoding = 1;
  	else
  		mcs_encoding = 2;
9166cc497   Johannes Berg   mac80211: impleme...
2060
2061
2062
2063
  	if (!max_vht_nss) {
  		/* find max_vht_nss for the given MCS */
  		for (i = 7; i >= 0; i--) {
  			int supp = (map >> (2 * i)) & 3;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2064

9166cc497   Johannes Berg   mac80211: impleme...
2065
2066
  			if (supp == 3)
  				continue;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2067

9166cc497   Johannes Berg   mac80211: impleme...
2068
2069
2070
2071
  			if (supp >= mcs_encoding) {
  				max_vht_nss = i + 1;
  				break;
  			}
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
  		}
  	}
  
  	if (!(cap->supp_mcs.tx_mcs_map &
  			cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE)))
  		return max_vht_nss;
  
  	ext_nss_bw = le32_get_bits(cap->vht_cap_info,
  				   IEEE80211_VHT_CAP_EXT_NSS_BW_MASK);
  	supp_width = le32_get_bits(cap->vht_cap_info,
  				   IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK);
  
  	/* if not capable, treat ext_nss_bw as 0 */
  	if (!ext_nss_bw_capable)
  		ext_nss_bw = 0;
  
  	/* This is invalid */
  	if (supp_width == 3)
  		return 0;
  
  	/* This is an invalid combination so pretend nothing is supported */
  	if (supp_width == 2 && (ext_nss_bw == 1 || ext_nss_bw == 2))
  		return 0;
  
  	/*
  	 * Cover all the special cases according to IEEE 802.11-2016
  	 * Table 9-250. All other cases are either factor of 1 or not
  	 * valid/supported.
  	 */
  	switch (bw) {
  	case IEEE80211_VHT_CHANWIDTH_USE_HT:
  	case IEEE80211_VHT_CHANWIDTH_80MHZ:
  		if ((supp_width == 1 || supp_width == 2) &&
  		    ext_nss_bw == 3)
  			return 2 * max_vht_nss;
  		break;
  	case IEEE80211_VHT_CHANWIDTH_160MHZ:
  		if (supp_width == 0 &&
  		    (ext_nss_bw == 1 || ext_nss_bw == 2))
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2111
  			return max_vht_nss / 2;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2112
2113
  		if (supp_width == 0 &&
  		    ext_nss_bw == 3)
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2114
  			return (3 * max_vht_nss) / 4;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2115
2116
2117
2118
2119
  		if (supp_width == 1 &&
  		    ext_nss_bw == 3)
  			return 2 * max_vht_nss;
  		break;
  	case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2120
  		if (supp_width == 0 && ext_nss_bw == 1)
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2121
2122
2123
  			return 0; /* not possible */
  		if (supp_width == 0 &&
  		    ext_nss_bw == 2)
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2124
  			return max_vht_nss / 2;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2125
2126
  		if (supp_width == 0 &&
  		    ext_nss_bw == 3)
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2127
  			return (3 * max_vht_nss) / 4;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2128
2129
2130
2131
2132
  		if (supp_width == 1 &&
  		    ext_nss_bw == 0)
  			return 0; /* not possible */
  		if (supp_width == 1 &&
  		    ext_nss_bw == 1)
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2133
  			return max_vht_nss / 2;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2134
2135
  		if (supp_width == 1 &&
  		    ext_nss_bw == 2)
93bc8ac49   Johannes Berg   cfg80211: fix iee...
2136
  			return (3 * max_vht_nss) / 4;
b0aa75f0b   Johannes Berg   ieee80211: add ne...
2137
2138
2139
2140
2141
2142
2143
  		break;
  	}
  
  	/* not covered or invalid combination received */
  	return max_vht_nss;
  }
  EXPORT_SYMBOL(ieee80211_get_vht_max_nss);
e6f405112   Manikanta Pubbisetty   {nl,mac}80211: fi...
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
  
  bool cfg80211_iftype_allowed(struct wiphy *wiphy, enum nl80211_iftype iftype,
  			     bool is_4addr, u8 check_swif)
  
  {
  	bool is_vlan = iftype == NL80211_IFTYPE_AP_VLAN;
  
  	switch (check_swif) {
  	case 0:
  		if (is_vlan && is_4addr)
  			return wiphy->flags & WIPHY_FLAG_4ADDR_AP;
  		return wiphy->interface_modes & BIT(iftype);
  	case 1:
  		if (!(wiphy->software_iftypes & BIT(iftype)) && is_vlan)
  			return wiphy->flags & WIPHY_FLAG_4ADDR_AP;
  		return wiphy->software_iftypes & BIT(iftype);
  	default:
  		break;
  	}
  
  	return false;
  }
  EXPORT_SYMBOL(cfg80211_iftype_allowed);