Blame view

net/wireless/wext-compat.c 38.7 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
fee52678d   Johannes Berg   cfg80211: handle ...
2
3
4
5
6
7
8
  /*
   * cfg80211 - wext compat code
   *
   * This is temporary code until all wireless functionality is migrated
   * into cfg80211, when that happens all the exports here go away and
   * we directly assign the wireless handlers of wireless interfaces.
   *
08645126d   Johannes Berg   cfg80211: impleme...
9
   * Copyright 2008-2009	Johannes Berg <johannes@sipsolutions.net>
3cfe91c4c   Johannes Berg   cfg80211: always ...
10
   * Copyright (C) 2019 Intel Corporation
fee52678d   Johannes Berg   cfg80211: handle ...
11
   */
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
12
  #include <linux/export.h>
fee52678d   Johannes Berg   cfg80211: handle ...
13
14
  #include <linux/wireless.h>
  #include <linux/nl80211.h>
691597cb2   Johannes Berg   cfg80211/mac80211...
15
  #include <linux/if_arp.h>
08645126d   Johannes Berg   cfg80211: impleme...
16
  #include <linux/etherdevice.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
17
  #include <linux/slab.h>
fee52678d   Johannes Berg   cfg80211: handle ...
18
  #include <net/iw_handler.h>
fee52678d   Johannes Berg   cfg80211: handle ...
19
  #include <net/cfg80211.h>
262eb9b22   Johannes Berg   cfg80211: split w...
20
  #include <net/cfg80211-wext.h>
0e82ffe3b   Johannes Berg   cfg80211: combine...
21
  #include "wext-compat.h"
fee52678d   Johannes Berg   cfg80211: handle ...
22
  #include "core.h"
e35e4d28b   Hila Gonen   cfg80211: add wra...
23
  #include "rdev-ops.h"
fee52678d   Johannes Berg   cfg80211: handle ...
24
25
26
27
28
  
  int cfg80211_wext_giwname(struct net_device *dev,
  			  struct iw_request_info *info,
  			  char *name, char *extra)
  {
fee52678d   Johannes Berg   cfg80211: handle ...
29
  	strcpy(name, "IEEE 802.11");
fee52678d   Johannes Berg   cfg80211: handle ...
30
31
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
32
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwname);
e60c7744f   Johannes Berg   cfg80211: handle ...
33
34
35
36
37
38
39
40
  
  int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
  			  u32 *mode, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	struct cfg80211_registered_device *rdev;
  	struct vif_params vifparams;
  	enum nl80211_iftype type;
f26cbf401   Zhao, Gang   cfg80211: change ...
41
  	rdev = wiphy_to_rdev(wdev->wiphy);
e60c7744f   Johannes Berg   cfg80211: handle ...
42

e60c7744f   Johannes Berg   cfg80211: handle ...
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  	switch (*mode) {
  	case IW_MODE_INFRA:
  		type = NL80211_IFTYPE_STATION;
  		break;
  	case IW_MODE_ADHOC:
  		type = NL80211_IFTYPE_ADHOC;
  		break;
  	case IW_MODE_REPEAT:
  		type = NL80211_IFTYPE_WDS;
  		break;
  	case IW_MODE_MONITOR:
  		type = NL80211_IFTYPE_MONITOR;
  		break;
  	default:
  		return -EINVAL;
  	}
ac7f9cfa2   Johannes Berg   cfg80211: accept ...
59
60
  	if (type == wdev->iftype)
  		return 0;
e60c7744f   Johannes Berg   cfg80211: handle ...
61
  	memset(&vifparams, 0, sizeof(vifparams));
818a986e4   Johannes Berg   cfg80211: move ad...
62
  	return cfg80211_change_iface(rdev, dev, type, &vifparams);
e60c7744f   Johannes Berg   cfg80211: handle ...
63
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
64
  EXPORT_WEXT_HANDLER(cfg80211_wext_siwmode);
e60c7744f   Johannes Berg   cfg80211: handle ...
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  
  int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
  			  u32 *mode, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	if (!wdev)
  		return -EOPNOTSUPP;
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_AP:
  		*mode = IW_MODE_MASTER;
  		break;
  	case NL80211_IFTYPE_STATION:
  		*mode = IW_MODE_INFRA;
  		break;
  	case NL80211_IFTYPE_ADHOC:
  		*mode = IW_MODE_ADHOC;
  		break;
  	case NL80211_IFTYPE_MONITOR:
  		*mode = IW_MODE_MONITOR;
  		break;
  	case NL80211_IFTYPE_WDS:
  		*mode = IW_MODE_REPEAT;
  		break;
  	case NL80211_IFTYPE_AP_VLAN:
  		*mode = IW_MODE_SECOND;		/* FIXME */
  		break;
  	default:
  		*mode = IW_MODE_AUTO;
  		break;
  	}
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
99
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwmode);
4aa188e1a   Johannes Berg   mac80211/cfg80211...
100
101
102
103
104
105
106
107
  
  
  int cfg80211_wext_giwrange(struct net_device *dev,
  			   struct iw_request_info *info,
  			   struct iw_point *data, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  	struct iw_range *range = (struct iw_range *) extra;
57fbcce37   Johannes Berg   cfg80211: remove ...
108
  	enum nl80211_band band;
9834c079d   Johannes Berg   cfg80211: fix giw...
109
  	int i, c = 0;
4aa188e1a   Johannes Berg   mac80211/cfg80211...
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  
  	if (!wdev)
  		return -EOPNOTSUPP;
  
  	data->length = sizeof(struct iw_range);
  	memset(range, 0, sizeof(struct iw_range));
  
  	range->we_version_compiled = WIRELESS_EXT;
  	range->we_version_source = 21;
  	range->retry_capa = IW_RETRY_LIMIT;
  	range->retry_flags = IW_RETRY_LIMIT;
  	range->min_retry = 0;
  	range->max_retry = 255;
  	range->min_rts = 0;
  	range->max_rts = 2347;
  	range->min_frag = 256;
  	range->max_frag = 2346;
4aa188e1a   Johannes Berg   mac80211/cfg80211...
127
128
129
130
131
132
133
134
  	range->max_encoding_tokens = 4;
  
  	range->max_qual.updated = IW_QUAL_NOISE_INVALID;
  
  	switch (wdev->wiphy->signal_type) {
  	case CFG80211_SIGNAL_TYPE_NONE:
  		break;
  	case CFG80211_SIGNAL_TYPE_MBM:
e7d83ed8d   Johannes Berg   wext: explicitly ...
135
  		range->max_qual.level = (u8)-110;
4aa188e1a   Johannes Berg   mac80211/cfg80211...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  		range->max_qual.qual = 70;
  		range->avg_qual.qual = 35;
  		range->max_qual.updated |= IW_QUAL_DBM;
  		range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
  		range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
  		break;
  	case CFG80211_SIGNAL_TYPE_UNSPEC:
  		range->max_qual.level = 100;
  		range->max_qual.qual = 100;
  		range->avg_qual.qual = 50;
  		range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
  		range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
  		break;
  	}
  
  	range->avg_qual.level = range->max_qual.level / 2;
  	range->avg_qual.noise = range->max_qual.noise / 2;
  	range->avg_qual.updated = range->max_qual.updated;
9834c079d   Johannes Berg   cfg80211: fix giw...
154
155
  	for (i = 0; i < wdev->wiphy->n_cipher_suites; i++) {
  		switch (wdev->wiphy->cipher_suites[i]) {
3daf09759   David Kilroy   cfg80211: Adverti...
156
  		case WLAN_CIPHER_SUITE_TKIP:
27bea66c2   David Kilroy   cfg80211: infer W...
157
158
  			range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP |
  					    IW_ENC_CAPA_WPA);
3daf09759   David Kilroy   cfg80211: Adverti...
159
160
161
  			break;
  
  		case WLAN_CIPHER_SUITE_CCMP:
27bea66c2   David Kilroy   cfg80211: infer W...
162
163
  			range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP |
  					    IW_ENC_CAPA_WPA2);
3daf09759   David Kilroy   cfg80211: Adverti...
164
  			break;
2ab658f9c   David Kilroy   cfg80211: set WE ...
165
166
167
168
169
170
171
172
173
174
  
  		case WLAN_CIPHER_SUITE_WEP40:
  			range->encoding_size[range->num_encoding_sizes++] =
  				WLAN_KEY_LEN_WEP40;
  			break;
  
  		case WLAN_CIPHER_SUITE_WEP104:
  			range->encoding_size[range->num_encoding_sizes++] =
  				WLAN_KEY_LEN_WEP104;
  			break;
3daf09759   David Kilroy   cfg80211: Adverti...
175
176
  		}
  	}
4aa188e1a   Johannes Berg   mac80211/cfg80211...
177

57fbcce37   Johannes Berg   cfg80211: remove ...
178
  	for (band = 0; band < NUM_NL80211_BANDS; band ++) {
4aa188e1a   Johannes Berg   mac80211/cfg80211...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  		struct ieee80211_supported_band *sband;
  
  		sband = wdev->wiphy->bands[band];
  
  		if (!sband)
  			continue;
  
  		for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
  			struct ieee80211_channel *chan = &sband->channels[i];
  
  			if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
  				range->freq[c].i =
  					ieee80211_frequency_to_channel(
  						chan->center_freq);
  				range->freq[c].m = chan->center_freq;
  				range->freq[c].e = 6;
  				c++;
  			}
  		}
  	}
  	range->num_channels = c;
  	range->num_frequency = c;
  
  	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
  	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
  	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
