• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Broadcom Dongle Host Driver (DHD), common DHD core.
3  *
4  * Copyright (C) 1999-2017, 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  *
25  * <<Broadcom-WL-IPTag/Open:>>
26  *
27  * $Id: dhd_common.c 710862 2017-07-14 07:43:59Z $
28  */
29 #include <typedefs.h>
30 #include <osl.h>
31 
32 #include <epivers.h>
33 #include <bcmutils.h>
34 
35 #include <bcmendian.h>
36 #include <dngl_stats.h>
37 #include <wlioctl.h>
38 #include <dhd.h>
39 #include <dhd_ip.h>
40 #include <bcmevent.h>
41 
42 #ifdef PCIE_FULL_DONGLE
43 #include <bcmmsgbuf.h>
44 #endif /* PCIE_FULL_DONGLE */
45 
46 #ifdef SHOW_LOGTRACE
47 #include <event_log.h>
48 #endif /* SHOW_LOGTRACE */
49 
50 #ifdef BCMPCIE
51 #include <dhd_flowring.h>
52 #endif
53 
54 #include <dhd_bus.h>
55 #include <dhd_proto.h>
56 #include <dhd_config.h>
57 #include <bcmsdbus.h>
58 #include <dhd_dbg.h>
59 #include <dhd_debug.h>
60 #include <dhd_mschdbg.h>
61 #include <msgtrace.h>
62 
63 #ifdef WL_CFG80211
64 #include <wl_cfg80211.h>
65 #endif
66 #ifdef PNO_SUPPORT
67 #include <dhd_pno.h>
68 #endif
69 #ifdef RTT_SUPPORT
70 #include <dhd_rtt.h>
71 #endif
72 
73 #ifdef DNGL_EVENT_SUPPORT
74 #include <dnglevent.h>
75 #endif
76 
77 #define htod32(i) (i)
78 #define htod16(i) (i)
79 #define dtoh32(i) (i)
80 #define dtoh16(i) (i)
81 #define htodchanspec(i) (i)
82 #define dtohchanspec(i) (i)
83 
84 #ifdef PROP_TXSTATUS
85 #include <wlfc_proto.h>
86 #include <dhd_wlfc.h>
87 #endif
88 
89 #ifdef DHD_WMF
90 #include <dhd_linux.h>
91 #include <dhd_wmf_linux.h>
92 #endif /* DHD_WMF */
93 
94 #ifdef DHD_L2_FILTER
95 #include <dhd_l2_filter.h>
96 #endif /* DHD_L2_FILTER */
97 
98 #ifdef DHD_PSTA
99 #include <dhd_psta.h>
100 #endif /* DHD_PSTA */
101 #ifdef DHD_TIMESYNC
102 #include <dhd_timesync.h>
103 #endif /* DHD_TIMESYNC */
104 
105 #ifdef DHD_WET
106 #include <dhd_wet.h>
107 #endif /* DHD_WET */
108 
109 #if defined(BCMEMBEDIMAGE) && defined(DHD_EFI)
110 #include <nvram_4364.h>
111 #endif
112 
113 #ifdef WLMEDIA_HTSF
114 extern void htsf_update(struct dhd_info *dhd, void *data);
115 #endif
116 
117 extern int is_wlc_event_frame(void *pktdata, uint pktlen, uint16 exp_usr_subtype,
118     bcm_event_msg_u_t *out_event);
119 
120 /* By default all logs are enabled */
121 int dhd_msg_level = DHD_ERROR_VAL | DHD_MSGTRACE_VAL | DHD_FWLOG_VAL;
122 
123 
124 #if defined(WL_WLC_SHIM)
125 #include <wl_shim.h>
126 #else
127 #endif /* WL_WLC_SHIM */
128 
129 #ifdef DHD_ULP
130 #include <dhd_ulp.h>
131 #endif /* DHD_ULP */
132 
133 #ifdef DHD_DEBUG
134 #include <sdiovar.h>
135 #endif /* DHD_DEBUG */
136 
137 #ifdef SOFTAP
138 char fw_path2[MOD_PARAM_PATHLEN];
139 extern bool softap_enabled;
140 #endif
141 
142 #ifdef REPORT_FATAL_TIMEOUTS
143 /* Default timeout value in ms */
144 #define SCAN_TIMEOUT_DEFAULT    1
145 #define JOIN_TIMEOUT_DEFAULT    7500
146 #ifdef DHD_EFI
147 #define BUS_TIMEOUT_DEFAULT     8000000  /* 800ms, in units of 100ns */
148 #define CMD_TIMEOUT_DEFAULT     15000000 /* 1.5sec, in units of 100ns */
149 #else
150 #define BUS_TIMEOUT_DEFAULT     800
151 #define CMD_TIMEOUT_DEFAULT     1200
152 #endif /* DHD_EFI */
153 #endif /* REPORT_FATAL_TIMEOUTS */
154 
155 #ifdef SHOW_LOGTRACE
156 #define BYTES_AHEAD_NUM        11    /* address in map file is before these many bytes */
157 #define READ_NUM_BYTES        1000 /* read map file each time this No. of bytes */
158 #define GO_BACK_FILE_POS_NUM_BYTES    100 /* set file pos back to cur pos */
159 static char *ramstart_str = "text_start"; /* string in mapfile has addr ramstart */
160 static char *rodata_start_str = "rodata_start"; /* string in mapfile has addr rodata start */
161 static char *rodata_end_str = "rodata_end"; /* string in mapfile has addr rodata end */
162 #define RAMSTART_BIT    0x01
163 #define RDSTART_BIT        0x02
164 #define RDEND_BIT        0x04
165 #define ALL_MAP_VAL        (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
166 #endif /* SHOW_LOGTRACE */
167 
168 /* Last connection success/failure status */
169 uint32 dhd_conn_event;
170 uint32 dhd_conn_status;
171 uint32 dhd_conn_reason;
172 
173 extern int dhd_iscan_request(void * dhdp, uint16 action);
174 extern void dhd_ind_scan_confirm(void *h, bool status);
175 extern int dhd_iscan_in_progress(void *h);
176 void dhd_iscan_lock(void);
177 void dhd_iscan_unlock(void);
178 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
179 #if !defined(AP) && defined(WLP2P)
180 extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd);
181 #endif
182 
183 extern int dhd_socram_dump(struct dhd_bus *bus);
184 
185 #ifdef DNGL_EVENT_SUPPORT
186 static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
187     bcm_dngl_event_msg_t *dngl_event, size_t pktlen);
188 static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event,
189     size_t pktlen);
190 #endif /* DNGL_EVENT_SUPPORT */
191 
192 #define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */
193 
194 bool ap_cfg_running = FALSE;
195 bool ap_fw_loaded = FALSE;
196 
197 /* Version string to report */
198 #ifdef DHD_DEBUG
199 #ifndef SRCBASE
200 #define SRCBASE        "drivers/net/wireless/bcmdhd"
201 #endif
202 #define DHD_COMPILED "\nCompiled in " SRCBASE
203 #endif /* DHD_DEBUG */
204 
205 #define CHIPID_MISMATCH    8
206 
207 #if defined(DHD_DEBUG)
208 const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR;
209 #else
210 const char dhd_version[] = "\nDongle Host Driver, version " EPI_VERSION_STR;
211 #endif
212 char fw_version[FW_VER_STR_LEN] = "\0";
213 char clm_version[CLM_VER_STR_LEN] = "\0";
214 
215 char bus_api_revision[BUS_API_REV_STR_LEN] = "\0";
216 
217 void dhd_set_timer(void *bus, uint wdtick);
218 
219 #if defined(TRAFFIC_MGMT_DWM)
220 static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd,
221     trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len);
222 #endif
223 
224 /* IOVar table */
225 enum {
226     IOV_VERSION = 1,
227     IOV_WLMSGLEVEL,
228     IOV_MSGLEVEL,
229     IOV_BCMERRORSTR,
230     IOV_BCMERROR,
231     IOV_WDTICK,
232     IOV_DUMP,
233     IOV_CLEARCOUNTS,
234     IOV_LOGDUMP,
235     IOV_LOGCAL,
236     IOV_LOGSTAMP,
237     IOV_GPIOOB,
238     IOV_IOCTLTIMEOUT,
239     IOV_CONS,
240     IOV_DCONSOLE_POLL,
241 #if defined(DHD_DEBUG)
242     IOV_DHD_JOIN_TIMEOUT_DBG,
243     IOV_SCAN_TIMEOUT,
244     IOV_MEM_DEBUG,
245 #endif /* defined(DHD_DEBUG) */
246 #ifdef PROP_TXSTATUS
247     IOV_PROPTXSTATUS_ENABLE,
248     IOV_PROPTXSTATUS_MODE,
249     IOV_PROPTXSTATUS_OPT,
250     IOV_PROPTXSTATUS_MODULE_IGNORE,
251     IOV_PROPTXSTATUS_CREDIT_IGNORE,
252     IOV_PROPTXSTATUS_TXSTATUS_IGNORE,
253     IOV_PROPTXSTATUS_RXPKT_CHK,
254 #endif /* PROP_TXSTATUS */
255     IOV_BUS_TYPE,
256 #ifdef WLMEDIA_HTSF
257     IOV_WLPKTDLYSTAT_SZ,
258 #endif
259     IOV_CHANGEMTU,
260     IOV_HOSTREORDER_FLOWS,
261 #ifdef DHDTCPACK_SUPPRESS
262     IOV_TCPACK_SUPPRESS,
263 #endif /* DHDTCPACK_SUPPRESS */
264 #ifdef DHD_WMF
265     IOV_WMF_BSS_ENAB,
266     IOV_WMF_UCAST_IGMP,
267     IOV_WMF_MCAST_DATA_SENDUP,
268 #ifdef WL_IGMP_UCQUERY
269     IOV_WMF_UCAST_IGMP_QUERY,
270 #endif /* WL_IGMP_UCQUERY */
271 #ifdef DHD_UCAST_UPNP
272     IOV_WMF_UCAST_UPNP,
273 #endif /* DHD_UCAST_UPNP */
274     IOV_WMF_PSTA_DISABLE,
275 #endif /* DHD_WMF */
276 #if defined(TRAFFIC_MGMT_DWM)
277     IOV_TRAFFIC_MGMT_DWM,
278 #endif
279     IOV_AP_ISOLATE,
280 #ifdef DHD_L2_FILTER
281     IOV_DHCP_UNICAST,
282     IOV_BLOCK_PING,
283     IOV_PROXY_ARP,
284     IOV_GRAT_ARP,
285 #endif /* DHD_L2_FILTER */
286     IOV_DHD_IE,
287 #ifdef DHD_PSTA
288     IOV_PSTA,
289 #endif /* DHD_PSTA */
290 #ifdef DHD_WET
291     IOV_WET,
292     IOV_WET_HOST_IPV4,
293     IOV_WET_HOST_MAC,
294 #endif /* DHD_WET */
295     IOV_CFG80211_OPMODE,
296     IOV_ASSERT_TYPE,
297     IOV_LMTEST,
298 #ifdef DHD_MCAST_REGEN
299     IOV_MCAST_REGEN_BSS_ENABLE,
300 #endif
301 #ifdef SHOW_LOGTRACE
302     IOV_DUMP_TRACE_LOG,
303 #endif /* SHOW_LOGTRACE */
304 #ifdef REPORT_FATAL_TIMEOUTS
305     IOV_SCAN_TO,
306     IOV_JOIN_TO,
307     IOV_CMD_TO,
308     IOV_OQS_TO,
309 #endif /* REPORT_FATAL_TIMEOUTS */
310     IOV_DONGLE_TRAP_TYPE,
311     IOV_DONGLE_TRAP_INFO,
312     IOV_BPADDR,
313     IOV_LAST,
314 #if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
315     IOV_LOG_CAPTURE_ENABLE,
316     IOV_LOG_DUMP
317 #endif /* DHD_EFI && DHD_LOG_DUMP */
318 };
319 
320 const bcm_iovar_t dhd_iovars[] = {
321     {"version",    IOV_VERSION,    0,    0,    IOVT_BUFFER,    sizeof(dhd_version) },
322     {"wlmsglevel",    IOV_WLMSGLEVEL,    0,    0,    IOVT_UINT32,    0 },
323 #ifdef DHD_DEBUG
324     {"msglevel",    IOV_MSGLEVEL,    0,    0,    IOVT_UINT32,    0 },
325     {"mem_debug",   IOV_MEM_DEBUG,  0,      0,      IOVT_BUFFER,    0 },
326 #endif /* DHD_DEBUG */
327     {"bcmerrorstr", IOV_BCMERRORSTR, 0, 0,    IOVT_BUFFER,    BCME_STRLEN },
328     {"bcmerror",    IOV_BCMERROR,    0,    0,    IOVT_INT8,    0 },
329     {"wdtick",    IOV_WDTICK, 0,    0,    IOVT_UINT32,    0 },
330     {"dump",    IOV_DUMP,    0,    0,    IOVT_BUFFER,    DHD_IOCTL_MAXLEN },
331     {"cons",    IOV_CONS,    0,    0,    IOVT_BUFFER,    0 },
332     {"dconpoll",    IOV_DCONSOLE_POLL, 0,    0,    IOVT_UINT32,    0 },
333     {"clearcounts", IOV_CLEARCOUNTS, 0, 0,    IOVT_VOID,    0 },
334     {"gpioob",    IOV_GPIOOB,    0,    0,    IOVT_UINT32,    0 },
335     {"ioctl_timeout",    IOV_IOCTLTIMEOUT,    0,    0,    IOVT_UINT32,    0 },
336 #ifdef PROP_TXSTATUS
337     {"proptx",    IOV_PROPTXSTATUS_ENABLE,    0,    0,    IOVT_BOOL,    0 },
338     /*
339     set the proptxtstatus operation mode:
340     0 - Do not do any proptxtstatus flow control
341     1 - Use implied credit from a packet status
342     2 - Use explicit credit
343     */
344     {"ptxmode",    IOV_PROPTXSTATUS_MODE,    0,    0, IOVT_UINT32,    0 },
345     {"proptx_opt", IOV_PROPTXSTATUS_OPT,    0,    0, IOVT_UINT32,    0 },
346     {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, 0, IOVT_BOOL, 0 },
347     {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, 0, IOVT_BOOL, 0 },
348     {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, 0, IOVT_BOOL, 0 },
349     {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, 0, IOVT_BOOL, 0 },
350 #endif /* PROP_TXSTATUS */
351     {"bustype", IOV_BUS_TYPE, 0, 0, IOVT_UINT32, 0},
352 #ifdef WLMEDIA_HTSF
353     {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, 0, IOVT_UINT8, 0 },
354 #endif
355     {"changemtu", IOV_CHANGEMTU, 0, 0, IOVT_UINT32, 0 },
356     {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, 0, IOVT_BUFFER,
357     (WLHOST_REORDERDATA_MAXFLOWS + 1) },
358 #ifdef DHDTCPACK_SUPPRESS
359     {"tcpack_suppress",    IOV_TCPACK_SUPPRESS,    0,    0, IOVT_UINT8,    0 },
360 #endif /* DHDTCPACK_SUPPRESS */
361 #ifdef DHD_WMF
362     {"wmf_bss_enable", IOV_WMF_BSS_ENAB,    0,    0, IOVT_BOOL,    0 },
363     {"wmf_ucast_igmp", IOV_WMF_UCAST_IGMP,    0,    0, IOVT_BOOL,    0 },
364     {"wmf_mcast_data_sendup", IOV_WMF_MCAST_DATA_SENDUP,    0,    0, IOVT_BOOL,    0 },
365 #ifdef WL_IGMP_UCQUERY
366     {"wmf_ucast_igmp_query", IOV_WMF_UCAST_IGMP_QUERY, (0), 0, IOVT_BOOL, 0 },
367 #endif /* WL_IGMP_UCQUERY */
368 #ifdef DHD_UCAST_UPNP
369     {"wmf_ucast_upnp", IOV_WMF_UCAST_UPNP, (0), 0, IOVT_BOOL, 0 },
370 #endif /* DHD_UCAST_UPNP */
371     {"wmf_psta_disable", IOV_WMF_PSTA_DISABLE, (0), 0, IOVT_BOOL, 0 },
372 #endif /* DHD_WMF */
373 #if defined(TRAFFIC_MGMT_DWM)
374     {"trf_mgmt_filters_add", IOV_TRAFFIC_MGMT_DWM, (0), 0, IOVT_BUFFER, 0},
375 #endif
376 #ifdef DHD_L2_FILTER
377     {"dhcp_unicast", IOV_DHCP_UNICAST, (0), 0, IOVT_BOOL, 0 },
378 #endif /* DHD_L2_FILTER */
379     {"ap_isolate", IOV_AP_ISOLATE, (0), 0, IOVT_BOOL, 0},
380 #ifdef DHD_L2_FILTER
381     {"block_ping", IOV_BLOCK_PING, (0), 0, IOVT_BOOL, 0},
382     {"proxy_arp", IOV_PROXY_ARP, (0), 0, IOVT_BOOL, 0},
383     {"grat_arp", IOV_GRAT_ARP, (0), 0, IOVT_BOOL, 0},
384 #endif /* DHD_L2_FILTER */
385     {"dhd_ie", IOV_DHD_IE, (0), 0, IOVT_BUFFER, 0},
386 #ifdef DHD_PSTA
387     /* PSTA/PSR Mode configuration. 0: DIABLED 1: PSTA 2: PSR */
388     {"psta", IOV_PSTA, 0, 0, IOVT_UINT32, 0},
389 #endif /* DHD PSTA */
390 #ifdef DHD_WET
391     /* WET Mode configuration. 0: DIABLED 1: WET */
392     {"wet", IOV_WET, 0, 0, IOVT_UINT32, 0},
393     {"wet_host_ipv4", IOV_WET_HOST_IPV4, 0, 0, IOVT_UINT32, 0},
394     {"wet_host_mac", IOV_WET_HOST_MAC, 0, 0, IOVT_BUFFER, 0},
395 #endif /* DHD WET */
396     {"op_mode",    IOV_CFG80211_OPMODE,    0,    0, IOVT_UINT32,    0 },
397     {"assert_type", IOV_ASSERT_TYPE, (0), 0, IOVT_UINT32, 0},
398     {"lmtest", IOV_LMTEST,    0,    0, IOVT_UINT32,    0 },
399 #ifdef DHD_MCAST_REGEN
400     {"mcast_regen_bss_enable", IOV_MCAST_REGEN_BSS_ENABLE, 0, 0, IOVT_BOOL, 0},
401 #endif
402 #ifdef SHOW_LOGTRACE
403     {"dump_trace_buf", IOV_DUMP_TRACE_LOG,    0, 0, IOVT_BUFFER,    sizeof(trace_buf_info_t) },
404 #endif /* SHOW_LOGTRACE */
405 #ifdef REPORT_FATAL_TIMEOUTS
406     {"scan_timeout", IOV_SCAN_TO, 0, 0, IOVT_UINT32, 0 },
407     {"join_timeout", IOV_JOIN_TO, 0, 0, IOVT_UINT32, 0 },
408     {"cmd_timeout", IOV_CMD_TO, 0, 0, IOVT_UINT32, 0 },
409     {"oqs_timeout", IOV_OQS_TO, 0, 0, IOVT_UINT32, 0 },
410 #endif /* REPORT_FATAL_TIMEOUTS */
411     {"trap_type", IOV_DONGLE_TRAP_TYPE, 0, 0, IOVT_UINT32, 0 },
412     {"trap_info", IOV_DONGLE_TRAP_INFO, 0, 0, IOVT_BUFFER, sizeof(trap_t) },
413 #ifdef DHD_DEBUG
414     {"bpaddr", IOV_BPADDR,    0, 0, IOVT_BUFFER,    sizeof(sdreg_t) },
415 #endif /* DHD_DEBUG */
416 #if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
417     {"log_capture_enable", IOV_LOG_CAPTURE_ENABLE, 0, 0, IOVT_UINT8, 0},
418     {"log_dump", IOV_LOG_DUMP,    0, 0, IOVT_UINT8, 0},
419 #endif /* DHD_EFI && DHD_LOG_DUMP */
420     {NULL, 0, 0, 0, 0, 0 }
421 };
422 
423 #define DHD_IOVAR_BUF_SIZE    128
424 
425 bool
dhd_query_bus_erros(dhd_pub_t * dhdp)426 dhd_query_bus_erros(dhd_pub_t *dhdp)
427 {
428     bool ret = FALSE;
429 
430     if (dhdp->dongle_reset) {
431         DHD_ERROR(("%s: Dongle Reset occurred, cannot proceed\n",
432             __FUNCTION__));
433         ret = TRUE;
434     }
435 
436     if (dhdp->dongle_trap_occured) {
437         DHD_ERROR(("%s: FW TRAP has occurred, cannot proceed\n",
438             __FUNCTION__));
439         ret = TRUE;
440 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27))
441         dhdp->hang_reason = HANG_REASON_DONGLE_TRAP;
442         dhd_os_send_hang_message(dhdp);
443 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) */
444     }
445 
446     if (dhdp->iovar_timeout_occured) {
447         DHD_ERROR(("%s: Resumed on timeout for previous IOVAR, cannot proceed\n",
448             __FUNCTION__));
449         ret = TRUE;
450     }
451 
452 #ifdef PCIE_FULL_DONGLE
453     if (dhdp->d3ack_timeout_occured) {
454         DHD_ERROR(("%s: Resumed on timeout for previous D3ACK, cannot proceed\n",
455             __FUNCTION__));
456         ret = TRUE;
457     }
458 #endif /* PCIE_FULL_DONGLE */
459 
460     return ret;
461 }
462 
463 #ifdef DHD_SSSR_DUMP
464 int
dhd_sssr_mempool_init(dhd_pub_t * dhd)465 dhd_sssr_mempool_init(dhd_pub_t *dhd)
466 {
467     dhd->sssr_mempool = (uint8 *) MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE);
468     if (dhd->sssr_mempool == NULL) {
469         DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n",
470             __FUNCTION__));
471         return BCME_ERROR;
472     }
473     return BCME_OK;
474 }
475 
476 void
dhd_sssr_mempool_deinit(dhd_pub_t * dhd)477 dhd_sssr_mempool_deinit(dhd_pub_t *dhd)
478 {
479     if (dhd->sssr_mempool) {
480         MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE);
481         dhd->sssr_mempool = NULL;
482     }
483 }
484 
485 int
dhd_get_sssr_reg_info(dhd_pub_t * dhd)486 dhd_get_sssr_reg_info(dhd_pub_t *dhd)
487 {
488     int ret = BCME_ERROR;
489 
490     DHD_ERROR(("%s: get sssr_reg_info\n", __FUNCTION__));
491     /* get sssr_reg_info from firmware */
492     memset((void *)&dhd->sssr_reg_info, 0, sizeof(dhd->sssr_reg_info));
493     if (bcm_mkiovar("sssr_reg_info", 0, 0, (char *)&dhd->sssr_reg_info,
494         sizeof(dhd->sssr_reg_info))) {
495         if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, &dhd->sssr_reg_info,
496             sizeof(dhd->sssr_reg_info), FALSE, 0)) < 0) {
497             DHD_ERROR(("%s: dhd_wl_ioctl_cmd failed (error=%d)\n", __FUNCTION__, ret));
498         }
499     } else {
500             DHD_ERROR(("%s: bcm_mkiovar failed\n", __FUNCTION__));
501     }
502 
503     return ret;
504 }
505 
506 uint32
dhd_get_sssr_bufsize(dhd_pub_t * dhd)507 dhd_get_sssr_bufsize(dhd_pub_t *dhd)
508 {
509     int i;
510     uint32 sssr_bufsize = 0;
511     /* Init all pointers to NULL */
512     for (i = 0; i < MAX_NUM_D11CORES; i++) {
513         sssr_bufsize += dhd->sssr_reg_info.mac_regs[i].sr_size;
514     }
515     sssr_bufsize += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
516 
517     /* Double the size as different dumps will be saved before and after SR */
518     sssr_bufsize = 2 * sssr_bufsize;
519 
520     return sssr_bufsize;
521 }
522 
523 int
dhd_sssr_dump_init(dhd_pub_t * dhd)524 dhd_sssr_dump_init(dhd_pub_t *dhd)
525 {
526     int i;
527     uint32 sssr_bufsize;
528     uint32 mempool_used = 0;
529 
530     dhd->sssr_inited = FALSE;
531 
532     /* check if sssr mempool is allocated */
533     if (dhd->sssr_mempool == NULL) {
534         DHD_ERROR(("%s: sssr_mempool is not allocated\n",
535             __FUNCTION__));
536         return BCME_ERROR;
537     }
538 
539     /* Get SSSR reg info */
540     if (dhd_get_sssr_reg_info(dhd) != BCME_OK) {
541         DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__));
542         return BCME_ERROR;
543     }
544 
545     /* Validate structure version */
546     if (dhd->sssr_reg_info.version != SSSR_REG_INFO_VER) {
547         DHD_ERROR(("%s: dhd->sssr_reg_info.version (%d : %d) mismatch\n",
548             __FUNCTION__, (int)dhd->sssr_reg_info.version, SSSR_REG_INFO_VER));
549         return BCME_ERROR;
550     }
551 
552     /* Validate structure length */
553     if (dhd->sssr_reg_info.length != sizeof(dhd->sssr_reg_info)) {
554         DHD_ERROR(("%s: dhd->sssr_reg_info.length (%d : %d) mismatch\n",
555             __FUNCTION__, (int)dhd->sssr_reg_info.length,
556             (int)sizeof(dhd->sssr_reg_info)));
557         return BCME_ERROR;
558     }
559 
560     /* validate fifo size */
561     sssr_bufsize = dhd_get_sssr_bufsize(dhd);
562     if (sssr_bufsize > DHD_SSSR_MEMPOOL_SIZE) {
563         DHD_ERROR(("%s: sssr_bufsize(%d) is greater than sssr_mempool(%d)\n",
564             __FUNCTION__, (int)sssr_bufsize, DHD_SSSR_MEMPOOL_SIZE));
565         return BCME_ERROR;
566     }
567 
568     /* init all pointers to NULL */
569     for (i = 0; i < MAX_NUM_D11CORES; i++) {
570         dhd->sssr_d11_before[i] = NULL;
571         dhd->sssr_d11_after[i] = NULL;
572     }
573     dhd->sssr_vasip_buf_before = NULL;
574     dhd->sssr_vasip_buf_after = NULL;
575 
576     /* Allocate memory */
577     for (i = 0; i < MAX_NUM_D11CORES; i++) {
578         if (dhd->sssr_reg_info.mac_regs[i].sr_size) {
579             dhd->sssr_d11_before[i] = (uint32 *)(dhd->sssr_mempool + mempool_used);
580             mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size;
581 
582             dhd->sssr_d11_after[i] = (uint32 *)(dhd->sssr_mempool + mempool_used);
583             mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size;
584         }
585     }
586 
587     if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) {
588         dhd->sssr_vasip_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used);
589         mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
590 
591         dhd->sssr_vasip_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
592         mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
593     }
594 
595     dhd->sssr_inited = TRUE;
596 
597     return BCME_OK;
598 }
599 
600 void
dhd_sssr_dump_deinit(dhd_pub_t * dhd)601 dhd_sssr_dump_deinit(dhd_pub_t *dhd)
602 {
603     int i;
604 
605     dhd->sssr_inited = FALSE;
606     /* init all pointers to NULL */
607     for (i = 0; i < MAX_NUM_D11CORES; i++) {
608         dhd->sssr_d11_before[i] = NULL;
609         dhd->sssr_d11_after[i] = NULL;
610     }
611     dhd->sssr_vasip_buf_before = NULL;
612     dhd->sssr_vasip_buf_after = NULL;
613 
614     return;
615 }
616 
617 #endif /* DHD_SSSR_DUMP */
618 
619 #ifdef DHD_FW_COREDUMP
dhd_get_fwdump_buf(dhd_pub_t * dhd_pub,uint32 length)620 void* dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length)
621 {
622     if (!dhd_pub->soc_ram) {
623 #if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
624         dhd_pub->soc_ram = (uint8*)DHD_OS_PREALLOC(dhd_pub,
625             DHD_PREALLOC_MEMDUMP_RAM, length);
626 #else
627         dhd_pub->soc_ram = (uint8*) MALLOC(dhd_pub->osh, length);
628 #endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
629     }
630 
631     if (dhd_pub->soc_ram == NULL) {
632         DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n",
633             __FUNCTION__));
634         dhd_pub->soc_ram_length = 0;
635     } else {
636         memset(dhd_pub->soc_ram, 0, length);
637         dhd_pub->soc_ram_length = length;
638     }
639 
640     /* soc_ram free handled in dhd_{free,clear} */
641     return dhd_pub->soc_ram;
642 }
643 #endif /* DHD_FW_COREDUMP */
644 
645 /* to NDIS developer, the structure dhd_common is redundant,
646  * please do NOT merge it back from other branches !!!
647  */
648 
649 int
dhd_common_socram_dump(dhd_pub_t * dhdp)650 dhd_common_socram_dump(dhd_pub_t *dhdp)
651 {
652 #ifdef BCMDBUS
653     return 0;
654 #else
655     return dhd_socram_dump(dhdp->bus);
656 #endif /* BCMDBUS */
657 }
658 
659 static int
dhd_dump(dhd_pub_t * dhdp,char * buf,int buflen)660 dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
661 {
662     char eabuf[ETHER_ADDR_STR_LEN];
663 
664     struct bcmstrbuf b;
665     struct bcmstrbuf *strbuf = &b;
666 
667     if (!dhdp || !dhdp->prot || !buf) {
668         return BCME_ERROR;
669     }
670 
671     bcm_binit(strbuf, buf, buflen);
672 
673     /* Base DHD info */
674     bcm_bprintf(strbuf, "%s\n", dhd_version);
675     bcm_bprintf(strbuf, "\n");
676     bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n",
677                 dhdp->up, dhdp->txoff, dhdp->busstate);
678     bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n",
679                 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
680     bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n",
681                 dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf));
682     bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror, dhdp->tickcnt);
683 
684     bcm_bprintf(strbuf, "dongle stats:\n");
685     bcm_bprintf(strbuf, "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n",
686                 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
687                 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
688     bcm_bprintf(strbuf, "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n",
689                 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
690                 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
691     bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast);
692 
693     bcm_bprintf(strbuf, "bus stats:\n");
694     bcm_bprintf(strbuf, "tx_packets %lu  tx_dropped %lu tx_multicast %lu tx_errors %lu\n",
695                 dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast, dhdp->tx_errors);
696     bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n",
697                 dhdp->tx_ctlpkts, dhdp->tx_ctlerrs);
698     bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
699                 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
700     bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n",
701                 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
702     bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n",
703                 dhdp->rx_readahead_cnt, dhdp->tx_realloc);
704     bcm_bprintf(strbuf, "tx_pktgetfail %lu rx_pktgetfail %lu\n",
705                 dhdp->tx_pktgetfail, dhdp->rx_pktgetfail);
706     bcm_bprintf(strbuf, "\n");
707 
708 #ifdef DMAMAP_STATS
709     /* Add DMA MAP info */
710     bcm_bprintf(strbuf, "DMA MAP stats: \n");
711     bcm_bprintf(strbuf, "txdata: %lu size: %luK, rxdata: %lu size: %luK\n",
712             dhdp->dma_stats.txdata, KB(dhdp->dma_stats.txdata_sz),
713             dhdp->dma_stats.rxdata, KB(dhdp->dma_stats.rxdata_sz));
714 #ifndef IOCTLRESP_USE_CONSTMEM
715     bcm_bprintf(strbuf, "IOCTL RX: %lu size: %luK ,",
716             dhdp->dma_stats.ioctl_rx, KB(dhdp->dma_stats.ioctl_rx_sz));
717 #endif /* !IOCTLRESP_USE_CONSTMEM */
718     bcm_bprintf(strbuf, "EVENT RX: %lu size: %luK, INFO RX: %lu size: %luK, "
719             "TSBUF RX: %lu size %luK\n",
720             dhdp->dma_stats.event_rx, KB(dhdp->dma_stats.event_rx_sz),
721             dhdp->dma_stats.info_rx, KB(dhdp->dma_stats.info_rx_sz),
722             dhdp->dma_stats.tsbuf_rx, KB(dhdp->dma_stats.tsbuf_rx_sz));
723     bcm_bprintf(strbuf, "Total : %luK \n",
724             KB(dhdp->dma_stats.txdata_sz + dhdp->dma_stats.rxdata_sz +
725             dhdp->dma_stats.ioctl_rx_sz + dhdp->dma_stats.event_rx_sz +
726             dhdp->dma_stats.tsbuf_rx_sz));
727 #endif /* DMAMAP_STATS */
728 
729     /* Add any prot info */
730     dhd_prot_dump(dhdp, strbuf);
731     bcm_bprintf(strbuf, "\n");
732 
733     /* Add any bus info */
734     dhd_bus_dump(dhdp, strbuf);
735 
736 
737 #if defined(DHD_LB_STATS)
738     dhd_lb_stats_dump(dhdp, strbuf);
739 #endif /* DHD_LB_STATS */
740 #ifdef DHD_WET
741     if (dhd_get_wet_mode(dhdp)) {
742         bcm_bprintf(strbuf, "Wet Dump:\n");
743         dhd_wet_dump(dhdp, strbuf);
744         }
745 #endif /* DHD_WET */
746     return (!strbuf->size ? BCME_BUFTOOSHORT : 0);
747 }
748 
749 void
dhd_dump_to_kernelog(dhd_pub_t * dhdp)750 dhd_dump_to_kernelog(dhd_pub_t *dhdp)
751 {
752     char buf[512];
753 
754     DHD_ERROR(("F/W version: %s\n", fw_version));
755     bcm_bprintf_bypass = TRUE;
756     dhd_dump(dhdp, buf, sizeof(buf));
757     bcm_bprintf_bypass = FALSE;
758 }
759 
760 int
dhd_wl_ioctl_cmd(dhd_pub_t * dhd_pub,int cmd,void * arg,int len,uint8 set,int ifidx)761 dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifidx)
762 {
763     wl_ioctl_t ioc;
764 
765     ioc.cmd = cmd;
766     ioc.buf = arg;
767     ioc.len = len;
768     ioc.set = set;
769 
770     return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len);
771 }
772 
773 int
dhd_wl_ioctl_get_intiovar(dhd_pub_t * dhd_pub,char * name,uint * pval,int cmd,uint8 set,int ifidx)774 dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval,
775     int cmd, uint8 set, int ifidx)
776 {
777     char iovbuf[WLC_IOCTL_SMLEN];
778     int ret = -1;
779 
780     memset(iovbuf, 0, sizeof(iovbuf));
781     if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) {
782         ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, sizeof(iovbuf), set, ifidx);
783         if (!ret) {
784             *pval = ltoh32(*((uint*)iovbuf));
785         } else {
786             DHD_ERROR(("%s: get int iovar %s failed, ERR %d\n",
787                 __FUNCTION__, name, ret));
788         }
789     } else {
790         DHD_ERROR(("%s: mkiovar %s failed\n",
791             __FUNCTION__, name));
792     }
793 
794     return ret;
795 }
796 
797 int
dhd_wl_ioctl_set_intiovar(dhd_pub_t * dhd_pub,char * name,uint val,int cmd,uint8 set,int ifidx)798 dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val,
799     int cmd, uint8 set, int ifidx)
800 {
801     char iovbuf[WLC_IOCTL_SMLEN] = {0};
802     int ret = -1;
803     int lval = htol32(val);
804     uint len;
805 
806     len = bcm_mkiovar(name, (char*)&lval, sizeof(lval), iovbuf, sizeof(iovbuf));
807 
808     if (len) {
809         ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, len, set, ifidx);
810         if (ret) {
811             DHD_ERROR(("%s: set int iovar %s failed, ERR %d\n",
812                 __FUNCTION__, name, ret));
813         }
814     } else {
815         DHD_ERROR(("%s: mkiovar %s failed\n",
816             __FUNCTION__, name));
817     }
818 
819     return ret;
820 }
821 
822 int
dhd_wl_ioctl(dhd_pub_t * dhd_pub,int ifidx,wl_ioctl_t * ioc,void * buf,int len)823 dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf, int len)
824 {
825     int ret = BCME_ERROR;
826     unsigned long flags;
827 #ifdef DUMP_IOCTL_IOV_LIST
828     dhd_iov_li_t *iov_li;
829 #endif /* DUMP_IOCTL_IOV_LIST */
830 #ifdef KEEPIF_ON_DEVICE_RESET
831         if (ioc->cmd == WLC_GET_VAR) {
832             dbus_config_t config;
833             config.general_param = 0;
834             if (!strcmp(buf, "wowl_activate")) {
835                 config.general_param = 2; /* 1 (TRUE) after decreased by 1 */
836             } else if (!strcmp(buf, "wowl_clear")) {
837                 config.general_param = 1; /* 0 (FALSE) after decreased by 1 */
838             }
839             if (config.general_param) {
840                 config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET;
841                 config.general_param--;
842                 dbus_set_config(dhd_pub->dbus, &config);
843             }
844         }
845 #endif /* KEEPIF_ON_DEVICE_RESET */
846 
847     if (dhd_os_proto_block(dhd_pub))
848     {
849 #ifdef DHD_LOG_DUMP
850         int slen, i, val, rem, lval, min_len;
851         char *pval, *pos, *msg;
852         char tmp[64];
853 
854         /* WLC_GET_VAR */
855         if (ioc->cmd == WLC_GET_VAR) {
856             min_len = MIN(sizeof(tmp) - 1, strlen(buf));
857             memset(tmp, 0, sizeof(tmp));
858             bcopy(buf, tmp, min_len);
859             tmp[min_len] = '\0';
860         }
861 #endif /* DHD_LOG_DUMP */
862         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
863         if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) {
864 #ifdef DHD_EFI
865             DHD_INFO(("%s: returning as busstate=%d\n",
866                 __FUNCTION__, dhd_pub->busstate));
867 #else
868             DHD_ERROR(("%s: returning as busstate=%d\n",
869                 __FUNCTION__, dhd_pub->busstate));
870 #endif /* DHD_EFI */
871             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
872             dhd_os_proto_unblock(dhd_pub);
873             return -ENODEV;
874         }
875         DHD_BUS_BUSY_SET_IN_IOVAR(dhd_pub);
876         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
877 
878 #ifdef DHD_PCIE_RUNTIMEPM
879         dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_wl_ioctl);
880 #endif /* DHD_PCIE_RUNTIMEPM */
881 
882         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
883         if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) {
884             DHD_ERROR(("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n",
885                 __FUNCTION__, dhd_pub->busstate, dhd_pub->dhd_bus_busy_state));
886             DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub);
887             dhd_os_busbusy_wake(dhd_pub);
888             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
889             dhd_os_proto_unblock(dhd_pub);
890             return -ENODEV;
891         }
892         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
893 
894 #if defined(WL_WLC_SHIM)
895         {
896             struct wl_shim_node *shim = dhd_pub_shim(dhd_pub);
897 
898             wl_io_pport_t io_pport;
899             io_pport.dhd_pub = dhd_pub;
900             io_pport.ifidx = ifidx;
901 
902             ret = wl_shim_ioctl(shim, ioc, len, &io_pport);
903             if (ret != BCME_OK) {
904                 DHD_TRACE(("%s: wl_shim_ioctl(%d) ERR %d\n",
905                     __FUNCTION__, ioc->cmd, ret));
906             }
907         }
908 #else
909 #ifdef DUMP_IOCTL_IOV_LIST
910         if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION && buf) {
911             if (!(iov_li = MALLOC(dhd_pub->osh, sizeof(*iov_li)))) {
912                 DHD_ERROR(("iovar dump list item allocation Failed\n"));
913             } else {
914                 iov_li->cmd = ioc->cmd;
915                 bcopy((char *)buf, iov_li->buff, strlen((char *)buf)+1);
916                 dhd_iov_li_append(dhd_pub, &dhd_pub->dump_iovlist_head,
917                     &iov_li->list);
918             }
919         }
920 #endif /* DUMP_IOCTL_IOV_LIST */
921         ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
922 #ifdef DUMP_IOCTL_IOV_LIST
923         if (ret == -ETIMEDOUT) {
924             DHD_ERROR(("Last %d issued commands: Latest one is at bottom.\n",
925                 IOV_LIST_MAX_LEN));
926             dhd_iov_li_print(&dhd_pub->dump_iovlist_head);
927         }
928 #endif /* DUMP_IOCTL_IOV_LIST */
929 #endif /* defined(WL_WLC_SHIM) */
930 #ifdef DHD_LOG_DUMP
931         if (ioc->cmd == WLC_GET_VAR || ioc->cmd == WLC_SET_VAR) {
932             lval = 0;
933             slen = strlen(buf) + 1;
934             msg = (char*)buf;
935             if (len >= slen + sizeof(lval)) {
936                 if (ioc->cmd == WLC_GET_VAR) {
937                     msg = tmp;
938                     lval = *(int*)buf;
939                 } else {
940                     min_len = MIN(ioc->len - slen, sizeof(int));
941                     bcopy((msg + slen), &lval, min_len);
942                 }
943             }
944             DHD_ERROR_MEM(("%s: cmd: %d, msg: %s, val: 0x%x, len: %d, set: %d\n",
945                 ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR",
946                 ioc->cmd, msg, lval, ioc->len, ioc->set));
947         } else {
948             slen = ioc->len;
949             if (buf != NULL) {
950                 val = *(int*)buf;
951                 pval = (char*)buf;
952                 pos = tmp;
953                 rem = sizeof(tmp);
954                 memset(tmp, 0, sizeof(tmp));
955                 for (i = 0; i < slen; i++) {
956                     if (rem <= 3) {
957                         /* At least 2 byte required + 1 byte(NULL) */
958                         break;
959                     }
960                     pos += snprintf(pos, rem, "%02x ", pval[i]);
961                     rem = sizeof(tmp) - (int)(pos - tmp);
962                 }
963                 /* Do not dump for WLC_GET_MAGIC and WLC_GET_VERSION */
964                 if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION)
965                     DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, val: %d(%s), "
966                         "len: %d, set: %d\n",
967                         ioc->cmd, val, tmp, ioc->len, ioc->set));
968             } else {
969                 DHD_ERROR_MEM(("WLC_IOCTL: cmd: %d, buf is NULL\n", ioc->cmd));
970             }
971         }
972 #endif /* DHD_LOG_DUMP */
973         if (ret && dhd_pub->up) {
974             /* Send hang event only if dhd_open() was success */
975             dhd_os_check_hang(dhd_pub, ifidx, ret);
976         }
977 
978         if (ret == -ETIMEDOUT && !dhd_pub->up) {
979             DHD_ERROR(("%s: 'resumed on timeout' error is "
980                 "occurred before the interface does not"
981                 " bring up\n", __FUNCTION__));
982             dhd_pub->busstate = DHD_BUS_DOWN;
983         }
984 
985         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
986         DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub);
987         dhd_os_busbusy_wake(dhd_pub);
988         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
989 
990         dhd_os_proto_unblock(dhd_pub);
991     }
992 
993     return ret;
994 }
995 
wl_get_port_num(wl_io_pport_t * io_pport)996 uint wl_get_port_num(wl_io_pport_t *io_pport)
997 {
998     return 0;
999 }
1000 
1001 /* Get bssidx from iovar params
1002  * Input:   dhd_pub - pointer to dhd_pub_t
1003  *        params  - IOVAR params
1004  * Output:  idx        - BSS index
1005  *        val        - ponter to the IOVAR arguments
1006  */
1007 static int
dhd_iovar_parse_bssidx(dhd_pub_t * dhd_pub,const char * params,uint32 * idx,const char ** val)1008 dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params, uint32 *idx, const char **val)
1009 {
1010     char *prefix = "bsscfg:";
1011     uint32    bssidx;
1012 
1013     if (!(strncmp(params, prefix, strlen(prefix)))) {
1014         /* per bss setting should be prefixed with 'bsscfg:' */
1015         const char *p = params + strlen(prefix);
1016 
1017         /* Skip Name */
1018         while (*p != '\0')
1019             p++;
1020         /* consider null */
1021         p = p + 1;
1022         bcopy(p, &bssidx, sizeof(uint32));
1023         /* Get corresponding dhd index */
1024         bssidx = dhd_bssidx2idx(dhd_pub, htod32(bssidx));
1025 
1026         if (bssidx >= DHD_MAX_IFS) {
1027             DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__));
1028             return BCME_ERROR;
1029         }
1030 
1031         /* skip bss idx */
1032         p += sizeof(uint32);
1033         *val = p;
1034         *idx = bssidx;
1035     } else {
1036         DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__));
1037         return BCME_ERROR;
1038     }
1039 
1040     return BCME_OK;
1041 }
1042 
1043 #if defined(DHD_DEBUG) && defined(BCMDBUS)
1044 /* USB Device console input function */
dhd_bus_console_in(dhd_pub_t * dhd,uchar * msg,uint msglen)1045 int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen)
1046 {
1047     DHD_TRACE(("%s \n", __FUNCTION__));
1048 
1049     return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE);
1050 }
1051 #endif /* DHD_DEBUG && BCMDBUS  */
1052 
1053 #ifdef DHD_DEBUG
1054 int
dhd_mem_debug(dhd_pub_t * dhd,char * msg,uint msglen)1055 dhd_mem_debug(dhd_pub_t *dhd, char *msg, uint msglen)
1056 {
1057     unsigned long int_arg = 0;
1058     char *p;
1059     char *end_ptr = NULL;
1060     dhd_dbg_mwli_t *mw_li;
1061     dll_t *item, *next;
1062     /* check if mwalloc, mwquery or mwfree was supplied arguement with space */
1063     p = bcmstrstr(msg, " ");
1064     if (p != NULL) {
1065         /* space should be converted to null as separation flag for firmware */
1066         *p = '\0';
1067         /* store the argument in int_arg */
1068         int_arg = bcm_strtoul(p+1, &end_ptr, 10);
1069     }
1070 
1071     if (!p && !strcmp(msg, "query")) {
1072         /* lets query the list inetrnally */
1073         if (dll_empty(dll_head_p(&dhd->mw_list_head))) {
1074             DHD_ERROR(("memwaste list is empty, call mwalloc < size > to allocate\n"));
1075             /* reset the id */
1076             dhd->mw_id = 0;
1077         } else {
1078             for (item = dll_head_p(&dhd->mw_list_head);
1079                     !dll_end(&dhd->mw_list_head, item); item = next) {
1080                 next = dll_next_p(item);
1081                 mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1082                 DHD_ERROR(("item: <id=%d, size=%d>\n", mw_li->id, mw_li->size));
1083             }
1084         }
1085     } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "alloc")) {
1086         int32 alloc_handle;
1087         /* convert size into KB and append as integer */
1088         *((int32 *)(p+1)) = int_arg*1024;
1089         *(p+1+sizeof(int32)) = '\0';
1090 
1091         /* recalculated length -> 5 bytes for "alloc" + 4 bytes for size +
1092          *1 bytes for null caracter
1093          */
1094         msglen = strlen(msg) + sizeof(int32) + 1;
1095         if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, msglen, FALSE, 0) < 0) {
1096             DHD_ERROR(("IOCTL failed for memdebug alloc\n"));
1097         }
1098 
1099         /* returned allocated handle from dongle, basically address of the allocated unit */
1100         alloc_handle = *((int32 *)msg);
1101 
1102         /* add a node in the list with tuple <id, handle, size> */
1103         if (alloc_handle == 0) {
1104             DHD_ERROR(("Reuqested size could not be allocated\n"));
1105         } else if (!(mw_li = MALLOC(dhd->osh, sizeof(*mw_li)))) {
1106             DHD_ERROR(("mw list item allocation Failed\n"));
1107         } else {
1108             mw_li->id = dhd->mw_id++;
1109             mw_li->handle = alloc_handle;
1110             mw_li->size = int_arg;
1111             /* append the node in the list */
1112             dll_append(&dhd->mw_list_head, &mw_li->list);
1113         }
1114     } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "free")) {
1115         /* inform dongle to free wasted chunk */
1116         int handle = 0;
1117         int size = 0;
1118         for (item = dll_head_p(&dhd->mw_list_head);
1119                 !dll_end(&dhd->mw_list_head, item); item = next) {
1120             next = dll_next_p(item);
1121             mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1122 
1123             if (mw_li->id == (int)int_arg) {
1124                 handle = mw_li->handle;
1125                 size = mw_li->size;
1126                 dll_delete(item);
1127                 MFREE(dhd->osh, mw_li, sizeof(*mw_li));
1128             }
1129         }
1130         if (handle) {
1131             int len;
1132             /* append the free handle and the chunk size in first 8 bytes
1133              * after the command and null character
1134              */
1135             *((int32 *)(p+1)) = handle;
1136             *((int32 *)((p+1)+sizeof(int32))) = size;
1137             /* append null as terminator */
1138             *(p+1+2*sizeof(int32)) = '\0';
1139             /* recalculated length -> 4 bytes for "free" + 8 bytes for hadnle and size
1140              * + 1 bytes for null caracter
1141              */
1142             len = strlen(msg) + 2*sizeof(int32) + 1;
1143             /* send iovar to free the chunk */
1144             if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, len, FALSE, 0) < 0) {
1145                 DHD_ERROR(("IOCTL failed for memdebug free\n"));
1146             }
1147         } else {
1148             DHD_ERROR(("specified id does not exist\n"));
1149         }
1150     } else {
1151         /* for all the wrong argument formats */
1152         return BCME_BADARG;
1153     }
1154     return 0;
1155 }
1156 
1157 extern void
dhd_mw_list_delete(dhd_pub_t * dhd,dll_t * list_head)1158 dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head)
1159 {
1160     dll_t *item;
1161     dhd_dbg_mwli_t *mw_li;
1162     while (!(dll_empty(list_head))) {
1163         item = dll_head_p(list_head);
1164         mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1165         dll_delete(item);
1166         MFREE(dhd->osh, mw_li, sizeof(*mw_li));
1167     }
1168 }
1169 #endif /* DHD_DEBUG */
1170 
1171 #ifdef PKT_STATICS
1172 extern pkt_statics_t tx_statics;
1173 extern void dhdsdio_txpktstatics(void);
1174 #endif
1175 
1176 static int
dhd_doiovar(dhd_pub_t * dhd_pub,const bcm_iovar_t * vi,uint32 actionid,const char * name,void * params,int plen,void * arg,int len,int val_size)1177 dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name,
1178             void *params, int plen, void *arg, int len, int val_size)
1179 {
1180     int bcmerror = 0;
1181     int32 int_val = 0;
1182     uint32 dhd_ver_len, bus_api_rev_len;
1183 
1184     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1185     DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
1186 
1187     if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0)
1188         goto exit;
1189 
1190     if (plen >= (int)sizeof(int_val))
1191         bcopy(params, &int_val, sizeof(int_val));
1192 
1193     switch (actionid) {
1194     case IOV_GVAL(IOV_VERSION):
1195         /* Need to have checked buffer length */
1196         dhd_ver_len = strlen(dhd_version);
1197         bus_api_rev_len = strlen(bus_api_revision);
1198         if (dhd_ver_len)
1199             bcm_strncpy_s((char*)arg, dhd_ver_len, dhd_version, dhd_ver_len);
1200         if (bus_api_rev_len)
1201             bcm_strncat_s((char*)arg + dhd_ver_len, bus_api_rev_len, bus_api_revision,
1202                 bus_api_rev_len);
1203 #ifdef PKT_STATICS
1204         memset((uint8*) &tx_statics, 0, sizeof(pkt_statics_t));
1205 #endif
1206         break;
1207 
1208     case IOV_GVAL(IOV_WLMSGLEVEL):
1209         printf("android_msg_level=0x%x\n", android_msg_level);
1210         printf("config_msg_level=0x%x\n", config_msg_level);
1211 #if defined(WL_WIRELESS_EXT)
1212         int_val = (int32)iw_msg_level;
1213         bcopy(&int_val, arg, val_size);
1214         printf("iw_msg_level=0x%x\n", iw_msg_level);
1215 #endif
1216 #ifdef WL_CFG80211
1217         int_val = (int32)wl_dbg_level;
1218         bcopy(&int_val, arg, val_size);
1219         printf("cfg_msg_level=0x%x\n", wl_dbg_level);
1220 #endif
1221         break;
1222 
1223     case IOV_SVAL(IOV_WLMSGLEVEL):
1224         if (int_val & DHD_ANDROID_VAL) {
1225             android_msg_level = (uint)(int_val & 0xFFFF);
1226             printf("android_msg_level=0x%x\n", android_msg_level);
1227         }
1228         if (int_val & DHD_CONFIG_VAL) {
1229             config_msg_level = (uint)(int_val & 0xFFFF);
1230             printf("config_msg_level=0x%x\n", config_msg_level);
1231         }
1232 #if defined(WL_WIRELESS_EXT)
1233         if (int_val & DHD_IW_VAL) {
1234             iw_msg_level = (uint)(int_val & 0xFFFF);
1235             printf("iw_msg_level=0x%x\n", iw_msg_level);
1236         }
1237 #endif
1238 #ifdef WL_CFG80211
1239         if (int_val & DHD_CFG_VAL) {
1240             wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF));
1241         }
1242 #endif
1243         break;
1244 
1245     case IOV_GVAL(IOV_MSGLEVEL):
1246         int_val = (int32)dhd_msg_level;
1247         bcopy(&int_val, arg, val_size);
1248 #ifdef PKT_STATICS
1249         dhdsdio_txpktstatics();
1250 #endif
1251         break;
1252 
1253     case IOV_SVAL(IOV_MSGLEVEL):
1254         dhd_msg_level = int_val;
1255         break;
1256 
1257     case IOV_GVAL(IOV_BCMERRORSTR):
1258         bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN);
1259         ((char *)arg)[BCME_STRLEN - 1] = 0x00;
1260         break;
1261 
1262     case IOV_GVAL(IOV_BCMERROR):
1263         int_val = (int32)dhd_pub->bcmerror;
1264         bcopy(&int_val, arg, val_size);
1265         break;
1266 
1267 #ifndef BCMDBUS
1268     case IOV_GVAL(IOV_WDTICK):
1269         int_val = (int32)dhd_watchdog_ms;
1270         bcopy(&int_val, arg, val_size);
1271         break;
1272 #endif /* !BCMDBUS */
1273 
1274     case IOV_SVAL(IOV_WDTICK):
1275         if (!dhd_pub->up) {
1276             bcmerror = BCME_NOTUP;
1277             break;
1278         }
1279 
1280         if (CUSTOM_DHD_WATCHDOG_MS == 0 && int_val == 0) {
1281             dhd_watchdog_ms = (uint)int_val;
1282         }
1283 
1284         dhd_os_wd_timer(dhd_pub, (uint)int_val);
1285         break;
1286 
1287     case IOV_GVAL(IOV_DUMP):
1288         bcmerror = dhd_dump(dhd_pub, arg, len);
1289         break;
1290 
1291 #ifndef BCMDBUS
1292     case IOV_GVAL(IOV_DCONSOLE_POLL):
1293         int_val = (int32)dhd_console_ms;
1294         bcopy(&int_val, arg, val_size);
1295         break;
1296 
1297     case IOV_SVAL(IOV_DCONSOLE_POLL):
1298         dhd_console_ms = (uint)int_val;
1299         break;
1300 
1301     case IOV_SVAL(IOV_CONS):
1302         if (len > 0)
1303             bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
1304         break;
1305 #endif /* !BCMDBUS */
1306 
1307     case IOV_SVAL(IOV_CLEARCOUNTS):
1308         dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
1309         dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
1310         dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
1311         dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
1312         dhd_pub->tx_dropped = 0;
1313         dhd_pub->rx_dropped = 0;
1314         dhd_pub->tx_pktgetfail = 0;
1315         dhd_pub->rx_pktgetfail = 0;
1316         dhd_pub->rx_readahead_cnt = 0;
1317         dhd_pub->tx_realloc = 0;
1318         dhd_pub->wd_dpc_sched = 0;
1319         memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
1320         dhd_bus_clearcounts(dhd_pub);
1321 #ifdef PROP_TXSTATUS
1322         /* clear proptxstatus related counters */
1323         dhd_wlfc_clear_counts(dhd_pub);
1324 #endif /* PROP_TXSTATUS */
1325 #if defined(DHD_LB_STATS)
1326         DHD_LB_STATS_RESET(dhd_pub);
1327 #endif /* DHD_LB_STATS */
1328         break;
1329 
1330 
1331     case IOV_GVAL(IOV_IOCTLTIMEOUT): {
1332         int_val = (int32)dhd_os_get_ioctl_resp_timeout();
1333         bcopy(&int_val, arg, sizeof(int_val));
1334         break;
1335     }
1336 
1337     case IOV_SVAL(IOV_IOCTLTIMEOUT): {
1338         if (int_val <= 0)
1339             bcmerror = BCME_BADARG;
1340         else
1341             dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
1342         break;
1343     }
1344 
1345 #ifdef PROP_TXSTATUS
1346     case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): {
1347         bool wlfc_enab = FALSE;
1348         bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
1349         if (bcmerror != BCME_OK)
1350             goto exit;
1351         int_val = wlfc_enab ? 1 : 0;
1352         bcopy(&int_val, arg, val_size);
1353         break;
1354     }
1355     case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): {
1356         bool wlfc_enab = FALSE;
1357         bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
1358         if (bcmerror != BCME_OK)
1359             goto exit;
1360 
1361         /* wlfc is already set as desired */
1362         if (wlfc_enab == (int_val == 0 ? FALSE : TRUE))
1363             goto exit;
1364 
1365         if (int_val == TRUE)
1366             bcmerror = dhd_wlfc_init(dhd_pub);
1367         else
1368             bcmerror = dhd_wlfc_deinit(dhd_pub);
1369 
1370         break;
1371     }
1372     case IOV_GVAL(IOV_PROPTXSTATUS_MODE):
1373         bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val);
1374         if (bcmerror != BCME_OK)
1375             goto exit;
1376         bcopy(&int_val, arg, val_size);
1377         break;
1378 
1379     case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
1380         dhd_wlfc_set_mode(dhd_pub, int_val);
1381         break;
1382 
1383     case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
1384         bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val);
1385         if (bcmerror != BCME_OK)
1386             goto exit;
1387         bcopy(&int_val, arg, val_size);
1388         break;
1389 
1390     case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
1391         dhd_wlfc_set_module_ignore(dhd_pub, int_val);
1392         break;
1393 
1394     case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
1395         bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val);
1396         if (bcmerror != BCME_OK)
1397             goto exit;
1398         bcopy(&int_val, arg, val_size);
1399         break;
1400 
1401     case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
1402         dhd_wlfc_set_credit_ignore(dhd_pub, int_val);
1403         break;
1404 
1405     case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
1406         bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val);
1407         if (bcmerror != BCME_OK)
1408             goto exit;
1409         bcopy(&int_val, arg, val_size);
1410         break;
1411 
1412     case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
1413         dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val);
1414         break;
1415 
1416     case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
1417         bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val);
1418         if (bcmerror != BCME_OK)
1419             goto exit;
1420         bcopy(&int_val, arg, val_size);
1421         break;
1422 
1423     case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
1424         dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val);
1425         break;
1426 
1427 #endif /* PROP_TXSTATUS */
1428 
1429     case IOV_GVAL(IOV_BUS_TYPE):
1430         /* The dhd application queries the driver to check if its usb or sdio.  */
1431 #ifdef BCMDBUS
1432         int_val = BUS_TYPE_USB;
1433 #endif /* BCMDBUS */
1434 #ifdef BCMSDIO
1435         int_val = BUS_TYPE_SDIO;
1436 #endif
1437 #ifdef PCIE_FULL_DONGLE
1438         int_val = BUS_TYPE_PCIE;
1439 #endif
1440         bcopy(&int_val, arg, val_size);
1441         break;
1442 
1443 
1444 #ifdef WLMEDIA_HTSF
1445     case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ):
1446         int_val = dhd_pub->htsfdlystat_sz;
1447         bcopy(&int_val, arg, val_size);
1448         break;
1449 
1450     case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ):
1451         dhd_pub->htsfdlystat_sz = int_val & 0xff;
1452         printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz);
1453         break;
1454 #endif
1455     case IOV_SVAL(IOV_CHANGEMTU):
1456         int_val &= 0xffff;
1457         bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
1458         break;
1459 
1460     case IOV_GVAL(IOV_HOSTREORDER_FLOWS):
1461     {
1462         uint i = 0;
1463         uint8 *ptr = (uint8 *)arg;
1464         uint8 count = 0;
1465 
1466         ptr++;
1467         for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) {
1468             if (dhd_pub->reorder_bufs[i] != NULL) {
1469                 *ptr = dhd_pub->reorder_bufs[i]->flow_id;
1470                 ptr++;
1471                 count++;
1472             }
1473         }
1474         ptr = (uint8 *)arg;
1475         *ptr = count;
1476         break;
1477     }
1478 #ifdef DHDTCPACK_SUPPRESS
1479     case IOV_GVAL(IOV_TCPACK_SUPPRESS): {
1480         int_val = (uint32)dhd_pub->tcpack_sup_mode;
1481         bcopy(&int_val, arg, val_size);
1482         break;
1483     }
1484     case IOV_SVAL(IOV_TCPACK_SUPPRESS): {
1485         bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val);
1486         break;
1487     }
1488 #endif /* DHDTCPACK_SUPPRESS */
1489 #ifdef DHD_WMF
1490     case IOV_GVAL(IOV_WMF_BSS_ENAB): {
1491         uint32    bssidx;
1492         dhd_wmf_t *wmf;
1493         const char *val;
1494 
1495         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1496             DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
1497             bcmerror = BCME_BADARG;
1498             break;
1499         }
1500 
1501         wmf = dhd_wmf_conf(dhd_pub, bssidx);
1502         int_val = wmf->wmf_enable ? 1 :0;
1503         bcopy(&int_val, arg, val_size);
1504         break;
1505     }
1506     case IOV_SVAL(IOV_WMF_BSS_ENAB): {
1507         /* Enable/Disable WMF */
1508         uint32    bssidx;
1509         dhd_wmf_t *wmf;
1510         const char *val;
1511 
1512         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1513             DHD_ERROR(("%s: wmf_bss_enable: bad parameter\n", __FUNCTION__));
1514             bcmerror = BCME_BADARG;
1515             break;
1516         }
1517 
1518         ASSERT(val);
1519         bcopy(val, &int_val, sizeof(uint32));
1520         wmf = dhd_wmf_conf(dhd_pub, bssidx);
1521         if (wmf->wmf_enable == int_val)
1522             break;
1523         if (int_val) {
1524             /* Enable WMF */
1525             if (dhd_wmf_instance_add(dhd_pub, bssidx) != BCME_OK) {
1526                 DHD_ERROR(("%s: Error in creating WMF instance\n",
1527                 __FUNCTION__));
1528                 break;
1529             }
1530             if (dhd_wmf_start(dhd_pub, bssidx) != BCME_OK) {
1531                 DHD_ERROR(("%s: Failed to start WMF\n", __FUNCTION__));
1532                 break;
1533             }
1534             wmf->wmf_enable = TRUE;
1535         } else {
1536             /* Disable WMF */
1537             wmf->wmf_enable = FALSE;
1538             dhd_wmf_stop(dhd_pub, bssidx);
1539             dhd_wmf_instance_del(dhd_pub, bssidx);
1540         }
1541         break;
1542     }
1543     case IOV_GVAL(IOV_WMF_UCAST_IGMP):
1544         int_val = dhd_pub->wmf_ucast_igmp ? 1 : 0;
1545         bcopy(&int_val, arg, val_size);
1546         break;
1547     case IOV_SVAL(IOV_WMF_UCAST_IGMP):
1548         if (dhd_pub->wmf_ucast_igmp == int_val)
1549             break;
1550 
1551         if (int_val >= OFF && int_val <= ON)
1552             dhd_pub->wmf_ucast_igmp = int_val;
1553         else
1554             bcmerror = BCME_RANGE;
1555         break;
1556     case IOV_GVAL(IOV_WMF_MCAST_DATA_SENDUP):
1557         int_val = dhd_wmf_mcast_data_sendup(dhd_pub, 0, FALSE, FALSE);
1558         bcopy(&int_val, arg, val_size);
1559         break;
1560     case IOV_SVAL(IOV_WMF_MCAST_DATA_SENDUP):
1561         dhd_wmf_mcast_data_sendup(dhd_pub, 0, TRUE, int_val);
1562         break;
1563 
1564 #ifdef WL_IGMP_UCQUERY
1565     case IOV_GVAL(IOV_WMF_UCAST_IGMP_QUERY):
1566         int_val = dhd_pub->wmf_ucast_igmp_query ? 1 : 0;
1567         bcopy(&int_val, arg, val_size);
1568         break;
1569     case IOV_SVAL(IOV_WMF_UCAST_IGMP_QUERY):
1570         if (dhd_pub->wmf_ucast_igmp_query == int_val)
1571             break;
1572 
1573         if (int_val >= OFF && int_val <= ON)
1574             dhd_pub->wmf_ucast_igmp_query = int_val;
1575         else
1576             bcmerror = BCME_RANGE;
1577         break;
1578 #endif /* WL_IGMP_UCQUERY */
1579 #ifdef DHD_UCAST_UPNP
1580     case IOV_GVAL(IOV_WMF_UCAST_UPNP):
1581         int_val = dhd_pub->wmf_ucast_upnp ? 1 : 0;
1582         bcopy(&int_val, arg, val_size);
1583         break;
1584     case IOV_SVAL(IOV_WMF_UCAST_UPNP):
1585         if (dhd_pub->wmf_ucast_upnp == int_val)
1586             break;
1587 
1588         if (int_val >= OFF && int_val <= ON)
1589             dhd_pub->wmf_ucast_upnp = int_val;
1590         else
1591             bcmerror = BCME_RANGE;
1592         break;
1593 #endif /* DHD_UCAST_UPNP */
1594 
1595     case IOV_GVAL(IOV_WMF_PSTA_DISABLE): {
1596         uint32    bssidx;
1597         const char *val;
1598 
1599         if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
1600             DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
1601             bcmerror = BCME_BADARG;
1602             break;
1603         }
1604 
1605         int_val = dhd_get_wmf_psta_disable(dhd_pub, bssidx);
1606         bcopy(&int_val, arg, val_size);
1607         break;
1608     }
1609 
1610     case IOV_SVAL(IOV_WMF_PSTA_DISABLE): {
1611         uint32    bssidx;
1612         const char *val;
1613 
1614         if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
1615             DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
1616             bcmerror = BCME_BADARG;
1617             break;
1618         }
1619 
1620         ASSERT(val);
1621         bcopy(val, &int_val, sizeof(uint32));
1622         dhd_set_wmf_psta_disable(dhd_pub, bssidx, int_val);
1623         break;
1624     }
1625 #endif /* DHD_WMF */
1626 
1627 #if defined(TRAFFIC_MGMT_DWM)
1628     case IOV_SVAL(IOV_TRAFFIC_MGMT_DWM): {
1629             trf_mgmt_filter_list_t   *trf_mgmt_filter_list =
1630                 (trf_mgmt_filter_list_t *)(arg);
1631             bcmerror = traffic_mgmt_add_dwm_filter(dhd_pub, trf_mgmt_filter_list, len);
1632         }
1633         break;
1634 #endif
1635 
1636 #ifdef DHD_L2_FILTER
1637     case IOV_GVAL(IOV_DHCP_UNICAST): {
1638         uint32 bssidx;
1639         const char *val;
1640         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1641             DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n",
1642                 __FUNCTION__, name));
1643             bcmerror = BCME_BADARG;
1644             break;
1645         }
1646         int_val = dhd_get_dhcp_unicast_status(dhd_pub, bssidx);
1647         memcpy(arg, &int_val, val_size);
1648         break;
1649     }
1650     case IOV_SVAL(IOV_DHCP_UNICAST): {
1651         uint32    bssidx;
1652         const char *val;
1653         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1654             DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n",
1655                 __FUNCTION__, name));
1656             bcmerror = BCME_BADARG;
1657             break;
1658         }
1659         memcpy(&int_val, val, sizeof(int_val));
1660         bcmerror = dhd_set_dhcp_unicast_status(dhd_pub, bssidx, int_val ? 1 : 0);
1661         break;
1662     }
1663     case IOV_GVAL(IOV_BLOCK_PING): {
1664         uint32 bssidx;
1665         const char *val;
1666 
1667         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1668             DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__));
1669             bcmerror = BCME_BADARG;
1670             break;
1671         }
1672         int_val = dhd_get_block_ping_status(dhd_pub, bssidx);
1673         memcpy(arg, &int_val, val_size);
1674         break;
1675     }
1676     case IOV_SVAL(IOV_BLOCK_PING): {
1677         uint32    bssidx;
1678         const char *val;
1679 
1680         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1681             DHD_ERROR(("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__));
1682             bcmerror = BCME_BADARG;
1683             break;
1684         }
1685         memcpy(&int_val, val, sizeof(int_val));
1686         bcmerror = dhd_set_block_ping_status(dhd_pub, bssidx, int_val ? 1 : 0);
1687         break;
1688     }
1689     case IOV_GVAL(IOV_PROXY_ARP): {
1690         uint32    bssidx;
1691         const char *val;
1692 
1693         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1694             DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__));
1695             bcmerror = BCME_BADARG;
1696             break;
1697         }
1698         int_val = dhd_get_parp_status(dhd_pub, bssidx);
1699         bcopy(&int_val, arg, val_size);
1700         break;
1701     }
1702     case IOV_SVAL(IOV_PROXY_ARP): {
1703         uint32    bssidx;
1704         const char *val;
1705 
1706         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1707             DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__));
1708             bcmerror = BCME_BADARG;
1709             break;
1710         }
1711         bcopy(val, &int_val, sizeof(int_val));
1712 
1713         /* Issue a iovar request to WL to update the proxy arp capability bit
1714          * in the Extended Capability IE of beacons/probe responses.
1715          */
1716         bcmerror = dhd_iovar(dhd_pub, bssidx, "proxy_arp_advertise", val, sizeof(int_val),
1717                 NULL, 0, TRUE);
1718         if (bcmerror == BCME_OK) {
1719             dhd_set_parp_status(dhd_pub, bssidx, int_val ? 1 : 0);
1720         }
1721         break;
1722     }
1723     case IOV_GVAL(IOV_GRAT_ARP): {
1724         uint32 bssidx;
1725         const char *val;
1726 
1727         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1728             DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__));
1729             bcmerror = BCME_BADARG;
1730             break;
1731         }
1732         int_val = dhd_get_grat_arp_status(dhd_pub, bssidx);
1733         memcpy(arg, &int_val, val_size);
1734         break;
1735     }
1736     case IOV_SVAL(IOV_GRAT_ARP): {
1737         uint32    bssidx;
1738         const char *val;
1739 
1740         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1741             DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__));
1742             bcmerror = BCME_BADARG;
1743             break;
1744         }
1745         memcpy(&int_val, val, sizeof(int_val));
1746         bcmerror = dhd_set_grat_arp_status(dhd_pub, bssidx, int_val ? 1 : 0);
1747         break;
1748     }
1749 #endif /* DHD_L2_FILTER */
1750     case IOV_SVAL(IOV_DHD_IE): {
1751         uint32    bssidx;
1752         const char *val;
1753 
1754         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1755             DHD_ERROR(("%s: dhd ie: bad parameter\n", __FUNCTION__));
1756             bcmerror = BCME_BADARG;
1757             break;
1758         }
1759 
1760         break;
1761     }
1762     case IOV_GVAL(IOV_AP_ISOLATE): {
1763         uint32    bssidx;
1764         const char *val;
1765 
1766         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1767             DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
1768             bcmerror = BCME_BADARG;
1769             break;
1770         }
1771 
1772         int_val = dhd_get_ap_isolate(dhd_pub, bssidx);
1773         bcopy(&int_val, arg, val_size);
1774         break;
1775     }
1776     case IOV_SVAL(IOV_AP_ISOLATE): {
1777         uint32    bssidx;
1778         const char *val;
1779 
1780         if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) != BCME_OK) {
1781             DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
1782             bcmerror = BCME_BADARG;
1783             break;
1784         }
1785 
1786         ASSERT(val);
1787         bcopy(val, &int_val, sizeof(uint32));
1788         dhd_set_ap_isolate(dhd_pub, bssidx, int_val);
1789         break;
1790     }
1791 #ifdef DHD_PSTA
1792     case IOV_GVAL(IOV_PSTA): {
1793         int_val = dhd_get_psta_mode(dhd_pub);
1794         bcopy(&int_val, arg, val_size);
1795         break;
1796         }
1797     case IOV_SVAL(IOV_PSTA): {
1798         if (int_val >= DHD_MODE_PSTA_DISABLED && int_val <= DHD_MODE_PSR) {
1799             dhd_set_psta_mode(dhd_pub, int_val);
1800         } else {
1801             bcmerror = BCME_RANGE;
1802         }
1803         break;
1804         }
1805 #endif /* DHD_PSTA */
1806 #ifdef DHD_WET
1807     case IOV_GVAL(IOV_WET):
1808          int_val = dhd_get_wet_mode(dhd_pub);
1809          bcopy(&int_val, arg, val_size);
1810          break;
1811 
1812     case IOV_SVAL(IOV_WET):
1813          if (int_val == 0 || int_val == 1) {
1814              dhd_set_wet_mode(dhd_pub, int_val);
1815              /* Delete the WET DB when disabled */
1816              if (!int_val) {
1817                  dhd_wet_sta_delete_list(dhd_pub);
1818              }
1819          } else {
1820              bcmerror = BCME_RANGE;
1821          }
1822                  break;
1823     case IOV_SVAL(IOV_WET_HOST_IPV4):
1824             dhd_set_wet_host_ipv4(dhd_pub, params, plen);
1825             break;
1826     case IOV_SVAL(IOV_WET_HOST_MAC):
1827             dhd_set_wet_host_mac(dhd_pub, params, plen);
1828         break;
1829 #endif /* DHD_WET */
1830 #ifdef DHD_MCAST_REGEN
1831     case IOV_GVAL(IOV_MCAST_REGEN_BSS_ENABLE): {
1832         uint32    bssidx;
1833         const char *val;
1834 
1835         if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
1836             DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__));
1837             bcmerror = BCME_BADARG;
1838             break;
1839         }
1840 
1841         int_val = dhd_get_mcast_regen_bss_enable(dhd_pub, bssidx);
1842         bcopy(&int_val, arg, val_size);
1843         break;
1844     }
1845 
1846     case IOV_SVAL(IOV_MCAST_REGEN_BSS_ENABLE): {
1847         uint32    bssidx;
1848         const char *val;
1849 
1850         if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) != BCME_OK) {
1851             DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n", __FUNCTION__));
1852             bcmerror = BCME_BADARG;
1853             break;
1854         }
1855 
1856         ASSERT(val);
1857         bcopy(val, &int_val, sizeof(uint32));
1858         dhd_set_mcast_regen_bss_enable(dhd_pub, bssidx, int_val);
1859         break;
1860     }
1861 #endif /* DHD_MCAST_REGEN */
1862 
1863     case IOV_GVAL(IOV_CFG80211_OPMODE): {
1864         int_val = (int32)dhd_pub->op_mode;
1865         bcopy(&int_val, arg, sizeof(int_val));
1866         break;
1867         }
1868     case IOV_SVAL(IOV_CFG80211_OPMODE): {
1869         if (int_val <= 0)
1870             bcmerror = BCME_BADARG;
1871         else
1872             dhd_pub->op_mode = int_val;
1873         break;
1874     }
1875 
1876     case IOV_GVAL(IOV_ASSERT_TYPE):
1877         int_val = g_assert_type;
1878         bcopy(&int_val, arg, val_size);
1879         break;
1880 
1881     case IOV_SVAL(IOV_ASSERT_TYPE):
1882         g_assert_type = (uint32)int_val;
1883         break;
1884 
1885 
1886 #if !defined(MACOSX_DHD)
1887     case IOV_GVAL(IOV_LMTEST): {
1888         *(uint32 *)arg = (uint32)lmtest;
1889         break;
1890     }
1891 
1892     case IOV_SVAL(IOV_LMTEST): {
1893         uint32 val = *(uint32 *)arg;
1894         if (val > 50)
1895             bcmerror = BCME_BADARG;
1896         else {
1897             lmtest = (uint)val;
1898             DHD_ERROR(("%s: lmtest %s\n",
1899                 __FUNCTION__, (lmtest == FALSE)? "OFF" : "ON"));
1900         }
1901         break;
1902     }
1903 #endif
1904 
1905 #ifdef SHOW_LOGTRACE
1906     case IOV_GVAL(IOV_DUMP_TRACE_LOG): {
1907         trace_buf_info_t *trace_buf_info;
1908 
1909         trace_buf_info = (trace_buf_info_t *)MALLOC(dhd_pub->osh,
1910                 sizeof(trace_buf_info_t));
1911         if (trace_buf_info != NULL) {
1912             dhd_get_read_buf_ptr(dhd_pub, trace_buf_info);
1913             memcpy((void*)arg, (void*)trace_buf_info, sizeof(trace_buf_info_t));
1914             MFREE(dhd_pub->osh, trace_buf_info, sizeof(trace_buf_info_t));
1915         } else {
1916             DHD_ERROR(("Memory allocation Failed\n"));
1917             bcmerror = BCME_NOMEM;
1918         }
1919         break;
1920     }
1921 #endif /* SHOW_LOGTRACE */
1922 #ifdef REPORT_FATAL_TIMEOUTS
1923     case IOV_GVAL(IOV_SCAN_TO): {
1924         dhd_get_scan_to_val(dhd_pub, (uint32 *)&int_val);
1925         bcopy(&int_val, arg, val_size);
1926         break;
1927     }
1928     case IOV_SVAL(IOV_SCAN_TO): {
1929         dhd_set_scan_to_val(dhd_pub, (uint32)int_val);
1930         break;
1931     }
1932     case IOV_GVAL(IOV_JOIN_TO): {
1933         dhd_get_join_to_val(dhd_pub, (uint32 *)&int_val);
1934         bcopy(&int_val, arg, val_size);
1935         break;
1936     }
1937     case IOV_SVAL(IOV_JOIN_TO): {
1938         dhd_set_join_to_val(dhd_pub, (uint32)int_val);
1939         break;
1940     }
1941     case IOV_GVAL(IOV_CMD_TO): {
1942         dhd_get_cmd_to_val(dhd_pub, (uint32 *)&int_val);
1943         bcopy(&int_val, arg, val_size);
1944         break;
1945     }
1946     case IOV_SVAL(IOV_CMD_TO): {
1947         dhd_set_cmd_to_val(dhd_pub, (uint32)int_val);
1948         break;
1949     }
1950     case IOV_GVAL(IOV_OQS_TO): {
1951         dhd_get_bus_to_val(dhd_pub, (uint32 *)&int_val);
1952         bcopy(&int_val, arg, val_size);
1953         break;
1954     }
1955     case IOV_SVAL(IOV_OQS_TO): {
1956         dhd_set_bus_to_val(dhd_pub, (uint32)int_val);
1957         break;
1958     }
1959 #endif /* REPORT_FATAL_TIMEOUTS */
1960 #ifdef DHD_DEBUG
1961 #if defined(BCMSDIO) || defined(BCMPCIE)
1962     case IOV_GVAL(IOV_DONGLE_TRAP_TYPE):
1963         if (dhd_pub->dongle_trap_occured)
1964             int_val = ltoh32(dhd_pub->last_trap_info.type);
1965         else
1966             int_val = 0;
1967         bcopy(&int_val, arg, val_size);
1968         break;
1969 
1970     case IOV_GVAL(IOV_DONGLE_TRAP_INFO):
1971     {
1972         struct bcmstrbuf strbuf;
1973         bcm_binit(&strbuf, arg, len);
1974         if (dhd_pub->dongle_trap_occured == FALSE) {
1975             bcm_bprintf(&strbuf, "no trap recorded\n");
1976             break;
1977         }
1978         dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf);
1979         break;
1980     }
1981 
1982     case IOV_GVAL(IOV_BPADDR):
1983         {
1984             sdreg_t sdreg;
1985             uint32 addr, size;
1986 
1987             memcpy(&sdreg, params, sizeof(sdreg));
1988 
1989             addr = sdreg.offset;
1990             size = sdreg.func;
1991 
1992             bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size,
1993                 (uint *)&int_val, TRUE);
1994 
1995             memcpy(arg, &int_val, sizeof(int32));
1996 
1997             break;
1998         }
1999 
2000     case IOV_SVAL(IOV_BPADDR):
2001         {
2002             sdreg_t sdreg;
2003             uint32 addr, size;
2004 
2005             memcpy(&sdreg, params, sizeof(sdreg));
2006 
2007             addr = sdreg.offset;
2008             size = sdreg.func;
2009 
2010             bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size,
2011                 (uint *)&sdreg.value,
2012                 FALSE);
2013 
2014             break;
2015         }
2016 #endif /* BCMSDIO || BCMPCIE */
2017     case IOV_SVAL(IOV_MEM_DEBUG):
2018         if (len > 0) {
2019             bcmerror = dhd_mem_debug(dhd_pub, arg, len - 1);
2020         }
2021         break;
2022 #endif /* DHD_DEBUG */
2023 #if defined(DHD_EFI) && defined(DHD_LOG_DUMP)
2024     case IOV_GVAL(IOV_LOG_CAPTURE_ENABLE):
2025         {
2026             int_val = dhd_pub->log_capture_enable;
2027             bcopy(&int_val, arg, val_size);
2028             break;
2029         }
2030 
2031     case IOV_SVAL(IOV_LOG_CAPTURE_ENABLE):
2032         {
2033             dhd_pub->log_capture_enable = (uint8)int_val;
2034             break;
2035         }
2036 
2037     case IOV_GVAL(IOV_LOG_DUMP):
2038         {
2039             dhd_prot_debug_info_print(dhd_pub);
2040             dhd_bus_mem_dump(dhd_pub);
2041             break;
2042         }
2043 #endif /* DHD_EFI && DHD_LOG_DUMP */
2044     default:
2045         bcmerror = BCME_UNSUPPORTED;
2046         break;
2047     }
2048 
2049 exit:
2050     DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
2051     return bcmerror;
2052 }
2053 
2054 /* Store the status of a connection attempt for later retrieval by an iovar */
2055 void
dhd_store_conn_status(uint32 event,uint32 status,uint32 reason)2056 dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
2057 {
2058     /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
2059      * because an encryption/rsn mismatch results in both events, and
2060      * the important information is in the WLC_E_PRUNE.
2061      */
2062     if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
2063           dhd_conn_event == WLC_E_PRUNE)) {
2064         dhd_conn_event = event;
2065         dhd_conn_status = status;
2066         dhd_conn_reason = reason;
2067     }
2068 }
2069 
2070 bool
dhd_prec_enq(dhd_pub_t * dhdp,struct pktq * q,void * pkt,int prec)2071 dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
2072 {
2073     void *p;
2074     int eprec = -1;        /* precedence to evict from */
2075     bool discard_oldest;
2076 
2077     /* Fast case, precedence queue is not full and we are also not
2078      * exceeding total queue length
2079      */
2080     if (!pktq_pfull(q, prec) && !pktq_full(q)) {
2081         pktq_penq(q, prec, pkt);
2082         return TRUE;
2083     }
2084 
2085     /* Determine precedence from which to evict packet, if any */
2086     if (pktq_pfull(q, prec))
2087         eprec = prec;
2088     else if (pktq_full(q)) {
2089         p = pktq_peek_tail(q, &eprec);
2090         ASSERT(p);
2091         if (eprec > prec || eprec < 0)
2092             return FALSE;
2093     }
2094 
2095     /* Evict if needed */
2096     if (eprec >= 0) {
2097         /* Detect queueing to unconfigured precedence */
2098         ASSERT(!pktq_pempty(q, eprec));
2099         discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
2100         if (eprec == prec && !discard_oldest)
2101             return FALSE;        /* refuse newer (incoming) packet */
2102         /* Evict packet according to discard policy */
2103         p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
2104         ASSERT(p);
2105 #ifdef DHDTCPACK_SUPPRESS
2106         if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) {
2107             DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2108                 __FUNCTION__, __LINE__));
2109             dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
2110         }
2111 #endif /* DHDTCPACK_SUPPRESS */
2112         PKTFREE(dhdp->osh, p, TRUE);
2113     }
2114 
2115     /* Enqueue */
2116     p = pktq_penq(q, prec, pkt);
2117     ASSERT(p);
2118 
2119     return TRUE;
2120 }
2121 
2122 /*
2123  * Functions to drop proper pkts from queue:
2124  *    If one pkt in queue is non-fragmented, drop first non-fragmented pkt only
2125  *    If all pkts in queue are all fragmented, find and drop one whole set fragmented pkts
2126  *    If can't find pkts matching upper 2 cases, drop first pkt anyway
2127  */
2128 bool
dhd_prec_drop_pkts(dhd_pub_t * dhdp,struct pktq * pq,int prec,f_droppkt_t fn)2129 dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec, f_droppkt_t fn)
2130 {
2131     struct pktq_prec *q = NULL;
2132     void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL, *prev_first = NULL;
2133     pkt_frag_t frag_info;
2134 
2135     ASSERT(dhdp && pq);
2136     ASSERT(prec >= 0 && prec < pq->num_prec);
2137 
2138     q = &pq->q[prec];
2139     p = q->head;
2140 
2141     if (p == NULL)
2142         return FALSE;
2143 
2144     while (p) {
2145         frag_info = pkt_frag_info(dhdp->osh, p);
2146         if (frag_info == DHD_PKT_FRAG_NONE) {
2147             break;
2148         } else if (frag_info == DHD_PKT_FRAG_FIRST) {
2149             if (first) {
2150                 /* No last frag pkt, use prev as last */
2151                 last = prev;
2152                 break;
2153             } else {
2154                 first = p;
2155                 prev_first = prev;
2156             }
2157         } else if (frag_info == DHD_PKT_FRAG_LAST) {
2158             if (first) {
2159                 last = p;
2160                 break;
2161             }
2162         }
2163 
2164         prev = p;
2165         p = PKTLINK(p);
2166     }
2167 
2168     if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) {
2169         /* Not found matching pkts, use oldest */
2170         prev = NULL;
2171         p = q->head;
2172         frag_info = 0;
2173     }
2174 
2175     if (frag_info == DHD_PKT_FRAG_NONE) {
2176         first = last = p;
2177         prev_first = prev;
2178     }
2179 
2180     p = first;
2181     while (p) {
2182         next = PKTLINK(p);
2183         q->len--;
2184         pq->len--;
2185 
2186         PKTSETLINK(p, NULL);
2187 
2188         if (fn)
2189             fn(dhdp, prec, p, TRUE);
2190 
2191         if (p == last)
2192             break;
2193 
2194         p = next;
2195     }
2196 
2197     if (prev_first == NULL) {
2198         if ((q->head = next) == NULL)
2199             q->tail = NULL;
2200     } else {
2201         PKTSETLINK(prev_first, next);
2202         if (!next)
2203             q->tail = prev_first;
2204     }
2205 
2206     return TRUE;
2207 }
2208 
2209 static int
dhd_iovar_op(dhd_pub_t * dhd_pub,const char * name,void * params,int plen,void * arg,int len,bool set)2210 dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name,
2211     void *params, int plen, void *arg, int len, bool set)
2212 {
2213     int bcmerror = 0;
2214     int val_size;
2215     const bcm_iovar_t *vi = NULL;
2216     uint32 actionid;
2217 
2218     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2219 
2220     ASSERT(name);
2221     ASSERT(len >= 0);
2222 
2223     /* Get MUST have return space */
2224     ASSERT(set || (arg && len));
2225 
2226     /* Set does NOT take qualifiers */
2227     ASSERT(!set || (!params && !plen));
2228 
2229     if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
2230         bcmerror = BCME_UNSUPPORTED;
2231         goto exit;
2232     }
2233 
2234     DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__,
2235         name, (set ? "set" : "get"), len, plen));
2236 
2237     /* set up 'params' pointer in case this is a set command so that
2238      * the convenience int and bool code can be common to set and get
2239      */
2240     if (params == NULL) {
2241         params = arg;
2242         plen = len;
2243     }
2244 
2245     if (vi->type == IOVT_VOID)
2246         val_size = 0;
2247     else if (vi->type == IOVT_BUFFER)
2248         val_size = len;
2249     else
2250         /* all other types are integer sized */
2251         val_size = sizeof(int);
2252 
2253     actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2254 
2255     bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size);
2256 
2257 exit:
2258     return bcmerror;
2259 }
2260 
2261 int
dhd_ioctl(dhd_pub_t * dhd_pub,dhd_ioctl_t * ioc,void * buf,uint buflen)2262 dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
2263 {
2264     int bcmerror = 0;
2265     unsigned long flags;
2266 
2267     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2268 
2269     if (!buf) {
2270         return BCME_BADARG;
2271     }
2272 
2273     dhd_os_dhdiovar_lock(dhd_pub);
2274     switch (ioc->cmd) {
2275         case DHD_GET_MAGIC:
2276             if (buflen < sizeof(int))
2277                 bcmerror = BCME_BUFTOOSHORT;
2278             else
2279                 *(int*)buf = DHD_IOCTL_MAGIC;
2280             break;
2281 
2282         case DHD_GET_VERSION:
2283             if (buflen < sizeof(int))
2284                 bcmerror = BCME_BUFTOOSHORT;
2285             else
2286                 *(int*)buf = DHD_IOCTL_VERSION;
2287             break;
2288 
2289         case DHD_GET_VAR:
2290         case DHD_SET_VAR:
2291             {
2292                 char *arg;
2293                 uint arglen;
2294 
2295                 DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2296                 if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) {
2297                     /* In platforms like FC19, the FW download is done via IOCTL
2298                      * and should not return error for IOCTLs fired before FW
2299                      * Download is done
2300                      */
2301                     if (dhd_fw_download_status(dhd_pub)) {
2302                         DHD_ERROR(("%s: returning as busstate=%d\n",
2303                                 __FUNCTION__, dhd_pub->busstate));
2304                         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2305                         dhd_os_dhdiovar_unlock(dhd_pub);
2306                         return -ENODEV;
2307                     }
2308                 }
2309                 DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhd_pub);
2310                 DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2311 
2312 #ifdef DHD_PCIE_RUNTIMEPM
2313                 dhdpcie_runtime_bus_wake(dhd_pub, TRUE, dhd_ioctl);
2314 #endif /* DHD_PCIE_RUNTIMEPM */
2315 
2316                 DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2317                 if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) {
2318                     /* If Suspend/Resume is tested via pcie_suspend IOVAR
2319                      * then continue to execute the IOVAR, return from here for
2320                      * other IOVARs, also include pciecfgreg and devreset to go
2321                      * through.
2322                      */
2323 #ifdef DHD_EFI
2324                     if (bcmstricmp((char *)buf, "pcie_suspend") &&
2325                         bcmstricmp((char *)buf, "pciecfgreg") &&
2326                         bcmstricmp((char *)buf, "devreset") &&
2327                         bcmstricmp((char *)buf, "sdio_suspend") &&
2328                         bcmstricmp((char *)buf, "control_signal"))
2329 #else
2330                     if (bcmstricmp((char *)buf, "pcie_suspend") &&
2331                         bcmstricmp((char *)buf, "pciecfgreg") &&
2332                         bcmstricmp((char *)buf, "devreset") &&
2333                         bcmstricmp((char *)buf, "sdio_suspend"))
2334 #endif /* DHD_EFI */
2335                     {
2336                         DHD_ERROR(("%s: bus is in suspend(%d)"
2337                             "or suspending(0x%x) state\n",
2338                             __FUNCTION__, dhd_pub->busstate,
2339                             dhd_pub->dhd_bus_busy_state));
2340                         DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2341                         dhd_os_busbusy_wake(dhd_pub);
2342                         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2343                         dhd_os_dhdiovar_unlock(dhd_pub);
2344                         return -ENODEV;
2345                     }
2346                 }
2347                 /* During devreset ioctl, we call dhdpcie_advertise_bus_cleanup,
2348                  * which will wait for all the busy contexts to get over for
2349                  * particular time and call ASSERT if timeout happens. As during
2350                  * devreset ioctal, we made DHD_BUS_BUSY_SET_IN_DHD_IOVAR,
2351                  * to avoid ASSERT, clear the IOCTL busy state. "devreset" ioctl is
2352                  * not used in Production platforms but only used in FC19 setups.
2353                  */
2354                 if (!bcmstricmp((char *)buf, "devreset")) {
2355                     DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2356                 }
2357                 DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2358 
2359                 /* scan past the name to any arguments */
2360                 for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--)
2361                     ;
2362 
2363                 if (*arg) {
2364                     bcmerror = BCME_BUFTOOSHORT;
2365                     goto unlock_exit;
2366                 }
2367 
2368                 /* account for the NUL terminator */
2369                 arg++, arglen--;
2370                 /* call with the appropriate arguments */
2371                 if (ioc->cmd == DHD_GET_VAR) {
2372                     bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen,
2373                             buf, buflen, IOV_GET);
2374                 } else {
2375                     bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0,
2376                             arg, arglen, IOV_SET);
2377                 }
2378                 if (bcmerror != BCME_UNSUPPORTED) {
2379                     goto unlock_exit;
2380                 }
2381 
2382                 /* not in generic table, try protocol module */
2383                 if (ioc->cmd == DHD_GET_VAR) {
2384                     bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg,
2385                             arglen, buf, buflen, IOV_GET);
2386                 } else {
2387                     bcmerror = dhd_prot_iovar_op(dhd_pub, buf,
2388                             NULL, 0, arg, arglen, IOV_SET);
2389                 }
2390                 if (bcmerror != BCME_UNSUPPORTED) {
2391                     goto unlock_exit;
2392                 }
2393 
2394                 /* if still not found, try bus module */
2395                 if (ioc->cmd == DHD_GET_VAR) {
2396                     bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
2397                             arg, arglen, buf, buflen, IOV_GET);
2398                 } else {
2399                     bcmerror = dhd_bus_iovar_op(dhd_pub, buf,
2400                             NULL, 0, arg, arglen, IOV_SET);
2401                 }
2402                 if (bcmerror != BCME_UNSUPPORTED) {
2403                     goto unlock_exit;
2404                 }
2405 
2406 #ifdef DHD_TIMESYNC
2407                 /* check TS module */
2408                 if (ioc->cmd == DHD_GET_VAR)
2409                     bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf, arg,
2410                         arglen, buf, buflen, IOV_GET);
2411                 else
2412                     bcmerror = dhd_timesync_iovar_op(dhd_pub->ts, buf,
2413                         NULL, 0, arg, arglen, IOV_SET);
2414 #endif /* DHD_TIMESYNC */
2415             }
2416             goto unlock_exit;
2417 
2418         default:
2419             bcmerror = BCME_UNSUPPORTED;
2420     }
2421     dhd_os_dhdiovar_unlock(dhd_pub);
2422     return bcmerror;
2423 
2424 unlock_exit:
2425     DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2426     DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2427     dhd_os_busbusy_wake(dhd_pub);
2428     DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2429     dhd_os_dhdiovar_unlock(dhd_pub);
2430     return bcmerror;
2431 }
2432 
2433 #ifdef SHOW_EVENTS
2434 static void
wl_show_host_event(dhd_pub_t * dhd_pub,wl_event_msg_t * event,void * event_data,void * raw_event_ptr,char * eventmask)2435 wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event, void *event_data,
2436     void *raw_event_ptr, char *eventmask)
2437 {
2438     uint i, status, reason;
2439     bool group = FALSE, flush_txq = FALSE, link = FALSE;
2440     bool host_data = FALSE; /* prints  event data after the case  when set */
2441     const char *auth_str;
2442     const char *event_name;
2443     uchar *buf;
2444     char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
2445     uint event_type, flags, auth_type, datalen;
2446 
2447     event_type = ntoh32(event->event_type);
2448     flags = ntoh16(event->flags);
2449     status = ntoh32(event->status);
2450     reason = ntoh32(event->reason);
2451     BCM_REFERENCE(reason);
2452     auth_type = ntoh32(event->auth_type);
2453     datalen = ntoh32(event->datalen);
2454 
2455     /* debug dump of event messages */
2456     snprintf(eabuf, sizeof(eabuf), "%02x:%02x:%02x:%02x:%02x:%02x",
2457             (uchar)event->addr.octet[0]&0xff,
2458             (uchar)event->addr.octet[1]&0xff,
2459             (uchar)event->addr.octet[2]&0xff,
2460             (uchar)event->addr.octet[3]&0xff,
2461             (uchar)event->addr.octet[4]&0xff,
2462             (uchar)event->addr.octet[5]&0xff);
2463 
2464     event_name = bcmevent_get_name(event_type);
2465     BCM_REFERENCE(event_name);
2466 
2467     if (flags & WLC_EVENT_MSG_LINK)
2468         link = TRUE;
2469     if (flags & WLC_EVENT_MSG_GROUP)
2470         group = TRUE;
2471     if (flags & WLC_EVENT_MSG_FLUSHTXQ)
2472         flush_txq = TRUE;
2473 
2474     switch (event_type) {
2475     case WLC_E_START:
2476     case WLC_E_DEAUTH:
2477     case WLC_E_DISASSOC:
2478         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2479         break;
2480 
2481     case WLC_E_ASSOC_IND:
2482     case WLC_E_REASSOC_IND:
2483 
2484         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2485         break;
2486 
2487     case WLC_E_ASSOC:
2488     case WLC_E_REASSOC:
2489         if (status == WLC_E_STATUS_SUCCESS) {
2490             DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
2491         } else if (status == WLC_E_STATUS_TIMEOUT) {
2492             DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
2493         } else if (status == WLC_E_STATUS_FAIL) {
2494             DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
2495                    event_name, eabuf, (int)reason));
2496         } else {
2497             DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
2498                    event_name, eabuf, (int)status));
2499         }
2500         break;
2501 
2502     case WLC_E_DEAUTH_IND:
2503     case WLC_E_DISASSOC_IND:
2504         DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason));
2505         break;
2506 
2507     case WLC_E_AUTH:
2508     case WLC_E_AUTH_IND:
2509         if (auth_type == DOT11_OPEN_SYSTEM)
2510             auth_str = "Open System";
2511         else if (auth_type == DOT11_SHARED_KEY)
2512             auth_str = "Shared Key";
2513         else {
2514             snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d", (int)auth_type);
2515             auth_str = err_msg;
2516         }
2517 
2518     if (event_type == WLC_E_AUTH_IND) {
2519             DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str));
2520         } else if (status == WLC_E_STATUS_SUCCESS) {
2521             DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n",
2522                 event_name, eabuf, auth_str));
2523         } else if (status == WLC_E_STATUS_TIMEOUT) {
2524             DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
2525                 event_name, eabuf, auth_str));
2526         } else if (status == WLC_E_STATUS_FAIL) {
2527             DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
2528                    event_name, eabuf, auth_str, (int)reason));
2529         }
2530         BCM_REFERENCE(auth_str);
2531 
2532         break;
2533 
2534     case WLC_E_JOIN:
2535     case WLC_E_ROAM:
2536     case WLC_E_SET_SSID:
2537         if (status == WLC_E_STATUS_SUCCESS) {
2538             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2539 #ifdef REPORT_FATAL_TIMEOUTS
2540             dhd_clear_join_error(dhd_pub, WLC_SSID_MASK);
2541 #endif /* REPORT_FATAL_TIMEOUTS */
2542         } else {
2543 #ifdef REPORT_FATAL_TIMEOUTS
2544             dhd_set_join_error(dhd_pub, WLC_SSID_MASK);
2545 #endif /* REPORT_FATAL_TIMEOUTS */
2546             if (status == WLC_E_STATUS_FAIL) {
2547                 DHD_EVENT(("MACEVENT: %s, failed\n", event_name));
2548             } else if (status == WLC_E_STATUS_NO_NETWORKS) {
2549                 DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name));
2550             } else {
2551                 DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
2552                     event_name, (int)status));
2553             }
2554         }
2555         break;
2556 
2557     case WLC_E_BEACON_RX:
2558         if (status == WLC_E_STATUS_SUCCESS) {
2559             DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
2560         } else if (status == WLC_E_STATUS_FAIL) {
2561             DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
2562         } else {
2563             DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
2564         }
2565         break;
2566 
2567     case WLC_E_LINK:
2568         DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN"));
2569         BCM_REFERENCE(link);
2570         break;
2571 
2572     case WLC_E_MIC_ERROR:
2573         DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
2574                event_name, eabuf, group, flush_txq));
2575         BCM_REFERENCE(group);
2576         BCM_REFERENCE(flush_txq);
2577         break;
2578 
2579     case WLC_E_ICV_ERROR:
2580     case WLC_E_UNICAST_DECODE_ERROR:
2581     case WLC_E_MULTICAST_DECODE_ERROR:
2582         DHD_EVENT(("MACEVENT: %s, MAC %s\n",
2583                event_name, eabuf));
2584         break;
2585 
2586     case WLC_E_TXFAIL:
2587         DHD_EVENT(("MACEVENT: %s, RA %s status %d\n", event_name, eabuf, status));
2588         break;
2589 
2590     case WLC_E_ASSOC_REQ_IE:
2591     case WLC_E_ASSOC_RESP_IE:
2592     case WLC_E_PMKID_CACHE:
2593         DHD_EVENT(("MACEVENT: %s\n", event_name));
2594         break;
2595 
2596     case WLC_E_SCAN_COMPLETE:
2597         DHD_EVENT(("MACEVENT: %s\n", event_name));
2598 #ifdef REPORT_FATAL_TIMEOUTS
2599         dhd_stop_scan_timer(dhd_pub);
2600 #endif /* REPORT_FATAL_TIMEOUTS */
2601         break;
2602     case WLC_E_RSSI_LQM:
2603     case WLC_E_PFN_NET_FOUND:
2604     case WLC_E_PFN_NET_LOST:
2605     case WLC_E_PFN_SCAN_COMPLETE:
2606     case WLC_E_PFN_SCAN_NONE:
2607     case WLC_E_PFN_SCAN_ALLGONE:
2608     case WLC_E_PFN_GSCAN_FULL_RESULT:
2609     case WLC_E_PFN_SSID_EXT:
2610         DHD_EVENT(("PNOEVENT: %s\n", event_name));
2611         break;
2612 
2613     case WLC_E_PSK_SUP:
2614     case WLC_E_PRUNE:
2615         DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n",
2616                    event_name, (int)status, (int)reason));
2617 #ifdef REPORT_FATAL_TIMEOUTS
2618         if ((status == WLC_E_STATUS_SUCCESS || status == WLC_E_STATUS_UNSOLICITED) &&
2619                 (reason == WLC_E_SUP_OTHER)) {
2620             dhd_clear_join_error(dhd_pub, WLC_WPA_MASK);
2621         } else {
2622             dhd_set_join_error(dhd_pub, WLC_WPA_MASK);
2623         }
2624 #endif /* REPORT_FATAL_TIMEOUTS */
2625         break;
2626 
2627 #ifdef WIFI_ACT_FRAME
2628     case WLC_E_ACTION_FRAME:
2629         DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
2630         break;
2631 #endif /* WIFI_ACT_FRAME */
2632 
2633 #ifdef SHOW_LOGTRACE
2634     case WLC_E_TRACE:
2635         DHD_EVENT(("MACEVENT: %s Logtrace\n", event_name));
2636         dhd_dbg_trace_evnt_handler(dhd_pub, event_data, raw_event_ptr, datalen);
2637         break;
2638 #endif /* SHOW_LOGTRACE */
2639 
2640     case WLC_E_RSSI:
2641         DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data))));
2642         break;
2643 
2644     case WLC_E_SERVICE_FOUND:
2645     case WLC_E_P2PO_ADD_DEVICE:
2646     case WLC_E_P2PO_DEL_DEVICE:
2647         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2648         break;
2649 
2650 #ifdef BT_WIFI_HANDOBER
2651     case WLC_E_BT_WIFI_HANDOVER_REQ:
2652         DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2653         break;
2654 #endif
2655 
2656     case WLC_E_CCA_CHAN_QUAL:
2657         if (datalen) {
2658             buf = (uchar *) event_data;
2659             DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d, "
2660                 "channel 0x%02x \n", event_name, event_type, eabuf, (int)status,
2661                 (int)reason, (int)auth_type, *(buf + 4)));
2662         }
2663         break;
2664     case WLC_E_ESCAN_RESULT:
2665     {
2666         DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d \n",
2667                event_name, event_type, eabuf, (int)status));
2668     }
2669         break;
2670     case WLC_E_PSK_AUTH:
2671         DHD_EVENT(("MACEVENT: %s, RA %s status %d Reason:%d\n",
2672         event_name, eabuf, status, reason));
2673         break;
2674     case WLC_E_IF:
2675     {
2676         struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data;
2677         BCM_REFERENCE(ifevent);
2678 
2679         DHD_EVENT(("MACEVENT: %s, opcode:0x%d  ifidx:%d\n",
2680         event_name, ifevent->opcode, ifevent->ifidx));
2681         break;
2682     }
2683 
2684 #ifdef SHOW_LOGTRACE
2685     case WLC_E_MSCH:
2686     {
2687         wl_mschdbg_event_handler(dhd_pub, raw_event_ptr, reason, event_data, datalen);
2688         break;
2689     }
2690 #endif /* SHOW_LOGTRACE */
2691 
2692     default:
2693         DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
2694                event_name, event_type, eabuf, (int)status, (int)reason,
2695                (int)auth_type));
2696         break;
2697     }
2698 
2699     /* show any appended data if message level is set to bytes or host_data is set */
2700     if ((DHD_BYTES_ON() || (host_data == TRUE)) && DHD_EVENT_ON() && datalen) {
2701         buf = (uchar *) event_data;
2702         BCM_REFERENCE(buf);
2703         DHD_EVENT((" data (%d) : ", datalen));
2704         for (i = 0; i < datalen; i++) {
2705             DHD_EVENT((" 0x%02x ", buf[i]));
2706         }
2707         DHD_EVENT(("\n"));
2708     }
2709 }
2710 #endif /* SHOW_EVENTS */
2711 
2712 #ifdef DNGL_EVENT_SUPPORT
2713 /* Check whether packet is a BRCM dngl event pkt. If it is, process event data. */
2714 int
dngl_host_event(dhd_pub_t * dhdp,void * pktdata,bcm_dngl_event_msg_t * dngl_event,size_t pktlen)2715 dngl_host_event(dhd_pub_t *dhdp, void *pktdata, bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
2716 {
2717     bcm_dngl_event_t *pvt_data = (bcm_dngl_event_t *)pktdata;
2718 
2719     dngl_host_event_process(dhdp, pvt_data, dngl_event, pktlen);
2720     return BCME_OK;
2721 }
2722 
2723 void
dngl_host_event_process(dhd_pub_t * dhdp,bcm_dngl_event_t * event,bcm_dngl_event_msg_t * dngl_event,size_t pktlen)2724 dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
2725     bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
2726 {
2727     uint8 *p = (uint8 *)(event + 1);
2728     uint16 type = ntoh16_ua((void *)&dngl_event->event_type);
2729     uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen);
2730     uint16 version = ntoh16_ua((void *)&dngl_event->version);
2731 
2732     DHD_EVENT(("VERSION:%d, EVENT TYPE:%d, DATALEN:%d\n", version, type, datalen));
2733     if (datalen > (pktlen - sizeof(bcm_dngl_event_t) + ETHER_TYPE_LEN)) {
2734         return;
2735     }
2736     if (version != BCM_DNGL_EVENT_MSG_VERSION) {
2737         DHD_ERROR(("%s:version mismatch:%d:%d\n", __FUNCTION__,
2738             version, BCM_DNGL_EVENT_MSG_VERSION));
2739         return;
2740     }
2741     switch (type) {
2742        case DNGL_E_SOCRAM_IND:
2743         {
2744            bcm_dngl_socramind_t *socramind_ptr = (bcm_dngl_socramind_t *)p;
2745            uint16 tag = ltoh32(socramind_ptr->tag);
2746            uint16 taglen = ltoh32(socramind_ptr->length);
2747            p = (uint8 *)socramind_ptr->value;
2748            DHD_EVENT(("Tag:%d Len:%d Datalen:%d\n", tag, taglen, datalen));
2749            switch (tag) {
2750             case SOCRAM_IND_ASSERT_TAG:
2751                 {
2752                 /*
2753                 * The payload consists of -
2754                 * null terminated function name padded till 32 bit boundary +
2755                 * Line number - (32 bits)
2756                 * Caller address (32 bits)
2757                 */
2758                 char *fnname = (char *)p;
2759                 if (datalen < (ROUNDUP(strlen(fnname) + 1, sizeof(uint32)) +
2760                     sizeof(uint32) * 2)) {
2761                     DHD_ERROR(("Wrong length:%d\n", datalen));
2762                     return;
2763                 }
2764                 DHD_EVENT(("ASSRT Function:%s ", p));
2765                 p += ROUNDUP(strlen(p) + 1, sizeof(uint32));
2766                 DHD_EVENT(("Line:%d ", *(uint32 *)p));
2767                 p += sizeof(uint32);
2768                 DHD_EVENT(("Caller Addr:0x%x\n", *(uint32 *)p));
2769                 break;
2770                 }
2771             case SOCRAM_IND_TAG_HEALTH_CHECK:
2772                {
2773                 bcm_dngl_healthcheck_t *dngl_hc = (bcm_dngl_healthcheck_t *)p;
2774                 DHD_EVENT(("SOCRAM_IND_HEALTHCHECK_TAG:%d Len:%d\n",
2775                 ltoh32(dngl_hc->top_module_tag), ltoh32(dngl_hc->top_module_len)));
2776                 if (DHD_EVENT_ON()) {
2777                     prhex("HEALTHCHECK", p, ltoh32(dngl_hc->top_module_len));
2778                 }
2779                 p = (uint8 *)dngl_hc->value;
2780 
2781                 switch (ltoh32(dngl_hc->top_module_tag)) {
2782                     case HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE:
2783                        {
2784                         bcm_dngl_pcie_hc_t *pcie_hc;
2785                         pcie_hc = (bcm_dngl_pcie_hc_t *)p;
2786                         BCM_REFERENCE(pcie_hc);
2787                         if (ltoh32(dngl_hc->top_module_len) <
2788                                 sizeof(bcm_dngl_pcie_hc_t)) {
2789                             DHD_ERROR(("Wrong length:%d\n",
2790                                 ltoh32(dngl_hc->top_module_len)));
2791                             return;
2792                         }
2793                         DHD_EVENT(("%d:PCIE HC error:%d flag:0x%x,"
2794                             " control:0x%x\n",
2795                             ltoh32(pcie_hc->version),
2796                             ltoh32(pcie_hc->pcie_err_ind_type),
2797                             ltoh32(pcie_hc->pcie_flag),
2798                             ltoh32(pcie_hc->pcie_control_reg)));
2799                         break;
2800                        }
2801                     default:
2802                         DHD_ERROR(("%s:Unknown module TAG:%d\n",
2803                           __FUNCTION__,
2804                           ltoh32(dngl_hc->top_module_tag)));
2805                         break;
2806                 }
2807                 break;
2808                }
2809             default:
2810                DHD_ERROR(("%s:Unknown TAG", __FUNCTION__));
2811                if (p && DHD_EVENT_ON()) {
2812                    prhex("SOCRAMIND", p, taglen);
2813                }
2814                break;
2815            }
2816            break;
2817         }
2818        default:
2819         DHD_ERROR(("%s:Unknown DNGL Event Type:%d", __FUNCTION__, type));
2820         if (p && DHD_EVENT_ON()) {
2821             prhex("SOCRAMIND", p, datalen);
2822         }
2823         break;
2824     }
2825 #ifdef DHD_FW_COREDUMP
2826     dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT;
2827 #endif /* DHD_FW_COREDUMP */
2828 #ifndef BCMDBUS
2829     if (dhd_socram_dump(dhdp->bus)) {
2830         DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__));
2831     } else {
2832         /* Notify framework */
2833         dhd_dbg_send_urgent_evt(dhdp, p, datalen);
2834     }
2835 #endif /* !BCMDBUS */
2836 }
2837 #endif /* DNGL_EVENT_SUPPORT */
2838 
2839 /* Stub for now. Will become real function as soon as shim
2840  * is being integrated to Android, Linux etc.
2841  */
2842 int
wl_event_process_default(wl_event_msg_t * event,struct wl_evt_pport * evt_pport)2843 wl_event_process_default(wl_event_msg_t *event, struct wl_evt_pport *evt_pport)
2844 {
2845     return BCME_OK;
2846 }
2847 
2848 int
wl_event_process(dhd_pub_t * dhd_pub,int * ifidx,void * pktdata,uint pktlen,void ** data_ptr,void * raw_event)2849 wl_event_process(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
2850     uint pktlen, void **data_ptr, void *raw_event)
2851 {
2852     wl_evt_pport_t evt_pport;
2853     wl_event_msg_t event;
2854     bcm_event_msg_u_t evu;
2855     int ret;
2856 
2857     /* make sure it is a BRCM event pkt and record event data */
2858     ret = wl_host_event_get_data(pktdata, pktlen, &evu);
2859     if (ret != BCME_OK) {
2860         return ret;
2861     }
2862 
2863     memcpy(&event, &evu.event, sizeof(wl_event_msg_t));
2864 
2865     /* convert event from network order to host order */
2866     wl_event_to_host_order(&event);
2867 
2868     /* record event params to evt_pport */
2869     evt_pport.dhd_pub = dhd_pub;
2870     evt_pport.ifidx = ifidx;
2871     evt_pport.pktdata = pktdata;
2872     evt_pport.data_ptr = data_ptr;
2873     evt_pport.raw_event = raw_event;
2874     evt_pport.data_len = pktlen;
2875 
2876 #if defined(WL_WLC_SHIM) && defined(WL_WLC_SHIM_EVENTS)
2877     {
2878         struct wl_shim_node *shim = dhd_pub_shim(dhd_pub);
2879         if (shim) {
2880             ret = wl_shim_event_process(shim, &event, &evt_pport);
2881         } else {
2882             /* events can come even before shim is initialized
2883              (when waiting for "wlc_ver" response)
2884              * handle them in a non-shim way.
2885              */
2886             DHD_ERROR(("%s: Events coming before shim initialization!\n",
2887                 __FUNCTION__));
2888             ret = wl_event_process_default(&event, &evt_pport);
2889         }
2890     }
2891 #else
2892     ret = wl_event_process_default(&event, &evt_pport);
2893 #endif /* WL_WLC_SHIM && WL_WLC_SHIM_EVENTS */
2894 
2895     return ret;
2896 }
2897 
2898 /* Check whether packet is a BRCM event pkt. If it is, record event data. */
2899 int
wl_host_event_get_data(void * pktdata,uint pktlen,bcm_event_msg_u_t * evu)2900 wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu)
2901 {
2902     int ret;
2903 
2904     ret = is_wlc_event_frame(pktdata, pktlen, 0, evu);
2905     if (ret != BCME_OK) {
2906         DHD_ERROR(("%s: Invalid event frame, err = %d\n",
2907             __FUNCTION__, ret));
2908     }
2909 
2910     return ret;
2911 }
2912 
2913 int
wl_process_host_event(dhd_pub_t * dhd_pub,int * ifidx,void * pktdata,uint pktlen,wl_event_msg_t * event,void ** data_ptr,void * raw_event)2914 wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen,
2915     wl_event_msg_t *event, void **data_ptr, void *raw_event)
2916 {
2917     bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
2918     bcm_event_msg_u_t evu;
2919     uint8 *event_data;
2920     uint32 type, status, datalen;
2921     uint16 flags;
2922     uint evlen;
2923     int ret;
2924     uint16 usr_subtype;
2925     char macstr[ETHER_ADDR_STR_LEN];
2926 
2927     BCM_REFERENCE(macstr);
2928 
2929     ret = wl_host_event_get_data(pktdata, pktlen, &evu);
2930     if (ret != BCME_OK) {
2931         return ret;
2932     }
2933 
2934     usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype);
2935     switch (usr_subtype) {
2936     case BCMILCP_BCM_SUBTYPE_EVENT:
2937         memcpy(event, &evu.event, sizeof(wl_event_msg_t));
2938         *data_ptr = &pvt_data[1];
2939         break;
2940     case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
2941 #ifdef DNGL_EVENT_SUPPORT
2942         /* If it is a DNGL event process it first */
2943         if (dngl_host_event(dhd_pub, pktdata, &evu.dngl_event, pktlen) == BCME_OK) {
2944             /*
2945              * Return error purposely to prevent DNGL event being processed
2946              * as BRCM event
2947              */
2948             return BCME_ERROR;
2949         }
2950 #endif /* DNGL_EVENT_SUPPORT */
2951         return BCME_NOTFOUND;
2952     default:
2953         return BCME_NOTFOUND;
2954     }
2955 
2956     /* start wl_event_msg process */
2957     event_data = *data_ptr;
2958     type = ntoh32_ua((void *)&event->event_type);
2959     flags = ntoh16_ua((void *)&event->flags);
2960     status = ntoh32_ua((void *)&event->status);
2961     datalen = ntoh32_ua((void *)&event->datalen);
2962     evlen = datalen + sizeof(bcm_event_t);
2963 
2964     switch (type) {
2965 #ifdef PROP_TXSTATUS
2966     case WLC_E_FIFO_CREDIT_MAP:
2967         dhd_wlfc_enable(dhd_pub);
2968         dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data);
2969         WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
2970             "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1],
2971             event_data[2],
2972             event_data[3], event_data[4], event_data[5]));
2973         break;
2974 
2975     case WLC_E_BCMC_CREDIT_SUPPORT:
2976         dhd_wlfc_BCMCCredit_support_event(dhd_pub);
2977         break;
2978 #ifdef LIMIT_BORROW
2979     case WLC_E_ALLOW_CREDIT_BORROW:
2980         dhd_wlfc_disable_credit_borrow_event(dhd_pub, event_data);
2981         break;
2982 #endif /* LIMIT_BORROW */
2983 #endif /* PROP_TXSTATUS */
2984 
2985 
2986     case WLC_E_ULP:
2987 #ifdef DHD_ULP
2988     {
2989         wl_ulp_event_t *ulp_evt = (wl_ulp_event_t *)event_data;
2990 
2991         /* Flush and disable console messages */
2992         if (ulp_evt->ulp_dongle_action == WL_ULP_DISABLE_CONSOLE) {
2993 #ifdef DHD_ULP_NOT_USED
2994             dhd_bus_ulp_disable_console(dhd_pub);
2995 #endif /* DHD_ULP_NOT_USED */
2996         }
2997         if (ulp_evt->ulp_dongle_action == WL_ULP_UCODE_DOWNLOAD) {
2998             dhd_bus_ucode_download(dhd_pub->bus);
2999         }
3000     }
3001 #endif /* DHD_ULP */
3002         break;
3003     case WLC_E_TDLS_PEER_EVENT:
3004 #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
3005         {
3006             dhd_tdls_event_handler(dhd_pub, event);
3007         }
3008 #endif
3009         break;
3010 
3011     case WLC_E_IF:
3012         {
3013         struct wl_event_data_if *ifevent = (struct wl_event_data_if *)event_data;
3014 
3015         /* Ignore the event if NOIF is set */
3016         if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) {
3017             DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
3018             return (BCME_UNSUPPORTED);
3019         }
3020 #ifdef PCIE_FULL_DONGLE
3021         dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx,
3022             ifevent->opcode, ifevent->role);
3023 #endif
3024 #ifdef PROP_TXSTATUS
3025         {
3026             uint8* ea = pvt_data->eth.ether_dhost;
3027             WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, "
3028                           "[%02x:%02x:%02x:%02x:%02x:%02x]\n",
3029                           ifevent->ifidx,
3030                           ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD":"DEL"),
3031                           ((ifevent->role == 0) ? "STA":"AP "),
3032                           ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]));
3033             (void)ea;
3034 
3035             if (ifevent->opcode == WLC_E_IF_CHANGE)
3036                 dhd_wlfc_interface_event(dhd_pub,
3037                     eWLFC_MAC_ENTRY_ACTION_UPDATE,
3038                     ifevent->ifidx, ifevent->role, ea);
3039             else
3040                 dhd_wlfc_interface_event(dhd_pub,
3041                     ((ifevent->opcode == WLC_E_IF_ADD) ?
3042                     eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL),
3043                     ifevent->ifidx, ifevent->role, ea);
3044 
3045             /* dhd already has created an interface by default, for 0 */
3046             if (ifevent->ifidx == 0)
3047                 break;
3048         }
3049 #endif /* PROP_TXSTATUS */
3050 
3051         if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
3052             if (ifevent->opcode == WLC_E_IF_ADD) {
3053                 if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname,
3054                     event->addr.octet)) {
3055                     DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d  %s\n",
3056                         __FUNCTION__, ifevent->ifidx, event->ifname));
3057                     return (BCME_ERROR);
3058                 }
3059             } else if (ifevent->opcode == WLC_E_IF_DEL) {
3060 #ifdef PCIE_FULL_DONGLE
3061                 /* Delete flowrings unconditionally for i/f delete */
3062                 dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info,
3063                     event->ifname));
3064 #endif /* PCIE_FULL_DONGLE */
3065                 dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
3066                     event->addr.octet);
3067                 /* Return ifidx (for vitual i/f, it will be > 0)
3068                  * so that no other operations on deleted interface
3069                  * are carried out
3070                  */
3071                 ret = ifevent->ifidx;
3072                 goto exit;
3073             } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
3074 #ifdef WL_CFG80211
3075                 dhd_event_ifchange(dhd_pub->info, ifevent, event->ifname,
3076                     event->addr.octet);
3077 #endif /* WL_CFG80211 */
3078             }
3079         } else {
3080 #if !defined(PROP_TXSTATUS) && !defined(PCIE_FULL_DONGLE) && defined(WL_CFG80211)
3081             DHD_INFO(("%s: Invalid ifidx %d for %s\n",
3082                __FUNCTION__, ifevent->ifidx, event->ifname));
3083 #endif /* !PROP_TXSTATUS && !PCIE_FULL_DONGLE && WL_CFG80211 */
3084         }
3085             /* send up the if event: btamp user needs it */
3086             *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
3087             /* push up to external supp/auth */
3088             dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
3089         break;
3090     }
3091 
3092 #ifdef WLMEDIA_HTSF
3093     case WLC_E_HTSFSYNC:
3094         htsf_update(dhd_pub->info, event_data);
3095         break;
3096 #endif /* WLMEDIA_HTSF */
3097     case WLC_E_NDIS_LINK:
3098         break;
3099     case WLC_E_PFN_NET_FOUND:
3100     case WLC_E_PFN_SCAN_ALLGONE: /* share with WLC_E_PFN_BSSID_NET_LOST */
3101     case WLC_E_PFN_NET_LOST:
3102         break;
3103 #if defined(PNO_SUPPORT)
3104     case WLC_E_PFN_BSSID_NET_FOUND:
3105     case WLC_E_PFN_BEST_BATCHING:
3106         dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
3107         break;
3108 #endif
3109 #if defined(RTT_SUPPORT)
3110     case WLC_E_PROXD:
3111         dhd_rtt_event_handler(dhd_pub, event, (void *)event_data);
3112         break;
3113 #endif /* RTT_SUPPORT */
3114         /* These are what external supplicant/authenticator wants */
3115     case WLC_E_ASSOC_IND:
3116     case WLC_E_AUTH_IND:
3117     case WLC_E_REASSOC_IND:
3118         dhd_findadd_sta(dhd_pub,
3119             dhd_ifname2idx(dhd_pub->info, event->ifname),
3120             &event->addr.octet);
3121         break;
3122 #ifndef BCMDBUS
3123 #if defined(DHD_FW_COREDUMP)
3124     case WLC_E_PSM_WATCHDOG:
3125         DHD_ERROR(("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__));
3126         if (dhd_socram_dump(dhd_pub->bus) != BCME_OK) {
3127             DHD_ERROR(("%s: socram dump ERROR : \n", __FUNCTION__));
3128         }
3129     break;
3130 #endif
3131 #endif /* !BCMDBUS */
3132 #ifdef DHD_WMF
3133     case WLC_E_PSTA_PRIMARY_INTF_IND:
3134         dhd_update_psta_interface_for_sta(dhd_pub, event->ifname,
3135             (void *)(event->addr.octet), (void*) event_data);
3136         break;
3137 #endif
3138     case WLC_E_LINK:
3139 #ifdef PCIE_FULL_DONGLE
3140         DHD_EVENT(("%s: Link event %d, flags %x, status %x\n",
3141             __FUNCTION__, type, flags, status));
3142         if (dhd_update_interface_link_status(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info,
3143             event->ifname), (uint8)flags) != BCME_OK) {
3144             DHD_ERROR(("%s: dhd_update_interface_link_status Failed.\n",
3145                 __FUNCTION__));
3146             break;
3147         }
3148         if (!flags) {
3149             DHD_ERROR(("%s: Deleting all STA from assoc list and flowrings.\n",
3150                 __FUNCTION__));
3151             /* Delete all sta and flowrings */
3152             dhd_del_all_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info, event->ifname));
3153             dhd_flow_rings_delete(dhd_pub, (uint8)dhd_ifname2idx(dhd_pub->info,
3154                 event->ifname));
3155         }
3156         /* fall through */
3157 #endif /* PCIE_FULL_DONGLE */
3158     case WLC_E_DEAUTH:
3159     case WLC_E_DEAUTH_IND:
3160     case WLC_E_DISASSOC:
3161     case WLC_E_DISASSOC_IND:
3162 #ifdef PCIE_FULL_DONGLE
3163         if (type != WLC_E_LINK) {
3164             uint8 ifindex = (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname);
3165             uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
3166             uint8 del_sta = TRUE;
3167 #ifdef WL_CFG80211
3168             if (role == WLC_E_IF_ROLE_STA &&
3169                 !wl_cfg80211_is_roam_offload(dhd_idx2net(dhd_pub, ifindex)) &&
3170                     !wl_cfg80211_is_event_from_connected_bssid(
3171                         dhd_idx2net(dhd_pub, ifindex), event, *ifidx)) {
3172                 del_sta = FALSE;
3173             }
3174 #endif /* WL_CFG80211 */
3175             DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, del_sta %d\n",
3176                 __FUNCTION__, type, flags, status, role, del_sta));
3177 
3178             if (del_sta) {
3179                 DHD_MAC_TO_STR((event->addr.octet), macstr);
3180                 DHD_EVENT(("%s: Deleting STA %s\n", __FUNCTION__, macstr));
3181 
3182                 dhd_del_sta(dhd_pub, dhd_ifname2idx(dhd_pub->info,
3183                     event->ifname), &event->addr.octet);
3184                 /* Delete all flowrings for STA and P2P Client */
3185                 if (role == WLC_E_IF_ROLE_STA || role == WLC_E_IF_ROLE_P2P_CLIENT) {
3186                     dhd_flow_rings_delete(dhd_pub, ifindex);
3187                 } else {
3188                     dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
3189                         (char *)&event->addr.octet[0]);
3190                 }
3191             }
3192         }
3193 #endif /* PCIE_FULL_DONGLE */
3194         /* fall through */
3195 
3196     default:
3197         *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
3198 #ifdef DHD_UPDATE_INTF_MAC
3199         if ((WLC_E_LINK == type) && (WLC_EVENT_MSG_LINK & flags)) {
3200             dhd_event_ifchange(dhd_pub->info,
3201             (struct wl_event_data_if *)event,
3202             event->ifname,
3203             event->addr.octet);
3204         }
3205 #endif /* DHD_UPDATE_INTF_MAC */
3206         /* push up to external supp/auth */
3207         dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
3208         DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n",
3209             __FUNCTION__, type, flags, status));
3210         BCM_REFERENCE(flags);
3211         BCM_REFERENCE(status);
3212 
3213         break;
3214     }
3215 #if defined(STBAP)
3216     /* For routers, EAPD will be working on these events.
3217      * Overwrite interface name to that event is pushed
3218      * to host with its registered interface name
3219      */
3220     memcpy(pvt_data->event.ifname, dhd_ifname(dhd_pub, *ifidx), IFNAMSIZ);
3221 #endif
3222 
3223 exit:
3224 
3225 #ifdef SHOW_EVENTS
3226     if (DHD_FWLOG_ON() || DHD_EVENT_ON()) {
3227         wl_show_host_event(dhd_pub, event,
3228             (void *)event_data, raw_event, dhd_pub->enable_log);
3229     }
3230 #endif /* SHOW_EVENTS */
3231 
3232     return ret;
3233 }
3234 
3235 int
wl_host_event(dhd_pub_t * dhd_pub,int * ifidx,void * pktdata,uint pktlen,wl_event_msg_t * event,void ** data_ptr,void * raw_event)3236 wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen,
3237     wl_event_msg_t *event, void **data_ptr, void *raw_event)
3238 {
3239     return wl_process_host_event(dhd_pub, ifidx, pktdata, pktlen, event, data_ptr,
3240             raw_event);
3241 }
3242 
3243 void
dhd_print_buf(void * pbuf,int len,int bytes_per_line)3244 dhd_print_buf(void *pbuf, int len, int bytes_per_line)
3245 {
3246 #ifdef DHD_DEBUG
3247     int i, j = 0;
3248     unsigned char *buf = pbuf;
3249 
3250     if (bytes_per_line == 0) {
3251         bytes_per_line = len;
3252     }
3253 
3254     for (i = 0; i < len; i++) {
3255         printf("%2.2x", *buf++);
3256         j++;
3257         if (j == bytes_per_line) {
3258             printf("\n");
3259             j = 0;
3260         } else {
3261             printf(":");
3262         }
3263     }
3264     printf("\n");
3265 #endif /* DHD_DEBUG */
3266 }
3267 #ifndef strtoul
3268 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
3269 #endif
3270 
3271 #if defined(PKT_FILTER_SUPPORT) || defined(DHD_PKT_LOGGING)
3272 /* Convert user's input in hex pattern to byte-size mask */
3273 int
wl_pattern_atoh(char * src,char * dst)3274 wl_pattern_atoh(char *src, char *dst)
3275 {
3276     int i;
3277     if (strncmp(src, "0x", 2) != 0 &&
3278         strncmp(src, "0X", 2) != 0) {
3279         DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
3280         return -1;
3281     }
3282     src = src + 2; /* Skip past 0x */
3283     if (strlen(src) % 2 != 0) {
3284         DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
3285         return -1;
3286     }
3287     for (i = 0; *src != '\0'; i++) {
3288         char num[3];
3289         bcm_strncpy_s(num, sizeof(num), src, 2);
3290         num[2] = '\0';
3291         dst[i] = (uint8)strtoul(num, NULL, 16);
3292         src += 2;
3293     }
3294     return i;
3295 }
3296 #endif /* PKT_FILTER_SUPPORT || DHD_PKT_LOGGING */
3297 
3298 #ifdef PKT_FILTER_SUPPORT
3299 void
dhd_pktfilter_offload_enable(dhd_pub_t * dhd,char * arg,int enable,int master_mode)3300 dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode)
3301 {
3302     char                *argv[8];
3303     int                    i = 0;
3304     const char            *str;
3305     int                    buf_len;
3306     int                    str_len;
3307     char                *arg_save = 0, *arg_org = 0;
3308     int                    rc;
3309     char                buf[32] = {0};
3310     wl_pkt_filter_enable_t    enable_parm;
3311     wl_pkt_filter_enable_t    * pkt_filterp;
3312 
3313     if (!arg)
3314         return;
3315 
3316     if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
3317         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
3318         goto fail;
3319     }
3320     arg_org = arg_save;
3321     memcpy(arg_save, arg, strlen(arg) + 1);
3322 
3323     argv[i] = bcmstrtok(&arg_save, " ", 0);
3324 
3325     i = 0;
3326     if (argv[i] == NULL) {
3327         DHD_ERROR(("No args provided\n"));
3328         goto fail;
3329     }
3330 
3331     str = "pkt_filter_enable";
3332     str_len = strlen(str);
3333     bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1);
3334     buf[ sizeof(buf) - 1 ] = '\0';
3335     buf_len = str_len + 1;
3336 
3337     pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
3338 
3339     /* Parse packet filter id. */
3340     enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
3341     if (dhd_conf_del_pkt_filter(dhd, enable_parm.id))
3342         goto fail;
3343 
3344     /* Parse enable/disable value. */
3345     enable_parm.enable = htod32(enable);
3346 
3347     buf_len += sizeof(enable_parm);
3348     memcpy((char *)pkt_filterp,
3349            &enable_parm,
3350            sizeof(enable_parm));
3351 
3352     /* Enable/disable the specified filter. */
3353     rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
3354     rc = rc >= 0 ? 0 : rc;
3355     if (rc)
3356         DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n",
3357         __FUNCTION__, enable?"enable":"disable", arg, rc));
3358     else
3359         DHD_TRACE(("%s: successfully %s pktfilter %s\n",
3360         __FUNCTION__, enable?"enable":"disable", arg));
3361 
3362     /* Contorl the master mode */
3363     rc = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_mode",
3364         master_mode, WLC_SET_VAR, TRUE, 0);
3365     rc = rc >= 0 ? 0 : rc;
3366     if (rc)
3367         DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n",
3368             __FUNCTION__, master_mode, rc));
3369 
3370 fail:
3371     if (arg_org)
3372         MFREE(dhd->osh, arg_org, strlen(arg) + 1);
3373 }
3374 
3375 /* Packet filter section: extended filters have named offsets, add table here */
3376 typedef struct {
3377     char *name;
3378     uint16 base;
3379 } wl_pfbase_t;
3380 
3381 static wl_pfbase_t basenames[] = { WL_PKT_FILTER_BASE_NAMES };
3382 
3383 static int
wl_pkt_filter_base_parse(char * name)3384 wl_pkt_filter_base_parse(char *name)
3385 {
3386     uint i;
3387     char *bname, *uname;
3388 
3389     for (i = 0; i < ARRAYSIZE(basenames); i++) {
3390         bname = basenames[i].name;
3391         for (uname = name; *uname; bname++, uname++) {
3392             if (*bname != bcm_toupper(*uname)) {
3393                 break;
3394             }
3395         }
3396         if (!*uname && !*bname) {
3397             break;
3398         }
3399     }
3400 
3401     if (i < ARRAYSIZE(basenames)) {
3402         return basenames[i].base;
3403     } else {
3404         return -1;
3405     }
3406 }
3407 
3408 void
dhd_pktfilter_offload_set(dhd_pub_t * dhd,char * arg)3409 dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg)
3410 {
3411     const char             *str;
3412     wl_pkt_filter_t        pkt_filter;
3413     wl_pkt_filter_t        *pkt_filterp;
3414     int                    buf_len;
3415     int                    str_len;
3416     int                 rc;
3417     uint32                mask_size;
3418     uint32                pattern_size;
3419     char                *argv[16], * buf = 0;
3420     int                    i = 0;
3421     char                *arg_save = 0, *arg_org = 0;
3422 #define BUF_SIZE        2048
3423 
3424     if (!arg)
3425         return;
3426 
3427     if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
3428         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
3429         goto fail;
3430     }
3431 
3432     arg_org = arg_save;
3433 
3434     if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) {
3435         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
3436         goto fail;
3437     }
3438     memset(buf, 0, BUF_SIZE);
3439     memcpy(arg_save, arg, strlen(arg) + 1);
3440 
3441     if (strlen(arg) > BUF_SIZE) {
3442         DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf)));
3443         goto fail;
3444     }
3445 
3446     argv[i] = bcmstrtok(&arg_save, " ", 0);
3447     while (argv[i++])
3448         argv[i] = bcmstrtok(&arg_save, " ", 0);
3449 
3450     i = 0;
3451     if (argv[i] == NULL) {
3452         DHD_ERROR(("No args provided\n"));
3453         goto fail;
3454     }
3455 
3456     str = "pkt_filter_add";
3457     str_len = strlen(str);
3458     bcm_strncpy_s(buf, BUF_SIZE, str, str_len);
3459     buf[ str_len ] = '\0';
3460     buf_len = str_len + 1;
3461 
3462     pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1);
3463 
3464     /* Parse packet filter id. */
3465     pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
3466     if (dhd_conf_del_pkt_filter(dhd, pkt_filter.id))
3467         goto fail;
3468 
3469     if (argv[++i] == NULL) {
3470         DHD_ERROR(("Polarity not provided\n"));
3471         goto fail;
3472     }
3473 
3474     /* Parse filter polarity. */
3475     pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
3476 
3477     if (argv[++i] == NULL) {
3478         DHD_ERROR(("Filter type not provided\n"));
3479         goto fail;
3480     }
3481 
3482     /* Parse filter type. */
3483     pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
3484 
3485     if ((pkt_filter.type == 0) || (pkt_filter.type == 1)) {
3486         if (argv[++i] == NULL) {
3487             DHD_ERROR(("Offset not provided\n"));
3488             goto fail;
3489         }
3490 
3491         /* Parse pattern filter offset. */
3492         pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
3493 
3494         if (argv[++i] == NULL) {
3495             DHD_ERROR(("Bitmask not provided\n"));
3496             goto fail;
3497         }
3498 
3499         /* Parse pattern filter mask. */
3500         mask_size =
3501             htod32(wl_pattern_atoh(argv[i],
3502             (char *) pkt_filterp->u.pattern.mask_and_pattern));
3503 
3504         if (argv[++i] == NULL) {
3505             DHD_ERROR(("Pattern not provided\n"));
3506             goto fail;
3507         }
3508 
3509         /* Parse pattern filter pattern. */
3510         pattern_size =
3511             htod32(wl_pattern_atoh(argv[i],
3512             (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size]));
3513 
3514         if (mask_size != pattern_size) {
3515             DHD_ERROR(("Mask and pattern not the same size\n"));
3516             goto fail;
3517         }
3518 
3519         pkt_filter.u.pattern.size_bytes = mask_size;
3520         buf_len += WL_PKT_FILTER_FIXED_LEN;
3521         buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size);
3522 
3523         /* Keep-alive attributes are set in local    variable (keep_alive_pkt), and
3524          * then memcpy'ed into buffer (keep_alive_pktp) since there is no
3525          * guarantee that the buffer is properly aligned.
3526          */
3527         memcpy((char *)pkt_filterp,
3528             &pkt_filter,
3529             WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
3530     } else if ((pkt_filter.type == 2) || (pkt_filter.type == 6)) {
3531         int list_cnt = 0;
3532         char *endptr;
3533         wl_pkt_filter_pattern_listel_t *pf_el = &pkt_filterp->u.patlist.patterns[0];
3534 
3535         while (argv[++i] != NULL) {
3536             /* Parse pattern filter base and offset. */
3537             if (bcm_isdigit(*argv[i])) {
3538                 /* Numeric base */
3539                 rc = strtoul(argv[i], &endptr, 0);
3540             } else {
3541                 endptr = strchr(argv[i], ':');
3542                 if (endptr) {
3543                     *endptr = '\0';
3544                     rc = wl_pkt_filter_base_parse(argv[i]);
3545                     if (rc == -1) {
3546                          printf("Invalid base %s\n", argv[i]);
3547                         goto fail;
3548                     }
3549                     *endptr = ':';
3550                 } else {
3551                     printf("Invalid [base:]offset format: %s\n", argv[i]);
3552                     goto fail;
3553                 }
3554             }
3555 
3556             if (*endptr == ':') {
3557                 pkt_filter.u.patlist.patterns[0].base_offs = htod16(rc);
3558                 rc = strtoul(endptr + 1, &endptr, 0);
3559             } else {
3560                 /* Must have had a numeric offset only */
3561                 pkt_filter.u.patlist.patterns[0].base_offs = htod16(0);
3562             }
3563 
3564             if (*endptr) {
3565                 printf("Invalid [base:]offset format: %s\n", argv[i]);
3566                 goto fail;
3567             }
3568             if (rc > 0x0000FFFF) {
3569                 printf("Offset too large\n");
3570                 goto fail;
3571             }
3572             pkt_filter.u.patlist.patterns[0].rel_offs = htod16(rc);
3573 
3574             /* Clear match_flag (may be set in parsing which follows) */
3575             pkt_filter.u.patlist.patterns[0].match_flags = htod16(0);
3576 
3577             /* Parse pattern filter mask and pattern directly into ioctl buffer */
3578             if (argv[++i] == NULL) {
3579                 printf("Bitmask not provided\n");
3580                 goto fail;
3581             }
3582             rc = wl_pattern_atoh(argv[i], (char*)pf_el->mask_and_data);
3583             if (rc == -1) {
3584                 printf("Rejecting: %s\n", argv[i]);
3585                 goto fail;
3586             }
3587             mask_size = htod16(rc);
3588 
3589             if (argv[++i] == NULL) {
3590                 printf("Pattern not provided\n");
3591                 goto fail;
3592             }
3593 
3594             if (*argv[i] == '!') {
3595                 pkt_filter.u.patlist.patterns[0].match_flags =
3596                     htod16(WL_PKT_FILTER_MFLAG_NEG);
3597                 (argv[i])++;
3598             }
3599             if (*argv[i] == '\0') {
3600                 printf("Pattern not provided\n");
3601                 goto fail;
3602             }
3603             rc = wl_pattern_atoh(argv[i], (char*)&pf_el->mask_and_data[rc]);
3604             if (rc == -1) {
3605                 printf("Rejecting: %s\n", argv[i]);
3606                 goto fail;
3607             }
3608             pattern_size = htod16(rc);
3609 
3610             if (mask_size != pattern_size) {
3611                 printf("Mask and pattern not the same size\n");
3612                 goto fail;
3613             }
3614 
3615             pkt_filter.u.patlist.patterns[0].size_bytes = mask_size;
3616 
3617             /* Account for the size of this pattern element */
3618             buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc;
3619 
3620             /* And the pattern element fields that were put in a local for
3621              * alignment purposes now get copied to the ioctl buffer.
3622              */
3623             memcpy((char*)pf_el, &pkt_filter.u.patlist.patterns[0],
3624                 WL_PKT_FILTER_PATTERN_FIXED_LEN);
3625 
3626             /* Move to next element location in ioctl buffer */
3627             pf_el = (wl_pkt_filter_pattern_listel_t*)
3628                 ((uint8*)pf_el + WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 2 * rc);
3629 
3630             /* Count list element */
3631             list_cnt++;
3632         }
3633 
3634         /* Account for initial fixed size, and copy initial fixed fields */
3635         buf_len += WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN;
3636 
3637         /* Update list count and total size */
3638         pkt_filter.u.patlist.list_cnt = list_cnt;
3639         pkt_filter.u.patlist.PAD1[0] = 0;
3640         pkt_filter.u.patlist.totsize = buf + buf_len - (char*)pkt_filterp;
3641         pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN;
3642 
3643         memcpy((char *)pkt_filterp, &pkt_filter,
3644             WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN);
3645     } else {
3646         DHD_ERROR(("Invalid filter type %d\n", pkt_filter.type));
3647         goto fail;
3648     }
3649 
3650     rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
3651     rc = rc >= 0 ? 0 : rc;
3652 
3653     if (rc)
3654         DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n",
3655         __FUNCTION__, arg, rc));
3656     else
3657         DHD_TRACE(("%s: successfully added pktfilter %s\n",
3658         __FUNCTION__, arg));
3659 
3660 fail:
3661     if (arg_org)
3662         MFREE(dhd->osh, arg_org, strlen(arg) + 1);
3663 
3664     if (buf)
3665         MFREE(dhd->osh, buf, BUF_SIZE);
3666 }
3667 
3668 void
dhd_pktfilter_offload_delete(dhd_pub_t * dhd,int id)3669 dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id)
3670 {
3671     int ret;
3672 
3673     ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_delete",
3674         id, WLC_SET_VAR, TRUE, 0);
3675     if (ret < 0) {
3676         DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n",
3677             __FUNCTION__, id, ret));
3678     }
3679     else
3680         DHD_TRACE(("%s: successfully deleted pktfilter %d\n",
3681         __FUNCTION__, id));
3682 }
3683 #endif /* PKT_FILTER_SUPPORT */
3684 
3685 /* ========================== */
3686 /* ==== ARP OFFLOAD SUPPORT = */
3687 /* ========================== */
3688 #ifdef ARP_OFFLOAD_SUPPORT
3689 void
dhd_arp_offload_set(dhd_pub_t * dhd,int arp_mode)3690 dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode)
3691 {
3692     int retcode;
3693 
3694     retcode = dhd_wl_ioctl_set_intiovar(dhd, "arp_ol",
3695         arp_mode, WLC_SET_VAR, TRUE, 0);
3696 
3697     retcode = retcode >= 0 ? 0 : retcode;
3698     if (retcode)
3699         DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
3700             __FUNCTION__, arp_mode, retcode));
3701     else
3702         DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n",
3703             __FUNCTION__, arp_mode));
3704 }
3705 
3706 void
dhd_arp_offload_enable(dhd_pub_t * dhd,int arp_enable)3707 dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable)
3708 {
3709     int retcode;
3710 
3711     retcode = dhd_wl_ioctl_set_intiovar(dhd, "arpoe",
3712         arp_enable, WLC_SET_VAR, TRUE, 0);
3713 
3714     retcode = retcode >= 0 ? 0 : retcode;
3715     if (retcode)
3716         DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
3717             __FUNCTION__, arp_enable, retcode));
3718     else
3719         DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n",
3720             __FUNCTION__, arp_enable));
3721     if (arp_enable) {
3722         uint32 version;
3723         retcode = dhd_wl_ioctl_get_intiovar(dhd, "arp_version",
3724             &version, WLC_GET_VAR, FALSE, 0);
3725         if (retcode) {
3726             DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
3727                 __FUNCTION__, retcode));
3728             dhd->arp_version = 1;
3729         }
3730         else {
3731             DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version));
3732             dhd->arp_version = version;
3733         }
3734     }
3735 }
3736 
3737 void
dhd_aoe_arp_clr(dhd_pub_t * dhd,int idx)3738 dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx)
3739 {
3740     int ret = 0;
3741 
3742     if (dhd == NULL) return;
3743     if (dhd->arp_version == 1)
3744         idx = 0;
3745 
3746     ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE);
3747     if (ret < 0)
3748         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
3749 }
3750 
3751 void
dhd_aoe_hostip_clr(dhd_pub_t * dhd,int idx)3752 dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
3753 {
3754     int ret = 0;
3755 
3756     if (dhd == NULL) return;
3757     if (dhd->arp_version == 1)
3758         idx = 0;
3759 
3760     ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE);
3761     if (ret < 0)
3762         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
3763 }
3764 
3765 void
dhd_arp_offload_add_ip(dhd_pub_t * dhd,uint32 ipaddr,int idx)3766 dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx)
3767 {
3768     int ret;
3769 
3770     if (dhd == NULL) return;
3771     if (dhd->arp_version == 1)
3772         idx = 0;
3773 
3774     ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr),
3775             NULL, 0, TRUE);
3776     if (ret)
3777         DHD_ERROR(("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret));
3778     else
3779         DHD_ARPOE(("%s: sARP H ipaddr entry added \n",
3780             __FUNCTION__));
3781 }
3782 
3783 int
dhd_arp_get_arp_hostip_table(dhd_pub_t * dhd,void * buf,int buflen,int idx)3784 dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx)
3785 {
3786     int ret, i;
3787     uint32 *ptr32 = buf;
3788     bool clr_bottom = FALSE;
3789 
3790     if (!buf)
3791         return -1;
3792     if (dhd == NULL) return -1;
3793     if (dhd->arp_version == 1)
3794         idx = 0;
3795 
3796     ret = dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen,
3797             FALSE);
3798     if (ret) {
3799         DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n",
3800         __FUNCTION__, ret));
3801 
3802         return -1;
3803     }
3804 
3805     /* clean up the buf, ascii reminder */
3806     for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
3807         if (!clr_bottom) {
3808             if (*ptr32 == 0)
3809                 clr_bottom = TRUE;
3810         } else {
3811             *ptr32 = 0;
3812         }
3813         ptr32++;
3814     }
3815 
3816     return 0;
3817 }
3818 #endif /* ARP_OFFLOAD_SUPPORT  */
3819 
3820 /*
3821  * Neighbor Discovery Offload: enable NDO feature
3822  * Called  by ipv6 event handler when interface comes up/goes down
3823  */
3824 int
dhd_ndo_enable(dhd_pub_t * dhd,int ndo_enable)3825 dhd_ndo_enable(dhd_pub_t * dhd, int ndo_enable)
3826 {
3827     int retcode;
3828 
3829     if (dhd == NULL)
3830         return -1;
3831 
3832     retcode = dhd_wl_ioctl_set_intiovar(dhd, "ndoe",
3833         ndo_enable, WLC_SET_VAR, TRUE, 0);
3834     if (retcode)
3835         DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n",
3836             __FUNCTION__, ndo_enable, retcode));
3837     else
3838         DHD_TRACE(("%s: successfully enabed ndo offload to %d\n",
3839             __FUNCTION__, ndo_enable));
3840 
3841     return retcode;
3842 }
3843 
3844 /*
3845  * Neighbor Discover Offload: enable NDO feature
3846  * Called  by ipv6 event handler when interface comes up
3847  */
3848 int
dhd_ndo_add_ip(dhd_pub_t * dhd,char * ipv6addr,int idx)3849 dhd_ndo_add_ip(dhd_pub_t *dhd, char* ipv6addr, int idx)
3850 {
3851     int iov_len = 0;
3852     char iovbuf[DHD_IOVAR_BUF_SIZE] = {0};
3853     int retcode;
3854 
3855     if (dhd == NULL)
3856         return -1;
3857 
3858     iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr,
3859         IPV6_ADDR_LEN, iovbuf, sizeof(iovbuf));
3860     if (!iov_len) {
3861         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
3862             __FUNCTION__, sizeof(iovbuf)));
3863         return -1;
3864     }
3865     retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
3866 
3867     if (retcode)
3868         DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n",
3869         __FUNCTION__, retcode));
3870     else
3871         DHD_TRACE(("%s: ndo ipaddr entry added \n",
3872         __FUNCTION__));
3873 
3874     return retcode;
3875 }
3876 
3877 /*
3878  * Neighbor Discover Offload: enable NDO feature
3879  * Called  by ipv6 event handler when interface goes down
3880  */
3881 int
dhd_ndo_remove_ip(dhd_pub_t * dhd,int idx)3882 dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx)
3883 {
3884     int iov_len = 0;
3885     char iovbuf[DHD_IOVAR_BUF_SIZE] = {0};
3886     int retcode;
3887 
3888     if (dhd == NULL)
3889         return -1;
3890 
3891     iov_len = bcm_mkiovar("nd_hostip_clear", NULL,
3892         0, iovbuf, sizeof(iovbuf));
3893     if (!iov_len) {
3894         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
3895             __FUNCTION__, sizeof(iovbuf)));
3896         return -1;
3897     }
3898     retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
3899 
3900     if (retcode)
3901         DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n",
3902         __FUNCTION__, retcode));
3903     else
3904         DHD_TRACE(("%s: ndo ipaddr entry removed \n",
3905         __FUNCTION__));
3906 
3907     return retcode;
3908 }
3909 
3910 /* Enhanced ND offload */
3911 uint16
dhd_ndo_get_version(dhd_pub_t * dhdp)3912 dhd_ndo_get_version(dhd_pub_t *dhdp)
3913 {
3914     char iovbuf[DHD_IOVAR_BUF_SIZE];
3915     wl_nd_hostip_t ndo_get_ver;
3916     int iov_len;
3917     int retcode;
3918     uint16 ver = 0;
3919 
3920     if (dhdp == NULL) {
3921         return BCME_ERROR;
3922     }
3923 
3924     memset(&iovbuf, 0, sizeof(iovbuf));
3925     ndo_get_ver.version = htod16(WL_ND_HOSTIP_IOV_VER);
3926     ndo_get_ver.op_type = htod16(WL_ND_HOSTIP_OP_VER);
3927     ndo_get_ver.length = htod32(WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16));
3928     ndo_get_ver.u.version = 0;
3929     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_get_ver,
3930             WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16), iovbuf, sizeof(iovbuf));
3931     if (!iov_len) {
3932         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
3933             __FUNCTION__, sizeof(iovbuf)));
3934         return BCME_ERROR;
3935     }
3936 
3937     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, iov_len, FALSE, 0);
3938     if (retcode) {
3939         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
3940         /* ver iovar not supported. NDO version is 0 */
3941         ver = 0;
3942     } else {
3943         wl_nd_hostip_t *ndo_ver_ret = (wl_nd_hostip_t *)iovbuf;
3944 
3945         if ((dtoh16(ndo_ver_ret->version) == WL_ND_HOSTIP_IOV_VER) &&
3946                 (dtoh16(ndo_ver_ret->op_type) == WL_ND_HOSTIP_OP_VER) &&
3947                 (dtoh32(ndo_ver_ret->length) == WL_ND_HOSTIP_FIXED_LEN
3948                     + sizeof(uint16))) {
3949             /* nd_hostip iovar version */
3950             ver = dtoh16(ndo_ver_ret->u.version);
3951         }
3952 
3953         DHD_TRACE(("%s: successfully get version: %d\n", __FUNCTION__, ver));
3954     }
3955 
3956     return ver;
3957 }
3958 
3959 int
dhd_ndo_add_ip_with_type(dhd_pub_t * dhdp,char * ipv6addr,uint8 type,int idx)3960 dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type, int idx)
3961 {
3962     char iovbuf[DHD_IOVAR_BUF_SIZE];
3963     wl_nd_hostip_t ndo_add_addr;
3964     int iov_len;
3965     int retcode;
3966 
3967     if (dhdp == NULL || ipv6addr == 0) {
3968         return BCME_ERROR;
3969     }
3970 
3971     /* wl_nd_hostip_t fixed param */
3972     ndo_add_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
3973     ndo_add_addr.op_type = htod16(WL_ND_HOSTIP_OP_ADD);
3974     ndo_add_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
3975     /* wl_nd_host_ip_addr_t param for add */
3976     memcpy(&ndo_add_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN);
3977     ndo_add_addr.u.host_ip.type = type;
3978 
3979     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_add_addr,
3980         WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf));
3981     if (!iov_len) {
3982         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
3983             __FUNCTION__, sizeof(iovbuf)));
3984         return BCME_ERROR;
3985     }
3986 
3987     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
3988     if (retcode) {
3989         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
3990 #ifdef NDO_CONFIG_SUPPORT
3991         if (retcode == BCME_NORESOURCE) {
3992             /* number of host ip addr exceeds FW capacity, Deactivate ND offload */
3993             DHD_INFO(("%s: Host IP count exceed device capacity,"
3994                 "ND offload deactivated\n", __FUNCTION__));
3995             dhdp->ndo_host_ip_overflow = TRUE;
3996             dhd_ndo_enable(dhdp, 0);
3997         }
3998 #endif /* NDO_CONFIG_SUPPORT */
3999     } else {
4000         DHD_TRACE(("%s: successfully added: %d\n", __FUNCTION__, retcode));
4001     }
4002 
4003     return retcode;
4004 }
4005 
4006 int
dhd_ndo_remove_ip_by_addr(dhd_pub_t * dhdp,char * ipv6addr,int idx)4007 dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx)
4008 {
4009     char iovbuf[DHD_IOVAR_BUF_SIZE];
4010     wl_nd_hostip_t ndo_del_addr;
4011     int iov_len;
4012     int retcode;
4013 
4014     if (dhdp == NULL || ipv6addr == 0) {
4015         return BCME_ERROR;
4016     }
4017 
4018     /* wl_nd_hostip_t fixed param */
4019     ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
4020     ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL);
4021     ndo_del_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
4022     /* wl_nd_host_ip_addr_t param for del */
4023     memcpy(&ndo_del_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN);
4024     ndo_del_addr.u.host_ip.type = 0;    /* don't care */
4025 
4026     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr,
4027         WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf));
4028     if (!iov_len) {
4029         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
4030             __FUNCTION__, sizeof(iovbuf)));
4031         return BCME_ERROR;
4032     }
4033 
4034     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4035     if (retcode) {
4036         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4037     } else {
4038         DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode));
4039     }
4040 
4041     return retcode;
4042 }
4043 
4044 int
dhd_ndo_remove_ip_by_type(dhd_pub_t * dhdp,uint8 type,int idx)4045 dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx)
4046 {
4047     char iovbuf[DHD_IOVAR_BUF_SIZE];
4048     wl_nd_hostip_t ndo_del_addr;
4049     int iov_len;
4050     int retcode;
4051 
4052     if (dhdp == NULL) {
4053         return BCME_ERROR;
4054     }
4055 
4056     /* wl_nd_hostip_t fixed param */
4057     ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
4058     if (type == WL_ND_IPV6_ADDR_TYPE_UNICAST) {
4059         ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_UC);
4060     } else if (type == WL_ND_IPV6_ADDR_TYPE_ANYCAST) {
4061         ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_AC);
4062     } else {
4063         return BCME_BADARG;
4064     }
4065     ndo_del_addr.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
4066 
4067     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr, WL_ND_HOSTIP_FIXED_LEN,
4068             iovbuf, sizeof(iovbuf));
4069     if (!iov_len) {
4070         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
4071             __FUNCTION__, sizeof(iovbuf)));
4072         return BCME_ERROR;
4073     }
4074 
4075     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4076     if (retcode) {
4077         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4078     } else {
4079         DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode));
4080     }
4081 
4082     return retcode;
4083 }
4084 
4085 int
dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t * dhdp,int enable)4086 dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable)
4087 {
4088     char iovbuf[DHD_IOVAR_BUF_SIZE];
4089     int iov_len;
4090     int retcode;
4091 
4092     if (dhdp == NULL) {
4093         return BCME_ERROR;
4094     }
4095 
4096     iov_len = bcm_mkiovar("nd_unsolicited_na_filter", (char *)&enable, sizeof(int),
4097             iovbuf, sizeof(iovbuf));
4098     if (!iov_len) {
4099         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n",
4100             __FUNCTION__, sizeof(iovbuf)));
4101         return BCME_ERROR;
4102     }
4103     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
4104     if (retcode)
4105         DHD_ERROR(("%s: failed to enable Unsolicited NA filter to %d, retcode = %d\n",
4106             __FUNCTION__, enable, retcode));
4107     else {
4108         DHD_TRACE(("%s: successfully enabled Unsolicited NA filter to %d\n",
4109             __FUNCTION__, enable));
4110     }
4111 
4112     return retcode;
4113 }
4114 
4115 
4116 /*
4117  * returns = TRUE if associated, FALSE if not associated
4118  */
dhd_is_associated(dhd_pub_t * dhd,uint8 ifidx,int * retval)4119 bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval)
4120 {
4121     char bssid[6], zbuf[6];
4122     int ret = -1;
4123 
4124     bzero(bssid, 6);
4125     bzero(zbuf, 6);
4126 
4127     ret  = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid,
4128         ETHER_ADDR_LEN, FALSE, ifidx);
4129     DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
4130 
4131     if (ret == BCME_NOTASSOCIATED) {
4132         DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
4133     }
4134 
4135     if (retval)
4136         *retval = ret;
4137 
4138     if (ret < 0)
4139         return FALSE;
4140 
4141     if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) == 0)) {
4142         DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
4143         return FALSE;
4144     }
4145     return TRUE;
4146 }
4147 
4148 /* Function to estimate possible DTIM_SKIP value */
4149 #if defined(BCMPCIE)
4150 int
dhd_get_suspend_bcn_li_dtim(dhd_pub_t * dhd,int * dtim_period,int * bcn_interval)4151 dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period, int *bcn_interval)
4152 {
4153     int bcn_li_dtim = 1; /* deafult no dtim skip setting */
4154     int ret = -1;
4155     int allowed_skip_dtim_cnt = 0;
4156 
4157     /* Check if associated */
4158     if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
4159         DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
4160         return bcn_li_dtim;
4161     }
4162 
4163     if (dtim_period == NULL || bcn_interval == NULL)
4164         return bcn_li_dtim;
4165 
4166     /* read associated AP beacon interval */
4167     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD,
4168         bcn_interval, sizeof(*bcn_interval), FALSE, 0)) < 0) {
4169         DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
4170         return bcn_li_dtim;
4171     }
4172 
4173     /* read associated AP dtim setup */
4174     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
4175         dtim_period, sizeof(*dtim_period), FALSE, 0)) < 0) {
4176         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
4177         return bcn_li_dtim;
4178     }
4179 
4180     /* if not assocated just return */
4181     if (*dtim_period == 0) {
4182         return bcn_li_dtim;
4183     }
4184 
4185     if (dhd->max_dtim_enable) {
4186         bcn_li_dtim =
4187             (int) (MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval)));
4188         if (bcn_li_dtim == 0) {
4189             bcn_li_dtim = 1;
4190         }
4191     } else {
4192         /* attemp to use platform defined dtim skip interval */
4193         bcn_li_dtim = dhd->suspend_bcn_li_dtim;
4194 
4195         /* check if sta listen interval fits into AP dtim */
4196         if (*dtim_period > CUSTOM_LISTEN_INTERVAL) {
4197             /* AP DTIM to big for our Listen Interval : no dtim skiping */
4198             bcn_li_dtim = NO_DTIM_SKIP;
4199             DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
4200                 __FUNCTION__, *dtim_period, CUSTOM_LISTEN_INTERVAL));
4201             return bcn_li_dtim;
4202         }
4203 
4204         if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) {
4205             allowed_skip_dtim_cnt =
4206                 MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval));
4207             bcn_li_dtim =
4208                 (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP;
4209         }
4210 
4211         if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) {
4212             /* Round up dtim_skip to fit into STAs Listen Interval */
4213             bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period);
4214             DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
4215         }
4216     }
4217 
4218     DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
4219         __FUNCTION__, *bcn_interval, bcn_li_dtim, *dtim_period, CUSTOM_LISTEN_INTERVAL));
4220 
4221     return bcn_li_dtim;
4222 }
4223 #else /* OEM_ANDROID && BCMPCIE */
4224 int
dhd_get_suspend_bcn_li_dtim(dhd_pub_t * dhd)4225 dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
4226 {
4227     int bcn_li_dtim = 1; /* deafult no dtim skip setting */
4228     int ret = -1;
4229     int dtim_period = 0;
4230     int ap_beacon = 0;
4231     int allowed_skip_dtim_cnt = 0;
4232     /* Check if associated */
4233     if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
4234         DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
4235         goto exit;
4236     }
4237 
4238     /* read associated AP beacon interval */
4239     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD,
4240         &ap_beacon, sizeof(ap_beacon), FALSE, 0)) < 0) {
4241         DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
4242         goto exit;
4243     }
4244 
4245     /* read associated ap's dtim setup */
4246     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD,
4247         &dtim_period, sizeof(dtim_period), FALSE, 0)) < 0) {
4248         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
4249         goto exit;
4250     }
4251 
4252     /* if not assocated just exit */
4253     if (dtim_period == 0) {
4254         goto exit;
4255     }
4256 
4257     if (dhd->max_dtim_enable) {
4258         bcn_li_dtim = (int) (MAX_DTIM_ALLOWED_INTERVAL / (ap_beacon * dtim_period));
4259         if (bcn_li_dtim == 0) {
4260             bcn_li_dtim = 1;
4261         }
4262         bcn_li_dtim = MAX(dhd->suspend_bcn_li_dtim, bcn_li_dtim);
4263     } else {
4264         /* attemp to use platform defined dtim skip interval */
4265         bcn_li_dtim = dhd->suspend_bcn_li_dtim;
4266 
4267         /* check if sta listen interval fits into AP dtim */
4268         if (dtim_period > CUSTOM_LISTEN_INTERVAL) {
4269             /* AP DTIM to big for our Listen Interval : no dtim skiping */
4270             bcn_li_dtim = NO_DTIM_SKIP;
4271             DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n",
4272                 __FUNCTION__, dtim_period, CUSTOM_LISTEN_INTERVAL));
4273             goto exit;
4274         }
4275 
4276         if ((dtim_period * ap_beacon * bcn_li_dtim) > MAX_DTIM_ALLOWED_INTERVAL) {
4277             allowed_skip_dtim_cnt =
4278                 MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon);
4279             bcn_li_dtim =
4280                 (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt : NO_DTIM_SKIP;
4281         }
4282 
4283         if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) {
4284             /* Round up dtim_skip to fit into STAs Listen Interval */
4285             bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period);
4286             DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
4287         }
4288     }
4289 
4290     if (dhd->conf->suspend_bcn_li_dtim >= 0)
4291         bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim;
4292     DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n",
4293         __FUNCTION__, ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL));
4294 
4295 exit:
4296     return bcn_li_dtim;
4297 }
4298 #endif /* OEM_ANDROID && BCMPCIE */
4299 
4300 /* Check if the mode supports STA MODE */
dhd_support_sta_mode(dhd_pub_t * dhd)4301 bool dhd_support_sta_mode(dhd_pub_t *dhd)
4302 {
4303 #ifdef  WL_CFG80211
4304     if (!(dhd->op_mode & DHD_FLAG_STA_MODE))
4305         return FALSE;
4306     else
4307 #endif /* WL_CFG80211 */
4308         return TRUE;
4309 }
4310 
4311 #if defined(KEEP_ALIVE)
dhd_keep_alive_onoff(dhd_pub_t * dhd)4312 int dhd_keep_alive_onoff(dhd_pub_t *dhd)
4313 {
4314     char                buf[32] = {0};
4315     const char            *str;
4316     wl_mkeep_alive_pkt_t    mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}};
4317     wl_mkeep_alive_pkt_t    *mkeep_alive_pktp;
4318     int                    buf_len;
4319     int                    str_len;
4320     int res                    = -1;
4321 
4322     if (!dhd_support_sta_mode(dhd))
4323         return res;
4324 
4325     DHD_TRACE(("%s execution\n", __FUNCTION__));
4326 
4327     str = "mkeep_alive";
4328     str_len = strlen(str);
4329     strncpy(buf, str, sizeof(buf) - 1);
4330     buf[ sizeof(buf) - 1 ] = '\0';
4331     mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1);
4332     mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period;
4333     buf_len = str_len + 1;
4334     mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
4335     mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
4336     /* Setup keep alive zero for null packet generation */
4337     mkeep_alive_pkt.keep_alive_id = 0;
4338     mkeep_alive_pkt.len_bytes = 0;
4339     buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
4340     bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data));
4341     /* Keep-alive attributes are set in local    variable (mkeep_alive_pkt), and
4342      * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
4343      * guarantee that the buffer is properly aligned.
4344      */
4345     memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN);
4346 
4347     res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
4348 
4349     return res;
4350 }
4351 #endif /* defined(KEEP_ALIVE) */
4352 
4353 #define CSCAN_TLV_TYPE_SSID_IE    'S'
4354 /*
4355  *  SSIDs list parsing from cscan tlv list
4356  */
4357 int
wl_parse_ssid_list_tlv(char ** list_str,wlc_ssid_ext_t * ssid,int max,int * bytes_left)4358 wl_parse_ssid_list_tlv(char** list_str, wlc_ssid_ext_t* ssid, int max, int *bytes_left)
4359 {
4360     char* str;
4361     int idx = 0;
4362 
4363     if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
4364         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
4365         return -1;
4366     }
4367     str = *list_str;
4368     while (*bytes_left > 0) {
4369         if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
4370             *list_str = str;
4371             DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
4372             return idx;
4373         }
4374 
4375         /* Get proper CSCAN_TLV_TYPE_SSID_IE */
4376         *bytes_left -= 1;
4377         str += 1;
4378         ssid[idx].rssi_thresh = 0;
4379         ssid[idx].flags = 0;
4380         if (str[0] == 0) {
4381             /* Broadcast SSID */
4382             ssid[idx].SSID_len = 0;
4383             memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
4384             *bytes_left -= 1;
4385             str += 1;
4386 
4387             DHD_TRACE(("BROADCAST SCAN  left=%d\n", *bytes_left));
4388         }
4389         else if (str[0] <= DOT11_MAX_SSID_LEN) {
4390             /* Get proper SSID size */
4391             ssid[idx].SSID_len = str[0];
4392             *bytes_left -= 1;
4393             str += 1;
4394 
4395             /* Get SSID */
4396             if (ssid[idx].SSID_len > *bytes_left) {
4397                 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
4398                 __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
4399                 return -1;
4400             }
4401 
4402             memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len);
4403 
4404             *bytes_left -= ssid[idx].SSID_len;
4405             str += ssid[idx].SSID_len;
4406             ssid[idx].hidden = TRUE;
4407 
4408             DHD_TRACE(("%s :size=%d left=%d\n",
4409                 (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left));
4410         }
4411         else {
4412             DHD_ERROR(("### SSID size more that %d\n", str[0]));
4413             return -1;
4414         }
4415 
4416         if (idx++ >  max) {
4417             DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx));
4418             return -1;
4419         }
4420     }
4421 
4422     *list_str = str;
4423     return idx;
4424 }
4425 
4426 #if defined(WL_WIRELESS_EXT)
4427 /* Android ComboSCAN support */
4428 
4429 /*
4430  *  data parsing from ComboScan tlv list
4431 */
4432 int
wl_iw_parse_data_tlv(char ** list_str,void * dst,int dst_size,const char token,int input_size,int * bytes_left)4433 wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token,
4434                      int input_size, int *bytes_left)
4435 {
4436     char* str;
4437     uint16 short_temp;
4438     uint32 int_temp;
4439 
4440     if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
4441         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
4442         return -1;
4443     }
4444     str = *list_str;
4445 
4446     /* Clean all dest bytes */
4447     memset(dst, 0, dst_size);
4448     while (*bytes_left > 0) {
4449         if (str[0] != token) {
4450             DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n",
4451                 __FUNCTION__, token, str[0], *bytes_left));
4452             return -1;
4453         }
4454 
4455         *bytes_left -= 1;
4456         str += 1;
4457 
4458         if (input_size == 1) {
4459             memcpy(dst, str, input_size);
4460         }
4461         else if (input_size == 2) {
4462             memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
4463                 input_size);
4464         }
4465         else if (input_size == 4) {
4466             memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
4467                 input_size);
4468         }
4469 
4470         *bytes_left -= input_size;
4471         str += input_size;
4472         *list_str = str;
4473         return 1;
4474     }
4475     return 1;
4476 }
4477 
4478 /*
4479  *  channel list parsing from cscan tlv list
4480 */
4481 int
wl_iw_parse_channel_list_tlv(char ** list_str,uint16 * channel_list,int channel_num,int * bytes_left)4482 wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list,
4483                              int channel_num, int *bytes_left)
4484 {
4485     char* str;
4486     int idx = 0;
4487 
4488     if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) {
4489         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
4490         return -1;
4491     }
4492     str = *list_str;
4493 
4494     while (*bytes_left > 0) {
4495         if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
4496             *list_str = str;
4497             DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
4498             return idx;
4499         }
4500         /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
4501         *bytes_left -= 1;
4502         str += 1;
4503 
4504         if (str[0] == 0) {
4505             /* All channels */
4506             channel_list[idx] = 0x0;
4507         }
4508         else {
4509             channel_list[idx] = (uint16)str[0];
4510             DHD_TRACE(("%s channel=%d \n", __FUNCTION__,  channel_list[idx]));
4511         }
4512         *bytes_left -= 1;
4513         str += 1;
4514 
4515         if (idx++ > 255) {
4516             DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
4517             return -1;
4518         }
4519     }
4520 
4521     *list_str = str;
4522     return idx;
4523 }
4524 
4525 /* Parse a comma-separated list from list_str into ssid array, starting
4526  * at index idx.  Max specifies size of the ssid array.  Parses ssids
4527  * and returns updated idx; if idx >= max not all fit, the excess have
4528  * not been copied.  Returns -1 on empty string, or on ssid too long.
4529  */
4530 int
wl_iw_parse_ssid_list(char ** list_str,wlc_ssid_t * ssid,int idx,int max)4531 wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max)
4532 {
4533     char *str, *ptr;
4534 
4535     if ((list_str == NULL) || (*list_str == NULL))
4536         return -1;
4537 
4538     for (str = *list_str; str != NULL; str = ptr) {
4539         /* check for next TAG */
4540         if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
4541             *list_str     = str + strlen(GET_CHANNEL);
4542             return idx;
4543         }
4544 
4545         if ((ptr = strchr(str, ',')) != NULL) {
4546             *ptr++ = '\0';
4547         }
4548 
4549         if (strlen(str) > DOT11_MAX_SSID_LEN) {
4550             DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
4551             return -1;
4552         }
4553 
4554         if (strlen(str) == 0)
4555             ssid[idx].SSID_len = 0;
4556 
4557         if (idx < max) {
4558             bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID));
4559             strncpy((char*)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1);
4560             ssid[idx].SSID_len = strlen(str);
4561         }
4562         idx++;
4563     }
4564     return idx;
4565 }
4566 
4567 /*
4568  * Parse channel list from iwpriv CSCAN
4569  */
4570 int
wl_iw_parse_channel_list(char ** list_str,uint16 * channel_list,int channel_num)4571 wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num)
4572 {
4573     int num;
4574     int val;
4575     char* str;
4576     char* endptr = NULL;
4577 
4578     if ((list_str == NULL)||(*list_str == NULL))
4579         return -1;
4580 
4581     str = *list_str;
4582     num = 0;
4583     while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
4584         val = (int)strtoul(str, &endptr, 0);
4585         if (endptr == str) {
4586             printf("could not parse channel number starting at"
4587                 " substring \"%s\" in list:\n%s\n",
4588                 str, *list_str);
4589             return -1;
4590         }
4591         str = endptr + strspn(endptr, " ,");
4592 
4593         if (num == channel_num) {
4594             DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n",
4595                 channel_num, *list_str));
4596             return -1;
4597         }
4598 
4599         channel_list[num++] = (uint16)val;
4600     }
4601     *list_str = str;
4602     return num;
4603 }
4604 
4605 #endif
4606 
4607 #if defined(TRAFFIC_MGMT_DWM)
traffic_mgmt_add_dwm_filter(dhd_pub_t * dhd,trf_mgmt_filter_list_t * trf_mgmt_filter_list,int len)4608 static int traffic_mgmt_add_dwm_filter(dhd_pub_t *dhd,
4609     trf_mgmt_filter_list_t * trf_mgmt_filter_list, int len)
4610 {
4611     int ret = 0;
4612     uint32              i;
4613     trf_mgmt_filter_t   *trf_mgmt_filter;
4614     uint8               dwm_tbl_entry;
4615     uint32              dscp = 0;
4616     uint16              dwm_filter_enabled = 0;
4617 
4618 
4619     /* Check parameter length is adequate */
4620     if (len < (OFFSETOF(trf_mgmt_filter_list_t, filter) +
4621         trf_mgmt_filter_list->num_filters * sizeof(trf_mgmt_filter_t))) {
4622         ret = BCME_BUFTOOSHORT;
4623         return ret;
4624     }
4625 
4626     bzero(&dhd->dhd_tm_dwm_tbl, sizeof(dhd_trf_mgmt_dwm_tbl_t));
4627 
4628     for (i = 0; i < trf_mgmt_filter_list->num_filters; i++) {
4629         trf_mgmt_filter = &trf_mgmt_filter_list->filter[i];
4630 
4631         dwm_filter_enabled = (trf_mgmt_filter->flags & TRF_FILTER_DWM);
4632 
4633         if (dwm_filter_enabled) {
4634             dscp = trf_mgmt_filter->dscp;
4635             if (dscp >= DHD_DWM_TBL_SIZE) {
4636                 ret = BCME_BADARG;
4637             return ret;
4638             }
4639         }
4640 
4641         dhd->dhd_tm_dwm_tbl.dhd_dwm_enabled = 1;
4642         /* set WMM AC bits */
4643         dwm_tbl_entry = (uint8) trf_mgmt_filter->priority;
4644         DHD_TRF_MGMT_DWM_SET_FILTER(dwm_tbl_entry);
4645 
4646         /* set favored bits */
4647         if (trf_mgmt_filter->flags & TRF_FILTER_FAVORED)
4648             DHD_TRF_MGMT_DWM_SET_FAVORED(dwm_tbl_entry);
4649 
4650         dhd->dhd_tm_dwm_tbl.dhd_dwm_tbl[dscp] =  dwm_tbl_entry;
4651     }
4652     return ret;
4653 }
4654 #endif
4655 
4656 /* Given filename and download type,  returns a buffer pointer and length
4657  * for download to f/w. Type can be FW or NVRAM.
4658  *
4659  */
dhd_get_download_buffer(dhd_pub_t * dhd,char * file_path,download_type_t component,char ** buffer,int * length)4660 int dhd_get_download_buffer(dhd_pub_t    *dhd, char *file_path, download_type_t component,
4661     char ** buffer, int *length)
4662 
4663 {
4664     int ret = BCME_ERROR;
4665     int len = 0;
4666     int file_len;
4667     void *image = NULL;
4668     uint8 *buf = NULL;
4669 
4670     /* Point to cache if available. */
4671 #ifdef CACHE_FW_IMAGES
4672     if (component == FW) {
4673         if (dhd->cached_fw_length) {
4674             len = dhd->cached_fw_length;
4675             buf = dhd->cached_fw;
4676         }
4677     }
4678     else if (component == NVRAM) {
4679         if (dhd->cached_nvram_length) {
4680             len = dhd->cached_nvram_length;
4681             buf = dhd->cached_nvram;
4682         }
4683     }
4684     else if (component == CLM_BLOB) {
4685         if (dhd->cached_clm_length) {
4686             len = dhd->cached_clm_length;
4687             buf = dhd->cached_clm;
4688         }
4689     } else {
4690         return ret;
4691     }
4692 #endif /* CACHE_FW_IMAGES */
4693     /* No Valid cache found on this call */
4694     if (!len) {
4695         file_len = *length;
4696         *length = 0;
4697 
4698         if (file_path) {
4699             image = dhd_os_open_image(file_path);
4700             if (image == NULL) {
4701                 printf("%s: Open image file failed %s\n", __FUNCTION__, file_path);
4702                 goto err;
4703             }
4704         }
4705 
4706         buf = MALLOCZ(dhd->osh, file_len);
4707         if (buf == NULL) {
4708             DHD_ERROR(("%s: Failed to allocate memory %d bytes\n",
4709                 __FUNCTION__, file_len));
4710             goto err;
4711         }
4712 
4713         /* Download image */
4714 #if defined(BCMEMBEDIMAGE) && defined(DHD_EFI)
4715         if (!image) {
4716             memcpy(buf, nvram_arr, sizeof(nvram_arr));
4717             len = sizeof(nvram_arr);
4718         } else {
4719             len = dhd_os_get_image_block((char *)buf, file_len, image);
4720             if ((len <= 0 || len > file_len)) {
4721                 MFREE(dhd->osh, buf, file_len);
4722                 goto err;
4723             }
4724         }
4725 #else
4726         len = dhd_os_get_image_block((char *)buf, file_len, image);
4727         if ((len <= 0 || len > file_len)) {
4728             MFREE(dhd->osh, buf, file_len);
4729             goto err;
4730         }
4731 #endif /* DHD_EFI */
4732     }
4733 
4734     ret = BCME_OK;
4735     *length = len;
4736     *buffer = (char *)buf;
4737 
4738     /* Cache if first call. */
4739 #ifdef CACHE_FW_IMAGES
4740     if (component == FW) {
4741         if (!dhd->cached_fw_length) {
4742             dhd->cached_fw = buf;
4743             dhd->cached_fw_length = len;
4744         }
4745     }
4746     else if (component == NVRAM) {
4747         if (!dhd->cached_nvram_length) {
4748             dhd->cached_nvram = buf;
4749             dhd->cached_nvram_length = len;
4750         }
4751     }
4752     else if (component == CLM_BLOB) {
4753         if (!dhd->cached_clm_length) {
4754              dhd->cached_clm = buf;
4755              dhd->cached_clm_length = len;
4756         }
4757     }
4758 #endif /* CACHE_FW_IMAGES */
4759 
4760 err:
4761     if (image)
4762         dhd_os_close_image(image);
4763 
4764     return ret;
4765 }
4766 
4767 int
dhd_download_2_dongle(dhd_pub_t * dhd,char * iovar,uint16 flag,uint16 dload_type,unsigned char * dload_buf,int len)4768 dhd_download_2_dongle(dhd_pub_t    *dhd, char *iovar, uint16 flag, uint16 dload_type,
4769     unsigned char *dload_buf, int len)
4770 {
4771     struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf;
4772     int err = 0;
4773     int dload_data_offset;
4774     static char iovar_buf[WLC_IOCTL_MEDLEN];
4775     int iovar_len;
4776 
4777     memset(iovar_buf, 0, sizeof(iovar_buf));
4778 
4779     dload_data_offset = OFFSETOF(wl_dload_data_t, data);
4780     dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag;
4781     dload_ptr->dload_type = dload_type;
4782     dload_ptr->len = htod32(len - dload_data_offset);
4783     dload_ptr->crc = 0;
4784     len = ROUNDUP(len, 8);
4785 
4786     iovar_len = bcm_mkiovar(iovar, (char *)dload_buf,
4787         (uint)len, iovar_buf, sizeof(iovar_buf));
4788     if (iovar_len == 0) {
4789         DHD_ERROR(("%s: insufficient buffer space passed to bcm_mkiovar for '%s' \n",
4790                    __FUNCTION__, iovar));
4791         return BCME_BUFTOOSHORT;
4792     }
4793 
4794     err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovar_buf,
4795             iovar_len, IOV_SET, 0);
4796 
4797     return err;
4798 }
4799 
4800 int
dhd_download_blob(dhd_pub_t * dhd,unsigned char * image,uint32 len,char * iovar)4801 dhd_download_blob(dhd_pub_t    *dhd, unsigned char *image,
4802         uint32 len, char *iovar)
4803 {
4804     int chunk_len;
4805     int size2alloc;
4806     unsigned char *new_buf;
4807     int err = 0, data_offset;
4808     uint16 dl_flag = DL_BEGIN;
4809 
4810     data_offset = OFFSETOF(wl_dload_data_t, data);
4811     size2alloc = data_offset + MAX_CHUNK_LEN;
4812     size2alloc = ROUNDUP(size2alloc, 8);
4813 
4814     if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) {
4815         do {
4816             chunk_len = dhd_os_get_image_block((char *)(new_buf + data_offset),
4817                 MAX_CHUNK_LEN, image);
4818             if (chunk_len < 0) {
4819                 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n",
4820                     __FUNCTION__, chunk_len));
4821                 err = BCME_ERROR;
4822                 goto exit;
4823             }
4824 
4825             if (len - chunk_len == 0)
4826                 dl_flag |= DL_END;
4827 
4828             err = dhd_download_2_dongle(dhd, iovar, dl_flag, DL_TYPE_CLM,
4829                 new_buf, data_offset + chunk_len);
4830 
4831             dl_flag &= ~DL_BEGIN;
4832 
4833             len = len - chunk_len;
4834         } while ((len > 0) && (err == 0));
4835     } else {
4836         err = BCME_NOMEM;
4837     }
4838 exit:
4839     if (new_buf) {
4840         MFREE(dhd->osh, new_buf, size2alloc);
4841     }
4842 
4843     return err;
4844 }
4845 
4846 int
dhd_check_current_clm_data(dhd_pub_t * dhd)4847 dhd_check_current_clm_data(dhd_pub_t *dhd)
4848 {
4849     char iovbuf[WLC_IOCTL_SMLEN] = {0};
4850     wl_country_t *cspec;
4851     int err = BCME_OK;
4852 
4853     bcm_mkiovar("country", NULL, 0, iovbuf, sizeof(iovbuf));
4854     err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
4855     if (err) {
4856         DHD_ERROR(("%s: country code get failed\n", __FUNCTION__));
4857         return err;
4858     }
4859 
4860     cspec = (wl_country_t *)iovbuf;
4861     if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) == 0) {
4862         DHD_ERROR(("%s: ----- This FW is not included CLM data -----\n",
4863             __FUNCTION__));
4864         return FALSE;
4865     }
4866     DHD_ERROR(("%s: ----- This FW is included CLM data -----\n",
4867         __FUNCTION__));
4868     return TRUE;
4869 }
4870 
4871 int
dhd_apply_default_clm(dhd_pub_t * dhd,char * clm_path)4872 dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
4873 {
4874     char *clm_blob_path;
4875     int len;
4876     unsigned char *imgbuf = NULL;
4877     int err = BCME_OK;
4878     char iovbuf[WLC_IOCTL_SMLEN] = {0};
4879     int status = FALSE;
4880 
4881     if (clm_path && clm_path[0] != '\0') {
4882         if (strlen(clm_path) > MOD_PARAM_PATHLEN) {
4883             DHD_ERROR(("clm path exceeds max len\n"));
4884             return BCME_ERROR;
4885         }
4886         clm_blob_path = clm_path;
4887         DHD_TRACE(("clm path from module param:%s\n", clm_path));
4888     } else {
4889         clm_blob_path = CONFIG_BCMDHD_CLM_PATH;
4890     }
4891 
4892     /* If CLM blob file is found on the filesystem, download the file.
4893      * After CLM file download or If the blob file is not present,
4894      * validate the country code before proceeding with the initialization.
4895      * If country code is not valid, fail the initialization.
4896      */
4897 
4898     imgbuf = dhd_os_open_image((char *)clm_blob_path);
4899     if (imgbuf == NULL) {
4900         printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path);
4901 #if defined(DHD_BLOB_EXISTENCE_CHECK)
4902         if (dhd->is_blob) {
4903             err = BCME_ERROR;
4904         } else {
4905             status = dhd_check_current_clm_data(dhd);
4906             if (status == TRUE) {
4907                 err = BCME_OK;
4908             } else {
4909                 err = BCME_ERROR;
4910             }
4911         }
4912 #endif /* DHD_BLOB_EXISTENCE_CHECK */
4913         goto exit;
4914     }
4915 
4916     len = dhd_os_get_image_size(imgbuf);
4917 
4918     if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && imgbuf) {
4919         status = dhd_check_current_clm_data(dhd);
4920         if (status == TRUE) {
4921 #if defined(DHD_BLOB_EXISTENCE_CHECK)
4922             if (dhd->op_mode != DHD_FLAG_MFG_MODE) {
4923                 if (dhd->is_blob) {
4924                     err = BCME_ERROR;
4925                 }
4926                 goto exit;
4927             }
4928 #else
4929             DHD_ERROR(("%s: CLM already exist in F/W, "
4930                 "new CLM data will be added to the end of existing CLM data!\n",
4931                 __FUNCTION__));
4932 #endif /* DHD_BLOB_EXISTENCE_CHECK */
4933         }
4934 
4935         /* Found blob file. Download the file */
4936         DHD_ERROR(("clm file download from %s \n", clm_blob_path));
4937         err = dhd_download_blob(dhd, imgbuf, len, "clmload");
4938         if (err) {
4939             DHD_ERROR(("%s: CLM download failed err=%d\n", __FUNCTION__, err));
4940             /* Retrieve clmload_status and print */
4941             bcm_mkiovar("clmload_status", NULL, 0, iovbuf, sizeof(iovbuf));
4942             err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
4943             if (err) {
4944                 DHD_ERROR(("%s: clmload_status get failed err=%d \n",
4945                     __FUNCTION__, err));
4946             } else {
4947                 DHD_ERROR(("%s: clmload_status: %d \n",
4948                     __FUNCTION__, *((int *)iovbuf)));
4949                 if (*((int *)iovbuf) == CHIPID_MISMATCH) {
4950                     DHD_ERROR(("Chip ID mismatch error \n"));
4951                 }
4952             }
4953             err = BCME_ERROR;
4954             goto exit;
4955         } else {
4956             DHD_INFO(("%s: CLM download succeeded \n", __FUNCTION__));
4957         }
4958     } else {
4959         DHD_INFO(("Skipping the clm download. len:%d memblk:%p \n", len, imgbuf));
4960     }
4961 
4962     /* Verify country code */
4963     status = dhd_check_current_clm_data(dhd);
4964 
4965     if (status != TRUE) {
4966         /* Country code not initialized or CLM download not proper */
4967         DHD_ERROR(("country code not initialized\n"));
4968         err = BCME_ERROR;
4969     }
4970 exit:
4971 
4972     if (imgbuf) {
4973         dhd_os_close_image(imgbuf);
4974     }
4975 
4976     return err;
4977 }
4978 
dhd_free_download_buffer(dhd_pub_t * dhd,void * buffer,int length)4979 void dhd_free_download_buffer(dhd_pub_t    *dhd, void *buffer, int length)
4980 {
4981 #ifdef CACHE_FW_IMAGES
4982     return;
4983 #endif
4984     MFREE(dhd->osh, buffer, length);
4985 }
4986 
4987 #if defined(DHD_8021X_DUMP)
4988 #define EAP_PRINT(str) \
4989     DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: " str "\n", \
4990     ifname, direction ? "TX" : "RX"));
4991 #else
4992 #define EAP_PRINT(str)
4993 #endif /* DHD_8021X_DUMP */
4994 /* Parse EAPOL 4 way handshake messages */
4995 void
dhd_dump_eapol_4way_message(dhd_pub_t * dhd,char * ifname,char * dump_data,bool direction)4996 dhd_dump_eapol_4way_message(dhd_pub_t *dhd, char *ifname,
4997     char *dump_data, bool direction)
4998 {
4999     unsigned char type;
5000     int pair, ack, mic, kerr, req, sec, install;
5001     unsigned short us_tmp;
5002 
5003     type = dump_data[15];
5004     if (type == 0) {
5005         if ((dump_data[22] == 1) && (dump_data[18] == 1)) {
5006             dhd->conf->eapol_status = EAPOL_STATUS_WPS_REQID;
5007             EAP_PRINT("EAP Packet, Request, Identity");
5008         } else if ((dump_data[22] == 1) && (dump_data[18] == 2)) {
5009             dhd->conf->eapol_status = EAPOL_STATUS_WPS_RSPID;
5010             EAP_PRINT("EAP Packet, Response, Identity");
5011         } else if (dump_data[22] == 254) {
5012             if (dump_data[30] == 1) {
5013                 dhd->conf->eapol_status = EAPOL_STATUS_WPS_WSC_START;
5014                 EAP_PRINT("EAP Packet, WSC Start");
5015             } else if (dump_data[30] == 4) {
5016                 if (dump_data[41] == 4) {
5017                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M1;
5018                     EAP_PRINT("EAP Packet, WPS M1");
5019                 } else if (dump_data[41] == 5) {
5020                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M2;
5021                     EAP_PRINT("EAP Packet, WPS M2");
5022                 } else if (dump_data[41] == 7) {
5023                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M3;
5024                     EAP_PRINT("EAP Packet, WPS M3");
5025                 } else if (dump_data[41] == 8) {
5026                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M4;
5027                     EAP_PRINT("EAP Packet, WPS M4");
5028                 } else if (dump_data[41] == 9) {
5029                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M5;
5030                     EAP_PRINT("EAP Packet, WPS M5");
5031                 } else if (dump_data[41] == 10) {
5032                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M6;
5033                     EAP_PRINT("EAP Packet, WPS M6");
5034                 } else if (dump_data[41] == 11) {
5035                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M7;
5036                     EAP_PRINT("EAP Packet, WPS M7");
5037                 } else if (dump_data[41] == 12) {
5038                     dhd->conf->eapol_status = EAPOL_STATUS_WPS_M8;
5039                     EAP_PRINT("EAP Packet, WPS M8");
5040                 }
5041             } else if (dump_data[30] == 5) {
5042                 dhd->conf->eapol_status = EAPOL_STATUS_WPS_DONE;
5043                 EAP_PRINT("EAP Packet, WSC Done");
5044             }
5045         } else {
5046             DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n",
5047                 ifname, direction ? "TX" : "RX",
5048                 dump_data[14], dump_data[15], dump_data[30]));
5049         }
5050     } else if (type == 3 && dump_data[18] == 2) {
5051         us_tmp = (dump_data[19] << 8) | dump_data[20];
5052         pair =  0 != (us_tmp & 0x08);
5053         ack = 0  != (us_tmp & 0x80);
5054         mic = 0  != (us_tmp & 0x100);
5055         kerr =  0 != (us_tmp & 0x400);
5056         req = 0  != (us_tmp & 0x800);
5057         sec = 0  != (us_tmp & 0x200);
5058         install  = 0 != (us_tmp & 0x40);
5059 
5060         if (!sec && !mic && ack && !install && pair && !kerr && !req) {
5061             dhd->conf->eapol_status = EAPOL_STATUS_WPA_M1;
5062             EAP_PRINT("EAPOL Packet, 4-way handshake, M1");
5063         } else if (pair && !install && !ack && mic && !sec && !kerr && !req) {
5064             dhd->conf->eapol_status = EAPOL_STATUS_WPA_M2;
5065             EAP_PRINT("EAPOL Packet, 4-way handshake, M2");
5066         } else if (pair && ack && mic && sec && !kerr && !req) {
5067             dhd->conf->eapol_status = EAPOL_STATUS_WPA_M3;
5068             EAP_PRINT("EAPOL Packet, 4-way handshake, M3");
5069         } else if (pair && !install && !ack && mic && sec && !req && !kerr) {
5070             dhd->conf->eapol_status = EAPOL_STATUS_WPA_M4;
5071             EAP_PRINT("EAPOL Packet, 4-way handshake, M4");
5072         } else {
5073             DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n",
5074                 ifname, direction ? "TX" : "RX",
5075                 dump_data[14], dump_data[15], dump_data[30]));
5076         }
5077     } else {
5078         DHD_ERROR(("ETHER_TYPE_802_1X[%s] [%s]: ver %d, type %d, replay %d\n",
5079             ifname, direction ? "TX" : "RX",
5080             dump_data[14], dump_data[15], dump_data[30]));
5081     }
5082 }
5083 
5084 #ifdef REPORT_FATAL_TIMEOUTS
init_dhd_timeouts(dhd_pub_t * pub)5085 void init_dhd_timeouts(dhd_pub_t *pub)
5086 {
5087     pub->timeout_info = MALLOC(pub->osh, sizeof(timeout_info_t));
5088     if (pub->timeout_info == NULL) {
5089         DHD_ERROR(("%s: Failed to alloc timeout_info\n", __FUNCTION__));
5090     } else {
5091         DHD_INFO(("Initializing dhd_timeouts\n"));
5092         pub->timeout_info->scan_timer_lock = dhd_os_spin_lock_init(pub->osh);
5093         pub->timeout_info->join_timer_lock = dhd_os_spin_lock_init(pub->osh);
5094         pub->timeout_info->bus_timer_lock = dhd_os_spin_lock_init(pub->osh);
5095         pub->timeout_info->cmd_timer_lock = dhd_os_spin_lock_init(pub->osh);
5096         pub->timeout_info->scan_timeout_val = SCAN_TIMEOUT_DEFAULT;
5097         pub->timeout_info->join_timeout_val = JOIN_TIMEOUT_DEFAULT;
5098         pub->timeout_info->cmd_timeout_val = CMD_TIMEOUT_DEFAULT;
5099         pub->timeout_info->bus_timeout_val = BUS_TIMEOUT_DEFAULT;
5100         pub->timeout_info->scan_timer_active = FALSE;
5101         pub->timeout_info->join_timer_active = FALSE;
5102         pub->timeout_info->cmd_timer_active = FALSE;
5103         pub->timeout_info->bus_timer_active = FALSE;
5104         pub->timeout_info->cmd_join_error = WLC_SSID_MASK;
5105         pub->timeout_info->cmd_request_id = 0;
5106     }
5107 }
5108 
5109 void
deinit_dhd_timeouts(dhd_pub_t * pub)5110 deinit_dhd_timeouts(dhd_pub_t *pub)
5111 {
5112     /* stop the join, scan bus, cmd timers
5113     * as failing to do so may cause a kernel panic if
5114     * an rmmod is done
5115     */
5116     if (!pub->timeout_info) {
5117         DHD_ERROR(("timeout_info pointer is NULL\n"));
5118         ASSERT(0);
5119         return;
5120     }
5121     if (dhd_stop_scan_timer(pub)) {
5122         DHD_ERROR(("dhd_stop_scan_timer failed\n"));
5123         ASSERT(0);
5124     }
5125     if (dhd_stop_bus_timer(pub)) {
5126         DHD_ERROR(("dhd_stop_bus_timer failed\n"));
5127         ASSERT(0);
5128     }
5129     if (dhd_stop_cmd_timer(pub)) {
5130         DHD_ERROR(("dhd_stop_cmd_timer failed\n"));
5131         ASSERT(0);
5132     }
5133     if (dhd_stop_join_timer(pub)) {
5134         DHD_ERROR(("dhd_stop_join_timer failed\n"));
5135         ASSERT(0);
5136     }
5137 
5138     dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->scan_timer_lock);
5139     dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->join_timer_lock);
5140     dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->bus_timer_lock);
5141     dhd_os_spin_lock_deinit(pub->osh, pub->timeout_info->cmd_timer_lock);
5142     MFREE(pub->osh, pub->timeout_info, sizeof(timeout_info_t));
5143     pub->timeout_info = NULL;
5144 }
5145 
5146 static void
dhd_cmd_timeout(void * ctx)5147 dhd_cmd_timeout(void *ctx)
5148 {
5149     dhd_pub_t *pub = (dhd_pub_t *)ctx;
5150     unsigned long flags;
5151 
5152     if (!pub->timeout_info) {
5153         DHD_ERROR(("DHD: timeout_info NULL\n"));
5154         ASSERT(0);
5155         return;
5156     }
5157 
5158     DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags);
5159     if (pub->timeout_info && pub->timeout_info->cmd_timer_active) {
5160         DHD_ERROR(("\nERROR COMMAND TIMEOUT TO:%d\n", pub->timeout_info->cmd_timeout_val));
5161         DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags);
5162 #ifdef PCIE_OOB
5163         /* Assert device_wake so that UART_Rx is available */
5164         if (dhd_bus_set_device_wake(pub->bus, TRUE)) {
5165             DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__));
5166             ASSERT(0);
5167         }
5168 #endif /* PCIE_OOB */
5169         if (dhd_stop_cmd_timer(pub)) {
5170             DHD_ERROR(("%s: dhd_stop_cmd_timer() failed\n", __FUNCTION__));
5171             ASSERT(0);
5172         }
5173         dhd_wakeup_ioctl_event(pub, IOCTL_RETURN_ON_ERROR);
5174         if (!dhd_query_bus_erros(pub))
5175             dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_COMMAND_TO);
5176     } else {
5177         DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags);
5178     }
5179 }
5180 
5181 int
dhd_start_cmd_timer(dhd_pub_t * pub)5182 dhd_start_cmd_timer(dhd_pub_t *pub)
5183 {
5184     int ret = BCME_OK;
5185     unsigned long flags = 0;
5186     uint32 cmd_to_ms;
5187 
5188     if (!pub->timeout_info) {
5189         DHD_ERROR(("DHD: timeout_info NULL\n"));
5190         ret = BCME_ERROR;
5191         ASSERT(0);
5192         goto exit_null;
5193     }
5194     DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags);
5195     cmd_to_ms = pub->timeout_info->cmd_timeout_val;
5196 
5197     if (pub->timeout_info->cmd_timeout_val == 0) {
5198         /* Disable Command timer timeout */
5199         DHD_INFO(("DHD: Command Timeout Disabled\n"));
5200         goto exit;
5201     }
5202     if (pub->timeout_info->cmd_timer_active) {
5203         DHD_ERROR(("%s:Timer already active\n", __FUNCTION__));
5204         ret = BCME_ERROR;
5205         ASSERT(0);
5206     } else {
5207         pub->timeout_info->cmd_timer = osl_timer_init(pub->osh,
5208             "cmd_timer", dhd_cmd_timeout, pub);
5209         osl_timer_update(pub->osh, pub->timeout_info->cmd_timer,
5210             cmd_to_ms, 0);
5211         pub->timeout_info->cmd_timer_active = TRUE;
5212     }
5213     if (ret == BCME_OK) {
5214         DHD_INFO(("%s Cmd Timer started\n", __FUNCTION__));
5215     }
5216 exit:
5217     DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags);
5218 exit_null:
5219     return ret;
5220 }
5221 
5222 int
dhd_stop_cmd_timer(dhd_pub_t * pub)5223 dhd_stop_cmd_timer(dhd_pub_t *pub)
5224 {
5225     int ret = BCME_OK;
5226     unsigned long flags = 0;
5227 
5228     if (!pub->timeout_info) {
5229         DHD_ERROR(("DHD: timeout_info NULL\n"));
5230         ret = BCME_ERROR;
5231         ASSERT(0);
5232         goto exit;
5233     }
5234     DHD_TIMER_LOCK(pub->timeout_info->cmd_timer_lock, flags);
5235 
5236     if (pub->timeout_info->cmd_timer_active) {
5237         osl_timer_del(pub->osh, pub->timeout_info->cmd_timer);
5238         pub->timeout_info->cmd_timer_active = FALSE;
5239     }
5240     else {
5241         DHD_INFO(("DHD: CMD timer is not active\n"));
5242     }
5243     if (ret == BCME_OK) {
5244         DHD_INFO(("%s Cmd Timer Stopped\n", __FUNCTION__));
5245     }
5246     DHD_TIMER_UNLOCK(pub->timeout_info->cmd_timer_lock, flags);
5247 exit:
5248     return ret;
5249 }
5250 
5251 static int
__dhd_stop_join_timer(dhd_pub_t * pub)5252 __dhd_stop_join_timer(dhd_pub_t *pub)
5253 {
5254     int ret = BCME_OK;
5255     if (!pub->timeout_info) {
5256         DHD_ERROR(("DHD: timeout_info NULL\n"));
5257         ASSERT(0);
5258         return BCME_ERROR;
5259     }
5260 
5261     if (pub->timeout_info->join_timer_active) {
5262         osl_timer_del(pub->osh, pub->timeout_info->join_timer);
5263         pub->timeout_info->join_timer_active = FALSE;
5264     } else {
5265         DHD_INFO(("DHD: JOIN timer is not active\n"));
5266     }
5267     if (ret == BCME_OK) {
5268         DHD_INFO(("%s: Join Timer Stopped\n", __FUNCTION__));
5269     }
5270     return ret;
5271 }
5272 
5273 static void
dhd_join_timeout(void * ctx)5274 dhd_join_timeout(void *ctx)
5275 {
5276     dhd_pub_t *pub = (dhd_pub_t *)ctx;
5277     unsigned long flags;
5278 
5279     if (!pub->timeout_info) {
5280         DHD_ERROR(("DHD: timeout_info NULL\n"));
5281         ASSERT(0);
5282         return;
5283     }
5284 
5285     DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags);
5286     if (pub->timeout_info->join_timer_active) {
5287         DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags);
5288         if (dhd_stop_join_timer(pub)) {
5289             DHD_ERROR(("%s: dhd_stop_join_timer() failed\n", __FUNCTION__));
5290             ASSERT(0);
5291         }
5292         if (pub->timeout_info->cmd_join_error) {
5293             DHD_ERROR(("\nERROR JOIN TIMEOUT TO:%d:0x%x\n",
5294                 pub->timeout_info->join_timeout_val,
5295                 pub->timeout_info->cmd_join_error));
5296 #ifdef DHD_FW_COREDUMP
5297                 /* collect core dump and crash */
5298                 pub->memdump_enabled = DUMP_MEMFILE_BUGON;
5299                 pub->memdump_type = DUMP_TYPE_JOIN_TIMEOUT;
5300                 dhd_bus_mem_dump(pub);
5301 #endif /* DHD_FW_COREDUMP */
5302         }
5303     } else {
5304         DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags);
5305     }
5306 }
5307 
5308 int
dhd_start_join_timer(dhd_pub_t * pub)5309 dhd_start_join_timer(dhd_pub_t *pub)
5310 {
5311     int ret = BCME_OK;
5312     unsigned long flags = 0;
5313     uint32 join_to_ms;
5314 
5315     if (!pub->timeout_info) {
5316         DHD_ERROR(("DHD: timeout_info NULL\n"));
5317         ret = BCME_ERROR;
5318         ASSERT(0);
5319         goto exit;
5320     }
5321 
5322     join_to_ms = pub->timeout_info->join_timeout_val;
5323     DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags);
5324     if (pub->timeout_info->join_timer_active) {
5325         DHD_ERROR(("%s:Stoping active timer\n", __FUNCTION__));
5326         __dhd_stop_join_timer(pub);
5327     }
5328     if (pub->timeout_info->join_timeout_val == 0) {
5329         /* Disable Join timer timeout */
5330         DHD_INFO(("DHD: Join Timeout Disabled\n"));
5331     } else {
5332         pub->timeout_info->join_timer = osl_timer_init(pub->osh,
5333             "join_timer", dhd_join_timeout, pub);
5334         osl_timer_update(pub->osh, pub->timeout_info->join_timer, join_to_ms, 0);
5335         pub->timeout_info->join_timer_active = TRUE;
5336         pub->timeout_info->cmd_join_error |= WLC_SSID_MASK;
5337     }
5338     if (ret == BCME_OK) {
5339         DHD_INFO(("%s:Join Timer started 0x%x\n", __FUNCTION__,
5340             pub->timeout_info->cmd_join_error));
5341     }
5342     DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags);
5343 exit:
5344     return ret;
5345 }
5346 
5347 int
dhd_stop_join_timer(dhd_pub_t * pub)5348 dhd_stop_join_timer(dhd_pub_t *pub)
5349 {
5350     int ret = BCME_OK;
5351     unsigned long flags;
5352 
5353     DHD_TIMER_LOCK(pub->timeout_info->join_timer_lock, flags);
5354     ret = __dhd_stop_join_timer(pub);
5355     DHD_TIMER_UNLOCK(pub->timeout_info->join_timer_lock, flags);
5356     return ret;
5357 }
5358 
5359 static void
dhd_scan_timeout(void * ctx)5360 dhd_scan_timeout(void *ctx)
5361 {
5362     dhd_pub_t *pub = (dhd_pub_t *)ctx;
5363     unsigned long flags;
5364 
5365      if (pub->timeout_info == NULL) {
5366         DHD_ERROR(("timeout_info pointer is NULL\n"));
5367         ASSERT(0);
5368         return;
5369      }
5370 
5371     DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags);
5372     if (pub->timeout_info && pub->timeout_info->scan_timer_active) {
5373         DHD_ERROR(("\nERROR SCAN TIMEOUT TO:%d\n", pub->timeout_info->scan_timeout_val));
5374         DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags);
5375         dhd_stop_scan_timer(pub);
5376         if (!dhd_query_bus_erros(pub))
5377             dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_SCAN_TO);
5378     } else {
5379         DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags);
5380     }
5381 }
5382 
5383 int
dhd_start_scan_timer(dhd_pub_t * pub)5384 dhd_start_scan_timer(dhd_pub_t *pub)
5385 {
5386     int ret = BCME_OK;
5387     unsigned long flags = 0;
5388     uint32 scan_to_ms;
5389 
5390     if (!pub->timeout_info) {
5391         DHD_ERROR(("DHD: timeout_info NULL\n"));
5392         ret = BCME_ERROR;
5393         ASSERT(0);
5394         goto exit_null;
5395     }
5396     DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags);
5397     scan_to_ms = pub->timeout_info->scan_timeout_val;
5398 
5399     if (pub->timeout_info->scan_timer_active) {
5400         /* NOTE : New scan timeout value will be effective
5401          * only once current scan is completed.
5402          */
5403         DHD_ERROR(("%s:Timer already active\n", __FUNCTION__));
5404         ret = BCME_ERROR;
5405         goto exit;
5406     }
5407 
5408     if (pub->timeout_info->scan_timeout_val == 0) {
5409         /* Disable Scan timer timeout */
5410         DHD_INFO(("DHD: Scan Timeout Disabled\n"));
5411     } else {
5412         pub->timeout_info->scan_timer = osl_timer_init(pub->osh, "scan_timer",
5413             dhd_scan_timeout, pub);
5414         pub->timeout_info->scan_timer_active = TRUE;
5415         osl_timer_update(pub->osh, pub->timeout_info->scan_timer, scan_to_ms, 0);
5416     }
5417     if (ret == BCME_OK) {
5418         DHD_INFO(("%s Scan Timer started\n", __FUNCTION__));
5419     }
5420 exit:
5421     DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags);
5422 exit_null:
5423     return ret;
5424 }
5425 
5426 int
dhd_stop_scan_timer(dhd_pub_t * pub)5427 dhd_stop_scan_timer(dhd_pub_t *pub)
5428 {
5429     int ret = BCME_OK;
5430     unsigned long flags = 0;
5431 
5432     if (!pub->timeout_info) {
5433         DHD_ERROR(("DHD: timeout_info NULL\n"));
5434         ret = BCME_ERROR;
5435         ASSERT(0);
5436         goto exit;
5437     }
5438     DHD_TIMER_LOCK(pub->timeout_info->scan_timer_lock, flags);
5439 
5440     if (pub->timeout_info->scan_timer_active) {
5441         osl_timer_del(pub->osh, pub->timeout_info->scan_timer);
5442         pub->timeout_info->scan_timer_active = FALSE;
5443     }
5444     else {
5445         DHD_INFO(("DHD: SCAN timer is not active\n"));
5446     }
5447 
5448     if (ret == BCME_OK) {
5449         DHD_INFO(("%s Scan Timer Stopped\n", __FUNCTION__));
5450     }
5451     DHD_TIMER_UNLOCK(pub->timeout_info->scan_timer_lock, flags);
5452 exit:
5453     return ret;
5454 }
5455 
5456 static void
dhd_bus_timeout(void * ctx)5457 dhd_bus_timeout(void *ctx)
5458 {
5459     dhd_pub_t *pub = (dhd_pub_t *)ctx;
5460     unsigned long flags;
5461 
5462     if (pub->timeout_info == NULL) {
5463         DHD_ERROR(("timeout_info pointer is NULL\n"));
5464         ASSERT(0);
5465         return;
5466     }
5467 
5468     DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags);
5469     if (pub->timeout_info->bus_timer_active) {
5470         DHD_ERROR(("\nERROR BUS TIMEOUT TO:%d\n", pub->timeout_info->bus_timeout_val));
5471         DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags);
5472 #ifdef PCIE_OOB
5473         /* Assert device_wake so that UART_Rx is available */
5474         if (dhd_bus_set_device_wake(pub->bus, TRUE)) {
5475             DHD_ERROR(("%s: dhd_bus_set_device_wake() failed\n", __FUNCTION__));
5476             ASSERT(0);
5477         }
5478 #endif /* PCIE_OOB */
5479         if (dhd_stop_bus_timer(pub)) {
5480             DHD_ERROR(("%s: dhd_stop_bus_timer() failed\n", __FUNCTION__));
5481             ASSERT(0);
5482         }
5483         if (!dhd_query_bus_erros(pub))
5484             dhd_send_trap_to_fw_for_timeout(pub, DHD_REASON_OQS_TO);
5485     } else {
5486         DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags);
5487     }
5488 }
5489 
5490 int
dhd_start_bus_timer(dhd_pub_t * pub)5491 dhd_start_bus_timer(dhd_pub_t *pub)
5492 {
5493     int ret = BCME_OK;
5494     unsigned long flags = 0;
5495     uint32 bus_to_ms;
5496 
5497     if (!pub->timeout_info) {
5498         DHD_ERROR(("DHD: timeout_info NULL\n"));
5499         ret = BCME_ERROR;
5500         ASSERT(0);
5501         goto exit_null;
5502     }
5503     DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags);
5504     bus_to_ms = pub->timeout_info->bus_timeout_val;
5505 
5506     if (pub->timeout_info->bus_timeout_val == 0) {
5507         /* Disable Bus timer timeout */
5508         DHD_INFO(("DHD: Bus Timeout Disabled\n"));
5509         goto exit;
5510     }
5511     if (pub->timeout_info->bus_timer_active) {
5512         DHD_ERROR(("%s:Timer already active\n", __FUNCTION__));
5513         ret = BCME_ERROR;
5514         ASSERT(0);
5515     } else {
5516         pub->timeout_info->bus_timer = osl_timer_init(pub->osh,
5517             "bus_timer", dhd_bus_timeout, pub);
5518         pub->timeout_info->bus_timer_active = TRUE;
5519         osl_timer_update(pub->osh, pub->timeout_info->bus_timer, bus_to_ms, 0);
5520     }
5521     if (ret == BCME_OK) {
5522         DHD_INFO(("%s: BUS Timer started\n", __FUNCTION__));
5523     }
5524 exit:
5525     DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags);
5526 exit_null:
5527     return ret;
5528 }
5529 
5530 int
dhd_stop_bus_timer(dhd_pub_t * pub)5531 dhd_stop_bus_timer(dhd_pub_t *pub)
5532 {
5533     int ret = BCME_OK;
5534     unsigned long flags = 0;
5535 
5536     if (!pub->timeout_info) {
5537         DHD_ERROR(("DHD: timeout_info NULL\n"));
5538         ret = BCME_ERROR;
5539         ASSERT(0);
5540         goto exit;
5541     }
5542     DHD_TIMER_LOCK(pub->timeout_info->bus_timer_lock, flags);
5543 
5544     if (pub->timeout_info->bus_timer_active) {
5545         osl_timer_del(pub->osh, pub->timeout_info->bus_timer);
5546         pub->timeout_info->bus_timer_active = FALSE;
5547     }
5548     else {
5549         DHD_INFO(("DHD: BUS timer is not active\n"));
5550     }
5551     if (ret == BCME_OK) {
5552         DHD_INFO(("%s: Bus Timer Stopped\n", __FUNCTION__));
5553     }
5554     DHD_TIMER_UNLOCK(pub->timeout_info->bus_timer_lock, flags);
5555 exit:
5556     return ret;
5557 }
5558 
5559 int
dhd_set_request_id(dhd_pub_t * pub,uint16 id,uint32 cmd)5560 dhd_set_request_id(dhd_pub_t *pub, uint16 id, uint32 cmd)
5561 {
5562     DHD_INFO(("%s: id:%d\n", __FUNCTION__, id));
5563     if (pub->timeout_info) {
5564         pub->timeout_info->cmd_request_id = id;
5565         pub->timeout_info->cmd = cmd;
5566         return BCME_OK;
5567     } else {
5568         return BCME_ERROR;
5569     }
5570 }
5571 
5572 uint16
dhd_get_request_id(dhd_pub_t * pub)5573 dhd_get_request_id(dhd_pub_t *pub)
5574 {
5575     if (pub->timeout_info) {
5576         return (pub->timeout_info->cmd_request_id);
5577     } else {
5578         return 0;
5579     }
5580 }
5581 
5582 void
dhd_set_join_error(dhd_pub_t * pub,uint32 mask)5583 dhd_set_join_error(dhd_pub_t *pub, uint32 mask)
5584 {
5585     DHD_INFO(("Setting join Error %d\n", mask));
5586     if (pub->timeout_info) {
5587         pub->timeout_info->cmd_join_error |= mask;
5588     }
5589 }
5590 
5591 void
dhd_clear_join_error(dhd_pub_t * pub,uint32 mask)5592 dhd_clear_join_error(dhd_pub_t *pub, uint32 mask)
5593 {
5594     DHD_INFO(("clear join Error %d\n", mask));
5595     if (pub->timeout_info) {
5596         pub->timeout_info->cmd_join_error &= ~mask;
5597     }
5598 }
5599 
5600 void
dhd_get_scan_to_val(dhd_pub_t * pub,uint32 * to_val)5601 dhd_get_scan_to_val(dhd_pub_t *pub, uint32 *to_val)
5602 {
5603     if (pub->timeout_info) {
5604         *to_val = pub->timeout_info->scan_timeout_val;
5605     } else {
5606         *to_val = 0;
5607     }
5608 }
5609 
5610 void
dhd_set_scan_to_val(dhd_pub_t * pub,uint32 to_val)5611 dhd_set_scan_to_val(dhd_pub_t *pub, uint32 to_val)
5612 {
5613     if (pub->timeout_info) {
5614         DHD_INFO(("Setting TO val:%d\n", to_val));
5615         pub->timeout_info->scan_timeout_val = to_val;
5616     }
5617 }
5618 
5619 void
dhd_get_join_to_val(dhd_pub_t * pub,uint32 * to_val)5620 dhd_get_join_to_val(dhd_pub_t *pub, uint32 *to_val)
5621 {
5622     if (pub->timeout_info) {
5623         *to_val = pub->timeout_info->join_timeout_val;
5624     } else {
5625         *to_val = 0;
5626     }
5627 }
5628 
5629 void
dhd_set_join_to_val(dhd_pub_t * pub,uint32 to_val)5630 dhd_set_join_to_val(dhd_pub_t *pub, uint32 to_val)
5631 {
5632     if (pub->timeout_info) {
5633         DHD_INFO(("Setting TO val:%d\n", to_val));
5634         pub->timeout_info->join_timeout_val = to_val;
5635     }
5636 }
5637 
5638 void
dhd_get_cmd_to_val(dhd_pub_t * pub,uint32 * to_val)5639 dhd_get_cmd_to_val(dhd_pub_t *pub, uint32 *to_val)
5640 {
5641     if (pub->timeout_info) {
5642         *to_val = pub->timeout_info->cmd_timeout_val;
5643     } else {
5644         *to_val = 0;
5645     }
5646 }
5647 
5648 void
dhd_set_cmd_to_val(dhd_pub_t * pub,uint32 to_val)5649 dhd_set_cmd_to_val(dhd_pub_t *pub, uint32 to_val)
5650 {
5651     if (pub->timeout_info) {
5652         DHD_INFO(("Setting TO val:%d\n", to_val));
5653         pub->timeout_info->cmd_timeout_val = to_val;
5654     }
5655 }
5656 
5657 void
dhd_get_bus_to_val(dhd_pub_t * pub,uint32 * to_val)5658 dhd_get_bus_to_val(dhd_pub_t *pub, uint32 *to_val)
5659 {
5660     if (pub->timeout_info) {
5661         *to_val = pub->timeout_info->bus_timeout_val;
5662     } else {
5663         *to_val = 0;
5664     }
5665 }
5666 
5667 void
dhd_set_bus_to_val(dhd_pub_t * pub,uint32 to_val)5668 dhd_set_bus_to_val(dhd_pub_t *pub, uint32 to_val)
5669 {
5670     if (pub->timeout_info) {
5671         DHD_INFO(("Setting TO val:%d\n", to_val));
5672         pub->timeout_info->bus_timeout_val = to_val;
5673     }
5674 }
5675 #endif /* REPORT_FATAL_TIMEOUTS */
5676 
5677 #ifdef SHOW_LOGTRACE
5678 int
dhd_parse_logstrs_file(osl_t * osh,char * raw_fmts,int logstrs_size,dhd_event_log_t * event_log)5679 dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
5680         dhd_event_log_t *event_log)
5681 {
5682     logstr_header_t *hdr = NULL;
5683     uint32 *lognums = NULL;
5684     char *logstrs = NULL;
5685     int ram_index = 0;
5686     char **fmts;
5687     int num_fmts = 0;
5688     int32 i = 0;
5689 
5690     /* Remember header from the logstrs.bin file */
5691     hdr = (logstr_header_t *) (raw_fmts + logstrs_size -
5692         sizeof(logstr_header_t));
5693 
5694     if (hdr->log_magic == LOGSTRS_MAGIC) {
5695         /*
5696         * logstrs.bin start with header.
5697         */
5698         num_fmts =    hdr->rom_logstrs_offset / sizeof(uint32);
5699         ram_index = (hdr->ram_lognums_offset -
5700             hdr->rom_lognums_offset) / sizeof(uint32);
5701         lognums = (uint32 *) &raw_fmts[hdr->rom_lognums_offset];
5702         logstrs = (char *)     &raw_fmts[hdr->rom_logstrs_offset];
5703     } else {
5704         /*
5705          * Legacy logstrs.bin format without header.
5706          */
5707         num_fmts = *((uint32 *) (raw_fmts)) / sizeof(uint32);
5708         if (num_fmts == 0) {
5709             /* Legacy ROM/RAM logstrs.bin format:
5710               *  - ROM 'lognums' section
5711               *   - RAM 'lognums' section
5712               *   - ROM 'logstrs' section.
5713               *   - RAM 'logstrs' section.
5714               *
5715               * 'lognums' is an array of indexes for the strings in the
5716               * 'logstrs' section. The first uint32 is 0 (index of first
5717               * string in ROM 'logstrs' section).
5718               *
5719               * The 4324b5 is the only ROM that uses this legacy format. Use the
5720               * fixed number of ROM fmtnums to find the start of the RAM
5721               * 'lognums' section. Use the fixed first ROM string ("Con\n") to
5722               * find the ROM 'logstrs' section.
5723               */
5724             #define NUM_4324B5_ROM_FMTS    186
5725             #define FIRST_4324B5_ROM_LOGSTR "Con\n"
5726             ram_index = NUM_4324B5_ROM_FMTS;
5727             lognums = (uint32 *) raw_fmts;
5728             num_fmts =    ram_index;
5729             logstrs = (char *) &raw_fmts[num_fmts << 2];
5730             while (strncmp(FIRST_4324B5_ROM_LOGSTR, logstrs, 4)) {
5731                 num_fmts++;
5732                 logstrs = (char *) &raw_fmts[num_fmts << 2];
5733             }
5734         } else {
5735                 /* Legacy RAM-only logstrs.bin format:
5736                  *      - RAM 'lognums' section
5737                  *      - RAM 'logstrs' section.
5738                  *
5739                  * 'lognums' is an array of indexes for the strings in the
5740                  * 'logstrs' section. The first uint32 is an index to the
5741                  * start of 'logstrs'. Therefore, if this index is divided
5742                  * by 'sizeof(uint32)' it provides the number of logstr
5743                  *    entries.
5744                  */
5745                 ram_index = 0;
5746                 lognums = (uint32 *) raw_fmts;
5747                 logstrs = (char *)    &raw_fmts[num_fmts << 2];
5748             }
5749     }
5750     fmts = MALLOC(osh, num_fmts  * sizeof(char *));
5751     if (fmts == NULL) {
5752         DHD_ERROR(("%s: Failed to allocate fmts memory\n", __FUNCTION__));
5753         return BCME_ERROR;
5754     }
5755     event_log->fmts_size = num_fmts  * sizeof(char *);
5756 
5757     for (i = 0; i < num_fmts; i++) {
5758         /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
5759         * (they are 0-indexed relative to 'rom_logstrs_offset').
5760         *
5761         * RAM lognums are already indexed to point to the correct RAM logstrs (they
5762         * are 0-indexed relative to the start of the logstrs.bin file).
5763         */
5764         if (i == ram_index) {
5765             logstrs = raw_fmts;
5766         }
5767         fmts[i] = &logstrs[lognums[i]];
5768     }
5769     event_log->fmts = fmts;
5770     event_log->raw_fmts_size = logstrs_size;
5771     event_log->raw_fmts = raw_fmts;
5772     event_log->num_fmts = num_fmts;
5773 
5774     return BCME_OK;
5775 }
5776 
dhd_parse_map_file(osl_t * osh,void * file,uint32 * ramstart,uint32 * rodata_start,uint32 * rodata_end)5777 int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart, uint32 *rodata_start,
5778         uint32 *rodata_end)
5779 {
5780     char *raw_fmts =  NULL;
5781     uint32 read_size = READ_NUM_BYTES;
5782     int error = 0;
5783     char *cptr = NULL;
5784     char c;
5785     uint8 count = 0;
5786 
5787     *ramstart = 0;
5788     *rodata_start = 0;
5789     *rodata_end = 0;
5790 
5791     /* Allocate 1 byte more than read_size to terminate it with NULL */
5792     raw_fmts = MALLOC(osh, read_size + 1);
5793     if (raw_fmts == NULL) {
5794         DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__));
5795         goto fail;
5796     }
5797 
5798     /* read ram start, rodata_start and rodata_end values from map  file */
5799     while (count != ALL_MAP_VAL)
5800     {
5801         error = dhd_os_read_file(file, raw_fmts, read_size);
5802         if (error < 0) {
5803             DHD_ERROR(("%s: map file read failed err:%d \n", __FUNCTION__,
5804                     error));
5805             goto fail;
5806         }
5807 
5808         /* End raw_fmts with NULL as strstr expects NULL terminated strings */
5809         raw_fmts[read_size] = '\0';
5810 
5811         /* Get ramstart address */
5812         if ((cptr = strstr(raw_fmts, ramstart_str))) {
5813             cptr = cptr - BYTES_AHEAD_NUM;
5814             sscanf(cptr, "%x %c text_start", ramstart, &c);
5815             count |= RAMSTART_BIT;
5816         }
5817 
5818         /* Get ram rodata start address */
5819         if ((cptr = strstr(raw_fmts, rodata_start_str))) {
5820             cptr = cptr - BYTES_AHEAD_NUM;
5821             sscanf(cptr, "%x %c rodata_start", rodata_start, &c);
5822             count |= RDSTART_BIT;
5823         }
5824 
5825         /* Get ram rodata end address */
5826         if ((cptr = strstr(raw_fmts, rodata_end_str))) {
5827             cptr = cptr - BYTES_AHEAD_NUM;
5828             sscanf(cptr, "%x %c rodata_end", rodata_end, &c);
5829             count |= RDEND_BIT;
5830         }
5831 
5832         if (error < (int)read_size) {
5833             /*
5834             * since we reset file pos back to earlier pos by
5835             * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
5836             * The reason for this is if string is spreaded across
5837             * bytes, the read function should not miss it.
5838             * So if ret value is less than read_size, reached EOF don't read further
5839             */
5840             break;
5841         }
5842         memset(raw_fmts, 0, read_size);
5843         /*
5844         * go back to predefined NUM of bytes so that we won't miss
5845         * the string and  addr even if it comes as splited in next read.
5846         */
5847         dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES);
5848     }
5849 
5850 
5851 fail:
5852     if (raw_fmts) {
5853         MFREE(osh, raw_fmts, read_size + 1);
5854         raw_fmts = NULL;
5855     }
5856     if (count == ALL_MAP_VAL)
5857         return BCME_OK;
5858     else {
5859         DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__,
5860                 count));
5861         return BCME_ERROR;
5862     }
5863 }
5864 
5865 #ifdef PCIE_FULL_DONGLE
5866 int
dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t * dhdp,void * pktbuf,dhd_event_log_t * event_data)5867 dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf,
5868         dhd_event_log_t *event_data)
5869 {
5870     uint32 infobuf_version;
5871     info_buf_payload_hdr_t *payload_hdr_ptr;
5872     uint16 payload_hdr_type;
5873     uint16 payload_hdr_length;
5874 
5875     DHD_TRACE(("%s:Enter\n", __FUNCTION__));
5876 
5877     if (PKTLEN(dhdp->osh, pktbuf) < sizeof(uint32)) {
5878         DHD_ERROR(("%s: infobuf too small for version field\n",
5879             __FUNCTION__));
5880         goto exit;
5881     }
5882     infobuf_version = *((uint32 *)PKTDATA(dhdp->osh, pktbuf));
5883     PKTPULL(dhdp->osh, pktbuf, sizeof(uint32));
5884     if (infobuf_version != PCIE_INFOBUF_V1) {
5885         DHD_ERROR(("%s: infobuf version %d is not PCIE_INFOBUF_V1\n",
5886             __FUNCTION__, infobuf_version));
5887         goto exit;
5888     }
5889 
5890     /* Version 1 infobuf has a single type/length (and then value) field */
5891     if (PKTLEN(dhdp->osh, pktbuf) < sizeof(info_buf_payload_hdr_t)) {
5892         DHD_ERROR(("%s: infobuf too small for v1 type/length  fields\n",
5893             __FUNCTION__));
5894         goto exit;
5895     }
5896     /* Process/parse the common info payload header (type/length) */
5897     payload_hdr_ptr = (info_buf_payload_hdr_t *)PKTDATA(dhdp->osh, pktbuf);
5898     payload_hdr_type = ltoh16(payload_hdr_ptr->type);
5899     payload_hdr_length = ltoh16(payload_hdr_ptr->length);
5900     if (payload_hdr_type != PCIE_INFOBUF_V1_TYPE_LOGTRACE) {
5901         DHD_ERROR(("%s: payload_hdr_type %d is not V1_TYPE_LOGTRACE\n",
5902             __FUNCTION__, payload_hdr_type));
5903         goto exit;
5904     }
5905     PKTPULL(dhdp->osh, pktbuf, sizeof(info_buf_payload_hdr_t));
5906 
5907     /* Validate that the specified length isn't bigger than the
5908      * provided data.
5909      */
5910     if (payload_hdr_length > PKTLEN(dhdp->osh, pktbuf)) {
5911         DHD_ERROR(("%s: infobuf logtrace length is bigger"
5912             " than actual buffer data\n", __FUNCTION__));
5913         goto exit;
5914     }
5915     dhd_dbg_trace_evnt_handler(dhdp, PKTDATA(dhdp->osh, pktbuf),
5916         event_data, payload_hdr_length);
5917 
5918     return BCME_OK;
5919 
5920 exit:
5921     return BCME_ERROR;
5922 }
5923 #endif /* PCIE_FULL_DONGLE */
5924 #endif /* SHOW_LOGTRACE */
5925 
5926 #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
5927 
5928 /* To handle the TDLS event in the dhd_common.c
5929  */
dhd_tdls_event_handler(dhd_pub_t * dhd_pub,wl_event_msg_t * event)5930 int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event)
5931 {
5932     int ret = BCME_OK;
5933 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5934 #pragma GCC diagnostic push
5935 #pragma GCC diagnostic ignored "-Wcast-qual"
5936 #endif
5937     ret = dhd_tdls_update_peer_info(dhd_pub, event);
5938 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
5939 #pragma GCC diagnostic pop
5940 #endif
5941     return ret;
5942 }
5943 
dhd_free_tdls_peer_list(dhd_pub_t * dhd_pub)5944 int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub)
5945 {
5946     tdls_peer_node_t *cur = NULL, *prev = NULL;
5947     if (!dhd_pub)
5948         return BCME_ERROR;
5949     cur = dhd_pub->peer_tbl.node;
5950 
5951     if ((dhd_pub->peer_tbl.node == NULL) && !dhd_pub->peer_tbl.tdls_peer_count)
5952         return BCME_ERROR;
5953 
5954     while (cur != NULL) {
5955         prev = cur;
5956         cur = cur->next;
5957         MFREE(dhd_pub->osh, prev, sizeof(tdls_peer_node_t));
5958     }
5959     dhd_pub->peer_tbl.tdls_peer_count = 0;
5960     dhd_pub->peer_tbl.node = NULL;
5961     return BCME_OK;
5962 }
5963 #endif    /* #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */
5964 
5965 #ifdef DUMP_IOCTL_IOV_LIST
5966 void
dhd_iov_li_append(dhd_pub_t * dhd,dll_t * list_head,dll_t * node)5967 dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node)
5968 {
5969     dll_t *item;
5970     dhd_iov_li_t *iov_li;
5971     dhd->dump_iovlist_len++;
5972 
5973     if (dhd->dump_iovlist_len == IOV_LIST_MAX_LEN+1) {
5974         item = dll_head_p(list_head);
5975         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
5976         dll_delete(item);
5977         MFREE(dhd->osh, iov_li, sizeof(*iov_li));
5978         dhd->dump_iovlist_len--;
5979     }
5980     dll_append(list_head, node);
5981 }
5982 
5983 void
dhd_iov_li_print(dll_t * list_head)5984 dhd_iov_li_print(dll_t *list_head)
5985 {
5986     dhd_iov_li_t *iov_li;
5987     dll_t *item, *next;
5988     uint8 index = 0;
5989     for (item = dll_head_p(list_head); !dll_end(list_head, item); item = next) {
5990         next = dll_next_p(item);
5991         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
5992         index++;
5993         DHD_ERROR(("%d:cmd_name = %s, cmd = %d.\n", index, iov_li->buff, iov_li->cmd));
5994     }
5995 }
5996 
5997 void
dhd_iov_li_delete(dhd_pub_t * dhd,dll_t * list_head)5998 dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head)
5999 {
6000     dll_t *item;
6001     dhd_iov_li_t *iov_li;
6002     while (!(dll_empty(list_head))) {
6003         item = dll_head_p(list_head);
6004         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
6005         dll_delete(item);
6006         MFREE(dhd->osh, iov_li, sizeof(*iov_li));
6007     }
6008 }
6009 #endif /* DUMP_IOCTL_IOV_LIST */
6010