2 * Copyright (c) 2010 Broadcom Corporation
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.
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.
19 #include <bcmendian.h>
20 #include <dngl_stats.h>
23 #include <dhd_proto.h>
29 char fw_path
[MOD_PARAM_PATHLEN
];
30 char nv_path
[MOD_PARAM_PATHLEN
];
32 /* Last connection success/failure status */
33 uint32 dhd_conn_event
;
34 uint32 dhd_conn_status
;
35 uint32 dhd_conn_reason
;
42 extern int dhdcdc_set_ioctl(dhd_pub_t
*dhd
, int ifidx
, uint cmd
, void *buf
,
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);
49 /* Packet alignment for most efficient SDIO (can change based on platform) */
51 #define DHD_SDALIGN 32
53 #if !ISPOWEROF2(DHD_SDALIGN)
54 #error DHD_SDALIGN is not a power of 2!
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__
63 const char dhd_version
[] = "Dongle Host Driver, version " EPI_VERSION_STR
;
66 void dhd_set_timer(void *bus
, uint wdtick
);
89 const bcm_iovar_t dhd_iovars
[] = {
90 {"version", IOV_VERSION
, 0, IOVT_BUFFER
, sizeof(dhd_version
)}
93 {"msglevel", IOV_MSGLEVEL
, 0, IOVT_UINT32
, 0}
95 #endif /* DHD_DEBUG */
96 {"bcmerrorstr", IOV_BCMERRORSTR
, 0, IOVT_BUFFER
, BCME_STRLEN
}
98 {"bcmerror", IOV_BCMERROR
, 0, IOVT_INT8
, 0}
100 {"wdtick", IOV_WDTICK
, 0, IOVT_UINT32
, 0}
102 {"dump", IOV_DUMP
, 0, IOVT_BUFFER
, DHD_IOCTL_MAXLEN
}
105 {"dconpoll", IOV_DCONSOLE_POLL
, 0, IOVT_UINT32
, 0}
107 {"cons", IOV_CONS
, 0, IOVT_BUFFER
, 0}
110 {"clearcounts", IOV_CLEARCOUNTS
, 0, IOVT_VOID
, 0}
112 {"gpioob", IOV_GPIOOB
, 0, IOVT_UINT32
, 0}
114 {"ioctl_timeout", IOV_IOCTLTIMEOUT
, 0, IOVT_UINT32
, 0}
119 void dhd_common_init(void)
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.
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
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);
135 #ifdef CONFIG_BCM4329_NVRAM_PATH
136 strncpy(nv_path
, CONFIG_BCM4329_NVRAM_PATH
, MOD_PARAM_PATHLEN
- 1);
142 static int dhd_dump(dhd_pub_t
*dhdp
, char *buf
, int buflen
)
144 char eabuf
[ETHER_ADDR_STR_LEN
];
147 struct bcmstrbuf
*strbuf
= &b
;
149 bcm_binit(strbuf
, buf
, buflen
);
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
,
161 bcm_bprintf(strbuf
, "pub.bcmerror %d tickcnt %d\n", dhdp
->bcmerror
,
164 bcm_bprintf(strbuf
, "dongle stats:\n");
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
);
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
);
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
);
183 "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld rx_flushed %ld\n",
184 dhdp
->rx_ctlpkts
, dhdp
->rx_ctlerrs
, dhdp
->rx_dropped
,
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");
192 /* Add any prot info */
193 dhd_prot_dump(dhdp
, strbuf
);
194 bcm_bprintf(strbuf
, "\n");
196 /* Add any bus info */
197 dhd_bus_dump(dhdp
, strbuf
);
199 return !strbuf
->size
? BCME_BUFTOOSHORT
: 0;
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
,
210 DHD_TRACE(("%s: Enter\n", __func__
));
212 bcmerror
= bcm_iovar_lencheck(vi
, arg
, len
, IOV_ISSET(actionid
));
216 if (plen
>= (int)sizeof(int_val
))
217 bcopy(params
, &int_val
, sizeof(int_val
));
220 case IOV_GVAL(IOV_VERSION
):
221 /* Need to have checked buffer length */
222 strncpy((char *)arg
, dhd_version
, len
);
225 case IOV_GVAL(IOV_MSGLEVEL
):
226 int_val
= (int32
) dhd_msg_level
;
227 bcopy(&int_val
, arg
, val_size
);
230 case IOV_SVAL(IOV_MSGLEVEL
):
231 dhd_msg_level
= int_val
;
234 case IOV_GVAL(IOV_BCMERRORSTR
):
235 strncpy((char *)arg
, bcmerrorstr(dhd_pub
->bcmerror
),
237 ((char *)arg
)[BCME_STRLEN
- 1] = 0x00;
240 case IOV_GVAL(IOV_BCMERROR
):
241 int_val
= (int32
) dhd_pub
->bcmerror
;
242 bcopy(&int_val
, arg
, val_size
);
245 case IOV_GVAL(IOV_WDTICK
):
246 int_val
= (int32
) dhd_watchdog_ms
;
247 bcopy(&int_val
, arg
, val_size
);
250 case IOV_SVAL(IOV_WDTICK
):
252 bcmerror
= BCME_NOTUP
;
255 dhd_os_wd_timer(dhd_pub
, (uint
) int_val
);
258 case IOV_GVAL(IOV_DUMP
):
259 bcmerror
= dhd_dump(dhd_pub
, arg
, len
);
263 case IOV_GVAL(IOV_DCONSOLE_POLL
):
264 int_val
= (int32
) dhd_console_ms
;
265 bcopy(&int_val
, arg
, val_size
);
268 case IOV_SVAL(IOV_DCONSOLE_POLL
):
269 dhd_console_ms
= (uint
) int_val
;
272 case IOV_SVAL(IOV_CONS
):
274 bcmerror
= dhd_bus_console_in(dhd_pub
, arg
, len
- 1);
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
);
291 case IOV_GVAL(IOV_IOCTLTIMEOUT
):{
292 int_val
= (int32
) dhd_os_get_ioctl_resp_timeout();
293 bcopy(&int_val
, arg
, sizeof(int_val
));
297 case IOV_SVAL(IOV_IOCTLTIMEOUT
):{
299 bcmerror
= BCME_BADARG
;
301 dhd_os_set_ioctl_resp_timeout((unsigned int)
307 bcmerror
= BCME_UNSUPPORTED
;
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
)
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.
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
;
330 bool dhd_prec_enq(dhd_pub_t
*dhdp
, struct pktq
*q
, void *pkt
, int prec
)
333 int eprec
= -1; /* precedence to evict from */
336 /* Fast case, precedence queue is not full and we are also not
337 * exceeding total queue length
339 if (!pktq_pfull(q
, prec
) && !pktq_full(q
)) {
340 pktq_penq(q
, prec
, pkt
);
344 /* Determine precedence from which to evict packet, if any */
345 if (pktq_pfull(q
, prec
))
347 else if (pktq_full(q
)) {
348 p
= pktq_peek_tail(q
, &eprec
);
354 /* Evict if needed */
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
,
365 DHD_ERROR(("%s: pktq_penq() failed, oldest %d.",
366 __func__
, discard_oldest
));
370 PKTFREE(dhdp
->osh
, p
, TRUE
);
374 p
= pktq_penq(q
, prec
, pkt
);
376 DHD_ERROR(("%s: pktq_penq() failed.", __func__
));
384 dhd_iovar_op(dhd_pub_t
*dhd_pub
, const char *name
,
385 void *params
, int plen
, void *arg
, int len
, bool set
)
389 const bcm_iovar_t
*vi
= NULL
;
392 DHD_TRACE(("%s: Enter\n", __func__
));
397 /* Get MUST have return space */
398 ASSERT(set
|| (arg
&& len
));
400 /* Set does NOT take qualifiers */
401 ASSERT(!set
|| (!params
&& !plen
));
403 vi
= bcm_iovar_lookup(dhd_iovars
, name
);
405 bcmerror
= BCME_UNSUPPORTED
;
409 DHD_CTL(("%s: %s %s, len %d plen %d\n", __func__
,
410 name
, (set
? "set" : "get"), len
, plen
));
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
415 if (params
== NULL
) {
420 if (vi
->type
== IOVT_VOID
)
422 else if (vi
->type
== IOVT_BUFFER
)
425 /* all other types are integer sized */
426 val_size
= sizeof(int);
428 actionid
= set
? IOV_SVAL(vi
->varid
) : IOV_GVAL(vi
->varid
);
430 dhd_doiovar(dhd_pub
, vi
, actionid
, name
, params
, plen
, arg
, len
,
437 int dhd_ioctl(dhd_pub_t
*dhd_pub
, dhd_ioctl_t
*ioc
, void *buf
, uint buflen
)
441 DHD_TRACE(("%s: Enter\n", __func__
));
448 if (buflen
< sizeof(int))
449 bcmerror
= BCME_BUFTOOSHORT
;
451 *(int *)buf
= DHD_IOCTL_MAGIC
;
454 case DHD_GET_VERSION
:
455 if (buflen
< sizeof(int))
456 bcmerror
= -BCME_BUFTOOSHORT
;
458 *(int *)buf
= DHD_IOCTL_VERSION
;
466 /* scan past the name to any arguments */
467 for (arg
= buf
, arglen
= buflen
; *arg
&& arglen
;
472 bcmerror
= BCME_BUFTOOSHORT
;
476 /* account for the NUL terminator */
479 /* call with the appropriate arguments */
480 if (ioc
->cmd
== DHD_GET_VAR
)
482 dhd_iovar_op(dhd_pub
, buf
, arg
, arglen
, buf
,
486 dhd_iovar_op(dhd_pub
, buf
, NULL
, 0, arg
,
488 if (bcmerror
!= BCME_UNSUPPORTED
)
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
,
497 bcmerror
= dhd_prot_iovar_op(dhd_pub
, buf
,
500 if (bcmerror
!= BCME_UNSUPPORTED
)
503 /* if still not found, try bus module */
504 if (ioc
->cmd
== DHD_GET_VAR
)
505 bcmerror
= dhd_bus_iovar_op(dhd_pub
, buf
,
509 bcmerror
= dhd_bus_iovar_op(dhd_pub
, buf
,
517 bcmerror
= BCME_UNSUPPORTED
;
524 static void wl_show_host_event(wl_event_msg_t
*event
, void *event_data
)
526 uint i
, status
, reason
;
527 bool group
= FALSE
, flush_txq
= FALSE
, link
= FALSE
;
528 char *auth_str
, *event_name
;
530 char err_msg
[256], eabuf
[ETHER_ADDR_STR_LEN
];
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"}, {
590 WLC_E_RSSI
, "RSSI"}, {
591 WLC_E_PFN_SCAN_COMPLETE
, "SCAN_COMPLETE"}
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);
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
;
615 DHD_EVENT(("EVENT: %s, event ID = %d\n", event_name
, event_type
));
617 if (flags
& WLC_EVENT_MSG_LINK
)
619 if (flags
& WLC_EVENT_MSG_GROUP
)
621 if (flags
& WLC_EVENT_MSG_FLUSHTXQ
)
624 switch (event_type
) {
628 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
631 case WLC_E_ASSOC_IND
:
632 case WLC_E_REASSOC_IND
:
633 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
, eabuf
));
638 if (status
== WLC_E_STATUS_SUCCESS
) {
639 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n",
641 } else if (status
== WLC_E_STATUS_TIMEOUT
) {
642 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n",
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
));
648 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status "
649 "%d\n", event_name
, eabuf
, (int)status
));
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
));
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";
666 sprintf(err_msg
, "AUTH unknown: %d", (int)auth_type
);
669 if (event_type
== WLC_E_AUTH_IND
) {
670 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name
,
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, "
681 event_name
, eabuf
, auth_str
, (int)reason
));
689 if (status
== WLC_E_STATUS_SUCCESS
) {
690 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name
,
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",
698 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
699 event_name
, (int)status
));
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
));
709 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name
,
715 DHD_EVENT(("MACEVENT: %s %s\n", event_name
,
716 link
? "UP" : "DOWN"));
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
));
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
));
731 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name
, eabuf
));
734 case WLC_E_SCAN_COMPLETE
:
735 case WLC_E_PMKID_CACHE
:
736 DHD_EVENT(("MACEVENT: %s\n", event_name
));
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
));
747 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
748 event_name
, (int)status
, (int)reason
));
753 static uint32 seqnum_prev
= 0;
758 buf
= (uchar
*) event_data
;
759 memcpy(&hdr
, buf
, MSGTRACE_HDRLEN
);
761 if (hdr
.version
!= MSGTRACE_VERSION
) {
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 */
771 /* There are 2 bytes available at the end of data */
772 buf
[MSGTRACE_HDRLEN
+ ntoh16(hdr
.len
)] = '\0';
774 if (ntoh32(hdr
.discarded_bytes
)
775 || ntoh32(hdr
.discarded_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
));
783 nblost
= ntoh32(hdr
.seqnum
) - seqnum_prev
- 1;
786 ("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
787 ntoh32(hdr
.seqnum
), nblost
);
789 seqnum_prev
= ntoh32(hdr
.seqnum
);
791 /* Display the trace buffer. Advance from \n to \n to
793 * printf (issue with Linux printk )
795 p
= (char *)&buf
[MSGTRACE_HDRLEN
];
796 while ((s
= strstr(p
, "\n")) != NULL
) {
803 /* Reset datalen to avoid display below */
809 DHD_EVENT(("MACEVENT: %s %d\n", event_name
,
810 ntoh32(*((int *)event_data
))));
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
));
820 /* show any appended data */
822 buf
= (uchar
*) event_data
;
823 DHD_EVENT((" data (%d) : ", datalen
));
824 for (i
= 0; i
< datalen
; i
++)
825 DHD_EVENT((" 0x%02x ", *buf
++));
829 #endif /* SHOW_EVENTS */
832 wl_host_event(struct dhd_info
*dhd
, int *ifidx
, void *pktdata
,
833 wl_event_msg_t
*event
, void **data_ptr
)
835 /* check whether packet is a BRCM event pkt */
836 bcm_event_t
*pvt_data
= (bcm_event_t
*) pktdata
;
842 if (bcmp(BRCM_OUI
, &pvt_data
->bcm_hdr
.oui
[0], DOT11_OUI_LEN
)) {
843 DHD_ERROR(("%s: mismatched OUI, bailing\n", __func__
));
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__
));
854 *data_ptr
= &pvt_data
[1];
855 event_data
= *data_ptr
;
857 /* memcpy since BRCM event pkt may be unaligned. */
858 memcpy(event
, &pvt_data
->event
, sizeof(wl_event_msg_t
));
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
);
868 dhd_if_event_t
*ifevent
= (dhd_if_event_t
*) event_data
;
869 DHD_TRACE(("%s: if event\n", __func__
));
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
,
876 pvt_data
->eth
.ether_dhost
,
880 dhd_del_if(dhd
, ifevent
->ifidx
);
882 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
883 __func__
, ifevent
->ifidx
,
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
);
894 case WLC_E_NDIS_LINK
:
898 /* These are what external supplicant/authenticator wants */
900 case WLC_E_ASSOC_IND
:
901 case WLC_E_REASSOC_IND
:
902 case WLC_E_DISASSOC_IND
:
903 case WLC_E_MIC_ERROR
:
905 /* Fall through: this should get _everything_ */
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
));
913 /* put it back to WLC_E_NDIS_LINK */
914 if (type
== WLC_E_NDIS_LINK
) {
917 temp
= ntoh32_ua((void *)&event
->event_type
);
918 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp
));
920 temp
= ntoh32(WLC_E_NDIS_LINK
);
921 memcpy((void *)(&pvt_data
->event
.event_type
), &temp
,
922 sizeof(pvt_data
->event
.event_type
));
928 wl_show_host_event(event
, event_data
);
929 #endif /* SHOW_EVENTS */
934 void wl_event_to_host_order(wl_event_msg_t
*evt
)
936 /* Event struct members passed from dongle to host are stored
938 * byte order. Convert all members to host-order.
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
);
949 void print_buf(void *pbuf
, int len
, int bytes_per_line
)
952 unsigned char *buf
= pbuf
;
954 if (bytes_per_line
== 0)
955 bytes_per_line
= len
;
957 for (i
= 0; i
< len
; i
++) {
958 printf("%2.2x", *buf
++);
960 if (j
== bytes_per_line
) {
970 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
972 /* Convert user's input in hex pattern to byte-size mask */
973 static int wl_pattern_atoh(char *src
, char *dst
)
976 if (strncmp(src
, "0x", 2) != 0 && strncmp(src
, "0X", 2) != 0) {
977 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
980 src
= src
+ 2; /* Skip past 0x */
981 if (strlen(src
) % 2 != 0) {
982 DHD_ERROR(("Mask invalid format. Length must be even.\n"));
985 for (i
= 0; *src
!= '\0'; i
++) {
987 strncpy(num
, src
, 2);
989 dst
[i
] = (u8
) strtoul(num
, NULL
, 16);
996 dhd_pktfilter_offload_enable(dhd_pub_t
*dhd
, char *arg
, int enable
,
1004 char *arg_save
= 0, *arg_org
= 0;
1007 wl_pkt_filter_enable_t enable_parm
;
1008 wl_pkt_filter_enable_t
*pkt_filterp
;
1010 arg_save
= MALLOC(dhd
->osh
, strlen(arg
) + 1);
1012 DHD_ERROR(("%s: kmalloc failed\n", __func__
));
1016 memcpy(arg_save
, arg
, strlen(arg
) + 1);
1018 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1021 if (NULL
== argv
[i
]) {
1022 DHD_ERROR(("No args provided\n"));
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;
1032 pkt_filterp
= (wl_pkt_filter_enable_t
*) (buf
+ str_len
+ 1);
1034 /* Parse packet filter id. */
1035 enable_parm
.id
= htod32(strtoul(argv
[i
], NULL
, 0));
1037 /* Parse enable/disable value. */
1038 enable_parm
.enable
= htod32(enable
);
1040 buf_len
+= sizeof(enable_parm
);
1041 memcpy((char *)pkt_filterp
, &enable_parm
, sizeof(enable_parm
));
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
;
1047 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1048 __func__
, arg
, rc
));
1050 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1053 /* Contorl the master mode */
1054 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode
, 4, buf
,
1056 rc
= dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, buf
, sizeof(buf
));
1057 rc
= rc
>= 0 ? 0 : rc
;
1059 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1060 __func__
, arg
, rc
));
1064 MFREE(dhd
->osh
, arg_org
, strlen(arg
) + 1);
1067 void dhd_pktfilter_offload_set(dhd_pub_t
*dhd
, char *arg
)
1070 wl_pkt_filter_t pkt_filter
;
1071 wl_pkt_filter_t
*pkt_filterp
;
1076 uint32 pattern_size
;
1077 char *argv
[8], *buf
= 0;
1079 char *arg_save
= 0, *arg_org
= 0;
1080 #define BUF_SIZE 2048
1082 if (!(arg_save
= MALLOC(dhd
->osh
, strlen(arg
) + 1))) {
1083 DHD_ERROR(("%s: kmalloc failed\n", __func__
));
1089 if (!(buf
= MALLOC(dhd
->osh
, BUF_SIZE
))) {
1090 DHD_ERROR(("%s: kmalloc failed\n", __func__
));
1094 memcpy(arg_save
, arg
, strlen(arg
) + 1);
1096 if (strlen(arg
) > BUF_SIZE
) {
1097 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg
),
1102 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1104 argv
[i
] = bcmstrtok(&arg_save
, " ", 0);
1107 if (NULL
== argv
[i
]) {
1108 DHD_ERROR(("No args provided\n"));
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;
1118 pkt_filterp
= (wl_pkt_filter_t
*) (buf
+ str_len
+ 1);
1120 /* Parse packet filter id. */
1121 pkt_filter
.id
= htod32(strtoul(argv
[i
], NULL
, 0));
1123 if (NULL
== argv
[++i
]) {
1124 DHD_ERROR(("Polarity not provided\n"));
1128 /* Parse filter polarity. */
1129 pkt_filter
.negate_match
= htod32(strtoul(argv
[i
], NULL
, 0));
1131 if (NULL
== argv
[++i
]) {
1132 DHD_ERROR(("Filter type not provided\n"));
1136 /* Parse filter type. */
1137 pkt_filter
.type
= htod32(strtoul(argv
[i
], NULL
, 0));
1139 if (NULL
== argv
[++i
]) {
1140 DHD_ERROR(("Offset not provided\n"));
1144 /* Parse pattern filter offset. */
1145 pkt_filter
.u
.pattern
.offset
= htod32(strtoul(argv
[i
], NULL
, 0));
1147 if (NULL
== argv
[++i
]) {
1148 DHD_ERROR(("Bitmask not provided\n"));
1152 /* Parse pattern filter mask. */
1154 htod32(wl_pattern_atoh
1155 (argv
[i
], (char *)pkt_filterp
->u
.pattern
.mask_and_pattern
));
1157 if (NULL
== argv
[++i
]) {
1158 DHD_ERROR(("Pattern not provided\n"));
1162 /* Parse pattern filter pattern. */
1164 htod32(wl_pattern_atoh(argv
[i
],
1165 (char *)&pkt_filterp
->u
.pattern
.
1166 mask_and_pattern
[mask_size
]));
1168 if (mask_size
!= pattern_size
) {
1169 DHD_ERROR(("Mask and pattern not the same size\n"));
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
);
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.
1182 memcpy((char *)pkt_filterp
,
1184 WL_PKT_FILTER_FIXED_LEN
+ WL_PKT_FILTER_PATTERN_FIXED_LEN
);
1186 rc
= dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, buf
, buf_len
);
1187 rc
= rc
>= 0 ? 0 : rc
;
1190 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1191 __func__
, arg
, rc
));
1193 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1198 MFREE(dhd
->osh
, arg_org
, strlen(arg
) + 1);
1201 MFREE(dhd
->osh
, buf
, BUF_SIZE
);
1204 void dhd_arp_offload_set(dhd_pub_t
*dhd
, int arp_mode
)
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
;
1213 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, "
1214 "retcode = %d\n", __func__
, arp_mode
, retcode
));
1216 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1217 __func__
, arp_mode
));
1220 void dhd_arp_offload_enable(dhd_pub_t
*dhd
, int arp_enable
)
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
;
1229 DHD_TRACE(("%s: failed to enabe ARP offload to %d, "
1230 "retcode = %d\n", __func__
, arp_enable
, retcode
));
1232 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1233 __func__
, arp_enable
));
1236 int dhd_preinit_ioctls(dhd_pub_t
*dhd
)
1238 char iovbuf
[WL_EVENTING_MASK_LEN
+ 12]; /* Room for
1239 "event_msgs" + '\0' + bitvec */
1241 char buf
[128], *ptr
;
1242 uint power_mode
= PM_FAST
;
1243 uint32 dongle_align
= DHD_SDALIGN
;
1245 uint bcn_timeout
= 3;
1246 int scan_assoc_time
= 40;
1247 int scan_unassoc_time
= 40;
1248 #ifdef GET_CUSTOM_MAC_ENABLE
1250 struct ether_addr ea_addr
;
1251 #endif /* GET_CUSTOM_MAC_ENABLE */
1253 dhd_os_proto_block(dhd
);
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
1262 ret
= dhd_custom_get_mac_address(ea_addr
.octet
);
1264 bcm_mkiovar("cur_etheraddr", (void *)&ea_addr
, ETHER_ADDR_LEN
,
1266 ret
= dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, buf
, sizeof(buf
));
1268 DHD_ERROR(("%s: can't set MAC address , error=%d\n",
1271 memcpy(dhd
->mac
.octet
, (void *)&ea_addr
,
1274 #endif /* GET_CUSTOM_MAC_ENABLE */
1276 /* Set Country code */
1277 if (dhd
->country_code
[0] != 0) {
1278 if (dhdcdc_set_ioctl(dhd
, 0, WLC_SET_COUNTRY
,
1280 sizeof(dhd
->country_code
)) < 0) {
1281 DHD_ERROR(("%s: country code setting failed\n",
1286 /* query for 'ver' to get version info from firmware */
1287 memset(buf
, 0, sizeof(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
));
1295 /* Set PowerSave mode */
1296 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_PM
, (char *)&power_mode
,
1297 sizeof(power_mode
));
1299 /* Match Host and Dongle rx alignment */
1300 bcm_mkiovar("bus:txglomalign", (char *)&dongle_align
, 4, iovbuf
,
1302 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
));
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
));
1308 /* Setup timeout if Beacons are lost and roam is off to report
1310 bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout
, 4, iovbuf
,
1312 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
));
1314 /* Enable/Disable build-in roaming to allowed ext supplicant to take
1316 bcm_mkiovar("roam_off", (char *)&dhd_roam
, 4, iovbuf
, sizeof(iovbuf
));
1317 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
));
1321 dhdcdc_set_ioctl(dhd
, 0, WLC_UP
, (char *)&up
, sizeof(up
));
1323 /* Setup event_msgs */
1324 bcm_mkiovar("event_msgs", dhd
->eventmask
, WL_EVENTING_MASK_LEN
, iovbuf
,
1326 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
));
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
));
1333 #ifdef ARP_OFFLOAD_SUPPORT
1334 /* Set and enable ARP offload feature */
1336 dhd_arp_offload_set(dhd
, dhd_arp_mode
);
1337 dhd_arp_offload_enable(dhd
, dhd_arp_enable
);
1338 #endif /* ARP_OFFLOAD_SUPPORT */
1340 #ifdef PKT_FILTER_SUPPORT
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
,
1348 dhd_pktfilter_offload_enable(dhd
,
1350 dhd_pkt_filter_init
,
1355 #endif /* PKT_FILTER_SUPPORT */
1357 dhd_os_proto_unblock(dhd
);
1363 uint iscan_thread_id
;
1364 iscan_buf_t
*iscan_chain
= 0;
1366 iscan_buf_t
*dhd_iscan_allocate_buf(dhd_pub_t
*dhd
, iscan_buf_t
**iscanbuf
)
1368 iscan_buf_t
*iscanbuf_alloc
= 0;
1369 iscan_buf_t
*iscanbuf_head
;
1373 iscanbuf_alloc
= (iscan_buf_t
*) MALLOC(dhd
->osh
, sizeof(iscan_buf_t
));
1374 if (iscanbuf_alloc
== NULL
)
1377 iscanbuf_alloc
->next
= NULL
;
1378 iscanbuf_head
= *iscanbuf
;
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
));
1384 if (iscanbuf_head
== NULL
) {
1385 *iscanbuf
= iscanbuf_alloc
;
1386 DHD_ISCAN(("%s: Head is allocated\n", __func__
));
1390 while (iscanbuf_head
->next
)
1391 iscanbuf_head
= iscanbuf_head
->next
;
1393 iscanbuf_head
->next
= iscanbuf_alloc
;
1397 return iscanbuf_alloc
;
1400 void dhd_iscan_free_buf(void *dhdp
, iscan_buf_t
*iscan_delete
)
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
);
1408 /* If iscan_delete is null then delete the entire
1409 * chain or else delete specific one provided
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
));
1420 while (iscanbuf_cur
) {
1421 if (iscanbuf_cur
== iscan_delete
)
1423 iscanbuf_prv
= iscanbuf_cur
;
1424 iscanbuf_cur
= iscanbuf_cur
->next
;
1427 iscanbuf_prv
->next
= iscan_delete
->next
;
1429 iscan_delete
->next
= 0;
1430 MFREE(dhd
->osh
, iscan_delete
, sizeof(iscan_buf_t
));
1438 iscan_buf_t
*dhd_iscan_result_buf(void)
1445 * print partial iscan_skip list differently
1447 int dhd_iscan_print_cache(iscan_buf_t
*iscan_skip
)
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
;
1457 iscan_cur
= dhd_iscan_result_buf();
1460 list
= (wl_iscan_results_t
*)iscan_cur
->iscan_buf
;
1464 results
= (wl_scan_results_t
*)&list
->results
;
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
));
1475 bi
= results
->bss_info
;
1476 for (i
= 0; i
< results
->count
; i
++) {
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]));
1486 bi
= (wl_bss_info_t
*) ((uintptr
) bi
+
1487 dtoh32(bi
->length
));
1489 iscan_cur
= iscan_cur
->next
;
1499 * delete disappeared AP from specific scan cache but skip partial
1500 * list in iscan_skip
1502 int dhd_iscan_delete_bss(void *dhdp
, void *addr
, iscan_buf_t
*iscan_skip
)
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
;
1510 uchar
*s_addr
= addr
;
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]));
1517 iscan_cur
= dhd_iscan_result_buf();
1520 if (iscan_cur
!= iscan_skip
) {
1521 list
= (wl_iscan_results_t
*)iscan_cur
->iscan_buf
;
1525 results
= (wl_scan_results_t
*)&list
->results
;
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
));
1536 bi
= results
->bss_info
;
1537 for (i
= 0; i
< results
->count
; i
++) {
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]));
1551 bi
= (wl_bss_info_t
*) ((uintptr
) bi
+
1556 bcopy(bi, bi_new, results->buflen -
1557 dtoh32(bi_new->length));
1558 results->buflen -= dtoh32(bi_new->length);
1562 dtoh32(bi_new
->length
);
1565 for (j
= i
; j
< results
->count
; j
++) {
1567 DHD_ISCAN(("%s: Moved up BSS[%2.2d:%2.2d]" "%X:%X:%X:%X:%X:%X\n",
1574 bi
->BSSID
.octet
[5]));
1595 if (results
->count
== 0) {
1596 /* Prune now empty partial
1598 dhd_iscan_free_buf(dhdp
,
1604 bi
= (wl_bss_info_t
*) ((uintptr
) bi
+
1605 dtoh32(bi
->length
));
1608 iscan_cur
= iscan_cur
->next
;
1617 int dhd_iscan_remove_duplicates(void *dhdp
, iscan_buf_t
*iscan_cur
)
1620 wl_iscan_results_t
*list
;
1621 wl_scan_results_t
*results
;
1622 wl_bss_info_t UNALIGNED
*bi
, *bi_new
, *bi_next
;
1626 DHD_ISCAN(("%s: Scan cache before delete\n", __func__
));
1627 dhd_iscan_print_cache(iscan_cur
);
1632 list
= (wl_iscan_results_t
*)iscan_cur
->iscan_buf
;
1636 results
= (wl_scan_results_t
*)&list
->results
;
1640 if (results
->version
!= WL_BSS_INFO_VERSION
) {
1641 DHD_ERROR(("%s: results->version %d != WL_BSS_INFO_VERSION\n",
1642 __func__
, results
->version
));
1646 bi
= results
->bss_info
;
1647 for (i
= 0; i
< results
->count
; i
++) {
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]));
1657 dhd_iscan_delete_bss(dhdp
, bi
->BSSID
.octet
, iscan_cur
);
1659 bi
= (wl_bss_info_t
*) ((uintptr
) bi
+ dtoh32(bi
->length
));
1663 DHD_ISCAN(("%s: Scan cache after delete\n", __func__
));
1664 dhd_iscan_print_cache(iscan_cur
);
1669 void dhd_iscan_ind_scan_confirm(void *dhdp
, bool status
)
1672 dhd_ind_scan_confirm(dhdp
, status
);
1675 int dhd_iscan_request(void *dhdp
, uint16 action
)
1678 wl_iscan_params_t params
;
1679 dhd_pub_t
*dhd
= dhd_bus_pub(dhdp
);
1680 char buf
[WLC_IOCTL_SMLEN
];
1682 memset(¶ms
, 0, sizeof(wl_iscan_params_t
));
1683 memcpy(¶ms
.params
.bssid
, ðer_bcast
, ETHER_ADDR_LEN
);
1685 params
.params
.bss_type
= DOT11_BSSTYPE_ANY
;
1686 params
.params
.scan_type
= DOT11_SCANTYPE_ACTIVE
;
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);
1694 params
.version
= htod32(ISCAN_REQ_VERSION
);
1695 params
.action
= htod16(action
);
1696 params
.scan_duration
= htod16(0);
1698 bcm_mkiovar("iscan", (char *)¶ms
, sizeof(wl_iscan_params_t
), buf
,
1700 rc
= dhd_wl_ioctl(dhdp
, WLC_SET_VAR
, buf
, WLC_IOCTL_SMLEN
);
1705 static int dhd_iscan_get_partial_result(void *dhdp
, uint
*scan_count
)
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
;
1712 dhd_pub_t
*dhd
= dhd_bus_pub(dhdp
);
1715 iscan_cur
= dhd_iscan_allocate_buf(dhd
, &iscan_chain
);
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
);
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;
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
);
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
);
1747 dhd_iscan_free_buf(dhdp
, iscan_cur
);
1749 dhd_iscan_remove_duplicates(dhdp
, iscan_cur
);
1754 #endif /* SIMPLE_ISCAN */
1757 int dhd_pno_clean(dhd_pub_t
*dhd
)
1760 int pfn_enabled
= 0;
1766 bcm_mkiovar("pfn", (char *)&pfn_enabled
, 4, iovbuf
, sizeof(iovbuf
));
1768 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
,
1769 sizeof(iovbuf
))) >= 0) {
1771 iov_len
= bcm_mkiovar("pfnclear", 0, 0, iovbuf
, sizeof(iovbuf
));
1774 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
,
1776 DHD_ERROR(("%s failed code %d\n", __func__
,
1781 DHD_ERROR(("%s failed code %d\n", __func__
, iov_len
));
1784 DHD_ERROR(("%s failed code %d\n", __func__
, ret
));
1789 int dhd_pno_enable(dhd_pub_t
*dhd
, int pfn_enabled
)
1794 if ((!dhd
) && ((pfn_enabled
!= 0) || (pfn_enabled
!= 1))) {
1795 DHD_ERROR(("%s error exit\n", __func__
));
1799 /* Enable/disable PNO */
1801 bcm_mkiovar("pfn", (char *)&pfn_enabled
, 4, iovbuf
,
1802 sizeof(iovbuf
))) > 0) {
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
));
1809 dhd
->pno_enable
= pfn_enabled
;
1810 DHD_TRACE(("%s set pno as %d\n", __func__
,
1814 DHD_ERROR(("%s failed err=%d\n", __func__
, ret
));
1819 /* Function to execute combined scan */
1821 dhd_pno_set(dhd_pub_t
*dhd
, wlc_ssid_t
*ssids_local
, int nssid
, uchar scan_fr
)
1826 wl_pfn_param_t pfn_param
;
1827 wl_pfn_t pfn_element
;
1829 DHD_TRACE(("%s nssid=%d nchan=%d\n", __func__
, nssid
, scan_fr
));
1831 if ((!dhd
) && (!ssids_local
)) {
1832 DHD_ERROR(("%s error exit\n", __func__
));
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 "
1844 /* #define PNO_DUMP 1 */
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
));
1854 #endif /* PNO_DUMP */
1856 /* clean up everything */
1857 if ((err
= dhd_pno_clean(dhd
)) < 0) {
1858 DHD_ERROR(("%s failed error=%d\n", __func__
, err
));
1861 memset(&pfn_param
, 0, sizeof(pfn_param
));
1862 memset(&pfn_element
, 0, sizeof(pfn_element
));
1864 /* set pfn parameters */
1865 pfn_param
.version
= htod32(PFN_VERSION
);
1866 pfn_param
.flags
= htod16((PFN_LIST_ORDER
<< SORT_CRITERIA_BIT
));
1868 /* set up pno scan fr */
1870 pfn_param
.scan_freq
= htod32(scan_fr
);
1872 bcm_mkiovar("pfn_set", (char *)&pfn_param
, sizeof(pfn_param
), iovbuf
,
1874 dhdcdc_set_ioctl(dhd
, 0, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
));
1876 /* set all pfn ssid */
1877 for (i
= 0; i
< nssid
; i
++) {
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);
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
;
1890 bcm_mkiovar("pfn_add", (char *)&pfn_element
,
1891 sizeof(pfn_element
), iovbuf
,
1892 sizeof(iovbuf
))) > 0) {
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",
1901 DHD_ERROR(("%s failed err=%d\n", __func__
, err
));
1905 /* dhd_pno_enable(dhd, 1); */
1909 int dhd_pno_get_status(dhd_pub_t
*dhd
)
1916 return dhd
->pno_enable
;
1919 #endif /* PNO_SUPPORT */
1921 /* Androd ComboSCAN support */