51cd4aabd   David Kilroy   cfg80211: allow d...
205
206
  	if (wdev->wiphy->max_scan_ssids > 0)
  		range->scan_capa |= IW_SCAN_CAPA_ESSID;
4aa188e1a   Johannes Berg   mac80211/cfg80211...
207
208
209
  
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
210
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwrange);
691597cb2   Johannes Berg   cfg80211/mac80211...
211

04a773ade   Johannes Berg   cfg80211/nl80211:...
212
213
214
  
  /**
   * cfg80211_wext_freq - get wext frequency for non-"auto"
04a773ade   Johannes Berg   cfg80211/nl80211:...
215
216
   * @freq: the wext freq encoding
   *
59bbb6f75   Johannes Berg   cfg80211: validat...
217
   * Returns a frequency, or a negative error code, or 0 for auto.
04a773ade   Johannes Berg   cfg80211/nl80211:...
218
   */
96998e3a2   Zhao, Gang   cfg80211: remove ...
219
  int cfg80211_wext_freq(struct iw_freq *freq)
04a773ade   Johannes Berg   cfg80211/nl80211:...
220
  {
0b258582f   Johannes Berg   cfg80211: fix wex...
221
  	/*
59bbb6f75   Johannes Berg   cfg80211: validat...
222
  	 * Parse frequency - return 0 for auto and
0b258582f   Johannes Berg   cfg80211: fix wex...
223
224
  	 * -EINVAL for impossible things.
  	 */
04a773ade   Johannes Berg   cfg80211/nl80211:...
225
  	if (freq->e == 0) {
57fbcce37   Johannes Berg   cfg80211: remove ...
226
  		enum nl80211_band band = NL80211_BAND_2GHZ;
04a773ade   Johannes Berg   cfg80211/nl80211:...
227
  		if (freq->m < 0)
59bbb6f75   Johannes Berg   cfg80211: validat...
228
  			return 0;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
229
  		if (freq->m > 14)
57fbcce37   Johannes Berg   cfg80211: remove ...
230
  			band = NL80211_BAND_5GHZ;
59eb21a65   Bruno Randolf   cfg80211: Extend ...
231
  		return ieee80211_channel_to_frequency(freq->m, band);
04a773ade   Johannes Berg   cfg80211/nl80211:...
232
233
234
235
  	} else {
  		int i, div = 1000000;
  		for (i = 0; i < freq->e; i++)
  			div /= 10;
0b258582f   Johannes Berg   cfg80211: fix wex...
236
  		if (div <= 0)
59bbb6f75   Johannes Berg   cfg80211: validat...
237
238
  			return -EINVAL;
  		return freq->m / div;
04a773ade   Johannes Berg   cfg80211/nl80211:...
239
  	}
04a773ade   Johannes Berg   cfg80211/nl80211:...
240
  }
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
241
242
243
244
245
246
  
  int cfg80211_wext_siwrts(struct net_device *dev,
  			 struct iw_request_info *info,
  			 struct iw_param *rts, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
247
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
248
249
250
251
252
253
254
255
256
  	u32 orts = wdev->wiphy->rts_threshold;
  	int err;
  
  	if (rts->disabled || !rts->fixed)
  		wdev->wiphy->rts_threshold = (u32) -1;
  	else if (rts->value < 0)
  		return -EINVAL;
  	else
  		wdev->wiphy->rts_threshold = rts->value;
e35e4d28b   Hila Gonen   cfg80211: add wra...
257
  	err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_RTS_THRESHOLD);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
258
259
260
261
262
  	if (err)
  		wdev->wiphy->rts_threshold = orts;
  
  	return err;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
263
  EXPORT_WEXT_HANDLER(cfg80211_wext_siwrts);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
264
265
266
267
268
269
270
271
272
273
274
275
276
  
  int cfg80211_wext_giwrts(struct net_device *dev,
  			 struct iw_request_info *info,
  			 struct iw_param *rts, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	rts->value = wdev->wiphy->rts_threshold;
  	rts->disabled = rts->value == (u32) -1;
  	rts->fixed = 1;
  
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
277
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwrts);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
278
279
280
281
282
283
  
  int cfg80211_wext_siwfrag(struct net_device *dev,
  			  struct iw_request_info *info,
  			  struct iw_param *frag, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
284
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
285
286
287
288
289
290
291
292
293
294
295
  	u32 ofrag = wdev->wiphy->frag_threshold;
  	int err;
  
  	if (frag->disabled || !frag->fixed)
  		wdev->wiphy->frag_threshold = (u32) -1;
  	else if (frag->value < 256)
  		return -EINVAL;
  	else {
  		/* Fragment length must be even, so strip LSB. */
  		wdev->wiphy->frag_threshold = frag->value & ~0x1;
  	}
e35e4d28b   Hila Gonen   cfg80211: add wra...
296
  	err = rdev_set_wiphy_params(rdev, WIPHY_PARAM_FRAG_THRESHOLD);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
297
298
299
300
301
  	if (err)
  		wdev->wiphy->frag_threshold = ofrag;
  
  	return err;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
302
  EXPORT_WEXT_HANDLER(cfg80211_wext_siwfrag);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
303
304
305
306
307
308
309
310
311
312
313
314
315
  
  int cfg80211_wext_giwfrag(struct net_device *dev,
  			  struct iw_request_info *info,
  			  struct iw_param *frag, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	frag->value = wdev->wiphy->frag_threshold;
  	frag->disabled = frag->value == (u32) -1;
  	frag->fixed = 1;
  
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
316
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwfrag);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
317

04b0c5c69   Johannes Berg   cfg80211: remove ...
318
319
320
  static int cfg80211_wext_siwretry(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_param *retry, char *extra)
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
321
322
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
323
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
324
325
326
327
  	u32 changed = 0;
  	u8 olong = wdev->wiphy->retry_long;
  	u8 oshort = wdev->wiphy->retry_short;
  	int err;
f5aa0d21d   Ujjal Roy   cfg80211: add san...
328
  	if (retry->disabled || retry->value < 1 || retry->value > 255 ||
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  	    (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
  		return -EINVAL;
  
  	if (retry->flags & IW_RETRY_LONG) {
  		wdev->wiphy->retry_long = retry->value;
  		changed |= WIPHY_PARAM_RETRY_LONG;
  	} else if (retry->flags & IW_RETRY_SHORT) {
  		wdev->wiphy->retry_short = retry->value;
  		changed |= WIPHY_PARAM_RETRY_SHORT;
  	} else {
  		wdev->wiphy->retry_short = retry->value;
  		wdev->wiphy->retry_long = retry->value;
  		changed |= WIPHY_PARAM_RETRY_LONG;
  		changed |= WIPHY_PARAM_RETRY_SHORT;
  	}
e35e4d28b   Hila Gonen   cfg80211: add wra...
344
  	err = rdev_set_wiphy_params(rdev, changed);
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
345
346
347
348
349
350
351
  	if (err) {
  		wdev->wiphy->retry_short = oshort;
  		wdev->wiphy->retry_long = olong;
  	}
  
  	return err;
  }
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
  
  int cfg80211_wext_giwretry(struct net_device *dev,
  			   struct iw_request_info *info,
  			   struct iw_param *retry, char *extra)
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	retry->disabled = 0;
  
  	if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) {
  		/*
  		 * First return short value, iwconfig will ask long value
  		 * later if needed
  		 */
60a4fe0ae   Ujjal Roy   cfg80211: fix wex...
366
  		retry->flags |= IW_RETRY_LIMIT | IW_RETRY_SHORT;
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
367
  		retry->value = wdev->wiphy->retry_short;
60a4fe0ae   Ujjal Roy   cfg80211: fix wex...
368
  		if (wdev->wiphy->retry_long == wdev->wiphy->retry_short)
b9a5f8cab   Jouni Malinen   nl80211: Add set/...
369
370
371
372
373
374
375
376
377
378
379
380
  			retry->flags |= IW_RETRY_LONG;
  
  		return 0;
  	}
  
  	if (retry->flags & IW_RETRY_LONG) {
  		retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
  		retry->value = wdev->wiphy->retry_long;
  	}
  
  	return 0;
  }
2afe38d15   Johannes Berg   cfg80211-wext: ex...
381
  EXPORT_WEXT_HANDLER(cfg80211_wext_giwretry);
08645126d   Johannes Berg   cfg80211: impleme...
382

fffd0934b   Johannes Berg   cfg80211: rework ...
383
  static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
e31b82136   Johannes Berg   cfg80211/mac80211...
384
385
386
  				     struct net_device *dev, bool pairwise,
  				     const u8 *addr, bool remove, bool tx_key,
  				     int idx, struct key_params *params)
08645126d   Johannes Berg   cfg80211: impleme...
387
388
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
fffd0934b   Johannes Berg   cfg80211: rework ...
389
  	int err, i;
98d3a7ca9   Johannes Berg   cfg80211: re-join...
390
  	bool rejoin = false;
fffd0934b   Johannes Berg   cfg80211: rework ...
391

e31b82136   Johannes Berg   cfg80211/mac80211...
392
393
  	if (pairwise && !addr)
  		return -EINVAL;
8f7d99ba8   Johannes Berg   cfg80211: wext: r...
394
395
396
397
  	/*
  	 * In many cases we won't actually need this, but it's better
  	 * to do it first in case the allocation fails. Don't use wext.
  	 */
fffd0934b   Johannes Berg   cfg80211: rework ...
398
399
  	if (!wdev->wext.keys) {
  		wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
89b706fb2   Johannes Berg   cfg80211: reduce ...
400
  					  GFP_KERNEL);
