]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/staging/brcm80211/brcmfmac/dhd_common.c
staging: brcm80211: fix checkpatch error 'assignment in if condition'
[mv-sheeva.git] / drivers / staging / brcm80211 / brcmfmac / dhd_common.c
1 /*
2  * Copyright (c) 2010 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <typedefs.h>
17 #include <osl.h>
18 #include <bcmutils.h>
19 #include <bcmendian.h>
20 #include <dngl_stats.h>
21 #include <dhd.h>
22 #include <dhd_bus.h>
23 #include <dhd_proto.h>
24 #include <dhd_dbg.h>
25 #include <msgtrace.h>
26 #include <wlioctl.h>
27
28 int dhd_msg_level;
29 char fw_path[MOD_PARAM_PATHLEN];
30 char nv_path[MOD_PARAM_PATHLEN];
31
32 /* Last connection success/failure status */
33 uint32 dhd_conn_event;
34 uint32 dhd_conn_status;
35 uint32 dhd_conn_reason;
36
37 #define htod32(i) i
38 #define htod16(i) i
39 #define dtoh32(i) i
40 #define dtoh16(i) i
41
42 extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf,
43                             uint len);
44 extern void dhd_ind_scan_confirm(void *h, bool status);
45 extern int dhd_wl_ioctl(dhd_pub_t *dhd, uint cmd, char *buf, uint buflen);
46 void dhd_iscan_lock(void);
47 void dhd_iscan_unlock(void);
48
49 /* Packet alignment for most efficient SDIO (can change based on platform) */
50 #ifndef DHD_SDALIGN
51 #define DHD_SDALIGN     32
52 #endif
53 #if !ISPOWEROF2(DHD_SDALIGN)
54 #error DHD_SDALIGN is not a power of 2!
55 #endif
56
57 #ifdef DHD_DEBUG
58 #define EPI_VERSION_STR         "4.218.248.5"
59 const char dhd_version[] =
60 "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " __DATE__
61 " at " __TIME__;
62 #else
63 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
64 #endif
65
66 void dhd_set_timer(void *bus, uint wdtick);
67
68 /* IOVar table */
69 enum {
70         IOV_VERSION = 1,
71         IOV_MSGLEVEL,
72         IOV_BCMERRORSTR,
73         IOV_BCMERROR,
74         IOV_WDTICK,
75         IOV_DUMP,
76 #ifdef DHD_DEBUG
77         IOV_CONS,
78         IOV_DCONSOLE_POLL,
79 #endif
80         IOV_CLEARCOUNTS,
81         IOV_LOGDUMP,
82         IOV_LOGCAL,
83         IOV_LOGSTAMP,
84         IOV_GPIOOB,
85         IOV_IOCTLTIMEOUT,
86         IOV_LAST
87 };
88
89 const bcm_iovar_t dhd_iovars[] = {
90         {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version)}
91         ,
92 #ifdef DHD_DEBUG
93         {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0}
94         ,
95 #endif                          /* DHD_DEBUG */
96         {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN}
97         ,
98         {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0}
99         ,
100         {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0}
101         ,
102         {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN}
103         ,
104 #ifdef DHD_DEBUG
105         {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0}
106         ,
107         {"cons", IOV_CONS, 0, IOVT_BUFFER, 0}
108         ,
109 #endif
110         {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0}
111         ,
112         {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0}
113         ,
114         {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0}
115         ,
116         {NULL, 0, 0, 0, 0}
117 };
118
119 void dhd_common_init(void)
120 {
121         /* Init global variables at run-time, not as part of the declaration.
122          * This is required to support init/de-init of the driver.
123          * Initialization
124          * of globals as part of the declaration results in non-deterministic
125          * behaviour since the value of the globals may be different on the
126          * first time that the driver is initialized vs subsequent
127          * initializations.
128          */
129         dhd_msg_level = DHD_ERROR_VAL;
130 #ifdef CONFIG_BCM4329_FW_PATH
131         strncpy(fw_path, CONFIG_BCM4329_FW_PATH, MOD_PARAM_PATHLEN - 1);
132 #else
133         fw_path[0] = '\0';
134 #endif
135 #ifdef CONFIG_BCM4329_NVRAM_PATH
136         strncpy(nv_path, CONFIG_BCM4329_NVRAM_PATH, MOD_PARAM_PATHLEN - 1);
137 #else
138         nv_path[0] = '\0';
139 #endif
140 }
141
142 static int dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
143 {
144         char eabuf[ETHER_ADDR_STR_LEN];
145
146         struct bcmstrbuf b;
147         struct bcmstrbuf *strbuf = &b;
148
149         bcm_binit(strbuf, buf, buflen);
150
151         /* Base DHD info */
152         bcm_bprintf(strbuf, "%s\n", dhd_version);
153         bcm_bprintf(strbuf, "\n");
154         bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
155                     dhdp->up, dhdp->txoff, dhdp->busstate);
156         bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
157                     dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
158         bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
159                     dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac,
160                                                                   eabuf));
161         bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror,
162                     dhdp->tickcnt);
163
164         bcm_bprintf(strbuf, "dongle stats:\n");
165         bcm_bprintf(strbuf,
166                     "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
167                     dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
168                     dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
169         bcm_bprintf(strbuf,
170                     "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
171                     dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
172                     dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
173         bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
174
175         bcm_bprintf(strbuf, "bus stats:\n");
176         bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
177                     dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
178         bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
179                     dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
180         bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld\n",
181                     dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
182         bcm_bprintf(strbuf,
183                     "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
184                     dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped,
185                     dhdp->rx_flushed);
186         bcm_bprintf(strbuf,
187                     "rx_readahead_cnt %ld tx_realloc %ld fc_packets %ld\n",
188                     dhdp->rx_readahead_cnt, dhdp->tx_realloc, dhdp->fc_packets);
189         bcm_bprintf(strbuf, "wd_dpc_sched %ld\n", dhdp->wd_dpc_sched);
190         bcm_bprintf(strbuf, "\n");
191
192         /* Add any prot info */
193         dhd_prot_dump(dhdp, strbuf);
194         bcm_bprintf(strbuf, "\n");
195
196         /* Add any bus info */
197         dhd_bus_dump(dhdp, strbuf);
198
199         return !strbuf->size ? BCME_BUFTOOSHORT : 0;
200 }
201
202 static int
203 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid,
204             const char *name, void *params, int plen, void *arg, int len,
205             int val_size)
206 {
207         int bcmerror = 0;
208         int32 int_val = 0;
209
210         DHD_TRACE(("%s: Enter\n", __func__));
211
212         bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid));
213         if (bcmerror != 0)
214                 goto exit;
215
216         if (plen >= (int)sizeof(int_val))
217                 bcopy(params, &int_val, sizeof(int_val));
218
219         switch (actionid) {
220         case IOV_GVAL(IOV_VERSION):
221                 /* Need to have checked buffer length */
222                 strncpy((char *)arg, dhd_version, len);
223                 break;
224
225         case IOV_GVAL(IOV_MSGLEVEL):
226                 int_val = (int32) dhd_msg_level;
227                 bcopy(&int_val, arg, val_size);
228                 break;
229
230         case IOV_SVAL(IOV_MSGLEVEL):
231                 dhd_msg_level = int_val;
232                 break;
233
234         case IOV_GVAL(IOV_BCMERRORSTR):
235                 strncpy((char *)arg, bcmerrorstr(dhd_pub->bcmerror),
236                         BCME_STRLEN);
237                 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
238                 break;
239
240         case IOV_GVAL(IOV_BCMERROR):
241                 int_val = (int32) dhd_pub->bcmerror;
242                 bcopy(&int_val, arg, val_size);
243                 break;
244
245         case IOV_GVAL(IOV_WDTICK):
246                 int_val = (int32) dhd_watchdog_ms;
247                 bcopy(&int_val, arg, val_size);
248                 break;
249
250         case IOV_SVAL(IOV_WDTICK):
251                 if (!dhd_pub->up) {
252                         bcmerror = BCME_NOTUP;
253                         break;
254                 }
255                 dhd_os_wd_timer(dhd_pub, (uint) int_val);
256                 break;
257
258         case IOV_GVAL(IOV_DUMP):
259                 bcmerror = dhd_dump(dhd_pub, arg, len);
260                 break;
261
262 #ifdef DHD_DEBUG
263         case IOV_GVAL(IOV_DCONSOLE_POLL):
264                 int_val = (int32) dhd_console_ms;
265                 bcopy(&int_val, arg, val_size);
266                 break;
267
268         case IOV_SVAL(IOV_DCONSOLE_POLL):
269                 dhd_console_ms = (uint) int_val;
270                 break;
271
272         case IOV_SVAL(IOV_CONS):
273                 if (len > 0)
274                         bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
275                 break;
276 #endif
277
278         case IOV_SVAL(IOV_CLEARCOUNTS):
279                 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
280                 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
281                 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
282                 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
283                 dhd_pub->rx_dropped = 0;
284                 dhd_pub->rx_readahead_cnt = 0;
285                 dhd_pub->tx_realloc = 0;
286                 dhd_pub->wd_dpc_sched = 0;
287                 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
288                 dhd_bus_clearcounts(dhd_pub);
289                 break;
290
291         case IOV_GVAL(IOV_IOCTLTIMEOUT):{
292                         int_val = (int32) dhd_os_get_ioctl_resp_timeout();
293                         bcopy(&int_val, arg, sizeof(int_val));
294                         break;
295                 }
296
297         case IOV_SVAL(IOV_IOCTLTIMEOUT):{
298                         if (int_val <= 0)
299                                 bcmerror = BCME_BADARG;
300                         else
301                                 dhd_os_set_ioctl_resp_timeout((unsigned int)
302                                                               int_val);
303                         break;
304                 }
305
306         default:
307                 bcmerror = BCME_UNSUPPORTED;
308                 break;
309         }
310
311 exit:
312         return bcmerror;
313 }
314
315 /* Store the status of a connection attempt for later retrieval by an iovar */
316 void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
317 {
318         /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
319          * because an encryption/rsn mismatch results in both events, and
320          * the important information is in the WLC_E_PRUNE.
321          */
322         if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
323               dhd_conn_event == WLC_E_PRUNE)) {
324                 dhd_conn_event = event;
325                 dhd_conn_status = status;
326                 dhd_conn_reason = reason;
327         }
328 }
329
330 bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
331 {
332         void *p;
333         int eprec = -1;         /* precedence to evict from */
334         bool discard_oldest;
335
336         /* Fast case, precedence queue is not full and we are also not
337          * exceeding total queue length
338          */
339         if (!pktq_pfull(q, prec) && !pktq_full(q)) {
340                 pktq_penq(q, prec, pkt);
341                 return TRUE;
342         }
343
344         /* Determine precedence from which to evict packet, if any */
345         if (pktq_pfull(q, prec))
346                 eprec = prec;
347         else if (pktq_full(q)) {
348                 p = pktq_peek_tail(q, &eprec);
349                 ASSERT(p);
350                 if (eprec > prec)
351                         return FALSE;
352         }
353
354         /* Evict if needed */
355         if (eprec >= 0) {
356                 /* Detect queueing to unconfigured precedence */
357                 ASSERT(!pktq_pempty(q, eprec));
358                 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
359                 if (eprec == prec && !discard_oldest)
360                         return FALSE;   /* refuse newer (incoming) packet */
361                 /* Evict packet according to discard policy */
362                 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q,
363                                                   eprec);
364                 if (p == NULL) {
365                         DHD_ERROR(("%s: pktq_penq() failed, oldest %d.",
366                                    __func__, discard_oldest));
367                         ASSERT(p);
368                 }
369
370                 PKTFREE(dhdp->osh, p, TRUE);
371         }
372
373         /* Enqueue */
374         p = pktq_penq(q, prec, pkt);
375         if (p == NULL) {
376                 DHD_ERROR(("%s: pktq_penq() failed.", __func__));
377                 ASSERT(p);
378         }
379
380         return TRUE;
381 }
382
383 static int
384 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
385              void *params, int plen, void *arg, int len, bool set)
386 {
387         int bcmerror = 0;
388         int val_size;
389         const bcm_iovar_t *vi = NULL;
390         uint32 actionid;
391
392         DHD_TRACE(("%s: Enter\n", __func__));
393
394         ASSERT(name);
395         ASSERT(len >= 0);
396
397         /* Get MUST have return space */
398         ASSERT(set || (arg && len));
399
400         /* Set does NOT take qualifiers */
401         ASSERT(!set || (!params && !plen));
402
403         vi = bcm_iovar_lookup(dhd_iovars, name);
404         if (vi == NULL) {
405                 bcmerror = BCME_UNSUPPORTED;
406                 goto exit;
407         }
408
409         DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__,
410                  name, (set ? "set" : "get"), len, plen));
411
412         /* set up 'params' pointer in case this is a set command so that
413          * the convenience int and bool code can be common to set and get
414          */
415         if (params == NULL) {
416                 params = arg;
417                 plen = len;
418         }
419
420         if (vi->type == IOVT_VOID)
421                 val_size = 0;
422         else if (vi->type == IOVT_BUFFER)
423                 val_size = len;
424         else
425                 /* all other types are integer sized */
426                 val_size = sizeof(int);
427
428         actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
429         bcmerror =
430             dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len,
431                         val_size);
432
433 exit:
434         return bcmerror;
435 }
436
437 int dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
438 {
439         int bcmerror = 0;
440
441         DHD_TRACE(("%s: Enter\n", __func__));
442
443         if (!buf)
444                 return BCME_BADARG;
445
446         switch (ioc->cmd) {
447         case DHD_GET_MAGIC:
448                 if (buflen < sizeof(int))
449                         bcmerror = BCME_BUFTOOSHORT;
450                 else
451                         *(int *)buf = DHD_IOCTL_MAGIC;
452                 break;
453
454         case DHD_GET_VERSION:
455                 if (buflen < sizeof(int))
456                         bcmerror = -BCME_BUFTOOSHORT;
457                 else
458                         *(int *)buf = DHD_IOCTL_VERSION;
459                 break;
460
461         case DHD_GET_VAR:
462         case DHD_SET_VAR:{
463                         char *arg;
464                         uint arglen;
465
466                         /* scan past the name to any arguments */
467                         for (arg = buf, arglen = buflen; *arg && arglen;
468                              arg++, arglen--)
469                                 ;
470
471                         if (*arg) {
472                                 bcmerror = BCME_BUFTOOSHORT;
473                                 break;
474                         }
475
476                         /* account for the NUL terminator */
477                         arg++, arglen--;
478
479                         /* call with the appropriate arguments */
480                         if (ioc->cmd == DHD_GET_VAR)
481                                 bcmerror =
482                                     dhd_iovar_op(dhd_pub, buf, arg, arglen, buf,
483                                                  buflen, IOV_GET);
484                         else
485                                 bcmerror =
486                                     dhd_iovar_op(dhd_pub, buf, NULL, 0, arg,
487                                                  arglen, IOV_SET);
488                         if (bcmerror != BCME_UNSUPPORTED)
489                                 break;
490
491                         /* not in generic table, try protocol module */
492                         if (ioc->cmd == DHD_GET_VAR)
493                                 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
494                                                              arglen, buf,
495                                                              buflen, IOV_GET);
496                         else
497                                 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
498                                                              NULL, 0, arg,
499                                                              arglen, IOV_SET);
500                         if (bcmerror != BCME_UNSUPPORTED)
501                                 break;
502
503                         /* if still not found, try bus module */
504                         if (ioc->cmd == DHD_GET_VAR)
505                                 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
506                                                             arg, arglen, buf,
507                                                             buflen, IOV_GET);
508                         else
509                                 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
510                                                             NULL, 0, arg,
511                                                             arglen, IOV_SET);
512
513                         break;
514                 }
515
516         default:
517                 bcmerror = BCME_UNSUPPORTED;
518         }
519
520         return bcmerror;
521 }
522
523 #ifdef SHOW_EVENTS
524 static void wl_show_host_event(wl_event_msg_t *event, void *event_data)
525 {
526         uint i, status, reason;
527         bool group = FALSE, flush_txq = FALSE, link = FALSE;
528         char *auth_str, *event_name;
529         uchar *buf;
530         char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
531         static struct {
532                 uint event;
533                 char *event_name;
534         } event_names[] = {
535                 {
536                 WLC_E_SET_SSID, "SET_SSID"}, {
537                 WLC_E_JOIN, "JOIN"}, {
538                 WLC_E_START, "START"}, {
539                 WLC_E_AUTH, "AUTH"}, {
540                 WLC_E_AUTH_IND, "AUTH_IND"}, {
541                 WLC_E_DEAUTH, "DEAUTH"}, {
542                 WLC_E_DEAUTH_IND, "DEAUTH_IND"}, {
543                 WLC_E_ASSOC, "ASSOC"}, {
544                 WLC_E_ASSOC_IND, "ASSOC_IND"}, {
545                 WLC_E_REASSOC, "REASSOC"}, {
546                 WLC_E_REASSOC_IND, "REASSOC_IND"}, {
547                 WLC_E_DISASSOC, "DISASSOC"}, {
548                 WLC_E_DISASSOC_IND, "DISASSOC_IND"}, {
549                 WLC_E_QUIET_START, "START_QUIET"}, {
550                 WLC_E_QUIET_END, "END_QUIET"}, {
551                 WLC_E_BEACON_RX, "BEACON_RX"}, {
552                 WLC_E_LINK, "LINK"}, {
553                 WLC_E_MIC_ERROR, "MIC_ERROR"}, {
554                 WLC_E_NDIS_LINK, "NDIS_LINK"}, {
555                 WLC_E_ROAM, "ROAM"}, {
556                 WLC_E_TXFAIL, "TXFAIL"}, {
557                 WLC_E_PMKID_CACHE, "PMKID_CACHE"}, {
558                 WLC_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
559                 WLC_E_PRUNE, "PRUNE"}, {
560                 WLC_E_AUTOAUTH, "AUTOAUTH"}, {
561                 WLC_E_EAPOL_MSG, "EAPOL_MSG"}, {
562                 WLC_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
563                 WLC_E_ADDTS_IND, "ADDTS_IND"}, {
564                 WLC_E_DELTS_IND, "DELTS_IND"}, {
565                 WLC_E_BCNSENT_IND, "BCNSENT_IND"}, {
566                 WLC_E_BCNRX_MSG, "BCNRX_MSG"}, {
567                 WLC_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
568                 WLC_E_ROAM_PREP, "ROAM_PREP"}, {
569                 WLC_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
570                 WLC_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
571                 WLC_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
572                 WLC_E_JOIN_START, "JOIN_START"}, {
573                 WLC_E_ROAM_START, "ROAM_START"}, {
574                 WLC_E_ASSOC_START, "ASSOC_START"}, {
575                 WLC_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
576                 WLC_E_RADIO, "RADIO"}, {
577                 WLC_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
578                 WLC_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
579                 WLC_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
580                 WLC_E_PSK_SUP, "PSK_SUP"}, {
581                 WLC_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
582                 WLC_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
583                 WLC_E_ICV_ERROR, "ICV_ERROR"}, {
584                 WLC_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
585                 WLC_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
586                 WLC_E_TRACE, "TRACE"}, {
587                 WLC_E_ACTION_FRAME, "ACTION FRAME"}, {
588                 WLC_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
589                 WLC_E_IF, "IF"}, {
590                 WLC_E_RSSI, "RSSI"}, {
591                 WLC_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}
592         };
593         uint event_type, flags, auth_type, datalen;
594         event_type = ntoh32(event->event_type);
595         flags = ntoh16(event->flags);
596         status = ntoh32(event->status);
597         reason = ntoh32(event->reason);
598         auth_type = ntoh32(event->auth_type);
599         datalen = ntoh32(event->datalen);
600         /* debug dump of event messages */
601         sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
602                 (uchar) event->addr.octet[0] & 0xff,
603                 (uchar) event->addr.octet[1] & 0xff,
604                 (uchar) event->addr.octet[2] & 0xff,
605                 (uchar) event->addr.octet[3] & 0xff,
606                 (uchar) event->addr.octet[4] & 0xff,
607                 (uchar) event->addr.octet[5] & 0xff);
608
609         event_name = "UNKNOWN";
610         for (i = 0; i < ARRAYSIZE(event_names); i++) {
611                 if (event_names[i].event == event_type)
612                         event_name = event_names[i].event_name;
613         }
614
615         DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name, event_type));
616
617         if (flags & WLC_EVENT_MSG_LINK)
618                 link = TRUE;
619         if (flags & WLC_EVENT_MSG_GROUP)
620                 group = TRUE;
621         if (flags & WLC_EVENT_MSG_FLUSHTXQ)
622                 flush_txq = TRUE;
623
624         switch (event_type) {
625         case WLC_E_START:
626         case WLC_E_DEAUTH:
627         case WLC_E_DISASSOC:
628                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
629                 break;
630
631         case WLC_E_ASSOC_IND:
632         case WLC_E_REASSOC_IND:
633                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
634                 break;
635
636         case WLC_E_ASSOC:
637         case WLC_E_REASSOC:
638                 if (status == WLC_E_STATUS_SUCCESS) {
639                         DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
640                                    event_name, eabuf));
641                 } else if (status == WLC_E_STATUS_TIMEOUT) {
642                         DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
643                                    event_name, eabuf));
644                 } else if (status == WLC_E_STATUS_FAIL) {
645                         DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
646                                    event_name, eabuf, (int)reason));
647                 } else {
648                         DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
649                                 "%d\n", event_name, eabuf, (int)status));
650                 }
651                 break;
652
653         case WLC_E_DEAUTH_IND:
654         case WLC_E_DISASSOC_IND:
655                 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name,
656                            eabuf, (int)reason));
657                 break;
658
659         case WLC_E_AUTH:
660         case WLC_E_AUTH_IND:
661                 if (auth_type == DOT11_OPEN_SYSTEM)
662                         auth_str = "Open System";
663                 else if (auth_type == DOT11_SHARED_KEY)
664                         auth_str = "Shared Key";
665                 else {
666                         sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
667                         auth_str = err_msg;
668                 }
669                 if (event_type == WLC_E_AUTH_IND) {
670                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name,
671                                    eabuf, auth_str));
672                 } else if (status == WLC_E_STATUS_SUCCESS) {
673                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
674                                    event_name, eabuf, auth_str));
675                 } else if (status == WLC_E_STATUS_TIMEOUT) {
676                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
677                                    event_name, eabuf, auth_str));
678                 } else if (status == WLC_E_STATUS_FAIL) {
679                         DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, "
680                                 "reason %d\n",
681                                 event_name, eabuf, auth_str, (int)reason));
682                 }
683
684                 break;
685
686         case WLC_E_JOIN:
687         case WLC_E_ROAM:
688         case WLC_E_SET_SSID:
689                 if (status == WLC_E_STATUS_SUCCESS) {
690                         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name,
691                                    eabuf));
692                 } else if (status == WLC_E_STATUS_FAIL) {
693                         DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
694                 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
695                         DHD_EVENT(("MACEVENT: %s, no networks found\n",
696                                    event_name));
697                 } else {
698                         DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
699                                    event_name, (int)status));
700                 }
701                 break;
702
703         case WLC_E_BEACON_RX:
704                 if (status == WLC_E_STATUS_SUCCESS) {
705                         DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
706                 } else if (status == WLC_E_STATUS_FAIL) {
707                         DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
708                 } else {
709                         DHD_EVENT(("MACEVENT: %s, status %d\n", event_name,
710                                    status));
711                 }
712                 break;
713
714         case WLC_E_LINK:
715                 DHD_EVENT(("MACEVENT: %s %s\n", event_name,
716                            link ? "UP" : "DOWN"));
717                 break;
718
719         case WLC_E_MIC_ERROR:
720                 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
721                            event_name, eabuf, group, flush_txq));
722                 break;
723
724         case WLC_E_ICV_ERROR:
725         case WLC_E_UNICAST_DECODE_ERROR:
726         case WLC_E_MULTICAST_DECODE_ERROR:
727                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
728                 break;
729
730         case WLC_E_TXFAIL:
731                 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
732                 break;
733
734         case WLC_E_SCAN_COMPLETE:
735         case WLC_E_PMKID_CACHE:
736                 DHD_EVENT(("MACEVENT: %s\n", event_name));
737                 break;
738
739         case WLC_E_PFN_NET_FOUND:
740         case WLC_E_PFN_NET_LOST:
741         case WLC_E_PFN_SCAN_COMPLETE:
742                 DHD_EVENT(("PNOEVENT: %s\n", event_name));
743                 break;
744
745         case WLC_E_PSK_SUP:
746         case WLC_E_PRUNE:
747                 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
748                            event_name, (int)status, (int)reason));
749                 break;
750
751         case WLC_E_TRACE:
752                 {
753                         static uint32 seqnum_prev = 0;
754                         msgtrace_hdr_t hdr;
755                         uint32 nblost;
756                         char *s, *p;
757
758                         buf = (uchar *) event_data;
759                         memcpy(&hdr, buf, MSGTRACE_HDRLEN);
760
761                         if (hdr.version != MSGTRACE_VERSION) {
762                                 printf
763                                     ("\nMACEVENT: %s [unsupported version --> "
764                                      "dhd version:%d dongle version:%d]\n",
765                                      event_name, MSGTRACE_VERSION, hdr.version);
766                                 /* Reset datalen to avoid display below */
767                                 datalen = 0;
768                                 break;
769                         }
770
771                         /* There are 2 bytes available at the end of data */
772                         buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
773
774                         if (ntoh32(hdr.discarded_bytes)
775                             || ntoh32(hdr.discarded_printf)) {
776                                 printf
777                                     ("\nWLC_E_TRACE: [Discarded traces in dongle -->"
778                                      "discarded_bytes %d discarded_printf %d]\n",
779                                      ntoh32(hdr.discarded_bytes),
780                                      ntoh32(hdr.discarded_printf));
781                         }
782
783                         nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
784                         if (nblost > 0) {
785                                 printf
786                                     ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
787                                      ntoh32(hdr.seqnum), nblost);
788                         }
789                         seqnum_prev = ntoh32(hdr.seqnum);
790
791                         /* Display the trace buffer. Advance from \n to \n to
792                          * avoid display big
793                          * printf (issue with Linux printk )
794                          */
795                         p = (char *)&buf[MSGTRACE_HDRLEN];
796                         while ((s = strstr(p, "\n")) != NULL) {
797                                 *s = '\0';
798                                 printf("%s\n", p);
799                                 p = s + 1;
800                         }
801                         printf("%s\n", p);
802
803                         /* Reset datalen to avoid display below */
804                         datalen = 0;
805                 }
806                 break;
807
808         case WLC_E_RSSI:
809                 DHD_EVENT(("MACEVENT: %s %d\n", event_name,
810                            ntoh32(*((int *)event_data))));
811                 break;
812
813         default:
814                 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
815                         "auth %d\n", event_name, event_type, eabuf,
816                         (int)status, (int)reason, (int)auth_type));
817                 break;
818         }
819
820         /* show any appended data */
821         if (datalen) {
822                 buf = (uchar *) event_data;
823                 DHD_EVENT((" data (%d) : ", datalen));
824                 for (i = 0; i < datalen; i++)
825                         DHD_EVENT((" 0x%02x ", *buf++));
826                 DHD_EVENT(("\n"));
827         }
828 }
829 #endif                          /* SHOW_EVENTS */
830
831 int
832 wl_host_event(struct dhd_info *dhd, int *ifidx, void *pktdata,
833               wl_event_msg_t *event, void **data_ptr)
834 {
835         /* check whether packet is a BRCM event pkt */
836         bcm_event_t *pvt_data = (bcm_event_t *) pktdata;
837         char *event_data;
838         uint32 type, status;
839         uint16 flags;
840         int evlen;
841
842         if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
843                 DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__));
844                 return BCME_ERROR;
845         }
846
847         /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
848         if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) !=
849             BCMILCP_BCM_SUBTYPE_EVENT) {
850                 DHD_ERROR(("%s: mismatched subtype, bailing\n", __func__));
851                 return BCME_ERROR;
852         }
853
854         *data_ptr = &pvt_data[1];
855         event_data = *data_ptr;
856
857         /* memcpy since BRCM event pkt may be unaligned. */
858         memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
859
860         type = ntoh32_ua((void *)&event->event_type);
861         flags = ntoh16_ua((void *)&event->flags);
862         status = ntoh32_ua((void *)&event->status);
863         evlen = ntoh32_ua((void *)&event->datalen) + sizeof(bcm_event_t);
864
865         switch (type) {
866         case WLC_E_IF:
867                 {
868                         dhd_if_event_t *ifevent = (dhd_if_event_t *) event_data;
869                         DHD_TRACE(("%s: if event\n", __func__));
870
871                         if (ifevent->ifidx > 0 &&
872                                  ifevent->ifidx < DHD_MAX_IFS) {
873                                 if (ifevent->action == WLC_E_IF_ADD)
874                                         dhd_add_if(dhd, ifevent->ifidx,
875                                                    NULL, event->ifname,
876                                                    pvt_data->eth.ether_dhost,
877                                                    ifevent->flags,
878                                                    ifevent->bssidx);
879                                 else
880                                         dhd_del_if(dhd, ifevent->ifidx);
881                         } else {
882                                 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
883                                            __func__, ifevent->ifidx,
884                                            event->ifname));
885                         }
886                 }
887                 /* send up the if event: btamp user needs it */
888                 *ifidx = dhd_ifname2idx(dhd, event->ifname);
889                 /* push up to external supp/auth */
890                 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
891                 break;
892
893 #ifdef P2P
894         case WLC_E_NDIS_LINK:
895                 break;
896 #endif
897                 /* fall through */
898                 /* These are what external supplicant/authenticator wants */
899         case WLC_E_LINK:
900         case WLC_E_ASSOC_IND:
901         case WLC_E_REASSOC_IND:
902         case WLC_E_DISASSOC_IND:
903         case WLC_E_MIC_ERROR:
904         default:
905                 /* Fall through: this should get _everything_  */
906
907                 *ifidx = dhd_ifname2idx(dhd, event->ifname);
908                 /* push up to external supp/auth */
909                 dhd_event(dhd, (char *)pvt_data, evlen, *ifidx);
910                 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
911                            __func__, type, flags, status));
912
913                 /* put it back to WLC_E_NDIS_LINK */
914                 if (type == WLC_E_NDIS_LINK) {
915                         uint32 temp;
916
917                         temp = ntoh32_ua((void *)&event->event_type);
918                         DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
919
920                         temp = ntoh32(WLC_E_NDIS_LINK);
921                         memcpy((void *)(&pvt_data->event.event_type), &temp,
922                                sizeof(pvt_data->event.event_type));
923                 }
924                 break;
925         }
926
927 #ifdef SHOW_EVENTS
928         wl_show_host_event(event, event_data);
929 #endif                          /* SHOW_EVENTS */
930
931         return BCME_OK;
932 }
933
934 void wl_event_to_host_order(wl_event_msg_t *evt)
935 {
936         /* Event struct members passed from dongle to host are stored
937          * in network
938          * byte order. Convert all members to host-order.
939          */
940         evt->event_type = ntoh32(evt->event_type);
941         evt->flags = ntoh16(evt->flags);
942         evt->status = ntoh32(evt->status);
943         evt->reason = ntoh32(evt->reason);
944         evt->auth_type = ntoh32(evt->auth_type);
945         evt->datalen = ntoh32(evt->datalen);
946         evt->version = ntoh16(evt->version);
947 }
948
949 void print_buf(void *pbuf, int len, int bytes_per_line)
950 {
951         int i, j = 0;
952         unsigned char *buf = pbuf;
953
954         if (bytes_per_line == 0)
955                 bytes_per_line = len;
956
957         for (i = 0; i < len; i++) {
958                 printf("%2.2x", *buf++);
959                 j++;
960                 if (j == bytes_per_line) {
961                         printf("\n");
962                         j = 0;
963                 } else {
964                         printf(":");
965                 }
966         }
967         printf("\n");
968 }
969
970 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
971
972 /* Convert user's input in hex pattern to byte-size mask */
973 static int wl_pattern_atoh(char *src, char *dst)
974 {
975         int i;
976         if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) {
977                 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
978                 return -1;
979         }
980         src = src + 2;          /* Skip past 0x */
981         if (strlen(src) % 2 != 0) {
982                 DHD_ERROR(("Mask invalid format. Length must be even.\n"));
983                 return -1;
984         }
985         for (i = 0; *src != '\0'; i++) {
986                 char num[3];
987                 strncpy(num, src, 2);
988                 num[2] = '\0';
989                 dst[i] = (uint8) strtoul(num, NULL, 16);
990                 src += 2;
991         }
992         return i;
993 }
994
995 void
996 dhd_pktfilter_offload_enable(dhd_pub_t *dhd, char *arg, int enable,
997                              int master_mode)
998 {
999         char *argv[8];
1000         int i = 0;
1001         const char *str;
1002         int buf_len;
1003         int str_len;
1004         char *arg_save = 0, *arg_org = 0;
1005         int rc;
1006         char buf[128];
1007         wl_pkt_filter_enable_t enable_parm;
1008         wl_pkt_filter_enable_t *pkt_filterp;
1009
1010         arg_save = MALLOC(dhd->osh, strlen(arg) + 1);
1011         if (!arg_save) {
1012                 DHD_ERROR(("%s: kmalloc failed\n", __func__));
1013                 goto fail;
1014         }
1015         arg_org = arg_save;
1016         memcpy(arg_save, arg, strlen(arg) + 1);
1017
1018         argv[i] = bcmstrtok(&arg_save, " ", 0);
1019
1020         i = 0;
1021         if (NULL == argv[i]) {
1022                 DHD_ERROR(("No args provided\n"));
1023                 goto fail;
1024         }
1025
1026         str = "pkt_filter_enable";
1027         str_len = strlen(str);
1028         strncpy(buf, str, str_len);
1029         buf[str_len] = '\0';
1030         buf_len = str_len + 1;
1031
1032         pkt_filterp = (wl_pkt_filter_enable_t *) (buf + str_len + 1);
1033
1034         /* Parse packet filter id. */
1035         enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1036
1037         /* Parse enable/disable value. */
1038         enable_parm.enable = htod32(enable);
1039
1040         buf_len += sizeof(enable_parm);
1041         memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
1042
1043         /* Enable/disable the specified filter. */
1044         rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
1045         rc = rc >= 0 ? 0 : rc;
1046         if (rc)
1047                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1048                            __func__, arg, rc));
1049         else
1050                 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1051                            __func__, arg));
1052
1053         /* Contorl the master mode */
1054         bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf,
1055                     sizeof(buf));
1056         rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1057         rc = rc >= 0 ? 0 : rc;
1058         if (rc)
1059                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1060                            __func__, arg, rc));
1061
1062 fail:
1063         if (arg_org)
1064                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1065 }
1066
1067 void dhd_pktfilter_offload_set(dhd_pub_t *dhd, char *arg)
1068 {
1069         const char *str;
1070         wl_pkt_filter_t pkt_filter;
1071         wl_pkt_filter_t *pkt_filterp;
1072         int buf_len;
1073         int str_len;
1074         int rc;
1075         uint32 mask_size;
1076         uint32 pattern_size;
1077         char *argv[8], *buf = 0;
1078         int i = 0;
1079         char *arg_save = 0, *arg_org = 0;
1080 #define BUF_SIZE                2048
1081
1082         if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1083                 DHD_ERROR(("%s: kmalloc failed\n", __func__));
1084                 goto fail;
1085         }
1086
1087         arg_org = arg_save;
1088
1089         if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1090                 DHD_ERROR(("%s: kmalloc failed\n", __func__));
1091                 goto fail;
1092         }
1093
1094         memcpy(arg_save, arg, strlen(arg) + 1);
1095
1096         if (strlen(arg) > BUF_SIZE) {
1097                 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg),
1098                            (int)sizeof(buf)));
1099                 goto fail;
1100         }
1101
1102         argv[i] = bcmstrtok(&arg_save, " ", 0);
1103         while (argv[i++])
1104                 argv[i] = bcmstrtok(&arg_save, " ", 0);
1105
1106         i = 0;
1107         if (NULL == argv[i]) {
1108                 DHD_ERROR(("No args provided\n"));
1109                 goto fail;
1110         }
1111
1112         str = "pkt_filter_add";
1113         str_len = strlen(str);
1114         strncpy(buf, str, str_len);
1115         buf[str_len] = '\0';
1116         buf_len = str_len + 1;
1117
1118         pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1119
1120         /* Parse packet filter id. */
1121         pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1122
1123         if (NULL == argv[++i]) {
1124                 DHD_ERROR(("Polarity not provided\n"));
1125                 goto fail;
1126         }
1127
1128         /* Parse filter polarity. */
1129         pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1130
1131         if (NULL == argv[++i]) {
1132                 DHD_ERROR(("Filter type not provided\n"));
1133                 goto fail;
1134         }
1135
1136         /* Parse filter type. */
1137         pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1138
1139         if (NULL == argv[++i]) {
1140                 DHD_ERROR(("Offset not provided\n"));
1141                 goto fail;
1142         }
1143
1144         /* Parse pattern filter offset. */
1145         pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1146
1147         if (NULL == argv[++i]) {
1148                 DHD_ERROR(("Bitmask not provided\n"));
1149                 goto fail;
1150         }
1151
1152         /* Parse pattern filter mask. */
1153         mask_size =
1154             htod32(wl_pattern_atoh
1155                    (argv[i], (char *)pkt_filterp->u.pattern.mask_and_pattern));
1156
1157         if (NULL == argv[++i]) {
1158                 DHD_ERROR(("Pattern not provided\n"));
1159                 goto fail;
1160         }
1161
1162         /* Parse pattern filter pattern. */
1163         pattern_size =
1164             htod32(wl_pattern_atoh(argv[i],
1165                                    (char *)&pkt_filterp->u.pattern.
1166                                    mask_and_pattern[mask_size]));
1167
1168         if (mask_size != pattern_size) {
1169                 DHD_ERROR(("Mask and pattern not the same size\n"));
1170                 goto fail;
1171         }
1172
1173         pkt_filter.u.pattern.size_bytes = mask_size;
1174         buf_len += WL_PKT_FILTER_FIXED_LEN;
1175         buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1176
1177         /* Keep-alive attributes are set in local
1178          * variable (keep_alive_pkt), and
1179          ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1180          ** guarantee that the buffer is properly aligned.
1181          */
1182         memcpy((char *)pkt_filterp,
1183                &pkt_filter,
1184                WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1185
1186         rc = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, buf_len);
1187         rc = rc >= 0 ? 0 : rc;
1188
1189         if (rc)
1190                 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1191                            __func__, arg, rc));
1192         else
1193                 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1194                            __func__, arg));
1195
1196 fail:
1197         if (arg_org)
1198                 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1199
1200         if (buf)
1201                 MFREE(dhd->osh, buf, BUF_SIZE);
1202 }
1203
1204 void dhd_arp_offload_set(dhd_pub_t *dhd, int arp_mode)
1205 {
1206         char iovbuf[32];
1207         int retcode;
1208
1209         bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1210         retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1211         retcode = retcode >= 0 ? 0 : retcode;
1212         if (retcode)
1213                 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
1214                         "retcode = %d\n", __func__, arp_mode, retcode));
1215         else
1216                 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1217                            __func__, arp_mode));
1218 }
1219
1220 void dhd_arp_offload_enable(dhd_pub_t *dhd, int arp_enable)
1221 {
1222         char iovbuf[32];
1223         int retcode;
1224
1225         bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1226         retcode = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1227         retcode = retcode >= 0 ? 0 : retcode;
1228         if (retcode)
1229                 DHD_TRACE(("%s: failed to enabe ARP offload to %d, "
1230                         "retcode = %d\n", __func__, arp_enable, retcode));
1231         else
1232                 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1233                            __func__, arp_enable));
1234 }
1235
1236 int dhd_preinit_ioctls(dhd_pub_t *dhd)
1237 {
1238         char iovbuf[WL_EVENTING_MASK_LEN + 12]; /*  Room for
1239                                  "event_msgs" + '\0' + bitvec  */
1240         uint up = 0;
1241         char buf[128], *ptr;
1242         uint power_mode = PM_FAST;
1243         uint32 dongle_align = DHD_SDALIGN;
1244         uint32 glom = 0;
1245         uint bcn_timeout = 3;
1246         int scan_assoc_time = 40;
1247         int scan_unassoc_time = 40;
1248 #ifdef GET_CUSTOM_MAC_ENABLE
1249         int ret = 0;
1250         struct ether_addr ea_addr;
1251 #endif                          /* GET_CUSTOM_MAC_ENABLE */
1252
1253         dhd_os_proto_block(dhd);
1254
1255 #ifdef GET_CUSTOM_MAC_ENABLE
1256         /* Read MAC address from external customer place
1257          ** NOTE that default mac address has to be present in
1258          ** otp or nvram file to bring up
1259          ** firmware but unique per board mac address maybe provided by
1260          ** customer code
1261          */
1262         ret = dhd_custom_get_mac_address(ea_addr.octet);
1263         if (!ret) {
1264                 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN,
1265                             buf, sizeof(buf));
1266                 ret = dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, buf, sizeof(buf));
1267                 if (ret < 0) {
1268                         DHD_ERROR(("%s: can't set MAC address , error=%d\n",
1269                                    __func__, ret));
1270                 } else
1271                         memcpy(dhd->mac.octet, (void *)&ea_addr,
1272                                ETHER_ADDR_LEN);
1273         }
1274 #endif                          /* GET_CUSTOM_MAC_ENABLE */
1275
1276         /* Set Country code */
1277         if (dhd->country_code[0] != 0) {
1278                 if (dhdcdc_set_ioctl(dhd, 0, WLC_SET_COUNTRY,
1279                                      dhd->country_code,
1280                                      sizeof(dhd->country_code)) < 0) {
1281                         DHD_ERROR(("%s: country code setting failed\n",
1282                                    __func__));
1283                 }
1284         }
1285
1286         /* query for 'ver' to get version info from firmware */
1287         memset(buf, 0, sizeof(buf));
1288         ptr = buf;
1289         bcm_mkiovar("ver", 0, 0, buf, sizeof(buf));
1290         dhdcdc_query_ioctl(dhd, 0, WLC_GET_VAR, buf, sizeof(buf));
1291         bcmstrtok(&ptr, "\n", 0);
1292         /* Print fw version info */
1293         DHD_ERROR(("Firmware version = %s\n", buf));
1294
1295         /* Set PowerSave mode */
1296         dhdcdc_set_ioctl(dhd, 0, WLC_SET_PM, (char *)&power_mode,
1297                          sizeof(power_mode));
1298
1299         /* Match Host and Dongle rx alignment */
1300         bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf,
1301                     sizeof(iovbuf));
1302         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1303
1304         /* disable glom option per default */
1305         bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf));
1306         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1307
1308         /* Setup timeout if Beacons are lost and roam is off to report
1309                  link down */
1310         bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf,
1311                     sizeof(iovbuf));
1312         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1313
1314         /* Enable/Disable build-in roaming to allowed ext supplicant to take
1315                  of romaing */
1316         bcm_mkiovar("roam_off", (char *)&dhd_roam, 4, iovbuf, sizeof(iovbuf));
1317         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1318
1319         /* Force STA UP */
1320         if (dhd_radio_up)
1321                 dhdcdc_set_ioctl(dhd, 0, WLC_UP, (char *)&up, sizeof(up));
1322
1323         /* Setup event_msgs */
1324         bcm_mkiovar("event_msgs", dhd->eventmask, WL_EVENTING_MASK_LEN, iovbuf,
1325                     sizeof(iovbuf));
1326         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1327
1328         dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_CHANNEL_TIME,
1329                          (char *)&scan_assoc_time, sizeof(scan_assoc_time));
1330         dhdcdc_set_ioctl(dhd, 0, WLC_SET_SCAN_UNASSOC_TIME,
1331                          (char *)&scan_unassoc_time, sizeof(scan_unassoc_time));
1332
1333 #ifdef ARP_OFFLOAD_SUPPORT
1334         /* Set and enable ARP offload feature */
1335         if (dhd_arp_enable)
1336                 dhd_arp_offload_set(dhd, dhd_arp_mode);
1337         dhd_arp_offload_enable(dhd, dhd_arp_enable);
1338 #endif                          /* ARP_OFFLOAD_SUPPORT */
1339
1340 #ifdef PKT_FILTER_SUPPORT
1341         {
1342                 int i;
1343                 /* Set up pkt filter */
1344                 if (dhd_pkt_filter_enable) {
1345                         for (i = 0; i < dhd->pktfilter_count; i++) {
1346                                 dhd_pktfilter_offload_set(dhd,
1347                                                           dhd->pktfilter[i]);
1348                                 dhd_pktfilter_offload_enable(dhd,
1349                                      dhd->pktfilter[i],
1350                                      dhd_pkt_filter_init,
1351                                      dhd_master_mode);
1352                         }
1353                 }
1354         }
1355 #endif                          /* PKT_FILTER_SUPPORT */
1356
1357         dhd_os_proto_unblock(dhd);
1358
1359         return 0;
1360 }
1361
1362 #ifdef SIMPLE_ISCAN
1363 uint iscan_thread_id;
1364 iscan_buf_t *iscan_chain = 0;
1365
1366 iscan_buf_t *dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1367 {
1368         iscan_buf_t *iscanbuf_alloc = 0;
1369         iscan_buf_t *iscanbuf_head;
1370
1371         dhd_iscan_lock();
1372
1373         iscanbuf_alloc = (iscan_buf_t *) MALLOC(dhd->osh, sizeof(iscan_buf_t));
1374         if (iscanbuf_alloc == NULL)
1375                 goto fail;
1376
1377         iscanbuf_alloc->next = NULL;
1378         iscanbuf_head = *iscanbuf;
1379
1380         DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1381                    "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1382                    __func__, iscanbuf_alloc, iscanbuf_head, dhd));
1383
1384         if (iscanbuf_head == NULL) {
1385                 *iscanbuf = iscanbuf_alloc;
1386                 DHD_ISCAN(("%s: Head is allocated\n", __func__));
1387                 goto fail;
1388         }
1389
1390         while (iscanbuf_head->next)
1391                 iscanbuf_head = iscanbuf_head->next;
1392
1393         iscanbuf_head->next = iscanbuf_alloc;
1394
1395 fail:
1396         dhd_iscan_unlock();
1397         return iscanbuf_alloc;
1398 }
1399
1400 void dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1401 {
1402         iscan_buf_t *iscanbuf_free = 0;
1403         iscan_buf_t *iscanbuf_prv = 0;
1404         iscan_buf_t *iscanbuf_cur = iscan_chain;
1405         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1406
1407         dhd_iscan_lock();
1408         /* If iscan_delete is null then delete the entire
1409          * chain or else delete specific one provided
1410          */
1411         if (!iscan_delete) {
1412                 while (iscanbuf_cur) {
1413                         iscanbuf_free = iscanbuf_cur;
1414                         iscanbuf_cur = iscanbuf_cur->next;
1415                         iscanbuf_free->next = 0;
1416                         MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1417                 }
1418                 iscan_chain = 0;
1419         } else {
1420                 while (iscanbuf_cur) {
1421                         if (iscanbuf_cur == iscan_delete)
1422                                 break;
1423                         iscanbuf_prv = iscanbuf_cur;
1424                         iscanbuf_cur = iscanbuf_cur->next;
1425                 }
1426                 if (iscanbuf_prv)
1427                         iscanbuf_prv->next = iscan_delete->next;
1428
1429                 iscan_delete->next = 0;
1430                 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1431
1432                 if (!iscanbuf_prv)
1433                         iscan_chain = 0;
1434         }
1435         dhd_iscan_unlock();
1436 }
1437
1438 iscan_buf_t *dhd_iscan_result_buf(void)
1439 {
1440         return iscan_chain;
1441 }
1442
1443 /*
1444 * print scan cache
1445 * print partial iscan_skip list differently
1446 */
1447 int dhd_iscan_print_cache(iscan_buf_t *iscan_skip)
1448 {
1449         int i = 0, l = 0;
1450         iscan_buf_t *iscan_cur;
1451         wl_iscan_results_t *list;
1452         wl_scan_results_t *results;
1453         wl_bss_info_t UNALIGNED *bi;
1454
1455         dhd_iscan_lock();
1456
1457         iscan_cur = dhd_iscan_result_buf();
1458
1459         while (iscan_cur) {
1460                 list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1461                 if (!list)
1462                         break;
1463
1464                 results = (wl_scan_results_t *)&list->results;
1465                 if (!results)
1466                         break;
1467
1468                 if (results->version != WL_BSS_INFO_VERSION) {
1469                         DHD_ISCAN(("%s: results->version %d != "
1470                                 "WL_BSS_INFO_VERSION\n",
1471                                 __func__, results->version));
1472                         goto done;
1473                 }
1474
1475                 bi = results->bss_info;
1476                 for (i = 0; i < results->count; i++) {
1477                         if (!bi)
1478                                 break;
1479
1480                         DHD_ISCAN(("%s[%2.2d:%2.2d] %X:%X:%X:%X:%X:%X\n",
1481                                    iscan_cur != iscan_skip ? "BSS" : "bss", l,
1482                                    i, bi->BSSID.octet[0], bi->BSSID.octet[1],
1483                                    bi->BSSID.octet[2], bi->BSSID.octet[3],
1484                                    bi->BSSID.octet[4], bi->BSSID.octet[5]));
1485
1486                         bi = (wl_bss_info_t *) ((uintptr) bi +
1487                                                 dtoh32(bi->length));
1488                 }
1489                 iscan_cur = iscan_cur->next;
1490                 l++;
1491         }
1492
1493 done:
1494         dhd_iscan_unlock();
1495         return 0;
1496 }
1497
1498 /*
1499 * delete disappeared AP from specific scan cache but skip partial
1500 * list in iscan_skip
1501 */
1502 int dhd_iscan_delete_bss(void *dhdp, void *addr, iscan_buf_t *iscan_skip)
1503 {
1504         int i = 0, j = 0, l = 0;
1505         iscan_buf_t *iscan_cur;
1506         wl_iscan_results_t *list;
1507         wl_scan_results_t *results;
1508         wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1509
1510         uchar *s_addr = addr;
1511
1512         dhd_iscan_lock();
1513         DHD_ISCAN(("%s: BSS to remove %X:%X:%X:%X:%X:%X\n",
1514                    __func__, s_addr[0], s_addr[1], s_addr[2],
1515                    s_addr[3], s_addr[4], s_addr[5]));
1516
1517         iscan_cur = dhd_iscan_result_buf();
1518
1519         while (iscan_cur) {
1520                 if (iscan_cur != iscan_skip) {
1521                         list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1522                         if (!list)
1523                                 break;
1524
1525                         results = (wl_scan_results_t *)&list->results;
1526                         if (!results)
1527                                 break;
1528
1529                         if (results->version != WL_BSS_INFO_VERSION) {
1530                                 DHD_ERROR(("%s: results->version %d != "
1531                                         "WL_BSS_INFO_VERSION\n",
1532                                         __func__, results->version));
1533                                 goto done;
1534                         }
1535
1536                         bi = results->bss_info;
1537                         for (i = 0; i < results->count; i++) {
1538                                 if (!bi)
1539                                         break;
1540
1541                                 if (!memcmp
1542                                     (bi->BSSID.octet, addr, ETHER_ADDR_LEN)) {
1543                                         DHD_ISCAN(("%s: Del BSS[%2.2d:%2.2d] "
1544                                         "%X:%X:%X:%X:%X:%X\n",
1545                                         __func__, l, i, bi->BSSID.octet[0],
1546                                         bi->BSSID.octet[1], bi->BSSID.octet[2],
1547                                         bi->BSSID.octet[3], bi->BSSID.octet[4],
1548                                         bi->BSSID.octet[5]));
1549
1550                                         bi_new = bi;
1551                                         bi = (wl_bss_info_t *) ((uintptr) bi +
1552                                                                 dtoh32
1553                                                                 (bi->length));
1554 /*
1555                         if(bi && bi_new) {
1556                                 bcopy(bi, bi_new, results->buflen -
1557                                 dtoh32(bi_new->length));
1558                                 results->buflen -= dtoh32(bi_new->length);
1559                         }
1560 */
1561                                         results->buflen -=
1562                                             dtoh32(bi_new->length);
1563                                         results->count--;
1564
1565                                         for (j = i; j < results->count; j++) {
1566                                                 if (bi && bi_new) {
1567                                                         DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]" "%X:%X:%X:%X:%X:%X\n",
1568                                                         __func__, l, j,
1569                                                         bi->BSSID.octet[0],
1570                                                         bi->BSSID.octet[1],
1571                                                         bi->BSSID.octet[2],
1572                                                         bi->BSSID.octet[3],
1573                                                         bi->BSSID.octet[4],
1574                                                         bi->BSSID.octet[5]));
1575
1576                                                         bi_next =
1577                                                             (wl_bss_info_t
1578                                                              *) ((uintptr) bi +
1579                                                                  dtoh32
1580                                                                  (bi->length));
1581                                                         bcopy(bi, bi_new,
1582                                                               dtoh32
1583                                                               (bi->length));
1584                                                         bi_new =
1585                                                             (wl_bss_info_t
1586                                                              *) ((uintptr)
1587                                                                  bi_new +
1588                                                                  dtoh32
1589                                                                  (bi_new->
1590                                                                   length));
1591                                                         bi = bi_next;
1592                                                 }
1593                                         }
1594
1595                                         if (results->count == 0) {
1596                                                 /* Prune now empty partial
1597                                                 scan list */
1598                                                 dhd_iscan_free_buf(dhdp,
1599                                                                    iscan_cur);
1600                                                 goto done;
1601                                         }
1602                                         break;
1603                                 }
1604                                 bi = (wl_bss_info_t *) ((uintptr) bi +
1605                                                         dtoh32(bi->length));
1606                         }
1607                 }
1608                 iscan_cur = iscan_cur->next;
1609                 l++;
1610         }
1611
1612 done:
1613         dhd_iscan_unlock();
1614         return 0;
1615 }
1616
1617 int dhd_iscan_remove_duplicates(void *dhdp, iscan_buf_t *iscan_cur)
1618 {
1619         int i = 0;
1620         wl_iscan_results_t *list;
1621         wl_scan_results_t *results;
1622         wl_bss_info_t UNALIGNED *bi, *bi_new, *bi_next;
1623
1624         dhd_iscan_lock();
1625
1626         DHD_ISCAN(("%s: Scan cache before delete\n", __func__));
1627         dhd_iscan_print_cache(iscan_cur);
1628
1629         if (!iscan_cur)
1630                 goto done;
1631
1632         list = (wl_iscan_results_t *)iscan_cur->iscan_buf;
1633         if (!list)
1634                 goto done;
1635
1636         results = (wl_scan_results_t *)&list->results;
1637         if (!results)
1638                 goto done;
1639
1640         if (results->version != WL_BSS_INFO_VERSION) {
1641                 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1642                            __func__, results->version));
1643                 goto done;
1644         }
1645
1646         bi = results->bss_info;
1647         for (i = 0; i < results->count; i++) {
1648                 if (!bi)
1649                         break;
1650
1651                 DHD_ISCAN(("%s: Find dups for BSS[%2.2d] %X:%X:%X:%X:%X:%X\n",
1652                            __func__, i, bi->BSSID.octet[0],
1653                            bi->BSSID.octet[1], bi->BSSID.octet[2],
1654                            bi->BSSID.octet[3], bi->BSSID.octet[4],
1655                            bi->BSSID.octet[5]));
1656
1657                 dhd_iscan_delete_bss(dhdp, bi->BSSID.octet, iscan_cur);
1658
1659                 bi = (wl_bss_info_t *) ((uintptr) bi + dtoh32(bi->length));
1660         }
1661
1662 done:
1663         DHD_ISCAN(("%s: Scan cache after delete\n", __func__));
1664         dhd_iscan_print_cache(iscan_cur);
1665         dhd_iscan_unlock();
1666         return 0;
1667 }
1668
1669 void dhd_iscan_ind_scan_confirm(void *dhdp, bool status)
1670 {
1671
1672         dhd_ind_scan_confirm(dhdp, status);
1673 }
1674
1675 int dhd_iscan_request(void *dhdp, uint16 action)
1676 {
1677         int rc;
1678         wl_iscan_params_t params;
1679         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1680         char buf[WLC_IOCTL_SMLEN];
1681
1682         memset(&params, 0, sizeof(wl_iscan_params_t));
1683         memcpy(&params.params.bssid, &ether_bcast, ETHER_ADDR_LEN);
1684
1685         params.params.bss_type = DOT11_BSSTYPE_ANY;
1686         params.params.scan_type = DOT11_SCANTYPE_ACTIVE;
1687
1688         params.params.nprobes = htod32(-1);
1689         params.params.active_time = htod32(-1);
1690         params.params.passive_time = htod32(-1);
1691         params.params.home_time = htod32(-1);
1692         params.params.channel_num = htod32(0);
1693
1694         params.version = htod32(ISCAN_REQ_VERSION);
1695         params.action = htod16(action);
1696         params.scan_duration = htod16(0);
1697
1698         bcm_mkiovar("iscan", (char *)&params, sizeof(wl_iscan_params_t), buf,
1699                     WLC_IOCTL_SMLEN);
1700         rc = dhd_wl_ioctl(dhdp, WLC_SET_VAR, buf, WLC_IOCTL_SMLEN);
1701
1702         return rc;
1703 }
1704
1705 static int dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1706 {
1707         wl_iscan_results_t *list_buf;
1708         wl_iscan_results_t list;
1709         wl_scan_results_t *results;
1710         iscan_buf_t *iscan_cur;
1711         int status = -1;
1712         dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1713         int rc;
1714
1715         iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1716         if (!iscan_cur) {
1717                 DHD_ERROR(("%s: Failed to allocate node\n", __func__));
1718                 dhd_iscan_free_buf(dhdp, 0);
1719                 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1720                 goto fail;
1721         }
1722
1723         dhd_iscan_lock();
1724
1725         memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1726         list_buf = (wl_iscan_results_t *) iscan_cur->iscan_buf;
1727         results = &list_buf->results;
1728         results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1729         results->version = 0;
1730         results->count = 0;
1731
1732         memset(&list, 0, sizeof(list));
1733         list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1734         bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1735                     iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1736         rc = dhd_wl_ioctl(dhdp, WLC_GET_VAR, iscan_cur->iscan_buf,
1737                           WLC_IW_ISCAN_MAXLEN);
1738
1739         results->buflen = dtoh32(results->buflen);
1740         results->version = dtoh32(results->version);
1741         *scan_count = results->count = dtoh32(results->count);
1742         status = dtoh32(list_buf->status);
1743
1744         dhd_iscan_unlock();
1745
1746         if (!(*scan_count))
1747                 dhd_iscan_free_buf(dhdp, iscan_cur);
1748         else
1749                 dhd_iscan_remove_duplicates(dhdp, iscan_cur);
1750
1751 fail:
1752         return status;
1753 }
1754 #endif                          /* SIMPLE_ISCAN */
1755
1756 #ifdef PNO_SUPPORT
1757 int dhd_pno_clean(dhd_pub_t *dhd)
1758 {
1759         char iovbuf[128];
1760         int pfn_enabled = 0;
1761         int iov_len = 0;
1762         int ret;
1763
1764         /* Disable pfn */
1765         iov_len =
1766             bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1767         if ((ret =
1768              dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1769                               sizeof(iovbuf))) >= 0) {
1770                 /* clear pfn */
1771                 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1772                 if (iov_len) {
1773                         if ((ret =
1774                              dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1775                                               iov_len)) < 0) {
1776                                 DHD_ERROR(("%s failed code %d\n", __func__,
1777                                            ret));
1778                         }
1779                 } else {
1780                         ret = -1;
1781                         DHD_ERROR(("%s failed code %d\n", __func__, iov_len));
1782                 }
1783         } else
1784                 DHD_ERROR(("%s failed code %d\n", __func__, ret));
1785
1786         return ret;
1787 }
1788
1789 int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1790 {
1791         char iovbuf[128];
1792         int ret = -1;
1793
1794         if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1795                 DHD_ERROR(("%s error exit\n", __func__));
1796                 return ret;
1797         }
1798
1799         /* Enable/disable PNO */
1800         if ((ret =
1801              bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf,
1802                          sizeof(iovbuf))) > 0) {
1803                 if ((ret =
1804                      dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1805                                       sizeof(iovbuf))) < 0) {
1806                         DHD_ERROR(("%s failed for error=%d\n", __func__, ret));
1807                         return ret;
1808                 } else {
1809                         dhd->pno_enable = pfn_enabled;
1810                         DHD_TRACE(("%s set pno as %d\n", __func__,
1811                                    dhd->pno_enable));
1812                 }
1813         } else
1814                 DHD_ERROR(("%s failed err=%d\n", __func__, ret));
1815
1816         return ret;
1817 }
1818
1819 /* Function to execute combined scan */
1820 int
1821 dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t *ssids_local, int nssid, uchar scan_fr)
1822 {
1823         int err = -1;
1824         char iovbuf[128];
1825         int k, i;
1826         wl_pfn_param_t pfn_param;
1827         wl_pfn_t pfn_element;
1828
1829         DHD_TRACE(("%s nssid=%d nchan=%d\n", __func__, nssid, scan_fr));
1830
1831         if ((!dhd) && (!ssids_local)) {
1832                 DHD_ERROR(("%s error exit\n", __func__));
1833                 err = -1;
1834         }
1835
1836         /* Check for broadcast ssid */
1837         for (k = 0; k < nssid; k++) {
1838                 if (!ssids_local[k].SSID_len) {
1839                         DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO "
1840                                 "setting\n", k));
1841                         return err;
1842                 }
1843         }
1844 /* #define  PNO_DUMP 1 */
1845 #ifdef PNO_DUMP
1846         {
1847                 int j;
1848                 for (j = 0; j < nssid; j++) {
1849                         DHD_ERROR(("%d: scan  for  %s size =%d\n", j,
1850                                    ssids_local[j].SSID,
1851                                    ssids_local[j].SSID_len));
1852                 }
1853         }
1854 #endif                          /* PNO_DUMP */
1855
1856         /* clean up everything */
1857         if ((err = dhd_pno_clean(dhd)) < 0) {
1858                 DHD_ERROR(("%s failed error=%d\n", __func__, err));
1859                 return err;
1860         }
1861         memset(&pfn_param, 0, sizeof(pfn_param));
1862         memset(&pfn_element, 0, sizeof(pfn_element));
1863
1864         /* set pfn parameters */
1865         pfn_param.version = htod32(PFN_VERSION);
1866         pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT));
1867
1868         /* set up pno scan fr */
1869         if (scan_fr != 0)
1870                 pfn_param.scan_freq = htod32(scan_fr);
1871
1872         bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf,
1873                     sizeof(iovbuf));
1874         dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf, sizeof(iovbuf));
1875
1876         /* set all pfn ssid */
1877         for (i = 0; i < nssid; i++) {
1878
1879                 pfn_element.bss_type = htod32(DOT11_BSSTYPE_INFRASTRUCTURE);
1880                 pfn_element.auth = (DOT11_OPEN_SYSTEM);
1881                 pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY);
1882                 pfn_element.wsec = htod32(0);
1883                 pfn_element.infra = htod32(1);
1884
1885                 memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID,
1886                        ssids_local[i].SSID_len);
1887                 pfn_element.ssid.SSID_len = ssids_local[i].SSID_len;
1888
1889                 if ((err =
1890                      bcm_mkiovar("pfn_add", (char *)&pfn_element,
1891                                  sizeof(pfn_element), iovbuf,
1892                                  sizeof(iovbuf))) > 0) {
1893                         if ((err =
1894                              dhdcdc_set_ioctl(dhd, 0, WLC_SET_VAR, iovbuf,
1895                                               sizeof(iovbuf))) < 0) {
1896                                 DHD_ERROR(("%s failed for i=%d error=%d\n",
1897                                            __func__, i, err));
1898                                 return err;
1899                         }
1900                 } else
1901                         DHD_ERROR(("%s failed err=%d\n", __func__, err));
1902         }
1903
1904         /* Enable PNO */
1905         /* dhd_pno_enable(dhd, 1); */
1906         return err;
1907 }
1908
1909 int dhd_pno_get_status(dhd_pub_t *dhd)
1910 {
1911         int ret = -1;
1912
1913         if (!dhd)
1914                 return ret;
1915         else
1916                 return dhd->pno_enable;
1917 }
1918
1919 #endif                          /* PNO_SUPPORT */
1920
1921 /* Androd ComboSCAN support */