wext.c 19.1 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * Copyright 2002-2005, Instant802 Networks, Inc.
 * Copyright 2005-2006, Devicescape Software, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <asm/uaccess.h>

#include <net/mac80211.h>
#include "ieee80211_i.h"
Johannes Berg's avatar
Johannes Berg committed
24
25
#include "led.h"
#include "rate.h"
26
27
28
#include "wpa.h"
#include "aes_ccm.h"

Johannes Berg's avatar
Johannes Berg committed
29

30
31
32
33
34
35
static int ieee80211_ioctl_siwgenie(struct net_device *dev,
				    struct iw_request_info *info,
				    struct iw_point *data, char *extra)
{
	struct ieee80211_sub_if_data *sdata;

36
37
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

38
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
39
		int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
40
41
		if (ret)
			return ret;
42
		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
43
		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
44
		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
45
		ieee80211_sta_req_auth(sdata);
46
47
48
49
50
51
52
53
54
55
56
57
		return 0;
	}

	return -EOPNOTSUPP;
}

static int ieee80211_ioctl_siwfreq(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_freq *freq, char *extra)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

58
	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
59
		return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
60
61
	else if (sdata->vif.type == NL80211_IFTYPE_STATION)
		sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
62
63
64
65

	/* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
	if (freq->e == 0) {
		if (freq->m < 0) {
66
			if (sdata->vif.type == NL80211_IFTYPE_STATION)
67
				sdata->u.mgd.flags |=
68
					IEEE80211_STA_AUTO_CHANNEL_SEL;
69
70
			return 0;
		} else
71
			return ieee80211_set_freq(sdata,
72
				ieee80211_channel_to_frequency(freq->m));
73
74
75
76
77
	} else {
		int i, div = 1000000;
		for (i = 0; i < freq->e; i++)
			div /= 10;
		if (div > 0)
78
			return ieee80211_set_freq(sdata, freq->m / div);
79
80
81
82
83
84
85
86
87
88
89
		else
			return -EINVAL;
	}
}


static int ieee80211_ioctl_giwfreq(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_freq *freq, char *extra)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
90
91
92
93
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
		return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
94

95
	freq->m = local->oper_channel->center_freq;
96
97
98
99
100
101
102
103
104
105
	freq->e = 6;

	return 0;
}


static int ieee80211_ioctl_siwessid(struct net_device *dev,
				    struct iw_request_info *info,
				    struct iw_point *data, char *ssid)
{
106
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
107
	size_t len = data->length;
108
	int ret;
109

110
111
112
	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
		return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);

113
114
115
116
	/* iwconfig uses nul termination in SSID.. */
	if (len > 0 && ssid[len - 1] == '\0')
		len--;

117
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
118
		if (data->flags)
119
			sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
120
		else
121
122
			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;

123
		ret = ieee80211_sta_set_ssid(sdata, ssid, len);
124
125
		if (ret)
			return ret;
126

127
		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
128
		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
129
		ieee80211_sta_req_auth(sdata);
130
		return 0;
131
	}
132
133
134
135
136
137
138
139
140
141
142

	return -EOPNOTSUPP;
}


static int ieee80211_ioctl_giwessid(struct net_device *dev,
				    struct iw_request_info *info,
				    struct iw_point *data, char *ssid)
{
	size_t len;
	struct ieee80211_sub_if_data *sdata;
143

144
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
145
146
147
148

	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
		return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);

149
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
150
		int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
		if (res == 0) {
			data->length = len;
			data->flags = 1;
		} else
			data->flags = 0;
		return res;
	}

	return -EOPNOTSUPP;
}


static int ieee80211_ioctl_siwap(struct net_device *dev,
				 struct iw_request_info *info,
				 struct sockaddr *ap_addr, char *extra)
{
167
168
169
170
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
		return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
171

172
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
173
		int ret;
174

175
		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
176
			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
177
178
				IEEE80211_STA_AUTO_CHANNEL_SEL;
		else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
179
			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
180
		else
181
			sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
182
		ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
183
184
		if (ret)
			return ret;
185
		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
186
		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
187
		ieee80211_sta_req_auth(sdata);
188
		return 0;
189
	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
		/*
		 * If it is necessary to update the WDS peer address
		 * while the interface is running, then we need to do
		 * more work here, namely if it is running we need to
		 * add a new and remove the old STA entry, this is
		 * normally handled by _open() and _stop().
		 */
		if (netif_running(dev))
			return -EBUSY;

		memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
		       ETH_ALEN);

		return 0;
204
205
206
207
208
209
210
211
212
213
	}

	return -EOPNOTSUPP;
}


static int ieee80211_ioctl_giwap(struct net_device *dev,
				 struct iw_request_info *info,
				 struct sockaddr *ap_addr, char *extra)
{
214
215
216
217
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
		return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
218

219
220
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
		if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
221
			ap_addr->sa_family = ARPHRD_ETHER;
222
223
			memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);
		} else
224
			memset(&ap_addr->sa_data, 0, ETH_ALEN);
225
		return 0;
226
	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
227
228
229
230
231
232
233
234
235
		ap_addr->sa_family = ARPHRD_ETHER;
		memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
		return 0;
	}

	return -EOPNOTSUPP;
}


236
237
238
239
240
static int ieee80211_ioctl_siwrate(struct net_device *dev,
				  struct iw_request_info *info,
				  struct iw_param *rate, char *extra)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
241
	int i, err = -EINVAL;
242
243
	u32 target_rate = rate->value / 100000;
	struct ieee80211_sub_if_data *sdata;
244
	struct ieee80211_supported_band *sband;
245
246

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
247
248
249

	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];

250
251
252
	/* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
	 * target_rate = X, rate->fixed = 1 means only rate X
	 * target_rate = X, rate->fixed = 0 means all rates <= X */
253
254
	sdata->max_ratectrl_rateidx = -1;
	sdata->force_unicast_rateidx = -1;
255
256
	if (rate->value < 0)
		return 0;
257
258
259
260

	for (i=0; i< sband->n_bitrates; i++) {
		struct ieee80211_rate *brate = &sband->bitrates[i];
		int this_rate = brate->bitrate;
261
262

		if (target_rate == this_rate) {
263
			sdata->max_ratectrl_rateidx = i;
264
			if (rate->fixed)
265
				sdata->force_unicast_rateidx = i;
266
267
			err = 0;
			break;
268
269
		}
	}
270
	return err;
271
272
}

273
274
275
276
277
278
279
static int ieee80211_ioctl_giwrate(struct net_device *dev,
				  struct iw_request_info *info,
				  struct iw_param *rate, char *extra)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct sta_info *sta;
	struct ieee80211_sub_if_data *sdata;
280
	struct ieee80211_supported_band *sband;
281
282

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
283

284
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
285
		return -EOPNOTSUPP;
286
287
288

	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];

289
290
	rcu_read_lock();

291
	sta = sta_info_get(local, sdata->u.mgd.bssid);
292

293
294
	if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
		rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
295
296
	else
		rate->value = 0;
297
298
299
300
301
302

	rcu_read_unlock();

	if (!sta)
		return -ENODEV;

303
	rate->value *= 100000;
304

305
306
307
	return 0;
}

308
309
310
311
312
static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
				      struct iw_request_info *info,
				      union iwreq_data *data, char *extra)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
313
	struct ieee80211_channel* chan = local->hw.conf.channel;
314
	bool reconf = false;
315
	u32 reconf_flags = 0;
316
	int new_power_level;
317
318
319
320
321

	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
		return -EINVAL;
	if (data->txpower.flags & IW_TXPOW_RANGE)
		return -EINVAL;
322
323
	if (!chan)
		return -EINVAL;
324

325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
	/* only change when not disabling */
	if (!data->txpower.disabled) {
		if (data->txpower.fixed) {
			if (data->txpower.value < 0)
				return -EINVAL;
			new_power_level = data->txpower.value;
			/*
			 * Debatable, but we cannot do a fixed power
			 * level above the regulatory constraint.
			 * Use "iwconfig wlan0 txpower 15dBm" instead.
			 */
			if (new_power_level > chan->max_power)
				return -EINVAL;
		} else {
			/*
			 * Automatic power level setting, max being the value
			 * passed in from userland.
			 */
			if (data->txpower.value < 0)
				new_power_level = -1;
			else
				new_power_level = data->txpower.value;
		}

		reconf = true;
350

351
352
353
354
355
356
		/*
		 * ieee80211_hw_config() will limit to the channel's
		 * max power and possibly power constraint from AP.
		 */
		local->user_power_level = new_power_level;
	}
