wext.c 18.9 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
		ieee80211_sta_req_auth(sdata);
45 46 47 48 49 50 51 52 53 54 55 56
		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);

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

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

94
	freq->m = local->oper_channel->center_freq;
95 96 97 98 99 100 101 102 103 104
	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)
{
105
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
106
	size_t len = data->length;
107
	int ret;
108

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

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

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

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

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

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

142
	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
143 144 145 146

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

147
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
148
		int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
		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)
{
165 166 167 168
	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);
169

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

173
		if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
174
			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
175 176
				IEEE80211_STA_AUTO_CHANNEL_SEL;
		else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
177
			sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
178
		else
179
			sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
180
		ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
181 182
		if (ret)
			return ret;
183
		sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
184
		ieee80211_sta_req_auth(sdata);
185
		return 0;
186
	} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
187 188 189 190 191 192 193 194 195 196 197 198 199 200
		/*
		 * 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;
201 202 203 204 205 206 207 208 209 210
	}

	return -EOPNOTSUPP;
}


static int ieee80211_ioctl_giwap(struct net_device *dev,
				 struct iw_request_info *info,
				 struct sockaddr *ap_addr, char *extra)
{
211 212 213 214
	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);
215

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

	return -EOPNOTSUPP;
}


233 234 235 236 237
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);
238
	int i, err = -EINVAL;
239 240
	u32 target_rate = rate->value / 100000;
	struct ieee80211_sub_if_data *sdata;
241
	struct ieee80211_supported_band *sband;
242 243

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
244 245 246

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

247 248 249
	/* 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 */
250 251
	sdata->max_ratectrl_rateidx = -1;
	sdata->force_unicast_rateidx = -1;
252 253
	if (rate->value < 0)
		return 0;
254 255 256 257

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

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

270 271 272 273 274 275 276
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;
277
	struct ieee80211_supported_band *sband;
278 279

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
280

281
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
282
		return -EOPNOTSUPP;
283 284 285

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

286 287
	rcu_read_lock();

288
	sta = sta_info_get(local, sdata->u.mgd.bssid);
289

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

	rcu_read_unlock();

	if (!sta)
		return -ENODEV;

300
	rate->value *= 100000;
301

302 303 304
	return 0;
}

305 306 307 308 309
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);
310
	struct ieee80211_channel* chan = local->hw.conf.channel;
311
	bool reconf = false;
312
	u32 reconf_flags = 0;
313
	int new_power_level;
314 315 316 317 318

	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
		return -EINVAL;
	if (data->txpower.flags & IW_TXPOW_RANGE)
		return -EINVAL;
319 320
	if (!chan)
		return -EINVAL;
321

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
	/* 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;
347

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

355 356
	if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
		local->hw.conf.radio_enabled = !(data->txpower.disabled);
357
		reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
I
Ivo van Doorn 已提交
358
		ieee80211_led_radio(local, local->hw.conf.radio_enabled);
359
	}
360

361
	if (reconf || reconf_flags)
362
		ieee80211_hw_config(local, reconf_flags);
363 364 365 366

	return 0;
}

367 368 369 370 371 372 373 374 375 376 377 378 379 380
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;
}

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

392 393 394
	if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
		return -EOPNOTSUPP;

395 396
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
		return -EINVAL;
397 398

	if (wrq->disabled) {
399
		ps = false;
400
		timeout = 0;
401
		goto set;
402 403 404 405 406 407
	}

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

414 415 416
	if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
		return -EINVAL;

417 418
	if (wrq->flags & IW_POWER_TIMEOUT)
		timeout = wrq->value / 1000;
419

420
 set:
421 422
	if (ps == sdata->u.mgd.powersave && timeout == conf->dynamic_ps_timeout)
		return 0;
423

424
	sdata->u.mgd.powersave = ps;
425
	conf->dynamic_ps_timeout = timeout;
426

427
	if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
428
		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
429

430
	ieee80211_recalc_ps(local, -1);
431

432
	return 0;
433 434 435 436 437 438 439
}

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

442
	wrqu->power.disabled = !sdata->u.mgd.powersave;
443 444 445 446

	return 0;
}

447 448 449 450 451 452 453 454 455 456 457 458 459
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:
460
	case IW_AUTH_CIPHER_GROUP_MGMT:
461
		break;
462 463 464 465
	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))
466
				sdata->u.mgd.flags |=
467 468
					IEEE80211_STA_TKIP_WEP_USED;
			else
469
				sdata->u.mgd.flags &=
470 471 472
					~IEEE80211_STA_TKIP_WEP_USED;
		}
		break;
473 474 475
	case IW_AUTH_DROP_UNENCRYPTED:
		sdata->drop_unencrypted = !!data->value;
		break;
476
	case IW_AUTH_PRIVACY_INVOKED:
477
		if (sdata->vif.type != NL80211_IFTYPE_STATION)
478 479
			ret = -EINVAL;
		else {
480
			sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
481
			/*
482 483 484
			 * Privacy invoked by wpa_supplicant, store the
			 * value and allow associating to a protected
			 * network without having a key up front.
485
			 */
486
			if (data->value)
487
				sdata->u.mgd.flags |=