fffd0934b   Johannes Berg   cfg80211: rework ...
401
402
  		if (!wdev->wext.keys)
  			return -ENOMEM;
b8676221f   David Spinadel   cfg80211: Add sup...
403
  		for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
fffd0934b   Johannes Berg   cfg80211: rework ...
404
405
406
407
408
409
410
  			wdev->wext.keys->params[i].key =
  				wdev->wext.keys->data[i];
  	}
  
  	if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
  	    wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
08645126d   Johannes Berg   cfg80211: impleme...
411
412
  
  	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
fffd0934b   Johannes Berg   cfg80211: rework ...
413
414
  		if (!wdev->current_bss)
  			return -ENOLINK;
08645126d   Johannes Berg   cfg80211: impleme...
415
416
417
418
419
420
421
422
423
  		if (!rdev->ops->set_default_mgmt_key)
  			return -EOPNOTSUPP;
  
  		if (idx < 4 || idx > 5)
  			return -EINVAL;
  	} else if (idx < 0 || idx > 3)
  		return -EINVAL;
  
  	if (remove) {
fffd0934b   Johannes Berg   cfg80211: rework ...
424
  		err = 0;
98d3a7ca9   Johannes Berg   cfg80211: re-join...
425
426
427
428
429
430
431
432
433
434
  		if (wdev->current_bss) {
  			/*
  			 * If removing the current TX key, we will need to
  			 * join a new IBSS without the privacy bit clear.
  			 */
  			if (idx == wdev->wext.default_key &&
  			    wdev->iftype == NL80211_IFTYPE_ADHOC) {
  				__cfg80211_leave_ibss(rdev, wdev->netdev, true);
  				rejoin = true;
  			}
e31b82136   Johannes Berg   cfg80211/mac80211...
435
436
437
438
439
  
  			if (!pairwise && addr &&
  			    !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
  				err = -ENOENT;
  			else
e35e4d28b   Hila Gonen   cfg80211: add wra...
440
441
  				err = rdev_del_key(rdev, dev, idx, pairwise,
  						   addr);
98d3a7ca9   Johannes Berg   cfg80211: re-join...
442
  		}
d55fb891f   Vivek Natarajan   cfg80211: Clear e...
443
  		wdev->wext.connect.privacy = false;
98d3a7ca9   Johannes Berg   cfg80211: re-join...
444
445
446
447
448
449
  		/*
  		 * Applications using wireless extensions expect to be
  		 * able to delete keys that don't exist, so allow that.
  		 */
  		if (err == -ENOENT)
  			err = 0;
08645126d   Johannes Berg   cfg80211: impleme...
450
  		if (!err) {
89b706fb2   Johannes Berg   cfg80211: reduce ...
451
  			if (!addr && idx < 4) {
538c9eb8b   Johannes Berg   cfg80211: clear w...
452
453
  				memset(wdev->wext.keys->data[idx], 0,
  				       sizeof(wdev->wext.keys->data[idx]));
fffd0934b   Johannes Berg   cfg80211: rework ...
454
455
456
  				wdev->wext.keys->params[idx].key_len = 0;
  				wdev->wext.keys->params[idx].cipher = 0;
  			}
08645126d   Johannes Berg   cfg80211: impleme...
457
458
459
460
461
  			if (idx == wdev->wext.default_key)
  				wdev->wext.default_key = -1;
  			else if (idx == wdev->wext.default_mgmt_key)
  				wdev->wext.default_mgmt_key = -1;
  		}
98d3a7ca9   Johannes Berg   cfg80211: re-join...
462
463
464
  
  		if (!err && rejoin)
  			err = cfg80211_ibss_wext_join(rdev, wdev);
e3da574a0   Johannes Berg   cfg80211: allow w...
465

08645126d   Johannes Berg   cfg80211: impleme...
466
  		return err;
fffd0934b   Johannes Berg   cfg80211: rework ...
467
  	}
08645126d   Johannes Berg   cfg80211: impleme...
468

fffd0934b   Johannes Berg   cfg80211: rework ...
469
470
  	if (addr)
  		tx_key = false;
e31b82136   Johannes Berg   cfg80211/mac80211...
471
  	if (cfg80211_validate_key_settings(rdev, params, idx, pairwise, addr))
fffd0934b   Johannes Berg   cfg80211: rework ...
472
  		return -EINVAL;
08645126d   Johannes Berg   cfg80211: impleme...
473

fffd0934b   Johannes Berg   cfg80211: rework ...
474
475
  	err = 0;
  	if (wdev->current_bss)
e35e4d28b   Hila Gonen   cfg80211: add wra...
476
  		err = rdev_add_key(rdev, dev, idx, pairwise, addr, params);
9381e267b   Johannes Berg   cfg80211: wext: o...
477
478
479
  	else if (params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
  		 params->cipher != WLAN_CIPHER_SUITE_WEP104)
  		return -EINVAL;
fffd0934b   Johannes Berg   cfg80211: rework ...
480
481
  	if (err)
  		return err;
8f7d99ba8   Johannes Berg   cfg80211: wext: r...
482
483
  	/*
  	 * We only need to store WEP keys, since they're the only keys that
eee79f809   Randy Dunlap   net: wireless: we...
484
  	 * can be set before a connection is established and persist after
8f7d99ba8   Johannes Berg   cfg80211: wext: r...
485
486
487
488
  	 * disconnecting.
  	 */
  	if (!addr && (params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
  		      params->cipher == WLAN_CIPHER_SUITE_WEP104)) {
fffd0934b   Johannes Berg   cfg80211: rework ...
489
490
491
492
493
494
  		wdev->wext.keys->params[idx] = *params;
  		memcpy(wdev->wext.keys->data[idx],
  			params->key, params->key_len);
  		wdev->wext.keys->params[idx].key =
  			wdev->wext.keys->data[idx];
  	}
08645126d   Johannes Berg   cfg80211: impleme...
495

1f00fca5c   Zhu Yi   cfg80211: set_def...
496
497
  	if ((params->cipher == WLAN_CIPHER_SUITE_WEP40 ||
  	     params->cipher == WLAN_CIPHER_SUITE_WEP104) &&
fffd0934b   Johannes Berg   cfg80211: rework ...
498
  	    (tx_key || (!addr && wdev->wext.default_key == -1))) {
98d3a7ca9   Johannes Berg   cfg80211: re-join...
499
500
501
502
503
504
505
506
507
508
509
  		if (wdev->current_bss) {
  			/*
  			 * If we are getting a new TX key from not having
  			 * had one before we need to join a new IBSS with
  			 * the privacy bit set.
  			 */
  			if (wdev->iftype == NL80211_IFTYPE_ADHOC &&
  			    wdev->wext.default_key == -1) {
  				__cfg80211_leave_ibss(rdev, wdev->netdev, true);
  				rejoin = true;
  			}
e35e4d28b   Hila Gonen   cfg80211: add wra...
510
  			err = rdev_set_default_key(rdev, dev, idx, true, true);
98d3a7ca9   Johannes Berg   cfg80211: re-join...
511
512
  		}
  		if (!err) {
fffd0934b   Johannes Berg   cfg80211: rework ...
513
  			wdev->wext.default_key = idx;
98d3a7ca9   Johannes Berg   cfg80211: re-join...
514
515
516
  			if (rejoin)
  				err = cfg80211_ibss_wext_join(rdev, wdev);
  		}
fffd0934b   Johannes Berg   cfg80211: rework ...
517
518
  		return err;
  	}
08645126d   Johannes Berg   cfg80211: impleme...
519

fffd0934b   Johannes Berg   cfg80211: rework ...
520
521
522
  	if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
  	    (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
  		if (wdev->current_bss)
e35e4d28b   Hila Gonen   cfg80211: add wra...
523
  			err = rdev_set_default_mgmt_key(rdev, dev, idx);
fffd0934b   Johannes Berg   cfg80211: rework ...
524
525
526
  		if (!err)
  			wdev->wext.default_mgmt_key = idx;
  		return err;
08645126d   Johannes Berg   cfg80211: impleme...
527
  	}
fffd0934b   Johannes Berg   cfg80211: rework ...
528
529
530
531
532
  
  	return 0;
  }
  
  static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
e31b82136   Johannes Berg   cfg80211/mac80211...
533
534
535
  				   struct net_device *dev, bool pairwise,
  				   const u8 *addr, bool remove, bool tx_key,
  				   int idx, struct key_params *params)
fffd0934b   Johannes Berg   cfg80211: rework ...
536
537
538
539
  {
  	int err;
  
  	wdev_lock(dev->ieee80211_ptr);
e31b82136   Johannes Berg   cfg80211/mac80211...
540
541
  	err = __cfg80211_set_encryption(rdev, dev, pairwise, addr,
  					remove, tx_key, idx, params);
fffd0934b   Johannes Berg   cfg80211: rework ...
542
543
544
  	wdev_unlock(dev->ieee80211_ptr);
  
  	return err;
08645126d   Johannes Berg   cfg80211: impleme...
545
  }
04b0c5c69   Johannes Berg   cfg80211: remove ...
546
547
548
  static int cfg80211_wext_siwencode(struct net_device *dev,
  				   struct iw_request_info *info,
  				   struct iw_point *erq, char *keybuf)
08645126d   Johannes Berg   cfg80211: impleme...
549
550
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
551
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
08645126d   Johannes Berg   cfg80211: impleme...
552
553
554
  	int idx, err;
  	bool remove = false;
  	struct key_params params;
