Merge branch develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / wl_android.c
1 /*
2  * Linux cfg80211 driver - Android related functions
3  *
4  * $Copyright Open Broadcom Corporation$
5  *
6  * $Id: wl_android.c 505064 2014-09-26 09:40:28Z $
7  */
8
9 #include <linux/module.h>
10 #include <linux/netdevice.h>
11 #include <net/netlink.h>
12 #ifdef CONFIG_COMPAT
13 #include <linux/compat.h>
14 #endif
15
16 #include <wl_android.h>
17 #include <wldev_common.h>
18 #include <wlioctl.h>
19 #include <bcmutils.h>
20 #include <linux_osl.h>
21 #include <dhd_dbg.h>
22 #include <dngl_stats.h>
23 #include <dhd.h>
24 #include <dhd_config.h>
25 #include <proto/bcmip.h>
26 #ifdef PNO_SUPPORT
27 #include <dhd_pno.h>
28 #endif
29 #ifdef BCMSDIO
30 #include <bcmsdbus.h>
31 #endif
32 #ifdef WL_CFG80211
33 #include <wl_cfg80211.h>
34 #endif
35 #ifdef WL_NAN
36 #include <wl_cfgnan.h>
37 #endif /* WL_NAN */
38
39 #ifndef WL_CFG80211
40 #define htod32(i) i
41 #define htod16(i) i
42 #define dtoh32(i) i
43 #define dtoh16(i) i
44 #define htodchanspec(i) i
45 #define dtohchanspec(i) i
46 #endif
47
48 /* message levels */
49 #define ANDROID_ERROR_LEVEL     0x0001
50 #define ANDROID_TRACE_LEVEL     0x0002
51 #define ANDROID_INFO_LEVEL      0x0004
52
53 uint android_msg_level = ANDROID_ERROR_LEVEL;
54
55 #define ANDROID_ERROR(x) \
56         do { \
57                 if (android_msg_level & ANDROID_ERROR_LEVEL) { \
58                         printk(KERN_ERR "ANDROID-ERROR) ");     \
59                         printk x; \
60                 } \
61         } while (0)
62 #define ANDROID_TRACE(x) \
63         do { \
64                 if (android_msg_level & ANDROID_TRACE_LEVEL) { \
65                         printk(KERN_ERR "ANDROID-TRACE) ");     \
66                         printk x; \
67                 } \
68         } while (0)
69 #define ANDROID_INFO(x) \
70         do { \
71                 if (android_msg_level & ANDROID_INFO_LEVEL) { \
72                         printk(KERN_ERR "ANDROID-INFO) ");      \
73                         printk x; \
74                 } \
75         } while (0)
76
77 /*
78  * Android private command strings, PLEASE define new private commands here
79  * so they can be updated easily in the future (if needed)
80  */
81
82 #define CMD_START               "START"
83 #define CMD_STOP                "STOP"
84 #define CMD_SCAN_ACTIVE         "SCAN-ACTIVE"
85 #define CMD_SCAN_PASSIVE        "SCAN-PASSIVE"
86 #define CMD_RSSI                "RSSI"
87 #define CMD_LINKSPEED           "LINKSPEED"
88 #ifdef PKT_FILTER_SUPPORT
89 #define CMD_RXFILTER_START      "RXFILTER-START"
90 #define CMD_RXFILTER_STOP       "RXFILTER-STOP"
91 #define CMD_RXFILTER_ADD        "RXFILTER-ADD"
92 #define CMD_RXFILTER_REMOVE     "RXFILTER-REMOVE"
93 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
94 #define CMD_PKT_FILTER_MODE             "PKT_FILTER_MODE"
95 #define CMD_PKT_FILTER_PORTS    "PKT_FILTER_PORTS"
96 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
97 #endif /* PKT_FILTER_SUPPORT */
98 #define CMD_BTCOEXSCAN_START    "BTCOEXSCAN-START"
99 #define CMD_BTCOEXSCAN_STOP     "BTCOEXSCAN-STOP"
100 #define CMD_BTCOEXMODE          "BTCOEXMODE"
101 #define CMD_SETSUSPENDOPT       "SETSUSPENDOPT"
102 #define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
103 #define CMD_P2P_DEV_ADDR        "P2P_DEV_ADDR"
104 #define CMD_SETFWPATH           "SETFWPATH"
105 #define CMD_SETBAND             "SETBAND"
106 #define CMD_GETBAND             "GETBAND"
107 #define CMD_COUNTRY             "COUNTRY"
108 #define CMD_P2P_SET_NOA         "P2P_SET_NOA"
109 #if !defined WL_ENABLE_P2P_IF
110 #define CMD_P2P_GET_NOA                 "P2P_GET_NOA"
111 #endif /* WL_ENABLE_P2P_IF */
112 #define CMD_P2P_SD_OFFLOAD              "P2P_SD_"
113 #define CMD_P2P_SET_PS          "P2P_SET_PS"
114 #define CMD_SET_AP_WPS_P2P_IE           "SET_AP_WPS_P2P_IE"
115 #define CMD_SETROAMMODE         "SETROAMMODE"
116 #define CMD_SETIBSSBEACONOUIDATA        "SETIBSSBEACONOUIDATA"
117 #define CMD_MIRACAST            "MIRACAST"
118 #define CMD_NAN         "NAN_"
119 #define CMD_GET_CHANNEL                 "GET_CHANNEL"
120 #define CMD_SET_ROAM                    "SET_ROAM_TRIGGER"                      
121 #define CMD_GET_ROAM                    "GET_ROAM_TRIGGER"
122 #define CMD_GET_KEEP_ALIVE              "GET_KEEP_ALIVE"
123 #define CMD_GET_PM                              "GET_PM"
124 #define CMD_SET_PM                              "SET_PM"
125 #define CMD_MONITOR                     "MONITOR"
126
127 #if defined(WL_SUPPORT_AUTO_CHANNEL)
128 #define CMD_GET_BEST_CHANNELS   "GET_BEST_CHANNELS"
129 #endif /* WL_SUPPORT_AUTO_CHANNEL */
130
131 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
132 #define CMD_SETMIRACAST         "SETMIRACAST"
133 #define CMD_ASSOCRESPIE         "ASSOCRESPIE"
134 #define CMD_RXRATESTATS        "RXRATESTATS"
135 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
136
137 #define CMD_KEEP_ALIVE          "KEEPALIVE"
138
139 /* CCX Private Commands */
140 #ifdef BCMCCX
141 #define CMD_GETCCKM_RN          "get cckm_rn"
142 #define CMD_SETCCKM_KRK         "set cckm_krk"
143 #define CMD_GET_ASSOC_RES_IES   "get assoc_res_ies"
144 #endif
145
146 #ifdef PNO_SUPPORT
147 #define CMD_PNOSSIDCLR_SET      "PNOSSIDCLR"
148 #define CMD_PNOSETUP_SET        "PNOSETUP "
149 #define CMD_PNOENABLE_SET       "PNOFORCE"
150 #define CMD_PNODEBUG_SET        "PNODEBUG"
151 #define CMD_WLS_BATCHING        "WLS_BATCHING"
152 #endif /* PNO_SUPPORT */
153
154 #define CMD_OKC_SET_PMK         "SET_PMK"
155 #define CMD_OKC_ENABLE          "OKC_ENABLE"
156
157 #define CMD_HAPD_MAC_FILTER     "HAPD_MAC_FILTER"
158
159 #ifdef WLFBT
160 #define CMD_GET_FTKEY      "GET_FTKEY"
161 #endif
162
163 #ifdef WLAIBSS
164 #define CMD_SETIBSSTXFAILEVENT          "SETIBSSTXFAILEVENT"
165 #define CMD_GET_IBSS_PEER_INFO          "GETIBSSPEERINFO"
166 #define CMD_GET_IBSS_PEER_INFO_ALL      "GETIBSSPEERINFOALL"
167 #define CMD_SETIBSSROUTETABLE           "SETIBSSROUTETABLE"
168 #define CMD_SETIBSSAMPDU                        "SETIBSSAMPDU"
169 #define CMD_SETIBSSANTENNAMODE          "SETIBSSANTENNAMODE"
170 #endif /* WLAIBSS */
171
172 #define CMD_ROAM_OFFLOAD                        "SETROAMOFFLOAD"
173 #define CMD_ROAM_OFFLOAD_APLIST         "SETROAMOFFLAPLIST"
174 #define CMD_GET_LINK_STATUS                     "GETLINKSTATUS"
175
176 #ifdef P2PRESP_WFDIE_SRC
177 #define CMD_P2P_SET_WFDIE_RESP      "P2P_SET_WFDIE_RESP"
178 #define CMD_P2P_GET_WFDIE_RESP      "P2P_GET_WFDIE_RESP"
179 #endif /* P2PRESP_WFDIE_SRC */
180
181 /* related with CMD_GET_LINK_STATUS */
182 #define WL_ANDROID_LINK_VHT                                     0x01
183 #define WL_ANDROID_LINK_MIMO                                    0x02
184 #define WL_ANDROID_LINK_AP_VHT_SUPPORT          0x04
185 #define WL_ANDROID_LINK_AP_MIMO_SUPPORT 0x08
186
187 /* miracast related definition */
188 #define MIRACAST_MODE_OFF       0
189 #define MIRACAST_MODE_SOURCE    1
190 #define MIRACAST_MODE_SINK      2
191
192 #ifndef MIRACAST_AMPDU_SIZE
193 #define MIRACAST_AMPDU_SIZE     8
194 #endif
195
196 #ifndef MIRACAST_MCHAN_ALGO
197 #define MIRACAST_MCHAN_ALGO     1
198 #endif
199
200 #ifndef MIRACAST_MCHAN_BW
201 #define MIRACAST_MCHAN_BW       25
202 #endif
203
204 #ifdef CONNECTION_STATISTICS
205 #define CMD_GET_CONNECTION_STATS        "GET_CONNECTION_STATS"
206
207 struct connection_stats {
208         u32 txframe;
209         u32 txbyte;
210         u32 txerror;
211         u32 rxframe;
212         u32 rxbyte;
213         u32 txfail;
214         u32 txretry;
215         u32 txretrie;
216         u32 txrts;
217         u32 txnocts;
218         u32 txexptime;
219         u32 txrate;
220         u8      chan_idle;
221 };
222 #endif /* CONNECTION_STATISTICS */
223
224 static LIST_HEAD(miracast_resume_list);
225 #ifdef WL_CFG80211
226 static u8 miracast_cur_mode;
227 #endif
228
229 struct io_cfg {
230         s8 *iovar;
231         s32 param;
232         u32 ioctl;
233         void *arg;
234         u32 len;
235         struct list_head list;
236 };
237
238 typedef struct _android_wifi_priv_cmd {
239         char *buf;
240         int used_len;
241         int total_len;
242 } android_wifi_priv_cmd;
243
244 #ifdef CONFIG_COMPAT
245 typedef struct _compat_android_wifi_priv_cmd {
246         compat_caddr_t buf;
247         int used_len;
248         int total_len;
249 } compat_android_wifi_priv_cmd;
250 #endif /* CONFIG_COMPAT */
251
252 #if defined(BCMFW_ROAM_ENABLE)
253 #define CMD_SET_ROAMPREF        "SET_ROAMPREF"
254
255 #define MAX_NUM_SUITES          10
256 #define WIDTH_AKM_SUITE         8
257 #define JOIN_PREF_RSSI_LEN              0x02
258 #define JOIN_PREF_RSSI_SIZE             4       /* RSSI pref header size in bytes */
259 #define JOIN_PREF_WPA_HDR_SIZE          4 /* WPA pref header size in bytes */
260 #define JOIN_PREF_WPA_TUPLE_SIZE        12      /* Tuple size in bytes */
261 #define JOIN_PREF_MAX_WPA_TUPLES        16
262 #define MAX_BUF_SIZE            (JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE + \
263                                            (JOIN_PREF_WPA_TUPLE_SIZE * JOIN_PREF_MAX_WPA_TUPLES))
264 #endif /* BCMFW_ROAM_ENABLE */
265
266 #ifdef WL_GENL
267 static s32 wl_genl_handle_msg(struct sk_buff *skb, struct genl_info *info);
268 static int wl_genl_init(void);
269 static int wl_genl_deinit(void);
270
271 extern struct net init_net;
272 /* attribute policy: defines which attribute has which type (e.g int, char * etc)
273  * possible values defined in net/netlink.h
274  */
275 static struct nla_policy wl_genl_policy[BCM_GENL_ATTR_MAX + 1] = {
276         [BCM_GENL_ATTR_STRING] = { .type = NLA_NUL_STRING },
277         [BCM_GENL_ATTR_MSG] = { .type = NLA_BINARY },
278 };
279
280 #define WL_GENL_VER 1
281 /* family definition */
282 static struct genl_family wl_genl_family = {
283         .id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
284         .hdrsize = 0,
285         .name = "bcm-genl",        /* Netlink I/F for Android */
286         .version = WL_GENL_VER,     /* Version Number */
287         .maxattr = BCM_GENL_ATTR_MAX,
288 };
289
290 /* commands: mapping between the command enumeration and the actual function */
291 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
292 struct genl_ops wl_genl_ops[] = {
293         {
294         .cmd = BCM_GENL_CMD_MSG,
295         .flags = 0,
296         .policy = wl_genl_policy,
297         .doit = wl_genl_handle_msg,
298         .dumpit = NULL,
299         },
300 };
301 #else
302 struct genl_ops wl_genl_ops = {
303         .cmd = BCM_GENL_CMD_MSG,
304         .flags = 0,
305         .policy = wl_genl_policy,
306         .doit = wl_genl_handle_msg,
307         .dumpit = NULL,
308
309 };
310 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
311
312 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0))
313 static struct genl_multicast_group wl_genl_mcast[] = {
314          { .name = "bcm-genl-mcast", },
315 };
316 #else
317 static struct genl_multicast_group wl_genl_mcast = {
318         .id = GENL_ID_GENERATE,    /* Genetlink would generate the ID */
319         .name = "bcm-genl-mcast",
320 };
321 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) */
322 #endif /* WL_GENL */
323
324 /**
325  * Extern function declarations (TODO: move them to dhd_linux.h)
326  */
327 int dhd_net_bus_devreset(struct net_device *dev, uint8 flag);
328 int dhd_dev_init_ioctl(struct net_device *dev);
329 #ifdef WL_CFG80211
330 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
331 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, dhd_pub_t *dhd, char *command);
332 #else
333 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
334 { return 0; }
335 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
336 { return 0; }
337 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
338 { return 0; }
339 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
340 { return 0; }
341 #endif /* WL_CFG80211 */
342
343
344 #ifdef ENABLE_4335BT_WAR
345 extern int bcm_bt_lock(int cookie);
346 extern void bcm_bt_unlock(int cookie);
347 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24; /* cookie is "WiFi" */
348 #endif /* ENABLE_4335BT_WAR */
349
350 extern bool ap_fw_loaded;
351 extern char iface_name[IFNAMSIZ];
352
353 /**
354  * Local (static) functions and variables
355  */
356
357 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
358  * time (only) in dhd_open, subsequential wifi on will be handled by
359  * wl_android_wifi_on
360  */
361 int g_wifi_on = TRUE;
362
363 /**
364  * Local (static) function definitions
365  */
366 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
367 {
368         int link_speed;
369         int bytes_written;
370         int error;
371
372         error = wldev_get_link_speed(net, &link_speed);
373         if (error)
374                 return -1;
375
376         /* Convert Kbps to Android Mbps */
377         link_speed = link_speed / 1000;
378         bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
379         ANDROID_INFO(("%s: command result is %s\n", __FUNCTION__, command));
380         return bytes_written;
381 }
382
383 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
384 {
385         wlc_ssid_t ssid = {0};
386         int rssi;
387         int bytes_written = 0;
388         int error;
389
390         error = wldev_get_rssi(net, &rssi);
391         if (error)
392                 return -1;
393 #if defined(RSSIOFFSET)
394         rssi = wl_update_rssi_offset(net, rssi);
395 #endif
396
397         error = wldev_get_ssid(net, &ssid);
398         if (error)
399                 return -1;
400         if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
401                 ANDROID_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
402         } else {
403                 memcpy(command, ssid.SSID, ssid.SSID_len);
404                 bytes_written = ssid.SSID_len;
405         }
406         bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
407         ANDROID_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
408         return bytes_written;
409 }
410
411 static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
412 {
413         int suspend_flag;
414         int ret_now;
415         int ret = 0;
416
417         suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
418
419         if (suspend_flag != 0)
420                 suspend_flag = 1;
421         ret_now = net_os_set_suspend_disable(dev, suspend_flag);
422
423         if (ret_now != suspend_flag) {
424                 if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
425                         ANDROID_INFO(("%s: Suspend Flag %d -> %d\n",
426                                 __FUNCTION__, ret_now, suspend_flag));
427                 else
428                         ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
429         }
430         return ret;
431 }
432
433 static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
434 {
435         int ret = 0;
436
437 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
438         int suspend_flag;
439
440         suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
441         if (suspend_flag != 0)
442                 suspend_flag = 1;
443
444         if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
445                 ANDROID_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
446         else
447                 ANDROID_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
448 #endif
449
450         return ret;
451 }
452
453 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
454 {
455         uint band;
456         int bytes_written;
457         int error;
458
459         error = wldev_get_band(dev, &band);
460         if (error)
461                 return -1;
462         bytes_written = snprintf(command, total_len, "Band %d", band);
463         return bytes_written;
464 }
465
466
467 #ifdef PNO_SUPPORT
468 #define PNO_PARAM_SIZE 50
469 #define VALUE_SIZE 50
470 #define LIMIT_STR_FMT  ("%50s %50s")
471 static int
472 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
473 {
474         int err = BCME_OK;
475         uint i, tokens;
476         char *pos, *pos2, *token, *token2, *delim;
477         char param[PNO_PARAM_SIZE], value[VALUE_SIZE];
478         struct dhd_pno_batch_params batch_params;
479         ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
480         if (total_len < strlen(CMD_WLS_BATCHING)) {
481                 ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
482                 err = BCME_ERROR;
483                 goto exit;
484         }
485         pos = command + strlen(CMD_WLS_BATCHING) + 1;
486         memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params));
487
488         if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
489                 pos += strlen(PNO_BATCHING_SET) + 1;
490                 while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
491                         memset(param, 0, sizeof(param));
492                         memset(value, 0, sizeof(value));
493                         if (token == NULL || !*token)
494                                 break;
495                         if (*token == '\0')
496                                 continue;
497                         delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
498                         if (delim != NULL)
499                                 *delim = ' ';
500
501                         tokens = sscanf(token, LIMIT_STR_FMT, param, value);
502                         if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_SCANFREQ))) {
503                                 batch_params.scan_fr = simple_strtol(value, NULL, 0);
504                                 ANDROID_INFO(("scan_freq : %d\n", batch_params.scan_fr));
505                         } else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_BESTN))) {
506                                 batch_params.bestn = simple_strtol(value, NULL, 0);
507                                 ANDROID_INFO(("bestn : %d\n", batch_params.bestn));
508                         } else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
509                                 batch_params.mscan = simple_strtol(value, NULL, 0);
510                                 ANDROID_INFO(("mscan : %d\n", batch_params.mscan));
511                         } else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_CHANNEL))) {
512                                 i = 0;
513                                 pos2 = value;
514                                 tokens = sscanf(value, "<%s>", value);
515                                 if (tokens != 1) {
516                                         err = BCME_ERROR;
517                                         ANDROID_ERROR(("%s : invalid format for channel"
518                                         " <> params\n", __FUNCTION__));
519                                         goto exit;
520                                 }
521                                         while ((token2 = strsep(&pos2,
522                                         PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
523                                         if (token2 == NULL || !*token2)
524                                                 break;
525                                         if (*token2 == '\0')
526                                                 continue;
527                                         if (*token2 == 'A' || *token2 == 'B') {
528                                                 batch_params.band = (*token2 == 'A')?
529                                                         WLC_BAND_5G : WLC_BAND_2G;
530                                                 ANDROID_INFO(("band : %s\n",
531                                                         (*token2 == 'A')? "A" : "B"));
532                                         } else {
533                                                 batch_params.chan_list[i++] =
534                                                 simple_strtol(token2, NULL, 0);
535                                                 batch_params.nchan++;
536                                                 ANDROID_INFO(("channel :%d\n",
537                                                 batch_params.chan_list[i-1]));
538                                         }
539                                  }
540                         } else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_RTT))) {
541                                 batch_params.rtt = simple_strtol(value, NULL, 0);
542                                 ANDROID_INFO(("rtt : %d\n", batch_params.rtt));
543                         } else {
544                                 ANDROID_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
545                                 err = BCME_ERROR;
546                                 goto exit;
547                         }
548                 }
549                 err = dhd_dev_pno_set_for_batch(dev, &batch_params);
550                 if (err < 0) {
551                         ANDROID_ERROR(("failed to configure batch scan\n"));
552                 } else {
553                         memset(command, 0, total_len);
554                         err = sprintf(command, "%d", err);
555                 }
556         } else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
557                 err = dhd_dev_pno_get_for_batch(dev, command, total_len);
558                 if (err < 0) {
559                         ANDROID_ERROR(("failed to getting batching results\n"));
560                 } else {
561                         err = strlen(command);
562                 }
563         } else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
564                 err = dhd_dev_pno_stop_for_batch(dev);
565                 if (err < 0) {
566                         ANDROID_ERROR(("failed to stop batching scan\n"));
567                 } else {
568                         memset(command, 0, total_len);
569                         err = sprintf(command, "OK");
570                 }
571         } else {
572                 ANDROID_ERROR(("%s : unknown command\n", __FUNCTION__));
573                 err = BCME_ERROR;
574                 goto exit;
575         }
576 exit:
577         return err;
578 }
579 #ifndef WL_SCHED_SCAN
580 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
581 {
582         wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
583         int res = -1;
584         int nssid = 0;
585         cmd_tlv_t *cmd_tlv_temp;
586         char *str_ptr;
587         int tlv_size_left;
588         int pno_time = 0;
589         int pno_repeat = 0;
590         int pno_freq_expo_max = 0;
591
592 #ifdef PNO_SET_DEBUG
593         int i;
594         char pno_in_example[] = {
595                 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
596                 'S', '1', '2', '0',
597                 'S',
598                 0x05,
599                 'd', 'l', 'i', 'n', 'k',
600                 'S',
601                 0x04,
602                 'G', 'O', 'O', 'G',
603                 'T',
604                 '0', 'B',
605                 'R',
606                 '2',
607                 'M',
608                 '2',
609                 0x00
610                 };
611 #endif /* PNO_SET_DEBUG */
612         ANDROID_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
613
614         if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
615                 ANDROID_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
616                 goto exit_proc;
617         }
618 #ifdef PNO_SET_DEBUG
619         memcpy(command, pno_in_example, sizeof(pno_in_example));
620         total_len = sizeof(pno_in_example);
621 #endif
622         str_ptr = command + strlen(CMD_PNOSETUP_SET);
623         tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
624
625         cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
626         memset(ssids_local, 0, sizeof(ssids_local));
627
628         if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
629                 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
630                 (cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
631
632                 str_ptr += sizeof(cmd_tlv_t);
633                 tlv_size_left -= sizeof(cmd_tlv_t);
634
635                 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
636                         MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
637                         ANDROID_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
638                         goto exit_proc;
639                 } else {
640                         if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
641                                 ANDROID_ERROR(("%s scan duration corrupted field size %d\n",
642                                         __FUNCTION__, tlv_size_left));
643                                 goto exit_proc;
644                         }
645                         str_ptr++;
646                         pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
647                         ANDROID_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
648
649                         if (str_ptr[0] != 0) {
650                                 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
651                                         ANDROID_ERROR(("%s pno repeat : corrupted field\n",
652                                                 __FUNCTION__));
653                                         goto exit_proc;
654                                 }
655                                 str_ptr++;
656                                 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
657                                 ANDROID_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
658                                 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
659                                         ANDROID_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
660                                                 __FUNCTION__));
661                                         goto exit_proc;
662                                 }
663                                 str_ptr++;
664                                 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
665                                 ANDROID_INFO(("%s: pno_freq_expo_max=%d\n",
666                                         __FUNCTION__, pno_freq_expo_max));
667                         }
668                 }
669         } else {
670                 ANDROID_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
671                 goto exit_proc;
672         }
673
674         res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
675                 pno_freq_expo_max, NULL, 0);
676 exit_proc:
677         return res;
678 }
679 #endif /* !WL_SCHED_SCAN */
680 #endif /* PNO_SUPPORT  */
681
682 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
683 {
684         int ret;
685         int bytes_written = 0;
686
687         ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
688         if (ret)
689                 return 0;
690         bytes_written = sizeof(struct ether_addr);
691         return bytes_written;
692 }
693
694 #ifdef BCMCCX
695 static int wl_android_get_cckm_rn(struct net_device *dev, char *command)
696 {
697         int error, rn;
698
699         ANDROID_TRACE(("%s:wl_android_get_cckm_rn\n", dev->name));
700
701         error = wldev_iovar_getint(dev, "cckm_rn", &rn);
702         if (unlikely(error)) {
703                 ANDROID_ERROR(("wl_android_get_cckm_rn error (%d)\n", error));
704                 return -1;
705         }
706         memcpy(command, &rn, sizeof(int));
707
708         return sizeof(int);
709 }
710
711 static int wl_android_set_cckm_krk(struct net_device *dev, char *command)
712 {
713         int error;
714         unsigned char key[16];
715         static char iovar_buf[WLC_IOCTL_MEDLEN];
716
717         ANDROID_TRACE(("%s: wl_iw_set_cckm_krk\n", dev->name));
718
719         memset(iovar_buf, 0, sizeof(iovar_buf));
720         memcpy(key, command+strlen("set cckm_krk")+1, 16);
721
722         error = wldev_iovar_setbuf(dev, "cckm_krk", key, sizeof(key),
723                 iovar_buf, WLC_IOCTL_MEDLEN, NULL);
724         if (unlikely(error))
725         {
726                 ANDROID_ERROR((" cckm_krk set error (%d)\n", error));
727                 return -1;
728         }
729         return 0;
730 }
731
732 static int wl_android_get_assoc_res_ies(struct net_device *dev, char *command)
733 {
734         int error;
735         u8 buf[WL_ASSOC_INFO_MAX];
736         wl_assoc_info_t assoc_info;
737         u32 resp_ies_len = 0;
738         int bytes_written = 0;
739
740         ANDROID_TRACE(("%s: wl_iw_get_assoc_res_ies\n", dev->name));
741
742         error = wldev_iovar_getbuf(dev, "assoc_info", NULL, 0, buf, WL_ASSOC_INFO_MAX, NULL);
743         if (unlikely(error)) {
744                 ANDROID_ERROR(("could not get assoc info (%d)\n", error));
745                 return -1;
746         }
747
748         memcpy(&assoc_info, buf, sizeof(wl_assoc_info_t));
749         assoc_info.req_len = htod32(assoc_info.req_len);
750         assoc_info.resp_len = htod32(assoc_info.resp_len);
751         assoc_info.flags = htod32(assoc_info.flags);
752
753         if (assoc_info.resp_len) {
754                 resp_ies_len = assoc_info.resp_len - sizeof(struct dot11_assoc_resp);
755         }
756
757         /* first 4 bytes are ie len */
758         memcpy(command, &resp_ies_len, sizeof(u32));
759         bytes_written = sizeof(u32);
760
761         /* get the association resp IE's if there are any */
762         if (resp_ies_len) {
763                 error = wldev_iovar_getbuf(dev, "assoc_resp_ies", NULL, 0,
764                         buf, WL_ASSOC_INFO_MAX, NULL);
765                 if (unlikely(error)) {
766                         ANDROID_ERROR(("could not get assoc resp_ies (%d)\n", error));
767                         return -1;
768                 }
769
770                 memcpy(command+sizeof(u32), buf, resp_ies_len);
771                 bytes_written += resp_ies_len;
772         }
773         return bytes_written;
774 }
775
776 #endif /* BCMCCX */
777
778 int
779 wl_android_set_ap_mac_list(struct net_device *dev, int macmode, struct maclist *maclist)
780 {
781         int i, j, match;
782         int ret = 0;
783         char mac_buf[MAX_NUM_OF_ASSOCLIST *
784                 sizeof(struct ether_addr) + sizeof(uint)] = {0};
785         struct maclist *assoc_maclist = (struct maclist *)mac_buf;
786
787         /* set filtering mode */
788         if ((ret = wldev_ioctl(dev, WLC_SET_MACMODE, &macmode, sizeof(macmode), true)) != 0) {
789                 ANDROID_ERROR(("%s : WLC_SET_MACMODE error=%d\n", __FUNCTION__, ret));
790                 return ret;
791         }
792         if (macmode != MACLIST_MODE_DISABLED) {
793                 /* set the MAC filter list */
794                 if ((ret = wldev_ioctl(dev, WLC_SET_MACLIST, maclist,
795                         sizeof(int) + sizeof(struct ether_addr) * maclist->count, true)) != 0) {
796                         ANDROID_ERROR(("%s : WLC_SET_MACLIST error=%d\n", __FUNCTION__, ret));
797                         return ret;
798                 }
799                 /* get the current list of associated STAs */
800                 assoc_maclist->count = MAX_NUM_OF_ASSOCLIST;
801                 if ((ret = wldev_ioctl(dev, WLC_GET_ASSOCLIST, assoc_maclist,
802                         sizeof(mac_buf), false)) != 0) {
803                         ANDROID_ERROR(("%s : WLC_GET_ASSOCLIST error=%d\n", __FUNCTION__, ret));
804                         return ret;
805                 }
806                 /* do we have any STA associated?  */
807                 if (assoc_maclist->count) {
808                         /* iterate each associated STA */
809                         for (i = 0; i < assoc_maclist->count; i++) {
810                                 match = 0;
811                                 /* compare with each entry */
812                                 for (j = 0; j < maclist->count; j++) {
813                                         ANDROID_INFO(("%s : associated="MACDBG " list="MACDBG "\n",
814                                         __FUNCTION__, MAC2STRDBG(assoc_maclist->ea[i].octet),
815                                         MAC2STRDBG(maclist->ea[j].octet)));
816                                         if (memcmp(assoc_maclist->ea[i].octet,
817                                                 maclist->ea[j].octet, ETHER_ADDR_LEN) == 0) {
818                                                 match = 1;
819                                                 break;
820                                         }
821                                 }
822                                 /* do conditional deauth */
823                                 /*   "if not in the allow list" or "if in the deny list" */
824                                 if ((macmode == MACLIST_MODE_ALLOW && !match) ||
825                                         (macmode == MACLIST_MODE_DENY && match)) {
826                                         scb_val_t scbval;
827
828                                         scbval.val = htod32(1);
829                                         memcpy(&scbval.ea, &assoc_maclist->ea[i],
830                                                 ETHER_ADDR_LEN);
831                                         if ((ret = wldev_ioctl(dev,
832                                                 WLC_SCB_DEAUTHENTICATE_FOR_REASON,
833                                                 &scbval, sizeof(scb_val_t), true)) != 0)
834                                                 ANDROID_ERROR(("%s WLC_SCB_DEAUTHENTICATE error=%d\n",
835                                                         __FUNCTION__, ret));
836                                 }
837                         }
838                 }
839         }
840         return ret;
841 }
842
843 /*
844  * HAPD_MAC_FILTER mac_mode mac_cnt mac_addr1 mac_addr2
845  *
846  */
847 static int
848 wl_android_set_mac_address_filter(struct net_device *dev, const char* str)
849 {
850         int i;
851         int ret = 0;
852         int macnum = 0;
853         int macmode = MACLIST_MODE_DISABLED;
854         struct maclist *list;
855         char eabuf[ETHER_ADDR_STR_LEN];
856
857         /* string should look like below (macmode/macnum/maclist) */
858         /*   1 2 00:11:22:33:44:55 00:11:22:33:44:ff  */
859
860         /* get the MAC filter mode */
861         macmode = bcm_atoi(strsep((char**)&str, " "));
862
863         if (macmode < MACLIST_MODE_DISABLED || macmode > MACLIST_MODE_ALLOW) {
864                 ANDROID_ERROR(("%s : invalid macmode %d\n", __FUNCTION__, macmode));
865                 return -1;
866         }
867
868         macnum = bcm_atoi(strsep((char**)&str, " "));
869         if (macnum < 0 || macnum > MAX_NUM_MAC_FILT) {
870                 ANDROID_ERROR(("%s : invalid number of MAC address entries %d\n",
871                         __FUNCTION__, macnum));
872                 return -1;
873         }
874         /* allocate memory for the MAC list */
875         list = (struct maclist*)kmalloc(sizeof(int) +
876                 sizeof(struct ether_addr) * macnum, GFP_KERNEL);
877         if (!list) {
878                 ANDROID_ERROR(("%s : failed to allocate memory\n", __FUNCTION__));
879                 return -1;
880         }
881         /* prepare the MAC list */
882         list->count = htod32(macnum);
883         bzero((char *)eabuf, ETHER_ADDR_STR_LEN);
884         for (i = 0; i < list->count; i++) {
885                 strncpy(eabuf, strsep((char**)&str, " "), ETHER_ADDR_STR_LEN - 1);
886                 if (!(ret = bcm_ether_atoe(eabuf, &list->ea[i]))) {
887                         ANDROID_ERROR(("%s : mac parsing err index=%d, addr=%s\n",
888                                 __FUNCTION__, i, eabuf));
889                         list->count--;
890                         break;
891                 }
892                 ANDROID_INFO(("%s : %d/%d MACADDR=%s", __FUNCTION__, i, list->count, eabuf));
893         }
894         /* set the list */
895         if ((ret = wl_android_set_ap_mac_list(dev, macmode, list)) != 0)
896                 ANDROID_ERROR(("%s : Setting MAC list failed error=%d\n", __FUNCTION__, ret));
897
898         kfree(list);
899
900         return 0;
901 }
902
903 /**
904  * Global function definitions (declared in wl_android.h)
905  */
906
907 int wl_android_wifi_on(struct net_device *dev)
908 {
909         int ret = 0;
910 #ifdef CONFIG_MACH_UNIVERSAL5433
911         int retry;
912         /* Do not retry old revision Helsinki Prime */
913         if (!check_rev()) {
914                 retry = 1;
915         } else {
916                 retry = POWERUP_MAX_RETRY;
917         }
918 #else
919         int retry = POWERUP_MAX_RETRY;
920 #endif /* CONFIG_MACH_UNIVERSAL5433 */
921
922         if (!dev) {
923                 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
924                 return -EINVAL;
925         }
926
927         printk("%s in 1\n", __FUNCTION__);
928         dhd_net_if_lock(dev);
929         printk("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
930         if (!g_wifi_on) {
931                 do {
932                         dhd_net_wifi_platform_set_power(dev, TRUE, WIFI_TURNON_DELAY);
933 #ifdef BCMSDIO
934                         ret = dhd_net_bus_resume(dev, 0);
935 #endif /* BCMSDIO */
936 #ifdef BCMPCIE
937                         ret = dhd_net_bus_devreset(dev, FALSE);
938 #endif /* BCMPCIE */
939                         if (ret == 0)
940                                 break;
941                         ANDROID_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
942                                 retry));
943 #ifdef BCMPCIE
944                         dhd_net_bus_devreset(dev, TRUE);
945 #endif /* BCMPCIE */
946                         dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
947                 } while (retry-- > 0);
948                 if (ret != 0) {
949                         ANDROID_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
950                         goto exit;
951                 }
952 #ifdef BCMSDIO
953                 ret = dhd_net_bus_devreset(dev, FALSE);
954                 if (ret)
955                         goto err;
956                 dhd_net_bus_resume(dev, 1);
957 #endif /* BCMSDIO */
958
959 #ifndef BCMPCIE
960                 if (!ret) {
961                         if (dhd_dev_init_ioctl(dev) < 0) {
962                                 ret = -EFAULT;
963                                 goto err;
964                         }
965                 }
966 #endif /* !BCMPCIE */
967                 g_wifi_on = TRUE;
968         }
969
970 exit:
971         printk("%s: Success\n", __FUNCTION__);
972         dhd_net_if_unlock(dev);
973         return ret;
974
975 #ifdef BCMSDIO
976 err:
977         dhd_net_bus_devreset(dev, TRUE);
978         dhd_net_bus_suspend(dev);
979         dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
980         printk("%s: Failed\n", __FUNCTION__);
981         dhd_net_if_unlock(dev);
982         return ret;
983 #endif
984 }
985
986 int wl_android_wifi_off(struct net_device *dev)
987 {
988         int ret = 0;
989
990         if (!dev) {
991                 ANDROID_ERROR(("%s: dev is null\n", __FUNCTION__));
992                 return -EINVAL;
993         }
994
995         printk("%s in 1\n", __FUNCTION__);
996         dhd_net_if_lock(dev);
997         printk("%s in 2: g_wifi_on=%d\n", __FUNCTION__, g_wifi_on);
998         if (g_wifi_on) {
999 #if defined(BCMSDIO) || defined(BCMPCIE)
1000                 ret = dhd_net_bus_devreset(dev, TRUE);
1001 #ifdef BCMSDIO
1002                 dhd_net_bus_suspend(dev);
1003 #endif /* BCMSDIO */
1004 #endif /* BCMSDIO || BCMPCIE */
1005                 dhd_net_wifi_platform_set_power(dev, FALSE, WIFI_TURNOFF_DELAY);
1006                 g_wifi_on = FALSE;
1007         }
1008         printk("%s out\n", __FUNCTION__);
1009         dhd_net_if_unlock(dev);
1010
1011         return ret;
1012 }
1013
1014 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
1015 {
1016         if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
1017                 return -1;
1018         return dhd_net_set_fw_path(net, command + strlen(CMD_SETFWPATH) + 1);
1019 }
1020
1021 #ifdef CONNECTION_STATISTICS
1022 static int
1023 wl_chanim_stats(struct net_device *dev, u8 *chan_idle)
1024 {
1025         int err;
1026         wl_chanim_stats_t *list;
1027         /* Parameter _and_ returned buffer of chanim_stats. */
1028         wl_chanim_stats_t param;
1029         u8 result[WLC_IOCTL_SMLEN];
1030         chanim_stats_t *stats;
1031
1032         memset(&param, 0, sizeof(param));
1033         memset(result, 0, sizeof(result));
1034
1035         param.buflen = htod32(sizeof(wl_chanim_stats_t));
1036         param.count = htod32(WL_CHANIM_COUNT_ONE);
1037
1038         if ((err = wldev_iovar_getbuf(dev, "chanim_stats", (char*)&param, sizeof(wl_chanim_stats_t),
1039                 (char*)result, sizeof(result), 0)) < 0) {
1040                 ANDROID_ERROR(("Failed to get chanim results %d \n", err));
1041                 return err;
1042         }
1043
1044         list = (wl_chanim_stats_t*)result;
1045
1046         list->buflen = dtoh32(list->buflen);
1047         list->version = dtoh32(list->version);
1048         list->count = dtoh32(list->count);
1049
1050         if (list->buflen == 0) {
1051                 list->version = 0;
1052                 list->count = 0;
1053         } else if (list->version != WL_CHANIM_STATS_VERSION) {
1054                 ANDROID_ERROR(("Sorry, firmware has wl_chanim_stats version %d "
1055                         "but driver supports only version %d.\n",
1056                                 list->version, WL_CHANIM_STATS_VERSION));
1057                 list->buflen = 0;
1058                 list->count = 0;
1059         }
1060
1061         stats = list->stats;
1062         stats->glitchcnt = dtoh32(stats->glitchcnt);
1063         stats->badplcp = dtoh32(stats->badplcp);
1064         stats->chanspec = dtoh16(stats->chanspec);
1065         stats->timestamp = dtoh32(stats->timestamp);
1066         stats->chan_idle = dtoh32(stats->chan_idle);
1067
1068         ANDROID_INFO(("chanspec: 0x%4x glitch: %d badplcp: %d idle: %d timestamp: %d\n",
1069                 stats->chanspec, stats->glitchcnt, stats->badplcp, stats->chan_idle,
1070                 stats->timestamp));
1071
1072         *chan_idle = stats->chan_idle;
1073
1074         return (err);
1075 }
1076
1077 static int
1078 wl_android_get_connection_stats(struct net_device *dev, char *command, int total_len)
1079 {
1080         wl_cnt_t* cnt = NULL;
1081         int link_speed = 0;
1082         struct connection_stats *output;
1083         unsigned int bufsize = 0;
1084         int bytes_written = 0;
1085         int ret = 0;
1086
1087         ANDROID_INFO(("%s: enter Get Connection Stats\n", __FUNCTION__));
1088
1089         if (total_len <= 0) {
1090                 ANDROID_ERROR(("%s: invalid buffer size %d\n", __FUNCTION__, total_len));
1091                 goto error;
1092         }
1093
1094         bufsize = total_len;
1095         if (bufsize < sizeof(struct connection_stats)) {
1096                 ANDROID_ERROR(("%s: not enough buffer size, provided=%u, requires=%u\n",
1097                         __FUNCTION__, bufsize,
1098                         sizeof(struct connection_stats)));
1099                 goto error;
1100         }
1101
1102         if ((cnt = kmalloc(sizeof(*cnt), GFP_KERNEL)) == NULL) {
1103                 ANDROID_ERROR(("kmalloc failed\n"));
1104                 return -1;
1105         }
1106         memset(cnt, 0, sizeof(*cnt));
1107
1108         ret = wldev_iovar_getbuf(dev, "counters", NULL, 0, (char *)cnt, sizeof(wl_cnt_t), NULL);
1109         if (ret) {
1110                 ANDROID_ERROR(("%s: wldev_iovar_getbuf() failed, ret=%d\n",
1111                         __FUNCTION__, ret));
1112                 goto error;
1113         }
1114
1115         if (dtoh16(cnt->version) > WL_CNT_T_VERSION) {
1116                 ANDROID_ERROR(("%s: incorrect version of wl_cnt_t, expected=%u got=%u\n",
1117                         __FUNCTION__,  WL_CNT_T_VERSION, cnt->version));
1118                 goto error;
1119         }
1120
1121         /* link_speed is in kbps */
1122         ret = wldev_get_link_speed(dev, &link_speed);
1123         if (ret || link_speed < 0) {
1124                 ANDROID_ERROR(("%s: wldev_get_link_speed() failed, ret=%d, speed=%d\n",
1125                         __FUNCTION__, ret, link_speed));
1126                 goto error;
1127         }
1128
1129         output = (struct connection_stats *)command;
1130         output->txframe   = dtoh32(cnt->txframe);
1131         output->txbyte    = dtoh32(cnt->txbyte);
1132         output->txerror   = dtoh32(cnt->txerror);
1133         output->rxframe   = dtoh32(cnt->rxframe);
1134         output->rxbyte    = dtoh32(cnt->rxbyte);
1135         output->txfail    = dtoh32(cnt->txfail);
1136         output->txretry   = dtoh32(cnt->txretry);
1137         output->txretrie  = dtoh32(cnt->txretrie);
1138         output->txrts     = dtoh32(cnt->txrts);
1139         output->txnocts   = dtoh32(cnt->txnocts);
1140         output->txexptime = dtoh32(cnt->txexptime);
1141         output->txrate    = link_speed;
1142
1143         /* Channel idle ratio. */
1144         if (wl_chanim_stats(dev, &(output->chan_idle)) < 0) {
1145                 output->chan_idle = 0;
1146         };
1147
1148         kfree(cnt);
1149
1150         bytes_written = sizeof(struct connection_stats);
1151         return bytes_written;
1152
1153 error:
1154         if (cnt) {
1155                 kfree(cnt);
1156         }
1157         return -1;
1158 }
1159 #endif /* CONNECTION_STATISTICS */
1160
1161 static int
1162 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
1163 {
1164         uchar pmk[33];
1165         int error = 0;
1166         char smbuf[WLC_IOCTL_SMLEN];
1167 #ifdef OKC_DEBUG
1168         int i = 0;
1169 #endif
1170
1171         bzero(pmk, sizeof(pmk));
1172         memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
1173         error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
1174         if (error) {
1175                 ANDROID_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
1176         }
1177 #ifdef OKC_DEBUG
1178         ANDROID_ERROR(("PMK is "));
1179         for (i = 0; i < 32; i++)
1180                 ANDROID_ERROR(("%02X ", pmk[i]));
1181
1182         ANDROID_ERROR(("\n"));
1183 #endif
1184         return error;
1185 }
1186
1187 static int
1188 wl_android_okc_enable(struct net_device *dev, char *command, int total_len)
1189 {
1190         int error = 0;
1191         char okc_enable = 0;
1192
1193         okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
1194         error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
1195         if (error) {
1196                 ANDROID_ERROR(("Failed to %s OKC, error = %d\n",
1197                         okc_enable ? "enable" : "disable", error));
1198         }
1199
1200         wldev_iovar_setint(dev, "ccx_enable", 0);
1201
1202         return error;
1203 }
1204
1205
1206
1207 int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len)
1208 {
1209         int error = 0;
1210         int mode = 0;
1211
1212         if (sscanf(command, "%*s %d", &mode) != 1) {
1213                 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1214                 return -1;
1215         }
1216
1217         error = wldev_iovar_setint(dev, "roam_off", mode);
1218         if (error) {
1219                 ANDROID_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
1220                 __FUNCTION__, mode, error));
1221                 return -1;
1222         }
1223         else
1224                 ANDROID_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
1225                 __FUNCTION__, mode, error));
1226         return 0;
1227 }
1228
1229 #ifdef WL_CFG80211
1230 int wl_android_set_ibss_beacon_ouidata(struct net_device *dev, char *command, int total_len)
1231 {
1232         char ie_buf[VNDR_IE_MAX_LEN];
1233         char *ioctl_buf = NULL;
1234         char hex[] = "XX";
1235         char *pcmd = NULL;
1236         int ielen = 0, datalen = 0, idx = 0, tot_len = 0;
1237         vndr_ie_setbuf_t *vndr_ie = NULL;
1238         s32 iecount;
1239         uint32 pktflag;
1240         u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1241         s32 err = BCME_OK;
1242
1243         /* Check the VSIE (Vendor Specific IE) which was added.
1244          *  If exist then send IOVAR to delete it
1245          */
1246         if (wl_cfg80211_ibss_vsie_delete(dev) != BCME_OK) {
1247                 return -EINVAL;
1248         }
1249
1250         pcmd = command + strlen(CMD_SETIBSSBEACONOUIDATA) + 1;
1251         for (idx = 0; idx < DOT11_OUI_LEN; idx++) {
1252                 hex[0] = *pcmd++;
1253                 hex[1] = *pcmd++;
1254                 ie_buf[idx] =  (uint8)simple_strtoul(hex, NULL, 16);
1255         }
1256         pcmd++;
1257         while ((*pcmd != '\0') && (idx < VNDR_IE_MAX_LEN)) {
1258                 hex[0] = *pcmd++;
1259                 hex[1] = *pcmd++;
1260                 ie_buf[idx++] =  (uint8)simple_strtoul(hex, NULL, 16);
1261                 datalen++;
1262         }
1263         tot_len = sizeof(vndr_ie_setbuf_t) + (datalen - 1);
1264         vndr_ie = (vndr_ie_setbuf_t *) kzalloc(tot_len, kflags);
1265         if (!vndr_ie) {
1266                 ANDROID_ERROR(("IE memory alloc failed\n"));
1267                 return -ENOMEM;
1268         }
1269         /* Copy the vndr_ie SET command ("add"/"del") to the buffer */
1270         strncpy(vndr_ie->cmd, "add", VNDR_IE_CMD_LEN - 1);
1271         vndr_ie->cmd[VNDR_IE_CMD_LEN - 1] = '\0';
1272
1273         /* Set the IE count - the buffer contains only 1 IE */
1274         iecount = htod32(1);
1275         memcpy((void *)&vndr_ie->vndr_ie_buffer.iecount, &iecount, sizeof(s32));
1276
1277         /* Set packet flag to indicate that BEACON's will contain this IE */
1278         pktflag = htod32(VNDR_IE_BEACON_FLAG | VNDR_IE_PRBRSP_FLAG);
1279         memcpy((void *)&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].pktflag, &pktflag,
1280                 sizeof(u32));
1281         /* Set the IE ID */
1282         vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.id = (uchar) DOT11_MNG_PROPR_ID;
1283
1284         memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, &ie_buf,
1285                 DOT11_OUI_LEN);
1286         memcpy(&vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data,
1287                 &ie_buf[DOT11_OUI_LEN], datalen);
1288
1289         ielen = DOT11_OUI_LEN + datalen;
1290         vndr_ie->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.len = (uchar) ielen;
1291
1292         ioctl_buf = kmalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
1293         if (!ioctl_buf) {
1294                 ANDROID_ERROR(("ioctl memory alloc failed\n"));
1295                 if (vndr_ie) {
1296                         kfree(vndr_ie);
1297                 }
1298                 return -ENOMEM;
1299         }
1300         memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN); /* init the buffer */
1301         err = wldev_iovar_setbuf(dev, "ie", vndr_ie, tot_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
1302
1303
1304         if (err != BCME_OK) {
1305                 err = -EINVAL;
1306                 if (vndr_ie) {
1307                         kfree(vndr_ie);
1308                 }
1309         }
1310         else {
1311                 /* do NOT free 'vndr_ie' for the next process */
1312                 wl_cfg80211_ibss_vsie_set_buffer(vndr_ie, tot_len);
1313         }
1314
1315         if (ioctl_buf) {
1316                 kfree(ioctl_buf);
1317         }
1318
1319         return err;
1320 }
1321 #endif
1322
1323 #if defined(BCMFW_ROAM_ENABLE)
1324 static int
1325 wl_android_set_roampref(struct net_device *dev, char *command, int total_len)
1326 {
1327         int error = 0;
1328         char smbuf[WLC_IOCTL_SMLEN];
1329         uint8 buf[MAX_BUF_SIZE];
1330         uint8 *pref = buf;
1331         char *pcmd;
1332         int num_ucipher_suites = 0;
1333         int num_akm_suites = 0;
1334         wpa_suite_t ucipher_suites[MAX_NUM_SUITES];
1335         wpa_suite_t akm_suites[MAX_NUM_SUITES];
1336         int num_tuples = 0;
1337         int total_bytes = 0;
1338         int total_len_left;
1339         int i, j;
1340         char hex[] = "XX";
1341
1342         pcmd = command + strlen(CMD_SET_ROAMPREF) + 1;
1343         total_len_left = total_len - strlen(CMD_SET_ROAMPREF) + 1;
1344
1345         num_akm_suites = simple_strtoul(pcmd, NULL, 16);
1346         /* Increment for number of AKM suites field + space */
1347         pcmd += 3;
1348         total_len_left -= 3;
1349
1350         /* check to make sure pcmd does not overrun */
1351         if (total_len_left < (num_akm_suites * WIDTH_AKM_SUITE))
1352                 return -1;
1353
1354         memset(buf, 0, sizeof(buf));
1355         memset(akm_suites, 0, sizeof(akm_suites));
1356         memset(ucipher_suites, 0, sizeof(ucipher_suites));
1357
1358         /* Save the AKM suites passed in the command */
1359         for (i = 0; i < num_akm_suites; i++) {
1360                 /* Store the MSB first, as required by join_pref */
1361                 for (j = 0; j < 4; j++) {
1362                         hex[0] = *pcmd++;
1363                         hex[1] = *pcmd++;
1364                         buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
1365                 }
1366                 memcpy((uint8 *)&akm_suites[i], buf, sizeof(uint32));
1367         }
1368
1369         total_len_left -= (num_akm_suites * WIDTH_AKM_SUITE);
1370         num_ucipher_suites = simple_strtoul(pcmd, NULL, 16);
1371         /* Increment for number of cipher suites field + space */
1372         pcmd += 3;
1373         total_len_left -= 3;
1374
1375         if (total_len_left < (num_ucipher_suites * WIDTH_AKM_SUITE))
1376                 return -1;
1377
1378         /* Save the cipher suites passed in the command */
1379         for (i = 0; i < num_ucipher_suites; i++) {
1380                 /* Store the MSB first, as required by join_pref */
1381                 for (j = 0; j < 4; j++) {
1382                         hex[0] = *pcmd++;
1383                         hex[1] = *pcmd++;
1384                         buf[j] = (uint8)simple_strtoul(hex, NULL, 16);
1385                 }
1386                 memcpy((uint8 *)&ucipher_suites[i], buf, sizeof(uint32));
1387         }
1388
1389         /* Join preference for RSSI
1390          * Type   : 1 byte (0x01)
1391          * Length : 1 byte (0x02)
1392          * Value  : 2 bytes     (reserved)
1393          */
1394         *pref++ = WL_JOIN_PREF_RSSI;
1395         *pref++ = JOIN_PREF_RSSI_LEN;
1396         *pref++ = 0;
1397         *pref++ = 0;
1398
1399         /* Join preference for WPA
1400          * Type   : 1 byte (0x02)
1401          * Length : 1 byte (not used)
1402          * Value  : (variable length)
1403          *              reserved: 1 byte
1404          *      count   : 1 byte (no of tuples)
1405          *              Tuple1  : 12 bytes
1406          *                      akm[4]
1407          *                      ucipher[4]
1408          *                      mcipher[4]
1409          *              Tuple2  : 12 bytes
1410          *              Tuplen  : 12 bytes
1411          */
1412         num_tuples = num_akm_suites * num_ucipher_suites;
1413         if (num_tuples != 0) {
1414                 if (num_tuples <= JOIN_PREF_MAX_WPA_TUPLES) {
1415                         *pref++ = WL_JOIN_PREF_WPA;
1416                         *pref++ = 0;
1417                         *pref++ = 0;
1418                         *pref++ = (uint8)num_tuples;
1419                         total_bytes = JOIN_PREF_RSSI_SIZE + JOIN_PREF_WPA_HDR_SIZE +
1420                                 (JOIN_PREF_WPA_TUPLE_SIZE * num_tuples);
1421                 } else {
1422                         ANDROID_ERROR(("%s: Too many wpa configs for join_pref \n", __FUNCTION__));
1423                         return -1;
1424                 }
1425         } else {
1426                 /* No WPA config, configure only RSSI preference */
1427                 total_bytes = JOIN_PREF_RSSI_SIZE;
1428         }
1429
1430         /* akm-ucipher-mcipher tuples in the format required for join_pref */
1431         for (i = 0; i < num_ucipher_suites; i++) {
1432                 for (j = 0; j < num_akm_suites; j++) {
1433                         memcpy(pref, (uint8 *)&akm_suites[j], WPA_SUITE_LEN);
1434                         pref += WPA_SUITE_LEN;
1435                         memcpy(pref, (uint8 *)&ucipher_suites[i], WPA_SUITE_LEN);
1436                         pref += WPA_SUITE_LEN;
1437                         /* Set to 0 to match any available multicast cipher */
1438                         memset(pref, 0, WPA_SUITE_LEN);
1439                         pref += WPA_SUITE_LEN;
1440                 }
1441         }
1442
1443         prhex("join pref", (uint8 *)buf, total_bytes);
1444         error = wldev_iovar_setbuf(dev, "join_pref", buf, total_bytes, smbuf, sizeof(smbuf), NULL);
1445         if (error) {
1446                 ANDROID_ERROR(("Failed to set join_pref, error = %d\n", error));
1447         }
1448         return error;
1449 }
1450 #endif /* defined(BCMFW_ROAM_ENABLE */
1451
1452 #ifdef WL_CFG80211
1453 static int
1454 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
1455 {
1456         struct io_cfg *resume_cfg;
1457         s32 ret;
1458
1459         resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL);
1460         if (!resume_cfg)
1461                 return -ENOMEM;
1462
1463         if (config->iovar) {
1464                 ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
1465                 if (ret) {
1466                         ANDROID_ERROR(("%s: Failed to get current %s value\n",
1467                                 __FUNCTION__, config->iovar));
1468                         goto error;
1469                 }
1470
1471                 ret = wldev_iovar_setint(dev, config->iovar, config->param);
1472                 if (ret) {
1473                         ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
1474                                 config->iovar, config->param));
1475                         goto error;
1476                 }
1477
1478                 resume_cfg->iovar = config->iovar;
1479         } else {
1480                 resume_cfg->arg = kzalloc(config->len, GFP_KERNEL);
1481                 if (!resume_cfg->arg) {
1482                         ret = -ENOMEM;
1483                         goto error;
1484                 }
1485                 ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false);
1486                 if (ret) {
1487                         ANDROID_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
1488                                 config->ioctl));
1489                         goto error;
1490                 }
1491                 ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true);
1492                 if (ret) {
1493                         ANDROID_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
1494                                 config->iovar, config->param));
1495                         goto error;
1496                 }
1497                 if (config->ioctl + 1 == WLC_SET_PM)
1498                         wl_cfg80211_update_power_mode(dev);
1499                 resume_cfg->ioctl = config->ioctl;
1500                 resume_cfg->len = config->len;
1501         }
1502
1503         list_add(&resume_cfg->list, head);
1504
1505         return 0;
1506 error:
1507         kfree(resume_cfg->arg);
1508         kfree(resume_cfg);
1509         return ret;
1510 }
1511
1512 static void
1513 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
1514 {
1515         struct io_cfg *config;
1516         struct list_head *cur, *q;
1517         s32 ret = 0;
1518
1519         list_for_each_safe(cur, q, head) {
1520                 config = list_entry(cur, struct io_cfg, list);
1521                 if (config->iovar) {
1522                         if (!ret)
1523                                 ret = wldev_iovar_setint(dev, config->iovar,
1524                                         config->param);
1525                 } else {
1526                         if (!ret)
1527                                 ret = wldev_ioctl(dev, config->ioctl + 1,
1528                                         config->arg, config->len, true);
1529                         if (config->ioctl + 1 == WLC_SET_PM)
1530                                 wl_cfg80211_update_power_mode(dev);
1531                         kfree(config->arg);
1532                 }
1533                 list_del(cur);
1534                 kfree(config);
1535         }
1536 }
1537
1538 static int
1539 wl_android_set_miracast(struct net_device *dev, char *command, int total_len)
1540 {
1541         int mode, val;
1542         int ret = 0;
1543         struct io_cfg config;
1544
1545         if (sscanf(command, "%*s %d", &mode) != 1) {
1546                 ANDROID_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
1547                 return -1;
1548         }
1549
1550         ANDROID_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
1551
1552         if (miracast_cur_mode == mode)
1553                 return 0;
1554
1555         wl_android_iolist_resume(dev, &miracast_resume_list);
1556         miracast_cur_mode = MIRACAST_MODE_OFF;
1557
1558         switch (mode) {
1559         case MIRACAST_MODE_SOURCE:
1560                 /* setting mchan_algo to platform specific value */
1561                 config.iovar = "mchan_algo";
1562
1563                 ret = wldev_ioctl(dev, WLC_GET_BCNPRD, &val, sizeof(int), false);
1564                 if (!ret && val > 100) {
1565                         config.param = 0;
1566                         ANDROID_ERROR(("%s: Connected station's beacon interval: "
1567                                 "%d and set mchan_algo to %d \n",
1568                                 __FUNCTION__, val, config.param));
1569                 }
1570                 else {
1571                         config.param = MIRACAST_MCHAN_ALGO;
1572                 }
1573                 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
1574                 if (ret)
1575                         goto resume;
1576
1577                 /* setting mchan_bw to platform specific value */
1578                 config.iovar = "mchan_bw";
1579                 config.param = MIRACAST_MCHAN_BW;
1580                 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
1581                 if (ret)
1582                         goto resume;
1583
1584                 /* setting apmdu to platform specific value */
1585                 config.iovar = "ampdu_mpdu";
1586                 config.param = MIRACAST_AMPDU_SIZE;
1587                 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
1588                 if (ret)
1589                         goto resume;
1590                 /* FALLTROUGH */
1591                 /* Source mode shares most configurations with sink mode.
1592                  * Fall through here to avoid code duplication
1593                  */
1594         case MIRACAST_MODE_SINK:
1595                 /* disable internal roaming */
1596                 config.iovar = "roam_off";
1597                 config.param = 1;
1598                 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
1599                 if (ret)
1600                         goto resume;
1601                 /* tunr off pm */
1602                 val = 0;
1603                 config.iovar = NULL;
1604                 config.ioctl = WLC_GET_PM;
1605                 config.arg = &val;
1606                 config.len = sizeof(int);
1607                 ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
1608                 if (ret)
1609                         goto resume;
1610
1611                 break;
1612         case MIRACAST_MODE_OFF:
1613         default:
1614                 break;
1615         }
1616         miracast_cur_mode = mode;
1617
1618         return 0;
1619
1620 resume:
1621         ANDROID_ERROR(("%s: turnoff miracast mode because of err%d\n", __FUNCTION__, ret));
1622         wl_android_iolist_resume(dev, &miracast_resume_list);
1623         return ret;
1624 }
1625 #endif
1626
1627 #define NETLINK_OXYGEN     30
1628 #define AIBSS_BEACON_TIMEOUT    10
1629
1630 static struct sock *nl_sk = NULL;
1631
1632 static void wl_netlink_recv(struct sk_buff *skb)
1633 {
1634         ANDROID_ERROR(("netlink_recv called\n"));
1635 }
1636
1637 static int wl_netlink_init(void)
1638 {
1639 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
1640         struct netlink_kernel_cfg cfg = {
1641                 .input  = wl_netlink_recv,
1642         };
1643 #endif
1644
1645         if (nl_sk != NULL) {
1646                 ANDROID_ERROR(("nl_sk already exist\n"));
1647                 return BCME_ERROR;
1648         }
1649
1650 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
1651         nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN,
1652                 0, wl_netlink_recv, NULL, THIS_MODULE);
1653 #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0))
1654         nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, THIS_MODULE, &cfg);
1655 #else
1656         nl_sk = netlink_kernel_create(&init_net, NETLINK_OXYGEN, &cfg);
1657 #endif
1658
1659         if (nl_sk == NULL) {
1660                 ANDROID_ERROR(("nl_sk is not ready\n"));
1661                 return BCME_ERROR;
1662         }
1663
1664         return BCME_OK;
1665 }
1666
1667 static void wl_netlink_deinit(void)
1668 {
1669         if (nl_sk) {
1670                 netlink_kernel_release(nl_sk);
1671                 nl_sk = NULL;
1672         }
1673 }
1674
1675 s32
1676 wl_netlink_send_msg(int pid, int type, int seq, void *data, size_t size)
1677 {
1678         struct sk_buff *skb = NULL;
1679         struct nlmsghdr *nlh = NULL;
1680         int ret = -1;
1681
1682         if (nl_sk == NULL) {
1683                 ANDROID_ERROR(("nl_sk was not initialized\n"));
1684                 goto nlmsg_failure;
1685         }
1686
1687         skb = alloc_skb(NLMSG_SPACE(size), GFP_ATOMIC);
1688         if (skb == NULL) {
1689                 ANDROID_ERROR(("failed to allocate memory\n"));
1690                 goto nlmsg_failure;
1691         }
1692
1693         nlh = nlmsg_put(skb, 0, 0, 0, size, 0);
1694         if (nlh == NULL) {
1695                 ANDROID_ERROR(("failed to build nlmsg, skb_tailroom:%d, nlmsg_total_size:%d\n",
1696                         skb_tailroom(skb), nlmsg_total_size(size)));
1697                 dev_kfree_skb(skb);
1698                 goto nlmsg_failure;
1699         }
1700
1701         memcpy(nlmsg_data(nlh), data, size);
1702         nlh->nlmsg_seq = seq;
1703         nlh->nlmsg_type = type;
1704
1705         /* netlink_unicast() takes ownership of the skb and frees it itself. */
1706         ret = netlink_unicast(nl_sk, skb, pid, 0);
1707         ANDROID_TRACE(("netlink_unicast() pid=%d, ret=%d\n", pid, ret));
1708
1709 nlmsg_failure:
1710         return ret;
1711 }
1712
1713 #ifdef WLAIBSS
1714 static int wl_android_set_ibss_txfail_event(struct net_device *dev, char *command, int total_len)
1715 {
1716         int err = 0;
1717         int retry = 0;
1718         int pid = 0;
1719         aibss_txfail_config_t txfail_config = {0, 0, 0, 0};
1720         char smbuf[WLC_IOCTL_SMLEN];
1721
1722         if (sscanf(command, CMD_SETIBSSTXFAILEVENT " %d %d", &retry, &pid) <= 0) {
1723                 ANDROID_ERROR(("Failed to get Parameter from : %s\n", command));
1724                 return -1;
1725         }
1726
1727         /* set pid, and if the event was happened, let's send a notification through netlink */
1728         wl_cfg80211_set_txfail_pid(pid);
1729
1730         /* If retry value is 0, it disables the functionality for TX Fail. */
1731         if (retry > 0) {
1732                 txfail_config.max_tx_retry = retry;
1733                 txfail_config.bcn_timeout = 0;  /* 0 : disable tx fail from beacon */
1734         }
1735         txfail_config.version = AIBSS_TXFAIL_CONFIG_VER_0;
1736         txfail_config.len = sizeof(txfail_config);
1737
1738         err = wldev_iovar_setbuf(dev, "aibss_txfail_config", (void *) &txfail_config,
1739                 sizeof(aibss_txfail_config_t), smbuf, WLC_IOCTL_SMLEN, NULL);
1740         ANDROID_TRACE(("retry=%d, pid=%d, err=%d\n", retry, pid, err));
1741
1742         return ((err == 0)?total_len:err);
1743 }
1744
1745 static int wl_android_get_ibss_peer_info(struct net_device *dev, char *command,
1746         int total_len, bool bAll)
1747 {
1748         int error;
1749         int bytes_written = 0;
1750         void *buf = NULL;
1751         bss_peer_list_info_t peer_list_info;
1752         bss_peer_info_t *peer_info;
1753         int i;
1754         bool found = false;
1755         struct ether_addr mac_ea;
1756
1757         ANDROID_TRACE(("get ibss peer info(%s)\n", bAll?"true":"false"));
1758
1759         if (!bAll) {
1760                 if (sscanf (command, "GETIBSSPEERINFO %02x:%02x:%02x:%02x:%02x:%02x",
1761                         (unsigned int *)&mac_ea.octet[0], (unsigned int *)&mac_ea.octet[1],
1762                         (unsigned int *)&mac_ea.octet[2], (unsigned int *)&mac_ea.octet[3],
1763                         (unsigned int *)&mac_ea.octet[4], (unsigned int *)&mac_ea.octet[5]) != 6) {
1764                         ANDROID_TRACE(("invalid MAC address\n"));
1765                         return -1;
1766                 }
1767         }
1768
1769         if ((buf = kmalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL)) == NULL) {
1770                 ANDROID_ERROR(("kmalloc failed\n"));
1771                 return -1;
1772         }
1773
1774         error = wldev_iovar_getbuf(dev, "bss_peer_info", NULL, 0, buf, WLC_IOCTL_MAXLEN, NULL);
1775         if (unlikely(error)) {
1776                 ANDROID_ERROR(("could not get ibss peer info (%d)\n", error));
1777                 kfree(buf);
1778                 return -1;
1779         }
1780
1781         memcpy(&peer_list_info, buf, sizeof(peer_list_info));
1782         peer_list_info.version = htod16(peer_list_info.version);
1783         peer_list_info.bss_peer_info_len = htod16(peer_list_info.bss_peer_info_len);
1784         peer_list_info.count = htod32(peer_list_info.count);
1785
1786         ANDROID_TRACE(("ver:%d, len:%d, count:%d\n", peer_list_info.version,
1787                 peer_list_info.bss_peer_info_len, peer_list_info.count));
1788
1789         if (peer_list_info.count > 0) {
1790                 if (bAll)
1791                         bytes_written += sprintf(&command[bytes_written], "%u ",
1792                                 peer_list_info.count);
1793
1794                 peer_info = (bss_peer_info_t *) ((void *)buf + BSS_PEER_LIST_INFO_FIXED_LEN);
1795
1796
1797                 for (i = 0; i < peer_list_info.count; i++) {
1798
1799                         ANDROID_TRACE(("index:%d rssi:%d, tx:%u, rx:%u\n", i, peer_info->rssi,
1800                                 peer_info->tx_rate, peer_info->rx_rate));
1801
1802                         if (!bAll &&
1803                                 memcmp(&mac_ea, &peer_info->ea, sizeof(struct ether_addr)) == 0) {
1804                                 found = true;
1805                         }
1806
1807                         if (bAll || found) {
1808                                 bytes_written += sprintf(&command[bytes_written], MACF,
1809                                         ETHER_TO_MACF(peer_info->ea));
1810                                 bytes_written += sprintf(&command[bytes_written], " %u %d ",
1811                                         peer_info->tx_rate/1000, peer_info->rssi);
1812                         }
1813
1814                         if (found)
1815                                 break;
1816
1817                         peer_info = (bss_peer_info_t *)((void *)peer_info+sizeof(bss_peer_info_t));
1818                 }
1819         }
1820         else {
1821                 ANDROID_ERROR(("could not get ibss peer info : no item\n"));
1822         }
1823         bytes_written += sprintf(&command[bytes_written], "%s", "\0");
1824
1825         ANDROID_TRACE(("command(%u):%s\n", total_len, command));
1826         ANDROID_TRACE(("bytes_written:%d\n", bytes_written));
1827
1828         kfree(buf);
1829         return bytes_written;
1830 }
1831
1832 int wl_android_set_ibss_routetable(struct net_device *dev, char *command, int total_len)
1833 {
1834
1835         char *pcmd = command;
1836         char *str = NULL;
1837
1838         ibss_route_tbl_t *route_tbl = NULL;
1839         char *ioctl_buf = NULL;
1840         u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
1841         s32 err = BCME_OK;
1842         uint32 route_tbl_len;
1843         uint32 entries;
1844         char *endptr;
1845         uint32 i = 0;
1846         struct ipv4_addr  dipaddr;
1847         struct ether_addr ea;
1848
1849         route_tbl_len = sizeof(ibss_route_tbl_t) +
1850                 (MAX_IBSS_ROUTE_TBL_ENTRY - 1) * sizeof(ibss_route_entry_t);
1851         route_tbl = (ibss_route_tbl_t *)kzalloc(route_tbl_len, kflags);
1852         if (!route_tbl) {
1853                 ANDROID_ERROR(("Route TBL alloc failed\n"));
1854                 return -ENOMEM;
1855         }
1856         ioctl_buf = kzalloc(WLC_IOCTL_MEDLEN, GFP_KERNEL);
1857         if (!ioctl_buf) {
1858                 ANDROID_ERROR(("ioctl memory alloc failed\n"));
1859                 if (route_tbl) {
1860                         kfree(route_tbl);
1861                 }
1862                 return -ENOMEM;
1863         }
1864         memset(ioctl_buf, 0, WLC_IOCTL_MEDLEN);
1865
1866         /* drop command */
1867         str = bcmstrtok(&pcmd, " ", NULL);
1868
1869         /* get count */
1870         str = bcmstrtok(&pcmd, " ",  NULL);
1871         if (!str) {
1872                 ANDROID_ERROR(("Invalid number parameter %s\n", str));
1873                 err = -EINVAL;
1874                 goto exit;
1875         }
1876         entries = bcm_strtoul(str, &endptr, 0);
1877         if (*endptr != '\0') {
1878                 ANDROID_ERROR(("Invalid number parameter %s\n", str));
1879                 err = -EINVAL;
1880                 goto exit;
1881         }
1882         ANDROID_INFO(("Routing table count:%d\n", entries));
1883         route_tbl->num_entry = entries;
1884
1885         for (i = 0; i < entries; i++) {
1886                 str = bcmstrtok(&pcmd, " ", NULL);
1887                 if (!str || !bcm_atoipv4(str, &dipaddr)) {
1888                         ANDROID_ERROR(("Invalid ip string %s\n", str));
1889                         err = -EINVAL;
1890                         goto exit;
1891                 }
1892
1893
1894                 str = bcmstrtok(&pcmd, " ", NULL);
1895                 if (!str || !bcm_ether_atoe(str, &ea)) {
1896                         ANDROID_ERROR(("Invalid ethernet string %s\n", str));
1897                         err = -EINVAL;
1898                         goto exit;
1899                 }
1900                 bcopy(&dipaddr, &route_tbl->route_entry[i].ipv4_addr, IPV4_ADDR_LEN);
1901                 bcopy(&ea, &route_tbl->route_entry[i].nexthop, ETHER_ADDR_LEN);
1902         }
1903
1904         route_tbl_len = sizeof(ibss_route_tbl_t) +
1905                 ((!entries?0:(entries - 1)) * sizeof(ibss_route_entry_t));
1906         err = wldev_iovar_setbuf(dev, "ibss_route_tbl",
1907                 route_tbl, route_tbl_len, ioctl_buf, WLC_IOCTL_MEDLEN, NULL);
1908         if (err != BCME_OK) {
1909                 ANDROID_ERROR(("Fail to set iovar %d\n", err));
1910                 err = -EINVAL;
1911         }
1912
1913 exit:
1914         if (route_tbl)
1915                 kfree(route_tbl);
1916         if (ioctl_buf)
1917                 kfree(ioctl_buf);
1918         return err;
1919
1920 }
1921
1922 int
1923 wl_android_set_ibss_ampdu(struct net_device *dev, char *command, int total_len)
1924 {
1925         char *pcmd = command;
1926         char *str = NULL, *endptr = NULL;
1927         struct ampdu_aggr aggr;
1928         char smbuf[WLC_IOCTL_SMLEN];
1929         int idx;
1930         int err = 0;
1931         int wme_AC2PRIO[AC_COUNT][2] = {
1932                 {PRIO_8021D_VO, PRIO_8021D_NC},         /* AC_VO - 3 */
1933                 {PRIO_8021D_CL, PRIO_8021D_VI},         /* AC_VI - 2 */
1934                 {PRIO_8021D_BK, PRIO_8021D_NONE},       /* AC_BK - 1 */
1935                 {PRIO_8021D_BE, PRIO_8021D_EE}};        /* AC_BE - 0 */
1936
1937         ANDROID_TRACE(("set ibss ampdu:%s\n", command));
1938
1939         memset(&aggr, 0, sizeof(aggr));
1940         /* Cofigure all priorities */
1941         aggr.conf_TID_bmap = NBITMASK(NUMPRIO);
1942
1943         /* acquire parameters */
1944         /* drop command */
1945         str = bcmstrtok(&pcmd, " ", NULL);
1946
1947         for (idx = 0; idx < AC_COUNT; idx++) {
1948                 bool on;
1949                 str = bcmstrtok(&pcmd, " ", NULL);
1950                 if (!str) {
1951                         ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
1952                         return -EINVAL;
1953                 }
1954                 on = bcm_strtoul(str, &endptr, 0) ? TRUE : FALSE;
1955                 if (*endptr != '\0') {
1956                         ANDROID_ERROR(("Invalid number format %s\n", str));
1957                         return -EINVAL;
1958                 }
1959                 if (on) {
1960                         setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][0]);
1961                         setbit(&aggr.enab_TID_bmap, wme_AC2PRIO[idx][1]);
1962                 }
1963         }
1964
1965         err = wldev_iovar_setbuf(dev, "ampdu_txaggr", (void *)&aggr,
1966         sizeof(aggr), smbuf, WLC_IOCTL_SMLEN, NULL);
1967
1968         return ((err == 0) ? total_len : err);
1969 }
1970
1971 int wl_android_set_ibss_antenna(struct net_device *dev, char *command, int total_len)
1972 {
1973         char *pcmd = command;
1974         char *str = NULL;
1975         int txchain, rxchain;
1976         int err = 0;
1977
1978         ANDROID_TRACE(("set ibss antenna:%s\n", command));
1979
1980         /* acquire parameters */
1981         /* drop command */
1982         str = bcmstrtok(&pcmd, " ", NULL);
1983
1984         /* TX chain */
1985         str = bcmstrtok(&pcmd, " ", NULL);
1986         if (!str) {
1987                 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
1988                 return -EINVAL;
1989         }
1990         txchain = bcm_atoi(str);
1991
1992         /* RX chain */
1993         str = bcmstrtok(&pcmd, " ", NULL);
1994         if (!str) {
1995                 ANDROID_ERROR(("Invalid parameter : %s\n", pcmd));
1996                 return -EINVAL;
1997         }
1998         rxchain = bcm_atoi(str);
1999
2000         err = wldev_iovar_setint(dev, "txchain", txchain);
2001         if (err != 0)
2002                 return err;
2003         err = wldev_iovar_setint(dev, "rxchain", rxchain);
2004         return ((err == 0)?total_len:err);
2005 }
2006 #endif /* WLAIBSS */
2007
2008 int wl_keep_alive_set(struct net_device *dev, char* extra, int total_len)
2009 {
2010         char                            buf[256];
2011         const char                      *str;
2012         wl_mkeep_alive_pkt_t    mkeep_alive_pkt;
2013         wl_mkeep_alive_pkt_t    *mkeep_alive_pktp;
2014         int                                     buf_len;
2015         int                                     str_len;
2016         int res                                 = -1;
2017         uint period_msec = 0;
2018
2019         if (extra == NULL)
2020         {
2021                  ANDROID_ERROR(("%s: extra is NULL\n", __FUNCTION__));
2022                  return -1;
2023         }
2024         if (sscanf(extra, "%d", &period_msec) != 1)
2025         {
2026                  ANDROID_ERROR(("%s: sscanf error. check period_msec value\n", __FUNCTION__));
2027                  return -EINVAL;
2028         }
2029         ANDROID_ERROR(("%s: period_msec is %d\n", __FUNCTION__, period_msec));
2030
2031         memset(&mkeep_alive_pkt, 0, sizeof(wl_mkeep_alive_pkt_t));
2032
2033         str = "mkeep_alive";
2034         str_len = strlen(str);
2035         strncpy(buf, str, str_len);
2036         buf[ str_len ] = '\0';
2037         mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
2038         mkeep_alive_pkt.period_msec = period_msec;
2039         buf_len = str_len + 1;
2040         mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
2041         mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
2042
2043         /* Setup keep alive zero for null packet generation */
2044         mkeep_alive_pkt.keep_alive_id = 0;
2045         mkeep_alive_pkt.len_bytes = 0;
2046         buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
2047         /* Keep-alive attributes are set in local       variable (mkeep_alive_pkt), and
2048          * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
2049          * guarantee that the buffer is properly aligned.
2050          */
2051         memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
2052
2053         if ((res = wldev_ioctl(dev, WLC_SET_VAR, buf, buf_len, TRUE)) < 0)
2054         {
2055                 ANDROID_ERROR(("%s:keep_alive set failed. res[%d]\n", __FUNCTION__, res));
2056         }
2057         else
2058         {
2059                 ANDROID_ERROR(("%s:keep_alive set ok. res[%d]\n", __FUNCTION__, res));
2060         }
2061
2062         return res;
2063 }
2064
2065
2066 static const char *
2067 get_string_by_separator(char *result, int result_len, const char *src, char separator)
2068 {
2069         char *end = result + result_len - 1;
2070         while ((result != end) && (*src != separator) && (*src)) {
2071                 *result++ = *src++;
2072         }
2073         *result = 0;
2074         if (*src == separator)
2075                 ++src;
2076         return src;
2077 }
2078
2079 int
2080 wl_android_set_roam_offload_bssid_list(struct net_device *dev, const char *cmd)
2081 {
2082         char sbuf[32];
2083         int i, cnt, size, err, ioctl_buf_len;
2084         roamoffl_bssid_list_t *bssid_list;
2085         const char *str = cmd;
2086         char *ioctl_buf;
2087
2088         str = get_string_by_separator(sbuf, 32, str, ',');
2089         cnt = bcm_atoi(sbuf);
2090         cnt = MIN(cnt, MAX_ROAMOFFL_BSSID_NUM);
2091         size = sizeof(int) + sizeof(struct ether_addr) * cnt;
2092         ANDROID_ERROR(("ROAM OFFLOAD BSSID LIST %d BSSIDs, size %d\n", cnt, size));
2093         bssid_list = kmalloc(size, GFP_KERNEL);
2094         if (bssid_list == NULL) {
2095                 ANDROID_ERROR(("%s: memory alloc for bssid list(%d) failed\n",
2096                         __FUNCTION__, size));
2097                 return -ENOMEM;
2098         }
2099         ioctl_buf_len = size + 64;
2100         ioctl_buf = kmalloc(ioctl_buf_len, GFP_KERNEL);
2101         if (ioctl_buf == NULL) {
2102                 ANDROID_ERROR(("%s: memory alloc for ioctl_buf(%d) failed\n",
2103                         __FUNCTION__, ioctl_buf_len));
2104                 kfree(bssid_list);
2105                 return -ENOMEM;
2106         }
2107
2108         for (i = 0; i < cnt; i++) {
2109                 str = get_string_by_separator(sbuf, 32, str, ',');
2110                 if (bcm_ether_atoe(sbuf, &bssid_list->bssid[i]) == 0) {
2111                         ANDROID_ERROR(("%s: Invalid station MAC Address!!!\n", __FUNCTION__));
2112                         kfree(bssid_list);
2113                         kfree(ioctl_buf);
2114                         return -1;
2115                 }
2116         }
2117
2118         bssid_list->cnt = cnt;
2119         err = wldev_iovar_setbuf(dev, "roamoffl_bssid_list",
2120                 bssid_list, size, ioctl_buf, ioctl_buf_len, NULL);
2121         kfree(bssid_list);
2122         kfree(ioctl_buf);
2123
2124         return err;
2125 }
2126
2127 #ifdef P2PRESP_WFDIE_SRC
2128 static int wl_android_get_wfdie_resp(struct net_device *dev, char *command, int total_len)
2129 {
2130         int error = 0;
2131         int bytes_written = 0;
2132         int only_resp_wfdsrc = 0;
2133
2134         error = wldev_iovar_getint(dev, "p2p_only_resp_wfdsrc", &only_resp_wfdsrc);
2135         if (error) {
2136                 ANDROID_ERROR(("%s: Failed to get the mode for only_resp_wfdsrc, error = %d\n",
2137                         __FUNCTION__, error));
2138                 return -1;
2139         }
2140
2141         bytes_written = snprintf(command, total_len, "%s %d",
2142                 CMD_P2P_GET_WFDIE_RESP, only_resp_wfdsrc);
2143
2144         return bytes_written;
2145 }
2146
2147 static int wl_android_set_wfdie_resp(struct net_device *dev, int only_resp_wfdsrc)
2148 {
2149         int error = 0;
2150
2151         error = wldev_iovar_setint(dev, "p2p_only_resp_wfdsrc", only_resp_wfdsrc);
2152         if (error) {
2153                 ANDROID_ERROR(("%s: Failed to set only_resp_wfdsrc %d, error = %d\n",
2154                         __FUNCTION__, only_resp_wfdsrc, error));
2155                 return -1;
2156         }
2157
2158         return 0;
2159 }
2160 #endif /* P2PRESP_WFDIE_SRC */
2161
2162 static int wl_android_get_link_status(struct net_device *dev, char *command,
2163         int total_len)
2164 {
2165         int bytes_written, error, result = 0, single_stream, stf = -1, i, nss = 0, mcs_map;
2166         uint32 rspec;
2167         uint encode, rate, txexp;
2168         struct wl_bss_info *bi;
2169         int datalen = sizeof(uint32) + sizeof(wl_bss_info_t);
2170         char buf[datalen];
2171
2172         /* get BSS information */
2173         *(u32 *) buf = htod32(datalen);
2174         error = wldev_ioctl(dev, WLC_GET_BSS_INFO, (void *)buf, datalen, false);
2175         if (unlikely(error)) {
2176                 ANDROID_ERROR(("Could not get bss info %d\n", error));
2177                 return -1;
2178         }
2179
2180         bi = (struct wl_bss_info *) (buf + sizeof(uint32));
2181
2182         for (i = 0; i < ETHER_ADDR_LEN; i++) {
2183                 if (bi->BSSID.octet[i] > 0) {
2184                         break;
2185                 }
2186         }
2187
2188         if (i == ETHER_ADDR_LEN) {
2189                 ANDROID_TRACE(("No BSSID\n"));
2190                 return -1;
2191         }
2192
2193         /* check VHT capability at beacon */
2194         if (bi->vht_cap) {
2195                 if (CHSPEC_IS5G(bi->chanspec)) {
2196                         result |= WL_ANDROID_LINK_AP_VHT_SUPPORT;
2197                 }
2198         }
2199
2200         /* get a rspec (radio spectrum) rate */
2201         error = wldev_iovar_getint(dev, "nrate", &rspec);
2202         if (unlikely(error) || rspec == 0) {
2203                 ANDROID_ERROR(("get link status error (%d)\n", error));
2204                 return -1;
2205         }
2206
2207         encode = (rspec & WL_RSPEC_ENCODING_MASK);
2208         rate = (rspec & WL_RSPEC_RATE_MASK);
2209         txexp = (rspec & WL_RSPEC_TXEXP_MASK) >> WL_RSPEC_TXEXP_SHIFT;
2210
2211         switch (encode) {
2212         case WL_RSPEC_ENCODE_HT:
2213                 /* check Rx MCS Map for HT */
2214                 for (i = 0; i < MAX_STREAMS_SUPPORTED; i++) {
2215                         int8 bitmap = 0xFF;
2216                         if (i == MAX_STREAMS_SUPPORTED-1) {
2217                                 bitmap = 0x7F;
2218                         }
2219                         if (bi->basic_mcs[i] & bitmap) {
2220                                 nss++;
2221                         }
2222                 }
2223                 break;
2224         case WL_RSPEC_ENCODE_VHT:
2225                 /* check Rx MCS Map for VHT */
2226                 for (i = 1; i <= VHT_CAP_MCS_MAP_NSS_MAX; i++) {
2227                         mcs_map = VHT_MCS_MAP_GET_MCS_PER_SS(i, dtoh16(bi->vht_rxmcsmap));
2228                         if (mcs_map != VHT_CAP_MCS_MAP_NONE) {
2229                                 nss++;
2230                         }
2231                 }
2232                 break;
2233         }
2234
2235         /* check MIMO capability with nss in beacon */
2236         if (nss > 1) {
2237                 result |= WL_ANDROID_LINK_AP_MIMO_SUPPORT;
2238         }
2239
2240         single_stream = (encode == WL_RSPEC_ENCODE_RATE) ||
2241                 ((encode == WL_RSPEC_ENCODE_HT) && rate < 8) ||
2242                 ((encode == WL_RSPEC_ENCODE_VHT) &&
2243                 ((rspec & WL_RSPEC_VHT_NSS_MASK) >> WL_RSPEC_VHT_NSS_SHIFT) == 1);
2244
2245         if (txexp == 0) {
2246                 if ((rspec & WL_RSPEC_STBC) && single_stream) {
2247                         stf = OLD_NRATE_STF_STBC;
2248                 } else {
2249                         stf = (single_stream) ? OLD_NRATE_STF_SISO : OLD_NRATE_STF_SDM;
2250                 }
2251         } else if (txexp == 1 && single_stream) {
2252                 stf = OLD_NRATE_STF_CDD;
2253         }
2254
2255         /* check 11ac (VHT) */
2256         if (encode == WL_RSPEC_ENCODE_VHT) {
2257                 if (CHSPEC_IS5G(bi->chanspec)) {
2258                         result |= WL_ANDROID_LINK_VHT;
2259                 }
2260         }
2261
2262         /* check MIMO */
2263         if (result & WL_ANDROID_LINK_AP_MIMO_SUPPORT) {
2264                 switch (stf) {
2265                 case OLD_NRATE_STF_SISO:
2266                         break;
2267                 case OLD_NRATE_STF_CDD:
2268                 case OLD_NRATE_STF_STBC:
2269                         result |= WL_ANDROID_LINK_MIMO;
2270                         break;
2271                 case OLD_NRATE_STF_SDM:
2272                         if (!single_stream) {
2273                                 result |= WL_ANDROID_LINK_MIMO;
2274                         }
2275                         break;
2276                 }
2277         }
2278
2279         ANDROID_TRACE(("%s:result=%d, stf=%d, single_stream=%d, mcs map=%d\n",
2280                 __FUNCTION__, result, stf, single_stream, nss));
2281
2282         bytes_written = sprintf(command, "%s %d", CMD_GET_LINK_STATUS, result);
2283
2284         return bytes_written;
2285 }
2286
2287 int
2288 wl_android_get_channel(
2289 struct net_device *dev, char* command, int total_len)
2290 {
2291         int ret;
2292         channel_info_t ci;
2293         int bytes_written = 0;
2294
2295         if (!(ret = wldev_ioctl(dev, WLC_GET_CHANNEL, &ci, sizeof(channel_info_t), FALSE))) {
2296                 ANDROID_TRACE(("hw_channel %d\n", ci.hw_channel));
2297                 ANDROID_TRACE(("target_channel %d\n", ci.target_channel));
2298                 ANDROID_TRACE(("scan_channel %d\n", ci.scan_channel));
2299                 bytes_written = snprintf(command, sizeof(channel_info_t)+2, "channel %d", ci.hw_channel);
2300                 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
2301         }
2302
2303         return bytes_written;
2304 }
2305
2306 int
2307 wl_android_set_roam_trigger(
2308 struct net_device *dev, char* command, int total_len)
2309 {
2310         int ret = 0;
2311         int roam_trigger[2];
2312
2313         sscanf(command, "%*s %10d", &roam_trigger[0]);
2314         roam_trigger[1] = WLC_BAND_ALL;
2315         
2316         ret = wldev_ioctl(dev, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 1);
2317         if (ret)
2318                 ANDROID_ERROR(("WLC_SET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
2319
2320         return ret;
2321 }
2322
2323 int
2324 wl_android_get_roam_trigger(
2325 struct net_device *dev, char *command, int total_len)
2326 {
2327         int ret;
2328         int bytes_written;
2329         int roam_trigger[2] = {0, 0};
2330         int trigger[2]= {0, 0};
2331         
2332         roam_trigger[1] = WLC_BAND_2G;
2333         ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
2334         if (!ret)
2335                 trigger[0] = roam_trigger[0];
2336         else
2337                 ANDROID_ERROR(("2G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
2338
2339         roam_trigger[1] = WLC_BAND_5G;
2340         ret = wldev_ioctl(dev, WLC_GET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), 0);
2341         if (!ret)
2342                 trigger[1] = roam_trigger[0];
2343         else
2344                 ANDROID_ERROR(("5G WLC_GET_ROAM_TRIGGER ERROR %d ret=%d\n", roam_trigger[0], ret));
2345         
2346         ANDROID_TRACE(("roam_trigger %d %d\n", trigger[0], trigger[1]));
2347         bytes_written = snprintf(command, total_len, "%d %d", trigger[0], trigger[1]);
2348
2349         return bytes_written;
2350 }
2351
2352 s32
2353 wl_android_get_keep_alive(struct net_device *dev, char *command, int total_len) {
2354
2355         wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
2356         int bytes_written = -1;
2357         int res = -1, len, i = 0;
2358         char* str = "mkeep_alive";
2359
2360         ANDROID_TRACE(("%s: command = %s\n", __FUNCTION__, command));
2361
2362         len = WLC_IOCTL_MEDLEN;
2363         mkeep_alive_pktp = kmalloc(len, GFP_KERNEL);
2364         memset(mkeep_alive_pktp, 0, len);
2365         strcpy((char*)mkeep_alive_pktp, str);
2366
2367         if ((res = wldev_ioctl(dev, WLC_GET_VAR, mkeep_alive_pktp, len, FALSE))<0) {
2368                 ANDROID_ERROR(("%s: GET mkeep_alive ERROR %d\n", __FUNCTION__, res));
2369                 goto exit;
2370         } else {
2371                 printf("Id            :%d\n"
2372                            "Period (msec) :%d\n"
2373                            "Length        :%d\n"
2374                            "Packet        :0x",
2375                            mkeep_alive_pktp->keep_alive_id,
2376                            dtoh32(mkeep_alive_pktp->period_msec),
2377                            dtoh16(mkeep_alive_pktp->len_bytes));
2378                 for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
2379                         printf("%02x", mkeep_alive_pktp->data[i]);
2380                 }
2381                 printf("\n");
2382         }
2383         bytes_written = snprintf(command, total_len, "mkeep_alive_period_msec %d ", dtoh32(mkeep_alive_pktp->period_msec));
2384         bytes_written += snprintf(command+bytes_written, total_len, "0x");
2385         for (i=0; i<mkeep_alive_pktp->len_bytes; i++) {
2386                 bytes_written += snprintf(command+bytes_written, total_len, "%x", mkeep_alive_pktp->data[i]);
2387         }
2388         ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
2389
2390 exit:
2391         kfree(mkeep_alive_pktp);
2392         return bytes_written;
2393 }
2394
2395 int
2396 wl_android_set_pm(struct net_device *dev,char *command, int total_len)
2397 {
2398         int pm, ret = -1;
2399
2400         ANDROID_TRACE(("%s: cmd %s\n", __FUNCTION__, command));
2401
2402         sscanf(command, "%*s %d", &pm);
2403
2404         ret = wldev_ioctl(dev, WLC_SET_PM, &pm, sizeof(pm), FALSE);
2405         if (ret)
2406                 ANDROID_ERROR(("WLC_SET_PM ERROR %d ret=%d\n", pm, ret));
2407
2408         return ret;
2409 }
2410
2411 int
2412 wl_android_get_pm(struct net_device *dev,char *command, int total_len)
2413 {
2414
2415         int ret = 0;
2416         int pm_local;
2417         char *pm;
2418         int bytes_written=-1;
2419
2420         ret = wldev_ioctl(dev, WLC_GET_PM, &pm_local, sizeof(pm_local),FALSE);
2421         if (!ret) {
2422                 ANDROID_TRACE(("%s: PM = %d\n", __func__, pm_local));
2423                 if (pm_local == PM_OFF)
2424                         pm = "PM_OFF";
2425                 else if(pm_local == PM_MAX)
2426                         pm = "PM_MAX";
2427                 else if(pm_local == PM_FAST)
2428                         pm = "PM_FAST";
2429                 else {
2430                         pm_local = 0;
2431                         pm = "Invalid";
2432                 }
2433                 bytes_written = snprintf(command, total_len, "PM %s", pm);
2434                 ANDROID_TRACE(("%s: command result is %s\n", __FUNCTION__, command));
2435         }
2436         return bytes_written;
2437 }
2438
2439 static int
2440 wl_android_set_monitor(struct net_device *dev, char *command, int total_len)
2441 {
2442         int val;
2443         int ret = 0;
2444         int bytes_written;
2445
2446         sscanf(command, "%*s %d", &val);
2447         bytes_written = wldev_ioctl(dev, WLC_SET_MONITOR, &val, sizeof(int), 1);
2448         if (bytes_written)
2449                 ANDROID_ERROR(("WLC_SET_MONITOR ERROR %d ret=%d\n", val, ret));
2450         return bytes_written;
2451 }
2452
2453 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
2454 {
2455 #define PRIVATE_COMMAND_MAX_LEN 8192
2456         int ret = 0;
2457         char *command = NULL;
2458         int bytes_written = 0;
2459         android_wifi_priv_cmd priv_cmd;
2460
2461         net_os_wake_lock(net);
2462
2463         if (!ifr->ifr_data) {
2464                 ret = -EINVAL;
2465                 goto exit;
2466         }
2467
2468 #ifdef CONFIG_COMPAT
2469         if (is_compat_task()) {
2470                 compat_android_wifi_priv_cmd compat_priv_cmd;
2471                 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data,
2472                         sizeof(compat_android_wifi_priv_cmd))) {
2473                         ret = -EFAULT;
2474                         goto exit;
2475
2476                 }
2477                 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
2478                 priv_cmd.used_len = compat_priv_cmd.used_len;
2479                 priv_cmd.total_len = compat_priv_cmd.total_len;
2480         } else
2481 #endif /* CONFIG_COMPAT */
2482         {
2483                 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
2484                         ret = -EFAULT;
2485                         goto exit;
2486                 }
2487         }
2488         if ((priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN) || (priv_cmd.total_len < 0)) {
2489                 ANDROID_ERROR(("%s: too long priavte command\n", __FUNCTION__));
2490                 ret = -EINVAL;
2491                 goto exit;
2492         }
2493         command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL);
2494         if (!command)
2495         {
2496                 ANDROID_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
2497                 ret = -ENOMEM;
2498                 goto exit;
2499         }
2500         if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
2501                 ret = -EFAULT;
2502                 goto exit;
2503         }
2504         command[priv_cmd.total_len] = '\0';
2505
2506         ANDROID_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
2507
2508         if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
2509                 ANDROID_INFO(("%s, Received regular START command\n", __FUNCTION__));
2510                 bytes_written = wl_android_wifi_on(net);
2511         }
2512         else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
2513                 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
2514         }
2515
2516         if (!g_wifi_on) {
2517                 ANDROID_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
2518                         __FUNCTION__, command, ifr->ifr_name));
2519                 ret = 0;
2520                 goto exit;
2521         }
2522
2523         if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
2524                 bytes_written = wl_android_wifi_off(net);
2525         }
2526         else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
2527                 /* TBD: SCAN-ACTIVE */
2528         }
2529         else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
2530                 /* TBD: SCAN-PASSIVE */
2531         }
2532         else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
2533                 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
2534         }
2535         else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
2536                 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
2537         }
2538 #ifdef PKT_FILTER_SUPPORT
2539         else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
2540                 bytes_written = net_os_enable_packet_filter(net, 1);
2541         }
2542         else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
2543                 bytes_written = net_os_enable_packet_filter(net, 0);
2544         }
2545         else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
2546                 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
2547                 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
2548         }
2549         else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
2550                 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
2551                 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
2552         }
2553 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
2554         else if (strnicmp(command, CMD_PKT_FILTER_MODE, strlen(CMD_PKT_FILTER_MODE)) == 0) {
2555                 dhd_set_packet_filter_mode(net, &command[strlen(CMD_PKT_FILTER_MODE) + 1]);
2556         } else if (strnicmp(command, CMD_PKT_FILTER_PORTS, strlen(CMD_PKT_FILTER_PORTS)) == 0) {
2557                 bytes_written = dhd_set_packet_filter_ports(net,
2558                         &command[strlen(CMD_PKT_FILTER_PORTS) + 1]);
2559                 ret = bytes_written;
2560         }
2561 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
2562 #endif /* PKT_FILTER_SUPPORT */
2563         else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
2564                 /* TBD: BTCOEXSCAN-START */
2565         }
2566         else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
2567                 /* TBD: BTCOEXSCAN-STOP */
2568         }
2569         else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
2570 #ifdef WL_CFG80211
2571                 void *dhdp = wl_cfg80211_get_dhdp();
2572                 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, dhdp, command);
2573 #else
2574 #ifdef PKT_FILTER_SUPPORT
2575                 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
2576
2577                 if (mode == 1)
2578                         net_os_enable_packet_filter(net, 0); /* DHCP starts */
2579                 else
2580                         net_os_enable_packet_filter(net, 1); /* DHCP ends */
2581 #endif /* PKT_FILTER_SUPPORT */
2582 #endif /* WL_CFG80211 */
2583         }
2584         else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
2585                 bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
2586         }
2587         else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
2588                 bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
2589         }
2590         else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
2591                 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
2592 #ifdef WL_HOST_BAND_MGMT
2593                 s32 ret = 0;
2594                 if ((ret = wl_cfg80211_set_band(net, band)) < 0) {
2595                         if (ret == BCME_UNSUPPORTED) {
2596                                 /* If roam_var is unsupported, fallback to the original method */
2597                                 ANDROID_ERROR(("WL_HOST_BAND_MGMT defined, "
2598                                         "but roam_band iovar unsupported in the firmware\n"));
2599                         } else {
2600                                 bytes_written = -1;
2601                                 goto exit;
2602                         }
2603                 }
2604                 if ((band == WLC_BAND_AUTO) || (ret == BCME_UNSUPPORTED))
2605                         bytes_written = wldev_set_band(net, band);
2606 #else
2607                 bytes_written = wldev_set_band(net, band);
2608 #endif /* WL_HOST_BAND_MGMT */
2609         }
2610         else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
2611                 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
2612         }
2613 #ifdef WL_CFG80211
2614         /* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
2615         else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
2616                 char *country_code = command + strlen(CMD_COUNTRY) + 1;
2617 #ifdef CUSTOMER_HW5
2618                 /* Customer_hw5 want to keep connections */
2619                 bytes_written = wldev_set_country(net, country_code, true, false);
2620 #else
2621                 bytes_written = wldev_set_country(net, country_code, true, true);
2622 #endif
2623         }
2624 #endif /* WL_CFG80211 */
2625
2626
2627 #ifdef PNO_SUPPORT
2628         else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
2629                 bytes_written = dhd_dev_pno_stop_for_ssid(net);
2630         }
2631 #ifndef WL_SCHED_SCAN
2632         else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
2633                 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
2634         }
2635 #endif /* !WL_SCHED_SCAN */
2636         else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
2637                 int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
2638                 bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
2639         }
2640         else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
2641                 bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
2642         }
2643 #endif /* PNO_SUPPORT */
2644         else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
2645                 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
2646         }
2647         else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
2648                 int skip = strlen(CMD_P2P_SET_NOA) + 1;
2649                 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
2650                         priv_cmd.total_len - skip);
2651         }
2652 #ifdef WL_SDO
2653         else if (strnicmp(command, CMD_P2P_SD_OFFLOAD, strlen(CMD_P2P_SD_OFFLOAD)) == 0) {
2654                 u8 *buf = command;
2655                 u8 *cmd_id = NULL;
2656                 int len;
2657
2658                 cmd_id = strsep((char **)&buf, " ");
2659                 /* if buf == NULL, means no arg */
2660                 if (buf == NULL)
2661                         len = 0;
2662                 else
2663                         len = strlen(buf);
2664
2665                 bytes_written = wl_cfg80211_sd_offload(net, cmd_id, buf, len);
2666         }
2667 #endif /* WL_SDO */
2668 #ifdef WL_NAN
2669         else if (strnicmp(command, CMD_NAN, strlen(CMD_NAN)) == 0) {
2670                 bytes_written = wl_cfg80211_nan_cmd_handler(net, command,
2671                         priv_cmd.total_len);
2672         }
2673 #endif /* WL_NAN */
2674 #if !defined WL_ENABLE_P2P_IF
2675         else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
2676                 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
2677         }
2678 #endif /* WL_ENABLE_P2P_IF */
2679         else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
2680                 int skip = strlen(CMD_P2P_SET_PS) + 1;
2681                 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
2682                         priv_cmd.total_len - skip);
2683         }
2684 #ifdef WL_CFG80211
2685         else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
2686                 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
2687                 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
2688                 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
2689                         priv_cmd.total_len - skip, *(command + skip - 2) - '0');
2690         }
2691 #ifdef WLFBT
2692         else if (strnicmp(command, CMD_GET_FTKEY, strlen(CMD_GET_FTKEY)) == 0) {
2693                 wl_cfg80211_get_fbt_key(command);
2694                 bytes_written = FBT_KEYLEN;
2695         }
2696 #endif /* WLFBT */
2697 #endif /* WL_CFG80211 */
2698         else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0)
2699                 bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
2700         else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0)
2701                 bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len);
2702 #ifdef BCMCCX
2703         else if (strnicmp(command, CMD_GETCCKM_RN, strlen(CMD_GETCCKM_RN)) == 0) {
2704                 bytes_written = wl_android_get_cckm_rn(net, command);
2705         }
2706         else if (strnicmp(command, CMD_SETCCKM_KRK, strlen(CMD_SETCCKM_KRK)) == 0) {
2707                 bytes_written = wl_android_set_cckm_krk(net, command);
2708         }
2709         else if (strnicmp(command, CMD_GET_ASSOC_RES_IES, strlen(CMD_GET_ASSOC_RES_IES)) == 0) {
2710                 bytes_written = wl_android_get_assoc_res_ies(net, command);
2711         }
2712 #endif /* BCMCCX */
2713 #if defined(WL_SUPPORT_AUTO_CHANNEL)
2714         else if (strnicmp(command, CMD_GET_BEST_CHANNELS,
2715                 strlen(CMD_GET_BEST_CHANNELS)) == 0) {
2716                 bytes_written = wl_cfg80211_get_best_channels(net, command,
2717                         priv_cmd.total_len);
2718         }
2719 #endif /* WL_SUPPORT_AUTO_CHANNEL */
2720         else if (strnicmp(command, CMD_HAPD_MAC_FILTER, strlen(CMD_HAPD_MAC_FILTER)) == 0) {
2721                 int skip = strlen(CMD_HAPD_MAC_FILTER) + 1;
2722                 wl_android_set_mac_address_filter(net, (const char*)command+skip);
2723         }
2724         else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
2725                 bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
2726 #if defined(BCMFW_ROAM_ENABLE)
2727         else if (strnicmp(command, CMD_SET_ROAMPREF, strlen(CMD_SET_ROAMPREF)) == 0) {
2728                 bytes_written = wl_android_set_roampref(net, command, priv_cmd.total_len);
2729         }
2730 #endif /* BCMFW_ROAM_ENABLE */
2731 #ifdef WL_CFG80211
2732         else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
2733                 bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
2734 #if defined(CUSTOM_PLATFORM_NV_TEGRA)
2735         else if (strnicmp(command, CMD_SETMIRACAST, strlen(CMD_SETMIRACAST)) == 0)
2736                 bytes_written = wldev_miracast_tuning(net, command, priv_cmd.total_len);
2737         else if (strnicmp(command, CMD_ASSOCRESPIE, strlen(CMD_ASSOCRESPIE)) == 0)
2738                 bytes_written = wldev_get_assoc_resp_ie(net, command, priv_cmd.total_len);
2739         else if (strnicmp(command, CMD_RXRATESTATS, strlen(CMD_RXRATESTATS)) == 0)
2740                 bytes_written = wldev_get_rx_rate_stats(net, command, priv_cmd.total_len);
2741 #endif /* defined(CUSTOM_PLATFORM_NV_TEGRA) */
2742         else if (strnicmp(command, CMD_SETIBSSBEACONOUIDATA, strlen(CMD_SETIBSSBEACONOUIDATA)) == 0)
2743                 bytes_written = wl_android_set_ibss_beacon_ouidata(net,
2744                 command, priv_cmd.total_len);
2745 #endif
2746 #ifdef WLAIBSS
2747         else if (strnicmp(command, CMD_SETIBSSTXFAILEVENT,
2748                 strlen(CMD_SETIBSSTXFAILEVENT)) == 0)
2749                 bytes_written = wl_android_set_ibss_txfail_event(net, command, priv_cmd.total_len);
2750         else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO_ALL,
2751                 strlen(CMD_GET_IBSS_PEER_INFO_ALL)) == 0)
2752                 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
2753                         TRUE);
2754         else if (strnicmp(command, CMD_GET_IBSS_PEER_INFO,
2755                 strlen(CMD_GET_IBSS_PEER_INFO)) == 0)
2756                 bytes_written = wl_android_get_ibss_peer_info(net, command, priv_cmd.total_len,
2757                         FALSE);
2758         else if (strnicmp(command, CMD_SETIBSSROUTETABLE,
2759                 strlen(CMD_SETIBSSROUTETABLE)) == 0)
2760                 bytes_written = wl_android_set_ibss_routetable(net, command,
2761                         priv_cmd.total_len);
2762         else if (strnicmp(command, CMD_SETIBSSAMPDU, strlen(CMD_SETIBSSAMPDU)) == 0)
2763                 bytes_written = wl_android_set_ibss_ampdu(net, command, priv_cmd.total_len);
2764         else if (strnicmp(command, CMD_SETIBSSANTENNAMODE, strlen(CMD_SETIBSSANTENNAMODE)) == 0)
2765                 bytes_written = wl_android_set_ibss_antenna(net, command, priv_cmd.total_len);
2766 #endif /* WLAIBSS */
2767         else if (strnicmp(command, CMD_KEEP_ALIVE, strlen(CMD_KEEP_ALIVE)) == 0) {
2768                 int skip = strlen(CMD_KEEP_ALIVE) + 1;
2769                 bytes_written = wl_keep_alive_set(net, command + skip, priv_cmd.total_len - skip);
2770         }
2771 #ifdef WL_CFG80211
2772         else if (strnicmp(command, CMD_ROAM_OFFLOAD, strlen(CMD_ROAM_OFFLOAD)) == 0) {
2773                 int enable = *(command + strlen(CMD_ROAM_OFFLOAD) + 1) - '0';
2774                 bytes_written = wl_cfg80211_enable_roam_offload(net, enable);
2775         }
2776         else if (strnicmp(command, CMD_ROAM_OFFLOAD_APLIST, strlen(CMD_ROAM_OFFLOAD_APLIST)) == 0) {
2777                 bytes_written = wl_android_set_roam_offload_bssid_list(net,
2778                         command + strlen(CMD_ROAM_OFFLOAD_APLIST) + 1);
2779         }
2780 #endif
2781 #ifdef P2PRESP_WFDIE_SRC
2782         else if (strnicmp(command, CMD_P2P_SET_WFDIE_RESP,
2783                 strlen(CMD_P2P_SET_WFDIE_RESP)) == 0) {
2784                 int mode = *(command + strlen(CMD_P2P_SET_WFDIE_RESP) + 1) - '0';
2785                 bytes_written = wl_android_set_wfdie_resp(net, mode);
2786         } else if (strnicmp(command, CMD_P2P_GET_WFDIE_RESP,
2787                 strlen(CMD_P2P_GET_WFDIE_RESP)) == 0) {
2788                 bytes_written = wl_android_get_wfdie_resp(net, command, priv_cmd.total_len);
2789         }
2790 #endif /* P2PRESP_WFDIE_SRC */
2791         else if (strnicmp(command, CMD_GET_LINK_STATUS, strlen(CMD_GET_LINK_STATUS)) == 0) {
2792                 bytes_written = wl_android_get_link_status(net, command, priv_cmd.total_len);
2793         }
2794 #ifdef CONNECTION_STATISTICS
2795         else if (strnicmp(command, CMD_GET_CONNECTION_STATS,
2796                 strlen(CMD_GET_CONNECTION_STATS)) == 0) {
2797                 bytes_written = wl_android_get_connection_stats(net, command,
2798                         priv_cmd.total_len);
2799         }
2800 #endif
2801         else if(strnicmp(command, CMD_GET_CHANNEL, strlen(CMD_GET_CHANNEL)) == 0) {
2802                 bytes_written = wl_android_get_channel(net, command, priv_cmd.total_len);
2803         }
2804         else if (strnicmp(command, CMD_SET_ROAM, strlen(CMD_SET_ROAM)) == 0) {
2805                 bytes_written = wl_android_set_roam_trigger(net, command, priv_cmd.total_len);
2806         }
2807         else if (strnicmp(command, CMD_GET_ROAM, strlen(CMD_GET_ROAM)) == 0) {
2808                 bytes_written = wl_android_get_roam_trigger(net, command, priv_cmd.total_len);
2809         }
2810         else if (strnicmp(command, CMD_GET_KEEP_ALIVE, strlen(CMD_GET_KEEP_ALIVE)) == 0) {
2811                 int skip = strlen(CMD_GET_KEEP_ALIVE) + 1;
2812                 bytes_written = wl_android_get_keep_alive(net, command+skip, priv_cmd.total_len-skip);
2813         }
2814         else if (strnicmp(command, CMD_GET_PM, strlen(CMD_GET_PM)) == 0) {
2815                 bytes_written = wl_android_get_pm(net, command, priv_cmd.total_len);
2816         }
2817         else if (strnicmp(command, CMD_SET_PM, strlen(CMD_SET_PM)) == 0) {
2818                 bytes_written = wl_android_set_pm(net, command, priv_cmd.total_len);
2819         }
2820         else if (strnicmp(command, CMD_MONITOR, strlen(CMD_MONITOR)) == 0) {
2821                 bytes_written = wl_android_set_monitor(net, command, priv_cmd.total_len);
2822         } else {
2823                 ANDROID_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
2824                 snprintf(command, 3, "OK");
2825                 bytes_written = strlen("OK");
2826         }
2827
2828         if (bytes_written >= 0) {
2829                 if ((bytes_written == 0) && (priv_cmd.total_len > 0))
2830                         command[0] = '\0';
2831                 if (bytes_written >= priv_cmd.total_len) {
2832                         ANDROID_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
2833                         bytes_written = priv_cmd.total_len;
2834                 } else {
2835                         bytes_written++;
2836                 }
2837                 priv_cmd.used_len = bytes_written;
2838                 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
2839                         ANDROID_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
2840                         ret = -EFAULT;
2841                 }
2842         }
2843         else {
2844                 ret = bytes_written;
2845         }
2846
2847 exit:
2848         net_os_wake_unlock(net);
2849         if (command) {
2850                 kfree(command);
2851         }
2852
2853         return ret;
2854 }
2855
2856 int wl_android_init(void)
2857 {
2858         int ret = 0;
2859
2860 #ifdef ENABLE_INSMOD_NO_FW_LOAD
2861         dhd_download_fw_on_driverload = FALSE;
2862 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
2863         if (!iface_name[0]) {
2864                 memset(iface_name, 0, IFNAMSIZ);
2865                 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
2866         }
2867
2868 #ifdef WL_GENL
2869         wl_genl_init();
2870 #endif
2871         wl_netlink_init();
2872
2873         return ret;
2874 }
2875
2876 int wl_android_exit(void)
2877 {
2878         int ret = 0;
2879         struct io_cfg *cur, *q;
2880
2881 #ifdef WL_GENL
2882         wl_genl_deinit();
2883 #endif /* WL_GENL */
2884         wl_netlink_deinit();
2885
2886         list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
2887                 list_del(&cur->list);
2888                 kfree(cur);
2889         }
2890
2891         return ret;
2892 }
2893
2894 void wl_android_post_init(void)
2895 {
2896
2897 #ifdef ENABLE_4335BT_WAR
2898         bcm_bt_unlock(lock_cookie_wifi);
2899         printk("%s: btlock released\n", __FUNCTION__);
2900 #endif /* ENABLE_4335BT_WAR */
2901
2902         if (!dhd_download_fw_on_driverload)
2903                 g_wifi_on = FALSE;
2904 }
2905
2906 #ifdef WL_GENL
2907 /* Generic Netlink Initializaiton */
2908 static int wl_genl_init(void)
2909 {
2910         int ret;
2911
2912         ANDROID_TRACE(("GEN Netlink Init\n\n"));
2913
2914 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
2915         /* register new family */
2916         ret = genl_register_family(&wl_genl_family);
2917         if (ret != 0)
2918                 goto failure;
2919
2920         /* register functions (commands) of the new family */
2921         ret = genl_register_ops(&wl_genl_family, &wl_genl_ops);
2922         if (ret != 0) {
2923                 ANDROID_ERROR(("register ops failed: %i\n", ret));
2924                 genl_unregister_family(&wl_genl_family);
2925                 goto failure;
2926         }
2927
2928         ret = genl_register_mc_group(&wl_genl_family, &wl_genl_mcast);
2929 #else
2930         ret = genl_register_family_with_ops_groups(&wl_genl_family, wl_genl_ops, wl_genl_mcast);
2931 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) */
2932         if (ret != 0) {
2933                 ANDROID_ERROR(("register mc_group failed: %i\n", ret));
2934 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
2935                 genl_unregister_ops(&wl_genl_family, &wl_genl_ops);
2936 #endif
2937                 genl_unregister_family(&wl_genl_family);
2938                 goto failure;
2939         }
2940
2941         return 0;
2942
2943 failure:
2944         ANDROID_ERROR(("Registering Netlink failed!!\n"));
2945         return -1;
2946 }
2947
2948 /* Generic netlink deinit */
2949 static int wl_genl_deinit(void)
2950 {
2951
2952 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
2953         if (genl_unregister_ops(&wl_genl_family, &wl_genl_ops) < 0)
2954                 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
2955 #endif
2956         if (genl_unregister_family(&wl_genl_family) < 0)
2957                 ANDROID_ERROR(("Unregister wl_genl_ops failed\n"));
2958
2959         return 0;
2960 }
2961
2962 s32 wl_event_to_bcm_event(u16 event_type)
2963 {
2964         u16 event = -1;
2965
2966         switch (event_type) {
2967                 case WLC_E_SERVICE_FOUND:
2968                         event = BCM_E_SVC_FOUND;
2969                         break;
2970                 case WLC_E_P2PO_ADD_DEVICE:
2971                         event = BCM_E_DEV_FOUND;
2972                         break;
2973                 case WLC_E_P2PO_DEL_DEVICE:
2974                         event = BCM_E_DEV_LOST;
2975                         break;
2976         /* Above events are supported from BCM Supp ver 47 Onwards */
2977 #ifdef BT_WIFI_HANDOVER
2978                 case WLC_E_BT_WIFI_HANDOVER_REQ:
2979                         event = BCM_E_DEV_BT_WIFI_HO_REQ;
2980                         break;
2981 #endif /* BT_WIFI_HANDOVER */
2982
2983                 default:
2984                         ANDROID_ERROR(("Event not supported\n"));
2985         }
2986
2987         return event;
2988 }
2989
2990 s32
2991 wl_genl_send_msg(
2992         struct net_device *ndev,
2993         u32 event_type,
2994         u8 *buf,
2995         u16 len,
2996         u8 *subhdr,
2997         u16 subhdr_len)
2998 {
2999         int ret = 0;
3000         struct sk_buff *skb = NULL;
3001         void *msg;
3002         u32 attr_type = 0;
3003         bcm_event_hdr_t *hdr = NULL;
3004         int mcast = 1; /* By default sent as mutlicast type */
3005         int pid = 0;
3006         u8 *ptr = NULL, *p = NULL;
3007         u32 tot_len = sizeof(bcm_event_hdr_t) + subhdr_len + len;
3008         u16 kflags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
3009
3010
3011         ANDROID_TRACE(("Enter \n"));
3012
3013         /* Decide between STRING event and Data event */
3014         if (event_type == 0)
3015                 attr_type = BCM_GENL_ATTR_STRING;
3016         else
3017                 attr_type = BCM_GENL_ATTR_MSG;
3018
3019         skb = genlmsg_new(NLMSG_GOODSIZE, kflags);
3020         if (skb == NULL) {
3021                 ret = -ENOMEM;
3022                 goto out;
3023         }
3024
3025         msg = genlmsg_put(skb, 0, 0, &wl_genl_family, 0, BCM_GENL_CMD_MSG);
3026         if (msg == NULL) {
3027                 ret = -ENOMEM;
3028                 goto out;
3029         }
3030
3031
3032         if (attr_type == BCM_GENL_ATTR_STRING) {
3033                 /* Add a BCM_GENL_MSG attribute. Since it is specified as a string.
3034                  * make sure it is null terminated
3035                  */
3036                 if (subhdr || subhdr_len) {
3037                         ANDROID_ERROR(("No sub hdr support for the ATTR STRING type \n"));
3038                         ret =  -EINVAL;
3039                         goto out;
3040                 }
3041
3042                 ret = nla_put_string(skb, BCM_GENL_ATTR_STRING, buf);
3043                 if (ret != 0) {
3044                         ANDROID_ERROR(("nla_put_string failed\n"));
3045                         goto out;
3046                 }
3047         } else {
3048                 /* ATTR_MSG */
3049
3050                 /* Create a single buffer for all */
3051                 p = ptr = kzalloc(tot_len, kflags);
3052                 if (!ptr) {
3053                         ret = -ENOMEM;
3054                         ANDROID_ERROR(("ENOMEM!!\n"));
3055                         goto out;
3056                 }
3057
3058                 /* Include the bcm event header */
3059                 hdr = (bcm_event_hdr_t *)ptr;
3060                 hdr->event_type = wl_event_to_bcm_event(event_type);
3061                 hdr->len = len + subhdr_len;
3062                 ptr += sizeof(bcm_event_hdr_t);
3063
3064                 /* Copy subhdr (if any) */
3065                 if (subhdr && subhdr_len) {
3066                         memcpy(ptr, subhdr, subhdr_len);
3067                         ptr += subhdr_len;
3068                 }
3069
3070                 /* Copy the data */
3071                 if (buf && len) {
3072                         memcpy(ptr, buf, len);
3073                 }
3074
3075                 ret = nla_put(skb, BCM_GENL_ATTR_MSG, tot_len, p);
3076                 if (ret != 0) {
3077                         ANDROID_ERROR(("nla_put_string failed\n"));
3078                         goto out;
3079                 }
3080         }
3081
3082         if (mcast) {
3083                 int err = 0;
3084                 /* finalize the message */
3085                 genlmsg_end(skb, msg);
3086                 /* NETLINK_CB(skb).dst_group = 1; */
3087
3088 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
3089                 if ((err = genlmsg_multicast(skb, 0, wl_genl_mcast.id, GFP_ATOMIC)) < 0)
3090 #else
3091                 if ((err = genlmsg_multicast(&wl_genl_family, skb, 0, 0, GFP_ATOMIC)) < 0)
3092 #endif
3093                         ANDROID_ERROR(("genlmsg_multicast for attr(%d) failed. Error:%d \n",
3094                                 attr_type, err));
3095                 else
3096                         ANDROID_TRACE(("Multicast msg sent successfully. attr_type:%d len:%d \n",
3097                                 attr_type, tot_len));
3098         } else {
3099                 NETLINK_CB(skb).dst_group = 0; /* Not in multicast group */
3100
3101                 /* finalize the message */
3102                 genlmsg_end(skb, msg);
3103
3104                 /* send the message back */
3105                 if (genlmsg_unicast(&init_net, skb, pid) < 0)
3106                         ANDROID_ERROR(("genlmsg_unicast failed\n"));
3107         }
3108
3109 out:
3110         if (p)
3111                 kfree(p);
3112         if (ret)
3113                 nlmsg_free(skb);
3114
3115         return ret;
3116 }
3117
3118 static s32
3119 wl_genl_handle_msg(
3120         struct sk_buff *skb,
3121         struct genl_info *info)
3122 {
3123         struct nlattr *na;
3124         u8 *data = NULL;
3125
3126         ANDROID_TRACE(("Enter \n"));
3127
3128         if (info == NULL) {
3129                 return -EINVAL;
3130         }
3131
3132         na = info->attrs[BCM_GENL_ATTR_MSG];
3133         if (!na) {
3134                 ANDROID_ERROR(("nlattribute NULL\n"));
3135                 return -EINVAL;
3136         }
3137
3138         data = (char *)nla_data(na);
3139         if (!data) {
3140                 ANDROID_ERROR(("Invalid data\n"));
3141                 return -EINVAL;
3142         } else {
3143                 /* Handle the data */
3144 #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) || defined(WL_COMPAT_WIRELESS)
3145                 ANDROID_TRACE(("%s: Data received from pid (%d) \n", __func__,
3146                         info->snd_pid));
3147 #else
3148                 ANDROID_TRACE(("%s: Data received from pid (%d) \n", __func__,
3149                         info->snd_portid));
3150 #endif /* (LINUX_VERSION < VERSION(3, 7, 0) || WL_COMPAT_WIRELESS */
3151         }
3152
3153         return 0;
3154 }
3155 #endif /* WL_GENL */
3156
3157
3158 #if defined(RSSIAVG)
3159 void
3160 wl_free_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3161 {
3162         wl_rssi_cache_t *node, *cur, **rssi_head;
3163         int i=0;
3164
3165         rssi_head = &rssi_cache_ctrl->m_cache_head;
3166         node = *rssi_head;
3167
3168         for (;node;) {
3169                 ANDROID_INFO(("%s: Free %d with BSSID %pM\n",
3170                         __FUNCTION__, i, &node->BSSID));
3171                 cur = node;
3172                 node = cur->next;
3173                 kfree(cur);
3174                 i++;
3175         }
3176         *rssi_head = NULL;
3177 }
3178
3179 void
3180 wl_delete_dirty_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3181 {
3182         wl_rssi_cache_t *node, *prev, **rssi_head;
3183         int i = -1, tmp = 0;
3184         struct timeval now;
3185
3186         do_gettimeofday(&now);
3187
3188         rssi_head = &rssi_cache_ctrl->m_cache_head;
3189         node = *rssi_head;
3190         prev = node;
3191         for (;node;) {
3192                 i++;
3193                 if (now.tv_sec > node->tv.tv_sec) {
3194                         if (node == *rssi_head) {
3195                                 tmp = 1;
3196                                 *rssi_head = node->next;
3197                         } else {
3198                                 tmp = 0;
3199                                 prev->next = node->next;
3200                         }
3201                         ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
3202                                 __FUNCTION__, i, &node->BSSID));
3203                         kfree(node);
3204                         if (tmp == 1) {
3205                                 node = *rssi_head;
3206                                 prev = node;
3207                         } else {
3208                                 node = prev->next;
3209                         }
3210                         continue;
3211                 }
3212                 prev = node;
3213                 node = node->next;
3214         }
3215 }
3216
3217 void
3218 wl_delete_disconnected_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, u8 *bssid)
3219 {
3220         wl_rssi_cache_t *node, *prev, **rssi_head;
3221         int i = -1, tmp = 0;
3222
3223         rssi_head = &rssi_cache_ctrl->m_cache_head;
3224         node = *rssi_head;
3225         prev = node;
3226         for (;node;) {
3227                 i++;
3228                 if (!memcmp(&node->BSSID, bssid, ETHER_ADDR_LEN)) {
3229                         if (node == *rssi_head) {
3230                                 tmp = 1;
3231                                 *rssi_head = node->next;
3232                         } else {
3233                                 tmp = 0;
3234                                 prev->next = node->next;
3235                         }
3236                         ANDROID_INFO(("%s: Del %d with BSSID %pM\n",
3237                                 __FUNCTION__, i, &node->BSSID));
3238                         kfree(node);
3239                         if (tmp == 1) {
3240                                 node = *rssi_head;
3241                                 prev = node;
3242                         } else {
3243                                 node = prev->next;
3244                         }
3245                         continue;
3246                 }
3247                 prev = node;
3248                 node = node->next;
3249         }
3250 }
3251
3252 void
3253 wl_reset_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl)
3254 {
3255         wl_rssi_cache_t *node, **rssi_head;
3256
3257         rssi_head = &rssi_cache_ctrl->m_cache_head;
3258
3259         /* reset dirty */
3260         node = *rssi_head;
3261         for (;node;) {
3262                 node->dirty += 1;
3263                 node = node->next;
3264         }
3265 }
3266
3267 int
3268 wl_update_connected_rssi_cache(struct net_device *net, wl_rssi_cache_ctrl_t *rssi_cache_ctrl, int *rssi_avg)
3269 {
3270         wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3271         int j, k=0;
3272         int rssi, error=0;
3273         struct ether_addr bssid;
3274         struct timeval now, timeout;
3275
3276         if (!g_wifi_on)
3277                 return 0;
3278
3279         error = wldev_ioctl(net, WLC_GET_BSSID, &bssid, sizeof(bssid), false);
3280         if (error == BCME_NOTASSOCIATED) {
3281                 ANDROID_INFO(("%s: Not Associated! res:%d\n", __FUNCTION__, error));
3282                 return 0;
3283         }
3284         if (error) {
3285                 ANDROID_ERROR(("Could not get bssid (%d)\n", error));
3286         }
3287         error = wldev_get_rssi(net, &rssi);
3288         if (error) {
3289                 ANDROID_ERROR(("Could not get rssi (%d)\n", error));
3290                 return error;
3291         }
3292
3293         do_gettimeofday(&now);
3294         timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3295         if (timeout.tv_sec < now.tv_sec) {
3296                 /*
3297                  * Integer overflow - assume long enough timeout to be assumed
3298                  * to be infinite, i.e., the timeout would never happen.
3299                  */
3300                 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3301                         __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3302         }
3303
3304         /* update RSSI */
3305         rssi_head = &rssi_cache_ctrl->m_cache_head;
3306         node = *rssi_head;
3307         prev = NULL;
3308         for (;node;) {
3309                 if (!memcmp(&node->BSSID, &bssid, ETHER_ADDR_LEN)) {
3310                         ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d\n",
3311                                 __FUNCTION__, k, &bssid, rssi));
3312                         for(j=0; j<RSSIAVG_LEN-1; j++)
3313                                 node->RSSI[j] = node->RSSI[j+1];
3314                         node->RSSI[j] = rssi;
3315                         node->dirty = 0;
3316                         node->tv = timeout;
3317                         goto exit;
3318                 }
3319                 prev = node;
3320                 node = node->next;
3321                 k++;
3322         }
3323
3324         leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3325         if (!leaf) {
3326                 ANDROID_ERROR(("%s: Memory alloc failure %d\n",
3327                         __FUNCTION__, sizeof(wl_rssi_cache_t)));
3328                 return 0;
3329         }
3330         ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%d in the leaf\n",
3331                         __FUNCTION__, k, &bssid, rssi));
3332
3333         leaf->next = NULL;
3334         leaf->dirty = 0;
3335         leaf->tv = timeout;
3336         memcpy(&leaf->BSSID, &bssid, ETHER_ADDR_LEN);
3337         for (j=0; j<RSSIAVG_LEN; j++)
3338                 leaf->RSSI[j] = rssi;
3339
3340         if (!prev)
3341                 *rssi_head = leaf;
3342         else
3343                 prev->next = leaf;
3344
3345 exit:
3346         *rssi_avg = (int)wl_get_avg_rssi(rssi_cache_ctrl, &bssid);
3347
3348         return error;
3349 }
3350
3351 void
3352 wl_update_rssi_cache(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, wl_scan_results_t *ss_list)
3353 {
3354         wl_rssi_cache_t *node, *prev, *leaf, **rssi_head;
3355         wl_bss_info_t *bi = NULL;
3356         int i, j, k;
3357         struct timeval now, timeout;
3358
3359         if (!ss_list->count)
3360                 return;
3361
3362         do_gettimeofday(&now);
3363         timeout.tv_sec = now.tv_sec + RSSICACHE_TIMEOUT;
3364         if (timeout.tv_sec < now.tv_sec) {
3365                 /*
3366                  * Integer overflow - assume long enough timeout to be assumed
3367                  * to be infinite, i.e., the timeout would never happen.
3368                  */
3369                 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3370                         __FUNCTION__, RSSICACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3371         }
3372
3373         rssi_head = &rssi_cache_ctrl->m_cache_head;
3374
3375         /* update RSSI */
3376         for (i = 0; i < ss_list->count; i++) {
3377                 node = *rssi_head;
3378                 prev = NULL;
3379                 k = 0;
3380                 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3381                 for (;node;) {
3382                         if (!memcmp(&node->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3383                                 ANDROID_INFO(("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
3384                                         __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3385                                 for(j=0; j<RSSIAVG_LEN-1; j++)
3386                                         node->RSSI[j] = node->RSSI[j+1];
3387                                 node->RSSI[j] = dtoh16(bi->RSSI);
3388                                 node->dirty = 0;
3389                                 node->tv = timeout;
3390                                 break;
3391                         }
3392                         prev = node;
3393                         node = node->next;
3394                         k++;
3395                 }
3396
3397                 if (node)
3398                         continue;
3399
3400                 leaf = kmalloc(sizeof(wl_rssi_cache_t), GFP_KERNEL);
3401                 if (!leaf) {
3402                         ANDROID_ERROR(("%s: Memory alloc failure %d\n",
3403                                 __FUNCTION__, sizeof(wl_rssi_cache_t)));
3404                         return;
3405                 }
3406                 ANDROID_INFO(("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n",
3407                                 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3408
3409                 leaf->next = NULL;
3410                 leaf->dirty = 0;
3411                 leaf->tv = timeout;
3412                 memcpy(&leaf->BSSID, &bi->BSSID, ETHER_ADDR_LEN);
3413                 for (j=0; j<RSSIAVG_LEN; j++)
3414                         leaf->RSSI[j] = dtoh16(bi->RSSI);
3415
3416                 if (!prev)
3417                         *rssi_head = leaf;
3418                 else
3419                         prev->next = leaf;
3420         }
3421 }
3422
3423 int16
3424 wl_get_avg_rssi(wl_rssi_cache_ctrl_t *rssi_cache_ctrl, void *addr)
3425 {
3426         wl_rssi_cache_t *node, **rssi_head;
3427         int j, rssi_sum, rssi=RSSI_MINVAL;
3428
3429         rssi_head = &rssi_cache_ctrl->m_cache_head;
3430
3431         node = *rssi_head;
3432         for (;node;) {
3433                 if (!memcmp(&node->BSSID, addr, ETHER_ADDR_LEN)) {
3434                         rssi_sum = 0;
3435                         rssi = 0;
3436                         for (j=0; j<RSSIAVG_LEN; j++)
3437                                 rssi_sum += node->RSSI[RSSIAVG_LEN-j-1];
3438                         rssi = rssi_sum / j;
3439                         break;
3440                 }
3441                 node = node->next;
3442         }
3443         rssi = MIN(rssi, RSSI_MAXVAL);
3444         if (rssi == RSSI_MINVAL) {
3445                 ANDROID_ERROR(("%s: BSSID %pM does not in RSSI cache\n",
3446                 __FUNCTION__, addr));
3447         }
3448         return (int16)rssi;
3449 }
3450 #endif
3451
3452 #if defined(RSSIOFFSET)
3453 int
3454 wl_update_rssi_offset(struct net_device *net, int rssi)
3455 {
3456         uint chip, chiprev;
3457
3458         if (!g_wifi_on)
3459                 return rssi;
3460
3461         chip = dhd_conf_get_chip(dhd_get_pub(net));
3462         chiprev = dhd_conf_get_chiprev(dhd_get_pub(net));
3463         if (chip == BCM4330_CHIP_ID && chiprev == BCM4330B2_CHIP_REV) {
3464 #if defined(RSSIOFFSET_NEW)
3465                 int j;
3466                 for (j=0; j<RSSI_OFFSET; j++) {
3467                         if (rssi - (RSSI_OFFSET_MINVAL+RSSI_OFFSET_INTVAL*(j+1)) < 0)
3468                                 break;
3469                 }
3470                 rssi += j;
3471 #else
3472                 rssi += RSSI_OFFSET;
3473 #endif
3474         }
3475         return MIN(rssi, RSSI_MAXVAL);
3476 }
3477 #endif
3478
3479 #if defined(BSSCACHE)
3480 #define WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN       32
3481
3482 void
3483 wl_free_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3484 {
3485         wl_bss_cache_t *node, *cur, **bss_head;
3486         int i=0;
3487
3488         ANDROID_TRACE(("%s called\n", __FUNCTION__));
3489
3490         bss_head = &bss_cache_ctrl->m_cache_head;
3491         node = *bss_head;
3492
3493         for (;node;) {
3494                 ANDROID_TRACE(("%s: Free %d with BSSID %pM\n",
3495                         __FUNCTION__, i, &node->results.bss_info->BSSID));
3496                 cur = node;
3497                 node = cur->next;
3498                 kfree(cur);
3499                 i++;
3500         }
3501         *bss_head = NULL;
3502 }
3503
3504 void
3505 wl_delete_dirty_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3506 {
3507         wl_bss_cache_t *node, *prev, **bss_head;
3508         int i = -1, tmp = 0;
3509         struct timeval now;
3510
3511         do_gettimeofday(&now);
3512
3513         bss_head = &bss_cache_ctrl->m_cache_head;
3514         node = *bss_head;
3515         prev = node;
3516         for (;node;) {
3517                 i++;
3518                 if (now.tv_sec > node->tv.tv_sec) {
3519                         if (node == *bss_head) {
3520                                 tmp = 1;
3521                                 *bss_head = node->next;
3522                         } else {
3523                                 tmp = 0;
3524                                 prev->next = node->next;
3525                         }
3526                         ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
3527                                 __FUNCTION__, i, &node->results.bss_info->BSSID,
3528                                 dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
3529                         kfree(node);
3530                         if (tmp == 1) {
3531                                 node = *bss_head;
3532                                 prev = node;
3533                         } else {
3534                                 node = prev->next;
3535                         }
3536                         continue;
3537                 }
3538                 prev = node;
3539                 node = node->next;
3540         }
3541 }
3542
3543 void
3544 wl_delete_disconnected_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, u8 *bssid)
3545 {
3546         wl_bss_cache_t *node, *prev, **bss_head;
3547         int i = -1, tmp = 0;
3548
3549         bss_head = &bss_cache_ctrl->m_cache_head;
3550         node = *bss_head;
3551         prev = node;
3552         for (;node;) {
3553                 i++;
3554                 if (!memcmp(&node->results.bss_info->BSSID, bssid, ETHER_ADDR_LEN)) {
3555                         if (node == *bss_head) {
3556                                 tmp = 1;
3557                                 *bss_head = node->next;
3558                         } else {
3559                                 tmp = 0;
3560                                 prev->next = node->next;
3561                         }
3562                         ANDROID_TRACE(("%s: Del %d with BSSID %pM, RSSI=%d, SSID \"%s\"\n",
3563                                 __FUNCTION__, i, &node->results.bss_info->BSSID,
3564                                 dtoh16(node->results.bss_info->RSSI), node->results.bss_info->SSID));
3565                         kfree(node);
3566                         if (tmp == 1) {
3567                                 node = *bss_head;
3568                                 prev = node;
3569                         } else {
3570                                 node = prev->next;
3571                         }
3572                         continue;
3573                 }
3574                 prev = node;
3575                 node = node->next;
3576         }
3577 }
3578
3579 void
3580 wl_reset_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3581 {
3582         wl_bss_cache_t *node, **bss_head;
3583
3584         bss_head = &bss_cache_ctrl->m_cache_head;
3585
3586         /* reset dirty */
3587         node = *bss_head;
3588         for (;node;) {
3589                 node->dirty += 1;
3590                 node = node->next;
3591         }
3592 }
3593
3594 void
3595 wl_update_bss_cache(wl_bss_cache_ctrl_t *bss_cache_ctrl, wl_scan_results_t *ss_list)
3596 {
3597         wl_bss_cache_t *node, *prev, *leaf, *tmp, **bss_head;
3598         wl_bss_info_t *bi = NULL;
3599         int i, k=0;
3600         struct timeval now, timeout;
3601
3602         if (!ss_list->count)
3603                 return;
3604
3605         do_gettimeofday(&now);
3606         timeout.tv_sec = now.tv_sec + BSSCACHE_TIMEOUT;
3607         if (timeout.tv_sec < now.tv_sec) {
3608                 /*
3609                  * Integer overflow - assume long enough timeout to be assumed
3610                  * to be infinite, i.e., the timeout would never happen.
3611                  */
3612                 ANDROID_TRACE(("%s: Too long timeout (secs=%d) to ever happen - now=%lu, timeout=%lu",
3613                         __FUNCTION__, BSSCACHE_TIMEOUT, now.tv_sec, timeout.tv_sec));
3614         }
3615
3616         bss_head = &bss_cache_ctrl->m_cache_head;
3617
3618         for (i=0; i < ss_list->count; i++) {
3619                 node = *bss_head;
3620                 prev = NULL;
3621                 bi = bi ? (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length)) : ss_list->bss_info;
3622                 
3623                 for (;node;) {
3624                         if (!memcmp(&node->results.bss_info->BSSID, &bi->BSSID, ETHER_ADDR_LEN)) {
3625                                 tmp = node;
3626                                 leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3627                                 if (!leaf) {
3628                                         ANDROID_ERROR(("%s: Memory alloc failure %d and keep old BSS info\n",
3629                                                 __FUNCTION__, dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3630                                         break;
3631                                 }
3632
3633                                 memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
3634                                 leaf->next = node->next;
3635                                 leaf->dirty = 0;
3636                                 leaf->tv = timeout;
3637                                 leaf->results.count = 1;
3638                                 leaf->results.version = ss_list->version;
3639                                 ANDROID_TRACE(("%s: Update %d with BSSID %pM, RSSI=%d, SSID \"%s\", length=%d\n",
3640                                         __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID, dtoh32(bi->length)));
3641                                 if (!prev)
3642                                         *bss_head = leaf;
3643                                 else
3644                                         prev->next = leaf;
3645                                 node = leaf;
3646                                 prev = node;
3647
3648                                 kfree(tmp);
3649                                 k++;
3650                                 break;
3651                         }
3652                         prev = node;
3653                         node = node->next;
3654                 }
3655
3656                 if (node)
3657                         continue;
3658
3659                 leaf = kmalloc(dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN, GFP_KERNEL);
3660                 if (!leaf) {
3661                         ANDROID_ERROR(("%s: Memory alloc failure %d\n", __FUNCTION__,
3662                                 dtoh32(bi->length) + WLC_IW_SS_CACHE_CTRL_FIELD_MAXLEN));
3663                         return;
3664                 }
3665                 ANDROID_TRACE(("%s: Add %d with cached BSSID %pM, RSSI=%d, SSID \"%s\" in the leaf\n",
3666                                 __FUNCTION__, k, &bi->BSSID, dtoh16(bi->RSSI), bi->SSID));
3667
3668                 memcpy(leaf->results.bss_info, bi, dtoh32(bi->length));
3669                 leaf->next = NULL;
3670                 leaf->dirty = 0;
3671                 leaf->tv = timeout;
3672                 leaf->results.count = 1;
3673                 leaf->results.version = ss_list->version;
3674                 k++;
3675
3676                 if (!prev)
3677                         *bss_head = leaf;
3678                 else
3679                         prev->next = leaf;
3680         }
3681 }
3682
3683 void
3684 wl_release_bss_cache_ctrl(wl_bss_cache_ctrl_t *bss_cache_ctrl)
3685 {
3686         ANDROID_TRACE(("%s:\n", __FUNCTION__));
3687         wl_free_bss_cache(bss_cache_ctrl);
3688 }
3689 #endif