/kern_2.6.32/drivers/net/wireless/bcm4329/src/wl/sys/wl_iw.c

http://omnia2droid.googlecode.com/ · C · 7874 lines · 6263 code · 1534 blank · 77 comment · 1031 complexity · 0d24aa2c9517cc7cfbefc1af7086e842 MD5 · raw file

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