fffd0934b   Johannes Berg   cfg80211: rework ...
555
556
557
  	if (wdev->iftype != NL80211_IFTYPE_STATION &&
  	    wdev->iftype != NL80211_IFTYPE_ADHOC)
  		return -EOPNOTSUPP;
08645126d   Johannes Berg   cfg80211: impleme...
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
  	/* no use -- only MFP (set_default_mgmt_key) is optional */
  	if (!rdev->ops->del_key ||
  	    !rdev->ops->add_key ||
  	    !rdev->ops->set_default_key)
  		return -EOPNOTSUPP;
  
  	idx = erq->flags & IW_ENCODE_INDEX;
  	if (idx == 0) {
  		idx = wdev->wext.default_key;
  		if (idx < 0)
  			idx = 0;
  	} else if (idx < 1 || idx > 4)
  		return -EINVAL;
  	else
  		idx--;
  
  	if (erq->flags & IW_ENCODE_DISABLED)
  		remove = true;
  	else if (erq->length == 0) {
  		/* No key data - just set the default TX key index */
fffd0934b   Johannes Berg   cfg80211: rework ...
578
579
580
  		err = 0;
  		wdev_lock(wdev);
  		if (wdev->current_bss)
e35e4d28b   Hila Gonen   cfg80211: add wra...
581
582
  			err = rdev_set_default_key(rdev, dev, idx, true,
  						   true);
08645126d   Johannes Berg   cfg80211: impleme...
583
584
  		if (!err)
  			wdev->wext.default_key = idx;
fffd0934b   Johannes Berg   cfg80211: rework ...
585
  		wdev_unlock(wdev);
08645126d   Johannes Berg   cfg80211: impleme...
586
587
588
589
590
591
592
593
594
595
596
597
  		return err;
  	}
  
  	memset(&params, 0, sizeof(params));
  	params.key = keybuf;
  	params.key_len = erq->length;
  	if (erq->length == 5)
  		params.cipher = WLAN_CIPHER_SUITE_WEP40;
  	else if (erq->length == 13)
  		params.cipher = WLAN_CIPHER_SUITE_WEP104;
  	else if (!remove)
  		return -EINVAL;
e31b82136   Johannes Berg   cfg80211/mac80211...
598
  	return cfg80211_set_encryption(rdev, dev, false, NULL, remove,
08645126d   Johannes Berg   cfg80211: impleme...
599
600
601
  				       wdev->wext.default_key == -1,
  				       idx, &params);
  }
08645126d   Johannes Berg   cfg80211: impleme...
602

04b0c5c69   Johannes Berg   cfg80211: remove ...
603
604
605
  static int cfg80211_wext_siwencodeext(struct net_device *dev,
  				      struct iw_request_info *info,
  				      struct iw_point *erq, char *extra)
08645126d   Johannes Berg   cfg80211: impleme...
606
607
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
608
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
08645126d   Johannes Berg   cfg80211: impleme...
609
610
611
612
613
614
  	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
  	const u8 *addr;
  	int idx;
  	bool remove = false;
  	struct key_params params;
  	u32 cipher;
fffd0934b   Johannes Berg   cfg80211: rework ...
615
616
617
  	if (wdev->iftype != NL80211_IFTYPE_STATION &&
  	    wdev->iftype != NL80211_IFTYPE_ADHOC)
  		return -EOPNOTSUPP;
08645126d   Johannes Berg   cfg80211: impleme...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  	/* no use -- only MFP (set_default_mgmt_key) is optional */
  	if (!rdev->ops->del_key ||
  	    !rdev->ops->add_key ||
  	    !rdev->ops->set_default_key)
  		return -EOPNOTSUPP;
  
  	switch (ext->alg) {
  	case IW_ENCODE_ALG_NONE:
  		remove = true;
  		cipher = 0;
  		break;
  	case IW_ENCODE_ALG_WEP:
  		if (ext->key_len == 5)
  			cipher = WLAN_CIPHER_SUITE_WEP40;
  		else if (ext->key_len == 13)
  			cipher = WLAN_CIPHER_SUITE_WEP104;
  		else
  			return -EINVAL;
  		break;
  	case IW_ENCODE_ALG_TKIP:
  		cipher = WLAN_CIPHER_SUITE_TKIP;
  		break;
  	case IW_ENCODE_ALG_CCMP:
  		cipher = WLAN_CIPHER_SUITE_CCMP;
  		break;
  	case IW_ENCODE_ALG_AES_CMAC:
  		cipher = WLAN_CIPHER_SUITE_AES_CMAC;
  		break;
  	default:
  		return -EOPNOTSUPP;
  	}
  
  	if (erq->flags & IW_ENCODE_DISABLED)
  		remove = true;
  
  	idx = erq->flags & IW_ENCODE_INDEX;
  	if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
  		if (idx < 4 || idx > 5) {
  			idx = wdev->wext.default_mgmt_key;
  			if (idx < 0)
  				return -EINVAL;
  		} else
  			idx--;
  	} else {
  		if (idx < 1 || idx > 4) {
  			idx = wdev->wext.default_key;
  			if (idx < 0)
  				return -EINVAL;
  		} else
  			idx--;
  	}
  
  	addr = ext->addr.sa_data;
  	if (is_broadcast_ether_addr(addr))
  		addr = NULL;
  
  	memset(&params, 0, sizeof(params));
  	params.key = ext->key;
  	params.key_len = ext->key_len;
  	params.cipher = cipher;
faa8fdc85   Jouni Malinen   nl80211: Add RSC ...
678
679
680
681
  	if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
  		params.seq = ext->rx_seq;
  		params.seq_len = 6;
  	}
08645126d   Johannes Berg   cfg80211: impleme...
682
  	return cfg80211_set_encryption(
e31b82136   Johannes Berg   cfg80211/mac80211...
683
684
685
  			rdev, dev,
  			!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY),
  			addr, remove,
08645126d   Johannes Berg   cfg80211: impleme...
686
687
688
  			ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
  			idx, &params);
  }
08645126d   Johannes Berg   cfg80211: impleme...
689

04b0c5c69   Johannes Berg   cfg80211: remove ...
690
691
692
  static int cfg80211_wext_giwencode(struct net_device *dev,
  				   struct iw_request_info *info,
  				   struct iw_point *erq, char *keybuf)
08645126d   Johannes Berg   cfg80211: impleme...
693
694
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
fffd0934b   Johannes Berg   cfg80211: rework ...
695
  	int idx;
08645126d   Johannes Berg   cfg80211: impleme...
696

fffd0934b   Johannes Berg   cfg80211: rework ...
697
698
  	if (wdev->iftype != NL80211_IFTYPE_STATION &&
  	    wdev->iftype != NL80211_IFTYPE_ADHOC)
08645126d   Johannes Berg   cfg80211: impleme...
699
700
701
702
703
704
705
706
707
708
709
710
711
  		return -EOPNOTSUPP;
  
  	idx = erq->flags & IW_ENCODE_INDEX;
  	if (idx == 0) {
  		idx = wdev->wext.default_key;
  		if (idx < 0)
  			idx = 0;
  	} else if (idx < 1 || idx > 4)
  		return -EINVAL;
  	else
  		idx--;
  
  	erq->flags = idx + 1;
fffd0934b   Johannes Berg   cfg80211: rework ...
712
  	if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
08645126d   Johannes Berg   cfg80211: impleme...
713
714
715
716
  		erq->flags |= IW_ENCODE_DISABLED;
  		erq->length = 0;
  		return 0;
  	}
fffd0934b   Johannes Berg   cfg80211: rework ...
717
718
719
720
721
722
  	erq->length = min_t(size_t, erq->length,
  			    wdev->wext.keys->params[idx].key_len);
  	memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
  	erq->flags |= IW_ENCODE_ENABLED;
  
  	return 0;
08645126d   Johannes Berg   cfg80211: impleme...
723
  }
7643a2c3f   Johannes Berg   cfg80211: move tx...
724

04b0c5c69   Johannes Berg   cfg80211: remove ...
725
726
727
  static int cfg80211_wext_siwfreq(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_freq *wextfreq, char *extra)
0e82ffe3b   Johannes Berg   cfg80211: combine...
728
729
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
730
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
683b6d3b3   Johannes Berg   cfg80211: pass a ...
731
  	struct cfg80211_chan_def chandef = {
3d9d1d665   Johannes Berg   nl80211/cfg80211:...
732
  		.width = NL80211_CHAN_WIDTH_20_NOHT,
683b6d3b3   Johannes Berg   cfg80211: pass a ...
733
  	};
5fe231e87   Johannes Berg   cfg80211: vastly ...
734
  	int freq;
0e82ffe3b   Johannes Berg   cfg80211: combine...
735
736
737
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_STATION:
59bbb6f75   Johannes Berg   cfg80211: validat...
738
  		return cfg80211_mgd_wext_siwfreq(dev, info, wextfreq, extra);
0e82ffe3b   Johannes Berg   cfg80211: combine...
739
  	case NL80211_IFTYPE_ADHOC:
59bbb6f75   Johannes Berg   cfg80211: validat...
740
  		return cfg80211_ibss_wext_siwfreq(dev, info, wextfreq, extra);
f444de05d   Johannes Berg   cfg80211/mac80211...
741
  	case NL80211_IFTYPE_MONITOR:
96998e3a2   Zhao, Gang   cfg80211: remove ...
742
  		freq = cfg80211_wext_freq(wextfreq);
