upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / net / wireless / bcm4330 / src / dhd / sys / dhd_common.c
1 /*
2  * Broadcom Dongle Host Driver (DHD), common DHD core.
3  *
4  * Copyright (C) 1999-2011, Broadcom Corporation
5  * 
6  *         Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  * 
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  * 
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: dhd_common.c,v 1.57.2.21.4.1 2011-02-01 19:36:23 $
25  */
26 #include <typedefs.h>
27 #include <osl.h>
28
29 #include <epivers.h>
30 #include <bcmutils.h>
31
32 #include <bcmendian.h>
33 #include <dngl_stats.h>
34 #include <wlioctl.h>
35 #include <dhd.h>
36
37 #include <proto/bcmevent.h>
38
39 #include <dhd_bus.h>
40 #include <dhd_proto.h>
41 #include <dhd_dbg.h>
42 #include <msgtrace.h>
43
44 /*filters related headers*/
45 #include <proto/ethernet.h>
46 #include <proto/802.1d.h>
47 #include <proto/802.11.h>
48 #include <proto/bcmip.h>
49 /*filters related headers end*/
50
51
52
53 #ifdef WLMEDIA_HTSF
54 extern void htsf_update(struct dhd_info *dhd, void *data);
55 #endif
56 int dhd_msg_level;
57
58
59
60 char fw_path[MOD_PARAM_PATHLEN];
61 char nv_path[MOD_PARAM_PATHLEN];
62
63 /* Last connection success/failure status */
64 uint32 dhd_conn_event;
65 uint32 dhd_conn_status;
66 uint32 dhd_conn_reason;
67
68 #define htod32(i) i
69 #define htod16(i) i
70 #define dtoh32(i) i
71 #define dtoh16(i) i
72 /*filters*/
73 typedef struct wl_filter_tag {
74         uint32 filterid;
75         int    filtersize;
76         uint8  filterdata[100];
77         uint32 filterset;
78 }wl_filter_tag_t;
79
80 #ifdef BCM_PKTFILTER_BASE_PORT
81 /* status table for wl_filter_pref_t */
82 typedef enum {
83         REMOVED,
84         REMOVE,
85         ADD,
86         ADDED
87 } wl_filter_pref_status_t;
88
89 typedef struct wl_filter_pref {
90   uint8 set; /* 1 is configuration set, 0 is unset*/
91   uint8 type; /* 0x6 is TCP, 0x11 is UDP*/
92   wl_filter_pref_status_t status; /* 0 REMOVED, 1 REMOVE, 2 ADD , 3 ADDED   */
93   uint  port; /* Port Num*/
94   wl_filter_tag_t *filter_tag_p;
95 } wl_filter_pref_t;
96 int set_unicast_add_filter(dhd_pub_t *dhd,wl_filter_tag_t *, wl_filter_pref_t *,int );
97 int set_unicast_remove_filter(dhd_pub_t *dhd,wl_filter_tag_t *, wl_filter_pref_t *);
98 #else
99 int set_bcast_filter(dhd_pub_t *dhd, wl_filter_tag_t *);
100 int set_mcast_filter(dhd_pub_t *dhd, wl_filter_tag_t *);
101 #endif
102 int dhd_set_pktfilter_mode(dhd_pub_t *dhd, int flag);
103 int dhd_config_pktfilter(dhd_pub_t *dhd, uint32 id ,uint32 flag);
104
105 #define PKTFILTER_BCAST_ID 100
106 #define PKTFILTER_MCAST_ID 101
107 #define PKTFILTER_UCAST_ID 102
108
109 #define MAX_PKT_FILTERS 3
110 #ifdef BCM_PKTFILTER_BASE_PORT
111 #define MAX_PKT_PREFS MAX_PKT_FILTERS
112 #endif
113 wl_filter_tag_t filters[MAX_PKT_FILTERS];
114 #ifdef BCM_PKTFILTER_BASE_PORT
115 wl_filter_pref_t filters_pref[MAX_PKT_PREFS];
116 #endif
117 /*end of filters*/
118 extern void dhd_ind_scan_confirm(void *h, bool status);
119 extern int dhd_iscan_in_progress(void *h);
120 void dhd_iscan_lock(void);
121 void dhd_iscan_unlock(void);
122 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
123
124 /* Packet alignment for most efficient SDIO (can change based on platform) */
125 #ifndef DHD_SDALIGN
126 #define DHD_SDALIGN     32
127 #endif
128 #if !ISPOWEROF2(DHD_SDALIGN)
129 #error DHD_SDALIGN is not a power of 2!
130 #endif
131
132 #ifdef DHD_DEBUG
133 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
134         __DATE__ " at " __TIME__;
135 #else
136 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
137 #endif
138
139 void dhd_set_timer(void *bus, uint wdtick);
140
141
142
143 /* IOVar table */
144 enum {
145         IOV_VERSION = 1,
146         IOV_MSGLEVEL,
147         IOV_BCMERRORSTR,
148         IOV_BCMERROR,
149         IOV_WDTICK,
150         IOV_DUMP,
151         IOV_CLEARCOUNTS,
152         IOV_LOGDUMP,
153         IOV_LOGCAL,
154         IOV_LOGSTAMP,
155         IOV_GPIOOB,
156         IOV_IOCTLTIMEOUT,
157 #if defined(DHD_DEBUG)
158         IOV_CONS,
159         IOV_DCONSOLE_POLL,
160 #endif /* defined(DHD_DEBUG) */
161         IOV_BUS_TYPE,
162 #ifdef WLMEDIA_HTSF
163         IOV_WLPKTDLYSTAT_SZ,
164 #endif
165         IOV_CHANGEMTU,
166         IOV_LAST
167 };
168
169 const bcm_iovar_t dhd_iovars[] = {
170         {"version",     IOV_VERSION,    0,      IOVT_BUFFER,    sizeof(dhd_version) },
171 #ifdef DHD_DEBUG
172         {"msglevel",    IOV_MSGLEVEL,   0,      IOVT_UINT32,    0 },
173 #endif /* DHD_DEBUG */
174         {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER,        BCME_STRLEN },
175         {"bcmerror",    IOV_BCMERROR,   0,      IOVT_INT8,      0 },
176         {"wdtick",      IOV_WDTICK, 0,  IOVT_UINT32,    0 },
177         {"dump",        IOV_DUMP,       0,      IOVT_BUFFER,    DHD_IOCTL_MAXLEN },
178 #ifdef DHD_DEBUG
179         {"cons",        IOV_CONS,       0,      IOVT_BUFFER,    0 },
180         {"dconpoll",    IOV_DCONSOLE_POLL, 0,   IOVT_UINT32,    0 },
181 #endif
182         {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID,  0 },
183         {"gpioob",      IOV_GPIOOB,     0,      IOVT_UINT32,    0 },
184         {"ioctl_timeout",       IOV_IOCTLTIMEOUT,       0,      IOVT_UINT32,    0 },
185         {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
186 #ifdef WLMEDIA_HTSF
187         {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
188 #endif
189         {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
190         {NULL, 0, 0, 0, 0 }
191 };
192
193 struct dhd_cmn *
194 dhd_common_init(osl_t *osh)
195 {
196         dhd_cmn_t *cmn;
197
198         /* Init global variables at run-time, not as part of the declaration.
199          * This is required to support init/de-init of the driver. Initialization
200          * of globals as part of the declaration results in non-deterministic
201          * behavior since the value of the globals may be different on the
202          * first time that the driver is initialized vs subsequent initializations.
203          */
204         dhd_msg_level = DHD_ERROR_VAL;
205         /* Allocate private bus interface state */
206         if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) {
207                 DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__));
208                 return NULL;
209         }
210         memset(cmn, 0, sizeof(dhd_cmn_t));
211         cmn->osh = osh;
212
213 #ifdef CONFIG_BCM4329_FW_PATH
214         strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN-1);
215 #else /* CONFIG_BCM4329_FW_PATH */
216         fw_path[0] = '\0';
217 #endif /* CONFIG_BCM4329_FW_PATH */
218 #ifdef CONFIG_BCM4329_NVRAM_PATH
219         strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
220 #else /* CONFIG_BCM4329_NVRAM_PATH */
221         nv_path[0] = '\0';
222 #endif /* CONFIG_BCM4329_NVRAM_PATH */
223         return cmn;
224 }
225
226 void
227 dhd_common_deinit(dhd_pub_t *dhd_pub)
228 {
229         osl_t *osh;
230         dhd_cmn_t *cmn = dhd_pub->cmn;
231
232         if (!cmn)
233                 return;
234
235         osh = cmn->osh;
236         dhd_pub->cmn = NULL;
237         MFREE(osh, cmn, sizeof(dhd_cmn_t));
238 }
239
240 static int
241 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
242 {
243         char eabuf[ETHER_ADDR_STR_LEN];
244
245         struct bcmstrbuf b;
246         struct bcmstrbuf *strbuf = &b;
247
248         bcm_binit(strbuf, buf, buflen);
249
250         /* Base DHD info */
251         bcm_bprintf(strbuf, "%s\n", dhd_version);
252         bcm_bprintf(strbuf, "\n");
253         bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
254                     dhdp->up, dhdp->txoff, dhdp->busstate);
255         bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
256                     dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
257         bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
258                     dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
259         bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
260
261         bcm_bprintf(strbuf, "dongle stats:\n");
262         bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
263                     dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
264                     dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
265         bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
266                     dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
267                     dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
268         bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
269
270         bcm_bprintf(strbuf, "bus stats:\n");
271         bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
272                     dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
273         bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
274                     dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
275         bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
276                     dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
277         bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n",
278                     dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
279         bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n",
280                     dhdp->rx_readahead_cnt, dhdp->tx_realloc);
281         bcm_bprintf(strbuf, "\n");
282
283         /* Add any prot info */
284         dhd_prot_dump(dhdp, strbuf);
285         bcm_bprintf(strbuf, "\n");
286
287         /* Add any bus info */
288         dhd_bus_dump(dhdp, strbuf);
289
290         return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
291 }
292
293 int
294 dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
295 {
296         wl_ioctl_t ioc;
297
298         ioc.cmd = cmd;
299         ioc.buf = arg;
300         ioc.len = len;
301         ioc.set = set;
302
303         return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
304 }
305
306
307 int
308 dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
309 {
310         int ret;
311
312         dhd_os_proto_block(dhd_pub);
313         ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
314         dhd_os_proto_unblock(dhd_pub);
315
316         return ret;
317 }
318
319 static int
320 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
321             void *params, int plen, void *arg, int len, int val_size)
322 {
323         int bcmerror = 0;
324         int32 int_val = 0;
325
326         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
327         DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
328
329         if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
330                 goto exit;
331
332         if (plen >= (int)sizeof(int_val))
333                 bcopy(params, &int_val, sizeof(int_val));
334
335         switch (actionid) {
336         case IOV_GVAL(IOV_VERSION):
337                 /* Need to have checked buffer length */
338                 strncpy((char*)arg, dhd_version, len);
339                 break;
340
341         case IOV_GVAL(IOV_MSGLEVEL):
342                 int_val = (int32)dhd_msg_level;
343                 bcopy(&int_val, arg, val_size);
344                 break;
345
346         case IOV_SVAL(IOV_MSGLEVEL):
347                 dhd_msg_level = int_val;
348                 break;
349         case IOV_GVAL(IOV_BCMERRORSTR):
350                 strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
351                 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
352                 break;
353
354         case IOV_GVAL(IOV_BCMERROR):
355                 int_val = (int32)dhd_pub->bcmerror;
356                 bcopy(&int_val, arg, val_size);
357                 break;
358
359         case IOV_GVAL(IOV_WDTICK):
360                 int_val = (int32)dhd_watchdog_ms;
361                 bcopy(&int_val, arg, val_size);
362                 break;
363
364         case IOV_SVAL(IOV_WDTICK):
365                 if (!dhd_pub->up) {
366                         bcmerror = BCME_NOTUP;
367                         break;
368                 }
369                 dhd_os_wd_timer(dhd_pub, (uint)int_val);
370                 break;
371
372         case IOV_GVAL(IOV_DUMP):
373                 bcmerror = dhd_dump(dhd_pub, arg, len);
374                 break;
375
376 #ifdef DHD_DEBUG
377         case IOV_GVAL(IOV_DCONSOLE_POLL):
378                 int_val = (int32)dhd_console_ms;
379                 bcopy(&int_val, arg, val_size);
380                 break;
381
382         case IOV_SVAL(IOV_DCONSOLE_POLL):
383                 dhd_console_ms = (uint)int_val;
384                 break;
385
386         case IOV_SVAL(IOV_CONS):
387                 if (len > 0)
388                         bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
389                 break;
390 #endif /* DHD_DEBUG */
391
392         case IOV_SVAL(IOV_CLEARCOUNTS):
393                 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
394                 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
395                 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
396                 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
397                 dhd_pub->rx_dropped = 0;
398                 dhd_pub->rx_readahead_cnt = 0;
399                 dhd_pub->tx_realloc = 0;
400                 dhd_pub->wd_dpc_sched = 0;
401                 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
402                 dhd_bus_clearcounts(dhd_pub);
403                 break;
404
405
406         case IOV_GVAL(IOV_IOCTLTIMEOUT): {
407                 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
408                 bcopy(&int_val, arg, sizeof(int_val));
409                 break;
410         }
411
412         case IOV_SVAL(IOV_IOCTLTIMEOUT): {
413                 if (int_val <= 0)
414                         bcmerror = BCME_BADARG;
415                 else
416                         dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
417                 break;
418         }
419
420
421
422         case IOV_GVAL(IOV_BUS_TYPE):
423         /* The dhd application query the driver to check if its usb or sdio.  */
424 #ifdef BCMDHDUSB
425                 int_val = BUS_TYPE_USB;
426 #endif
427                 int_val = BUS_TYPE_SDIO;
428                 bcopy(&int_val, arg, val_size);
429                 break;
430
431
432 #ifdef WLMEDIA_HTSF
433         case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
434                 int_val = dhd_pub->htsfdlystat_sz;
435                 bcopy(&int_val, arg, val_size);
436                 break;
437
438         case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
439                 dhd_pub->htsfdlystat_sz = int_val & 0xff;
440                 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
441                 break;
442 #endif
443         case IOV_SVAL(IOV_CHANGEMTU):
444                 int_val &= 0xffff;
445                 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
446                 break;
447
448         default:
449                 bcmerror = BCME_UNSUPPORTED;
450                 break;
451         }
452
453 exit:
454         DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
455         return bcmerror;
456 }
457
458 /* Store the status of a connection attempt for later retrieval by an iovar */
459 void
460 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
461 {
462         /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
463          * because an encryption/rsn mismatch results in both events, and
464          * the important information is in the WLC_E_PRUNE.
465          */
466         if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
467               dhd_conn_event == WLC_E_PRUNE)) {
468                 dhd_conn_event = event;
469                 dhd_conn_status = status;
470                 dhd_conn_reason = reason;
471         }
472 }
473
474 bool
475 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
476 {
477         void *p;
478         int eprec = -1;         /* precedence to evict from */
479         bool discard_oldest;
480
481         /* Fast case, precedence queue is not full and we are also not
482          * exceeding total queue length
483          */
484         if (!pktq_pfull(q, prec) && !pktq_full(q)) {
485                 pktq_penq(q, prec, pkt);
486                 return TRUE;
487         }
488
489         /* Determine precedence from which to evict packet, if any */
490         if (pktq_pfull(q, prec))
491                 eprec = prec;
492         else if (pktq_full(q)) {
493                 p = pktq_peek_tail(q, &eprec);
494                 ASSERT(p);
495                 if (eprec > prec)
496                         return FALSE;
497         }
498
499         /* Evict if needed */
500         if (eprec >= 0) {
501                 /* Detect queueing to unconfigured precedence */
502                 ASSERT(!pktq_pempty(q, eprec));
503                 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
504                 if (eprec == prec && !discard_oldest)
505                         return FALSE;           /* refuse newer (incoming) packet */
506                 /* Evict packet according to discard policy */
507                 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
508                 ASSERT(p);
509
510                 PKTFREE(dhdp->osh, p, TRUE);
511         }
512
513         /* Enqueue */
514         p = pktq_penq(q, prec, pkt);
515         ASSERT(p);
516
517         return TRUE;
518 }
519
520 static int
521 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
522         void *params, int plen, void *arg, int len, bool set)
523 {
524         int bcmerror = 0;
525         int val_size;
526         const bcm_iovar_t *vi = NULL;
527         uint32 actionid;
528
529         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
530
531         ASSERT(name);
532         ASSERT(len >= 0);
533
534         /* Get MUST have return space */
535         ASSERT(set || (arg && len));
536
537         /* Set does NOT take qualifiers */
538         ASSERT(!set || (!params && !plen));
539
540         if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
541                 bcmerror = BCME_UNSUPPORTED;
542                 goto exit;
543         }
544
545         DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
546                 name, (set ? "set" : "get"), len, plen));
547
548         /* set up 'params' pointer in case this is a set command so that
549          * the convenience int and bool code can be common to set and get
550          */
551         if (params == NULL) {
552                 params = arg;
553                 plen = len;
554         }
555
556         if (vi->type == IOVT_VOID)
557                 val_size = 0;
558         else if (vi->type == IOVT_BUFFER)
559                 val_size = len;
560         else
561                 /* all other types are integer sized */
562                 val_size = sizeof(int);
563
564         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
565
566         bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
567
568 exit:
569         return bcmerror;
570 }
571
572 int
573 dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
574 {
575         int bcmerror = 0;
576
577         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
578
579         if (!buf) {
580                 return BCME_BADARG;
581         }
582
583         switch (ioc->cmd) {
584         case DHD_GET_MAGIC:
585                 if (buflen < sizeof(int))
586                         bcmerror = BCME_BUFTOOSHORT;
587                 else
588                         *(int*)buf = DHD_IOCTL_MAGIC;
589                 break;
590
591         case DHD_GET_VERSION:
592                 if (buflen < sizeof(int))
593                         bcmerror = -BCME_BUFTOOSHORT;
594                 else
595                         *(int*)buf = DHD_IOCTL_VERSION;
596                 break;
597
598         case DHD_GET_VAR:
599         case DHD_SET_VAR: {
600                 char *arg;
601                 uint arglen;
602
603                 /* scan past the name to any arguments */
604                 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
605                         ;
606
607                 if (*arg) {
608                         bcmerror = BCME_BUFTOOSHORT;
609                         break;
610                 }
611
612                 /* account for the NUL terminator */
613                 arg++, arglen--;
614
615                 /* call with the appropriate arguments */
616                 if (ioc->cmd == DHD_GET_VAR)
617                         bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
618                         buf, buflen, IOV_GET);
619                 else
620                         bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
621                 if (bcmerror != BCME_UNSUPPORTED)
622                         break;
623
624                 /* not in generic table, try protocol module */
625                 if (ioc->cmd == DHD_GET_VAR)
626                         bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
627                                 arglen, buf, buflen, IOV_GET);
628                 else
629                         bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
630                                 NULL, 0, arg, arglen, IOV_SET);
631                 if (bcmerror != BCME_UNSUPPORTED)
632                         break;
633
634                 /* if still not found, try bus module */
635                 if (ioc->cmd == DHD_GET_VAR) {
636                         bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
637                                 arg, arglen, buf, buflen, IOV_GET);
638                 } else {
639                         bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
640                                 NULL, 0, arg, arglen, IOV_SET);
641                 }
642
643                 break;
644         }
645
646         default:
647                 bcmerror = BCME_UNSUPPORTED;
648         }
649
650         return bcmerror;
651 }
652
653 #ifdef SHOW_EVENTS
654 static void
655 wl_show_host_event(wl_event_msg_t *event, void *event_data)
656 {
657         uint i, status, reason;
658         bool group = FALSE, flush_txq = FALSE, link = FALSE;
659         const char *auth_str;
660         const char *event_name;
661         uchar *buf;
662         char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
663         uint event_type, flags, auth_type, datalen;
664
665         event_type = ntoh32(event->event_type);
666         flags = ntoh16(event->flags);
667         status = ntoh32(event->status);
668         reason = ntoh32(event->reason);
669         auth_type = ntoh32(event->auth_type);
670         datalen = ntoh32(event->datalen);
671
672         /* debug dump of event messages */
673         sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
674                 (uchar)event->addr.octet[0]&0xff,
675                 (uchar)event->addr.octet[1]&0xff,
676                 (uchar)event->addr.octet[2]&0xff,
677                 (uchar)event->addr.octet[3]&0xff,
678                 (uchar)event->addr.octet[4]&0xff,
679                 (uchar)event->addr.octet[5]&0xff);
680
681         event_name = "UNKNOWN";
682         for (i = 0; i < (uint)bcmevent_names_size; i++)
683                 if (bcmevent_names[i].event == event_type)
684                         event_name = bcmevent_names[i].name;
685
686         if (flags & WLC_EVENT_MSG_LINK)
687                 link = TRUE;
688         if (flags & WLC_EVENT_MSG_GROUP)
689                 group = TRUE;
690         if (flags & WLC_EVENT_MSG_FLUSHTXQ)
691                 flush_txq = TRUE;
692
693         switch (event_type) {
694         case WLC_E_START:
695         case WLC_E_DEAUTH:
696         case WLC_E_DISASSOC:
697                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
698                 break;
699
700         case WLC_E_ASSOC_IND:
701         case WLC_E_REASSOC_IND:
702
703                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
704                 break;
705
706         case WLC_E_ASSOC:
707         case WLC_E_REASSOC:
708                 if (status == WLC_E_STATUS_SUCCESS) {
709                         DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
710                 } else if (status == WLC_E_STATUS_TIMEOUT) {
711                         DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
712                 } else if (status == WLC_E_STATUS_FAIL) {
713                         DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
714                                event_name, eabuf, (int)reason));
715                 } else {
716                         DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
717                                event_name, eabuf, (int)status));
718                 }
719                 break;
720
721         case WLC_E_DEAUTH_IND:
722         case WLC_E_DISASSOC_IND:
723                 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
724                 break;
725
726         case WLC_E_AUTH:
727         case WLC_E_AUTH_IND:
728                 if (auth_type == DOT11_OPEN_SYSTEM)
729                         auth_str = "Open System";
730                 else if (auth_type == DOT11_SHARED_KEY)
731                         auth_str = "Shared Key";
732                 else {
733                         sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
734                         auth_str = err_msg;
735                 }
736                 if (event_type == WLC_E_AUTH_IND) {
737                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
738                 } else if (status == WLC_E_STATUS_SUCCESS) {
739                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
740                                 event_name, eabuf, auth_str));
741                 } else if (status == WLC_E_STATUS_TIMEOUT) {
742                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
743                                 event_name, eabuf, auth_str));
744                 } else if (status == WLC_E_STATUS_FAIL) {
745                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
746                                event_name, eabuf, auth_str, (int)reason));
747                 }
748
749                 break;
750
751         case WLC_E_JOIN:
752         case WLC_E_ROAM:
753         case WLC_E_SET_SSID:
754                 if (status == WLC_E_STATUS_SUCCESS) {
755                         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
756                 } else if (status == WLC_E_STATUS_FAIL) {
757                         DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
758                 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
759                         DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
760                 } else {
761                         DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
762                                 event_name, (int)status));
763                 }
764                 break;
765
766         case WLC_E_BEACON_RX:
767                 if (status == WLC_E_STATUS_SUCCESS) {
768                         DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
769                 } else if (status == WLC_E_STATUS_FAIL) {
770                         DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
771                 } else {
772                         DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
773                 }
774                 break;
775
776         case WLC_E_LINK:
777                 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
778                 break;
779
780         case WLC_E_MIC_ERROR:
781                 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
782                        event_name, eabuf, group, flush_txq));
783                 break;
784
785         case WLC_E_ICV_ERROR:
786         case WLC_E_UNICAST_DECODE_ERROR:
787         case WLC_E_MULTICAST_DECODE_ERROR:
788                 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
789                        event_name, eabuf));
790                 break;
791
792         case WLC_E_TXFAIL:
793                 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
794                 break;
795
796         case WLC_E_SCAN_COMPLETE:
797         case WLC_E_PMKID_CACHE:
798                 DHD_EVENT(("MACEVENT: %s\n", event_name));
799                 break;
800
801         case WLC_E_PFN_NET_FOUND:
802         case WLC_E_PFN_NET_LOST:
803         case WLC_E_PFN_SCAN_COMPLETE:
804                 DHD_EVENT(("PNOEVENT: %s\n", event_name));
805                 break;
806
807         case WLC_E_PSK_SUP:
808         case WLC_E_PRUNE:
809                 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
810                            event_name, (int)status, (int)reason));
811                 break;
812
813 #ifdef WIFI_ACT_FRAME
814         case WLC_E_ACTION_FRAME:
815                 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
816                 break;
817 #endif /* WIFI_ACT_FRAME */
818
819         case WLC_E_TRACE: {
820                 static uint32 seqnum_prev = 0;
821                 msgtrace_hdr_t hdr;
822                 uint32 nblost;
823                 char *s, *p;
824
825                 buf = (uchar *) event_data;
826                 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
827
828                 if (hdr.version != MSGTRACE_VERSION) {
829                         printf("\nMACEVENT: %s [unsupported version --> "
830                                "dhd version:%d dongle version:%d]\n",
831                                event_name, MSGTRACE_VERSION, hdr.version);
832                         /* Reset datalen to avoid display below */
833                         datalen = 0;
834                         break;
835                 }
836
837                 /* There are 2 bytes available at the end of data */
838                 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
839
840                 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
841                         printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
842                                "discarded_bytes %d discarded_printf %d]\n",
843                                ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
844                 }
845
846                 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
847                 if (nblost > 0) {
848                         printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
849                                ntoh32(hdr.seqnum), nblost);
850                 }
851                 seqnum_prev = ntoh32(hdr.seqnum);
852
853                 /* Display the trace buffer. Advance from \n to \n to avoid display big
854                  * printf (issue with Linux printk )
855                  */
856                 p = (char *)&buf[MSGTRACE_HDRLEN];
857                 while ((s = strstr(p, "\n")) != NULL) {
858                         *s = '\0';
859                         printf("%s\n", p);
860                         p = s+1;
861                 }
862                 printf("%s\n", p);
863
864                 /* Reset datalen to avoid display below */
865                 datalen = 0;
866                 break;
867         }
868
869
870         case WLC_E_RSSI:
871                 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
872                 break;
873
874         default:
875                 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
876                        event_name, event_type, eabuf, (int)status, (int)reason,
877                        (int)auth_type));
878                 break;
879         }
880
881         /* show any appended data */
882         if (datalen) {
883                 buf = (uchar *) event_data;
884                 DHD_EVENT((" data (%d) : ", datalen));
885                 for (i = 0; i < datalen; i++)
886                         DHD_EVENT((" 0x%02x ", *buf++));
887                 DHD_EVENT(("\n"));
888         }
889 }
890 #endif /* SHOW_EVENTS */
891
892 int
893 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
894               wl_event_msg_t *event, void **data_ptr)
895 {
896         /* check whether packet is a BRCM event pkt */
897         bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
898         char *event_data;
899         uint32 type, status, reason, datalen;
900         uint16 flags;
901         int evlen;
902
903         if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
904                 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
905                 return (BCME_ERROR);
906         }
907
908         /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
909         if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
910                 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
911                 return (BCME_ERROR);
912         }
913
914         *data_ptr = &pvt_data[1];
915         event_data = *data_ptr;
916
917         /* memcpy since BRCM event pkt may be unaligned. */
918         memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
919
920         type = ntoh32_ua((void *)&event->event_type);
921         flags = ntoh16_ua((void *)&event->flags);
922         status = ntoh32_ua((void *)&event->status);
923         reason = ntoh32_ua((void *)&event->reason);
924         datalen = ntoh32_ua((void *)&event->datalen);
925         evlen = datalen + sizeof(bcm_event_t);
926
927         switch (type) {
928
929         case WLC_E_IF:
930                 {
931                 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
932
933                 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
934                         if (ifevent->action == WLC_E_IF_ADD)
935                                 dhd_add_if(dhd_pub->info, ifevent->ifidx,
936                                            NULL, event->ifname,
937                                            event->addr.octet,
938                                            ifevent->flags, ifevent->bssidx);
939                         else
940                                 dhd_del_if(dhd_pub->info, ifevent->ifidx);
941                 } else {
942                         DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
943                                    __FUNCTION__, ifevent->ifidx, event->ifname));
944                 }
945                         }
946                         /* send up the if event: btamp user needs it */
947                         *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
948                         /* push up to external supp/auth */
949                         dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
950                         break;
951
952
953 #ifdef WLMEDIA_HTSF
954         case WLC_E_HTSFSYNC:
955                 htsf_update(dhd_pub->info, event_data);
956                 break;
957 #endif /* WLMEDIA_HTSF */
958         case WLC_E_NDIS_LINK: {
959                 uint32 temp = hton32(WLC_E_LINK);
960
961                 memcpy((void *)(&pvt_data->event.event_type), &temp,
962                        sizeof(pvt_data->event.event_type));
963         }
964                 /* These are what external supplicant/authenticator wants */
965                 /* fall through */
966         case WLC_E_LINK:
967         case WLC_E_DEAUTH:
968         case WLC_E_DEAUTH_IND:
969         case WLC_E_DISASSOC:
970         case WLC_E_DISASSOC_IND:
971                 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
972                            __FUNCTION__, type, flags, status));
973                 /* fall through */
974         default:
975                 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
976                 /* push up to external supp/auth */
977                 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
978                 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
979                            __FUNCTION__, type, flags, status));
980
981                 /* put it back to WLC_E_NDIS_LINK */
982                 if (type == WLC_E_NDIS_LINK) {
983                         uint32 temp;
984
985                         temp = ntoh32_ua((void *)&event->event_type);
986                         DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
987
988                         temp = ntoh32(WLC_E_NDIS_LINK);
989                         memcpy((void *)(&pvt_data->event.event_type), &temp,
990                                sizeof(pvt_data->event.event_type));
991                 }
992                 break;
993         }
994
995 #ifdef SHOW_EVENTS
996         wl_show_host_event(event, (void *)event_data);
997 #endif /* SHOW_EVENTS */
998
999         return (BCME_OK);
1000 }
1001
1002 void
1003 wl_event_to_host_order(wl_event_msg_t * evt)
1004 {
1005         /* Event struct members passed from dongle to host are stored in network
1006          * byte order. Convert all members to host-order.
1007          */
1008         evt->event_type = ntoh32(evt->event_type);
1009         evt->flags = ntoh16(evt->flags);
1010         evt->status = ntoh32(evt->status);
1011         evt->reason = ntoh32(evt->reason);
1012         evt->auth_type = ntoh32(evt->auth_type);
1013         evt->datalen = ntoh32(evt->datalen);
1014         evt->version = ntoh16(evt->version);
1015 }
1016
1017 void
1018 dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1019 {
1020         int i, j = 0;
1021         unsigned char *buf = pbuf;
1022
1023         if (bytes_per_line == 0) {
1024                 bytes_per_line = len;
1025         }
1026
1027         for (i = 0; i < len; i++) {
1028                 printf("%2.2x", *buf++);
1029                 j++;
1030                 if (j == bytes_per_line) {
1031                         printf("\n");
1032                         j = 0;
1033                 } else {
1034                         printf(":");
1035                 }
1036         }
1037         printf("\n");
1038 }
1039
1040 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1041
1042 /* Convert user's input in hex pattern to byte-size mask */
1043 static int
1044 wl_pattern_atoh(char *src, char *dst)
1045 {
1046         int i;
1047         if (strncmp(src, "0x", 2) != 0 &&
1048             strncmp(src, "0X", 2) != 0) {
1049                 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1050                 return -1;
1051         }
1052         src = src + 2; /* Skip past 0x */
1053         if (strlen(src) % 2 != 0) {
1054                 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1055                 return -1;
1056         }
1057         for (i = 0; *src != '\0'; i++) {
1058                 char num[3];
1059                 strncpy(num, src, 2);
1060                 num[2] = '\0';
1061                 dst[i] = (uint8)strtoul(num, NULL, 16);
1062                 src += 2;
1063         }
1064         return i;
1065 }
1066
1067 extern int dhd_preinit_ioctls(dhd_pub_t *dhd);
1068
1069 void
1070 dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1071 {
1072         char                            *argv[8];
1073         int                                     i = 0;
1074         const char                      *str;
1075         int                                     buf_len;
1076         int                                     str_len;
1077         char                            *arg_save = 0, *arg_org = 0;
1078         int                                     rc;
1079         char                            buf[128];
1080         wl_pkt_filter_enable_t  enable_parm;
1081         wl_pkt_filter_enable_t  * pkt_filterp;
1082
1083         if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1084                 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1085                 goto fail;
1086         }
1087         arg_org = arg_save;
1088         memcpy(arg_save, arg, strlen(arg) + 1);
1089
1090         argv[i] = bcmstrtok(&arg_save, " ", 0);
1091
1092         i = 0;
1093         if (NULL == argv[i]) {
1094                 DHD_ERROR(("No args provided\n"));
1095                 goto fail;
1096         }
1097
1098         str = "pkt_filter_enable";
1099         str_len = strlen(str);
1100         strncpy(buf, str, str_len);
1101         buf[str_len] = '\0';
1102         buf_len = str_len + 1;
1103
1104         pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1105
1106         /* Parse packet filter id. */
1107         enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1108
1109         /* Parse enable/disable value. */
1110         enable_parm.enable = htod32(enable);
1111
1112         buf_len += sizeof(enable_parm);
1113         memcpy((char *)pkt_filterp,
1114                &enable_parm,
1115                sizeof(enable_parm));
1116
1117         /* Enable/disable the specified filter. */
1118         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1119         rc = rc >= 0 ? 0 : rc;
1120         if (rc)
1121                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1122                 __FUNCTION__, arg, rc));
1123         else
1124                 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1125                 __FUNCTION__, arg));
1126
1127         /* Contorl the master mode */
1128         bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
1129         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
1130         rc = rc >= 0 ? 0 : rc;
1131         if (rc)
1132                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1133                 __FUNCTION__, arg, rc));
1134
1135 fail:
1136         if (arg_org)
1137                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1138 }
1139
1140 void
1141 dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
1142 {
1143         const char                      *str;
1144         wl_pkt_filter_t         pkt_filter;
1145         wl_pkt_filter_t         *pkt_filterp;
1146         int                                     buf_len;
1147         int                                     str_len;
1148         int                             rc;
1149         uint32                          mask_size;
1150         uint32                          pattern_size;
1151         char                            *argv[8], * buf = 0;
1152         int                                     i = 0;
1153         char                            *arg_save = 0, *arg_org = 0;
1154 #define BUF_SIZE                2048
1155
1156         if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1157                 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1158                 goto fail;
1159         }
1160
1161         arg_org = arg_save;
1162
1163         if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1164                 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1165                 goto fail;
1166         }
1167
1168         memcpy(arg_save, arg, strlen(arg) + 1);
1169
1170         if (strlen(arg) > BUF_SIZE) {
1171                 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
1172                 goto fail;
1173         }
1174
1175         argv[i] = bcmstrtok(&arg_save, " ", 0);
1176         while (argv[i++])
1177                 argv[i] = bcmstrtok(&arg_save, " ", 0);
1178
1179         i = 0;
1180         if (NULL == argv[i]) {
1181                 DHD_ERROR(("No args provided\n"));
1182                 goto fail;
1183         }
1184
1185         str = "pkt_filter_add";
1186         str_len = strlen(str);
1187         strncpy(buf, str, str_len);
1188         buf[ str_len ] = '\0';
1189         buf_len = str_len + 1;
1190
1191         pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1192
1193         /* Parse packet filter id. */
1194         pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1195
1196         if (NULL == argv[++i]) {
1197                 DHD_ERROR(("Polarity not provided\n"));
1198                 goto fail;
1199         }
1200
1201         /* Parse filter polarity. */
1202         pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1203
1204         if (NULL == argv[++i]) {
1205                 DHD_ERROR(("Filter type not provided\n"));
1206                 goto fail;
1207         }
1208
1209         /* Parse filter type. */
1210         pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1211
1212         if (NULL == argv[++i]) {
1213                 DHD_ERROR(("Offset not provided\n"));
1214                 goto fail;
1215         }
1216
1217         /* Parse pattern filter offset. */
1218         pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1219
1220         if (NULL == argv[++i]) {
1221                 DHD_ERROR(("Bitmask not provided\n"));
1222                 goto fail;
1223         }
1224
1225         /* Parse pattern filter mask. */
1226         mask_size =
1227                 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
1228
1229         if (NULL == argv[++i]) {
1230                 DHD_ERROR(("Pattern not provided\n"));
1231                 goto fail;
1232         }
1233
1234         /* Parse pattern filter pattern. */
1235         pattern_size =
1236                 htod32(wl_pattern_atoh(argv[i],
1237                  (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
1238
1239         if (mask_size != pattern_size) {
1240                 DHD_ERROR(("Mask and pattern not the same size\n"));
1241                 goto fail;
1242         }
1243
1244         pkt_filter.u.pattern.size_bytes = mask_size;
1245         buf_len += WL_PKT_FILTER_FIXED_LEN;
1246         buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1247
1248         /* Keep-alive attributes are set in local       variable (keep_alive_pkt), and
1249         ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1250         ** guarantee that the buffer is properly aligned.
1251         */
1252         memcpy((char *)pkt_filterp,
1253                &pkt_filter,
1254                WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1255
1256         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1257         rc = rc >= 0 ? 0 : rc;
1258
1259         if (rc)
1260                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1261                 __FUNCTION__, arg, rc));
1262         else
1263                 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1264                 __FUNCTION__, arg));
1265
1266 fail:
1267         if (arg_org)
1268                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1269
1270         if (buf)
1271                 MFREE(dhd->osh, buf, BUF_SIZE);
1272 }
1273
1274 void
1275 dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
1276 {
1277         char iovbuf[32];
1278         int retcode;
1279
1280         bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1281         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1282         retcode = retcode >= 0 ? 0 : retcode;
1283         if (retcode)
1284                 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1285                 __FUNCTION__, arp_mode, retcode));
1286         else
1287                 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1288                 __FUNCTION__, arp_mode));
1289 }
1290
1291 void
1292 dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
1293 {
1294         char iovbuf[32];
1295         int retcode;
1296
1297         bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1298         retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1299         retcode = retcode >= 0 ? 0 : retcode;
1300         if (retcode)
1301                 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1302                 __FUNCTION__, arp_enable, retcode));
1303         else
1304                 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1305                 __FUNCTION__, arp_enable));
1306 }
1307
1308 /* send up locally generated event */
1309 void
1310 dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
1311 {
1312         switch (ntoh32(event->event_type)) {
1313         default:
1314                 break;
1315         }
1316
1317         /* Call per-port handler. */
1318         dhd_sendup_event(dhdp, event, data);
1319 }
1320
1321
1322
1323 #ifdef SIMPLE_ISCAN
1324
1325 uint iscan_thread_id;
1326 iscan_buf_t * iscan_chain = 0;
1327
1328 iscan_buf_t *
1329 dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1330 {
1331         iscan_buf_t *iscanbuf_alloc = 0;
1332         iscan_buf_t *iscanbuf_head;
1333
1334         DHD_TRACE(("%s: Entered\n", __FUNCTION__));
1335         dhd_iscan_lock();
1336
1337         iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
1338         if (iscanbuf_alloc == NULL)
1339                 goto fail;
1340
1341         iscanbuf_alloc->next = NULL;
1342         iscanbuf_head = *iscanbuf;
1343
1344         DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1345                    "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1346                    __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
1347
1348         if (iscanbuf_head == NULL) {
1349                 *iscanbuf = iscanbuf_alloc;
1350                 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
1351                 goto fail;
1352         }
1353
1354         while (iscanbuf_head->next)
1355                 iscanbuf_head = iscanbuf_head->next;
1356
1357         iscanbuf_head->next = iscanbuf_alloc;
1358
1359 fail:
1360         dhd_iscan_unlock();
1361         return iscanbuf_alloc;
1362 }
1363
1364 void
1365 dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1366 {
1367         iscan_buf_t *iscanbuf_free = 0;
1368         iscan_buf_t *iscanbuf_prv = 0;
1369         iscan_buf_t *iscanbuf_cur;
1370         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1371         DHD_TRACE(("%s: Entered\n", __FUNCTION__));
1372
1373         dhd_iscan_lock();
1374
1375         iscanbuf_cur = iscan_chain;
1376
1377         /* If iscan_delete is null then delete the entire 
1378          * chain or else delete specific one provided
1379          */
1380         if (!iscan_delete) {
1381                 while (iscanbuf_cur) {
1382                         iscanbuf_free = iscanbuf_cur;
1383                         iscanbuf_cur = iscanbuf_cur->next;
1384                         iscanbuf_free->next = 0;
1385                         MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1386                 }
1387                 iscan_chain = 0;
1388         } else {
1389                 while (iscanbuf_cur) {
1390                         if (iscanbuf_cur == iscan_delete)
1391                                 break;
1392                         iscanbuf_prv = iscanbuf_cur;
1393                         iscanbuf_cur = iscanbuf_cur->next;
1394                 }
1395                 if (iscanbuf_prv)
1396                         iscanbuf_prv->next = iscan_delete->next;
1397
1398                 iscan_delete->next = 0;
1399                 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1400
1401                 if (!iscanbuf_prv)
1402                         iscan_chain = 0;
1403         }
1404         dhd_iscan_unlock();
1405 }
1406
1407 iscan_buf_t *
1408 dhd_iscan_result_buf(void)
1409 {
1410         return iscan_chain;
1411 }
1412
1413 /*
1414 * delete disappeared AP from specific scan cache
1415 */
1416 int
1417 dhd_iscan_delete_bss(/* TBD void *dhdp, */ void *addr)
1418 {
1419         int i = 0, j = 0, l = 0;
1420         iscan_buf_t *iscan_cur;
1421         wl_iscan_results_t *list;
1422         wl_scan_results_t *results;
1423         wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1424
1425         uchar *s_addr = addr;
1426         DHD_TRACE(("%s: Entered\n", __FUNCTION__));
1427
1428         dhd_iscan_lock();
1429         DHD_TRACE(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
1430         __FUNCTION__, s_addr[0], s_addr[1], s_addr[2],
1431         s_addr[3], s_addr[4], s_addr[5]));
1432
1433         DHD_TRACE(("%s: Scan cache before delete\n",
1434         __FUNCTION__));
1435
1436         iscan_cur = dhd_iscan_result_buf();
1437
1438         while (iscan_cur) {
1439                         list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1440                         if (!list)
1441                                 break;
1442
1443                         results = (wl_scan_results_t *)&list->results;
1444                         if (!results)
1445                                 break;
1446
1447                         if (results->version != WL_BSS_INFO_VERSION) {
1448                         DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1449                                 __FUNCTION__, results->version));
1450                                 goto done;
1451                         }
1452
1453                         bi = results->bss_info;
1454                         for (i = 0; i < results->count; i++) {
1455                                 if (!bi)
1456                                         break;
1457
1458                                 if (!memcmp(bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
1459                                         DHD_TRACE(("%s: Del BSS[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
1460                                         __FUNCTION__, l, i, bi->BSSID.octet[0], bi->BSSID.octet[1],
1461                                         bi->BSSID.octet[2], bi->BSSID.octet[3], bi->BSSID.octet[4],
1462                                         bi->BSSID.octet[5]));
1463
1464                                         bi_new = bi;
1465                                         bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1466
1467
1468                                         for (j = i; j < results->count; j++) {
1469                                         DHD_TRACE(("%s: Moved up BSS[%2.2d:%2.2d]"
1470                                         " %X:%X:%X:%X:%X:%X\n",
1471                                         __FUNCTION__, l, j, bi->BSSID.octet[0], bi->BSSID.octet[1],
1472                                         bi->BSSID.octet[2], bi->BSSID.octet[3], bi->BSSID.octet[4],
1473                                         bi->BSSID.octet[5]));
1474
1475                                         bi_next = (wl_bss_info_t *)((uintptr)bi +
1476                                                 dtoh32(bi->length));
1477                                                         bcopy(bi, bi_new, dtoh32(bi->length));
1478                                         bi_new = (wl_bss_info_t *)((uintptr)bi_new +
1479                                                 dtoh32(bi_new->length));
1480                                                         bi = bi_next;
1481                                                 }
1482                                 results->count--;
1483                                         if (results->count == 0) {
1484                                                 /* Prune now empty partial scan list */
1485                                                 goto done;
1486                                         }
1487                                         break;
1488                                 }
1489
1490                                 bi = (wl_bss_info_t *)((uintptr)bi + dtoh32(bi->length));
1491                         }
1492                 iscan_cur = iscan_cur->next;
1493                 l++;
1494         }
1495
1496 done:
1497         DHD_TRACE(("%s: Scan cache after delete\n",
1498                 __FUNCTION__));
1499         dhd_iscan_unlock();
1500         return 0;
1501 }
1502
1503 int
1504 dhd_iscan_request(void * dhdp, uint16 action)
1505 {
1506         int rc;
1507         wl_iscan_params_t params;
1508         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1509         char buf[WLC_IOCTL_SMLEN];
1510
1511         DHD_TRACE(("%s: Entered\n", __FUNCTION__));
1512
1513         memset(&params, 0, sizeof(wl_iscan_params_t));
1514         memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
1515
1516         params.params.bss_type = DOT11_BSSTYPE_ANY;
1517         params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
1518
1519         params.params.nprobes = htod32(-1);
1520         params.params.active_time = htod32(-1);
1521         params.params.passive_time = htod32(-1);
1522         params.params.home_time = htod32(-1);
1523         params.params.channel_num = htod32(0);
1524
1525         params.version = htod32(ISCAN_REQ_VERSION);
1526         params.action = htod16(action);
1527         params.scan_duration = htod16(0);
1528
1529         bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf, WLC_IOCTL_SMLEN);
1530         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN, TRUE, 0);
1531
1532         return rc;
1533 }
1534
1535 static int
1536 dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1537 {
1538         wl_iscan_results_t *list_buf;
1539         wl_iscan_results_t list;
1540         wl_scan_results_t *results;
1541         iscan_buf_t *iscan_cur;
1542         int status = -1;
1543         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1544         int rc;
1545
1546         DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1547
1548         iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1549         if (!iscan_cur) {
1550                 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
1551                 dhd_iscan_free_buf(dhdp, 0);
1552                 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1553                 dhd_ind_scan_confirm(dhdp, FALSE);
1554                 goto fail;
1555         }
1556
1557         dhd_iscan_lock();
1558
1559         memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1560         list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
1561         results = &list_buf->results;
1562         results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1563         results->version = 0;
1564         results->count = 0;
1565
1566         memset(&list, 0, sizeof(list));
1567         list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1568         bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1569                 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1570         rc = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iscan_cur->iscan_buf,
1571                               WLC_IW_ISCAN_MAXLEN, FALSE, 0);
1572
1573         results->buflen = dtoh32(results->buflen);
1574         results->version = dtoh32(results->version);
1575         *scan_count = results->count = dtoh32(results->count);
1576         status = dtoh32(list_buf->status);
1577         DHD_TRACE(("%s: Got %d resuls\n", __FUNCTION__, results->count));
1578
1579         dhd_iscan_unlock();
1580
1581         if (!(*scan_count)) {
1582                 dhd_iscan_free_buf(dhdp, iscan_cur);
1583         }
1584 fail:
1585         return status;
1586 }
1587
1588 #endif 
1589
1590 #ifdef PNO_SUPPORT
1591 int dhd_pno_clean(dhd_pub_t *dhd)
1592 {
1593         char iovbuf[128];
1594         int pfn_enabled = 0;
1595         int iov_len = 0;
1596         int ret;
1597
1598         /* Disable pfn */
1599         iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1600         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) {
1601                 /* clear pfn */
1602                 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1603                 if (iov_len) {
1604                         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1605                                                     iov_len, TRUE, 0)) < 0) {
1606                                 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1607                         }
1608                 }
1609                 else {
1610                         ret = -1;
1611                         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
1612                 }
1613         }
1614         else
1615                 DHD_ERROR(("%s pfn enable/disable failed: code %d\n", __FUNCTION__, ret));
1616
1617         return ret;
1618 }
1619
1620 int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1621 {
1622         char iovbuf[128];
1623         uint8 bssid[6];
1624         int ret = -1;
1625
1626         if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1627                 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1628                 return ret;
1629         }
1630         memset(iovbuf, 0, sizeof(iovbuf));
1631         /* Check if disassoc to enable pno */
1632         if ((pfn_enabled) &&
1633                 ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID,
1634                 (char *)&bssid, ETHER_ADDR_LEN, TRUE, 0)) == BCME_NOTASSOCIATED)) {
1635                         DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__));
1636         }
1637         else if (pfn_enabled) {
1638                 DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n",
1639                         __FUNCTION__, ret));
1640                 return ret;
1641         }
1642         /* Enable/disable PNO */
1643         if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
1644                 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1645                                             sizeof(iovbuf), TRUE, 0)) < 0) {
1646                         DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
1647                         return ret;
1648                 }
1649                 else {
1650                         dhd->pno_enable = pfn_enabled;
1651                         DHD_TRACE(("%s set pno as %d\n", __FUNCTION__, dhd->pno_enable));
1652                 }
1653         }
1654         else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
1655
1656         return ret;
1657 }
1658
1659 /* Function to execute combined scan */
1660 int
1661 dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
1662         int pno_repeat, int pno_freq_expo_max)
1663 {
1664         int err = -1;
1665         char iovbuf[128];
1666         int k, i;
1667         wl_pfn_param_t pfn_param;
1668         wl_pfn_t        pfn_element;
1669         uint len = 0;
1670
1671         DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr));
1672
1673         if ((!dhd) && (!ssids_local)) {
1674                 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1675                 err = -1;
1676         }
1677
1678         /* Check for broadcast ssid */
1679         for (k = 0; k < nssid; k++) {
1680                 if (!ssids_local[k].SSID_len) {
1681                         DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k));
1682                         return err;
1683                 }
1684         }
1685 /* #define  PNO_DUMP 1 */
1686 #ifdef PNO_DUMP
1687         {
1688                 int j;
1689                 for (j = 0; j < nssid; j++) {
1690                         DHD_ERROR(("%d: scan  for  %s size =%d\n", j,
1691                                 ssids_local[j].SSID, ssids_local[j].SSID_len));
1692                 }
1693         }
1694 #endif /* PNO_DUMP */
1695
1696         /* clean up everything */
1697         if  ((err = dhd_pno_clean(dhd)) < 0) {
1698                 DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err));
1699                 return err;
1700         }
1701         memset(&pfn_param, 0, sizeof(pfn_param));
1702         memset(&pfn_element, 0, sizeof(pfn_element));
1703
1704         /* set pfn parameters */
1705         pfn_param.version = htod32(PFN_VERSION);
1706         pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
1707         /* check and set extra pno params */
1708         if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) {
1709                 pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT);
1710                 pfn_param.repeat = htod32(pno_repeat);
1711                 pfn_param.exp = htod32(pno_freq_expo_max);
1712         }
1713         /* set up pno scan fr */
1714         if (scan_fr  != 0)
1715                 pfn_param.scan_freq = htod32(scan_fr);
1716
1717         if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) {
1718                 DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC));
1719                 return err;
1720         }
1721         if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) {
1722                 DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC));
1723                 return err;
1724         }
1725         len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf));
1726         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0);
1727
1728         /* set all pfn ssid */
1729         for (i = 0; i < nssid; i++) {
1730
1731                 pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
1732                 pfn_element.auth = (DOT11_OPEN_SYSTEM);
1733                 pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
1734                 pfn_element.wsec = htod32(0);
1735                 pfn_element.infra = htod32(1);
1736
1737                 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len);
1738                 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
1739
1740                 if ((len =
1741                 bcm_mkiovar("pfn_add", (char *)&pfn_element,
1742                         sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) {
1743                         if ((err =
1744                         dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) {
1745                                 DHD_ERROR(("%s failed for i=%d error=%d\n",
1746                                         __FUNCTION__, i, err));
1747                                 return err;
1748                         }
1749                         else
1750                                 DHD_ERROR(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n",
1751                                         __FUNCTION__, pfn_param.scan_freq,
1752                                         pfn_param.repeat, pfn_param.exp));
1753                 }
1754                 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err));
1755         }
1756
1757         /* Enable PNO */
1758         /* dhd_pno_enable(dhd, 1); */
1759         return err;
1760 }
1761
1762 int dhd_pno_get_status(dhd_pub_t *dhd)
1763 {
1764         int ret = -1;
1765
1766         if (!dhd)
1767                 return ret;
1768         else
1769                 return (dhd->pno_enable);
1770 }
1771
1772 #endif /* PNO_SUPPORT */
1773
1774 int dhd_enable_filters(dhd_pub_t *dhd)
1775 {
1776    int i = 0;
1777    if(!dhd)
1778           return -1;
1779
1780    DHD_TRACE(("%s: Enter.. \n", __FUNCTION__));
1781 #ifdef BCM_PKTFILTER_BASE_PORT
1782    for (i = 0 ; i < MAX_PKT_FILTERS ; i++) {
1783       if(filters[i].filterset == TRUE)
1784            dhd_config_pktfilter(dhd,filters[i].filterid, TRUE);
1785    }
1786 #else
1787    dhd_config_pktfilter(dhd, PKTFILTER_BCAST_ID, TRUE);
1788    dhd_config_pktfilter(dhd, PKTFILTER_MCAST_ID, TRUE);
1789 #endif
1790    return 0;
1791 }
1792 int dhd_disable_filters(dhd_pub_t *dhd)
1793 {
1794    int i = 0;
1795    if(!dhd)
1796         return -1;
1797
1798
1799    DHD_TRACE(("%s: Enter.. \n", __FUNCTION__));
1800 #ifdef BCM_PKTFILTER_BASE_PORT
1801    for (i = 0 ; i < MAX_PKT_FILTERS ; i++) {
1802       if(filters[i].filterset == TRUE)
1803            dhd_config_pktfilter(dhd,filters[i].filterid, FALSE);
1804    }
1805 #else
1806    dhd_config_pktfilter(dhd, PKTFILTER_BCAST_ID, FALSE);
1807    dhd_config_pktfilter(dhd, PKTFILTER_MCAST_ID, FALSE);
1808 #endif
1809    return 0;
1810 }
1811
1812 int
1813 dhd_set_filter(dhd_pub_t *dhd, wl_filter_tag_t *filter)
1814 {
1815   int ret = 0;
1816   //char iovbuf[1024] = {0};
1817   char iovbuf[1000] = {0}; //reduced array size to get rid of compiler warning
1818   wl_ioctl_t ioc = {0};
1819   int ioctl_len = 0;
1820
1821   if(!dhd)
1822   {
1823         DHD_ERROR(("%s: dhd pointer NULL\n", __FUNCTION__));
1824         return -1;
1825   }
1826
1827   if((ioctl_len = strlen("pkt_filter_add") + 1 + filter->filtersize) > sizeof(iovbuf))
1828         return -1;
1829
1830
1831   ret = bcm_mkiovar("pkt_filter_add", (char *)filter->filterdata, filter->filtersize, iovbuf, sizeof(iovbuf));
1832
1833   memset(&ioc, 0 , sizeof(ioc));
1834   ioc.cmd = WLC_SET_VAR;
1835   ioc.buf = iovbuf;
1836   ioc.len = ioctl_len;
1837   ioc.set = TRUE;
1838
1839   if( (ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ioctl_len,TRUE,0) ) < 0)
1840   {
1841         DHD_ERROR(("%s: Error in add filter ret=%d \n", __FUNCTION__, ret));
1842         filter->filterset = FALSE;
1843         return -1;
1844   }
1845
1846    filter->filterset = TRUE;
1847    return 0;
1848 }
1849
1850 /* The number of bytes between the start of the 'EtherType' of the ethernet
1851  * header, and the end of the 'Destination port' of the UDP header.
1852  */
1853 #define PATTERN_SIZE_BYTES   26
1854 #define MASK_SIZE_BYTES      PATTERN_SIZE_BYTES
1855
1856    /* The 'EtherType' field is 12 bytes from the start of the ethernet header. */
1857 #define PATTERN_OFFSET       12
1858 #ifdef BCM_PKTFILTER_BASE_PORT
1859 int
1860 set_unicast_add_filter(dhd_pub_t *dhd,wl_filter_tag_t *filter, wl_filter_pref_t *filter_pref,int index)
1861 {
1862
1863    wl_pkt_filter_t         *pktfilter = NULL;
1864    wl_pkt_filter_pattern_t *filter_pattern;
1865    uint8                   *pattern;
1866    uint8                   *mask;
1867
1868    struct ether_header     ether_hdr_mask;
1869    struct bcmudp_hdr       udp_hdr_mask;
1870    struct bcmtcp_hdr       tcp_hdr_mask;
1871    struct ipv4_hdr         ip_hdr_mask;
1872    struct ether_header     ether_hdr_pattern;
1873    struct bcmudp_hdr       udp_hdr_pattern;
1874    struct bcmtcp_hdr       tcp_hdr_pattern;
1875    struct ipv4_hdr         ip_hdr_pattern;
1876
1877    /* Check whether the filter is already set */
1878    if (filter->filterset == TRUE)
1879         return 0;
1880
1881    DHD_ERROR(("%s: Enter.. \n", __FUNCTION__));
1882    pktfilter = (wl_pkt_filter_t *)filter->filterdata;
1883
1884    /* configure pattern to match against received packets*/
1885    memset(&ether_hdr_pattern,0,sizeof(ether_hdr_pattern));
1886    memset(&udp_hdr_pattern,0,sizeof(udp_hdr_pattern));
1887    memset(&tcp_hdr_pattern,0,sizeof(tcp_hdr_pattern));
1888    memset(&ip_hdr_pattern,0,sizeof(ip_hdr_pattern));
1889
1890    /*Ethernet header. Validate that 'EtherType' is IP */
1891    ether_hdr_pattern.ether_type = hton16(ETHER_TYPE_IP);
1892    if (filter_pref->type == IP_PROT_UDP) {
1893       /*IP header. Validate that 'Protocol' is UDP*/
1894        ip_hdr_pattern.prot = IP_PROT_UDP;
1895
1896       /* UDP header. Validate that 'Destination port is ' */
1897       udp_hdr_pattern.dst_port = hton16(filter_pref->port);
1898    } else if (filter_pref->type == IP_PROT_TCP) {
1899
1900        /*IP header. Validate that 'Protocol' is UDP*/
1901        ip_hdr_pattern.prot = IP_PROT_TCP;
1902
1903       /* TCP header. Validate that 'Destination port is ' */
1904       tcp_hdr_pattern.dst_port = hton16(filter_pref->port);
1905
1906    }
1907    /* configure bitmask that indicates which bits of received packets to match against specified pattern */
1908
1909    memset(&ether_hdr_mask,0,sizeof(ether_hdr_mask));
1910    memset(&udp_hdr_mask,0,sizeof(udp_hdr_mask));
1911    memset(&tcp_hdr_mask,0,sizeof(tcp_hdr_mask));
1912    memset(&ip_hdr_mask,0,sizeof(ip_hdr_mask));
1913
1914    /*Ethernet header. Validate that 'EtherType' is IP */
1915    ether_hdr_mask.ether_type = hton16(0xffff);
1916
1917    /* IP header. Validate that 'Protocol is UDP'*/
1918    ip_hdr_mask.prot = 0xff;
1919    if (filter_pref->type == IP_PROT_UDP) {
1920       udp_hdr_mask.dst_port = hton16(0xffff);
1921    }
1922    else if (filter_pref->type == IP_PROT_TCP) {
1923       /* UDP header. */
1924       tcp_hdr_mask.dst_port = hton16(0xffff);
1925
1926    }
1927    pktfilter->id = htol32(index+200);;
1928    pktfilter->type = WL_PKT_FILTER_TYPE_PATTERN_MATCH;
1929    /*1-negate mach. 0 is default*/
1930    pktfilter->negate_match = 0;
1931    pktfilter->u.pattern.offset = PATTERN_OFFSET;
1932    pktfilter->u.pattern.size_bytes = PATTERN_SIZE_BYTES;
1933
1934    filter_pattern = &pktfilter->u.pattern;
1935    mask = filter_pattern->mask_and_pattern;
1936    memcpy(mask,&ether_hdr_mask.ether_type, ETHER_TYPE_LEN);
1937    memcpy(mask+ETHER_TYPE_LEN,&ip_hdr_mask, sizeof(ip_hdr_mask));
1938    if (filter_pref->type == IP_PROT_UDP) {
1939        memcpy(mask+ETHER_TYPE_LEN + sizeof(ip_hdr_mask),&udp_hdr_mask,sizeof(udp_hdr_mask));
1940    } else if (filter_pref->type == IP_PROT_TCP) {
1941        memcpy(mask+ETHER_TYPE_LEN + sizeof(ip_hdr_mask),&tcp_hdr_mask,sizeof(tcp_hdr_mask));
1942    }
1943
1944
1945    pattern = &filter_pattern->mask_and_pattern[MASK_SIZE_BYTES];
1946    memcpy(pattern,&ether_hdr_pattern.ether_type,ETHER_TYPE_LEN);
1947    memcpy(pattern+ETHER_TYPE_LEN, &ip_hdr_pattern, sizeof(ip_hdr_pattern));
1948    if (filter_pref->type == IP_PROT_UDP) {
1949        memcpy(pattern+ETHER_TYPE_LEN+sizeof(ip_hdr_pattern),&udp_hdr_pattern,sizeof(udp_hdr_pattern));
1950    } else if (filter_pref->type == IP_PROT_TCP) {
1951        memcpy(pattern+ETHER_TYPE_LEN+sizeof(ip_hdr_pattern),&tcp_hdr_pattern,sizeof(tcp_hdr_pattern));
1952    }
1953    filter->filtersize = WL_PKT_FILTER_FIXED_LEN;
1954    filter->filtersize += (WL_PKT_FILTER_PATTERN_FIXED_LEN + MASK_SIZE_BYTES + PATTERN_SIZE_BYTES);
1955    filter->filterid = 200+index;
1956
1957    filter_pref->status = ADDED;
1958    filter_pref->filter_tag_p = filter;
1959
1960    return dhd_set_filter(dhd, filter);
1961  }
1962
1963 int
1964 set_unicast_remove_filter(dhd_pub_t *dhd,wl_filter_tag_t *filter, wl_filter_pref_t *filter_pref)
1965 {
1966
1967   int ret = 0;
1968   //char iovbuf[1024] = {0};
1969   char iovbuf[992] = {0}; //reduced array size to get rid of compiler warning
1970   wl_ioctl_t ioc = {0};
1971   int ioctl_len = 0;
1972   int val = htod32(filter->filterid);
1973   DHD_ERROR(("%s: Enter.. \n", __FUNCTION__));
1974   if(!dhd)
1975   {
1976         DHD_ERROR(("%s: dhd pointer NULL\n", __FUNCTION__));
1977         return -1;
1978   }
1979
1980   if((ioctl_len = strlen("pkt_filter_delete") + 1 + sizeof(int)) > sizeof(iovbuf))
1981         return -1;
1982
1983   ret = bcm_mkiovar("pkt_filter_delete", (char *)(&val), sizeof(val), iovbuf, sizeof(iovbuf));
1984
1985   memset(&ioc, 0 , sizeof(ioc));
1986   ioc.cmd = WLC_SET_VAR;
1987   ioc.buf = iovbuf;
1988   ioc.len = ioctl_len;
1989   ioc.set = TRUE;
1990
1991   if( (ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, ioctl_len,TRUE,0) ) < 0)
1992   {
1993         DHD_ERROR(("%s: Error in remove filter ret=%d \n", __FUNCTION__, ret));
1994         return -1;
1995   }
1996
1997    filter->filterset = FALSE;
1998    filter->filterid = 0;
1999    filter->filtersize = 0;
2000    filter_pref->status = REMOVED;
2001    filter_pref->filter_tag_p = NULL;
2002    filter_pref->set = FALSE;
2003    return 0;
2004 }
2005
2006 int
2007 dhd_custom_set_pktfilters(dhd_pub_t *dhd,int protocol,int port,int *id)
2008 {
2009    int i,j,error = 0;
2010    DHD_ERROR(("%s: Enter\n", __FUNCTION__));
2011    if (!dhd) {
2012          DHD_ERROR(("%s: dhd pointer NULL\n",__FUNCTION__));
2013          return -1;
2014    }
2015
2016    for (i = 0 ; i < MAX_PKT_PREFS ; i++)
2017    {
2018        if (*id == -1) {
2019          if (filters_pref[i].set == FALSE) {
2020               filters_pref[i].set = TRUE;
2021               filters_pref[i].port = port;
2022               filters_pref[i].status = ADD;
2023               filters_pref[i].type = (protocol == 1)? IP_PROT_TCP : IP_PROT_UDP;
2024               break;
2025          }
2026        } else {
2027            if((filters_pref[i].filter_tag_p != NULL)
2028                   && (filters_pref[i].filter_tag_p->filterid == *id)) {
2029                   filters_pref[i].status = REMOVE;
2030                   break;
2031            }
2032
2033        }
2034    }
2035    if (i == MAX_PKT_PREFS) return -1;
2036
2037    for (i = 0 ; i < MAX_PKT_PREFS ; i++)
2038     {
2039         if (filters_pref[i].set) {
2040
2041               if(filters_pref[i].status == ADD) {
2042                     for (j = 0 ; j < MAX_PKT_FILTERS ; j++) {
2043                              if(!filters[j].filterset) {
2044                                  error = set_unicast_add_filter(dhd,&filters[j],&filters_pref[i],j);
2045                                  *id = filters[j].filterid;
2046                                  break;
2047                              }
2048                     }
2049
2050
2051               } else if(filters_pref[i].status == REMOVE) {
2052                      error = set_unicast_remove_filter(dhd,filters_pref[i].filter_tag_p,&filters_pref[i]);
2053                      *id = -1;
2054               }
2055         }
2056
2057
2058     }
2059    //FALSE-Discard on match. TRUE Forward on Match
2060    error = dhd_set_pktfilter_mode(dhd, TRUE);
2061
2062    return error;
2063 }
2064
2065 #endif
2066 int
2067 dhd_set_pktfilters(dhd_pub_t *dhd)
2068 {
2069
2070    DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2071
2072    if(!dhd)
2073    {
2074          DHD_ERROR(("%s: dhd pointer NULL\n",__FUNCTION__));
2075          return -1;
2076    }
2077
2078 #ifndef BCM_PKTFILTER_BASE_PORT
2079    set_bcast_filter(dhd, &filters[0]);
2080    //set_mcast_filter(bus, &filters[1]);
2081    //FALSE-Discard on match. TRUE Forward on Match
2082    dhd_set_pktfilter_mode(dhd, FALSE);
2083 #endif
2084
2085    return 0;
2086 }
2087
2088
2089 #ifndef BCM_PKTFILTER_BASE_PORT
2090 int set_bcast_filter(dhd_pub_t *dhd, wl_filter_tag_t *filter)
2091 {
2092    int byteoffset = 0;
2093    wl_pkt_filter_t *pktfilter = NULL;
2094
2095    /* Check whether the filter is already set */
2096    if(filter->filterset == TRUE)
2097         return 0;
2098
2099    pktfilter = (wl_pkt_filter_t *)filter->filterdata;
2100
2101    pktfilter->id = htol32(PKTFILTER_BCAST_ID);
2102
2103    /*1-negate mach. 0 is default*/
2104    pktfilter->negate_match = 0;
2105
2106    pktfilter->type = 0;
2107
2108    /* Offset 0 means first byte of ethernet header */
2109    pktfilter->u.pattern.offset = 0;
2110
2111    /* mask is 1 byte */
2112    pktfilter->u.pattern.size_bytes = htol32(6);
2113
2114    /* filter mask */
2115    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2116    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2117    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2118    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2119    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2120    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2121
2122    /* filter pattern */
2123    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2124    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2125    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2126    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2127    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2128    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0xff;
2129
2130    filter->filterid = PKTFILTER_BCAST_ID;
2131
2132    filter->filtersize = WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN + byteoffset;
2133
2134    dhd_set_filter(dhd, filter);
2135
2136    return 0;
2137 }
2138
2139 int set_mcast_filter(dhd_pub_t *dhd, wl_filter_tag_t *filter)
2140 {
2141    int byteoffset = 0;
2142    wl_pkt_filter_t *pktfilter = NULL;
2143
2144    /* Check whether the filter is already set */
2145    if(filter->filterset == TRUE)
2146         return 0;
2147
2148    pktfilter = (wl_pkt_filter_t *)filter->filterdata;
2149
2150    pktfilter->id = htol32(PKTFILTER_MCAST_ID);
2151
2152    /*1-negate mach. 0 is default*/
2153    pktfilter->negate_match = 0;
2154
2155    pktfilter->type = 0;
2156
2157    /* Offset 0 means first byte of ethernet header */
2158    pktfilter->u.pattern.offset = 0;
2159
2160    /* mask is 1 byte */
2161    pktfilter->u.pattern.size_bytes = htol32(1);
2162
2163    /* filter mask */
2164    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0x01;
2165
2166    /* filter pattern */
2167    pktfilter->u.pattern.mask_and_pattern[byteoffset++] = 0x01;
2168
2169    filter->filterid = PKTFILTER_MCAST_ID;
2170
2171    filter->filtersize = WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN + byteoffset;
2172
2173    dhd_set_filter(dhd, filter);
2174
2175    return 0;
2176 }
2177 #endif
2178
2179 int dhd_set_pktfilter_mode(dhd_pub_t *dhd, int flag)
2180 {
2181
2182    int ret = 0;
2183    int len = 0;
2184    int filter_mode = flag;
2185    char iovbuf[50] = {0};
2186
2187    if(!dhd)
2188    {
2189          DHD_ERROR(("%s: dhd ptr is NULL \n",__FUNCTION__));
2190         return -1;
2191    }
2192
2193    if(dhd == NULL)
2194    {
2195          DHD_ERROR(("%s: dhd ptr is NULL \n", __FUNCTION__));
2196         return -1;
2197    }
2198
2199    /* Set filter mode. 0-Discard on match, 1- Forward on Match */
2200    if( (ret = bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, sizeof(filter_mode), iovbuf, sizeof(iovbuf))) >  0 )
2201    {
2202         len = ret;
2203
2204             if((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE,0)) < 0)
2205         {
2206            DHD_ERROR(("%s:Set filter mode failure. ret-> %d \n", __FUNCTION__, ret));
2207                return -1;
2208         }
2209
2210    }
2211    else
2212    {
2213          return -1;
2214    }
2215    return 0;
2216
2217 }
2218
2219
2220 int dhd_config_pktfilter(dhd_pub_t *dhd, uint32 id ,uint32 flag)
2221 {
2222
2223    int ret = 0;
2224    int len = 0;
2225    wl_pkt_filter_enable_t pktconfig;
2226    char iovbuf[80] = {0};
2227
2228    pktconfig.id            = id;
2229    pktconfig.enable        = flag;
2230
2231    DHD_TRACE(("%s: Enter.. Flag->%d \n", __FUNCTION__, flag));
2232    DHD_ERROR(("%s: Enter.. Flag->%d \n", __FUNCTION__, flag));
2233
2234    /* Enable filter */
2235    if( (len = bcm_mkiovar("pkt_filter_enable", (char *)&pktconfig, sizeof(pktconfig), iovbuf, sizeof(iovbuf))) > 0)
2236    {
2237
2238       if((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE,0)) < 0)
2239       {
2240           DHD_ERROR(("%s: Config packetfilter failure. ret->%d \n", __FUNCTION__, ret));
2241           return -1;
2242       }
2243    }
2244    else
2245        DHD_ERROR(("%s: bcm_mkiovar failed. \n", __FUNCTION__));
2246
2247
2248    return 0;
2249
2250 }
2251
2252