/drivers/net/wireless/bcmdhd/dhd_common.c
C | 2451 lines | 1878 code | 381 blank | 192 comment | 381 complexity | b6c74bc5217f61cccb221d0bccae9147 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
Large files files are truncated, but you can click here to view the full file
1/*
2 * Broadcom Dongle Host Driver (DHD), common DHD core.
3 *
4 * Copyright (C) 1999-2011, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 * $Id: dhd_common.c 331276 2012-05-04 08:05:57Z $
25 */
26#include <typedefs.h>
27#include <osl.h>
28
29#include <epivers.h>
30#include <bcmutils.h>
31
32#include <bcmendian.h>
33#include <dngl_stats.h>
34#include <wlioctl.h>
35#include <dhd.h>
36
37#include <proto/bcmevent.h>
38
39#include <dhd_bus.h>
40#include <dhd_proto.h>
41#include <dhd_dbg.h>
42#include <msgtrace.h>
43
44#ifdef WL_CFG80211
45#include <wl_cfg80211.h>
46#endif
47#include <proto/bt_amp_hci.h>
48#include <dhd_bta.h>
49#ifdef SET_RANDOM_MAC_SOFTAP
50#include <linux/random.h>
51#include <linux/jiffies.h>
52#endif
53
54#ifdef PROP_TXSTATUS
55#include <wlfc_proto.h>
56#include <dhd_wlfc.h>
57#endif
58
59
60#ifdef WLMEDIA_HTSF
61extern void htsf_update(struct dhd_info *dhd, void *data);
62#endif
63int dhd_msg_level = DHD_ERROR_VAL;
64
65
66#include <wl_iw.h>
67
68char fw_path[MOD_PARAM_PATHLEN];
69char nv_path[MOD_PARAM_PATHLEN];
70
71#ifdef SOFTAP
72char fw_path2[MOD_PARAM_PATHLEN];
73extern bool softap_enabled;
74#endif
75
76/* Last connection success/failure status */
77uint32 dhd_conn_event;
78uint32 dhd_conn_status;
79uint32 dhd_conn_reason;
80
81#define htod32(i) i
82#define htod16(i) i
83#define dtoh32(i) i
84#define dtoh16(i) i
85extern int dhd_iscan_request(void * dhdp, uint16 action);
86extern void dhd_ind_scan_confirm(void *h, bool status);
87extern int dhd_iscan_in_progress(void *h);
88void dhd_iscan_lock(void);
89void dhd_iscan_unlock(void);
90extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
91bool ap_cfg_running = FALSE;
92bool ap_fw_loaded = FALSE;
93
94
95#ifdef DHD_DEBUG
96const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on "
97 __DATE__ " at " __TIME__;
98#else
99const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
100#endif
101
102void dhd_set_timer(void *bus, uint wdtick);
103
104/* IOVar table */
105enum {
106 IOV_VERSION = 1,
107 IOV_MSGLEVEL,
108 IOV_BCMERRORSTR,
109 IOV_BCMERROR,
110 IOV_WDTICK,
111 IOV_DUMP,
112 IOV_CLEARCOUNTS,
113 IOV_LOGDUMP,
114 IOV_LOGCAL,
115 IOV_LOGSTAMP,
116 IOV_GPIOOB,
117 IOV_IOCTLTIMEOUT,
118 IOV_HCI_CMD, /* HCI command */
119 IOV_HCI_ACL_DATA, /* HCI data packet */
120#if defined(DHD_DEBUG)
121 IOV_CONS,
122 IOV_DCONSOLE_POLL,
123#endif /* defined(DHD_DEBUG) */
124#ifdef PROP_TXSTATUS
125 IOV_PROPTXSTATUS_ENABLE,
126 IOV_PROPTXSTATUS_MODE,
127#endif
128 IOV_BUS_TYPE,
129#ifdef WLMEDIA_HTSF
130 IOV_WLPKTDLYSTAT_SZ,
131#endif
132 IOV_CHANGEMTU,
133 IOV_LAST
134};
135
136const bcm_iovar_t dhd_iovars[] = {
137 {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) },
138#ifdef DHD_DEBUG
139 {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 },
140#endif /* DHD_DEBUG */
141 {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN },
142 {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 },
143 {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 },
144 {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN },
145#ifdef DHD_DEBUG
146 {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 },
147 {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 },
148#endif
149 {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 },
150 {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 },
151 {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 },
152 {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0},
153 {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0},
154#ifdef PROP_TXSTATUS
155 {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 },
156 /*
157 set the proptxtstatus operation mode:
158 0 - Do not do any proptxtstatus flow control
159 1 - Use implied credit from a packet status
160 2 - Use explicit credit
161 */
162 {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 },
163#endif
164 {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0},
165#ifdef WLMEDIA_HTSF
166 {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 },
167#endif
168 {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 },
169 {NULL, 0, 0, 0, 0 }
170};
171
172struct dhd_cmn *
173dhd_common_init(osl_t *osh)
174{
175 dhd_cmn_t *cmn;
176
177 /* Init global variables at run-time, not as part of the declaration.
178 * This is required to support init/de-init of the driver. Initialization
179 * of globals as part of the declaration results in non-deterministic
180 * behavior since the value of the globals may be different on the
181 * first time that the driver is initialized vs subsequent initializations.
182 */
183 /* Allocate private bus interface state */
184 if (!(cmn = MALLOC(osh, sizeof(dhd_cmn_t)))) {
185 DHD_ERROR(("%s: MALLOC failed\n", __FUNCTION__));
186 return NULL;
187 }
188 memset(cmn, 0, sizeof(dhd_cmn_t));
189 cmn->osh = osh;
190
191#ifdef CONFIG_BCMDHD_FW_PATH
192 bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1);
193#else /* CONFIG_BCMDHD_FW_PATH */
194 fw_path[0] = '\0';
195#endif /* CONFIG_BCMDHD_FW_PATH */
196#ifdef CONFIG_BCMDHD_NVRAM_PATH
197 bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1);
198#else /* CONFIG_BCMDHD_NVRAM_PATH */
199 nv_path[0] = '\0';
200#endif /* CONFIG_BCMDHD_NVRAM_PATH */
201#ifdef SOFTAP
202 fw_path2[0] = '\0';
203#endif
204 return cmn;
205}
206
207void
208dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn)
209{
210 osl_t *osh;
211 dhd_cmn_t *cmn;
212
213 if (dhd_pub != NULL)
214 cmn = dhd_pub->cmn;
215 else
216 cmn = sa_cmn;
217
218 if (!cmn)
219 return;
220
221 osh = cmn->osh;
222
223 if (dhd_pub != NULL)
224 dhd_pub->cmn = NULL;
225 MFREE(osh, cmn, sizeof(dhd_cmn_t));
226}
227
228static int
229dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
230{
231 char eabuf[ETHER_ADDR_STR_LEN];
232
233 struct bcmstrbuf b;
234 struct bcmstrbuf *strbuf = &b;
235
236 bcm_binit(strbuf, buf, buflen);
237
238 /* Base DHD info */
239 bcm_bprintf(strbuf, "%s\n", dhd_version);
240 bcm_bprintf(strbuf, "\n");
241 bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
242 dhdp->up, dhdp->txoff, dhdp->busstate);
243 bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n",
244 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
245 bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
246 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
247 bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt);
248
249 bcm_bprintf(strbuf, "dongle stats:\n");
250 bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n",
251 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
252 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
253 bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n",
254 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
255 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
256 bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast);
257
258 bcm_bprintf(strbuf, "bus stats:\n");
259 bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n",
260 dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors);
261 bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n",
262 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
263 bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n",
264 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
265 bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n",
266 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
267 bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n",
268 dhdp->rx_readahead_cnt, dhdp->tx_realloc);
269 bcm_bprintf(strbuf, "\n");
270
271 /* Add any prot info */
272 dhd_prot_dump(dhdp, strbuf);
273 bcm_bprintf(strbuf, "\n");
274
275 /* Add any bus info */
276 dhd_bus_dump(dhdp, strbuf);
277
278 return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
279}
280
281int
282dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex)
283{
284 wl_ioctl_t ioc;
285
286 ioc.cmd = cmd;
287 ioc.buf = arg;
288 ioc.len = len;
289 ioc.set = set;
290
291 return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len);
292}
293
294
295int
296dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len)
297{
298 int ret;
299
300 dhd_os_proto_block(dhd_pub);
301
302 ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len);
303 if (ret)
304 dhd_os_check_hang(dhd_pub, ifindex, ret);
305
306 dhd_os_proto_unblock(dhd_pub);
307 return ret;
308}
309
310static int
311dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
312 void *params, int plen, void *arg, int len, int val_size)
313{
314 int bcmerror = 0;
315 int32 int_val = 0;
316
317 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
318 DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
319
320 if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
321 goto exit;
322
323 if (plen >= (int)sizeof(int_val))
324 bcopy(params, &int_val, sizeof(int_val));
325
326 switch (actionid) {
327 case IOV_GVAL(IOV_VERSION):
328 /* Need to have checked buffer length */
329 bcm_strncpy_s((char*)arg, len, dhd_version, len);
330 break;
331
332 case IOV_GVAL(IOV_MSGLEVEL):
333 int_val = (int32)dhd_msg_level;
334 bcopy(&int_val, arg, val_size);
335 break;
336
337 case IOV_SVAL(IOV_MSGLEVEL):
338 dhd_msg_level = int_val;
339#ifdef WL_CFG80211
340 /* Enable DHD and WL logs in oneshot */
341 if (dhd_msg_level & DHD_WL_VAL)
342 wl_cfg80211_enable_trace(dhd_msg_level);
343#endif
344 break;
345 case IOV_GVAL(IOV_BCMERRORSTR):
346 bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
347 ((char *)arg)[BCME_STRLEN - 1] = 0x00;
348 break;
349
350 case IOV_GVAL(IOV_BCMERROR):
351 int_val = (int32)dhd_pub->bcmerror;
352 bcopy(&int_val, arg, val_size);
353 break;
354
355 case IOV_GVAL(IOV_WDTICK):
356 int_val = (int32)dhd_watchdog_ms;
357 bcopy(&int_val, arg, val_size);
358 break;
359
360 case IOV_SVAL(IOV_WDTICK):
361 if (!dhd_pub->up) {
362 bcmerror = BCME_NOTUP;
363 break;
364 }
365 dhd_os_wd_timer(dhd_pub, (uint)int_val);
366 break;
367
368 case IOV_GVAL(IOV_DUMP):
369 bcmerror = dhd_dump(dhd_pub, arg, len);
370 break;
371
372#ifdef DHD_DEBUG
373 case IOV_GVAL(IOV_DCONSOLE_POLL):
374 int_val = (int32)dhd_console_ms;
375 bcopy(&int_val, arg, val_size);
376 break;
377
378 case IOV_SVAL(IOV_DCONSOLE_POLL):
379 dhd_console_ms = (uint)int_val;
380 break;
381
382 case IOV_SVAL(IOV_CONS):
383 if (len > 0)
384 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
385 break;
386#endif /* DHD_DEBUG */
387
388 case IOV_SVAL(IOV_CLEARCOUNTS):
389 dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
390 dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
391 dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
392 dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
393 dhd_pub->rx_dropped = 0;
394 dhd_pub->rx_readahead_cnt = 0;
395 dhd_pub->tx_realloc = 0;
396 dhd_pub->wd_dpc_sched = 0;
397 memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
398 dhd_bus_clearcounts(dhd_pub);
399#ifdef PROP_TXSTATUS
400 /* clear proptxstatus related counters */
401 if (dhd_pub->wlfc_state) {
402 athost_wl_status_info_t *wlfc =
403 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
404 wlfc_hanger_t* hanger;
405
406 memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t));
407
408 hanger = (wlfc_hanger_t*)wlfc->hanger;
409 hanger->pushed = 0;
410 hanger->popped = 0;
411 hanger->failed_slotfind = 0;
412 hanger->failed_to_pop = 0;
413 hanger->failed_to_push = 0;
414 }
415#endif /* PROP_TXSTATUS */
416 break;
417
418
419 case IOV_GVAL(IOV_IOCTLTIMEOUT): {
420 int_val = (int32)dhd_os_get_ioctl_resp_timeout();
421 bcopy(&int_val, arg, sizeof(int_val));
422 break;
423 }
424
425 case IOV_SVAL(IOV_IOCTLTIMEOUT): {
426 if (int_val <= 0)
427 bcmerror = BCME_BADARG;
428 else
429 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
430 break;
431 }
432
433 case IOV_SVAL(IOV_HCI_CMD): {
434 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg;
435
436 /* sanity check: command preamble present */
437 if (len < HCI_CMD_PREAMBLE_SIZE)
438 return BCME_BUFTOOSHORT;
439
440 /* sanity check: command parameters are present */
441 if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen))
442 return BCME_BUFTOOSHORT;
443
444 dhd_bta_docmd(dhd_pub, cmd, len);
445 break;
446 }
447
448 case IOV_SVAL(IOV_HCI_ACL_DATA): {
449 amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg;
450
451 /* sanity check: HCI header present */
452 if (len < HCI_ACL_DATA_PREAMBLE_SIZE)
453 return BCME_BUFTOOSHORT;
454
455 /* sanity check: ACL data is present */
456 if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen))
457 return BCME_BUFTOOSHORT;
458
459 dhd_bta_tx_hcidata(dhd_pub, ACL_data, len);
460 break;
461 }
462
463#ifdef PROP_TXSTATUS
464 case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE):
465 int_val = dhd_pub->wlfc_enabled? 1 : 0;
466 bcopy(&int_val, arg, val_size);
467 break;
468
469 case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE):
470 dhd_pub->wlfc_enabled = int_val? 1 : 0;
471 break;
472
473 case IOV_GVAL(IOV_PROPTXSTATUS_MODE): {
474 athost_wl_status_info_t *wlfc =
475 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
476 int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0;
477 bcopy(&int_val, arg, val_size);
478 break;
479 }
480
481 case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
482 if (dhd_pub->wlfc_state) {
483 athost_wl_status_info_t *wlfc =
484 (athost_wl_status_info_t*)dhd_pub->wlfc_state;
485 wlfc->proptxstatus_mode = int_val & 0xff;
486 }
487 break;
488#endif /* PROP_TXSTATUS */
489
490 case IOV_GVAL(IOV_BUS_TYPE):
491 /* The dhd application queries the driver to check if its usb or sdio. */
492#ifdef BCMDHDUSB
493 int_val = BUS_TYPE_USB;
494#endif
495 int_val = BUS_TYPE_SDIO;
496 bcopy(&int_val, arg, val_size);
497 break;
498
499
500#ifdef WLMEDIA_HTSF
501 case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
502 int_val = dhd_pub->htsfdlystat_sz;
503 bcopy(&int_val, arg, val_size);
504 break;
505
506 case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
507 dhd_pub->htsfdlystat_sz = int_val & 0xff;
508 printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
509 break;
510#endif
511 case IOV_SVAL(IOV_CHANGEMTU):
512 int_val &= 0xffff;
513 bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
514 break;
515
516 default:
517 bcmerror = BCME_UNSUPPORTED;
518 break;
519 }
520
521exit:
522 DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
523 return bcmerror;
524}
525
526/* Store the status of a connection attempt for later retrieval by an iovar */
527void
528dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
529{
530 /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
531 * because an encryption/rsn mismatch results in both events, and
532 * the important information is in the WLC_E_PRUNE.
533 */
534 if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
535 dhd_conn_event == WLC_E_PRUNE)) {
536 dhd_conn_event = event;
537 dhd_conn_status = status;
538 dhd_conn_reason = reason;
539 }
540}
541
542bool
543dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
544{
545 void *p;
546 int eprec = -1; /* precedence to evict from */
547 bool discard_oldest;
548
549 /* Fast case, precedence queue is not full and we are also not
550 * exceeding total queue length
551 */
552 if (!pktq_pfull(q, prec) && !pktq_full(q)) {
553 pktq_penq(q, prec, pkt);
554 return TRUE;
555 }
556
557 /* Determine precedence from which to evict packet, if any */
558 if (pktq_pfull(q, prec))
559 eprec = prec;
560 else if (pktq_full(q)) {
561 p = pktq_peek_tail(q, &eprec);
562 ASSERT(p);
563 if (eprec > prec || eprec < 0)
564 return FALSE;
565 }
566
567 /* Evict if needed */
568 if (eprec >= 0) {
569 /* Detect queueing to unconfigured precedence */
570 ASSERT(!pktq_pempty(q, eprec));
571 discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
572 if (eprec == prec && !discard_oldest)
573 return FALSE; /* refuse newer (incoming) packet */
574 /* Evict packet according to discard policy */
575 p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
576 ASSERT(p);
577
578 PKTFREE(dhdp->osh, p, TRUE);
579 }
580
581 /* Enqueue */
582 p = pktq_penq(q, prec, pkt);
583 ASSERT(p);
584
585 return TRUE;
586}
587
588static int
589dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
590 void *params, int plen, void *arg, int len, bool set)
591{
592 int bcmerror = 0;
593 int val_size;
594 const bcm_iovar_t *vi = NULL;
595 uint32 actionid;
596
597 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
598
599 ASSERT(name);
600 ASSERT(len >= 0);
601
602 /* Get MUST have return space */
603 ASSERT(set || (arg && len));
604
605 /* Set does NOT take qualifiers */
606 ASSERT(!set || (!params && !plen));
607
608 if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
609 bcmerror = BCME_UNSUPPORTED;
610 goto exit;
611 }
612
613 DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
614 name, (set ? "set" : "get"), len, plen));
615
616 /* set up 'params' pointer in case this is a set command so that
617 * the convenience int and bool code can be common to set and get
618 */
619 if (params == NULL) {
620 params = arg;
621 plen = len;
622 }
623
624 if (vi->type == IOVT_VOID)
625 val_size = 0;
626 else if (vi->type == IOVT_BUFFER)
627 val_size = len;
628 else
629 /* all other types are integer sized */
630 val_size = sizeof(int);
631
632 actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
633
634 bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
635
636exit:
637 return bcmerror;
638}
639
640int
641dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen)
642{
643 int bcmerror = 0;
644
645 DHD_TRACE(("%s: Enter\n", __FUNCTION__));
646
647 if (!buf) {
648 return BCME_BADARG;
649 }
650
651 switch (ioc->cmd) {
652 case DHD_GET_MAGIC:
653 if (buflen < sizeof(int))
654 bcmerror = BCME_BUFTOOSHORT;
655 else
656 *(int*)buf = DHD_IOCTL_MAGIC;
657 break;
658
659 case DHD_GET_VERSION:
660 if (buflen < sizeof(int))
661 bcmerror = -BCME_BUFTOOSHORT;
662 else
663 *(int*)buf = DHD_IOCTL_VERSION;
664 break;
665
666 case DHD_GET_VAR:
667 case DHD_SET_VAR: {
668 char *arg;
669 uint arglen;
670
671 /* scan past the name to any arguments */
672 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
673 ;
674
675 if (*arg) {
676 bcmerror = BCME_BUFTOOSHORT;
677 break;
678 }
679
680 /* account for the NUL terminator */
681 arg++, arglen--;
682
683 /* call with the appropriate arguments */
684 if (ioc->cmd == DHD_GET_VAR)
685 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
686 buf, buflen, IOV_GET);
687 else
688 bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
689 if (bcmerror != BCME_UNSUPPORTED)
690 break;
691
692 /* not in generic table, try protocol module */
693 if (ioc->cmd == DHD_GET_VAR)
694 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
695 arglen, buf, buflen, IOV_GET);
696 else
697 bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
698 NULL, 0, arg, arglen, IOV_SET);
699 if (bcmerror != BCME_UNSUPPORTED)
700 break;
701
702 /* if still not found, try bus module */
703 if (ioc->cmd == DHD_GET_VAR) {
704 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
705 arg, arglen, buf, buflen, IOV_GET);
706 } else {
707 bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
708 NULL, 0, arg, arglen, IOV_SET);
709 }
710
711 break;
712 }
713
714 default:
715 bcmerror = BCME_UNSUPPORTED;
716 }
717
718 return bcmerror;
719}
720
721#ifdef SHOW_EVENTS
722static void
723wl_show_host_event(wl_event_msg_t *event, void *event_data)
724{
725 uint i, status, reason;
726 bool group = FALSE, flush_txq = FALSE, link = FALSE;
727 const char *auth_str;
728 const char *event_name;
729 uchar *buf;
730 char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
731 uint event_type, flags, auth_type, datalen;
732
733 event_type = ntoh32(event->event_type);
734 flags = ntoh16(event->flags);
735 status = ntoh32(event->status);
736 reason = ntoh32(event->reason);
737 auth_type = ntoh32(event->auth_type);
738 datalen = ntoh32(event->datalen);
739
740 /* debug dump of event messages */
741 sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x",
742 (uchar)event->addr.octet[0]&0xff,
743 (uchar)event->addr.octet[1]&0xff,
744 (uchar)event->addr.octet[2]&0xff,
745 (uchar)event->addr.octet[3]&0xff,
746 (uchar)event->addr.octet[4]&0xff,
747 (uchar)event->addr.octet[5]&0xff);
748
749 event_name = "UNKNOWN";
750 for (i = 0; i < (uint)bcmevent_names_size; i++)
751 if (bcmevent_names[i].event == event_type)
752 event_name = bcmevent_names[i].name;
753
754 if (flags & WLC_EVENT_MSG_LINK)
755 link = TRUE;
756 if (flags & WLC_EVENT_MSG_GROUP)
757 group = TRUE;
758 if (flags & WLC_EVENT_MSG_FLUSHTXQ)
759 flush_txq = TRUE;
760
761 switch (event_type) {
762 case WLC_E_START:
763 case WLC_E_DEAUTH:
764 case WLC_E_DISASSOC:
765 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
766 break;
767
768 case WLC_E_ASSOC_IND:
769 case WLC_E_REASSOC_IND:
770
771 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
772 break;
773
774 case WLC_E_ASSOC:
775 case WLC_E_REASSOC:
776 if (status == WLC_E_STATUS_SUCCESS) {
777 DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
778 } else if (status == WLC_E_STATUS_TIMEOUT) {
779 DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
780 } else if (status == WLC_E_STATUS_FAIL) {
781 DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
782 event_name, eabuf, (int)reason));
783 } else {
784 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
785 event_name, eabuf, (int)status));
786 }
787 break;
788
789 case WLC_E_DEAUTH_IND:
790 case WLC_E_DISASSOC_IND:
791 DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
792 break;
793
794 case WLC_E_AUTH:
795 case WLC_E_AUTH_IND:
796 if (auth_type == DOT11_OPEN_SYSTEM)
797 auth_str = "Open System";
798 else if (auth_type == DOT11_SHARED_KEY)
799 auth_str = "Shared Key";
800 else {
801 sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
802 auth_str = err_msg;
803 }
804 if (event_type == WLC_E_AUTH_IND) {
805 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
806 } else if (status == WLC_E_STATUS_SUCCESS) {
807 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
808 event_name, eabuf, auth_str));
809 } else if (status == WLC_E_STATUS_TIMEOUT) {
810 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
811 event_name, eabuf, auth_str));
812 } else if (status == WLC_E_STATUS_FAIL) {
813 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
814 event_name, eabuf, auth_str, (int)reason));
815 }
816
817 break;
818
819 case WLC_E_JOIN:
820 case WLC_E_ROAM:
821 case WLC_E_SET_SSID:
822 if (status == WLC_E_STATUS_SUCCESS) {
823 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
824 } else if (status == WLC_E_STATUS_FAIL) {
825 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
826 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
827 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
828 } else {
829 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
830 event_name, (int)status));
831 }
832 break;
833
834 case WLC_E_BEACON_RX:
835 if (status == WLC_E_STATUS_SUCCESS) {
836 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
837 } else if (status == WLC_E_STATUS_FAIL) {
838 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
839 } else {
840 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
841 }
842 break;
843
844 case WLC_E_LINK:
845 DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
846 break;
847
848 case WLC_E_MIC_ERROR:
849 DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
850 event_name, eabuf, group, flush_txq));
851 break;
852
853 case WLC_E_ICV_ERROR:
854 case WLC_E_UNICAST_DECODE_ERROR:
855 case WLC_E_MULTICAST_DECODE_ERROR:
856 DHD_EVENT(("MACEVENT: %s, MAC %s\n",
857 event_name, eabuf));
858 break;
859
860 case WLC_E_TXFAIL:
861 DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf));
862 break;
863
864 case WLC_E_SCAN_COMPLETE:
865 case WLC_E_ASSOC_REQ_IE:
866 case WLC_E_ASSOC_RESP_IE:
867 case WLC_E_PMKID_CACHE:
868 DHD_EVENT(("MACEVENT: %s\n", event_name));
869 break;
870
871 case WLC_E_PFN_NET_FOUND:
872 case WLC_E_PFN_NET_LOST:
873 case WLC_E_PFN_SCAN_COMPLETE:
874 case WLC_E_PFN_SCAN_NONE:
875 case WLC_E_PFN_SCAN_ALLGONE:
876 DHD_EVENT(("PNOEVENT: %s\n", event_name));
877 break;
878
879 case WLC_E_PSK_SUP:
880 case WLC_E_PRUNE:
881 DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
882 event_name, (int)status, (int)reason));
883 break;
884
885#ifdef WIFI_ACT_FRAME
886 case WLC_E_ACTION_FRAME:
887 DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
888 break;
889#endif /* WIFI_ACT_FRAME */
890
891 case WLC_E_TRACE: {
892 static uint32 seqnum_prev = 0;
893 msgtrace_hdr_t hdr;
894 uint32 nblost;
895 char *s, *p;
896
897 buf = (uchar *) event_data;
898 memcpy(&hdr, buf, MSGTRACE_HDRLEN);
899
900 if (hdr.version != MSGTRACE_VERSION) {
901 printf("\nMACEVENT: %s [unsupported version --> "
902 "dhd version:%d dongle version:%d]\n",
903 event_name, MSGTRACE_VERSION, hdr.version);
904 /* Reset datalen to avoid display below */
905 datalen = 0;
906 break;
907 }
908
909 /* There are 2 bytes available at the end of data */
910 buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0';
911
912 if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) {
913 printf("\nWLC_E_TRACE: [Discarded traces in dongle -->"
914 "discarded_bytes %d discarded_printf %d]\n",
915 ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf));
916 }
917
918 nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1;
919 if (nblost > 0) {
920 printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n",
921 ntoh32(hdr.seqnum), nblost);
922 }
923 seqnum_prev = ntoh32(hdr.seqnum);
924
925 /* Display the trace buffer. Advance from \n to \n to avoid display big
926 * printf (issue with Linux printk )
927 */
928 p = (char *)&buf[MSGTRACE_HDRLEN];
929 while ((s = strstr(p, "\n")) != NULL) {
930 *s = '\0';
931 printf("%s\n", p);
932 p = s+1;
933 }
934 printf("%s\n", p);
935
936 /* Reset datalen to avoid display below */
937 datalen = 0;
938 break;
939 }
940
941
942 case WLC_E_RSSI:
943 DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
944 break;
945
946 default:
947 DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
948 event_name, event_type, eabuf, (int)status, (int)reason,
949 (int)auth_type));
950 break;
951 }
952
953 /* show any appended data */
954 if (datalen) {
955 buf = (uchar *) event_data;
956 DHD_EVENT((" data (%d) : ", datalen));
957 for (i = 0; i < datalen; i++)
958 DHD_EVENT((" 0x%02x ", *buf++));
959 DHD_EVENT(("\n"));
960 }
961}
962#endif /* SHOW_EVENTS */
963
964int
965wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
966 wl_event_msg_t *event, void **data_ptr)
967{
968 /* check whether packet is a BRCM event pkt */
969 bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
970 uint8 *event_data;
971 uint32 type, status, reason, datalen;
972 uint16 flags;
973 int evlen;
974
975 if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) {
976 DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__));
977 return (BCME_ERROR);
978 }
979
980 /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
981 if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) {
982 DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__));
983 return (BCME_ERROR);
984 }
985
986 *data_ptr = &pvt_data[1];
987 event_data = *data_ptr;
988
989 /* memcpy since BRCM event pkt may be unaligned. */
990 memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t));
991
992 type = ntoh32_ua((void *)&event->event_type);
993 flags = ntoh16_ua((void *)&event->flags);
994 status = ntoh32_ua((void *)&event->status);
995 reason = ntoh32_ua((void *)&event->reason);
996 datalen = ntoh32_ua((void *)&event->datalen);
997 evlen = datalen + sizeof(bcm_event_t);
998
999 DHD_TRACE(("RX: event_type:%d flags:%d status:%d reason:%d \n",
1000 type, flags, status, reason));
1001
1002 switch (type) {
1003#ifdef PROP_TXSTATUS
1004 case WLC_E_FIFO_CREDIT_MAP:
1005 dhd_wlfc_event(dhd_pub->info);
1006 dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data);
1007 WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
1008 "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
1009 event_data[2],
1010 event_data[3], event_data[4], event_data[5]));
1011 break;
1012#endif
1013
1014 case WLC_E_IF:
1015 {
1016 dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data;
1017#ifdef PROP_TXSTATUS
1018 {
1019 uint8* ea = pvt_data->eth.ether_dhost;
1020 WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
1021 "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
1022 ifevent->ifidx,
1023 ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"),
1024 ((ifevent->is_AP == 0) ? "STA":"AP "),
1025 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
1026 (void)ea;
1027
1028 dhd_wlfc_interface_event(dhd_pub->info,
1029 ((ifevent->action == WLC_E_IF_ADD) ?
1030 eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
1031 ifevent->ifidx, ifevent->is_AP, ea);
1032
1033 /* dhd already has created an interface by default, for 0 */
1034 if (ifevent->ifidx == 0)
1035 break;
1036 }
1037#endif /* PROP_TXSTATUS */
1038
1039#ifdef WL_CFG80211
1040 if (wl_cfg80211_is_progress_ifchange()) {
1041 DHD_ERROR(("%s: ifidx %d for %s action %d\n",
1042 __FUNCTION__, ifevent->ifidx,
1043 event->ifname, ifevent->action));
1044 if (ifevent->action == WLC_E_IF_ADD)
1045 wl_cfg80211_notify_ifchange();
1046 return (BCME_OK);
1047 }
1048#endif /* WL_CFG80211 */
1049 if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
1050 if (ifevent->action == WLC_E_IF_ADD) {
1051 if (dhd_add_if(dhd_pub->info, ifevent->ifidx,
1052 NULL, event->ifname,
1053 event->addr.octet,
1054 ifevent->flags, ifevent->bssidx)) {
1055 DHD_ERROR(("%s: dhd_add_if failed!!"
1056 " ifidx: %d for %s\n",
1057 __FUNCTION__,
1058 ifevent->ifidx,
1059 event->ifname));
1060 return (BCME_ERROR);
1061 }
1062 }
1063 else
1064 dhd_del_if(dhd_pub->info, ifevent->ifidx);
1065 } else {
1066#ifndef PROP_TXSTATUS
1067 DHD_ERROR(("%s: Invalid ifidx %d for %s\n",
1068 __FUNCTION__, ifevent->ifidx, event->ifname));
1069#endif /* !PROP_TXSTATUS */
1070 }
1071 }
1072 /* send up the if event: btamp user needs it */
1073 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1074 /* push up to external supp/auth */
1075 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1076 break;
1077
1078
1079#ifdef WLMEDIA_HTSF
1080 case WLC_E_HTSFSYNC:
1081 htsf_update(dhd_pub->info, event_data);
1082 break;
1083#endif /* WLMEDIA_HTSF */
1084 case WLC_E_NDIS_LINK: {
1085 uint32 temp = hton32(WLC_E_LINK);
1086
1087 memcpy((void *)(&pvt_data->event.event_type), &temp,
1088 sizeof(pvt_data->event.event_type));
1089 }
1090 /* These are what external supplicant/authenticator wants */
1091 /* fall through */
1092 case WLC_E_LINK:
1093 case WLC_E_DEAUTH:
1094 case WLC_E_DEAUTH_IND:
1095 case WLC_E_DISASSOC:
1096 case WLC_E_DISASSOC_IND:
1097 DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
1098 __FUNCTION__, type, flags, status));
1099 /* fall through */
1100 default:
1101 *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
1102 /* push up to external supp/auth */
1103 dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
1104 DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
1105 __FUNCTION__, type, flags, status));
1106
1107 /* put it back to WLC_E_NDIS_LINK */
1108 if (type == WLC_E_NDIS_LINK) {
1109 uint32 temp;
1110
1111 temp = ntoh32_ua((void *)&event->event_type);
1112 DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp));
1113
1114 temp = ntoh32(WLC_E_NDIS_LINK);
1115 memcpy((void *)(&pvt_data->event.event_type), &temp,
1116 sizeof(pvt_data->event.event_type));
1117 }
1118 break;
1119 }
1120
1121#ifdef SHOW_EVENTS
1122 wl_show_host_event(event, (void *)event_data);
1123#endif /* SHOW_EVENTS */
1124
1125 return (BCME_OK);
1126}
1127
1128void
1129wl_event_to_host_order(wl_event_msg_t * evt)
1130{
1131 /* Event struct members passed from dongle to host are stored in network
1132 * byte order. Convert all members to host-order.
1133 */
1134 evt->event_type = ntoh32(evt->event_type);
1135 evt->flags = ntoh16(evt->flags);
1136 evt->status = ntoh32(evt->status);
1137 evt->reason = ntoh32(evt->reason);
1138 evt->auth_type = ntoh32(evt->auth_type);
1139 evt->datalen = ntoh32(evt->datalen);
1140 evt->version = ntoh16(evt->version);
1141}
1142
1143void
1144dhd_print_buf(void *pbuf, int len, int bytes_per_line)
1145{
1146#ifdef DHD_DEBUG
1147 int i, j = 0;
1148 unsigned char *buf = pbuf;
1149
1150 if (bytes_per_line == 0) {
1151 bytes_per_line = len;
1152 }
1153
1154 for (i = 0; i < len; i++) {
1155 printf("%2.2x", *buf++);
1156 j++;
1157 if (j == bytes_per_line) {
1158 printf("\n");
1159 j = 0;
1160 } else {
1161 printf(":");
1162 }
1163 }
1164 printf("\n");
1165#endif /* DHD_DEBUG */
1166}
1167
1168#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
1169
1170/* Convert user's input in hex pattern to byte-size mask */
1171static int
1172wl_pattern_atoh(char *src, char *dst)
1173{
1174 int i;
1175 if (strncmp(src, "0x", 2) != 0 &&
1176 strncmp(src, "0X", 2) != 0) {
1177 DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
1178 return -1;
1179 }
1180 src = src + 2; /* Skip past 0x */
1181 if (strlen(src) % 2 != 0) {
1182 DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
1183 return -1;
1184 }
1185 for (i = 0; *src != '\0'; i++) {
1186 char num[3];
1187 bcm_strncpy_s(num, sizeof(num), src, 2);
1188 num[2] = '\0';
1189 dst[i] = (uint8)strtoul(num, NULL, 16);
1190 src += 2;
1191 }
1192 return i;
1193}
1194
1195void
1196dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
1197{
1198 char *argv[8];
1199 int i = 0;
1200 const char *str;
1201 int buf_len;
1202 int str_len;
1203 char *arg_save = 0, *arg_org = 0;
1204 int rc;
1205 char buf[128];
1206 wl_pkt_filter_enable_t enable_parm;
1207 wl_pkt_filter_enable_t * pkt_filterp;
1208
1209 if (!arg)
1210 return;
1211
1212 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1213 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1214 goto fail;
1215 }
1216 arg_org = arg_save;
1217 memcpy(arg_save, arg, strlen(arg) + 1);
1218
1219 argv[i] = bcmstrtok(&arg_save, " ", 0);
1220
1221 i = 0;
1222 if (argv[i] == NULL) {
1223 DHD_ERROR(("No args provided\n"));
1224 goto fail;
1225 }
1226
1227 str = "pkt_filter_enable";
1228 str_len = strlen(str);
1229 bcm_strncpy_s(buf, sizeof(buf), str, str_len);
1230 buf[str_len] = '\0';
1231 buf_len = str_len + 1;
1232
1233 pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
1234
1235 /* Parse packet filter id. */
1236 enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
1237
1238 /* Parse enable/disable value. */
1239 enable_parm.enable = htod32(enable);
1240
1241 buf_len += sizeof(enable_parm);
1242 memcpy((char *)pkt_filterp,
1243 &enable_parm,
1244 sizeof(enable_parm));
1245
1246 /* Enable/disable the specified filter. */
1247 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1248 rc = rc >= 0 ? 0 : rc;
1249 if (rc)
1250 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1251 __FUNCTION__, arg, rc));
1252 else
1253 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1254 __FUNCTION__, arg));
1255
1256 /* Contorl the master mode */
1257 bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf));
1258 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0);
1259 rc = rc >= 0 ? 0 : rc;
1260 if (rc)
1261 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1262 __FUNCTION__, arg, rc));
1263
1264fail:
1265 if (arg_org)
1266 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1267}
1268
1269void
1270dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
1271{
1272 const char *str;
1273 wl_pkt_filter_t pkt_filter;
1274 wl_pkt_filter_t *pkt_filterp;
1275 int buf_len;
1276 int str_len;
1277 int rc;
1278 uint32 mask_size;
1279 uint32 pattern_size;
1280 char *argv[8], * buf = 0;
1281 int i = 0;
1282 char *arg_save = 0, *arg_org = 0;
1283#define BUF_SIZE 2048
1284
1285 if (!arg)
1286 return;
1287
1288 if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
1289 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1290 goto fail;
1291 }
1292
1293 arg_org = arg_save;
1294
1295 if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
1296 DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__));
1297 goto fail;
1298 }
1299
1300 memcpy(arg_save, arg, strlen(arg) + 1);
1301
1302 if (strlen(arg) > BUF_SIZE) {
1303 DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
1304 goto fail;
1305 }
1306
1307 argv[i] = bcmstrtok(&arg_save, " ", 0);
1308 while (argv[i++])
1309 argv[i] = bcmstrtok(&arg_save, " ", 0);
1310
1311 i = 0;
1312 if (argv[i] == NULL) {
1313 DHD_ERROR(("No args provided\n"));
1314 goto fail;
1315 }
1316
1317 str = "pkt_filter_add";
1318 str_len = strlen(str);
1319 bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
1320 buf[ str_len ] = '\0';
1321 buf_len = str_len + 1;
1322
1323 pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
1324
1325 /* Parse packet filter id. */
1326 pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
1327
1328 if (argv[++i] == NULL) {
1329 DHD_ERROR(("Polarity not provided\n"));
1330 goto fail;
1331 }
1332
1333 /* Parse filter polarity. */
1334 pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
1335
1336 if (argv[++i] == NULL) {
1337 DHD_ERROR(("Filter type not provided\n"));
1338 goto fail;
1339 }
1340
1341 /* Parse filter type. */
1342 pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
1343
1344 if (argv[++i] == NULL) {
1345 DHD_ERROR(("Offset not provided\n"));
1346 goto fail;
1347 }
1348
1349 /* Parse pattern filter offset. */
1350 pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
1351
1352 if (argv[++i] == NULL) {
1353 DHD_ERROR(("Bitmask not provided\n"));
1354 goto fail;
1355 }
1356
1357 /* Parse pattern filter mask. */
1358 mask_size =
1359 htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern));
1360
1361 if (argv[++i] == NULL) {
1362 DHD_ERROR(("Pattern not provided\n"));
1363 goto fail;
1364 }
1365
1366 /* Parse pattern filter pattern. */
1367 pattern_size =
1368 htod32(wl_pattern_atoh(argv[i],
1369 (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
1370
1371 if (mask_size != pattern_size) {
1372 DHD_ERROR(("Mask and pattern not the same size\n"));
1373 goto fail;
1374 }
1375
1376 pkt_filter.u.pattern.size_bytes = mask_size;
1377 buf_len += WL_PKT_FILTER_FIXED_LEN;
1378 buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
1379
1380 /* Keep-alive attributes are set in local variable (keep_alive_pkt), and
1381 ** then memcpy'ed into buffer (keep_alive_pktp) since there is no
1382 ** guarantee that the buffer is properly aligned.
1383 */
1384 memcpy((char *)pkt_filterp,
1385 &pkt_filter,
1386 WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
1387
1388 rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
1389 rc = rc >= 0 ? 0 : rc;
1390
1391 if (rc)
1392 DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
1393 __FUNCTION__, arg, rc));
1394 else
1395 DHD_TRACE(("%s: successfully added pktfilter %s\n",
1396 __FUNCTION__, arg));
1397
1398fail:
1399 if (arg_org)
1400 MFREE(dhd->osh, arg_org, strlen(arg) + 1);
1401
1402 if (buf)
1403 MFREE(dhd->osh, buf, BUF_SIZE);
1404}
1405
1406/* ========================== */
1407/* ==== ARP OFFLOAD SUPPORT = */
1408/* ========================== */
1409#ifdef ARP_OFFLOAD_SUPPORT
1410void
1411dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
1412{
1413 char iovbuf[32];
1414 int retcode;
1415
1416 bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf));
1417 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1418 retcode = retcode >= 0 ? 0 : retcode;
1419 if (retcode)
1420 DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
1421 __FUNCTION__, arp_mode, retcode));
1422 else
1423 DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n",
1424 __FUNCTION__, arp_mode));
1425}
1426
1427void
1428dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
1429{
1430 char iovbuf[32];
1431 int retcode;
1432
1433 bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf));
1434 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
1435 retcode = retcode >= 0 ? 0 : retcode;
1436 if (retcode)
1437 DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
1438 __FUNCTION__, arp_enable, retcode));
1439 else
1440 DHD_TRACE(("%s: successfully enabed ARP offload to %d\n",
1441 __FUNCTION__, arp_enable));
1442}
1443
1444void
1445dhd_aoe_arp_clr(dhd_pub_t *dhd)
1446{
1447 int ret = 0;
1448 int iov_len = 0;
1449 char iovbuf[128];
1450
1451 if (dhd == NULL) return;
1452
1453 iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf));
1454 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0))
1455 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1456}
1457
1458void
1459dhd_aoe_hostip_clr(dhd_pub_t *dhd)
1460{
1461 int ret = 0;
1462 int iov_len = 0;
1463 char iovbuf[128];
1464
1465 if (dhd == NULL) return;
1466
1467 iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf));
1468 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0)
1469 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1470}
1471
1472void
1473dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr)
1474{
1475 int iov_len = 0;
1476 char iovbuf[32];
1477 int retcode;
1478
1479 iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf));
1480 retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
1481
1482 if (retcode)
1483 DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n",
1484 __FUNCTION__, retcode));
1485 else
1486 DHD_TRACE(("%s: sARP H ipaddr entry added \n",
1487 __FUNCTION__));
1488}
1489
1490int
1491dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen)
1492{
1493 int retcode, i;
1494 int iov_len = 0;
1495 uint32 *ptr32 = buf;
1496 bool clr_bottom = FALSE;
1497
1498 if (!buf)
1499 return -1;
1500
1501 iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen);
1502 retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0);
1503
1504 if (retcode) {
1505 DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n",
1506 __FUNCTION__, retcode));
1507
1508 return -1;
1509 }
1510
1511 /* clean up the buf, ascii reminder */
1512 for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
1513 if (!clr_bottom) {
1514 if (*ptr32 == 0)
1515 clr_bottom = TRUE;
1516 } else {
1517 *ptr32 = 0;
1518 }
1519 ptr32++;
1520 }
1521
1522 return 0;
1523}
1524#endif /* ARP_OFFLOAD_SUPPORT */
1525
1526/* send up locally generated event */
1527void
1528dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data)
1529{
1530 switch (ntoh32(event->event_type)) {
1531 case WLC_E_BTA_HCI_EVENT:
1532 break;
1533 default:
1534 break;
1535 }
1536
1537 /* Call per-port handler. */
1538 dhd_sendup_event(dhdp, event, data);
1539}
1540
1541#ifdef SIMPLE_ISCAN
1542
1543uint iscan_thread_id = 0;
1544iscan_buf_t * iscan_chain = 0;
1545
1546iscan_buf_t *
1547dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
1548{
1549 iscan_buf_t *iscanbuf_alloc = 0;
1550 iscan_buf_t *iscanbuf_head;
1551
1552 DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1553 dhd_iscan_lock();
1554
1555 iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t));
1556 if (iscanbuf_alloc == NULL)
1557 goto fail;
1558
1559 iscanbuf_alloc->next = NULL;
1560 iscanbuf_head = *iscanbuf;
1561
1562 DHD_ISCAN(("%s: addr of allocated node = 0x%X"
1563 "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
1564 __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
1565
1566 if (iscanbuf_head == NULL) {
1567 *iscanbuf = iscanbuf_alloc;
1568 DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
1569 goto fail;
1570 }
1571
1572 while (iscanbuf_head->next)
1573 iscanbuf_head = iscanbuf_head->next;
1574
1575 iscanbuf_head->next = iscanbuf_alloc;
1576
1577fail:
1578 dhd_iscan_unlock();
1579 return iscanbuf_alloc;
1580}
1581
1582void
1583dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
1584{
1585 iscan_buf_t *iscanbuf_free = 0;
1586 iscan_buf_t *iscanbuf_prv = 0;
1587 iscan_buf_t *iscanbuf_cur;
1588 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1589 DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
1590
1591 dhd_iscan_lock();
1592
1593 iscanbuf_cur = iscan_chain;
1594
1595 /* If iscan_delete is null then delete the entire
1596 * chain or else delete specific one provided
1597 */
1598 if (!iscan_delete) {
1599 while (iscanbuf_cur) {
1600 iscanbuf_free = iscanbuf_cur;
1601 iscanbuf_cur = iscanbuf_cur->next;
1602 iscanbuf_free->next = 0;
1603 MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
1604 }
1605 iscan_chain = 0;
1606 } else {
1607 while (iscanbuf_cur) {
1608 if (iscanbuf_cur == iscan_delete)
1609 break;
1610 iscanbuf_prv = iscanbuf_cur;
1611 iscanbuf_cur = iscanbuf_cur->next;
1612 }
1613 if (iscanbuf_prv)
1614 iscanbuf_prv->next = iscan_delete->next;
1615
1616 iscan_delete->next = 0;
1617 MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
1618
1619 if (!iscanbuf_prv)
1620 iscan_chain = 0;
1621 }
1622 dhd_iscan_unlock();
1623}
1624
1625iscan_buf_t *
1626dhd_iscan_result_buf(void)
1627{
1628 return iscan_chain;
1629}
1630
1631int
1632dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size)
1633{
1634 int rc = -1;
1635 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1636 char *buf;
1637 char iovar[] = "iscan";
1638 uint32 allocSize = 0;
1639 wl_ioctl_t ioctl;
1640
1641 if (pParams) {
1642 allocSize = (size + strlen(iovar) + 1);
1643 if ((allocSize < size) || (allocSize < strlen(iovar)))
1644 {
1645 DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n",
1646 __FUNCTION__, allocSize, size, strlen(iovar)));
1647 goto cleanUp;
1648 }
1649 buf = MALLOC(dhd->osh, allocSize);
1650
1651 if (buf == NULL)
1652 {
1653 DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize));
1654 goto cleanUp;
1655 }
1656 ioctl.cmd = WLC_SET_VAR;
1657 bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize);
1658 rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize);
1659 }
1660
1661cleanUp:
1662 if (buf) {
1663 MFREE(dhd->osh, buf, allocSize);
1664 }
1665
1666 return rc;
1667}
1668
1669static int
1670dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
1671{
1672 wl_iscan_results_t *list_buf;
1673 wl_iscan_results_t list;
1674 wl_scan_results_t *results;
1675 iscan_buf_t *iscan_cur;
1676 int status = -1;
1677 dhd_pub_t *dhd = dhd_bus_pub(dhdp);
1678 int rc;
1679 wl_ioctl_t ioctl;
1680
1681 DHD_ISCAN(("%s: Enter\n", __FUNCTION__));
1682
1683 iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
1684 if (!iscan_cur) {
1685 DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
1686 dhd_iscan_free_buf(dhdp, 0);
1687 dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
1688 dhd_ind_scan_confirm(dhdp, FALSE);
1689 goto fail;
1690 }
1691
1692 dhd_iscan_lock();
1693
1694 memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
1695 list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf;
1696 results = &list_buf->results;
1697 results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
1698 results->version = 0;
1699 results->count = 0;
1700
1701 memset(&list, 0, sizeof(list));
1702 list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
1703 bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
1704 iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1705 ioctl.cmd = WLC_GET_VAR;
1706 ioctl.set = FALSE;
1707 rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
1708
1709 results->buflen = dtoh32(results->buflen);
1710 results->version = dtoh32(results->version);
1711 *scan_count = results->count = dtoh32(results->count);
1712 status = dtoh32(list_buf->status);
1713 DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status));
1714
1715 dhd_iscan_unlock();
1716
1717 if (!(*scan_count)) {
1718 /* TODO: race condition when FLUSH already called */
1719 dhd_iscan_free_buf(dhdp, 0);
1720 }
1721fail:
1722 return status;
1723}
1724
1725#endif /* SIMPLE_ISCAN */
1726
1727/*
1728 * returns = TRUE if associated, FALSE if not associated
1729 * third paramter retval can return error from error
1730 */
1731bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval)
1732{
1733 char bssid[6], zbuf[6];
1734 int ret;
1735
1736 bzero(bssid, 6);
1737 bzero(zbuf, 6);
1738
1739 ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0);
1740 DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
1741
1742 if (retval)
1743 *retval = ret;
1744
1745 if (ret == BCME_NOTASSOCIATED) {
1746 DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
1747 }
1748
1749 if (ret < 0)
1750 return FALSE;
1751
1752 if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) {
1753 /* STA is assocoated BSSID is non zero */
1754
1755 if (bss_buf) {
1756 /* return bss if caller provided buf */
1757 memcpy(bss_buf, bssid, ETHER_ADDR_LEN);
1758 }
1759 return TRUE;
1760 } else {
1761 DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
1762 return FALSE;
1763 }
1764}
1765
1766/* Function to estimate possible DTIM_SKIP value */
1767int
1768dhd_get_dtim_skip(dhd_pub_t *dhd)
1769{
1770 int bcn_li_dtim;
1771 int ret = -1;
1772 int dtim_assoc = 0;
1773
1774 if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1))
1775 bcn_li_dtim = 3;
1776 else
1777 bcn_li_dtim = dhd->dtim_skip;
1778
1779 /* Check if associated */
1780 if (dhd_is_associated(dhd, NULL, NULL) == FALSE) {
1781 DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
1782 goto exit;
1783 }
1784
1785 /* if assoc grab ap's dtim value */
1786 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
1787 &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) {
1788 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1789 goto exit;
1790 }
1791
1792 DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n",
1793 __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL));
1794
1795 /* if not assocated just eixt */
1796 if (dtim_assoc == 0) {
1797 goto exit;
1798 }
1799
1800 /* check if sta listen interval fits into AP dtim */
1801 if (dtim_assoc > LISTEN_INTERVAL) {
1802 /* AP DTIM to big for our Listen Interval : no dtim skiping */
1803 bcn_li_dtim = 1;
1804 DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
1805 __FUNCTION__, dtim_assoc, LISTEN_INTERVAL));
1806 goto exit;
1807 }
1808
1809 if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) {
1810 /* Round up dtim_skip to fit into STAs Listen Interval */
1811 bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc);
1812 DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
1813 }
1814
1815exit:
1816 return bcn_li_dtim;
1817}
1818
1819/* Check if HostAPD or WFD mode setup */
1820bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd)
1821{
1822#ifdef WL_CFG80211
1823#ifndef WL_ENABLE_P2P_IF
1824 /* To be back compatble with ICS MR1 release where p2p interface
1825 * disable but wlan0 used for p2p
1826 */
1827 if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) ||
1828 ((dhd->op_mode & WFD_MASK) == WFD_MASK)) {
1829 return TRUE;
1830 }
1831 else
1832#else
1833 /* concurent mode with p2p interface for wfd and wlan0 for sta */
1834 if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) ||
1835 ((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) {
1836 DHD_ERROR(("%s P2P enabled for mode=%d\n", __FUNCTION__, dhd->op_mode));
1837 return TRUE;
1838 }
1839 else
1840#endif /* WL_ENABLE_P2P_IF */
1841#endif /* WL_CFG80211 */
1842 return FALSE;
1843}
1844
1845#ifdef PNO_SUPPORT
1846int
1847dhd_pno_clean(dhd_pub_t *dhd)
1848{
1849 char iovbuf[128];
1850 int pfn_enabled = 0;
1851 int iov_len = 0;
1852 int ret;
1853
1854 /* Disable pfn */
1855 iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf));
1856 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) {
1857 /* clear pfn */
1858 iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf));
1859 if (iov_len) {
1860 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf,
1861 iov_len, TRUE, 0)) < 0) {
1862 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1863 }
1864 }
1865 else {
1866 ret = -1;
1867 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len));
1868 }
1869 }
1870 else
1871 DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
1872
1873 return ret;
1874}
1875
1876int
1877dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled)
1878{
1879 char iovbuf[128];
1880 int ret = -1;
1881
1882 if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) {
1883 DHD_ERROR(("%s error exit\n", __FUNCTION__));
1884 return ret;
1885 }
1886
1887
1888 memset(iovbuf, 0, sizeof(iovbuf));
1889
1890#ifndef WL_SCHED_SCAN
1891 if (dhd_check_ap_wfd_mode_set(dhd) == TRUE)
1892 return (ret);
1893
1894 if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) {
1895 DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__));
1896 return ret;
1897 }
1898#endif /* !WL_SCHED_SCAN */
1899
1900 /* Enable/disable PNO */
1901 if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) {
1902 if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR,
1903 iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) {
1904 DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret));
1905 return ret;
1906 }
1907 else {
1908 dhd->pno_enable = pfn_enabled;
1909 DHD_TRACE(("%s set pno as %s\n",
1910 __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable"));
1911 }
1912 }
1913 else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret));
1914
1915 return ret;
1916}
1917
1918/* Function to execute combined scan */
1919int
1920dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr,
1921 int pno_repeat, int pno_freq_expo_max)
1922{
1923 int err = -1;
1924 char iovbuf[128];
1925 int k, i;
1926 wl_pfn_param_t pfn_param;
1927 wl_pfn_t pfn_element;
1928 uint len = 0;
1929
1930 DH…
Large files files are truncated, but you can click here to view the full file