59bbb6f75   Johannes Berg   cfg80211: validat...
743
744
745
  		if (freq < 0)
  			return freq;
  		if (freq == 0)
0e82ffe3b   Johannes Berg   cfg80211: combine...
746
  			return -EINVAL;
3d9d1d665   Johannes Berg   nl80211/cfg80211:...
747
  		chandef.center_freq1 = freq;
683b6d3b3   Johannes Berg   cfg80211: pass a ...
748
749
750
  		chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
  		if (!chandef.chan)
  			return -EINVAL;
5fe231e87   Johannes Berg   cfg80211: vastly ...
751
  		return cfg80211_set_monitor_channel(rdev, &chandef);
cc1d2806b   Johannes Berg   cfg80211: provide...
752
  	case NL80211_IFTYPE_MESH_POINT:
96998e3a2   Zhao, Gang   cfg80211: remove ...
753
  		freq = cfg80211_wext_freq(wextfreq);
cc1d2806b   Johannes Berg   cfg80211: provide...
754
755
756
757
  		if (freq < 0)
  			return freq;
  		if (freq == 0)
  			return -EINVAL;
3d9d1d665   Johannes Berg   nl80211/cfg80211:...
758
  		chandef.center_freq1 = freq;
683b6d3b3   Johannes Berg   cfg80211: pass a ...
759
760
761
  		chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
  		if (!chandef.chan)
  			return -EINVAL;
5fe231e87   Johannes Berg   cfg80211: vastly ...
762
  		return cfg80211_set_mesh_channel(rdev, wdev, &chandef);
f444de05d   Johannes Berg   cfg80211/mac80211...
763
764
  	default:
  		return -EOPNOTSUPP;
0e82ffe3b   Johannes Berg   cfg80211: combine...
765
766
  	}
  }
0e82ffe3b   Johannes Berg   cfg80211: combine...
767

04b0c5c69   Johannes Berg   cfg80211: remove ...
768
769
770
  static int cfg80211_wext_giwfreq(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_freq *freq, char *extra)
0e82ffe3b   Johannes Berg   cfg80211: combine...
771
772
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
773
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
f43e5210c   Johannes Berg   cfg80211: initial...
774
  	struct cfg80211_chan_def chandef = {};
683b6d3b3   Johannes Berg   cfg80211: pass a ...
775
  	int ret;
0e82ffe3b   Johannes Berg   cfg80211: combine...
776
777
778
779
780
781
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_STATION:
  		return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
  	case NL80211_IFTYPE_ADHOC:
  		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
e999882a0   Johannes Berg   mac80211/cfg80211...
782
  	case NL80211_IFTYPE_MONITOR:
5b7ccaf3f   Johannes Berg   cfg80211/mac80211...
783
  		if (!rdev->ops->get_channel)
e999882a0   Johannes Berg   mac80211/cfg80211...
784
  			return -EINVAL;
683b6d3b3   Johannes Berg   cfg80211: pass a ...
785
786
787
788
  		ret = rdev_get_channel(rdev, wdev, &chandef);
  		if (ret)
  			return ret;
  		freq->m = chandef.chan->center_freq;
e999882a0   Johannes Berg   mac80211/cfg80211...
789
790
  		freq->e = 6;
  		return 0;
0e82ffe3b   Johannes Berg   cfg80211: combine...
791
  	default:
e8c9bd5b8   Johannes Berg   cfg80211: clarify...
792
  		return -EINVAL;
0e82ffe3b   Johannes Berg   cfg80211: combine...
793
794
  	}
  }
0e82ffe3b   Johannes Berg   cfg80211: combine...
795

04b0c5c69   Johannes Berg   cfg80211: remove ...
796
797
798
  static int cfg80211_wext_siwtxpower(struct net_device *dev,
  				    struct iw_request_info *info,
  				    union iwreq_data *data, char *extra)
7643a2c3f   Johannes Berg   cfg80211: move tx...
799
800
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
801
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
802
  	enum nl80211_tx_power_setting type;
7643a2c3f   Johannes Berg   cfg80211: move tx...
803
804
805
806
807
808
809
810
811
812
813
814
  	int dbm = 0;
  
  	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
  		return -EINVAL;
  	if (data->txpower.flags & IW_TXPOW_RANGE)
  		return -EINVAL;
  
  	if (!rdev->ops->set_tx_power)
  		return -EOPNOTSUPP;
  
  	/* only change when not disabling */
  	if (!data->txpower.disabled) {
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
815
  		rfkill_set_sw_state(rdev->rfkill, false);
7643a2c3f   Johannes Berg   cfg80211: move tx...
816
817
818
819
820
821
822
823
  		if (data->txpower.fixed) {
  			/*
  			 * wext doesn't support negative values, see
  			 * below where it's for automatic
  			 */
  			if (data->txpower.value < 0)
  				return -EINVAL;
  			dbm = data->txpower.value;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
824
  			type = NL80211_TX_POWER_FIXED;
7643a2c3f   Johannes Berg   cfg80211: move tx...
825
826
827
828
829
830
831
  			/* TODO: do regulatory check! */
  		} else {
  			/*
  			 * Automatic power level setting, max being the value
  			 * passed in from userland.
  			 */
  			if (data->txpower.value < 0) {
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
832
  				type = NL80211_TX_POWER_AUTOMATIC;
7643a2c3f   Johannes Berg   cfg80211: move tx...
833
834
  			} else {
  				dbm = data->txpower.value;
fa61cf70a   Juuso Oikarinen   cfg80211/mac80211...
835
  				type = NL80211_TX_POWER_LIMITED;
7643a2c3f   Johannes Berg   cfg80211: move tx...
836
837
838
  			}
  		}
  	} else {
3cfe91c4c   Johannes Berg   cfg80211: always ...
839
840
  		if (rfkill_set_sw_state(rdev->rfkill, true))
  			schedule_work(&rdev->rfkill_block);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
841
  		return 0;
7643a2c3f   Johannes Berg   cfg80211: move tx...
842
  	}
c8442118a   Johannes Berg   cfg80211: allow p...
843
  	return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
7643a2c3f   Johannes Berg   cfg80211: move tx...
844
  }
7643a2c3f   Johannes Berg   cfg80211: move tx...
845

04b0c5c69   Johannes Berg   cfg80211: remove ...
846
847
848
  static int cfg80211_wext_giwtxpower(struct net_device *dev,
  				    struct iw_request_info *info,
  				    union iwreq_data *data, char *extra)
7643a2c3f   Johannes Berg   cfg80211: move tx...
849
850
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
851
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
7643a2c3f   Johannes Berg   cfg80211: move tx...
852
853
854
855
856
857
858
859
860
  	int err, val;
  
  	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
  		return -EINVAL;
  	if (data->txpower.flags & IW_TXPOW_RANGE)
  		return -EINVAL;
  
  	if (!rdev->ops->get_tx_power)
  		return -EOPNOTSUPP;
c8442118a   Johannes Berg   cfg80211: allow p...
861
  	err = rdev_get_tx_power(rdev, wdev, &val);
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
862
  	if (err)
7643a2c3f   Johannes Berg   cfg80211: move tx...
863
864
865
866
  		return err;
  
  	/* well... oh well */
  	data->txpower.fixed = 1;
1f87f7d3a   Johannes Berg   cfg80211: add rfk...
867
  	data->txpower.disabled = rfkill_blocked(rdev->rfkill);
7643a2c3f   Johannes Berg   cfg80211: move tx...
868
869
870
871
872
  	data->txpower.value = val;
  	data->txpower.flags = IW_TXPOW_DBM;
  
  	return 0;
  }
f21293549   Johannes Berg   cfg80211: managed...
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
  
  static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
  				 s32 auth_alg)
  {
  	int nr_alg = 0;
  
  	if (!auth_alg)
  		return -EINVAL;
  
  	if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM |
  			 IW_AUTH_ALG_SHARED_KEY |
  			 IW_AUTH_ALG_LEAP))
  		return -EINVAL;
  
  	if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) {
  		nr_alg++;
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
  	}
  
  	if (auth_alg & IW_AUTH_ALG_SHARED_KEY) {
  		nr_alg++;
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY;
  	}
  
  	if (auth_alg & IW_AUTH_ALG_LEAP) {
  		nr_alg++;
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP;
  	}
  
  	if (nr_alg > 1)
  		wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
  
  	return 0;
  }
  
  static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
  {
f21293549   Johannes Berg   cfg80211: managed...
910
  	if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
323d566ea   Gábor Stefanik   cfg80211: fix dis...
911
912
  			     IW_AUTH_WPA_VERSION_WPA2|
  		             IW_AUTH_WPA_VERSION_DISABLED))
f21293549   Johannes Berg   cfg80211: managed...
913
  		return -EINVAL;
323d566ea   Gábor Stefanik   cfg80211: fix dis...
914
915
916
917
918
919
920
921
  	if ((wpa_versions & IW_AUTH_WPA_VERSION_DISABLED) &&
  	    (wpa_versions & (IW_AUTH_WPA_VERSION_WPA|
  			     IW_AUTH_WPA_VERSION_WPA2)))
  		return -EINVAL;
  
  	if (wpa_versions & IW_AUTH_WPA_VERSION_DISABLED)
  		wdev->wext.connect.crypto.wpa_versions &=
  			~(NL80211_WPA_VERSION_1|NL80211_WPA_VERSION_2);
f21293549   Johannes Berg   cfg80211: managed...
922
923
924
925
926
927
928
929
930
931
  	if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
  		wdev->wext.connect.crypto.wpa_versions |=
  			NL80211_WPA_VERSION_1;
  
  	if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2)
  		wdev->wext.connect.crypto.wpa_versions |=
  			NL80211_WPA_VERSION_2;
  
  	return 0;
  }