357

358
359
	if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
		local->hw.conf.radio_enabled = !(data->txpower.disabled);
360
		reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
361
		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
362
	}
363

364
	if (reconf || reconf_flags)
365
		ieee80211_hw_config(local, reconf_flags);
366
367
368
369

	return 0;
}

370
371
372
373
374
375
376
377
378
379
380
381
382
383
static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
				   struct iw_request_info *info,
				   union iwreq_data *data, char *extra)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);

	data->txpower.fixed = 1;
	data->txpower.disabled = !(local->hw.conf.radio_enabled);
	data->txpower.value = local->hw.conf.power_level;
	data->txpower.flags = IW_TXPOW_DBM;

	return 0;
}

384
385
386
387
388
static int ieee80211_ioctl_siwpower(struct net_device *dev,
				    struct iw_request_info *info,
				    struct iw_param *wrq,
				    char *extra)
{
389
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
390
391
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct ieee80211_conf *conf = &local->hw.conf;
392
	int timeout = 0;
393
394
	bool ps;

395
396
397
	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
		return -EOPNOTSUPP;

398
399
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
		return -EINVAL;
400
401

	if (wrq->disabled) {
402
		ps = false;
403
		timeout = 0;
404
		goto set;
405
406
407
408
409
410
	}

	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 */
411
		ps = true;
412
		break;
413
	default:                /* Otherwise we ignore */
414
		return -EINVAL;
415
416
	}

417
418
419
	if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
		return -EINVAL;

420
421
	if (wrq->flags & IW_POWER_TIMEOUT)
		timeout = wrq->value / 1000;
422

423
 set:
424
425
	if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
		return 0;
426

427
	sdata->u.mgd.powersave = ps;
428
	conf->dynamic_ps_timeout = timeout;
429

430
	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
431
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
432

433
	ieee80211_recalc_ps(local, -1);
434

435
	return 0;
436
437
438
439
440
441
442
}

static int ieee80211_ioctl_giwpower(struct net_device *dev,
				    struct iw_request_info *info,
				    union iwreq_data *wrqu,
				    char *extra)
{
443
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
444

445
	wrqu->power.disabled = !sdata->u.mgd.powersave;
446
447
448
449

	return 0;
}

450
451
452
453
454
455
456
457
458
459
460
461
462
static int ieee80211_ioctl_siwauth(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_param *data, char *extra)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	int ret = 0;

	switch (data->flags & IW_AUTH_INDEX) {
	case IW_AUTH_WPA_VERSION:
	case IW_AUTH_CIPHER_GROUP:
	case IW_AUTH_WPA_ENABLED:
	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
	case IW_AUTH_KEY_MGMT:
463
	case IW_AUTH_CIPHER_GROUP_MGMT:
464
		break;
465
466
467
468
	case IW_AUTH_CIPHER_PAIRWISE:
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
			if (data->value & (IW_AUTH_CIPHER_WEP40 |
			    IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
469
				sdata->u.mgd.flags |=
470
471
					IEEE80211_STA_TKIP_WEP_USED;
			else
472
				sdata->u.mgd.flags &=
473
474
475
					~IEEE80211_STA_TKIP_WEP_USED;
		}
		break;
476
477
478
	case IW_AUTH_DROP_UNENCRYPTED:
		sdata->drop_unencrypted = !!data->value;
		break;
479
	case IW_AUTH_PRIVACY_INVOKED:
480
		if (sdata->vif.type != NL80211_IFTYPE_STATION)
481
482
			ret = -EINVAL;
		else {
483
			sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
484
			/*
485
486
487
			 * Privacy invoked by wpa_supplicant, store the
			 * value and allow associating to a protected
			 * network without having a key up front.
488
			 */
489
			if (data->value)
490
				sdata->u.mgd.flags |=
491
					IEEE80211_STA_PRIVACY_INVOKED;
492
493
494
		}
		break;
	case IW_AUTH_80211_AUTH_ALG:
495
496
		if (sdata->vif.type == NL80211_IFTYPE_STATION)
			sdata->u.mgd.auth_algs = data->value;
497
498
499
		else
			ret = -EOPNOTSUPP;
		break;
500
	case IW_AUTH_MFP:
501
502
503
504
		if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
			ret = -EOPNOTSUPP;
			break;
		}
505
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
506
507
			switch (data->value) {
			case IW_AUTH_MFP_DISABLED:
508
				sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
509
510
				break;
			case IW_AUTH_MFP_OPTIONAL:
511
				sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
512
513
				break;
			case IW_AUTH_MFP_REQUIRED:
514
				sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
515
516
517
518
519
				break;
			default:
				ret = -EINVAL;
			}
		} else
