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"
J
Johannes Berg 已提交
24 25
#include "led.h"
#include "rate.h"
26 27 28
#include "wpa.h"
#include "aes_ccm.h"

J
Johannes Berg 已提交
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;
I
Ivo van Doorn 已提交
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;

J
Johannes Berg 已提交
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
	}
J
Johannes Berg 已提交
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 */
J
Johannes Berg 已提交
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 */
J
Johannes Berg 已提交
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,
};