4f5dadceb   Johannes Berg   cfg80211: fix MFP...
932
  static int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
f21293549   Johannes Berg   cfg80211: managed...
933
  {
f21293549   Johannes Berg   cfg80211: managed...
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
  	if (cipher & IW_AUTH_CIPHER_WEP40)
  		wdev->wext.connect.crypto.cipher_group =
  			WLAN_CIPHER_SUITE_WEP40;
  	else if (cipher & IW_AUTH_CIPHER_WEP104)
  		wdev->wext.connect.crypto.cipher_group =
  			WLAN_CIPHER_SUITE_WEP104;
  	else if (cipher & IW_AUTH_CIPHER_TKIP)
  		wdev->wext.connect.crypto.cipher_group =
  			WLAN_CIPHER_SUITE_TKIP;
  	else if (cipher & IW_AUTH_CIPHER_CCMP)
  		wdev->wext.connect.crypto.cipher_group =
  			WLAN_CIPHER_SUITE_CCMP;
  	else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
  		wdev->wext.connect.crypto.cipher_group =
  			WLAN_CIPHER_SUITE_AES_CMAC;
c5f8289cd   Jouni Malinen   cfg80211: Fix WEX...
949
950
  	else if (cipher & IW_AUTH_CIPHER_NONE)
  		wdev->wext.connect.crypto.cipher_group = 0;
f21293549   Johannes Berg   cfg80211: managed...
951
952
953
954
955
  	else
  		return -EINVAL;
  
  	return 0;
  }
4f5dadceb   Johannes Berg   cfg80211: fix MFP...
956
  static int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
f21293549   Johannes Berg   cfg80211: managed...
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
  {
  	int nr_ciphers = 0;
  	u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
  
  	if (cipher & IW_AUTH_CIPHER_WEP40) {
  		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40;
  		nr_ciphers++;
  	}
  
  	if (cipher & IW_AUTH_CIPHER_WEP104) {
  		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104;
  		nr_ciphers++;
  	}
  
  	if (cipher & IW_AUTH_CIPHER_TKIP) {
  		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP;
  		nr_ciphers++;
  	}
  
  	if (cipher & IW_AUTH_CIPHER_CCMP) {
  		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP;
  		nr_ciphers++;
  	}
  
  	if (cipher & IW_AUTH_CIPHER_AES_CMAC) {
  		ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC;
  		nr_ciphers++;
  	}
  
  	BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
  
  	wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
  
  	return 0;
  }
4f5dadceb   Johannes Berg   cfg80211: fix MFP...
992
  static int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
f21293549   Johannes Berg   cfg80211: managed...
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
  {
  	int nr_akm_suites = 0;
  
  	if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
  			IW_AUTH_KEY_MGMT_PSK))
  		return -EINVAL;
  
  	if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
  		wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
  			WLAN_AKM_SUITE_8021X;
  		nr_akm_suites++;
  	}
  
  	if (key_mgt & IW_AUTH_KEY_MGMT_PSK) {
  		wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
  			WLAN_AKM_SUITE_PSK;
  		nr_akm_suites++;
  	}
  
  	wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
  
  	return 0;
  }
04b0c5c69   Johannes Berg   cfg80211: remove ...
1016
1017
1018
  static int cfg80211_wext_siwauth(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_param *data, char *extra)
f21293549   Johannes Berg   cfg80211: managed...
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
  
  	switch (data->flags & IW_AUTH_INDEX) {
  	case IW_AUTH_PRIVACY_INVOKED:
  		wdev->wext.connect.privacy = data->value;
  		return 0;
  	case IW_AUTH_WPA_VERSION:
  		return cfg80211_set_wpa_version(wdev, data->value);
  	case IW_AUTH_CIPHER_GROUP:
  		return cfg80211_set_cipher_group(wdev, data->value);
  	case IW_AUTH_KEY_MGMT:
  		return cfg80211_set_key_mgt(wdev, data->value);
  	case IW_AUTH_CIPHER_PAIRWISE:
  		return cfg80211_set_cipher_pairwise(wdev, data->value);
  	case IW_AUTH_80211_AUTH_ALG:
  		return cfg80211_set_auth_alg(wdev, data->value);
  	case IW_AUTH_WPA_ENABLED:
  	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
  	case IW_AUTH_DROP_UNENCRYPTED:
  	case IW_AUTH_MFP:
  		return 0;
  	default:
  		return -EOPNOTSUPP;
  	}
  }
f21293549   Johannes Berg   cfg80211: managed...
1048

04b0c5c69   Johannes Berg   cfg80211: remove ...
1049
1050
1051
  static int cfg80211_wext_giwauth(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_param *data, char *extra)
f21293549   Johannes Berg   cfg80211: managed...
1052
1053
1054
1055
1056
  {
  	/* XXX: what do we need? */
  
  	return -EOPNOTSUPP;
  }
bc92afd92   Johannes Berg   cfg80211: impleme...
1057

04b0c5c69   Johannes Berg   cfg80211: remove ...
1058
1059
1060
  static int cfg80211_wext_siwpower(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_param *wrq, char *extra)
bc92afd92   Johannes Berg   cfg80211: impleme...
1061
1062
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1063
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1064
1065
  	bool ps = wdev->ps;
  	int timeout = wdev->ps_timeout;
bc92afd92   Johannes Berg   cfg80211: impleme...
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
  	int err;
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EINVAL;
  
  	if (!rdev->ops->set_power_mgmt)
  		return -EOPNOTSUPP;
  
  	if (wrq->disabled) {
  		ps = false;
  	} else {
  		switch (wrq->flags & IW_POWER_MODE) {
  		case IW_POWER_ON:       /* If not specified */
  		case IW_POWER_MODE:     /* If set all mask */
  		case IW_POWER_ALL_R:    /* If explicitely state all */
  			ps = true;
  			break;
  		default:                /* Otherwise we ignore */
  			return -EINVAL;
  		}
  
  		if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
  			return -EINVAL;
  
  		if (wrq->flags & IW_POWER_TIMEOUT)
  			timeout = wrq->value / 1000;
  	}
e35e4d28b   Hila Gonen   cfg80211: add wra...
1093
  	err = rdev_set_power_mgmt(rdev, dev, ps, timeout);
bc92afd92   Johannes Berg   cfg80211: impleme...
1094
1095
  	if (err)
  		return err;
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1096
1097
  	wdev->ps = ps;
  	wdev->ps_timeout = timeout;
bc92afd92   Johannes Berg   cfg80211: impleme...
1098
1099
1100
1101
  
  	return 0;
  
  }
bc92afd92   Johannes Berg   cfg80211: impleme...
1102

04b0c5c69   Johannes Berg   cfg80211: remove ...
1103
1104
1105
  static int cfg80211_wext_giwpower(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_param *wrq, char *extra)
bc92afd92   Johannes Berg   cfg80211: impleme...
1106
1107
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
ffb9eb3d8   Kalle Valo   nl80211: add powe...
1108
  	wrq->disabled = !wdev->ps;
bc92afd92   Johannes Berg   cfg80211: impleme...
1109
1110
1111
  
  	return 0;
  }
ab737a4f7   Johannes Berg   cfg80211: impleme...
1112

562e48226   Johannes Berg   cfg80211: combine...
1113
1114
1115
  static int cfg80211_wds_wext_siwap(struct net_device *dev,
  				   struct iw_request_info *info,
  				   struct sockaddr *addr, char *extra)
ab737a4f7   Johannes Berg   cfg80211: impleme...
1116
1117
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1118
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
ab737a4f7   Johannes Berg   cfg80211: impleme...
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  	int err;
  
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
  		return -EINVAL;
  
  	if (addr->sa_family != ARPHRD_ETHER)
  		return -EINVAL;
  
  	if (netif_running(dev))
  		return -EBUSY;
  
  	if (!rdev->ops->set_wds_peer)
  		return -EOPNOTSUPP;
e35e4d28b   Hila Gonen   cfg80211: add wra...
1132
  	err = rdev_set_wds_peer(rdev, dev, (u8 *)&addr->sa_data);
ab737a4f7   Johannes Berg   cfg80211: impleme...
1133
1134
1135
1136
1137
1138
1139
  	if (err)
  		return err;
  
  	memcpy(&wdev->wext.bssid, (u8 *) &addr->sa_data, ETH_ALEN);
  
  	return 0;
  }
ab737a4f7   Johannes Berg   cfg80211: impleme...
1140

562e48226   Johannes Berg   cfg80211: combine...
1141
1142
1143
  static int cfg80211_wds_wext_giwap(struct net_device *dev,
  				   struct iw_request_info *info,
  				   struct sockaddr *addr, char *extra)
ab737a4f7   Johannes Berg   cfg80211: impleme...
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_WDS))
  		return -EINVAL;
  
  	addr->sa_family = ARPHRD_ETHER;
  	memcpy(&addr->sa_data, wdev->wext.bssid, ETH_ALEN);
  
  	return 0;
  }
9930380f0   Johannes Berg   cfg80211: impleme...
1155

04b0c5c69   Johannes Berg   cfg80211: remove ...
1156
1157
1158
  static int cfg80211_wext_siwrate(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_param *rate, char *extra)