520
521
			ret = -EOPNOTSUPP;
		break;
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
	default:
		ret = -EOPNOTSUPP;
		break;
	}
	return ret;
}

/* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
{
	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
	struct iw_statistics *wstats = &local->wstats;
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	struct sta_info *sta = NULL;

Johannes Berg's avatar
Johannes Berg committed
537
538
	rcu_read_lock();

539
540
541
	if (sdata->vif.type == NL80211_IFTYPE_STATION)
		sta = sta_info_get(local, sdata->u.mgd.bssid);

542
543
544
545
546
547
548
549
	if (!sta) {
		wstats->discard.fragment = 0;
		wstats->discard.misc = 0;
		wstats->qual.qual = 0;
		wstats->qual.level = 0;
		wstats->qual.noise = 0;
		wstats->qual.updated = IW_QUAL_ALL_INVALID;
	} else {
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
		wstats->qual.updated = 0;
		/*
		 * mirror what cfg80211 does for iwrange/scan results,
		 * otherwise userspace gets confused.
		 */
		if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
				       IEEE80211_HW_SIGNAL_DBM)) {
			wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED;
			wstats->qual.updated |= IW_QUAL_QUAL_UPDATED;
		} else {
			wstats->qual.updated |= IW_QUAL_LEVEL_INVALID;
			wstats->qual.updated |= IW_QUAL_QUAL_INVALID;
		}

		if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
			wstats->qual.level = sta->last_signal;
			wstats->qual.qual = sta->last_signal;
		} else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
			int sig = sta->last_signal;

			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;
		}

		if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
			/*
			 * This assumes that if driver reports noise, it also
			 * reports signal in dBm.
			 */
			wstats->qual.noise = sta->last_noise;
			wstats->qual.updated |= IW_QUAL_NOISE_UPDATED;
		} else {
			wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
		}
589
	}
Johannes Berg's avatar
Johannes Berg committed
590
591
592

	rcu_read_unlock();

593
594
595
596
597
598
599
600
601
602
603
604
	return wstats;
}

static int ieee80211_ioctl_giwauth(struct net_device *dev,
				   struct iw_request_info *info,
				   struct iw_param *data, char *extra)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
	int ret = 0;

	switch (data->flags & IW_AUTH_INDEX) {
	case IW_AUTH_80211_AUTH_ALG:
605
606
		if (sdata->vif.type == NL80211_IFTYPE_STATION)
			data->value = sdata->u.mgd.auth_algs;
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
		else
			ret = -EOPNOTSUPP;
		break;
	default:
		ret = -EOPNOTSUPP;
		break;
	}
	return ret;
}


/* Structures to export the Wireless Handlers */