488
					IEEE80211_STA_PRIVACY_INVOKED;
489 490 491
		}
		break;
	case IW_AUTH_80211_AUTH_ALG:
492 493
		if (sdata->vif.type == NL80211_IFTYPE_STATION)
			sdata->u.mgd.auth_algs = data->value;
494 495 496
		else
			ret = -EOPNOTSUPP;
		break;
497
	case IW_AUTH_MFP:
498 499 500 501
		if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
			ret = -EOPNOTSUPP;
			break;
		}
502
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
503 504
			switch (data->value) {
			case IW_AUTH_MFP_DISABLED:
505
				sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
506 507
				break;
			case IW_AUTH_MFP_OPTIONAL:
508
				sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
509 510
				break;
			case IW_AUTH_MFP_REQUIRED:
511
				sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
512 513 514 515 516
				break;
			default:
				ret = -EINVAL;
			}
		} else
517 518
			ret = -EOPNOTSUPP;
		break;
519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
	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 已提交
534 535
	rcu_read_lock();

536 537 538
	if (sdata->vif.type == NL80211_IFTYPE_STATION)
		sta = sta_info_get(local, sdata->u.mgd.bssid);

539 540 541 542 543 544 545 546
	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 {
547 548 549 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
		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;
		}
586
	}
J
Johannes Berg 已提交
587 588 589

	rcu_read_unlock();

590 591 592 593 594 595 596 597 598 599 600 601
	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:
602 603
		if (sdata->vif.type == NL80211_IFTYPE_STATION)
			data->value = sdata->u.mgd.auth_algs;
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
		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 已提交
620
	(iw_handler) cfg80211_wext_giwname,		/* SIOCGIWNAME */
621 622 623 624
	(iw_handler) NULL,				/* SIOCSIWNWID */
	(iw_handler) NULL,				/* SIOCGIWNWID */
	(iw_handler) ieee80211_ioctl_siwfreq,		/* SIOCSIWFREQ */
	(iw_handler) ieee80211_ioctl_giwfreq,		/* SIOCGIWFREQ */
625 626
	(iw_handler) cfg80211_wext_siwmode,		/* SIOCSIWMODE */
	(iw_handler) cfg80211_wext_giwmode,		/* SIOCGIWMODE */
627 628 629
	(iw_handler) NULL,				/* SIOCSIWSENS */
	(iw_handler) NULL,				/* SIOCGIWSENS */
	(iw_handler) NULL /* not used */,		/* SIOCSIWRANGE */
630
	(iw_handler) cfg80211_wext_giwrange,		/* SIOCGIWRANGE */
631 632 633 634
	(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 已提交
635 636 637 638
	(iw_handler) NULL,				/* SIOCSIWSPY */
	(iw_handler) NULL,				/* SIOCGIWSPY */
	(iw_handler) NULL,				/* SIOCSIWTHRSPY */
	(iw_handler) NULL,				/* SIOCGIWTHRSPY */
639 640
	(iw_handler) ieee80211_ioctl_siwap,		/* SIOCSIWAP */
	(iw_handler) ieee80211_ioctl_giwap,		/* SIOCGIWAP */
641
	(iw_handler) cfg80211_wext_siwmlme,		/* SIOCSIWMLME */
642
	(iw_handler) NULL,				/* SIOCGIWAPLIST */
643 644
	(iw_handler) cfg80211_wext_siwscan,		/* SIOCSIWSCAN */
	(iw_handler) cfg80211_wext_giwscan,		/* SIOCGIWSCAN */
645 646 647 648 649 650
	(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 -- */
651
	(iw_handler) ieee80211_ioctl_siwrate,		/* SIOCSIWRATE */
652
	(iw_handler) ieee80211_ioctl_giwrate,		/* SIOCGIWRATE */
653 654 655 656
	(iw_handler) cfg80211_wext_siwrts,		/* SIOCSIWRTS */
	(iw_handler) cfg80211_wext_giwrts,		/* SIOCGIWRTS */
	(iw_handler) cfg80211_wext_siwfrag,		/* SIOCSIWFRAG */
	(iw_handler) cfg80211_wext_giwfrag,		/* SIOCGIWFRAG */
657
	(iw_handler) ieee80211_ioctl_siwtxpower,	/* SIOCSIWTXPOW */
658
	(iw_handler) ieee80211_ioctl_giwtxpower,	/* SIOCGIWTXPOW */
659 660
	(iw_handler) cfg80211_wext_siwretry,		/* SIOCSIWRETRY */
	(iw_handler) cfg80211_wext_giwretry,		/* SIOCGIWRETRY */
661 662
	(iw_handler) cfg80211_wext_siwencode,		/* SIOCSIWENCODE */
	(iw_handler) cfg80211_wext_giwencode,		/* SIOCGIWENCODE */
663 664
	(iw_handler) ieee80211_ioctl_siwpower,		/* SIOCSIWPOWER */
	(iw_handler) ieee80211_ioctl_giwpower,		/* SIOCGIWPOWER */
665 666 667 668 669 670
	(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 */
671
	(iw_handler) cfg80211_wext_siwencodeext,	/* SIOCSIWENCODEEXT */
672 673 674 675 676 677 678 679 680 681 682
	(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,
};