9930380f0   Johannes Berg   cfg80211: impleme...
1159
1160
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1161
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
9930380f0   Johannes Berg   cfg80211: impleme...
1162
  	struct cfg80211_bitrate_mask mask;
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1163
1164
1165
1166
  	u32 fixed, maxrate;
  	struct ieee80211_supported_band *sband;
  	int band, ridx;
  	bool match = false;
9930380f0   Johannes Berg   cfg80211: impleme...
1167
1168
1169
  
  	if (!rdev->ops->set_bitrate_mask)
  		return -EOPNOTSUPP;
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1170
1171
  	memset(&mask, 0, sizeof(mask));
  	fixed = 0;
54233261d   John W. Linville   cfg80211: fix wex...
1172
  	maxrate = (u32)-1;
9930380f0   Johannes Berg   cfg80211: impleme...
1173
1174
1175
1176
  
  	if (rate->value < 0) {
  		/* nothing */
  	} else if (rate->fixed) {
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1177
  		fixed = rate->value / 100000;
9930380f0   Johannes Berg   cfg80211: impleme...
1178
  	} else {
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1179
1180
  		maxrate = rate->value / 100000;
  	}
57fbcce37   Johannes Berg   cfg80211: remove ...
1181
  	for (band = 0; band < NUM_NL80211_BANDS; band++) {
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
  		sband = wdev->wiphy->bands[band];
  		if (sband == NULL)
  			continue;
  		for (ridx = 0; ridx < sband->n_bitrates; ridx++) {
  			struct ieee80211_rate *srate = &sband->bitrates[ridx];
  			if (fixed == srate->bitrate) {
  				mask.control[band].legacy = 1 << ridx;
  				match = true;
  				break;
  			}
  			if (srate->bitrate <= maxrate) {
  				mask.control[band].legacy |= 1 << ridx;
  				match = true;
  			}
  		}
9930380f0   Johannes Berg   cfg80211: impleme...
1197
  	}
37eb0b164   Jouni Malinen   cfg80211/mac80211...
1198
1199
  	if (!match)
  		return -EINVAL;
e35e4d28b   Hila Gonen   cfg80211: add wra...
1200
  	return rdev_set_bitrate_mask(rdev, dev, NULL, &mask);
9930380f0   Johannes Berg   cfg80211: impleme...
1201
  }
9930380f0   Johannes Berg   cfg80211: impleme...
1202

04b0c5c69   Johannes Berg   cfg80211: remove ...
1203
1204
1205
  static int cfg80211_wext_giwrate(struct net_device *dev,
  				 struct iw_request_info *info,
  				 struct iw_param *rate, char *extra)
9930380f0   Johannes Berg   cfg80211: impleme...
1206
1207
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1208
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
5762d7d3e   Johannes Berg   cfg80211: fix sta...
1209
  	struct station_info sinfo = {};
a71d62dbf   Johannes Berg   cfg80211: fix rac...
1210
  	u8 addr[ETH_ALEN];
9930380f0   Johannes Berg   cfg80211: impleme...
1211
1212
1213
1214
1215
1216
1217
  	int err;
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EOPNOTSUPP;
  
  	if (!rdev->ops->get_station)
  		return -EOPNOTSUPP;
a71d62dbf   Johannes Berg   cfg80211: fix rac...
1218
1219
  	err = 0;
  	wdev_lock(wdev);
6c230c027   Samuel Ortiz   cfg80211: check f...
1220
  	if (wdev->current_bss)
a71d62dbf   Johannes Berg   cfg80211: fix rac...
1221
  		memcpy(addr, wdev->current_bss->pub.bssid, ETH_ALEN);
6c230c027   Samuel Ortiz   cfg80211: check f...
1222
  	else
a71d62dbf   Johannes Berg   cfg80211: fix rac...
1223
1224
1225
1226
  		err = -EOPNOTSUPP;
  	wdev_unlock(wdev);
  	if (err)
  		return err;
9930380f0   Johannes Berg   cfg80211: impleme...
1227

e35e4d28b   Hila Gonen   cfg80211: add wra...
1228
  	err = rdev_get_station(rdev, dev, addr, &sinfo);
9930380f0   Johannes Berg   cfg80211: impleme...
1229
1230
  	if (err)
  		return err;
848e616e6   Stefan Seyfried   cfg80211: fix wex...
1231
1232
1233
1234
  	if (!(sinfo.filled & BIT_ULL(NL80211_STA_INFO_TX_BITRATE))) {
  		err = -EOPNOTSUPP;
  		goto free;
  	}
9930380f0   Johannes Berg   cfg80211: impleme...
1235

254416aae   John W. Linville   wireless: report ...
1236
  	rate->value = 100000 * cfg80211_calculate_bitrate(&sinfo.txrate);
9930380f0   Johannes Berg   cfg80211: impleme...
1237

848e616e6   Stefan Seyfried   cfg80211: fix wex...
1238
1239
1240
  free:
  	cfg80211_sinfo_release_content(&sinfo);
  	return err;
9930380f0   Johannes Berg   cfg80211: impleme...
1241
  }
8990646d2   Johannes Berg   cfg80211: impleme...
1242
1243
  
  /* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
04b0c5c69   Johannes Berg   cfg80211: remove ...
1244
  static struct iw_statistics *cfg80211_wireless_stats(struct net_device *dev)
8990646d2   Johannes Berg   cfg80211: impleme...
1245
1246
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1247
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
8990646d2   Johannes Berg   cfg80211: impleme...
1248
1249
  	/* we are under RTNL - globally locked - so can use static structs */
  	static struct iw_statistics wstats;
848e616e6   Stefan Seyfried   cfg80211: fix wex...
1250
  	static struct station_info sinfo = {};
c56c5714f   Johannes Berg   cfg80211: fix wex...
1251
  	u8 bssid[ETH_ALEN];
8990646d2   Johannes Berg   cfg80211: impleme...
1252
1253
1254
1255
1256
1257
  
  	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION)
  		return NULL;
  
  	if (!rdev->ops->get_station)
  		return NULL;
c56c5714f   Johannes Berg   cfg80211: fix wex...
1258
1259
1260
1261
  	/* Grab BSSID of current BSS, if any */
  	wdev_lock(wdev);
  	if (!wdev->current_bss) {
  		wdev_unlock(wdev);
8990646d2   Johannes Berg   cfg80211: impleme...
1262
  		return NULL;
c56c5714f   Johannes Berg   cfg80211: fix wex...
1263
1264
1265
  	}
  	memcpy(bssid, wdev->current_bss->pub.bssid, ETH_ALEN);
  	wdev_unlock(wdev);
8990646d2   Johannes Berg   cfg80211: impleme...
1266

9c5a18a31   Johannes Berg   cfg80211: wext: c...
1267
  	memset(&sinfo, 0, sizeof(sinfo));
e35e4d28b   Hila Gonen   cfg80211: add wra...
1268
  	if (rdev_get_station(rdev, dev, bssid, &sinfo))
8990646d2   Johannes Berg   cfg80211: impleme...
1269
1270
1271
1272
1273
1274
  		return NULL;
  
  	memset(&wstats, 0, sizeof(wstats));
  
  	switch (rdev->wiphy.signal_type) {
  	case CFG80211_SIGNAL_TYPE_MBM:
397c657a0   Omer Efrat   cfg80211: use BIT...
1275
  		if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) {
8990646d2   Johannes Berg   cfg80211: impleme...
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
  			int sig = sinfo.signal;
  			wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
  			wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
  			wstats.qual.updated |= IW_QUAL_DBM;
  			wstats.qual.level = sig;
  			if (sig < -110)
  				sig = -110;
  			else if (sig > -40)
  				sig = -40;
  			wstats.qual.qual = sig + 110;
  			break;
  		}
7b506ff6f   Miaohe Lin   net: wireless: Co...
1288
  		fallthrough;
8990646d2   Johannes Berg   cfg80211: impleme...
1289
  	case CFG80211_SIGNAL_TYPE_UNSPEC:
397c657a0   Omer Efrat   cfg80211: use BIT...
1290
  		if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_SIGNAL)) {
8990646d2   Johannes Berg   cfg80211: impleme...
1291
1292
1293
1294
1295
1296
  			wstats.qual.updated |= IW_QUAL_LEVEL_UPDATED;
  			wstats.qual.updated |= IW_QUAL_QUAL_UPDATED;
  			wstats.qual.level = sinfo.signal;
  			wstats.qual.qual = sinfo.signal;
  			break;
  		}
7b506ff6f   Miaohe Lin   net: wireless: Co...
1297
  		fallthrough;
8990646d2   Johannes Berg   cfg80211: impleme...
1298
1299
1300
1301
1302
1303
  	default:
  		wstats.qual.updated |= IW_QUAL_LEVEL_INVALID;
  		wstats.qual.updated |= IW_QUAL_QUAL_INVALID;
  	}
  
  	wstats.qual.updated |= IW_QUAL_NOISE_INVALID;
397c657a0   Omer Efrat   cfg80211: use BIT...
1304
  	if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_RX_DROP_MISC))
5a5c731aa   Ben Greear   wireless: Set som...
1305
  		wstats.discard.misc = sinfo.rx_dropped_misc;
397c657a0   Omer Efrat   cfg80211: use BIT...
1306
  	if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_TX_FAILED))
5a5c731aa   Ben Greear   wireless: Set som...
1307
  		wstats.discard.retries = sinfo.tx_failed;
8990646d2   Johannes Berg   cfg80211: impleme...
1308

848e616e6   Stefan Seyfried   cfg80211: fix wex...
1309
  	cfg80211_sinfo_release_content(&sinfo);
