bcmdhd wifi:update driver 1.201.59.5
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rkwifi / bcmdhd / dhd_common.c
1 /*
2  * Broadcom Dongle Host Driver (DHD), common DHD core.
3  *
4  * $Copyright Open Broadcom Corporation$
5  *
6  * $Id: dhd_common.c 492215 2014-07-20 16:44:15Z $
7  */
8 #include <typedefs.h>
9 #include <osl.h>
10
11 #include <epivers.h>
12 #include <bcmutils.h>
13
14 #include <bcmendian.h>
15 #include <dngl_stats.h>
16 #include <wlioctl.h>
17 #include <dhd.h>
18 #include <dhd_ip.h>
19 #include <proto/bcmevent.h>
20
21 #ifdef SHOW_LOGTRACE
22 #include <event_log.h>
23 #endif /* SHOW_LOGTRACE */
24
25 #ifdef BCMPCIE
26 #include <dhd_flowring.h>
27 #endif
28
29 #include <dhd_bus.h>
30 #include <dhd_proto.h>
31 #include <dhd_config.h>
32 #include <dhd_dbg.h>
33 #include <msgtrace.h>
34
35 #ifdef WL_CFG80211
36 #include <wl_cfg80211.h>
37 #endif
38 #ifdef WLBTAMP
39 #include <proto/bt_amp_hci.h>
40 #include <dhd_bta.h>
41 #endif
42 #ifdef PNO_SUPPORT
43 #include <dhd_pno.h>
44 #endif
45
46 #define htod32(i) (i)
47 #define htod16(i) (i)
48 #define dtoh32(i) (i)
49 #define dtoh16(i) (i)
50 #define htodchanspec(i) (i)
51 #define dtohchanspec(i) (i)
52
53 #ifdef PROP_TXSTATUS
54 #include <wlfc_proto.h>
55 #include <dhd_wlfc.h>
56 #endif
57
58 #ifdef DHD_WMF
59 #include <dhd_linux.h>
60 #include <dhd_wmf_linux.h>
61 #endif /* DHD_WMF */
62
63
64 #ifdef WLMEDIA_HTSF
65 extern void htsf_update(struct dhd_info *dhd, void *data);
66 #endif
67 int dhd_msg_level = DHD_ERROR_VAL;
68
69
70 #include <wl_iw.h>
71
72 #ifdef SOFTAP
73 char fw_path2[MOD_PARAM_PATHLEN];
74 extern bool softap_enabled;
75 #endif
76
77 /* Last connection success/failure status */
78 uint32 dhd_conn_event;
79 uint32 dhd_conn_status;
80 uint32 dhd_conn_reason;
81
82 #if defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE)
83 static int check_event_log_sequence_number(uint32 seq_no);
84 #endif /* defined(SHOW_EVENTS) && defined(SHOW_LOGTRACE) */
85 extern int dhd_iscan_request(void * dhdp, uint16 action);
86 extern void dhd_ind_scan_confirm(void *h, bool status);
87 extern int dhd_iscan_in_progress(void *h);
88 void dhd_iscan_lock(void);
89 void dhd_iscan_unlock(void);
90 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
91 #if !defined(AP) && defined(WLP2P)
92 extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd);
93 #endif
94 bool ap_cfg_running = FALSE;
95 bool ap_fw_loaded = FALSE;
96
97 /* Version string to report */
98 #ifdef DHD_DEBUG
99 #ifndef SRCBASE
100 #define SRCBASE        "drivers/net/wireless/bcmdhd"
101 #endif
102 #define DHD_COMPILED "\nCompiled in " SRCBASE
103 #endif /* DHD_DEBUG */
104
105 #if defined(DHD_DEBUG)
106 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR
107         DHD_COMPILED " on " __DATE__ " at " __TIME__;
108 #else
109 const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR "\nCompiled from ";
110 #endif 
111
112 void dhd_set_timer(void *bus, uint wdtick);
113
114
115
116 /* IOVar table */
117 enum {
118         IOV_VERSION = 1,
119         IOV_WLMSGLEVEL,
120         IOV_MSGLEVEL,
121         IOV_BCMERRORSTR,
122         IOV_BCMERROR,
123         IOV_WDTICK,
124         IOV_DUMP,
125         IOV_CLEARCOUNTS,
126         IOV_LOGDUMP,
127         IOV_LOGCAL,
128         IOV_LOGSTAMP,
129         IOV_GPIOOB,
130         IOV_IOCTLTIMEOUT,
131 #ifdef WLBTAMP
132         IOV_HCI_CMD,            /* HCI command */
133         IOV_HCI_ACL_DATA,       /* HCI data packet */
134 #endif
135 #if defined(DHD_DEBUG)
136         IOV_CONS,
137         IOV_DCONSOLE_POLL,
138 #endif /* defined(DHD_DEBUG) */
139 #ifdef PROP_TXSTATUS
140         IOV_PROPTXSTATUS_ENABLE,
141         IOV_PROPTXSTATUS_MODE,
142         IOV_PROPTXSTATUS_OPT,
143 #ifdef QMONITOR
144         IOV_QMON_TIME_THRES,
145         IOV_QMON_TIME_PERCENT,
146 #endif /* QMONITOR */
147         IOV_PROPTXSTATUS_MODULE_IGNORE,
148         IOV_PROPTXSTATUS_CREDIT_IGNORE,
149         IOV_PROPTXSTATUS_TXSTATUS_IGNORE,
150         IOV_PROPTXSTATUS_RXPKT_CHK,
151 #endif /* PROP_TXSTATUS */
152         IOV_BUS_TYPE,
153 #ifdef WLMEDIA_HTSF
154         IOV_WLPKTDLYSTAT_SZ,
155 #endif
156         IOV_CHANGEMTU,
157         IOV_HOSTREORDER_FLOWS,
158 #ifdef DHDTCPACK_SUPPRESS
159         IOV_TCPACK_SUPPRESS,
160 #endif /* DHDTCPACK_SUPPRESS */
161 #ifdef DHD_WMF
162         IOV_WMF_BSS_ENAB,
163         IOV_WMF_UCAST_IGMP,
164         IOV_WMF_MCAST_DATA_SENDUP,
165 #ifdef WL_IGMP_UCQUERY
166         IOV_WMF_UCAST_IGMP_QUERY,
167 #endif /* WL_IGMP_UCQUERY */
168 #ifdef DHD_UCAST_UPNP
169         IOV_WMF_UCAST_UPNP,
170 #endif /* DHD_UCAST_UPNP */
171 #endif /* DHD_WMF */
172         IOV_AP_ISOLATE,
173 #ifdef DHD_UNICAST_DHCP
174         IOV_DHCP_UNICAST,
175 #endif /* DHD_UNICAST_DHCP */
176 #ifdef DHD_L2_FILTER
177         IOV_BLOCK_PING,
178 #endif
179         IOV_LAST
180 };
181
182 const bcm_iovar_t dhd_iovars[] = {
183         {"version",     IOV_VERSION,    0,      IOVT_BUFFER,    sizeof(dhd_version) },
184         {"wlmsglevel",  IOV_WLMSGLEVEL, 0,      IOVT_UINT32,    0 },
185 #ifdef DHD_DEBUG
186         {"msglevel",    IOV_MSGLEVEL,   0,      IOVT_UINT32,    0 },
187 #endif /* DHD_DEBUG */
188         {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER,        BCME_STRLEN },
189         {"bcmerror",    IOV_BCMERROR,   0,      IOVT_INT8,      0 },
190         {"wdtick",      IOV_WDTICK, 0,  IOVT_UINT32,    0 },
191         {"dump",        IOV_DUMP,       0,      IOVT_BUFFER,    DHD_IOCTL_MAXLEN },
192 #ifdef DHD_DEBUG
193         {"cons",        IOV_CONS,       0,      IOVT_BUFFER,    0 },
194         {"dconpoll",    IOV_DCONSOLE_POLL, 0,   IOVT_UINT32,    0 },
195 #endif
196         {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID,  0 },
197         {"gpioob",      IOV_GPIOOB,     0,      IOVT_UINT32,    0 },
198         {"ioctl_timeout",       IOV_IOCTLTIMEOUT,       0,      IOVT_UINT32,    0 },
199 #ifdef WLBTAMP
200         {"HCI_cmd",     IOV_HCI_CMD,    0,      IOVT_BUFFER,    0},
201         {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0,   IOVT_BUFFER,    0},
202 #endif
203 #ifdef PROP_TXSTATUS
204         {"proptx",      IOV_PROPTXSTATUS_ENABLE,        0,      IOVT_BOOL,      0 },
205         /*
206         set the proptxtstatus operation mode:
207         0 - Do not do any proptxtstatus flow control
208         1 - Use implied credit from a packet status
209         2 - Use explicit credit
210         */
211         {"ptxmode",     IOV_PROPTXSTATUS_MODE,  0,      IOVT_UINT32,    0 },
212         {"proptx_opt", IOV_PROPTXSTATUS_OPT,    0,      IOVT_UINT32,    0 },
213 #ifdef QMONITOR
214         {"qtime_thres", IOV_QMON_TIME_THRES,    0,      IOVT_UINT32,    0 },
215         {"qtime_percent", IOV_QMON_TIME_PERCENT, 0,     IOVT_UINT32,    0 },
216 #endif /* QMONITOR */
217         {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, IOVT_BOOL, 0 },
218         {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, IOVT_BOOL, 0 },
219         {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, IOVT_BOOL, 0 },
220         {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, IOVT_BOOL, 0 },
221 #endif /* PROP_TXSTATUS */
222         {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
223 #ifdef WLMEDIA_HTSF
224         {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
225 #endif
226         {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
227         {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER,
228         (WLHOST_REORDERDATA_MAXFLOWS + 1) },
229 #ifdef DHDTCPACK_SUPPRESS
230         {"tcpack_suppress",     IOV_TCPACK_SUPPRESS,    0,      IOVT_UINT8,     0 },
231 #endif /* DHDTCPACK_SUPPRESS */
232 #ifdef DHD_WMF
233         {"wmf_bss_enable", IOV_WMF_BSS_ENAB,    0,      IOVT_BOOL,      0 },
234         {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP,  0,      IOVT_BOOL,      0 },
235         {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP,    0,      IOVT_BOOL,      0 },
236 #ifdef WL_IGMP_UCQUERY
237         {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), IOVT_BOOL, 0 },
238 #endif /* WL_IGMP_UCQUERY */
239 #ifdef DHD_UCAST_UPNP
240         {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), IOVT_BOOL, 0 },
241 #endif /* DHD_UCAST_UPNP */
242 #endif /* DHD_WMF */
243 #ifdef DHD_UNICAST_DHCP
244         {"dhcp_unicast", IOV_DHCP_UNICAST, (0), IOVT_BOOL, 0 },
245 #endif /* DHD_UNICAST_DHCP */
246         {"ap_isolate", IOV_AP_ISOLATE, (0), IOVT_BOOL, 0},
247 #ifdef DHD_L2_FILTER
248         {"block_ping", IOV_BLOCK_PING, (0), IOVT_BOOL, 0},
249 #endif
250         {NULL, 0, 0, 0, 0 }
251 };
252
253 #define DHD_IOVAR_BUF_SIZE      128
254
255 /* to NDIS developer, the structure dhd_common is redundant,
256  * please do NOT merge it back from other branches !!!
257  */
258
259 static int
260 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
261 {
262         char eabuf[ETHER_ADDR_STR_LEN];
263
264         struct bcmstrbuf b;
265         struct bcmstrbuf *strbuf = &b;
266
267         bcm_binit(strbuf, buf, buflen);
268
269         /* Base DHD info */
270         bcm_bprintf(strbuf, "%s\n", dhd_version);
271         bcm_bprintf(strbuf, "\n");
272         bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
273                     dhdp->up, dhdp->txoff, dhdp->busstate);
274         bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n",
275                     dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
276         bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
277                     dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
278         bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt);
279
280         bcm_bprintf(strbuf, "dongle stats:\n");
281         bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n",
282                     dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
283                     dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
284         bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n",
285                     dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
286                     dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
287         bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast);
288
289         bcm_bprintf(strbuf, "bus stats:\n");
290         bcm_bprintf(strbuf, "tx_packets %lu  tx_dropped %lu tx_multicast %lu tx_errors %lu\n",
291                     dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors);
292         bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n",
293                     dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
294         bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
295                     dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
296         bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n",
297                     dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
298         bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n",
299                     dhdp->rx_readahead_cnt, dhdp->tx_realloc);
300         bcm_bprintf(strbuf, "\n");
301
302         /* Add any prot info */
303         dhd_prot_dump(dhdp, strbuf);
304         bcm_bprintf(strbuf, "\n");
305
306         /* Add any bus info */
307         dhd_bus_dump(dhdp, strbuf);
308
309
310         return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
311 }
312
313 int
314 dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx)
315 {
316         wl_ioctl_t ioc;
317
318         ioc.cmd = cmd;
319         ioc.buf = arg;
320         ioc.len = len;
321         ioc.set = set;
322
323         return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len);
324 }
325
326 int
327 dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
328 {
329         int ret = BCME_ERROR;
330
331         if (dhd_os_proto_block(dhd_pub))
332         {
333 #if defined(WL_WLC_SHIM)
334                 wl_info_t *wl = dhd_pub_wlinfo(dhd_pub);
335
336                 wl_io_pport_t io_pport;
337                 io_pport.dhd_pub = dhd_pub;
338                 io_pport.ifidx = ifidx;
339
340                 ret = wl_shim_ioctl(wl->shim, ioc, &io_pport);
341                 if (ret != BCME_OK) {
342                         DHD_ERROR(("%s: wl_shim_ioctl(%d) ERR %d\n", __FUNCTION__, ioc->cmd, ret));
343                 }
344 #else
345                 ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
346 #endif /* defined(WL_WLC_SHIM) */
347
348                 if (ret && dhd_pub->up) {
349                         /* Send hang event only if dhd_open() was success */
350                         dhd_os_check_hang(dhd_pub, ifidx, ret);
351                 }
352
353                 if (ret == -ETIMEDOUT && !dhd_pub->up) {
354                         DHD_ERROR(("%s: 'resumed on timeout' error is "
355                                 "occurred before the interface does not"
356                                 " bring up\n", __FUNCTION__));
357                         dhd_pub->busstate = DHD_BUS_DOWN;
358                 }
359
360                 dhd_os_proto_unblock(dhd_pub);
361
362         }
363
364         return ret;
365 }
366
367 uint wl_get_port_num(wl_io_pport_t *io_pport)
368 {
369         return 0;
370 }
371
372 /* Get bssidx from iovar params
373  * Input:   dhd_pub - pointer to dhd_pub_t
374  *          params  - IOVAR params
375  * Output:  idx     - BSS index
376  *          val     - ponter to the IOVAR arguments
377  */
378 static int
379 dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, char *params, int *idx, char **val)
380 {
381         char *prefix = "bsscfg:";
382         uint32  bssidx;
383
384         if (!(strncmp(params, prefix, strlen(prefix)))) {
385                 /* per bss setting should be prefixed with 'bsscfg:' */
386                 char *p = (char *)params + strlen(prefix);
387
388                 /* Skip Name */
389                 while (*p != '\0')
390                         p++;
391                 /* consider null */
392                 p = p + 1;
393                 bcopy(p, &bssidx, sizeof(uint32));
394                 /* Get corresponding dhd index */
395                 bssidx = dhd_bssidx2idx(dhd_pub, bssidx);
396
397                 if (bssidx >= DHD_MAX_IFS) {
398                         DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__));
399                         return BCME_ERROR;
400                 }
401
402                 /* skip bss idx */
403                 p += sizeof(uint32);
404                 *val = p;
405                 *idx = bssidx;
406         } else {
407                 DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__));
408                 return BCME_ERROR;
409         }
410
411         return BCME_OK;
412 }
413
414 static int
415 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
416             void *params, int plen, void *arg, int len, int val_size)
417 {
418         int bcmerror = 0;
419         int32 int_val = 0;
420
421         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
422         DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
423
424         if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
425                 goto exit;
426
427         if (plen >= (int)sizeof(int_val))
428                 bcopy(params, &int_val, sizeof(int_val));
429
430         switch (actionid) {
431         case IOV_GVAL(IOV_VERSION):
432                 /* Need to have checked buffer length */
433                 bcm_strncpy_s((char*)arg, len, dhd_version, len);
434                 break;
435
436         case IOV_GVAL(IOV_WLMSGLEVEL):
437                 printf("android_msg_level=0x%x\n", android_msg_level);
438                 printf("config_msg_level=0x%x\n", config_msg_level);
439 #if defined(WL_WIRELESS_EXT)
440                 int_val = (int32)iw_msg_level;
441                 bcopy(&int_val, arg, val_size);
442                 printf("iw_msg_level=0x%x\n", iw_msg_level);
443 #endif
444 #ifdef WL_CFG80211
445                 int_val = (int32)wl_dbg_level;
446                 bcopy(&int_val, arg, val_size);
447                 printf("cfg_msg_level=0x%x\n", wl_dbg_level);
448 #endif
449                 break;
450
451         case IOV_SVAL(IOV_WLMSGLEVEL):
452                 if (int_val & DHD_ANDROID_VAL) {
453                         android_msg_level = (uint)(int_val & 0xFFFF);
454                         printf("android_msg_level=0x%x\n", android_msg_level);
455                 }
456                 if (int_val & DHD_CONFIG_VAL) {
457                         config_msg_level = (uint)(int_val & 0xFFFF);
458                         printf("config_msg_level=0x%x\n", config_msg_level);
459                 }
460 #if defined(WL_WIRELESS_EXT)
461                 if (int_val & DHD_IW_VAL) {
462                         iw_msg_level = (uint)(int_val & 0xFFFF);
463                         printf("iw_msg_level=0x%x\n", iw_msg_level);
464                 }
465 #endif
466 #ifdef WL_CFG80211
467                 if (int_val & DHD_CFG_VAL) {
468                         wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF));
469                 }
470 #endif
471                 break;
472
473         case IOV_GVAL(IOV_MSGLEVEL):
474                 int_val = (int32)dhd_msg_level;
475                 bcopy(&int_val, arg, val_size);
476                 break;
477
478         case IOV_SVAL(IOV_MSGLEVEL):
479                 dhd_msg_level = int_val;
480                 break;
481
482         case IOV_GVAL(IOV_BCMERRORSTR):
483                 bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
484                 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
485                 break;
486
487         case IOV_GVAL(IOV_BCMERROR):
488                 int_val = (int32)dhd_pub->bcmerror;
489                 bcopy(&int_val, arg, val_size);
490                 break;
491
492         case IOV_GVAL(IOV_WDTICK):
493                 int_val = (int32)dhd_watchdog_ms;
494                 bcopy(&int_val, arg, val_size);
495                 break;
496
497         case IOV_SVAL(IOV_WDTICK):
498                 if (!dhd_pub->up) {
499                         bcmerror = BCME_NOTUP;
500                         break;
501                 }
502                 dhd_os_wd_timer(dhd_pub, (uint)int_val);
503                 break;
504
505         case IOV_GVAL(IOV_DUMP):
506                 bcmerror = dhd_dump(dhd_pub, arg, len);
507                 break;
508
509 #ifdef DHD_DEBUG
510         case IOV_GVAL(IOV_DCONSOLE_POLL):
511                 int_val = (int32)dhd_console_ms;
512                 bcopy(&int_val, arg, val_size);
513                 break;
514
515         case IOV_SVAL(IOV_DCONSOLE_POLL):
516                 dhd_console_ms = (uint)int_val;
517                 break;
518
519         case IOV_SVAL(IOV_CONS):
520                 if (len > 0)
521                         bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
522                 break;
523 #endif /* DHD_DEBUG */
524
525         case IOV_SVAL(IOV_CLEARCOUNTS):
526                 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
527                 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
528                 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
529                 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
530                 dhd_pub->tx_dropped = 0;
531                 dhd_pub->rx_dropped = 0;
532                 dhd_pub->rx_readahead_cnt = 0;
533                 dhd_pub->tx_realloc = 0;
534                 dhd_pub->wd_dpc_sched = 0;
535                 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
536                 dhd_bus_clearcounts(dhd_pub);
537 #ifdef PROP_TXSTATUS
538                 /* clear proptxstatus related counters */
539                 dhd_wlfc_clear_counts(dhd_pub);
540 #endif /* PROP_TXSTATUS */
541                 break;
542
543
544         case IOV_GVAL(IOV_IOCTLTIMEOUT): {
545                 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
546                 bcopy(&int_val, arg, sizeof(int_val));
547                 break;
548         }
549
550         case IOV_SVAL(IOV_IOCTLTIMEOUT): {
551                 if (int_val <= 0)
552                         bcmerror = BCME_BADARG;
553                 else
554                         dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
555                 break;
556         }
557
558 #ifdef WLBTAMP
559         case IOV_SVAL(IOV_HCI_CMD): {
560                 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg;
561
562                 /* sanity check: command preamble present */
563                 if (len < HCI_CMD_PREAMBLE_SIZE)
564                         return BCME_BUFTOOSHORT;
565
566                 /* sanity check: command parameters are present */
567                 if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen))
568                         return BCME_BUFTOOSHORT;
569
570                 dhd_bta_docmd(dhd_pub, cmd, len);
571                 break;
572         }
573
574         case IOV_SVAL(IOV_HCI_ACL_DATA): {
575                 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg;
576
577                 /* sanity check: HCI header present */
578                 if (len < HCI_ACL_DATA_PREAMBLE_SIZE)
579                         return BCME_BUFTOOSHORT;
580
581                 /* sanity check: ACL data is present */
582                 if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen))
583                         return BCME_BUFTOOSHORT;
584
585                 dhd_bta_tx_hcidata(dhd_pub, ACL_data, len);
586                 break;
587         }
588 #endif /* WLBTAMP */
589
590 #ifdef PROP_TXSTATUS
591         case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): {
592                 bool wlfc_enab = FALSE;
593                 bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
594                 if (bcmerror != BCME_OK)
595                         goto exit;
596                 int_val = wlfc_enab ? 1 : 0;
597                 bcopy(&int_val, arg, val_size);
598                 break;
599         }
600         case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): {
601                 bool wlfc_enab = FALSE;
602                 bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
603                 if (bcmerror != BCME_OK)
604                         goto exit;
605
606                 /* wlfc is already set as desired */
607                 if (wlfc_enab == (int_val == 0 ? FALSE : TRUE))
608                         goto exit;
609
610                 if (int_val == TRUE)
611                         bcmerror = dhd_wlfc_init(dhd_pub);
612                 else
613                         bcmerror = dhd_wlfc_deinit(dhd_pub);
614
615                 break;
616         }
617         case IOV_GVAL(IOV_PROPTXSTATUS_MODE):
618                 bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val);
619                 if (bcmerror != BCME_OK)
620                         goto exit;
621                 bcopy(&int_val, arg, val_size);
622                 break;
623
624         case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
625                 dhd_wlfc_set_mode(dhd_pub, int_val);
626                 break;
627 #ifdef QMONITOR
628         case IOV_GVAL(IOV_QMON_TIME_THRES): {
629                 int_val = dhd_qmon_thres(dhd_pub, FALSE, 0);
630                 bcopy(&int_val, arg, val_size);
631                 break;
632         }
633
634         case IOV_SVAL(IOV_QMON_TIME_THRES): {
635                 dhd_qmon_thres(dhd_pub, TRUE, int_val);
636                 break;
637         }
638
639         case IOV_GVAL(IOV_QMON_TIME_PERCENT): {
640                 int_val = dhd_qmon_getpercent(dhd_pub);
641                 bcopy(&int_val, arg, val_size);
642                 break;
643         }
644 #endif /* QMONITOR */
645
646         case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
647                 bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val);
648                 if (bcmerror != BCME_OK)
649                         goto exit;
650                 bcopy(&int_val, arg, val_size);
651                 break;
652
653         case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
654                 dhd_wlfc_set_module_ignore(dhd_pub, int_val);
655                 break;
656
657         case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
658                 bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val);
659                 if (bcmerror != BCME_OK)
660                         goto exit;
661                 bcopy(&int_val, arg, val_size);
662                 break;
663
664         case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
665                 dhd_wlfc_set_credit_ignore(dhd_pub, int_val);
666                 break;
667
668         case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
669                 bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val);
670                 if (bcmerror != BCME_OK)
671                         goto exit;
672                 bcopy(&int_val, arg, val_size);
673                 break;
674
675         case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
676                 dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val);
677                 break;
678
679         case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
680                 bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val);
681                 if (bcmerror != BCME_OK)
682                         goto exit;
683                 bcopy(&int_val, arg, val_size);
684                 break;
685
686         case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
687                 dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val);
688                 break;
689
690 #endif /* PROP_TXSTATUS */
691
692         case IOV_GVAL(IOV_BUS_TYPE):
693                 /* The dhd application queries the driver to check if its usb or sdio.  */
694 #ifdef BCMDHDUSB
695                 int_val = BUS_TYPE_USB;
696 #endif
697 #ifdef BCMSDIO
698                 int_val = BUS_TYPE_SDIO;
699 #endif
700 #ifdef PCIE_FULL_DONGLE
701                 int_val = BUS_TYPE_PCIE;
702 #endif
703                 bcopy(&int_val, arg, val_size);
704                 break;
705
706
707 #ifdef WLMEDIA_HTSF
708         case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
709                 int_val = dhd_pub->htsfdlystat_sz;
710                 bcopy(&int_val, arg, val_size);
711                 break;
712
713         case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
714                 dhd_pub->htsfdlystat_sz = int_val & 0xff;
715                 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
716                 break;
717 #endif
718         case IOV_SVAL(IOV_CHANGEMTU):
719                 int_val &= 0xffff;
720                 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
721                 break;
722
723         case IOV_GVAL(IOV_HOSTREORDER_FLOWS):
724         {
725                 uint i = 0;
726                 uint8 *ptr = (uint8 *)arg;
727                 uint8 count = 0;
728
729                 ptr++;
730                 for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) {
731                         if (dhd_pub->reorder_bufs[i] != NULL) {
732                                 *ptr = dhd_pub->reorder_bufs[i]->flow_id;
733                                 ptr++;
734                                 count++;
735                         }
736                 }
737                 ptr = (uint8 *)arg;
738                 *ptr = count;
739                 break;
740         }
741 #ifdef DHDTCPACK_SUPPRESS
742         case IOV_GVAL(IOV_TCPACK_SUPPRESS): {
743                 int_val = (uint32)dhd_pub->tcpack_sup_mode;
744                 bcopy(&int_val, arg, val_size);
745                 break;
746         }
747         case IOV_SVAL(IOV_TCPACK_SUPPRESS): {
748                 bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val);
749                 break;
750         }
751 #endif /* DHDTCPACK_SUPPRESS */
752 #ifdef DHD_WMF
753         case IOV_GVAL(IOV_WMF_BSS_ENAB): {
754                 uint32  bssidx;
755                 dhd_wmf_t *wmf;
756                 char *val;
757
758                 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
759                         DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
760                         bcmerror = BCME_BADARG;
761                         break;
762                 }
763
764                 wmf = dhd_wmf_conf(dhd_pub, bssidx);
765                 int_val = wmf->wmf_enable ? 1 :0;
766                 bcopy(&int_val, arg, val_size);
767                 break;
768         }
769         case IOV_SVAL(IOV_WMF_BSS_ENAB): {
770                 /* Enable/Disable WMF */
771                 uint32  bssidx;
772                 dhd_wmf_t *wmf;
773                 char *val;
774
775                 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
776                         DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
777                         bcmerror = BCME_BADARG;
778                         break;
779                 }
780
781                 ASSERT(val);
782                 bcopy(val, &int_val, sizeof(uint32));
783                 wmf = dhd_wmf_conf(dhd_pub, bssidx);
784                 if (wmf->wmf_enable == int_val)
785                         break;
786                 if (int_val) {
787                         /* Enable WMF */
788                         if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) {
789                                 DHD_ERROR(("%s: Error in creating WMF instance\n",
790                                 __FUNCTION__));
791                                 break;
792                         }
793                         if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) {
794                                 DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__));
795                                 break;
796                         }
797                         wmf->wmf_enable = TRUE;
798                 } else {
799                         /* Disable WMF */
800                         wmf->wmf_enable = FALSE;
801                         dhd_wmf_stop(dhd_pub, bssidx);
802                         dhd_wmf_instance_del(dhd_pub, bssidx);
803                 }
804                 break;
805         }
806         case IOV_GVAL(IOV_WMF_UCAST_IGMP):
807                 int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0;
808                 bcopy(&int_val, arg, val_size);
809                 break;
810         case IOV_SVAL(IOV_WMF_UCAST_IGMP):
811                 if (dhd_pub->wmf_ucast_igmp == int_val)
812                         break;
813
814                 if (int_val >= OFF && int_val <= ON)
815                         dhd_pub->wmf_ucast_igmp = int_val;
816                 else
817                         bcmerror = BCME_RANGE;
818                 break;
819         case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP):
820                 int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE);
821                 bcopy(&int_val, arg, val_size);
822                 break;
823         case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP):
824                 dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val);
825                 break;
826
827 #ifdef WL_IGMP_UCQUERY
828         case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY):
829                 int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0;
830                 bcopy(&int_val, arg, val_size);
831                 break;
832         case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY):
833                 if (dhd_pub->wmf_ucast_igmp_query == int_val)
834                         break;
835
836                 if (int_val >= OFF && int_val <= ON)
837                         dhd_pub->wmf_ucast_igmp_query = int_val;
838                 else
839                         bcmerror = BCME_RANGE;
840                 break;
841 #endif /* WL_IGMP_UCQUERY */
842 #ifdef DHD_UCAST_UPNP
843         case IOV_GVAL(IOV_WMF_UCAST_UPNP):
844                 int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0;
845                 bcopy(&int_val, arg, val_size);
846                 break;
847         case IOV_SVAL(IOV_WMF_UCAST_UPNP):
848                 if (dhd_pub->wmf_ucast_upnp == int_val)
849                         break;
850
851                 if (int_val >= OFF && int_val <= ON)
852                         dhd_pub->wmf_ucast_upnp = int_val;
853                 else
854                         bcmerror = BCME_RANGE;
855                 break;
856 #endif /* DHD_UCAST_UPNP */
857 #endif /* DHD_WMF */
858
859
860 #ifdef DHD_UNICAST_DHCP
861         case IOV_GVAL(IOV_DHCP_UNICAST):
862                 int_val = dhd_pub->dhcp_unicast;
863                 bcopy(&int_val, arg, val_size);
864                 break;
865         case IOV_SVAL(IOV_DHCP_UNICAST):
866                 if (dhd_pub->dhcp_unicast == int_val)
867                         break;
868
869                 if (int_val >= OFF || int_val <= ON) {
870                         dhd_pub->dhcp_unicast = int_val;
871                 } else {
872                         bcmerror = BCME_RANGE;
873                 }
874                 break;
875 #endif /* DHD_UNICAST_DHCP */
876 #ifdef DHD_L2_FILTER
877         case IOV_GVAL(IOV_BLOCK_PING):
878                 int_val = dhd_pub->block_ping;
879                 bcopy(&int_val, arg, val_size);
880                 break;
881         case IOV_SVAL(IOV_BLOCK_PING):
882                 if (dhd_pub->block_ping == int_val)
883                         break;
884                 if (int_val >= OFF || int_val <= ON) {
885                         dhd_pub->block_ping = int_val;
886                 } else {
887                         bcmerror = BCME_RANGE;
888                 }
889                 break;
890 #endif
891
892         case IOV_GVAL(IOV_AP_ISOLATE): {
893                 uint32  bssidx;
894                 char *val;
895
896                 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
897                         DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
898                         bcmerror = BCME_BADARG;
899                         break;
900                 }
901
902                 int_val = dhd_get_ap_isolate(dhd_pub, bssidx);
903                 bcopy(&int_val, arg, val_size);
904                 break;
905         }
906         case IOV_SVAL(IOV_AP_ISOLATE): {
907                 uint32  bssidx;
908                 char *val;
909
910                 if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
911                         DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
912                         bcmerror = BCME_BADARG;
913                         break;
914                 }
915
916                 ASSERT(val);
917                 bcopy(val, &int_val, sizeof(uint32));
918                 dhd_set_ap_isolate(dhd_pub, bssidx, int_val);
919                 break;
920         }
921
922         default:
923                 bcmerror = BCME_UNSUPPORTED;
924                 break;
925         }
926
927 exit:
928         DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
929         return bcmerror;
930 }
931
932 /* Store the status of a connection attempt for later retrieval by an iovar */
933 void
934 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
935 {
936         /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
937          * because an encryption/rsn mismatch results in both events, and
938          * the important information is in the WLC_E_PRUNE.
939          */
940         if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
941               dhd_conn_event == WLC_E_PRUNE)) {
942                 dhd_conn_event = event;
943                 dhd_conn_status = status;
944                 dhd_conn_reason = reason;
945         }
946 }
947
948 bool
949 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
950 {
951         void *p;
952         int eprec = -1;         /* precedence to evict from */
953         bool discard_oldest;
954
955         /* Fast case, precedence queue is not full and we are also not
956          * exceeding total queue length
957          */
958         if (!pktq_pfull(q, prec) && !pktq_full(q)) {
959                 pktq_penq(q, prec, pkt);
960                 return TRUE;
961         }
962
963         /* Determine precedence from which to evict packet, if any */
964         if (pktq_pfull(q, prec))
965                 eprec = prec;
966         else if (pktq_full(q)) {
967                 p = pktq_peek_tail(q, &eprec);
968                 ASSERT(p);
969                 if (eprec > prec || eprec < 0)
970                         return FALSE;
971         }
972
973         /* Evict if needed */
974         if (eprec >= 0) {
975                 /* Detect queueing to unconfigured precedence */
976                 ASSERT(!pktq_pempty(q, eprec));
977                 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
978                 if (eprec == prec && !discard_oldest)
979                         return FALSE;           /* refuse newer (incoming) packet */
980                 /* Evict packet according to discard policy */
981                 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
982                 ASSERT(p);
983 #ifdef DHDTCPACK_SUPPRESS
984                 if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) {
985                         DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
986                                 __FUNCTION__, __LINE__));
987                         dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
988                 }
989 #endif /* DHDTCPACK_SUPPRESS */
990                 PKTFREE(dhdp->osh, p, TRUE);
991         }
992
993         /* Enqueue */
994         p = pktq_penq(q, prec, pkt);
995         ASSERT(p);
996
997         return TRUE;
998 }
999
1000 /*
1001  * Functions to drop proper pkts from queue:
1002  *      If one pkt in queue is non-fragmented, drop first non-fragmented pkt only
1003  *      If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts
1004  *      If can't find pkts matching upper 2 cases, drop first pkt anyway
1005  */
1006 bool
1007 dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn)
1008 {
1009         struct pktq_prec *q = NULL;
1010         void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL;
1011         pkt_frag_t frag_info;
1012
1013         ASSERT(dhdp && pq);
1014         ASSERT(prec >= 0 && prec < pq->num_prec);
1015
1016         q = &pq->q[prec];
1017         p = q->head;
1018
1019         if (p == NULL)
1020                 return FALSE;
1021
1022         while (p) {
1023                 frag_info = pkt_frag_info(dhdp->osh, p);
1024                 if (frag_info == DHD_PKT_FRAG_NONE) {
1025                         break;
1026                 } else if (frag_info == DHD_PKT_FRAG_FIRST) {
1027                         if (first) {
1028                                 /* No last frag pkt, use prev as last */
1029                                 last = prev;
1030                                 break;
1031                         } else {
1032                                 first = p;
1033                                 prev_first = prev;
1034                         }
1035                 } else if (frag_info == DHD_PKT_FRAG_LAST) {
1036                         if (first) {
1037                                 last = p;
1038                                 break;
1039                         }
1040                 }
1041
1042                 prev = p;
1043                 p = PKTLINK(p);
1044         }
1045
1046         if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) {
1047                 /* Not found matching pkts, use oldest */
1048                 prev = NULL;
1049                 p = q->head;
1050                 frag_info = 0;
1051         }
1052
1053         if (frag_info == DHD_PKT_FRAG_NONE) {
1054                 first = last = p;
1055                 prev_first = prev;
1056         }
1057
1058         p = first;
1059         while (p) {
1060                 next = PKTLINK(p);
1061                 q->len--;
1062                 pq->len--;
1063
1064                 PKTSETLINK(p, NULL);
1065
1066                 if (fn)
1067                         fn(dhdp, prec, p, TRUE);
1068
1069                 if (p == last)
1070                         break;
1071
1072                 p = next;
1073         }
1074
1075         if (prev_first == NULL) {
1076                 if ((q->head = next) == NULL)
1077                         q->tail = NULL;
1078         } else {
1079                 PKTSETLINK(prev_first, next);
1080                 if (!next)
1081                         q->tail = prev_first;
1082         }
1083
1084         return TRUE;
1085 }
1086
1087 static int
1088 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
1089         void *params, int plen, void *arg, int len, bool set)
1090 {
1091         int bcmerror = 0;
1092         int val_size;
1093         const bcm_iovar_t *vi = NULL;
1094         uint32 actionid;
1095
1096         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1097
1098         ASSERT(name);
1099         ASSERT(len >= 0);
1100
1101         /* Get MUST have return space */
1102         ASSERT(set || (arg && len));
1103
1104         /* Set does NOT take qualifiers */
1105         ASSERT(!set || (!params && !plen));
1106
1107         if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
1108                 bcmerror = BCME_UNSUPPORTED;
1109                 goto exit;
1110         }
1111
1112         DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
1113                 name, (set ? "set" : "get"), len, plen));
1114
1115         /* set up 'params' pointer in case this is a set command so that
1116          * the convenience int and bool code can be common to set and get
1117          */
1118         if (params == NULL) {
1119                 params = arg;
1120                 plen = len;
1121         }
1122
1123         if (vi->type == IOVT_VOID)
1124                 val_size = 0;
1125         else if (vi->type == IOVT_BUFFER)
1126                 val_size = len;
1127         else
1128                 /* all other types are integer sized */
1129                 val_size = sizeof(int);
1130
1131         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
1132
1133         bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
1134
1135 exit:
1136         return bcmerror;
1137 }
1138
1139 int
1140 dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
1141 {
1142         int bcmerror = 0;
1143
1144         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1145
1146         if (!buf) {
1147                 return BCME_BADARG;
1148         }
1149
1150         switch (ioc->cmd) {
1151         case DHD_GET_MAGIC:
1152                 if (buflen < sizeof(int))
1153                         bcmerror = BCME_BUFTOOSHORT;
1154                 else
1155                         *(int*)buf = DHD_IOCTL_MAGIC;
1156                 break;
1157
1158         case DHD_GET_VERSION:
1159                 if (buflen < sizeof(int))
1160                         bcmerror = BCME_BUFTOOSHORT;
1161                 else
1162                         *(int*)buf = DHD_IOCTL_VERSION;
1163                 break;
1164
1165         case DHD_GET_VAR:
1166         case DHD_SET_VAR: {
1167                 char *arg;
1168                 uint arglen;
1169
1170                 /* scan past the name to any arguments */
1171                 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
1172                         ;
1173
1174                 if (*arg) {
1175                         bcmerror = BCME_BUFTOOSHORT;
1176                         break;
1177                 }
1178
1179                 /* account for the NUL terminator */
1180                 arg++, arglen--;
1181
1182                 /* call with the appropriate arguments */
1183                 if (ioc->cmd == DHD_GET_VAR)
1184                         bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
1185                         buf, buflen, IOV_GET);
1186                 else
1187                         bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
1188                 if (bcmerror != BCME_UNSUPPORTED)
1189                         break;
1190
1191                 /* not in generic table, try protocol module */
1192                 if (ioc->cmd == DHD_GET_VAR)
1193                         bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
1194                                 arglen, buf, buflen, IOV_GET);
1195                 else
1196                         bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
1197                                 NULL, 0, arg, arglen, IOV_SET);
1198                 if (bcmerror != BCME_UNSUPPORTED)
1199                         break;
1200
1201                 /* if still not found, try bus module */
1202                 if (ioc->cmd == DHD_GET_VAR) {
1203                         bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
1204                                 arg, arglen, buf, buflen, IOV_GET);
1205                 } else {
1206                         bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
1207                                 NULL, 0, arg, arglen, IOV_SET);
1208                 }
1209
1210                 break;
1211         }
1212
1213         default:
1214                 bcmerror = BCME_UNSUPPORTED;
1215         }
1216
1217         return bcmerror;
1218 }
1219
1220 #ifdef SHOW_EVENTS
1221 #ifdef SHOW_LOGTRACE
1222
1223 #define AVOID_BYTE 64
1224 #define MAX_NO_OF_ARG 16
1225
1226 static int
1227 check_event_log_sequence_number(uint32 seq_no)
1228 {
1229         int32 diff;
1230         uint32 ret;
1231         static uint32 logtrace_seqnum_prev = 0;
1232
1233         diff = ntoh32(seq_no)-logtrace_seqnum_prev;
1234         switch (diff)
1235         {
1236                 case 0:
1237                         ret = -1; /* duplicate packet . drop */
1238                         break;
1239
1240                 case 1:
1241                         ret =0; /* in order */
1242                         break;
1243
1244                 default:
1245                         if ((ntoh32(seq_no) == 0) &&
1246                                 (logtrace_seqnum_prev == 0xFFFFFFFF) ) { /* in-order - Roll over */
1247                                         ret = 0;
1248                         } else {
1249
1250                                 if (diff > 0) {
1251                                         DHD_EVENT(("WLC_E_TRACE:"
1252                                                 "Event lost (log) seqnum %d nblost %d\n",
1253                                                 ntoh32(seq_no), (diff-1)));
1254                                 } else {
1255                                         DHD_EVENT(("WLC_E_TRACE:"
1256                                                 "Event Packets coming out of order!!\n"));
1257                                 }
1258                                 ret = 0;
1259                         }
1260         }
1261
1262         logtrace_seqnum_prev = ntoh32(seq_no);
1263
1264         return ret;
1265 }
1266 #endif /* SHOW_LOGTRACE */
1267
1268 static void
1269 wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
1270         void *raw_event_ptr, char *eventmask)
1271 {
1272         uint i, status, reason;
1273         bool group = FALSE, flush_txq = FALSE, link = FALSE;
1274         const char *auth_str;
1275         const char *event_name;
1276         uchar *buf;
1277         char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
1278         uint event_type, flags, auth_type, datalen;
1279
1280         event_type = ntoh32(event->event_type);
1281         flags = ntoh16(event->flags);
1282         status = ntoh32(event->status);
1283         reason = ntoh32(event->reason);
1284         BCM_REFERENCE(reason);
1285         auth_type = ntoh32(event->auth_type);
1286         datalen = ntoh32(event->datalen);
1287
1288         /* debug dump of event messages */
1289         snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x",
1290                 (uchar)event->addr.octet[0]&0xff,
1291                 (uchar)event->addr.octet[1]&0xff,
1292                 (uchar)event->addr.octet[2]&0xff,
1293                 (uchar)event->addr.octet[3]&0xff,
1294                 (uchar)event->addr.octet[4]&0xff,
1295                 (uchar)event->addr.octet[5]&0xff);
1296
1297         event_name = bcmevent_get_name(event_type);
1298         BCM_REFERENCE(event_name);
1299
1300         if (flags & WLC_EVENT_MSG_LINK)
1301                 link = TRUE;
1302         if (flags & WLC_EVENT_MSG_GROUP)
1303                 group = TRUE;
1304         if (flags & WLC_EVENT_MSG_FLUSHTXQ)
1305                 flush_txq = TRUE;
1306
1307         switch (event_type) {
1308         case WLC_E_START:
1309         case WLC_E_DEAUTH:
1310         case WLC_E_DISASSOC:
1311                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1312                 break;
1313
1314         case WLC_E_ASSOC_IND:
1315         case WLC_E_REASSOC_IND:
1316
1317                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1318                 break;
1319
1320         case WLC_E_ASSOC:
1321         case WLC_E_REASSOC:
1322                 if (status == WLC_E_STATUS_SUCCESS) {
1323                         DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
1324                 } else if (status == WLC_E_STATUS_TIMEOUT) {
1325                         DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
1326                 } else if (status == WLC_E_STATUS_FAIL) {
1327                         DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
1328                                event_name, eabuf, (int)reason));
1329                 } else {
1330                         DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
1331                                event_name, eabuf, (int)status));
1332                 }
1333                 break;
1334
1335         case WLC_E_DEAUTH_IND:
1336         case WLC_E_DISASSOC_IND:
1337                 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
1338                 break;
1339
1340         case WLC_E_AUTH:
1341         case WLC_E_AUTH_IND:
1342                 if (auth_type == DOT11_OPEN_SYSTEM)
1343                         auth_str = "Open System";
1344                 else if (auth_type == DOT11_SHARED_KEY)
1345                         auth_str = "Shared Key";
1346                 else {
1347                         snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type);
1348                         auth_str = err_msg;
1349                 }
1350                 if (event_type == WLC_E_AUTH_IND) {
1351                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
1352                 } else if (status == WLC_E_STATUS_SUCCESS) {
1353                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
1354                                 event_name, eabuf, auth_str));
1355                 } else if (status == WLC_E_STATUS_TIMEOUT) {
1356                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
1357                                 event_name, eabuf, auth_str));
1358                 } else if (status == WLC_E_STATUS_FAIL) {
1359                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
1360                                event_name, eabuf, auth_str, (int)reason));
1361                 }
1362                 BCM_REFERENCE(auth_str);
1363
1364                 break;
1365
1366         case WLC_E_JOIN:
1367         case WLC_E_ROAM:
1368         case WLC_E_SET_SSID:
1369                 if (status == WLC_E_STATUS_SUCCESS) {
1370                         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1371                 } else if (status == WLC_E_STATUS_FAIL) {
1372                         DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
1373                 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
1374                         DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
1375                 } else {
1376                         DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
1377                                 event_name, (int)status));
1378                 }
1379                 break;
1380
1381         case WLC_E_BEACON_RX:
1382                 if (status == WLC_E_STATUS_SUCCESS) {
1383                         DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
1384                 } else if (status == WLC_E_STATUS_FAIL) {
1385                         DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
1386                 } else {
1387                         DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
1388                 }
1389                 break;
1390
1391         case WLC_E_LINK:
1392                 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
1393                 BCM_REFERENCE(link);
1394                 break;
1395
1396         case WLC_E_MIC_ERROR:
1397                 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
1398                        event_name, eabuf, group, flush_txq));
1399                 BCM_REFERENCE(group);
1400                 BCM_REFERENCE(flush_txq);
1401                 break;
1402
1403         case WLC_E_ICV_ERROR:
1404         case WLC_E_UNICAST_DECODE_ERROR:
1405         case WLC_E_MULTICAST_DECODE_ERROR:
1406                 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
1407                        event_name, eabuf));
1408                 break;
1409
1410         case WLC_E_TXFAIL:
1411                 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
1412                 break;
1413
1414         case WLC_E_SCAN_COMPLETE:
1415         case WLC_E_ASSOC_REQ_IE:
1416         case WLC_E_ASSOC_RESP_IE:
1417         case WLC_E_PMKID_CACHE:
1418                 DHD_EVENT(("MACEVENT: %s\n", event_name));
1419                 break;
1420
1421         case WLC_E_PFN_NET_FOUND:
1422         case WLC_E_PFN_NET_LOST:
1423         case WLC_E_PFN_SCAN_COMPLETE:
1424         case WLC_E_PFN_SCAN_NONE:
1425         case WLC_E_PFN_SCAN_ALLGONE:
1426                 DHD_EVENT(("PNOEVENT: %s\n", event_name));
1427                 break;
1428
1429         case WLC_E_PSK_SUP:
1430         case WLC_E_PRUNE:
1431                 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
1432                            event_name, (int)status, (int)reason));
1433                 break;
1434
1435 #ifdef WIFI_ACT_FRAME
1436         case WLC_E_ACTION_FRAME:
1437                 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
1438                 break;
1439 #endif /* WIFI_ACT_FRAME */
1440
1441 #ifdef SHOW_LOGTRACE
1442         case WLC_E_TRACE:
1443         {
1444                 msgtrace_hdr_t hdr;
1445                 uint32 nblost;
1446                 uint8 count;
1447                 char *s, *p;
1448                 static uint32 seqnum_prev = 0;
1449                 uint32 *record = NULL;
1450                 uint32 *log_ptr =  NULL;
1451                 uint32 writeindex = 0;
1452                 event_log_hdr_t event_hdr;
1453                 int no_of_fmts = 0;
1454                 char *fmt = NULL;
1455                 dhd_event_log_t *raw_event = (dhd_event_log_t *) raw_event_ptr;
1456
1457                 buf = (uchar *) event_data;
1458                 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
1459
1460                 if (hdr.version != MSGTRACE_VERSION) {
1461                         DHD_EVENT(("\nMACEVENT: %s [unsupported version --> "
1462                                 "dhd version:%d dongle version:%d]\n",
1463                                 event_name, MSGTRACE_VERSION, hdr.version));
1464                         /* Reset datalen to avoid display below */
1465                         datalen = 0;
1466                         break;
1467                 }
1468
1469                 if (hdr.trace_type == MSGTRACE_HDR_TYPE_MSG) {
1470                         /* There are 2 bytes available at the end of data */
1471                         buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
1472
1473                         if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
1474                                 DHD_EVENT(("WLC_E_TRACE: [Discarded traces in dongle -->"
1475                                         "discarded_bytes %d discarded_printf %d]\n",
1476                                         ntoh32(hdr.discarded_bytes),
1477                                         ntoh32(hdr.discarded_printf)));
1478                         }
1479
1480                         nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
1481                         if (nblost > 0) {
1482                                 DHD_EVENT(("WLC_E_TRACE:"
1483                                         "[Event lost (msg) --> seqnum %d nblost %d\n",
1484                                         ntoh32(hdr.seqnum), nblost));
1485                         }
1486                         seqnum_prev = ntoh32(hdr.seqnum);
1487
1488                         /* Display the trace buffer. Advance from
1489                          * \n to \n to avoid display big
1490                          * printf (issue with Linux printk )
1491                          */
1492                         p = (char *)&buf[MSGTRACE_HDRLEN];
1493                         while (*p != '\0' && (s = strstr(p, "\n")) != NULL) {
1494                                 *s = '\0';
1495                                 DHD_EVENT(("%s\n", p));
1496                                 p = s+1;
1497                         }
1498                         if (*p)
1499                                 DHD_EVENT(("%s", p));
1500
1501                         /* Reset datalen to avoid display below */
1502                         datalen = 0;
1503
1504                 } else if (hdr.trace_type == MSGTRACE_HDR_TYPE_LOG) {
1505                         /* Let the standard event printing work for now */
1506                         uint32 timestamp, w, malloc_len;
1507
1508                         if (check_event_log_sequence_number(hdr.seqnum)) {
1509
1510                                 DHD_EVENT(("%s: WLC_E_TRACE:"
1511                                         "[Event duplicate (log) %d] dropping!!\n",
1512                                         __FUNCTION__, hdr.seqnum));
1513                                 return; /* drop duplicate events */
1514                         }
1515
1516                         p = (char *)&buf[MSGTRACE_HDRLEN];
1517                         datalen -= MSGTRACE_HDRLEN;
1518                         w = ntoh32((uint32)*p);
1519                         p += 4;
1520                         datalen -= 4;
1521                         timestamp = ntoh32((uint32)*p);
1522                         BCM_REFERENCE(timestamp);
1523                         BCM_REFERENCE(w);
1524
1525                         DHD_EVENT(("timestamp %x%x\n", timestamp, w));
1526
1527                         if (raw_event->fmts) {
1528                                 malloc_len = datalen+ AVOID_BYTE;
1529                                 record = (uint32 *)MALLOC(dhd_pub->osh, malloc_len);
1530                                 if (record == NULL) {
1531                                         DHD_EVENT(("MSGTRACE_HDR_TYPE_LOG:"
1532                                                 "malloc failed\n"));
1533                                         return;
1534                                 }
1535                                 log_ptr = (uint32 *) (p + datalen);
1536                                 writeindex = datalen/4;
1537
1538                                 if (record) {
1539                                         while (datalen > 4) {
1540                                                 log_ptr--;
1541                                                 datalen -= 4;
1542                                                 event_hdr.t = *log_ptr;
1543                                                 /*
1544                                                  * Check for partially overriten entries
1545                                                  */
1546                                                 if (log_ptr - (uint32 *) p < event_hdr.count) {
1547                                                                 break;
1548                                                 }
1549                                                 /*
1550                                                 * Check for end of the Frame.
1551                                                 */
1552                                                 if (event_hdr.tag ==  EVENT_LOG_TAG_NULL) {
1553                                                         continue;
1554                                                 }
1555                                                 /*
1556                                                 * Check For Special Time Stamp Packet
1557                                                 */
1558                                                 if (event_hdr.tag == EVENT_LOG_TAG_TS) {
1559                                                         datalen -= 12;
1560                                                         log_ptr = log_ptr - 3;
1561                                                         continue;
1562                                                 }
1563
1564                                                 log_ptr[0] = event_hdr.t;
1565                                                 if (event_hdr.count > MAX_NO_OF_ARG) {
1566                                                         break;
1567                                                 }
1568                                                 /* Now place the header at the front
1569                                                 * and copy back.
1570                                                 */
1571                                                 log_ptr -= event_hdr.count;
1572
1573                                                 writeindex = writeindex - event_hdr.count;
1574                                                 record[writeindex++] = event_hdr.t;
1575                                                 for (count = 0; count < (event_hdr.count-1);
1576                                                         count++) {
1577                                                         record[writeindex++] = log_ptr[count];
1578                                                 }
1579                                                 writeindex = writeindex - event_hdr.count;
1580                                                 datalen = datalen - (event_hdr.count * 4);
1581                                                 no_of_fmts++;
1582                                         }
1583                                 }
1584
1585                                 while (no_of_fmts--)
1586                                 {
1587                                         event_log_hdr_t event_hdr;
1588                                         event_hdr.t = record[writeindex];
1589
1590                                         if ((event_hdr.fmt_num>>2) < raw_event->num_fmts) {
1591                                                 fmt = raw_event->fmts[event_hdr.fmt_num>>2];
1592                                                 DHD_EVENT((fmt,
1593                                                         record[writeindex + 1],
1594                                                         record[writeindex + 2],
1595                                                         record[writeindex + 3],
1596                                                         record[writeindex + 4],
1597                                                         record[writeindex + 5],
1598                                                         record[writeindex + 6],
1599                                                         record[writeindex + 7],
1600                                                         record[writeindex + 8],
1601                                                         record[writeindex + 9],
1602                                                         record[writeindex + 10],
1603                                                         record[writeindex + 11],
1604                                                         record[writeindex + 12],
1605                                                         record[writeindex + 13],
1606                                                         record[writeindex + 14],
1607                                                         record[writeindex + 15],
1608                                                         record[writeindex + 16]));
1609
1610                                                 if (fmt[strlen(fmt) - 1] != '\n') {
1611                                                         /* Add newline if missing */
1612                                                         DHD_EVENT(("\n"));
1613                                                 }
1614                                         }
1615
1616                                         writeindex = writeindex + event_hdr.count;
1617                                 }
1618
1619                                 if (record) {
1620                                         MFREE(dhd_pub->osh, record, malloc_len);
1621                                         record = NULL;
1622                                 }
1623                         } else {
1624                                 while (datalen > 4) {
1625                                         p += 4;
1626                                         datalen -= 4;
1627                                         /* Print each word.  DO NOT ntoh it.  */
1628                                         DHD_EVENT((" %8.8x", *((uint32 *) p)));
1629                                 }
1630                                 DHD_EVENT(("\n"));
1631                         }
1632                         datalen = 0;
1633                 }
1634                 break;
1635         }
1636 #endif /* SHOW_LOGTRACE */
1637
1638         case WLC_E_RSSI:
1639                 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
1640                 break;
1641
1642         case WLC_E_SERVICE_FOUND:
1643         case WLC_E_P2PO_ADD_DEVICE:
1644         case WLC_E_P2PO_DEL_DEVICE:
1645                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1646                 break;
1647
1648 #ifdef BT_WIFI_HANDOBER
1649         case WLC_E_BT_WIFI_HANDOVER_REQ:
1650                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
1651                 break;
1652 #endif
1653
1654         default:
1655                 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
1656                        event_name, event_type, eabuf, (int)status, (int)reason,
1657                        (int)auth_type));
1658                 break;
1659         }
1660
1661         /* show any appended data */
1662         if (DHD_BYTES_ON() && DHD_EVENT_ON() && datalen) {
1663                 buf = (uchar *) event_data;
1664                 BCM_REFERENCE(buf);
1665                 DHD_EVENT((" data (%d) : ", datalen));
1666                 for (i = 0; i < datalen; i++)
1667                         DHD_EVENT((" 0x%02x ", *buf++));
1668                 DHD_EVENT(("\n"));
1669         }
1670 }
1671 #endif /* SHOW_EVENTS */
1672
1673 int
1674 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
1675         wl_event_msg_t *event, void **data_ptr, void *raw_event)
1676 {
1677         /* check whether packet is a BRCM event pkt */
1678         bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
1679         uint8 *event_data;
1680         uint32 type, status, datalen;
1681         uint16 flags;
1682         int evlen;
1683         int hostidx;
1684
1685         if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
1686                 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
1687                 return (BCME_ERROR);
1688         }
1689
1690         /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
1691         if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
1692                 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
1693                 return (BCME_ERROR);
1694         }
1695
1696         *data_ptr = &pvt_data[1];
1697         event_data = *data_ptr;
1698
1699
1700         /* memcpy since BRCM event pkt may be unaligned. */
1701         memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
1702
1703         type = ntoh32_ua((void *)&event->event_type);
1704         flags = ntoh16_ua((void *)&event->flags);
1705         status = ntoh32_ua((void *)&event->status);
1706         datalen = ntoh32_ua((void *)&event->datalen);
1707         evlen = datalen + sizeof(bcm_event_t);
1708
1709         /* find equivalent host index for event ifidx */
1710         hostidx = dhd_ifidx2hostidx(dhd_pub->info, event->ifidx);
1711
1712         switch (type) {
1713 #ifdef PROP_TXSTATUS
1714         case WLC_E_FIFO_CREDIT_MAP:
1715                 dhd_wlfc_enable(dhd_pub);
1716                 dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data);
1717                 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1718                         "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
1719                         event_data[2],
1720                         event_data[3], event_data[4], event_data[5]));
1721                 break;
1722
1723         case WLC_E_BCMC_CREDIT_SUPPORT:
1724                 dhd_wlfc_BCMCCredit_support_event(dhd_pub);
1725                 break;
1726 #endif
1727
1728         case WLC_E_IF:
1729                 {
1730                 struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data;
1731
1732                 /* Ignore the event if NOIF is set */
1733                 if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) {
1734                         DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
1735                         return (BCME_UNSUPPORTED);
1736                 }
1737 #ifdef PCIE_FULL_DONGLE
1738                 dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx,
1739                         ifevent->opcode, ifevent->role);
1740 #endif
1741 #ifdef PROP_TXSTATUS
1742                 {
1743                         uint8* ea = pvt_data->eth.ether_dhost;
1744                         WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1745                                       "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1746                                       ifevent->ifidx,
1747                                       ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"),
1748                                       ((ifevent->role == 0) ? "STA":"AP "),
1749                                       ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
1750                         (void)ea;
1751
1752                         if (ifevent->opcode == WLC_E_IF_CHANGE)
1753                                 dhd_wlfc_interface_event(dhd_pub,
1754                                         eWLFC_MAC_ENTRY_ACTION_UPDATE,
1755                                         ifevent->ifidx, ifevent->role, ea);
1756                         else
1757                                 dhd_wlfc_interface_event(dhd_pub,
1758                                         ((ifevent->opcode == WLC_E_IF_ADD) ?
1759                                         eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
1760                                         ifevent->ifidx, ifevent->role, ea);
1761
1762                         /* dhd already has created an interface by default, for 0 */
1763                         if (ifevent->ifidx == 0)
1764                                 break;
1765                 }
1766 #endif /* PROP_TXSTATUS */
1767
1768                 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
1769                         if (ifevent->opcode == WLC_E_IF_ADD) {
1770                                 if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname,
1771                                         event->addr.octet)) {
1772
1773                                         DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d  %s\n",
1774                                                 __FUNCTION__, ifevent->ifidx, event->ifname));
1775                                         return (BCME_ERROR);
1776                                 }
1777                         } else if (ifevent->opcode == WLC_E_IF_DEL) {
1778                                 dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
1779                                         event->addr.octet);
1780                         } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
1781 #ifdef WL_CFG80211
1782                                 wl_cfg80211_notify_ifchange(ifevent->ifidx,
1783                                         event->ifname, event->addr.octet, ifevent->bssidx);
1784 #endif /* WL_CFG80211 */
1785                         }
1786                 } else {
1787 #if !defined(PROP_TXSTATUS) || !defined(PCIE_FULL_DONGLE)
1788                         DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1789                                    __FUNCTION__, ifevent->ifidx, event->ifname));
1790 #endif /* !PROP_TXSTATUS */
1791                 }
1792                         /* send up the if event: btamp user needs it */
1793                         *ifidx = hostidx;
1794                         /* push up to external supp/auth */
1795                         dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1796                 break;
1797         }
1798
1799 #ifdef WLMEDIA_HTSF
1800         case WLC_E_HTSFSYNC:
1801                 htsf_update(dhd_pub->info, event_data);
1802                 break;
1803 #endif /* WLMEDIA_HTSF */
1804 #if defined(NDISVER) && (NDISVER >= 0x0630)
1805         case WLC_E_NDIS_LINK:
1806                 break;
1807 #else
1808         case WLC_E_NDIS_LINK: {
1809                 uint32 temp = hton32(WLC_E_LINK);
1810
1811                 memcpy((void *)(&pvt_data->event.event_type), &temp,
1812                        sizeof(pvt_data->event.event_type));
1813                 break;
1814         }
1815 #endif /* NDISVER >= 0x0630 */
1816         case WLC_E_PFN_NET_FOUND:
1817         case WLC_E_PFN_NET_LOST:
1818                 break;
1819 #if defined(PNO_SUPPORT)
1820         case WLC_E_PFN_BSSID_NET_FOUND:
1821         case WLC_E_PFN_BSSID_NET_LOST:
1822         case WLC_E_PFN_BEST_BATCHING:
1823                 dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
1824                 break;
1825 #endif 
1826                 /* These are what external supplicant/authenticator wants */
1827         case WLC_E_ASSOC_IND:
1828         case WLC_E_AUTH_IND:
1829         case WLC_E_REASSOC_IND:
1830                 dhd_findadd_sta(dhd_pub, hostidx, &event->addr.octet);
1831                 break;
1832         case WLC_E_LINK:
1833 #ifdef PCIE_FULL_DONGLE
1834                 if (dhd_update_interface_link_status(dhd_pub, (uint8)hostidx,
1835                         (uint8)flags) != BCME_OK)
1836                         break;
1837                 if (!flags) {
1838                         dhd_flow_rings_delete(dhd_pub, hostidx);
1839                 }
1840                 /* fall through */
1841 #endif
1842         case WLC_E_DEAUTH:
1843         case WLC_E_DEAUTH_IND:
1844         case WLC_E_DISASSOC:
1845         case WLC_E_DISASSOC_IND:
1846                 if (type != WLC_E_LINK) {
1847                         dhd_del_sta(dhd_pub, hostidx, &event->addr.octet);
1848                 }
1849                 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1850                            __FUNCTION__, type, flags, status));
1851 #ifdef PCIE_FULL_DONGLE
1852                 if (type != WLC_E_LINK) {
1853                         uint8 ifindex = (uint8)hostidx;
1854                         uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
1855                         if (DHD_IF_ROLE_STA(role)) {
1856                                 dhd_flow_rings_delete(dhd_pub, ifindex);
1857                         } else {
1858                                 dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
1859                                         &event->addr.octet[0]);
1860                         }
1861                 }
1862 #endif
1863                 /* fall through */
1864         default:
1865                 *ifidx = hostidx;
1866                 /* push up to external supp/auth */
1867                 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1868                 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1869                            __FUNCTION__, type, flags, status));
1870                 BCM_REFERENCE(flags);
1871                 BCM_REFERENCE(status);
1872
1873                 break;
1874         }
1875
1876 #ifdef SHOW_EVENTS
1877         wl_show_host_event(dhd_pub, event,
1878                 (void *)event_data, raw_event, dhd_pub->enable_log);
1879 #endif /* SHOW_EVENTS */
1880
1881         return (BCME_OK);
1882 }
1883
1884 void
1885 wl_event_to_host_order(wl_event_msg_t * evt)
1886 {
1887         /* Event struct members passed from dongle to host are stored in network
1888          * byte order. Convert all members to host-order.
1889          */
1890         evt->event_type = ntoh32(evt->event_type);
1891         evt->flags = ntoh16(evt->flags);
1892         evt->status = ntoh32(evt->status);
1893         evt->reason = ntoh32(evt->reason);
1894         evt->auth_type = ntoh32(evt->auth_type);
1895         evt->datalen = ntoh32(evt->datalen);
1896         evt->version = ntoh16(evt->version);
1897 }
1898
1899 void
1900 dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1901 {
1902 #ifdef DHD_DEBUG
1903         int i, j = 0;
1904         unsigned char *buf = pbuf;
1905
1906         if (bytes_per_line == 0) {
1907                 bytes_per_line = len;
1908         }
1909
1910         for (i = 0; i < len; i++) {
1911                 printf("%2.2x", *buf++);
1912                 j++;
1913                 if (j == bytes_per_line) {
1914                         printf("\n");
1915                         j = 0;
1916                 } else {
1917                         printf(":");
1918                 }
1919         }
1920         printf("\n");
1921 #endif /* DHD_DEBUG */
1922 }
1923 #ifndef strtoul
1924 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1925 #endif
1926
1927 #ifdef PKT_FILTER_SUPPORT
1928 /* Convert user's input in hex pattern to byte-size mask */
1929 static int
1930 wl_pattern_atoh(char *src, char *dst)
1931 {
1932         int i;
1933         if (strncmp(src, "0x", 2) != 0 &&
1934             strncmp(src, "0X", 2) != 0) {
1935                 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1936                 return -1;
1937         }
1938         src = src + 2; /* Skip past 0x */
1939         if (strlen(src) % 2 != 0) {
1940                 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1941                 return -1;
1942         }
1943         for (i = 0; *src != '\0'; i++) {
1944                 char num[3];
1945                 bcm_strncpy_s(num, sizeof(num), src, 2);
1946                 num[2] = '\0';
1947                 dst[i] = (uint8)strtoul(num, NULL, 16);
1948                 src += 2;
1949         }
1950         return i;
1951 }
1952
1953 void
1954 dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1955 {
1956         char                            *argv[8];
1957         int                                     i = 0;
1958         const char                      *str;
1959         int                                     buf_len;
1960         int                                     str_len;
1961         char                            *arg_save = 0, *arg_org = 0;
1962         int                                     rc;
1963         char                            buf[32] = {0};
1964         wl_pkt_filter_enable_t  enable_parm;
1965         wl_pkt_filter_enable_t  * pkt_filterp;
1966
1967         if (!arg)
1968                 return;
1969
1970         if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1971                 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
1972                 goto fail;
1973         }
1974         arg_org = arg_save;
1975         memcpy(arg_save, arg, strlen(arg) + 1);
1976
1977         argv[i] = bcmstrtok(&arg_save, " ", 0);
1978
1979         i = 0;
1980         if (argv[i] == NULL) {
1981                 DHD_ERROR(("No args provided\n"));
1982                 goto fail;
1983         }
1984
1985         str = "pkt_filter_enable";
1986         str_len = strlen(str);
1987         bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1);
1988         buf[ sizeof(buf) - 1 ] = '\0';
1989         buf_len = str_len + 1;
1990
1991         pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1992
1993         /* Parse packet filter id. */
1994         enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1995         if (dhd_conf_del_pkt_filter(dhd, enable_parm.id))
1996                 goto fail;
1997
1998         /* Parse enable/disable value. */
1999         enable_parm.enable = htod32(enable);
2000
2001         buf_len += sizeof(enable_parm);
2002         memcpy((char *)pkt_filterp,
2003                &enable_parm,
2004                sizeof(enable_parm));
2005
2006         /* Enable/disable the specified filter. */
2007         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2008         rc = rc >= 0 ? 0 : rc;
2009         if (rc)
2010                 DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n",
2011                 __FUNCTION__, enable?"enable":"disable", arg, rc));
2012         else
2013                 DHD_TRACE(("%s: successfully %s pktfilter %s\n",
2014                 __FUNCTION__, enable?"enable":"disable", arg));
2015
2016         /* Contorl the master mode */
2017         bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
2018         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
2019         rc = rc >= 0 ? 0 : rc;
2020         if (rc)
2021                 DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n",
2022                 __FUNCTION__, master_mode, rc));
2023
2024 fail:
2025         if (arg_org)
2026                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
2027 }
2028
2029 void
2030 dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
2031 {
2032         const char                      *str;
2033         wl_pkt_filter_t         pkt_filter;
2034         wl_pkt_filter_t         *pkt_filterp;
2035         int                                     buf_len;
2036         int                                     str_len;
2037         int                             rc;
2038         uint32                          mask_size;
2039         uint32                          pattern_size;
2040         char                            *argv[8], * buf = 0;
2041         int                                     i = 0;
2042         char                            *arg_save = 0, *arg_org = 0;
2043 #define BUF_SIZE                2048
2044
2045         if (!arg)
2046                 return;
2047
2048         if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
2049                 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
2050                 goto fail;
2051         }
2052
2053         arg_org = arg_save;
2054
2055         if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
2056                 DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
2057                 goto fail;
2058         }
2059
2060         memcpy(arg_save, arg, strlen(arg) + 1);
2061
2062         if (strlen(arg) > BUF_SIZE) {
2063                 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
2064                 goto fail;
2065         }
2066
2067         argv[i] = bcmstrtok(&arg_save, " ", 0);
2068         while (argv[i++])
2069                 argv[i] = bcmstrtok(&arg_save, " ", 0);
2070
2071         i = 0;
2072         if (argv[i] == NULL) {
2073                 DHD_ERROR(("No args provided\n"));
2074                 goto fail;
2075         }
2076
2077         str = "pkt_filter_add";
2078         str_len = strlen(str);
2079         bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
2080         buf[ str_len ] = '\0';
2081         buf_len = str_len + 1;
2082
2083         pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
2084
2085         /* Parse packet filter id. */
2086         pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
2087         if (dhd_conf_del_pkt_filter(dhd, pkt_filter.id))
2088                 goto fail;
2089
2090         if (argv[++i] == NULL) {
2091                 DHD_ERROR(("Polarity not provided\n"));
2092                 goto fail;
2093         }
2094
2095         /* Parse filter polarity. */
2096         pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
2097
2098         if (argv[++i] == NULL) {
2099                 DHD_ERROR(("Filter type not provided\n"));
2100                 goto fail;
2101         }
2102
2103         /* Parse filter type. */
2104         pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
2105
2106         if (argv[++i] == NULL) {
2107                 DHD_ERROR(("Offset not provided\n"));
2108                 goto fail;
2109         }
2110
2111         /* Parse pattern filter offset. */
2112         pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
2113
2114         if (argv[++i] == NULL) {
2115                 DHD_ERROR(("Bitmask not provided\n"));
2116                 goto fail;
2117         }
2118
2119         /* Parse pattern filter mask. */
2120         mask_size =
2121                 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
2122
2123         if (argv[++i] == NULL) {
2124                 DHD_ERROR(("Pattern not provided\n"));
2125                 goto fail;
2126         }
2127
2128         /* Parse pattern filter pattern. */
2129         pattern_size =
2130                 htod32(wl_pattern_atoh(argv[i],
2131                  (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
2132
2133         if (mask_size != pattern_size) {
2134                 DHD_ERROR(("Mask and pattern not the same size\n"));
2135                 goto fail;
2136         }
2137
2138         pkt_filter.u.pattern.size_bytes = mask_size;
2139         buf_len += WL_PKT_FILTER_FIXED_LEN;
2140         buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
2141
2142         /* Keep-alive attributes are set in local       variable (keep_alive_pkt), and
2143         ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
2144         ** guarantee that the buffer is properly aligned.
2145         */
2146         memcpy((char *)pkt_filterp,
2147                &pkt_filter,
2148                WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
2149
2150         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2151         rc = rc >= 0 ? 0 : rc;
2152
2153         if (rc)
2154                 DHD_ERROR(("%s: failed to add pktfilter %s, retcode = %d\n",
2155                 __FUNCTION__, arg, rc));
2156         else
2157                 DHD_TRACE(("%s: successfully added pktfilter %s\n",
2158                 __FUNCTION__, arg));
2159
2160 fail:
2161         if (arg_org)
2162                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
2163
2164         if (buf)
2165                 MFREE(dhd->osh, buf, BUF_SIZE);
2166 }
2167
2168 void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id)
2169 {
2170         char iovbuf[32];
2171         int ret;
2172
2173         bcm_mkiovar("pkt_filter_delete", (char *)&id, 4, iovbuf, sizeof(iovbuf));
2174         ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
2175         if (ret < 0) {
2176                 DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n",
2177                         __FUNCTION__, id, ret));
2178         }
2179         else
2180                 DHD_TRACE(("%s: successfully deleted pktfilter %d\n",
2181                 __FUNCTION__, id));
2182 }
2183 #endif /* PKT_FILTER_SUPPORT */
2184
2185 /* ========================== */
2186 /* ==== ARP OFFLOAD SUPPORT = */
2187 /* ========================== */
2188 #ifdef ARP_OFFLOAD_SUPPORT
2189 void
2190 dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
2191 {
2192         char iovbuf[DHD_IOVAR_BUF_SIZE];
2193         int iovar_len;
2194         int retcode;
2195
2196         iovar_len = bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
2197         if (!iovar_len) {
2198                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2199                         __FUNCTION__, sizeof(iovbuf)));
2200                 return;
2201         }
2202
2203         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
2204         retcode = retcode >= 0 ? 0 : retcode;
2205         if (retcode)
2206                 DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
2207                         __FUNCTION__, arp_mode, retcode));
2208         else
2209                 DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n",
2210                         __FUNCTION__, arp_mode));
2211 }
2212
2213 void
2214 dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
2215 {
2216         char iovbuf[DHD_IOVAR_BUF_SIZE];
2217         int iovar_len;
2218         int retcode;
2219
2220         iovar_len = bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
2221         if (!iovar_len) {
2222                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2223                         __FUNCTION__, sizeof(iovbuf)));
2224                 return;
2225         }
2226
2227         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iovar_len, TRUE, 0);
2228         retcode = retcode >= 0 ? 0 : retcode;
2229         if (retcode)
2230                 DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
2231                         __FUNCTION__, arp_enable, retcode));
2232         else
2233                 DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n",
2234                         __FUNCTION__, arp_enable));
2235         if (arp_enable) {
2236                 uint32 version;
2237                 bcm_mkiovar("arp_version", 0, 0, iovbuf, sizeof(iovbuf));
2238                 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
2239                 if (retcode) {
2240                         DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
2241                                 __FUNCTION__, retcode));
2242                         dhd->arp_version = 1;
2243                 }
2244                 else {
2245                         memcpy(&version, iovbuf, sizeof(version));
2246                         DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version));
2247                         dhd->arp_version = version;
2248                 }
2249         }
2250 }
2251
2252 void
2253 dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx)
2254 {
2255         int ret = 0;
2256         int iov_len = 0;
2257         char iovbuf[DHD_IOVAR_BUF_SIZE];
2258
2259         if (dhd == NULL) return;
2260         if (dhd->arp_version == 1)
2261                 idx = 0;
2262
2263         iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
2264         if (!iov_len) {
2265                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2266                         __FUNCTION__, sizeof(iovbuf)));
2267                 return;
2268         }
2269         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
2270                 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2271 }
2272
2273 void
2274 dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
2275 {
2276         int ret = 0;
2277         int iov_len = 0;
2278         char iovbuf[DHD_IOVAR_BUF_SIZE];
2279
2280         if (dhd == NULL) return;
2281         if (dhd->arp_version == 1)
2282                 idx = 0;
2283
2284         iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
2285         if (!iov_len) {
2286                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2287                         __FUNCTION__, sizeof(iovbuf)));
2288                 return;
2289         }
2290         if ((ret  = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx)) < 0)
2291                 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2292 }
2293
2294 void
2295 dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx)
2296 {
2297         int iov_len = 0;
2298         char iovbuf[DHD_IOVAR_BUF_SIZE];
2299         int retcode;
2300
2301
2302         if (dhd == NULL) return;
2303         if (dhd->arp_version == 1)
2304                 idx = 0;
2305         iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr,
2306                 sizeof(ipaddr), iovbuf, sizeof(iovbuf));
2307         if (!iov_len) {
2308                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2309                         __FUNCTION__, sizeof(iovbuf)));
2310                 return;
2311         }
2312         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2313
2314         if (retcode)
2315                 DHD_ERROR(("%s: ARP ip addr add failed, retcode = %d\n",
2316                         __FUNCTION__, retcode));
2317         else
2318                 DHD_ARPOE(("%s: sARP H ipaddr entry added \n",
2319                         __FUNCTION__));
2320 }
2321
2322 int
2323 dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx)
2324 {
2325         int retcode, i;
2326         int iov_len;
2327         uint32 *ptr32 = buf;
2328         bool clr_bottom = FALSE;
2329
2330         if (!buf)
2331                 return -1;
2332         if (dhd == NULL) return -1;
2333         if (dhd->arp_version == 1)
2334                 idx = 0;
2335
2336         iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
2337         BCM_REFERENCE(iov_len);
2338         retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, idx);
2339
2340         if (retcode) {
2341                 DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n",
2342                         __FUNCTION__, retcode));
2343
2344                 return -1;
2345         }
2346
2347         /* clean up the buf, ascii reminder */
2348         for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
2349                 if (!clr_bottom) {
2350                         if (*ptr32 == 0)
2351                                 clr_bottom = TRUE;
2352                 } else {
2353                         *ptr32 = 0;
2354                 }
2355                 ptr32++;
2356         }
2357
2358         return 0;
2359 }
2360 #endif /* ARP_OFFLOAD_SUPPORT  */
2361
2362 /*
2363  * Neighbor Discovery Offload: enable NDO feature
2364  * Called  by ipv6 event handler when interface comes up/goes down
2365  */
2366 int
2367 dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable)
2368 {
2369         char iovbuf[DHD_IOVAR_BUF_SIZE];
2370         int iov_len;
2371         int retcode;
2372
2373         if (dhd == NULL)
2374                 return -1;
2375
2376         iov_len = bcm_mkiovar("ndoe", (char *)&ndo_enable, 4, iovbuf, sizeof(iovbuf));
2377         if (!iov_len) {
2378                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2379                         __FUNCTION__, sizeof(iovbuf)));
2380                 return -1;
2381         }
2382         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
2383         if (retcode)
2384                 DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n",
2385                         __FUNCTION__, ndo_enable, retcode));
2386         else
2387                 DHD_TRACE(("%s: successfully enabed ndo offload to %d\n",
2388                         __FUNCTION__, ndo_enable));
2389
2390         return retcode;
2391 }
2392
2393 /*
2394  * Neighbor Discover Offload: enable NDO feature
2395  * Called  by ipv6 event handler when interface comes up
2396  */
2397 int
2398 dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx)
2399 {
2400         int iov_len = 0;
2401         char iovbuf[DHD_IOVAR_BUF_SIZE];
2402         int retcode;
2403
2404         if (dhd == NULL)
2405                 return -1;
2406
2407         iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr,
2408                 IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf));
2409         if (!iov_len) {
2410                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2411                         __FUNCTION__, sizeof(iovbuf)));
2412                 return -1;
2413         }
2414         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2415
2416         if (retcode)
2417                 DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n",
2418                 __FUNCTION__, retcode));
2419         else
2420                 DHD_TRACE(("%s: ndo ipaddr entry added \n",
2421                 __FUNCTION__));
2422
2423         return retcode;
2424 }
2425 /*
2426  * Neighbor Discover Offload: enable NDO feature
2427  * Called  by ipv6 event handler when interface goes down
2428  */
2429 int
2430 dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx)
2431 {
2432         int iov_len = 0;
2433         char iovbuf[DHD_IOVAR_BUF_SIZE];
2434         int retcode;
2435
2436         if (dhd == NULL)
2437                 return -1;
2438
2439         iov_len = bcm_mkiovar("nd_hostip_clear", NULL,
2440                 0, iovbuf, sizeof(iovbuf));
2441         if (!iov_len) {
2442                 DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
2443                         __FUNCTION__, sizeof(iovbuf)));
2444                 return -1;
2445         }
2446         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
2447
2448         if (retcode)
2449                 DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n",
2450                 __FUNCTION__, retcode));
2451         else
2452                 DHD_TRACE(("%s: ndo ipaddr entry removed \n",
2453                 __FUNCTION__));
2454
2455         return retcode;
2456 }
2457
2458 /* send up locally generated event */
2459 void
2460 dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
2461 {
2462         switch (ntoh32(event->event_type)) {
2463 #ifdef WLBTAMP
2464         case WLC_E_BTA_HCI_EVENT:
2465                 break;
2466 #endif /* WLBTAMP */
2467         default:
2468                 break;
2469         }
2470
2471         /* Call per-port handler. */
2472         dhd_sendup_event(dhdp, event, data);
2473 }
2474
2475
2476 /*
2477  * returns = TRUE if associated, FALSE if not associated
2478  */
2479 bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
2480 {
2481         char bssid[6], zbuf[6];
2482         int ret = -1;
2483
2484         bzero(bssid, 6);
2485         bzero(zbuf, 6);
2486
2487         ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
2488         DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
2489
2490         if (ret == BCME_NOTASSOCIATED) {
2491                 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
2492         }
2493
2494         if (retval)
2495                 *retval = ret;
2496
2497         if (ret < 0)
2498                 return FALSE;
2499
2500         if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
2501                 /*  STA is assocoated BSSID is non zero */
2502
2503                 if (bss_buf) {
2504                         /* return bss if caller provided buf */
2505                         memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
2506                 }
2507                 return TRUE;
2508         } else {
2509                 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
2510                 return FALSE;
2511         }
2512 }
2513
2514 /* Function to estimate possible DTIM_SKIP value */
2515 int
2516 dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
2517 {
2518         int bcn_li_dtim = 1; /* deafult no dtim skip setting */
2519         int ret = -1;
2520         int dtim_period = 0;
2521         int ap_beacon = 0;
2522         int allowed_skip_dtim_cnt = 0;
2523         /* Check if associated */
2524         if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
2525                 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
2526                 goto exit;
2527         }
2528
2529         /* read associated AP beacon interval */
2530         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD,
2531                 &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) {
2532                 DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
2533                 goto exit;
2534         }
2535
2536         /* read associated ap's dtim setup */
2537         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
2538                 &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) {
2539                 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
2540                 goto exit;
2541         }
2542
2543         /* if not assocated just eixt */
2544         if (dtim_period == 0) {
2545                 goto exit;
2546         }
2547
2548         /* attemp to use platform defined dtim skip interval */
2549         bcn_li_dtim = dhd->suspend_bcn_li_dtim;
2550
2551         /* check if sta listen interval fits into AP dtim */
2552         if (dtim_period > CUSTOM_LISTEN_INTERVAL) {
2553                 /* AP DTIM to big for our Listen Interval : no dtim skiping */
2554                 bcn_li_dtim = NO_DTIM_SKIP;
2555                 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
2556                         __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL));
2557                 goto exit;
2558         }
2559
2560         if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) {
2561                  allowed_skip_dtim_cnt = MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon);
2562                  bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP;
2563         }
2564
2565         if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) {
2566                 /* Round up dtim_skip to fit into STAs Listen Interval */
2567                 bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period);
2568                 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
2569         }
2570
2571         DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
2572                 __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL));
2573
2574 exit:
2575         return bcn_li_dtim;
2576 }
2577
2578 /* Check if the mode supports STA MODE */
2579 bool dhd_support_sta_mode(dhd_pub_t *dhd)
2580 {
2581
2582 #ifdef  WL_CFG80211
2583         if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
2584                 return FALSE;
2585         else
2586 #endif /* WL_CFG80211 */
2587                 return TRUE;
2588 }
2589
2590 #if defined(KEEP_ALIVE)
2591 int dhd_keep_alive_onoff(dhd_pub_t *dhd)
2592 {
2593         char                            buf[32] = {0};
2594         const char                      *str;
2595         wl_mkeep_alive_pkt_t    mkeep_alive_pkt = {0};
2596         wl_mkeep_alive_pkt_t    *mkeep_alive_pktp;
2597         int                                     buf_len;
2598         int                                     str_len;
2599         int res                                 = -1;
2600
2601         if (!dhd_support_sta_mode(dhd))
2602                 return res;
2603
2604         DHD_TRACE(("%s execution\n", __FUNCTION__));
2605
2606         str = "mkeep_alive";
2607         str_len = strlen(str);
2608         strncpy(buf, str, sizeof(buf) - 1);
2609         buf[ sizeof(buf) - 1 ] = '\0';
2610         mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
2611         mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period;
2612         buf_len = str_len + 1;
2613         mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
2614         mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
2615         /* Setup keep alive zero for null packet generation */
2616         mkeep_alive_pkt.keep_alive_id = 0;
2617         mkeep_alive_pkt.len_bytes = 0;
2618         buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
2619         bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data));
2620         /* Keep-alive attributes are set in local       variable (mkeep_alive_pkt), and
2621          * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
2622          * guarantee that the buffer is properly aligned.
2623          */
2624         memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
2625
2626         res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
2627
2628         return res;
2629 }
2630 #endif /* defined(KEEP_ALIVE) */
2631 /* Android ComboSCAN support */
2632
2633 /*
2634  *  data parsing from ComboScan tlv list
2635 */
2636 int
2637 wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
2638                      int input_size, int *bytes_left)
2639 {
2640         char* str;
2641         uint16 short_temp;
2642         uint32 int_temp;
2643
2644         if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2645                 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2646                 return -1;
2647         }
2648         str = *list_str;
2649
2650         /* Clean all dest bytes */
2651         memset(dst, 0, dst_size);
2652         while (*bytes_left > 0) {
2653
2654                 if (str[0] != token) {
2655                         DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
2656                                 __FUNCTION__, token, str[0], *bytes_left));
2657                         return -1;
2658                 }
2659
2660                 *bytes_left -= 1;
2661                 str += 1;
2662
2663                 if (input_size == 1) {
2664                         memcpy(dst, str, input_size);
2665                 }
2666                 else if (input_size == 2) {
2667                         memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
2668                                 input_size);
2669                 }
2670                 else if (input_size == 4) {
2671                         memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
2672                                 input_size);
2673                 }
2674
2675                 *bytes_left -= input_size;
2676                 str += input_size;
2677                 *list_str = str;
2678                 return 1;
2679         }
2680         return 1;
2681 }
2682
2683 /*
2684  *  channel list parsing from cscan tlv list
2685 */
2686 int
2687 wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
2688                              int channel_num, int *bytes_left)
2689 {
2690         char* str;
2691         int idx = 0;
2692
2693         if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
2694                 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2695                 return -1;
2696         }
2697         str = *list_str;
2698
2699         while (*bytes_left > 0) {
2700
2701                 if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
2702                         *list_str = str;
2703                         DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2704                         return idx;
2705                 }
2706                 /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
2707                 *bytes_left -= 1;
2708                 str += 1;
2709
2710                 if (str[0] == 0) {
2711                         /* All channels */
2712                         channel_list[idx] = 0x0;
2713                 }
2714                 else {
2715                         channel_list[idx] = (uint16)str[0];
2716                         DHD_TRACE(("%s channel=%d \n", __FUNCTION__,  channel_list[idx]));
2717                 }
2718                 *bytes_left -= 1;
2719                 str += 1;
2720
2721                 if (idx++ > 255) {
2722                         DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
2723                         return -1;
2724                 }
2725         }
2726
2727         *list_str = str;
2728         return idx;
2729 }
2730
2731 /*
2732  *  SSIDs list parsing from cscan tlv list
2733  */
2734 int
2735 wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left)
2736 {
2737         char* str;
2738         int idx = 0;
2739
2740         if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
2741                 DHD_ERROR(("%s error paramters\n", __FUNCTION__));
2742                 return -1;
2743         }
2744         str = *list_str;
2745         while (*bytes_left > 0) {
2746
2747                 if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
2748                         *list_str = str;
2749                         DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
2750                         return idx;
2751                 }
2752
2753                 /* Get proper CSCAN_TLV_TYPE_SSID_IE */
2754                 *bytes_left -= 1;
2755                 str += 1;
2756
2757                 if (str[0] == 0) {
2758                         /* Broadcast SSID */
2759                         ssid[idx].SSID_len = 0;
2760                         memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
2761                         *bytes_left -= 1;
2762                         str += 1;
2763
2764                         DHD_TRACE(("BROADCAST SCAN  left=%d\n", *bytes_left));
2765                 }
2766                 else if (str[0] <= DOT11_MAX_SSID_LEN) {
2767                         /* Get proper SSID size */
2768                         ssid[idx].SSID_len = str[0];
2769                         *bytes_left -= 1;
2770                         str += 1;
2771
2772                         /* Get SSID */
2773                         if (ssid[idx].SSID_len > *bytes_left) {
2774                                 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
2775                                 __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
2776                                 return -1;
2777                         }
2778
2779                         memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
2780
2781                         *bytes_left -= ssid[idx].SSID_len;
2782                         str += ssid[idx].SSID_len;
2783
2784                         DHD_TRACE(("%s :size=%d left=%d\n",
2785                                 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
2786                 }
2787                 else {
2788                         DHD_ERROR(("### SSID size more that %d\n", str[0]));
2789                         return -1;
2790                 }
2791
2792                 if (idx++ >  max) {
2793                         DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
2794                         return -1;
2795                 }
2796         }
2797
2798         *list_str = str;
2799         return idx;
2800 }
2801
2802 /* Parse a comma-separated list from list_str into ssid array, starting
2803  * at index idx.  Max specifies size of the ssid array.  Parses ssids
2804  * and returns updated idx; if idx >= max not all fit, the excess have
2805  * not been copied.  Returns -1 on empty string, or on ssid too long.
2806  */
2807 int
2808 wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
2809 {
2810         char* str, *ptr;
2811
2812         if ((list_str == NULL) || (*list_str == NULL))
2813                 return -1;
2814
2815         for (str = *list_str; str != NULL; str = ptr) {
2816
2817                 /* check for next TAG */
2818                 if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
2819                         *list_str        = str + strlen(GET_CHANNEL);
2820                         return idx;
2821                 }
2822
2823                 if ((ptr = strchr(str, ',')) != NULL) {
2824                         *ptr++ = '\0';
2825                 }
2826
2827                 if (strlen(str) > DOT11_MAX_SSID_LEN) {
2828                         DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
2829                         return -1;
2830                 }
2831
2832                 if (strlen(str) == 0)
2833                         ssid[idx].SSID_len = 0;
2834
2835                 if (idx < max) {
2836                         bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID));
2837                         strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1);
2838                         ssid[idx].SSID_len = strlen(str);
2839                 }
2840                 idx++;
2841         }
2842         return idx;
2843 }
2844
2845 /*
2846  * Parse channel list from iwpriv CSCAN
2847  */
2848 int
2849 wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
2850 {
2851         int num;
2852         int val;
2853         char* str;
2854         char* endptr = NULL;
2855
2856         if ((list_str == NULL)||(*list_str == NULL))
2857                 return -1;
2858
2859         str = *list_str;
2860         num = 0;
2861         while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
2862                 val = (int)strtoul(str, &endptr, 0);
2863                 if (endptr == str) {
2864                         printf("could not parse channel number starting at"
2865                                 " substring \"%s\" in list:\n%s\n",
2866                                 str, *list_str);
2867                         return -1;
2868                 }
2869                 str = endptr + strspn(endptr, " ,");
2870
2871                 if (num == channel_num) {
2872                         DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
2873                                 channel_num, *list_str));
2874                         return -1;
2875                 }
2876
2877                 channel_list[num++] = (uint16)val;
2878         }
2879         *list_str = str;
2880         return num;
2881 }