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