8990646d2   Johannes Berg   cfg80211: impleme...
1310
1311
  	return &wstats;
  }
562e48226   Johannes Berg   cfg80211: combine...
1312

04b0c5c69   Johannes Berg   cfg80211: remove ...
1313
1314
1315
  static int cfg80211_wext_siwap(struct net_device *dev,
  			       struct iw_request_info *info,
  			       struct sockaddr *ap_addr, char *extra)
562e48226   Johannes Berg   cfg80211: combine...
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_ADHOC:
  		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
  	case NL80211_IFTYPE_STATION:
  		return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
  	case NL80211_IFTYPE_WDS:
  		return cfg80211_wds_wext_siwap(dev, info, ap_addr, extra);
  	default:
  		return -EOPNOTSUPP;
  	}
  }
562e48226   Johannes Berg   cfg80211: combine...
1330

04b0c5c69   Johannes Berg   cfg80211: remove ...
1331
1332
1333
  static int cfg80211_wext_giwap(struct net_device *dev,
  			       struct iw_request_info *info,
  			       struct sockaddr *ap_addr, char *extra)
562e48226   Johannes Berg   cfg80211: combine...
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_ADHOC:
  		return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
  	case NL80211_IFTYPE_STATION:
  		return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
  	case NL80211_IFTYPE_WDS:
  		return cfg80211_wds_wext_giwap(dev, info, ap_addr, extra);
  	default:
  		return -EOPNOTSUPP;
  	}
  }
1f9298f96   Johannes Berg   cfg80211: combine...
1348

04b0c5c69   Johannes Berg   cfg80211: remove ...
1349
1350
1351
  static int cfg80211_wext_siwessid(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_point *data, char *ssid)
1f9298f96   Johannes Berg   cfg80211: combine...
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
  
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_ADHOC:
  		return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
  	case NL80211_IFTYPE_STATION:
  		return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
  	default:
  		return -EOPNOTSUPP;
  	}
  }
1f9298f96   Johannes Berg   cfg80211: combine...
1364

04b0c5c69   Johannes Berg   cfg80211: remove ...
1365
1366
1367
  static int cfg80211_wext_giwessid(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_point *data, char *ssid)
1f9298f96   Johannes Berg   cfg80211: combine...
1368
1369
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
42da2f948   Johannes Berg   wireless extensio...
1370
1371
  	data->flags = 0;
  	data->length = 0;
1f9298f96   Johannes Berg   cfg80211: combine...
1372
1373
1374
1375
1376
1377
1378
1379
1380
  	switch (wdev->iftype) {
  	case NL80211_IFTYPE_ADHOC:
  		return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
  	case NL80211_IFTYPE_STATION:
  		return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
  	default:
  		return -EOPNOTSUPP;
  	}
  }
a9a11622c   Johannes Berg   cfg80211: self-co...
1381

04b0c5c69   Johannes Berg   cfg80211: remove ...
1382
1383
1384
  static int cfg80211_wext_siwpmksa(struct net_device *dev,
  				  struct iw_request_info *info,
  				  struct iw_point *data, char *extra)
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1385
1386
  {
  	struct wireless_dev *wdev = dev->ieee80211_ptr;
f26cbf401   Zhao, Gang   cfg80211: change ...
1387
  	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
  	struct cfg80211_pmksa cfg_pmksa;
  	struct iw_pmksa *pmksa = (struct iw_pmksa *)extra;
  
  	memset(&cfg_pmksa, 0, sizeof(struct cfg80211_pmksa));
  
  	if (wdev->iftype != NL80211_IFTYPE_STATION)
  		return -EINVAL;
  
  	cfg_pmksa.bssid = pmksa->bssid.sa_data;
  	cfg_pmksa.pmkid = pmksa->pmkid;
  
  	switch (pmksa->cmd) {
  	case IW_PMKSA_ADD:
  		if (!rdev->ops->set_pmksa)
  			return -EOPNOTSUPP;
e35e4d28b   Hila Gonen   cfg80211: add wra...
1403
  		return rdev_set_pmksa(rdev, dev, &cfg_pmksa);
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1404
1405
1406
1407
  
  	case IW_PMKSA_REMOVE:
  		if (!rdev->ops->del_pmksa)
  			return -EOPNOTSUPP;
e35e4d28b   Hila Gonen   cfg80211: add wra...
1408
  		return rdev_del_pmksa(rdev, dev, &cfg_pmksa);
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1409
1410
1411
1412
  
  	case IW_PMKSA_FLUSH:
  		if (!rdev->ops->flush_pmksa)
  			return -EOPNOTSUPP;
e35e4d28b   Hila Gonen   cfg80211: add wra...
1413
  		return rdev_flush_pmksa(rdev, dev);
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1414
1415
1416
1417
1418
  
  	default:
  		return -EOPNOTSUPP;
  	}
  }
a9a11622c   Johannes Berg   cfg80211: self-co...
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
  static const iw_handler cfg80211_handlers[] = {
  	[IW_IOCTL_IDX(SIOCGIWNAME)]	= (iw_handler) cfg80211_wext_giwname,
  	[IW_IOCTL_IDX(SIOCSIWFREQ)]	= (iw_handler) cfg80211_wext_siwfreq,
  	[IW_IOCTL_IDX(SIOCGIWFREQ)]	= (iw_handler) cfg80211_wext_giwfreq,
  	[IW_IOCTL_IDX(SIOCSIWMODE)]	= (iw_handler) cfg80211_wext_siwmode,
  	[IW_IOCTL_IDX(SIOCGIWMODE)]	= (iw_handler) cfg80211_wext_giwmode,
  	[IW_IOCTL_IDX(SIOCGIWRANGE)]	= (iw_handler) cfg80211_wext_giwrange,
  	[IW_IOCTL_IDX(SIOCSIWAP)]	= (iw_handler) cfg80211_wext_siwap,
  	[IW_IOCTL_IDX(SIOCGIWAP)]	= (iw_handler) cfg80211_wext_giwap,
  	[IW_IOCTL_IDX(SIOCSIWMLME)]	= (iw_handler) cfg80211_wext_siwmlme,
  	[IW_IOCTL_IDX(SIOCSIWSCAN)]	= (iw_handler) cfg80211_wext_siwscan,
  	[IW_IOCTL_IDX(SIOCGIWSCAN)]	= (iw_handler) cfg80211_wext_giwscan,
  	[IW_IOCTL_IDX(SIOCSIWESSID)]	= (iw_handler) cfg80211_wext_siwessid,
  	[IW_IOCTL_IDX(SIOCGIWESSID)]	= (iw_handler) cfg80211_wext_giwessid,
  	[IW_IOCTL_IDX(SIOCSIWRATE)]	= (iw_handler) cfg80211_wext_siwrate,
  	[IW_IOCTL_IDX(SIOCGIWRATE)]	= (iw_handler) cfg80211_wext_giwrate,
  	[IW_IOCTL_IDX(SIOCSIWRTS)]	= (iw_handler) cfg80211_wext_siwrts,
  	[IW_IOCTL_IDX(SIOCGIWRTS)]	= (iw_handler) cfg80211_wext_giwrts,
  	[IW_IOCTL_IDX(SIOCSIWFRAG)]	= (iw_handler) cfg80211_wext_siwfrag,
  	[IW_IOCTL_IDX(SIOCGIWFRAG)]	= (iw_handler) cfg80211_wext_giwfrag,
  	[IW_IOCTL_IDX(SIOCSIWTXPOW)]	= (iw_handler) cfg80211_wext_siwtxpower,
  	[IW_IOCTL_IDX(SIOCGIWTXPOW)]	= (iw_handler) cfg80211_wext_giwtxpower,
  	[IW_IOCTL_IDX(SIOCSIWRETRY)]	= (iw_handler) cfg80211_wext_siwretry,
  	[IW_IOCTL_IDX(SIOCGIWRETRY)]	= (iw_handler) cfg80211_wext_giwretry,
  	[IW_IOCTL_IDX(SIOCSIWENCODE)]	= (iw_handler) cfg80211_wext_siwencode,
  	[IW_IOCTL_IDX(SIOCGIWENCODE)]	= (iw_handler) cfg80211_wext_giwencode,
  	[IW_IOCTL_IDX(SIOCSIWPOWER)]	= (iw_handler) cfg80211_wext_siwpower,
  	[IW_IOCTL_IDX(SIOCGIWPOWER)]	= (iw_handler) cfg80211_wext_giwpower,
  	[IW_IOCTL_IDX(SIOCSIWGENIE)]	= (iw_handler) cfg80211_wext_siwgenie,
  	[IW_IOCTL_IDX(SIOCSIWAUTH)]	= (iw_handler) cfg80211_wext_siwauth,
  	[IW_IOCTL_IDX(SIOCGIWAUTH)]	= (iw_handler) cfg80211_wext_giwauth,
  	[IW_IOCTL_IDX(SIOCSIWENCODEEXT)]= (iw_handler) cfg80211_wext_siwencodeext,
2944b2c2d   Samuel Ortiz   cfg80211: Add PMK...
1451
  	[IW_IOCTL_IDX(SIOCSIWPMKSA)]	= (iw_handler) cfg80211_wext_siwpmksa,
a9a11622c   Johannes Berg   cfg80211: self-co...
1452
1453
1454
1455
1456
1457
1458
  };
  
  const struct iw_handler_def cfg80211_wext_handler = {
  	.num_standard		= ARRAY_SIZE(cfg80211_handlers),
  	.standard		= cfg80211_handlers,
  	.get_wireless_stats = cfg80211_wireless_stats,
  };