Home | History | Annotate | Download | only in sys
      1 /*
      2  * Linux Wireless Extensions support
      3  *
      4  * Copyright (C) 1999-2010, Broadcom Corporation
      5  *
      6  *      Unless you and Broadcom execute a separate written software license
      7  * agreement governing use of this software, this software is licensed to you
      8  * under the terms of the GNU General Public License version 2 (the "GPL"),
      9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
     10  * following added to such license:
     11  *
     12  *      As a special exception, the copyright holders of this software give you
     13  * permission to link this software with independent modules, and to copy and
     14  * distribute the resulting executable under terms of your choice, provided that
     15  * you also meet, for each linked independent module, the terms and conditions of
     16  * the license of that module.  An independent module is a module which is not
     17  * derived from this software.  The special exception does not apply to any
     18  * modifications of the software.
     19  *
     20  *      Notwithstanding the above, under no circumstances may you combine this
     21  * software in any way with any other Broadcom software provided under a license
     22  * other than the GPL, without Broadcom's express prior written consent.
     23  *
     24  * $Id: wl_iw.c,v 1.51.4.9.2.6.4.142.4.13 2010/09/15 03:34:56 Exp $
     25  */
     26 
     27 
     28 #include <typedefs.h>
     29 #include <linuxver.h>
     30 #include <osl.h>
     31 
     32 #include <bcmutils.h>
     33 #include <bcmendian.h>
     34 #include <proto/ethernet.h>
     35 
     36 #include <linux/if_arp.h>
     37 #include <asm/uaccess.h>
     38 
     39 #include <dngl_stats.h>
     40 #include <dhd.h>
     41 #include <dhdioctl.h>
     42 
     43 typedef void wlc_info_t;
     44 typedef void wl_info_t;
     45 typedef const struct si_pub  si_t;
     46 #include <wlioctl.h>
     47 
     48 #include <proto/ethernet.h>
     49 #include <dngl_stats.h>
     50 #include <dhd.h>
     51 #define WL_ERROR(x) printf x
     52 #define WL_TRACE(x)
     53 #define WL_ASSOC(x)
     54 #define WL_INFORM(x)
     55 #define WL_WSEC(x)
     56 #define WL_SCAN(x)
     57 
     58 #include <wl_iw.h>
     59 
     60 
     61 
     62 #ifndef IW_ENCODE_ALG_SM4
     63 #define IW_ENCODE_ALG_SM4 0x20
     64 #endif
     65 
     66 #ifndef IW_AUTH_WAPI_ENABLED
     67 #define IW_AUTH_WAPI_ENABLED 0x20
     68 #endif
     69 
     70 #ifndef IW_AUTH_WAPI_VERSION_1
     71 #define IW_AUTH_WAPI_VERSION_1	0x00000008
     72 #endif
     73 
     74 #ifndef IW_AUTH_CIPHER_SMS4
     75 #define IW_AUTH_CIPHER_SMS4	0x00000020
     76 #endif
     77 
     78 #ifndef IW_AUTH_KEY_MGMT_WAPI_PSK
     79 #define IW_AUTH_KEY_MGMT_WAPI_PSK 4
     80 #endif
     81 
     82 #ifndef IW_AUTH_KEY_MGMT_WAPI_CERT
     83 #define IW_AUTH_KEY_MGMT_WAPI_CERT 8
     84 #endif
     85 
     86 
     87 #define IW_WSEC_ENABLED(wsec)	((wsec) & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED | SMS4_ENABLED))
     88 
     89 #include <linux/rtnetlink.h>
     90 #include <linux/mutex.h>
     91 
     92 #define WL_IW_USE_ISCAN  1
     93 #define ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS  1
     94 
     95 #if defined(SOFTAP)
     96 #define WL_SOFTAP(x) printk x
     97 static struct net_device *priv_dev;
     98 static bool ap_cfg_running = FALSE;
     99 static bool ap_fw_loaded = FALSE;
    100 struct net_device *ap_net_dev = NULL;
    101 struct semaphore  ap_eth_sema;
    102 static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap);
    103 static int wl_iw_softap_deassoc_stations(struct net_device *dev);
    104 #endif
    105 
    106 #define WL_IW_IOCTL_CALL(func_call) \
    107 	do {				\
    108 		func_call;		\
    109 	} while (0)
    110 
    111 static int		g_onoff = G_WLAN_SET_ON;
    112 wl_iw_extra_params_t	 g_wl_iw_params;
    113 static struct mutex	wl_start_lock;
    114 static struct mutex	wl_cache_lock;
    115 
    116 extern bool wl_iw_conn_status_str(uint32 event_type, uint32 status,
    117 	uint32 reason, char* stringBuf, uint buflen);
    118 #include <bcmsdbus.h>
    119 extern void dhd_customer_gpio_wlan_ctrl(int onoff);
    120 extern uint dhd_dev_reset(struct net_device *dev, uint8 flag);
    121 extern void dhd_dev_init_ioctl(struct net_device *dev);
    122 int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val);
    123 
    124 uint wl_msg_level = WL_ERROR_VAL;
    125 
    126 #define MAX_WLIW_IOCTL_LEN 1024
    127 
    128 
    129 #if defined(IL_BIGENDIAN)
    130 #include <bcmendian.h>
    131 #define htod32(i) (bcmswap32(i))
    132 #define htod16(i) (bcmswap16(i))
    133 #define dtoh32(i) (bcmswap32(i))
    134 #define dtoh16(i) (bcmswap16(i))
    135 #define htodchanspec(i) htod16(i)
    136 #define dtohchanspec(i) dtoh16(i)
    137 #else
    138 #define htod32(i) i
    139 #define htod16(i) i
    140 #define dtoh32(i) i
    141 #define dtoh16(i) i
    142 #define htodchanspec(i) i
    143 #define dtohchanspec(i) i
    144 #endif
    145 
    146 #ifdef CONFIG_WIRELESS_EXT
    147 
    148 extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev);
    149 extern int dhd_wait_pend8021x(struct net_device *dev);
    150 #endif
    151 
    152 #if WIRELESS_EXT < 19
    153 #define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
    154 #define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
    155 #endif
    156 
    157 static void *g_scan = NULL;
    158 static volatile uint g_scan_specified_ssid;
    159 static wlc_ssid_t g_specific_ssid;
    160 
    161 static wlc_ssid_t g_ssid;
    162 
    163 static wl_iw_ss_cache_ctrl_t g_ss_cache_ctrl;
    164 static volatile uint g_first_broadcast_scan;
    165 static volatile uint g_first_counter_scans;
    166 #define MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN 3
    167 
    168 
    169 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
    170 #define DAEMONIZE(a) daemonize(a); \
    171 	allow_signal(SIGKILL); \
    172 	allow_signal(SIGTERM);
    173 #else
    174 #define RAISE_RX_SOFTIRQ() \
    175 	cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ)
    176 #define DAEMONIZE(a) daemonize(); \
    177 	do { if (a) \
    178 		strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \
    179 	} while (0);
    180 #endif
    181 
    182 #if defined(WL_IW_USE_ISCAN)
    183 #if !defined(CSCAN)
    184 static void wl_iw_free_ss_cache(void);
    185 static int   wl_iw_run_ss_cache_timer(int kick_off);
    186 #endif
    187 int  wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag);
    188 static int dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len);
    189 #define ISCAN_STATE_IDLE   0
    190 #define ISCAN_STATE_SCANING 1
    191 
    192 #define WLC_IW_ISCAN_MAXLEN   2048
    193 typedef struct iscan_buf {
    194 	struct iscan_buf * next;
    195 	char   iscan_buf[WLC_IW_ISCAN_MAXLEN];
    196 } iscan_buf_t;
    197 
    198 typedef struct iscan_info {
    199 	struct net_device *dev;
    200 	struct timer_list timer;
    201 	uint32 timer_ms;
    202 	uint32 timer_on;
    203 	int    iscan_state;
    204 	iscan_buf_t * list_hdr;
    205 	iscan_buf_t * list_cur;
    206 
    207 
    208 	long sysioc_pid;
    209 	struct semaphore sysioc_sem;
    210 	struct completion sysioc_exited;
    211 
    212 	uint32 scan_flag;
    213 #if defined CSCAN
    214 	char ioctlbuf[WLC_IOCTL_MEDLEN];
    215 #else
    216 	char ioctlbuf[WLC_IOCTL_SMLEN];
    217 #endif
    218 	wl_iscan_params_t *iscan_ex_params_p;
    219 	int iscan_ex_param_size;
    220 } iscan_info_t;
    221 #define COEX_DHCP 1
    222 static void wl_iw_bt_flag_set(struct net_device *dev, bool set);
    223 static void wl_iw_bt_release(void);
    224 
    225 typedef enum bt_coex_status {
    226 	BT_DHCP_IDLE = 0,
    227 	BT_DHCP_START,
    228 	BT_DHCP_OPPORTUNITY_WINDOW,
    229 	BT_DHCP_FLAG_FORCE_TIMEOUT
    230 } coex_status_t;
    231 #define BT_DHCP_OPPORTUNITY_WINDOW_TIEM	2500
    232 #define BT_DHCP_FLAG_FORCE_TIME				5500
    233 
    234 typedef struct bt_info {
    235 	struct net_device *dev;
    236 	struct timer_list timer;
    237 	uint32 timer_ms;
    238 	uint32 timer_on;
    239 	int	bt_state;
    240 
    241 
    242 	long bt_pid;
    243 	struct semaphore bt_sem;
    244 	struct completion bt_exited;
    245 } bt_info_t;
    246 
    247 bt_info_t *g_bt = NULL;
    248 static void wl_iw_bt_timerfunc(ulong data);
    249 iscan_info_t *g_iscan = NULL;
    250 static void wl_iw_timerfunc(ulong data);
    251 static void wl_iw_set_event_mask(struct net_device *dev);
    252 static int
    253 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action);
    254 #endif
    255 static int
    256 wl_iw_set_scan(
    257 	struct net_device *dev,
    258 	struct iw_request_info *info,
    259 	union iwreq_data *wrqu,
    260 	char *extra
    261 );
    262 
    263 #ifndef CSCAN
    264 static int
    265 wl_iw_get_scan(
    266 	struct net_device *dev,
    267 	struct iw_request_info *info,
    268 	struct iw_point *dwrq,
    269 	char *extra
    270 );
    271 
    272 static uint
    273 wl_iw_get_scan_prep(
    274 	wl_scan_results_t *list,
    275 	struct iw_request_info *info,
    276 	char *extra,
    277 	short max_size
    278 );
    279 #endif
    280 
    281 static void swap_key_from_BE(
    282 	        wl_wsec_key_t *key
    283 )
    284 {
    285 	key->index = htod32(key->index);
    286 	key->len = htod32(key->len);
    287 	key->algo = htod32(key->algo);
    288 	key->flags = htod32(key->flags);
    289 	key->rxiv.hi = htod32(key->rxiv.hi);
    290 	key->rxiv.lo = htod16(key->rxiv.lo);
    291 	key->iv_initialized = htod32(key->iv_initialized);
    292 }
    293 
    294 static void swap_key_to_BE(
    295 	        wl_wsec_key_t *key
    296 )
    297 {
    298 	key->index = dtoh32(key->index);
    299 	key->len = dtoh32(key->len);
    300 	key->algo = dtoh32(key->algo);
    301 	key->flags = dtoh32(key->flags);
    302 	key->rxiv.hi = dtoh32(key->rxiv.hi);
    303 	key->rxiv.lo = dtoh16(key->rxiv.lo);
    304 	key->iv_initialized = dtoh32(key->iv_initialized);
    305 }
    306 
    307 static int
    308 dev_wlc_ioctl(
    309 	struct net_device *dev,
    310 	int cmd,
    311 	void *arg,
    312 	int len
    313 )
    314 {
    315 	struct ifreq ifr;
    316 	wl_ioctl_t ioc;
    317 	mm_segment_t fs;
    318 	int ret = -EINVAL;
    319 
    320 	if (!dev) {
    321 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
    322 		return ret;
    323 	}
    324 
    325 	net_os_wake_lock(dev);
    326 
    327 	WL_INFORM(("\n%s, PID:%x: send Local IOCTL -> dhd: cmd:0x%x, buf:%p, len:%d ,\n",
    328 		__FUNCTION__, current->pid, cmd, arg, len));
    329 
    330 	if (g_onoff == G_WLAN_SET_ON) {
    331 		memset(&ioc, 0, sizeof(ioc));
    332 		ioc.cmd = cmd;
    333 		ioc.buf = arg;
    334 		ioc.len = len;
    335 
    336 		strcpy(ifr.ifr_name, dev->name);
    337 		ifr.ifr_data = (caddr_t) &ioc;
    338 
    339 		ret = dev_open(dev);
    340 		if (ret) {
    341 			WL_ERROR(("%s: Error dev_open: %d\n", __func__, ret));
    342 			net_os_wake_unlock(dev);
    343 			return ret;
    344 		}
    345 
    346 		fs = get_fs();
    347 		set_fs(get_ds());
    348 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31))
    349 		ret = dev->do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
    350 #else
    351 		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, SIOCDEVPRIVATE);
    352 #endif
    353 		set_fs(fs);
    354 	}
    355 	else {
    356 		WL_TRACE(("%s: call after driver stop : ignored\n", __FUNCTION__));
    357 	}
    358 
    359 	net_os_wake_unlock(dev);
    360 
    361 	return ret;
    362 }
    363 
    364 
    365 static int
    366 dev_wlc_intvar_get_reg(
    367 	struct net_device *dev,
    368 	char *name,
    369 	uint  reg,
    370 	int *retval)
    371 {
    372 	union {
    373 		char buf[WLC_IOCTL_SMLEN];
    374 		int val;
    375 	} var;
    376 	int error;
    377 
    378 	uint len;
    379 	len = bcm_mkiovar(name, (char *)(&reg), sizeof(reg), (char *)(&var), sizeof(var.buf));
    380 	ASSERT(len);
    381 	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
    382 
    383 	*retval = dtoh32(var.val);
    384 	return (error);
    385 }
    386 
    387 
    388 static int
    389 dev_wlc_intvar_set_reg(
    390 	struct net_device *dev,
    391 	char *name,
    392 	char *addr,
    393 	char * val)
    394 {
    395 	char reg_addr[8];
    396 
    397 	memset(reg_addr, 0, sizeof(reg_addr));
    398 	memcpy((char *)&reg_addr[0], (char *)addr, 4);
    399 	memcpy((char *)&reg_addr[4], (char *)val, 4);
    400 
    401 	return (dev_wlc_bufvar_set(dev, name,  (char *)&reg_addr[0], sizeof(reg_addr)));
    402 }
    403 
    404 
    405 static int
    406 dev_wlc_intvar_set(
    407 	struct net_device *dev,
    408 	char *name,
    409 	int val)
    410 {
    411 	char buf[WLC_IOCTL_SMLEN];
    412 	uint len;
    413 
    414 	val = htod32(val);
    415 	len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf));
    416 	ASSERT(len);
    417 
    418 	return (dev_wlc_ioctl(dev, WLC_SET_VAR, buf, len));
    419 }
    420 
    421 #if defined(WL_IW_USE_ISCAN)
    422 static int
    423 dev_iw_iovar_setbuf(
    424 	struct net_device *dev,
    425 	char *iovar,
    426 	void *param,
    427 	int paramlen,
    428 	void *bufptr,
    429 	int buflen)
    430 {
    431 	int iolen;
    432 
    433 	iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
    434 	ASSERT(iolen);
    435 
    436 	if (iolen == 0)
    437 		return 0;
    438 
    439 	return (dev_wlc_ioctl(dev, WLC_SET_VAR, bufptr, iolen));
    440 }
    441 
    442 static int
    443 dev_iw_iovar_getbuf(
    444 	struct net_device *dev,
    445 	char *iovar,
    446 	void *param,
    447 	int paramlen,
    448 	void *bufptr,
    449 	int buflen)
    450 {
    451 	int iolen;
    452 
    453 	iolen = bcm_mkiovar(iovar, param, paramlen, bufptr, buflen);
    454 	ASSERT(iolen);
    455 
    456 	return (dev_wlc_ioctl(dev, WLC_GET_VAR, bufptr, buflen));
    457 }
    458 #endif
    459 
    460 
    461 #if WIRELESS_EXT > 17
    462 static int
    463 dev_wlc_bufvar_set(
    464 	struct net_device *dev,
    465 	char *name,
    466 	char *buf, int len)
    467 {
    468 	static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
    469 	uint buflen;
    470 
    471 	buflen = bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf));
    472 	ASSERT(buflen);
    473 
    474 	return (dev_wlc_ioctl(dev, WLC_SET_VAR, ioctlbuf, buflen));
    475 }
    476 #endif
    477 
    478 
    479 static int
    480 dev_wlc_bufvar_get(
    481 	struct net_device *dev,
    482 	char *name,
    483 	char *buf, int buflen)
    484 {
    485 	static char ioctlbuf[MAX_WLIW_IOCTL_LEN];
    486 	int error;
    487 	uint len;
    488 
    489 	len = bcm_mkiovar(name, NULL, 0, ioctlbuf, sizeof(ioctlbuf));
    490 	ASSERT(len);
    491 	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)ioctlbuf, MAX_WLIW_IOCTL_LEN);
    492 	if (!error)
    493 		bcopy(ioctlbuf, buf, buflen);
    494 
    495 	return (error);
    496 }
    497 
    498 
    499 
    500 static int
    501 dev_wlc_intvar_get(
    502 	struct net_device *dev,
    503 	char *name,
    504 	int *retval)
    505 {
    506 	union {
    507 		char buf[WLC_IOCTL_SMLEN];
    508 		int val;
    509 	} var;
    510 	int error;
    511 
    512 	uint len;
    513 	uint data_null;
    514 
    515 	len = bcm_mkiovar(name, (char *)(&data_null), 0, (char *)(&var), sizeof(var.buf));
    516 	ASSERT(len);
    517 	error = dev_wlc_ioctl(dev, WLC_GET_VAR, (void *)&var, len);
    518 
    519 	*retval = dtoh32(var.val);
    520 
    521 	return (error);
    522 }
    523 
    524 
    525 #if WIRELESS_EXT > 12
    526 static int
    527 wl_iw_set_active_scan(
    528 	struct net_device *dev,
    529 	struct iw_request_info *info,
    530 	union iwreq_data *wrqu,
    531 	char *extra
    532 )
    533 {
    534 	int as = 0;
    535 	int error = 0;
    536 	char *p = extra;
    537 
    538 #if defined(WL_IW_USE_ISCAN)
    539 	if (g_iscan->iscan_state == ISCAN_STATE_IDLE)
    540 #endif
    541 		error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
    542 #if defined(WL_IW_USE_ISCAN)
    543 	else
    544 		g_iscan->scan_flag = as;
    545 #endif
    546 	p += snprintf(p, MAX_WX_STRING, "OK");
    547 
    548 	wrqu->data.length = p - extra + 1;
    549 	return error;
    550 }
    551 
    552 static int
    553 wl_iw_set_passive_scan(
    554 	struct net_device *dev,
    555 	struct iw_request_info *info,
    556 	union iwreq_data *wrqu,
    557 	char *extra
    558 )
    559 {
    560 	int ps = 1;
    561 	int error = 0;
    562 	char *p = extra;
    563 
    564 #if defined(WL_IW_USE_ISCAN)
    565 	if (g_iscan->iscan_state == ISCAN_STATE_IDLE) {
    566 #endif
    567 
    568 
    569 		if (g_scan_specified_ssid == 0) {
    570 			error = dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &ps, sizeof(ps));
    571 		}
    572 #if defined(WL_IW_USE_ISCAN)
    573 	}
    574 	else
    575 		g_iscan->scan_flag = ps;
    576 #endif
    577 
    578 	p += snprintf(p, MAX_WX_STRING, "OK");
    579 
    580 	wrqu->data.length = p - extra + 1;
    581 	return error;
    582 }
    583 
    584 static int
    585 wl_iw_get_macaddr(
    586 	struct net_device *dev,
    587 	struct iw_request_info *info,
    588 	union iwreq_data *wrqu,
    589 	char *extra
    590 )
    591 {
    592 	int error;
    593 	char buf[128];
    594 	struct ether_addr *id;
    595 	char *p = extra;
    596 
    597 
    598 	strcpy(buf, "cur_etheraddr");
    599 	error = dev_wlc_ioctl(dev, WLC_GET_VAR, buf, sizeof(buf));
    600 	id = (struct ether_addr *) buf;
    601 	p += snprintf(p, MAX_WX_STRING, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
    602 		id->octet[0], id->octet[1], id->octet[2],
    603 		id->octet[3], id->octet[4], id->octet[5]);
    604 	wrqu->data.length = p - extra + 1;
    605 
    606 	return error;
    607 }
    608 
    609 
    610 static int
    611 wl_iw_set_country(
    612 	struct net_device *dev,
    613 	struct iw_request_info *info,
    614 	union iwreq_data *wrqu,
    615 	char *extra
    616 )
    617 {
    618 	char country_code[WLC_CNTRY_BUF_SZ];
    619 	int error = 0;
    620 	char *p = extra;
    621 	int country_offset;
    622 	int country_code_size;
    623 
    624 	WL_TRACE(("%s\n", __FUNCTION__));
    625 	memset(country_code, 0, sizeof(country_code));
    626 
    627 	country_offset = strcspn(extra, " ");
    628 	country_code_size = strlen(extra) - country_offset;
    629 
    630 
    631 	if (country_offset != 0) {
    632 		strncpy(country_code, extra + country_offset + 1,
    633 			MIN(country_code_size, sizeof(country_code)));
    634 
    635 
    636 		if ((error = dev_wlc_ioctl(dev, WLC_SET_COUNTRY,
    637 			&country_code, sizeof(country_code))) >= 0) {
    638 			p += snprintf(p, MAX_WX_STRING, "OK");
    639 			WL_TRACE(("%s: set country %s OK\n", __FUNCTION__, country_code));
    640 			goto exit;
    641 		}
    642 	}
    643 
    644 	WL_ERROR(("%s: set country %s failed code %d\n", __FUNCTION__, country_code, error));
    645 	p += snprintf(p, MAX_WX_STRING, "FAIL");
    646 
    647 exit:
    648 	wrqu->data.length = p - extra + 1;
    649 	return error;
    650 }
    651 
    652 #ifdef CUSTOMER_HW2
    653 static int
    654 wl_iw_set_power_mode(
    655 	struct net_device *dev,
    656 	struct iw_request_info *info,
    657 	union iwreq_data *wrqu,
    658 	char *extra
    659 )
    660 {
    661 	int error = 0;
    662 	char *p = extra;
    663 	static int pm = PM_FAST;
    664 	int pm_local = PM_OFF;
    665 	char powermode_val = 0;
    666 
    667 	strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1);
    668 
    669 	if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
    670 
    671 		WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
    672 
    673 		dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm));
    674 		dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
    675 
    676 		/* Disable packet filtering if necessary */
    677 		net_os_set_packet_filter(dev, 0);
    678 
    679 	} else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
    680 
    681 		WL_TRACE(("%s: DHCP session done\n", __FUNCTION__));
    682 
    683 		dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
    684 
    685 		/* Enable packet filtering if was turned off */
    686 		net_os_set_packet_filter(dev, 1);
    687 
    688 	} else {
    689 		WL_ERROR(("Unkwown yet power setting, ignored\n"));
    690 	}
    691 
    692 	p += snprintf(p, MAX_WX_STRING, "OK");
    693 
    694 	wrqu->data.length = p - extra + 1;
    695 
    696 	return error;
    697 }
    698 #endif
    699 
    700 static int
    701 wl_iw_get_power_mode(
    702 	struct net_device *dev,
    703 	struct iw_request_info *info,
    704 	union iwreq_data *wrqu,
    705 	char *extra
    706 )
    707 {
    708 	int error;
    709 	char *p = extra;
    710 	int pm_local = PM_FAST;
    711 
    712 	error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local));
    713 	if (!error) {
    714 		WL_TRACE(("%s: Powermode = %d\n", __func__, pm_local));
    715 		if (pm_local == PM_OFF)
    716 			pm_local = 1; /* Active */
    717 		else
    718 			pm_local = 0; /* Auto */
    719 		p += snprintf(p, MAX_WX_STRING, "powermode = %d", pm_local);
    720 	}
    721 	else {
    722 		WL_TRACE(("%s: Error = %d\n", __func__, error));
    723 		p += snprintf(p, MAX_WX_STRING, "FAIL");
    724 	}
    725 	wrqu->data.length = p - extra + 1;
    726 	return error;
    727 }
    728 
    729 static int
    730 wl_iw_set_btcoex_dhcp(
    731 	struct net_device *dev,
    732 	struct iw_request_info *info,
    733 	union iwreq_data *wrqu,
    734 	char *extra
    735 )
    736 {
    737 	int error = 0;
    738 	char *p = extra;
    739 #ifndef CUSTOMER_HW2
    740 	static int  pm = PM_FAST;
    741 	int  pm_local = PM_OFF;
    742 #endif
    743 	char powermode_val = 0;
    744 	char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 };
    745 	char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 };
    746 	char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 };
    747 
    748 	uint32 regaddr;
    749 	static uint32 saved_reg66;
    750 	static uint32 saved_reg41;
    751 	static uint32 saved_reg68;
    752 	static bool saved_status = FALSE;
    753 
    754 	char buf_flag7_default[8] =   { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
    755 #ifndef CUSTOMER_HW2
    756 	uint32 temp1, temp2;
    757 #endif
    758 
    759 #ifdef CUSTOMER_HW2
    760 	strncpy((char *)&powermode_val, extra + strlen("BTCOEXMODE") + 1, 1);
    761 #else
    762 	strncpy((char *)&powermode_val, extra + strlen("POWERMODE") + 1, 1);
    763 #endif
    764 
    765 	if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) {
    766 
    767 		WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__));
    768 
    769 		if ((saved_status == FALSE) &&
    770 #ifndef CUSTOMER_HW2
    771 			(!dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))) &&
    772 #endif
    773 			(!dev_wlc_intvar_get_reg(dev, "btc_params", 66,  &saved_reg66)) &&
    774 			(!dev_wlc_intvar_get_reg(dev, "btc_params", 41,  &saved_reg41)) &&
    775 			(!dev_wlc_intvar_get_reg(dev, "btc_params", 68,  &saved_reg68)))   {
    776 				saved_status = TRUE;
    777 				WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", \
    778 					saved_reg66, saved_reg41, saved_reg68));
    779 
    780 #ifndef CUSTOMER_HW2
    781 				dev_wlc_ioctl(dev, WLC_SET_PM, &pm_local, sizeof(pm_local));
    782 #endif
    783 
    784 		dev_wlc_bufvar_set(dev, "btc_params", \
    785 				   (char *)&buf_reg66va_dhcp_on[0], sizeof(buf_reg66va_dhcp_on));
    786 		dev_wlc_bufvar_set(dev, "btc_params", \
    787 				   (char *)&buf_reg41va_dhcp_on[0], sizeof(buf_reg41va_dhcp_on));
    788 		dev_wlc_bufvar_set(dev, "btc_params", \
    789 				   (char *)&buf_reg68va_dhcp_on[0], sizeof(buf_reg68va_dhcp_on));
    790 #ifndef CUSTOMER_HW2
    791 				if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 12, &temp1)) &&
    792 					(!dev_wlc_intvar_get_reg(dev, "btc_params", 13, &temp2)))
    793 				{
    794 					if ((temp1 != 0) && (temp2 != 0)) {
    795 #endif
    796 						g_bt->bt_state = BT_DHCP_START;
    797 						g_bt->timer_on = 1;
    798 						mod_timer(&g_bt->timer, g_bt->timer.expires);
    799 						WL_TRACE(("%s enable BT DHCP Timer\n", \
    800 							__FUNCTION__));
    801 #ifndef CUSTOMER_HW2
    802 					}
    803 				}
    804 #endif
    805 		}
    806 		else if (saved_status == TRUE) {
    807 			WL_ERROR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__));
    808 		}
    809 	}
    810 #ifdef CUSTOMER_HW2
    811 	else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) {
    812 #else
    813 	else if (strnicmp((char *)&powermode_val, "0", strlen("0")) == 0) {
    814 #endif
    815 		WL_TRACE(("%s: DHCP session done\n", __FUNCTION__));
    816 
    817 #ifndef CUSTOMER_HW2
    818 		dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm));
    819 #endif
    820 
    821 		WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__));
    822 		if (g_bt->timer_on) {
    823 			g_bt->timer_on = 0;
    824 			del_timer_sync(&g_bt->timer);
    825 		}
    826 
    827 		dev_wlc_bufvar_set(dev, "btc_flags", \
    828 				(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
    829 
    830 		if (saved_status) {
    831 			regaddr = 66;
    832 			dev_wlc_intvar_set_reg(dev, "btc_params", \
    833 				(char *)&regaddr, (char *)&saved_reg66);
    834 			regaddr = 41;
    835 			dev_wlc_intvar_set_reg(dev, "btc_params", \
    836 				(char *)&regaddr, (char *)&saved_reg41);
    837 			regaddr = 68;
    838 			dev_wlc_intvar_set_reg(dev, "btc_params", \
    839 				(char *)&regaddr, (char *)&saved_reg68);
    840 		}
    841 		saved_status = FALSE;
    842 	}
    843 	else {
    844 		WL_ERROR(("Unkwown yet power setting, ignored\n"));
    845 	}
    846 
    847 	p += snprintf(p, MAX_WX_STRING, "OK");
    848 
    849 	wrqu->data.length = p - extra + 1;
    850 
    851 	return error;
    852 }
    853 
    854 static int
    855 wl_iw_set_suspend(
    856 	struct net_device *dev,
    857 	struct iw_request_info *info,
    858 	union iwreq_data *wrqu,
    859 	char *extra
    860 )
    861 {
    862 	int suspend_flag;
    863 	int ret_now;
    864 	int ret = 0;
    865 
    866 	suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0';
    867 
    868 	if (suspend_flag != 0)
    869 		suspend_flag = 1;
    870 
    871 	ret_now = net_os_set_suspend_disable(dev, suspend_flag);
    872 
    873 	if (ret_now != suspend_flag) {
    874 		if (!(ret = net_os_set_suspend(dev, ret_now)))
    875 			WL_ERROR(("%s: Suspend Flag %d -> %d\n", \
    876 					__FUNCTION__, ret_now, suspend_flag));
    877 		else
    878 			WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
    879 	}
    880 
    881 	return ret;
    882 }
    883 
    884 int
    885 wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len)
    886 {
    887 	int i, c;
    888 	char *p = ssid_buf;
    889 
    890 	if (ssid_len > 32) ssid_len = 32;
    891 
    892 	for (i = 0; i < ssid_len; i++) {
    893 		c = (int)ssid[i];
    894 		if (c == '\\') {
    895 			*p++ = '\\';
    896 			*p++ = '\\';
    897 		} else if (isprint((uchar)c)) {
    898 			*p++ = (char)c;
    899 		} else {
    900 			p += sprintf(p, "\\x%02X", c);
    901 		}
    902 	}
    903 	*p = '\0';
    904 
    905 	return p - ssid_buf;
    906 }
    907 
    908 static int
    909 wl_iw_get_link_speed(
    910 	struct net_device *dev,
    911 	struct iw_request_info *info,
    912 	union iwreq_data *wrqu,
    913 	char *extra
    914 )
    915 {
    916 	int error = 0;
    917 	char *p = extra;
    918 	static int link_speed;
    919 
    920 	net_os_wake_lock(dev);
    921 	if (g_onoff == G_WLAN_SET_ON) {
    922 		error = dev_wlc_ioctl(dev, WLC_GET_RATE, &link_speed, sizeof(link_speed));
    923 		link_speed *= 500000;
    924 	}
    925 
    926 	p += snprintf(p, MAX_WX_STRING, "LinkSpeed %d", link_speed/1000000);
    927 
    928 	wrqu->data.length = p - extra + 1;
    929 
    930 	net_os_wake_unlock(dev);
    931 	return error;
    932 }
    933 
    934 
    935 static int
    936 wl_iw_get_dtim_skip(
    937 	struct net_device *dev,
    938 	struct iw_request_info *info,
    939 	union iwreq_data *wrqu,
    940 	char *extra
    941 )
    942 {
    943 	int error = -1;
    944 	char *p = extra;
    945 	char iovbuf[32];
    946 
    947 	net_os_wake_lock(dev);
    948 	if (g_onoff == G_WLAN_SET_ON) {
    949 
    950 			memset(iovbuf, 0, sizeof(iovbuf));
    951 			strcpy(iovbuf, "bcn_li_dtim");
    952 
    953 			if ((error = dev_wlc_ioctl(dev, WLC_GET_VAR,
    954 				&iovbuf, sizeof(iovbuf))) >= 0) {
    955 
    956 				p += snprintf(p, MAX_WX_STRING, "Dtim_skip %d", iovbuf[0]);
    957 				WL_TRACE(("%s: get dtim_skip = %d\n", __FUNCTION__, iovbuf[0]));
    958 				wrqu->data.length = p - extra + 1;
    959 			}
    960 			else
    961 				WL_ERROR(("%s: get dtim_skip failed code %d\n", \
    962 					__FUNCTION__, error));
    963 	}
    964 	net_os_wake_unlock(dev);
    965 	return error;
    966 }
    967 
    968 
    969 static int
    970 wl_iw_set_dtim_skip(
    971 	struct net_device *dev,
    972 	struct iw_request_info *info,
    973 	union iwreq_data *wrqu,
    974 	char *extra
    975 )
    976 {
    977 	int error = -1;
    978 	char *p = extra;
    979 	int bcn_li_dtim;
    980 	char iovbuf[32];
    981 
    982 	net_os_wake_lock(dev);
    983 	if (g_onoff == G_WLAN_SET_ON) {
    984 
    985 		bcn_li_dtim = htod32((uint)*(extra + strlen(DTIM_SKIP_SET_CMD) + 1) - '0');
    986 
    987 		if ((bcn_li_dtim >= 0) || ((bcn_li_dtim <= 5))) {
    988 
    989 			memset(iovbuf, 0, sizeof(iovbuf));
    990 			bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim,
    991 				4, iovbuf, sizeof(iovbuf));
    992 
    993 			if ((error = dev_wlc_ioctl(dev, WLC_SET_VAR,
    994 				&iovbuf, sizeof(iovbuf))) >= 0) {
    995 				p += snprintf(p, MAX_WX_STRING, "OK");
    996 
    997 				net_os_set_dtim_skip(dev, bcn_li_dtim);
    998 
    999 				WL_TRACE(("%s: set dtim_skip %d OK\n", __FUNCTION__, \
   1000 					bcn_li_dtim));
   1001 				goto exit;
   1002 			}
   1003 			else  WL_ERROR(("%s: set dtim_skip %d failed code %d\n", \
   1004 				__FUNCTION__, bcn_li_dtim, error));
   1005 		}
   1006 		else  WL_ERROR(("%s Incorrect dtim_skip setting %d, ignored\n", \
   1007 			__FUNCTION__, bcn_li_dtim));
   1008 	}
   1009 
   1010 	p += snprintf(p, MAX_WX_STRING, "FAIL");
   1011 
   1012 exit:
   1013 	wrqu->data.length = p - extra + 1;
   1014 	net_os_wake_unlock(dev);
   1015 	return error;
   1016 }
   1017 
   1018 
   1019 static int
   1020 wl_iw_get_band(
   1021 	struct net_device *dev,
   1022 	struct iw_request_info *info,
   1023 	union iwreq_data *wrqu,
   1024 	char *extra
   1025 )
   1026 {
   1027 	int error = -1;
   1028 	char *p = extra;
   1029 	static int band;
   1030 
   1031 	net_os_wake_lock(dev);
   1032 
   1033 	if (g_onoff == G_WLAN_SET_ON) {
   1034 		error = dev_wlc_ioctl(dev, WLC_GET_BAND, &band, sizeof(band));
   1035 
   1036 		p += snprintf(p, MAX_WX_STRING, "Band %d", band);
   1037 
   1038 		wrqu->data.length = p - extra + 1;
   1039 	}
   1040 
   1041 	net_os_wake_unlock(dev);
   1042 	return error;
   1043 }
   1044 
   1045 
   1046 static int
   1047 wl_iw_set_band(
   1048 	struct net_device *dev,
   1049 	struct iw_request_info *info,
   1050 	union iwreq_data *wrqu,
   1051 	char *extra
   1052 )
   1053 {
   1054 	int error = -1;
   1055 	char *p = extra;
   1056 	uint band;
   1057 
   1058 	net_os_wake_lock(dev);
   1059 
   1060 	if (g_onoff == G_WLAN_SET_ON) {
   1061 
   1062 		band = htod32((uint)*(extra + strlen(BAND_SET_CMD) + 1) - '0');
   1063 
   1064 		if ((band == WLC_BAND_AUTO) || (band == WLC_BAND_5G) || (band == WLC_BAND_2G)) {
   1065 
   1066 
   1067 			if ((error = dev_wlc_ioctl(dev, WLC_SET_BAND,
   1068 				&band, sizeof(band))) >= 0) {
   1069 				p += snprintf(p, MAX_WX_STRING, "OK");
   1070 				WL_TRACE(("%s: set band %d OK\n", __FUNCTION__, band));
   1071 				goto exit;
   1072 			}
   1073 			else WL_ERROR(("%s: set band %d failed code %d\n", __FUNCTION__, \
   1074 					band, error));
   1075 		}
   1076 		else WL_ERROR(("%s Incorrect band setting %d, ignored\n", __FUNCTION__, band));
   1077 	}
   1078 
   1079 	p += snprintf(p, MAX_WX_STRING, "FAIL");
   1080 
   1081 exit:
   1082 	wrqu->data.length = p - extra + 1;
   1083 	net_os_wake_unlock(dev);
   1084 	return error;
   1085 }
   1086 
   1087 #ifdef PNO_SUPPORT
   1088 
   1089 static int
   1090 wl_iw_set_pno_reset(
   1091 	struct net_device *dev,
   1092 	struct iw_request_info *info,
   1093 	union iwreq_data *wrqu,
   1094 	char *extra
   1095 )
   1096 {
   1097 	int error = -1;
   1098 	char *p = extra;
   1099 
   1100 	net_os_wake_lock(dev);
   1101 	if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
   1102 
   1103 		if ((error = dhd_dev_pno_reset(dev)) >= 0) {
   1104 				p += snprintf(p, MAX_WX_STRING, "OK");
   1105 				WL_TRACE(("%s: set OK\n", __FUNCTION__));
   1106 				goto exit;
   1107 		}
   1108 		else  WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
   1109 	}
   1110 
   1111 	p += snprintf(p, MAX_WX_STRING, "FAIL");
   1112 
   1113 exit:
   1114 	wrqu->data.length = p - extra + 1;
   1115 	net_os_wake_unlock(dev);
   1116 	return error;
   1117 }
   1118 
   1119 
   1120 
   1121 static int
   1122 wl_iw_set_pno_enable(
   1123 	struct net_device *dev,
   1124 	struct iw_request_info *info,
   1125 	union iwreq_data *wrqu,
   1126 	char *extra
   1127 )
   1128 {
   1129 	int error = -1;
   1130 	char *p = extra;
   1131 	int pfn_enabled;
   1132 
   1133 	net_os_wake_lock(dev);
   1134 	pfn_enabled = htod32((uint)*(extra + strlen(PNOENABLE_SET_CMD) + 1) - '0');
   1135 
   1136 	if ((g_onoff == G_WLAN_SET_ON) && (dev != NULL)) {
   1137 
   1138 		if ((error = dhd_dev_pno_enable(dev, pfn_enabled)) >= 0) {
   1139 				p += snprintf(p, MAX_WX_STRING, "OK");
   1140 				WL_TRACE(("%s: set OK\n", __FUNCTION__));
   1141 				goto exit;
   1142 		}
   1143 		else  WL_ERROR(("%s: failed code %d\n", __FUNCTION__, error));
   1144 	}
   1145 
   1146 	p += snprintf(p, MAX_WX_STRING, "FAIL");
   1147 
   1148 exit:
   1149 	wrqu->data.length = p - extra + 1;
   1150 	net_os_wake_unlock(dev);
   1151 	return error;
   1152 }
   1153 
   1154 
   1155 
   1156 static int
   1157 wl_iw_set_pno_set(
   1158 	struct net_device *dev,
   1159 	struct iw_request_info *info,
   1160 	union iwreq_data *wrqu,
   1161 	char *extra
   1162 )
   1163 {
   1164 	int res = -1;
   1165 	wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
   1166 	int nssid = 0;
   1167 	cmd_tlv_t *cmd_tlv_temp;
   1168 	char type;
   1169 	char *str_ptr;
   1170 	int tlv_size_left;
   1171 	int pno_time;
   1172 
   1173 #ifdef PNO_SET_DEBUG
   1174 	int i;
   1175 	char pno_in_example[] = {'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ', \
   1176 							'S', 0x01, 0x01, 0x00,
   1177 							'S',
   1178 							0x04,
   1179 							'B', 'R', 'C', 'M',
   1180 							'S',
   1181 							0x04,
   1182 							'G', 'O', 'O', 'G',
   1183 							'T',
   1184 							0x00,
   1185 							0x0A
   1186 							};
   1187 #endif
   1188 
   1189 	net_os_wake_lock(dev);
   1190 	WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
   1191 		__FUNCTION__, info->cmd, info->flags,
   1192 		wrqu->data.pointer, wrqu->data.length));
   1193 
   1194 	if (g_onoff == G_WLAN_SET_OFF) {
   1195 		WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
   1196 		goto exit_proc;
   1197 	}
   1198 
   1199 	if (wrqu->data.length < (strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t))) {
   1200 		WL_ERROR(("%s aggument=%d  less %d\n", __FUNCTION__, \
   1201 			wrqu->data.length, strlen(PNOSETUP_SET_CMD) + sizeof(cmd_tlv_t)));
   1202 		goto exit_proc;
   1203 	}
   1204 
   1205 #ifdef PNO_SET_DEBUG
   1206 	if (!(extra = kmalloc(sizeof(pno_in_example) +100, GFP_KERNEL))) {
   1207 		res = -ENOMEM;
   1208 		goto exit_proc;
   1209 	}
   1210 	memcpy(extra, pno_in_example, sizeof(pno_in_example));
   1211 	wrqu->data.length = sizeof(pno_in_example);
   1212 	for (i = 0; i < wrqu->data.length; i++)
   1213 		printf("%02X ", extra[i]);
   1214 	printf("\n");
   1215 #endif
   1216 
   1217 	str_ptr = extra;
   1218 #ifdef PNO_SET_DEBUG
   1219 	str_ptr +=  strlen("PNOSETUP ");
   1220 	tlv_size_left = wrqu->data.length - strlen("PNOSETUP ");
   1221 #else
   1222 	str_ptr +=  strlen(PNOSETUP_SET_CMD);
   1223 	tlv_size_left = wrqu->data.length - strlen(PNOSETUP_SET_CMD);
   1224 #endif
   1225 
   1226 	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
   1227 	memset(ssids_local, 0, sizeof(ssids_local));
   1228 
   1229 	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) && \
   1230 		(cmd_tlv_temp->version == PNO_TLV_VERSION) && \
   1231 		(cmd_tlv_temp->subver == PNO_TLV_SUBVERSION))
   1232 	{
   1233 		str_ptr += sizeof(cmd_tlv_t);
   1234 		tlv_size_left  -= sizeof(cmd_tlv_t);
   1235 
   1236 		if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
   1237 				MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
   1238 			WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
   1239 			goto exit_proc;
   1240 		}
   1241 		else {
   1242 			while (tlv_size_left > 0)
   1243 			{
   1244 				type = str_ptr[0];
   1245 				switch (type) {
   1246 					case PNO_TLV_TYPE_TIME:
   1247 
   1248 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   1249 						&pno_time, \
   1250 						sizeof(pno_time), \
   1251 						type, sizeof(short), &tlv_size_left)) == -1) {
   1252 							WL_ERROR(("%s return %d\n", \
   1253 							__FUNCTION__, res));
   1254 							goto exit_proc;
   1255 					}
   1256 					break;
   1257 
   1258 					default:
   1259 						WL_ERROR(("%s get unkwown type %X\n", \
   1260 							__FUNCTION__, type));
   1261 						goto exit_proc;
   1262 					break;
   1263 				}
   1264 			}
   1265 		}
   1266 	}
   1267 	else {
   1268 		WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
   1269 		goto exit_proc;
   1270 	}
   1271 
   1272 	res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time);
   1273 
   1274 exit_proc:
   1275 	net_os_wake_unlock(dev);
   1276 	return res;
   1277 }
   1278 #endif
   1279 
   1280 static int
   1281 wl_iw_get_rssi(
   1282 	struct net_device *dev,
   1283 	struct iw_request_info *info,
   1284 	union iwreq_data *wrqu,
   1285 	char *extra
   1286 )
   1287 {
   1288 	static int rssi = 0;
   1289 	static wlc_ssid_t ssid = {0};
   1290 	int error = 0;
   1291 	char *p = extra;
   1292 	static char ssidbuf[SSID_FMT_BUF_LEN];
   1293 	scb_val_t scb_val;
   1294 
   1295 	net_os_wake_lock(dev);
   1296 
   1297 	bzero(&scb_val, sizeof(scb_val_t));
   1298 
   1299 	if (g_onoff == G_WLAN_SET_ON) {
   1300 		error = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t));
   1301 		if (error) {
   1302 			WL_ERROR(("%s: Fails %d\n", __FUNCTION__, error));
   1303 			net_os_wake_unlock(dev);
   1304 			return error;
   1305 		}
   1306 		rssi = dtoh32(scb_val.val);
   1307 
   1308 		error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid));
   1309 		if (!error) {
   1310 			ssid.SSID_len = dtoh32(ssid.SSID_len);
   1311 			wl_format_ssid(ssidbuf, ssid.SSID, dtoh32(ssid.SSID_len));
   1312 		}
   1313 	}
   1314 
   1315 	p += snprintf(p, MAX_WX_STRING, "%s rssi %d ", ssidbuf, rssi);
   1316 	wrqu->data.length = p - extra + 1;
   1317 
   1318 	net_os_wake_unlock(dev);
   1319 	return error;
   1320 }
   1321 
   1322 int
   1323 wl_iw_send_priv_event(
   1324 	struct net_device *dev,
   1325 	char *flag
   1326 )
   1327 {
   1328 	union iwreq_data wrqu;
   1329 	char extra[IW_CUSTOM_MAX + 1];
   1330 	int cmd;
   1331 
   1332 	cmd = IWEVCUSTOM;
   1333 	memset(&wrqu, 0, sizeof(wrqu));
   1334 	if (strlen(flag) > sizeof(extra))
   1335 		return -1;
   1336 
   1337 	strcpy(extra, flag);
   1338 	wrqu.data.length = strlen(extra);
   1339 	wireless_send_event(dev, cmd, &wrqu, extra);
   1340 	net_os_wake_lock_timeout_enable(dev);
   1341 	WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra));
   1342 
   1343 	return 0;
   1344 }
   1345 
   1346 
   1347 int
   1348 wl_control_wl_start(struct net_device *dev)
   1349 {
   1350 	int ret = 0;
   1351 
   1352 	WL_TRACE(("Enter %s \n", __FUNCTION__));
   1353 
   1354 	if (!dev) {
   1355 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   1356 		return -1;
   1357 	}
   1358 
   1359 	mutex_lock(&wl_start_lock);
   1360 
   1361 	if (g_onoff == G_WLAN_SET_OFF) {
   1362 		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
   1363 
   1364 #if defined(BCMLXSDMMC)
   1365 		sdioh_start(NULL, 0);
   1366 #endif
   1367 
   1368 		dhd_dev_reset(dev, 0);
   1369 
   1370 #if defined(BCMLXSDMMC)
   1371 		sdioh_start(NULL, 1);
   1372 #endif
   1373 
   1374 		dhd_dev_init_ioctl(dev);
   1375 
   1376 		g_onoff = G_WLAN_SET_ON;
   1377 	}
   1378 	WL_TRACE(("Exited %s \n", __FUNCTION__));
   1379 
   1380 	mutex_unlock(&wl_start_lock);
   1381 	return ret;
   1382 }
   1383 
   1384 
   1385 static int
   1386 wl_iw_control_wl_off(
   1387 	struct net_device *dev,
   1388 	struct iw_request_info *info
   1389 )
   1390 {
   1391 	int ret = 0;
   1392 	WL_TRACE(("Enter %s\n", __FUNCTION__));
   1393 
   1394 	if (!dev) {
   1395 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   1396 		return -1;
   1397 	}
   1398 
   1399 	mutex_lock(&wl_start_lock);
   1400 
   1401 #ifdef SOFTAP
   1402 	ap_cfg_running = FALSE;
   1403 #endif
   1404 
   1405 	if (g_onoff == G_WLAN_SET_ON) {
   1406 		g_onoff = G_WLAN_SET_OFF;
   1407 #if defined(WL_IW_USE_ISCAN)
   1408 		g_iscan->iscan_state = ISCAN_STATE_IDLE;
   1409 #endif
   1410 
   1411 		dhd_dev_reset(dev, 1);
   1412 
   1413 #if defined(WL_IW_USE_ISCAN)
   1414 #if !defined(CSCAN)
   1415 		wl_iw_free_ss_cache();
   1416 		wl_iw_run_ss_cache_timer(0);
   1417 
   1418 		g_ss_cache_ctrl.m_link_down = 1;
   1419 #endif
   1420 		memset(g_scan, 0, G_SCAN_RESULTS);
   1421 		g_scan_specified_ssid = 0;
   1422 
   1423 		g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
   1424 		g_first_counter_scans = 0;
   1425 #endif
   1426 
   1427 #if defined(BCMLXSDMMC)
   1428 		sdioh_stop(NULL);
   1429 #endif
   1430 
   1431 		net_os_set_dtim_skip(dev, 0);
   1432 
   1433 		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
   1434 
   1435 		wl_iw_send_priv_event(dev, "STOP");
   1436 	}
   1437 
   1438 	mutex_unlock(&wl_start_lock);
   1439 
   1440 	WL_TRACE(("Exited %s\n", __FUNCTION__));
   1441 
   1442 	return ret;
   1443 }
   1444 
   1445 static int
   1446 wl_iw_control_wl_on(
   1447 	struct net_device *dev,
   1448 	struct iw_request_info *info
   1449 )
   1450 {
   1451 	int ret = 0;
   1452 
   1453 	WL_TRACE(("Enter %s \n", __FUNCTION__));
   1454 
   1455 	ret = wl_control_wl_start(dev);
   1456 
   1457 	wl_iw_send_priv_event(dev, "START");
   1458 
   1459 #ifdef SOFTAP
   1460 	if (!ap_fw_loaded) {
   1461 		wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
   1462 	}
   1463 #else
   1464 	wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
   1465 #endif
   1466 
   1467 	WL_TRACE(("Exited %s \n", __FUNCTION__));
   1468 
   1469 	return ret;
   1470 }
   1471 
   1472 #ifdef SOFTAP
   1473 static struct ap_profile my_ap;
   1474 static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap);
   1475 static int get_assoc_sta_list(struct net_device *dev, char *buf, int len);
   1476 static int set_ap_mac_list(struct net_device *dev, char *buf);
   1477 
   1478 #define PTYPE_STRING	0
   1479 #define PTYPE_INTDEC	1
   1480 #define PTYPE_INTHEX	2
   1481 #define PTYPE_STR_HEX	3
   1482 int get_parmeter_from_string(
   1483 	char **str_ptr, const char *token, int param_type, void  *dst, int param_max_len);
   1484 
   1485 #endif
   1486 
   1487 int hex2num(char c)
   1488 {
   1489 	if (c >= '0' && c <= '9')
   1490 		return c - '0';
   1491 	if (c >= 'a' && c <= 'f')
   1492 		return c - 'a' + 10;
   1493 	if (c >= 'A' && c <= 'F')
   1494 		return c - 'A' + 10;
   1495 	return -1;
   1496 }
   1497 
   1498 int hex2byte(const char *hex)
   1499 {
   1500 	int a, b;
   1501 	a = hex2num(*hex++);
   1502 	if (a < 0)
   1503 		return -1;
   1504 	b = hex2num(*hex++);
   1505 	if (b < 0)
   1506 		return -1;
   1507 	return (a << 4) | b;
   1508 }
   1509 
   1510 
   1511 
   1512 int hstr_2_buf(const char *txt, u8 *buf, int len)
   1513 {
   1514 	int i;
   1515 
   1516 	for (i = 0; i < len; i++) {
   1517 		int a, b;
   1518 
   1519 		a = hex2num(*txt++);
   1520 		if (a < 0)
   1521 			return -1;
   1522 		b = hex2num(*txt++);
   1523 		if (b < 0)
   1524 			return -1;
   1525 		*buf++ = (a << 4) | b;
   1526 	}
   1527 
   1528 	return 0;
   1529 }
   1530 
   1531 #ifdef SOFTAP
   1532 int init_ap_profile_from_string(char *param_str, struct ap_profile *ap_cfg)
   1533 {
   1534 	char *str_ptr = param_str;
   1535 	char sub_cmd[16];
   1536 	int ret = 0;
   1537 
   1538 	memset(sub_cmd, 0, sizeof(sub_cmd));
   1539 	memset(ap_cfg, 0, sizeof(struct ap_profile));
   1540 
   1541 	if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=",
   1542 		PTYPE_STRING, sub_cmd, SSID_LEN) != 0) {
   1543 		return -1;
   1544 	}
   1545 	if (strncmp(sub_cmd, "AP_CFG", 6)) {
   1546 		WL_ERROR(("ERROR: sub_cmd:%s != 'AP_CFG'!\n", sub_cmd));
   1547 		return -1;
   1548 	}
   1549 
   1550 	ret = get_parmeter_from_string(&str_ptr, "SSID=", PTYPE_STRING, ap_cfg->ssid, SSID_LEN);
   1551 
   1552 	ret |= get_parmeter_from_string(&str_ptr, "SEC=", PTYPE_STRING,  ap_cfg->sec, SEC_LEN);
   1553 
   1554 	ret |= get_parmeter_from_string(&str_ptr, "KEY=", PTYPE_STRING,  ap_cfg->key, KEY_LEN);
   1555 
   1556 	ret |= get_parmeter_from_string(&str_ptr, "CHANNEL=", PTYPE_INTDEC, &ap_cfg->channel, 5);
   1557 
   1558 	ret |= get_parmeter_from_string(&str_ptr, "PREAMBLE=", PTYPE_INTDEC, &ap_cfg->preamble, 5);
   1559 
   1560 	ret |= get_parmeter_from_string(&str_ptr, "MAX_SCB=", PTYPE_INTDEC,  &ap_cfg->max_scb, 5);
   1561 
   1562 	return ret;
   1563 }
   1564 #endif
   1565 
   1566 
   1567 #ifdef SOFTAP
   1568 static int iwpriv_set_ap_config(struct net_device *dev,
   1569 		struct iw_request_info *info,
   1570 		union iwreq_data *wrqu,
   1571 		char *ext)
   1572 {
   1573 	int res = 0;
   1574 	char  *extra = NULL;
   1575 	struct ap_profile *ap_cfg = &my_ap;
   1576 
   1577 	WL_TRACE(("> Got IWPRIV SET_AP IOCTL: info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
   1578 		info->cmd, info->flags,
   1579 		wrqu->data.pointer, wrqu->data.length));
   1580 
   1581 	if (wrqu->data.length != 0) {
   1582 
   1583 		char *str_ptr;
   1584 
   1585 		if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
   1586 			return -ENOMEM;
   1587 
   1588 		if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
   1589 			kfree(extra);
   1590 			return -EFAULT;
   1591 		}
   1592 
   1593 		extra[wrqu->data.length] = 0;
   1594 		WL_SOFTAP((" Got str param in iw_point:\n %s\n", extra));
   1595 
   1596 		memset(ap_cfg, 0, sizeof(struct ap_profile));
   1597 
   1598 		str_ptr = extra;
   1599 
   1600 		if ((res = init_ap_profile_from_string(extra, ap_cfg)) < 0) {
   1601 			WL_ERROR(("%s failed to parse %d\n", __FUNCTION__, res));
   1602 			kfree(extra);
   1603 			return -1;
   1604 		}
   1605 
   1606 	} else {
   1607 		WL_ERROR(("IWPRIV argument len = 0 \n"));
   1608 		return -1;
   1609 	}
   1610 
   1611 	if ((res = set_ap_cfg(dev, ap_cfg)) < 0)
   1612 		WL_ERROR(("%s failed to set_ap_cfg %d\n", __FUNCTION__, res));
   1613 
   1614 	kfree(extra);
   1615 
   1616 	return res;
   1617 }
   1618 #endif
   1619 
   1620 
   1621 #ifdef SOFTAP
   1622 static int iwpriv_get_assoc_list(struct net_device *dev,
   1623 		struct iw_request_info *info,
   1624 		union iwreq_data *p_iwrq,
   1625 		char *extra)
   1626 {
   1627 	int i, ret = 0;
   1628 	char mac_buf[256];
   1629 	struct maclist *sta_maclist = (struct maclist *)mac_buf;
   1630 
   1631 	char mac_lst[256];
   1632 	char *p_mac_str;
   1633 
   1634 	WL_TRACE(("\n %s: IWPRIV IOCTL: cmd:%hx, flags:%hx, extra:%p, iwp.len:%d, \
   1635 		iwp.len:%p, iwp.flags:%x  \n", __FUNCTION__, info->cmd, info->flags, \
   1636 		extra, p_iwrq->data.length, p_iwrq->data.pointer, p_iwrq->data.flags));
   1637 
   1638 	WL_SOFTAP(("extra:%s\n", extra));
   1639 	print_buf((u8 *)p_iwrq, 16, 0);
   1640 
   1641 	memset(sta_maclist, 0, sizeof(mac_buf));
   1642 
   1643 	sta_maclist->count = 8;
   1644 
   1645 	WL_TRACE((" net device:%s, buf_sz:%d\n", dev->name, sizeof(mac_buf)));
   1646 	get_assoc_sta_list(dev, mac_buf, 256);
   1647 	WL_TRACE((" got %d stations\n", sta_maclist->count));
   1648 
   1649 	memset(mac_lst, 0, sizeof(mac_lst));
   1650 	p_mac_str = mac_lst;
   1651 
   1652 	for (i = 0; i < 8; i++) {
   1653 		struct ether_addr *id = &sta_maclist->ea[i];
   1654 
   1655 		WL_SOFTAP(("dhd_drv>> sta_mac[%d] :", i));
   1656 		print_buf((unsigned char *)&sta_maclist->ea[i], 6, 0);
   1657 
   1658 		p_mac_str += snprintf(p_mac_str, MAX_WX_STRING,
   1659 			"Mac[%d]=%02X:%02X:%02X:%02X:%02X:%02X\n", i,
   1660 			id->octet[0], id->octet[1], id->octet[2],
   1661 			id->octet[3], id->octet[4], id->octet[5]);
   1662 
   1663 	}
   1664 
   1665 	p_iwrq->data.length = strlen(mac_lst);
   1666 
   1667 	WL_TRACE(("u.pointer:%p\n", p_iwrq->data.pointer));
   1668 	WL_TRACE(("resulting str:\n%s \n len:%d\n\n", mac_lst, p_iwrq->data.length));
   1669 
   1670 	if (p_iwrq->data.length) {
   1671 		if (copy_to_user(p_iwrq->data.pointer, mac_lst, p_iwrq->data.length)) {
   1672 			WL_ERROR(("%s: Can't copy to user\n", __FUNCTION__));
   1673 			return -EFAULT;
   1674 		}
   1675 	}
   1676 
   1677 	WL_TRACE(("Exited %s \n", __FUNCTION__));
   1678 	return ret;
   1679 }
   1680 #endif
   1681 
   1682 
   1683 #ifdef SOFTAP
   1684 static int iwpriv_set_mac_filters(struct net_device *dev,
   1685 		struct iw_request_info *info,
   1686 		union iwreq_data *wrqu,
   1687 		char *ext)
   1688 {
   1689 
   1690 	int i, ret = -1;
   1691 	char *extra = NULL;
   1692 	u8  macfilt[8][6];
   1693 	int mac_cnt = 0;
   1694 	char sub_cmd[16];
   1695 
   1696 	WL_TRACE((">>> Got IWPRIV SET_MAC_FILTER IOCTL:  info->cmd:%x, \
   1697 			info->flags:%x, u.data:%p, u.len:%d\n",
   1698 			info->cmd, info->flags,
   1699 			wrqu->data.pointer, wrqu->data.length));
   1700 
   1701 	if (wrqu->data.length != 0) {
   1702 
   1703 		char *str_ptr;
   1704 
   1705 		if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
   1706 			return -ENOMEM;
   1707 
   1708 		if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
   1709 			kfree(extra);
   1710 			return -EFAULT;
   1711 		}
   1712 
   1713 		extra[wrqu->data.length] = 0;
   1714 		WL_SOFTAP((" Got parameter string in iw_point:\n %s \n", extra));
   1715 
   1716 		memset(macfilt, 0, sizeof(macfilt));
   1717 		memset(sub_cmd, 0, sizeof(sub_cmd));
   1718 
   1719 		str_ptr = extra;
   1720 
   1721 		if (get_parmeter_from_string(&str_ptr, "ASCII_CMD=", PTYPE_STRING, sub_cmd, 15) != 0) {
   1722 			goto exit_proc;
   1723 		}
   1724 
   1725 #define MAC_FILT_MAX 8
   1726 
   1727 		if (strncmp(sub_cmd, "MAC_FLT_W", strlen("MAC_FLT_W"))) {
   1728 			WL_ERROR(("ERROR: sub_cmd:%s != 'MAC_FLT_W'!\n", sub_cmd));
   1729 			goto exit_proc;
   1730 		}
   1731 
   1732 		if (get_parmeter_from_string(&str_ptr, "MAC_CNT=",
   1733 			PTYPE_INTDEC, &mac_cnt, 4) != 0) {
   1734 			WL_ERROR(("ERROR: MAC_CNT param is missing \n"));
   1735 			goto exit_proc;
   1736 		}
   1737 
   1738 		if (mac_cnt > MAC_FILT_MAX) {
   1739 			WL_ERROR(("ERROR: number of MAC filters > MAX\n"));
   1740 			goto exit_proc;
   1741 		}
   1742 
   1743 		for (i = 0; i < mac_cnt; i++) {
   1744 			if (get_parmeter_from_string(&str_ptr, "MAC=",
   1745 				PTYPE_STR_HEX, macfilt[i], 12) != 0) {
   1746 				WL_ERROR(("ERROR: MAC_filter[%d] is missing !\n", i));
   1747 				goto exit_proc;
   1748 			}
   1749 		}
   1750 
   1751 		for (i = 0; i < mac_cnt; i++) {
   1752 			WL_SOFTAP(("mac_filt[%d]:", i));
   1753 			print_buf(macfilt[i], 6, 0);
   1754 		}
   1755 
   1756 		wrqu->data.pointer = NULL;
   1757 		wrqu->data.length = 0;
   1758 		ret = 0;
   1759 
   1760 	} else {
   1761 		WL_ERROR(("IWPRIV argument len is 0\n"));
   1762 		return -1;
   1763 	}
   1764 
   1765 	exit_proc:
   1766 	kfree(extra);
   1767 	return ret;
   1768 }
   1769 #endif
   1770 
   1771 #endif
   1772 
   1773 #if WIRELESS_EXT < 13
   1774 struct iw_request_info
   1775 {
   1776 	__u16		cmd;
   1777 	__u16		flags;
   1778 };
   1779 
   1780 typedef int (*iw_handler)(struct net_device *dev,
   1781 		struct iw_request_info *info,
   1782 		void *wrqu,
   1783 		char *extra);
   1784 #endif
   1785 
   1786 static int
   1787 wl_iw_config_commit(
   1788 	struct net_device *dev,
   1789 	struct iw_request_info *info,
   1790 	void *zwrq,
   1791 	char *extra
   1792 )
   1793 {
   1794 	wlc_ssid_t ssid;
   1795 	int error;
   1796 	struct sockaddr bssid;
   1797 
   1798 	WL_TRACE(("%s: SIOCSIWCOMMIT\n", dev->name));
   1799 
   1800 	if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid))))
   1801 		return error;
   1802 
   1803 	ssid.SSID_len = dtoh32(ssid.SSID_len);
   1804 
   1805 	if (!ssid.SSID_len)
   1806 		return 0;
   1807 
   1808 	bzero(&bssid, sizeof(struct sockaddr));
   1809 	if ((error = dev_wlc_ioctl(dev, WLC_REASSOC, &bssid, ETHER_ADDR_LEN))) {
   1810 		WL_ERROR(("%s: WLC_REASSOC to %s failed \n", __FUNCTION__, ssid.SSID));
   1811 		return error;
   1812 	}
   1813 
   1814 	return 0;
   1815 }
   1816 
   1817 static int
   1818 wl_iw_get_name(
   1819 	struct net_device *dev,
   1820 	struct iw_request_info *info,
   1821 	char *cwrq,
   1822 	char *extra
   1823 )
   1824 {
   1825 	WL_TRACE(("%s: SIOCGIWNAME\n", dev->name));
   1826 
   1827 	strcpy(cwrq, "IEEE 802.11-DS");
   1828 
   1829 	return 0;
   1830 }
   1831 
   1832 static int
   1833 wl_iw_set_freq(
   1834 	struct net_device *dev,
   1835 	struct iw_request_info *info,
   1836 	struct iw_freq *fwrq,
   1837 	char *extra
   1838 )
   1839 {
   1840 	int error, chan;
   1841 	uint sf = 0;
   1842 
   1843 	WL_TRACE(("%s %s: SIOCSIWFREQ\n", __FUNCTION__, dev->name));
   1844 
   1845 #if defined(SOFTAP)
   1846 	if (ap_cfg_running) {
   1847 		WL_TRACE(("%s:>> not executed, 'SOFT_AP is active' \n", __FUNCTION__));
   1848 		return 0;
   1849 	}
   1850 #endif
   1851 
   1852 
   1853 	if (fwrq->e == 0 && fwrq->m < MAXCHANNEL) {
   1854 		chan = fwrq->m;
   1855 	}
   1856 
   1857 
   1858 	else {
   1859 
   1860 		if (fwrq->e >= 6) {
   1861 			fwrq->e -= 6;
   1862 			while (fwrq->e--)
   1863 				fwrq->m *= 10;
   1864 		} else if (fwrq->e < 6) {
   1865 			while (fwrq->e++ < 6)
   1866 				fwrq->m /= 10;
   1867 		}
   1868 
   1869 	if (fwrq->m > 4000 && fwrq->m < 5000)
   1870 		sf = WF_CHAN_FACTOR_4_G;
   1871 
   1872 		chan = wf_mhz2channel(fwrq->m, sf);
   1873 	}
   1874 	chan = htod32(chan);
   1875 	if ((error = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &chan, sizeof(chan))))
   1876 		return error;
   1877 
   1878 	g_wl_iw_params.target_channel = chan;
   1879 
   1880 	return -EINPROGRESS;
   1881 }
   1882 
   1883 static int
   1884 wl_iw_get_freq(
   1885 	struct net_device *dev,
   1886 	struct iw_request_info *info,
   1887 	struct iw_freq *fwrq,
   1888 	char *extra
   1889 )
   1890 {
   1891 	channel_info_t ci;
   1892 	int error;
   1893 
   1894 	WL_TRACE(("%s: SIOCGIWFREQ\n", dev->name));
   1895 
   1896 	if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
   1897 		return error;
   1898 
   1899 	fwrq->m = dtoh32(ci.hw_channel);
   1900 	fwrq->e = dtoh32(0);
   1901 	return 0;
   1902 }
   1903 
   1904 static int
   1905 wl_iw_set_mode(
   1906 	struct net_device *dev,
   1907 	struct iw_request_info *info,
   1908 	__u32 *uwrq,
   1909 	char *extra
   1910 )
   1911 {
   1912 	int infra = 0, ap = 0, error = 0;
   1913 
   1914 	WL_TRACE(("%s: SIOCSIWMODE\n", dev->name));
   1915 
   1916 	switch (*uwrq) {
   1917 	case IW_MODE_MASTER:
   1918 		infra = ap = 1;
   1919 		break;
   1920 	case IW_MODE_ADHOC:
   1921 	case IW_MODE_AUTO:
   1922 		break;
   1923 	case IW_MODE_INFRA:
   1924 		infra = 1;
   1925 		break;
   1926 	default:
   1927 		return -EINVAL;
   1928 	}
   1929 	infra = htod32(infra);
   1930 	ap = htod32(ap);
   1931 
   1932 	if ((error = dev_wlc_ioctl(dev, WLC_SET_INFRA, &infra, sizeof(infra))) ||
   1933 	    (error = dev_wlc_ioctl(dev, WLC_SET_AP, &ap, sizeof(ap))))
   1934 		return error;
   1935 
   1936 
   1937 	return -EINPROGRESS;
   1938 }
   1939 
   1940 static int
   1941 wl_iw_get_mode(
   1942 	struct net_device *dev,
   1943 	struct iw_request_info *info,
   1944 	__u32 *uwrq,
   1945 	char *extra
   1946 )
   1947 {
   1948 	int error, infra = 0, ap = 0;
   1949 
   1950 	WL_TRACE(("%s: SIOCGIWMODE\n", dev->name));
   1951 
   1952 	if ((error = dev_wlc_ioctl(dev, WLC_GET_INFRA, &infra, sizeof(infra))) ||
   1953 	    (error = dev_wlc_ioctl(dev, WLC_GET_AP, &ap, sizeof(ap))))
   1954 		return error;
   1955 
   1956 	infra = dtoh32(infra);
   1957 	ap = dtoh32(ap);
   1958 	*uwrq = infra ? ap ? IW_MODE_MASTER : IW_MODE_INFRA : IW_MODE_ADHOC;
   1959 
   1960 	return 0;
   1961 }
   1962 
   1963 static int
   1964 wl_iw_get_range(
   1965 	struct net_device *dev,
   1966 	struct iw_request_info *info,
   1967 	struct iw_point *dwrq,
   1968 	char *extra
   1969 )
   1970 {
   1971 	struct iw_range *range = (struct iw_range *) extra;
   1972 	wl_uint32_list_t *list;
   1973 	wl_rateset_t rateset;
   1974 	int8 *channels;
   1975 	int error, i, k;
   1976 	uint sf, ch;
   1977 
   1978 	int phytype;
   1979 	int bw_cap = 0, sgi_tx = 0, nmode = 0;
   1980 	channel_info_t ci;
   1981 	uint8 nrate_list2copy = 0;
   1982 	uint16 nrate_list[4][8] = { {13, 26, 39, 52, 78, 104, 117, 130},
   1983 		{14, 29, 43, 58, 87, 116, 130, 144},
   1984 		{27, 54, 81, 108, 162, 216, 243, 270},
   1985 		{30, 60, 90, 120, 180, 240, 270, 300}};
   1986 
   1987 	WL_TRACE(("%s: SIOCGIWRANGE\n", dev->name));
   1988 
   1989 	if (!extra)
   1990 		return -EINVAL;
   1991 
   1992 	channels = kmalloc((MAXCHANNEL+1)*4, GFP_KERNEL);
   1993 	if (!channels) {
   1994 		WL_ERROR(("Could not alloc channels\n"));
   1995 		return -ENOMEM;
   1996 	}
   1997 	list = (wl_uint32_list_t *)channels;
   1998 
   1999 	dwrq->length = sizeof(struct iw_range);
   2000 	memset(range, 0, sizeof(range));
   2001 
   2002 	range->min_nwid = range->max_nwid = 0;
   2003 
   2004 	list->count = htod32(MAXCHANNEL);
   2005 	if ((error = dev_wlc_ioctl(dev, WLC_GET_VALID_CHANNELS, channels, (MAXCHANNEL+1)*4))) {
   2006 		kfree(channels);
   2007 		return error;
   2008 	}
   2009 	for (i = 0; i < dtoh32(list->count) && i < IW_MAX_FREQUENCIES; i++) {
   2010 		range->freq[i].i = dtoh32(list->element[i]);
   2011 
   2012 		ch = dtoh32(list->element[i]);
   2013 		if (ch <= CH_MAX_2G_CHANNEL)
   2014 			sf = WF_CHAN_FACTOR_2_4_G;
   2015 		else
   2016 			sf = WF_CHAN_FACTOR_5_G;
   2017 
   2018 		range->freq[i].m = wf_channel2mhz(ch, sf);
   2019 		range->freq[i].e = 6;
   2020 	}
   2021 	range->num_frequency = range->num_channels = i;
   2022 
   2023 	range->max_qual.qual = 5;
   2024 
   2025 	range->max_qual.level = 0x100 - 200;
   2026 
   2027 	range->max_qual.noise = 0x100 - 200;
   2028 
   2029 	range->sensitivity = 65535;
   2030 
   2031 #if WIRELESS_EXT > 11
   2032 
   2033 	range->avg_qual.qual = 3;
   2034 
   2035 	range->avg_qual.level = 0x100 + WL_IW_RSSI_GOOD;
   2036 
   2037 	range->avg_qual.noise = 0x100 - 75;
   2038 #endif
   2039 
   2040 	if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset)))) {
   2041 		kfree(channels);
   2042 		return error;
   2043 	}
   2044 	rateset.count = dtoh32(rateset.count);
   2045 	range->num_bitrates = rateset.count;
   2046 	for (i = 0; i < rateset.count && i < IW_MAX_BITRATES; i++)
   2047 		range->bitrate[i] = (rateset.rates[i]& 0x7f) * 500000;
   2048 	dev_wlc_intvar_get(dev, "nmode", &nmode);
   2049 	dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
   2050 
   2051 	if (nmode == 1 && phytype == WLC_PHY_TYPE_SSN) {
   2052 		dev_wlc_intvar_get(dev, "mimo_bw_cap", &bw_cap);
   2053 		dev_wlc_intvar_get(dev, "sgi_tx", &sgi_tx);
   2054 		dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t));
   2055 		ci.hw_channel = dtoh32(ci.hw_channel);
   2056 
   2057 		if (bw_cap == 0 ||
   2058 			(bw_cap == 2 && ci.hw_channel <= 14)) {
   2059 			if (sgi_tx == 0)
   2060 				nrate_list2copy = 0;
   2061 			else
   2062 				nrate_list2copy = 1;
   2063 		}
   2064 		if (bw_cap == 1 ||
   2065 			(bw_cap == 2 && ci.hw_channel >= 36)) {
   2066 			if (sgi_tx == 0)
   2067 				nrate_list2copy = 2;
   2068 			else
   2069 				nrate_list2copy = 3;
   2070 		}
   2071 		range->num_bitrates += 8;
   2072 		for (k = 0; i < range->num_bitrates; k++, i++) {
   2073 
   2074 			range->bitrate[i] = (nrate_list[nrate_list2copy][k]) * 500000;
   2075 		}
   2076 	}
   2077 
   2078 	if ((error = dev_wlc_ioctl(dev, WLC_GET_PHYTYPE, &i, sizeof(i)))) {
   2079 		kfree(channels);
   2080 		return error;
   2081 	}
   2082 	i = dtoh32(i);
   2083 	if (i == WLC_PHY_TYPE_A)
   2084 		range->throughput = 24000000;
   2085 	else
   2086 		range->throughput = 1500000;
   2087 
   2088 	range->min_rts = 0;
   2089 	range->max_rts = 2347;
   2090 	range->min_frag = 256;
   2091 	range->max_frag = 2346;
   2092 
   2093 	range->max_encoding_tokens = DOT11_MAX_DEFAULT_KEYS;
   2094 	range->num_encoding_sizes = 4;
   2095 	range->encoding_size[0] = WEP1_KEY_SIZE;
   2096 	range->encoding_size[1] = WEP128_KEY_SIZE;
   2097 #if WIRELESS_EXT > 17
   2098 	range->encoding_size[2] = TKIP_KEY_SIZE;
   2099 #else
   2100 	range->encoding_size[2] = 0;
   2101 #endif
   2102 	range->encoding_size[3] = AES_KEY_SIZE;
   2103 
   2104 	range->min_pmp = 0;
   2105 	range->max_pmp = 0;
   2106 	range->min_pmt = 0;
   2107 	range->max_pmt = 0;
   2108 	range->pmp_flags = 0;
   2109 	range->pm_capa = 0;
   2110 
   2111 	range->num_txpower = 2;
   2112 	range->txpower[0] = 1;
   2113 	range->txpower[1] = 255;
   2114 	range->txpower_capa = IW_TXPOW_MWATT;
   2115 
   2116 #if WIRELESS_EXT > 10
   2117 	range->we_version_compiled = WIRELESS_EXT;
   2118 	range->we_version_source = 19;
   2119 
   2120 	range->retry_capa = IW_RETRY_LIMIT;
   2121 	range->retry_flags = IW_RETRY_LIMIT;
   2122 	range->r_time_flags = 0;
   2123 
   2124 	range->min_retry = 1;
   2125 	range->max_retry = 255;
   2126 
   2127 	range->min_r_time = 0;
   2128 	range->max_r_time = 0;
   2129 #endif
   2130 
   2131 #if WIRELESS_EXT > 17
   2132 	range->enc_capa = IW_ENC_CAPA_WPA;
   2133 	range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
   2134 	range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
   2135 #ifdef BCMWPA2
   2136 	range->enc_capa |= IW_ENC_CAPA_WPA2;
   2137 #endif
   2138 
   2139 	IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
   2140 
   2141 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
   2142 	IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
   2143 	IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP);
   2144 	IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE);
   2145 #ifdef BCMWPA2
   2146 	IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND);
   2147 #endif
   2148 #endif
   2149 
   2150 	kfree(channels);
   2151 
   2152 	return 0;
   2153 }
   2154 
   2155 static int
   2156 rssi_to_qual(int rssi)
   2157 {
   2158 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
   2159 		return 0;
   2160 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
   2161 		return 1;
   2162 	else if (rssi <= WL_IW_RSSI_LOW)
   2163 		return 2;
   2164 	else if (rssi <= WL_IW_RSSI_GOOD)
   2165 		return 3;
   2166 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
   2167 		return 4;
   2168 	else
   2169 		return 5;
   2170 }
   2171 
   2172 static int
   2173 wl_iw_set_spy(
   2174 	struct net_device *dev,
   2175 	struct iw_request_info *info,
   2176 	struct iw_point *dwrq,
   2177 	char *extra
   2178 )
   2179 {
   2180 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   2181 	struct sockaddr *addr = (struct sockaddr *) extra;
   2182 	int i;
   2183 
   2184 	WL_TRACE(("%s: SIOCSIWSPY\n", dev->name));
   2185 
   2186 	if (!extra)
   2187 		return -EINVAL;
   2188 
   2189 	iw->spy_num = MIN(ARRAYSIZE(iw->spy_addr), dwrq->length);
   2190 	for (i = 0; i < iw->spy_num; i++)
   2191 		memcpy(&iw->spy_addr[i], addr[i].sa_data, ETHER_ADDR_LEN);
   2192 	memset(iw->spy_qual, 0, sizeof(iw->spy_qual));
   2193 
   2194 	return 0;
   2195 }
   2196 
   2197 static int
   2198 wl_iw_get_spy(
   2199 	struct net_device *dev,
   2200 	struct iw_request_info *info,
   2201 	struct iw_point *dwrq,
   2202 	char *extra
   2203 )
   2204 {
   2205 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   2206 	struct sockaddr *addr = (struct sockaddr *) extra;
   2207 	struct iw_quality *qual = (struct iw_quality *) &addr[iw->spy_num];
   2208 	int i;
   2209 
   2210 	WL_TRACE(("%s: SIOCGIWSPY\n", dev->name));
   2211 
   2212 	if (!extra)
   2213 		return -EINVAL;
   2214 
   2215 	dwrq->length = iw->spy_num;
   2216 	for (i = 0; i < iw->spy_num; i++) {
   2217 		memcpy(addr[i].sa_data, &iw->spy_addr[i], ETHER_ADDR_LEN);
   2218 		addr[i].sa_family = AF_UNIX;
   2219 		memcpy(&qual[i], &iw->spy_qual[i], sizeof(struct iw_quality));
   2220 		iw->spy_qual[i].updated = 0;
   2221 	}
   2222 
   2223 	return 0;
   2224 }
   2225 
   2226 
   2227 static int
   2228 wl_iw_ch_to_chanspec(int ch, wl_join_params_t *join_params, int *join_params_size)
   2229 {
   2230 	chanspec_t chanspec = 0;
   2231 
   2232 	if (ch != 0) {
   2233 
   2234 		join_params->params.chanspec_num = 1;
   2235 		join_params->params.chanspec_list[0] = ch;
   2236 
   2237 		if (join_params->params.chanspec_list[0])
   2238 			chanspec |= WL_CHANSPEC_BAND_2G;
   2239 		else
   2240 			chanspec |= WL_CHANSPEC_BAND_5G;
   2241 
   2242 		chanspec |= WL_CHANSPEC_BW_20;
   2243 		chanspec |= WL_CHANSPEC_CTL_SB_NONE;
   2244 
   2245 		*join_params_size += WL_ASSOC_PARAMS_FIXED_SIZE +
   2246 			join_params->params.chanspec_num * sizeof(chanspec_t);
   2247 
   2248 		join_params->params.chanspec_list[0]  &= WL_CHANSPEC_CHAN_MASK;
   2249 		join_params->params.chanspec_list[0] |= chanspec;
   2250 		join_params->params.chanspec_list[0] =
   2251 		        htodchanspec(join_params->params.chanspec_list[0]);
   2252 
   2253 		join_params->params.chanspec_num = htod32(join_params->params.chanspec_num);
   2254 
   2255 		WL_TRACE(("%s  join_params->params.chanspec_list[0]= %X\n", \
   2256 			__FUNCTION__, join_params->params.chanspec_list[0]));
   2257 	}
   2258 	return 1;
   2259 }
   2260 
   2261 static int
   2262 wl_iw_set_wap(
   2263 	struct net_device *dev,
   2264 	struct iw_request_info *info,
   2265 	struct sockaddr *awrq,
   2266 	char *extra
   2267 )
   2268 {
   2269 	int error = -EINVAL;
   2270 	wl_join_params_t join_params;
   2271 	int join_params_size;
   2272 
   2273 	WL_TRACE(("%s: SIOCSIWAP\n", dev->name));
   2274 
   2275 	if (awrq->sa_family != ARPHRD_ETHER) {
   2276 		WL_ERROR(("Invalid Header...sa_family\n"));
   2277 		return -EINVAL;
   2278 	}
   2279 
   2280 
   2281 	if (ETHER_ISBCAST(awrq->sa_data) || ETHER_ISNULLADDR(awrq->sa_data)) {
   2282 		scb_val_t scbval;
   2283 
   2284 		bzero(&scbval, sizeof(scb_val_t));
   2285 
   2286 		(void) dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
   2287 		return 0;
   2288 	}
   2289 
   2290 
   2291 
   2292 	memset(&join_params, 0, sizeof(join_params));
   2293 	join_params_size = sizeof(join_params.ssid);
   2294 
   2295 	memcpy(join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
   2296 	join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
   2297 	memcpy(&join_params.params.bssid, awrq->sa_data, ETHER_ADDR_LEN);
   2298 
   2299 	WL_TRACE(("%s  target_channel=%d\n", __FUNCTION__, g_wl_iw_params.target_channel));
   2300 	wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
   2301 
   2302 	if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
   2303 		WL_ERROR(("%s Invalid ioctl data=%d\n", __FUNCTION__, error));
   2304 		return error;
   2305 	}
   2306 
   2307 	if (g_ssid.SSID_len) {
   2308 		WL_TRACE(("%s: join SSID=%s BSSID="MACSTR" ch=%d\n", __FUNCTION__,  \
   2309 			g_ssid.SSID, MAC2STR((u8 *)awrq->sa_data), \
   2310 			g_wl_iw_params.target_channel));
   2311 	}
   2312 
   2313 
   2314 	memset(&g_ssid, 0, sizeof(g_ssid));
   2315 	return 0;
   2316 }
   2317 
   2318 static int
   2319 wl_iw_get_wap(
   2320 	struct net_device *dev,
   2321 	struct iw_request_info *info,
   2322 	struct sockaddr *awrq,
   2323 	char *extra
   2324 )
   2325 {
   2326 	WL_TRACE(("%s: SIOCGIWAP\n", dev->name));
   2327 
   2328 	awrq->sa_family = ARPHRD_ETHER;
   2329 	memset(awrq->sa_data, 0, ETHER_ADDR_LEN);
   2330 
   2331 
   2332 	(void) dev_wlc_ioctl(dev, WLC_GET_BSSID, awrq->sa_data, ETHER_ADDR_LEN);
   2333 
   2334 	return 0;
   2335 }
   2336 
   2337 #if WIRELESS_EXT > 17
   2338 static int
   2339 wl_iw_mlme(
   2340 	struct net_device *dev,
   2341 	struct iw_request_info *info,
   2342 	struct sockaddr *awrq,
   2343 	char *extra
   2344 )
   2345 {
   2346 	struct iw_mlme *mlme;
   2347 	scb_val_t scbval;
   2348 	int error  = -EINVAL;
   2349 
   2350 	WL_TRACE(("%s: SIOCSIWMLME DISASSOC/DEAUTH\n", dev->name));
   2351 
   2352 	mlme = (struct iw_mlme *)extra;
   2353 	if (mlme == NULL) {
   2354 		WL_ERROR(("Invalid ioctl data.\n"));
   2355 		return error;
   2356 	}
   2357 
   2358 	scbval.val = mlme->reason_code;
   2359 	bcopy(&mlme->addr.sa_data, &scbval.ea, ETHER_ADDR_LEN);
   2360 
   2361 	if (mlme->cmd == IW_MLME_DISASSOC) {
   2362 		scbval.val = htod32(scbval.val);
   2363 		error = dev_wlc_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t));
   2364 	}
   2365 	else if (mlme->cmd == IW_MLME_DEAUTH) {
   2366 		scbval.val = htod32(scbval.val);
   2367 		error = dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
   2368 			sizeof(scb_val_t));
   2369 	}
   2370 	else {
   2371 		WL_ERROR(("Invalid ioctl data.\n"));
   2372 		return error;
   2373 	}
   2374 
   2375 	return error;
   2376 }
   2377 #endif
   2378 
   2379 #ifndef WL_IW_USE_ISCAN
   2380 static int
   2381 wl_iw_get_aplist(
   2382 	struct net_device *dev,
   2383 	struct iw_request_info *info,
   2384 	struct iw_point *dwrq,
   2385 	char *extra
   2386 )
   2387 {
   2388 	wl_scan_results_t *list;
   2389 	struct sockaddr *addr = (struct sockaddr *) extra;
   2390 	struct iw_quality qual[IW_MAX_AP];
   2391 	wl_bss_info_t *bi = NULL;
   2392 	int error, i;
   2393 	uint buflen = dwrq->length;
   2394 
   2395 	WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
   2396 
   2397 	if (!extra)
   2398 		return -EINVAL;
   2399 
   2400 	list = kmalloc(buflen, GFP_KERNEL);
   2401 	if (!list)
   2402 		return -ENOMEM;
   2403 	memset(list, 0, buflen);
   2404 	list->buflen = htod32(buflen);
   2405 	if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, buflen))) {
   2406 		WL_ERROR(("%d: Scan results error %d\n", __LINE__, error));
   2407 		kfree(list);
   2408 		return error;
   2409 	}
   2410 	list->buflen = dtoh32(list->buflen);
   2411 	list->version = dtoh32(list->version);
   2412 	list->count = dtoh32(list->count);
   2413 	if (list->version != WL_BSS_INFO_VERSION) {
   2414 		WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \
   2415 			 __FUNCTION__, list->version));
   2416 		kfree(list);
   2417 		return -EINVAL;
   2418 	}
   2419 
   2420 	for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
   2421 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
   2422 		ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
   2423 			buflen));
   2424 
   2425 
   2426 		if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
   2427 			continue;
   2428 
   2429 
   2430 		memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
   2431 		addr[dwrq->length].sa_family = ARPHRD_ETHER;
   2432 		qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
   2433 		qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
   2434 		qual[dwrq->length].noise = 0x100 + bi->phy_noise;
   2435 
   2436 
   2437 #if WIRELESS_EXT > 18
   2438 		qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
   2439 #else
   2440 		qual[dwrq->length].updated = 7;
   2441 #endif
   2442 
   2443 		dwrq->length++;
   2444 	}
   2445 
   2446 	kfree(list);
   2447 
   2448 	if (dwrq->length) {
   2449 		memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
   2450 
   2451 		dwrq->flags = 1;
   2452 	}
   2453 	return 0;
   2454 }
   2455 #endif
   2456 
   2457 #ifdef WL_IW_USE_ISCAN
   2458 static int
   2459 wl_iw_iscan_get_aplist(
   2460 	struct net_device *dev,
   2461 	struct iw_request_info *info,
   2462 	struct iw_point *dwrq,
   2463 	char *extra
   2464 )
   2465 {
   2466 	wl_scan_results_t *list;
   2467 	iscan_buf_t * buf;
   2468 	iscan_info_t *iscan = g_iscan;
   2469 
   2470 	struct sockaddr *addr = (struct sockaddr *) extra;
   2471 	struct iw_quality qual[IW_MAX_AP];
   2472 	wl_bss_info_t *bi = NULL;
   2473 	int i;
   2474 
   2475 	WL_TRACE(("%s: SIOCGIWAPLIST\n", dev->name));
   2476 
   2477 	if (!extra)
   2478 		return -EINVAL;
   2479 
   2480 	if ((!iscan) || (iscan->sysioc_pid < 0)) {
   2481 		WL_ERROR(("%s error\n", __FUNCTION__));
   2482 		return 0;
   2483 	}
   2484 
   2485 	buf = iscan->list_hdr;
   2486 
   2487 	while (buf) {
   2488 		list = &((wl_iscan_results_t*)buf->iscan_buf)->results;
   2489 		if (list->version != WL_BSS_INFO_VERSION) {
   2490 			WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \
   2491 				__FUNCTION__, list->version));
   2492 			return -EINVAL;
   2493 		}
   2494 
   2495 		bi = NULL;
   2496 		for (i = 0, dwrq->length = 0; i < list->count && dwrq->length < IW_MAX_AP; i++) {
   2497 			bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length))
   2498 			          : list->bss_info;
   2499 			ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
   2500 				WLC_IW_ISCAN_MAXLEN));
   2501 
   2502 
   2503 			if (!(dtoh16(bi->capability) & DOT11_CAP_ESS))
   2504 				continue;
   2505 
   2506 
   2507 			memcpy(addr[dwrq->length].sa_data, &bi->BSSID, ETHER_ADDR_LEN);
   2508 			addr[dwrq->length].sa_family = ARPHRD_ETHER;
   2509 			qual[dwrq->length].qual = rssi_to_qual(dtoh16(bi->RSSI));
   2510 			qual[dwrq->length].level = 0x100 + dtoh16(bi->RSSI);
   2511 			qual[dwrq->length].noise = 0x100 + bi->phy_noise;
   2512 
   2513 
   2514 #if WIRELESS_EXT > 18
   2515 			qual[dwrq->length].updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
   2516 #else
   2517 			qual[dwrq->length].updated = 7;
   2518 #endif
   2519 
   2520 			dwrq->length++;
   2521 		}
   2522 		buf = buf->next;
   2523 	}
   2524 	if (dwrq->length) {
   2525 		memcpy(&addr[dwrq->length], qual, sizeof(struct iw_quality) * dwrq->length);
   2526 
   2527 		dwrq->flags = 1;
   2528 	}
   2529 	return 0;
   2530 }
   2531 
   2532 static int
   2533 wl_iw_iscan_prep(wl_scan_params_t *params, wlc_ssid_t *ssid)
   2534 {
   2535 	int err = 0;
   2536 
   2537 	memcpy(&params->bssid, &ether_bcast, ETHER_ADDR_LEN);
   2538 	params->bss_type = DOT11_BSSTYPE_ANY;
   2539 	params->scan_type = 0;
   2540 	params->nprobes = -1;
   2541 	params->active_time = -1;
   2542 	params->passive_time = -1;
   2543 	params->home_time = -1;
   2544 	params->channel_num = 0;
   2545 
   2546 	params->nprobes = htod32(params->nprobes);
   2547 	params->active_time = htod32(params->active_time);
   2548 	params->passive_time = htod32(params->passive_time);
   2549 	params->home_time = htod32(params->home_time);
   2550 	if (ssid && ssid->SSID_len)
   2551 		memcpy(&params->ssid, ssid, sizeof(wlc_ssid_t));
   2552 
   2553 	return err;
   2554 }
   2555 
   2556 static int
   2557 wl_iw_iscan(iscan_info_t *iscan, wlc_ssid_t *ssid, uint16 action)
   2558 {
   2559 	int err = 0;
   2560 
   2561 	iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
   2562 	iscan->iscan_ex_params_p->action = htod16(action);
   2563 	iscan->iscan_ex_params_p->scan_duration = htod16(0);
   2564 
   2565 	WL_SCAN(("%s : nprobes=%d\n", __FUNCTION__, iscan->iscan_ex_params_p->params.nprobes));
   2566 	WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
   2567 	WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
   2568 	WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
   2569 	WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
   2570 	WL_SCAN(("bss_type=%d\n", iscan->iscan_ex_params_p->params.bss_type));
   2571 
   2572 
   2573 	if ((err = dev_iw_iovar_setbuf(iscan->dev, "iscan", iscan->iscan_ex_params_p, \
   2574 		iscan->iscan_ex_param_size, iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
   2575 			WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
   2576 			err = -1;
   2577 	}
   2578 
   2579 	return err;
   2580 }
   2581 
   2582 static void
   2583 wl_iw_timerfunc(ulong data)
   2584 {
   2585 	iscan_info_t *iscan = (iscan_info_t *)data;
   2586 	if (iscan) {
   2587 		iscan->timer_on = 0;
   2588 		if (iscan->iscan_state != ISCAN_STATE_IDLE) {
   2589 			WL_SCAN(("timer trigger\n"));
   2590 			up(&iscan->sysioc_sem);
   2591 		}
   2592 	}
   2593 }
   2594 static void wl_iw_set_event_mask(struct net_device *dev)
   2595 {
   2596 	char eventmask[WL_EVENTING_MASK_LEN];
   2597 	char iovbuf[WL_EVENTING_MASK_LEN + 12];
   2598 
   2599 	dev_iw_iovar_getbuf(dev, "event_msgs", "", 0, iovbuf, sizeof(iovbuf));
   2600 	bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN);
   2601 	setbit(eventmask, WLC_E_SCAN_COMPLETE);
   2602 	dev_iw_iovar_setbuf(dev, "event_msgs", eventmask, WL_EVENTING_MASK_LEN,
   2603 		iovbuf, sizeof(iovbuf));
   2604 }
   2605 
   2606 static uint32
   2607 wl_iw_iscan_get(iscan_info_t *iscan)
   2608 {
   2609 	iscan_buf_t * buf;
   2610 	iscan_buf_t * ptr;
   2611 	wl_iscan_results_t * list_buf;
   2612 	wl_iscan_results_t list;
   2613 	wl_scan_results_t *results;
   2614 	uint32 status;
   2615 	int res;
   2616 
   2617 	mutex_lock(&wl_cache_lock);
   2618 	if (iscan->list_cur) {
   2619 		buf = iscan->list_cur;
   2620 		iscan->list_cur = buf->next;
   2621 	}
   2622 	else {
   2623 		buf = kmalloc(sizeof(iscan_buf_t), GFP_KERNEL);
   2624 		if (!buf) {
   2625 			WL_ERROR(("%s can't alloc iscan_buf_t : going to abort currect iscan\n", \
   2626 						__FUNCTION__));
   2627 			mutex_unlock(&wl_cache_lock);
   2628 			return WL_SCAN_RESULTS_NO_MEM;
   2629 		}
   2630 		buf->next = NULL;
   2631 		if (!iscan->list_hdr)
   2632 			iscan->list_hdr = buf;
   2633 		else {
   2634 			ptr = iscan->list_hdr;
   2635 			while (ptr->next) {
   2636 				ptr = ptr->next;
   2637 			}
   2638 			ptr->next = buf;
   2639 		}
   2640 	}
   2641 	memset(buf->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
   2642 	list_buf = (wl_iscan_results_t*)buf->iscan_buf;
   2643 	results = &list_buf->results;
   2644 	results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
   2645 	results->version = 0;
   2646 	results->count = 0;
   2647 
   2648 	memset(&list, 0, sizeof(list));
   2649 	list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
   2650 	res = dev_iw_iovar_getbuf(
   2651 		iscan->dev,
   2652 		"iscanresults",
   2653 		&list,
   2654 		WL_ISCAN_RESULTS_FIXED_SIZE,
   2655 		buf->iscan_buf,
   2656 		WLC_IW_ISCAN_MAXLEN);
   2657 	if (res == 0) {
   2658 		results->buflen = dtoh32(results->buflen);
   2659 		results->version = dtoh32(results->version);
   2660 		results->count = dtoh32(results->count);
   2661 		WL_SCAN(("results->count = %d\n", results->count));
   2662 
   2663 		WL_SCAN(("results->buflen = %d\n", results->buflen));
   2664 		status = dtoh32(list_buf->status);
   2665 	} else {
   2666 		WL_ERROR(("%s returns error %d\n", __FUNCTION__, res));
   2667 		status = WL_SCAN_RESULTS_NO_MEM;
   2668 	}
   2669 	mutex_unlock(&wl_cache_lock);
   2670 	return status;
   2671 }
   2672 
   2673 static void wl_iw_force_specific_scan(iscan_info_t *iscan)
   2674 {
   2675 	WL_TRACE(("%s force Specific SCAN for %s\n", __FUNCTION__, g_specific_ssid.SSID));
   2676 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2677 	rtnl_lock();
   2678 #endif
   2679 	(void) dev_wlc_ioctl(iscan->dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid));
   2680 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2681 	rtnl_unlock();
   2682 #endif
   2683 }
   2684 
   2685 static void wl_iw_send_scan_complete(iscan_info_t *iscan)
   2686 {
   2687 #ifndef SANDGATE2G
   2688 	union iwreq_data wrqu;
   2689 
   2690 	memset(&wrqu, 0, sizeof(wrqu));
   2691 
   2692 	wireless_send_event(iscan->dev, SIOCGIWSCAN, &wrqu, NULL);
   2693 	if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED)
   2694 		g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_READY;
   2695 	WL_TRACE(("Send Event ISCAN complete\n"));
   2696 #endif
   2697 }
   2698 
   2699 static int
   2700 _iscan_sysioc_thread(void *data)
   2701 {
   2702 	uint32 status;
   2703 	iscan_info_t *iscan = (iscan_info_t *)data;
   2704 	static bool iscan_pass_abort = FALSE;
   2705 
   2706 	DAEMONIZE("iscan_sysioc");
   2707 
   2708 	status = WL_SCAN_RESULTS_PARTIAL;
   2709 	while (down_interruptible(&iscan->sysioc_sem) == 0) {
   2710 
   2711 		net_os_wake_lock(iscan->dev);
   2712 
   2713 #if defined(SOFTAP)
   2714 		if (ap_cfg_running) {
   2715 			WL_SCAN(("%s skipping SCAN ops in AP mode !!!\n", __FUNCTION__));
   2716 			net_os_wake_unlock(iscan->dev);
   2717 			continue;
   2718 		}
   2719 #endif
   2720 
   2721 		if (iscan->timer_on) {
   2722 			iscan->timer_on = 0;
   2723 			del_timer_sync(&iscan->timer);
   2724 		}
   2725 
   2726 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2727 		rtnl_lock();
   2728 #endif
   2729 		status = wl_iw_iscan_get(iscan);
   2730 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2731 		rtnl_unlock();
   2732 #endif
   2733 
   2734 		if (g_scan_specified_ssid && (iscan_pass_abort == TRUE)) {
   2735 			WL_SCAN(("%s Get results from specific scan status=%d\n", __FUNCTION__, status));
   2736 			wl_iw_send_scan_complete(iscan);
   2737 			iscan_pass_abort = FALSE;
   2738 			status  = -1;
   2739 		}
   2740 
   2741 		switch (status) {
   2742 			case WL_SCAN_RESULTS_PARTIAL:
   2743 				WL_SCAN(("iscanresults incomplete\n"));
   2744 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2745 				rtnl_lock();
   2746 #endif
   2747 
   2748 				wl_iw_iscan(iscan, NULL, WL_SCAN_ACTION_CONTINUE);
   2749 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   2750 				rtnl_unlock();
   2751 #endif
   2752 
   2753 				mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
   2754 				iscan->timer_on = 1;
   2755 				break;
   2756 			case WL_SCAN_RESULTS_SUCCESS:
   2757 				WL_SCAN(("iscanresults complete\n"));
   2758 				iscan->iscan_state = ISCAN_STATE_IDLE;
   2759 				wl_iw_send_scan_complete(iscan);
   2760 				break;
   2761 			case WL_SCAN_RESULTS_PENDING:
   2762 				WL_SCAN(("iscanresults pending\n"));
   2763 
   2764 				mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
   2765 				iscan->timer_on = 1;
   2766 				break;
   2767 			case WL_SCAN_RESULTS_ABORTED:
   2768 				WL_SCAN(("iscanresults aborted\n"));
   2769 				iscan->iscan_state = ISCAN_STATE_IDLE;
   2770 				if (g_scan_specified_ssid == 0)
   2771 					wl_iw_send_scan_complete(iscan);
   2772 				else {
   2773 					iscan_pass_abort = TRUE;
   2774 					wl_iw_force_specific_scan(iscan);
   2775 				}
   2776 				break;
   2777 			case WL_SCAN_RESULTS_NO_MEM:
   2778 				WL_SCAN(("iscanresults can't alloc memory: skip\n"));
   2779 				iscan->iscan_state = ISCAN_STATE_IDLE;
   2780 				break;
   2781 			default:
   2782 				WL_SCAN(("iscanresults returned unknown status %d\n", status));
   2783 				break;
   2784 		}
   2785 
   2786 		net_os_wake_unlock(iscan->dev);
   2787 	}
   2788 
   2789 	if (iscan->timer_on) {
   2790 		iscan->timer_on = 0;
   2791 		del_timer_sync(&iscan->timer);
   2792 	}
   2793 
   2794 	complete_and_exit(&iscan->sysioc_exited, 0);
   2795 }
   2796 #endif
   2797 
   2798 #if !defined(CSCAN)
   2799 
   2800 static void
   2801 wl_iw_set_ss_cache_timer_flag(void)
   2802 {
   2803 	g_ss_cache_ctrl.m_timer_expired = 1;
   2804 	WL_TRACE(("%s called\n", __FUNCTION__));
   2805 }
   2806 
   2807 static int
   2808 wl_iw_init_ss_cache_ctrl(void)
   2809 {
   2810 	WL_TRACE(("%s :\n", __FUNCTION__));
   2811 	g_ss_cache_ctrl.m_prev_scan_mode = 0;
   2812 	g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
   2813 	g_ss_cache_ctrl.m_cache_head = NULL;
   2814 	g_ss_cache_ctrl.m_link_down = 0;
   2815 	g_ss_cache_ctrl.m_timer_expired = 0;
   2816 	memset(g_ss_cache_ctrl.m_active_bssid, 0, ETHER_ADDR_LEN);
   2817 
   2818 	g_ss_cache_ctrl.m_timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
   2819 	if (!g_ss_cache_ctrl.m_timer) {
   2820 		return -ENOMEM;
   2821 	}
   2822 	g_ss_cache_ctrl.m_timer->function = (void *)wl_iw_set_ss_cache_timer_flag;
   2823 	init_timer(g_ss_cache_ctrl.m_timer);
   2824 
   2825 	return 0;
   2826 }
   2827 
   2828 
   2829 
   2830 static void
   2831 wl_iw_free_ss_cache(void)
   2832 {
   2833 	wl_iw_ss_cache_t *node, *cur;
   2834 	wl_iw_ss_cache_t **spec_scan_head;
   2835 
   2836 	WL_TRACE(("%s called\n", __FUNCTION__));
   2837 
   2838 	mutex_lock(&wl_cache_lock);
   2839 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
   2840 	node = *spec_scan_head;
   2841 
   2842 	for (;node;) {
   2843 		WL_TRACE(("%s : SSID - %s\n", __FUNCTION__, node->bss_info->SSID));
   2844 		cur = node;
   2845 		node = cur->next;
   2846 		kfree(cur);
   2847 	}
   2848 	*spec_scan_head = NULL;
   2849 	mutex_unlock(&wl_cache_lock);
   2850 }
   2851 
   2852 
   2853 
   2854 static int
   2855 wl_iw_run_ss_cache_timer(int kick_off)
   2856 {
   2857 	struct timer_list **timer;
   2858 
   2859 	timer = &g_ss_cache_ctrl.m_timer;
   2860 
   2861 	if (*timer) {
   2862 		if (kick_off) {
   2863 			(*timer)->expires = jiffies + 30000 * HZ / 1000;
   2864 			add_timer(*timer);
   2865 			WL_TRACE(("%s : timer starts \n", __FUNCTION__));
   2866 		} else {
   2867 			del_timer_sync(*timer);
   2868 			WL_TRACE(("%s : timer stops \n", __FUNCTION__));
   2869 		}
   2870 	}
   2871 
   2872 	return 0;
   2873 }
   2874 
   2875 
   2876 void
   2877 wl_iw_release_ss_cache_ctrl(void)
   2878 {
   2879 	WL_TRACE(("%s :\n", __FUNCTION__));
   2880 	wl_iw_free_ss_cache();
   2881 	wl_iw_run_ss_cache_timer(0);
   2882 	if (g_ss_cache_ctrl.m_timer) {
   2883 		kfree(g_ss_cache_ctrl.m_timer);
   2884 	}
   2885 }
   2886 
   2887 
   2888 
   2889 static void
   2890 wl_iw_reset_ss_cache(void)
   2891 {
   2892 	wl_iw_ss_cache_t *node, *prev, *cur;
   2893 	wl_iw_ss_cache_t **spec_scan_head;
   2894 
   2895 	mutex_lock(&wl_cache_lock);
   2896 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
   2897 	node = *spec_scan_head;
   2898 	prev = node;
   2899 
   2900 	for (;node;) {
   2901 		WL_TRACE(("%s : node SSID %s \n", __FUNCTION__, node->bss_info->SSID));
   2902 		if (!node->dirty) {
   2903 			cur = node;
   2904 			if (cur == *spec_scan_head) {
   2905 				*spec_scan_head = cur->next;
   2906 				prev = *spec_scan_head;
   2907 			}
   2908 			else {
   2909 				prev->next = cur->next;
   2910 			}
   2911 			node = cur->next;
   2912 
   2913 			WL_TRACE(("%s : Del node : SSID %s\n", __FUNCTION__, cur->bss_info->SSID));
   2914 			kfree(cur);
   2915 			continue;
   2916 		}
   2917 
   2918 		node->dirty = 0;
   2919 		prev = node;
   2920 		node = node->next;
   2921 	}
   2922 	mutex_unlock(&wl_cache_lock);
   2923 }
   2924 
   2925 
   2926 static int
   2927 wl_iw_add_bss_to_ss_cache(wl_scan_results_t *ss_list)
   2928 {
   2929 
   2930 	wl_iw_ss_cache_t *node, *prev, *leaf;
   2931 	wl_iw_ss_cache_t **spec_scan_head;
   2932 	wl_bss_info_t *bi = NULL;
   2933 	int i;
   2934 
   2935 	if (!ss_list->count) {
   2936 		return 0;
   2937 	}
   2938 
   2939 	mutex_lock(&wl_cache_lock);
   2940 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
   2941 
   2942 	for (i = 0; i < ss_list->count; i++) {
   2943 
   2944 		node = *spec_scan_head;
   2945 		prev = node;
   2946 
   2947 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
   2948 
   2949 		WL_TRACE(("%s : find %d with specific SSID %s\n", __FUNCTION__, i, bi->SSID));
   2950 		for (;node;) {
   2951 			if (!memcmp(&node->bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
   2952 
   2953 				WL_TRACE(("dirty marked : SSID %s\n", bi->SSID));
   2954 				node->dirty = 1;
   2955 				break;
   2956 			}
   2957 			prev = node;
   2958 			node = node->next;
   2959 		}
   2960 
   2961 		if (node) {
   2962 			continue;
   2963 		}
   2964 		leaf = kmalloc(bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
   2965 		if (!leaf) {
   2966 			WL_ERROR(("Memory alloc failure %d\n", \
   2967 				bi->length + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
   2968 			mutex_unlock(&wl_cache_lock);
   2969 			return -ENOMEM;
   2970 		}
   2971 
   2972 		memcpy(leaf->bss_info, bi, bi->length);
   2973 		leaf->next = NULL;
   2974 		leaf->dirty = 1;
   2975 		leaf->count = 1;
   2976 		leaf->version = ss_list->version;
   2977 
   2978 		if (!prev) {
   2979 			*spec_scan_head = leaf;
   2980 		}
   2981 		else {
   2982 			prev->next = leaf;
   2983 		}
   2984 	}
   2985 	mutex_unlock(&wl_cache_lock);
   2986 	return 0;
   2987 }
   2988 
   2989 
   2990 static int
   2991 wl_iw_merge_scan_cache(struct iw_request_info *info, char *extra, uint buflen_from_user,
   2992 __u16 *merged_len)
   2993 {
   2994 	wl_iw_ss_cache_t *node;
   2995 	wl_scan_results_t *list_merge;
   2996 
   2997 	mutex_lock(&wl_cache_lock);
   2998 	node = g_ss_cache_ctrl.m_cache_head;
   2999 	for (;node;) {
   3000 		list_merge = (wl_scan_results_t *)node;
   3001 		WL_TRACE(("%s: Cached Specific APs list=%d\n", __FUNCTION__, list_merge->count));
   3002 		if (buflen_from_user - *merged_len > 0) {
   3003 			*merged_len += (__u16) wl_iw_get_scan_prep(list_merge, info,
   3004 				extra + *merged_len, buflen_from_user - *merged_len);
   3005 		}
   3006 		else {
   3007 			WL_TRACE(("%s: exit with break\n", __FUNCTION__));
   3008 			break;
   3009 		}
   3010 		node = node->next;
   3011 	}
   3012 	mutex_unlock(&wl_cache_lock);
   3013 	return 0;
   3014 }
   3015 
   3016 
   3017 static int
   3018 wl_iw_delete_bss_from_ss_cache(void *addr)
   3019 {
   3020 
   3021 	wl_iw_ss_cache_t *node, *prev;
   3022 	wl_iw_ss_cache_t **spec_scan_head;
   3023 
   3024 	mutex_lock(&wl_cache_lock);
   3025 	spec_scan_head = &g_ss_cache_ctrl.m_cache_head;
   3026 	node = *spec_scan_head;
   3027 	prev = node;
   3028 	for (;node;) {
   3029 		if (!memcmp(&node->bss_info->BSSID, addr, ETHER_ADDR_LEN)) {
   3030 			if (node == *spec_scan_head) {
   3031 				*spec_scan_head = node->next;
   3032 			}
   3033 			else {
   3034 				prev->next = node->next;
   3035 			}
   3036 
   3037 			WL_TRACE(("%s : Del node : %s\n", __FUNCTION__, node->bss_info->SSID));
   3038 			kfree(node);
   3039 			break;
   3040 		}
   3041 
   3042 		prev = node;
   3043 		node = node->next;
   3044 	}
   3045 
   3046 	memset(addr, 0, ETHER_ADDR_LEN);
   3047 	mutex_unlock(&wl_cache_lock);
   3048 	return 0;
   3049 }
   3050 
   3051 #endif
   3052 
   3053 
   3054 static int
   3055 wl_iw_set_scan(
   3056 	struct net_device *dev,
   3057 	struct iw_request_info *info,
   3058 	union iwreq_data *wrqu,
   3059 	char *extra
   3060 )
   3061 {
   3062 	int error;
   3063 	WL_TRACE(("%s dev:%s: SIOCSIWSCAN : SCAN\n", __FUNCTION__, dev->name));
   3064 
   3065 #if defined(CSCAN)
   3066 	WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
   3067 	return -EINVAL;
   3068 #endif
   3069 
   3070 #if defined(SOFTAP)
   3071 	if (ap_cfg_running) {
   3072 		WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
   3073 		return 0;
   3074 	}
   3075 #endif
   3076 
   3077 	if (g_onoff == G_WLAN_SET_OFF)
   3078 		return 0;
   3079 
   3080 	memset(&g_specific_ssid, 0, sizeof(g_specific_ssid));
   3081 #ifndef WL_IW_USE_ISCAN
   3082 	g_scan_specified_ssid = 0;
   3083 #endif
   3084 
   3085 #if WIRELESS_EXT > 17
   3086 
   3087 	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
   3088 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
   3089 			struct iw_scan_req *req = (struct iw_scan_req *)extra;
   3090 			if (g_first_broadcast_scan != BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
   3091 				WL_TRACE(("%s Ignoring SC %s first BC is not done = %d\n", \
   3092 						__FUNCTION__, req->essid, \
   3093 						g_first_broadcast_scan));
   3094 				return -EBUSY;
   3095 			}
   3096 			if (g_scan_specified_ssid) {
   3097 				WL_TRACE(("%s Specific SCAN is not done ignore scan for = %s \n", \
   3098 					__FUNCTION__, req->essid));
   3099 				return -EBUSY;
   3100 			}
   3101 			else {
   3102 				g_specific_ssid.SSID_len = MIN(sizeof(g_specific_ssid.SSID), \
   3103 										req->essid_len);
   3104 				memcpy(g_specific_ssid.SSID, req->essid, g_specific_ssid.SSID_len);
   3105 				g_specific_ssid.SSID_len = htod32(g_specific_ssid.SSID_len);
   3106 				g_scan_specified_ssid = 1;
   3107 				WL_TRACE(("### Specific scan ssid=%s len=%d\n", \
   3108 						g_specific_ssid.SSID, g_specific_ssid.SSID_len));
   3109 			}
   3110 		}
   3111 	}
   3112 #endif
   3113 
   3114 	if ((error = dev_wlc_ioctl(dev, WLC_SCAN, &g_specific_ssid, sizeof(g_specific_ssid)))) {
   3115 		WL_TRACE(("#### Set SCAN for %s failed with %d\n", g_specific_ssid.SSID, error));
   3116 		g_scan_specified_ssid = 0;
   3117 		return -EBUSY;
   3118 	}
   3119 
   3120 	return 0;
   3121 }
   3122 
   3123 #ifdef WL_IW_USE_ISCAN
   3124 int
   3125 wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag)
   3126 {
   3127 	wlc_ssid_t ssid;
   3128 	iscan_info_t *iscan = g_iscan;
   3129 
   3130 	if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_IDLE) {
   3131 		g_first_broadcast_scan = BROADCAST_SCAN_FIRST_STARTED;
   3132 		WL_TRACE(("%s: First Brodcast scan was forced\n", __FUNCTION__));
   3133 	}
   3134 	else if (g_first_broadcast_scan == BROADCAST_SCAN_FIRST_STARTED) {
   3135 		WL_TRACE(("%s: ignore ISCAN request first BS is not done yet\n", __FUNCTION__));
   3136 		return 0;
   3137 	}
   3138 
   3139 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   3140 	if (flag)
   3141 		rtnl_lock();
   3142 #endif
   3143 
   3144 	dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &iscan->scan_flag, sizeof(iscan->scan_flag));
   3145 	wl_iw_set_event_mask(dev);
   3146 
   3147 	WL_TRACE(("+++: Set Broadcast ISCAN\n"));
   3148 
   3149 	memset(&ssid, 0, sizeof(ssid));
   3150 
   3151 	iscan->list_cur = iscan->list_hdr;
   3152 	iscan->iscan_state = ISCAN_STATE_SCANING;
   3153 
   3154 	memset(&iscan->iscan_ex_params_p->params, 0, iscan->iscan_ex_param_size);
   3155 	wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, &ssid);
   3156 	wl_iw_iscan(iscan, &ssid, WL_SCAN_ACTION_START);
   3157 
   3158 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   3159 	if (flag)
   3160 		rtnl_unlock();
   3161 #endif
   3162 
   3163 	mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
   3164 
   3165 	iscan->timer_on = 1;
   3166 
   3167 	return 0;
   3168 }
   3169 
   3170 static int
   3171 wl_iw_iscan_set_scan(
   3172 	struct net_device *dev,
   3173 	struct iw_request_info *info,
   3174 	union iwreq_data *wrqu,
   3175 	char *extra
   3176 )
   3177 {
   3178 	wlc_ssid_t ssid;
   3179 	iscan_info_t *iscan = g_iscan;
   3180 	int ret = 0;
   3181 
   3182 	WL_TRACE(("%s: SIOCSIWSCAN : ISCAN\n", dev->name));
   3183 
   3184 #if defined(CSCAN)
   3185 	WL_ERROR(("%s: Scan from SIOCGIWSCAN not supported\n", __FUNCTION__));
   3186 	return -EINVAL;
   3187 #endif
   3188 
   3189 	net_os_wake_lock(dev);
   3190 
   3191 #if defined(SOFTAP)
   3192 	if (ap_cfg_running) {
   3193 		WL_TRACE(("\n>%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
   3194 		goto set_scan_end;
   3195 	}
   3196 #endif
   3197 
   3198 	if (g_onoff == G_WLAN_SET_OFF) {
   3199 		WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
   3200 		goto set_scan_end;
   3201 	}
   3202 
   3203 #ifdef PNO_SUPPORT
   3204 	if  (dhd_dev_get_pno_status(dev)) {
   3205 		WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
   3206 	}
   3207 #endif
   3208 
   3209 	if ((!iscan) || (iscan->sysioc_pid < 0)) {
   3210 		WL_ERROR(("%s error\n", __FUNCTION__));
   3211 		goto set_scan_end;
   3212 	}
   3213 
   3214 	if (g_scan_specified_ssid) {
   3215 		WL_TRACE(("%s Specific SCAN already running ignoring BC scan\n", \
   3216 				__FUNCTION__));
   3217 		ret = EBUSY;
   3218 		goto set_scan_end;
   3219 	}
   3220 
   3221 	memset(&ssid, 0, sizeof(ssid));
   3222 
   3223 #if WIRELESS_EXT > 17
   3224 
   3225 	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
   3226 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
   3227 			int as = 0;
   3228 			struct iw_scan_req *req = (struct iw_scan_req *)extra;
   3229 			ssid.SSID_len = MIN(sizeof(ssid.SSID), req->essid_len);
   3230 			memcpy(ssid.SSID, req->essid, ssid.SSID_len);
   3231 			ssid.SSID_len = htod32(ssid.SSID_len);
   3232 			dev_wlc_ioctl(dev, WLC_SET_PASSIVE_SCAN, &as, sizeof(as));
   3233 			wl_iw_set_event_mask(dev);
   3234 			ret = wl_iw_set_scan(dev, info, wrqu, extra);
   3235 			goto set_scan_end;
   3236 		}
   3237 		else {
   3238 			g_scan_specified_ssid = 0;
   3239 
   3240 			if (iscan->iscan_state == ISCAN_STATE_SCANING) {
   3241 				WL_TRACE(("%s ISCAN already in progress \n", __FUNCTION__));
   3242 				goto set_scan_end;
   3243 			}
   3244 		}
   3245 	}
   3246 #endif
   3247 
   3248 #if !defined(CSCAN)
   3249 	if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
   3250 		if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
   3251 
   3252 			WL_ERROR(("%s Clean up First scan flag which is %d\n", \
   3253 				 __FUNCTION__, g_first_broadcast_scan));
   3254 			g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
   3255 		}
   3256 		else {
   3257 			WL_ERROR(("%s Ignoring Broadcast Scan:First Scan is not done yet %d\n", \
   3258 					__FUNCTION__, g_first_counter_scans));
   3259 			ret = -EBUSY;
   3260 			goto set_scan_end;
   3261 		}
   3262 	}
   3263 #endif
   3264 
   3265 	wl_iw_iscan_set_scan_broadcast_prep(dev, 0);
   3266 
   3267 set_scan_end:
   3268 	net_os_wake_unlock(dev);
   3269 	return ret;
   3270 }
   3271 #endif
   3272 
   3273 #if WIRELESS_EXT > 17
   3274 static bool
   3275 ie_is_wpa_ie(uint8 **wpaie, uint8 **tlvs, int *tlvs_len)
   3276 {
   3277 	uint8 *ie = *wpaie;
   3278 
   3279 	if ((ie[1] >= 6) &&
   3280 		!bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x01"), 4)) {
   3281 		return TRUE;
   3282 	}
   3283 
   3284 	ie += ie[1] + 2;
   3285 
   3286 	*tlvs_len -= (int)(ie - *tlvs);
   3287 
   3288 	*tlvs = ie;
   3289 	return FALSE;
   3290 }
   3291 
   3292 static bool
   3293 ie_is_wps_ie(uint8 **wpsie, uint8 **tlvs, int *tlvs_len)
   3294 {
   3295 	uint8 *ie = *wpsie;
   3296 
   3297 	if ((ie[1] >= 4) &&
   3298 		!bcmp((const void *)&ie[2], (const void *)(WPA_OUI "\x04"), 4)) {
   3299 		return TRUE;
   3300 	}
   3301 
   3302 	ie += ie[1] + 2;
   3303 
   3304 	*tlvs_len -= (int)(ie - *tlvs);
   3305 
   3306 	*tlvs = ie;
   3307 	return FALSE;
   3308 }
   3309 #endif
   3310 
   3311 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
   3312 	size_t len, int uppercase)
   3313 {
   3314 	size_t i;
   3315 	char *pos = buf, *end = buf + buf_size;
   3316 	int ret;
   3317 	if (buf_size == 0)
   3318 		return 0;
   3319 	for (i = 0; i < len; i++) {
   3320 		ret = snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
   3321 			data[i]);
   3322 		if (ret < 0 || ret >= end - pos) {
   3323 			end[-1] = '\0';
   3324 			return pos - buf;
   3325 		}
   3326 		pos += ret;
   3327 	}
   3328 	end[-1] = '\0';
   3329 	return pos - buf;
   3330 }
   3331 
   3332 
   3333 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
   3334 {
   3335 	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
   3336 }
   3337 
   3338 static int
   3339 wl_iw_handle_scanresults_ies(char **event_p, char *end,
   3340 	struct iw_request_info *info, wl_bss_info_t *bi)
   3341 {
   3342 #if WIRELESS_EXT > 17
   3343 	struct iw_event	iwe;
   3344 	char *event;
   3345 	char *buf;
   3346 	int custom_event_len;
   3347 
   3348 	event = *event_p;
   3349 	if (bi->ie_length) {
   3350 
   3351 		bcm_tlv_t *ie;
   3352 		uint8 *ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
   3353 		int ptr_len = bi->ie_length;
   3354 
   3355 #ifdef BCMWPA2
   3356 		if ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_RSN_ID))) {
   3357 			iwe.cmd = IWEVGENIE;
   3358 			iwe.u.data.length = ie->len + 2;
   3359 			event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
   3360 		}
   3361 		ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
   3362 #endif
   3363 
   3364 		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
   3365 
   3366 			if (ie_is_wps_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
   3367 				iwe.cmd = IWEVGENIE;
   3368 				iwe.u.data.length = ie->len + 2;
   3369 				event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
   3370 				break;
   3371 			}
   3372 		}
   3373 
   3374 		ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
   3375 		ptr_len = bi->ie_length;
   3376 		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WPA_ID))) {
   3377 			if (ie_is_wpa_ie(((uint8 **)&ie), &ptr, &ptr_len)) {
   3378 				iwe.cmd = IWEVGENIE;
   3379 				iwe.u.data.length = ie->len + 2;
   3380 				event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
   3381 				break;
   3382 			}
   3383 		}
   3384 
   3385 		ptr = ((uint8 *)bi) + sizeof(wl_bss_info_t);
   3386 		ptr_len = bi->ie_length;
   3387 
   3388 		while ((ie = bcm_parse_tlvs(ptr, ptr_len, DOT11_MNG_WAPI_ID))) {
   3389 			WL_TRACE(("%s: found a WAPI IE...\n", __FUNCTION__));
   3390 #ifdef WAPI_IE_USE_GENIE
   3391 			iwe.cmd = IWEVGENIE;
   3392 			iwe.u.data.length = ie->len + 2;
   3393 			event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)ie);
   3394 #else
   3395 			iwe.cmd = IWEVCUSTOM;
   3396 			custom_event_len = strlen("wapi_ie=") + 2*(ie->len + 2);
   3397 			iwe.u.data.length = custom_event_len;
   3398 
   3399 			buf = kmalloc(custom_event_len+1, GFP_KERNEL);
   3400 			if (buf == NULL)
   3401 			{
   3402 				WL_ERROR(("malloc(%d) returned NULL...\n", custom_event_len));
   3403 				break;
   3404 			}
   3405 
   3406 			memcpy(buf, "wapi_ie=", 8);
   3407 			wpa_snprintf_hex(buf + 8, 2+1, &(ie->id), 1);
   3408 			wpa_snprintf_hex(buf + 10, 2+1, &(ie->len), 1);
   3409 			wpa_snprintf_hex(buf + 12, 2*ie->len+1, ie->data, ie->len);
   3410 			event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, buf);
   3411 #endif
   3412 			break;
   3413 		}
   3414 	*event_p = event;
   3415 	}
   3416 #endif
   3417 
   3418 	return 0;
   3419 }
   3420 
   3421 #ifndef CSCAN
   3422 static uint
   3423 wl_iw_get_scan_prep(
   3424 	wl_scan_results_t *list,
   3425 	struct iw_request_info *info,
   3426 	char *extra,
   3427 	short max_size)
   3428 {
   3429 	int  i, j;
   3430 	struct iw_event  iwe;
   3431 	wl_bss_info_t *bi = NULL;
   3432 	char *event = extra, *end = extra + max_size - WE_ADD_EVENT_FIX, *value;
   3433 	int	ret = 0;
   3434 
   3435 	ASSERT(list);
   3436 
   3437 	for (i = 0; i < list->count && i < IW_MAX_AP; i++)
   3438 	{
   3439 		if (list->version != WL_BSS_INFO_VERSION) {
   3440 			WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n", \
   3441 				__FUNCTION__, list->version));
   3442 			return ret;
   3443 		 }
   3444 
   3445 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
   3446 
   3447 		WL_TRACE(("%s : %s\n", __FUNCTION__, bi->SSID));
   3448 
   3449 		iwe.cmd = SIOCGIWAP;
   3450 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
   3451 		memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
   3452 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
   3453 
   3454 		iwe.u.data.length = dtoh32(bi->SSID_len);
   3455 		iwe.cmd = SIOCGIWESSID;
   3456 		iwe.u.data.flags = 1;
   3457 		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
   3458 
   3459 
   3460 		if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
   3461 			iwe.cmd = SIOCGIWMODE;
   3462 			if (dtoh16(bi->capability) & DOT11_CAP_ESS)
   3463 				iwe.u.mode = IW_MODE_INFRA;
   3464 			else
   3465 				iwe.u.mode = IW_MODE_ADHOC;
   3466 			event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
   3467 		}
   3468 
   3469 
   3470 		iwe.cmd = SIOCGIWFREQ;
   3471 		iwe.u.freq.m = wf_channel2mhz(CHSPEC_CHANNEL(bi->chanspec),
   3472 			CHSPEC_CHANNEL(bi->chanspec) <= CH_MAX_2G_CHANNEL ?
   3473 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
   3474 		iwe.u.freq.e = 6;
   3475 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
   3476 
   3477 
   3478 		iwe.cmd = IWEVQUAL;
   3479 		iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
   3480 		iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
   3481 		iwe.u.qual.noise = 0x100 + bi->phy_noise;
   3482 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
   3483 
   3484 		wl_iw_handle_scanresults_ies(&event, end, info, bi);
   3485 
   3486 		iwe.cmd = SIOCGIWENCODE;
   3487 		if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
   3488 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
   3489 		else
   3490 			iwe.u.data.flags = IW_ENCODE_DISABLED;
   3491 		iwe.u.data.length = 0;
   3492 		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
   3493 
   3494 
   3495 		if (bi->rateset.count) {
   3496 			if (((event -extra) + IW_EV_LCP_LEN) <= (uintptr)end) {
   3497 				value = event + IW_EV_LCP_LEN;
   3498 				iwe.cmd = SIOCGIWRATE;
   3499 
   3500 				iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
   3501 				for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
   3502 					iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
   3503 					value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
   3504 						IW_EV_PARAM_LEN);
   3505 				}
   3506 				event = value;
   3507 			}
   3508 		}
   3509 	}
   3510 
   3511 	if ((ret = (event - extra)) < 0) {
   3512 		WL_ERROR(("==> Wrong size\n"));
   3513 		ret = 0;
   3514 	}
   3515 	WL_TRACE(("%s: size=%d bytes prepared \n", __FUNCTION__, (unsigned int)(event - extra)));
   3516 	return (uint)ret;
   3517 }
   3518 
   3519 static int
   3520 wl_iw_get_scan(
   3521 	struct net_device *dev,
   3522 	struct iw_request_info *info,
   3523 	struct iw_point *dwrq,
   3524 	char *extra
   3525 )
   3526 {
   3527 	channel_info_t ci;
   3528 	wl_scan_results_t *list_merge;
   3529 	wl_scan_results_t *list = (wl_scan_results_t *) g_scan;
   3530 	int error;
   3531 	uint buflen_from_user = dwrq->length;
   3532 	uint len =  G_SCAN_RESULTS;
   3533 	__u16 len_ret = 0;
   3534 #if !defined(CSCAN)
   3535 	__u16 merged_len = 0;
   3536 #endif
   3537 #if defined(WL_IW_USE_ISCAN)
   3538 	iscan_info_t *iscan = g_iscan;
   3539 	iscan_buf_t * p_buf;
   3540 #if  !defined(CSCAN)
   3541 	uint32 counter = 0;
   3542 #endif
   3543 #endif
   3544 	WL_TRACE(("%s: buflen_from_user %d: \n", dev->name, buflen_from_user));
   3545 
   3546 	if (!extra) {
   3547 		WL_TRACE(("%s: wl_iw_get_scan return -EINVAL\n", dev->name));
   3548 		return -EINVAL;
   3549 	}
   3550 
   3551 
   3552 	if ((error = dev_wlc_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(ci))))
   3553 		return error;
   3554 	ci.scan_channel = dtoh32(ci.scan_channel);
   3555 	if (ci.scan_channel)
   3556 		return -EAGAIN;
   3557 
   3558 #if !defined(CSCAN)
   3559 	if (g_ss_cache_ctrl.m_timer_expired) {
   3560 		wl_iw_free_ss_cache();
   3561 		g_ss_cache_ctrl.m_timer_expired ^= 1;
   3562 	}
   3563 	if ((!g_scan_specified_ssid && g_ss_cache_ctrl.m_prev_scan_mode) ||
   3564 		g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
   3565 		g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
   3566 
   3567 		wl_iw_reset_ss_cache();
   3568 	}
   3569 	g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
   3570 	if (g_scan_specified_ssid) {
   3571 		g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
   3572 	}
   3573 	else {
   3574 		g_ss_cache_ctrl.m_cons_br_scan_cnt++;
   3575 	}
   3576 #endif
   3577 
   3578 	if (g_scan_specified_ssid) {
   3579 
   3580 		list = kmalloc(len, GFP_KERNEL);
   3581 		if (!list) {
   3582 			WL_TRACE(("%s: wl_iw_get_scan return -ENOMEM\n", dev->name));
   3583 			g_scan_specified_ssid = 0;
   3584 			return -ENOMEM;
   3585 		}
   3586 	}
   3587 
   3588 	memset(list, 0, len);
   3589 	list->buflen = htod32(len);
   3590 	if ((error = dev_wlc_ioctl(dev, WLC_SCAN_RESULTS, list, len))) {
   3591 		WL_ERROR(("%s: %s : Scan_results ERROR %d\n", dev->name, __FUNCTION__, error));
   3592 		dwrq->length = len;
   3593 		if (g_scan_specified_ssid) {
   3594 			g_scan_specified_ssid = 0;
   3595 			kfree(list);
   3596 		}
   3597 		return 0;
   3598 	}
   3599 	list->buflen = dtoh32(list->buflen);
   3600 	list->version = dtoh32(list->version);
   3601 	list->count = dtoh32(list->count);
   3602 
   3603 	if (list->version != WL_BSS_INFO_VERSION) {
   3604 		WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
   3605 				__FUNCTION__, list->version));
   3606 		if (g_scan_specified_ssid) {
   3607 			g_scan_specified_ssid = 0;
   3608 			kfree(list);
   3609 		}
   3610 		return -EINVAL;
   3611 	}
   3612 
   3613 #if !defined(CSCAN)
   3614 	if (g_scan_specified_ssid) {
   3615 
   3616 		wl_iw_add_bss_to_ss_cache(list);
   3617 		kfree(list);
   3618 	}
   3619 
   3620 	mutex_lock(&wl_cache_lock);
   3621 #if defined(WL_IW_USE_ISCAN)
   3622 	if (g_scan_specified_ssid)
   3623 		WL_TRACE(("%s: Specified scan APs from scan=%d\n", __FUNCTION__, list->count));
   3624 	p_buf = iscan->list_hdr;
   3625 
   3626 	while (p_buf != iscan->list_cur) {
   3627 		list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
   3628 		WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
   3629 		counter += list_merge->count;
   3630 		if (list_merge->count > 0)
   3631 			len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
   3632 				extra+len_ret, buflen_from_user -len_ret);
   3633 		p_buf = p_buf->next;
   3634 	}
   3635 	WL_TRACE(("%s merged with total Bcast APs=%d\n", __FUNCTION__, counter));
   3636 #else
   3637 	list_merge = (wl_scan_results_t *) g_scan;
   3638 	len_ret = (__u16) wl_iw_get_scan_prep(list_merge, info, extra, buflen_from_user);
   3639 #endif
   3640 	mutex_unlock(&wl_cache_lock);
   3641 	if (g_ss_cache_ctrl.m_link_down) {
   3642 		wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
   3643 	}
   3644 
   3645 	wl_iw_merge_scan_cache(info, extra+len_ret, buflen_from_user-len_ret, &merged_len);
   3646 	len_ret += merged_len;
   3647 	wl_iw_run_ss_cache_timer(0);
   3648 	wl_iw_run_ss_cache_timer(1);
   3649 #else
   3650 
   3651 	if (g_scan_specified_ssid) {
   3652 		WL_TRACE(("%s: Specified scan APs in the list =%d\n", __FUNCTION__, list->count));
   3653 		len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
   3654 		kfree(list);
   3655 
   3656 #if defined(WL_IW_USE_ISCAN)
   3657 		p_buf = iscan->list_hdr;
   3658 
   3659 		while (p_buf != iscan->list_cur) {
   3660 			list_merge = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
   3661 			WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
   3662 			if (list_merge->count > 0)
   3663 				len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info,
   3664 				    extra+len_ret, buflen_from_user -len_ret);
   3665 			p_buf = p_buf->next;
   3666 		}
   3667 #else
   3668 		list_merge = (wl_scan_results_t *) g_scan;
   3669 		WL_TRACE(("%s: Bcast APs list=%d\n", __FUNCTION__, list_merge->count));
   3670 		if (list_merge->count > 0)
   3671 			len_ret += (__u16) wl_iw_get_scan_prep(list_merge, info, extra+len_ret,
   3672 				buflen_from_user -len_ret);
   3673 #endif
   3674 	}
   3675 	else {
   3676 		list = (wl_scan_results_t *) g_scan;
   3677 		len_ret = (__u16) wl_iw_get_scan_prep(list, info, extra, buflen_from_user);
   3678 	}
   3679 #endif
   3680 
   3681 #if defined(WL_IW_USE_ISCAN)
   3682 
   3683 	g_scan_specified_ssid = 0;
   3684 #endif
   3685 
   3686 	if ((len_ret + WE_ADD_EVENT_FIX) < buflen_from_user)
   3687 		len = len_ret;
   3688 
   3689 	dwrq->length = len;
   3690 	dwrq->flags = 0;
   3691 
   3692 	WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, list->count));
   3693 	return 0;
   3694 }
   3695 #endif
   3696 
   3697 #if defined(WL_IW_USE_ISCAN)
   3698 static int
   3699 wl_iw_iscan_get_scan(
   3700 	struct net_device *dev,
   3701 	struct iw_request_info *info,
   3702 	struct iw_point *dwrq,
   3703 	char *extra
   3704 )
   3705 {
   3706 	wl_scan_results_t *list;
   3707 	struct iw_event	iwe;
   3708 	wl_bss_info_t *bi = NULL;
   3709 	int ii, j;
   3710 	int apcnt;
   3711 	char *event = extra, *end = extra + dwrq->length, *value;
   3712 	iscan_info_t *iscan = g_iscan;
   3713 	iscan_buf_t * p_buf;
   3714 	uint32  counter = 0;
   3715 	uint8   channel;
   3716 #if !defined(CSCAN)
   3717 	__u16 merged_len = 0;
   3718 	uint buflen_from_user = dwrq->length;
   3719 #endif
   3720 
   3721 	WL_TRACE(("%s %s buflen_from_user %d:\n", dev->name, __FUNCTION__, dwrq->length));
   3722 
   3723 #if defined(SOFTAP)
   3724 	if (ap_cfg_running) {
   3725 		WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
   3726 		return -EINVAL;
   3727 	}
   3728 #endif
   3729 
   3730 	if (!extra) {
   3731 		WL_TRACE(("%s: INVALID SIOCGIWSCAN GET bad parameter\n", dev->name));
   3732 		return -EINVAL;
   3733 	}
   3734 
   3735 	if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_READY) {
   3736 		WL_TRACE(("%s %s: first ISCAN results are NOT ready yet \n", \
   3737 			 dev->name, __FUNCTION__));
   3738 		return -EAGAIN;
   3739 	}
   3740 
   3741 	if ((!iscan) || (iscan->sysioc_pid < 0)) {
   3742 		WL_ERROR(("%ssysioc_pid\n", __FUNCTION__));
   3743 		return -EAGAIN;
   3744 	}
   3745 
   3746 #if !defined(CSCAN)
   3747 	if (g_ss_cache_ctrl.m_timer_expired) {
   3748 		wl_iw_free_ss_cache();
   3749 		g_ss_cache_ctrl.m_timer_expired ^= 1;
   3750 	}
   3751 	if (g_scan_specified_ssid) {
   3752 		return wl_iw_get_scan(dev, info, dwrq, extra);
   3753 	}
   3754 	else {
   3755 		if (g_ss_cache_ctrl.m_link_down) {
   3756 			wl_iw_delete_bss_from_ss_cache(g_ss_cache_ctrl.m_active_bssid);
   3757 		}
   3758 		if (g_ss_cache_ctrl.m_prev_scan_mode || g_ss_cache_ctrl.m_cons_br_scan_cnt > 4) {
   3759 			g_ss_cache_ctrl.m_cons_br_scan_cnt = 0;
   3760 
   3761 			wl_iw_reset_ss_cache();
   3762 		}
   3763 		g_ss_cache_ctrl.m_prev_scan_mode = g_scan_specified_ssid;
   3764 		g_ss_cache_ctrl.m_cons_br_scan_cnt++;
   3765 	}
   3766 #endif
   3767 
   3768 	WL_TRACE(("%s: SIOCGIWSCAN GET broadcast results\n", dev->name));
   3769 	apcnt = 0;
   3770 	p_buf = iscan->list_hdr;
   3771 
   3772 	while (p_buf != iscan->list_cur) {
   3773 	    list = &((wl_iscan_results_t*)p_buf->iscan_buf)->results;
   3774 
   3775 	    counter += list->count;
   3776 
   3777 	    if (list->version != WL_BSS_INFO_VERSION) {
   3778 		WL_ERROR(("%s : list->version %d != WL_BSS_INFO_VERSION\n",
   3779 			 __FUNCTION__, list->version));
   3780 		return -EINVAL;
   3781 	    }
   3782 
   3783 	    bi = NULL;
   3784 	    for (ii = 0; ii < list->count && apcnt < IW_MAX_AP; apcnt++, ii++) {
   3785 		bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : list->bss_info;
   3786 		ASSERT(((uintptr)bi + dtoh32(bi->length)) <= ((uintptr)list +
   3787 			WLC_IW_ISCAN_MAXLEN));
   3788 
   3789 
   3790 		if (event + ETHER_ADDR_LEN + bi->SSID_len + IW_EV_UINT_LEN + IW_EV_FREQ_LEN +
   3791 			IW_EV_QUAL_LEN >= end)
   3792 			return -E2BIG;
   3793 
   3794 		iwe.cmd = SIOCGIWAP;
   3795 		iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
   3796 		memcpy(iwe.u.ap_addr.sa_data, &bi->BSSID, ETHER_ADDR_LEN);
   3797 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_ADDR_LEN);
   3798 
   3799 
   3800 		iwe.u.data.length = dtoh32(bi->SSID_len);
   3801 		iwe.cmd = SIOCGIWESSID;
   3802 		iwe.u.data.flags = 1;
   3803 		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, bi->SSID);
   3804 
   3805 
   3806 		if (dtoh16(bi->capability) & (DOT11_CAP_ESS | DOT11_CAP_IBSS)) {
   3807 			iwe.cmd = SIOCGIWMODE;
   3808 			if (dtoh16(bi->capability) & DOT11_CAP_ESS)
   3809 				iwe.u.mode = IW_MODE_INFRA;
   3810 			else
   3811 				iwe.u.mode = IW_MODE_ADHOC;
   3812 			event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_UINT_LEN);
   3813 		}
   3814 
   3815 
   3816 		iwe.cmd = SIOCGIWFREQ;
   3817 		channel = (bi->ctl_ch == 0) ? CHSPEC_CHANNEL(bi->chanspec) : bi->ctl_ch;
   3818 		iwe.u.freq.m = wf_channel2mhz(channel,
   3819 			channel <= CH_MAX_2G_CHANNEL ?
   3820 			WF_CHAN_FACTOR_2_4_G : WF_CHAN_FACTOR_5_G);
   3821 		iwe.u.freq.e = 6;
   3822 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_FREQ_LEN);
   3823 
   3824 
   3825 		iwe.cmd = IWEVQUAL;
   3826 		iwe.u.qual.qual = rssi_to_qual(dtoh16(bi->RSSI));
   3827 		iwe.u.qual.level = 0x100 + dtoh16(bi->RSSI);
   3828 		iwe.u.qual.noise = 0x100 + bi->phy_noise;
   3829 		event = IWE_STREAM_ADD_EVENT(info, event, end, &iwe, IW_EV_QUAL_LEN);
   3830 
   3831 
   3832 		wl_iw_handle_scanresults_ies(&event, end, info, bi);
   3833 
   3834 
   3835 		iwe.cmd = SIOCGIWENCODE;
   3836 		if (dtoh16(bi->capability) & DOT11_CAP_PRIVACY)
   3837 			iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
   3838 		else
   3839 			iwe.u.data.flags = IW_ENCODE_DISABLED;
   3840 		iwe.u.data.length = 0;
   3841 		event = IWE_STREAM_ADD_POINT(info, event, end, &iwe, (char *)event);
   3842 
   3843 
   3844 		if (bi->rateset.count) {
   3845 			if (event + IW_MAX_BITRATES*IW_EV_PARAM_LEN >= end)
   3846 				return -E2BIG;
   3847 
   3848 			value = event + IW_EV_LCP_LEN;
   3849 			iwe.cmd = SIOCGIWRATE;
   3850 
   3851 			iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
   3852 			for (j = 0; j < bi->rateset.count && j < IW_MAX_BITRATES; j++) {
   3853 				iwe.u.bitrate.value = (bi->rateset.rates[j] & 0x7f) * 500000;
   3854 				value = IWE_STREAM_ADD_VALUE(info, event, value, end, &iwe,
   3855 					IW_EV_PARAM_LEN);
   3856 			}
   3857 			event = value;
   3858 		}
   3859 	    }
   3860 	    p_buf = p_buf->next;
   3861 	}
   3862 
   3863 	dwrq->length = event - extra;
   3864 	dwrq->flags = 0;
   3865 
   3866 #if !defined(CSCAN)
   3867 	wl_iw_merge_scan_cache(info, event, buflen_from_user - dwrq->length, &merged_len);
   3868 	dwrq->length += merged_len;
   3869 	wl_iw_run_ss_cache_timer(0);
   3870 	wl_iw_run_ss_cache_timer(1);
   3871 #endif /* CSCAN */
   3872 	g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
   3873 
   3874 	WL_TRACE(("%s return to WE %d bytes APs=%d\n", __FUNCTION__, dwrq->length, counter));
   3875 
   3876 	return 0;
   3877 }
   3878 #endif
   3879 
   3880 static int
   3881 wl_iw_set_essid(
   3882 	struct net_device *dev,
   3883 	struct iw_request_info *info,
   3884 	struct iw_point *dwrq,
   3885 	char *extra
   3886 )
   3887 {
   3888 	int error;
   3889 	wl_join_params_t join_params;
   3890 	int join_params_size;
   3891 
   3892 	WL_TRACE(("%s: SIOCSIWESSID\n", dev->name));
   3893 
   3894 
   3895 	memset(&g_ssid, 0, sizeof(g_ssid));
   3896 
   3897 	CHECK_EXTRA_FOR_NULL(extra);
   3898 
   3899 	if (dwrq->length && extra) {
   3900 #if WIRELESS_EXT > 20
   3901 		g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length);
   3902 #else
   3903 		g_ssid.SSID_len = MIN(sizeof(g_ssid.SSID), dwrq->length-1);
   3904 #endif
   3905 		memcpy(g_ssid.SSID, extra, g_ssid.SSID_len);
   3906 	} else {
   3907 
   3908 		g_ssid.SSID_len = 0;
   3909 	}
   3910 	g_ssid.SSID_len = htod32(g_ssid.SSID_len);
   3911 
   3912 	memset(&join_params, 0, sizeof(join_params));
   3913 	join_params_size = sizeof(join_params.ssid);
   3914 
   3915 	memcpy(&join_params.ssid.SSID, g_ssid.SSID, g_ssid.SSID_len);
   3916 	join_params.ssid.SSID_len = htod32(g_ssid.SSID_len);
   3917 	memcpy(&join_params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
   3918 
   3919 	wl_iw_ch_to_chanspec(g_wl_iw_params.target_channel, &join_params, &join_params_size);
   3920 
   3921 	if ((error = dev_wlc_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size))) {
   3922 		WL_ERROR(("Invalid ioctl data=%d\n", error));
   3923 		return error;
   3924 	}
   3925 
   3926 	if (g_ssid.SSID_len) {
   3927 		WL_TRACE(("%s: join SSID=%s ch=%d\n", __FUNCTION__, \
   3928 			g_ssid.SSID,  g_wl_iw_params.target_channel));
   3929 	}
   3930 	return 0;
   3931 }
   3932 
   3933 static int
   3934 wl_iw_get_essid(
   3935 	struct net_device *dev,
   3936 	struct iw_request_info *info,
   3937 	struct iw_point *dwrq,
   3938 	char *extra
   3939 )
   3940 {
   3941 	wlc_ssid_t ssid;
   3942 	int error;
   3943 
   3944 	WL_TRACE(("%s: SIOCGIWESSID\n", dev->name));
   3945 
   3946 	if (!extra)
   3947 		return -EINVAL;
   3948 
   3949 	if ((error = dev_wlc_ioctl(dev, WLC_GET_SSID, &ssid, sizeof(ssid)))) {
   3950 		WL_ERROR(("Error getting the SSID\n"));
   3951 		return error;
   3952 	}
   3953 
   3954 	ssid.SSID_len = dtoh32(ssid.SSID_len);
   3955 
   3956 	memcpy(extra, ssid.SSID, ssid.SSID_len);
   3957 
   3958 	dwrq->length = ssid.SSID_len;
   3959 
   3960 	dwrq->flags = 1;
   3961 
   3962 	return 0;
   3963 }
   3964 
   3965 static int
   3966 wl_iw_set_nick(
   3967 	struct net_device *dev,
   3968 	struct iw_request_info *info,
   3969 	struct iw_point *dwrq,
   3970 	char *extra
   3971 )
   3972 {
   3973 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   3974 
   3975 	WL_TRACE(("%s: SIOCSIWNICKN\n", dev->name));
   3976 
   3977 	if (!extra)
   3978 		return -EINVAL;
   3979 
   3980 	if (dwrq->length > sizeof(iw->nickname))
   3981 		return -E2BIG;
   3982 
   3983 	memcpy(iw->nickname, extra, dwrq->length);
   3984 	iw->nickname[dwrq->length - 1] = '\0';
   3985 
   3986 	return 0;
   3987 }
   3988 
   3989 static int
   3990 wl_iw_get_nick(
   3991 	struct net_device *dev,
   3992 	struct iw_request_info *info,
   3993 	struct iw_point *dwrq,
   3994 	char *extra
   3995 )
   3996 {
   3997 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   3998 
   3999 	WL_TRACE(("%s: SIOCGIWNICKN\n", dev->name));
   4000 
   4001 	if (!extra)
   4002 		return -EINVAL;
   4003 
   4004 	strcpy(extra, iw->nickname);
   4005 	dwrq->length = strlen(extra) + 1;
   4006 
   4007 	return 0;
   4008 }
   4009 
   4010 static int wl_iw_set_rate(
   4011 	struct net_device *dev,
   4012 	struct iw_request_info *info,
   4013 	struct iw_param *vwrq,
   4014 	char *extra
   4015 )
   4016 {
   4017 	wl_rateset_t rateset;
   4018 	int error, rate, i, error_bg, error_a;
   4019 
   4020 	WL_TRACE(("%s: SIOCSIWRATE\n", dev->name));
   4021 
   4022 
   4023 	if ((error = dev_wlc_ioctl(dev, WLC_GET_CURR_RATESET, &rateset, sizeof(rateset))))
   4024 		return error;
   4025 
   4026 	rateset.count = dtoh32(rateset.count);
   4027 
   4028 	if (vwrq->value < 0) {
   4029 
   4030 		rate = rateset.rates[rateset.count - 1] & 0x7f;
   4031 	} else if (vwrq->value < rateset.count) {
   4032 
   4033 		rate = rateset.rates[vwrq->value] & 0x7f;
   4034 	} else {
   4035 
   4036 		rate = vwrq->value / 500000;
   4037 	}
   4038 
   4039 	if (vwrq->fixed) {
   4040 
   4041 		error_bg = dev_wlc_intvar_set(dev, "bg_rate", rate);
   4042 		error_a = dev_wlc_intvar_set(dev, "a_rate", rate);
   4043 
   4044 		if (error_bg && error_a)
   4045 			return (error_bg | error_a);
   4046 	} else {
   4047 
   4048 
   4049 		error_bg = dev_wlc_intvar_set(dev, "bg_rate", 0);
   4050 
   4051 		error_a = dev_wlc_intvar_set(dev, "a_rate", 0);
   4052 
   4053 		if (error_bg && error_a)
   4054 			return (error_bg | error_a);
   4055 
   4056 
   4057 		for (i = 0; i < rateset.count; i++)
   4058 			if ((rateset.rates[i] & 0x7f) > rate)
   4059 				break;
   4060 		rateset.count = htod32(i);
   4061 
   4062 
   4063 		if ((error = dev_wlc_ioctl(dev, WLC_SET_RATESET, &rateset, sizeof(rateset))))
   4064 			return error;
   4065 	}
   4066 
   4067 	return 0;
   4068 }
   4069 
   4070 static int wl_iw_get_rate(
   4071 	struct net_device *dev,
   4072 	struct iw_request_info *info,
   4073 	struct iw_param *vwrq,
   4074 	char *extra
   4075 )
   4076 {
   4077 	int error, rate;
   4078 
   4079 	WL_TRACE(("%s: SIOCGIWRATE\n", dev->name));
   4080 
   4081 
   4082 	if ((error = dev_wlc_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate))))
   4083 		return error;
   4084 	rate = dtoh32(rate);
   4085 	vwrq->value = rate * 500000;
   4086 
   4087 	return 0;
   4088 }
   4089 
   4090 static int
   4091 wl_iw_set_rts(
   4092 	struct net_device *dev,
   4093 	struct iw_request_info *info,
   4094 	struct iw_param *vwrq,
   4095 	char *extra
   4096 )
   4097 {
   4098 	int error, rts;
   4099 
   4100 	WL_TRACE(("%s: SIOCSIWRTS\n", dev->name));
   4101 
   4102 	if (vwrq->disabled)
   4103 		rts = DOT11_DEFAULT_RTS_LEN;
   4104 	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_RTS_LEN)
   4105 		return -EINVAL;
   4106 	else
   4107 		rts = vwrq->value;
   4108 
   4109 	if ((error = dev_wlc_intvar_set(dev, "rtsthresh", rts)))
   4110 		return error;
   4111 
   4112 	return 0;
   4113 }
   4114 
   4115 static int
   4116 wl_iw_get_rts(
   4117 	struct net_device *dev,
   4118 	struct iw_request_info *info,
   4119 	struct iw_param *vwrq,
   4120 	char *extra
   4121 )
   4122 {
   4123 	int error, rts;
   4124 
   4125 	WL_TRACE(("%s: SIOCGIWRTS\n", dev->name));
   4126 
   4127 	if ((error = dev_wlc_intvar_get(dev, "rtsthresh", &rts)))
   4128 		return error;
   4129 
   4130 	vwrq->value = rts;
   4131 	vwrq->disabled = (rts >= DOT11_DEFAULT_RTS_LEN);
   4132 	vwrq->fixed = 1;
   4133 
   4134 	return 0;
   4135 }
   4136 
   4137 static int
   4138 wl_iw_set_frag(
   4139 	struct net_device *dev,
   4140 	struct iw_request_info *info,
   4141 	struct iw_param *vwrq,
   4142 	char *extra
   4143 )
   4144 {
   4145 	int error, frag;
   4146 
   4147 	WL_TRACE(("%s: SIOCSIWFRAG\n", dev->name));
   4148 
   4149 	if (vwrq->disabled)
   4150 		frag = DOT11_DEFAULT_FRAG_LEN;
   4151 	else if (vwrq->value < 0 || vwrq->value > DOT11_DEFAULT_FRAG_LEN)
   4152 		return -EINVAL;
   4153 	else
   4154 		frag = vwrq->value;
   4155 
   4156 	if ((error = dev_wlc_intvar_set(dev, "fragthresh", frag)))
   4157 		return error;
   4158 
   4159 	return 0;
   4160 }
   4161 
   4162 static int
   4163 wl_iw_get_frag(
   4164 	struct net_device *dev,
   4165 	struct iw_request_info *info,
   4166 	struct iw_param *vwrq,
   4167 	char *extra
   4168 )
   4169 {
   4170 	int error, fragthreshold;
   4171 
   4172 	WL_TRACE(("%s: SIOCGIWFRAG\n", dev->name));
   4173 
   4174 	if ((error = dev_wlc_intvar_get(dev, "fragthresh", &fragthreshold)))
   4175 		return error;
   4176 
   4177 	vwrq->value = fragthreshold;
   4178 	vwrq->disabled = (fragthreshold >= DOT11_DEFAULT_FRAG_LEN);
   4179 	vwrq->fixed = 1;
   4180 
   4181 	return 0;
   4182 }
   4183 
   4184 static int
   4185 wl_iw_set_txpow(
   4186 	struct net_device *dev,
   4187 	struct iw_request_info *info,
   4188 	struct iw_param *vwrq,
   4189 	char *extra
   4190 )
   4191 {
   4192 	int error, disable;
   4193 	uint16 txpwrmw;
   4194 	WL_TRACE(("%s: SIOCSIWTXPOW\n", dev->name));
   4195 
   4196 
   4197 	disable = vwrq->disabled ? WL_RADIO_SW_DISABLE : 0;
   4198 	disable += WL_RADIO_SW_DISABLE << 16;
   4199 
   4200 	disable = htod32(disable);
   4201 	if ((error = dev_wlc_ioctl(dev, WLC_SET_RADIO, &disable, sizeof(disable))))
   4202 		return error;
   4203 
   4204 
   4205 	if (disable & WL_RADIO_SW_DISABLE)
   4206 		return 0;
   4207 
   4208 
   4209 	if (!(vwrq->flags & IW_TXPOW_MWATT))
   4210 		return -EINVAL;
   4211 
   4212 
   4213 	if (vwrq->value < 0)
   4214 		return 0;
   4215 
   4216 	if (vwrq->value > 0xffff) txpwrmw = 0xffff;
   4217 	else txpwrmw = (uint16)vwrq->value;
   4218 
   4219 
   4220 	error = dev_wlc_intvar_set(dev, "qtxpower", (int)(bcm_mw_to_qdbm(txpwrmw)));
   4221 	return error;
   4222 }
   4223 
   4224 static int
   4225 wl_iw_get_txpow(
   4226 	struct net_device *dev,
   4227 	struct iw_request_info *info,
   4228 	struct iw_param *vwrq,
   4229 	char *extra
   4230 )
   4231 {
   4232 	int error, disable, txpwrdbm;
   4233 	uint8 result;
   4234 
   4235 	WL_TRACE(("%s: SIOCGIWTXPOW\n", dev->name));
   4236 
   4237 	if ((error = dev_wlc_ioctl(dev, WLC_GET_RADIO, &disable, sizeof(disable))) ||
   4238 	    (error = dev_wlc_intvar_get(dev, "qtxpower", &txpwrdbm)))
   4239 		return error;
   4240 
   4241 	disable = dtoh32(disable);
   4242 	result = (uint8)(txpwrdbm & ~WL_TXPWR_OVERRIDE);
   4243 	vwrq->value = (int32)bcm_qdbm_to_mw(result);
   4244 	vwrq->fixed = 0;
   4245 	vwrq->disabled = (disable & (WL_RADIO_SW_DISABLE | WL_RADIO_HW_DISABLE)) ? 1 : 0;
   4246 	vwrq->flags = IW_TXPOW_MWATT;
   4247 
   4248 	return 0;
   4249 }
   4250 
   4251 #if WIRELESS_EXT > 10
   4252 static int
   4253 wl_iw_set_retry(
   4254 	struct net_device *dev,
   4255 	struct iw_request_info *info,
   4256 	struct iw_param *vwrq,
   4257 	char *extra
   4258 )
   4259 {
   4260 	int error, lrl, srl;
   4261 
   4262 	WL_TRACE(("%s: SIOCSIWRETRY\n", dev->name));
   4263 
   4264 
   4265 	if (vwrq->disabled || (vwrq->flags & IW_RETRY_LIFETIME))
   4266 		return -EINVAL;
   4267 
   4268 
   4269 	if (vwrq->flags & IW_RETRY_LIMIT) {
   4270 
   4271 
   4272 #if WIRELESS_EXT > 20
   4273 	if ((vwrq->flags & IW_RETRY_LONG) ||(vwrq->flags & IW_RETRY_MAX) ||
   4274 		!((vwrq->flags & IW_RETRY_SHORT) || (vwrq->flags & IW_RETRY_MIN))) {
   4275 #else
   4276 	if ((vwrq->flags & IW_RETRY_MAX) || !(vwrq->flags & IW_RETRY_MIN)) {
   4277 #endif
   4278 			lrl = htod32(vwrq->value);
   4279 			if ((error = dev_wlc_ioctl(dev, WLC_SET_LRL, &lrl, sizeof(lrl))))
   4280 				return error;
   4281 		}
   4282 
   4283 
   4284 #if WIRELESS_EXT > 20
   4285 	if ((vwrq->flags & IW_RETRY_SHORT) ||(vwrq->flags & IW_RETRY_MIN) ||
   4286 		!((vwrq->flags & IW_RETRY_LONG) || (vwrq->flags & IW_RETRY_MAX))) {
   4287 #else
   4288 		if ((vwrq->flags & IW_RETRY_MIN) || !(vwrq->flags & IW_RETRY_MAX)) {
   4289 #endif
   4290 			srl = htod32(vwrq->value);
   4291 			if ((error = dev_wlc_ioctl(dev, WLC_SET_SRL, &srl, sizeof(srl))))
   4292 				return error;
   4293 		}
   4294 	}
   4295 	return 0;
   4296 }
   4297 
   4298 static int
   4299 wl_iw_get_retry(
   4300 	struct net_device *dev,
   4301 	struct iw_request_info *info,
   4302 	struct iw_param *vwrq,
   4303 	char *extra
   4304 )
   4305 {
   4306 	int error, lrl, srl;
   4307 
   4308 	WL_TRACE(("%s: SIOCGIWRETRY\n", dev->name));
   4309 
   4310 	vwrq->disabled = 0;
   4311 
   4312 
   4313 	if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
   4314 		return -EINVAL;
   4315 
   4316 
   4317 	if ((error = dev_wlc_ioctl(dev, WLC_GET_LRL, &lrl, sizeof(lrl))) ||
   4318 	    (error = dev_wlc_ioctl(dev, WLC_GET_SRL, &srl, sizeof(srl))))
   4319 		return error;
   4320 
   4321 	lrl = dtoh32(lrl);
   4322 	srl = dtoh32(srl);
   4323 
   4324 
   4325 	if (vwrq->flags & IW_RETRY_MAX) {
   4326 		vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
   4327 		vwrq->value = lrl;
   4328 	} else {
   4329 		vwrq->flags = IW_RETRY_LIMIT;
   4330 		vwrq->value = srl;
   4331 		if (srl != lrl)
   4332 			vwrq->flags |= IW_RETRY_MIN;
   4333 	}
   4334 
   4335 	return 0;
   4336 }
   4337 #endif
   4338 
   4339 static int
   4340 wl_iw_set_encode(
   4341 	struct net_device *dev,
   4342 	struct iw_request_info *info,
   4343 	struct iw_point *dwrq,
   4344 	char *extra
   4345 )
   4346 {
   4347 	wl_wsec_key_t key;
   4348 	int error, val, wsec;
   4349 
   4350 	WL_TRACE(("%s: SIOCSIWENCODE\n", dev->name));
   4351 
   4352 	memset(&key, 0, sizeof(key));
   4353 
   4354 	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
   4355 
   4356 		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
   4357 			val = htod32(key.index);
   4358 			if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
   4359 				return error;
   4360 			val = dtoh32(val);
   4361 			if (val)
   4362 				break;
   4363 		}
   4364 
   4365 		if (key.index == DOT11_MAX_DEFAULT_KEYS)
   4366 			key.index = 0;
   4367 	} else {
   4368 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
   4369 		if (key.index >= DOT11_MAX_DEFAULT_KEYS)
   4370 			return -EINVAL;
   4371 	}
   4372 
   4373 
   4374 	if (!extra || !dwrq->length || (dwrq->flags & IW_ENCODE_NOKEY)) {
   4375 
   4376 		val = htod32(key.index);
   4377 		if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY, &val, sizeof(val))))
   4378 			return error;
   4379 	} else {
   4380 		key.len = dwrq->length;
   4381 
   4382 		if (dwrq->length > sizeof(key.data))
   4383 			return -EINVAL;
   4384 
   4385 		memcpy(key.data, extra, dwrq->length);
   4386 
   4387 		key.flags = WL_PRIMARY_KEY;
   4388 		switch (key.len) {
   4389 		case WEP1_KEY_SIZE:
   4390 			key.algo = CRYPTO_ALGO_WEP1;
   4391 			break;
   4392 		case WEP128_KEY_SIZE:
   4393 			key.algo = CRYPTO_ALGO_WEP128;
   4394 			break;
   4395 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
   4396 		case TKIP_KEY_SIZE:
   4397 			key.algo = CRYPTO_ALGO_TKIP;
   4398 			break;
   4399 #endif
   4400 		case AES_KEY_SIZE:
   4401 			key.algo = CRYPTO_ALGO_AES_CCM;
   4402 			break;
   4403 		default:
   4404 			return -EINVAL;
   4405 		}
   4406 
   4407 
   4408 		swap_key_from_BE(&key);
   4409 		if ((error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key))))
   4410 			return error;
   4411 	}
   4412 
   4413 
   4414 	val = (dwrq->flags & IW_ENCODE_DISABLED) ? 0 : WEP_ENABLED;
   4415 
   4416 	if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
   4417 		return error;
   4418 
   4419 	wsec  &= ~(WEP_ENABLED);
   4420 	wsec |= val;
   4421 
   4422 	if ((error = dev_wlc_intvar_set(dev, "wsec", wsec)))
   4423 		return error;
   4424 
   4425 
   4426 	val = (dwrq->flags & IW_ENCODE_RESTRICTED) ? 1 : 0;
   4427 	val = htod32(val);
   4428 	if ((error = dev_wlc_ioctl(dev, WLC_SET_AUTH, &val, sizeof(val))))
   4429 		return error;
   4430 
   4431 	return 0;
   4432 }
   4433 
   4434 static int
   4435 wl_iw_get_encode(
   4436 	struct net_device *dev,
   4437 	struct iw_request_info *info,
   4438 	struct iw_point *dwrq,
   4439 	char *extra
   4440 )
   4441 {
   4442 	wl_wsec_key_t key;
   4443 	int error, val, wsec, auth;
   4444 
   4445 	WL_TRACE(("%s: SIOCGIWENCODE\n", dev->name));
   4446 
   4447 
   4448 	bzero(&key, sizeof(wl_wsec_key_t));
   4449 
   4450 	if ((dwrq->flags & IW_ENCODE_INDEX) == 0) {
   4451 
   4452 		for (key.index = 0; key.index < DOT11_MAX_DEFAULT_KEYS; key.index++) {
   4453 			val = key.index;
   4454 			if ((error = dev_wlc_ioctl(dev, WLC_GET_KEY_PRIMARY, &val, sizeof(val))))
   4455 				return error;
   4456 			val = dtoh32(val);
   4457 			if (val)
   4458 				break;
   4459 		}
   4460 	} else
   4461 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
   4462 
   4463 	if (key.index >= DOT11_MAX_DEFAULT_KEYS)
   4464 		key.index = 0;
   4465 
   4466 
   4467 
   4468 	if ((error = dev_wlc_ioctl(dev, WLC_GET_WSEC, &wsec, sizeof(wsec))) ||
   4469 	    (error = dev_wlc_ioctl(dev, WLC_GET_AUTH, &auth, sizeof(auth))))
   4470 		return error;
   4471 
   4472 	swap_key_to_BE(&key);
   4473 
   4474 	wsec = dtoh32(wsec);
   4475 	auth = dtoh32(auth);
   4476 
   4477 	dwrq->length = MIN(DOT11_MAX_KEY_SIZE, key.len);
   4478 
   4479 
   4480 	dwrq->flags = key.index + 1;
   4481 	if (!(wsec & (WEP_ENABLED | TKIP_ENABLED | AES_ENABLED))) {
   4482 
   4483 		dwrq->flags |= IW_ENCODE_DISABLED;
   4484 	}
   4485 	if (auth) {
   4486 
   4487 		dwrq->flags |= IW_ENCODE_RESTRICTED;
   4488 	}
   4489 
   4490 
   4491 	if (dwrq->length && extra)
   4492 		memcpy(extra, key.data, dwrq->length);
   4493 
   4494 	return 0;
   4495 }
   4496 
   4497 static int
   4498 wl_iw_set_power(
   4499 	struct net_device *dev,
   4500 	struct iw_request_info *info,
   4501 	struct iw_param *vwrq,
   4502 	char *extra
   4503 )
   4504 {
   4505 	int error, pm;
   4506 
   4507 	WL_TRACE(("%s: SIOCSIWPOWER\n", dev->name));
   4508 
   4509 	pm = vwrq->disabled ? PM_OFF : PM_MAX;
   4510 
   4511 	pm = htod32(pm);
   4512 	if ((error = dev_wlc_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm))))
   4513 		return error;
   4514 
   4515 	return 0;
   4516 }
   4517 
   4518 static int
   4519 wl_iw_get_power(
   4520 	struct net_device *dev,
   4521 	struct iw_request_info *info,
   4522 	struct iw_param *vwrq,
   4523 	char *extra
   4524 )
   4525 {
   4526 	int error, pm;
   4527 
   4528 	WL_TRACE(("%s: SIOCGIWPOWER\n", dev->name));
   4529 
   4530 	if ((error = dev_wlc_ioctl(dev, WLC_GET_PM, &pm, sizeof(pm))))
   4531 		return error;
   4532 
   4533 	pm = dtoh32(pm);
   4534 	vwrq->disabled = pm ? 0 : 1;
   4535 	vwrq->flags = IW_POWER_ALL_R;
   4536 
   4537 	return 0;
   4538 }
   4539 
   4540 #if WIRELESS_EXT > 17
   4541 static int
   4542 wl_iw_set_wpaie(
   4543 	struct net_device *dev,
   4544 	struct iw_request_info *info,
   4545 	struct iw_point *iwp,
   4546 	char *extra
   4547 )
   4548 {
   4549 	uchar buf[WLC_IOCTL_SMLEN] = {0};
   4550 	uchar *p = buf;
   4551 	int wapi_ie_size;
   4552 
   4553 	WL_TRACE(("%s: SIOCSIWGENIE\n", dev->name));
   4554 
   4555 	CHECK_EXTRA_FOR_NULL(extra);
   4556 
   4557 	if (extra[0] == DOT11_MNG_WAPI_ID)
   4558 	{
   4559 		wapi_ie_size = iwp->length;
   4560 		memcpy(p, extra, iwp->length);
   4561 		dev_wlc_bufvar_set(dev, "wapiie", buf, wapi_ie_size);
   4562 	}
   4563 	else
   4564 		dev_wlc_bufvar_set(dev, "wpaie", extra, iwp->length);
   4565 
   4566 	return 0;
   4567 }
   4568 
   4569 static int
   4570 wl_iw_get_wpaie(
   4571 	struct net_device *dev,
   4572 	struct iw_request_info *info,
   4573 	struct iw_point *iwp,
   4574 	char *extra
   4575 )
   4576 {
   4577 	WL_TRACE(("%s: SIOCGIWGENIE\n", dev->name));
   4578 	iwp->length = 64;
   4579 	dev_wlc_bufvar_get(dev, "wpaie", extra, iwp->length);
   4580 	return 0;
   4581 }
   4582 
   4583 static int
   4584 wl_iw_set_encodeext(
   4585 	struct net_device *dev,
   4586 	struct iw_request_info *info,
   4587 	struct iw_point *dwrq,
   4588 	char *extra
   4589 )
   4590 {
   4591 	wl_wsec_key_t key;
   4592 	int error;
   4593 	struct iw_encode_ext *iwe;
   4594 
   4595 	WL_TRACE(("%s: SIOCSIWENCODEEXT\n", dev->name));
   4596 
   4597 	CHECK_EXTRA_FOR_NULL(extra);
   4598 
   4599 	memset(&key, 0, sizeof(key));
   4600 	iwe = (struct iw_encode_ext *)extra;
   4601 
   4602 
   4603 	if (dwrq->flags & IW_ENCODE_DISABLED) {
   4604 
   4605 	}
   4606 
   4607 
   4608 	key.index = 0;
   4609 	if (dwrq->flags & IW_ENCODE_INDEX)
   4610 		key.index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
   4611 
   4612 	key.len = iwe->key_len;
   4613 
   4614 
   4615 	if (!ETHER_ISMULTI(iwe->addr.sa_data))
   4616 		bcopy((void *)&iwe->addr.sa_data, (char *)&key.ea, ETHER_ADDR_LEN);
   4617 
   4618 
   4619 	if (key.len == 0) {
   4620 		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
   4621 			WL_WSEC(("Changing the the primary Key to %d\n", key.index));
   4622 
   4623 			key.index = htod32(key.index);
   4624 			error = dev_wlc_ioctl(dev, WLC_SET_KEY_PRIMARY,
   4625 				&key.index, sizeof(key.index));
   4626 			if (error)
   4627 				return error;
   4628 		}
   4629 
   4630 		else {
   4631 			swap_key_from_BE(&key);
   4632 			dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
   4633 		}
   4634 	}
   4635 	else {
   4636 		if (iwe->key_len > sizeof(key.data))
   4637 			return -EINVAL;
   4638 
   4639 		WL_WSEC(("Setting the key index %d\n", key.index));
   4640 		if (iwe->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
   4641 			WL_WSEC(("key is a Primary Key\n"));
   4642 			key.flags = WL_PRIMARY_KEY;
   4643 		}
   4644 
   4645 		bcopy((void *)iwe->key, key.data, iwe->key_len);
   4646 
   4647 		if (iwe->alg == IW_ENCODE_ALG_TKIP) {
   4648 			uint8 keybuf[8];
   4649 			bcopy(&key.data[24], keybuf, sizeof(keybuf));
   4650 			bcopy(&key.data[16], &key.data[24], sizeof(keybuf));
   4651 			bcopy(keybuf, &key.data[16], sizeof(keybuf));
   4652 		}
   4653 
   4654 
   4655 		if (iwe->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
   4656 			uchar *ivptr;
   4657 			ivptr = (uchar *)iwe->rx_seq;
   4658 			key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
   4659 				(ivptr[3] << 8) | ivptr[2];
   4660 			key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
   4661 			key.iv_initialized = TRUE;
   4662 		}
   4663 
   4664 		switch (iwe->alg) {
   4665 			case IW_ENCODE_ALG_NONE:
   4666 				key.algo = CRYPTO_ALGO_OFF;
   4667 				break;
   4668 			case IW_ENCODE_ALG_WEP:
   4669 				if (iwe->key_len == WEP1_KEY_SIZE)
   4670 					key.algo = CRYPTO_ALGO_WEP1;
   4671 				else
   4672 					key.algo = CRYPTO_ALGO_WEP128;
   4673 				break;
   4674 			case IW_ENCODE_ALG_TKIP:
   4675 				key.algo = CRYPTO_ALGO_TKIP;
   4676 				break;
   4677 			case IW_ENCODE_ALG_CCMP:
   4678 				key.algo = CRYPTO_ALGO_AES_CCM;
   4679 				break;
   4680 			case IW_ENCODE_ALG_SM4:
   4681 				key.algo = CRYPTO_ALGO_SMS4;
   4682 				if (iwe->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
   4683 					key.flags &= ~WL_PRIMARY_KEY;
   4684 				}
   4685 				break;
   4686 			default:
   4687 				break;
   4688 		}
   4689 		swap_key_from_BE(&key);
   4690 
   4691 		dhd_wait_pend8021x(dev);
   4692 
   4693 		error = dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
   4694 		if (error)
   4695 			return error;
   4696 	}
   4697 	return 0;
   4698 }
   4699 
   4700 #if WIRELESS_EXT > 17
   4701 #ifdef BCMWPA2
   4702 struct {
   4703 	pmkid_list_t pmkids;
   4704 	pmkid_t foo[MAXPMKID-1];
   4705 } pmkid_list;
   4706 
   4707 static int
   4708 wl_iw_set_pmksa(
   4709 	struct net_device *dev,
   4710 	struct iw_request_info *info,
   4711 	struct iw_param *vwrq,
   4712 	char *extra
   4713 )
   4714 {
   4715 	struct iw_pmksa *iwpmksa;
   4716 	uint i;
   4717 	int ret = 0;
   4718 	char eabuf[ETHER_ADDR_STR_LEN];
   4719 
   4720 	WL_WSEC(("%s: SIOCSIWPMKSA\n", dev->name));
   4721 	CHECK_EXTRA_FOR_NULL(extra);
   4722 
   4723 	iwpmksa = (struct iw_pmksa *)extra;
   4724 	bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
   4725 
   4726 	if (iwpmksa->cmd == IW_PMKSA_FLUSH) {
   4727 		WL_WSEC(("wl_iw_set_pmksa - IW_PMKSA_FLUSH\n"));
   4728 		bzero((char *)&pmkid_list, sizeof(pmkid_list));
   4729 	}
   4730 
   4731 	else if (iwpmksa->cmd == IW_PMKSA_REMOVE) {
   4732 		{
   4733 			pmkid_list_t pmkid, *pmkidptr;
   4734 			uint j;
   4735 			pmkidptr = &pmkid;
   4736 
   4737 			bcopy(&iwpmksa->bssid.sa_data[0], &pmkidptr->pmkid[0].BSSID, ETHER_ADDR_LEN);
   4738 			bcopy(&iwpmksa->pmkid[0], &pmkidptr->pmkid[0].PMKID, WPA2_PMKID_LEN);
   4739 
   4740 			WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_REMOVE - PMKID: %s = ",
   4741 				bcm_ether_ntoa(&pmkidptr->pmkid[0].BSSID,
   4742 				eabuf)));
   4743 			for (j = 0; j < WPA2_PMKID_LEN; j++)
   4744 				WL_WSEC(("%02x ", pmkidptr->pmkid[0].PMKID[j]));
   4745 			WL_WSEC(("\n"));
   4746 		}
   4747 
   4748 		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
   4749 			if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
   4750 				ETHER_ADDR_LEN))
   4751 				break;
   4752 
   4753 		if ((pmkid_list.pmkids.npmkid > 0) && (i < pmkid_list.pmkids.npmkid)) {
   4754 			bzero(&pmkid_list.pmkids.pmkid[i], sizeof(pmkid_t));
   4755 			for (; i < (pmkid_list.pmkids.npmkid - 1); i++) {
   4756 				bcopy(&pmkid_list.pmkids.pmkid[i+1].BSSID,
   4757 					&pmkid_list.pmkids.pmkid[i].BSSID,
   4758 					ETHER_ADDR_LEN);
   4759 				bcopy(&pmkid_list.pmkids.pmkid[i+1].PMKID,
   4760 					&pmkid_list.pmkids.pmkid[i].PMKID,
   4761 					WPA2_PMKID_LEN);
   4762 			}
   4763 			pmkid_list.pmkids.npmkid--;
   4764 		}
   4765 		else
   4766 			ret = -EINVAL;
   4767 	}
   4768 
   4769 	else if (iwpmksa->cmd == IW_PMKSA_ADD) {
   4770 		for (i = 0; i < pmkid_list.pmkids.npmkid; i++)
   4771 			if (!bcmp(&iwpmksa->bssid.sa_data[0], &pmkid_list.pmkids.pmkid[i].BSSID,
   4772 				ETHER_ADDR_LEN))
   4773 				break;
   4774 		if (i < MAXPMKID) {
   4775 			bcopy(&iwpmksa->bssid.sa_data[0],
   4776 				&pmkid_list.pmkids.pmkid[i].BSSID,
   4777 				ETHER_ADDR_LEN);
   4778 			bcopy(&iwpmksa->pmkid[0], &pmkid_list.pmkids.pmkid[i].PMKID,
   4779 				WPA2_PMKID_LEN);
   4780 			if (i == pmkid_list.pmkids.npmkid)
   4781 				pmkid_list.pmkids.npmkid++;
   4782 		}
   4783 		else
   4784 			ret = -EINVAL;
   4785 
   4786 		{
   4787 			uint j;
   4788 			uint k;
   4789 			k = pmkid_list.pmkids.npmkid;
   4790 			WL_WSEC(("wl_iw_set_pmksa,IW_PMKSA_ADD - PMKID: %s = ",
   4791 				bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[k].BSSID,
   4792 				eabuf)));
   4793 			for (j = 0; j < WPA2_PMKID_LEN; j++)
   4794 				WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[k].PMKID[j]));
   4795 			WL_WSEC(("\n"));
   4796 		}
   4797 	}
   4798 	WL_WSEC(("PRINTING pmkid LIST - No of elements %d, ret = %d\n", pmkid_list.pmkids.npmkid, ret));
   4799 	for (i = 0; i < pmkid_list.pmkids.npmkid; i++) {
   4800 		uint j;
   4801 		WL_WSEC(("PMKID[%d]: %s = ", i,
   4802 			bcm_ether_ntoa(&pmkid_list.pmkids.pmkid[i].BSSID,
   4803 			eabuf)));
   4804 		for (j = 0; j < WPA2_PMKID_LEN; j++)
   4805 			WL_WSEC(("%02x ", pmkid_list.pmkids.pmkid[i].PMKID[j]));
   4806 		WL_WSEC(("\n"));
   4807 	}
   4808 	WL_WSEC(("\n"));
   4809 
   4810 	if (!ret)
   4811 		ret = dev_wlc_bufvar_set(dev, "pmkid_info", (char *)&pmkid_list, sizeof(pmkid_list));
   4812 	return ret;
   4813 }
   4814 #endif
   4815 #endif
   4816 
   4817 static int
   4818 wl_iw_get_encodeext(
   4819 	struct net_device *dev,
   4820 	struct iw_request_info *info,
   4821 	struct iw_param *vwrq,
   4822 	char *extra
   4823 )
   4824 {
   4825 	WL_TRACE(("%s: SIOCGIWENCODEEXT\n", dev->name));
   4826 	return 0;
   4827 }
   4828 
   4829 static int
   4830 wl_iw_set_wpaauth(
   4831 	struct net_device *dev,
   4832 	struct iw_request_info *info,
   4833 	struct iw_param *vwrq,
   4834 	char *extra
   4835 )
   4836 {
   4837 	int error = 0;
   4838 	int paramid;
   4839 	int paramval;
   4840 	int val = 0;
   4841 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   4842 
   4843 	WL_TRACE(("%s: SIOCSIWAUTH\n", dev->name));
   4844 
   4845 #if defined(SOFTAP)
   4846 	if (ap_cfg_running) {
   4847 		WL_TRACE(("%s: Not executed, reason -'SOFTAP is active'\n", __FUNCTION__));
   4848 		return 0;
   4849 	}
   4850 #endif
   4851 
   4852 	paramid = vwrq->flags & IW_AUTH_INDEX;
   4853 	paramval = vwrq->value;
   4854 
   4855 	WL_TRACE(("%s: SIOCSIWAUTH, paramid = 0x%0x, paramval = 0x%0x\n",
   4856 		dev->name, paramid, paramval));
   4857 
   4858 	switch (paramid) {
   4859 	case IW_AUTH_WPA_VERSION:
   4860 
   4861 		if (paramval & IW_AUTH_WPA_VERSION_DISABLED)
   4862 			val = WPA_AUTH_DISABLED;
   4863 		else if (paramval & (IW_AUTH_WPA_VERSION_WPA))
   4864 			val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED;
   4865 #ifdef BCMWPA2
   4866 		else if (paramval & IW_AUTH_WPA_VERSION_WPA2)
   4867 			val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED;
   4868 #endif
   4869 		else if (paramval & IW_AUTH_WAPI_VERSION_1)
   4870 			val = WPA_AUTH_WAPI;
   4871 		WL_INFORM(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val));
   4872 		if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
   4873 			return error;
   4874 		break;
   4875 	case IW_AUTH_CIPHER_PAIRWISE:
   4876 	case IW_AUTH_CIPHER_GROUP:
   4877 
   4878 
   4879 		if (paramval & (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104))
   4880 			val = 	WEP_ENABLED;
   4881 		if (paramval & IW_AUTH_CIPHER_TKIP)
   4882 			val = TKIP_ENABLED;
   4883 		if (paramval & IW_AUTH_CIPHER_CCMP)
   4884 			val = AES_ENABLED;
   4885 		if (paramval & IW_AUTH_CIPHER_SMS4)
   4886 			val = SMS4_ENABLED;
   4887 
   4888 		if (paramid == IW_AUTH_CIPHER_PAIRWISE) {
   4889 			iw->pwsec = val;
   4890 			val |= iw->gwsec;
   4891 		}
   4892 		else {
   4893 			iw->gwsec = val;
   4894 			val |= iw->pwsec;
   4895 		}
   4896 
   4897 		if (iw->privacy_invoked && !val) {
   4898 			WL_WSEC(("%s: %s: 'Privacy invoked' TRUE but clearing wsec, assuming "
   4899 				"we're a WPS enrollee\n", dev->name, __FUNCTION__));
   4900 			if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
   4901 				WL_WSEC(("Failed to set iovar is_WPS_enrollee\n"));
   4902 				return error;
   4903 			}
   4904 		} else if (val) {
   4905 			if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
   4906 				WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
   4907 				return error;
   4908 			}
   4909 		}
   4910 
   4911 		if ((error = dev_wlc_intvar_set(dev, "wsec", val)))
   4912 			return error;
   4913 
   4914 		break;
   4915 
   4916 	case IW_AUTH_KEY_MGMT:
   4917 		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
   4918 			return error;
   4919 
   4920 		if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
   4921 			if (paramval & IW_AUTH_KEY_MGMT_PSK)
   4922 				val = WPA_AUTH_PSK;
   4923 			else
   4924 				val = WPA_AUTH_UNSPECIFIED;
   4925 		}
   4926 #ifdef BCMWPA2
   4927 		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
   4928 			if (paramval & IW_AUTH_KEY_MGMT_PSK)
   4929 				val = WPA2_AUTH_PSK;
   4930 			else
   4931 				val = WPA2_AUTH_UNSPECIFIED;
   4932 		}
   4933 #endif
   4934 		if (paramval & (IW_AUTH_KEY_MGMT_WAPI_PSK | IW_AUTH_KEY_MGMT_WAPI_CERT))
   4935 			val = WPA_AUTH_WAPI;
   4936 		WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
   4937 		if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val)))
   4938 			return error;
   4939 
   4940 		break;
   4941 	case IW_AUTH_TKIP_COUNTERMEASURES:
   4942 		dev_wlc_bufvar_set(dev, "tkip_countermeasures", (char *)&paramval, 1);
   4943 		break;
   4944 
   4945 	case IW_AUTH_80211_AUTH_ALG:
   4946 
   4947 		WL_INFORM(("Setting the D11auth %d\n", paramval));
   4948 		if (paramval == IW_AUTH_ALG_OPEN_SYSTEM)
   4949 			val = 0;
   4950 		else if (paramval == IW_AUTH_ALG_SHARED_KEY)
   4951 			val = 1;
   4952 		else if (paramval == (IW_AUTH_ALG_OPEN_SYSTEM | IW_AUTH_ALG_SHARED_KEY))
   4953 			val = 2;
   4954 		else
   4955 			error = 1;
   4956 		if (!error && (error = dev_wlc_intvar_set(dev, "auth", val)))
   4957 			return error;
   4958 		break;
   4959 
   4960 	case IW_AUTH_WPA_ENABLED:
   4961 		if (paramval == 0) {
   4962 			iw->pwsec = 0;
   4963 			iw->gwsec = 0;
   4964 			if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
   4965 				return error;
   4966 			if (val & (TKIP_ENABLED | AES_ENABLED)) {
   4967 				val &= ~(TKIP_ENABLED | AES_ENABLED);
   4968 				dev_wlc_intvar_set(dev, "wsec", val);
   4969 			}
   4970 			val = 0;
   4971 		WL_INFORM(("%s: %d: setting wpa_auth to %d\n", __FUNCTION__, __LINE__, val));
   4972 			dev_wlc_intvar_set(dev, "wpa_auth", 0);
   4973 			return error;
   4974 		}
   4975 
   4976 
   4977 		break;
   4978 
   4979 	case IW_AUTH_DROP_UNENCRYPTED:
   4980 		dev_wlc_bufvar_set(dev, "wsec_restrict", (char *)&paramval, 1);
   4981 		break;
   4982 
   4983 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
   4984 		dev_wlc_bufvar_set(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
   4985 		break;
   4986 
   4987 #if WIRELESS_EXT > 17
   4988 	case IW_AUTH_ROAMING_CONTROL:
   4989 		WL_INFORM(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
   4990 
   4991 		break;
   4992 	case IW_AUTH_PRIVACY_INVOKED: {
   4993 		int wsec;
   4994 
   4995 		if (paramval == 0) {
   4996 			iw->privacy_invoked = FALSE;
   4997 			if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
   4998 				WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
   4999 				return error;
   5000 			}
   5001 		} else {
   5002 			iw->privacy_invoked = TRUE;
   5003 			if ((error = dev_wlc_intvar_get(dev, "wsec", &wsec)))
   5004 				return error;
   5005 
   5006 			if (!(IW_WSEC_ENABLED(wsec))) {
   5007 
   5008 				if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", TRUE))) {
   5009 					WL_WSEC(("Failed to set iovar is_WPS_enrollee\n"));
   5010 					return error;
   5011 				}
   5012 			} else {
   5013 				if ((error = dev_wlc_intvar_set(dev, "is_WPS_enrollee", FALSE))) {
   5014 					WL_WSEC(("Failed to clear iovar is_WPS_enrollee\n"));
   5015 					return error;
   5016 				}
   5017 			}
   5018 		}
   5019 		break;
   5020 	}
   5021 #endif
   5022 	case IW_AUTH_WAPI_ENABLED:
   5023 		if ((error = dev_wlc_intvar_get(dev, "wsec", &val)))
   5024 			return error;
   5025 		if (paramval) {
   5026 			val |= SMS4_ENABLED;
   5027 			if ((error = dev_wlc_intvar_set(dev, "wsec", val))) {
   5028 				WL_ERROR(("%s: setting wsec to 0x%0x returned error %d\n",
   5029 					__FUNCTION__, val, error));
   5030 				return error;
   5031 			}
   5032 			if ((error = dev_wlc_intvar_set(dev, "wpa_auth", WPA_AUTH_WAPI))) {
   5033 				WL_ERROR(("%s: setting wpa_auth(WPA_AUTH_WAPI) returned %d\n",
   5034 					__FUNCTION__, error));
   5035 				return error;
   5036 			}
   5037 		}
   5038 
   5039 		break;
   5040 	default:
   5041 		break;
   5042 	}
   5043 	return 0;
   5044 }
   5045 #ifdef BCMWPA2
   5046 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK) || ((_val) & WPA2_AUTH_PSK))
   5047 #else
   5048 #define VAL_PSK(_val) (((_val) & WPA_AUTH_PSK))
   5049 #endif
   5050 
   5051 static int
   5052 wl_iw_get_wpaauth(
   5053 	struct net_device *dev,
   5054 	struct iw_request_info *info,
   5055 	struct iw_param *vwrq,
   5056 	char *extra
   5057 )
   5058 {
   5059 	int error;
   5060 	int paramid;
   5061 	int paramval = 0;
   5062 	int val;
   5063 	wl_iw_t *iw = *(wl_iw_t **)netdev_priv(dev);
   5064 
   5065 	WL_TRACE(("%s: SIOCGIWAUTH\n", dev->name));
   5066 
   5067 	paramid = vwrq->flags & IW_AUTH_INDEX;
   5068 
   5069 	switch (paramid) {
   5070 	case IW_AUTH_WPA_VERSION:
   5071 
   5072 		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
   5073 			return error;
   5074 		if (val & (WPA_AUTH_NONE | WPA_AUTH_DISABLED))
   5075 			paramval = IW_AUTH_WPA_VERSION_DISABLED;
   5076 		else if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED))
   5077 			paramval = IW_AUTH_WPA_VERSION_WPA;
   5078 #ifdef BCMWPA2
   5079 		else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED))
   5080 			paramval = IW_AUTH_WPA_VERSION_WPA2;
   5081 #endif
   5082 		break;
   5083 	case IW_AUTH_CIPHER_PAIRWISE:
   5084 	case IW_AUTH_CIPHER_GROUP:
   5085 		if (paramid == IW_AUTH_CIPHER_PAIRWISE)
   5086 			val = iw->pwsec;
   5087 		else
   5088 			val = iw->gwsec;
   5089 
   5090 		paramval = 0;
   5091 		if (val) {
   5092 			if (val & WEP_ENABLED)
   5093 				paramval |= (IW_AUTH_CIPHER_WEP40 | IW_AUTH_CIPHER_WEP104);
   5094 			if (val & TKIP_ENABLED)
   5095 				paramval |= (IW_AUTH_CIPHER_TKIP);
   5096 			if (val & AES_ENABLED)
   5097 				paramval |= (IW_AUTH_CIPHER_CCMP);
   5098 		}
   5099 		else
   5100 			paramval = IW_AUTH_CIPHER_NONE;
   5101 		break;
   5102 	case IW_AUTH_KEY_MGMT:
   5103 
   5104 		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
   5105 			return error;
   5106 		if (VAL_PSK(val))
   5107 			paramval = IW_AUTH_KEY_MGMT_PSK;
   5108 		else
   5109 			paramval = IW_AUTH_KEY_MGMT_802_1X;
   5110 
   5111 		break;
   5112 	case IW_AUTH_TKIP_COUNTERMEASURES:
   5113 		dev_wlc_bufvar_get(dev, "tkip_countermeasures", (char *)&paramval, 1);
   5114 		break;
   5115 
   5116 	case IW_AUTH_DROP_UNENCRYPTED:
   5117 		dev_wlc_bufvar_get(dev, "wsec_restrict", (char *)&paramval, 1);
   5118 		break;
   5119 
   5120 	case IW_AUTH_RX_UNENCRYPTED_EAPOL:
   5121 		dev_wlc_bufvar_get(dev, "rx_unencrypted_eapol", (char *)&paramval, 1);
   5122 		break;
   5123 
   5124 	case IW_AUTH_80211_AUTH_ALG:
   5125 
   5126 		if ((error = dev_wlc_intvar_get(dev, "auth", &val)))
   5127 			return error;
   5128 		if (!val)
   5129 			paramval = IW_AUTH_ALG_OPEN_SYSTEM;
   5130 		else
   5131 			paramval = IW_AUTH_ALG_SHARED_KEY;
   5132 		break;
   5133 	case IW_AUTH_WPA_ENABLED:
   5134 		if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val)))
   5135 			return error;
   5136 		if (val)
   5137 			paramval = TRUE;
   5138 		else
   5139 			paramval = FALSE;
   5140 		break;
   5141 #if WIRELESS_EXT > 17
   5142 	case IW_AUTH_ROAMING_CONTROL:
   5143 		WL_ERROR(("%s: IW_AUTH_ROAMING_CONTROL\n", __FUNCTION__));
   5144 
   5145 		break;
   5146 	case IW_AUTH_PRIVACY_INVOKED:
   5147 		paramval = iw->privacy_invoked;
   5148 		break;
   5149 #endif
   5150 	}
   5151 	vwrq->value = paramval;
   5152 	return 0;
   5153 }
   5154 #endif
   5155 
   5156 
   5157 #ifdef SOFTAP
   5158 
   5159 static int ap_macmode = MACLIST_MODE_DISABLED;
   5160 static struct mflist ap_black_list;
   5161 static int
   5162 wl_iw_parse_wep(char *keystr, wl_wsec_key_t *key)
   5163 {
   5164 	char hex[] = "XX";
   5165 	unsigned char *data = key->data;
   5166 
   5167 	switch (strlen(keystr)) {
   5168 	case 5:
   5169 	case 13:
   5170 	case 16:
   5171 		key->len = strlen(keystr);
   5172 		memcpy(data, keystr, key->len + 1);
   5173 		break;
   5174 	case 12:
   5175 	case 28:
   5176 	case 34:
   5177 	case 66:
   5178 		if (!strnicmp(keystr, "0x", 2))
   5179 			keystr += 2;
   5180 		else
   5181 			return -1;
   5182 	case 10:
   5183 	case 26:
   5184 	case 32:
   5185 	case 64:
   5186 		key->len = strlen(keystr) / 2;
   5187 		while (*keystr) {
   5188 			strncpy(hex, keystr, 2);
   5189 			*data++ = (char) bcm_strtoul(hex, NULL, 16);
   5190 			keystr += 2;
   5191 		}
   5192 		break;
   5193 	default:
   5194 		return -1;
   5195 	}
   5196 
   5197 	switch (key->len) {
   5198 	case 5:
   5199 		key->algo = CRYPTO_ALGO_WEP1;
   5200 		break;
   5201 	case 13:
   5202 		key->algo = CRYPTO_ALGO_WEP128;
   5203 		break;
   5204 	case 16:
   5205 		key->algo = CRYPTO_ALGO_AES_CCM;
   5206 		break;
   5207 	case 32:
   5208 		key->algo = CRYPTO_ALGO_TKIP;
   5209 		break;
   5210 	default:
   5211 		return -1;
   5212 	}
   5213 
   5214 	key->flags |= WL_PRIMARY_KEY;
   5215 
   5216 	return 0;
   5217 }
   5218 
   5219 #ifdef EXT_WPA_CRYPTO
   5220 #define SHA1HashSize 20
   5221 extern void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
   5222 				int iterations, u8 *buf, size_t buflen);
   5223 
   5224 #else
   5225 
   5226 #define SHA1HashSize 20
   5227 int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
   5228 				int iterations, u8 *buf, size_t buflen)
   5229 {
   5230 	WL_ERROR(("WARNING: %s is not implemented !!!\n", __FUNCTION__));
   5231 	return -1;
   5232 }
   5233 
   5234 #endif
   5235 
   5236 
   5237 int dev_iw_write_cfg1_bss_var(struct net_device *dev, int val)
   5238 {
   5239 	struct {
   5240 		int cfg;
   5241 		int val;
   5242 	} bss_setbuf;
   5243 
   5244 	int bss_set_res;
   5245 	char smbuf[WLC_IOCTL_SMLEN];
   5246 	memset(smbuf, 0, sizeof(smbuf));
   5247 
   5248 	bss_setbuf.cfg = 1;
   5249 	bss_setbuf.val = val;
   5250 
   5251 	bss_set_res = dev_iw_iovar_setbuf(dev, "bss",
   5252 		&bss_setbuf, sizeof(bss_setbuf), smbuf, sizeof(smbuf));
   5253 	WL_TRACE(("%s: bss_set_result:%d set with %d\n", __FUNCTION__, bss_set_res, val));
   5254 
   5255 	return bss_set_res;
   5256 }
   5257 
   5258 
   5259 int dev_iw_read_cfg1_bss_var(struct net_device *dev, int *val)
   5260 {
   5261 	int bsscfg_idx = 1;
   5262 	int bss_set_res;
   5263 	char smbuf[WLC_IOCTL_SMLEN];
   5264 	memset(smbuf, 0, sizeof(smbuf));
   5265 
   5266 	bss_set_res = dev_iw_iovar_getbuf(dev, "bss", \
   5267 		 &bsscfg_idx, sizeof(bsscfg_idx), smbuf, sizeof(smbuf));
   5268 	*val = *(int*)smbuf;
   5269 	*val = dtoh32(*val);
   5270 	WL_TRACE(("%s: status=%d bss_get_result=%d\n", __FUNCTION__, bss_set_res, *val));
   5271 	return bss_set_res;
   5272 }
   5273 
   5274 
   5275 #ifndef AP_ONLY
   5276 static int wl_bssiovar_mkbuf(
   5277 			const char *iovar,
   5278 			int bssidx,
   5279 			void *param,
   5280 			int paramlen,
   5281 			void *bufptr,
   5282 			int buflen,
   5283 			int *perr)
   5284 {
   5285 	const char *prefix = "bsscfg:";
   5286 	int8 *p;
   5287 	uint prefixlen;
   5288 	uint namelen;
   5289 	uint iolen;
   5290 
   5291 	prefixlen = strlen(prefix);
   5292 	namelen = strlen(iovar) + 1;
   5293 	iolen = prefixlen + namelen + sizeof(int) + paramlen;
   5294 
   5295 	if (buflen < 0 || iolen > (uint)buflen) {
   5296 		*perr = BCME_BUFTOOSHORT;
   5297 		return 0;
   5298 	}
   5299 
   5300 	p = (int8 *)bufptr;
   5301 
   5302 	memcpy(p, prefix, prefixlen);
   5303 	p += prefixlen;
   5304 
   5305 	memcpy(p, iovar, namelen);
   5306 	p += namelen;
   5307 
   5308 	bssidx = htod32(bssidx);
   5309 	memcpy(p, &bssidx, sizeof(int32));
   5310 	p += sizeof(int32);
   5311 
   5312 	if (paramlen)
   5313 		memcpy(p, param, paramlen);
   5314 
   5315 	*perr = 0;
   5316 	return iolen;
   5317 }
   5318 #endif
   5319 
   5320 
   5321 int get_user_params(char *user_params, struct iw_point *dwrq)
   5322 {
   5323 	int ret = 0;
   5324 
   5325 	if (copy_from_user(user_params, dwrq->pointer, dwrq->length)) {
   5326 		WL_ERROR(("\n%s: no user params: uptr:%p, ulen:%d\n",
   5327 			__FUNCTION__, dwrq->pointer, dwrq->length));
   5328 		return -EFAULT;
   5329 	}
   5330 
   5331 	WL_TRACE(("\n%s: iwpriv user params:%s\n", __FUNCTION__, user_params));
   5332 
   5333 	return ret;
   5334 }
   5335 
   5336 
   5337 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
   5338 
   5339 #if defined(CSCAN)
   5340 
   5341 static int
   5342 wl_iw_combined_scan_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, int nchan)
   5343 {
   5344 	int params_size = WL_SCAN_PARAMS_FIXED_SIZE + WL_NUMCHANNELS * sizeof(uint16);
   5345 	int err = 0;
   5346 	char *p;
   5347 	int i;
   5348 	iscan_info_t *iscan = g_iscan;
   5349 
   5350 	WL_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, nchan));
   5351 
   5352 	if ((!dev) && (!g_iscan) && (!iscan->iscan_ex_params_p)) {
   5353 		WL_ERROR(("%s error exit\n", __FUNCTION__));
   5354 		err = -1;
   5355 		goto exit;
   5356 	}
   5357 
   5358 #ifdef PNO_SUPPORT
   5359 	if  (dhd_dev_get_pno_status(dev)) {
   5360 		WL_ERROR(("%s: Scan called when PNO is active\n", __FUNCTION__));
   5361 	}
   5362 #endif
   5363 
   5364 	params_size += WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
   5365 
   5366 	if (nssid > 0) {
   5367 		i = OFFSETOF(wl_scan_params_t, channel_list) + nchan * sizeof(uint16);
   5368 		i = ROUNDUP(i, sizeof(uint32));
   5369 		if (i + nssid * sizeof(wlc_ssid_t) > params_size) {
   5370 			printf("additional ssids exceed params_size\n");
   5371 			err = -1;
   5372 			goto exit;
   5373 		}
   5374 
   5375 		p = ((char*)&iscan->iscan_ex_params_p->params) + i;
   5376 		memcpy(p, ssids_local, nssid * sizeof(wlc_ssid_t));
   5377 		p += nssid * sizeof(wlc_ssid_t);
   5378 	} else {
   5379 		p = (char*)iscan->iscan_ex_params_p->params.channel_list + nchan * sizeof(uint16);
   5380 	}
   5381 
   5382 
   5383 	iscan->iscan_ex_params_p->params.channel_num = \
   5384 		htod32((nssid << WL_SCAN_PARAMS_NSSID_SHIFT) | \
   5385 					(nchan & WL_SCAN_PARAMS_COUNT_MASK));
   5386 
   5387 	nssid = \
   5388 	(uint)((iscan->iscan_ex_params_p->params.channel_num >> WL_SCAN_PARAMS_NSSID_SHIFT) & \
   5389 		               WL_SCAN_PARAMS_COUNT_MASK);
   5390 
   5391 
   5392 	params_size = (int) (p - (char*)iscan->iscan_ex_params_p + nssid * sizeof(wlc_ssid_t));
   5393 	iscan->iscan_ex_param_size = params_size;
   5394 
   5395 	iscan->list_cur = iscan->list_hdr;
   5396 	iscan->iscan_state = ISCAN_STATE_SCANING;
   5397 	wl_iw_set_event_mask(dev);
   5398 	mod_timer(&iscan->timer, jiffies + iscan->timer_ms*HZ/1000);
   5399 
   5400 	iscan->timer_on = 1;
   5401 
   5402 #ifdef SCAN_DUMP
   5403 	{
   5404 		int i;
   5405 		WL_SCAN(("\n### List of SSIDs to scan ###\n"));
   5406 		for (i = 0; i < nssid; i++) {
   5407 			if (!ssids_local[i].SSID_len)
   5408 				WL_SCAN(("%d: Broadcast scan\n", i));
   5409 			else
   5410 			WL_SCAN(("%d: scan  for  %s size =%d\n", i, \
   5411 				ssids_local[i].SSID, ssids_local[i].SSID_len));
   5412 		}
   5413 		WL_SCAN(("### List of channels to scan ###\n"));
   5414 		for (i = 0; i < nchan; i++)
   5415 		{
   5416 			WL_SCAN(("%d ", iscan->iscan_ex_params_p->params.channel_list[i]));
   5417 		}
   5418 		WL_SCAN(("\nnprobes=%d\n", iscan->iscan_ex_params_p->params.nprobes));
   5419 		WL_SCAN(("active_time=%d\n", iscan->iscan_ex_params_p->params.active_time));
   5420 		WL_SCAN(("passive_time=%d\n", iscan->iscan_ex_params_p->params.passive_time));
   5421 		WL_SCAN(("home_time=%d\n", iscan->iscan_ex_params_p->params.home_time));
   5422 		WL_SCAN(("scan_type=%d\n", iscan->iscan_ex_params_p->params.scan_type));
   5423 		WL_SCAN(("\n###################\n"));
   5424 	}
   5425 #endif
   5426 
   5427 	if (params_size > WLC_IOCTL_MEDLEN) {
   5428 			WL_ERROR(("Set ISCAN for %s due to params_size=%d  \n", \
   5429 				__FUNCTION__, params_size));
   5430 			err = -1;
   5431 	}
   5432 
   5433 	if ((err = dev_iw_iovar_setbuf(dev, "iscan", iscan->iscan_ex_params_p, \
   5434 			iscan->iscan_ex_param_size, \
   5435 			iscan->ioctlbuf, sizeof(iscan->ioctlbuf)))) {
   5436 			WL_ERROR(("Set ISCAN for %s failed with %d\n", __FUNCTION__, err));
   5437 			err = -1;
   5438 	}
   5439 
   5440 exit:
   5441 
   5442 	return err;
   5443 }
   5444 
   5445 
   5446 static int iwpriv_set_cscan(struct net_device *dev, struct iw_request_info *info, \
   5447 				union iwreq_data *wrqu, char *ext)
   5448 {
   5449 	int res = 0;
   5450 	char  *extra = NULL;
   5451 	iscan_info_t *iscan = g_iscan;
   5452 	wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
   5453 	int nssid = 0;
   5454 	int nchan = 0;
   5455 
   5456 	WL_TRACE(("\%s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
   5457 		__FUNCTION__, info->cmd, info->flags,
   5458 		wrqu->data.pointer, wrqu->data.length));
   5459 
   5460 	if (g_onoff == G_WLAN_SET_OFF) {
   5461 		WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
   5462 		return -1;
   5463 	}
   5464 
   5465 	if (wrqu->data.length != 0) {
   5466 
   5467 		char *str_ptr;
   5468 
   5469 		if (!iscan->iscan_ex_params_p) {
   5470 			return -EFAULT;
   5471 		}
   5472 
   5473 		if (!(extra = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
   5474 			return -ENOMEM;
   5475 
   5476 		if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
   5477 			kfree(extra);
   5478 			return -EFAULT;
   5479 		}
   5480 
   5481 		extra[wrqu->data.length] = 0;
   5482 		WL_ERROR(("Got str param in iw_point:\n %s\n", extra));
   5483 
   5484 		str_ptr = extra;
   5485 
   5486 		if (strncmp(str_ptr, GET_SSID, strlen(GET_SSID))) {
   5487 			WL_ERROR(("%s Error: extracting SSID='' string\n", __FUNCTION__));
   5488 			goto exit_proc;
   5489 		}
   5490 		str_ptr += strlen(GET_SSID);
   5491 		nssid = wl_iw_parse_ssid_list(&str_ptr, ssids_local, nssid, \
   5492 						WL_SCAN_PARAMS_SSID_MAX);
   5493 		if (nssid == -1) {
   5494 			WL_ERROR(("%s wrong ssid list", __FUNCTION__));
   5495 			return -1;
   5496 		}
   5497 
   5498 		memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
   5499 		ASSERT(iscan->iscan_ex_param_size < WLC_IOCTL_MAXLEN);
   5500 
   5501 
   5502 		wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
   5503 		iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
   5504 		iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
   5505 		iscan->iscan_ex_params_p->scan_duration = htod16(0);
   5506 
   5507 
   5508 		if ((nchan = wl_iw_parse_channel_list(&str_ptr, \
   5509 					&iscan->iscan_ex_params_p->params.channel_list[0], \
   5510 					WL_NUMCHANNELS)) == -1) {
   5511 			WL_ERROR(("%s missing channel list\n", __FUNCTION__));
   5512 			return -1;
   5513 		}
   5514 
   5515 
   5516 		get_parmeter_from_string(&str_ptr, \
   5517 				GET_NPROBE, PTYPE_INTDEC, \
   5518 				&iscan->iscan_ex_params_p->params.nprobes, 2);
   5519 
   5520 		get_parmeter_from_string(&str_ptr, GET_ACTIVE_ASSOC_DWELL, PTYPE_INTDEC, \
   5521 						&iscan->iscan_ex_params_p->params.active_time, 4);
   5522 
   5523 		get_parmeter_from_string(&str_ptr, GET_PASSIVE_ASSOC_DWELL, PTYPE_INTDEC, \
   5524 						&iscan->iscan_ex_params_p->params.passive_time, 4);
   5525 
   5526 		get_parmeter_from_string(&str_ptr, GET_HOME_DWELL, PTYPE_INTDEC, \
   5527 					&iscan->iscan_ex_params_p->params.home_time, 4);
   5528 
   5529 		get_parmeter_from_string(&str_ptr, GET_SCAN_TYPE, PTYPE_INTDEC, \
   5530 					&iscan->iscan_ex_params_p->params.scan_type, 1);
   5531 
   5532 		res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
   5533 
   5534 	} else {
   5535 		  WL_ERROR(("IWPRIV argument len = 0 \n"));
   5536 		  return -1;
   5537 	}
   5538 
   5539 exit_proc:
   5540 
   5541 	kfree(extra);
   5542 
   5543 	return res;
   5544 }
   5545 
   5546 
   5547 static int
   5548 wl_iw_set_cscan(
   5549 	struct net_device *dev,
   5550 	struct iw_request_info *info,
   5551 	union iwreq_data *wrqu,
   5552 	char *extra
   5553 )
   5554 {
   5555 	int res = -1;
   5556 	iscan_info_t *iscan = g_iscan;
   5557 	wlc_ssid_t ssids_local[WL_SCAN_PARAMS_SSID_MAX];
   5558 	int nssid = 0;
   5559 	int nchan = 0;
   5560 	cscan_tlv_t *cscan_tlv_temp;
   5561 	char type;
   5562 	char *str_ptr;
   5563 	int tlv_size_left;
   5564 #ifdef TLV_DEBUG
   5565 	int i;
   5566 	char tlv_in_example[] = {			'C', 'S', 'C', 'A', 'N', ' ', \
   5567 							0x53, 0x01, 0x00, 0x00,
   5568 							'S',
   5569 							0x00,
   5570 							'S',
   5571 							0x04,
   5572 							'B', 'R', 'C', 'M',
   5573 							'C',
   5574 							0x06,
   5575 							'P',
   5576 							0x94,
   5577 							0x11,
   5578 							'T',
   5579 							0x01
   5580 							};
   5581 #endif
   5582 
   5583 	WL_TRACE(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n",
   5584 		__FUNCTION__, info->cmd, info->flags,
   5585 		wrqu->data.pointer, wrqu->data.length));
   5586 
   5587 	net_os_wake_lock(dev);
   5588 
   5589 	if (g_onoff == G_WLAN_SET_OFF) {
   5590 		WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__));
   5591 		goto exit_proc;
   5592 	}
   5593 
   5594 
   5595 	if (wrqu->data.length < (strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t))) {
   5596 		WL_ERROR(("%s aggument=%d  less %d\n", __FUNCTION__, \
   5597 			wrqu->data.length, strlen(CSCAN_COMMAND) + sizeof(cscan_tlv_t)));
   5598 		goto exit_proc;
   5599 	}
   5600 
   5601 #ifdef TLV_DEBUG
   5602 	memcpy(extra, tlv_in_example, sizeof(tlv_in_example));
   5603 	wrqu->data.length = sizeof(tlv_in_example);
   5604 	for (i = 0; i < wrqu->data.length; i++)
   5605 		printf("%02X ", extra[i]);
   5606 	printf("\n");
   5607 #endif
   5608 
   5609 	str_ptr = extra;
   5610 	str_ptr +=  strlen(CSCAN_COMMAND);
   5611 	tlv_size_left = wrqu->data.length - strlen(CSCAN_COMMAND);
   5612 
   5613 	cscan_tlv_temp = (cscan_tlv_t *)str_ptr;
   5614 	memset(ssids_local, 0, sizeof(ssids_local));
   5615 
   5616 	if ((cscan_tlv_temp->prefix == CSCAN_TLV_PREFIX) && \
   5617 		(cscan_tlv_temp->version == CSCAN_TLV_VERSION) && \
   5618 		(cscan_tlv_temp->subver == CSCAN_TLV_SUBVERSION))
   5619 	{
   5620 		str_ptr += sizeof(cscan_tlv_t);
   5621 		tlv_size_left  -= sizeof(cscan_tlv_t);
   5622 
   5623 
   5624 		if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local, \
   5625 				WL_SCAN_PARAMS_SSID_MAX, &tlv_size_left)) <= 0) {
   5626 			WL_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
   5627 			goto exit_proc;
   5628 		}
   5629 		else {
   5630 
   5631 			memset(iscan->iscan_ex_params_p, 0, iscan->iscan_ex_param_size);
   5632 
   5633 
   5634 			wl_iw_iscan_prep(&iscan->iscan_ex_params_p->params, NULL);
   5635 			iscan->iscan_ex_params_p->version = htod32(ISCAN_REQ_VERSION);
   5636 			iscan->iscan_ex_params_p->action = htod16(WL_SCAN_ACTION_START);
   5637 			iscan->iscan_ex_params_p->scan_duration = htod16(0);
   5638 
   5639 
   5640 			while (tlv_size_left > 0)
   5641 			{
   5642 			type = str_ptr[0];
   5643 			switch (type) {
   5644 				case CSCAN_TLV_TYPE_CHANNEL_IE:
   5645 
   5646 					if ((nchan = wl_iw_parse_channel_list_tlv(&str_ptr, \
   5647 					&iscan->iscan_ex_params_p->params.channel_list[0], \
   5648 					WL_NUMCHANNELS, &tlv_size_left)) == -1) {
   5649 					WL_ERROR(("%s missing channel list\n", \
   5650 						 __FUNCTION__));
   5651 						goto exit_proc;
   5652 					}
   5653 				break;
   5654 				case CSCAN_TLV_TYPE_NPROBE_IE:
   5655 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   5656 						&iscan->iscan_ex_params_p->params.nprobes, \
   5657 						sizeof(iscan->iscan_ex_params_p->params.nprobes), \
   5658 						type, sizeof(char), &tlv_size_left)) == -1) {
   5659 						WL_ERROR(("%s return %d\n", \
   5660 							__FUNCTION__, res));
   5661 							goto exit_proc;
   5662 					}
   5663 				break;
   5664 				case CSCAN_TLV_TYPE_ACTIVE_IE:
   5665 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   5666 					&iscan->iscan_ex_params_p->params.active_time, \
   5667 					sizeof(iscan->iscan_ex_params_p->params.active_time), \
   5668 					type, sizeof(short), &tlv_size_left)) == -1) {
   5669 						WL_ERROR(("%s return %d\n", \
   5670 						__FUNCTION__, res));
   5671 						goto exit_proc;
   5672 					}
   5673 				break;
   5674 				case CSCAN_TLV_TYPE_PASSIVE_IE:
   5675 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   5676 					&iscan->iscan_ex_params_p->params.passive_time, \
   5677 					sizeof(iscan->iscan_ex_params_p->params.passive_time), \
   5678 					type, sizeof(short), &tlv_size_left)) == -1) {
   5679 						WL_ERROR(("%s return %d\n", \
   5680 						__FUNCTION__, res));
   5681 						goto exit_proc;
   5682 					}
   5683 				break;
   5684 				case CSCAN_TLV_TYPE_HOME_IE:
   5685 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   5686 					&iscan->iscan_ex_params_p->params.home_time, \
   5687 					sizeof(iscan->iscan_ex_params_p->params.home_time), \
   5688 					type, sizeof(short), &tlv_size_left)) == -1) {
   5689 						WL_ERROR(("%s return %d\n", \
   5690 						__FUNCTION__, res));
   5691 						goto exit_proc;
   5692 					}
   5693 				break;
   5694 				case CSCAN_TLV_TYPE_STYPE_IE:
   5695 					if ((res = wl_iw_parse_data_tlv(&str_ptr, \
   5696 					&iscan->iscan_ex_params_p->params.scan_type, \
   5697 					sizeof(iscan->iscan_ex_params_p->params.scan_type), \
   5698 					type, sizeof(char), &tlv_size_left)) == -1) {
   5699 					WL_ERROR(("%s return %d\n", \
   5700 						__FUNCTION__, res));
   5701 						goto exit_proc;
   5702 					}
   5703 				break;
   5704 
   5705 				default :
   5706 					WL_ERROR(("%s get unkwown type %X\n", \
   5707 						__FUNCTION__, type));
   5708 					goto exit_proc;
   5709 				break;
   5710 				}
   5711 			}
   5712 			}
   5713 		}
   5714 		else {
   5715 			WL_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
   5716 			goto exit_proc;
   5717 		}
   5718 
   5719 		if (g_first_broadcast_scan < BROADCAST_SCAN_FIRST_RESULT_CONSUMED) {
   5720 			if (++g_first_counter_scans == MAX_ALLOWED_BLOCK_SCAN_FROM_FIRST_SCAN) {
   5721 
   5722 				WL_ERROR(("%s Clean up First scan flag which is %d\n", \
   5723 						 __FUNCTION__, g_first_broadcast_scan));
   5724 				g_first_broadcast_scan = BROADCAST_SCAN_FIRST_RESULT_CONSUMED;
   5725 			}
   5726 			else {
   5727 				WL_ERROR(("%s Ignoring CSCAN : First Scan is not done yet %d\n", \
   5728 						__FUNCTION__, g_first_counter_scans));
   5729 				res = -EBUSY;
   5730 				goto exit_proc;
   5731 			}
   5732 		}
   5733 
   5734 		res = wl_iw_combined_scan_set(dev, ssids_local, nssid, nchan);
   5735 
   5736 exit_proc:
   5737 	net_os_wake_unlock(dev);
   5738 	return res;
   5739 }
   5740 
   5741 #endif
   5742 
   5743 #ifdef SOFTAP
   5744 #ifndef AP_ONLY
   5745 
   5746 static int thr_wait_for_2nd_eth_dev(void *data)
   5747 {
   5748 	int ret = 0;
   5749 
   5750 	DAEMONIZE("wl0_eth_wthread");
   5751 
   5752 	WL_TRACE(("\n>%s threda started:, PID:%x\n", __FUNCTION__, current->pid));
   5753 
   5754 	if (down_timeout(&ap_eth_sema,  msecs_to_jiffies(5000)) != 0) {
   5755 		WL_ERROR(("\n%s: sap_eth_sema timeout \n", __FUNCTION__));
   5756 		ret = -1;
   5757 		goto fail;
   5758 	}
   5759 
   5760 	if (!ap_net_dev) {
   5761 		WL_ERROR((" ap_net_dev is null !!!"));
   5762 		ret = -1;
   5763 		goto fail;
   5764 	}
   5765 
   5766 	WL_TRACE(("\n>%s: Thread:'softap ethdev IF:%s is detected !!!'\n\n",
   5767 		__FUNCTION__, ap_net_dev->name));
   5768 
   5769 	ap_cfg_running = TRUE;
   5770 
   5771 	bcm_mdelay(500);
   5772 
   5773 	wl_iw_send_priv_event(priv_dev, "AP_SET_CFG_OK");
   5774 
   5775 fail:
   5776 	WL_TRACE(("\n>%s, thread completed\n", __FUNCTION__));
   5777 
   5778 	return ret;
   5779 }
   5780 #endif
   5781 #ifndef AP_ONLY
   5782 static int last_auto_channel = 6;
   5783 #endif
   5784 static int get_softap_auto_channel(struct net_device *dev, struct ap_profile *ap)
   5785 {
   5786 	int chosen = 0;
   5787 	wl_uint32_list_t request;
   5788 	int rescan = 0;
   5789 	int retry = 0;
   5790 	int updown = 0;
   5791 	int ret = 0;
   5792 	wlc_ssid_t null_ssid;
   5793 	int res = 0;
   5794 #ifndef AP_ONLY
   5795 	int iolen = 0;
   5796 	int mkvar_err = 0;
   5797 	int bsscfg_index = 1;
   5798 	char buf[WLC_IOCTL_SMLEN];
   5799 #endif
   5800 	WL_SOFTAP(("Enter %s\n", __FUNCTION__));
   5801 
   5802 #ifndef AP_ONLY
   5803 	if (ap_cfg_running) {
   5804 		ap->channel = last_auto_channel;
   5805 		return res;
   5806 	}
   5807 #endif
   5808 	memset(&null_ssid, 0, sizeof(wlc_ssid_t));
   5809 	res |= dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown));
   5810 #ifdef AP_ONLY
   5811 	res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &null_ssid, sizeof(null_ssid));
   5812 #else
   5813 	iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&null_ssid), \
   5814 		null_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
   5815 	ASSERT(iolen);
   5816 	res |= dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen);
   5817 #endif
   5818 	auto_channel_retry:
   5819 			request.count = htod32(0);
   5820 			ret = dev_wlc_ioctl(dev, WLC_START_CHANNEL_SEL, &request, sizeof(request));
   5821 			if (ret < 0) {
   5822 				WL_ERROR(("can't start auto channel scan\n"));
   5823 				goto fail;
   5824 			}
   5825 
   5826 	get_channel_retry:
   5827 			bcm_mdelay(500);
   5828 
   5829 			ret = dev_wlc_ioctl(dev, WLC_GET_CHANNEL_SEL, &chosen, sizeof(chosen));
   5830 			if (ret < 0 || dtoh32(chosen) == 0) {
   5831 				if (retry++ < 3)
   5832 					goto get_channel_retry;
   5833 				else {
   5834 					WL_ERROR(("can't get auto channel sel, err = %d, \
   5835 						chosen = %d\n", ret, chosen));
   5836 					goto fail;
   5837 				}
   5838 			}
   5839 			if ((chosen == 1) && (!rescan++))
   5840 				goto auto_channel_retry;
   5841 			WL_SOFTAP(("Set auto channel = %d\n", chosen));
   5842 			ap->channel = chosen;
   5843 			if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown))) < 0) {
   5844 				WL_ERROR(("%s fail to set up err =%d\n", __FUNCTION__, res));
   5845 				goto fail;
   5846 			}
   5847 #ifndef AP_ONLY
   5848 	if (!res)
   5849 		last_auto_channel = ap->channel;
   5850 #endif
   5851 
   5852 fail :
   5853 	return res;
   5854 }
   5855 
   5856 
   5857 static int set_ap_cfg(struct net_device *dev, struct ap_profile *ap)
   5858 {
   5859 	int updown = 0;
   5860 	int channel = 0;
   5861 
   5862 	wlc_ssid_t ap_ssid;
   5863 	int max_assoc = 8;
   5864 
   5865 	int res = 0;
   5866 	int apsta_var = 0;
   5867 #ifndef AP_ONLY
   5868 	int mpc = 0;
   5869 	int iolen = 0;
   5870 	int mkvar_err = 0;
   5871 	int bsscfg_index = 1;
   5872 	char buf[WLC_IOCTL_SMLEN];
   5873 #endif
   5874 
   5875 	if (!dev) {
   5876 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   5877 		return -1;
   5878 	}
   5879 
   5880 	net_os_wake_lock(dev);
   5881 
   5882 	WL_SOFTAP(("wl_iw: set ap profile:\n"));
   5883 	WL_SOFTAP(("	ssid = '%s'\n", ap->ssid));
   5884 	WL_SOFTAP(("	security = '%s'\n", ap->sec));
   5885 	if (ap->key[0] != '\0')
   5886 		WL_SOFTAP(("	key = '%s'\n", ap->key));
   5887 	WL_SOFTAP(("	channel = %d\n", ap->channel));
   5888 	WL_SOFTAP(("	max scb = %d\n", ap->max_scb));
   5889 
   5890 #ifdef AP_ONLY
   5891 	if (ap_cfg_running) {
   5892 		wl_iw_softap_deassoc_stations(dev);
   5893 		ap_cfg_running = FALSE;
   5894 	}
   5895 #endif
   5896 
   5897 	if (ap_cfg_running == FALSE) {
   5898 
   5899 #ifndef AP_ONLY
   5900 
   5901 		sema_init(&ap_eth_sema, 0);
   5902 
   5903 		mpc = 0;
   5904 		if ((res = dev_wlc_intvar_set(dev, "mpc", mpc))) {
   5905 			WL_ERROR(("%s fail to set mpc\n", __FUNCTION__));
   5906 			goto fail;
   5907 		}
   5908 #endif
   5909 
   5910 		updown = 0;
   5911 		if ((res = dev_wlc_ioctl(dev, WLC_DOWN, &updown, sizeof(updown)))) {
   5912 			WL_ERROR(("%s fail to set updown\n", __FUNCTION__));
   5913 			goto fail;
   5914 		}
   5915 
   5916 #ifdef AP_ONLY
   5917 		apsta_var = 0;
   5918 		if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
   5919 			WL_ERROR(("%s fail to set apsta_var 0\n", __FUNCTION__));
   5920 			goto fail;
   5921 		}
   5922 		apsta_var = 1;
   5923 		if ((res = dev_wlc_ioctl(dev, WLC_SET_AP, &apsta_var, sizeof(apsta_var)))) {
   5924 			WL_ERROR(("%s fail to set apsta_var 1\n", __FUNCTION__));
   5925 			goto fail;
   5926 		}
   5927 		res = dev_wlc_ioctl(dev, WLC_GET_AP, &apsta_var, sizeof(apsta_var));
   5928 #else
   5929 		apsta_var = 1;
   5930 		iolen = wl_bssiovar_mkbuf("apsta",
   5931 			bsscfg_index,  &apsta_var, sizeof(apsta_var)+4,
   5932 			buf, sizeof(buf), &mkvar_err);
   5933 		ASSERT(iolen);
   5934 		if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) < 0) {
   5935 			WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
   5936 			goto fail;
   5937 		}
   5938 		WL_TRACE(("\n>in %s: apsta set result: %d \n", __FUNCTION__, res));
   5939 #endif
   5940 
   5941 		updown = 1;
   5942 		if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown))) < 0) {
   5943 			WL_ERROR(("%s fail to set apsta \n", __FUNCTION__));
   5944 			goto fail;
   5945 		}
   5946 
   5947 	} else {
   5948 
   5949 		if (!ap_net_dev) {
   5950 			WL_ERROR(("%s: ap_net_dev is null\n", __FUNCTION__));
   5951 			goto fail;
   5952 		}
   5953 
   5954 		res = wl_iw_softap_deassoc_stations(ap_net_dev);
   5955 
   5956 
   5957 		if ((res = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
   5958 			WL_ERROR(("%s fail to set bss down\n", __FUNCTION__));
   5959 			goto fail;
   5960 		}
   5961 	}
   5962 
   5963 
   5964 	if ((ap->channel == 0) && (get_softap_auto_channel(dev, ap) < 0)) {
   5965 		ap->channel = 1;
   5966 		WL_ERROR(("%s auto channel failed, pick up channel=%d\n", \
   5967 			__FUNCTION__, ap->channel));
   5968 	}
   5969 
   5970 	channel = ap->channel;
   5971 	if ((res = dev_wlc_ioctl(dev, WLC_SET_CHANNEL, &channel, sizeof(channel)))) {
   5972 			WL_ERROR(("%s fail to set channel\n", __FUNCTION__));
   5973 			goto fail;
   5974 	}
   5975 
   5976 	if (ap_cfg_running == FALSE) {
   5977 		updown = 0;
   5978 		if ((res = dev_wlc_ioctl(dev, WLC_UP, &updown, sizeof(updown)))) {
   5979 			WL_ERROR(("%s fail to set up\n", __FUNCTION__));
   5980 			goto fail;
   5981 		}
   5982 	}
   5983 
   5984 	max_assoc = ap->max_scb;
   5985 	if ((res = dev_wlc_intvar_set(dev, "maxassoc", max_assoc))) {
   5986 			WL_ERROR(("%s fail to set maxassoc\n", __FUNCTION__));
   5987 			goto fail;
   5988 	}
   5989 
   5990 	ap_ssid.SSID_len = strlen(ap->ssid);
   5991 	strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
   5992 
   5993 #ifdef AP_ONLY
   5994 	if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
   5995 		WL_ERROR(("ERROR:%d in:%s, wl_iw_set_ap_security is skipped\n", \
   5996 		res, __FUNCTION__));
   5997 		goto fail;
   5998 	}
   5999 	wl_iw_send_priv_event(dev, "ASCII_CMD=AP_BSS_START");
   6000 	ap_cfg_running = TRUE;
   6001 #else
   6002 	iolen = wl_bssiovar_mkbuf("ssid", bsscfg_index, (char *)(&ap_ssid),
   6003 		ap_ssid.SSID_len+4, buf, sizeof(buf), &mkvar_err);
   6004 	ASSERT(iolen);
   6005 	if ((res = dev_wlc_ioctl(dev, WLC_SET_VAR, buf, iolen)) != 0) {
   6006 		WL_ERROR(("ERROR:%d in:%s, Security & BSS reconfiguration is skipped\n", \
   6007 		res, __FUNCTION__));
   6008 		goto fail;
   6009 	}
   6010 	if (ap_cfg_running == FALSE) {
   6011 		kernel_thread(thr_wait_for_2nd_eth_dev, 0, 0);
   6012 	} else {
   6013 		if (ap_net_dev == NULL) {
   6014 			WL_ERROR(("%s ERROR: ap_net_dev is NULL !!!\n", __FUNCTION__));
   6015 			goto fail;
   6016 		}
   6017 
   6018 		WL_ERROR(("%s: %s Configure security & restart AP bss \n", \
   6019 			 __FUNCTION__, ap_net_dev->name));
   6020 
   6021 		if ((res = wl_iw_set_ap_security(ap_net_dev, &my_ap)) < 0) {
   6022 			WL_ERROR(("%s fail to set security : %d\n", __FUNCTION__, res));
   6023 			goto fail;
   6024 		}
   6025 
   6026 		if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0) {
   6027 			WL_ERROR(("%s fail to set bss up\n", __FUNCTION__));
   6028 			goto fail;
   6029 		}
   6030 	}
   6031 #endif
   6032 fail:
   6033 	WL_SOFTAP(("%s exit with %d\n", __FUNCTION__, res));
   6034 
   6035 	net_os_wake_unlock(dev);
   6036 
   6037 	return res;
   6038 }
   6039 
   6040 
   6041 static int wl_iw_set_ap_security(struct net_device *dev, struct ap_profile *ap)
   6042 {
   6043 	int wsec = 0;
   6044 	int wpa_auth = 0;
   6045 	int res = 0;
   6046 	int i;
   6047 	char *ptr;
   6048 #ifdef AP_ONLY
   6049 	int mpc = 0;
   6050 	wlc_ssid_t ap_ssid;
   6051 #endif
   6052 	wl_wsec_key_t key;
   6053 
   6054 	WL_SOFTAP(("\nsetting SOFTAP security mode:\n"));
   6055 	WL_SOFTAP(("wl_iw: set ap profile:\n"));
   6056 	WL_SOFTAP(("	ssid = '%s'\n", ap->ssid));
   6057 	WL_SOFTAP(("	security = '%s'\n", ap->sec));
   6058 	if (ap->key[0] != '\0')
   6059 		WL_SOFTAP(("	key = '%s'\n", ap->key));
   6060 	WL_SOFTAP(("	channel = %d\n", ap->channel));
   6061 	WL_SOFTAP(("	max scb = %d\n", ap->max_scb));
   6062 
   6063 	if (strnicmp(ap->sec, "open", strlen("open")) == 0) {
   6064 		wsec = 0;
   6065 		res = dev_wlc_intvar_set(dev, "wsec", wsec);
   6066 		wpa_auth = WPA_AUTH_DISABLED;
   6067 		res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
   6068 
   6069 		WL_SOFTAP(("=====================\n"));
   6070 		WL_SOFTAP((" wsec & wpa_auth set 'OPEN', result:&d %d\n", res));
   6071 		WL_SOFTAP(("=====================\n"));
   6072 
   6073 	} else if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
   6074 
   6075 		memset(&key, 0, sizeof(key));
   6076 
   6077 		wsec = WEP_ENABLED;
   6078 		res = dev_wlc_intvar_set(dev, "wsec", wsec);
   6079 
   6080 		key.index = 0;
   6081 		if (wl_iw_parse_wep(ap->key, &key)) {
   6082 			WL_SOFTAP(("wep key parse err!\n"));
   6083 			return -1;
   6084 		}
   6085 
   6086 		key.index = htod32(key.index);
   6087 		key.len = htod32(key.len);
   6088 		key.algo = htod32(key.algo);
   6089 		key.flags = htod32(key.flags);
   6090 
   6091 		res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
   6092 
   6093 		wpa_auth = WPA_AUTH_DISABLED;
   6094 		res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
   6095 
   6096 		WL_SOFTAP(("=====================\n"));
   6097 		WL_SOFTAP((" wsec & auth set 'WEP', result:&d %d\n", res));
   6098 		WL_SOFTAP(("=====================\n"));
   6099 
   6100 	} else if (strnicmp(ap->sec, "wpa2-psk", strlen("wpa2-psk")) == 0) {
   6101 		wsec_pmk_t psk;
   6102 		size_t key_len;
   6103 
   6104 		wsec = AES_ENABLED;
   6105 		dev_wlc_intvar_set(dev, "wsec", wsec);
   6106 
   6107 		key_len = strlen(ap->key);
   6108 		if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
   6109 			WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
   6110 			WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
   6111 			return -1;
   6112 		}
   6113 
   6114 		if (key_len < WSEC_MAX_PSK_LEN) {
   6115 			unsigned char output[2*SHA1HashSize];
   6116 			char key_str_buf[WSEC_MAX_PSK_LEN+1];
   6117 
   6118 			memset(output, 0, sizeof(output));
   6119 			pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
   6120 
   6121 			ptr = key_str_buf;
   6122 			for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
   6123 				sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4], \
   6124 					 (uint)output[i*4+1], (uint)output[i*4+2], \
   6125 					 (uint)output[i*4+3]);
   6126 				ptr += 8;
   6127 			}
   6128 			WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
   6129 
   6130 			psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
   6131 			memcpy(psk.key, key_str_buf, psk.key_len);
   6132 		} else {
   6133 			psk.key_len = htod16((ushort) key_len);
   6134 			memcpy(psk.key, ap->key, key_len);
   6135 		}
   6136 		psk.flags = htod16(WSEC_PASSPHRASE);
   6137 		dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
   6138 
   6139 		wpa_auth = WPA2_AUTH_PSK;
   6140 		dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
   6141 
   6142 	} else if (strnicmp(ap->sec, "wpa-psk", strlen("wpa-psk")) == 0) {
   6143 
   6144 		wsec_pmk_t psk;
   6145 		size_t key_len;
   6146 
   6147 		wsec = TKIP_ENABLED;
   6148 		res = dev_wlc_intvar_set(dev, "wsec", wsec);
   6149 
   6150 		key_len = strlen(ap->key);
   6151 		if (key_len < WSEC_MIN_PSK_LEN || key_len > WSEC_MAX_PSK_LEN) {
   6152 			WL_SOFTAP(("passphrase must be between %d and %d characters long\n",
   6153 			WSEC_MIN_PSK_LEN, WSEC_MAX_PSK_LEN));
   6154 			return -1;
   6155 		}
   6156 
   6157 		if (key_len < WSEC_MAX_PSK_LEN) {
   6158 			unsigned char output[2*SHA1HashSize];
   6159 			char key_str_buf[WSEC_MAX_PSK_LEN+1];
   6160 
   6161 			WL_SOFTAP(("%s: do passhash...\n", __FUNCTION__));
   6162 
   6163 			pbkdf2_sha1(ap->key, ap->ssid, strlen(ap->ssid), 4096, output, 32);
   6164 
   6165 			ptr = key_str_buf;
   6166 			for (i = 0; i < (WSEC_MAX_PSK_LEN/8); i++) {
   6167 				WL_SOFTAP(("[%02d]: %08x\n", i, *((unsigned int *)&output[i*4])));
   6168 
   6169 				sprintf(ptr, "%02x%02x%02x%02x", (uint)output[i*4],
   6170 					(uint)output[i*4+1], (uint)output[i*4+2],
   6171 					(uint)output[i*4+3]);
   6172 				ptr += 8;
   6173 			}
   6174 			WL_SOFTAP(("%s: passphase = %s\n", __FUNCTION__, key_str_buf));
   6175 
   6176 			psk.key_len = htod16((ushort)WSEC_MAX_PSK_LEN);
   6177 			memcpy(psk.key, key_str_buf, psk.key_len);
   6178 		} else {
   6179 			psk.key_len = htod16((ushort) key_len);
   6180 			memcpy(psk.key, ap->key, key_len);
   6181 		}
   6182 
   6183 		psk.flags = htod16(WSEC_PASSPHRASE);
   6184 		res |= dev_wlc_ioctl(dev, WLC_SET_WSEC_PMK, &psk, sizeof(psk));
   6185 
   6186 		wpa_auth = WPA_AUTH_PSK;
   6187 		res |= dev_wlc_intvar_set(dev, "wpa_auth", wpa_auth);
   6188 
   6189 		WL_SOFTAP((" wsec & auth set 'wpa-psk' (TKIP), result:&d %d\n", res));
   6190 	}
   6191 
   6192 #ifdef AP_ONLY
   6193 		ap_ssid.SSID_len = strlen(ap->ssid);
   6194 		strncpy(ap_ssid.SSID, ap->ssid, ap_ssid.SSID_len);
   6195 		res |= dev_wlc_ioctl(dev, WLC_SET_SSID, &ap_ssid, sizeof(ap_ssid));
   6196 		mpc = 0;
   6197 		res |= dev_wlc_intvar_set(dev, "mpc", mpc);
   6198 		if (strnicmp(ap->sec, "wep", strlen("wep")) == 0) {
   6199 			res |= dev_wlc_ioctl(dev, WLC_SET_KEY, &key, sizeof(key));
   6200 		}
   6201 #endif
   6202 	return res;
   6203 }
   6204 
   6205 
   6206 
   6207 int get_parmeter_from_string(
   6208 			char **str_ptr, const char *token,
   6209 			int param_type, void  *dst, int param_max_len)
   6210 {
   6211 	char int_str[7] = "0";
   6212 	int parm_str_len;
   6213 	char  *param_str_begin;
   6214 	char  *param_str_end;
   6215 	char  *orig_str = *str_ptr;
   6216 
   6217 	if ((*str_ptr) && !strncmp(*str_ptr, token, strlen(token))) {
   6218 
   6219 		strsep(str_ptr, "=,");
   6220 		param_str_begin = *str_ptr;
   6221 		strsep(str_ptr, "=,");
   6222 
   6223 		if (*str_ptr == NULL) {
   6224 			parm_str_len = strlen(param_str_begin);
   6225 		} else {
   6226 			param_str_end = *str_ptr-1;
   6227 			parm_str_len = param_str_end - param_str_begin;
   6228 		}
   6229 
   6230 		WL_TRACE((" 'token:%s', len:%d, ", token, parm_str_len));
   6231 
   6232 		if (parm_str_len > param_max_len) {
   6233 			WL_TRACE((" WARNING: extracted param len:%d is > MAX:%d\n",
   6234 				parm_str_len, param_max_len));
   6235 
   6236 			parm_str_len = param_max_len;
   6237 		}
   6238 
   6239 		switch (param_type) {
   6240 
   6241 		case PTYPE_INTDEC: {
   6242 			int *pdst_int = dst;
   6243 			char *eptr;
   6244 
   6245 			if (parm_str_len > sizeof(int_str))
   6246 				 parm_str_len = sizeof(int_str);
   6247 
   6248 			memcpy(int_str, param_str_begin, parm_str_len);
   6249 
   6250 			*pdst_int = simple_strtoul(int_str, &eptr, 10);
   6251 
   6252 			WL_TRACE((" written as integer:%d\n",  *pdst_int));
   6253 			}
   6254 			break;
   6255 		case PTYPE_STR_HEX: {
   6256 			u8 *buf = dst;
   6257 
   6258 			param_max_len = param_max_len >> 1;
   6259 			hstr_2_buf(param_str_begin, buf, param_max_len);
   6260 			print_buf(buf, param_max_len, 0);
   6261 			}
   6262 			break;
   6263 		default:
   6264 			memcpy(dst, param_str_begin, parm_str_len);
   6265 			*((char *)dst + parm_str_len) = 0;
   6266 			WL_TRACE((" written as a string:%s\n", (char *)dst));
   6267 			break;
   6268 		}
   6269 
   6270 		return 0;
   6271 	} else {
   6272 		WL_ERROR(("\n %s: ERROR: can't find token:%s in str:%s \n",
   6273 			__FUNCTION__, token, orig_str));
   6274 
   6275 		return -1;
   6276 	}
   6277 }
   6278 
   6279 
   6280 static int wl_iw_softap_deassoc_stations(struct net_device *dev)
   6281 {
   6282 	int i;
   6283 	int res = 0;
   6284 	char mac_buf[128] = {0};
   6285 	struct maclist *assoc_maclist = (struct maclist *)mac_buf;
   6286 
   6287 	memset(assoc_maclist, 0, sizeof(mac_buf));
   6288 	assoc_maclist->count = 8;
   6289 
   6290 	res = dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 128);
   6291 	if (res != 0) {
   6292 		WL_SOFTAP((" Error:%d in :%s, Couldn't get ASSOC List\n", res, __FUNCTION__));
   6293 		return res;
   6294 	}
   6295 
   6296 	if (assoc_maclist->count) {
   6297 		for (i = 0; i < assoc_maclist->count; i++) {
   6298 			scb_val_t scbval;
   6299 
   6300 			scbval.val = htod32(1);
   6301 			bcopy(&assoc_maclist->ea[i], &scbval.ea, ETHER_ADDR_LEN);
   6302 
   6303 			WL_SOFTAP(("deauth STA:%d \n", i));
   6304 			res |= dev_wlc_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON,
   6305 					&scbval, sizeof(scb_val_t));
   6306 		}
   6307 	} else {
   6308 		WL_SOFTAP((" STA ASSOC list is empty\n"));
   6309 	}
   6310 
   6311 	if (res != 0)
   6312 		WL_SOFTAP((" Error:%d in :%s\n", res, __FUNCTION__));
   6313 	else if (assoc_maclist->count) {
   6314 
   6315 		bcm_mdelay(200);
   6316 	}
   6317 	return res;
   6318 }
   6319 
   6320 
   6321 static int iwpriv_softap_stop(struct net_device *dev,
   6322 	struct iw_request_info *info,
   6323 	union iwreq_data *wrqu,
   6324 	char *ext)
   6325 {
   6326 	int res = 0;
   6327 
   6328 	WL_SOFTAP(("got iwpriv AP_BSS_STOP\n"));
   6329 
   6330 	if ((!dev) && (!ap_net_dev)) {
   6331 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   6332 		return res;
   6333 	}
   6334 
   6335 	net_os_wake_lock(dev);
   6336 
   6337 	if ((ap_cfg_running == TRUE)) {
   6338 #ifdef AP_ONLY
   6339 		 wl_iw_softap_deassoc_stations(dev);
   6340 #else
   6341 		 wl_iw_softap_deassoc_stations(ap_net_dev);
   6342 
   6343 		if ((res = dev_iw_write_cfg1_bss_var(dev, 2)) < 0)
   6344 			WL_ERROR(("%s failed to del BSS err = %d", __FUNCTION__, res));
   6345 #endif
   6346 
   6347 		bcm_mdelay(100);
   6348 
   6349 		wrqu->data.length = 0;
   6350 		ap_cfg_running = FALSE;
   6351 	}
   6352 	else
   6353 		WL_ERROR(("%s: was called when SoftAP is OFF : move on\n", __FUNCTION__));
   6354 
   6355 	WL_SOFTAP(("%s Done with %d\n", __FUNCTION__, res));
   6356 
   6357 	net_os_wake_unlock(dev);
   6358 
   6359 	return res;
   6360 }
   6361 
   6362 
   6363 static int iwpriv_fw_reload(struct net_device *dev,
   6364 		struct iw_request_info *info,
   6365 		union iwreq_data *wrqu,
   6366 		char *ext)
   6367 {
   6368 	int ret = -1;
   6369 	char extra[256];
   6370 	char *fwstr = fw_path;
   6371 
   6372 	WL_SOFTAP(("current firmware_path[]=%s\n", fwstr));
   6373 
   6374 	WL_TRACE((">Got FW_RELOAD cmd:"
   6375 				"info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d, \
   6376 				fw_path:%p, len:%d \n",
   6377 				info->cmd, info->flags,
   6378 				wrqu->data.pointer, wrqu->data.length, fwstr, strlen(fwstr)));
   6379 
   6380 	if ((wrqu->data.length > 4) && (wrqu->data.length < sizeof(extra))) {
   6381 
   6382 		char *str_ptr;
   6383 
   6384 		if (copy_from_user(extra, wrqu->data.pointer, wrqu->data.length)) {
   6385 			ret = -EFAULT;
   6386 			goto exit_proc;
   6387 		}
   6388 
   6389 		extra[wrqu->data.length] = 8;
   6390 		str_ptr = extra;
   6391 
   6392 		if (get_parmeter_from_string(&str_ptr, "FW_PATH=", PTYPE_STRING, fwstr, 255) != 0) {
   6393 			WL_ERROR(("Error: extracting FW_PATH='' string\n"));
   6394 			goto exit_proc;
   6395 		}
   6396 
   6397 		if (strstr(fwstr, "apsta") != NULL) {
   6398 			WL_SOFTAP(("GOT APSTA FIRMWARE\n"));
   6399 			ap_fw_loaded = TRUE;
   6400 		} else {
   6401 			WL_SOFTAP(("GOT STA FIRMWARE\n"));
   6402 			ap_fw_loaded = FALSE;
   6403 		}
   6404 
   6405 		WL_SOFTAP(("SET firmware_path[]=%s , str_p:%p\n", fwstr, fwstr));
   6406 		ret = 0;
   6407 	} else {
   6408 		WL_ERROR(("Error: ivalid param len:%d\n", wrqu->data.length));
   6409 	}
   6410 
   6411 exit_proc:
   6412 	return ret;
   6413 }
   6414 #endif
   6415 
   6416 #ifdef SOFTAP
   6417 static int iwpriv_wpasupp_loop_tst(struct net_device *dev,
   6418 		struct iw_request_info *info,
   6419 		union iwreq_data *wrqu,
   6420 		char *ext)
   6421 {
   6422 	int res = 0;
   6423 	char  *params = NULL;
   6424 
   6425 	WL_TRACE((">Got IWPRIV  wp_supp loopback cmd test:"
   6426 				"info->cmd:%x, info->flags:%x, u.data:%p, u.len:%d\n",
   6427 				info->cmd, info->flags,
   6428 				wrqu->data.pointer, wrqu->data.length));
   6429 
   6430 	if (wrqu->data.length != 0) {
   6431 
   6432 		if (!(params = kmalloc(wrqu->data.length+1, GFP_KERNEL)))
   6433 			return -ENOMEM;
   6434 
   6435 		if (copy_from_user(params, wrqu->data.pointer, wrqu->data.length)) {
   6436 			kfree(params);
   6437 			return -EFAULT;
   6438 		}
   6439 
   6440 		params[wrqu->data.length] = 0;
   6441 		WL_SOFTAP(("\n>> copied from user:\n %s\n", params));
   6442 	} else {
   6443 		WL_ERROR(("ERROR param length is 0\n"));
   6444 		return -EFAULT;
   6445 	}
   6446 
   6447 	res = wl_iw_send_priv_event(dev, params);
   6448 	kfree(params);
   6449 
   6450 	return res;
   6451 }
   6452 #endif
   6453 
   6454 
   6455 static int
   6456 iwpriv_en_ap_bss(
   6457 		struct net_device *dev,
   6458 		struct iw_request_info *info,
   6459 		void *wrqu,
   6460 		char *extra)
   6461 {
   6462 	int res = 0;
   6463 
   6464 	if (!dev) {
   6465 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   6466 		return -1;
   6467 	}
   6468 
   6469 	net_os_wake_lock(dev);
   6470 
   6471 	WL_TRACE(("%s: rcvd IWPRIV IOCTL:  for dev:%s\n", __FUNCTION__, dev->name));
   6472 
   6473 #ifndef AP_ONLY
   6474 	if ((res = wl_iw_set_ap_security(dev, &my_ap)) != 0) {
   6475 		WL_ERROR((" %s ERROR setting SOFTAP security in :%d\n", __FUNCTION__, res));
   6476 	}
   6477 	else {
   6478 		if ((res = dev_iw_write_cfg1_bss_var(dev, 1)) < 0)
   6479 			WL_ERROR(("%s fail to set bss up err=%d\n", __FUNCTION__, res));
   6480 		else
   6481 			bcm_mdelay(100);
   6482 	}
   6483 
   6484 #endif
   6485 	WL_SOFTAP(("%s done with res %d \n", __FUNCTION__, res));
   6486 
   6487 	net_os_wake_unlock(dev);
   6488 
   6489 	return res;
   6490 }
   6491 
   6492 static int
   6493 get_assoc_sta_list(struct net_device *dev, char *buf, int len)
   6494 {
   6495 	WL_TRACE(("calling dev_wlc_ioctl(dev:%p, cmd:%d, buf:%p, len:%d)\n",
   6496 		dev, WLC_GET_ASSOCLIST, buf, len));
   6497 
   6498 	dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, buf, len);
   6499 
   6500 	return 0;
   6501 }
   6502 
   6503 
   6504 static int
   6505 set_ap_mac_list(struct net_device *dev, char *buf)
   6506 {
   6507 	struct mac_list_set *mac_list_set = (struct mac_list_set *)buf;
   6508 	struct maclist *white_maclist = (struct maclist *)&mac_list_set->white_list;
   6509 	struct maclist *black_maclist = (struct maclist *)&mac_list_set->black_list;
   6510 	int mac_mode = mac_list_set->mode;
   6511 	int length;
   6512 	int i;
   6513 
   6514 	ap_macmode = mac_mode;
   6515 	if (mac_mode == MACLIST_MODE_DISABLED) {
   6516 
   6517 		bzero(&ap_black_list, sizeof(struct mflist));
   6518 
   6519 		dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
   6520 	} else {
   6521 		scb_val_t scbval;
   6522 		char mac_buf[256] = {0};
   6523 		struct maclist *assoc_maclist = (struct maclist *) mac_buf;
   6524 
   6525 		mac_mode = MACLIST_MODE_ALLOW;
   6526 
   6527 		dev_wlc_ioctl(dev, WLC_SET_MACMODE, &mac_mode, sizeof(mac_mode));
   6528 
   6529 		length = sizeof(white_maclist->count)+white_maclist->count*ETHER_ADDR_LEN;
   6530 		dev_wlc_ioctl(dev, WLC_SET_MACLIST, white_maclist, length);
   6531 		WL_SOFTAP(("White List, length %d:\n", length));
   6532 		for (i = 0; i < white_maclist->count; i++)
   6533 			WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n",
   6534 				i, white_maclist->ea[i].octet[0], white_maclist->ea[i].octet[1],
   6535 				white_maclist->ea[i].octet[2],
   6536 				white_maclist->ea[i].octet[3], white_maclist->ea[i].octet[4],
   6537 				white_maclist->ea[i].octet[5]));
   6538 
   6539 		bcopy(black_maclist, &ap_black_list, sizeof(ap_black_list));
   6540 
   6541 		WL_SOFTAP(("Black List, size %d:\n", sizeof(ap_black_list)));
   6542 		for (i = 0; i < ap_black_list.count; i++)
   6543 			WL_SOFTAP(("mac %d: %02X:%02X:%02X:%02X:%02X:%02X\n",
   6544 				i, ap_black_list.ea[i].octet[0], ap_black_list.ea[i].octet[1],
   6545 				ap_black_list.ea[i].octet[2],
   6546 				ap_black_list.ea[i].octet[3],
   6547 				ap_black_list.ea[i].octet[4], ap_black_list.ea[i].octet[5]));
   6548 
   6549 		dev_wlc_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist, 256);
   6550 		if (assoc_maclist->count) {
   6551 			int j;
   6552 			for (i = 0; i < assoc_maclist->count; i++) {
   6553 				for (j = 0; j < white_maclist->count; j++) {
   6554 					if (!bcmp(&assoc_maclist->ea[i], &white_maclist->ea[j],
   6555 						ETHER_ADDR_LEN)) {
   6556 						WL_SOFTAP(("match allow, let it be\n"));
   6557 						break;
   6558 					}
   6559 				}
   6560 				if (j == white_maclist->count) {
   6561 						WL_SOFTAP(("match black, deauth it\n"));
   6562 						scbval.val = htod32(1);
   6563 						bcopy(&assoc_maclist->ea[i], &scbval.ea,
   6564 							ETHER_ADDR_LEN);
   6565 						dev_wlc_ioctl(dev,
   6566 							WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scbval,
   6567 							sizeof(scb_val_t));
   6568 				}
   6569 			}
   6570 		}
   6571 	}
   6572 	return 0;
   6573 }
   6574 #endif
   6575 
   6576 
   6577 #ifdef SOFTAP
   6578 int set_macfilt_from_string(struct mflist *pmflist, char **param_str)
   6579 {
   6580 	return 0;
   6581 }
   6582 #endif
   6583 
   6584 
   6585 #ifdef SOFTAP
   6586 #define PARAM_OFFSET PROFILE_OFFSET
   6587 
   6588 int wl_iw_process_private_ascii_cmd(
   6589 			struct net_device *dev,
   6590 			struct iw_request_info *info,
   6591 			union iwreq_data *dwrq,
   6592 			char *cmd_str)
   6593 {
   6594 	int ret = 0;
   6595 	char *sub_cmd = cmd_str + PROFILE_OFFSET + strlen("ASCII_CMD=");
   6596 
   6597 	WL_SOFTAP(("\n %s: ASCII_CMD: offs_0:%s, offset_32:\n'%s'\n",
   6598 		__FUNCTION__, cmd_str, cmd_str + PROFILE_OFFSET));
   6599 
   6600 	if (strnicmp(sub_cmd, "AP_CFG", strlen("AP_CFG")) == 0) {
   6601 
   6602 		WL_SOFTAP((" AP_CFG \n"));
   6603 
   6604 
   6605 		if (init_ap_profile_from_string(cmd_str+PROFILE_OFFSET, &my_ap) != 0) {
   6606 			WL_ERROR(("ERROR: SoftAP CFG prams !\n"));
   6607 			ret = -1;
   6608 		} else {
   6609 			ret = set_ap_cfg(dev, &my_ap);
   6610 		}
   6611 
   6612 	} else if (strnicmp(sub_cmd, "AP_BSS_START", strlen("AP_BSS_START")) == 0) {
   6613 
   6614 		WL_SOFTAP(("\n SOFTAP - ENABLE BSS \n"));
   6615 
   6616 		WL_SOFTAP(("\n!!! got 'WL_AP_EN_BSS' from WPA supplicant, dev:%s\n", dev->name));
   6617 
   6618 #ifndef AP_ONLY
   6619 		if (ap_net_dev == NULL) {
   6620 			printf("\n ERROR: SOFTAP net_dev* is NULL !!!\n");
   6621 		} else {
   6622 			if ((ret = iwpriv_en_ap_bss(ap_net_dev, info, dwrq, cmd_str)) < 0)
   6623 				WL_ERROR(("%s line %d fail to set bss up\n", \
   6624 					__FUNCTION__, __LINE__));
   6625 		}
   6626 #else
   6627 		if ((ret = iwpriv_en_ap_bss(dev, info, dwrq, cmd_str)) < 0)
   6628 				WL_ERROR(("%s line %d fail to set bss up\n", \
   6629 					__FUNCTION__, __LINE__));
   6630 #endif
   6631 	} else if (strnicmp(sub_cmd, "ASSOC_LST", strlen("ASSOC_LST")) == 0) {
   6632 		/* no code yet */
   6633 	} else if (strnicmp(sub_cmd, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) {
   6634 		WL_SOFTAP((" \n temp DOWN SOFTAP\n"));
   6635 #ifndef AP_ONLY
   6636 		if ((ret = dev_iw_write_cfg1_bss_var(dev, 0)) < 0) {
   6637 				WL_ERROR(("%s line %d fail to set bss down\n", \
   6638 					__FUNCTION__, __LINE__));
   6639 		}
   6640 #endif
   6641 	}
   6642 
   6643 	return ret;
   6644 }
   6645 #endif
   6646 
   6647 static int wl_iw_set_priv(
   6648 	struct net_device *dev,
   6649 	struct iw_request_info *info,
   6650 	struct iw_point *dwrq,
   6651 	char *ext
   6652 )
   6653 {
   6654 	int ret = 0;
   6655 	char * extra;
   6656 
   6657 	if (!(extra = kmalloc(dwrq->length, GFP_KERNEL)))
   6658 	    return -ENOMEM;
   6659 
   6660 	if (copy_from_user(extra, dwrq->pointer, dwrq->length)) {
   6661 	    kfree(extra);
   6662 	    return -EFAULT;
   6663 	}
   6664 
   6665 	WL_TRACE(("%s: SIOCSIWPRIV request %s, info->cmd:%x, info->flags:%d\n dwrq->length:%d",
   6666 		dev->name, extra, info->cmd, info->flags, dwrq->length));
   6667 
   6668 	net_os_wake_lock(dev);
   6669 
   6670 	if (dwrq->length && extra) {
   6671 		if (strnicmp(extra, "START", strlen("START")) == 0) {
   6672 			wl_iw_control_wl_on(dev, info);
   6673 			WL_TRACE(("%s, Received regular START command\n", __FUNCTION__));
   6674 		}
   6675 
   6676 		if (g_onoff == G_WLAN_SET_OFF) {
   6677 			WL_TRACE(("%s, missing START, Fail\n", __FUNCTION__));
   6678 			kfree(extra);
   6679 			net_os_wake_unlock(dev);
   6680 			return -EFAULT;
   6681 		}
   6682 
   6683 		if (strnicmp(extra, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) {
   6684 #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
   6685 			WL_TRACE(("%s: active scan setting suppressed\n", dev->name));
   6686 #else
   6687 			ret = wl_iw_set_active_scan(dev, info, (union iwreq_data *)dwrq, extra);
   6688 #endif
   6689 		} else if (strnicmp(extra, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0)
   6690 #ifdef ENABLE_ACTIVE_PASSIVE_SCAN_SUPPRESS
   6691 			WL_TRACE(("%s: passive scan setting suppressed\n", dev->name));
   6692 #else
   6693 			ret = wl_iw_set_passive_scan(dev, info, (union iwreq_data *)dwrq, extra);
   6694 #endif
   6695 		else if (strnicmp(extra, "RSSI", strlen("RSSI")) == 0)
   6696 			ret = wl_iw_get_rssi(dev, info, (union iwreq_data *)dwrq, extra);
   6697 		else if (strnicmp(extra, "LINKSPEED", strlen("LINKSPEED")) == 0)
   6698 			ret = wl_iw_get_link_speed(dev, info, (union iwreq_data *)dwrq, extra);
   6699 		else if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0)
   6700 			ret = wl_iw_get_macaddr(dev, info, (union iwreq_data *)dwrq, extra);
   6701 		else if (strnicmp(extra, "COUNTRY", strlen("COUNTRY")) == 0)
   6702 			ret = wl_iw_set_country(dev, info, (union iwreq_data *)dwrq, extra);
   6703 		else if (strnicmp(extra, "STOP", strlen("STOP")) == 0)
   6704 			ret = wl_iw_control_wl_off(dev, info);
   6705 	    else if (strnicmp(extra, BAND_GET_CMD, strlen(BAND_GET_CMD)) == 0)
   6706 			ret = wl_iw_get_band(dev, info, (union iwreq_data *)dwrq, extra);
   6707 	    else if (strnicmp(extra, BAND_SET_CMD, strlen(BAND_SET_CMD)) == 0)
   6708 			ret = wl_iw_set_band(dev, info, (union iwreq_data *)dwrq, extra);
   6709 	    else if (strnicmp(extra, DTIM_SKIP_GET_CMD, strlen(DTIM_SKIP_GET_CMD)) == 0)
   6710 			ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
   6711 	    else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0)
   6712 			ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra);
   6713 	    else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0)
   6714 			ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra);
   6715 #if defined(PNO_SUPPORT)
   6716 	    else if (strnicmp(extra, PNOSSIDCLR_SET_CMD, strlen(PNOSSIDCLR_SET_CMD)) == 0)
   6717 			ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra);
   6718 	    else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0)
   6719 			ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra);
   6720 	    else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0)
   6721 			ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra);
   6722 #endif
   6723 #if defined(CSCAN)
   6724 	    else if (strnicmp(extra, CSCAN_COMMAND, strlen(CSCAN_COMMAND)) == 0)
   6725 			ret = wl_iw_set_cscan(dev, info, (union iwreq_data *)dwrq, extra);
   6726 #endif
   6727 #ifdef CUSTOMER_HW2
   6728 		else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
   6729 			ret = wl_iw_set_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
   6730 		else if (strnicmp(extra, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0)
   6731 			ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
   6732 #else
   6733 		else if (strnicmp(extra, "POWERMODE", strlen("POWERMODE")) == 0)
   6734 			ret = wl_iw_set_btcoex_dhcp(dev, info, (union iwreq_data *)dwrq, extra);
   6735 #endif
   6736 		else if (strnicmp(extra, "GETPOWER", strlen("GETPOWER")) == 0)
   6737 			ret = wl_iw_get_power_mode(dev, info, (union iwreq_data *)dwrq, extra);
   6738 #ifdef SOFTAP
   6739 		else if (strnicmp(extra, "ASCII_CMD", strlen("ASCII_CMD")) == 0) {
   6740 			wl_iw_process_private_ascii_cmd(dev, info, (union iwreq_data *)dwrq, extra);
   6741 		} else if (strnicmp(extra, "AP_MAC_LIST_SET", strlen("AP_MAC_LIST_SET")) == 0) {
   6742 			WL_SOFTAP(("penguin, set AP_MAC_LIST_SET\n"));
   6743 			set_ap_mac_list(dev, (extra + PROFILE_OFFSET));
   6744 		}
   6745 #endif
   6746 		else {
   6747 			WL_TRACE(("Unknown PRIVATE command: %s: ignored\n", extra));
   6748 			snprintf(extra, MAX_WX_STRING, "OK");
   6749 			dwrq->length = strlen("OK") + 1;
   6750 		}
   6751 	}
   6752 
   6753 	net_os_wake_unlock(dev);
   6754 
   6755 	if (extra) {
   6756 		if (copy_to_user(dwrq->pointer, extra, dwrq->length)) {
   6757 			kfree(extra);
   6758 			return -EFAULT;
   6759 		}
   6760 
   6761 		kfree(extra);
   6762 	}
   6763 
   6764 	return ret;
   6765 }
   6766 
   6767 static const iw_handler wl_iw_handler[] =
   6768 {
   6769 	(iw_handler) wl_iw_config_commit,
   6770 	(iw_handler) wl_iw_get_name,
   6771 	(iw_handler) NULL,
   6772 	(iw_handler) NULL,
   6773 	(iw_handler) wl_iw_set_freq,
   6774 	(iw_handler) wl_iw_get_freq,
   6775 	(iw_handler) wl_iw_set_mode,
   6776 	(iw_handler) wl_iw_get_mode,
   6777 	(iw_handler) NULL,
   6778 	(iw_handler) NULL,
   6779 	(iw_handler) NULL,
   6780 	(iw_handler) wl_iw_get_range,
   6781 	(iw_handler) wl_iw_set_priv,
   6782 	(iw_handler) NULL,
   6783 	(iw_handler) NULL,
   6784 	(iw_handler) NULL,
   6785 	(iw_handler) wl_iw_set_spy,
   6786 	(iw_handler) wl_iw_get_spy,
   6787 	(iw_handler) NULL,
   6788 	(iw_handler) NULL,
   6789 	(iw_handler) wl_iw_set_wap,
   6790 	(iw_handler) wl_iw_get_wap,
   6791 #if WIRELESS_EXT > 17
   6792 	(iw_handler) wl_iw_mlme,
   6793 #else
   6794 	(iw_handler) NULL,
   6795 #endif
   6796 #if defined(WL_IW_USE_ISCAN)
   6797 	(iw_handler) wl_iw_iscan_get_aplist,
   6798 #else
   6799 	(iw_handler) wl_iw_get_aplist,
   6800 #endif
   6801 #if WIRELESS_EXT > 13
   6802 #if defined(WL_IW_USE_ISCAN)
   6803 	(iw_handler) wl_iw_iscan_set_scan,
   6804 	(iw_handler) wl_iw_iscan_get_scan,
   6805 #else
   6806 	(iw_handler) wl_iw_set_scan,
   6807 	(iw_handler) wl_iw_get_scan,
   6808 #endif
   6809 #else
   6810 	(iw_handler) NULL,
   6811 	(iw_handler) NULL,
   6812 #endif
   6813 	(iw_handler) wl_iw_set_essid,
   6814 	(iw_handler) wl_iw_get_essid,
   6815 	(iw_handler) wl_iw_set_nick,
   6816 	(iw_handler) wl_iw_get_nick,
   6817 	(iw_handler) NULL,
   6818 	(iw_handler) NULL,
   6819 	(iw_handler) wl_iw_set_rate,
   6820 	(iw_handler) wl_iw_get_rate,
   6821 	(iw_handler) wl_iw_set_rts,
   6822 	(iw_handler) wl_iw_get_rts,
   6823 	(iw_handler) wl_iw_set_frag,
   6824 	(iw_handler) wl_iw_get_frag,
   6825 	(iw_handler) wl_iw_set_txpow,
   6826 	(iw_handler) wl_iw_get_txpow,
   6827 #if WIRELESS_EXT > 10
   6828 	(iw_handler) wl_iw_set_retry,
   6829 	(iw_handler) wl_iw_get_retry,
   6830 #endif
   6831 	(iw_handler) wl_iw_set_encode,
   6832 	(iw_handler) wl_iw_get_encode,
   6833 	(iw_handler) wl_iw_set_power,
   6834 	(iw_handler) wl_iw_get_power,
   6835 #if WIRELESS_EXT > 17
   6836 	(iw_handler) NULL,
   6837 	(iw_handler) NULL,
   6838 	(iw_handler) wl_iw_set_wpaie,
   6839 	(iw_handler) wl_iw_get_wpaie,
   6840 	(iw_handler) wl_iw_set_wpaauth,
   6841 	(iw_handler) wl_iw_get_wpaauth,
   6842 	(iw_handler) wl_iw_set_encodeext,
   6843 	(iw_handler) wl_iw_get_encodeext,
   6844 #ifdef BCMWPA2
   6845 	(iw_handler) wl_iw_set_pmksa,
   6846 #endif
   6847 #endif
   6848 };
   6849 
   6850 #if WIRELESS_EXT > 12
   6851 static const iw_handler wl_iw_priv_handler[] = {
   6852 	NULL,
   6853 	(iw_handler)wl_iw_set_active_scan,
   6854 	NULL,
   6855 	(iw_handler)wl_iw_get_rssi,
   6856 	NULL,
   6857 	(iw_handler)wl_iw_set_passive_scan,
   6858 	NULL,
   6859 	(iw_handler)wl_iw_get_link_speed,
   6860 	NULL,
   6861 	(iw_handler)wl_iw_get_macaddr,
   6862 	NULL,
   6863 	(iw_handler)wl_iw_control_wl_off,
   6864 	NULL,
   6865 	(iw_handler)wl_iw_control_wl_on,
   6866 #ifdef SOFTAP
   6867 	NULL,
   6868 	(iw_handler)iwpriv_set_ap_config,
   6869 
   6870 	NULL,
   6871 	(iw_handler)iwpriv_get_assoc_list,
   6872 
   6873 	NULL,
   6874 	(iw_handler)iwpriv_set_mac_filters,
   6875 
   6876 	NULL,
   6877 	(iw_handler)iwpriv_en_ap_bss,
   6878 
   6879 	NULL,
   6880 	(iw_handler)iwpriv_wpasupp_loop_tst,
   6881 
   6882 	NULL,
   6883 	(iw_handler)iwpriv_softap_stop,
   6884 
   6885 	NULL,
   6886 	(iw_handler)iwpriv_fw_reload,
   6887 #endif
   6888 #if defined(CSCAN)
   6889 
   6890 	NULL,
   6891 	(iw_handler)iwpriv_set_cscan
   6892 #endif
   6893 };
   6894 
   6895 static const struct iw_priv_args wl_iw_priv_args[] = {
   6896 	{
   6897 		WL_IW_SET_ACTIVE_SCAN,
   6898 		0,
   6899 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6900 		"SCAN-ACTIVE"
   6901 	},
   6902 	{
   6903 		WL_IW_GET_RSSI,
   6904 		0,
   6905 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6906 		"RSSI"
   6907 	},
   6908 	{
   6909 		WL_IW_SET_PASSIVE_SCAN,
   6910 		0,
   6911 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6912 		"SCAN-PASSIVE"
   6913 	},
   6914 	{
   6915 		WL_IW_GET_LINK_SPEED,
   6916 		0,
   6917 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6918 		"LINKSPEED"
   6919 	},
   6920 	{
   6921 		WL_IW_GET_CURR_MACADDR,
   6922 		0,
   6923 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6924 		"Macaddr"
   6925 	},
   6926 	{
   6927 		WL_IW_SET_STOP,
   6928 		0,
   6929 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6930 		"STOP"
   6931 	},
   6932 	{
   6933 		WL_IW_SET_START,
   6934 		0,
   6935 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6936 		"START"
   6937 	},
   6938 
   6939 #ifdef SOFTAP
   6940 	{
   6941 		WL_SET_AP_CFG,
   6942 		IW_PRIV_TYPE_CHAR |  256,
   6943 		0,
   6944 		"AP_SET_CFG"
   6945 	},
   6946 
   6947 	{
   6948 		WL_AP_STA_LIST,
   6949 		0,
   6950 		IW_PRIV_TYPE_CHAR | 0,
   6951 		"AP_GET_STA_LIST"
   6952 	},
   6953 
   6954 	{
   6955 		WL_AP_MAC_FLTR,
   6956 		IW_PRIV_TYPE_CHAR | 256,
   6957 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
   6958 		"AP_SET_MAC_FLTR"
   6959 	},
   6960 
   6961 	{
   6962 		WL_AP_BSS_START,
   6963 		0,
   6964 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING,
   6965 		"AP_BSS_START"
   6966 	},
   6967 
   6968 	{
   6969 		AP_LPB_CMD,
   6970 		IW_PRIV_TYPE_CHAR | 256,
   6971 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
   6972 		"AP_LPB_CMD"
   6973 	},
   6974 
   6975 	{
   6976 		WL_AP_STOP,
   6977 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
   6978 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
   6979 		"AP_BSS_STOP"
   6980 	},
   6981 
   6982 	{
   6983 		WL_FW_RELOAD,
   6984 		IW_PRIV_TYPE_CHAR | 256,
   6985 		IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 0,
   6986 		"WL_FW_RELOAD"
   6987 	},
   6988 #endif
   6989 #if defined(CSCAN)
   6990 	{
   6991 		WL_COMBO_SCAN,
   6992 		IW_PRIV_TYPE_CHAR | 1024,
   6993 		0,
   6994 		"CSCAN"
   6995 	},
   6996 #endif
   6997 };
   6998 
   6999 const struct iw_handler_def wl_iw_handler_def =
   7000 {
   7001 	.num_standard = ARRAYSIZE(wl_iw_handler),
   7002 	.standard = (iw_handler *) wl_iw_handler,
   7003 	.num_private = ARRAYSIZE(wl_iw_priv_handler),
   7004 	.num_private_args = ARRAY_SIZE(wl_iw_priv_args),
   7005 	.private = (iw_handler *)wl_iw_priv_handler,
   7006 	.private_args = (void *) wl_iw_priv_args,
   7007 
   7008 #if WIRELESS_EXT >= 19
   7009 	get_wireless_stats: dhd_get_wireless_stats,
   7010 #endif
   7011 };
   7012 #endif
   7013 
   7014 
   7015 int wl_iw_ioctl(
   7016 	struct net_device *dev,
   7017 	struct ifreq *rq,
   7018 	int cmd
   7019 )
   7020 {
   7021 	struct iwreq *wrq = (struct iwreq *) rq;
   7022 	struct iw_request_info info;
   7023 	iw_handler handler;
   7024 	char *extra = NULL;
   7025 	int token_size = 1, max_tokens = 0, ret = 0;
   7026 
   7027 	net_os_wake_lock(dev);
   7028 
   7029 	WL_TRACE(("%s: cmd:%x alled via dhd->do_ioctl()entry point\n", __FUNCTION__, cmd));
   7030 	if (cmd < SIOCIWFIRST ||
   7031 		IW_IOCTL_IDX(cmd) >= ARRAYSIZE(wl_iw_handler) ||
   7032 		!(handler = wl_iw_handler[IW_IOCTL_IDX(cmd)])) {
   7033 			WL_ERROR(("%s: error in cmd=%x : not supported\n", __FUNCTION__, cmd));
   7034 			net_os_wake_unlock(dev);
   7035 			return -EOPNOTSUPP;
   7036 	}
   7037 
   7038 	switch (cmd) {
   7039 
   7040 	case SIOCSIWESSID:
   7041 	case SIOCGIWESSID:
   7042 	case SIOCSIWNICKN:
   7043 	case SIOCGIWNICKN:
   7044 		max_tokens = IW_ESSID_MAX_SIZE + 1;
   7045 		break;
   7046 
   7047 	case SIOCSIWENCODE:
   7048 	case SIOCGIWENCODE:
   7049 #if WIRELESS_EXT > 17
   7050 	case SIOCSIWENCODEEXT:
   7051 	case SIOCGIWENCODEEXT:
   7052 #endif
   7053 		max_tokens = wrq->u.data.length;
   7054 		break;
   7055 
   7056 	case SIOCGIWRANGE:
   7057 		max_tokens = sizeof(struct iw_range) + 500;
   7058 		break;
   7059 
   7060 	case SIOCGIWAPLIST:
   7061 		token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
   7062 		max_tokens = IW_MAX_AP;
   7063 		break;
   7064 
   7065 #if WIRELESS_EXT > 13
   7066 	case SIOCGIWSCAN:
   7067 #if defined(WL_IW_USE_ISCAN)
   7068 	if (g_iscan)
   7069 		max_tokens = wrq->u.data.length;
   7070 	else
   7071 #endif
   7072 		max_tokens = IW_SCAN_MAX_DATA;
   7073 		break;
   7074 #endif
   7075 
   7076 	case SIOCSIWSPY:
   7077 		token_size = sizeof(struct sockaddr);
   7078 		max_tokens = IW_MAX_SPY;
   7079 		break;
   7080 
   7081 	case SIOCGIWSPY:
   7082 		token_size = sizeof(struct sockaddr) + sizeof(struct iw_quality);
   7083 		max_tokens = IW_MAX_SPY;
   7084 		break;
   7085 
   7086 #if WIRELESS_EXT > 17
   7087 	case SIOCSIWPMKSA:
   7088 	case SIOCSIWGENIE:
   7089 #endif
   7090 	case SIOCSIWPRIV:
   7091 		max_tokens = wrq->u.data.length;
   7092 		break;
   7093 	}
   7094 
   7095 	if (max_tokens && wrq->u.data.pointer) {
   7096 		if (wrq->u.data.length > max_tokens) {
   7097 			WL_ERROR(("%s: error in cmd=%x wrq->u.data.length=%d  > max_tokens=%d\n", \
   7098 				__FUNCTION__, cmd, wrq->u.data.length, max_tokens));
   7099 			ret = -E2BIG;
   7100 			goto wl_iw_ioctl_done;
   7101 		}
   7102 		if (!(extra = kmalloc(max_tokens * token_size, GFP_KERNEL))) {
   7103 			ret = -ENOMEM;
   7104 			goto wl_iw_ioctl_done;
   7105 		}
   7106 
   7107 		if (copy_from_user(extra, wrq->u.data.pointer, wrq->u.data.length * token_size)) {
   7108 			kfree(extra);
   7109 			ret = -EFAULT;
   7110 			goto wl_iw_ioctl_done;
   7111 		}
   7112 	}
   7113 
   7114 	info.cmd = cmd;
   7115 	info.flags = 0;
   7116 
   7117 	ret = handler(dev, &info, &wrq->u, extra);
   7118 
   7119 	if (extra) {
   7120 		if (copy_to_user(wrq->u.data.pointer, extra, wrq->u.data.length * token_size)) {
   7121 			kfree(extra);
   7122 			ret = -EFAULT;
   7123 			goto wl_iw_ioctl_done;
   7124 		}
   7125 
   7126 		kfree(extra);
   7127 	}
   7128 
   7129 wl_iw_ioctl_done:
   7130 
   7131 	net_os_wake_unlock(dev);
   7132 
   7133 	return ret;
   7134 }
   7135 
   7136 
   7137 bool
   7138 wl_iw_conn_status_str(uint32 event_type, uint32 status, uint32 reason,
   7139 	char* stringBuf, uint buflen)
   7140 {
   7141 	typedef struct conn_fail_event_map_t {
   7142 		uint32 inEvent;
   7143 		uint32 inStatus;
   7144 		uint32 inReason;
   7145 		const char* outName;
   7146 		const char* outCause;
   7147 	} conn_fail_event_map_t;
   7148 
   7149 
   7150 #	define WL_IW_DONT_CARE	9999
   7151 	const conn_fail_event_map_t event_map [] = {
   7152 
   7153 
   7154 		{WLC_E_SET_SSID,     WLC_E_STATUS_SUCCESS,   WL_IW_DONT_CARE,
   7155 		"Conn", "Success"},
   7156 		{WLC_E_SET_SSID,     WLC_E_STATUS_NO_NETWORKS, WL_IW_DONT_CARE,
   7157 		"Conn", "NoNetworks"},
   7158 		{WLC_E_SET_SSID,     WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
   7159 		"Conn", "ConfigMismatch"},
   7160 		{WLC_E_PRUNE,        WL_IW_DONT_CARE,        WLC_E_PRUNE_ENCR_MISMATCH,
   7161 		"Conn", "EncrypMismatch"},
   7162 		{WLC_E_PRUNE,        WL_IW_DONT_CARE,        WLC_E_RSN_MISMATCH,
   7163 		"Conn", "RsnMismatch"},
   7164 		{WLC_E_AUTH,         WLC_E_STATUS_TIMEOUT,   WL_IW_DONT_CARE,
   7165 		"Conn", "AuthTimeout"},
   7166 		{WLC_E_AUTH,         WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
   7167 		"Conn", "AuthFail"},
   7168 		{WLC_E_AUTH,         WLC_E_STATUS_NO_ACK,    WL_IW_DONT_CARE,
   7169 		"Conn", "AuthNoAck"},
   7170 		{WLC_E_REASSOC,      WLC_E_STATUS_FAIL,      WL_IW_DONT_CARE,
   7171 		"Conn", "ReassocFail"},
   7172 		{WLC_E_REASSOC,      WLC_E_STATUS_TIMEOUT,   WL_IW_DONT_CARE,
   7173 		"Conn", "ReassocTimeout"},
   7174 		{WLC_E_REASSOC,      WLC_E_STATUS_ABORT,     WL_IW_DONT_CARE,
   7175 		"Conn", "ReassocAbort"},
   7176 		{WLC_E_PSK_SUP,      WLC_SUP_KEYED,          WL_IW_DONT_CARE,
   7177 		"Sup", "ConnSuccess"},
   7178 		{WLC_E_PSK_SUP,      WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
   7179 		"Sup", "WpaHandshakeFail"},
   7180 		{WLC_E_DEAUTH_IND,   WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
   7181 		"Conn", "Deauth"},
   7182 		{WLC_E_DISASSOC_IND, WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
   7183 		"Conn", "DisassocInd"},
   7184 		{WLC_E_DISASSOC,     WL_IW_DONT_CARE,        WL_IW_DONT_CARE,
   7185 		"Conn", "Disassoc"}
   7186 	};
   7187 
   7188 	const char* name = "";
   7189 	const char* cause = NULL;
   7190 	int i;
   7191 
   7192 
   7193 	for (i = 0;  i < sizeof(event_map)/sizeof(event_map[0]);  i++) {
   7194 		const conn_fail_event_map_t* row = &event_map[i];
   7195 		if (row->inEvent == event_type &&
   7196 		    (row->inStatus == status || row->inStatus == WL_IW_DONT_CARE) &&
   7197 		    (row->inReason == reason || row->inReason == WL_IW_DONT_CARE)) {
   7198 			name = row->outName;
   7199 			cause = row->outCause;
   7200 			break;
   7201 		}
   7202 	}
   7203 
   7204 
   7205 	if (cause) {
   7206 		memset(stringBuf, 0, buflen);
   7207 		snprintf(stringBuf, buflen, "%s %s %02d %02d",
   7208 			name, cause, status, reason);
   7209 		WL_INFORM(("Connection status: %s\n", stringBuf));
   7210 		return TRUE;
   7211 	} else {
   7212 		return FALSE;
   7213 	}
   7214 }
   7215 
   7216 #if WIRELESS_EXT > 14
   7217 
   7218 static bool
   7219 wl_iw_check_conn_fail(wl_event_msg_t *e, char* stringBuf, uint buflen)
   7220 {
   7221 	uint32 event = ntoh32(e->event_type);
   7222 	uint32 status =  ntoh32(e->status);
   7223 	uint32 reason =  ntoh32(e->reason);
   7224 
   7225 	if (wl_iw_conn_status_str(event, status, reason, stringBuf, buflen)) {
   7226 		return TRUE;
   7227 	}
   7228 	else
   7229 		return FALSE;
   7230 }
   7231 #endif
   7232 
   7233 #ifndef IW_CUSTOM_MAX
   7234 #define IW_CUSTOM_MAX 256
   7235 #endif
   7236 
   7237 void
   7238 wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data)
   7239 {
   7240 #if WIRELESS_EXT > 13
   7241 	union iwreq_data wrqu;
   7242 	char extra[IW_CUSTOM_MAX + 1];
   7243 	int cmd = 0;
   7244 	uint32 event_type = ntoh32(e->event_type);
   7245 	uint16 flags =  ntoh16(e->flags);
   7246 	uint32 datalen = ntoh32(e->datalen);
   7247 	uint32 status =  ntoh32(e->status);
   7248 	uint32 toto;
   7249 	static uint32 roam_no_success = 0;
   7250 	static bool roam_no_success_send = FALSE;
   7251 
   7252 	memset(&wrqu, 0, sizeof(wrqu));
   7253 	memset(extra, 0, sizeof(extra));
   7254 
   7255 	if (!dev) {
   7256 		WL_ERROR(("%s: dev is null\n", __FUNCTION__));
   7257 		return;
   7258 	}
   7259 
   7260 	net_os_wake_lock(dev);
   7261 
   7262 	WL_TRACE(("%s: dev=%s event=%d \n", __FUNCTION__, dev->name, event_type));
   7263 
   7264 	switch (event_type) {
   7265 #if defined(SOFTAP)
   7266 	case WLC_E_PRUNE:
   7267 		if (ap_cfg_running) {
   7268 			char *macaddr = (char *)&e->addr;
   7269 			WL_SOFTAP(("PRUNE received, %02X:%02X:%02X:%02X:%02X:%02X!\n",
   7270 				macaddr[0], macaddr[1], macaddr[2], macaddr[3], \
   7271 				macaddr[4], macaddr[5]));
   7272 
   7273 			if (ap_macmode) {
   7274 				int i;
   7275 				for (i = 0; i < ap_black_list.count; i++) {
   7276 					if (!bcmp(macaddr, &ap_black_list.ea[i], \
   7277 						sizeof(struct ether_addr))) {
   7278 						WL_SOFTAP(("mac in black list, ignore it\n"));
   7279 						break;
   7280 					}
   7281 				}
   7282 
   7283 				if (i == ap_black_list.count) {
   7284 					char mac_buf[32] = {0};
   7285 					sprintf(mac_buf, "STA_BLOCK %02X:%02X:%02X:%02X:%02X:%02X",
   7286 						macaddr[0], macaddr[1], macaddr[2],
   7287 						macaddr[3], macaddr[4], macaddr[5]);
   7288 					wl_iw_send_priv_event(priv_dev, mac_buf);
   7289 				}
   7290 			}
   7291 		}
   7292 		break;
   7293 #endif
   7294 	case WLC_E_TXFAIL:
   7295 		cmd = IWEVTXDROP;
   7296 		memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
   7297 		wrqu.addr.sa_family = ARPHRD_ETHER;
   7298 		break;
   7299 #if WIRELESS_EXT > 14
   7300 	case WLC_E_JOIN:
   7301 	case WLC_E_ASSOC_IND:
   7302 	case WLC_E_REASSOC_IND:
   7303 #if defined(SOFTAP)
   7304 		WL_SOFTAP(("STA connect received %d\n", event_type));
   7305 		if (ap_cfg_running) {
   7306 			wl_iw_send_priv_event(priv_dev, "STA_JOIN");
   7307 			goto wl_iw_event_end;
   7308 		}
   7309 #endif
   7310 		memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
   7311 		wrqu.addr.sa_family = ARPHRD_ETHER;
   7312 		cmd = IWEVREGISTERED;
   7313 		break;
   7314 	case WLC_E_ROAM:
   7315 		if (status != WLC_E_STATUS_SUCCESS) {
   7316 			roam_no_success++;
   7317 			if ((roam_no_success == 3) && (roam_no_success_send == FALSE)) {
   7318 
   7319 				roam_no_success_send = TRUE;
   7320 				bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
   7321 				bzero(&extra, ETHER_ADDR_LEN);
   7322 				cmd = SIOCGIWAP;
   7323 				WL_ERROR(("%s  ROAMING did not succeeded , send Link Down\n", \
   7324 					__FUNCTION__));
   7325 			} else {
   7326 				WL_TRACE(("##### ROAMING did not succeeded %d\n", roam_no_success));
   7327 				goto wl_iw_event_end;
   7328 			}
   7329 		} else {
   7330 			memcpy(wrqu.addr.sa_data, &e->addr.octet, ETHER_ADDR_LEN);
   7331 			wrqu.addr.sa_family = ARPHRD_ETHER;
   7332 			cmd = SIOCGIWAP;
   7333 		}
   7334 		break;
   7335 	case WLC_E_DEAUTH_IND:
   7336 	case WLC_E_DISASSOC_IND:
   7337 #if defined(SOFTAP)
   7338 		WL_SOFTAP(("STA disconnect received %d\n", event_type));
   7339 		if (ap_cfg_running) {
   7340 			wl_iw_send_priv_event(priv_dev, "STA_LEAVE");
   7341 			goto wl_iw_event_end;
   7342 		}
   7343 #endif
   7344 		cmd = SIOCGIWAP;
   7345 		bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
   7346 		wrqu.addr.sa_family = ARPHRD_ETHER;
   7347 		bzero(&extra, ETHER_ADDR_LEN);
   7348 		break;
   7349 	case WLC_E_LINK:
   7350 	case WLC_E_NDIS_LINK:
   7351 		cmd = SIOCGIWAP;
   7352 		if (!(flags & WLC_EVENT_MSG_LINK)) {
   7353 #ifdef SOFTAP
   7354 #ifdef AP_ONLY
   7355 		if (ap_cfg_running) {
   7356 #else
   7357 		if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
   7358 #endif
   7359 				WL_SOFTAP(("AP DOWN %d\n", event_type));
   7360 				wl_iw_send_priv_event(priv_dev, "AP_DOWN");
   7361 			} else {
   7362 				WL_TRACE(("STA_Link Down\n"));
   7363 				g_ss_cache_ctrl.m_link_down = 1;
   7364 			}
   7365 #else
   7366 			g_ss_cache_ctrl.m_link_down = 1;
   7367 #endif
   7368 			WL_TRACE(("Link Down\n"));
   7369 
   7370 			bzero(wrqu.addr.sa_data, ETHER_ADDR_LEN);
   7371 			bzero(&extra, ETHER_ADDR_LEN);
   7372 		}
   7373 		else {
   7374 			memcpy(wrqu.addr.sa_data, &e->addr, ETHER_ADDR_LEN);
   7375 			g_ss_cache_ctrl.m_link_down = 0;
   7376 
   7377 			memcpy(g_ss_cache_ctrl.m_active_bssid, &e->addr, ETHER_ADDR_LEN);
   7378 
   7379 #ifdef SOFTAP
   7380 #ifdef AP_ONLY
   7381 			if (ap_cfg_running) {
   7382 #else
   7383 			if (ap_cfg_running && !strncmp(dev->name, "wl0.1", 5)) {
   7384 #endif
   7385 				WL_SOFTAP(("AP UP %d\n", event_type));
   7386 				wl_iw_send_priv_event(priv_dev, "AP_UP");
   7387 			} else {
   7388 				WL_TRACE(("STA_LINK_UP\n"));
   7389 				roam_no_success_send = FALSE;
   7390 				roam_no_success = 0;
   7391 			}
   7392 #endif
   7393 			WL_TRACE(("Link UP\n"));
   7394 
   7395 		}
   7396 		net_os_wake_lock_timeout_enable(dev);
   7397 		wrqu.addr.sa_family = ARPHRD_ETHER;
   7398 		break;
   7399 	case WLC_E_ACTION_FRAME:
   7400 		cmd = IWEVCUSTOM;
   7401 		if (datalen + 1 <= sizeof(extra)) {
   7402 			wrqu.data.length = datalen + 1;
   7403 			extra[0] = WLC_E_ACTION_FRAME;
   7404 			memcpy(&extra[1], data, datalen);
   7405 			WL_TRACE(("WLC_E_ACTION_FRAME len %d \n", wrqu.data.length));
   7406 		}
   7407 		break;
   7408 
   7409 	case WLC_E_ACTION_FRAME_COMPLETE:
   7410 		cmd = IWEVCUSTOM;
   7411 		memcpy(&toto, data, 4);
   7412 		if (sizeof(status) + 1 <= sizeof(extra)) {
   7413 			wrqu.data.length = sizeof(status) + 1;
   7414 			extra[0] = WLC_E_ACTION_FRAME_COMPLETE;
   7415 			memcpy(&extra[1], &status, sizeof(status));
   7416 			printf("wl_iw_event status %d PacketId %d \n", status, toto);
   7417 			printf("WLC_E_ACTION_FRAME_COMPLETE len %d \n", wrqu.data.length);
   7418 		}
   7419 		break;
   7420 #endif
   7421 #if WIRELESS_EXT > 17
   7422 	case WLC_E_MIC_ERROR: {
   7423 		struct	iw_michaelmicfailure  *micerrevt = (struct  iw_michaelmicfailure  *)&extra;
   7424 		cmd = IWEVMICHAELMICFAILURE;
   7425 		wrqu.data.length = sizeof(struct iw_michaelmicfailure);
   7426 		if (flags & WLC_EVENT_MSG_GROUP)
   7427 			micerrevt->flags |= IW_MICFAILURE_GROUP;
   7428 		else
   7429 			micerrevt->flags |= IW_MICFAILURE_PAIRWISE;
   7430 		memcpy(micerrevt->src_addr.sa_data, &e->addr, ETHER_ADDR_LEN);
   7431 		micerrevt->src_addr.sa_family = ARPHRD_ETHER;
   7432 
   7433 		break;
   7434 	}
   7435 #ifdef BCMWPA2
   7436 	case WLC_E_PMKID_CACHE: {
   7437 		if (data)
   7438 		{
   7439 			struct iw_pmkid_cand *iwpmkidcand = (struct iw_pmkid_cand *)&extra;
   7440 			pmkid_cand_list_t *pmkcandlist;
   7441 			pmkid_cand_t	*pmkidcand;
   7442 			int count;
   7443 
   7444 			cmd = IWEVPMKIDCAND;
   7445 			pmkcandlist = data;
   7446 			count = ntoh32_ua((uint8 *)&pmkcandlist->npmkid_cand);
   7447 			ASSERT(count >= 0);
   7448 			wrqu.data.length = sizeof(struct iw_pmkid_cand);
   7449 			pmkidcand = pmkcandlist->pmkid_cand;
   7450 			while (count) {
   7451 				bzero(iwpmkidcand, sizeof(struct iw_pmkid_cand));
   7452 				if (pmkidcand->preauth)
   7453 					iwpmkidcand->flags |= IW_PMKID_CAND_PREAUTH;
   7454 				bcopy(&pmkidcand->BSSID, &iwpmkidcand->bssid.sa_data,
   7455 					ETHER_ADDR_LEN);
   7456 #ifndef SANDGATE2G
   7457 				wireless_send_event(dev, cmd, &wrqu, extra);
   7458 #endif
   7459 				pmkidcand++;
   7460 				count--;
   7461 			}
   7462 		}
   7463 		goto wl_iw_event_end;
   7464 	}
   7465 #endif
   7466 #endif
   7467 
   7468 	case WLC_E_SCAN_COMPLETE:
   7469 #if defined(WL_IW_USE_ISCAN)
   7470 		if ((g_iscan) && (g_iscan->sysioc_pid >= 0) &&
   7471 			(g_iscan->iscan_state != ISCAN_STATE_IDLE))
   7472 		{
   7473 			up(&g_iscan->sysioc_sem);
   7474 		} else {
   7475 			cmd = SIOCGIWSCAN;
   7476 			wrqu.data.length = strlen(extra);
   7477 			WL_TRACE(("Event WLC_E_SCAN_COMPLETE from specific scan %d\n", \
   7478 				g_iscan->iscan_state));
   7479 		}
   7480 #else
   7481 		cmd = SIOCGIWSCAN;
   7482 		wrqu.data.length = strlen(extra);
   7483 		WL_TRACE(("Event WLC_E_SCAN_COMPLETE\n"));
   7484 #endif
   7485 		break;
   7486 
   7487 	case WLC_E_PFN_NET_FOUND:
   7488 	{
   7489 		wlc_ssid_t	* ssid;
   7490 		ssid = (wlc_ssid_t *)data;
   7491 		WL_TRACE(("%s Event WLC_E_PFN_NET_FOUND, send %s up : find %s len=%d\n", \
   7492 			__FUNCTION__, PNO_EVENT_UP, ssid->SSID, ssid->SSID_len));
   7493 		net_os_wake_lock_timeout_enable(dev);
   7494 		cmd = IWEVCUSTOM;
   7495 		memset(&wrqu, 0, sizeof(wrqu));
   7496 		strcpy(extra, PNO_EVENT_UP);
   7497 		wrqu.data.length = strlen(extra);
   7498 	}
   7499 	break;
   7500 
   7501 	default:
   7502 
   7503 		WL_TRACE(("Unknown Event %d: ignoring\n", event_type));
   7504 		break;
   7505 	}
   7506 #ifndef SANDGATE2G
   7507 	if (cmd) {
   7508 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31))
   7509 		if (cmd == SIOCGIWSCAN)
   7510 			wireless_send_event(dev, cmd, &wrqu, NULL);
   7511 		else
   7512 #endif
   7513 		wireless_send_event(dev, cmd, &wrqu, extra);
   7514 	}
   7515 #endif
   7516 
   7517 #if WIRELESS_EXT > 14
   7518 
   7519 	memset(extra, 0, sizeof(extra));
   7520 	if (wl_iw_check_conn_fail(e, extra, sizeof(extra))) {
   7521 		cmd = IWEVCUSTOM;
   7522 		wrqu.data.length = strlen(extra);
   7523 #ifndef SANDGATE2G
   7524 		wireless_send_event(dev, cmd, &wrqu, extra);
   7525 #endif
   7526 	}
   7527 #endif
   7528 wl_iw_event_end:
   7529 	net_os_wake_unlock(dev);
   7530 #endif
   7531 }
   7532 
   7533 int wl_iw_get_wireless_stats(struct net_device *dev, struct iw_statistics *wstats)
   7534 {
   7535 	int res = 0;
   7536 	wl_cnt_t cnt;
   7537 	int phy_noise;
   7538 	int rssi;
   7539 	scb_val_t scb_val;
   7540 
   7541 	phy_noise = 0;
   7542 	if ((res = dev_wlc_ioctl(dev, WLC_GET_PHY_NOISE, &phy_noise, sizeof(phy_noise))))
   7543 		goto done;
   7544 
   7545 	phy_noise = dtoh32(phy_noise);
   7546 	WL_TRACE(("wl_iw_get_wireless_stats phy noise=%d\n", phy_noise));
   7547 
   7548 	bzero(&scb_val, sizeof(scb_val_t));
   7549 	if ((res = dev_wlc_ioctl(dev, WLC_GET_RSSI, &scb_val, sizeof(scb_val_t))))
   7550 		goto done;
   7551 
   7552 	rssi = dtoh32(scb_val.val);
   7553 	WL_TRACE(("wl_iw_get_wireless_stats rssi=%d\n", rssi));
   7554 	if (rssi <= WL_IW_RSSI_NO_SIGNAL)
   7555 		wstats->qual.qual = 0;
   7556 	else if (rssi <= WL_IW_RSSI_VERY_LOW)
   7557 		wstats->qual.qual = 1;
   7558 	else if (rssi <= WL_IW_RSSI_LOW)
   7559 		wstats->qual.qual = 2;
   7560 	else if (rssi <= WL_IW_RSSI_GOOD)
   7561 		wstats->qual.qual = 3;
   7562 	else if (rssi <= WL_IW_RSSI_VERY_GOOD)
   7563 		wstats->qual.qual = 4;
   7564 	else
   7565 		wstats->qual.qual = 5;
   7566 
   7567 
   7568 	wstats->qual.level = 0x100 + rssi;
   7569 	wstats->qual.noise = 0x100 + phy_noise;
   7570 #if WIRELESS_EXT > 18
   7571 	wstats->qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM);
   7572 #else
   7573 	wstats->qual.updated |= 7;
   7574 #endif
   7575 
   7576 #if WIRELESS_EXT > 11
   7577 	WL_TRACE(("wl_iw_get_wireless_stats counters=%d\n", (int)sizeof(wl_cnt_t)));
   7578 
   7579 	memset(&cnt, 0, sizeof(wl_cnt_t));
   7580 	res = dev_wlc_bufvar_get(dev, "counters", (char *)&cnt, sizeof(wl_cnt_t));
   7581 	if (res)
   7582 	{
   7583 		WL_ERROR(("wl_iw_get_wireless_stats counters failed error=%d\n", res));
   7584 		goto done;
   7585 	}
   7586 
   7587 	cnt.version = dtoh16(cnt.version);
   7588 	if (cnt.version != WL_CNT_T_VERSION) {
   7589 		WL_TRACE(("\tIncorrect version of counters struct: expected %d; got %d\n",
   7590 			WL_CNT_T_VERSION, cnt.version));
   7591 		goto done;
   7592 	}
   7593 
   7594 	wstats->discard.nwid = 0;
   7595 	wstats->discard.code = dtoh32(cnt.rxundec);
   7596 	wstats->discard.fragment = dtoh32(cnt.rxfragerr);
   7597 	wstats->discard.retries = dtoh32(cnt.txfail);
   7598 	wstats->discard.misc = dtoh32(cnt.rxrunt) + dtoh32(cnt.rxgiant);
   7599 	wstats->miss.beacon = 0;
   7600 
   7601 	WL_TRACE(("wl_iw_get_wireless_stats counters txframe=%d txbyte=%d\n",
   7602 		dtoh32(cnt.txframe), dtoh32(cnt.txbyte)));
   7603 	WL_TRACE(("wl_iw_get_wireless_stats counters rxfrmtoolong=%d\n", dtoh32(cnt.rxfrmtoolong)));
   7604 	WL_TRACE(("wl_iw_get_wireless_stats counters rxbadplcp=%d\n", dtoh32(cnt.rxbadplcp)));
   7605 	WL_TRACE(("wl_iw_get_wireless_stats counters rxundec=%d\n", dtoh32(cnt.rxundec)));
   7606 	WL_TRACE(("wl_iw_get_wireless_stats counters rxfragerr=%d\n", dtoh32(cnt.rxfragerr)));
   7607 	WL_TRACE(("wl_iw_get_wireless_stats counters txfail=%d\n", dtoh32(cnt.txfail)));
   7608 	WL_TRACE(("wl_iw_get_wireless_stats counters rxrunt=%d\n", dtoh32(cnt.rxrunt)));
   7609 	WL_TRACE(("wl_iw_get_wireless_stats counters rxgiant=%d\n", dtoh32(cnt.rxgiant)));
   7610 
   7611 #endif
   7612 
   7613 done:
   7614 	return res;
   7615 }
   7616 static void
   7617 wl_iw_bt_flag_set(
   7618 	struct net_device *dev,
   7619 	bool set)
   7620 {
   7621 	char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 };
   7622 	char buf_flag7_default[8]   = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00};
   7623 
   7624 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   7625 	rtnl_lock();
   7626 #endif
   7627 
   7628 	if (set == TRUE) {
   7629 		dev_wlc_bufvar_set(dev, "btc_flags",
   7630 					(char *)&buf_flag7_dhcp_on[0], sizeof(buf_flag7_dhcp_on));
   7631 	}
   7632 	else  {
   7633 		dev_wlc_bufvar_set(dev, "btc_flags",
   7634 					(char *)&buf_flag7_default[0], sizeof(buf_flag7_default));
   7635 	}
   7636 
   7637 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
   7638 	rtnl_unlock();
   7639 #endif
   7640 }
   7641 
   7642 static void
   7643 wl_iw_bt_timerfunc(ulong data)
   7644 {
   7645 	bt_info_t  *bt_local = (bt_info_t *)data;
   7646 	bt_local->timer_on = 0;
   7647 	WL_TRACE(("%s\n", __FUNCTION__));
   7648 
   7649 	up(&bt_local->bt_sem);
   7650 }
   7651 
   7652 static int
   7653 _bt_dhcp_sysioc_thread(void *data)
   7654 {
   7655 	DAEMONIZE("dhcp_sysioc");
   7656 
   7657 	while (down_interruptible(&g_bt->bt_sem) == 0) {
   7658 
   7659 		net_os_wake_lock(g_bt->dev);
   7660 
   7661 		if (g_bt->timer_on) {
   7662 			g_bt->timer_on = 0;
   7663 			del_timer_sync(&g_bt->timer);
   7664 		}
   7665 
   7666 		switch (g_bt->bt_state) {
   7667 			case BT_DHCP_START:
   7668 				g_bt->bt_state = BT_DHCP_OPPORTUNITY_WINDOW;
   7669 				mod_timer(&g_bt->timer, jiffies + BT_DHCP_OPPORTUNITY_WINDOW_TIEM*HZ/1000);
   7670 				g_bt->timer_on = 1;
   7671 				break;
   7672 
   7673 			case BT_DHCP_OPPORTUNITY_WINDOW:
   7674 				WL_TRACE(("%s waiting for %d msec expired, force bt flag\n", \
   7675 						__FUNCTION__, BT_DHCP_OPPORTUNITY_WINDOW_TIEM));
   7676 				if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, TRUE);
   7677 				g_bt->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT;
   7678 				mod_timer(&g_bt->timer, jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000);
   7679 				g_bt->timer_on = 1;
   7680 				break;
   7681 
   7682 			case BT_DHCP_FLAG_FORCE_TIMEOUT:
   7683 				WL_TRACE(("%s waiting for %d msec expired remove bt flag\n", \
   7684 						__FUNCTION__, BT_DHCP_FLAG_FORCE_TIME));
   7685 
   7686 				if (g_bt->dev)  wl_iw_bt_flag_set(g_bt->dev, FALSE);
   7687 				g_bt->bt_state = BT_DHCP_IDLE;
   7688 				g_bt->timer_on = 0;
   7689 				break;
   7690 
   7691 			default:
   7692 				WL_ERROR(("%s error g_status=%d !!!\n", __FUNCTION__, \
   7693 				          g_bt->bt_state));
   7694 				if (g_bt->dev) wl_iw_bt_flag_set(g_bt->dev, FALSE);
   7695 				g_bt->bt_state = BT_DHCP_IDLE;
   7696 				g_bt->timer_on = 0;
   7697 				break;
   7698 		}
   7699 
   7700 		net_os_wake_unlock(g_bt->dev);
   7701 	}
   7702 
   7703 	if (g_bt->timer_on) {
   7704 		g_bt->timer_on = 0;
   7705 		del_timer_sync(&g_bt->timer);
   7706 	}
   7707 
   7708 	complete_and_exit(&g_bt->bt_exited, 0);
   7709 }
   7710 
   7711 static void
   7712 wl_iw_bt_release(void)
   7713 {
   7714 	bt_info_t *bt_local = g_bt;
   7715 
   7716 	if (!bt_local) {
   7717 		return;
   7718 	}
   7719 
   7720 	if (bt_local->bt_pid >= 0) {
   7721 		KILL_PROC(bt_local->bt_pid, SIGTERM);
   7722 		wait_for_completion(&bt_local->bt_exited);
   7723 	}
   7724 	kfree(bt_local);
   7725 	g_bt = NULL;
   7726 }
   7727 
   7728 static int
   7729 wl_iw_bt_init(struct net_device *dev)
   7730 {
   7731 	bt_info_t *bt_dhcp = NULL;
   7732 
   7733 	bt_dhcp = kmalloc(sizeof(bt_info_t), GFP_KERNEL);
   7734 	if (!bt_dhcp)
   7735 		return -ENOMEM;
   7736 
   7737 	memset(bt_dhcp, 0, sizeof(bt_info_t));
   7738 	bt_dhcp->bt_pid = -1;
   7739 	g_bt = bt_dhcp;
   7740 	bt_dhcp->dev = dev;
   7741 	bt_dhcp->bt_state = BT_DHCP_IDLE;
   7742 
   7743 
   7744 	bt_dhcp->timer_ms    = 10;
   7745 	init_timer(&bt_dhcp->timer);
   7746 	bt_dhcp->timer.data = (ulong)bt_dhcp;
   7747 	bt_dhcp->timer.function = wl_iw_bt_timerfunc;
   7748 
   7749 	sema_init(&bt_dhcp->bt_sem, 0);
   7750 	init_completion(&bt_dhcp->bt_exited);
   7751 	bt_dhcp->bt_pid = kernel_thread(_bt_dhcp_sysioc_thread, bt_dhcp, 0);
   7752 	if (bt_dhcp->bt_pid < 0) {
   7753 		WL_ERROR(("Failed in %s\n", __FUNCTION__));
   7754 		return -ENOMEM;
   7755 	}
   7756 
   7757 	return 0;
   7758 }
   7759 
   7760 int wl_iw_attach(struct net_device *dev, void * dhdp)
   7761 {
   7762 	int params_size;
   7763 	wl_iw_t *iw;
   7764 #if defined(WL_IW_USE_ISCAN)
   7765 	iscan_info_t *iscan = NULL;
   7766 #endif
   7767 
   7768 	mutex_init(&wl_cache_lock);
   7769 	mutex_init(&wl_start_lock);
   7770 
   7771 #if defined(WL_IW_USE_ISCAN)
   7772 	if (!dev)
   7773 		return 0;
   7774 
   7775 	memset(&g_wl_iw_params, 0, sizeof(wl_iw_extra_params_t));
   7776 
   7777 #ifdef CSCAN
   7778 	params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params)) +
   7779 	    (WL_NUMCHANNELS * sizeof(uint16)) + WL_SCAN_PARAMS_SSID_MAX * sizeof(wlc_ssid_t);
   7780 #else
   7781 	params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_iscan_params_t, params));
   7782 #endif
   7783 	iscan = kmalloc(sizeof(iscan_info_t), GFP_KERNEL);
   7784 	if (!iscan)
   7785 		return -ENOMEM;
   7786 	memset(iscan, 0, sizeof(iscan_info_t));
   7787 
   7788 	iscan->iscan_ex_params_p = (wl_iscan_params_t*)kmalloc(params_size, GFP_KERNEL);
   7789 	if (!iscan->iscan_ex_params_p)
   7790 		return -ENOMEM;
   7791 	iscan->iscan_ex_param_size = params_size;
   7792 	iscan->sysioc_pid = -1;
   7793 
   7794 	g_iscan = iscan;
   7795 	iscan->dev = dev;
   7796 	iscan->iscan_state = ISCAN_STATE_IDLE;
   7797 	g_first_broadcast_scan = BROADCAST_SCAN_FIRST_IDLE;
   7798 	g_first_counter_scans = 0;
   7799 	g_iscan->scan_flag = 0;
   7800 
   7801 	iscan->timer_ms    = 8000;
   7802 	init_timer(&iscan->timer);
   7803 	iscan->timer.data = (ulong)iscan;
   7804 	iscan->timer.function = wl_iw_timerfunc;
   7805 
   7806 	sema_init(&iscan->sysioc_sem, 0);
   7807 	init_completion(&iscan->sysioc_exited);
   7808 	iscan->sysioc_pid = kernel_thread(_iscan_sysioc_thread, iscan, 0);
   7809 	if (iscan->sysioc_pid < 0)
   7810 		return -ENOMEM;
   7811 #endif
   7812 
   7813 	iw = *(wl_iw_t **)netdev_priv(dev);
   7814 	iw->pub = (dhd_pub_t *)dhdp;
   7815 #ifdef SOFTAP
   7816 	priv_dev = dev;
   7817 #endif
   7818 	g_scan = NULL;
   7819 
   7820 	g_scan = (void *)kmalloc(G_SCAN_RESULTS, GFP_KERNEL);
   7821 	if (!g_scan)
   7822 		return -ENOMEM;
   7823 
   7824 	memset(g_scan, 0, G_SCAN_RESULTS);
   7825 	g_scan_specified_ssid = 0;
   7826 
   7827 #if !defined(CSCAN)
   7828 	wl_iw_init_ss_cache_ctrl();
   7829 #endif
   7830 
   7831 	wl_iw_bt_init(dev);
   7832 
   7833 	return 0;
   7834 }
   7835 
   7836 void wl_iw_detach(void)
   7837 {
   7838 #if defined(WL_IW_USE_ISCAN)
   7839 	iscan_buf_t  *buf;
   7840 	iscan_info_t *iscan = g_iscan;
   7841 
   7842 	if (!iscan)
   7843 		return;
   7844 	if (iscan->sysioc_pid >= 0) {
   7845 		KILL_PROC(iscan->sysioc_pid, SIGTERM);
   7846 		wait_for_completion(&iscan->sysioc_exited);
   7847 	}
   7848 	mutex_lock(&wl_cache_lock);
   7849 	while (iscan->list_hdr) {
   7850 		buf = iscan->list_hdr->next;
   7851 		kfree(iscan->list_hdr);
   7852 		iscan->list_hdr = buf;
   7853 	}
   7854 	kfree(iscan->iscan_ex_params_p);
   7855 	kfree(iscan);
   7856 	g_iscan = NULL;
   7857 	mutex_unlock(&wl_cache_lock);
   7858 #endif
   7859 
   7860 	if (g_scan)
   7861 		kfree(g_scan);
   7862 
   7863 	g_scan = NULL;
   7864 #if !defined(CSCAN)
   7865 	wl_iw_release_ss_cache_ctrl();
   7866 #endif
   7867 	wl_iw_bt_release();
   7868 #ifdef SOFTAP
   7869 	if (ap_cfg_running) {
   7870 		WL_TRACE(("\n%s AP is going down\n", __FUNCTION__));
   7871 		wl_iw_send_priv_event(priv_dev, "AP_DOWN");
   7872 	}
   7873 #endif
   7874 
   7875 }
   7876