/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

Large files are truncated click here to view the full 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