PageRenderTime 119ms CodeModel.GetById 2ms app.highlight 102ms RepoModel.GetById 1ms app.codeStats 0ms

/src/wl/sys/wl_iw.c

https://bitbucket.org/agalog/broadcom
C | 2722 lines | 2246 code | 463 blank | 13 comment | 337 complexity | fad4fc2b1ea39f4f18a48e5a3e755ce2 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * Linux Wireless Extensions support
   3 *
   4 * Copyright (C) 2010, Broadcom Corporation
   5 * All Rights Reserved.
   6 * 
   7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
   8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
   9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
  10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
  11 *
  12 * $Id: wl_iw.c,v 1.133.2.1.28.9 2011-01-26 22:23:18 Exp $
  13 */
  14
  15#if defined(USE_IW)
  16
  17#define LINUX_PORT
  18
  19#include <typedefs.h>
  20#include <linuxver.h>
  21#include <osl.h>
  22
  23#include <bcmutils.h>
  24#include <bcmendian.h>
  25#include <proto/ethernet.h>
  26
  27#include <linux/if_arp.h>
  28#include <asm/uaccess.h>
  29
  30typedef const struct si_pub	si_t;
  31#include <wlioctl.h>
  32
  33#include <wl_dbg.h>
  34#include <wl_iw.h>
  35
  36extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
  37	uint32 reason, char* stringBuf, uint buflen);
  38
  39#define MAX_WLIW_IOCTL_LEN 1024
  40
  41#define htod32(i) i
  42#define htod16(i) i
  43#define dtoh32(i) i
  44#define dtoh16(i) i
  45#define htodchanspec(i) i
  46#define dtohchanspec(i) i
  47
  48extern struct iw_statistics *wl_get_wireless_stats(struct net_device *dev);
  49
  50#if WIRELESS_EXT < 19
  51#define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
  52#define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
  53#endif 
  54
  55#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
  56#define IW_DEV_IF(dev)        ((wl_iw_t *)netdev_priv(dev))
  57#else
  58#define IW_DEV_IF(dev)        ((wl_iw_t *)dev->priv)
  59#endif
  60
  61static void swap_key_from_BE(
  62	        wl_wsec_key_t *key
  63)
  64{
  65	key->index = htod32(key->index);
  66	key->len = htod32(key->len);
  67	key->algo = htod32(key->algo);
  68	key->flags = htod32(key->flags);
  69	key->rxiv.hi = htod32(key->rxiv.hi);
  70	key->rxiv.lo = htod16(key->rxiv.lo);
  71	key->iv_initialized = htod32(key->iv_initialized);
  72}
  73
  74static void swap_key_to_BE(
  75	        wl_wsec_key_t *key
  76)
  77{
  78	key->index = dtoh32(key->index);
  79	key->len = dtoh32(key->len);
  80	key->algo = dtoh32(key->algo);
  81	key->flags = dtoh32(key->flags);
  82	key->rxiv.hi = dtoh32(key->rxiv.hi);
  83	key->rxiv.lo = dtoh16(key->rxiv.lo);
  84	key->iv_initialized = dtoh32(key->iv_initialized);
  85}
  86
  87static int
  88dev_wlc_ioctl(
  89	struct net_device *dev,
  90	int cmd,
  91	void *arg,
  92	int len
  93)
  94{
  95	struct ifreq ifr;
  96	wl_ioctl_t ioc;
  97	mm_segment_t fs;
  98	int ret;
  99
 100	memset(&ioc, 0, sizeof(ioc));
 101	ioc.cmd = cmd;
 102	ioc.buf = arg;
 103	ioc.len = len;
 104
 105	strcpy(ifr.ifr_name, dev->name);
 106	ifr.ifr_data = (caddr_t) &ioc;
 107
 108	fs = get_fs();
 109	set_fs(get_ds());
 110#if defined(WL_USE_NETDEV_OPS)
 111	ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
 112#else
 113	ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
 114#endif
 115	set_fs(fs);
 116
 117	return ret;
 118}
 119
 120static int
 121dev_wlc_intvar_set(
 122	struct net_device *dev,
 123	char *name,
 124	int val)
 125{
 126	char buf[WLC_IOCTL_SMLEN];
 127	uint len;
 128
 129	val = htod32(val);
 130	len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
 131	ASSERT(len);
 132
 133	return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
 134}
 135
 136#if WIRELESS_EXT > 17
 137static int
 138dev_wlc_bufvar_set(
 139	struct net_device *dev,
 140	char *name,
 141	char *buf, int len)
 142{
 143	char *ioctlbuf;
 144	uint buflen;
 145	int error;
 146
 147	ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL);
 148	if (!ioctlbuf)
 149		return -ENOMEM;
 150
 151	buflen = bcm_mkiovar(name, buf, len, ioctlbuf, MAX_WLIW_IOCTL_LEN);
 152	ASSERT(buflen);
 153	error = dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen);
 154
 155	kfree(ioctlbuf);
 156	return error;
 157}
 158#endif 
 159
 160static int
 161dev_wlc_bufvar_get(
 162	struct net_device *dev,
 163	char *name,
 164	char *buf, int buflen)
 165{
 166	char *ioctlbuf;
 167	int error;
 168
 169	uint len;
 170
 171	ioctlbuf = kmalloc(MAX_WLIW_IOCTL_LEN, GFP_KERNEL);
 172	if (!ioctlbuf)
 173		return -ENOMEM;
 174	len = bcm_mkiovar(name, NULL, 0, ioctlbuf, MAX_WLIW_IOCTL_LEN);
 175	ASSERT(len);
 176	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
 177	if (!error)
 178		bcopy(ioctlbuf, buf, buflen);
 179
 180	kfree(ioctlbuf);
 181	return (error);
 182}
 183
 184static int
 185dev_wlc_intvar_get(
 186	struct net_device *dev,
 187	char *name,
 188	int *retval)
 189{
 190	union {
 191		char buf[WLC_IOCTL_SMLEN];
 192		int val;
 193	} var;
 194	int error;
 195
 196	uint len;
 197	uint data_null;
 198
 199	len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
 200	ASSERT(len);
 201	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
 202
 203	*retval = dtoh32(var.val);
 204
 205	return (error);
 206}
 207
 208#if WIRELESS_EXT < 13
 209struct iw_request_info
 210{
 211	__u16		cmd;		
 212	__u16		flags;		
 213};
 214
 215typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
 216	void *wrqu, char *extra);
 217#endif 
 218
 219#if WIRELESS_EXT > 12
 220static int
 221wl_iw_set_leddc(
 222	struct net_device *dev,
 223	struct iw_request_info *info,
 224	union iwreq_data *wrqu,
 225	char *extra
 226)
 227{
 228	int dc = *(int *)extra;
 229	int error;
 230
 231	error = dev_wlc_intvar_set(dev, "leddc", dc);
 232	return error;
 233}
 234
 235static int
 236wl_iw_set_vlanmode(
 237	struct net_device *dev,
 238	struct iw_request_info *info,
 239	union iwreq_data *wrqu,
 240	char *extra
 241)
 242{
 243	int mode = *(int *)extra;
 244	int error;
 245
 246	mode = htod32(mode);
 247	error = dev_wlc_intvar_set(dev, "vlan_mode", mode);
 248	return error;
 249}
 250
 251static int
 252wl_iw_set_pm(
 253	struct net_device *dev,
 254	struct iw_request_info *info,
 255	union iwreq_data *wrqu,
 256	char *extra
 257)
 258{
 259	int pm = *(int *)extra;
 260	int error;
 261
 262	pm = htod32(pm);
 263	error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
 264	return error;
 265}
 266#endif 
 267
 268static int
 269wl_iw_config_commit(
 270	struct net_device *dev,
 271	struct iw_request_info *info,
 272	void *zwrq,
 273	char *extra
 274)
 275{
 276	wlc_ssid_t ssid;
 277	int error;
 278	struct sockaddr bssid;
 279
 280	WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
 281
 282	if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
 283		return error;
 284
 285	ssid.SSID_len = dtoh32(ssid.SSID_len);
 286
 287	if (!ssid.SSID_len)
 288		return 0;
 289
 290	bzero(&bssid, sizeof(struct sockaddr));
 291	if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
 292		WL_ERROR(("%s: WLC_REASSOC failed (%d)\n", __FUNCTION__, error));
 293		return error;
 294	}
 295
 296	return 0;
 297}
 298
 299static int
 300wl_iw_get_name(
 301	struct net_device *dev,
 302	struct iw_request_info *info,
 303	union iwreq_data *cwrq,
 304	char *extra
 305)
 306{
 307	int phytype, err;
 308	uint band[3];
 309	char cap[5];
 310
 311	WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
 312
 313	cap[0] = 0;
 314	if ((err = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype))) < 0)
 315		goto done;
 316	if ((err = dev_wlc_ioctl(dev, WLC_GET_BANDLIST, band, sizeof(band))) < 0)
 317		goto done;
 318
 319	band[0] = dtoh32(band[0]);
 320	switch (phytype) {
 321		case WLC_PHY_TYPE_A:
 322			strcpy(cap, "a");
 323			break;
 324		case WLC_PHY_TYPE_B:
 325			strcpy(cap, "b");
 326			break;
 327		case WLC_PHY_TYPE_LP:
 328		case WLC_PHY_TYPE_G:
 329			if (band[0] >= 2)
 330				strcpy(cap, "abg");
 331			else
 332				strcpy(cap, "bg");
 333			break;
 334		case WLC_PHY_TYPE_N:
 335			if (band[0] >= 2)
 336				strcpy(cap, "abgn");
 337			else
 338				strcpy(cap, "bgn");
 339			break;
 340	}
 341done:
 342	snprintf(cwrq->name, IFNAMSIZ, "IEEE 802.11%s", cap);
 343	return 0;
 344}
 345
 346static int
 347wl_iw_set_freq(
 348	struct net_device *dev,
 349	struct iw_request_info *info,
 350	struct iw_freq *fwrq,
 351	char *extra
 352)
 353{
 354	int error, chan;
 355	uint sf = 0;
 356
 357	WL_TRACE(("%s: SIOCSIWFREQ\n", dev->name));
 358
 359	if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
 360		chan = fwrq->m;
 361	}
 362
 363	else {
 364
 365		if (fwrq->e >= 6) {
 366			fwrq->e -= 6;
 367			while (fwrq->e--)
 368				fwrq->m *= 10;
 369		} else if (fwrq->e < 6) {
 370			while (fwrq->e++ < 6)
 371				fwrq->m /= 10;
 372		}
 373
 374	if (fwrq->m > 4000 && fwrq->m < 5000)
 375		sf = WF_CHAN_FACTOR_4_G; 
 376
 377		chan = wf_mhz2channel(fwrq->m, sf);
 378	}
 379	chan = htod32(chan);
 380	if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
 381		return error;
 382
 383	return -EINPROGRESS;
 384}
 385
 386static int
 387wl_iw_get_freq(
 388	struct net_device *dev,
 389	struct iw_request_info *info,
 390	struct iw_freq *fwrq,
 391	char *extra
 392)
 393{
 394	channel_info_t ci;
 395	int error;
 396
 397	WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
 398
 399	if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
 400		return error;
 401
 402	fwrq->m = dtoh32(ci.hw_channel);
 403	fwrq->e = dtoh32(0);
 404	return 0;
 405}
 406
 407static int
 408wl_iw_set_mode(
 409	struct net_device *dev,
 410	struct iw_request_info *info,
 411	__u32 *uwrq,
 412	char *extra
 413)
 414{
 415	int infra = 0, ap = 0, error = 0;
 416
 417	WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
 418
 419	switch (*uwrq) {
 420	case IW_MODE_MASTER:
 421		infra = ap = 1;
 422		break;
 423	case IW_MODE_ADHOC:
 424	case IW_MODE_AUTO:
 425		break;
 426	case IW_MODE_INFRA:
 427		infra = 1;
 428		break;
 429	default:
 430		return -EINVAL;
 431	}
 432	infra = htod32(infra);
 433	ap = htod32(ap);
 434
 435	if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
 436	    (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
 437		return error;
 438
 439	return -EINPROGRESS;
 440}
 441
 442static int
 443wl_iw_get_mode(
 444	struct net_device *dev,
 445	struct iw_request_info *info,
 446	__u32 *uwrq,
 447	char *extra
 448)
 449{
 450	int error, infra = 0, ap = 0;
 451
 452	WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
 453
 454	if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
 455	    (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
 456		return error;
 457
 458	infra = dtoh32(infra);
 459	ap = dtoh32(ap);
 460	*uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
 461
 462	return 0;
 463}
 464
 465static int
 466wl_iw_get_range(
 467	struct net_device *dev,
 468	struct iw_request_info *info,
 469	struct iw_point *dwrq,
 470	char *extra
 471)
 472{
 473	struct iw_range *range = (struct iw_range *) extra;
 474	static int channels[MAXCHANNEL+1];
 475	wl_uint32_list_t *list = (wl_uint32_list_t *) channels;
 476	wl_rateset_t rateset;
 477	int error, i, k;
 478	uint sf, ch;
 479
 480	int phytype;
 481	int bw_cap = 0, sgi_tx = 0, nmode = 0;
 482	channel_info_t ci;
 483	uint8 nrate_list2copy = 0;
 484	uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
 485		{14, 29, 43, 58, 87, 116, 130, 144},
 486		{27, 54, 81, 108, 162, 216, 243, 270},
 487		{30, 60, 90, 120, 180, 240, 270, 300}};
 488
 489	WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
 490
 491	if (!extra)
 492		return -EINVAL;
 493
 494	dwrq->length = sizeof(struct iw_range);
 495	memset(range, 0, sizeof(range));
 496
 497	range->min_nwid = range->max_nwid = 0;
 498
 499	list->count = htod32(MAXCHANNEL);
 500	if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, sizeof(channels))))
 501		return error;
 502	for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
 503		range->freq[i].i = dtoh32(list->element[i]);
 504
 505		ch = dtoh32(list->element[i]);
 506		if (ch <= CH_MAX_2G_CHANNEL)
 507			sf = WF_CHAN_FACTOR_2_4_G;
 508		else
 509			sf = WF_CHAN_FACTOR_5_G;
 510
 511		range->freq[i].m = wf_channel2mhz(ch, sf);
 512		range->freq[i].e = 6;
 513	}
 514	range->num_frequency = range->num_channels = i;
 515
 516	range->max_qual.qual = 5;
 517
 518	range->max_qual.level = 0x100 - 200;	
 519
 520	range->max_qual.noise = 0x100 - 200;	
 521
 522	range->sensitivity = 65535;
 523
 524#if WIRELESS_EXT > 11
 525
 526	range->avg_qual.qual = 3;
 527
 528	range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
 529
 530	range->avg_qual.noise = 0x100 - 75;	
 531#endif 
 532
 533	if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
 534		return error;
 535	rateset.count = dtoh32(rateset.count);
 536	range->num_bitrates = rateset.count;
 537	for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
 538		range->bitrate[i] = (rateset.rates[i] & 0x7f) * 500000; 
 539	dev_wlc_intvar_get(dev, "nmode", &nmode);
 540	dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
 541
 542	if (nmode == 1 && ((phytype == WLC_PHY_TYPE_SSN) || (phytype == WLC_PHY_TYPE_LCN))) {
 543		dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
 544		dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
 545		dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
 546		ci.hw_channel = dtoh32(ci.hw_channel);
 547
 548		if (bw_cap == 0 ||
 549			(bw_cap == 2 && ci.hw_channel <= 14)) {
 550			if (sgi_tx == 0)
 551				nrate_list2copy = 0;
 552			else
 553				nrate_list2copy = 1;
 554		}
 555		if (bw_cap == 1 ||
 556			(bw_cap == 2 && ci.hw_channel >= 36)) {
 557			if (sgi_tx == 0)
 558				nrate_list2copy = 2;
 559			else
 560				nrate_list2copy = 3;
 561		}
 562		range->num_bitrates += 8;
 563		for (k = 0; i < range->num_bitrates; k++, i++) {
 564
 565			range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
 566		}
 567	}
 568
 569	if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i))))
 570		return error;
 571	i = dtoh32(i);
 572	if (i == WLC_PHY_TYPE_A)
 573		range->throughput = 24000000;	
 574	else
 575		range->throughput = 1500000;	
 576
 577	range->min_rts = 0;
 578	range->max_rts = 2347;
 579	range->min_frag = 256;
 580	range->max_frag = 2346;
 581
 582	range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
 583	range->num_encoding_sizes = 4;
 584	range->encoding_size[0] = WEP1_KEY_SIZE;
 585	range->encoding_size[1] = WEP128_KEY_SIZE;
 586#if WIRELESS_EXT > 17
 587	range->encoding_size[2] = TKIP_KEY_SIZE;
 588#else
 589	range->encoding_size[2] = 0;
 590#endif
 591	range->encoding_size[3] = AES_KEY_SIZE;
 592
 593	range->min_pmp = 0;
 594	range->max_pmp = 0;
 595	range->min_pmt = 0;
 596	range->max_pmt = 0;
 597	range->pmp_flags = 0;
 598	range->pm_capa = 0;
 599
 600	range->num_txpower = 2;
 601	range->txpower[0] = 1;
 602	range->txpower[1] = 255;
 603	range->txpower_capa = IW_TXPOW_MWATT;
 604
 605#if WIRELESS_EXT > 10
 606	range->we_version_compiled = WIRELESS_EXT;
 607	range->we_version_source = 19;
 608
 609	range->retry_capa = IW_RETRY_LIMIT;
 610	range->retry_flags = IW_RETRY_LIMIT;
 611	range->r_time_flags = 0;
 612
 613	range->min_retry = 1;
 614	range->max_retry = 255;
 615
 616	range->min_r_time = 0;
 617	range->max_r_time = 0;
 618#endif 
 619
 620#if WIRELESS_EXT > 17
 621	range->enc_capa = IW_ENC_CAPA_WPA;
 622	range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
 623	range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
 624	range->enc_capa |= IW_ENC_CAPA_WPA2;
 625
 626	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
 627
 628	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
 629	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
 630	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
 631	IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
 632	IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
 633
 634#if WIRELESS_EXT >= 22 && defined(IW_SCAN_CAPA_ESSID)
 635
 636	range->scan_capa = IW_SCAN_CAPA_ESSID;
 637#endif
 638#endif 
 639
 640	return 0;
 641}
 642
 643static int
 644rssi_to_qual(int rssi)
 645{
 646	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
 647		return 0;
 648	else if (rssi <= WL_IW_RSSI_VERY_LOW)
 649		return 1;
 650	else if (rssi <= WL_IW_RSSI_LOW)
 651		return 2;
 652	else if (rssi <= WL_IW_RSSI_GOOD)
 653		return 3;
 654	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
 655		return 4;
 656	else
 657		return 5;
 658}
 659
 660static int
 661wl_iw_set_spy(
 662	struct net_device *dev,
 663	struct iw_request_info *info,
 664	struct iw_point *dwrq,
 665	char *extra
 666)
 667{
 668	wl_iw_t *iw = IW_DEV_IF(dev);
 669	struct sockaddr *addr = (struct sockaddr *) extra;
 670	int i;
 671
 672	WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
 673
 674	if (!extra)
 675		return -EINVAL;
 676
 677	iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
 678	for (i = 0; i < iw->spy_num; i++)
 679		memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
 680	memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
 681
 682	return 0;
 683}
 684
 685static int
 686wl_iw_get_spy(
 687	struct net_device *dev,
 688	struct iw_request_info *info,
 689	struct iw_point *dwrq,
 690	char *extra
 691)
 692{
 693	wl_iw_t *iw = IW_DEV_IF(dev);
 694	struct sockaddr *addr = (struct sockaddr *) extra;
 695	struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
 696	int i;
 697
 698	WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
 699
 700	if (!extra)
 701		return -EINVAL;
 702
 703	dwrq->length = iw->spy_num;
 704	for (i = 0; i < iw->spy_num; i++) {
 705		memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
 706		addr[i].sa_family = AF_UNIX;
 707		memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
 708		iw->spy_qual[i].updated = 0;
 709	}
 710
 711	return 0;
 712}
 713
 714static int
 715wl_iw_set_wap(
 716	struct net_device *dev,
 717	struct iw_request_info *info,
 718	struct sockaddr *awrq,
 719	char *extra
 720)
 721{
 722	int error = -EINVAL;
 723#ifdef BCMDBG
 724
 725#endif
 726
 727	WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
 728
 729	if (awrq->sa_family != ARPHRD_ETHER) {
 730		WL_ERROR(("%s: Invalid Header...sa_family\n", __FUNCTION__));
 731		return -EINVAL;
 732	}
 733
 734	if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
 735		scb_val_t scbval;
 736		bzero(&scbval, sizeof(scb_val_t));
 737		if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t)))) {
 738			WL_ERROR(("%s: WLC_DISASSOC failed (%d).\n", __FUNCTION__, error));
 739		}
 740		return 0;
 741	}
 742
 743	if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, awrq->sa_data, ETHER_ADDR_LEN))) {
 744		WL_ERROR(("%s: WLC_REASSOC failed (%d).\n", __FUNCTION__, error));
 745		return error;
 746	}
 747
 748	return 0;
 749}
 750
 751static int
 752wl_iw_get_wap(
 753	struct net_device *dev,
 754	struct iw_request_info *info,
 755	struct sockaddr *awrq,
 756	char *extra
 757)
 758{
 759	WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
 760
 761	awrq->sa_family = ARPHRD_ETHER;
 762	memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
 763
 764	(void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
 765
 766	return 0;
 767}
 768
 769#if WIRELESS_EXT > 17
 770static int
 771wl_iw_mlme(
 772	struct net_device *dev,
 773	struct iw_request_info *info,
 774	struct sockaddr *awrq,
 775	char *extra
 776)
 777{
 778	struct iw_mlme *mlme;
 779	scb_val_t scbval;
 780	int error  = -EINVAL;
 781
 782	WL_TRACE(("%s: SIOCSIWMLME\n", dev->name));
 783
 784	mlme = (struct iw_mlme *)extra;
 785	if (mlme == NULL) {
 786		WL_ERROR(("Invalid ioctl data.\n"));
 787		return error;
 788	}
 789
 790	scbval.val = mlme->reason_code;
 791	bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
 792
 793	if (mlme->cmd == IW_MLME_DISASSOC) {
 794		scbval.val = htod32(scbval.val);
 795		error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
 796	}
 797	else if (mlme->cmd == IW_MLME_DEAUTH) {
 798		scbval.val = htod32(scbval.val);
 799		error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
 800			sizeof(scb_val_t));
 801	}
 802	else {
 803		WL_ERROR(("%s: Invalid ioctl data.\n", __FUNCTION__));
 804		return error;
 805	}
 806
 807	return error;
 808}
 809#endif 
 810
 811static int
 812wl_iw_get_aplist(
 813	struct net_device *dev,
 814	struct iw_request_info *info,
 815	struct iw_point *dwrq,
 816	char *extra
 817)
 818{
 819	wl_scan_results_t *list;
 820	struct sockaddr *addr = (struct sockaddr *) extra;
 821	struct iw_quality qual[IW_MAX_AP];
 822	wl_bss_info_t *bi = NULL;
 823	int error, i;
 824	uint buflen = dwrq->length;
 825
 826	WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
 827
 828	if (!extra)
 829		return -EINVAL;
 830
 831	list = kmalloc(buflen, GFP_KERNEL);
 832	if (!list)
 833		return -ENOMEM;
 834	memset(list, 0, buflen);
 835	list->buflen = htod32(buflen);
 836	if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
 837		WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
 838		kfree(list);
 839		return error;
 840	}
 841	list->buflen = dtoh32(list->buflen);
 842	list->version = dtoh32(list->version);
 843	list->count = dtoh32(list->count);
 844	ASSERT(list->version == WL_BSS_INFO_VERSION);
 845
 846	for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
 847		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
 848		ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
 849			buflen));
 850
 851		if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
 852			continue;
 853
 854		memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
 855		addr[dwrq->length].sa_family = ARPHRD_ETHER;
 856		qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
 857		qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
 858		qual[dwrq->length].noise = 0x100 + bi->phy_noise;
 859
 860#if WIRELESS_EXT > 18
 861		qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 862#else
 863		qual[dwrq->length].updated = 7;
 864#endif 
 865
 866		dwrq->length++;
 867	}
 868
 869	kfree(list);
 870
 871	if (dwrq->length) {
 872		memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
 873
 874		dwrq->flags = 1;
 875	}
 876
 877	return 0;
 878}
 879
 880#if WIRELESS_EXT > 13
 881static int
 882wl_iw_set_scan(
 883	struct net_device *dev,
 884	struct iw_request_info *info,
 885	union iwreq_data *wrqu,
 886	char *extra
 887)
 888{
 889	wlc_ssid_t ssid;
 890
 891	WL_TRACE(("%s: SIOCSIWSCAN\n", dev->name));
 892
 893	memset(&ssid, 0, sizeof(ssid));
 894
 895#if WIRELESS_EXT > 17
 896
 897	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
 898		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
 899			struct iw_scan_req *req = (struct iw_scan_req *)extra;
 900			ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
 901			memcpy(ssid.SSID, req->essid, ssid.SSID_len);
 902			ssid.SSID_len = htod32(ssid.SSID_len);
 903		}
 904	}
 905#endif
 906
 907	(void) dev_wlc_ioctl(dev, WLC_SCAN, &ssid, sizeof(ssid));
 908
 909	return 0;
 910}
 911
 912#if WIRELESS_EXT > 17
 913static bool
 914ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
 915{
 916
 917	uint8 *ie = *wpaie;
 918
 919	if ((ie[1] >= 6) &&
 920		!bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
 921		return TRUE;
 922	}
 923
 924	ie += ie[1] + 2;
 925
 926	*tlvs_len -= (int)(ie - *tlvs);
 927
 928	*tlvs = ie;
 929	return FALSE;
 930}
 931
 932static bool
 933ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
 934{
 935
 936	uint8 *ie = *wpsie;
 937
 938	if ((ie[1] >= 4) &&
 939		!bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
 940		return TRUE;
 941	}
 942
 943	ie += ie[1] + 2;
 944
 945	*tlvs_len -= (int)(ie - *tlvs);
 946
 947	*tlvs = ie;
 948	return FALSE;
 949}
 950#endif 
 951
 952static int
 953wl_iw_handle_scanresults_ies(char **event_p, char *end,
 954	struct iw_request_info *info, wl_bss_info_t *bi)
 955{
 956#if WIRELESS_EXT > 17
 957	struct iw_event	iwe;
 958	char *event;
 959
 960	event = *event_p;
 961	if (bi->ie_length) {
 962
 963		bcm_tlv_t *ie;
 964		uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 965		int ptr_len = bi->ie_length;
 966
 967		if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
 968			iwe.cmd = IWEVGENIE;
 969			iwe.u.data.length = ie->len + 2;
 970			event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
 971		}
 972		ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 973
 974		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
 975
 976			if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
 977				iwe.cmd = IWEVGENIE;
 978				iwe.u.data.length = ie->len + 2;
 979				event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
 980				break;
 981			}
 982		}
 983
 984		ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
 985		ptr_len = bi->ie_length;
 986		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
 987			if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
 988				iwe.cmd = IWEVGENIE;
 989				iwe.u.data.length = ie->len + 2;
 990				event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
 991				break;
 992			}
 993		}
 994
 995	*event_p = event;
 996	}
 997
 998#endif 
 999	return 0;
