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