• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Broadcom Dongle Host Driver (DHD), common DHD core.
3  *
4  * Copyright (C) 1999-2019, Broadcom.
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
16  * of the license of that module.  An independent module is a module which is
17  * not 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 826445 2019-06-20 04:47:47Z $
28  */
29 #include <typedefs.h>
30 #include <osl.h>
31 
32 #include <epivers.h>
33 #include <bcmutils.h>
34 #include <bcmstdlib_s.h>
35 
36 #include <bcmendian.h>
37 #include <dngl_stats.h>
38 #include <dhd.h>
39 #include <dhd_ip.h>
40 #include <bcmevent.h>
41 #include <dhdioctl.h>
42 
43 #ifdef PCIE_FULL_DONGLE
44 #include <bcmmsgbuf.h>
45 #endif /* PCIE_FULL_DONGLE */
46 
47 #ifdef SHOW_LOGTRACE
48 #include <event_log.h>
49 #endif /* SHOW_LOGTRACE */
50 
51 #ifdef BCMPCIE
52 #include <dhd_flowring.h>
53 #endif // endif
54 
55 #include <dhd_bus.h>
56 #include <dhd_proto.h>
57 #include <bcmsdbus.h>
58 #include <dhd_dbg.h>
59 #include <802.1d.h>
60 #include <dhd_debug.h>
61 #include <dhd_dbg_ring.h>
62 #include <dhd_mschdbg.h>
63 #include <msgtrace.h>
64 #include <dhd_config.h>
65 #include <wl_android.h>
66 
67 #ifdef WL_CFG80211
68 #include <wl_cfg80211.h>
69 #endif // endif
70 #if defined(PNO_SUPPORT)
71 #include <dhd_pno.h>
72 #endif /* OEM_ANDROID && PNO_SUPPORT */
73 #ifdef RTT_SUPPORT
74 #include <dhd_rtt.h>
75 #endif // endif
76 
77 #ifdef DNGL_EVENT_SUPPORT
78 #include <dnglevent.h>
79 #endif // endif
80 
81 #define htod32(i) (i)
82 #define htod16(i) (i)
83 #define dtoh32(i) (i)
84 #define dtoh16(i) (i)
85 #define htodchanspec(i) (i)
86 #define dtohchanspec(i) (i)
87 
88 #ifdef PROP_TXSTATUS
89 #include <wlfc_proto.h>
90 #include <dhd_wlfc.h>
91 #endif // endif
92 
93 #if defined(DHD_POST_EAPOL_M1_AFTER_ROAM_EVT)
94 #include <dhd_linux.h>
95 #endif // endif
96 
97 #ifdef DHD_L2_FILTER
98 #include <dhd_l2_filter.h>
99 #endif /* DHD_L2_FILTER */
100 
101 #ifdef DHD_PSTA
102 #include <dhd_psta.h>
103 #endif /* DHD_PSTA */
104 
105 #ifdef DHD_WET
106 #include <dhd_wet.h>
107 #endif /* DHD_WET */
108 
109 #ifdef DHD_LOG_DUMP
110 #include <dhd_dbg.h>
111 #endif /* DHD_LOG_DUMP */
112 
113 #ifdef DHD_LOG_PRINT_RATE_LIMIT
114 int log_print_threshold = 0;
115 #endif /* DHD_LOG_PRINT_RATE_LIMIT */
116 int dhd_msg_level = DHD_ERROR_VAL | DHD_FWLOG_VAL; // | DHD_EVENT_VAL
117 /* For CUSTOMER_HW4 do not enable DHD_IOVAR_MEM_VAL by default */
118 //	| DHD_PKT_MON_VAL;
119 
120 #if defined(WL_WIRELESS_EXT)
121 #include <wl_iw.h>
122 #endif // endif
123 
124 #ifdef DHD_ULP
125 #include <dhd_ulp.h>
126 #endif /* DHD_ULP */
127 
128 #ifdef DHD_DEBUG
129 #include <sdiovar.h>
130 #endif /* DHD_DEBUG */
131 
132 #ifdef DHD_PCIE_NATIVE_RUNTIMEPM
133 #include <linux/pm_runtime.h>
134 #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
135 
136 #ifdef CSI_SUPPORT
137 #include <dhd_csi.h>
138 #endif /* CSI_SUPPORT */
139 
140 #ifdef SOFTAP
141 char fw_path2[MOD_PARAM_PATHLEN];
142 extern bool softap_enabled;
143 #endif // endif
144 #ifdef PROP_TXSTATUS
145 extern int disable_proptx;
146 #endif /* PROP_TXSTATUS */
147 
148 #ifdef SHOW_LOGTRACE
149 #define BYTES_AHEAD_NUM 10  /* address in map file is before these many bytes  \
150                              */
151 #define READ_NUM_BYTES 1000 /* read map file each time this No. of bytes */
152 #define GO_BACK_FILE_POS_NUM_BYTES 100 /* set file pos back to cur pos */
153 static char *ramstart_str =
154     " text_start"; /* string in mapfile has addr ramstart */
155 static char *rodata_start_str =
156     " rodata_start"; /* string in mapfile has addr rodata start */
157 static char *rodata_end_str =
158     " rodata_end"; /* string in mapfile has addr rodata end */
159 #define RAMSTART_BIT 0x01
160 #define RDSTART_BIT 0x02
161 #define RDEND_BIT 0x04
162 #define ALL_MAP_VAL (RAMSTART_BIT | RDSTART_BIT | RDEND_BIT)
163 #endif /* SHOW_LOGTRACE */
164 
165 #ifdef SHOW_LOGTRACE
166 /* the fw file path is taken from either the module parameter at
167  * insmod time or is defined as a constant of different values
168  * for different platforms
169  */
170 extern char *st_str_file_path;
171 #endif /* SHOW_LOGTRACE */
172 
173 #define DHD_TPUT_MAX_TX_PKTS_BATCH 1000
174 
175 #ifdef EWP_EDL
176 typedef struct msg_hdr_edl {
177     uint32 infobuf_ver;
178     info_buf_payload_hdr_t pyld_hdr;
179     msgtrace_hdr_t trace_hdr;
180 } msg_hdr_edl_t;
181 #endif /* EWP_EDL */
182 
183 /* Last connection success/failure status */
184 uint32 dhd_conn_event;
185 uint32 dhd_conn_status;
186 uint32 dhd_conn_reason;
187 
188 extern int dhd_iscan_request(void *dhdp, uint16 action);
189 extern void dhd_ind_scan_confirm(void *h, bool status);
190 extern int dhd_iscan_in_progress(void *h);
191 void dhd_iscan_lock(void);
192 void dhd_iscan_unlock(void);
193 extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx);
194 #if !defined(AP) && defined(WLP2P)
195 extern int dhd_get_concurrent_capabilites(dhd_pub_t *dhd);
196 #endif // endif
197 
198 extern int dhd_socram_dump(struct dhd_bus *bus);
199 extern void dhd_set_packet_filter(dhd_pub_t *dhd);
200 
201 #ifdef DNGL_EVENT_SUPPORT
202 static void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
203                                     bcm_dngl_event_msg_t *dngl_event,
204                                     size_t pktlen);
205 static int dngl_host_event(dhd_pub_t *dhdp, void *pktdata,
206                            bcm_dngl_event_msg_t *dngl_event, size_t pktlen);
207 #endif /* DNGL_EVENT_SUPPORT */
208 
209 #define MAX_CHUNK_LEN 1408 /* 8 * 8 * 22 */
210 
211 bool ap_cfg_running = FALSE;
212 bool ap_fw_loaded = FALSE;
213 
214 #ifdef WLEASYMESH
215 extern int dhd_set_1905_almac(dhd_pub_t *dhdp, uint8 ifidx, uint8 *ea,
216                               bool mcast);
217 extern int dhd_get_1905_almac(dhd_pub_t *dhdp, uint8 ifidx, uint8 *ea,
218                               bool mcast);
219 #endif /* WLEASYMESH */
220 
221 #define CHIPID_MISMATCH 8
222 
223 #define DHD_VERSION "Dongle Host Driver, version " EPI_VERSION_STR "\n"
224 
225 #if defined(DHD_DEBUG) && defined(DHD_COMPILED)
226 const char dhd_version[] = DHD_VERSION DHD_COMPILED
227     " compiled on " __DATE__ " at " __TIME__ "\n\0<TIMESTAMP>";
228 #else
229 const char dhd_version[] = DHD_VERSION;
230 #endif /* DHD_DEBUG && DHD_COMPILED */
231 
232 char fw_version[FW_VER_STR_LEN] = "\0";
233 char clm_version[CLM_VER_STR_LEN] = "\0";
234 
235 char bus_api_revision[BUS_API_REV_STR_LEN] = "\0";
236 
237 void dhd_set_timer(void *bus, uint wdtick);
238 
239 static char *ioctl2str(uint32 ioctl);
240 
241 /* IOVar table */
242 enum {
243     IOV_VERSION = 1,
244     IOV_WLMSGLEVEL,
245     IOV_MSGLEVEL,
246     IOV_BCMERRORSTR,
247     IOV_BCMERROR,
248     IOV_WDTICK,
249     IOV_DUMP,
250     IOV_CLEARCOUNTS,
251     IOV_LOGDUMP,
252     IOV_LOGCAL,
253     IOV_LOGSTAMP,
254     IOV_GPIOOB,
255     IOV_IOCTLTIMEOUT,
256     IOV_CONS,
257     IOV_DCONSOLE_POLL,
258 #if defined(DHD_DEBUG)
259     IOV_DHD_JOIN_TIMEOUT_DBG,
260     IOV_SCAN_TIMEOUT,
261     IOV_MEM_DEBUG,
262 #ifdef BCMPCIE
263     IOV_FLOW_RING_DEBUG,
264 #endif /* BCMPCIE */
265 #endif /* defined(DHD_DEBUG) */
266 #ifdef PROP_TXSTATUS
267     IOV_PROPTXSTATUS_ENABLE,
268     IOV_PROPTXSTATUS_MODE,
269     IOV_PROPTXSTATUS_OPT,
270     IOV_PROPTXSTATUS_MODULE_IGNORE,
271     IOV_PROPTXSTATUS_CREDIT_IGNORE,
272     IOV_PROPTXSTATUS_TXSTATUS_IGNORE,
273     IOV_PROPTXSTATUS_RXPKT_CHK,
274 #endif /* PROP_TXSTATUS */
275     IOV_BUS_TYPE,
276     IOV_CHANGEMTU,
277     IOV_HOSTREORDER_FLOWS,
278 #ifdef DHDTCPACK_SUPPRESS
279     IOV_TCPACK_SUPPRESS,
280 #endif /* DHDTCPACK_SUPPRESS */
281     IOV_AP_ISOLATE,
282 #ifdef DHD_L2_FILTER
283     IOV_DHCP_UNICAST,
284     IOV_BLOCK_PING,
285     IOV_PROXY_ARP,
286     IOV_GRAT_ARP,
287     IOV_BLOCK_TDLS,
288 #endif /* DHD_L2_FILTER */
289     IOV_DHD_IE,
290 #ifdef DHD_PSTA
291     IOV_PSTA,
292 #endif /* DHD_PSTA */
293 #ifdef DHD_WET
294     IOV_WET,
295     IOV_WET_HOST_IPV4,
296     IOV_WET_HOST_MAC,
297 #endif /* DHD_WET */
298     IOV_CFG80211_OPMODE,
299     IOV_ASSERT_TYPE,
300     IOV_LMTEST,
301 #ifdef DHD_MCAST_REGEN
302     IOV_MCAST_REGEN_BSS_ENABLE,
303 #endif // endif
304 #ifdef SHOW_LOGTRACE
305     IOV_DUMP_TRACE_LOG,
306 #endif /* SHOW_LOGTRACE */
307     IOV_DONGLE_TRAP_TYPE,
308     IOV_DONGLE_TRAP_INFO,
309     IOV_BPADDR,
310     IOV_DUMP_DONGLE, /**< dumps core registers and d11 memories */
311 #if defined(DHD_LOG_DUMP)
312     IOV_LOG_DUMP,
313 #endif /* DHD_LOG_DUMP */
314     IOV_TPUT_TEST,
315     IOV_FIS_TRIGGER,
316     IOV_DEBUG_BUF_DEST_STAT,
317 #ifdef DHD_DEBUG
318     IOV_INDUCE_ERROR,
319 #endif /* DHD_DEBUG */
320 #ifdef WL_IFACE_MGMT_CONF
321 #ifdef WL_CFG80211
322 #ifdef WL_NANP2P
323     IOV_CONC_DISC,
324 #endif /* WL_NANP2P */
325 #ifdef WL_IFACE_MGMT
326     IOV_IFACE_POLICY,
327 #endif /* WL_IFACE_MGMT */
328 #endif /* WL_CFG80211 */
329 #endif /* WL_IFACE_MGMT_CONF */
330 #ifdef RTT_GEOFENCE_CONT
331 #if defined(RTT_SUPPORT) && defined(WL_NAN)
332     IOV_RTT_GEOFENCE_TYPE_OVRD,
333 #endif /* RTT_SUPPORT && WL_NAN */
334 #endif /* RTT_GEOFENCE_CONT */
335 #ifdef WLEASYMESH
336     IOV_1905_AL_UCAST,
337     IOV_1905_AL_MCAST,
338 #endif /* WLEASYMESH */
339     IOV_LAST
340 };
341 
342 const bcm_iovar_t dhd_iovars[] = {
343     /* name         varid                   flags   flags2 type     minlen */
344     {"version", IOV_VERSION, 0, 0, IOVT_BUFFER, sizeof(dhd_version)},
345     {"wlmsglevel", IOV_WLMSGLEVEL, 0, 0, IOVT_UINT32, 0},
346 #ifdef DHD_DEBUG
347     {"msglevel", IOV_MSGLEVEL, 0, 0, IOVT_UINT32, 0},
348     {"mem_debug", IOV_MEM_DEBUG, 0, 0, IOVT_BUFFER, 0},
349 #ifdef BCMPCIE
350     {"flow_ring_debug", IOV_FLOW_RING_DEBUG, 0, 0, IOVT_BUFFER, 0},
351 #endif /* BCMPCIE */
352 #endif /* DHD_DEBUG */
353     {"bcmerrorstr", IOV_BCMERRORSTR, 0, 0, IOVT_BUFFER, BCME_STRLEN},
354     {"bcmerror", IOV_BCMERROR, 0, 0, IOVT_INT8, 0},
355     {"wdtick", IOV_WDTICK, 0, 0, IOVT_UINT32, 0},
356     {"dump", IOV_DUMP, 0, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN},
357     {"cons", IOV_CONS, 0, 0, IOVT_BUFFER, 0},
358     {"dconpoll", IOV_DCONSOLE_POLL, 0, 0, IOVT_UINT32, 0},
359     {"clearcounts", IOV_CLEARCOUNTS, 0, 0, IOVT_VOID, 0},
360     {"gpioob", IOV_GPIOOB, 0, 0, IOVT_UINT32, 0},
361     {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, 0, IOVT_UINT32, 0},
362 #ifdef PROP_TXSTATUS
363     {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, 0, IOVT_BOOL, 0},
364     /*
365     set the proptxtstatus operation mode:
366     0 - Do not do any proptxtstatus flow control
367     1 - Use implied credit from a packet status
368     2 - Use explicit credit
369     */
370     {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, 0, IOVT_UINT32, 0},
371     {"proptx_opt", IOV_PROPTXSTATUS_OPT, 0, 0, IOVT_UINT32, 0},
372     {"pmodule_ignore", IOV_PROPTXSTATUS_MODULE_IGNORE, 0, 0, IOVT_BOOL, 0},
373     {"pcredit_ignore", IOV_PROPTXSTATUS_CREDIT_IGNORE, 0, 0, IOVT_BOOL, 0},
374     {"ptxstatus_ignore", IOV_PROPTXSTATUS_TXSTATUS_IGNORE, 0, 0, IOVT_BOOL, 0},
375     {"rxpkt_chk", IOV_PROPTXSTATUS_RXPKT_CHK, 0, 0, IOVT_BOOL, 0},
376 #endif /* PROP_TXSTATUS */
377     {"bustype", IOV_BUS_TYPE, 0, 0, IOVT_UINT32, 0},
378     {"changemtu", IOV_CHANGEMTU, 0, 0, IOVT_UINT32, 0},
379     {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, 0, IOVT_BUFFER,
380      (WLHOST_REORDERDATA_MAXFLOWS + 1)},
381 #ifdef DHDTCPACK_SUPPRESS
382     {"tcpack_suppress", IOV_TCPACK_SUPPRESS, 0, 0, IOVT_UINT8, 0},
383 #endif /* DHDTCPACK_SUPPRESS */
384 #ifdef DHD_L2_FILTER
385     {"dhcp_unicast", IOV_DHCP_UNICAST, (0), 0, IOVT_BOOL, 0},
386 #endif /* DHD_L2_FILTER */
387     {"ap_isolate", IOV_AP_ISOLATE, (0), 0, IOVT_BOOL, 0},
388 #ifdef DHD_L2_FILTER
389     {"block_ping", IOV_BLOCK_PING, (0), 0, IOVT_BOOL, 0},
390     {"proxy_arp", IOV_PROXY_ARP, (0), 0, IOVT_BOOL, 0},
391     {"grat_arp", IOV_GRAT_ARP, (0), 0, IOVT_BOOL, 0},
392     {"block_tdls", IOV_BLOCK_TDLS, (0), IOVT_BOOL, 0},
393 #endif /* DHD_L2_FILTER */
394     {"dhd_ie", IOV_DHD_IE, (0), 0, IOVT_BUFFER, 0},
395 #ifdef DHD_PSTA
396     /* PSTA/PSR Mode configuration. 0: DIABLED 1: PSTA 2: PSR */
397     {"psta", IOV_PSTA, 0, 0, IOVT_UINT32, 0},
398 #endif /* DHD PSTA */
399 #ifdef DHD_WET
400     /* WET Mode configuration. 0: DIABLED 1: WET */
401     {"wet", IOV_WET, 0, 0, IOVT_UINT32, 0},
402     {"wet_host_ipv4", IOV_WET_HOST_IPV4, 0, 0, IOVT_UINT32, 0},
403     {"wet_host_mac", IOV_WET_HOST_MAC, 0, 0, IOVT_BUFFER, 0},
404 #endif /* DHD WET */
405     {"op_mode", IOV_CFG80211_OPMODE, 0, 0, IOVT_UINT32, 0},
406     {"assert_type", IOV_ASSERT_TYPE, (0), 0, IOVT_UINT32, 0},
407     {"lmtest", IOV_LMTEST, 0, 0, IOVT_UINT32, 0},
408 #ifdef DHD_MCAST_REGEN
409     {"mcast_regen_bss_enable", IOV_MCAST_REGEN_BSS_ENABLE, 0, 0, IOVT_BOOL, 0},
410 #endif // endif
411 #ifdef SHOW_LOGTRACE
412     {"dump_trace_buf", IOV_DUMP_TRACE_LOG, 0, 0, IOVT_BUFFER,
413      sizeof(trace_buf_info_t)},
414 #endif /* SHOW_LOGTRACE */
415     {"trap_type", IOV_DONGLE_TRAP_TYPE, 0, 0, IOVT_UINT32, 0},
416     {"trap_info", IOV_DONGLE_TRAP_INFO, 0, 0, IOVT_BUFFER, sizeof(trap_t)},
417 #ifdef DHD_DEBUG
418     {"bpaddr", IOV_BPADDR, 0, 0, IOVT_BUFFER, sizeof(sdreg_t)},
419 #endif /* DHD_DEBUG */
420     {"dump_dongle", IOV_DUMP_DONGLE, 0, 0, IOVT_BUFFER,
421      MAX(sizeof(dump_dongle_in_t), sizeof(dump_dongle_out_t))},
422 #if defined(DHD_LOG_DUMP)
423     {"log_dump", IOV_LOG_DUMP, 0, 0, IOVT_UINT8, 0},
424 #endif /* DHD_LOG_DUMP */
425     {"debug_buf_dest_stat", IOV_DEBUG_BUF_DEST_STAT, 0, 0, IOVT_UINT32, 0},
426 #ifdef DHD_DEBUG
427     {"induce_error", IOV_INDUCE_ERROR, (0), 0, IOVT_UINT16, 0},
428 #endif /* DHD_DEBUG */
429 #ifdef WL_IFACE_MGMT_CONF
430 #ifdef WL_CFG80211
431 #ifdef WL_NANP2P
432     {"conc_disc", IOV_CONC_DISC, (0), 0, IOVT_UINT16, 0},
433 #endif /* WL_NANP2P */
434 #ifdef WL_IFACE_MGMT
435     {"if_policy", IOV_IFACE_POLICY, (0), 0, IOVT_BUFFER,
436      sizeof(iface_mgmt_data_t)},
437 #endif /* WL_IFACE_MGMT */
438 #endif /* WL_CFG80211 */
439 #endif /* WL_IFACE_MGMT_CONF */
440 #ifdef RTT_GEOFENCE_CONT
441 #if defined(RTT_SUPPORT) && defined(WL_NAN)
442     {"rtt_geofence_type_ovrd", IOV_RTT_GEOFENCE_TYPE_OVRD, (0), 0, IOVT_BOOL,
443      0},
444 #endif /* RTT_SUPPORT && WL_NAN */
445 #endif /* RTT_GEOFENCE_CONT */
446 #ifdef WLEASYMESH
447     {"1905_al_ucast", IOV_1905_AL_UCAST, 0, 0, IOVT_BUFFER, ETHER_ADDR_LEN},
448     {"1905_al_mcast", IOV_1905_AL_MCAST, 0, 0, IOVT_BUFFER, ETHER_ADDR_LEN},
449 #endif /* WLEASYMESH */
450     {NULL, 0, 0, 0, 0, 0}};
451 
452 #define DHD_IOVAR_BUF_SIZE 128
453 
dhd_query_bus_erros(dhd_pub_t * dhdp)454 bool dhd_query_bus_erros(dhd_pub_t *dhdp)
455 {
456     bool ret = FALSE;
457 
458     if (dhdp->dongle_reset) {
459         DHD_ERROR_RLMT(
460             ("%s: Dongle Reset occurred, cannot proceed\n", __FUNCTION__));
461         ret = TRUE;
462     }
463 
464     if (dhdp->dongle_trap_occured) {
465         DHD_ERROR_RLMT(
466             ("%s: FW TRAP has occurred, cannot proceed\n", __FUNCTION__));
467         ret = TRUE;
468         dhdp->hang_reason = HANG_REASON_DONGLE_TRAP;
469         dhd_os_send_hang_message(dhdp);
470     }
471 
472     if (dhdp->iovar_timeout_occured) {
473         DHD_ERROR_RLMT(
474             ("%s: Resumed on timeout for previous IOVAR, cannot proceed\n",
475              __FUNCTION__));
476         ret = TRUE;
477     }
478 
479 #ifdef PCIE_FULL_DONGLE
480     if (dhdp->d3ack_timeout_occured) {
481         DHD_ERROR_RLMT(
482             ("%s: Resumed on timeout for previous D3ACK, cannot proceed\n",
483              __FUNCTION__));
484         ret = TRUE;
485     }
486     if (dhdp->livelock_occured) {
487         DHD_ERROR_RLMT(
488             ("%s: LIVELOCK occurred for previous msg, cannot proceed\n",
489              __FUNCTION__));
490         ret = TRUE;
491     }
492 
493     if (dhdp->pktid_audit_failed) {
494         DHD_ERROR_RLMT(
495             ("%s: pktid_audit_failed, cannot proceed\n", __FUNCTION__));
496         ret = TRUE;
497     }
498 #endif /* PCIE_FULL_DONGLE */
499 
500     if (dhdp->iface_op_failed) {
501         DHD_ERROR_RLMT(("%s: iface_op_failed, cannot proceed\n", __FUNCTION__));
502         ret = TRUE;
503     }
504 
505     if (dhdp->scan_timeout_occurred) {
506         DHD_ERROR_RLMT(
507             ("%s: scan_timeout_occurred, cannot proceed\n", __FUNCTION__));
508         ret = TRUE;
509     }
510 
511     if (dhdp->scan_busy_occurred) {
512         DHD_ERROR_RLMT(
513             ("%s: scan_busy_occurred, cannot proceed\n", __FUNCTION__));
514         ret = TRUE;
515     }
516 
517 #ifdef DNGL_AXI_ERROR_LOGGING
518     if (dhdp->axi_error) {
519         DHD_ERROR_RLMT(
520             ("%s: AXI error occurred, cannot proceed\n", __FUNCTION__));
521         ret = TRUE;
522     }
523 #endif /* DNGL_AXI_ERROR_LOGGING */
524 
525     if (dhd_bus_get_linkdown(dhdp)) {
526         DHD_ERROR_RLMT(
527             ("%s : PCIE Link down occurred, cannot proceed\n", __FUNCTION__));
528         ret = TRUE;
529     }
530 
531     if (dhd_bus_get_cto(dhdp)) {
532         DHD_ERROR_RLMT(
533             ("%s : CTO Recovery reported, cannot proceed\n", __FUNCTION__));
534         ret = TRUE;
535     }
536 
537     return ret;
538 }
539 
dhd_clear_bus_errors(dhd_pub_t * dhdp)540 void dhd_clear_bus_errors(dhd_pub_t *dhdp)
541 {
542     if (!dhdp) {
543         return;
544     }
545 
546     dhdp->dongle_reset = FALSE;
547     dhdp->dongle_trap_occured = FALSE;
548     dhdp->iovar_timeout_occured = FALSE;
549 #ifdef PCIE_FULL_DONGLE
550     dhdp->d3ack_timeout_occured = FALSE;
551     dhdp->livelock_occured = FALSE;
552     dhdp->pktid_audit_failed = FALSE;
553 #endif // endif
554     dhdp->iface_op_failed = FALSE;
555     dhdp->scan_timeout_occurred = FALSE;
556     dhdp->scan_busy_occurred = FALSE;
557 }
558 
559 #ifdef DHD_SSSR_DUMP
560 
561 /* This can be overwritten by module parameter defined in dhd_linux.c */
562 uint support_sssr_dump = TRUE;
563 
dhd_sssr_mempool_init(dhd_pub_t * dhd)564 int dhd_sssr_mempool_init(dhd_pub_t *dhd)
565 {
566     dhd->sssr_mempool = (uint8 *)MALLOCZ(dhd->osh, DHD_SSSR_MEMPOOL_SIZE);
567     if (dhd->sssr_mempool == NULL) {
568         DHD_ERROR(("%s: MALLOC of sssr_mempool failed\n", __FUNCTION__));
569         return BCME_ERROR;
570     }
571     return BCME_OK;
572 }
573 
dhd_sssr_mempool_deinit(dhd_pub_t * dhd)574 void dhd_sssr_mempool_deinit(dhd_pub_t *dhd)
575 {
576     if (dhd->sssr_mempool) {
577         MFREE(dhd->osh, dhd->sssr_mempool, DHD_SSSR_MEMPOOL_SIZE);
578         dhd->sssr_mempool = NULL;
579     }
580 }
581 
dhd_dump_sssr_reg_info(sssr_reg_info_v1_t * sssr_reg_info)582 void dhd_dump_sssr_reg_info(sssr_reg_info_v1_t *sssr_reg_info)
583 {
584 }
585 
dhd_get_sssr_reg_info(dhd_pub_t * dhd)586 int dhd_get_sssr_reg_info(dhd_pub_t *dhd)
587 {
588     int ret;
589     /* get sssr_reg_info from firmware */
590     memset((void *)&dhd->sssr_reg_info, 0, sizeof(dhd->sssr_reg_info));
591     ret =
592         dhd_iovar(dhd, 0, "sssr_reg_info", NULL, 0, (char *)&dhd->sssr_reg_info,
593                   sizeof(dhd->sssr_reg_info), FALSE);
594     if (ret < 0) {
595         DHD_ERROR(("%s: sssr_reg_info failed (error=%d)\n", __FUNCTION__, ret));
596         return BCME_ERROR;
597     }
598 
599     dhd_dump_sssr_reg_info(&dhd->sssr_reg_info);
600     return BCME_OK;
601 }
602 
dhd_get_sssr_bufsize(dhd_pub_t * dhd)603 uint32 dhd_get_sssr_bufsize(dhd_pub_t *dhd)
604 {
605     int i;
606     uint32 sssr_bufsize = 0;
607     /* Init all pointers to NULL */
608     for (i = 0; i < MAX_NUM_D11CORES; i++) {
609         sssr_bufsize += dhd->sssr_reg_info.mac_regs[i].sr_size;
610     }
611     sssr_bufsize += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
612 
613     /* Double the size as different dumps will be saved before and after SR */
614     sssr_bufsize = 0x2 * sssr_bufsize;
615 
616     return sssr_bufsize;
617 }
618 
dhd_sssr_dump_init(dhd_pub_t * dhd)619 int dhd_sssr_dump_init(dhd_pub_t *dhd)
620 {
621     int i;
622     uint32 sssr_bufsize;
623     uint32 mempool_used = 0;
624 
625     dhd->sssr_inited = FALSE;
626 
627     if (!support_sssr_dump) {
628         DHD_ERROR(("%s: sssr dump not inited as instructed by mod param\n",
629                    __FUNCTION__));
630         return BCME_OK;
631     }
632 
633     /* check if sssr mempool is allocated */
634     if (dhd->sssr_mempool == NULL) {
635         DHD_ERROR(("%s: sssr_mempool is not allocated\n", __FUNCTION__));
636         return BCME_ERROR;
637     }
638 
639     /* Get SSSR reg info */
640     if (dhd_get_sssr_reg_info(dhd) != BCME_OK) {
641         DHD_ERROR(("%s: dhd_get_sssr_reg_info failed\n", __FUNCTION__));
642         return BCME_ERROR;
643     }
644 
645     /* Validate structure version */
646     if (dhd->sssr_reg_info.version > SSSR_REG_INFO_VER_1) {
647         DHD_ERROR(("%s: dhd->sssr_reg_info.version (%d : %d) mismatch\n",
648                    __FUNCTION__, (int)dhd->sssr_reg_info.version,
649                    SSSR_REG_INFO_VER));
650         return BCME_ERROR;
651     }
652 
653     /* Validate structure length */
654     if (dhd->sssr_reg_info.length < sizeof(sssr_reg_info_v0_t)) {
655         DHD_ERROR(("%s: dhd->sssr_reg_info.length (%d : %d) mismatch\n",
656                    __FUNCTION__, (int)dhd->sssr_reg_info.length,
657                    (int)sizeof(dhd->sssr_reg_info)));
658         return BCME_ERROR;
659     }
660 
661     /* validate fifo size */
662     sssr_bufsize = dhd_get_sssr_bufsize(dhd);
663     if (sssr_bufsize > DHD_SSSR_MEMPOOL_SIZE) {
664         DHD_ERROR(("%s: sssr_bufsize(%d) is greater than sssr_mempool(%d)\n",
665                    __FUNCTION__, (int)sssr_bufsize, DHD_SSSR_MEMPOOL_SIZE));
666         return BCME_ERROR;
667     }
668 
669     /* init all pointers to NULL */
670     for (i = 0; i < MAX_NUM_D11CORES; i++) {
671         dhd->sssr_d11_before[i] = NULL;
672         dhd->sssr_d11_after[i] = NULL;
673     }
674     dhd->sssr_dig_buf_before = NULL;
675     dhd->sssr_dig_buf_after = NULL;
676 
677     /* Allocate memory */
678     for (i = 0; i < MAX_NUM_D11CORES; i++) {
679         if (dhd->sssr_reg_info.mac_regs[i].sr_size) {
680             dhd->sssr_d11_before[i] =
681                 (uint32 *)(dhd->sssr_mempool + mempool_used);
682             mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size;
683 
684             dhd->sssr_d11_after[i] =
685                 (uint32 *)(dhd->sssr_mempool + mempool_used);
686             mempool_used += dhd->sssr_reg_info.mac_regs[i].sr_size;
687         }
688     }
689 
690     if (dhd->sssr_reg_info.vasip_regs.vasip_sr_size) {
691         dhd->sssr_dig_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used);
692         mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
693 
694         dhd->sssr_dig_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
695         mempool_used += dhd->sssr_reg_info.vasip_regs.vasip_sr_size;
696     } else if ((dhd->sssr_reg_info.length >
697                 OFFSETOF(sssr_reg_info_v1_t, dig_mem_info)) &&
698                dhd->sssr_reg_info.dig_mem_info.dig_sr_addr) {
699         dhd->sssr_dig_buf_before = (uint32 *)(dhd->sssr_mempool + mempool_used);
700         mempool_used += dhd->sssr_reg_info.dig_mem_info.dig_sr_size;
701 
702         dhd->sssr_dig_buf_after = (uint32 *)(dhd->sssr_mempool + mempool_used);
703         mempool_used += dhd->sssr_reg_info.dig_mem_info.dig_sr_size;
704     }
705 
706     dhd->sssr_inited = TRUE;
707 
708     return BCME_OK;
709 }
710 
dhd_sssr_dump_deinit(dhd_pub_t * dhd)711 void dhd_sssr_dump_deinit(dhd_pub_t *dhd)
712 {
713     int i;
714 
715     dhd->sssr_inited = FALSE;
716     /* init all pointers to NULL */
717     for (i = 0; i < MAX_NUM_D11CORES; i++) {
718         dhd->sssr_d11_before[i] = NULL;
719         dhd->sssr_d11_after[i] = NULL;
720     }
721     dhd->sssr_dig_buf_before = NULL;
722     dhd->sssr_dig_buf_after = NULL;
723 
724     return;
725 }
726 
dhd_sssr_print_filepath(dhd_pub_t * dhd,char * path)727 void dhd_sssr_print_filepath(dhd_pub_t *dhd, char *path)
728 {
729     bool print_info = FALSE;
730     int dump_mode;
731 
732     if (!dhd || !path) {
733         DHD_ERROR(("%s: dhd or memdump_path is NULL\n", __FUNCTION__));
734         return;
735     }
736 
737     if (!dhd->sssr_dump_collected) {
738         /* SSSR dump is not collected */
739         return;
740     }
741 
742     dump_mode = dhd->sssr_dump_mode;
743 
744     if (bcmstrstr(path, "core_0_before")) {
745         if (dhd->sssr_d11_outofreset[0] && dump_mode == SSSR_DUMP_MODE_SSSR) {
746             print_info = TRUE;
747         }
748     } else if (bcmstrstr(path, "core_0_after")) {
749         if (dhd->sssr_d11_outofreset[0]) {
750             print_info = TRUE;
751         }
752     } else if (bcmstrstr(path, "core_1_before")) {
753         if (dhd->sssr_d11_outofreset[1] && dump_mode == SSSR_DUMP_MODE_SSSR) {
754             print_info = TRUE;
755         }
756     } else if (bcmstrstr(path, "core_1_after")) {
757         if (dhd->sssr_d11_outofreset[1]) {
758             print_info = TRUE;
759         }
760     } else {
761         print_info = TRUE;
762     }
763 
764     if (print_info) {
765         DHD_ERROR(
766             ("%s: file_path = %s%s\n", __FUNCTION__, path, FILE_NAME_HAL_TAG));
767     }
768 }
769 #endif /* DHD_SSSR_DUMP */
770 
771 #ifdef DHD_FW_COREDUMP
dhd_get_fwdump_buf(dhd_pub_t * dhd_pub,uint32 length)772 void *dhd_get_fwdump_buf(dhd_pub_t *dhd_pub, uint32 length)
773 {
774     if (!dhd_pub->soc_ram) {
775 #if defined(CONFIG_DHD_USE_STATIC_BUF) && defined(DHD_USE_STATIC_MEMDUMP)
776         dhd_pub->soc_ram =
777             (uint8 *)DHD_OS_PREALLOC(dhd_pub, DHD_PREALLOC_MEMDUMP_RAM, length);
778 #else
779         dhd_pub->soc_ram = (uint8 *)MALLOC(dhd_pub->osh, length);
780 #endif /* CONFIG_DHD_USE_STATIC_BUF && DHD_USE_STATIC_MEMDUMP */
781     }
782 
783     if (dhd_pub->soc_ram == NULL) {
784         DHD_ERROR(("%s: Failed to allocate memory for fw crash snap shot.\n",
785                    __FUNCTION__));
786         dhd_pub->soc_ram_length = 0;
787     } else {
788         memset(dhd_pub->soc_ram, 0, length);
789         dhd_pub->soc_ram_length = length;
790     }
791 
792     /* soc_ram free handled in dhd_{free,clear} */
793     return dhd_pub->soc_ram;
794 }
795 #endif /* DHD_FW_COREDUMP */
796 
797 /* to NDIS developer, the structure dhd_common is redundant,
798  * please do NOT merge it back from other branches !!!
799  */
800 
dhd_common_socram_dump(dhd_pub_t * dhdp)801 int dhd_common_socram_dump(dhd_pub_t *dhdp)
802 {
803 #ifdef BCMDBUS
804     return 0;
805 #else
806     return dhd_socram_dump(dhdp->bus);
807 #endif /* BCMDBUS */
808 }
809 
dhd_dump(dhd_pub_t * dhdp,char * buf,int buflen)810 int dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen)
811 {
812     struct bcmstrbuf b;
813     struct bcmstrbuf *strbuf = &b;
814 
815     if (!dhdp || !dhdp->prot || !buf) {
816         return BCME_ERROR;
817     }
818 
819     bcm_binit(strbuf, buf, buflen);
820 
821     /* Base DHD info */
822     bcm_bprintf(strbuf, "%s\n", dhd_version);
823     bcm_bprintf(strbuf, "\n");
824     bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", dhdp->up,
825                 dhdp->txoff, dhdp->busstate);
826     bcm_bprintf(strbuf, "pub.hdrlen %u pub.maxctl %u pub.rxsz %u\n",
827                 dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz);
828     bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac " MACDBG "\n",
829                 dhdp->iswl, dhdp->drv_version, MAC2STRDBG(&dhdp->mac));
830     bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %u\n", dhdp->bcmerror,
831                 dhdp->tickcnt);
832 
833     bcm_bprintf(strbuf, "dongle stats:\n");
834     bcm_bprintf(strbuf,
835                 "tx_packets %lu tx_bytes %lu tx_errors %lu tx_dropped %lu\n",
836                 dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes,
837                 dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped);
838     bcm_bprintf(strbuf,
839                 "rx_packets %lu rx_bytes %lu rx_errors %lu rx_dropped %lu\n",
840                 dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes,
841                 dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped);
842     bcm_bprintf(strbuf, "multicast %lu\n", dhdp->dstats.multicast);
843 
844     bcm_bprintf(strbuf, "bus stats:\n");
845     bcm_bprintf(
846         strbuf,
847         "tx_packets %lu  tx_dropped %lu tx_multicast %lu tx_errors %lu\n",
848         dhdp->tx_packets, dhdp->tx_dropped, dhdp->tx_multicast,
849         dhdp->tx_errors);
850     bcm_bprintf(strbuf, "tx_ctlpkts %lu tx_ctlerrs %lu\n", dhdp->tx_ctlpkts,
851                 dhdp->tx_ctlerrs);
852     bcm_bprintf(strbuf, "rx_packets %lu rx_multicast %lu rx_errors %lu \n",
853                 dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors);
854     bcm_bprintf(strbuf, "rx_ctlpkts %lu rx_ctlerrs %lu rx_dropped %lu\n",
855                 dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped);
856     bcm_bprintf(strbuf, "rx_readahead_cnt %lu tx_realloc %lu\n",
857                 dhdp->rx_readahead_cnt, dhdp->tx_realloc);
858     bcm_bprintf(strbuf, "tx_pktgetfail %lu rx_pktgetfail %lu\n",
859                 dhdp->tx_pktgetfail, dhdp->rx_pktgetfail);
860     bcm_bprintf(strbuf, "tx_big_packets %lu\n", dhdp->tx_big_packets);
861     bcm_bprintf(strbuf, "\n");
862 #ifdef DMAMAP_STATS
863     /* Add DMA MAP info */
864     bcm_bprintf(strbuf, "DMA MAP stats: \n");
865     bcm_bprintf(strbuf, "txdata: %lu size: %luK, rxdata: %lu size: %luK\n",
866                 dhdp->dma_stats.txdata, KB(dhdp->dma_stats.txdata_sz),
867                 dhdp->dma_stats.rxdata, KB(dhdp->dma_stats.rxdata_sz));
868 #ifndef IOCTLRESP_USE_CONSTMEM
869     bcm_bprintf(strbuf, "IOCTL RX: %lu size: %luK ,", dhdp->dma_stats.ioctl_rx,
870                 KB(dhdp->dma_stats.ioctl_rx_sz));
871 #endif /* !IOCTLRESP_USE_CONSTMEM */
872     bcm_bprintf(strbuf,
873                 "EVENT RX: %lu size: %luK, INFO RX: %lu size: %luK, "
874                 "TSBUF RX: %lu size %luK\n",
875                 dhdp->dma_stats.event_rx, KB(dhdp->dma_stats.event_rx_sz),
876                 dhdp->dma_stats.info_rx, KB(dhdp->dma_stats.info_rx_sz),
877                 dhdp->dma_stats.tsbuf_rx, KB(dhdp->dma_stats.tsbuf_rx_sz));
878     bcm_bprintf(strbuf, "Total : %luK \n",
879                 KB(dhdp->dma_stats.txdata_sz + dhdp->dma_stats.rxdata_sz +
880                    dhdp->dma_stats.ioctl_rx_sz + dhdp->dma_stats.event_rx_sz +
881                    dhdp->dma_stats.tsbuf_rx_sz));
882 #endif /* DMAMAP_STATS */
883     bcm_bprintf(strbuf, "dhd_induce_error : %u\n", dhdp->dhd_induce_error);
884     /* Add any prot info */
885     dhd_prot_dump(dhdp, strbuf);
886     bcm_bprintf(strbuf, "\n");
887 
888     /* Add any bus info */
889     dhd_bus_dump(dhdp, strbuf);
890 
891 #if defined(DHD_LB_STATS)
892     dhd_lb_stats_dump(dhdp, strbuf);
893 #endif /* DHD_LB_STATS */
894 #ifdef DHD_WET
895     if (dhd_get_wet_mode(dhdp)) {
896         bcm_bprintf(strbuf, "Wet Dump:\n");
897         dhd_wet_dump(dhdp, strbuf);
898     }
899 #endif /* DHD_WET */
900 
901     /* return remaining buffer length */
902     return (!strbuf->size ? BCME_BUFTOOSHORT : strbuf->size);
903 }
904 
dhd_dump_to_kernelog(dhd_pub_t * dhdp)905 void dhd_dump_to_kernelog(dhd_pub_t *dhdp)
906 {
907     char buf[512];
908 
909     DHD_ERROR(("F/W version: %s\n", fw_version));
910     bcm_bprintf_bypass = TRUE;
911     dhd_dump(dhdp, buf, sizeof(buf));
912     bcm_bprintf_bypass = FALSE;
913 }
914 
dhd_wl_ioctl_cmd(dhd_pub_t * dhd_pub,int cmd,void * arg,int len,uint8 set,int ifidx)915 int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set,
916                      int ifidx)
917 {
918     wl_ioctl_t ioc;
919 
920     ioc.cmd = cmd;
921     ioc.buf = arg;
922     ioc.len = len;
923     ioc.set = set;
924 
925     return dhd_wl_ioctl(dhd_pub, ifidx, &ioc, arg, len);
926 }
927 
dhd_wl_ioctl_get_intiovar(dhd_pub_t * dhd_pub,char * name,uint * pval,int cmd,uint8 set,int ifidx)928 int dhd_wl_ioctl_get_intiovar(dhd_pub_t *dhd_pub, char *name, uint *pval,
929                               int cmd, uint8 set, int ifidx)
930 {
931     char iovbuf[WLC_IOCTL_SMLEN];
932     int ret = -1;
933 
934     memset(iovbuf, 0, sizeof(iovbuf));
935     if (bcm_mkiovar(name, NULL, 0, iovbuf, sizeof(iovbuf))) {
936         ret =
937             dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, sizeof(iovbuf), set, ifidx);
938         if (!ret) {
939             *pval = ltoh32(*((uint *)iovbuf));
940         } else {
941             DHD_ERROR(("%s: get int iovar %s failed, ERR %d\n", __FUNCTION__,
942                        name, ret));
943         }
944     } else {
945         DHD_ERROR(("%s: mkiovar %s failed\n", __FUNCTION__, name));
946     }
947 
948     return ret;
949 }
950 
dhd_wl_ioctl_set_intiovar(dhd_pub_t * dhd_pub,char * name,uint val,int cmd,uint8 set,int ifidx)951 int dhd_wl_ioctl_set_intiovar(dhd_pub_t *dhd_pub, char *name, uint val, int cmd,
952                               uint8 set, int ifidx)
953 {
954     char iovbuf[WLC_IOCTL_SMLEN];
955     int ret = -1;
956     int lval = htol32(val);
957     uint len;
958 
959     len =
960         bcm_mkiovar(name, (char *)&lval, sizeof(lval), iovbuf, sizeof(iovbuf));
961     if (len) {
962         ret = dhd_wl_ioctl_cmd(dhd_pub, cmd, iovbuf, len, set, ifidx);
963         if (ret) {
964             DHD_ERROR(("%s: set int iovar %s failed, ERR %d\n", __FUNCTION__,
965                        name, ret));
966         }
967     } else {
968         DHD_ERROR(("%s: mkiovar %s failed\n", __FUNCTION__, name));
969     }
970 
971     return ret;
972 }
973 
974 static struct ioctl2str_s {
975     uint32 ioctl;
976     char *name;
977 } ioctl2str_array[] = {{WLC_UP, "UP"},
978                        {WLC_DOWN, "DOWN"},
979                        {WLC_SET_PROMISC, "SET_PROMISC"},
980                        {WLC_SET_INFRA, "SET_INFRA"},
981                        {WLC_SET_AUTH, "SET_AUTH"},
982                        {WLC_SET_SSID, "SET_SSID"},
983                        {WLC_RESTART, "RESTART"},
984                        {WLC_SET_CHANNEL, "SET_CHANNEL"},
985                        {WLC_SET_RATE_PARAMS, "SET_RATE_PARAMS"},
986                        {WLC_SET_KEY, "SET_KEY"},
987                        {WLC_SCAN, "SCAN"},
988                        {WLC_DISASSOC, "DISASSOC"},
989                        {WLC_REASSOC, "REASSOC"},
990                        {WLC_SET_COUNTRY, "SET_COUNTRY"},
991                        {WLC_SET_WAKE, "SET_WAKE"},
992                        {WLC_SET_SCANSUPPRESS, "SET_SCANSUPPRESS"},
993                        {WLC_SCB_DEAUTHORIZE, "SCB_DEAUTHORIZE"},
994                        {WLC_SET_WSEC, "SET_WSEC"},
995                        {WLC_SET_INTERFERENCE_MODE, "SET_INTERFERENCE_MODE"},
996                        {WLC_SET_RADAR, "SET_RADAR"},
997                        {0, NULL}};
998 
ioctl2str(uint32 ioctl)999 static char *ioctl2str(uint32 ioctl)
1000 {
1001     struct ioctl2str_s *p = ioctl2str_array;
1002 
1003     while (p->name != NULL) {
1004         if (p->ioctl == ioctl) {
1005             return p->name;
1006         }
1007         p++;
1008     }
1009 
1010     return "";
1011 }
1012 
1013 /**
1014  * @param ioc          IO control struct, members are partially used by this
1015  * function.
1016  * @param buf [inout]  Contains parameters to send to dongle, contains dongle
1017  * response on return.
1018  * @param len          Maximum number of bytes that dongle is allowed to write
1019  * into 'buf'.
1020  */
dhd_wl_ioctl(dhd_pub_t * dhd_pub,int ifidx,wl_ioctl_t * ioc,void * buf,int len)1021 int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifidx, wl_ioctl_t *ioc, void *buf,
1022                  int len)
1023 {
1024     int ret = BCME_ERROR;
1025     unsigned long flags;
1026 #ifdef DUMP_IOCTL_IOV_LIST
1027     dhd_iov_li_t *iov_li;
1028 #endif /* DUMP_IOCTL_IOV_LIST */
1029     int hostsleep_set = 0;
1030     int hostsleep_val = 0;
1031 
1032 #ifdef DHD_PCIE_NATIVE_RUNTIMEPM
1033     DHD_OS_WAKE_LOCK(dhd_pub);
1034     if (pm_runtime_get_sync(dhd_bus_to_dev(dhd_pub->bus)) < 0) {
1035         DHD_RPM(("%s: pm_runtime_get_sync error. \n", __FUNCTION__));
1036         DHD_OS_WAKE_UNLOCK(dhd_pub);
1037         return BCME_ERROR;
1038     }
1039 #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
1040 
1041 #ifdef KEEPIF_ON_DEVICE_RESET
1042     if (ioc->cmd == WLC_GET_VAR) {
1043         dbus_config_t config;
1044         config.general_param = 0;
1045         if (buf) {
1046             if (!strcmp(buf, "wowl_activate")) {
1047                 /* 1 (TRUE) after decreased by 1 */
1048                 config.general_param = 0x2;
1049             } else if (!strcmp(buf, "wowl_clear")) {
1050                 /* 0 (FALSE) after decreased by 1 */
1051                 config.general_param = 1;
1052             }
1053         }
1054         if (config.general_param) {
1055             config.config_id = DBUS_CONFIG_ID_KEEPIF_ON_DEVRESET;
1056             config.general_param--;
1057             dbus_set_config(dhd_pub->dbus, &config);
1058         }
1059     }
1060 #endif /* KEEPIF_ON_DEVICE_RESET */
1061 
1062     if (dhd_os_proto_block(dhd_pub)) {
1063 #ifdef DHD_LOG_DUMP
1064         int slen, val, lval, min_len;
1065         char *msg, tmp[64];
1066 
1067         /* WLC_GET_VAR */
1068         if (ioc->cmd == WLC_GET_VAR && buf) {
1069             min_len = MIN(sizeof(tmp) - 1, strlen(buf));
1070             memset(tmp, 0, sizeof(tmp));
1071             bcopy(buf, tmp, min_len);
1072             tmp[min_len] = '\0';
1073         }
1074 #endif /* DHD_LOG_DUMP */
1075 
1076 #ifdef DHD_DISCONNECT_TRACE
1077         if ((WLC_DISASSOC == ioc->cmd) || (WLC_DOWN == ioc->cmd) ||
1078             (WLC_DISASSOC_MYAP == ioc->cmd)) {
1079             DHD_ERROR(("IOCTL Disconnect WiFi: %d\n", ioc->cmd));
1080         }
1081 #endif /* HW_DISCONNECT_TRACE */
1082 
1083         /* logging of iovars that are send to the dongle, ./dhd msglevel +iovar
1084          */
1085         if (ioc->set == TRUE) {
1086             char *pars = (char *)buf; // points at user buffer
1087             if (ioc->cmd == WLC_SET_VAR && buf) {
1088                 DHD_DNGL_IOVAR_SET(("iovar:%d: set %s", ifidx, pars));
1089                 if (ioc->len > 1 + sizeof(uint32)) {
1090                     // skip iovar name:
1091                     pars += strnlen(pars, ioc->len - 1 - sizeof(uint32));
1092                     pars++; // skip NULL character
1093                 }
1094             } else {
1095                 DHD_DNGL_IOVAR_SET(("ioctl:%d: set %d %s", ifidx, ioc->cmd,
1096                                     ioctl2str(ioc->cmd)));
1097             }
1098             if (pars != NULL) {
1099                 DHD_DNGL_IOVAR_SET((" 0x%x\n", *(uint32 *)pars));
1100             } else {
1101                 DHD_DNGL_IOVAR_SET((" NULL\n"));
1102             }
1103         }
1104 
1105         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
1106         if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub)) {
1107             DHD_INFO(("%s: returning as busstate=%d\n", __FUNCTION__,
1108                       dhd_pub->busstate));
1109             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
1110             dhd_os_proto_unblock(dhd_pub);
1111             return -ENODEV;
1112         }
1113         DHD_BUS_BUSY_SET_IN_IOVAR(dhd_pub);
1114         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
1115 
1116         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
1117         if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) {
1118             DHD_ERROR(
1119                 ("%s: bus is in suspend(%d) or suspending(0x%x) state!!\n",
1120                  __FUNCTION__, dhd_pub->busstate, dhd_pub->dhd_bus_busy_state));
1121             DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub);
1122             dhd_os_busbusy_wake(dhd_pub);
1123             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
1124             dhd_os_proto_unblock(dhd_pub);
1125             return -ENODEV;
1126         }
1127         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
1128 
1129 #ifdef DUMP_IOCTL_IOV_LIST
1130         if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION && buf) {
1131             if (!(iov_li = MALLOC(dhd_pub->osh, sizeof(*iov_li)))) {
1132                 DHD_ERROR(("iovar dump list item allocation Failed\n"));
1133             } else {
1134                 iov_li->cmd = ioc->cmd;
1135                 if (buf) {
1136                     bcopy((char *)buf, iov_li->buff, strlen((char *)buf) + 1);
1137                 }
1138                 dhd_iov_li_append(dhd_pub, &dhd_pub->dump_iovlist_head,
1139                                   &iov_li->list);
1140             }
1141         }
1142 #endif /* DUMP_IOCTL_IOV_LIST */
1143 
1144         if (dhd_conf_check_hostsleep(dhd_pub, ioc->cmd, ioc->buf, len,
1145                                      &hostsleep_set, &hostsleep_val, &ret)) {
1146             goto exit;
1147         }
1148         ret = dhd_prot_ioctl(dhd_pub, ifidx, ioc, buf, len);
1149         dhd_conf_get_hostsleep(dhd_pub, hostsleep_set, hostsleep_val, ret);
1150 
1151 #ifdef DUMP_IOCTL_IOV_LIST
1152         if (ret == -ETIMEDOUT) {
1153             DHD_ERROR(("Last %d issued commands: Latest one is at bottom.\n",
1154                        IOV_LIST_MAX_LEN));
1155             dhd_iov_li_print(&dhd_pub->dump_iovlist_head);
1156         }
1157 #endif /* DUMP_IOCTL_IOV_LIST */
1158 #ifdef DHD_LOG_DUMP
1159         if ((ioc->cmd == WLC_GET_VAR || ioc->cmd == WLC_SET_VAR) &&
1160             buf != NULL) {
1161             if (buf) {
1162                 lval = 0;
1163                 slen = strlen(buf) + 1;
1164                 msg = (char *)buf;
1165                 if (len >= slen + sizeof(lval)) {
1166                     if (ioc->cmd == WLC_GET_VAR) {
1167                         msg = tmp;
1168                         lval = *(int *)buf;
1169                     } else {
1170                         min_len = MIN(ioc->len - slen, sizeof(int));
1171                         bcopy((msg + slen), &lval, min_len);
1172                     }
1173                     if (!strncmp(msg, "cur_etheraddr",
1174                                  strlen("cur_etheraddr"))) {
1175                         lval = 0;
1176                     }
1177                 }
1178                 DHD_IOVAR_MEM(
1179                     ("%s: cmd: %d, msg: %s val: 0x%x,"
1180                      " len: %d, set: %d, txn-id: %d\n",
1181                      ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR",
1182                      ioc->cmd, msg, lval, ioc->len, ioc->set,
1183                      dhd_prot_get_ioctl_trans_id(dhd_pub)));
1184             } else {
1185                 DHD_IOVAR_MEM(
1186                     ("%s: cmd: %d, len: %d, set: %d, txn-id: %d\n",
1187                      ioc->cmd == WLC_GET_VAR ? "WLC_GET_VAR" : "WLC_SET_VAR",
1188                      ioc->cmd, ioc->len, ioc->set,
1189                      dhd_prot_get_ioctl_trans_id(dhd_pub)));
1190             }
1191         } else {
1192             slen = ioc->len;
1193             if (buf != NULL && slen != 0) {
1194                 if (slen >= 0x4) {
1195                     val = *(int *)buf;
1196                 } else if (slen >= 0x2) {
1197                     val = *(short *)buf;
1198                 } else {
1199                     val = *(char *)buf;
1200                 }
1201                 /* Do not dump for WLC_GET_MAGIC and WLC_GET_VERSION */
1202                 if (ioc->cmd != WLC_GET_MAGIC && ioc->cmd != WLC_GET_VERSION) {
1203                     DHD_IOVAR_MEM(("WLC_IOCTL: cmd: %d, val: %d, len: %d, "
1204                                    "set: %d\n",
1205                                    ioc->cmd, val, ioc->len, ioc->set));
1206                 }
1207             } else {
1208                 DHD_IOVAR_MEM(("WLC_IOCTL: cmd: %d, buf is NULL\n", ioc->cmd));
1209             }
1210         }
1211 #endif /* DHD_LOG_DUMP */
1212         if (ret && dhd_pub->up) {
1213             /* Send hang event only if dhd_open() was success */
1214             dhd_os_check_hang(dhd_pub, ifidx, ret);
1215         }
1216 
1217         if (ret == -ETIMEDOUT && !dhd_pub->up) {
1218             DHD_ERROR(("%s: 'resumed on timeout' error is "
1219                        "occurred before the interface does not"
1220                        " bring up\n",
1221                        __FUNCTION__));
1222         }
1223 
1224     exit:
1225         DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
1226         DHD_BUS_BUSY_CLEAR_IN_IOVAR(dhd_pub);
1227         dhd_os_busbusy_wake(dhd_pub);
1228         DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
1229 
1230         dhd_os_proto_unblock(dhd_pub);
1231     }
1232 
1233 #ifdef DHD_PCIE_NATIVE_RUNTIMEPM
1234     pm_runtime_mark_last_busy(dhd_bus_to_dev(dhd_pub->bus));
1235     pm_runtime_put_autosuspend(dhd_bus_to_dev(dhd_pub->bus));
1236 
1237     DHD_OS_WAKE_UNLOCK(dhd_pub);
1238 #endif /* DHD_PCIE_NATIVE_RUNTIMEPM */
1239 
1240 #ifdef WL_MONITOR
1241     /* Intercept monitor ioctl here, add/del monitor if */
1242     if (ret == BCME_OK && ioc->cmd == WLC_SET_MONITOR) {
1243         int val = 0;
1244         if (buf != NULL && len != 0) {
1245             if (len >= 0x4) {
1246                 val = *(int *)buf;
1247             } else if (len >= 0x2) {
1248                 val = *(short *)buf;
1249             } else {
1250                 val = *(char *)buf;
1251             }
1252         }
1253         dhd_set_monitor(dhd_pub, ifidx, val);
1254     }
1255 #endif /* WL_MONITOR */
1256 
1257     return ret;
1258 }
1259 
wl_get_port_num(wl_io_pport_t * io_pport)1260 uint wl_get_port_num(wl_io_pport_t *io_pport)
1261 {
1262     return 0;
1263 }
1264 
1265 /* Get bssidx from iovar params
1266  * Input:   dhd_pub - pointer to dhd_pub_t
1267  *	    params  - IOVAR params
1268  * Output:  idx	    - BSS index
1269  *	    val	    - ponter to the IOVAR arguments
1270  */
dhd_iovar_parse_bssidx(dhd_pub_t * dhd_pub,const char * params,uint32 * idx,const char ** val)1271 static int dhd_iovar_parse_bssidx(dhd_pub_t *dhd_pub, const char *params,
1272                                   uint32 *idx, const char **val)
1273 {
1274     char *prefix = "bsscfg:";
1275     uint32 bssidx;
1276 
1277     if (!(strncmp(params, prefix, strlen(prefix)))) {
1278         /* per bss setting should be prefixed with 'bsscfg:' */
1279         const char *p = params + strlen(prefix);
1280 
1281         /* Skip Name */
1282         while (*p != '\0') {
1283             p++;
1284         }
1285         /* consider null */
1286         p = p + 1;
1287         bcopy(p, &bssidx, sizeof(uint32));
1288         /* Get corresponding dhd index */
1289         bssidx = dhd_bssidx2idx(dhd_pub, htod32(bssidx));
1290         if (bssidx >= DHD_MAX_IFS) {
1291             DHD_ERROR(("%s Wrong bssidx provided\n", __FUNCTION__));
1292             return BCME_ERROR;
1293         }
1294 
1295         /* skip bss idx */
1296         p += sizeof(uint32);
1297         *val = p;
1298         *idx = bssidx;
1299     } else {
1300         DHD_ERROR(("%s: bad parameter for per bss iovar\n", __FUNCTION__));
1301         return BCME_ERROR;
1302     }
1303 
1304     return BCME_OK;
1305 }
1306 
1307 #if defined(DHD_DEBUG) && defined(BCMDBUS)
1308 /* USB Device console input function */
dhd_bus_console_in(dhd_pub_t * dhd,uchar * msg,uint msglen)1309 int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen)
1310 {
1311     DHD_TRACE(("%s \n", __FUNCTION__));
1312 
1313     return dhd_iovar(dhd, 0, "cons", msg, msglen, NULL, 0, TRUE);
1314 }
1315 #endif /* DHD_DEBUG && BCMDBUS  */
1316 
1317 #ifdef DHD_DEBUG
dhd_mem_debug(dhd_pub_t * dhd,uchar * msg,uint msglen)1318 int dhd_mem_debug(dhd_pub_t *dhd, uchar *msg, uint msglen)
1319 {
1320     unsigned long int_arg = 0;
1321     char *p;
1322     char *end_ptr = NULL;
1323     dhd_dbg_mwli_t *mw_li;
1324     dll_t *item, *next;
1325     /* check if mwalloc, mwquery or mwfree was supplied arguement with space */
1326     p = bcmstrstr((char *)msg, " ");
1327     if (p != NULL) {
1328         /* space should be converted to null as separation flag for firmware */
1329         *p = '\0';
1330         /* store the argument in int_arg */
1331         int_arg = bcm_strtoul(p + 1, &end_ptr, 0xA);
1332     }
1333 
1334     if (!p && !strcmp(msg, "query")) {
1335         /* lets query the list inetrnally */
1336         if (dll_empty(dll_head_p(&dhd->mw_list_head))) {
1337             DHD_ERROR((
1338                 "memwaste list is empty, call mwalloc < size > to allocate\n"));
1339         } else {
1340             for (item = dll_head_p(&dhd->mw_list_head);
1341                  !dll_end(&dhd->mw_list_head, item); item = next) {
1342                 next = dll_next_p(item);
1343                 mw_li =
1344                     (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1345                 DHD_ERROR(("item: <id=%d, size=%d>\n", mw_li->id, mw_li->size));
1346             }
1347         }
1348     } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "alloc")) {
1349         int32 alloc_handle;
1350         /* convert size into KB and append as integer */
1351         *((int32 *)(p + 1)) = int_arg * 0x400;
1352         *(p + 1 + sizeof(int32)) = '\0';
1353 
1354         /* recalculated length -> 5 bytes for "alloc" + 4 bytes for size +
1355          * 1 bytes for null caracter
1356          */
1357         msglen = strlen(msg) + sizeof(int32) + 1;
1358         if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, msglen + 1, FALSE, 0) < 0) {
1359             DHD_ERROR(("IOCTL failed for memdebug alloc\n"));
1360         }
1361 
1362         /* returned allocated handle from dongle, basically address of the
1363          * allocated unit */
1364         alloc_handle = *((int32 *)msg);
1365 
1366         /* add a node in the list with tuple <id, handle, size> */
1367         if (alloc_handle == 0) {
1368             DHD_ERROR(("Reuqested size could not be allocated\n"));
1369         } else if (!(mw_li = MALLOC(dhd->osh, sizeof(*mw_li)))) {
1370             DHD_ERROR(("mw list item allocation Failed\n"));
1371         } else {
1372             mw_li->id = dhd->mw_id++;
1373             mw_li->handle = alloc_handle;
1374             mw_li->size = int_arg;
1375             /* append the node in the list */
1376             dll_append(&dhd->mw_list_head, &mw_li->list);
1377         }
1378     } else if (p && end_ptr && (*end_ptr == '\0') && !strcmp(msg, "free")) {
1379         /* inform dongle to free wasted chunk */
1380         int handle = 0;
1381         int size = 0;
1382         for (item = dll_head_p(&dhd->mw_list_head);
1383              !dll_end(&dhd->mw_list_head, item); item = next) {
1384             next = dll_next_p(item);
1385             mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1386             if (mw_li->id == (int)int_arg) {
1387                 handle = mw_li->handle;
1388                 size = mw_li->size;
1389                 dll_delete(item);
1390                 MFREE(dhd->osh, mw_li, sizeof(*mw_li));
1391                 if (dll_empty(dll_head_p(&dhd->mw_list_head))) {
1392                     /* reset the id */
1393                     dhd->mw_id = 0;
1394                 }
1395             }
1396         }
1397         if (handle) {
1398             int len;
1399             /* append the free handle and the chunk size in first 8 bytes
1400              * after the command and null character
1401              */
1402             *((int32 *)(p + 1)) = handle;
1403             *((int32 *)((p + 1) + sizeof(int32))) = size;
1404             /* append null as terminator */
1405             *(p + 1 + 0x2 * sizeof(int32)) = '\0';
1406             /* recalculated length -> 4 bytes for "free" + 8 bytes for hadnle
1407              * and size
1408              * + 1 bytes for null caracter
1409              */
1410             len = strlen(msg) + 0x2 * sizeof(int32) + 1;
1411             /* send iovar to free the chunk */
1412             if (dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, msg, len, FALSE, 0) < 0) {
1413                 DHD_ERROR(("IOCTL failed for memdebug free\n"));
1414             }
1415         } else {
1416             DHD_ERROR(("specified id does not exist\n"));
1417         }
1418     } else {
1419         /* for all the wrong argument formats */
1420         return BCME_BADARG;
1421     }
1422     return 0;
1423 }
dhd_mw_list_delete(dhd_pub_t * dhd,dll_t * list_head)1424 extern void dhd_mw_list_delete(dhd_pub_t *dhd, dll_t *list_head)
1425 {
1426     dll_t *item;
1427     dhd_dbg_mwli_t *mw_li;
1428     while (!(dll_empty(list_head))) {
1429         item = dll_head_p(list_head);
1430         mw_li = (dhd_dbg_mwli_t *)CONTAINEROF(item, dhd_dbg_mwli_t, list);
1431         dll_delete(item);
1432         MFREE(dhd->osh, mw_li, sizeof(*mw_li));
1433     }
1434 }
1435 #ifdef BCMPCIE
dhd_flow_ring_debug(dhd_pub_t * dhd,char * msg,uint msglen)1436 int dhd_flow_ring_debug(dhd_pub_t *dhd, char *msg, uint msglen)
1437 {
1438     flow_ring_table_t *flow_ring_table;
1439     char *cmd;
1440     char *end_ptr = NULL;
1441     uint8 prio;
1442     uint16 flowid;
1443     int i;
1444     int ret = 0;
1445     cmd = bcmstrstr(msg, " ");
1446     BCM_REFERENCE(prio);
1447     if (cmd != NULL) {
1448         /* in order to use string operations append null */
1449         *cmd = '\0';
1450     } else {
1451         DHD_ERROR(("missing: create/delete args\n"));
1452         return BCME_ERROR;
1453     }
1454     if (cmd && !strcmp(msg, "create")) {
1455         /* extract <"source address", "destination address", "priority"> */
1456         uint8 sa[ETHER_ADDR_LEN], da[ETHER_ADDR_LEN];
1457         BCM_REFERENCE(sa);
1458         BCM_REFERENCE(da);
1459         msg = msg + strlen("create") + 1;
1460         /* fill ethernet source address */
1461         for (i = 0; i < ETHER_ADDR_LEN; i++) {
1462             sa[i] = (uint8)bcm_strtoul(msg, &end_ptr, 0x10);
1463             if (*end_ptr == ':') {
1464                 msg = (end_ptr + 1);
1465             } else if (i != 0x5) {
1466                 DHD_ERROR(("not a valid source mac addr\n"));
1467                 return BCME_ERROR;
1468             }
1469         }
1470         if (*end_ptr != ' ') {
1471             DHD_ERROR(("missing: destiantion mac id\n"));
1472             return BCME_ERROR;
1473         } else {
1474             /* skip space */
1475             msg = end_ptr + 1;
1476         }
1477         /* fill ethernet destination address */
1478         for (i = 0; i < ETHER_ADDR_LEN; i++) {
1479             da[i] = (uint8)bcm_strtoul(msg, &end_ptr, 0x10);
1480             if (*end_ptr == ':') {
1481                 msg = (end_ptr + 1);
1482             } else if (i != 0x5) {
1483                 DHD_ERROR(("not a valid destination  mac addr\n"));
1484                 return BCME_ERROR;
1485             }
1486         }
1487         if (*end_ptr != ' ') {
1488             DHD_ERROR(("missing: priority\n"));
1489             return BCME_ERROR;
1490         } else {
1491             msg = end_ptr + 1;
1492         }
1493         /* parse priority */
1494         prio = (uint8)bcm_strtoul(msg, &end_ptr, 0xA);
1495         if (prio > MAXPRIO) {
1496             DHD_ERROR(("%s: invalid priority. Must be between 0-7 inclusive\n",
1497                        __FUNCTION__));
1498             return BCME_ERROR;
1499         }
1500 
1501         if (*end_ptr != '\0') {
1502             DHD_ERROR(("msg not truncated with NULL character\n"));
1503             return BCME_ERROR;
1504         }
1505         ret = dhd_flowid_debug_create(dhd, 0, prio, (char *)sa, (char *)da,
1506                                       &flowid);
1507         if (ret != BCME_OK) {
1508             DHD_ERROR(
1509                 ("%s: flowring creation failed ret: %d\n", __FUNCTION__, ret));
1510             return BCME_ERROR;
1511         }
1512         return BCME_OK;
1513     } else if (cmd && !strcmp(msg, "delete")) {
1514         msg = msg + strlen("delete") + 1;
1515         /* parse flowid */
1516         flowid = (uint16)bcm_strtoul(msg, &end_ptr, 0xA);
1517         if (*end_ptr != '\0') {
1518             DHD_ERROR(("msg not truncated with NULL character\n"));
1519             return BCME_ERROR;
1520         }
1521 
1522         /* Find flowid from ifidx 0 since this IOVAR creating flowring with
1523          * ifidx 0 */
1524         if (dhd_flowid_find_by_ifidx(dhd, 0, flowid) != BCME_OK) {
1525             DHD_ERROR(("%s : Deleting not created flowid: %u\n", __FUNCTION__,
1526                        flowid));
1527             return BCME_ERROR;
1528         }
1529 
1530         flow_ring_table = (flow_ring_table_t *)dhd->flow_ring_table;
1531         ret = dhd_bus_flow_ring_delete_request(
1532             dhd->bus, (void *)&flow_ring_table[flowid]);
1533         if (ret != BCME_OK) {
1534             DHD_ERROR(
1535                 ("%s: flowring deletion failed ret: %d\n", __FUNCTION__, ret));
1536             return BCME_ERROR;
1537         }
1538         return BCME_OK;
1539     }
1540     DHD_ERROR(("%s: neither create nor delete\n", __FUNCTION__));
1541     return BCME_ERROR;
1542 }
1543 #endif /* BCMPCIE */
1544 #endif /* DHD_DEBUG */
1545 
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)1546 static int dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi,
1547                        uint32 actionid, const char *name, void *params,
1548                        int plen, void *arg, int len, int val_size)
1549 {
1550     int bcmerror = 0;
1551     int32 int_val = 0;
1552     uint32 dhd_ver_len, bus_api_rev_len;
1553 
1554     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
1555     DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name));
1556 
1557     if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) !=
1558         0) {
1559         goto exit;
1560     }
1561 
1562     if (plen >= (int)sizeof(int_val)) {
1563         bcopy(params, &int_val, sizeof(int_val));
1564     }
1565 
1566     switch (actionid) {
1567         case IOV_GVAL(IOV_VERSION):
1568             /* Need to have checked buffer length */
1569             dhd_ver_len = strlen(dhd_version);
1570             bus_api_rev_len = strlen(bus_api_revision);
1571             if (dhd_ver_len) {
1572                 bcm_strncpy_s((char *)arg, dhd_ver_len, dhd_version,
1573                               dhd_ver_len);
1574             }
1575             if (bus_api_rev_len) {
1576                 bcm_strncat_s((char *)arg + dhd_ver_len, bus_api_rev_len,
1577                               bus_api_revision, bus_api_rev_len);
1578             }
1579             break;
1580 
1581         case IOV_GVAL(IOV_WLMSGLEVEL):
1582             printf("android_msg_level=0x%x\n", android_msg_level);
1583             printf("config_msg_level=0x%x\n", config_msg_level);
1584 #if defined(WL_WIRELESS_EXT)
1585             int_val = (int32)iw_msg_level;
1586             bcopy(&int_val, arg, val_size);
1587             printf("iw_msg_level=0x%x\n", iw_msg_level);
1588 #endif
1589 #ifdef WL_CFG80211
1590             int_val = (int32)wl_dbg_level;
1591             bcopy(&int_val, arg, val_size);
1592             printf("cfg_msg_level=0x%x\n", wl_dbg_level);
1593 #endif
1594             break;
1595 
1596         case IOV_SVAL(IOV_WLMSGLEVEL):
1597             if (int_val & DHD_ANDROID_VAL) {
1598                 android_msg_level = (uint)(int_val & 0xFFFF);
1599                 printf("android_msg_level=0x%x\n", android_msg_level);
1600             }
1601             if (int_val & DHD_CONFIG_VAL) {
1602                 config_msg_level = (uint)(int_val & 0xFFFF);
1603                 printf("config_msg_level=0x%x\n", config_msg_level);
1604             }
1605 #if defined(WL_WIRELESS_EXT)
1606             if (int_val & DHD_IW_VAL) {
1607                 iw_msg_level = (uint)(int_val & 0xFFFF);
1608                 printf("iw_msg_level=0x%x\n", iw_msg_level);
1609             }
1610 #endif
1611 #ifdef WL_CFG80211
1612             if (int_val & DHD_CFG_VAL) {
1613                 wl_cfg80211_enable_trace((u32)(int_val & 0xFFFF));
1614             }
1615 #endif
1616             break;
1617 
1618         case IOV_GVAL(IOV_MSGLEVEL):
1619             int_val = (int32)dhd_msg_level;
1620             bcopy(&int_val, arg, val_size);
1621             break;
1622 
1623         case IOV_SVAL(IOV_MSGLEVEL):
1624             dhd_msg_level = int_val;
1625             break;
1626 
1627         case IOV_GVAL(IOV_BCMERRORSTR):
1628             bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror),
1629                           BCME_STRLEN);
1630             ((char *)arg)[BCME_STRLEN - 1] = 0x00;
1631             break;
1632 
1633         case IOV_GVAL(IOV_BCMERROR):
1634             int_val = (int32)dhd_pub->bcmerror;
1635             bcopy(&int_val, arg, val_size);
1636             break;
1637 
1638 #ifndef BCMDBUS
1639         case IOV_GVAL(IOV_WDTICK):
1640             int_val = (int32)dhd_watchdog_ms;
1641             bcopy(&int_val, arg, val_size);
1642             break;
1643 #endif /* !BCMDBUS */
1644 
1645         case IOV_SVAL(IOV_WDTICK):
1646             if (!dhd_pub->up) {
1647                 bcmerror = BCME_NOTUP;
1648                 break;
1649             }
1650 
1651             dhd_watchdog_ms = (uint)int_val;
1652 
1653             dhd_os_wd_timer(dhd_pub, (uint)int_val);
1654             break;
1655 
1656         case IOV_GVAL(IOV_DUMP):
1657             if (dhd_dump(dhd_pub, arg, len) <= 0) {
1658                 bcmerror = BCME_ERROR;
1659             } else {
1660                 bcmerror = BCME_OK;
1661             }
1662             break;
1663 
1664 #ifndef BCMDBUS
1665         case IOV_GVAL(IOV_DCONSOLE_POLL):
1666             int_val = (int32)dhd_pub->dhd_console_ms;
1667             bcopy(&int_val, arg, val_size);
1668             break;
1669 
1670         case IOV_SVAL(IOV_DCONSOLE_POLL):
1671             dhd_pub->dhd_console_ms = (uint)int_val;
1672             break;
1673 
1674 #if defined(DHD_DEBUG)
1675         case IOV_SVAL(IOV_CONS):
1676             if (len > 0) {
1677 #ifdef CONSOLE_DPC
1678                 bcmerror = dhd_bus_txcons(dhd_pub, arg, len - 1);
1679 #else
1680                 bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1);
1681 #endif
1682             }
1683             break;
1684 #endif /* DHD_DEBUG */
1685 #endif /* !BCMDBUS */
1686 
1687         case IOV_SVAL(IOV_CLEARCOUNTS):
1688             dhd_pub->tx_packets = dhd_pub->rx_packets = 0;
1689             dhd_pub->tx_errors = dhd_pub->rx_errors = 0;
1690             dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0;
1691             dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0;
1692             dhd_pub->tx_dropped = 0;
1693             dhd_pub->rx_dropped = 0;
1694             dhd_pub->tx_pktgetfail = 0;
1695             dhd_pub->rx_pktgetfail = 0;
1696             dhd_pub->rx_readahead_cnt = 0;
1697             dhd_pub->tx_realloc = 0;
1698             dhd_pub->wd_dpc_sched = 0;
1699             dhd_pub->tx_big_packets = 0;
1700             memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats));
1701             dhd_bus_clearcounts(dhd_pub);
1702 #ifdef PROP_TXSTATUS
1703             /* clear proptxstatus related counters */
1704             dhd_wlfc_clear_counts(dhd_pub);
1705 #endif /* PROP_TXSTATUS */
1706 #if defined(DHD_LB_STATS)
1707             DHD_LB_STATS_RESET(dhd_pub);
1708 #endif /* DHD_LB_STATS */
1709             break;
1710 
1711         case IOV_GVAL(IOV_IOCTLTIMEOUT): {
1712             int_val = (int32)dhd_os_get_ioctl_resp_timeout();
1713             bcopy(&int_val, arg, sizeof(int_val));
1714             break;
1715         }
1716 
1717         case IOV_SVAL(IOV_IOCTLTIMEOUT): {
1718             if (int_val <= 0) {
1719                 bcmerror = BCME_BADARG;
1720             } else {
1721                 dhd_os_set_ioctl_resp_timeout((unsigned int)int_val);
1722             }
1723             break;
1724         }
1725 
1726 #ifdef PROP_TXSTATUS
1727         case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): {
1728             bool wlfc_enab = FALSE;
1729             bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
1730             if (bcmerror != BCME_OK) {
1731                 goto exit;
1732             }
1733             int_val = wlfc_enab ? 1 : 0;
1734             bcopy(&int_val, arg, val_size);
1735             break;
1736         }
1737         case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): {
1738             bool wlfc_enab = FALSE;
1739             bcmerror = dhd_wlfc_get_enable(dhd_pub, &wlfc_enab);
1740             if (bcmerror != BCME_OK) {
1741                 goto exit;
1742             }
1743 
1744             /* wlfc is already set as desired */
1745             if (wlfc_enab == (int_val == 0 ? FALSE : TRUE)) {
1746                 goto exit;
1747             }
1748 
1749             if (int_val == TRUE && disable_proptx) {
1750                 disable_proptx = 0;
1751             }
1752 
1753             if (int_val == TRUE) {
1754                 bcmerror = dhd_wlfc_init(dhd_pub);
1755             } else {
1756                 bcmerror = dhd_wlfc_deinit(dhd_pub);
1757             }
1758 
1759             break;
1760         }
1761         case IOV_GVAL(IOV_PROPTXSTATUS_MODE):
1762             bcmerror = dhd_wlfc_get_mode(dhd_pub, &int_val);
1763             if (bcmerror != BCME_OK) {
1764                 goto exit;
1765             }
1766             bcopy(&int_val, arg, val_size);
1767             break;
1768 
1769         case IOV_SVAL(IOV_PROPTXSTATUS_MODE):
1770             dhd_wlfc_set_mode(dhd_pub, int_val);
1771             break;
1772 
1773         case IOV_GVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
1774             bcmerror = dhd_wlfc_get_module_ignore(dhd_pub, &int_val);
1775             if (bcmerror != BCME_OK) {
1776                 goto exit;
1777             }
1778             bcopy(&int_val, arg, val_size);
1779             break;
1780 
1781         case IOV_SVAL(IOV_PROPTXSTATUS_MODULE_IGNORE):
1782             dhd_wlfc_set_module_ignore(dhd_pub, int_val);
1783             break;
1784 
1785         case IOV_GVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
1786             bcmerror = dhd_wlfc_get_credit_ignore(dhd_pub, &int_val);
1787             if (bcmerror != BCME_OK) {
1788                 goto exit;
1789             }
1790             bcopy(&int_val, arg, val_size);
1791             break;
1792 
1793         case IOV_SVAL(IOV_PROPTXSTATUS_CREDIT_IGNORE):
1794             dhd_wlfc_set_credit_ignore(dhd_pub, int_val);
1795             break;
1796 
1797         case IOV_GVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
1798             bcmerror = dhd_wlfc_get_txstatus_ignore(dhd_pub, &int_val);
1799             if (bcmerror != BCME_OK) {
1800                 goto exit;
1801             }
1802             bcopy(&int_val, arg, val_size);
1803             break;
1804 
1805         case IOV_SVAL(IOV_PROPTXSTATUS_TXSTATUS_IGNORE):
1806             dhd_wlfc_set_txstatus_ignore(dhd_pub, int_val);
1807             break;
1808 
1809         case IOV_GVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
1810             bcmerror = dhd_wlfc_get_rxpkt_chk(dhd_pub, &int_val);
1811             if (bcmerror != BCME_OK) {
1812                 goto exit;
1813             }
1814             bcopy(&int_val, arg, val_size);
1815             break;
1816 
1817         case IOV_SVAL(IOV_PROPTXSTATUS_RXPKT_CHK):
1818             dhd_wlfc_set_rxpkt_chk(dhd_pub, int_val);
1819             break;
1820 
1821 #endif /* PROP_TXSTATUS */
1822 
1823         case IOV_GVAL(IOV_BUS_TYPE):
1824             /* The dhd application queries the driver to check if its usb or
1825              * sdio.  */
1826 #ifdef BCMDBUS
1827             int_val = BUS_TYPE_USB;
1828 #endif // endif
1829 #ifdef BCMSDIO
1830             int_val = BUS_TYPE_SDIO;
1831 #endif // endif
1832 #ifdef PCIE_FULL_DONGLE
1833             int_val = BUS_TYPE_PCIE;
1834 #endif // endif
1835             bcopy(&int_val, arg, val_size);
1836             break;
1837 
1838         case IOV_SVAL(IOV_CHANGEMTU):
1839             int_val &= 0xffff;
1840             bcmerror = dhd_change_mtu(dhd_pub, int_val, 0);
1841             break;
1842 
1843         case IOV_GVAL(IOV_HOSTREORDER_FLOWS): {
1844             uint i = 0;
1845             uint8 *ptr = (uint8 *)arg;
1846             uint8 count = 0;
1847 
1848             ptr++;
1849             for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) {
1850                 if (dhd_pub->reorder_bufs[i] != NULL) {
1851                     *ptr = dhd_pub->reorder_bufs[i]->flow_id;
1852                     ptr++;
1853                     count++;
1854                 }
1855             }
1856             ptr = (uint8 *)arg;
1857             *ptr = count;
1858             break;
1859         }
1860 #ifdef DHDTCPACK_SUPPRESS
1861         case IOV_GVAL(IOV_TCPACK_SUPPRESS): {
1862             int_val = (uint32)dhd_pub->tcpack_sup_mode;
1863             bcopy(&int_val, arg, val_size);
1864             break;
1865         }
1866         case IOV_SVAL(IOV_TCPACK_SUPPRESS): {
1867             bcmerror = dhd_tcpack_suppress_set(dhd_pub, (uint8)int_val);
1868             break;
1869         }
1870 #endif /* DHDTCPACK_SUPPRESS */
1871 
1872 #ifdef DHD_L2_FILTER
1873         case IOV_GVAL(IOV_DHCP_UNICAST): {
1874             uint32 bssidx;
1875             const char *val;
1876             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1877                 BCME_OK) {
1878                 DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n",
1879                            __FUNCTION__, name));
1880                 bcmerror = BCME_BADARG;
1881                 break;
1882             }
1883             int_val = dhd_get_dhcp_unicast_status(dhd_pub, bssidx);
1884             memcpy(arg, &int_val, val_size);
1885             break;
1886         }
1887         case IOV_SVAL(IOV_DHCP_UNICAST): {
1888             uint32 bssidx;
1889             const char *val;
1890             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1891                 BCME_OK) {
1892                 DHD_ERROR(("%s: IOV_DHCP_UNICAST: bad parameterand name = %s\n",
1893                            __FUNCTION__, name));
1894                 bcmerror = BCME_BADARG;
1895                 break;
1896             }
1897             memcpy(&int_val, val, sizeof(int_val));
1898             bcmerror =
1899                 dhd_set_dhcp_unicast_status(dhd_pub, bssidx, int_val ? 1 : 0);
1900             break;
1901         }
1902         case IOV_GVAL(IOV_BLOCK_PING): {
1903             uint32 bssidx;
1904             const char *val;
1905 
1906             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1907                 BCME_OK) {
1908                 DHD_ERROR(
1909                     ("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__));
1910                 bcmerror = BCME_BADARG;
1911                 break;
1912             }
1913             int_val = dhd_get_block_ping_status(dhd_pub, bssidx);
1914             memcpy(arg, &int_val, val_size);
1915             break;
1916         }
1917         case IOV_SVAL(IOV_BLOCK_PING): {
1918             uint32 bssidx;
1919             const char *val;
1920 
1921             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1922                 BCME_OK) {
1923                 DHD_ERROR(
1924                     ("%s: IOV_BLOCK_PING: bad parameter\n", __FUNCTION__));
1925                 bcmerror = BCME_BADARG;
1926                 break;
1927             }
1928             memcpy(&int_val, val, sizeof(int_val));
1929             bcmerror =
1930                 dhd_set_block_ping_status(dhd_pub, bssidx, int_val ? 1 : 0);
1931             break;
1932         }
1933         case IOV_GVAL(IOV_PROXY_ARP): {
1934             uint32 bssidx;
1935             const char *val;
1936 
1937             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1938                 BCME_OK) {
1939                 DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__));
1940                 bcmerror = BCME_BADARG;
1941                 break;
1942             }
1943             int_val = dhd_get_parp_status(dhd_pub, bssidx);
1944             bcopy(&int_val, arg, val_size);
1945             break;
1946         }
1947         case IOV_SVAL(IOV_PROXY_ARP): {
1948             uint32 bssidx;
1949             const char *val;
1950 
1951             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1952                 BCME_OK) {
1953                 DHD_ERROR(("%s: IOV_PROXY_ARP: bad parameter\n", __FUNCTION__));
1954                 bcmerror = BCME_BADARG;
1955                 break;
1956             }
1957             bcopy(val, &int_val, sizeof(int_val));
1958 
1959             /* Issue a iovar request to WL to update the proxy arp capability
1960              * bit in the Extended Capability IE of beacons/probe responses.
1961              */
1962             bcmerror = dhd_iovar(dhd_pub, bssidx, "proxy_arp_advertise", val,
1963                                  sizeof(int_val), NULL, 0, TRUE);
1964             if (bcmerror == BCME_OK) {
1965                 dhd_set_parp_status(dhd_pub, bssidx, int_val ? 1 : 0);
1966             }
1967             break;
1968         }
1969         case IOV_GVAL(IOV_GRAT_ARP): {
1970             uint32 bssidx;
1971             const char *val;
1972 
1973             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1974                 BCME_OK) {
1975                 DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__));
1976                 bcmerror = BCME_BADARG;
1977                 break;
1978             }
1979             int_val = dhd_get_grat_arp_status(dhd_pub, bssidx);
1980             memcpy(arg, &int_val, val_size);
1981             break;
1982         }
1983         case IOV_SVAL(IOV_GRAT_ARP): {
1984             uint32 bssidx;
1985             const char *val;
1986 
1987             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
1988                 BCME_OK) {
1989                 DHD_ERROR(("%s: IOV_GRAT_ARP: bad parameter\n", __FUNCTION__));
1990                 bcmerror = BCME_BADARG;
1991                 break;
1992             }
1993             memcpy(&int_val, val, sizeof(int_val));
1994             bcmerror =
1995                 dhd_set_grat_arp_status(dhd_pub, bssidx, int_val ? 1 : 0);
1996             break;
1997         }
1998         case IOV_GVAL(IOV_BLOCK_TDLS): {
1999             uint32 bssidx;
2000             const char *val;
2001 
2002             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
2003                 BCME_OK) {
2004                 DHD_ERROR(
2005                     ("%s: IOV_BLOCK_TDLS: bad parameter\n", __FUNCTION__));
2006                 bcmerror = BCME_BADARG;
2007                 break;
2008             }
2009             int_val = dhd_get_block_tdls_status(dhd_pub, bssidx);
2010             memcpy(arg, &int_val, val_size);
2011             break;
2012         }
2013         case IOV_SVAL(IOV_BLOCK_TDLS): {
2014             uint32 bssidx;
2015             const char *val;
2016 
2017             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
2018                 BCME_OK) {
2019                 DHD_ERROR(
2020                     ("%s: IOV_BLOCK_TDLS: bad parameter\n", __FUNCTION__));
2021                 bcmerror = BCME_BADARG;
2022                 break;
2023             }
2024             memcpy(&int_val, val, sizeof(int_val));
2025             bcmerror =
2026                 dhd_set_block_tdls_status(dhd_pub, bssidx, int_val ? 1 : 0);
2027             break;
2028         }
2029 #endif /* DHD_L2_FILTER */
2030         case IOV_SVAL(IOV_DHD_IE): {
2031             uint32 bssidx;
2032             const char *val;
2033 
2034             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
2035                 BCME_OK) {
2036                 DHD_ERROR(("%s: dhd ie: bad parameter\n", __FUNCTION__));
2037                 bcmerror = BCME_BADARG;
2038                 break;
2039             }
2040 
2041             break;
2042         }
2043         case IOV_GVAL(IOV_AP_ISOLATE): {
2044             uint32 bssidx;
2045             const char *val;
2046 
2047             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
2048                 BCME_OK) {
2049                 DHD_ERROR(("%s: ap isoalate: bad parameter\n", __FUNCTION__));
2050                 bcmerror = BCME_BADARG;
2051                 break;
2052             }
2053 
2054             int_val = dhd_get_ap_isolate(dhd_pub, bssidx);
2055             bcopy(&int_val, arg, val_size);
2056             break;
2057         }
2058         case IOV_SVAL(IOV_AP_ISOLATE): {
2059             uint32 bssidx;
2060             const char *val;
2061 
2062             if (dhd_iovar_parse_bssidx(dhd_pub, name, &bssidx, &val) !=
2063                 BCME_OK) {
2064                 DHD_ERROR(("%s: ap isolate: bad parameter\n", __FUNCTION__));
2065                 bcmerror = BCME_BADARG;
2066                 break;
2067             }
2068 
2069             ASSERT(val);
2070             bcopy(val, &int_val, sizeof(uint32));
2071             dhd_set_ap_isolate(dhd_pub, bssidx, int_val);
2072             break;
2073         }
2074 #ifdef DHD_PSTA
2075         case IOV_GVAL(IOV_PSTA): {
2076             int_val = dhd_get_psta_mode(dhd_pub);
2077             bcopy(&int_val, arg, val_size);
2078             break;
2079         }
2080         case IOV_SVAL(IOV_PSTA): {
2081             if (int_val >= DHD_MODE_PSTA_DISABLED && int_val <= DHD_MODE_PSR) {
2082                 dhd_set_psta_mode(dhd_pub, int_val);
2083             } else {
2084                 bcmerror = BCME_RANGE;
2085             }
2086             break;
2087         }
2088 #endif /* DHD_PSTA */
2089 #ifdef DHD_WET
2090         case IOV_GVAL(IOV_WET):
2091             int_val = dhd_get_wet_mode(dhd_pub);
2092             bcopy(&int_val, arg, val_size);
2093             break;
2094 
2095         case IOV_SVAL(IOV_WET):
2096             if (int_val == 0 || int_val == 1) {
2097                 dhd_set_wet_mode(dhd_pub, int_val);
2098                 /* Delete the WET DB when disabled */
2099                 if (!int_val) {
2100                     dhd_wet_sta_delete_list(dhd_pub);
2101                 }
2102             } else {
2103                 bcmerror = BCME_RANGE;
2104             }
2105             break;
2106         case IOV_SVAL(IOV_WET_HOST_IPV4):
2107             dhd_set_wet_host_ipv4(dhd_pub, params, plen);
2108             break;
2109         case IOV_SVAL(IOV_WET_HOST_MAC):
2110             dhd_set_wet_host_mac(dhd_pub, params, plen);
2111             break;
2112 #endif /* DHD_WET */
2113 #ifdef DHD_MCAST_REGEN
2114         case IOV_GVAL(IOV_MCAST_REGEN_BSS_ENABLE): {
2115             uint32 bssidx;
2116             const char *val;
2117 
2118             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2119                 BCME_OK) {
2120                 DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n",
2121                            __FUNCTION__));
2122                 bcmerror = BCME_BADARG;
2123                 break;
2124             }
2125 
2126             int_val = dhd_get_mcast_regen_bss_enable(dhd_pub, bssidx);
2127             bcopy(&int_val, arg, val_size);
2128             break;
2129         }
2130 
2131         case IOV_SVAL(IOV_MCAST_REGEN_BSS_ENABLE): {
2132             uint32 bssidx;
2133             const char *val;
2134 
2135             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2136                 BCME_OK) {
2137                 DHD_ERROR(("%s: mcast_regen_bss_enable: bad parameter\n",
2138                            __FUNCTION__));
2139                 bcmerror = BCME_BADARG;
2140                 break;
2141             }
2142 
2143             ASSERT(val);
2144             bcopy(val, &int_val, sizeof(uint32));
2145             dhd_set_mcast_regen_bss_enable(dhd_pub, bssidx, int_val);
2146             break;
2147         }
2148 #endif /* DHD_MCAST_REGEN */
2149 
2150         case IOV_GVAL(IOV_CFG80211_OPMODE): {
2151             int_val = (int32)dhd_pub->op_mode;
2152             bcopy(&int_val, arg, sizeof(int_val));
2153             break;
2154         }
2155         case IOV_SVAL(IOV_CFG80211_OPMODE): {
2156             if (int_val <= 0) {
2157                 bcmerror = BCME_BADARG;
2158             } else {
2159                 dhd_pub->op_mode = int_val;
2160             }
2161             break;
2162         }
2163 
2164         case IOV_GVAL(IOV_ASSERT_TYPE):
2165             int_val = g_assert_type;
2166             bcopy(&int_val, arg, val_size);
2167             break;
2168 
2169         case IOV_SVAL(IOV_ASSERT_TYPE):
2170             g_assert_type = (uint32)int_val;
2171             break;
2172 
2173 #if !defined(MACOSX_DHD)
2174         case IOV_GVAL(IOV_LMTEST): {
2175             *(uint32 *)arg = (uint32)lmtest;
2176             break;
2177         }
2178 
2179         case IOV_SVAL(IOV_LMTEST): {
2180             uint32 val = *(uint32 *)arg;
2181             if (val > 0x32) {
2182                 bcmerror = BCME_BADARG;
2183             } else {
2184                 lmtest = (uint)val;
2185                 DHD_ERROR(("%s: lmtest %s\n", __FUNCTION__,
2186                            (lmtest == FALSE) ? "OFF" : "ON"));
2187             }
2188             break;
2189         }
2190 #endif // endif
2191 
2192 #ifdef SHOW_LOGTRACE
2193         case IOV_GVAL(IOV_DUMP_TRACE_LOG): {
2194             trace_buf_info_t *trace_buf_info = (trace_buf_info_t *)arg;
2195             dhd_dbg_ring_t *dbg_verbose_ring = NULL;
2196 
2197             dbg_verbose_ring =
2198                 dhd_dbg_get_ring_from_ring_id(dhd_pub, FW_VERBOSE_RING_ID);
2199             if (dbg_verbose_ring == NULL) {
2200                 DHD_ERROR(("dbg_verbose_ring is NULL\n"));
2201                 bcmerror = BCME_UNSUPPORTED;
2202                 break;
2203             }
2204 
2205             if (trace_buf_info != NULL) {
2206                 bzero(trace_buf_info, sizeof(trace_buf_info_t));
2207                 dhd_dbg_read_ring_into_trace_buf(dbg_verbose_ring,
2208                                                  trace_buf_info);
2209             } else {
2210                 DHD_ERROR(("%s: arg is NULL\n", __FUNCTION__));
2211                 bcmerror = BCME_NOMEM;
2212             }
2213             break;
2214         }
2215 #endif /* SHOW_LOGTRACE */
2216 #ifdef DHD_DEBUG
2217 #if defined(BCMSDIO) || defined(BCMPCIE)
2218         case IOV_GVAL(IOV_DONGLE_TRAP_TYPE):
2219             if (dhd_pub->dongle_trap_occured) {
2220                 int_val = ltoh32(dhd_pub->last_trap_info.type);
2221             } else {
2222                 int_val = 0;
2223             }
2224             bcopy(&int_val, arg, val_size);
2225             break;
2226 
2227         case IOV_GVAL(IOV_DONGLE_TRAP_INFO): {
2228             struct bcmstrbuf strbuf;
2229             bcm_binit(&strbuf, arg, len);
2230             if (dhd_pub->dongle_trap_occured == FALSE) {
2231                 bcm_bprintf(&strbuf, "no trap recorded\n");
2232                 break;
2233             }
2234             dhd_bus_dump_trap_info(dhd_pub->bus, &strbuf);
2235             break;
2236         }
2237 
2238         case IOV_GVAL(IOV_BPADDR): {
2239             sdreg_t sdreg;
2240             uint32 addr, size;
2241 
2242             memcpy(&sdreg, params, sizeof(sdreg));
2243 
2244             addr = sdreg.offset;
2245             size = sdreg.func;
2246 
2247             bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size,
2248                                                  (uint *)&int_val, TRUE);
2249 
2250             memcpy(arg, &int_val, sizeof(int32));
2251 
2252             break;
2253         }
2254 
2255         case IOV_SVAL(IOV_BPADDR): {
2256             sdreg_t sdreg;
2257             uint32 addr, size;
2258 
2259             memcpy(&sdreg, params, sizeof(sdreg));
2260 
2261             addr = sdreg.offset;
2262             size = sdreg.func;
2263 
2264             bcmerror = dhd_bus_readwrite_bp_addr(dhd_pub, addr, size,
2265                                                  (uint *)&sdreg.value, FALSE);
2266 
2267             break;
2268         }
2269 #endif /* BCMSDIO || BCMPCIE */
2270 #ifdef BCMPCIE
2271         case IOV_SVAL(IOV_FLOW_RING_DEBUG): {
2272             bcmerror = dhd_flow_ring_debug(dhd_pub, arg, len);
2273             break;
2274         }
2275 #endif /* BCMPCIE */
2276         case IOV_SVAL(IOV_MEM_DEBUG):
2277             if (len > 0) {
2278                 bcmerror = dhd_mem_debug(dhd_pub, arg, len - 1);
2279             }
2280             break;
2281 #endif /* DHD_DEBUG */
2282 #if defined(DHD_LOG_DUMP)
2283         case IOV_GVAL(IOV_LOG_DUMP): {
2284             dhd_prot_debug_info_print(dhd_pub);
2285             dhd_log_dump_trigger(dhd_pub, CMD_DEFAULT);
2286             break;
2287         }
2288 #endif /* DHD_LOG_DUMP */
2289         case IOV_GVAL(IOV_DEBUG_BUF_DEST_STAT): {
2290             if (dhd_pub->debug_buf_dest_support) {
2291                 debug_buf_dest_stat_t *debug_buf_dest_stat =
2292                     (debug_buf_dest_stat_t *)arg;
2293                 memcpy(debug_buf_dest_stat, dhd_pub->debug_buf_dest_stat,
2294                        sizeof(dhd_pub->debug_buf_dest_stat));
2295             } else {
2296                 bcmerror = BCME_DISABLED;
2297             }
2298             break;
2299         }
2300 
2301 #ifdef DHD_DEBUG
2302         case IOV_SVAL(IOV_INDUCE_ERROR): {
2303             if (int_val >= DHD_INDUCE_ERROR_MAX) {
2304                 DHD_ERROR(("%s: Invalid command : %u\n", __FUNCTION__,
2305                            (uint16)int_val));
2306             } else {
2307                 dhd_pub->dhd_induce_error = (uint16)int_val;
2308             }
2309             break;
2310         }
2311 #endif /* DHD_DEBUG */
2312 
2313 #ifdef WL_IFACE_MGMT_CONF
2314 #ifdef WL_CFG80211
2315 #ifdef WL_NANP2P
2316         case IOV_GVAL(IOV_CONC_DISC): {
2317             int_val = wl_cfg80211_get_iface_conc_disc(
2318                 dhd_linux_get_primary_netdev(dhd_pub));
2319             bcopy(&int_val, arg, sizeof(int_val));
2320             break;
2321         }
2322         case IOV_SVAL(IOV_CONC_DISC): {
2323             bcmerror = wl_cfg80211_set_iface_conc_disc(
2324                 dhd_linux_get_primary_netdev(dhd_pub), (uint8)int_val);
2325             break;
2326         }
2327 #endif /* WL_NANP2P */
2328 #ifdef WL_IFACE_MGMT
2329         case IOV_GVAL(IOV_IFACE_POLICY): {
2330             int_val = wl_cfg80211_get_iface_policy(
2331                 dhd_linux_get_primary_netdev(dhd_pub));
2332             bcopy(&int_val, arg, sizeof(int_val));
2333             break;
2334         }
2335         case IOV_SVAL(IOV_IFACE_POLICY): {
2336             bcmerror = wl_cfg80211_set_iface_policy(
2337                 dhd_linux_get_primary_netdev(dhd_pub), arg, len);
2338             break;
2339         }
2340 #endif /* WL_IFACE_MGMT */
2341 #endif /* WL_CFG80211 */
2342 #endif /* WL_IFACE_MGMT_CONF */
2343 #ifdef RTT_GEOFENCE_CONT
2344 #if defined(RTT_SUPPORT) && defined(WL_NAN)
2345         case IOV_GVAL(IOV_RTT_GEOFENCE_TYPE_OVRD): {
2346             bool enable = 0;
2347             dhd_rtt_get_geofence_cont_ind(dhd_pub, &enable);
2348             int_val = enable ? 1 : 0;
2349             bcopy(&int_val, arg, val_size);
2350             break;
2351         }
2352         case IOV_SVAL(IOV_RTT_GEOFENCE_TYPE_OVRD): {
2353             bool enable = *(bool *)arg;
2354             dhd_rtt_set_geofence_cont_ind(dhd_pub, enable);
2355             break;
2356         }
2357 #endif /* RTT_SUPPORT && WL_NAN */
2358 #endif /* RTT_GEOFENCE_CONT */
2359 #ifdef WLEASYMESH
2360         case IOV_SVAL(IOV_1905_AL_UCAST): {
2361             uint32 bssidx;
2362             const char *val;
2363             uint8 ea[6] = {0};
2364             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2365                 BCME_OK) {
2366                 DHD_ERROR(("%s: 1905_al_ucast: bad parameter\n", __FUNCTION__));
2367                 bcmerror = BCME_BADARG;
2368                 break;
2369             }
2370             bcopy(val, ea, ETHER_ADDR_LEN);
2371             printf("IOV_1905_AL_UCAST:" MACDBG "\n", MAC2STRDBG(ea));
2372             bcmerror = dhd_set_1905_almac(dhd_pub, bssidx, ea, FALSE);
2373             break;
2374         }
2375         case IOV_GVAL(IOV_1905_AL_UCAST): {
2376             uint32 bssidx;
2377             const char *val;
2378             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2379                 BCME_OK) {
2380                 DHD_ERROR(("%s: 1905_al_ucast: bad parameter\n", __FUNCTION__));
2381                 bcmerror = BCME_BADARG;
2382                 break;
2383             }
2384 
2385             bcmerror = dhd_get_1905_almac(dhd_pub, bssidx, arg, FALSE);
2386             break;
2387         }
2388         case IOV_SVAL(IOV_1905_AL_MCAST): {
2389             uint32 bssidx;
2390             const char *val;
2391             uint8 ea[6] = {0};
2392             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2393                 BCME_OK) {
2394                 DHD_ERROR(("%s: 1905_al_mcast: bad parameter\n", __FUNCTION__));
2395                 bcmerror = BCME_BADARG;
2396                 break;
2397             }
2398             bcopy(val, ea, ETHER_ADDR_LEN);
2399             printf("IOV_1905_AL_MCAST:" MACDBG "\n", MAC2STRDBG(ea));
2400             bcmerror = dhd_set_1905_almac(dhd_pub, bssidx, ea, TRUE);
2401             break;
2402         }
2403         case IOV_GVAL(IOV_1905_AL_MCAST): {
2404             uint32 bssidx;
2405             const char *val;
2406             if (dhd_iovar_parse_bssidx(dhd_pub, (char *)name, &bssidx, &val) !=
2407                 BCME_OK) {
2408                 DHD_ERROR(("%s: 1905_al_mcast: bad parameter\n", __FUNCTION__));
2409                 bcmerror = BCME_BADARG;
2410                 break;
2411             }
2412 
2413             bcmerror = dhd_get_1905_almac(dhd_pub, bssidx, arg, TRUE);
2414             break;
2415         }
2416 #endif /* WLEASYMESH */
2417         default:
2418             bcmerror = BCME_UNSUPPORTED;
2419             break;
2420     }
2421 
2422 exit:
2423     DHD_TRACE(
2424         ("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror));
2425     return bcmerror;
2426 }
2427 
2428 /* Store the status of a connection attempt for later retrieval by an iovar */
dhd_store_conn_status(uint32 event,uint32 status,uint32 reason)2429 void dhd_store_conn_status(uint32 event, uint32 status, uint32 reason)
2430 {
2431     /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID
2432      * because an encryption/rsn mismatch results in both events, and
2433      * the important information is in the WLC_E_PRUNE.
2434      */
2435     if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL &&
2436           dhd_conn_event == WLC_E_PRUNE)) {
2437         dhd_conn_event = event;
2438         dhd_conn_status = status;
2439         dhd_conn_reason = reason;
2440     }
2441 }
2442 
dhd_prec_enq(dhd_pub_t * dhdp,struct pktq * q,void * pkt,int prec)2443 bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec)
2444 {
2445     void *p;
2446     int eprec = -1; /* precedence to evict from */
2447     bool discard_oldest;
2448 
2449     /* Fast case, precedence queue is not full and we are also not
2450      * exceeding total queue length
2451      */
2452     if (!pktqprec_full(q, prec) && !pktq_full(q)) {
2453         pktq_penq(q, prec, pkt);
2454         return TRUE;
2455     }
2456 
2457     /* Determine precedence from which to evict packet, if any */
2458     if (pktqprec_full(q, prec)) {
2459         eprec = prec;
2460     } else if (pktq_full(q)) {
2461         p = pktq_peek_tail(q, &eprec);
2462         ASSERT(p);
2463         if (eprec > prec || eprec < 0) {
2464             return FALSE;
2465         }
2466     }
2467 
2468     /* Evict if needed */
2469     if (eprec >= 0) {
2470         /* Detect queueing to unconfigured precedence */
2471         ASSERT(!pktqprec_empty(q, eprec));
2472         discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec);
2473         if (eprec == prec && !discard_oldest) {
2474             return FALSE; /* refuse newer (incoming) packet */
2475         }
2476         /* Evict packet according to discard policy */
2477         p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec);
2478         ASSERT(p);
2479 #ifdef DHDTCPACK_SUPPRESS
2480         if (dhd_tcpack_check_xmit(dhdp, p) == BCME_ERROR) {
2481             DHD_ERROR(("%s %d: tcpack_suppress ERROR!!! Stop using it\n",
2482                        __FUNCTION__, __LINE__));
2483             dhd_tcpack_suppress_set(dhdp, TCPACK_SUP_OFF);
2484         }
2485 #endif /* DHDTCPACK_SUPPRESS */
2486         PKTFREE(dhdp->osh, p, TRUE);
2487     }
2488 
2489     /* Enqueue */
2490     p = pktq_penq(q, prec, pkt);
2491     ASSERT(p);
2492 
2493     return TRUE;
2494 }
2495 
2496 /*
2497  * Functions to drop proper pkts from queue:
2498  *	If one pkt in queue is non-fragmented, drop first non-fragmented pkt only
2499  *	If all pkts in queue are all fragmented, find and drop one whole set
2500  * fragmented pkts If can't find pkts matching upper 2 cases, drop first pkt
2501  * anyway
2502  */
dhd_prec_drop_pkts(dhd_pub_t * dhdp,struct pktq * pq,int prec,f_droppkt_t fn)2503 bool dhd_prec_drop_pkts(dhd_pub_t *dhdp, struct pktq *pq, int prec,
2504                         f_droppkt_t fn)
2505 {
2506     struct pktq_prec *q = NULL;
2507     void *p, *prev = NULL, *next = NULL, *first = NULL, *last = NULL,
2508              *prev_first = NULL;
2509     pkt_frag_t frag_info;
2510 
2511     ASSERT(dhdp && pq);
2512     ASSERT(prec >= 0 && prec < pq->num_prec);
2513 
2514     q = &pq->q[prec];
2515     p = q->head;
2516 
2517     if (p == NULL) {
2518         return FALSE;
2519     }
2520 
2521     while (p) {
2522         frag_info = pkt_frag_info(dhdp->osh, p);
2523         if (frag_info == DHD_PKT_FRAG_NONE) {
2524             break;
2525         } else if (frag_info == DHD_PKT_FRAG_FIRST) {
2526             if (first) {
2527                 /* No last frag pkt, use prev as last */
2528                 last = prev;
2529                 break;
2530             } else {
2531                 first = p;
2532                 prev_first = prev;
2533             }
2534         } else if (frag_info == DHD_PKT_FRAG_LAST) {
2535             if (first) {
2536                 last = p;
2537                 break;
2538             }
2539         }
2540 
2541         prev = p;
2542         p = PKTLINK(p);
2543     }
2544 
2545     if ((p == NULL) || ((frag_info != DHD_PKT_FRAG_NONE) && !(first && last))) {
2546         /* Not found matching pkts, use oldest */
2547         prev = NULL;
2548         p = q->head;
2549         frag_info = 0;
2550     }
2551 
2552     if (frag_info == DHD_PKT_FRAG_NONE) {
2553         first = last = p;
2554         prev_first = prev;
2555     }
2556 
2557     p = first;
2558     while (p) {
2559         next = PKTLINK(p);
2560         q->n_pkts--;
2561         pq->n_pkts_tot--;
2562 
2563 #ifdef WL_TXQ_STALL
2564         q->dequeue_count++;
2565 #endif // endif
2566 
2567         PKTSETLINK(p, NULL);
2568 
2569         if (fn) {
2570             fn(dhdp, prec, p, TRUE);
2571         }
2572 
2573         if (p == last) {
2574             break;
2575         }
2576 
2577         p = next;
2578     }
2579 
2580     if (prev_first == NULL) {
2581         if ((q->head = next) == NULL) {
2582             q->tail = NULL;
2583         }
2584     } else {
2585         PKTSETLINK(prev_first, next);
2586         if (!next) {
2587             q->tail = prev_first;
2588         }
2589     }
2590 
2591     return TRUE;
2592 }
2593 
dhd_iovar_op(dhd_pub_t * dhd_pub,const char * name,void * params,int plen,void * arg,int len,bool set)2594 static int dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, void *params,
2595                         int plen, void *arg, int len, bool set)
2596 {
2597     int bcmerror = 0;
2598     int val_size;
2599     const bcm_iovar_t *vi = NULL;
2600     uint32 actionid;
2601 
2602     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2603 
2604     ASSERT(name);
2605     ASSERT(len >= 0);
2606 
2607     /* Get MUST have return space */
2608     ASSERT(set || (arg && len));
2609 
2610     /* Set does NOT take qualifiers */
2611     ASSERT(!set || (!params && !plen));
2612 
2613     if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) {
2614         bcmerror = BCME_UNSUPPORTED;
2615         goto exit;
2616     }
2617 
2618     DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, name,
2619              (set ? "set" : "get"), len, plen));
2620 
2621     /* set up 'params' pointer in case this is a set command so that
2622      * the convenience int and bool code can be common to set and get
2623      */
2624     if (params == NULL) {
2625         params = arg;
2626         plen = len;
2627     }
2628 
2629     if (vi->type == IOVT_VOID) {
2630         val_size = 0;
2631     } else if (vi->type == IOVT_BUFFER) {
2632         val_size = len;
2633     } else {
2634         /* all other types are integer sized */
2635         val_size = sizeof(int);
2636     }
2637 
2638     actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
2639 
2640     bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len,
2641                            val_size);
2642 
2643 exit:
2644     return bcmerror;
2645 }
2646 
dhd_ioctl(dhd_pub_t * dhd_pub,dhd_ioctl_t * ioc,void * buf,uint buflen)2647 int dhd_ioctl(dhd_pub_t *dhd_pub, dhd_ioctl_t *ioc, void *buf, uint buflen)
2648 {
2649     int bcmerror = 0;
2650     unsigned long flags;
2651 
2652     DHD_TRACE(("%s: Enter\n", __FUNCTION__));
2653 
2654     if (!buf) {
2655         return BCME_BADARG;
2656     }
2657 
2658     dhd_os_dhdiovar_lock(dhd_pub);
2659     switch (ioc->cmd) {
2660         case DHD_GET_MAGIC:
2661             if (buflen < sizeof(int)) {
2662                 bcmerror = BCME_BUFTOOSHORT;
2663             } else {
2664                 *(int *)buf = DHD_IOCTL_MAGIC;
2665             }
2666             break;
2667 
2668         case DHD_GET_VERSION:
2669             if (buflen < sizeof(int)) {
2670                 bcmerror = BCME_BUFTOOSHORT;
2671             } else {
2672                 *(int *)buf = DHD_IOCTL_VERSION;
2673             }
2674             break;
2675 
2676         case DHD_GET_VAR:
2677         case DHD_SET_VAR: {
2678             char *arg;
2679             uint arglen;
2680 
2681             DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2682             if (DHD_BUS_CHECK_DOWN_OR_DOWN_IN_PROGRESS(dhd_pub) &&
2683                 bcmstricmp((char *)buf, "devreset")) {
2684                 /* In platforms like FC19, the FW download is done via IOCTL
2685                  * and should not return error for IOCTLs fired before FW
2686                  * Download is done
2687                  */
2688                 if (dhd_fw_download_status(dhd_pub) == FW_DOWNLOAD_DONE) {
2689                     DHD_ERROR(("%s: returning as busstate=%d\n", __FUNCTION__,
2690                                dhd_pub->busstate));
2691                     DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2692                     dhd_os_dhdiovar_unlock(dhd_pub);
2693                     return -ENODEV;
2694                 }
2695             }
2696             DHD_BUS_BUSY_SET_IN_DHD_IOVAR(dhd_pub);
2697             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2698 
2699             DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2700             if (DHD_BUS_CHECK_SUSPEND_OR_SUSPEND_IN_PROGRESS(dhd_pub)) {
2701                 /* If Suspend/Resume is tested via pcie_suspend IOVAR
2702                  * then continue to execute the IOVAR, return from here for
2703                  * other IOVARs, also include pciecfgreg and devreset to go
2704                  * through.
2705                  */
2706                 if (bcmstricmp((char *)buf, "pcie_suspend") &&
2707                     bcmstricmp((char *)buf, "pciecfgreg") &&
2708                     bcmstricmp((char *)buf, "devreset") &&
2709                     bcmstricmp((char *)buf, "sdio_suspend")) {
2710                     DHD_ERROR(("%s: bus is in suspend(%d)"
2711                                "or suspending(0x%x) state\n",
2712                                __FUNCTION__, dhd_pub->busstate,
2713                                dhd_pub->dhd_bus_busy_state));
2714                     DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2715                     dhd_os_busbusy_wake(dhd_pub);
2716                     DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2717                     dhd_os_dhdiovar_unlock(dhd_pub);
2718                     return -ENODEV;
2719                 }
2720             }
2721             /* During devreset ioctl, we call dhdpcie_advertise_bus_cleanup,
2722              * which will wait for all the busy contexts to get over for
2723              * particular time and call ASSERT if timeout happens. As during
2724              * devreset ioctal, we made DHD_BUS_BUSY_SET_IN_DHD_IOVAR,
2725              * to avoid ASSERT, clear the IOCTL busy state. "devreset" ioctl is
2726              * not used in Production platforms but only used in FC19 setups.
2727              */
2728             if (!bcmstricmp((char *)buf, "devreset") ||
2729 #ifdef BCMPCIE
2730                 (dhd_bus_is_multibp_capable(dhd_pub->bus) &&
2731                  !bcmstricmp((char *)buf, "dwnldstate")) ||
2732 #endif /* BCMPCIE */
2733                 FALSE) {
2734                 DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2735             }
2736             DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2737 
2738             /* scan past the name to any arguments */
2739             for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) {
2740                 ;
2741             }
2742 
2743             if (*arg) {
2744                 bcmerror = BCME_BUFTOOSHORT;
2745                 goto unlock_exit;
2746             }
2747 
2748             /* account for the NUL terminator */
2749             arg++, arglen--;
2750             /* call with the appropriate arguments */
2751             if (ioc->cmd == DHD_GET_VAR) {
2752                 bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, buf, buflen,
2753                                         IOV_GET);
2754             } else {
2755                 bcmerror =
2756                     dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET);
2757             }
2758             if (bcmerror != BCME_UNSUPPORTED) {
2759                 goto unlock_exit;
2760             }
2761 
2762             /* not in generic table, try protocol module */
2763             if (ioc->cmd == DHD_GET_VAR) {
2764                 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, arglen, buf,
2765                                              buflen, IOV_GET);
2766             } else {
2767                 bcmerror = dhd_prot_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen,
2768                                              IOV_SET);
2769             }
2770             if (bcmerror != BCME_UNSUPPORTED) {
2771                 goto unlock_exit;
2772             }
2773 
2774             /* if still not found, try bus module */
2775             if (ioc->cmd == DHD_GET_VAR) {
2776                 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, arg, arglen, buf,
2777                                             buflen, IOV_GET);
2778             } else {
2779                 bcmerror = dhd_bus_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen,
2780                                             IOV_SET);
2781             }
2782             if (bcmerror != BCME_UNSUPPORTED) {
2783                 goto unlock_exit;
2784             }
2785         }
2786             goto unlock_exit;
2787 
2788         default:
2789             bcmerror = BCME_UNSUPPORTED;
2790     }
2791     dhd_os_dhdiovar_unlock(dhd_pub);
2792     return bcmerror;
2793 
2794 unlock_exit:
2795     DHD_LINUX_GENERAL_LOCK(dhd_pub, flags);
2796     DHD_BUS_BUSY_CLEAR_IN_DHD_IOVAR(dhd_pub);
2797     dhd_os_busbusy_wake(dhd_pub);
2798     DHD_LINUX_GENERAL_UNLOCK(dhd_pub, flags);
2799     dhd_os_dhdiovar_unlock(dhd_pub);
2800     return bcmerror;
2801 }
2802 
2803 #ifdef SHOW_EVENTS
2804 
wl_show_host_event(dhd_pub_t * dhd_pub,wl_event_msg_t * event,void * event_data,void * raw_event_ptr,char * eventmask)2805 static void wl_show_host_event(dhd_pub_t *dhd_pub, wl_event_msg_t *event,
2806                                void *event_data, void *raw_event_ptr,
2807                                char *eventmask)
2808 {
2809     uint i, status, reason;
2810     bool group = FALSE, flush_txq = FALSE, link = FALSE;
2811     bool host_data = FALSE; /* prints  event data after the case  when set */
2812     const char *auth_str;
2813     const char *event_name;
2814     uchar *buf;
2815     char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
2816     uint event_type, flags, auth_type, datalen;
2817 
2818     event_type = ntoh32(event->event_type);
2819     flags = ntoh16(event->flags);
2820     status = ntoh32(event->status);
2821     reason = ntoh32(event->reason);
2822     BCM_REFERENCE(reason);
2823     auth_type = ntoh32(event->auth_type);
2824     datalen = ntoh32(event->datalen);
2825 
2826     /* debug dump of event messages */
2827     snprintf(eabuf, sizeof(eabuf), MACDBG, MAC2STRDBG(event->addr.octet));
2828 
2829     event_name = bcmevent_get_name(event_type);
2830     BCM_REFERENCE(event_name);
2831 
2832     if (flags & WLC_EVENT_MSG_LINK) {
2833         link = TRUE;
2834     }
2835     if (flags & WLC_EVENT_MSG_GROUP) {
2836         group = TRUE;
2837     }
2838     if (flags & WLC_EVENT_MSG_FLUSHTXQ) {
2839         flush_txq = TRUE;
2840     }
2841 
2842     switch (event_type) {
2843         case WLC_E_START:
2844         case WLC_E_DEAUTH:
2845         case WLC_E_DISASSOC:
2846             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2847             break;
2848 
2849         case WLC_E_ASSOC_IND:
2850         case WLC_E_REASSOC_IND:
2851 
2852             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2853 
2854             break;
2855 
2856         case WLC_E_ASSOC:
2857         case WLC_E_REASSOC:
2858             if (status == WLC_E_STATUS_SUCCESS) {
2859                 DHD_EVENT(
2860                     ("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf));
2861             } else if (status == WLC_E_STATUS_TIMEOUT) {
2862                 DHD_EVENT(
2863                     ("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf));
2864             } else if (status == WLC_E_STATUS_FAIL) {
2865                 DHD_EVENT(
2866                     ("MACEVENT: %s, MAC %s, FAILURE, status %d reason %d\n",
2867                      event_name, eabuf, (int)status, (int)reason));
2868             } else {
2869                 DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n",
2870                            event_name, eabuf, (int)status));
2871             }
2872 
2873             break;
2874 
2875         case WLC_E_DEAUTH_IND:
2876         case WLC_E_DISASSOC_IND:
2877             DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf,
2878                        (int)reason));
2879             break;
2880 
2881         case WLC_E_AUTH:
2882         case WLC_E_AUTH_IND:
2883             if (auth_type == DOT11_OPEN_SYSTEM) {
2884                 auth_str = "Open System";
2885             } else if (auth_type == DOT11_SHARED_KEY) {
2886                 auth_str = "Shared Key";
2887             } else if (auth_type == DOT11_SAE) {
2888                 auth_str = "SAE";
2889             } else {
2890                 snprintf(err_msg, sizeof(err_msg), "AUTH unknown: %d",
2891                          (int)auth_type);
2892                 auth_str = err_msg;
2893             }
2894 
2895             if (event_type == WLC_E_AUTH_IND) {
2896                 DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf,
2897                            auth_str));
2898             } else if (status == WLC_E_STATUS_SUCCESS) {
2899                 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", event_name,
2900                            eabuf, auth_str));
2901             } else if (status == WLC_E_STATUS_TIMEOUT) {
2902                 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", event_name,
2903                            eabuf, auth_str));
2904             } else if (status == WLC_E_STATUS_FAIL) {
2905                 DHD_EVENT(
2906                     ("MACEVENT: %s, MAC %s, %s, FAILURE, status %d reason %d\n",
2907                      event_name, eabuf, auth_str, (int)status, (int)reason));
2908             } else if (status == WLC_E_STATUS_NO_ACK) {
2909                 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, NOACK\n", event_name,
2910                            eabuf, auth_str));
2911             } else {
2912                 DHD_EVENT(("MACEVENT: %s, MAC %s, %s, status %d reason %d\n",
2913                            event_name, eabuf, auth_str, (int)status,
2914                            (int)reason));
2915             }
2916             BCM_REFERENCE(auth_str);
2917 
2918             break;
2919 
2920         case WLC_E_JOIN:
2921         case WLC_E_ROAM:
2922         case WLC_E_SET_SSID:
2923             if (status == WLC_E_STATUS_SUCCESS) {
2924                 DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2925             } else {
2926                 if (status == WLC_E_STATUS_FAIL) {
2927                     DHD_EVENT(("MACEVENT: %s, failed status %d\n", event_name,
2928                                status));
2929                 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
2930                     DHD_EVENT(
2931                         ("MACEVENT: %s, no networks found\n", event_name));
2932                 } else {
2933                     DHD_EVENT(("MACEVENT: %s, unexpected status %d\n",
2934                                event_name, (int)status));
2935                 }
2936             }
2937             break;
2938 
2939         case WLC_E_BEACON_RX:
2940             if (status == WLC_E_STATUS_SUCCESS) {
2941                 DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name));
2942             } else if (status == WLC_E_STATUS_FAIL) {
2943                 DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name));
2944             } else {
2945                 DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status));
2946             }
2947             break;
2948 
2949         case WLC_E_LINK:
2950             DHD_EVENT(("MACEVENT: %s %s flags:0x%x status:%d\n", event_name,
2951                        link ? "UP" : "DOWN", flags, status));
2952             BCM_REFERENCE(link);
2953             break;
2954 
2955         case WLC_E_MIC_ERROR:
2956             DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", event_name,
2957                        eabuf, group, flush_txq));
2958             BCM_REFERENCE(group);
2959             BCM_REFERENCE(flush_txq);
2960             break;
2961 
2962         case WLC_E_ICV_ERROR:
2963         case WLC_E_UNICAST_DECODE_ERROR:
2964         case WLC_E_MULTICAST_DECODE_ERROR:
2965             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
2966             break;
2967 
2968         case WLC_E_TXFAIL:
2969             DHD_EVENT(
2970                 ("MACEVENT: %s, RA %s status %d\n", event_name, eabuf, status));
2971             break;
2972 
2973         case WLC_E_ASSOC_REQ_IE:
2974         case WLC_E_ASSOC_RESP_IE:
2975         case WLC_E_PMKID_CACHE:
2976             DHD_EVENT(("MACEVENT: %s\n", event_name));
2977             break;
2978 
2979         case WLC_E_SCAN_COMPLETE:
2980             DHD_EVENT(("MACEVENT: %s\n", event_name));
2981             break;
2982         case WLC_E_RSSI_LQM:
2983         case WLC_E_PFN_NET_FOUND:
2984         case WLC_E_PFN_NET_LOST:
2985         case WLC_E_PFN_SCAN_COMPLETE:
2986         case WLC_E_PFN_SCAN_NONE:
2987         case WLC_E_PFN_SCAN_ALLGONE:
2988         case WLC_E_PFN_GSCAN_FULL_RESULT:
2989         case WLC_E_PFN_SSID_EXT:
2990             DHD_EVENT(("PNOEVENT: %s\n", event_name));
2991             break;
2992 
2993         case WLC_E_PFN_SCAN_BACKOFF:
2994         case WLC_E_PFN_BSSID_SCAN_BACKOFF:
2995             DHD_EVENT(("PNOEVENT: %s, status %d, reason %d\n", event_name,
2996                        (int)status, (int)reason));
2997             break;
2998 
2999         case WLC_E_PSK_SUP:
3000         case WLC_E_PRUNE:
3001             DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", event_name,
3002                        (int)status, (int)reason));
3003             break;
3004 
3005 #ifdef WIFI_ACT_FRAME
3006         case WLC_E_ACTION_FRAME:
3007             DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf));
3008             break;
3009 #endif /* WIFI_ACT_FRAME */
3010 
3011 #ifdef SHOW_LOGTRACE
3012         case WLC_E_TRACE: {
3013             dhd_dbg_trace_evnt_handler(dhd_pub, event_data, raw_event_ptr,
3014                                        datalen);
3015             break;
3016         }
3017 #endif /* SHOW_LOGTRACE */
3018 
3019         case WLC_E_RSSI:
3020             DHD_EVENT(("MACEVENT: %s %d\n", event_name,
3021                        ntoh32(*((int *)event_data))));
3022             break;
3023 
3024         case WLC_E_SERVICE_FOUND:
3025         case WLC_E_P2PO_ADD_DEVICE:
3026         case WLC_E_P2PO_DEL_DEVICE:
3027             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
3028             break;
3029 
3030 #ifdef BT_WIFI_HANDOBER
3031         case WLC_E_BT_WIFI_HANDOVER_REQ:
3032             DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf));
3033             break;
3034 #endif // endif
3035 
3036         case WLC_E_CCA_CHAN_QUAL:
3037             if (datalen) {
3038                 cca_chan_qual_event_t *cca_event =
3039                     (cca_chan_qual_event_t *)event_data;
3040                 if (cca_event->id == WL_CHAN_QUAL_FULLPM_CCA) {
3041                     cca_only_chan_qual_event_t *cca_only_event =
3042                         (cca_only_chan_qual_event_t *)cca_event;
3043                     BCM_REFERENCE(cca_only_event);
3044                     DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
3045                                "auth %d,"
3046                                " channel 0x%02x\n",
3047                                event_name, event_type, eabuf, (int)status,
3048                                (int)reason, (int)auth_type,
3049                                cca_event->chanspec));
3050                     DHD_EVENT(
3051                         ("\tTOTAL (dur %dms me %dms notme %dms interf %dms"
3052                          " ts 0x%08x)\n",
3053                          cca_only_event->cca_busy_ext.duration,
3054                          cca_only_event->cca_busy_ext.congest_ibss,
3055                          cca_only_event->cca_busy_ext.congest_obss,
3056                          cca_only_event->cca_busy_ext.interference,
3057                          cca_only_event->cca_busy_ext.timestamp));
3058                     DHD_EVENT(
3059                         ("\t  !PM (dur %dms me %dms notme %dms interf %dms)\n",
3060                          cca_only_event->cca_busy_nopm.duration,
3061                          cca_only_event->cca_busy_nopm.congest_ibss,
3062                          cca_only_event->cca_busy_nopm.congest_obss,
3063                          cca_only_event->cca_busy_nopm.interference));
3064                     DHD_EVENT(
3065                         ("\t   PM (dur %dms me %dms notme %dms interf %dms)\n",
3066                          cca_only_event->cca_busy_pm.duration,
3067                          cca_only_event->cca_busy_pm.congest_ibss,
3068                          cca_only_event->cca_busy_pm.congest_obss,
3069                          cca_only_event->cca_busy_pm.interference));
3070                 } else if (cca_event->id == WL_CHAN_QUAL_FULL_CCA) {
3071                     DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
3072                                "auth %d,"
3073                                " channel 0x%02x (dur %dms ibss %dms obss %dms "
3074                                "interf %dms"
3075                                " ts 0x%08x)\n",
3076                                event_name, event_type, eabuf, (int)status,
3077                                (int)reason, (int)auth_type, cca_event->chanspec,
3078                                cca_event->cca_busy_ext.duration,
3079                                cca_event->cca_busy_ext.congest_ibss,
3080                                cca_event->cca_busy_ext.congest_obss,
3081                                cca_event->cca_busy_ext.interference,
3082                                cca_event->cca_busy_ext.timestamp));
3083                 } else if (cca_event->id == WL_CHAN_QUAL_CCA) {
3084                     DHD_EVENT(
3085                         ("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth "
3086                          "%d,"
3087                          " channel 0x%02x (dur %dms busy %dms ts 0x%08x)\n",
3088                          event_name, event_type, eabuf, (int)status,
3089                          (int)reason, (int)auth_type, cca_event->chanspec,
3090                          cca_event->cca_busy.duration,
3091                          cca_event->cca_busy.congest,
3092                          cca_event->cca_busy.timestamp));
3093                 } else if ((cca_event->id == WL_CHAN_QUAL_NF) ||
3094                            (cca_event->id == WL_CHAN_QUAL_NF_LTE)) {
3095                     DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
3096                                "auth %d,"
3097                                " channel 0x%02x (NF[%d] %ddB)\n",
3098                                event_name, event_type, eabuf, (int)status,
3099                                (int)reason, (int)auth_type, cca_event->chanspec,
3100                                cca_event->id, cca_event->noise));
3101                 } else {
3102                     DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, "
3103                                "auth %d,"
3104                                " channel 0x%02x (unknown ID %d)\n",
3105                                event_name, event_type, eabuf, (int)status,
3106                                (int)reason, (int)auth_type, cca_event->chanspec,
3107                                cca_event->id));
3108                 }
3109             }
3110             break;
3111         case WLC_E_ESCAN_RESULT: {
3112             wl_escan_result_v2_t *escan_result =
3113                 (wl_escan_result_v2_t *)event_data;
3114             BCM_REFERENCE(escan_result);
3115             if ((status == WLC_E_STATUS_SUCCESS) ||
3116                 (status == WLC_E_STATUS_ABORT)) {
3117                 DHD_EVENT(("MACEVENT: %s %d, status %d sync-id %u\n",
3118                            event_name, event_type, (int)status,
3119                            dtoh16(escan_result->sync_id)));
3120             } else {
3121                 DHD_TRACE(("MACEVENT: %s %d, MAC %s, status %d \n", event_name,
3122                            event_type, eabuf, (int)status));
3123             }
3124 
3125             break;
3126         }
3127         case WLC_E_IF: {
3128             struct wl_event_data_if *ifevent =
3129                 (struct wl_event_data_if *)event_data;
3130             BCM_REFERENCE(ifevent);
3131 
3132             DHD_EVENT(("MACEVENT: %s, opcode:0x%d  ifidx:%d role:%d\n",
3133                        event_name, ifevent->opcode, ifevent->ifidx,
3134                        ifevent->role));
3135             break;
3136         }
3137 #ifdef SHOW_LOGTRACE
3138         case WLC_E_MSCH: {
3139             wl_mschdbg_event_handler(dhd_pub, raw_event_ptr, reason, event_data,
3140                                      datalen);
3141             break;
3142         }
3143 #endif /* SHOW_LOGTRACE */
3144 
3145         case WLC_E_PSK_AUTH:
3146             DHD_EVENT(("MACEVENT: %s, RA %s status %d Reason:%d\n", event_name,
3147                        eabuf, status, reason));
3148             break;
3149         case WLC_E_AGGR_EVENT: {
3150             event_aggr_data_t *aggrbuf = event_data;
3151             int j = 0, len = 0;
3152             uint8 *data = aggrbuf->data;
3153             DHD_EVENT(
3154                 ("MACEVENT: %s, num of events %d total len %d sub events: ",
3155                  event_name, aggrbuf->num_events, aggrbuf->len));
3156             for (j = 0; j < aggrbuf->num_events; j++) {
3157                 wl_event_msg_t *sub_event = (wl_event_msg_t *)data;
3158                 if (len > aggrbuf->len) {
3159                     DHD_ERROR(("%s: Aggr events corrupted!", __FUNCTION__));
3160                     break;
3161                 }
3162                 DHD_EVENT(
3163                     ("\n Event type: %d ", ntoh32(sub_event->event_type)));
3164                 len += ALIGN_SIZE(
3165                     (ntoh32(sub_event->datalen) + sizeof(wl_event_msg_t)),
3166                     sizeof(uint64));
3167                 buf = (uchar *)(data + sizeof(wl_event_msg_t));
3168                 BCM_REFERENCE(buf);
3169                 DHD_EVENT((" data (%d) : ", ntoh32(sub_event->datalen)));
3170                 for (i = 0; i < ntoh32(sub_event->datalen); i++) {
3171                     DHD_EVENT((" 0x%02x ", buf[i]));
3172                 }
3173                 data = aggrbuf->data + len;
3174             }
3175             DHD_EVENT(("\n"));
3176             break;
3177         }
3178         case WLC_E_NAN_CRITICAL: {
3179             DHD_LOG_MEM(("MACEVENT: %s, type:%d\n", event_name, reason));
3180             break;
3181         }
3182         case WLC_E_NAN_NON_CRITICAL: {
3183             DHD_TRACE(("MACEVENT: %s, type:%d\n", event_name, reason));
3184             break;
3185         }
3186         case WLC_E_PROXD: {
3187             wl_proxd_event_t *proxd = (wl_proxd_event_t *)event_data;
3188             DHD_LOG_MEM(("MACEVENT: %s, event:%d, status:%d\n", event_name,
3189                          proxd->type, reason));
3190             break;
3191         }
3192         case WLC_E_RPSNOA: {
3193             rpsnoa_stats_t *stat = event_data;
3194             if (datalen == sizeof(*stat)) {
3195                 DHD_EVENT(("MACEVENT: %s, band %s, status %d, pps %d\n",
3196                            event_name,
3197                            (stat->band == WLC_BAND_2G) ? "2G" : "5G",
3198                            stat->state, stat->last_pps));
3199             }
3200             break;
3201         }
3202         case WLC_E_PHY_CAL: {
3203             DHD_EVENT(("MACEVENT: %s, reason:%d\n", event_name, reason));
3204             break;
3205         }
3206         case WLC_E_WA_LQM: {
3207             wl_event_wa_lqm_t *event_wa_lqm = (wl_event_wa_lqm_t *)event_data;
3208             bcm_xtlv_t *subevent;
3209             wl_event_wa_lqm_basic_t *elqm_basic;
3210 
3211             if ((event_wa_lqm->ver != WL_EVENT_WA_LQM_VER) ||
3212                 (event_wa_lqm->len <
3213                  sizeof(wl_event_wa_lqm_t) + BCM_XTLV_HDR_SIZE)) {
3214                 DHD_ERROR(("MACEVENT: %s invalid (ver=%d len=%d)\n", event_name,
3215                            event_wa_lqm->ver, event_wa_lqm->len));
3216                 break;
3217             }
3218 
3219             subevent = (bcm_xtlv_t *)event_wa_lqm->subevent;
3220             if ((subevent->id != WL_EVENT_WA_LQM_BASIC) ||
3221                 (subevent->len < sizeof(wl_event_wa_lqm_basic_t))) {
3222                 DHD_ERROR(("MACEVENT: %s invalid sub-type (id=%d len=%d)\n",
3223                            event_name, subevent->id, subevent->len));
3224                 break;
3225             }
3226 
3227             elqm_basic = (wl_event_wa_lqm_basic_t *)subevent->data;
3228             BCM_REFERENCE(elqm_basic);
3229             DHD_EVENT(("MACEVENT: %s (RSSI=%d SNR=%d TxRate=%d RxRate=%d)\n",
3230                        event_name, elqm_basic->rssi, elqm_basic->snr,
3231                        elqm_basic->tx_rate, elqm_basic->rx_rate));
3232             break;
3233         }
3234         default:
3235             DHD_EVENT(
3236                 ("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n",
3237                  event_name, event_type, eabuf, (int)status, (int)reason,
3238                  (int)auth_type));
3239             break;
3240     }
3241 
3242     /* show any appended data if message level is set to bytes or host_data is
3243      * set */
3244     if ((DHD_BYTES_ON() || (host_data == TRUE)) && DHD_EVENT_ON() && datalen) {
3245         buf = (uchar *)event_data;
3246         BCM_REFERENCE(buf);
3247         DHD_EVENT((" data (%d) : ", datalen));
3248         for (i = 0; i < datalen; i++) {
3249             DHD_EVENT((" 0x%02x ", buf[i]));
3250         }
3251         DHD_EVENT(("\n"));
3252     }
3253 } /* wl_show_host_event */
3254 #endif /* SHOW_EVENTS */
3255 
3256 #ifdef DNGL_EVENT_SUPPORT
3257 /* Check whether packet is a BRCM dngl event pkt. If it is, process event data.
3258  */
dngl_host_event(dhd_pub_t * dhdp,void * pktdata,bcm_dngl_event_msg_t * dngl_event,size_t pktlen)3259 int dngl_host_event(dhd_pub_t *dhdp, void *pktdata,
3260                     bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
3261 {
3262     bcm_dngl_event_t *pvt_data = (bcm_dngl_event_t *)pktdata;
3263 
3264     dngl_host_event_process(dhdp, pvt_data, dngl_event, pktlen);
3265     return BCME_OK;
3266 }
3267 
3268 #ifdef PARSE_DONGLE_HOST_EVENT
3269 typedef struct hck_id_to_str_s {
3270     uint32 id;
3271     char *name;
3272 } hck_id_to_str_t;
3273 
3274 hck_id_to_str_t hck_sw_id_to_str[] = {
3275     {WL_HC_DD_PCIE, "WL_HC_DD_PCIE"},
3276     {WL_HC_DD_RX_DMA_STALL, "WL_HC_DD_RX_DMA_STALL"},
3277     {WL_HC_DD_RX_STALL, "WL_HC_DD_RX_STALL"},
3278     {WL_HC_DD_TX_STALL, "WL_HC_DD_TX_STALL"},
3279     {WL_HC_DD_SCAN_STALL, "WL_HC_DD_SCAN_STALL"},
3280     {WL_HC_DD_PHY, "WL_HC_DD_PHY"},
3281     {WL_HC_DD_REINIT, "WL_HC_DD_REINIT"},
3282     {WL_HC_DD_TXQ_STALL, "WL_HC_DD_TXQ_STALL"},
3283     {0, NULL}};
3284 
3285 hck_id_to_str_t hck_pcie_module_to_str[] = {
3286     {HEALTH_CHECK_PCIEDEV_INDUCED_IND, "PCIEDEV_INDUCED_IND"},
3287     {HEALTH_CHECK_PCIEDEV_H2D_DMA_IND, "PCIEDEV_H2D_DMA_IND"},
3288     {HEALTH_CHECK_PCIEDEV_D2H_DMA_IND, "PCIEDEV_D2H_DMA_IND"},
3289     {HEALTH_CHECK_PCIEDEV_IOCTL_STALL_IND, "PCIEDEV_IOCTL_STALL_IND"},
3290     {HEALTH_CHECK_PCIEDEV_D3ACK_STALL_IND, "PCIEDEV_D3ACK_STALL_IND"},
3291     {HEALTH_CHECK_PCIEDEV_NODS_IND, "PCIEDEV_NODS_IND"},
3292     {HEALTH_CHECK_PCIEDEV_LINKSPEED_FALLBACK_IND,
3293      "PCIEDEV_LINKSPEED_FALLBACK_IND"},
3294     {HEALTH_CHECK_PCIEDEV_DSACK_STALL_IND, "PCIEDEV_DSACK_STALL_IND"},
3295     {0, NULL}};
3296 
3297 hck_id_to_str_t hck_rx_stall_v2_to_str[] = {
3298     {BCM_RX_HC_RESERVED, "BCM_RX_HC_RESERVED"},
3299     {BCM_RX_HC_UNSPECIFIED, "BCM_RX_HC_UNSPECIFIED"},
3300     {BCM_RX_HC_UNICAST_DECRYPT_FAIL, "BCM_RX_HC_UNICAST_DECRYPT_FAIL"},
3301     {BCM_RX_HC_BCMC_DECRYPT_FAIL, "BCM_RX_HC_BCMC_DECRYPT_FAIL"},
3302     {BCM_RX_HC_UNICAST_REPLAY, "BCM_RX_HC_UNICAST_REPLAY"},
3303     {BCM_RX_HC_BCMC_REPLAY, "BCM_RX_HC_BCMC_REPLAY"},
3304     {BCM_RX_HC_AMPDU_DUP, "BCM_RX_HC_AMPDU_DUP"},
3305     {0, NULL}};
3306 
dhd_print_dongle_hck_id(uint32 id,hck_id_to_str_t * hck)3307 static void dhd_print_dongle_hck_id(uint32 id, hck_id_to_str_t *hck)
3308 {
3309     while (hck->name != NULL) {
3310         if (hck->id == id) {
3311             DHD_ERROR(("DONGLE_HCK_EVENT: %s\n", hck->name));
3312             return;
3313         }
3314         hck++;
3315     }
3316 }
3317 
dhd_parse_hck_common_sw_event(bcm_xtlv_t * wl_hc)3318 void dhd_parse_hck_common_sw_event(bcm_xtlv_t *wl_hc)
3319 {
3320     wl_rx_hc_info_v2_t *hck_rx_stall_v2;
3321     uint16 id;
3322 
3323     id = ltoh16(wl_hc->id);
3324     if (id == WL_HC_DD_RX_STALL_V2) {
3325         /*  map the hck_rx_stall_v2 structure to the value of the XTLV */
3326         hck_rx_stall_v2 = (wl_rx_hc_info_v2_t *)wl_hc;
3327         DHD_ERROR(("type:%d len:%d if_idx:%d ac:%d pkts:%d"
3328                    " drop:%d alert_th:%d reason:%d peer_ea:" MACF "\n",
3329                    hck_rx_stall_v2->type, hck_rx_stall_v2->length,
3330                    hck_rx_stall_v2->if_idx, hck_rx_stall_v2->ac,
3331                    hck_rx_stall_v2->rx_hc_pkts,
3332                    hck_rx_stall_v2->rx_hc_dropped_all,
3333                    hck_rx_stall_v2->rx_hc_alert_th, hck_rx_stall_v2->reason,
3334                    ETHER_TO_MACF(hck_rx_stall_v2->peer_ea)));
3335         dhd_print_dongle_hck_id(ltoh32(hck_rx_stall_v2->reason),
3336                                 hck_rx_stall_v2_to_str);
3337     } else {
3338         dhd_print_dongle_hck_id(ltoh16(wl_hc->id), hck_sw_id_to_str);
3339     }
3340 }
3341 
3342 #endif /* PARSE_DONGLE_HOST_EVENT */
3343 
dngl_host_event_process(dhd_pub_t * dhdp,bcm_dngl_event_t * event,bcm_dngl_event_msg_t * dngl_event,size_t pktlen)3344 void dngl_host_event_process(dhd_pub_t *dhdp, bcm_dngl_event_t *event,
3345                              bcm_dngl_event_msg_t *dngl_event, size_t pktlen)
3346 {
3347     uint8 *p = (uint8 *)(event + 1);
3348     uint16 type = ntoh16_ua((void *)&dngl_event->event_type);
3349     uint16 datalen = ntoh16_ua((void *)&dngl_event->datalen);
3350     uint16 version = ntoh16_ua((void *)&dngl_event->version);
3351 
3352     DHD_EVENT(
3353         ("VERSION:%d, EVENT TYPE:%d, DATALEN:%d\n", version, type, datalen));
3354     if (datalen > (pktlen - sizeof(bcm_dngl_event_t) + ETHER_TYPE_LEN)) {
3355         return;
3356     }
3357     if (version != BCM_DNGL_EVENT_MSG_VERSION) {
3358         DHD_ERROR(("%s:version mismatch:%d:%d\n", __FUNCTION__, version,
3359                    BCM_DNGL_EVENT_MSG_VERSION));
3360         return;
3361     }
3362     switch (type) {
3363         case DNGL_E_SOCRAM_IND: {
3364             bcm_dngl_socramind_t *socramind_ptr = (bcm_dngl_socramind_t *)p;
3365             uint16 tag = ltoh32(socramind_ptr->tag);
3366             uint16 taglen = ltoh32(socramind_ptr->length);
3367             p = (uint8 *)socramind_ptr->value;
3368             DHD_EVENT(("Tag:%d Len:%d Datalen:%d\n", tag, taglen, datalen));
3369             switch (tag) {
3370                 case SOCRAM_IND_ASSERT_TAG: {
3371                     /*
3372                      * The payload consists of -
3373                      * null terminated function name padded till 32 bit boundary
3374                      * + Line number - (32 bits) Caller address (32 bits)
3375                      */
3376                     char *fnname = (char *)p;
3377                     if (datalen < (ROUNDUP(strlen(fnname) + 1, sizeof(uint32)) +
3378                                    sizeof(uint32) * 0x2)) {
3379                         DHD_ERROR(("Wrong length:%d\n", datalen));
3380                         return;
3381                     }
3382                     DHD_EVENT(("ASSRT Function:%s ", p));
3383                     p += ROUNDUP(strlen(p) + 1, sizeof(uint32));
3384                     DHD_EVENT(("Line:%d ", *(uint32 *)p));
3385                     p += sizeof(uint32);
3386                     DHD_EVENT(("Caller Addr:0x%x\n", *(uint32 *)p));
3387 #ifdef PARSE_DONGLE_HOST_EVENT
3388                     DHD_ERROR(("DONGLE_HCK_EVENT: SOCRAM_IND_ASSERT_TAG\n"));
3389 #endif /* PARSE_DONGLE_HOST_EVENT */
3390                     break;
3391                 }
3392                 case SOCRAM_IND_TAG_HEALTH_CHECK: {
3393                     bcm_dngl_healthcheck_t *dngl_hc =
3394                         (bcm_dngl_healthcheck_t *)p;
3395                     DHD_EVENT(
3396                         ("SOCRAM_IND_HEALTHCHECK_TAG:%d Len:%d datalen:%d\n",
3397                          ltoh32(dngl_hc->top_module_tag),
3398                          ltoh32(dngl_hc->top_module_len), datalen));
3399                     if (DHD_EVENT_ON()) {
3400                         prhex("HEALTHCHECK", p,
3401                               MIN(ltoh32(dngl_hc->top_module_len) +
3402                                       BCM_XTLV_HDR_SIZE,
3403                                   datalen));
3404                     }
3405 #ifdef DHD_LOG_DUMP
3406                     memset(dhdp->health_chk_event_data, 0, HEALTH_CHK_BUF_SIZE);
3407                     memcpy(dhdp->health_chk_event_data, p,
3408                            MIN(ltoh32(dngl_hc->top_module_len),
3409                                HEALTH_CHK_BUF_SIZE));
3410 #endif /* DHD_LOG_DUMP */
3411                     p = (uint8 *)dngl_hc->value;
3412 
3413                     switch (ltoh32(dngl_hc->top_module_tag)) {
3414                         case HEALTH_CHECK_TOP_LEVEL_MODULE_PCIEDEV_RTE: {
3415                             bcm_dngl_pcie_hc_t *pcie_hc;
3416                             pcie_hc = (bcm_dngl_pcie_hc_t *)p;
3417                             BCM_REFERENCE(pcie_hc);
3418                             if (ltoh32(dngl_hc->top_module_len) <
3419                                 sizeof(bcm_dngl_pcie_hc_t)) {
3420                                 DHD_ERROR(("Wrong length:%d\n",
3421                                            ltoh32(dngl_hc->top_module_len)));
3422                                 return;
3423                             }
3424                             DHD_EVENT(("%d:PCIE HC error:%d flag:0x%x,"
3425                                        " control:0x%x\n",
3426                                        ltoh32(pcie_hc->version),
3427                                        ltoh32(pcie_hc->pcie_err_ind_type),
3428                                        ltoh32(pcie_hc->pcie_flag),
3429                                        ltoh32(pcie_hc->pcie_control_reg)));
3430 #ifdef PARSE_DONGLE_HOST_EVENT
3431                             dhd_print_dongle_hck_id(
3432                                 ltoh32(pcie_hc->pcie_err_ind_type),
3433                                 hck_pcie_module_to_str);
3434 #endif /* PARSE_DONGLE_HOST_EVENT */
3435                             break;
3436                         }
3437 #ifdef HCHK_COMMON_SW_EVENT
3438                         case HCHK_SW_ENTITY_WL_PRIMARY:
3439                         case HCHK_SW_ENTITY_WL_SECONDARY: {
3440                             bcm_xtlv_t *wl_hc = (bcm_xtlv_t *)p;
3441 
3442                             if (ltoh32(dngl_hc->top_module_len) <
3443                                 sizeof(bcm_xtlv_t)) {
3444                                 DHD_ERROR(("WL SW HC Wrong length:%d\n",
3445                                            ltoh32(dngl_hc->top_module_len)));
3446                                 return;
3447                             }
3448                             BCM_REFERENCE(wl_hc);
3449                             DHD_EVENT(("WL SW HC type %d len %d\n",
3450                                        ltoh16(wl_hc->id), ltoh16(wl_hc->len)));
3451 
3452 #ifdef PARSE_DONGLE_HOST_EVENT
3453                             dhd_parse_hck_common_sw_event(wl_hc);
3454 #endif /* PARSE_DONGLE_HOST_EVENT */
3455                             break;
3456                         }
3457 #endif /* HCHK_COMMON_SW_EVENT */
3458                         default: {
3459                             DHD_ERROR(("%s:Unknown module TAG:%d\n",
3460                                        __FUNCTION__,
3461                                        ltoh32(dngl_hc->top_module_tag)));
3462                             break;
3463                         }
3464                     }
3465                     break;
3466                 }
3467                 default:
3468                     DHD_ERROR(("%s:Unknown TAG\n", __FUNCTION__));
3469                     if (p && DHD_EVENT_ON()) {
3470                         prhex("SOCRAMIND", p, taglen);
3471                     }
3472                     break;
3473             }
3474             break;
3475         }
3476         default:
3477             DHD_ERROR(("%s:Unknown DNGL Event Type:%d\n", __FUNCTION__, type));
3478             if (p && DHD_EVENT_ON()) {
3479                 prhex("SOCRAMIND", p, datalen);
3480             }
3481             break;
3482     }
3483 #ifndef BCMDBUS
3484 #ifdef DHD_FW_COREDUMP
3485     if (dhdp->memdump_enabled) {
3486         dhdp->memdump_type = DUMP_TYPE_DONGLE_HOST_EVENT;
3487         if (dhd_socram_dump(dhdp->bus)) {
3488             DHD_ERROR(("%s: socram dump failed\n", __FUNCTION__));
3489         }
3490     }
3491 #else
3492     dhd_dbg_send_urgent_evt(dhdp, p, datalen);
3493 #endif /* DHD_FW_COREDUMP */
3494 #endif /* !BCMDBUS */
3495 }
3496 
3497 #endif /* DNGL_EVENT_SUPPORT */
3498 
3499 /* Stub for now. Will become real function as soon as shim
3500  * is being integrated to Android, Linux etc.
3501  */
wl_event_process_default(wl_event_msg_t * event,struct wl_evt_pport * evt_pport)3502 int wl_event_process_default(wl_event_msg_t *event,
3503                              struct wl_evt_pport *evt_pport)
3504 {
3505     return BCME_OK;
3506 }
3507 
wl_event_process(dhd_pub_t * dhd_pub,int * ifidx,void * pktdata,uint pktlen,void ** data_ptr,void * raw_event)3508 int wl_event_process(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen,
3509                      void **data_ptr, void *raw_event)
3510 {
3511     wl_evt_pport_t evt_pport;
3512     wl_event_msg_t event;
3513     bcm_event_msg_u_t evu;
3514     int ret;
3515 
3516     /* make sure it is a BRCM event pkt and record event data */
3517     ret = wl_host_event_get_data(pktdata, pktlen, &evu);
3518     if (ret != BCME_OK) {
3519         return ret;
3520     }
3521 
3522     memcpy(&event, &evu.event, sizeof(wl_event_msg_t));
3523 
3524     /* convert event from network order to host order */
3525     wl_event_to_host_order(&event);
3526 
3527     /* record event params to evt_pport */
3528     evt_pport.dhd_pub = dhd_pub;
3529     evt_pport.ifidx = ifidx;
3530     evt_pport.pktdata = pktdata;
3531     evt_pport.data_ptr = data_ptr;
3532     evt_pport.raw_event = raw_event;
3533     evt_pport.data_len = pktlen;
3534 
3535     ret = wl_event_process_default(&event, &evt_pport);
3536 
3537     return ret;
3538 } /* wl_event_process */
3539 
3540 /* Check whether packet is a BRCM event pkt. If it is, record event data. */
wl_host_event_get_data(void * pktdata,uint pktlen,bcm_event_msg_u_t * evu)3541 int wl_host_event_get_data(void *pktdata, uint pktlen, bcm_event_msg_u_t *evu)
3542 {
3543     int ret;
3544 
3545     ret = is_wlc_event_frame(pktdata, pktlen, 0, evu);
3546     if (ret != BCME_OK) {
3547         DHD_ERROR(("%s: Invalid event frame, err = %d\n", __FUNCTION__, ret));
3548     }
3549 
3550     return ret;
3551 }
3552 
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)3553 int wl_process_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata,
3554                           uint pktlen, wl_event_msg_t *event, void **data_ptr,
3555                           void *raw_event)
3556 {
3557     bcm_event_t *pvt_data = (bcm_event_t *)pktdata;
3558     bcm_event_msg_u_t evu;
3559     uint8 *event_data;
3560     uint32 type, status, datalen, reason;
3561     uint16 flags;
3562     uint evlen;
3563     int ret;
3564     uint16 usr_subtype;
3565 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
3566     dhd_if_t *ifp = NULL;
3567 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
3568 
3569     ret = wl_host_event_get_data(pktdata, pktlen, &evu);
3570     if (ret != BCME_OK) {
3571         return ret;
3572     }
3573 
3574     usr_subtype = ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype);
3575     switch (usr_subtype) {
3576         case BCMILCP_BCM_SUBTYPE_EVENT:
3577             memcpy(event, &evu.event, sizeof(wl_event_msg_t));
3578             *data_ptr = &pvt_data[1];
3579             break;
3580         case BCMILCP_BCM_SUBTYPE_DNGLEVENT:
3581 #ifdef DNGL_EVENT_SUPPORT
3582             /* If it is a DNGL event process it first */
3583             if (dngl_host_event(dhd_pub, pktdata, &evu.dngl_event, pktlen) ==
3584                 BCME_OK) {
3585                 /*
3586                  * Return error purposely to prevent DNGL event being processed
3587                  * as BRCM event
3588                  */
3589                 return BCME_ERROR;
3590             }
3591 #endif /* DNGL_EVENT_SUPPORT */
3592             return BCME_NOTFOUND;
3593         default:
3594             return BCME_NOTFOUND;
3595     }
3596 
3597     /* start wl_event_msg process */
3598     event_data = *data_ptr;
3599     type = ntoh32_ua((void *)&event->event_type);
3600     flags = ntoh16_ua((void *)&event->flags);
3601     status = ntoh32_ua((void *)&event->status);
3602     reason = ntoh32_ua((void *)&event->reason);
3603     datalen = ntoh32_ua((void *)&event->datalen);
3604     evlen = datalen + sizeof(bcm_event_t);
3605 
3606     switch (type) {
3607 #ifdef PROP_TXSTATUS
3608         case WLC_E_FIFO_CREDIT_MAP:
3609             dhd_wlfc_enable(dhd_pub);
3610             dhd_wlfc_FIFOcreditmap_event(dhd_pub, event_data);
3611             WLFC_DBGMESG(
3612                 ("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): "
3613                  "(%d,%d,%d,%d),(%d),(%d)\n",
3614                  event_data[0], event_data[1], event_data[0x2], event_data[0x3],
3615                  event_data[0x4], event_data[0x5]));
3616             break;
3617 
3618         case WLC_E_BCMC_CREDIT_SUPPORT:
3619             dhd_wlfc_BCMCCredit_support_event(dhd_pub);
3620             break;
3621 #ifdef LIMIT_BORROW
3622         case WLC_E_ALLOW_CREDIT_BORROW:
3623             dhd_wlfc_disable_credit_borrow_event(dhd_pub, event_data);
3624             break;
3625 #endif /* LIMIT_BORROW */
3626 #endif /* PROP_TXSTATUS */
3627 
3628         case WLC_E_ULP:
3629 #ifdef DHD_ULP
3630         {
3631             wl_ulp_event_t *ulp_evt = (wl_ulp_event_t *)event_data;
3632 
3633             /* Flush and disable console messages */
3634             if (ulp_evt->ulp_dongle_action == WL_ULP_DISABLE_CONSOLE) {
3635 #ifdef DHD_ULP_NOT_USED
3636                 dhd_bus_ulp_disable_console(dhd_pub);
3637 #endif /* DHD_ULP_NOT_USED */
3638             }
3639             if (ulp_evt->ulp_dongle_action == WL_ULP_UCODE_DOWNLOAD) {
3640                 dhd_bus_ucode_download(dhd_pub->bus);
3641             }
3642         }
3643 #endif /* DHD_ULP */
3644         break;
3645         case WLC_E_TDLS_PEER_EVENT:
3646 #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
3647         {
3648             dhd_tdls_event_handler(dhd_pub, event);
3649         }
3650 #endif // endif
3651         break;
3652 
3653         case WLC_E_IF: {
3654             struct wl_event_data_if *ifevent =
3655                 (struct wl_event_data_if *)event_data;
3656 
3657             /* Ignore the event if NOIF is set */
3658             if (ifevent->reserved & WLC_E_IF_FLAGS_BSSCFG_NOIF) {
3659                 DHD_ERROR(("WLC_E_IF: NO_IF set, event Ignored\r\n"));
3660                 return (BCME_UNSUPPORTED);
3661             }
3662 #ifdef PCIE_FULL_DONGLE
3663             dhd_update_interface_flow_info(dhd_pub, ifevent->ifidx,
3664                                            ifevent->opcode, ifevent->role);
3665 #endif // endif
3666 #ifdef PROP_TXSTATUS
3667             {
3668                 uint8 *ea = pvt_data->eth.ether_dhost;
3669                 WLFC_DBGMESG(
3670                     ("WLC_E_IF: idx:%d, action:%s, iftype:%s, [" MACDBG
3671                      "]\n" ifevent->ifidx,
3672                      ((ifevent->opcode == WLC_E_IF_ADD) ? "ADD" : "DEL"),
3673                      ((ifevent->role == 0) ? "STA" : "AP "), MAC2STRDBG(ea)));
3674                 (void)ea;
3675 
3676                 if (ifevent->opcode == WLC_E_IF_CHANGE) {
3677                     dhd_wlfc_interface_event(dhd_pub,
3678                                              eWLFC_MAC_ENTRY_ACTION_UPDATE,
3679                                              ifevent->ifidx, ifevent->role, ea);
3680                 } else {
3681                     dhd_wlfc_interface_event(dhd_pub,
3682                                              ((ifevent->opcode == WLC_E_IF_ADD)
3683                                                   ? eWLFC_MAC_ENTRY_ACTION_ADD
3684                                                   : eWLFC_MAC_ENTRY_ACTION_DEL),
3685                                              ifevent->ifidx, ifevent->role, ea);
3686                 }
3687 
3688                 /* dhd already has created an interface by default, for 0 */
3689                 if (ifevent->ifidx == 0) {
3690                     break;
3691                 }
3692             }
3693 #endif /* PROP_TXSTATUS */
3694 
3695             if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) {
3696                 if (ifevent->opcode == WLC_E_IF_ADD) {
3697                     if (dhd_event_ifadd(dhd_pub->info, ifevent, event->ifname,
3698                                         event->addr.octet)) {
3699                         DHD_ERROR(("%s: dhd_event_ifadd failed ifidx: %d  %s\n",
3700                                    __FUNCTION__, ifevent->ifidx,
3701                                    event->ifname));
3702                         return (BCME_ERROR);
3703                     }
3704                 } else if (ifevent->opcode == WLC_E_IF_DEL) {
3705 #ifdef PCIE_FULL_DONGLE
3706                     /* Delete flowrings unconditionally for i/f delete */
3707                     dhd_flow_rings_delete(
3708                         dhd_pub,
3709                         (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname));
3710 #endif /* PCIE_FULL_DONGLE */
3711                     dhd_event_ifdel(dhd_pub->info, ifevent, event->ifname,
3712                                     event->addr.octet);
3713                 } else if (ifevent->opcode == WLC_E_IF_CHANGE) {
3714 #ifdef WL_CFG80211
3715                     dhd_event_ifchange(dhd_pub->info, ifevent, event->ifname,
3716                                        event->addr.octet);
3717 #endif /* WL_CFG80211 */
3718                 }
3719             } else {
3720 #if !defined(PROP_TXSTATUS) && !defined(PCIE_FULL_DONGLE) &&                   \
3721     defined(WL_CFG80211)
3722                 DHD_INFO(("%s: Invalid ifidx %d for %s\n", __FUNCTION__,
3723                           ifevent->ifidx, event->ifname));
3724 #endif /* !PROP_TXSTATUS && !PCIE_FULL_DONGLE && WL_CFG80211 */
3725             }
3726             /* send up the if event: btamp user needs it */
3727             *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
3728             /* push up to external supp/auth */
3729             dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
3730             break;
3731         }
3732 
3733         case WLC_E_NDIS_LINK:
3734             break;
3735         case WLC_E_PFN_NET_FOUND:
3736         case WLC_E_PFN_SCAN_ALLGONE: /* share with WLC_E_PFN_BSSID_NET_LOST */
3737         case WLC_E_PFN_NET_LOST:
3738             break;
3739 #if defined(PNO_SUPPORT)
3740         case WLC_E_PFN_BSSID_NET_FOUND:
3741         case WLC_E_PFN_BEST_BATCHING:
3742             dhd_pno_event_handler(dhd_pub, event, (void *)event_data);
3743             break;
3744 #endif // endif
3745 #if defined(RTT_SUPPORT)
3746         case WLC_E_PROXD:
3747 #ifndef WL_CFG80211
3748             dhd_rtt_event_handler(dhd_pub, event, (void *)event_data);
3749 #endif /* WL_CFG80211 */
3750             break;
3751 #endif      /* RTT_SUPPORT */
3752             /* These are what external supplicant/authenticator wants */
3753         case WLC_E_ASSOC_IND:
3754         case WLC_E_AUTH_IND:
3755         case WLC_E_REASSOC_IND:
3756             dhd_findadd_sta(dhd_pub,
3757                             dhd_ifname2idx(dhd_pub->info, event->ifname),
3758                             &event->addr.octet);
3759             break;
3760 #ifndef BCMDBUS
3761 #if defined(DHD_FW_COREDUMP)
3762         case WLC_E_PSM_WATCHDOG:
3763             DHD_ERROR(
3764                 ("%s: WLC_E_PSM_WATCHDOG event received : \n", __FUNCTION__));
3765             if (dhd_socram_dump(dhd_pub->bus) != BCME_OK) {
3766                 DHD_ERROR(("%s: socram dump ERROR : \n", __FUNCTION__));
3767             }
3768             break;
3769 #endif // endif
3770 #endif /* !BCMDBUS */
3771         case WLC_E_NATOE_NFCT:
3772 #ifdef WL_NATOE
3773             DHD_EVENT(("%s: WLC_E_NATOE_NFCT event received \n", __FUNCTION__));
3774             dhd_natoe_ct_event(dhd_pub, event_data);
3775 #endif /* WL_NATOE */
3776             break;
3777 #ifdef WL_NAN
3778         case WLC_E_SLOTTED_BSS_PEER_OP:
3779             DHD_EVENT(("%s: WLC_E_SLOTTED_BSS_PEER_OP event received for peer: "
3780                        "" MACDBG ", status = %d\n",
3781                        __FUNCTION__, MAC2STRDBG(event->addr.octet), status));
3782             if (status == WLC_E_STATUS_SLOTTED_PEER_ADD) {
3783                 dhd_findadd_sta(dhd_pub,
3784                                 dhd_ifname2idx(dhd_pub->info, event->ifname),
3785                                 &event->addr.octet);
3786             } else if (status == WLC_E_STATUS_SLOTTED_PEER_DEL) {
3787                 uint8 ifindex =
3788                     (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname);
3789                 BCM_REFERENCE(ifindex);
3790                 dhd_del_sta(dhd_pub,
3791                             dhd_ifname2idx(dhd_pub->info, event->ifname),
3792                             &event->addr.octet);
3793 #ifdef PCIE_FULL_DONGLE
3794                 dhd_flow_rings_delete_for_peer(dhd_pub, ifindex,
3795                                                (char *)&event->addr.octet[0]);
3796 #endif // endif
3797             } else {
3798                 DHD_ERROR(("%s: WLC_E_SLOTTED_BSS_PEER_OP: Status is not "
3799                            "expected = %d\n",
3800                            __FUNCTION__, status));
3801             }
3802             break;
3803 #endif /* WL_NAN */
3804 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
3805         case WLC_E_REASSOC:
3806             ifp = dhd_get_ifp(dhd_pub, event->ifidx);
3807             if (!ifp) {
3808                 break;
3809             }
3810 
3811             /* Consider STA role only since roam is disabled on P2P GC.
3812              * Drop EAPOL M1 frame only if roam is done to same BSS.
3813              */
3814             if ((status == WLC_E_STATUS_SUCCESS) &&
3815                 IS_STA_IFACE(ndev_to_wdev(ifp->net)) &&
3816                 wl_cfg80211_is_event_from_connected_bssid(ifp->net, event,
3817                                                           event->ifidx)) {
3818                 ifp->recv_reassoc_evt = TRUE;
3819             }
3820             break;
3821 #endif /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
3822 #if defined(CSI_SUPPORT)
3823         case WLC_E_CSI:
3824             dhd_csi_event_handler(dhd_pub, event, (void *)event_data);
3825             break;
3826 #endif /* CSI_SUPPORT */
3827         case WLC_E_LINK:
3828 #ifdef PCIE_FULL_DONGLE
3829             if (dhd_update_interface_link_status(
3830                     dhd_pub,
3831                     (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname),
3832                     (uint8)flags) != BCME_OK) {
3833                 DHD_ERROR(("%s: dhd_update_interface_link_status Failed.\n",
3834                            __FUNCTION__));
3835                 break;
3836             }
3837             if (!flags) {
3838                 DHD_ERROR(
3839                     ("%s: Deleting all STA from assoc list and flowrings.\n",
3840                      __FUNCTION__));
3841                 /* Delete all sta and flowrings */
3842                 dhd_del_all_sta(dhd_pub,
3843                                 dhd_ifname2idx(dhd_pub->info, event->ifname));
3844                 dhd_flow_rings_delete(
3845                     dhd_pub,
3846                     (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname));
3847             }
3848             /* fall through */
3849 #endif /* PCIE_FULL_DONGLE */
3850         case WLC_E_DEAUTH:
3851         case WLC_E_DEAUTH_IND:
3852         case WLC_E_DISASSOC:
3853         case WLC_E_DISASSOC_IND:
3854 #ifdef PCIE_FULL_DONGLE
3855             if (type != WLC_E_LINK) {
3856                 uint8 ifindex =
3857                     (uint8)dhd_ifname2idx(dhd_pub->info, event->ifname);
3858                 uint8 role = dhd_flow_rings_ifindex2role(dhd_pub, ifindex);
3859                 uint8 del_sta = TRUE;
3860 #ifdef WL_CFG80211
3861                 if (role == WLC_E_IF_ROLE_STA &&
3862                     !wl_cfg80211_is_roam_offload(
3863                         dhd_idx2net(dhd_pub, ifindex)) &&
3864                     !wl_cfg80211_is_event_from_connected_bssid(
3865                         dhd_idx2net(dhd_pub, ifindex), event, *ifidx)) {
3866                     del_sta = FALSE;
3867                 }
3868 #endif /* WL_CFG80211 */
3869                 DHD_EVENT(("%s: Link event %d, flags %x, status %x, role %d, "
3870                            "del_sta %d\n",
3871                            __FUNCTION__, type, flags, status, role, del_sta));
3872 
3873                 if (del_sta) {
3874                     DHD_EVENT(("%s: Deleting STA " MACDBG "\n", __FUNCTION__,
3875                                MAC2STRDBG(event->addr.octet)));
3876 
3877                     dhd_del_sta(dhd_pub,
3878                                 dhd_ifname2idx(dhd_pub->info, event->ifname),
3879                                 &event->addr.octet);
3880                     /* Delete all flowrings for STA and P2P Client */
3881                     if (role == WLC_E_IF_ROLE_STA ||
3882                         role == WLC_E_IF_ROLE_P2P_CLIENT) {
3883                         dhd_flow_rings_delete(dhd_pub, ifindex);
3884                     } else {
3885                         dhd_flow_rings_delete_for_peer(
3886                             dhd_pub, ifindex, (char *)&event->addr.octet[0]);
3887                     }
3888                 }
3889             }
3890 #endif /* PCIE_FULL_DONGLE */
3891 #ifdef DHD_POST_EAPOL_M1_AFTER_ROAM_EVT
3892             /* fall through */
3893             ifp = dhd_get_ifp(dhd_pub, event->ifidx);
3894             if (ifp) {
3895                 ifp->recv_reassoc_evt = FALSE;
3896                 ifp->post_roam_evt = FALSE;
3897             }
3898 #endif      /* DHD_POST_EAPOL_M1_AFTER_ROAM_EVT */
3899             /* fall through */
3900         default:
3901             *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname);
3902 #ifdef DHD_UPDATE_INTF_MAC
3903             if ((WLC_E_LINK == type) && (WLC_EVENT_MSG_LINK & flags)) {
3904                 dhd_event_ifchange(dhd_pub->info,
3905                                    (struct wl_event_data_if *)event,
3906                                    event->ifname, event->addr.octet);
3907             }
3908 #endif /* DHD_UPDATE_INTF_MAC */
3909             /* push up to external supp/auth */
3910             dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx);
3911             DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", __FUNCTION__,
3912                        type, flags, status));
3913             BCM_REFERENCE(flags);
3914             BCM_REFERENCE(status);
3915             BCM_REFERENCE(reason);
3916 
3917             break;
3918     }
3919 #if defined(STBAP)
3920     /* For routers, EAPD will be working on these events.
3921      * Overwrite interface name to that event is pushed
3922      * to host with its registered interface name
3923      */
3924     memcpy(pvt_data->event.ifname, dhd_ifname(dhd_pub, *ifidx), IFNAMSIZ);
3925 #endif // endif
3926 
3927 #ifdef DHD_STATUS_LOGGING
3928     if (dhd_pub->statlog) {
3929         dhd_statlog_process_event(dhd_pub, type, *ifidx, status, reason, flags);
3930     }
3931 #endif /* DHD_STATUS_LOGGING */
3932 
3933 #ifdef SHOW_EVENTS
3934     if (DHD_FWLOG_ON() || DHD_EVENT_ON()) {
3935         wl_show_host_event(dhd_pub, event, (void *)event_data, raw_event,
3936                            dhd_pub->enable_log);
3937     }
3938 #endif /* SHOW_EVENTS */
3939 
3940     return (BCME_OK);
3941 } /* wl_process_host_event */
3942 
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)3943 int wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, uint pktlen,
3944                   wl_event_msg_t *event, void **data_ptr, void *raw_event)
3945 {
3946     return wl_process_host_event(dhd_pub, ifidx, pktdata, pktlen, event,
3947                                  data_ptr, raw_event);
3948 }
3949 
dhd_print_buf(void * pbuf,int len,int bytes_per_line)3950 void dhd_print_buf(void *pbuf, int len, int bytes_per_line)
3951 {
3952 #ifdef DHD_DEBUG
3953     int i, j = 0;
3954     unsigned char *buf = pbuf;
3955 
3956     if (bytes_per_line == 0) {
3957         bytes_per_line = len;
3958     }
3959 
3960     for (i = 0; i < len; i++) {
3961         printf("%2.2x", *buf++);
3962         j++;
3963         if (j == bytes_per_line) {
3964             printf("\n");
3965             j = 0;
3966         } else {
3967             printf(":");
3968         }
3969     }
3970     printf("\n");
3971 #endif /* DHD_DEBUG */
3972 }
3973 #ifndef strtoul
3974 #define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base))
3975 #endif // endif
3976 
3977 /* Convert user's input in hex pattern to byte-size mask */
wl_pattern_atoh(char * src,char * dst)3978 int wl_pattern_atoh(char *src, char *dst)
3979 {
3980     int i;
3981     if (strncmp(src, "0x", 0x2) != 0 && strncmp(src, "0X", 0x2) != 0) {
3982         DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
3983         return -1;
3984     }
3985     src = src + 0x2; /* Skip past 0x */
3986     if (strlen(src) % 0x2 != 0) {
3987         DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
3988         return -1;
3989     }
3990     for (i = 0; *src != '\0'; i++) {
3991         char num[0x3];
3992         bcm_strncpy_s(num, sizeof(num), src, 0x2);
3993         num[0x2] = '\0';
3994         dst[i] = (uint8)strtoul(num, NULL, 0x10);
3995         src += 0x2;
3996     }
3997     return i;
3998 }
3999 
4000 #if defined(PKT_FILTER_SUPPORT)
pattern_atoh_len(char * src,char * dst,int len)4001 int pattern_atoh_len(char *src, char *dst, int len)
4002 {
4003     int i;
4004     if (strncmp(src, "0x", HD_PREFIX_SIZE) != 0 &&
4005         strncmp(src, "0X", HD_PREFIX_SIZE) != 0) {
4006         DHD_ERROR(("Mask invalid format. Needs to start with 0x\n"));
4007         return -1;
4008     }
4009     src = src + HD_PREFIX_SIZE; /* Skip past 0x */
4010     if (strlen(src) % HD_BYTE_SIZE != 0) {
4011         DHD_ERROR(("Mask invalid format. Needs to be of even length\n"));
4012         return -1;
4013     }
4014     for (i = 0; *src != '\0'; i++) {
4015         char num[HD_BYTE_SIZE + 1];
4016 
4017         if (i > len - 1) {
4018             DHD_ERROR(("pattern not in range, idx: %d len: %d\n", i, len));
4019             return -1;
4020         }
4021         bcm_strncpy_s(num, sizeof(num), src, HD_BYTE_SIZE);
4022         num[HD_BYTE_SIZE] = '\0';
4023         dst[i] = (uint8)strtoul(num, NULL, 16);
4024         src += HD_BYTE_SIZE;
4025     }
4026     return i;
4027 }
4028 #endif // endif
4029 
4030 #ifdef PKT_FILTER_SUPPORT
dhd_pktfilter_offload_enable(dhd_pub_t * dhd,char * arg,int enable,int master_mode)4031 void dhd_pktfilter_offload_enable(dhd_pub_t *dhd, char *arg, int enable,
4032                                   int master_mode)
4033 {
4034     char *argv[8];
4035     int i = 0;
4036     const char *str;
4037     int buf_len;
4038     int str_len;
4039     char *arg_save = 0, *arg_org = 0;
4040     int rc;
4041     char buf[32] = {0};
4042     wl_pkt_filter_enable_t enable_parm;
4043     wl_pkt_filter_enable_t *pkt_filterp;
4044 
4045     if (!arg) {
4046         return;
4047     }
4048 
4049     if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
4050         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
4051         goto fail;
4052     }
4053     arg_org = arg_save;
4054     memcpy(arg_save, arg, strlen(arg) + 1);
4055 
4056     argv[i] = bcmstrtok(&arg_save, " ", 0);
4057 
4058     i = 0;
4059     if (argv[i] == NULL) {
4060         DHD_ERROR(("No args provided\n"));
4061         goto fail;
4062     }
4063 
4064     str = "pkt_filter_enable";
4065     str_len = strlen(str);
4066     bcm_strncpy_s(buf, sizeof(buf) - 1, str, sizeof(buf) - 1);
4067     buf[sizeof(buf) - 1] = '\0';
4068     buf_len = str_len + 1;
4069 
4070     pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1);
4071 
4072     /* Parse packet filter id. */
4073     enable_parm.id = htod32(strtoul(argv[i], NULL, 0));
4074     if (dhd_conf_del_pkt_filter(dhd, enable_parm.id)) {
4075         goto fail;
4076     }
4077 
4078     /* Parse enable/disable value. */
4079     enable_parm.enable = htod32(enable);
4080 
4081     buf_len += sizeof(enable_parm);
4082     memcpy((char *)pkt_filterp, &enable_parm, sizeof(enable_parm));
4083 
4084     /* Enable/disable the specified filter. */
4085     rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
4086     rc = rc >= 0 ? 0 : rc;
4087     if (rc) {
4088         DHD_ERROR(("%s: failed to %s pktfilter %s, retcode = %d\n",
4089                    __FUNCTION__, enable ? "enable" : "disable", arg, rc));
4090         dhd_set_packet_filter(dhd);
4091         rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
4092         rc = rc >= 0 ? 0 : rc;
4093         if (rc) {
4094             DHD_TRACE_HW4(
4095                 ("%s: 2nd retry failed to add pktfilter %s, retcode = %d\n",
4096                  __FUNCTION__, arg, rc));
4097         } else {
4098             DHD_TRACE_HW4(("%s: 2nd retry successfully added pktfilter %s\n",
4099                            __FUNCTION__, arg));
4100         }
4101     } else {
4102         DHD_TRACE(("%s: successfully %s pktfilter %s\n", __FUNCTION__,
4103                    enable ? "enable" : "disable", arg));
4104     }
4105 
4106     /* Contorl the master mode */
4107     rc = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_mode", master_mode,
4108                                    WLC_SET_VAR, TRUE, 0);
4109     rc = rc >= 0 ? 0 : rc;
4110     if (rc) {
4111         DHD_TRACE(("%s: failed to set pkt_filter_mode %d, retcode = %d\n",
4112                    __FUNCTION__, master_mode, rc));
4113     }
4114 
4115 fail:
4116     if (arg_org) {
4117         MFREE(dhd->osh, arg_org, strlen(arg) + 1);
4118     }
4119 }
4120 
4121 /* Packet filter section: extended filters have named offsets, add table here */
4122 typedef struct {
4123     char *name;
4124     uint16 base;
4125 } wl_pfbase_t;
4126 
4127 static wl_pfbase_t basenames[] = {WL_PKT_FILTER_BASE_NAMES};
4128 
wl_pkt_filter_base_parse(char * name)4129 static int wl_pkt_filter_base_parse(char *name)
4130 {
4131     uint i;
4132     char *bname, *uname;
4133 
4134     for (i = 0; i < ARRAYSIZE(basenames); i++) {
4135         bname = basenames[i].name;
4136         for (uname = name; *uname; bname++, uname++) {
4137             if (*bname != bcm_toupper(*uname)) {
4138                 break;
4139             }
4140         }
4141         if (!*uname && !*bname) {
4142             break;
4143         }
4144     }
4145 
4146     if (i < ARRAYSIZE(basenames)) {
4147         return basenames[i].base;
4148     } else {
4149         return -1;
4150     }
4151 }
4152 
dhd_pktfilter_offload_set(dhd_pub_t * dhd,char * arg)4153 void dhd_pktfilter_offload_set(dhd_pub_t *dhd, char *arg)
4154 {
4155     const char *str;
4156     wl_pkt_filter_t pkt_filter;
4157     wl_pkt_filter_t *pkt_filterp;
4158     int buf_len;
4159     int str_len;
4160     int rc = -1;
4161     uint32 mask_size;
4162     uint32 pattern_size;
4163     char *argv[MAXPKT_ARG] = {0}, *buf = 0;
4164     int i = 0;
4165     char *arg_save = 0, *arg_org = 0;
4166 
4167     if (!arg) {
4168         return;
4169     }
4170 
4171     if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) {
4172         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
4173         goto fail;
4174     }
4175 
4176     arg_org = arg_save;
4177 
4178     if (!(buf = MALLOC(dhd->osh, MAX_PKTFLT_BUF_SIZE))) {
4179         DHD_ERROR(("%s: malloc failed\n", __FUNCTION__));
4180         goto fail;
4181     }
4182 
4183     memset(buf, 0, MAX_PKTFLT_BUF_SIZE);
4184     memcpy(arg_save, arg, strlen(arg) + 1);
4185 
4186     if (strlen(arg) > MAX_PKTFLT_BUF_SIZE) {
4187         DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg),
4188                    (int)sizeof(buf)));
4189         goto fail;
4190     }
4191 
4192     argv[i] = bcmstrtok(&arg_save, " ", 0);
4193     while (argv[i++]) {
4194         if (i >= MAXPKT_ARG) {
4195             DHD_ERROR(("Invalid args provided\n"));
4196             goto fail;
4197         }
4198         argv[i] = bcmstrtok(&arg_save, " ", 0);
4199     }
4200 
4201     i = 0;
4202     if (argv[i] == NULL) {
4203         DHD_ERROR(("No args provided\n"));
4204         goto fail;
4205     }
4206 
4207     str = "pkt_filter_add";
4208     str_len = strlen(str);
4209     bcm_strncpy_s(buf, MAX_PKTFLT_BUF_SIZE, str, str_len);
4210     buf[str_len] = '\0';
4211     buf_len = str_len + 1;
4212 
4213     pkt_filterp = (wl_pkt_filter_t *)(buf + str_len + 1);
4214 
4215     /* Parse packet filter id. */
4216     pkt_filter.id = htod32(strtoul(argv[i], NULL, 0));
4217 
4218     if (argv[++i] == NULL) {
4219         DHD_ERROR(("Polarity not provided\n"));
4220         goto fail;
4221     }
4222 
4223     /* Parse filter polarity. */
4224     pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0));
4225 
4226     if (argv[++i] == NULL) {
4227         DHD_ERROR(("Filter type not provided\n"));
4228         goto fail;
4229     }
4230 
4231     /* Parse filter type. */
4232     pkt_filter.type = htod32(strtoul(argv[i], NULL, 0));
4233 
4234     if ((pkt_filter.type == 0) || (pkt_filter.type == 1)) {
4235         if (argv[++i] == NULL) {
4236             DHD_ERROR(("Offset not provided\n"));
4237             goto fail;
4238         }
4239 
4240         /* Parse pattern filter offset. */
4241         pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0));
4242 
4243         if (argv[++i] == NULL) {
4244             DHD_ERROR(("Bitmask not provided\n"));
4245             goto fail;
4246         }
4247 
4248         /* Parse pattern filter mask. */
4249         rc = wl_pattern_atoh(argv[i],
4250                              (char *)pkt_filterp->u.pattern.mask_and_pattern);
4251         if (rc == -1) {
4252             DHD_ERROR(("Rejecting: %s\n", argv[i]));
4253             goto fail;
4254         }
4255         mask_size = htod32(rc);
4256         if (argv[++i] == NULL) {
4257             DHD_ERROR(("Pattern not provided\n"));
4258             goto fail;
4259         }
4260 
4261         /* Parse pattern filter pattern. */
4262         rc = wl_pattern_atoh(
4263             argv[i],
4264             (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size]);
4265         if (rc == -1) {
4266             DHD_ERROR(("Rejecting: %s\n", argv[i]));
4267             goto fail;
4268         }
4269         pattern_size = htod32(rc);
4270         if (mask_size != pattern_size) {
4271             DHD_ERROR(("Mask and pattern not the same size\n"));
4272             goto fail;
4273         }
4274 
4275         pkt_filter.u.pattern.size_bytes = mask_size;
4276         buf_len += WL_PKT_FILTER_FIXED_LEN;
4277         buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 0x2 * mask_size);
4278 
4279         /* Keep-alive attributes are set in local	variable (keep_alive_pkt),
4280          * and then memcpy'ed into buffer (keep_alive_pktp) since there is no
4281          * guarantee that the buffer is properly aligned.
4282          */
4283         memcpy((char *)pkt_filterp, &pkt_filter,
4284                WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN);
4285     } else if ((pkt_filter.type == 0x2) || (pkt_filter.type == 0x6)) {
4286         int list_cnt = 0;
4287         char *endptr = NULL;
4288         wl_pkt_filter_pattern_listel_t *pf_el =
4289             (wl_pkt_filter_pattern_listel_t *)&pkt_filterp->u.patlist
4290                 .patterns[0];
4291 
4292         while (argv[++i] != NULL) {
4293             /* Check valid buffer size. */
4294             if ((buf_len + MAX_PKTFLT_FIXED_BUF_SIZE) > MAX_PKTFLT_BUF_SIZE) {
4295                 DHD_ERROR(("buffer over length MAX_PKTFLT_FIXED_BUF_SIZE\n"));
4296                 goto fail;
4297             }
4298 
4299             /* Parse pattern filter base and offset. */
4300             if (bcm_isdigit(*argv[i])) {
4301                 /* Numeric base */
4302                 rc = strtoul(argv[i], &endptr, 0);
4303             } else {
4304                 endptr = strchr(argv[i], ':');
4305                 if (endptr) {
4306                     *endptr = '\0';
4307                     rc = wl_pkt_filter_base_parse(argv[i]);
4308                     if (rc == -1) {
4309                         printf("Invalid base %s\n", argv[i]);
4310                         goto fail;
4311                     }
4312                     *endptr = ':';
4313                 }
4314             }
4315 
4316             if (endptr == NULL) {
4317                 printf("Invalid [base:]offset format: %s\n", argv[i]);
4318                 goto fail;
4319             }
4320 
4321             if (*endptr == ':') {
4322                 pf_el->base_offs = htod16(rc);
4323                 rc = strtoul(endptr + 1, &endptr, 0);
4324             } else {
4325                 /* Must have had a numeric offset only */
4326                 pf_el->base_offs = htod16(0);
4327             }
4328 
4329             if (*endptr) {
4330                 printf("Invalid [base:]offset format: %s\n", argv[i]);
4331                 goto fail;
4332             }
4333             if (rc > 0x0000FFFF) {
4334                 printf("Offset too large\n");
4335                 goto fail;
4336             }
4337             pf_el->rel_offs = htod16(rc);
4338 
4339             /* Clear match_flag (may be set in parsing which follows) */
4340             pf_el->match_flags = htod16(0);
4341 
4342             /* Parse pattern filter mask and pattern directly into ioctl buffer
4343              */
4344             if (argv[++i] == NULL) {
4345                 printf("Bitmask not provided\n");
4346                 goto fail;
4347             }
4348             rc = wl_pattern_atoh(argv[i], (char *)pf_el->mask_and_data);
4349             if ((rc == -1) || (rc > MAX_PKTFLT_FIXED_PATTERN_SIZE)) {
4350                 printf("Rejecting: %s\n", argv[i]);
4351                 goto fail;
4352             }
4353             mask_size = htod16(rc);
4354 
4355             if (argv[++i] == NULL) {
4356                 printf("Pattern not provided\n");
4357                 goto fail;
4358             }
4359 
4360             if (*argv[i] == '!') {
4361                 pf_el->match_flags = htod16(WL_PKT_FILTER_MFLAG_NEG);
4362                 (argv[i])++;
4363             }
4364             if (*argv[i] == '\0') {
4365                 printf("Pattern not provided\n");
4366                 goto fail;
4367             }
4368             rc = wl_pattern_atoh(argv[i], (char *)&pf_el->mask_and_data[rc]);
4369             if ((rc == -1) || (rc > MAX_PKTFLT_FIXED_PATTERN_SIZE)) {
4370                 printf("Rejecting: %s\n", argv[i]);
4371                 goto fail;
4372             }
4373             pattern_size = htod16(rc);
4374 
4375             if (mask_size != pattern_size) {
4376                 printf("Mask and pattern not the same size\n");
4377                 goto fail;
4378             }
4379 
4380             pf_el->size_bytes = mask_size;
4381 
4382             /* Account for the size of this pattern element */
4383             buf_len += WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 0x2 * rc;
4384 
4385             /* Move to next element location in ioctl buffer */
4386             pf_el = (wl_pkt_filter_pattern_listel_t
4387                          *)((uint8 *)pf_el +
4388                             WL_PKT_FILTER_PATTERN_LISTEL_FIXED_LEN + 0x2 * rc);
4389 
4390             /* Count list element */
4391             list_cnt++;
4392         }
4393 
4394         /* Account for initial fixed size, and copy initial fixed fields */
4395         buf_len +=
4396             WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN;
4397 
4398         if (buf_len > MAX_PKTFLT_BUF_SIZE) {
4399             DHD_ERROR(("buffer over length MAX_PKTFLT_BUF_SIZE\n"));
4400             goto fail;
4401         }
4402         /* Update list count and total size */
4403         pkt_filter.u.patlist.list_cnt = list_cnt;
4404         pkt_filter.u.patlist.PAD1[0] = 0;
4405         pkt_filter.u.patlist.totsize = buf + buf_len - (char *)pkt_filterp;
4406         pkt_filter.u.patlist.totsize -= WL_PKT_FILTER_FIXED_LEN;
4407 
4408         memcpy((char *)pkt_filterp, &pkt_filter,
4409                WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_LIST_FIXED_LEN);
4410     } else {
4411         DHD_ERROR(("Invalid filter type %d\n", pkt_filter.type));
4412         goto fail;
4413     }
4414 
4415     rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
4416     rc = rc >= 0 ? 0 : rc;
4417 
4418     if (rc) {
4419         DHD_ERROR(("%s: failed to add pktfilter %s, retcode = %d\n",
4420                    __FUNCTION__, arg, rc));
4421     } else {
4422         DHD_TRACE(("%s: successfully added pktfilter %s\n", __FUNCTION__, arg));
4423     }
4424 
4425 fail:
4426     if (arg_org) {
4427         MFREE(dhd->osh, arg_org, strlen(arg) + 1);
4428     }
4429 
4430     if (buf) {
4431         MFREE(dhd->osh, buf, MAX_PKTFLT_BUF_SIZE);
4432     }
4433 }
4434 
dhd_pktfilter_offload_delete(dhd_pub_t * dhd,int id)4435 void dhd_pktfilter_offload_delete(dhd_pub_t *dhd, int id)
4436 {
4437     int ret;
4438 
4439     ret = dhd_wl_ioctl_set_intiovar(dhd, "pkt_filter_delete", id, WLC_SET_VAR,
4440                                     TRUE, 0);
4441     if (ret < 0) {
4442         DHD_ERROR(("%s: Failed to delete filter ID:%d, ret=%d\n", __FUNCTION__,
4443                    id, ret));
4444     } else {
4445         DHD_TRACE(
4446             ("%s: successfully deleted pktfilter %d\n", __FUNCTION__, id));
4447     }
4448 }
4449 #endif /* PKT_FILTER_SUPPORT */
4450 
4451 /* ========================== */
4452 /* ==== ARP OFFLOAD SUPPORT = */
4453 /* ========================== */
4454 #ifdef ARP_OFFLOAD_SUPPORT
dhd_arp_offload_set(dhd_pub_t * dhd,int arp_mode)4455 void dhd_arp_offload_set(dhd_pub_t *dhd, int arp_mode)
4456 {
4457     int retcode;
4458 
4459     retcode = dhd_wl_ioctl_set_intiovar(dhd, "arp_ol", arp_mode, WLC_SET_VAR,
4460                                         TRUE, 0);
4461 
4462     retcode = retcode >= 0 ? 0 : retcode;
4463     if (retcode) {
4464         DHD_ERROR(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n",
4465                    __FUNCTION__, arp_mode, retcode));
4466     } else {
4467         DHD_ARPOE(("%s: successfully set ARP offload mode to 0x%x\n",
4468                    __FUNCTION__, arp_mode));
4469     }
4470 }
4471 
dhd_arp_offload_enable(dhd_pub_t * dhd,int arp_enable)4472 void dhd_arp_offload_enable(dhd_pub_t *dhd, int arp_enable)
4473 {
4474     int retcode;
4475 #ifdef WL_CFG80211
4476     /* Do not enable arp offload in case of non-STA interfaces active */
4477     if (arp_enable &&
4478         (wl_cfg80211_check_vif_in_use(dhd_linux_get_primary_netdev(dhd)))) {
4479         DHD_TRACE(
4480             ("%s: Virtual interfaces active, ignore arp offload request \n",
4481              __FUNCTION__));
4482         return;
4483     }
4484 #endif /* WL_CFG80211 */
4485     retcode = dhd_wl_ioctl_set_intiovar(dhd, "arpoe", arp_enable, WLC_SET_VAR,
4486                                         TRUE, 0);
4487 
4488     retcode = retcode >= 0 ? 0 : retcode;
4489     if (retcode) {
4490         DHD_ERROR(("%s: failed to enabe ARP offload to %d, retcode = %d\n",
4491                    __FUNCTION__, arp_enable, retcode));
4492     } else
4493 #ifdef DHD_LOG_DUMP
4494         DHD_LOG_MEM(("%s: successfully enabed ARP offload to %d\n",
4495                      __FUNCTION__, arp_enable));
4496 #else
4497         DHD_ARPOE(("%s: successfully enabed ARP offload to %d\n", __FUNCTION__,
4498                    arp_enable));
4499 #endif /* DHD_LOG_DUMP */
4500     if (arp_enable) {
4501         uint32 version;
4502         retcode = dhd_wl_ioctl_get_intiovar(dhd, "arp_version", &version,
4503                                             WLC_GET_VAR, FALSE, 0);
4504         if (retcode) {
4505             DHD_INFO(("%s: fail to get version (maybe version 1:retcode = %d\n",
4506                       __FUNCTION__, retcode));
4507             dhd->arp_version = 1;
4508         } else {
4509             DHD_INFO(("%s: ARP Version= %x\n", __FUNCTION__, version));
4510             dhd->arp_version = version;
4511         }
4512     }
4513 }
4514 
dhd_aoe_arp_clr(dhd_pub_t * dhd,int idx)4515 void dhd_aoe_arp_clr(dhd_pub_t *dhd, int idx)
4516 {
4517     int ret = 0;
4518 
4519     if (dhd == NULL) {
4520         return;
4521     }
4522     if (dhd->arp_version == 1) {
4523         idx = 0;
4524     }
4525 
4526     ret = dhd_iovar(dhd, idx, "arp_table_clear", NULL, 0, NULL, 0, TRUE);
4527     if (ret < 0) {
4528         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
4529     } else {
4530 #ifdef DHD_LOG_DUMP
4531         DHD_LOG_MEM(("%s: ARP table clear\n", __FUNCTION__));
4532 #else
4533         DHD_TRACE(("%s: ARP table clear\n", __FUNCTION__));
4534 #endif /* DHD_LOG_DUMP */
4535     }
4536     /* mac address isn't cleared here but it will be cleared after dongle off */
4537     dhd->hmac_updated = 0;
4538 }
4539 
dhd_aoe_hostip_clr(dhd_pub_t * dhd,int idx)4540 void dhd_aoe_hostip_clr(dhd_pub_t *dhd, int idx)
4541 {
4542     int ret = 0;
4543 
4544     if (dhd == NULL) {
4545         return;
4546     }
4547     if (dhd->arp_version == 1) {
4548         idx = 0;
4549     }
4550 
4551     ret = dhd_iovar(dhd, idx, "arp_hostip_clear", NULL, 0, NULL, 0, TRUE);
4552     if (ret < 0) {
4553         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
4554     } else {
4555 #ifdef DHD_LOG_DUMP
4556         DHD_LOG_MEM(("%s: ARP host ip clear\n", __FUNCTION__));
4557 #else
4558         DHD_TRACE(("%s: ARP host ip clear\n", __FUNCTION__));
4559 #endif /* DHD_LOG_DUMP */
4560     }
4561 }
4562 
dhd_arp_offload_add_ip(dhd_pub_t * dhd,uint32 ipaddr,int idx)4563 void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr, int idx)
4564 {
4565     int ret;
4566 
4567     if (dhd == NULL) {
4568         return;
4569     }
4570     if (dhd->arp_version == 1) {
4571         idx = 0;
4572     }
4573 
4574     ret = dhd_iovar(dhd, idx, "arp_hostip", (char *)&ipaddr, sizeof(ipaddr),
4575                     NULL, 0, TRUE);
4576     if (ret < 0) {
4577         DHD_ERROR(
4578             ("%s: ARP ip addr add failed, ret = %d\n", __FUNCTION__, ret));
4579     } else {
4580         /* mac address is updated in the dongle */
4581         dhd->hmac_updated = 1;
4582 #ifdef DHD_LOG_DUMP
4583         DHD_LOG_MEM(("%s: ARP ip addr entry added \n", __FUNCTION__));
4584 #else
4585         DHD_ARPOE(("%s: ARP ip addr entry added \n", __FUNCTION__));
4586 #endif /* DHD_LOG_DUMP */
4587     }
4588 }
4589 
dhd_arp_get_arp_hostip_table(dhd_pub_t * dhd,void * buf,int buflen,int idx)4590 int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen, int idx)
4591 {
4592     int ret, i;
4593     uint32 *ptr32 = buf;
4594     bool clr_bottom = FALSE;
4595 
4596     if (!buf) {
4597         return -1;
4598     }
4599     if (dhd == NULL) {
4600         return -1;
4601     }
4602     if (dhd->arp_version == 1) {
4603         idx = 0;
4604     }
4605 
4606     ret =
4607         dhd_iovar(dhd, idx, "arp_hostip", NULL, 0, (char *)buf, buflen, FALSE);
4608     if (ret) {
4609         DHD_ERROR(("%s: ioctl WLC_GET_VAR error %d\n", __FUNCTION__, ret));
4610 
4611         return -1;
4612     }
4613 
4614     /* clean up the buf, ascii reminder */
4615     for (i = 0; i < MAX_IPV4_ENTRIES; i++) {
4616         if (!clr_bottom) {
4617             if (*ptr32 == 0) {
4618                 clr_bottom = TRUE;
4619             }
4620         } else {
4621             *ptr32 = 0;
4622         }
4623         ptr32++;
4624     }
4625 
4626     return 0;
4627 }
4628 #endif /* ARP_OFFLOAD_SUPPORT  */
4629 
4630 /*
4631  * Neighbor Discovery Offload: enable NDO feature
4632  * Called  by ipv6 event handler when interface comes up/goes down
4633  */
dhd_ndo_enable(dhd_pub_t * dhd,int ndo_enable)4634 int dhd_ndo_enable(dhd_pub_t *dhd, int ndo_enable)
4635 {
4636     int retcode;
4637 
4638     if (dhd == NULL) {
4639         return -1;
4640     }
4641 
4642 #if defined(WL_CFG80211) && defined(WL_NAN)
4643     if (wl_cfgnan_is_dp_active(dhd_linux_get_primary_netdev(dhd))) {
4644         /* If nan dp is active, skip NDO */
4645         DHD_INFO(("Active NAN DP, skip NDO\n"));
4646         return 0;
4647     }
4648 #endif /* WL_CFG80211 && WL_NAN */
4649 #ifdef WL_CFG80211
4650     if (dhd->op_mode & DHD_FLAG_HOSTAP_MODE) {
4651         /* NDO disable on STA+SOFTAP mode */
4652         ndo_enable = FALSE;
4653     }
4654 #endif /* WL_CFG80211 */
4655     retcode = dhd_wl_ioctl_set_intiovar(dhd, "ndoe", ndo_enable, WLC_SET_VAR,
4656                                         TRUE, 0);
4657     if (retcode) {
4658         DHD_ERROR(("%s: failed to enabe ndo to %d, retcode = %d\n",
4659                    __FUNCTION__, ndo_enable, retcode));
4660     } else {
4661         DHD_TRACE(("%s: successfully enabed ndo offload to %d\n", __FUNCTION__,
4662                    ndo_enable));
4663     }
4664 
4665     return retcode;
4666 }
4667 
4668 /*
4669  * Neighbor Discover Offload: enable NDO feature
4670  * Called  by ipv6 event handler when interface comes up
4671  */
dhd_ndo_add_ip(dhd_pub_t * dhd,char * ipv6addr,int idx)4672 int dhd_ndo_add_ip(dhd_pub_t *dhd, char *ipv6addr, int idx)
4673 {
4674     int iov_len = 0;
4675     char iovbuf[DHD_IOVAR_BUF_SIZE];
4676     int retcode;
4677 
4678     if (dhd == NULL) {
4679         return -1;
4680     }
4681 
4682     iov_len = bcm_mkiovar("nd_hostip", (char *)ipv6addr, IPV6_ADDR_LEN, iovbuf,
4683                           sizeof(iovbuf));
4684     if (!iov_len) {
4685         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4686                    sizeof(iovbuf)));
4687         return -1;
4688     }
4689     retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4690     if (retcode) {
4691         DHD_ERROR(("%s: ndo ip addr add failed, retcode = %d\n", __FUNCTION__,
4692                    retcode));
4693     } else {
4694         DHD_TRACE(("%s: ndo ipaddr entry added \n", __FUNCTION__));
4695     }
4696 
4697     return retcode;
4698 }
4699 
4700 /*
4701  * Neighbor Discover Offload: enable NDO feature
4702  * Called  by ipv6 event handler when interface goes down
4703  */
dhd_ndo_remove_ip(dhd_pub_t * dhd,int idx)4704 int dhd_ndo_remove_ip(dhd_pub_t *dhd, int idx)
4705 {
4706     int iov_len = 0;
4707     char iovbuf[DHD_IOVAR_BUF_SIZE];
4708     int retcode;
4709 
4710     if (dhd == NULL) {
4711         return -1;
4712     }
4713 
4714     iov_len = bcm_mkiovar("nd_hostip_clear", NULL, 0, iovbuf, sizeof(iovbuf));
4715     if (!iov_len) {
4716         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4717                    sizeof(iovbuf)));
4718         return -1;
4719     }
4720     retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4721     if (retcode) {
4722         DHD_ERROR(("%s: ndo ip addr remove failed, retcode = %d\n",
4723                    __FUNCTION__, retcode));
4724     } else {
4725         DHD_TRACE(("%s: ndo ipaddr entry removed \n", __FUNCTION__));
4726     }
4727 
4728     return retcode;
4729 }
4730 /* Enhanced ND offload */
dhd_ndo_get_version(dhd_pub_t * dhdp)4731 uint16 dhd_ndo_get_version(dhd_pub_t *dhdp)
4732 {
4733     char iovbuf[DHD_IOVAR_BUF_SIZE];
4734     wl_nd_hostip_t ndo_get_ver;
4735     int iov_len;
4736     int retcode;
4737     uint16 ver = 0;
4738 
4739     if (dhdp == NULL) {
4740         return BCME_ERROR;
4741     }
4742 
4743     memset(&iovbuf, 0, sizeof(iovbuf));
4744     ndo_get_ver.version = htod16(WL_ND_HOSTIP_IOV_VER);
4745     ndo_get_ver.op_type = htod16(WL_ND_HOSTIP_OP_VER);
4746     ndo_get_ver.length = htod32(WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16));
4747     ndo_get_ver.u.version = 0;
4748     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_get_ver,
4749                           WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16), iovbuf,
4750                           sizeof(iovbuf));
4751     if (!iov_len) {
4752         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4753                    sizeof(iovbuf)));
4754         return BCME_ERROR;
4755     }
4756 
4757     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, iov_len, FALSE, 0);
4758     if (retcode) {
4759         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4760         /* ver iovar not supported. NDO version is 0 */
4761         ver = 0;
4762     } else {
4763         wl_nd_hostip_t *ndo_ver_ret = (wl_nd_hostip_t *)iovbuf;
4764 
4765         if ((dtoh16(ndo_ver_ret->version) == WL_ND_HOSTIP_IOV_VER) &&
4766             (dtoh16(ndo_ver_ret->op_type) == WL_ND_HOSTIP_OP_VER) &&
4767             (dtoh32(ndo_ver_ret->length) ==
4768              WL_ND_HOSTIP_FIXED_LEN + sizeof(uint16))) {
4769             /* nd_hostip iovar version */
4770             ver = dtoh16(ndo_ver_ret->u.version);
4771         }
4772 
4773         DHD_TRACE(("%s: successfully get version: %d\n", __FUNCTION__, ver));
4774     }
4775 
4776     return ver;
4777 }
4778 
dhd_ndo_add_ip_with_type(dhd_pub_t * dhdp,char * ipv6addr,uint8 type,int idx)4779 int dhd_ndo_add_ip_with_type(dhd_pub_t *dhdp, char *ipv6addr, uint8 type,
4780                              int idx)
4781 {
4782     char iovbuf[DHD_IOVAR_BUF_SIZE];
4783     wl_nd_hostip_t ndo_add_addr;
4784     int iov_len;
4785     int retcode;
4786 
4787     if (dhdp == NULL || ipv6addr == 0) {
4788         return BCME_ERROR;
4789     }
4790 
4791     /* wl_nd_hostip_t fixed param */
4792     ndo_add_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
4793     ndo_add_addr.op_type = htod16(WL_ND_HOSTIP_OP_ADD);
4794     ndo_add_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
4795     /* wl_nd_host_ip_addr_t param for add */
4796     memcpy(&ndo_add_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN);
4797     ndo_add_addr.u.host_ip.type = type;
4798 
4799     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_add_addr,
4800                           WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf));
4801     if (!iov_len) {
4802         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4803                    sizeof(iovbuf)));
4804         return BCME_ERROR;
4805     }
4806 
4807     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4808     if (retcode) {
4809         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4810 #ifdef NDO_CONFIG_SUPPORT
4811         if (retcode == BCME_NORESOURCE) {
4812             /* number of host ip addr exceeds FW capacity, Deactivate ND offload
4813              */
4814             DHD_INFO(("%s: Host IP count exceed device capacity,"
4815                       "ND offload deactivated\n",
4816                       __FUNCTION__));
4817             dhdp->ndo_host_ip_overflow = TRUE;
4818             dhd_ndo_enable(dhdp, FALSE);
4819         }
4820 #endif /* NDO_CONFIG_SUPPORT */
4821     } else {
4822         DHD_TRACE(("%s: successfully added: %d\n", __FUNCTION__, retcode));
4823     }
4824 
4825     return retcode;
4826 }
4827 
dhd_ndo_remove_ip_by_addr(dhd_pub_t * dhdp,char * ipv6addr,int idx)4828 int dhd_ndo_remove_ip_by_addr(dhd_pub_t *dhdp, char *ipv6addr, int idx)
4829 {
4830     char iovbuf[DHD_IOVAR_BUF_SIZE];
4831     wl_nd_hostip_t ndo_del_addr;
4832     int iov_len;
4833     int retcode;
4834 
4835     if (dhdp == NULL || ipv6addr == 0) {
4836         return BCME_ERROR;
4837     }
4838 
4839     /* wl_nd_hostip_t fixed param */
4840     ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
4841     ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL);
4842     ndo_del_addr.length = htod32(WL_ND_HOSTIP_WITH_ADDR_LEN);
4843     /* wl_nd_host_ip_addr_t param for del */
4844     memcpy(&ndo_del_addr.u.host_ip.ip_addr, ipv6addr, IPV6_ADDR_LEN);
4845     ndo_del_addr.u.host_ip.type = 0; /* don't care */
4846 
4847     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr,
4848                           WL_ND_HOSTIP_WITH_ADDR_LEN, iovbuf, sizeof(iovbuf));
4849     if (!iov_len) {
4850         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4851                    sizeof(iovbuf)));
4852         return BCME_ERROR;
4853     }
4854 
4855     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4856     if (retcode) {
4857         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4858     } else {
4859         DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode));
4860     }
4861 
4862     return retcode;
4863 }
4864 
dhd_ndo_remove_ip_by_type(dhd_pub_t * dhdp,uint8 type,int idx)4865 int dhd_ndo_remove_ip_by_type(dhd_pub_t *dhdp, uint8 type, int idx)
4866 {
4867     char iovbuf[DHD_IOVAR_BUF_SIZE];
4868     wl_nd_hostip_t ndo_del_addr;
4869     int iov_len;
4870     int retcode;
4871 
4872     if (dhdp == NULL) {
4873         return BCME_ERROR;
4874     }
4875 
4876     /* wl_nd_hostip_t fixed param */
4877     ndo_del_addr.version = htod16(WL_ND_HOSTIP_IOV_VER);
4878     if (type == WL_ND_IPV6_ADDR_TYPE_UNICAST) {
4879         ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_UC);
4880     } else if (type == WL_ND_IPV6_ADDR_TYPE_ANYCAST) {
4881         ndo_del_addr.op_type = htod16(WL_ND_HOSTIP_OP_DEL_AC);
4882     } else {
4883         return BCME_BADARG;
4884     }
4885     ndo_del_addr.length = htod32(WL_ND_HOSTIP_FIXED_LEN);
4886 
4887     iov_len = bcm_mkiovar("nd_hostip", (char *)&ndo_del_addr,
4888                           WL_ND_HOSTIP_FIXED_LEN, iovbuf, sizeof(iovbuf));
4889     if (!iov_len) {
4890         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4891                    sizeof(iovbuf)));
4892         return BCME_ERROR;
4893     }
4894 
4895     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, idx);
4896     if (retcode) {
4897         DHD_ERROR(("%s: failed, retcode = %d\n", __FUNCTION__, retcode));
4898     } else {
4899         DHD_TRACE(("%s: successfully removed: %d\n", __FUNCTION__, retcode));
4900     }
4901 
4902     return retcode;
4903 }
4904 
dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t * dhdp,int enable)4905 int dhd_ndo_unsolicited_na_filter_enable(dhd_pub_t *dhdp, int enable)
4906 {
4907     char iovbuf[DHD_IOVAR_BUF_SIZE];
4908     int iov_len;
4909     int retcode;
4910 
4911     if (dhdp == NULL) {
4912         return BCME_ERROR;
4913     }
4914 
4915     iov_len = bcm_mkiovar("nd_unsolicited_na_filter", (char *)&enable,
4916                           sizeof(int), iovbuf, sizeof(iovbuf));
4917     if (!iov_len) {
4918         DHD_ERROR(("%s: Insufficient iovar buffer size %zu \n", __FUNCTION__,
4919                    sizeof(iovbuf)));
4920         return BCME_ERROR;
4921     }
4922 
4923     retcode = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0);
4924     if (retcode) {
4925         DHD_ERROR(
4926             ("%s: failed to enable Unsolicited NA filter to %d, retcode = %d\n",
4927              __FUNCTION__, enable, retcode));
4928     } else {
4929         DHD_TRACE(("%s: successfully enabled Unsolicited NA filter to %d\n",
4930                    __FUNCTION__, enable));
4931     }
4932 
4933     return retcode;
4934 }
4935 #ifdef SIMPLE_ISCAN
4936 
4937 uint iscan_thread_id = 0;
4938 iscan_buf_t *iscan_chain = 0;
4939 
dhd_iscan_allocate_buf(dhd_pub_t * dhd,iscan_buf_t ** iscanbuf)4940 iscan_buf_t *dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf)
4941 {
4942     iscan_buf_t *iscanbuf_alloc = 0;
4943     iscan_buf_t *iscanbuf_head;
4944 
4945     DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
4946     dhd_iscan_lock();
4947 
4948     iscanbuf_alloc = (iscan_buf_t *)MALLOC(dhd->osh, sizeof(iscan_buf_t));
4949     if (iscanbuf_alloc == NULL) {
4950         goto fail;
4951     }
4952 
4953     iscanbuf_alloc->next = NULL;
4954     iscanbuf_head = *iscanbuf;
4955 
4956     DHD_ISCAN(("%s: addr of allocated node = 0x%X"
4957                "addr of iscanbuf_head = 0x%X dhd = 0x%X\n",
4958                __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd));
4959 
4960     if (iscanbuf_head == NULL) {
4961         *iscanbuf = iscanbuf_alloc;
4962         DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__));
4963         goto fail;
4964     }
4965 
4966     while (iscanbuf_head->next) {
4967         iscanbuf_head = iscanbuf_head->next;
4968     }
4969 
4970     iscanbuf_head->next = iscanbuf_alloc;
4971 
4972 fail:
4973     dhd_iscan_unlock();
4974     return iscanbuf_alloc;
4975 }
4976 
dhd_iscan_free_buf(void * dhdp,iscan_buf_t * iscan_delete)4977 void dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete)
4978 {
4979     iscan_buf_t *iscanbuf_free = 0;
4980     iscan_buf_t *iscanbuf_prv = 0;
4981     iscan_buf_t *iscanbuf_cur;
4982     dhd_pub_t *dhd = dhd_bus_pub(dhdp);
4983     DHD_ISCAN(("%s: Entered\n", __FUNCTION__));
4984 
4985     dhd_iscan_lock();
4986 
4987     iscanbuf_cur = iscan_chain;
4988 
4989     /* If iscan_delete is null then delete the entire
4990      * chain or else delete specific one provided
4991      */
4992     if (!iscan_delete) {
4993         while (iscanbuf_cur) {
4994             iscanbuf_free = iscanbuf_cur;
4995             iscanbuf_cur = iscanbuf_cur->next;
4996             iscanbuf_free->next = 0;
4997             MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t));
4998         }
4999         iscan_chain = 0;
5000     } else {
5001         while (iscanbuf_cur) {
5002             if (iscanbuf_cur == iscan_delete) {
5003                 break;
5004             }
5005             iscanbuf_prv = iscanbuf_cur;
5006             iscanbuf_cur = iscanbuf_cur->next;
5007         }
5008         if (iscanbuf_prv) {
5009             iscanbuf_prv->next = iscan_delete->next;
5010         }
5011 
5012         iscan_delete->next = 0;
5013         MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t));
5014 
5015         if (!iscanbuf_prv) {
5016             iscan_chain = 0;
5017         }
5018     }
5019     dhd_iscan_unlock();
5020 }
5021 
dhd_iscan_result_buf(void)5022 iscan_buf_t *dhd_iscan_result_buf(void)
5023 {
5024     return iscan_chain;
5025 }
5026 
dhd_iscan_issue_request(void * dhdp,wl_iscan_params_t * pParams,uint32 size)5027 int dhd_iscan_issue_request(void *dhdp, wl_iscan_params_t *pParams, uint32 size)
5028 {
5029     int rc = -1;
5030     dhd_pub_t *dhd = dhd_bus_pub(dhdp);
5031     char *buf;
5032     char iovar[] = "iscan";
5033     uint32 allocSize = 0;
5034     wl_ioctl_t ioctl;
5035     int len;
5036 
5037     if (pParams) {
5038         allocSize = (size + strlen(iovar) + 1);
5039         if ((allocSize < size) || (allocSize < strlen(iovar))) {
5040             DHD_ERROR(
5041                 ("%s: overflow - allocation size too large %d < %d + %d!\n",
5042                  __FUNCTION__, allocSize, size, strlen(iovar)));
5043             goto cleanUp;
5044         }
5045         buf = MALLOC(dhd->osh, allocSize);
5046         if (buf == NULL) {
5047             DHD_ERROR(
5048                 ("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize));
5049             goto cleanUp;
5050         }
5051         ioctl.cmd = WLC_SET_VAR;
5052         len = bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize);
5053         if (len == 0) {
5054             rc = BCME_BUFTOOSHORT;
5055             goto cleanUp;
5056         }
5057         rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, len);
5058     }
5059 
5060 cleanUp:
5061     if (buf) {
5062         MFREE(dhd->osh, buf, allocSize);
5063     }
5064 
5065     return rc;
5066 }
5067 
dhd_iscan_get_partial_result(void * dhdp,uint * scan_count)5068 static int dhd_iscan_get_partial_result(void *dhdp, uint *scan_count)
5069 {
5070     wl_iscan_results_t *list_buf;
5071     wl_iscan_results_t list;
5072     wl_scan_results_t *results;
5073     iscan_buf_t *iscan_cur;
5074     int status = -1;
5075     dhd_pub_t *dhd = dhd_bus_pub(dhdp);
5076     int rc;
5077     wl_ioctl_t ioctl;
5078     int len;
5079 
5080     DHD_ISCAN(("%s: Enter\n", __FUNCTION__));
5081 
5082     iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain);
5083     if (!iscan_cur) {
5084         DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__));
5085         dhd_iscan_free_buf(dhdp, 0);
5086         dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
5087         dhd_ind_scan_confirm(dhdp, FALSE);
5088         goto fail;
5089     }
5090 
5091     dhd_iscan_lock();
5092 
5093     memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN);
5094     list_buf = (wl_iscan_results_t *)iscan_cur->iscan_buf;
5095     results = &list_buf->results;
5096     results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE;
5097     results->version = 0;
5098     results->count = 0;
5099 
5100     memset(&list, 0, sizeof(list));
5101     list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN);
5102     len =
5103         bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE,
5104                     iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
5105     if (len == 0) {
5106         dhd_iscan_free_buf(dhdp, 0);
5107         dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT);
5108         dhd_ind_scan_confirm(dhdp, FALSE);
5109         status = BCME_BUFTOOSHORT;
5110         goto fail;
5111     }
5112     ioctl.cmd = WLC_GET_VAR;
5113     ioctl.set = FALSE;
5114     rc =
5115         dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN);
5116 
5117     results->buflen = dtoh32(results->buflen);
5118     results->version = dtoh32(results->version);
5119     *scan_count = results->count = dtoh32(results->count);
5120     status = dtoh32(list_buf->status);
5121     DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__,
5122                results->count, status));
5123 
5124     dhd_iscan_unlock();
5125 
5126     if (!(*scan_count)) {
5127         /* race condition when FLUSH already called */
5128         dhd_iscan_free_buf(dhdp, 0);
5129     }
5130 fail:
5131     return status;
5132 }
5133 
5134 #endif /* SIMPLE_ISCAN */
5135 
5136 /*
5137  * returns = TRUE if associated, FALSE if not associated
5138  */
dhd_is_associated(dhd_pub_t * dhd,uint8 ifidx,int * retval)5139 bool dhd_is_associated(dhd_pub_t *dhd, uint8 ifidx, int *retval)
5140 {
5141     char bssid[0x6], zbuf[0x6];
5142     int ret = -1;
5143 
5144     bzero(bssid, 0x6);
5145     bzero(zbuf, 0x6);
5146 
5147     ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN,
5148                            FALSE, ifidx);
5149     DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret));
5150 
5151     if (ret == BCME_NOTASSOCIATED) {
5152         DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret));
5153     }
5154 
5155     if (retval) {
5156         *retval = ret;
5157     }
5158 
5159     if (ret < 0) {
5160         return FALSE;
5161     }
5162 
5163     if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) == 0)) {
5164         DHD_TRACE(
5165             ("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__));
5166         return FALSE;
5167     }
5168     return TRUE;
5169 }
5170 
5171 /* Function to estimate possible DTIM_SKIP value */
5172 #if defined(BCMPCIE)
dhd_get_suspend_bcn_li_dtim(dhd_pub_t * dhd,int * dtim_period,int * bcn_interval)5173 int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd, int *dtim_period,
5174                                 int *bcn_interval)
5175 {
5176     int bcn_li_dtim = 1; /* deafult no dtim skip setting */
5177     int ret = -1;
5178     int allowed_skip_dtim_cnt = 0;
5179 
5180     if (dhd->disable_dtim_in_suspend) {
5181         DHD_ERROR(("%s Disable bcn_li_dtim in suspend\n", __FUNCTION__));
5182         bcn_li_dtim = 0;
5183         return bcn_li_dtim;
5184     }
5185 
5186     /* Check if associated */
5187     if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
5188         DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
5189         return bcn_li_dtim;
5190     }
5191 
5192     if (dtim_period == NULL || bcn_interval == NULL) {
5193         return bcn_li_dtim;
5194     }
5195 
5196     /* read associated AP beacon interval */
5197     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, bcn_interval,
5198                                 sizeof(*bcn_interval), FALSE, 0)) < 0) {
5199         DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
5200         return bcn_li_dtim;
5201     }
5202 
5203     /* read associated AP dtim setup */
5204     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, dtim_period,
5205                                 sizeof(*dtim_period), FALSE, 0)) < 0) {
5206         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
5207         return bcn_li_dtim;
5208     }
5209 
5210     /* if not assocated just return */
5211     if (*dtim_period == 0) {
5212         return bcn_li_dtim;
5213     }
5214 
5215     if (dhd->max_dtim_enable) {
5216         bcn_li_dtim = (int)(MAX_DTIM_ALLOWED_INTERVAL /
5217                             ((*dtim_period) * (*bcn_interval)));
5218         if (bcn_li_dtim == 0) {
5219             bcn_li_dtim = 1;
5220         }
5221     } else {
5222         /* attemp to use platform defined dtim skip interval */
5223         bcn_li_dtim = dhd->suspend_bcn_li_dtim;
5224 
5225         /* check if sta listen interval fits into AP dtim */
5226         if (*dtim_period > CUSTOM_LISTEN_INTERVAL) {
5227             /* AP DTIM to big for our Listen Interval : no dtim skiping */
5228             bcn_li_dtim = NO_DTIM_SKIP;
5229             DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", __FUNCTION__,
5230                        *dtim_period, CUSTOM_LISTEN_INTERVAL));
5231             return bcn_li_dtim;
5232         }
5233 
5234         if (((*dtim_period) * (*bcn_interval) * bcn_li_dtim) >
5235             MAX_DTIM_ALLOWED_INTERVAL) {
5236             allowed_skip_dtim_cnt =
5237                 MAX_DTIM_ALLOWED_INTERVAL / ((*dtim_period) * (*bcn_interval));
5238             bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt
5239                                                        : NO_DTIM_SKIP;
5240         }
5241 
5242         if ((bcn_li_dtim * (*dtim_period)) > CUSTOM_LISTEN_INTERVAL) {
5243             /* Round up dtim_skip to fit into STAs Listen Interval */
5244             bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / *dtim_period);
5245             DHD_TRACE(
5246                 ("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
5247         }
5248     }
5249 
5250     if (dhd->conf->suspend_bcn_li_dtim >= 0) {
5251         bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim;
5252     }
5253     DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", __FUNCTION__,
5254                *bcn_interval, bcn_li_dtim, *dtim_period,
5255                CUSTOM_LISTEN_INTERVAL));
5256 
5257     return bcn_li_dtim;
5258 }
5259 #else  /* OEM_ANDROID && BCMPCIE */
dhd_get_suspend_bcn_li_dtim(dhd_pub_t * dhd)5260 int dhd_get_suspend_bcn_li_dtim(dhd_pub_t *dhd)
5261 {
5262     int bcn_li_dtim = 1; /* deafult no dtim skip setting */
5263     int ret = -1;
5264     int dtim_period = 0;
5265     int ap_beacon = 0;
5266     int allowed_skip_dtim_cnt = 0;
5267 
5268     if (dhd->disable_dtim_in_suspend) {
5269         DHD_ERROR(("%s Disable bcn_li_dtim in suspend\n", __FUNCTION__));
5270         bcn_li_dtim = 0;
5271         goto exit;
5272     }
5273 
5274     /* Check if associated */
5275     if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
5276         DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret));
5277         goto exit;
5278     }
5279 
5280     /* read associated AP beacon interval */
5281     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BCNPRD, &ap_beacon,
5282                                 sizeof(ap_beacon), FALSE, 0)) < 0) {
5283         DHD_ERROR(("%s get beacon failed code %d\n", __FUNCTION__, ret));
5284         goto exit;
5285     }
5286 
5287     /* read associated ap's dtim setup */
5288     if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, &dtim_period,
5289                                 sizeof(dtim_period), FALSE, 0)) < 0) {
5290         DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret));
5291         goto exit;
5292     }
5293 
5294     /* if not assocated just exit */
5295     if (dtim_period == 0) {
5296         goto exit;
5297     }
5298 
5299     if (dhd->max_dtim_enable) {
5300         bcn_li_dtim =
5301             (int)(MAX_DTIM_ALLOWED_INTERVAL / (ap_beacon * dtim_period));
5302         if (bcn_li_dtim == 0) {
5303             bcn_li_dtim = 1;
5304         }
5305     } else {
5306         /* attemp to use platform defined dtim skip interval */
5307         bcn_li_dtim = dhd->suspend_bcn_li_dtim;
5308 
5309         /* check if sta listen interval fits into AP dtim */
5310         if (dtim_period > CUSTOM_LISTEN_INTERVAL) {
5311             /* AP DTIM to big for our Listen Interval : no dtim skiping */
5312             bcn_li_dtim = NO_DTIM_SKIP;
5313             DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", __FUNCTION__,
5314                        dtim_period, CUSTOM_LISTEN_INTERVAL));
5315             goto exit;
5316         }
5317 
5318         if ((dtim_period * ap_beacon * bcn_li_dtim) >
5319             MAX_DTIM_ALLOWED_INTERVAL) {
5320             allowed_skip_dtim_cnt =
5321                 MAX_DTIM_ALLOWED_INTERVAL / (dtim_period * ap_beacon);
5322             bcn_li_dtim = (allowed_skip_dtim_cnt != 0) ? allowed_skip_dtim_cnt
5323                                                        : NO_DTIM_SKIP;
5324         }
5325 
5326         if ((bcn_li_dtim * dtim_period) > CUSTOM_LISTEN_INTERVAL) {
5327             /* Round up dtim_skip to fit into STAs Listen Interval */
5328             bcn_li_dtim = (int)(CUSTOM_LISTEN_INTERVAL / dtim_period);
5329             DHD_TRACE(
5330                 ("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim));
5331         }
5332     }
5333 
5334     if (dhd->conf->suspend_bcn_li_dtim >= 0) {
5335         bcn_li_dtim = dhd->conf->suspend_bcn_li_dtim;
5336     }
5337     DHD_ERROR(("%s beacon=%d bcn_li_dtim=%d DTIM=%d Listen=%d\n", __FUNCTION__,
5338                ap_beacon, bcn_li_dtim, dtim_period, CUSTOM_LISTEN_INTERVAL));
5339 
5340 exit:
5341     return bcn_li_dtim;
5342 }
5343 #endif /* OEM_ANDROID && BCMPCIE */
5344 
5345 #ifdef CONFIG_SILENT_ROAM
dhd_sroam_set_mon(dhd_pub_t * dhd,bool set)5346 int dhd_sroam_set_mon(dhd_pub_t *dhd, bool set)
5347 {
5348     int ret = BCME_OK;
5349     wlc_sroam_t *psroam;
5350     wlc_sroam_info_t *sroam;
5351     uint sroamlen = sizeof(*sroam) + SROAM_HDRLEN;
5352 
5353     /* Check if associated */
5354     if (dhd_is_associated(dhd, 0, NULL) == FALSE) {
5355         DHD_TRACE(("%s NOT assoc\n", __FUNCTION__));
5356         return ret;
5357     }
5358 
5359     if (set && (dhd->op_mode & (DHD_FLAG_HOSTAP_MODE | DHD_FLAG_P2P_GC_MODE |
5360                                 DHD_FLAG_P2P_GO_MODE))) {
5361         DHD_INFO(
5362             (" Failed to set sroam %d, op_mode 0x%04x\n", set, dhd->op_mode));
5363         return ret;
5364     }
5365 
5366     if (!dhd->sroam_turn_on) {
5367         DHD_INFO((" Failed to set sroam %d, sroam turn %d\n", set,
5368                   dhd->sroam_turn_on));
5369         return ret;
5370     }
5371     psroam = (wlc_sroam_t *)MALLOCZ(dhd->osh, sroamlen);
5372     if (!psroam) {
5373         DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
5374         return BCME_NOMEM;
5375     }
5376 
5377     ret = dhd_iovar(dhd, 0, "sroam", NULL, 0, (char *)psroam, sroamlen, FALSE);
5378     if (ret < 0) {
5379         DHD_ERROR(("%s Failed to Get sroam %d\n", __FUNCTION__, ret));
5380         goto done;
5381     }
5382 
5383     if (psroam->ver != WLC_SILENT_ROAM_CUR_VER) {
5384         ret = BCME_VERSION;
5385         goto done;
5386     }
5387 
5388     sroam = (wlc_sroam_info_t *)psroam->data;
5389     sroam->sroam_on = set;
5390     DHD_INFO((" Silent roam monitor mode %s\n", set ? "On" : "Off"));
5391 
5392     ret = dhd_iovar(dhd, 0, "sroam", (char *)psroam, sroamlen, NULL, 0, TRUE);
5393     if (ret < 0) {
5394         DHD_ERROR(("%s Failed to Set sroam %d\n", __FUNCTION__, ret));
5395     }
5396 
5397 done:
5398     if (psroam) {
5399         MFREE(dhd->osh, psroam, sroamlen);
5400     }
5401     return ret;
5402 }
5403 #endif /* CONFIG_SILENT_ROAM */
5404 
5405 /* Check if the mode supports STA MODE */
dhd_support_sta_mode(dhd_pub_t * dhd)5406 bool dhd_support_sta_mode(dhd_pub_t *dhd)
5407 {
5408 #ifdef WL_CFG80211
5409     if (!(dhd->op_mode & DHD_FLAG_STA_MODE)) {
5410         return FALSE;
5411     } else
5412 #endif /* WL_CFG80211 */
5413         return TRUE;
5414 }
5415 
5416 #if defined(KEEP_ALIVE)
dhd_keep_alive_onoff(dhd_pub_t * dhd)5417 int dhd_keep_alive_onoff(dhd_pub_t *dhd)
5418 {
5419     char buf[32] = {0};
5420     const char *str;
5421     wl_mkeep_alive_pkt_t mkeep_alive_pkt = {0, 0, 0, 0, 0, {0}};
5422     wl_mkeep_alive_pkt_t *mkeep_alive_pktp;
5423     int buf_len;
5424     int str_len;
5425     int res = -1;
5426 
5427     if (!dhd_support_sta_mode(dhd)) {
5428         return res;
5429     }
5430 
5431     DHD_TRACE(("%s execution\n", __FUNCTION__));
5432 
5433     str = "mkeep_alive";
5434     str_len = strlen(str);
5435     strncpy(buf, str, sizeof(buf) - 1);
5436     buf[sizeof(buf) - 1] = '\0';
5437     mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *)(buf + str_len + 1);
5438     mkeep_alive_pkt.period_msec = dhd->conf->keep_alive_period;
5439     buf_len = str_len + 1;
5440     mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION);
5441     mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN);
5442     /* Setup keep alive zero for null packet generation */
5443     mkeep_alive_pkt.keep_alive_id = 0;
5444     mkeep_alive_pkt.len_bytes = 0;
5445     buf_len += WL_MKEEP_ALIVE_FIXED_LEN;
5446     bzero(mkeep_alive_pkt.data, sizeof(mkeep_alive_pkt.data));
5447     /* Keep-alive attributes are set in local	variable (mkeep_alive_pkt), and
5448      * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no
5449      * guarantee that the buffer is properly aligned.
5450      */
5451     memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt,
5452            WL_MKEEP_ALIVE_FIXED_LEN);
5453 
5454     res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0);
5455 
5456     return res;
5457 }
5458 #endif /* defined(KEEP_ALIVE) */
5459 #define CSCAN_TLV_TYPE_SSID_IE 'S'
5460 /*
5461  *  SSIDs list parsing from cscan tlv list
5462  */
wl_parse_ssid_list_tlv(char ** list_str,wlc_ssid_ext_t * ssid,int max,int * bytes_left)5463 int wl_parse_ssid_list_tlv(char **list_str, wlc_ssid_ext_t *ssid, int max,
5464                            int *bytes_left)
5465 {
5466     char *str;
5467     int idx = 0;
5468     uint8 len;
5469 
5470     if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) {
5471         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
5472         return BCME_BADARG;
5473     }
5474     str = *list_str;
5475     while (*bytes_left > 0) {
5476         if (str[0] != CSCAN_TLV_TYPE_SSID_IE) {
5477             *list_str = str;
5478             DHD_TRACE(
5479                 ("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0]));
5480             return idx;
5481         }
5482 
5483         if (idx >= max) {
5484             DHD_ERROR(("%s number of SSIDs more than %d\n", __FUNCTION__, idx));
5485             return BCME_BADARG;
5486         }
5487 
5488         /* Get proper CSCAN_TLV_TYPE_SSID_IE */
5489         *bytes_left -= 1;
5490         if (*bytes_left == 0) {
5491             DHD_ERROR(("%s no length field.\n", __FUNCTION__));
5492             return BCME_BADARG;
5493         }
5494         str += 1;
5495         ssid[idx].rssi_thresh = 0;
5496         ssid[idx].flags = 0;
5497         len = str[0];
5498         if (len == 0) {
5499             /* Broadcast SSID */
5500             ssid[idx].SSID_len = 0;
5501             memset((char *)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN);
5502             *bytes_left -= 1;
5503             str += 1;
5504 
5505             DHD_TRACE(("BROADCAST SCAN  left=%d\n", *bytes_left));
5506         } else if (len <= DOT11_MAX_SSID_LEN) {
5507             /* Get proper SSID size */
5508             ssid[idx].SSID_len = len;
5509             *bytes_left -= 1;
5510             /* Get SSID */
5511             if (ssid[idx].SSID_len > *bytes_left) {
5512                 DHD_ERROR(("%s out of memory range len=%d but left=%d\n",
5513                            __FUNCTION__, ssid[idx].SSID_len, *bytes_left));
5514                 return BCME_BADARG;
5515             }
5516             str += 1;
5517             memcpy((char *)ssid[idx].SSID, str, ssid[idx].SSID_len);
5518 
5519             *bytes_left -= ssid[idx].SSID_len;
5520             str += ssid[idx].SSID_len;
5521             ssid[idx].hidden = TRUE;
5522 
5523             DHD_TRACE(("%s :size=%d left=%d\n", (char *)ssid[idx].SSID,
5524                        ssid[idx].SSID_len, *bytes_left));
5525         } else {
5526             DHD_ERROR(("### SSID size more than %d\n", str[0]));
5527             return BCME_BADARG;
5528         }
5529         idx++;
5530     }
5531 
5532     *list_str = str;
5533     return idx;
5534 }
5535 
5536 #if defined(WL_WIRELESS_EXT)
5537 /* Android ComboSCAN support */
5538 
5539 /*
5540  *  data parsing from ComboScan tlv list
5541  */
wl_iw_parse_data_tlv(char ** list_str,void * dst,int dst_size,const char token,int input_size,int * bytes_left)5542 int wl_iw_parse_data_tlv(char **list_str, void *dst, int dst_size,
5543                          const char token, int input_size, int *bytes_left)
5544 {
5545     char *str;
5546     uint16 short_temp;
5547     uint32 int_temp;
5548 
5549     if ((list_str == NULL) || (*list_str == NULL) || (bytes_left == NULL) ||
5550         (*bytes_left < 0)) {
5551         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
5552         return -1;
5553     }
5554     str = *list_str;
5555 
5556     /* Clean all dest bytes */
5557     memset(dst, 0, dst_size);
5558     if (*bytes_left > 0) {
5559         if (str[0] != token) {
5560             DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", __FUNCTION__,
5561                        token, str[0], *bytes_left));
5562             return -1;
5563         }
5564 
5565         *bytes_left -= 1;
5566         str += 1;
5567 
5568         if (input_size == 1) {
5569             memcpy(dst, str, input_size);
5570         } else if (input_size == 0x2) {
5571             memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)),
5572                    input_size);
5573         } else if (input_size == 0x4) {
5574             memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)),
5575                    input_size);
5576         }
5577 
5578         *bytes_left -= input_size;
5579         str += input_size;
5580         *list_str = str;
5581         return 1;
5582     }
5583     return 1;
5584 }
5585 
5586 /*
5587  *  channel list parsing from cscan tlv list
5588  */
wl_iw_parse_channel_list_tlv(char ** list_str,uint16 * channel_list,int channel_num,int * bytes_left)5589 int wl_iw_parse_channel_list_tlv(char **list_str, uint16 *channel_list,
5590                                  int channel_num, int *bytes_left)
5591 {
5592     char *str;
5593     int idx = 0;
5594 
5595     if ((list_str == NULL) || (*list_str == NULL) || (bytes_left == NULL) ||
5596         (*bytes_left < 0)) {
5597         DHD_ERROR(("%s error paramters\n", __FUNCTION__));
5598         return -1;
5599     }
5600     str = *list_str;
5601 
5602     while (*bytes_left > 0) {
5603         if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) {
5604             *list_str = str;
5605             DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left,
5606                        str[0]));
5607             return idx;
5608         }
5609         /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */
5610         *bytes_left -= 1;
5611         str += 1;
5612 
5613         if (str[0] == 0) {
5614             /* All channels */
5615             channel_list[idx] = 0x0;
5616         } else {
5617             channel_list[idx] = (uint16)str[0];
5618             DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx]));
5619         }
5620         *bytes_left -= 1;
5621         str += 1;
5622 
5623         if (idx++ > 0xFF) {
5624             DHD_ERROR(("%s Too many channels \n", __FUNCTION__));
5625             return -1;
5626         }
5627     }
5628 
5629     *list_str = str;
5630     return idx;
5631 }
5632 
5633 /* Parse a comma-separated list from list_str into ssid array, starting
5634  * at index idx.  Max specifies size of the ssid array.  Parses ssids
5635  * and returns updated idx; if idx >= max not all fit, the excess have
5636  * not been copied.  Returns -1 on empty string, or on ssid too long.
5637  */
wl_iw_parse_ssid_list(char ** list_str,wlc_ssid_t * ssid,int idx,int max)5638 int wl_iw_parse_ssid_list(char **list_str, wlc_ssid_t *ssid, int idx, int max)
5639 {
5640     char *str, *ptr;
5641 
5642     if ((list_str == NULL) || (*list_str == NULL)) {
5643         return -1;
5644     }
5645 
5646     for (str = *list_str; str != NULL; str = ptr) {
5647         /* check for next TAG */
5648         if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) {
5649             *list_str = str + strlen(GET_CHANNEL);
5650             return idx;
5651         }
5652 
5653         if ((ptr = strchr(str, ',')) != NULL) {
5654             *ptr++ = '\0';
5655         }
5656 
5657         if (strlen(str) > DOT11_MAX_SSID_LEN) {
5658             DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN));
5659             return -1;
5660         }
5661 
5662         if (strlen(str) == 0) {
5663             ssid[idx].SSID_len = 0;
5664         }
5665 
5666         if (idx < max) {
5667             bzero(ssid[idx].SSID, sizeof(ssid[idx].SSID));
5668             strncpy((char *)ssid[idx].SSID, str, sizeof(ssid[idx].SSID) - 1);
5669             ssid[idx].SSID_len = strlen(str);
5670         }
5671         idx++;
5672     }
5673     return idx;
5674 }
5675 
5676 /*
5677  * Parse channel list from iwpriv CSCAN
5678  */
wl_iw_parse_channel_list(char ** list_str,uint16 * channel_list,int channel_num)5679 int wl_iw_parse_channel_list(char **list_str, uint16 *channel_list,
5680                              int channel_num)
5681 {
5682     int num;
5683     int val;
5684     char *str;
5685     char *endptr = NULL;
5686 
5687     if ((list_str == NULL) || (*list_str == NULL)) {
5688         return -1;
5689     }
5690 
5691     str = *list_str;
5692     num = 0;
5693     while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) {
5694         val = (int)strtoul(str, &endptr, 0);
5695         if (endptr == str) {
5696             printf("could not parse channel number starting at"
5697                    " substring \"%s\" in list:\n%s\n",
5698                    str, *list_str);
5699             return -1;
5700         }
5701         str = endptr + strspn(endptr, " ,");
5702 
5703         if (num == channel_num) {
5704             DHD_ERROR(
5705                 ("too many channels (more than %d) in channel list:\n%s\n",
5706                  channel_num, *list_str));
5707             return -1;
5708         }
5709 
5710         channel_list[num++] = (uint16)val;
5711     }
5712     *list_str = str;
5713     return num;
5714 }
5715 #endif
5716 
5717 /* Given filename and download type,  returns a buffer pointer and length
5718  * for download to f/w. Type can be FW or NVRAM.
5719  *
5720  */
dhd_get_download_buffer(dhd_pub_t * dhd,char * file_path,download_type_t component,char ** buffer,int * length)5721 int dhd_get_download_buffer(dhd_pub_t *dhd, char *file_path,
5722                             download_type_t component, char **buffer,
5723                             int *length)
5724 
5725 {
5726     int ret = BCME_ERROR;
5727     int len = 0;
5728     int file_len;
5729     void *image = NULL;
5730     uint8 *buf = NULL;
5731 
5732     /* Point to cache if available. */
5733     /* No Valid cache found on this call */
5734     if (!len) {
5735         file_len = *length;
5736         *length = 0;
5737 
5738         if (file_path) {
5739             image = dhd_os_open_image1(dhd, file_path);
5740             if (image == NULL) {
5741                 printf("%s: Open image file failed %s\n", __FUNCTION__,
5742                        file_path);
5743                 goto err;
5744             }
5745         }
5746 
5747         buf = MALLOCZ(dhd->osh, file_len);
5748         if (buf == NULL) {
5749             DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__,
5750                        file_len));
5751             goto err;
5752         }
5753 
5754         /* Download image */
5755         len = dhd_os_get_image_block((char *)buf, file_len, image);
5756         if ((len <= 0 || len > file_len)) {
5757             MFREE(dhd->osh, buf, file_len);
5758             goto err;
5759         }
5760     }
5761 
5762     ret = BCME_OK;
5763     *length = len;
5764     *buffer = (char *)buf;
5765 
5766     /* Cache if first call. */
5767 
5768 err:
5769     if (image) {
5770         dhd_os_close_image1(dhd, image);
5771     }
5772 
5773     return ret;
5774 }
5775 
dhd_download_2_dongle(dhd_pub_t * dhd,char * iovar,uint16 flag,uint16 dload_type,unsigned char * dload_buf,int len)5776 int dhd_download_2_dongle(dhd_pub_t *dhd, char *iovar, uint16 flag,
5777                           uint16 dload_type, unsigned char *dload_buf, int len)
5778 {
5779     struct wl_dload_data *dload_ptr = (struct wl_dload_data *)dload_buf;
5780     int err = 0;
5781     int dload_data_offset;
5782     static char iovar_buf[WLC_IOCTL_MEDLEN];
5783     int iovar_len;
5784 
5785     memset(iovar_buf, 0, sizeof(iovar_buf));
5786 
5787     dload_data_offset = OFFSETOF(wl_dload_data_t, data);
5788     dload_ptr->flag = (DLOAD_HANDLER_VER << DLOAD_FLAG_VER_SHIFT) | flag;
5789     dload_ptr->dload_type = dload_type;
5790     dload_ptr->len = htod32(len - dload_data_offset);
5791     dload_ptr->crc = 0;
5792     len = ROUNDUP(len, 0x8);
5793 
5794     iovar_len = bcm_mkiovar(iovar, (char *)dload_buf, (uint)len, iovar_buf,
5795                             sizeof(iovar_buf));
5796     if (iovar_len == 0) {
5797         DHD_ERROR(
5798             ("%s: insufficient buffer space passed to bcm_mkiovar for '%s' \n",
5799              __FUNCTION__, iovar));
5800         return BCME_BUFTOOSHORT;
5801     }
5802 
5803     err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovar_buf, iovar_len, IOV_SET, 0);
5804 
5805     return err;
5806 }
5807 
dhd_download_blob(dhd_pub_t * dhd,unsigned char * buf,uint32 len,char * iovar)5808 int dhd_download_blob(dhd_pub_t *dhd, unsigned char *buf, uint32 len,
5809                       char *iovar)
5810 
5811 {
5812     int chunk_len;
5813     int size2alloc;
5814     unsigned char *new_buf;
5815     int err = 0, data_offset;
5816     uint16 dl_flag = DL_BEGIN;
5817 
5818     data_offset = OFFSETOF(wl_dload_data_t, data);
5819     size2alloc = data_offset + MAX_CHUNK_LEN;
5820     size2alloc = ROUNDUP(size2alloc, 0x8);
5821     if ((new_buf = (unsigned char *)MALLOCZ(dhd->osh, size2alloc)) != NULL) {
5822         do {
5823             chunk_len = dhd_os_get_image_block((char *)(new_buf + data_offset),
5824                                                MAX_CHUNK_LEN, buf);
5825             if (chunk_len < 0) {
5826                 DHD_ERROR(("%s: dhd_os_get_image_block failed (%d)\n",
5827                            __FUNCTION__, chunk_len));
5828                 err = BCME_ERROR;
5829                 goto exit;
5830             }
5831             if (len - chunk_len == 0) {
5832                 dl_flag |= DL_END;
5833             }
5834 
5835             err = dhd_download_2_dongle(dhd, iovar, dl_flag, DL_TYPE_CLM,
5836                                         new_buf, data_offset + chunk_len);
5837 
5838             dl_flag &= ~DL_BEGIN;
5839 
5840             len = len - chunk_len;
5841         } while ((len > 0) && (err == 0));
5842     } else {
5843         err = BCME_NOMEM;
5844     }
5845 exit:
5846     if (new_buf) {
5847         MFREE(dhd->osh, new_buf, size2alloc);
5848     }
5849     return err;
5850 }
5851 
dhd_apply_default_txcap(dhd_pub_t * dhd,char * path)5852 int dhd_apply_default_txcap(dhd_pub_t *dhd, char *path)
5853 {
5854     return 0;
5855 }
5856 
dhd_check_current_clm_data(dhd_pub_t * dhd)5857 int dhd_check_current_clm_data(dhd_pub_t *dhd)
5858 {
5859     char iovbuf[WLC_IOCTL_SMLEN];
5860     wl_country_t *cspec;
5861     int err = BCME_OK;
5862 
5863     memset(iovbuf, 0, sizeof(iovbuf));
5864     err = bcm_mkiovar("country", NULL, 0, iovbuf, sizeof(iovbuf));
5865     if (err == 0) {
5866         err = BCME_BUFTOOSHORT;
5867         DHD_ERROR(("%s: bcm_mkiovar failed.", __FUNCTION__));
5868         return err;
5869     }
5870     err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0);
5871     if (err) {
5872         DHD_ERROR(("%s: country code get failed\n", __FUNCTION__));
5873         return err;
5874     }
5875     cspec = (wl_country_t *)iovbuf;
5876     if ((strncmp(cspec->ccode, WL_CCODE_NULL_COUNTRY, WLC_CNTRY_BUF_SZ)) == 0) {
5877         DHD_ERROR(("%s: ----- This FW is not included CLM data -----\n",
5878                    __FUNCTION__));
5879         return FALSE;
5880     }
5881     DHD_ERROR(("%s: ----- This FW is included CLM data -----\n", __FUNCTION__));
5882     return TRUE;
5883 }
5884 
dhd_apply_default_clm(dhd_pub_t * dhd,char * clm_path)5885 int dhd_apply_default_clm(dhd_pub_t *dhd, char *clm_path)
5886 {
5887     char *clm_blob_path;
5888     int len;
5889     char *memblock = NULL;
5890     int err = BCME_OK;
5891     char iovbuf[WLC_IOCTL_SMLEN];
5892     int status = FALSE;
5893 
5894     if (clm_path && clm_path[0] != '\0') {
5895         if (strlen(clm_path) > MOD_PARAM_PATHLEN) {
5896             DHD_ERROR(("clm path exceeds max len\n"));
5897             return BCME_ERROR;
5898         }
5899         clm_blob_path = clm_path;
5900         DHD_TRACE(("clm path from module param:%s\n", clm_path));
5901     } else {
5902         clm_blob_path = VENDOR_PATH CONFIG_BCMDHD_CLM_PATH;
5903     }
5904 
5905     /* If CLM blob file is found on the filesystem, download the file.
5906      * After CLM file download or If the blob file is not present,
5907      * validate the country code before proceeding with the initialization.
5908      * If country code is not valid, fail the initialization.
5909      */
5910     memblock = dhd_os_open_image1(dhd, (char *)clm_blob_path);
5911     if (memblock == NULL) {
5912         printf("%s: Ignore clm file %s\n", __FUNCTION__, clm_path);
5913 #if defined(DHD_BLOB_EXISTENCE_CHECK)
5914         if (dhd->is_blob) {
5915             err = BCME_ERROR;
5916         } else {
5917             status = dhd_check_current_clm_data(dhd);
5918             if (status == TRUE) {
5919                 err = BCME_OK;
5920             } else {
5921                 err = status;
5922             }
5923         }
5924 #endif /* DHD_BLOB_EXISTENCE_CHECK */
5925         goto exit;
5926     }
5927 
5928     len = dhd_os_get_image_size(memblock);
5929     if ((len > 0) && (len < MAX_CLM_BUF_SIZE) && memblock) {
5930         status = dhd_check_current_clm_data(dhd);
5931         if (status == TRUE) {
5932 #if defined(DHD_BLOB_EXISTENCE_CHECK)
5933             if (dhd->op_mode != DHD_FLAG_MFG_MODE) {
5934                 if (dhd->is_blob) {
5935                     err = BCME_ERROR;
5936                 }
5937                 goto exit;
5938             }
5939 #else
5940             DHD_ERROR((
5941                 "%s: CLM already exist in F/W, "
5942                 "new CLM data will be added to the end of existing CLM data!\n",
5943                 __FUNCTION__));
5944 #endif /* DHD_BLOB_EXISTENCE_CHECK */
5945         } else if (status != FALSE) {
5946             err = status;
5947             goto exit;
5948         }
5949 
5950         /* Found blob file. Download the file */
5951         DHD_TRACE(("clm file download from %s \n", clm_blob_path));
5952         err = dhd_download_blob(dhd, (unsigned char *)memblock, len, "clmload");
5953         if (err) {
5954             DHD_ERROR(("%s: CLM download failed err=%d\n", __FUNCTION__, err));
5955             /* Retrieve clmload_status and print */
5956             memset(iovbuf, 0, sizeof(iovbuf));
5957             len =
5958                 bcm_mkiovar("clmload_status", NULL, 0, iovbuf, sizeof(iovbuf));
5959             if (len == 0) {
5960                 err = BCME_BUFTOOSHORT;
5961                 goto exit;
5962             }
5963             err = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf),
5964                                    FALSE, 0);
5965             if (err) {
5966                 DHD_ERROR(("%s: clmload_status get failed err=%d \n",
5967                            __FUNCTION__, err));
5968             } else {
5969                 DHD_ERROR(("%s: clmload_status: %d \n", __FUNCTION__,
5970                            *((int *)iovbuf)));
5971                 if (*((int *)iovbuf) == CHIPID_MISMATCH) {
5972                     DHD_ERROR(("Chip ID mismatch error \n"));
5973                 }
5974             }
5975             err = BCME_ERROR;
5976             goto exit;
5977         } else {
5978             DHD_INFO(("%s: CLM download succeeded \n", __FUNCTION__));
5979         }
5980     } else {
5981         DHD_INFO(
5982             ("Skipping the clm download. len:%d memblk:%p \n", len, memblock));
5983     }
5984     /* Verify country code */
5985     status = dhd_check_current_clm_data(dhd);
5986     if (status != TRUE) {
5987         /* Country code not initialized or CLM download not proper */
5988         DHD_ERROR(("country code not initialized\n"));
5989         err = status;
5990     }
5991 exit:
5992 
5993     if (memblock) {
5994         dhd_os_close_image1(dhd, memblock);
5995     }
5996 
5997     return err;
5998 }
5999 
dhd_free_download_buffer(dhd_pub_t * dhd,void * buffer,int length)6000 void dhd_free_download_buffer(dhd_pub_t *dhd, void *buffer, int length)
6001 {
6002     MFREE(dhd->osh, buffer, length);
6003 }
6004 
6005 #ifdef SHOW_LOGTRACE
dhd_parse_logstrs_file(osl_t * osh,char * raw_fmts,int logstrs_size,dhd_event_log_t * event_log)6006 int dhd_parse_logstrs_file(osl_t *osh, char *raw_fmts, int logstrs_size,
6007                            dhd_event_log_t *event_log)
6008 {
6009     uint32 *lognums = NULL;
6010     char *logstrs = NULL;
6011     logstr_trailer_t *trailer = NULL;
6012     int ram_index = 0;
6013     char **fmts = NULL;
6014     int num_fmts = 0;
6015     bool match_fail = TRUE;
6016     int32 i = 0;
6017     uint8 *pfw_id = NULL;
6018     uint32 fwid = 0;
6019     void *file = NULL;
6020     int file_len = 0;
6021     char fwid_str[FWID_STR_LEN];
6022     uint32 hdr_logstrs_size = 0;
6023 
6024     /* Read last three words in the logstrs.bin file */
6025     trailer = (logstr_trailer_t *)(raw_fmts + logstrs_size -
6026                                    sizeof(logstr_trailer_t));
6027 
6028     if (trailer->log_magic == LOGSTRS_MAGIC) {
6029         /*
6030          * logstrs.bin has a header.
6031          */
6032         if (trailer->version == 1) {
6033             logstr_header_v1_t *hdr_v1 =
6034                 (logstr_header_v1_t *)(raw_fmts + logstrs_size -
6035                                        sizeof(logstr_header_v1_t));
6036             DHD_INFO(("%s: logstr header version = %u\n", __FUNCTION__,
6037                       hdr_v1->version));
6038             num_fmts = hdr_v1->rom_logstrs_offset / sizeof(uint32);
6039             ram_index =
6040                 (hdr_v1->ram_lognums_offset - hdr_v1->rom_lognums_offset) /
6041                 sizeof(uint32);
6042             lognums = (uint32 *)&raw_fmts[hdr_v1->rom_lognums_offset];
6043             logstrs = (char *)&raw_fmts[hdr_v1->rom_logstrs_offset];
6044             hdr_logstrs_size = hdr_v1->logstrs_size;
6045         } else if (trailer->version == 0x2) {
6046             logstr_header_t *hdr = (logstr_header_t *)(raw_fmts + logstrs_size -
6047                                                        sizeof(logstr_header_t));
6048             DHD_INFO(("%s: logstr header version = %u; flags = %x\n",
6049                       __FUNCTION__, hdr->trailer.version, hdr->trailer.flags));
6050 
6051             /* For ver. 2 of the header, need to match fwid of
6052              *  both logstrs.bin and fw bin
6053              */
6054 
6055             /* read the FWID from fw bin */
6056             file = dhd_os_open_image1(NULL, st_str_file_path);
6057             if (!file) {
6058                 DHD_ERROR(("%s: cannot open fw file !\n", __FUNCTION__));
6059                 goto error;
6060             }
6061             file_len = dhd_os_get_image_size(file);
6062             if (file_len <= 0) {
6063                 DHD_ERROR(("%s: bad fw file length !\n", __FUNCTION__));
6064                 goto error;
6065             }
6066             /* fwid is at the end of fw bin in string format */
6067             if (dhd_os_seek_file(file, file_len - (sizeof(fwid_str) - 1)) < 0) {
6068                 DHD_ERROR(("%s: can't seek file \n", __FUNCTION__));
6069                 goto error;
6070             }
6071 
6072             memset(fwid_str, 0, sizeof(fwid_str));
6073             if (dhd_os_get_image_block(fwid_str, sizeof(fwid_str) - 1, file) <=
6074                 0) {
6075                 DHD_ERROR(("%s: read fw file failed !\n", __FUNCTION__));
6076                 goto error;
6077             }
6078             pfw_id = (uint8 *)bcmstrnstr(fwid_str, sizeof(fwid_str) - 1,
6079                                          FWID_STR_1, strlen(FWID_STR_1));
6080             if (!pfw_id) {
6081                 pfw_id = (uint8 *)bcmstrnstr(fwid_str, sizeof(fwid_str) - 1,
6082                                              FWID_STR_2, strlen(FWID_STR_2));
6083                 if (!pfw_id) {
6084                     DHD_ERROR(
6085                         ("%s: could not find id in FW bin!\n", __FUNCTION__));
6086                     goto error;
6087                 }
6088             }
6089             /* search for the '-' in the fw id str, after which the
6090              * actual 4 byte fw id is present
6091              */
6092             while (pfw_id && *pfw_id != '-') {
6093                 ++pfw_id;
6094             }
6095             ++pfw_id;
6096             fwid = bcm_strtoul((char *)pfw_id, NULL, 0x10);
6097             /* check if fw id in logstrs.bin matches the fw one */
6098             if (hdr->trailer.fw_id != fwid) {
6099                 DHD_ERROR(("%s: logstr id does not match FW!"
6100                            "logstrs_fwid:0x%x, rtecdc_fwid:0x%x\n",
6101                            __FUNCTION__, hdr->trailer.fw_id, fwid));
6102                 goto error;
6103             }
6104 
6105             match_fail = FALSE;
6106             num_fmts = hdr->rom_logstrs_offset / sizeof(uint32);
6107             ram_index = (hdr->ram_lognums_offset - hdr->rom_lognums_offset) /
6108                         sizeof(uint32);
6109             lognums = (uint32 *)&raw_fmts[hdr->rom_lognums_offset];
6110             logstrs = (char *)&raw_fmts[hdr->rom_logstrs_offset];
6111             hdr_logstrs_size = hdr->logstrs_size;
6112 
6113         error:
6114             if (file) {
6115                 dhd_os_close_image1(NULL, file);
6116             }
6117             if (match_fail) {
6118                 return BCME_DECERR;
6119             }
6120         } else {
6121             DHD_ERROR(("%s: Invalid logstr version %u\n", __FUNCTION__,
6122                        trailer->version));
6123             return BCME_ERROR;
6124         }
6125         if (logstrs_size != hdr_logstrs_size) {
6126             DHD_ERROR(
6127                 ("%s: bad logstrs_size %d\n", __FUNCTION__, hdr_logstrs_size));
6128             return BCME_ERROR;
6129         }
6130     } else {
6131         /*
6132          * Legacy logstrs.bin format without header.
6133          */
6134         num_fmts = *((uint32 *)(raw_fmts)) / sizeof(uint32);
6135 
6136         /* Legacy RAM-only logstrs.bin format:
6137          *	  - RAM 'lognums' section
6138          *	  - RAM 'logstrs' section.
6139          *
6140          * 'lognums' is an array of indexes for the strings in the
6141          * 'logstrs' section. The first uint32 is an index to the
6142          * start of 'logstrs'. Therefore, if this index is divided
6143          * by 'sizeof(uint32)' it provides the number of logstr
6144          *	entries.
6145          */
6146         ram_index = 0;
6147         lognums = (uint32 *)raw_fmts;
6148         logstrs = (char *)&raw_fmts[num_fmts << 0x2];
6149     }
6150     if (num_fmts) {
6151         fmts = MALLOC(osh, num_fmts * sizeof(char *));
6152     }
6153     if (fmts == NULL) {
6154         DHD_ERROR(("%s: Failed to allocate fmts memory\n", __FUNCTION__));
6155         return BCME_ERROR;
6156     }
6157     event_log->fmts_size = num_fmts * sizeof(char *);
6158 
6159     for (i = 0; i < num_fmts; i++) {
6160         /* ROM lognums index into logstrs using 'rom_logstrs_offset' as a base
6161          * (they are 0-indexed relative to 'rom_logstrs_offset').
6162          *
6163          * RAM lognums are already indexed to point to the correct RAM logstrs
6164          * (they are 0-indexed relative to the start of the logstrs.bin file).
6165          */
6166         if (i == ram_index) {
6167             logstrs = raw_fmts;
6168         }
6169         fmts[i] = &logstrs[lognums[i]];
6170     }
6171     event_log->fmts = fmts;
6172     event_log->raw_fmts_size = logstrs_size;
6173     event_log->raw_fmts = raw_fmts;
6174     event_log->num_fmts = num_fmts;
6175     return BCME_OK;
6176 } /* dhd_parse_logstrs_file */
6177 
dhd_parse_map_file(osl_t * osh,void * file,uint32 * ramstart,uint32 * rodata_start,uint32 * rodata_end)6178 int dhd_parse_map_file(osl_t *osh, void *file, uint32 *ramstart,
6179                        uint32 *rodata_start, uint32 *rodata_end)
6180 {
6181     char *raw_fmts = NULL, *raw_fmts_loc = NULL;
6182     uint32 read_size = READ_NUM_BYTES;
6183     int error = 0;
6184     char *cptr = NULL;
6185     char c;
6186     uint8 count = 0;
6187 
6188     *ramstart = 0;
6189     *rodata_start = 0;
6190     *rodata_end = 0;
6191 
6192     /* Allocate 1 byte more than read_size to terminate it with NULL */
6193     raw_fmts = MALLOCZ(osh, read_size + 1);
6194     if (raw_fmts == NULL) {
6195         DHD_ERROR(("%s: Failed to allocate raw_fmts memory \n", __FUNCTION__));
6196         goto fail;
6197     }
6198 
6199     /* read ram start, rodata_start and rodata_end values from map  file */
6200     while (count != ALL_MAP_VAL) {
6201         error = dhd_os_read_file(file, raw_fmts, read_size);
6202         if (error < 0) {
6203             DHD_ERROR(
6204                 ("%s: map file read failed err:%d \n", __FUNCTION__, error));
6205             goto fail;
6206         }
6207 
6208         /* End raw_fmts with NULL as strstr expects NULL terminated strings */
6209         raw_fmts[read_size] = '\0';
6210 
6211         /* Get ramstart address */
6212         raw_fmts_loc = raw_fmts;
6213         if (!(count & RAMSTART_BIT) &&
6214             (cptr = bcmstrnstr(raw_fmts_loc, read_size, ramstart_str,
6215                                strlen(ramstart_str)))) {
6216             cptr = cptr - BYTES_AHEAD_NUM;
6217             sscanf(cptr, "%x %c text_start", ramstart, &c);
6218             count |= RAMSTART_BIT;
6219         }
6220 
6221         /* Get ram rodata start address */
6222         raw_fmts_loc = raw_fmts;
6223         if (!(count & RDSTART_BIT) &&
6224             (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_start_str,
6225                                strlen(rodata_start_str)))) {
6226             cptr = cptr - BYTES_AHEAD_NUM;
6227             sscanf(cptr, "%x %c rodata_start", rodata_start, &c);
6228             count |= RDSTART_BIT;
6229         }
6230 
6231         /* Get ram rodata end address */
6232         raw_fmts_loc = raw_fmts;
6233         if (!(count & RDEND_BIT) &&
6234             (cptr = bcmstrnstr(raw_fmts_loc, read_size, rodata_end_str,
6235                                strlen(rodata_end_str)))) {
6236             cptr = cptr - BYTES_AHEAD_NUM;
6237             sscanf(cptr, "%x %c rodata_end", rodata_end, &c);
6238             count |= RDEND_BIT;
6239         }
6240 
6241         if (error < (int)read_size) {
6242             /*
6243              * since we reset file pos back to earlier pos by
6244              * GO_BACK_FILE_POS_NUM_BYTES bytes we won't reach EOF.
6245              * The reason for this is if string is spreaded across
6246              * bytes, the read function should not miss it.
6247              * So if ret value is less than read_size, reached EOF don't read
6248              * further
6249              */
6250             break;
6251         }
6252         memset(raw_fmts, 0, read_size);
6253         /*
6254          * go back to predefined NUM of bytes so that we won't miss
6255          * the string and  addr even if it comes as splited in next read.
6256          */
6257         dhd_os_seek_file(file, -GO_BACK_FILE_POS_NUM_BYTES);
6258     }
6259 
6260 fail:
6261     if (raw_fmts) {
6262         MFREE(osh, raw_fmts, read_size + 1);
6263         raw_fmts = NULL;
6264     }
6265     if (count == ALL_MAP_VAL) {
6266         return BCME_OK;
6267     } else {
6268         DHD_ERROR(("%s: readmap error 0X%x \n", __FUNCTION__, count));
6269         return BCME_ERROR;
6270     }
6271 } /* dhd_parse_map_file */
6272 
6273 #ifdef PCIE_FULL_DONGLE
dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t * dhdp,void * pktbuf,dhd_event_log_t * event_data)6274 int dhd_event_logtrace_infobuf_pkt_process(dhd_pub_t *dhdp, void *pktbuf,
6275                                            dhd_event_log_t *event_data)
6276 {
6277     uint32 infobuf_version;
6278     info_buf_payload_hdr_t *payload_hdr_ptr;
6279     uint16 payload_hdr_type;
6280     uint16 payload_hdr_length;
6281 
6282     DHD_TRACE(("%s:Enter\n", __FUNCTION__));
6283 
6284     if (PKTLEN(dhdp->osh, pktbuf) < sizeof(uint32)) {
6285         DHD_ERROR(("%s: infobuf too small for version field\n", __FUNCTION__));
6286         goto exit;
6287     }
6288     infobuf_version = *((uint32 *)PKTDATA(dhdp->osh, pktbuf));
6289     PKTPULL(dhdp->osh, pktbuf, sizeof(uint32));
6290     if (infobuf_version != PCIE_INFOBUF_V1) {
6291         DHD_ERROR(("%s: infobuf version %d is not PCIE_INFOBUF_V1\n",
6292                    __FUNCTION__, infobuf_version));
6293         goto exit;
6294     }
6295 
6296     /* Version 1 infobuf has a single type/length (and then value) field */
6297     if (PKTLEN(dhdp->osh, pktbuf) < sizeof(info_buf_payload_hdr_t)) {
6298         DHD_ERROR(("%s: infobuf too small for v1 type/length  fields\n",
6299                    __FUNCTION__));
6300         goto exit;
6301     }
6302     /* Process/parse the common info payload header (type/length) */
6303     payload_hdr_ptr = (info_buf_payload_hdr_t *)PKTDATA(dhdp->osh, pktbuf);
6304     payload_hdr_type = ltoh16(payload_hdr_ptr->type);
6305     payload_hdr_length = ltoh16(payload_hdr_ptr->length);
6306     if (payload_hdr_type != PCIE_INFOBUF_V1_TYPE_LOGTRACE) {
6307         DHD_ERROR(("%s: payload_hdr_type %d is not V1_TYPE_LOGTRACE\n",
6308                    __FUNCTION__, payload_hdr_type));
6309         goto exit;
6310     }
6311     PKTPULL(dhdp->osh, pktbuf, sizeof(info_buf_payload_hdr_t));
6312 
6313     /* Validate that the specified length isn't bigger than the
6314      * provided data.
6315      */
6316     if (payload_hdr_length > PKTLEN(dhdp->osh, pktbuf)) {
6317         DHD_ERROR(("%s: infobuf logtrace length is bigger"
6318                    " than actual buffer data\n",
6319                    __FUNCTION__));
6320         goto exit;
6321     }
6322     dhd_dbg_trace_evnt_handler(dhdp, PKTDATA(dhdp->osh, pktbuf), event_data,
6323                                payload_hdr_length);
6324 
6325     return BCME_OK;
6326 
6327 exit:
6328     return BCME_ERROR;
6329 } /* dhd_event_logtrace_infobuf_pkt_process */
6330 #endif /* PCIE_FULL_DONGLE */
6331 #endif /* SHOW_LOGTRACE */
6332 
6333 #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE)
6334 
6335 /* To handle the TDLS event in the dhd_common.c
6336  */
dhd_tdls_event_handler(dhd_pub_t * dhd_pub,wl_event_msg_t * event)6337 int dhd_tdls_event_handler(dhd_pub_t *dhd_pub, wl_event_msg_t *event)
6338 {
6339     int ret = BCME_OK;
6340 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
6341 #pragma GCC diagnostic push
6342 #pragma GCC diagnostic ignored "-Wcast-qual"
6343 #endif // endif
6344     ret = dhd_tdls_update_peer_info(dhd_pub, event);
6345 #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
6346 #pragma GCC diagnostic pop
6347 #endif // endif
6348     return ret;
6349 }
6350 
dhd_free_tdls_peer_list(dhd_pub_t * dhd_pub)6351 int dhd_free_tdls_peer_list(dhd_pub_t *dhd_pub)
6352 {
6353     tdls_peer_node_t *cur = NULL, *prev = NULL;
6354     if (!dhd_pub) {
6355         return BCME_ERROR;
6356     }
6357     cur = dhd_pub->peer_tbl.node;
6358 
6359     if ((dhd_pub->peer_tbl.node == NULL) &&
6360         !dhd_pub->peer_tbl.tdls_peer_count) {
6361         return BCME_ERROR;
6362     }
6363 
6364     while (cur != NULL) {
6365         prev = cur;
6366         cur = cur->next;
6367         MFREE(dhd_pub->osh, prev, sizeof(tdls_peer_node_t));
6368     }
6369     dhd_pub->peer_tbl.tdls_peer_count = 0;
6370     dhd_pub->peer_tbl.node = NULL;
6371     return BCME_OK;
6372 }
6373 #endif /* #if defined(WLTDLS) && defined(PCIE_FULL_DONGLE) */
6374 
6375 /* pretty hex print a contiguous buffer
6376  * based on the debug level specified
6377  */
dhd_prhex(const char * msg,volatile uchar * buf,uint nbytes,uint8 dbg_level)6378 void dhd_prhex(const char *msg, volatile uchar *buf, uint nbytes,
6379                uint8 dbg_level)
6380 {
6381     char line[128], *p;
6382     int len = sizeof(line);
6383     int nchar;
6384     uint i;
6385 
6386     if (msg && (msg[0] != '\0')) {
6387         if (dbg_level == DHD_ERROR_VAL) {
6388             DHD_ERROR(("%s:\n", msg));
6389         } else if (dbg_level == DHD_INFO_VAL) {
6390             DHD_INFO(("%s:\n", msg));
6391         } else if (dbg_level == DHD_TRACE_VAL) {
6392             DHD_TRACE(("%s:\n", msg));
6393         }
6394     }
6395 
6396     p = line;
6397     for (i = 0; i < nbytes; i++) {
6398         if (i % 0x10 == 0) {
6399             nchar = snprintf(p, len, "  %04x: ", i); /* line prefix */
6400             p += nchar;
6401             len -= nchar;
6402         }
6403         if (len > 0) {
6404             nchar = snprintf(p, len, "%02x ", buf[i]);
6405             p += nchar;
6406             len -= nchar;
6407         }
6408 
6409         if (i % 0x10 == 0xF) {
6410             /* flush line */
6411             if (dbg_level == DHD_ERROR_VAL) {
6412                 DHD_ERROR(("%s:\n", line));
6413             } else if (dbg_level == DHD_INFO_VAL) {
6414                 DHD_INFO(("%s:\n", line));
6415             } else if (dbg_level == DHD_TRACE_VAL) {
6416                 DHD_TRACE(("%s:\n", line));
6417             }
6418             p = line;
6419             len = sizeof(line);
6420         }
6421     }
6422 
6423     /* flush last partial line */
6424     if (p != line) {
6425         if (dbg_level == DHD_ERROR_VAL) {
6426             DHD_ERROR(("%s:\n", line));
6427         } else if (dbg_level == DHD_INFO_VAL) {
6428             DHD_INFO(("%s:\n", line));
6429         } else if (dbg_level == DHD_TRACE_VAL) {
6430             DHD_TRACE(("%s:\n", line));
6431         }
6432     }
6433 }
6434 
6435 #ifdef DUMP_IOCTL_IOV_LIST
dhd_iov_li_append(dhd_pub_t * dhd,dll_t * list_head,dll_t * node)6436 void dhd_iov_li_append(dhd_pub_t *dhd, dll_t *list_head, dll_t *node)
6437 {
6438     dll_t *item;
6439     dhd_iov_li_t *iov_li;
6440     dhd->dump_iovlist_len++;
6441 
6442     if (dhd->dump_iovlist_len == IOV_LIST_MAX_LEN + 1) {
6443         item = dll_head_p(list_head);
6444         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
6445         dll_delete(item);
6446         MFREE(dhd->osh, iov_li, sizeof(*iov_li));
6447         dhd->dump_iovlist_len--;
6448     }
6449     dll_append(list_head, node);
6450 }
6451 
dhd_iov_li_print(dll_t * list_head)6452 void dhd_iov_li_print(dll_t *list_head)
6453 {
6454     dhd_iov_li_t *iov_li;
6455     dll_t *item, *next;
6456     uint8 index = 0;
6457     for (item = dll_head_p(list_head); !dll_end(list_head, item); item = next) {
6458         next = dll_next_p(item);
6459         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
6460         DHD_ERROR(("%d:cmd_name = %s, cmd = %d.\n", ++index, iov_li->buff,
6461                    iov_li->cmd));
6462     }
6463 }
6464 
dhd_iov_li_delete(dhd_pub_t * dhd,dll_t * list_head)6465 void dhd_iov_li_delete(dhd_pub_t *dhd, dll_t *list_head)
6466 {
6467     dll_t *item;
6468     dhd_iov_li_t *iov_li;
6469     while (!(dll_empty(list_head))) {
6470         item = dll_head_p(list_head);
6471         iov_li = (dhd_iov_li_t *)CONTAINEROF(item, dhd_iov_li_t, list);
6472         dll_delete(item);
6473         MFREE(dhd->osh, iov_li, sizeof(*iov_li));
6474     }
6475 }
6476 #endif /* DUMP_IOCTL_IOV_LIST */
6477 
6478 /* configuations of ecounters to be enabled by default in FW */
6479 static ecounters_cfg_t ecounters_cfg_tbl[] = {
6480     /* Global ecounters */
6481     {ECOUNTERS_STATS_TYPES_FLAG_GLOBAL, 0x0, WL_IFSTATS_XTLV_BUS_PCIE},
6482 
6483     /* Slice specific ecounters */
6484     {ECOUNTERS_STATS_TYPES_FLAG_SLICE, 0x0, WL_SLICESTATS_XTLV_PERIODIC_STATE},
6485     {ECOUNTERS_STATS_TYPES_FLAG_SLICE, 0x1, WL_SLICESTATS_XTLV_PERIODIC_STATE},
6486     {ECOUNTERS_STATS_TYPES_FLAG_SLICE, 0x1, WL_IFSTATS_XTLV_WL_SLICE_BTCOEX},
6487 
6488     /* Interface specific ecounters */
6489     {ECOUNTERS_STATS_TYPES_FLAG_IFACE, 0x0, WL_IFSTATS_XTLV_IF_PERIODIC_STATE},
6490     {ECOUNTERS_STATS_TYPES_FLAG_IFACE, 0x0, WL_IFSTATS_XTLV_GENERIC},
6491     {ECOUNTERS_STATS_TYPES_FLAG_IFACE, 0x0, WL_IFSTATS_XTLV_INFRA_SPECIFIC},
6492     {ECOUNTERS_STATS_TYPES_FLAG_IFACE, 0x0, WL_IFSTATS_XTLV_MGT_CNT},
6493 
6494     /* secondary interface */
6495 };
6496 
6497 static event_ecounters_cfg_t event_ecounters_cfg_tbl[] = {
6498     /* Interface specific event ecounters */
6499     {WLC_E_DEAUTH_IND, ECOUNTERS_STATS_TYPES_FLAG_IFACE, 0x0,
6500      WL_IFSTATS_XTLV_IF_EVENT_STATS},
6501 };
6502 
6503 /* Accepts an argument to -s, -g or -f and creates an XTLV */
dhd_create_ecounters_params(dhd_pub_t * dhd,uint16 type,uint16 if_slice_idx,uint16 stats_rep,uint8 ** xtlv)6504 int dhd_create_ecounters_params(dhd_pub_t *dhd, uint16 type,
6505                                 uint16 if_slice_idx, uint16 stats_rep,
6506                                 uint8 **xtlv)
6507 {
6508     uint8 *req_xtlv = NULL;
6509     ecounters_stats_types_report_req_t *req;
6510     bcm_xtlvbuf_t xtlvbuf, container_xtlvbuf;
6511     ecountersv2_xtlv_list_elt_t temp;
6512     uint16 xtlv_len = 0, total_len = 0;
6513     int rc = BCME_OK;
6514 
6515     /* fill in the stat type XTLV. For now there is no explicit TLV for the stat
6516      * type. */
6517     temp.id = stats_rep;
6518     temp.len = 0;
6519 
6520     /* Hence len/data = 0/NULL */
6521     xtlv_len += temp.len + BCM_XTLV_HDR_SIZE;
6522 
6523     /* Total length of the container */
6524     total_len = BCM_XTLV_HDR_SIZE +
6525                 OFFSETOF(ecounters_stats_types_report_req_t, stats_types_req) +
6526                 xtlv_len;
6527     /* Now allocate a structure for the entire request */
6528     if ((req_xtlv = (uint8 *)MALLOCZ(dhd->osh, total_len)) == NULL) {
6529         rc = BCME_NOMEM;
6530         goto fail;
6531     }
6532 
6533     /* container XTLV context */
6534     bcm_xtlv_buf_init(&container_xtlvbuf, (uint8 *)req_xtlv, total_len,
6535                       BCM_XTLV_OPTION_ALIGN32);
6536 
6537     /* Fill other XTLVs in the container. Leave space for XTLV headers */
6538     req = (ecounters_stats_types_report_req_t *)(req_xtlv + BCM_XTLV_HDR_SIZE);
6539     req->flags = type;
6540     if (type == ECOUNTERS_STATS_TYPES_FLAG_SLICE) {
6541         req->slice_mask = 0x1 << if_slice_idx;
6542     } else if (type == ECOUNTERS_STATS_TYPES_FLAG_IFACE) {
6543         req->if_index = if_slice_idx;
6544     }
6545 
6546     /* Fill remaining XTLVs */
6547     bcm_xtlv_buf_init(&xtlvbuf, (uint8 *)req->stats_types_req, xtlv_len,
6548                       BCM_XTLV_OPTION_ALIGN32);
6549     if (bcm_xtlv_put_data(&xtlvbuf, temp.id, NULL, temp.len)) {
6550         DHD_ERROR(
6551             ("Error creating XTLV for requested stats type = %d\n", temp.id));
6552         rc = BCME_ERROR;
6553         goto fail;
6554     }
6555 
6556     /* fill the top level container and get done with the XTLV container */
6557     rc = bcm_xtlv_put_data(
6558         &container_xtlvbuf, WL_ECOUNTERS_XTLV_REPORT_REQ, NULL,
6559         bcm_xtlv_buf_len(&xtlvbuf) +
6560             OFFSETOF(ecounters_stats_types_report_req_t, stats_types_req));
6561     if (rc) {
6562         DHD_ERROR(("Error creating parent XTLV for type = %d\n", req->flags));
6563         goto fail;
6564     }
6565 
6566 fail:
6567     if (rc && req_xtlv) {
6568         MFREE(dhd->osh, req_xtlv, total_len);
6569         req_xtlv = NULL;
6570     }
6571 
6572     /* update the xtlv pointer */
6573     *xtlv = req_xtlv;
6574     return rc;
6575 }
6576 
dhd_get_preserve_log_numbers(dhd_pub_t * dhd,uint32 * logset_mask)6577 int dhd_get_preserve_log_numbers(dhd_pub_t *dhd, uint32 *logset_mask)
6578 {
6579     wl_el_set_type_t logset_type, logset_op;
6580     int ret = BCME_ERROR;
6581     int i = 0, err = 0;
6582 
6583     if (!dhd || !logset_mask) {
6584         return BCME_BADARG;
6585     }
6586 
6587     *logset_mask = 0;
6588     memset(&logset_type, 0, sizeof(logset_type));
6589     memset(&logset_op, 0, sizeof(logset_op));
6590     logset_type.version = htod16(EVENT_LOG_SET_TYPE_CURRENT_VERSION);
6591     logset_type.len = htod16(sizeof(wl_el_set_type_t));
6592     for (i = 0; i < dhd->event_log_max_sets; i++) {
6593         logset_type.set = i;
6594         err = dhd_iovar(dhd, 0, "event_log_set_type", (char *)&logset_type,
6595                         sizeof(logset_type), (char *)&logset_op,
6596                         sizeof(logset_op), FALSE);
6597         /* the iovar may return 'unsupported' error if a log set number is not
6598          * present in the fw, so we should not return on error !
6599          */
6600         if (err == BCME_OK && logset_op.type == EVENT_LOG_SET_TYPE_PRSRV) {
6601             *logset_mask |= 0x01u << i;
6602             ret = BCME_OK;
6603             DHD_ERROR(("[INIT] logset:%d is preserve/chatty\n", i));
6604         }
6605     }
6606 
6607     return ret;
6608 }
6609 
dhd_ecounter_autoconfig(dhd_pub_t * dhd)6610 static int dhd_ecounter_autoconfig(dhd_pub_t *dhd)
6611 {
6612     int rc = BCME_OK;
6613     uint32 buf;
6614     rc = dhd_iovar(dhd, 0, "ecounters_autoconfig", NULL, 0, (char *)&buf,
6615                    sizeof(buf), FALSE);
6616     if (rc != BCME_OK) {
6617         if (rc != BCME_UNSUPPORTED) {
6618             rc = BCME_OK;
6619             DHD_ERROR(("%s Ecounter autoconfig in fw failed : %d\n",
6620                        __FUNCTION__, rc));
6621         } else {
6622             DHD_ERROR(
6623                 ("%s Ecounter autoconfig in FW not supported\n", __FUNCTION__));
6624         }
6625     }
6626 
6627     return rc;
6628 }
6629 
dhd_ecounter_configure(dhd_pub_t * dhd,bool enable)6630 int dhd_ecounter_configure(dhd_pub_t *dhd, bool enable)
6631 {
6632     int rc = BCME_OK;
6633     if (enable) {
6634         if (dhd_ecounter_autoconfig(dhd) != BCME_OK) {
6635             if ((rc = dhd_start_ecounters(dhd)) != BCME_OK) {
6636                 DHD_ERROR(("%s Ecounters start failed\n", __FUNCTION__));
6637             } else if ((rc = dhd_start_event_ecounters(dhd)) != BCME_OK) {
6638                 DHD_ERROR(("%s Event_Ecounters start failed\n", __FUNCTION__));
6639             }
6640         }
6641     } else {
6642         if ((rc = dhd_stop_ecounters(dhd)) != BCME_OK) {
6643             DHD_ERROR(("%s Ecounters stop failed\n", __FUNCTION__));
6644         } else if ((rc = dhd_stop_event_ecounters(dhd)) != BCME_OK) {
6645             DHD_ERROR(("%s Event_Ecounters stop failed\n", __FUNCTION__));
6646         }
6647     }
6648     return rc;
6649 }
6650 
dhd_start_ecounters(dhd_pub_t * dhd)6651 int dhd_start_ecounters(dhd_pub_t *dhd)
6652 {
6653     uint8 i = 0;
6654     uint8 *start_ptr;
6655     int rc = BCME_OK;
6656     bcm_xtlv_t *elt;
6657     ecounters_config_request_v2_t *req = NULL;
6658     ecountersv2_processed_xtlv_list_elt *list_elt, *tail = NULL;
6659     ecountersv2_processed_xtlv_list_elt *processed_containers_list = NULL;
6660     uint16 total_processed_containers_len = 0;
6661 
6662     for (i = 0; i < ARRAYSIZE(ecounters_cfg_tbl); i++) {
6663         ecounters_cfg_t *ecounter_stat = &ecounters_cfg_tbl[i];
6664 
6665         if ((list_elt = (ecountersv2_processed_xtlv_list_elt *)MALLOCZ(
6666                  dhd->osh, sizeof(*list_elt))) == NULL) {
6667             DHD_ERROR(("Ecounters v2: No memory to process\n"));
6668             goto fail;
6669         }
6670 
6671         rc = dhd_create_ecounters_params(
6672             dhd, ecounter_stat->type, ecounter_stat->if_slice_idx,
6673             ecounter_stat->stats_rep, &list_elt->data);
6674         if (rc) {
6675             DHD_ERROR(
6676                 ("Ecounters v2: Could not process: stat: %d return code: %d\n",
6677                  ecounter_stat->stats_rep, rc));
6678 
6679             /* Free allocated memory and go to fail to release any memories
6680              * allocated in previous iterations. Note that list_elt->data gets
6681              * populated in dhd_create_ecounters_params() and gets freed there
6682              * itself.
6683              */
6684             MFREE(dhd->osh, list_elt, sizeof(*list_elt));
6685             list_elt = NULL;
6686             goto fail;
6687         }
6688         elt = (bcm_xtlv_t *)list_elt->data;
6689 
6690         /* Put the elements in the order they are processed */
6691         if (processed_containers_list == NULL) {
6692             processed_containers_list = list_elt;
6693         } else {
6694             tail->next = list_elt;
6695         }
6696         tail = list_elt;
6697         /* Size of the XTLV returned */
6698         total_processed_containers_len += BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE;
6699     }
6700 
6701     /* Now create ecounters config request with totallength */
6702     req = (ecounters_config_request_v2_t *)MALLOCZ(
6703         dhd->osh, sizeof(*req) + total_processed_containers_len);
6704     if (req == NULL) {
6705         rc = BCME_NOMEM;
6706         goto fail;
6707     }
6708     req->version = ECOUNTERS_VERSION_2;
6709     req->logset = EVENT_LOG_SET_ECOUNTERS;
6710     req->reporting_period = ECOUNTERS_DEFAULT_PERIOD;
6711     req->num_reports = ECOUNTERS_NUM_REPORTS;
6712     req->len = total_processed_containers_len +
6713                OFFSETOF(ecounters_config_request_v2_t, ecounters_xtlvs);
6714 
6715     /* Copy config */
6716     start_ptr = req->ecounters_xtlvs;
6717 
6718     /* Now go element by element in the list */
6719     while (processed_containers_list) {
6720         list_elt = processed_containers_list;
6721 
6722         elt = (bcm_xtlv_t *)list_elt->data;
6723 
6724         memcpy(start_ptr, list_elt->data,
6725                BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE);
6726         start_ptr += (size_t)(BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE);
6727         processed_containers_list = processed_containers_list->next;
6728 
6729         /* Free allocated memories */
6730         MFREE(dhd->osh, elt, elt->len + BCM_XTLV_HDR_SIZE);
6731         MFREE(dhd->osh, list_elt, sizeof(*list_elt));
6732     }
6733 
6734     if ((rc = dhd_iovar(dhd, 0, "ecounters", (char *)req, req->len, NULL, 0,
6735                         TRUE)) < 0) {
6736         DHD_ERROR(("failed to start ecounters\n"));
6737     }
6738 
6739 fail:
6740     if (req) {
6741         MFREE(dhd->osh, req, sizeof(*req) + total_processed_containers_len);
6742     }
6743 
6744     /* Now go element by element in the list */
6745     while (processed_containers_list) {
6746         list_elt = processed_containers_list;
6747         elt = (bcm_xtlv_t *)list_elt->data;
6748         processed_containers_list = processed_containers_list->next;
6749 
6750         /* Free allocated memories */
6751         MFREE(dhd->osh, elt, elt->len + BCM_XTLV_HDR_SIZE);
6752         MFREE(dhd->osh, list_elt, sizeof(*list_elt));
6753     }
6754     return rc;
6755 }
6756 
dhd_stop_ecounters(dhd_pub_t * dhd)6757 int dhd_stop_ecounters(dhd_pub_t *dhd)
6758 {
6759     int rc = BCME_OK;
6760     ecounters_config_request_v2_t *req;
6761 
6762     /* Now create ecounters config request with totallength */
6763     req = (ecounters_config_request_v2_t *)MALLOCZ(dhd->osh, sizeof(*req));
6764     if (req == NULL) {
6765         rc = BCME_NOMEM;
6766         goto fail;
6767     }
6768     req->version = ECOUNTERS_VERSION_2;
6769     req->len = OFFSETOF(ecounters_config_request_v2_t, ecounters_xtlvs);
6770 
6771     if ((rc = dhd_iovar(dhd, 0, "ecounters", (char *)req, req->len, NULL, 0,
6772                         TRUE)) < 0) {
6773         DHD_ERROR(("failed to stop ecounters\n"));
6774     }
6775 
6776 fail:
6777     if (req) {
6778         MFREE(dhd->osh, req, sizeof(*req));
6779     }
6780     return rc;
6781 }
6782 
6783 /* configured event_id_array for event ecounters */
6784 typedef struct event_id_array {
6785     uint8 event_id;
6786     uint8 str_idx;
6787 } event_id_array_t;
6788 
6789 /* get event id array only from event_ecounters_cfg_tbl[] */
6790 static inline int
__dhd_event_ecounters_get_event_id_array(event_id_array_t * event_array)6791 __dhd_event_ecounters_get_event_id_array(event_id_array_t *event_array)
6792 {
6793     uint8 i;
6794     uint8 idx = 0;
6795     int32 prev_evt_id = -1;
6796 
6797     for (i = 0; i < (uint8)ARRAYSIZE(event_ecounters_cfg_tbl); i++) {
6798         if (prev_evt_id != event_ecounters_cfg_tbl[i].event_id) {
6799             if (prev_evt_id >= 0) {
6800                 idx++;
6801             }
6802             event_array[idx].event_id = event_ecounters_cfg_tbl[i].event_id;
6803             event_array[idx].str_idx = i;
6804         }
6805         prev_evt_id = event_ecounters_cfg_tbl[i].event_id;
6806     }
6807     return idx;
6808 }
6809 
6810 /* One event id has limit xtlv num to request based on wl_ifstats_xtlv_id * 2
6811  * interface */
6812 #define ECNTRS_MAX_XTLV_NUM (31 * 2)
6813 
dhd_start_event_ecounters(dhd_pub_t * dhd)6814 int dhd_start_event_ecounters(dhd_pub_t *dhd)
6815 {
6816     uint8 i, j = 0;
6817     uint8 event_id_cnt = 0;
6818     uint16 processed_containers_len = 0;
6819     uint16 max_xtlv_len = 0;
6820     int rc = BCME_OK;
6821     uint8 *ptr;
6822     uint8 *data;
6823     event_id_array_t *id_array;
6824     bcm_xtlv_t *elt = NULL;
6825     event_ecounters_config_request_v2_t *req = NULL;
6826 
6827     id_array = (event_id_array_t *)MALLOCZ(
6828         dhd->osh,
6829         sizeof(event_id_array_t) * ARRAYSIZE(event_ecounters_cfg_tbl));
6830     if (id_array == NULL) {
6831         rc = BCME_NOMEM;
6832         goto fail;
6833     }
6834     event_id_cnt = __dhd_event_ecounters_get_event_id_array(id_array);
6835     max_xtlv_len =
6836         ((BCM_XTLV_HDR_SIZE +
6837           OFFSETOF(event_ecounters_config_request_v2_t, ecounters_xtlvs)) *
6838          ECNTRS_MAX_XTLV_NUM);
6839 
6840     /* Now create ecounters config request with max allowed length */
6841     req = (event_ecounters_config_request_v2_t *)MALLOCZ(
6842         dhd->osh, sizeof(event_ecounters_config_request_v2_t *) + max_xtlv_len);
6843     if (req == NULL) {
6844         rc = BCME_NOMEM;
6845         goto fail;
6846     }
6847     for (i = 0; i <= event_id_cnt; i++) {
6848         /* req initialization by event id */
6849         req->version = ECOUNTERS_VERSION_2;
6850         req->logset = EVENT_LOG_SET_ECOUNTERS;
6851         req->event_id = id_array[i].event_id;
6852         req->flags = EVENT_ECOUNTERS_FLAGS_ADD;
6853         req->len = 0;
6854         processed_containers_len = 0;
6855 
6856         /* Copy config */
6857         ptr = req->ecounters_xtlvs;
6858 
6859         for (j = id_array[i].str_idx;
6860              j < (uint8)ARRAYSIZE(event_ecounters_cfg_tbl); j++) {
6861             event_ecounters_cfg_t *event_ecounter_stat =
6862                 &event_ecounters_cfg_tbl[j];
6863             if (id_array[i].event_id != event_ecounter_stat->event_id) {
6864                 break;
6865             }
6866 
6867             rc = dhd_create_ecounters_params(dhd, event_ecounter_stat->type,
6868                                              event_ecounter_stat->if_slice_idx,
6869                                              event_ecounter_stat->stats_rep,
6870                                              &data);
6871             if (rc) {
6872                 DHD_ERROR(("%s: Could not process: stat: %d return code: %d\n",
6873                            __FUNCTION__, event_ecounter_stat->stats_rep, rc));
6874                 goto fail;
6875             }
6876 
6877             elt = (bcm_xtlv_t *)data;
6878             memcpy(ptr, elt, BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE);
6879             ptr += (size_t)(BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE);
6880             processed_containers_len += BCM_XTLV_LEN(elt) + BCM_XTLV_HDR_SIZE;
6881 
6882             /* Free allocated memories alloced by dhd_create_ecounters_params */
6883             MFREE(dhd->osh, elt, elt->len + BCM_XTLV_HDR_SIZE);
6884 
6885             if (processed_containers_len > max_xtlv_len) {
6886                 DHD_ERROR(("%s XTLV NUM IS OVERFLOWED THAN ALLOWED!!\n",
6887                            __FUNCTION__));
6888                 rc = BCME_BADLEN;
6889                 goto fail;
6890             }
6891         }
6892 
6893         req->len =
6894             processed_containers_len +
6895             OFFSETOF(event_ecounters_config_request_v2_t, ecounters_xtlvs);
6896 
6897         DHD_INFO(("%s req version %d logset %d event_id %d flags %d len %d\n",
6898                   __FUNCTION__, req->version, req->logset, req->event_id,
6899                   req->flags, req->len));
6900 
6901         rc = dhd_iovar(dhd, 0, "event_ecounters", (char *)req, req->len, NULL,
6902                        0, TRUE);
6903         if (rc < 0) {
6904             DHD_ERROR(
6905                 ("failed to start event_ecounters(event id %d) with rc %d\n",
6906                  req->event_id, rc));
6907             goto fail;
6908         }
6909     }
6910 
6911 fail:
6912     /* Free allocated memories */
6913     if (req) {
6914         MFREE(dhd->osh, req,
6915               sizeof(event_ecounters_config_request_v2_t *) + max_xtlv_len);
6916     }
6917     if (id_array) {
6918         MFREE(dhd->osh, id_array,
6919               sizeof(event_id_array_t) * ARRAYSIZE(event_ecounters_cfg_tbl));
6920     }
6921     return rc;
6922 }
6923 
dhd_stop_event_ecounters(dhd_pub_t * dhd)6924 int dhd_stop_event_ecounters(dhd_pub_t *dhd)
6925 {
6926     int rc = BCME_OK;
6927     event_ecounters_config_request_v2_t *req;
6928 
6929     /* Now create ecounters config request with totallength */
6930     req =
6931         (event_ecounters_config_request_v2_t *)MALLOCZ(dhd->osh, sizeof(*req));
6932     if (req == NULL) {
6933         rc = BCME_NOMEM;
6934         goto fail;
6935     }
6936     req->version = ECOUNTERS_VERSION_2;
6937     req->flags = EVENT_ECOUNTERS_FLAGS_DEL_ALL;
6938     req->len = OFFSETOF(event_ecounters_config_request_v2_t, ecounters_xtlvs);
6939     if ((rc = dhd_iovar(dhd, 0, "event_ecounters", (char *)req, req->len, NULL,
6940                         0, TRUE)) < 0) {
6941         DHD_ERROR(("failed to stop event_ecounters\n"));
6942     }
6943 
6944 fail:
6945     if (req) {
6946         MFREE(dhd->osh, req, sizeof(*req));
6947     }
6948     return rc;
6949 }
6950 
6951 #ifdef DHD_LOG_DUMP
dhd_dump_debug_ring(dhd_pub_t * dhdp,void * ring_ptr,const void * user_buf,log_dump_section_hdr_t * sec_hdr,char * text_hdr,int buflen,uint32 sec_type)6952 int dhd_dump_debug_ring(dhd_pub_t *dhdp, void *ring_ptr, const void *user_buf,
6953                         log_dump_section_hdr_t *sec_hdr, char *text_hdr,
6954                         int buflen, uint32 sec_type)
6955 {
6956     uint32 rlen = 0;
6957     uint32 data_len = 0;
6958     void *data = NULL;
6959     unsigned long flags = 0;
6960     int ret = 0;
6961     dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr;
6962     int pos = 0;
6963     int fpos_sechdr = 0;
6964 
6965     if (!dhdp || !ring || !user_buf || !sec_hdr || !text_hdr) {
6966         return BCME_BADARG;
6967     }
6968     /* do not allow further writes to the ring
6969      * till we flush it
6970      */
6971     DHD_DBG_RING_LOCK(ring->lock, flags);
6972     ring->state = RING_SUSPEND;
6973     DHD_DBG_RING_UNLOCK(ring->lock, flags);
6974 
6975     if (dhdp->concise_dbg_buf) {
6976         /* re-use concise debug buffer temporarily
6977          * to pull ring data, to write
6978          * record by record to file
6979          */
6980         data_len = CONCISE_DUMP_BUFLEN;
6981         data = dhdp->concise_dbg_buf;
6982         ret = dhd_export_debug_data(text_hdr, NULL, user_buf, strlen(text_hdr),
6983                                     &pos);
6984         /* write the section header now with zero length,
6985          * once the correct length is found out, update
6986          * it later
6987          */
6988         fpos_sechdr = pos;
6989         sec_hdr->type = sec_type;
6990         sec_hdr->length = 0;
6991         ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf,
6992                                     sizeof(*sec_hdr), &pos);
6993         do {
6994             rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE);
6995             if (rlen > 0) {
6996                 /* write the log */
6997                 ret = dhd_export_debug_data(data, NULL, user_buf, rlen, &pos);
6998             }
6999             DHD_DBGIF(("%s: rlen : %d\n", __FUNCTION__, rlen));
7000         } while ((rlen > 0));
7001         /* now update the section header length in the file */
7002         /* Complete ring size is dumped by HAL, hence updating length to ring
7003          * size */
7004         sec_hdr->length = ring->ring_size;
7005         ret = dhd_export_debug_data((char *)sec_hdr, NULL, user_buf,
7006                                     sizeof(*sec_hdr), &fpos_sechdr);
7007     } else {
7008         DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__));
7009     }
7010     DHD_DBG_RING_LOCK(ring->lock, flags);
7011     ring->state = RING_ACTIVE;
7012     /* Resetting both read and write pointer,
7013      * since all items are read.
7014      */
7015     ring->rp = ring->wp = 0;
7016     DHD_DBG_RING_UNLOCK(ring->lock, flags);
7017 
7018     return ret;
7019 }
7020 
dhd_log_dump_ring_to_file(dhd_pub_t * dhdp,void * ring_ptr,void * file,unsigned long * file_posn,log_dump_section_hdr_t * sec_hdr,char * text_hdr,uint32 sec_type)7021 int dhd_log_dump_ring_to_file(dhd_pub_t *dhdp, void *ring_ptr, void *file,
7022                               unsigned long *file_posn,
7023                               log_dump_section_hdr_t *sec_hdr, char *text_hdr,
7024                               uint32 sec_type)
7025 {
7026     uint32 rlen = 0;
7027     uint32 data_len = 0, total_len = 0;
7028     void *data = NULL;
7029     unsigned long fpos_sechdr = 0;
7030     unsigned long flags = 0;
7031     int ret = 0;
7032     dhd_dbg_ring_t *ring = (dhd_dbg_ring_t *)ring_ptr;
7033 
7034     if (!dhdp || !ring || !file || !sec_hdr || !file_posn || !text_hdr) {
7035         return BCME_BADARG;
7036     }
7037 
7038     /* do not allow further writes to the ring
7039      * till we flush it
7040      */
7041     DHD_DBG_RING_LOCK(ring->lock, flags);
7042     ring->state = RING_SUSPEND;
7043     DHD_DBG_RING_UNLOCK(ring->lock, flags);
7044 
7045     if (dhdp->concise_dbg_buf) {
7046         /* re-use concise debug buffer temporarily
7047          * to pull ring data, to write
7048          * record by record to file
7049          */
7050         data_len = CONCISE_DUMP_BUFLEN;
7051         data = dhdp->concise_dbg_buf;
7052         dhd_os_write_file_posn(file, file_posn, text_hdr, strlen(text_hdr));
7053         /* write the section header now with zero length,
7054          * once the correct length is found out, update
7055          * it later
7056          */
7057         dhd_init_sec_hdr(sec_hdr);
7058         fpos_sechdr = *file_posn;
7059         sec_hdr->type = sec_type;
7060         sec_hdr->length = 0;
7061         dhd_os_write_file_posn(file, file_posn, (char *)sec_hdr,
7062                                sizeof(*sec_hdr));
7063         do {
7064             rlen = dhd_dbg_ring_pull_single(ring, data, data_len, TRUE);
7065             if (rlen > 0) {
7066                 /* write the log */
7067                 ret = dhd_os_write_file_posn(file, file_posn, data, rlen);
7068                 if (ret < 0) {
7069                     DHD_ERROR(("%s: write file error !\n", __FUNCTION__));
7070                     DHD_DBG_RING_LOCK(ring->lock, flags);
7071                     ring->state = RING_ACTIVE;
7072                     DHD_DBG_RING_UNLOCK(ring->lock, flags);
7073                     return BCME_ERROR;
7074                 }
7075             }
7076             total_len += rlen;
7077         } while (rlen > 0);
7078         /* now update the section header length in the file */
7079         sec_hdr->length = total_len;
7080         dhd_os_write_file_posn(file, &fpos_sechdr, (char *)sec_hdr,
7081                                sizeof(*sec_hdr));
7082     } else {
7083         DHD_ERROR(("%s: No concise buffer available !\n", __FUNCTION__));
7084     }
7085 
7086     DHD_DBG_RING_LOCK(ring->lock, flags);
7087     ring->state = RING_ACTIVE;
7088     /* Resetting both read and write pointer,
7089      * since all items are read.
7090      */
7091     ring->rp = ring->wp = 0;
7092     DHD_DBG_RING_UNLOCK(ring->lock, flags);
7093     return BCME_OK;
7094 }
7095 
7096 /* logdump cookie */
7097 #define MAX_LOGUDMP_COOKIE_CNT 10u
7098 #define LOGDUMP_COOKIE_STR_LEN 50u
dhd_logdump_cookie_init(dhd_pub_t * dhdp,uint8 * buf,uint32 buf_size)7099 int dhd_logdump_cookie_init(dhd_pub_t *dhdp, uint8 *buf, uint32 buf_size)
7100 {
7101     uint32 ring_size;
7102 
7103     if (!dhdp || !buf) {
7104         DHD_ERROR(("INVALID PTR: dhdp:%p buf:%p\n", dhdp, buf));
7105         return BCME_ERROR;
7106     }
7107 
7108     ring_size = dhd_ring_get_hdr_size() +
7109                 LOGDUMP_COOKIE_STR_LEN * MAX_LOGUDMP_COOKIE_CNT;
7110     if (buf_size < ring_size) {
7111         DHD_ERROR(("BUF SIZE IS TO SHORT: req:%d buf_size:%d\n", ring_size,
7112                    buf_size));
7113         return BCME_ERROR;
7114     }
7115 
7116     dhdp->logdump_cookie =
7117         dhd_ring_init(dhdp, buf, buf_size, LOGDUMP_COOKIE_STR_LEN,
7118                       MAX_LOGUDMP_COOKIE_CNT, DHD_RING_TYPE_FIXED);
7119     if (!dhdp->logdump_cookie) {
7120         DHD_ERROR(("FAIL TO INIT COOKIE RING\n"));
7121         return BCME_ERROR;
7122     }
7123 
7124     return BCME_OK;
7125 }
7126 
dhd_logdump_cookie_deinit(dhd_pub_t * dhdp)7127 void dhd_logdump_cookie_deinit(dhd_pub_t *dhdp)
7128 {
7129     if (!dhdp) {
7130         return;
7131     }
7132     if (dhdp->logdump_cookie) {
7133         dhd_ring_deinit(dhdp, dhdp->logdump_cookie);
7134     }
7135 
7136     return;
7137 }
7138 
dhd_logdump_cookie_save(dhd_pub_t * dhdp,char * cookie,char * type)7139 void dhd_logdump_cookie_save(dhd_pub_t *dhdp, char *cookie, char *type)
7140 {
7141     char *ptr;
7142 
7143     if (!dhdp || !cookie || !type || !dhdp->logdump_cookie) {
7144         DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p"
7145                    " type = %p, cookie_cfg:%p\n",
7146                    __FUNCTION__, dhdp, cookie, type,
7147                    dhdp ? dhdp->logdump_cookie : NULL));
7148         return;
7149     }
7150     ptr = (char *)dhd_ring_get_empty(dhdp->logdump_cookie);
7151     if (ptr == NULL) {
7152         DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__));
7153         return;
7154     }
7155     scnprintf(ptr, LOGDUMP_COOKIE_STR_LEN, "%s: %s\n", type, cookie);
7156     return;
7157 }
7158 
dhd_logdump_cookie_get(dhd_pub_t * dhdp,char * ret_cookie,uint32 buf_size)7159 int dhd_logdump_cookie_get(dhd_pub_t *dhdp, char *ret_cookie, uint32 buf_size)
7160 {
7161     char *ptr;
7162 
7163     if (!dhdp || !ret_cookie || !dhdp->logdump_cookie) {
7164         DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p"
7165                    "cookie=%p cookie_cfg:%p\n",
7166                    __FUNCTION__, dhdp, ret_cookie,
7167                    dhdp ? dhdp->logdump_cookie : NULL));
7168         return BCME_ERROR;
7169     }
7170     ptr = (char *)dhd_ring_get_first(dhdp->logdump_cookie);
7171     if (ptr == NULL) {
7172         DHD_ERROR(("%s : Skip to save due to locking\n", __FUNCTION__));
7173         return BCME_ERROR;
7174     }
7175     memcpy(ret_cookie, ptr, MIN(buf_size, strlen(ptr)));
7176     dhd_ring_free_first(dhdp->logdump_cookie);
7177     return BCME_OK;
7178 }
7179 
dhd_logdump_cookie_count(dhd_pub_t * dhdp)7180 int dhd_logdump_cookie_count(dhd_pub_t *dhdp)
7181 {
7182     if (!dhdp || !dhdp->logdump_cookie) {
7183         DHD_ERROR(("%s: At least one buffer ptr is NULL dhdp=%p cookie=%p\n",
7184                    __FUNCTION__, dhdp, dhdp ? dhdp->logdump_cookie : NULL));
7185         return 0;
7186     }
7187     return dhd_ring_get_cur_size(dhdp->logdump_cookie);
7188 }
7189 
__dhd_log_dump_cookie_to_file(dhd_pub_t * dhdp,void * fp,const void * user_buf,unsigned long * f_pos,char * buf,uint32 buf_size)7190 static inline int __dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp,
7191                                                 const void *user_buf,
7192                                                 unsigned long *f_pos, char *buf,
7193                                                 uint32 buf_size)
7194 {
7195     uint32 remain = buf_size;
7196     int ret = BCME_ERROR;
7197     char tmp_buf[LOGDUMP_COOKIE_STR_LEN];
7198     log_dump_section_hdr_t sec_hdr;
7199     uint32 read_idx;
7200     uint32 write_idx;
7201     read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie);
7202     write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie);
7203     while (dhd_logdump_cookie_count(dhdp) > 0) {
7204         memset(tmp_buf, 0, sizeof(tmp_buf));
7205         ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN);
7206         if (ret != BCME_OK) {
7207             return ret;
7208         }
7209         remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf);
7210     }
7211     dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx);
7212     dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx);
7213 
7214     ret = dhd_export_debug_data(COOKIE_LOG_HDR, fp, user_buf,
7215                                 strlen(COOKIE_LOG_HDR), f_pos);
7216     if (ret < 0) {
7217         DHD_ERROR(("%s : Write file Error for cookie hdr\n", __FUNCTION__));
7218         return ret;
7219     }
7220     sec_hdr.magic = LOG_DUMP_MAGIC;
7221     sec_hdr.timestamp = local_clock();
7222     sec_hdr.type = LOG_DUMP_SECTION_COOKIE;
7223     sec_hdr.length = buf_size - remain;
7224 
7225     ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf, sizeof(sec_hdr),
7226                                 f_pos);
7227     if (ret < 0) {
7228         DHD_ERROR(("%s : Write file Error for section hdr\n", __FUNCTION__));
7229         return ret;
7230     }
7231 
7232     ret = dhd_export_debug_data(buf, fp, user_buf, sec_hdr.length, f_pos);
7233     if (ret < 0) {
7234         DHD_ERROR(("%s : Write file Error for cookie data\n", __FUNCTION__));
7235     }
7236 
7237     return ret;
7238 }
7239 
dhd_log_dump_cookie_len(dhd_pub_t * dhdp)7240 uint32 dhd_log_dump_cookie_len(dhd_pub_t *dhdp)
7241 {
7242     int len = 0;
7243     char tmp_buf[LOGDUMP_COOKIE_STR_LEN];
7244     log_dump_section_hdr_t sec_hdr;
7245     char *buf = NULL;
7246     int ret = BCME_ERROR;
7247     uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN;
7248     uint32 read_idx;
7249     uint32 write_idx;
7250     uint32 remain;
7251 
7252     remain = buf_size;
7253 
7254     if (!dhdp || !dhdp->logdump_cookie) {
7255         DHD_ERROR(("%s At least one ptr is NULL "
7256                    "dhdp = %p cookie %p\n",
7257                    __FUNCTION__, dhdp, dhdp ? dhdp->logdump_cookie : NULL));
7258         goto exit;
7259     }
7260 
7261     buf = (char *)MALLOCZ(dhdp->osh, buf_size);
7262     if (!buf) {
7263         DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
7264         goto exit;
7265     }
7266 
7267     read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie);
7268     write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie);
7269     while (dhd_logdump_cookie_count(dhdp) > 0) {
7270         memset(tmp_buf, 0, sizeof(tmp_buf));
7271         ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN);
7272         if (ret != BCME_OK) {
7273             goto exit;
7274         }
7275         remain -= (uint32)strlen(tmp_buf);
7276     }
7277     dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx);
7278     dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx);
7279     len += strlen(COOKIE_LOG_HDR);
7280     len += sizeof(sec_hdr);
7281     len += (buf_size - remain);
7282 exit:
7283     if (buf) {
7284         MFREE(dhdp->osh, buf, buf_size);
7285     }
7286     return len;
7287 }
7288 
dhd_log_dump_cookie(dhd_pub_t * dhdp,const void * user_buf)7289 int dhd_log_dump_cookie(dhd_pub_t *dhdp, const void *user_buf)
7290 {
7291     int ret = BCME_ERROR;
7292     char tmp_buf[LOGDUMP_COOKIE_STR_LEN];
7293     log_dump_section_hdr_t sec_hdr;
7294     char *buf = NULL;
7295     uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN;
7296     int pos = 0;
7297     uint32 read_idx;
7298     uint32 write_idx;
7299     uint32 remain;
7300 
7301     remain = buf_size;
7302 
7303     if (!dhdp || !dhdp->logdump_cookie) {
7304         DHD_ERROR(("%s At least one ptr is NULL "
7305                    "dhdp = %p cookie %p\n",
7306                    __FUNCTION__, dhdp, dhdp ? dhdp->logdump_cookie : NULL));
7307         goto exit;
7308     }
7309 
7310     buf = (char *)MALLOCZ(dhdp->osh, buf_size);
7311     if (!buf) {
7312         DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
7313         goto exit;
7314     }
7315 
7316     read_idx = dhd_ring_get_read_idx(dhdp->logdump_cookie);
7317     write_idx = dhd_ring_get_write_idx(dhdp->logdump_cookie);
7318     while (dhd_logdump_cookie_count(dhdp) > 0) {
7319         memset(tmp_buf, 0, sizeof(tmp_buf));
7320         ret = dhd_logdump_cookie_get(dhdp, tmp_buf, LOGDUMP_COOKIE_STR_LEN);
7321         if (ret != BCME_OK) {
7322             goto exit;
7323         }
7324         remain -= scnprintf(&buf[buf_size - remain], remain, "%s", tmp_buf);
7325     }
7326     dhd_ring_set_read_idx(dhdp->logdump_cookie, read_idx);
7327     dhd_ring_set_write_idx(dhdp->logdump_cookie, write_idx);
7328     ret = dhd_export_debug_data(COOKIE_LOG_HDR, NULL, user_buf,
7329                                 strlen(COOKIE_LOG_HDR), &pos);
7330     sec_hdr.magic = LOG_DUMP_MAGIC;
7331     sec_hdr.timestamp = local_clock();
7332     sec_hdr.type = LOG_DUMP_SECTION_COOKIE;
7333     sec_hdr.length = buf_size - remain;
7334     ret = dhd_export_debug_data((char *)&sec_hdr, NULL, user_buf,
7335                                 sizeof(sec_hdr), &pos);
7336     ret = dhd_export_debug_data(buf, NULL, user_buf, sec_hdr.length, &pos);
7337 exit:
7338     if (buf) {
7339         MFREE(dhdp->osh, buf, buf_size);
7340     }
7341     return ret;
7342 }
7343 
dhd_log_dump_cookie_to_file(dhd_pub_t * dhdp,void * fp,const void * user_buf,unsigned long * f_pos)7344 int dhd_log_dump_cookie_to_file(dhd_pub_t *dhdp, void *fp, const void *user_buf,
7345                                 unsigned long *f_pos)
7346 {
7347     char *buf;
7348     int ret = BCME_ERROR;
7349     uint32 buf_size = MAX_LOGUDMP_COOKIE_CNT * LOGDUMP_COOKIE_STR_LEN;
7350 
7351     if (!dhdp || !dhdp->logdump_cookie || (!fp && !user_buf) || !f_pos) {
7352         DHD_ERROR(("%s At least one ptr is NULL "
7353                    "dhdp = %p cookie %p fp = %p f_pos = %p\n",
7354                    __FUNCTION__, dhdp, dhdp ? dhdp->logdump_cookie : NULL, fp,
7355                    f_pos));
7356         return ret;
7357     }
7358 
7359     buf = (char *)MALLOCZ(dhdp->osh, buf_size);
7360     if (!buf) {
7361         DHD_ERROR(("%s Fail to malloc buffer\n", __FUNCTION__));
7362         return ret;
7363     }
7364     ret =
7365         __dhd_log_dump_cookie_to_file(dhdp, fp, user_buf, f_pos, buf, buf_size);
7366     MFREE(dhdp->osh, buf, buf_size);
7367 
7368     return ret;
7369 }
7370 
7371 #endif /* DHD_LOG_DUMP */
7372 
7373 #ifdef DHD_LOG_DUMP
7374 #define DEBUG_DUMP_TRIGGER_INTERVAL_SEC 4
dhd_log_dump_trigger(dhd_pub_t * dhdp,int subcmd)7375 void dhd_log_dump_trigger(dhd_pub_t *dhdp, int subcmd)
7376 {
7377 #if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL)
7378     log_dump_type_t *flush_type;
7379 #endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */
7380     uint64 current_time_sec;
7381 
7382     if (!dhdp) {
7383         DHD_ERROR(("dhdp is NULL !\n"));
7384         return;
7385     }
7386 
7387     if (subcmd >= CMD_MAX || subcmd < CMD_DEFAULT) {
7388         DHD_ERROR(("%s : Invalid subcmd \n", __FUNCTION__));
7389         return;
7390     }
7391 
7392     current_time_sec = DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC);
7393 
7394     DHD_ERROR(
7395         ("%s: current_time_sec=%lld debug_dump_time_sec=%lld interval=%d\n",
7396          __FUNCTION__, current_time_sec, dhdp->debug_dump_time_sec,
7397          DEBUG_DUMP_TRIGGER_INTERVAL_SEC));
7398 
7399     if ((current_time_sec - dhdp->debug_dump_time_sec) <
7400         DEBUG_DUMP_TRIGGER_INTERVAL_SEC) {
7401         DHD_ERROR((
7402             "%s : Last debug dump triggered(%lld) within %d seconds, so SKIP\n",
7403             __FUNCTION__, dhdp->debug_dump_time_sec,
7404             DEBUG_DUMP_TRIGGER_INTERVAL_SEC));
7405         return;
7406     }
7407 
7408     clear_debug_dump_time(dhdp->debug_dump_time_str);
7409     /*  */
7410     dhdp->debug_dump_subcmd = subcmd;
7411 
7412     dhdp->debug_dump_time_sec =
7413         DIV_U64_BY_U32(OSL_LOCALTIME_NS(), NSEC_PER_SEC);
7414 
7415 #if defined(DHD_DUMP_FILE_WRITE_FROM_KERNEL)
7416     /* flush_type is freed at do_dhd_log_dump function */
7417     flush_type = MALLOCZ(dhdp->osh, sizeof(log_dump_type_t));
7418     if (flush_type) {
7419         *flush_type = DLD_BUF_TYPE_ALL;
7420         dhd_schedule_log_dump(dhdp, flush_type);
7421     } else {
7422         DHD_ERROR(("%s Fail to malloc flush_type\n", __FUNCTION__));
7423         return;
7424     }
7425 #endif /* DHD_DUMP_FILE_WRITE_FROM_KERNEL */
7426 
7427     /* Inside dhd_mem_dump, event notification will be sent to HAL and
7428      * from other context DHD pushes memdump, debug_dump and pktlog dump
7429      * to HAL and HAL will write into file
7430      */
7431 #if (defined(BCMPCIE) || defined(BCMSDIO)) && defined(DHD_FW_COREDUMP)
7432     dhdp->memdump_type = DUMP_TYPE_BY_SYSDUMP;
7433     dhd_bus_mem_dump(dhdp);
7434 #endif /* BCMPCIE && DHD_FW_COREDUMP */
7435 }
7436 #endif /* DHD_LOG_DUMP */
7437 
7438 #ifdef EWP_EDL
7439 /* For now we are allocating memory for EDL ring using DMA_ALLOC_CONSISTENT
7440  * The reason being that, in hikey, if we try to DMA_MAP prealloced memory
7441  * it is failing with an 'out of space in SWIOTLB' error
7442  */
dhd_edl_mem_init(dhd_pub_t * dhd)7443 int dhd_edl_mem_init(dhd_pub_t *dhd)
7444 {
7445     int ret = 0;
7446 
7447     memset(&dhd->edl_ring_mem, 0, sizeof(dhd->edl_ring_mem));
7448     ret = dhd_dma_buf_alloc(dhd, &dhd->edl_ring_mem, DHD_EDL_RING_SIZE);
7449     if (ret != BCME_OK) {
7450         DHD_ERROR(("%s: alloc of edl_ring_mem failed\n", __FUNCTION__));
7451         return BCME_ERROR;
7452     }
7453     return BCME_OK;
7454 }
7455 
7456 /* NOTE:- that dhd_edl_mem_deinit need NOT be called explicitly, because the
7457  * dma_buf for EDL is freed during 'dhd_prot_detach_edl_rings' which is called
7458  * during de-init.
7459  */
dhd_edl_mem_deinit(dhd_pub_t * dhd)7460 void dhd_edl_mem_deinit(dhd_pub_t *dhd)
7461 {
7462     if (dhd->edl_ring_mem.va != NULL) {
7463         dhd_dma_buf_free(dhd, &dhd->edl_ring_mem);
7464     }
7465 }
7466 
dhd_event_logtrace_process_edl(dhd_pub_t * dhdp,uint8 * data,void * evt_decode_data)7467 int dhd_event_logtrace_process_edl(dhd_pub_t *dhdp, uint8 *data,
7468                                    void *evt_decode_data)
7469 {
7470     msg_hdr_edl_t *msg = NULL;
7471     cmn_msg_hdr_t *cmn_msg_hdr = NULL;
7472     uint8 *buf = NULL;
7473 
7474     if (!data || !dhdp || !evt_decode_data) {
7475         DHD_ERROR(("%s: invalid args ! \n", __FUNCTION__));
7476         return BCME_ERROR;
7477     }
7478 
7479     /* format of data in each work item in the EDL ring:
7480      * |cmn_msg_hdr_t |payload (var len)|cmn_msg_hdr_t|
7481      * payload = |infobuf_ver(u32)|info_buf_payload_hdr_t|msgtrace_hdr_t|<var
7482      * len data>|
7483      */
7484     cmn_msg_hdr = (cmn_msg_hdr_t *)data;
7485     msg = (msg_hdr_edl_t *)(data + sizeof(cmn_msg_hdr_t));
7486     buf = (uint8 *)msg;
7487     /* validate the fields */
7488     if (ltoh32(msg->infobuf_ver) != PCIE_INFOBUF_V1) {
7489         DHD_ERROR(("%s: Skipping msg with invalid infobuf ver (0x%x)"
7490                    " expected (0x%x)\n",
7491                    __FUNCTION__, msg->infobuf_ver, PCIE_INFOBUF_V1));
7492         return BCME_VERSION;
7493     }
7494 
7495     /* in EDL, the request_id field of cmn_msg_hdr is overloaded to carry
7496      * payload length */
7497     if (sizeof(info_buf_payload_hdr_t) > cmn_msg_hdr->request_id) {
7498         DHD_ERROR(("%s: infobuf too small for v1 type/length fields\n",
7499                    __FUNCTION__));
7500         return BCME_BUFTOOLONG;
7501     }
7502 
7503     if (ltoh16(msg->pyld_hdr.type) != PCIE_INFOBUF_V1_TYPE_LOGTRACE) {
7504         DHD_ERROR(("%s: payload_hdr_type %d is not V1_TYPE_LOGTRACE\n",
7505                    __FUNCTION__, ltoh16(msg->pyld_hdr.type)));
7506         return BCME_BADOPTION;
7507     }
7508 
7509     if (ltoh16(msg->pyld_hdr.length) > cmn_msg_hdr->request_id) {
7510         DHD_ERROR(("%s: infobuf logtrace length %u is bigger"
7511                    " than available buffer size %u\n",
7512                    __FUNCTION__, ltoh16(msg->pyld_hdr.length),
7513                    cmn_msg_hdr->request_id));
7514         return BCME_BADLEN;
7515     }
7516 
7517     /* dhd_dbg_trace_evnt_handler expects the data to start from msgtrace_hdr_t
7518      */
7519     buf += sizeof(msg->infobuf_ver) + sizeof(msg->pyld_hdr);
7520     dhd_dbg_trace_evnt_handler(dhdp, buf, evt_decode_data,
7521                                ltoh16(msg->pyld_hdr.length));
7522 
7523     /* check 'dhdp->logtrace_pkt_sendup' and if true alloc an skb
7524      * copy the event data to the skb and send it up the stack
7525      */
7526     if (dhdp->logtrace_pkt_sendup) {
7527         DHD_INFO(("%s: send up event log, len %u bytes\n", __FUNCTION__,
7528                   (uint32)(ltoh16(msg->pyld_hdr.length) +
7529                            sizeof(info_buf_payload_hdr_t) + 0x4)));
7530         dhd_sendup_info_buf(dhdp, (uint8 *)msg);
7531     }
7532 
7533     return BCME_OK;
7534 }
7535 #endif /* EWP_EDL */
7536 
7537 #if defined(SHOW_LOGTRACE)
dhd_print_fw_ver_from_file(dhd_pub_t * dhdp,char * fwpath)7538 int dhd_print_fw_ver_from_file(dhd_pub_t *dhdp, char *fwpath)
7539 {
7540     void *file = NULL;
7541     int size = 0;
7542     char buf[FW_VER_STR_LEN];
7543     char *str = NULL;
7544     int ret = BCME_OK;
7545 
7546     if (!fwpath) {
7547         return BCME_BADARG;
7548     }
7549 
7550     file = dhd_os_open_image1(dhdp, fwpath);
7551     if (!file) {
7552         ret = BCME_ERROR;
7553         goto exit;
7554     }
7555     size = dhd_os_get_image_size(file);
7556     if (!size) {
7557         ret = BCME_ERROR;
7558         goto exit;
7559     }
7560 
7561     /* seek to the last 'X' bytes in the file */
7562     if (dhd_os_seek_file(file, size - FW_VER_STR_LEN) != BCME_OK) {
7563         ret = BCME_ERROR;
7564         goto exit;
7565     }
7566 
7567     /* read the last 'X' bytes of the file to a buffer */
7568     memset(buf, 0, FW_VER_STR_LEN);
7569     if (dhd_os_get_image_block(buf, FW_VER_STR_LEN - 1, file) < 0) {
7570         ret = BCME_ERROR;
7571         goto exit;
7572     }
7573     /* search for 'Version' in the buffer */
7574     str = bcmstrnstr(buf, FW_VER_STR_LEN, FW_VER_STR, strlen(FW_VER_STR));
7575     if (!str) {
7576         ret = BCME_ERROR;
7577         goto exit;
7578     }
7579     /* go back in the buffer to the last ascii character */
7580     while (str != buf && (*str >= ' ' && *str <= '~')) {
7581         --str;
7582     }
7583     /* reverse the final decrement, so that str is pointing
7584      * to the first ascii character in the buffer
7585      */
7586     ++str;
7587 
7588     if (strlen(str) > (FW_VER_STR_LEN - 1)) {
7589         ret = BCME_BADLEN;
7590         goto exit;
7591     }
7592 
7593     DHD_ERROR(("FW version in file '%s': %s\n", fwpath, str));
7594     /* copy to global variable, so that in case FW load fails, the
7595      * core capture logs will contain FW version read from the file
7596      */
7597     memset(fw_version, 0, FW_VER_STR_LEN);
7598     strlcpy(fw_version, str, FW_VER_STR_LEN);
7599 
7600 exit:
7601     if (file) {
7602         dhd_os_close_image1(dhdp, file);
7603     }
7604 
7605     return ret;
7606 }
7607 #endif // endif
7608 
7609 #if defined(DHD_H2D_LOG_TIME_SYNC)
7610 /*
7611  * Helper function:
7612  * Used for Dongle console message time syncing with Host printk
7613  */
dhd_h2d_log_time_sync(dhd_pub_t * dhd)7614 void dhd_h2d_log_time_sync(dhd_pub_t *dhd)
7615 {
7616     uint64 ts;
7617 
7618     /*
7619      * local_clock() returns time in nano seconds.
7620      * Dongle understand only milli seconds time.
7621      */
7622     ts = local_clock();
7623     /* Nano seconds to milli seconds */
7624     do_div(ts, 0xF4240);
7625     if (dhd_wl_ioctl_set_intiovar(dhd, "rte_timesync", ts, WLC_SET_VAR, TRUE,
7626                                   0)) {
7627         DHD_ERROR(("%s rte_timesync **** FAILED ****\n", __FUNCTION__));
7628         /* Stopping HOST Dongle console time syncing */
7629         dhd->dhd_rte_time_sync_ms = 0;
7630     }
7631 }
7632 #endif /* DHD_H2D_LOG_TIME_SYNC */
7633 
7634 #if defined(DISABLE_HE_ENAB) || defined(CUSTOM_CONTROL_HE_ENAB)
dhd_control_he_enab(dhd_pub_t * dhd,uint8 he_enab)7635 int dhd_control_he_enab(dhd_pub_t *dhd, uint8 he_enab)
7636 {
7637     int ret = BCME_OK;
7638     bcm_xtlv_t *pxtlv = NULL;
7639     uint8 mybuf[DHD_IOVAR_BUF_SIZE];
7640     uint16 mybuf_len = sizeof(mybuf);
7641     pxtlv = (bcm_xtlv_t *)mybuf;
7642 
7643     ret =
7644         bcm_pack_xtlv_entry((uint8 **)&pxtlv, &mybuf_len, WL_HE_CMD_ENAB,
7645                             sizeof(he_enab), &he_enab, BCM_XTLV_OPTION_ALIGN32);
7646     if (ret != BCME_OK) {
7647         ret = -EINVAL;
7648         DHD_ERROR(("%s failed to pack he enab, err: %s\n", __FUNCTION__,
7649                    bcmerrorstr(ret)));
7650         return ret;
7651     }
7652     ret = dhd_iovar(dhd, 0, "he", (char *)&mybuf, sizeof(mybuf), NULL, 0, TRUE);
7653     if (ret < 0) {
7654         DHD_ERROR(("%s he_enab (%d) set failed, err: %s\n", __FUNCTION__,
7655                    he_enab, bcmerrorstr(ret)));
7656     } else {
7657         DHD_ERROR(("%s he_enab (%d) set successed\n", __FUNCTION__, he_enab));
7658     }
7659 
7660     return ret;
7661 }
7662 #endif /* DISABLE_HE_ENAB || CUSTOM_CONTROL_HE_ENAB */
7663