static const iw_handler ieee80211_handler[] =
{
	(iw_handler) NULL,				/* SIOCSIWCOMMIT */
Johannes Berg's avatar
Johannes Berg committed
623
	(iw_handler) cfg80211_wext_giwname,		/* SIOCGIWNAME */
624
625
626
627
	(iw_handler) NULL,				/* SIOCSIWNWID */
	(iw_handler) NULL,				/* SIOCGIWNWID */
	(iw_handler) ieee80211_ioctl_siwfreq,		/* SIOCSIWFREQ */
	(iw_handler) ieee80211_ioctl_giwfreq,		/* SIOCGIWFREQ */
628
629
	(iw_handler) cfg80211_wext_siwmode,		/* SIOCSIWMODE */
	(iw_handler) cfg80211_wext_giwmode,		/* SIOCGIWMODE */
630
631
632
	(iw_handler) NULL,				/* SIOCSIWSENS */
	(iw_handler) NULL,				/* SIOCGIWSENS */
	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */
633
	(iw_handler) cfg80211_wext_giwrange,		/* SIOCGIWRANGE */
634
635
636
637
	(iw_handler) NULL /* not used */,		/* SIOCSIWPRIV */
	(iw_handler) NULL /* kernel code */,		/* SIOCGIWPRIV */
	(iw_handler) NULL /* not used */,		/* SIOCSIWSTATS */
	(iw_handler) NULL /* kernel code */,		/* SIOCGIWSTATS */
638
639
640
641
	(iw_handler) NULL,				/* SIOCSIWSPY */
	(iw_handler) NULL,				/* SIOCGIWSPY */
	(iw_handler) NULL,				/* SIOCSIWTHRSPY */
	(iw_handler) NULL,				/* SIOCGIWTHRSPY */
642
643
	(iw_handler) ieee80211_ioctl_siwap,		/* SIOCSIWAP */
	(iw_handler) ieee80211_ioctl_giwap,		/* SIOCGIWAP */
644
	(iw_handler) cfg80211_wext_siwmlme,		/* SIOCSIWMLME */
645
	(iw_handler) NULL,				/* SIOCGIWAPLIST */
646
647
	(iw_handler) cfg80211_wext_siwscan,		/* SIOCSIWSCAN */
	(iw_handler) cfg80211_wext_giwscan,		/* SIOCGIWSCAN */
648
649
650
651
652
653
	(iw_handler) ieee80211_ioctl_siwessid,		/* SIOCSIWESSID */
	(iw_handler) ieee80211_ioctl_giwessid,		/* SIOCGIWESSID */
	(iw_handler) NULL,				/* SIOCSIWNICKN */
	(iw_handler) NULL,				/* SIOCGIWNICKN */
	(iw_handler) NULL,				/* -- hole -- */
	(iw_handler) NULL,				/* -- hole -- */
654
	(iw_handler) ieee80211_ioctl_siwrate,		/* SIOCSIWRATE */
655
	(iw_handler) ieee80211_ioctl_giwrate,		/* SIOCGIWRATE */
656
657
658
659
	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */
	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
	(iw_handler) cfg80211_wext_siwfrag,		/* SIOCSIWFRAG */
	(iw_handler) cfg80211_wext_giwfrag,		/* SIOCGIWFRAG */
660
	(iw_handler) ieee80211_ioctl_siwtxpower,	/* SIOCSIWTXPOW */
661
	(iw_handler) ieee80211_ioctl_giwtxpower,	/* SIOCGIWTXPOW */
662
663
	(iw_handler) cfg80211_wext_siwretry,		/* SIOCSIWRETRY */
	(iw_handler) cfg80211_wext_giwretry,		/* SIOCGIWRETRY */
664
665
	(iw_handler) cfg80211_wext_siwencode,		/* SIOCSIWENCODE */
	(iw_handler) cfg80211_wext_giwencode,		/* SIOCGIWENCODE */
666
667
	(iw_handler) ieee80211_ioctl_siwpower,		/* SIOCSIWPOWER */
	(iw_handler) ieee80211_ioctl_giwpower,		/* SIOCGIWPOWER */
668
669
670
671
672
673
	(iw_handler) NULL,				/* -- hole -- */
	(iw_handler) NULL,				/* -- hole -- */
	(iw_handler) ieee80211_ioctl_siwgenie,		/* SIOCSIWGENIE */
	(iw_handler) NULL,				/* SIOCGIWGENIE */
	(iw_handler) ieee80211_ioctl_siwauth,		/* SIOCSIWAUTH */
	(iw_handler) ieee80211_ioctl_giwauth,		/* SIOCGIWAUTH */
674
	(iw_handler) cfg80211_wext_siwencodeext,	/* SIOCSIWENCODEEXT */
675
676
677
678
679
680
681
682
683
684
685
	(iw_handler) NULL,				/* SIOCGIWENCODEEXT */
	(iw_handler) NULL,				/* SIOCSIWPMKSA */
	(iw_handler) NULL,				/* -- hole -- */
};

const struct iw_handler_def ieee80211_iw_handler_def =
{
	.num_standard	= ARRAY_SIZE(ieee80211_handler),
	.standard	= (iw_handler *) ieee80211_handler,
	.get_wireless_stats = ieee80211_get_wireless_stats,
};