1000}
1001static int
1002wl_iw_get_scan(
1003	struct net_device *dev,
1004	struct iw_request_info *info,
1005	struct iw_point *dwrq,
1006	char *extra
1007)
1008{
1009	channel_info_t ci;
1010	wl_scan_results_t *list;
1011	struct iw_event	iwe;
1012	wl_bss_info_t *bi = NULL;
1013	int error, i, j;
1014	char *event = extra, *end = extra + IW_SCAN_MAX_DATA, *value;
1015	uint buflen = dwrq->length;
1016
1017	WL_TRACE(("%s: SIOCGIWSCAN\n", dev->name));
1018
1019	if (!extra)
1020		return -EINVAL;
1021
1022	if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
1023		return error;
1024	ci.scan_channel = dtoh32(ci.scan_channel);
1025	if (ci.scan_channel)
1026		return -EAGAIN;
1027
1028	list = kmalloc(buflen, GFP_KERNEL);
1029	if (!list)
1030		return -ENOMEM;
1031	memset(list, 0, buflen);
1032	list->buflen = htod32(buflen);
1033	if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
1034		kfree(list);
1035		return error;
1036	}
1037	list->buflen = dtoh32(list->buflen);
1038	list->version = dtoh32(list->version);
1039	list->count = dtoh32(list->count);
1040
1041	ASSERT(list->version == WL_BSS_INFO_VERSION);
1042
1043	for (i = 0; i < list->count && i < IW_MAX_AP; i++) {
1044		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
1045		ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
1046			buflen));
1047
1048		iwe.cmd = SIOCGIWAP;
1049		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
1050		memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
1051		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
1052
1053		iwe.u.data.length = dtoh32(bi->SSID_len);
1054		iwe.cmd = SIOCGIWESSID;
1055		iwe.u.data.flags = 1;
1056		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
1057
1058		if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
1059			iwe.cmd = SIOCGIWMODE;
1060			if (dtoh16(bi->capability) & DOT11_CAP_ESS)
1061				iwe.u.mode = IW_MODE_INFRA;
1062			else
1063				iwe.u.mode = IW_MODE_ADHOC;
1064			event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
1065		}
1066
1067		iwe.cmd = SIOCGIWFREQ;
1068		iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
1069			CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
1070			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
1071		iwe.u.freq.e = 6;
1072		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
1073
1074		iwe.cmd = IWEVQUAL;
1075		iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
1076		iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
1077		iwe.u.qual.noise = 0x100 + bi->phy_noise;
1078		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
1079
1080		 wl_iw_handle_scanresults_ies(&event, end, info, bi);
1081
1082		iwe.cmd = SIOCGIWENCODE;
1083		if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
1084			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
1085		else
1086			iwe.u.data.flags = IW_ENCODE_DISABLED;
1087		iwe.u.data.length = 0;
1088		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
1089
1090		if (bi->rateset.count) {
1091			value = event + IW_EV_LCP_LEN;
1092			iwe.cmd = SIOCGIWRATE;
1093
1094			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
1095			for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
1096				iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
1097				value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
1098					IW_EV_PARAM_LEN);
1099			}
1100			event = value;
1101		}
1102	}
1103
1104	kfree(list);
1105
1106	dwrq->length = event - extra;
1107	dwrq->flags = 0;	
1108
1109	return 0;
1110}
1111
1112#endif 
1113
1114static int
1115wl_iw_set_essid(
1116	struct net_device *dev,
1117	struct iw_request_info *info,
1118	struct iw_point *dwrq,
1119	char *extra
1120)
1121{
1122	wlc_ssid_t ssid;
1123	int error;
1124
1125	WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
1126
1127	memset(&ssid, 0, sizeof(ssid));
1128	if (dwrq->length && extra) {
1129#if WIRELESS_EXT > 20
1130		ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length);
1131#else
1132		ssid.SSID_len = MIN(sizeof(ssid.SSID), dwrq->length-1);
1133#endif
1134		memcpy(ssid.SSID, extra, ssid.SSID_len);
1135		ssid.SSID_len = htod32(ssid.SSID_len);
1136
1137		if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &ssid, sizeof(ssid))))
1138			return error;
1139	}
1140
1141	else {
1142		scb_val_t scbval;
1143		bzero(&scbval, sizeof(scb_val_t));
1144		if ((error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t))))
1145			return error;
1146	}
1147	return 0;
1148}
1149
1150static int
1151wl_iw_get_essid(
1152	struct net_device *dev,
1153	struct iw_request_info *info,
1154	struct iw_point *dwrq,
1155	char *extra
1156)
1157{
1158	wlc_ssid_t ssid;
1159	int error;
1160
1161	WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
1162
1163	if (!extra)
1164		return -EINVAL;
1165
1166	if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
1167		WL_ERROR(("Error getting the SSID\n"));
1168		return error;
1169	}
1170
1171	ssid.SSID_len = dtoh32(ssid.SSID_len);
1172
1173	memcpy(extra, ssid.SSID, ssid.SSID_len);
1174
1175	dwrq->length = ssid.SSID_len;
1176
1177	dwrq->flags = 1; 
1178
1179	return 0;
1180}
1181
1182static int
1183wl_iw_set_nick(
1184	struct net_device *dev,
1185	struct iw_request_info *info,
1186	struct iw_point *dwrq,
1187	char *extra
1188)
1189{
1190	wl_iw_t *iw = IW_DEV_IF(dev);
1191	WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
1192
1193	if (!extra)
1194		return -EINVAL;
1195
1196	if (dwrq->length > sizeof(iw->nickname))
1197		return -E2BIG;
1198
1199	memcpy(iw->nickname, extra, dwrq->length);
1200	iw->nickname[dwrq->length - 1] = '\0';
1201
1202	return 0;
1203}
1204
1205static int
1206wl_iw_get_nick(
1207	struct net_device *dev,
1208	struct iw_request_info *info,
1209	struct iw_point *dwrq,
1210	char *extra
1211)
1212{
1213	wl_iw_t *iw = IW_DEV_IF(dev);
1214	WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
1215
1216	if (!extra)
1217		return -EINVAL;
1218
1219	strcpy(extra, iw->nickname);
1220	dwrq->length = strlen(extra) + 1;
1221
1222	return 0;
1223}
1224
1225static int wl_iw_set_rate(
1226	struct net_device *dev,
1227	struct iw_request_info *info,
1228	struct iw_param *vwrq,
1229	char *extra
1230)
1231{
1232	wl_rateset_t rateset;
1233	int error, rate, i, error_bg, error_a;
1234
1235	WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
1236
1237	if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
1238		return error;
1239
1240	rateset.count = dtoh32(rateset.count);
1241
1242	if (vwrq->value < 0) {
1243
1244		rate = rateset.rates[rateset.count - 1] & 0x7f;
1245	} else if (vwrq->value < rateset.count) {
1246
1247		rate = rateset.rates[vwrq->value] & 0x7f;
1248	} else {
1249
1250		rate = vwrq->value / 500000;
1251	}
1252
1253	if (vwrq->fixed) {
1254
1255		error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
1256		error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
1257
1258		if (error_bg && error_a)
1259			return (error_bg | error_a);
1260	} else {
1261
1262		error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
1263
1264		error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
1265
1266		if (error_bg && error_a)
1267			return (error_bg | error_a);
1268
1269		for (i = 0; i < rateset.count; i++)
1270			if ((rateset.rates[i] & 0x7f) > rate)
1271				break;
1272		rateset.count = htod32(i);
1273
1274		if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
1275			return error;
1276	}
1277
1278	return 0;
1279}
1280
1281static int wl_iw_get_rate(
1282	struct net_device *dev,
1283	struct iw_request_info *info,
1284	struct iw_param *vwrq,
1285	char *extra
1286)
1287{
1288	int error, rate;
1289
1290	WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
1291
1292	if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
1293		return error;
1294	rate = dtoh32(rate);
1295	vwrq->value = rate * 500000;
1296
1297	return 0;
1298}
1299
1300static int
1301wl_iw_set_rts(
1302	struct net_device *dev,
1303	struct iw_request_info *info,
1304	struct iw_param *vwrq,
1305	char *extra
1306)
1307{
1308	int error, rts;
1309
1310	WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
1311
1312	if (vwrq->disabled)
1313		rts = DOT11_DEFAULT_RTS_LEN;
1314	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
1315		return -EINVAL;
1316	else
1317		rts = vwrq->value;
1318
1319	if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
1320		return error;
1321
1322	return 0;
1323}
1324
1325static int
1326wl_iw_get_rts(
1327	struct net_device *dev,
1328	struct iw_request_info *info,
1329	struct iw_param *vwrq,
1330	char *extra
1331)
1332{
1333	int error, rts;
1334
1335	WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
1336
1337	if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
1338		return error;
1339
1340	vwrq->value = rts;
1341	vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
1342	vwrq->fixed = 1;
1343
1344	return 0;
1345}
1346
1347static int
1348wl_iw_set_frag(
1349	struct net_device *dev,
1350	struct iw_request_info *info,
1351	struct iw_param *vwrq,
1352	char *extra
1353)
1354{
1355	int error, frag;
1356
1357	WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
1358
1359	if (vwrq->disabled)
1360		frag = DOT11_DEFAULT_FRAG_LEN;
1361	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
1362		return -EINVAL;
1363	else
1364		frag = vwrq->value;
1365
1366	if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
1367		return error;
1368
1369	return 0;
1370}
1371
1372static int
1373wl_iw_get_frag(
1374	struct net_device *dev,
1375	struct iw_request_info *info,
1376	struct iw_param *vwrq,
1377	char *extra
1378)
1379{
1380	int error, fragthreshold;
1381
1382	WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
1383
1384	if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
1385		return error;
1386
1387	vwrq->value = fragthreshold;
1388	vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
1389	vwrq->fixed = 1;
1390
1391	return 0;
1392}
1393
1394static int
1395wl_iw_set_txpow(
1396	struct net_device *dev,
1397	struct iw_request_info *info,
1398	struct iw_param *vwrq,
1399	char *extra
1400)
1401{
1402	int error, disable;
1403	uint16 txpwrmw;
1404	WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
1405
1406	disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
1407	disable += WL_RADIO_SW_DISABLE << 16;
1408
1409	disable = htod32(disable);
1410	if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
1411		return error;
1412
1413	if (disable & WL_RADIO_SW_DISABLE)
1414		return 0;
1415
1416	if (!(vwrq->flags & IW_TXPOW_MWATT))
1417		return -EINVAL;
1418
1419	if (vwrq->value < 0)
1420		return 0;
1421
1422	if (vwrq->value > 0xffff) txpwrmw = 0xffff;
1423	else txpwrmw = (uint16)vwrq->value;
1424
1425	error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
1426	return error;
1427}
1428
1429static int
1430wl_iw_get_txpow(
1431	struct net_device *dev,
1432	struct iw_request_info *info,
1433	struct iw_param *vwrq,
1434	char *extra
1435)
1436{
1437	int error, disable, txpwrdbm;
1438	uint8 result;
1439
1440	WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
1441
1442	if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
1443	    (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
1444		return error;
1445
1446	disable = dtoh32(disable);
1447	result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
1448	vwrq->value = (int32)bcm_qdbm_to_mw(result);
1449	vwrq->fixed = 0;
1450	vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
1451	vwrq->flags = IW_TXPOW_MWATT;
1452
1453	return 0;
1454}
1455
1456#if WIRELESS_EXT > 10
1457static int
1458wl_iw_set_retry(
1459	struct net_device *dev,
1460	struct iw_request_info *info,
1461	struct iw_param *vwrq,
1462	char *extra
1463)
1464{
1465	int error, lrl, srl;
1466
1467	WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
1468
1469	if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
1470		return -EINVAL;
1471
1472	if (vwrq->flags & IW_RETRY_LIMIT) {
1473
1474#if WIRELESS_EXT > 20
1475		if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
1476			!((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
1477#else
1478		if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
1479#endif 
1480
1481			lrl = htod32(vwrq->value);
1482			if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
1483				return error;
1484		}
1485
1486#if WIRELESS_EXT > 20
1487		if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
1488			!((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
1489#else
1490		if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
1491#endif 
1492
1493			srl = htod32(vwrq->value);
1494			if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
1495				return error;
1496		}
1497	}
1498
1499	return 0;
1500}
1501
1502static int
1503wl_iw_get_retry(
1504	struct net_device *dev,
1505	struct iw_request_info *info,
1506	struct iw_param *vwrq,
1507	char *extra
1508)
1509{
1510	int error, lrl, srl;
1511
1512	WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
1513
1514	vwrq->disabled = 0;      
1515
1516	if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
1517		return -EINVAL;
1518
1519	if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
1520	    (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
1521		return error;
1522
1523	lrl = dtoh32(lrl);
1524	srl = dtoh32(srl);
1525
1526	if (vwrq->flags & IW_RETRY_MAX) {
1527		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
1528		vwrq->value = lrl;
1529	} else {
1530		vwrq->flags = IW_RETRY_LIMIT;
1531		vwrq->value = srl;
1532		if (srl != lrl)
1533			vwrq->flags |= IW_RETRY_MIN;
1534	}
1535
1536	return 0;
1537}
1538#endif 
1539
1540static int
1541wl_iw_set_encode(
1542	struct net_device *dev,
1543	struct iw_request_info *info,
1544	struct iw_point *dwrq,
1545	char *extra
1546)
1547{
1548	wl_wsec_key_t key;
1549	int error, val, wsec;
1550
1551	WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
1552
1553	memset(&key, 0, sizeof(key));
1554
1555	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
1556
1557		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
1558			val = htod32(key.index);
1559			if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
1560				return error;
1561			val = dtoh32(val);
1562			if (val)
1563				break;
1564		}
1565
1566		if (key.index == DOT11_MAX_DEFAULT_KEYS)
1567			key.index = 0;
1568	} else {
1569		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1570		if (key.index >= DOT11_MAX_DEFAULT_KEYS)
1571			return -EINVAL;
1572	}
1573
1574	wsec = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
1575
1576	if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
1577		return error;
1578
1579	if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
1580
1581		val = htod32(key.index);
1582		if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
1583			return error;
1584	} else {
1585		key.len = dwrq->length;
1586
1587		if (dwrq->length > sizeof(key.data))
1588			return -EINVAL;
1589
1590		memcpy(key.data, extra, dwrq->length);
1591
1592		key.flags = WL_PRIMARY_KEY;
1593		switch (key.len) {
1594		case WEP1_KEY_SIZE:
1595			key.algo = CRYPTO_ALGO_WEP1;
1596			break;
1597		case WEP128_KEY_SIZE:
1598			key.algo = CRYPTO_ALGO_WEP128;
1599			break;
1600#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
1601		case TKIP_KEY_SIZE:
1602			key.algo = CRYPTO_ALGO_TKIP;
1603			break;
1604#endif
1605		case AES_KEY_SIZE:
1606			key.algo = CRYPTO_ALGO_AES_CCM;
1607			break;
1608		default:
1609			return -EINVAL;
1610		}
1611
1612		swap_key_from_BE(&key);
1613		if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
1614			return error;
1615	}
1616
1617	val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
1618	val = htod32(val);
1619	if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
1620		return error;
1621
1622	return 0;
1623}
1624
1625static int
1626wl_iw_get_encode(
1627	struct net_device *dev,
1628	struct iw_request_info *info,
1629	struct iw_point *dwrq,
1630	char *extra
1631)
1632{
1633	wl_wsec_key_t key;
1634	int error, val, wsec, auth;
1635
1636	WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
1637
1638	bzero(&key, sizeof(wl_wsec_key_t));
1639
1640	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
1641
1642		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
1643			val = key.index;
1644			if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
1645				return error;
1646			val = dtoh32(val);
1647			if (val)
1648				break;
1649		}
1650	} else
1651		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1652
1653	if (key.index >= DOT11_MAX_DEFAULT_KEYS)
1654		key.index = 0;
1655
1656	if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
1657	    (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
1658		return error;
1659
1660	swap_key_to_BE(&key);
1661
1662	wsec = dtoh32(wsec);
1663	auth = dtoh32(auth);
1664
1665	dwrq->length = MIN(IW_ENCODING_TOKEN_MAX, key.len);
1666
1667	dwrq->flags = key.index + 1;
1668	if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
1669
1670		dwrq->flags |= IW_ENCODE_DISABLED;
1671	}
1672	if (auth) {
1673
1674		dwrq->flags |= IW_ENCODE_RESTRICTED;
1675	}
1676
1677	if (dwrq->length && extra)
1678		memcpy(extra, key.data, dwrq->length);
1679
1680	return 0;
1681}
1682
1683static int
1684wl_iw_set_power(
1685	struct net_device *dev,
1686	struct iw_request_info *info,
1687	struct iw_param *vwrq,
1688	char *extra
1689)
1690{
1691	int error, pm;
1692
1693	WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
1694
1695	pm = vwrq->disabled ? PM_OFF : PM_MAX;
1696
1697	pm = htod32(pm);
1698	if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
1699		return error;
1700
1701	return 0;
1702}
1703
1704static int
1705wl_iw_get_power(
1706	struct net_device *dev,
1707	struct iw_request_info *info,
1708	struct iw_param *vwrq,
1709	char *extra
1710)
1711{
1712	int error, pm;
1713
1714	WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
1715
1716	if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
1717		return error;
1718
1719	pm = dtoh32(pm);
1720	vwrq->disabled = pm ? 0 : 1;
1721	vwrq->flags = IW_POWER_ALL_R;
1722
1723	return 0;
1724}
1725
1726#if WIRELESS_EXT > 17
1727static int
1728wl_iw_set_wpaie(
1729	struct net_device *dev,
1730	struct iw_request_info *info,
1731	struct iw_point *iwp,
1732	char *extra
1733)
1734{
1735		dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
1736
1737	return 0;
1738}
1739
1740static int
1741wl_iw_get_wpaie(
1742	struct net_device *dev,
1743	struct iw_request_info *info,
1744	struct iw_point *iwp,
1745	char *extra
1746)
1747{
1748	WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
1749	iwp->length = 64;
1750	dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
1751	return 0;
1752}
1753
1754static int
1755wl_iw_set_encodeext(
1756	struct net_device *dev,
1757	struct iw_request_info *info,
1758	struct iw_point *dwrq,
1759	char *extra
1760)
1761{
1762	wl_wsec_key_t key;
1763	int error;
1764	struct iw_encode_ext *iwe;
1765
1766	WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
1767
1768	memset(&key, 0, sizeof(key));
1769	iwe = (struct iw_encode_ext *)extra;
1770
1771	if (dwrq->flags & IW_ENCODE_DISABLED) {
1772
1773	}
1774
1775	key.index = 0;
1776	if (dwrq->flags & IW_ENCODE_INDEX)
1777		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
1778
1779	key.len = iwe->key_len;
1780
1781	if (!ETHER_ISMULTI(iwe->addr.sa_data))
1782		bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
1783
1784	if (key.len == 0) {
1785		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1786			WL_WSEC(("Changing the the primary Key to %d\n", key.index));
1787
1788			key.index = htod32(key.index);
1789			error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
1790				&key.index, sizeof(key.index));
1791			if (error)
1792				return error;
1793		}
1794
1795		else {
1796			swap_key_from_BE(&key);
1797			dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1798		}
1799	}
1800	else {
1801		if (iwe->key_len > sizeof(key.data))
1802			return -EINVAL;
1803
1804		WL_WSEC(("Setting the key index %d\n", key.index));
1805		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
1806			WL_WSEC(("key is a Primary Key\n"));
1807			key.flags = WL_PRIMARY_KEY;
1808		}
1809
1810		bcopy((void *)iwe->key, key.data, iwe->key_len);
1811
1812		if (iwe->alg == IW_ENCODE_ALG_TKIP) {
1813			uint8 keybuf[8];
1814			bcopy(&key.data[24], keybuf, sizeof(keybuf));
1815			bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
1816			bcopy(keybuf, &key.data[16], sizeof(keybuf));
1817		}
1818
1819		if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
1820			uchar *ivptr;
1821			ivptr = (uchar *)iwe->rx_seq;
1822			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
1823				(ivptr[3] << 8) | ivptr[2];
1824			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
1825			key.iv_initialized = TRUE;
1826		}
1827
1828		switch (iwe->alg) {
1829			case IW_ENCODE_ALG_NONE:
1830				key.algo = CRYPTO_ALGO_OFF;
1831				break;
1832			case IW_ENCODE_ALG_WEP:
1833				if (iwe->key_len == WEP1_KEY_SIZE)
1834					key.algo = CRYPTO_ALGO_WEP1;
1835				else
1836					key.algo = CRYPTO_ALGO_WEP128;
1837				break;
1838			case IW_ENCODE_ALG_TKIP:
1839				key.algo = CRYPTO_ALGO_TKIP;
1840				break;
1841			case IW_ENCODE_ALG_CCMP:
1842				key.algo = CRYPTO_ALGO_AES_CCM;
1843				break;
1844			default:
1845				break;
1846		}
1847		swap_key_from_BE(&key);
1848
1849		error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
1850		if (error)
1851			return error;
1852	}
1853	return 0;
1854}
1855#if WIRELESS_EXT > 17
1856struct {
1857	pmkid_list_t pmkids;
1858	pmkid_t foo[MAXPMKID-1];
1859} pmkid_list;
1860static int
1861wl_iw_set_pmksa(
1862	struct net_device *dev,
1863	struct iw_request_info *info,
1864	struct iw_param *vwrq,
1865	char *extra
1866)
1867{
1868	struct iw_pmksa *iwpmksa;
1869	uint i;
1870	char eabuf[ETHER_ADDR_STR_LEN];
1871	WL_TRACE(("%s: SIOCSIWPMKSA\n", dev->name));
1872	iwpmksa = (struct iw_pmksa *)extra;
1873	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
1874	if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
1875		WL_TRACE(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
1876		bzero((char *)&pmkid_list, sizeof(pmkid_list));
1877	}
1878	if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
1879		pmkid_list_t pmkid, *pmkidptr;
1880		pmkidptr = &pmkid;
1881		bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
1882		bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
1883		{
1884			uint j;
1885			WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
1886				bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
1887				eabuf)));
1888			for (j = 0; j < WPA2_PMKID_LEN; j++)
1889				WL_TRACE(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
1890			WL_TRACE(("\n"));
1891		}
1892		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
1893			if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
1894				ETHER_ADDR_LEN))
1895				break;
1896		for (; i < pmkid_list.pmkids.npmkid; i++) {
1897			bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
1898				&pmkid_list.pmkids.pmkid[i].BSSID,
1899				ETHER_ADDR_LEN);
1900			bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
1901				&pmkid_list.pmkids.pmkid[i].PMKID,
1902				WPA2_PMKID_LEN);
1903		}
1904		pmkid_list.pmkids.npmkid--;
1905	}
1906	if (iwpmksa->cmd == IW_PMKSA_ADD) {
1907		bcopy(&iwpmksa->bssid.sa_data[0],
1908			&pmkid_list.pmkids.pmkid[pmkid_list.pmkids.npmkid].BSSID,
1909			ETHER_ADDR_LEN);
1910		bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[pmkid_list.pmkids.npmkid].PMKID,
1911			WPA2_PMKID_LEN);
1912		{
1913			uint j;
1914			uint k;
1915			k = pmkid_list.pmkids.npmkid;
1916			WL_TRACE(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
1917				bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
1918				eabuf)));
1919			for (j = 0; j < WPA2_PMKID_LEN; j++)
1920				WL_TRACE(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
1921			WL_TRACE(("\n"));
1922		}
1923		pmkid_list.pmkids.npmkid++;
1924	}
1925	WL_TRACE(("PRINTING pmkid LIST - No of elements %d\n", pmkid_list.pmkids.npmkid));
1926	for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
1927		uint j;
1928		WL_TRACE(("PMKID[%d]: %s = ", i,
1929			bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
1930			eabuf)));
1931		for (j = 0; j < WPA2_PMKID_LEN; j++)
1932			WL_TRACE(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
1933		printf("\n");
1934	}
1935	WL_TRACE(("\n"));
1936	dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
1937	return 0;
1938}
1939#endif 
1940
1941static int
1942wl_iw_get_encodeext(
1943	struct net_device *dev,
1944	struct iw_request_info *info,
1945	struct iw_param *vwrq,
1946	char *extra
1947)
1948{
1949	WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
1950	return 0;
1951}
1952
1953static int
1954wl_iw_set_wpaauth(
1955	struct net_device *dev,
1956	struct iw_request_info *info,
1957	struct iw_param *vwrq,
1958	char *extra
1959)
1960{
1961	int error = 0;
1962	int paramid;
1963	int paramval;
1964	uint32 cipher_combined;
1965	int val = 0;
1966	wl_iw_t *iw = IW_DEV_IF(dev);
1967
1968	WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name));
1969
1970	paramid = vwrq->flags & IW_AUTH_INDEX;
1971	paramval = vwrq->value;
1972
1973	WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
1974		dev->name, paramid, paramval));
1975
1976	switch (paramid) {
1977
1978	case IW_AUTH_WPA_VERSION:
1979
1980		if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
1981			val = WPA_AUTH_DISABLED;
1982		else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
1983			val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
1984		else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
1985			val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
1986		WL_TRACE(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
1987		if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
1988			return error;
1989		break;
1990
1991	case IW_AUTH_CIPHER_PAIRWISE:
1992	case IW_AUTH_CIPHER_GROUP:
1993
1994		if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
1995			iw->pwsec = paramval;
1996		}
1997		else {
1998			iw->gwsec = paramval;
1999		}
2000
2001		if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
2002			return error;
2003
2004		cipher_combined = iw->gwsec | iw->pwsec;
2005		val &= ~(WEP_ENABLED | TKIP_ENABLED | AES_ENABLED);
2006		if (cipher_combined & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
2007			val |= WEP_ENABLED;
2008		if (cipher_combined & IW_AUTH_CIPHER_TKIP)
2009			val |= TKIP_ENABLED;
2010		if (cipher_combined & IW_AUTH_CIPHER_CCMP)
2011			val |= AES_ENABLED;
2012
2013		if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
2014			return error;
2015		break;
2016
2017	case IW_AUTH_KEY_MGMT:
2018		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
2019			return error;
2020
2021		if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
2022			if (paramval & IW_AUTH_KEY_MGMT_PSK)
2023				val = WPA_AUTH_PSK;
2024			else
2025				val = WPA_AUTH_UNSPECIFIED;
2026		}
2027		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
2028			if (paramval & IW_AUTH_KEY_MGMT_PSK)
2029				val = WPA2_AUTH_PSK;
2030			else
2031				val = WPA2_AUTH_UNSPECIFIED;
2032		}
2033		WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
2034		if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
2035			return error;
2036		break;
2037
2038	case IW_AUTH_TKIP_COUNTERMEASURES:
2039		dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
2040		break;
2041
2042	case IW_AUTH_80211_AUTH_ALG:
2043
2044		WL_ERROR(("Setting the D11auth %d\n", paramval));
2045		if (paramval & IW_AUTH_ALG_OPEN_SYSTEM)
2046			val = 0;
2047		else if (paramval & IW_AUTH_ALG_SHARED_KEY)
2048			val = 1;
2049		else
2050			error = 1;
2051		if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
2052			return error;
2053		break;
2054
2055	case IW_AUTH_WPA_ENABLED:
2056		if (paramval == 0) {
2057			val = 0;
2058			WL_TRACE(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
2059			error = dev_wlc_intvar_set(dev, "wpa_auth", val);
2060			return error;
2061		}
2062		else {
2063
2064		}
2065		break;
2066
2067	case IW_AUTH_DROP_UNENCRYPTED:
2068		dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
2069		break;
2070
2071	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2072		dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
2073		break;
2074
2075#if WIRELESS_EXT > 17
2076
2077	case IW_AUTH_ROAMING_CONTROL:
2078		WL_TRACE(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
2079
2080		break;
2081
2082	case IW_AUTH_PRIVACY_INVOKED:
2083		WL_TRACE(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__));
2084		break;
2085#endif 
2086
2087	default:
2088		break;
2089	}
2090	return 0;
2091}
2092#define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
2093
2094static int
2095wl_iw_get_wpaauth(
2096	struct net_device *dev,
2097	struct iw_request_info *info,
2098	struct iw_param *vwrq,
2099	char *extra
2100)
2101{
2102	int error;
2103	int paramid;
2104	int paramval = 0;
2105	int val;
2106	wl_iw_t *iw = IW_DEV_IF(dev);
2107
2108	WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
2109
2110	paramid = vwrq->flags & IW_AUTH_INDEX;
2111
2112	switch (paramid) {
2113	case IW_AUTH_WPA_VERSION:
2114
2115		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
2116			return error;
2117		if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
2118			paramval = IW_AUTH_WPA_VERSION_DISABLED;
2119		else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
2120			paramval = IW_AUTH_WPA_VERSION_WPA;
2121		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
2122			paramval = IW_AUTH_WPA_VERSION_WPA2;
2123		break;
2124
2125	case IW_AUTH_CIPHER_PAIRWISE:
2126		paramval = iw->pwsec;
2127		break;
2128
2129	case IW_AUTH_CIPHER_GROUP:
2130		paramval = iw->gwsec;
2131		break;
2132
2133	case IW_AUTH_KEY_MGMT:
2134
2135		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
2136			return error;
2137		if (VAL_PSK(val))
2138			paramval = IW_AUTH_KEY_MGMT_PSK;
2139		else
2140			paramval = IW_AUTH_KEY_MGMT_802_1X;
2141
2142		break;
2143	case IW_AUTH_TKIP_COUNTERMEASURES:
2144		dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
2145		break;
2146
2147	case IW_AUTH_DROP_UNENCRYPTED:
2148		dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
2149		break;
2150
2151	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
2152		dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
2153		break;
2154
2155	case IW_AUTH_80211_AUTH_ALG:
2156
2157		if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
2158			return error;
2159		if (!val)
2160			paramval = IW_AUTH_ALG_OPEN_SYSTEM;
2161		else
2162			paramval = IW_AUTH_ALG_SHARED_KEY;
2163		break;
2164	case IW_AUTH_WPA_ENABLED:
2165		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
2166			return error;
2167		if (val)
2168			paramval = TRUE;
2169		else
2170			paramval = FALSE;
2171		break;
2172#if WIRELESS_EXT > 17
2173	case IW_AUTH_ROAMING_CONTROL:
2174		WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
2175
2176		break;
2177	case IW_AUTH_PRIVACY_INVOKED:
2178		WL_ERROR(("%s: IW_AUTH_PRIVACY_INVOKED\n", __FUNCTION__));
2179		break;
2180#endif 
2181	}
2182	vwrq->value = paramval;
2183	return 0;
2184}
2185#endif 
2186
2187static const iw_handler wl_iw_handler[] =
2188{
2189	(iw_handler) wl_iw_config_commit,	
2190	(iw_handler) wl_iw_get_name,		
2191	(iw_handler) NULL,			
2192	(iw_handler) NULL,			
2193	(iw_handler) wl_iw_set_freq,		
2194	(iw_handler) wl_iw_get_freq,		
2195	(iw_handler) wl_iw_set_mode,		
2196	(iw_handler) wl_iw_get_mode,		
2197	(iw_handler) NULL,			
2198	(iw_handler) NULL,			
2199	(iw_handler) NULL,			
2200	(iw_handler) wl_iw_get_range,		
2201	(iw_handler) NULL,			
2202	(iw_handler) NULL,			
2203	(iw_handler) NULL,			
2204	(iw_handler) NULL,			
2205	(iw_handler) wl_iw_set_spy,		
2206	(iw_handler) wl_iw_get_spy,		
2207	(iw_handler) NULL,			
2208	(iw_handler) NULL,			
2209	(iw_handler) wl_iw_set_wap,		
2210	(iw_handler) wl_iw_get_wap,		
2211#if WIRELESS_EXT > 17
2212	(iw_handler) wl_iw_mlme,		
2213#else
2214	(iw_handler) NULL,			
2215#endif
2216	(iw_handler) wl_iw_get_aplist,		
2217#if WIRELESS_EXT > 13
2218	(iw_handler) wl_iw_set_scan,		
2219	(iw_handler) wl_iw_get_scan,		
2220#else	
2221	(iw_handler) NULL,			
2222	(iw_handler) NULL,			
2223#endif	
2224	(iw_handler) wl_iw_set_essid,		
2225	(iw_handler) wl_iw_get_essid,		
2226	(iw_handler) wl_iw_set_nick,		
2227	(iw_handler) wl_iw_get_nick,		
2228	(iw_handler) NULL,			
2229	(iw_handler) NULL,			
2230	(iw_handler) wl_iw_set_rate,		
2231	(iw_handler) wl_iw_get_rate,		
2232	(iw_handler) wl_iw_set_rts,		
2233	(iw_handler) wl_iw_get_rts,		
2234	(iw_handler) wl_iw_set_frag,		
2235	(iw_handler) wl_iw_get_frag,		
2236	(iw_handler) wl_iw_set_txpow,		
2237	(iw_handler) wl_iw_get_txpow,		
2238#if WIRELESS_EXT > 10
2239	(iw_handler) wl_iw_set_retry,		
2240	(iw_handler) wl_iw_get_retry,		
2241#endif 
2242	(iw_handler) wl_iw_set_encode,		
2243	(iw_handler) wl_iw_get_encode,		
2244	(iw_handler) wl_iw_set_power,		
2245	(iw_handler) wl_iw_get_power,		
2246#if WIRELESS_EXT > 17
2247	(iw_handler) NULL,			
2248	(iw_handler) NULL,			
2249	(iw_handler) wl_iw_set_wpaie,		
2250	(iw_handler) wl_iw_get_wpaie,		
2251	(iw_handler) wl_iw_set_wpaauth,		
2252	(iw_handler) wl_iw_get_wpaauth,		
2253	(iw_handler) wl_iw_set_encodeext,	
2254	(iw_handler) wl_iw_get_encodeext,	
2255	(iw_handler) wl_iw_set_pmksa,		
2256#endif 
2257};
2258
2259#if WIRELESS_EXT > 12
2260enum {
2261	WL_IW_SET_LEDDC = SIOCIWFIRSTPRIV,
2262	WL_IW_SET_VLANMODE,
2263	WL_IW_SET_PM
2264};
2265
2266static iw_handler wl_iw_priv_handler[] = {
2267	wl_iw_set_leddc,
2268	wl_iw_set_vlanmode,
2269	wl_iw_set_pm
2270};
2271
2272static struct iw_priv_args wl_iw_priv_args[] = {
2273	{
2274		WL_IW_SET_LEDDC,
2275		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2276		0,
2277		"set_leddc"
2278	},
2279	{
2280		WL_IW_SET_VLANMODE,
2281		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
2282		0,
2283		"set_vlanmode"
2284	},
2285	{
2286		WL_IW_SET_PM,
2287		IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED

Large files files are truncated, but you can click here to view the full file