1 /*
2 * DHD debugability: Status Information Logging support
3 *
4 * Copyright (C) 2020, 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 of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 *
21 * <<Broadcom-WL-IPTag/Open:>>
22 *
23 * $Id$
24 */
25
26 #include <linuxver.h>
27 #include <typedefs.h>
28 #include <osl.h>
29 #include <bcmutils.h>
30 #include <ethernet.h>
31 #include <bcmevent.h>
32 #include <dngl_stats.h>
33 #include <dhd.h>
34 #include <dhd_dbg.h>
35
36 #ifdef DHD_STATUS_LOGGING
37
38 #define DHD_STATLOG_ERR_INTERNAL(fmt, ...) DHD_ERROR(("STATLOG-" fmt, ##__VA_ARGS__))
39 #define DHD_STATLOG_INFO_INTERNAL(fmt, ...) DHD_INFO(("STATLOG-" fmt, ##__VA_ARGS__))
40
41 #define DHD_STATLOG_PRINT(x) DHD_ERROR(x)
42 #define DHD_STATLOG_ERR(x) DHD_STATLOG_ERR_INTERNAL x
43 #define DHD_STATLOG_INFO(x) DHD_STATLOG_INFO_INTERNAL x
44 #define DHD_STATLOG_VALID(stat) (((stat) > (ST(INVALID))) && ((stat) < (ST(MAX))))
45
46 dhd_statlog_handle_t *
dhd_attach_statlog(dhd_pub_t * dhdp,uint32 num_items,uint32 bdlog_num_items,uint32 logbuf_len)47 dhd_attach_statlog(dhd_pub_t *dhdp, uint32 num_items, uint32 bdlog_num_items, uint32 logbuf_len)
48 {
49 dhd_statlog_t *statlog = NULL;
50 void *buf = NULL;
51
52 if (!dhdp) {
53 DHD_STATLOG_ERR(("%s: dhdp is NULL\n", __FUNCTION__));
54 return NULL;
55 }
56
57 statlog = (dhd_statlog_t *)VMALLOCZ(dhdp->osh, sizeof(dhd_statlog_t));
58 if (!statlog) {
59 DHD_STATLOG_ERR(("%s: failed to allocate memory for dhd_statlog_t\n",
60 __FUNCTION__));
61 return NULL;
62 }
63
64 /* allocate log buffer */
65 statlog->logbuf = (uint8 *)VMALLOCZ(dhdp->osh, logbuf_len);
66 if (!statlog->logbuf) {
67 DHD_STATLOG_ERR(("%s: failed to alloc log buffer\n", __FUNCTION__));
68 goto error;
69 }
70 statlog->logbuf_len = logbuf_len;
71
72 /* alloc ring buffer */
73 statlog->bufsize = (uint32)(dhd_ring_get_hdr_size() +
74 DHD_STATLOG_RING_SIZE(num_items));
75 buf = VMALLOCZ(dhdp->osh, statlog->bufsize);
76 if (!buf) {
77 DHD_STATLOG_ERR(("%s: failed to allocate memory for ring buffer\n",
78 __FUNCTION__));
79 goto error;
80 }
81
82 statlog->ringbuf = dhd_ring_init(dhdp, buf, statlog->bufsize,
83 DHD_STATLOG_ITEM_SIZE, num_items, DHD_RING_TYPE_SINGLE_IDX);
84 if (!statlog->ringbuf) {
85 DHD_STATLOG_ERR(("%s: failed to init ring buffer\n", __FUNCTION__));
86 VMFREE(dhdp->osh, buf, statlog->bufsize);
87 goto error;
88 }
89
90 /* alloc ring buffer for bigdata logging */
91 statlog->bdlog_bufsize = (uint32)(dhd_ring_get_hdr_size() +
92 DHD_STATLOG_RING_SIZE(bdlog_num_items));
93 buf = VMALLOCZ(dhdp->osh, statlog->bdlog_bufsize);
94 if (!buf) {
95 DHD_STATLOG_ERR(("%s: failed to allocate memory for bigdata logging buffer\n",
96 __FUNCTION__));
97 goto error;
98 }
99
100 statlog->bdlog_ringbuf = dhd_ring_init(dhdp, buf, statlog->bdlog_bufsize,
101 DHD_STATLOG_ITEM_SIZE, bdlog_num_items, DHD_RING_TYPE_SINGLE_IDX);
102 if (!statlog->bdlog_ringbuf) {
103 DHD_STATLOG_ERR(("%s: failed to init ring buffer for bigdata logging\n",
104 __FUNCTION__));
105 VMFREE(dhdp->osh, buf, statlog->bdlog_bufsize);
106 goto error;
107 }
108
109 return (dhd_statlog_handle_t *)statlog;
110
111 error:
112 if (statlog->logbuf) {
113 VMFREE(dhdp->osh, statlog->logbuf, logbuf_len);
114 }
115
116 if (statlog->ringbuf) {
117 dhd_ring_deinit(dhdp, statlog->ringbuf);
118 VMFREE(dhdp->osh, statlog->ringbuf, statlog->bufsize);
119 }
120
121 if (statlog->bdlog_ringbuf) {
122 dhd_ring_deinit(dhdp, statlog->bdlog_ringbuf);
123 VMFREE(dhdp->osh, statlog->bdlog_ringbuf, statlog->bdlog_bufsize);
124 }
125
126 if (statlog) {
127 VMFREE(dhdp->osh, statlog, sizeof(dhd_statlog_t));
128 }
129
130 return NULL;
131 }
132
133 void
dhd_detach_statlog(dhd_pub_t * dhdp)134 dhd_detach_statlog(dhd_pub_t *dhdp)
135 {
136 dhd_statlog_t *statlog;
137
138 if (!dhdp) {
139 DHD_STATLOG_ERR(("%s: dhdp is NULL\n", __FUNCTION__));
140 return;
141 }
142
143 if (!dhdp->statlog) {
144 DHD_STATLOG_ERR(("%s: statlog is NULL\n", __FUNCTION__));
145 return;
146 }
147
148 statlog = (dhd_statlog_t *)(dhdp->statlog);
149
150 if (statlog->bdlog_ringbuf) {
151 dhd_ring_deinit(dhdp, statlog->bdlog_ringbuf);
152 VMFREE(dhdp->osh, statlog->bdlog_ringbuf, statlog->bdlog_bufsize);
153 }
154
155 if (statlog->ringbuf) {
156 dhd_ring_deinit(dhdp, statlog->ringbuf);
157 VMFREE(dhdp->osh, statlog->ringbuf, statlog->bufsize);
158 }
159
160 if (statlog->logbuf) {
161 VMFREE(dhdp->osh, statlog->logbuf, statlog->logbuf_len);
162 }
163
164 VMFREE(dhdp->osh, statlog, sizeof(dhd_statlog_t));
165 dhdp->statlog = NULL;
166 }
167
168 static int
dhd_statlog_ring_log(dhd_pub_t * dhdp,uint16 stat,uint8 ifidx,uint8 dir,uint16 status,uint16 reason)169 dhd_statlog_ring_log(dhd_pub_t *dhdp, uint16 stat, uint8 ifidx, uint8 dir,
170 uint16 status, uint16 reason)
171 {
172 dhd_statlog_t *statlog;
173 stat_elem_t *elem;
174
175 if (!dhdp || !dhdp->statlog) {
176 DHD_STATLOG_ERR(("%s: dhdp or dhdp->statlog is NULL\n",
177 __FUNCTION__));
178 return BCME_ERROR;
179 }
180
181 if (ifidx >= DHD_MAX_IFS) {
182 DHD_STATLOG_ERR(("%s: invalid ifidx %d\n", __FUNCTION__, ifidx));
183 return BCME_ERROR;
184 }
185
186 if (!DHD_STATLOG_VALID(stat)) {
187 DHD_STATLOG_ERR(("%s: invalid stat %d\n", __FUNCTION__, stat));
188 return BCME_ERROR;
189 }
190
191 statlog = (dhd_statlog_t *)(dhdp->statlog);
192 elem = (stat_elem_t *)dhd_ring_get_empty(statlog->ringbuf);
193 if (!elem) {
194 /* no available slot */
195 DHD_STATLOG_ERR(("%s: cannot allocate a new element\n",
196 __FUNCTION__));
197 return BCME_ERROR;
198 }
199
200 elem->ts_tz = OSL_SYSTZTIME_US();
201 elem->ts = OSL_LOCALTIME_NS();
202 elem->stat = stat;
203 elem->ifidx = ifidx;
204 elem->dir = dir;
205 elem->reason = reason;
206 elem->status = status;
207
208 /* Logging for the bigdata */
209 if (isset(statlog->bdmask, stat)) {
210 stat_elem_t *elem_bd;
211 elem_bd = (stat_elem_t *)dhd_ring_get_empty(statlog->bdlog_ringbuf);
212 if (!elem_bd) {
213 /* no available slot */
214 DHD_STATLOG_ERR(("%s: cannot allocate a new element for bigdata\n",
215 __FUNCTION__));
216 return BCME_ERROR;
217 }
218 bcopy(elem, elem_bd, sizeof(stat_elem_t));
219 }
220
221 return BCME_OK;
222 }
223
224 int
dhd_statlog_ring_log_data(dhd_pub_t * dhdp,uint16 stat,uint8 ifidx,uint8 dir,bool cond)225 dhd_statlog_ring_log_data(dhd_pub_t *dhdp, uint16 stat, uint8 ifidx,
226 uint8 dir, bool cond)
227 {
228 return cond ? dhd_statlog_ring_log(dhdp, stat, ifidx,
229 dir ? STDIR(TX) : STDIR(RX), 0, 0) : BCME_OK;
230 }
231
232 int
dhd_statlog_ring_log_data_reason(dhd_pub_t * dhdp,uint16 stat,uint8 ifidx,uint8 dir,uint16 reason)233 dhd_statlog_ring_log_data_reason(dhd_pub_t *dhdp, uint16 stat,
234 uint8 ifidx, uint8 dir, uint16 reason)
235 {
236 return dhd_statlog_ring_log(dhdp, stat, ifidx,
237 dir ? STDIR(TX) : STDIR(RX), 0, reason);
238 }
239
240 int
dhd_statlog_ring_log_ctrl(dhd_pub_t * dhdp,uint16 stat,uint8 ifidx,uint16 reason)241 dhd_statlog_ring_log_ctrl(dhd_pub_t *dhdp, uint16 stat, uint8 ifidx, uint16 reason)
242 {
243 return dhd_statlog_ring_log(dhdp, stat, ifidx, ST(DIR_TX), 0, reason);
244 }
245
246 int
dhd_statlog_process_event(dhd_pub_t * dhdp,int type,uint8 ifidx,uint16 status,uint16 reason,uint16 flags)247 dhd_statlog_process_event(dhd_pub_t *dhdp, int type, uint8 ifidx,
248 uint16 status, uint16 reason, uint16 flags)
249 {
250 int stat = ST(INVALID);
251 uint8 dir = STDIR(RX);
252
253 if (!dhdp || !dhdp->statlog) {
254 DHD_STATLOG_ERR(("%s: dhdp or dhdp->statlog is NULL\n",
255 __FUNCTION__));
256 return BCME_ERROR;
257 }
258
259 switch (type) {
260 case WLC_E_SET_SSID:
261 if (status == WLC_E_STATUS_SUCCESS) {
262 stat = ST(ASSOC_DONE);
263 } else if (status == WLC_E_STATUS_TIMEOUT) {
264 stat = ST(ASSOC_TIMEOUT);
265 } else if (status == WLC_E_STATUS_FAIL) {
266 stat = ST(ASSOC_FAIL);
267 } else if (status == WLC_E_STATUS_NO_ACK) {
268 stat = ST(ASSOC_NO_ACK);
269 } else if (status == WLC_E_STATUS_ABORT) {
270 stat = ST(ASSOC_ABORT);
271 } else if (status == WLC_E_STATUS_UNSOLICITED) {
272 stat = ST(ASSOC_UNSOLICITED);
273 } else if (status == WLC_E_STATUS_NO_NETWORKS) {
274 stat = ST(ASSOC_NO_NETWORKS);
275 } else {
276 stat = ST(ASSOC_OTHERS);
277 }
278 break;
279 case WLC_E_AUTH:
280 if (status == WLC_E_STATUS_SUCCESS) {
281 stat = ST(AUTH_DONE);
282 } else if (status == WLC_E_STATUS_TIMEOUT) {
283 stat = ST(AUTH_TIMEOUT);
284 } else if (status == WLC_E_STATUS_FAIL) {
285 stat = ST(AUTH_FAIL);
286 } else if (status == WLC_E_STATUS_NO_ACK) {
287 stat = ST(AUTH_NO_ACK);
288 } else {
289 stat = ST(AUTH_OTHERS);
290 }
291 dir = STDIR(TX);
292 break;
293 case WLC_E_AUTH_IND:
294 stat = ST(AUTH_DONE);
295 break;
296 case WLC_E_DEAUTH:
297 stat = ST(DEAUTH);
298 dir = STDIR(TX);
299 break;
300 case WLC_E_DEAUTH_IND:
301 stat = ST(DEAUTH);
302 break;
303 case WLC_E_DISASSOC:
304 stat = ST(DISASSOC);
305 dir = STDIR(TX);
306 break;
307 case WLC_E_LINK:
308 if (!(flags & WLC_EVENT_MSG_LINK)) {
309 stat = ST(LINKDOWN);
310 }
311 break;
312 case WLC_E_ROAM_PREP:
313 stat = ST(REASSOC_START);
314 break;
315 case WLC_E_ASSOC_REQ_IE:
316 stat = ST(ASSOC_REQ);
317 dir = STDIR(TX);
318 break;
319 case WLC_E_ASSOC_RESP_IE:
320 stat = ST(ASSOC_RESP);
321 break;
322 case WLC_E_BSSID:
323 if (status == WLC_E_STATUS_SUCCESS) {
324 stat = ST(REASSOC_DONE);
325 } else {
326 stat = ST(REASSOC_DONE_OTHERS);
327 }
328 break;
329 case WLC_E_REASSOC:
330 if (status == WLC_E_STATUS_SUCCESS) {
331 stat = ST(REASSOC_SUCCESS);
332 } else {
333 stat = ST(REASSOC_FAILURE);
334 }
335 dir = STDIR(TX);
336 break;
337 case WLC_E_ASSOC_IND:
338 stat = ST(ASSOC_REQ);
339 break;
340 default:
341 break;
342 }
343
344 /* logging interested events */
345 if (DHD_STATLOG_VALID(stat)) {
346 dhd_statlog_ring_log(dhdp, stat, ifidx, dir, status, reason);
347 }
348
349 return BCME_OK;
350 }
351
352 uint32
dhd_statlog_get_logbuf_len(dhd_pub_t * dhdp)353 dhd_statlog_get_logbuf_len(dhd_pub_t *dhdp)
354 {
355 uint32 length = 0;
356 dhd_statlog_t *statlog;
357
358 if (dhdp && dhdp->statlog) {
359 statlog = (dhd_statlog_t *)(dhdp->statlog);
360 length = statlog->logbuf_len;
361 }
362
363 return length;
364 }
365
366 void *
dhd_statlog_get_logbuf(dhd_pub_t * dhdp)367 dhd_statlog_get_logbuf(dhd_pub_t *dhdp)
368 {
369 dhd_statlog_t *statlog;
370 void *ret_addr = NULL;
371
372 if (dhdp && dhdp->statlog) {
373 statlog = (dhd_statlog_t *)(dhdp->statlog);
374 ret_addr = (void *)(statlog->logbuf);
375 }
376
377 return ret_addr;
378 }
379
380 /*
381 * called function uses buflen as the DHD_STATLOG_STATSTR_BUF_LEN max.
382 * So when adding a case, make sure the string is less than
383 * the DHD_STATLOG_STATSTR_BUF_LEN bytes
384 */
385 static void
dhd_statlog_stat_name(char * buf,uint32 buflen,uint32 state,uint8 dir)386 dhd_statlog_stat_name(char *buf, uint32 buflen, uint32 state, uint8 dir)
387 {
388 char *stat_str = NULL;
389 bool tx = (dir == STDIR(TX));
390 uint32 max_buf_len = MIN(buflen, DHD_STATLOG_STATSTR_BUF_LEN);
391
392 switch (state) {
393 case ST(INVALID):
394 stat_str = "INVALID_STATE";
395 break;
396 case ST(WLAN_POWER_ON):
397 stat_str = "WLAN_POWER_ON";
398 break;
399 case ST(WLAN_POWER_OFF):
400 stat_str = "WLAN_POWER_OFF";
401 break;
402 case ST(ASSOC_START):
403 stat_str = "ASSOC_START";
404 break;
405 case ST(AUTH_DONE):
406 stat_str = "AUTH_DONE";
407 break;
408 case ST(ASSOC_REQ):
409 stat_str = tx ? "ASSOC_REQ" : "RX_ASSOC_REQ";
410 break;
411 case ST(ASSOC_RESP):
412 stat_str = "ASSOC_RESP";
413 break;
414 case ST(ASSOC_DONE):
415 stat_str = "ASSOC_DONE";
416 break;
417 case ST(DISASSOC_START):
418 stat_str = "DISASSOC_START";
419 break;
420 case ST(DISASSOC_INT_START):
421 stat_str = "DISASSOC_INTERNAL_START";
422 break;
423 case ST(DISASSOC_DONE):
424 stat_str = "DISASSOC_DONE";
425 break;
426 case ST(DISASSOC):
427 stat_str = tx ? "DISASSOC_EVENT" : "DISASSOC_IND_EVENT";
428 break;
429 case ST(DEAUTH):
430 stat_str = tx ? "DEAUTH_EVENT" : "DEAUTH_IND_EVENT";
431 break;
432 case ST(LINKDOWN):
433 stat_str = "LINKDOWN_EVENT";
434 break;
435 case ST(REASSOC_START):
436 stat_str = "REASSOC_START";
437 break;
438 case ST(REASSOC_INFORM):
439 stat_str = "REASSOC_INFORM";
440 break;
441 case ST(REASSOC_DONE):
442 stat_str = "REASSOC_DONE_SUCCESS";
443 break;
444 case ST(EAPOL_M1):
445 stat_str = tx ? "TX_EAPOL_M1" : "RX_EAPOL_M1";
446 break;
447 case ST(EAPOL_M2):
448 stat_str = tx ? "TX_EAPOL_M2" : "RX_EAPOL_M2";
449 break;
450 case ST(EAPOL_M3):
451 stat_str = tx ? "TX_EAPOL_M3" : "RX_EAPOL_M3";
452 break;
453 case ST(EAPOL_M4):
454 stat_str = tx ? "TX_EAPOL_M4" : "RX_EAPOL_M4";
455 break;
456 case ST(EAPOL_GROUPKEY_M1):
457 stat_str = tx ? "TX_EAPOL_GROUPKEY_M1" : "RX_EAPOL_GROUPKEY_M1";
458 break;
459 case ST(EAPOL_GROUPKEY_M2):
460 stat_str = tx ? "TX_EAPOL_GROUPKEY_M2" : "RX_EAPOL_GROUPKEY_M2";
461 break;
462 case ST(EAP_REQ_IDENTITY):
463 stat_str = tx ? "TX_EAP_REQ_IDENTITY" : "RX_EAP_REQ_IDENTITY";
464 break;
465 case ST(EAP_RESP_IDENTITY):
466 stat_str = tx ? "TX_EAP_RESP_IDENTITY" : "RX_EAP_RESP_IDENTITY";
467 break;
468 case ST(EAP_REQ_TLS):
469 stat_str = tx ? "TX_EAP_REQ_TLS" : "RX_EAP_REQ_TLS";
470 break;
471 case ST(EAP_RESP_TLS):
472 stat_str = tx ? "TX_EAP_RESP_TLS" : "RX_EAP_RESP_TLS";
473 break;
474 case ST(EAP_REQ_LEAP):
475 stat_str = tx ? "TX_EAP_REQ_LEAP" : "RX_EAP_REQ_LEAP";
476 break;
477 case ST(EAP_RESP_LEAP):
478 stat_str = tx ? "TX_EAP_RESP_LEAP" : "RX_EAP_RESP_LEAP";
479 break;
480 case ST(EAP_REQ_TTLS):
481 stat_str = tx ? "TX_EAP_REQ_TTLS" : "RX_EAP_REQ_TTLS";
482 break;
483 case ST(EAP_RESP_TTLS):
484 stat_str = tx ? "TX_EAP_RESP_TTLS" : "RX_EAP_RESP_TTLS";
485 break;
486 case ST(EAP_REQ_AKA):
487 stat_str = tx ? "TX_EAP_REQ_AKA" : "RX_EAP_REQ_AKA";
488 break;
489 case ST(EAP_RESP_AKA):
490 stat_str = tx ? "TX_EAP_RESP_AKA" : "RX_EAP_RESP_AKA";
491 break;
492 case ST(EAP_REQ_PEAP):
493 stat_str = tx ? "TX_EAP_REQ_PEAP" : "RX_EAP_REQ_PEAP";
494 break;
495 case ST(EAP_RESP_PEAP):
496 stat_str = tx ? "TX_EAP_RESP_PEAP" : "RX_EAP_RESP_PEAP";
497 break;
498 case ST(EAP_REQ_FAST):
499 stat_str = tx ? "TX_EAP_REQ_FAST" : "RX_EAP_REQ_FAST";
500 break;
501 case ST(EAP_RESP_FAST):
502 stat_str = tx ? "TX_EAP_RESP_FAST" : "RX_EAP_RESP_FAST";
503 break;
504 case ST(EAP_REQ_PSK):
505 stat_str = tx ? "TX_EAP_REQ_PSK" : "RX_EAP_REQ_PSK";
506 break;
507 case ST(EAP_RESP_PSK):
508 stat_str = tx ? "TX_EAP_RESP_PSK" : "RX_EAP_RESP_PSK";
509 break;
510 case ST(EAP_REQ_AKAP):
511 stat_str = tx ? "TX_EAP_REQ_AKAP" : "RX_EAP_REQ_AKAP";
512 break;
513 case ST(EAP_RESP_AKAP):
514 stat_str = tx ? "TX_EAP_RESP_AKAP" : "RX_EAP_RESP_AKAP";
515 break;
516 case ST(EAP_SUCCESS):
517 stat_str = tx ? "TX_EAP_SUCCESS" : "RX_EAP_SUCCESS";
518 break;
519 case ST(EAP_FAILURE):
520 stat_str = tx ? "TX_EAP_FAILURE" : "RX_EAP_FAILURE";
521 break;
522 case ST(EAPOL_START):
523 stat_str = tx ? "TX_EAPOL_START" : "RX_EAPOL_START";
524 break;
525 case ST(WSC_START):
526 stat_str = tx ? "TX_WSC_START" : "RX_WSC_START";
527 break;
528 case ST(WSC_DONE):
529 stat_str = tx ? "TX_WSC_DONE" : "RX_WSC_DONE";
530 break;
531 case ST(WPS_M1):
532 stat_str = tx ? "TX_WPS_M1" : "RX_WPS_M1";
533 break;
534 case ST(WPS_M2):
535 stat_str = tx ? "TX_WPS_M2" : "RX_WPS_M2";
536 break;
537 case ST(WPS_M3):
538 stat_str = tx ? "TX_WPS_M3" : "RX_WPS_M3";
539 break;
540 case ST(WPS_M4):
541 stat_str = tx ? "TX_WPS_M4" : "RX_WPS_M4";
542 break;
543 case ST(WPS_M5):
544 stat_str = tx ? "TX_WPS_M5" : "RX_WPS_M5";
545 break;
546 case ST(WPS_M6):
547 stat_str = tx ? "TX_WPS_M6" : "RX_WPS_M6";
548 break;
549 case ST(WPS_M7):
550 stat_str = tx ? "TX_WPS_M7" : "RX_WPS_M7";
551 break;
552 case ST(WPS_M8):
553 stat_str = tx ? "TX_WPS_M8" : "RX_WPS_M8";
554 break;
555 case ST(8021X_OTHER):
556 stat_str = tx ? "TX_OTHER_8021X" : "RX_OTHER_8021X";
557 break;
558 case ST(INSTALL_KEY):
559 stat_str = "INSTALL_KEY";
560 break;
561 case ST(DELETE_KEY):
562 stat_str = "DELETE_KEY";
563 break;
564 case ST(INSTALL_PMKSA):
565 stat_str = "INSTALL_PMKSA";
566 break;
567 case ST(INSTALL_OKC_PMK):
568 stat_str = "INSTALL_OKC_PMK";
569 break;
570 case ST(DHCP_DISCOVER):
571 stat_str = tx ? "TX_DHCP_DISCOVER" : "RX_DHCP_DISCOVER";
572 break;
573 case ST(DHCP_OFFER):
574 stat_str = tx ? "TX_DHCP_OFFER" : "RX_DHCP_OFFER";
575 break;
576 case ST(DHCP_REQUEST):
577 stat_str = tx ? "TX_DHCP_REQUEST" : "RX_DHCP_REQUEST";
578 break;
579 case ST(DHCP_DECLINE):
580 stat_str = tx ? "TX_DHCP_DECLINE" : "RX_DHCP_DECLINE";
581 break;
582 case ST(DHCP_ACK):
583 stat_str = tx ? "TX_DHCP_ACK" : "RX_DHCP_ACK";
584 break;
585 case ST(DHCP_NAK):
586 stat_str = tx ? "TX_DHCP_NAK" : "RX_DHCP_NAK";
587 break;
588 case ST(DHCP_RELEASE):
589 stat_str = tx ? "TX_DHCP_RELEASE" : "RX_DHCP_RELEASE";
590 break;
591 case ST(DHCP_INFORM):
592 stat_str = tx ? "TX_DHCP_INFORM" : "RX_DHCP_INFORM";
593 break;
594 case ST(ICMP_PING_REQ):
595 stat_str = tx ? "TX_ICMP_PING_REQ" : "RX_ICMP_PING_REQ";
596 break;
597 case ST(ICMP_PING_RESP):
598 stat_str = tx ? "TX_ICMP_PING_RESP" : "RX_ICMP_PING_RESP";
599 break;
600 case ST(ICMP_DEST_UNREACH):
601 stat_str = tx ? "TX_ICMP_DEST_UNREACH" : "RX_ICMP_DEST_UNREACH";
602 break;
603 case ST(ICMP_OTHER):
604 stat_str = tx ? "TX_ICMP_OTHER" : "RX_ICMP_OTHER";
605 break;
606 case ST(ARP_REQ):
607 stat_str = tx ? "TX_ARP_REQ" : "RX_ARP_REQ";
608 break;
609 case ST(ARP_RESP):
610 stat_str = tx ? "TX_ARP_RESP" : "RX_ARP_RESP";
611 break;
612 case ST(DNS_QUERY):
613 stat_str = tx ? "TX_DNS_QUERY" : "RX_DNS_QUERY";
614 break;
615 case ST(DNS_RESP):
616 stat_str = tx ? "TX_DNS_RESP" : "RX_DNS_RESP";
617 break;
618 case ST(REASSOC_SUCCESS):
619 stat_str = "REASSOC_SUCCESS";
620 break;
621 case ST(REASSOC_FAILURE):
622 stat_str = "REASSOC_FAILURE";
623 break;
624 case ST(AUTH_TIMEOUT):
625 stat_str = "AUTH_TIMEOUT";
626 break;
627 case ST(AUTH_FAIL):
628 stat_str = "AUTH_FAIL";
629 break;
630 case ST(AUTH_NO_ACK):
631 stat_str = "AUTH_NO_ACK";
632 break;
633 case ST(AUTH_OTHERS):
634 stat_str = "AUTH_FAIL_OTHER_STATUS";
635 break;
636 case ST(ASSOC_TIMEOUT):
637 stat_str = "ASSOC_TIMEOUT";
638 break;
639 case ST(ASSOC_FAIL):
640 stat_str = "ASSOC_FAIL";
641 break;
642 case ST(ASSOC_NO_ACK):
643 stat_str = "ASSOC_NO_ACK";
644 break;
645 case ST(ASSOC_ABORT):
646 stat_str = "ASSOC_ABORT";
647 break;
648 case ST(ASSOC_UNSOLICITED):
649 stat_str = "ASSOC_UNSOLICITED";
650 break;
651 case ST(ASSOC_NO_NETWORKS):
652 stat_str = "ASSOC_NO_NETWORKS";
653 break;
654 case ST(ASSOC_OTHERS):
655 stat_str = "ASSOC_FAIL_OTHER_STATUS";
656 break;
657 case ST(REASSOC_DONE_OTHERS):
658 stat_str = "REASSOC_DONE_OTHER_STATUS";
659 break;
660 default:
661 stat_str = "UNKNOWN_STATUS";
662 break;
663 }
664
665 strncpy(buf, stat_str, max_buf_len);
666 buf[max_buf_len - 1] = '\0';
667 }
668
669 static void
dhd_statlog_get_timestamp(stat_elem_t * elem,uint64 * sec,uint64 * usec)670 dhd_statlog_get_timestamp(stat_elem_t *elem, uint64 *sec, uint64 *usec)
671 {
672 uint64 ts_nsec, rem_nsec;
673
674 ts_nsec = elem->ts;
675 rem_nsec = DIV_AND_MOD_U64_BY_U32(ts_nsec, NSEC_PER_SEC);
676 *sec = ts_nsec;
677 *usec = (uint64)(rem_nsec / NSEC_PER_USEC);
678 }
679
680 static void
dhd_statlog_convert_time(stat_elem_t * elem,uint8 * buf,uint32 buflen)681 dhd_statlog_convert_time(stat_elem_t *elem, uint8 *buf, uint32 buflen)
682 {
683 #if defined(LINUX) || defined(linux)
684 struct rtc_time tm;
685 uint64 ts_sec, rem_usec;
686
687 if (!buf) {
688 DHD_STATLOG_ERR(("%s: buf is NULL\n", __FUNCTION__));
689 return;
690 }
691
692 bzero(buf, buflen);
693 ts_sec = elem->ts_tz;
694 rem_usec = DIV_AND_MOD_U64_BY_U32(ts_sec, USEC_PER_SEC);
695
696 rtc_time_to_tm((unsigned long)ts_sec, &tm);
697 snprintf(buf, buflen, DHD_STATLOG_TZFMT_YYMMDDHHMMSSMS,
698 tm.tm_year - 100, tm.tm_mon + 1, tm.tm_mday,
699 tm.tm_hour, tm.tm_min, tm.tm_sec,
700 (uint32)(rem_usec / USEC_PER_MSEC));
701 #endif /* LINUX || linux */
702 }
703
704 #ifdef DHD_LOG_DUMP
705 static int
dhd_statlog_dump(dhd_statlog_t * statlog,char * buf,uint32 buflen)706 dhd_statlog_dump(dhd_statlog_t *statlog, char *buf, uint32 buflen)
707 {
708 stat_elem_t *elem;
709 struct bcmstrbuf b;
710 struct bcmstrbuf *strbuf = &b;
711 char stat_str[DHD_STATLOG_STATSTR_BUF_LEN];
712 char ts_str[DHD_STATLOG_TZFMT_BUF_LEN];
713 uint64 sec = 0, usec = 0;
714
715 if (!statlog) {
716 DHD_STATLOG_ERR(("%s: statlog is NULL\n", __FUNCTION__));
717 return BCME_ERROR;
718 }
719
720 bcm_binit(strbuf, buf, buflen);
721 bzero(stat_str, sizeof(stat_str));
722 bzero(ts_str, sizeof(ts_str));
723 dhd_ring_whole_lock(statlog->ringbuf);
724 elem = (stat_elem_t *)dhd_ring_get_first(statlog->ringbuf);
725 while (elem) {
726 if (DHD_STATLOG_VALID(elem->stat)) {
727 dhd_statlog_stat_name(stat_str, sizeof(stat_str),
728 elem->stat, elem->dir);
729 dhd_statlog_get_timestamp(elem, &sec, &usec);
730 dhd_statlog_convert_time(elem, ts_str, sizeof(ts_str));
731 bcm_bprintf(strbuf, "[%s][%5lu.%06lu] status=%s, ifidx=%d, "
732 "reason=%d, status=%d\n", ts_str, (unsigned long)sec,
733 (unsigned long)usec, stat_str, elem->ifidx,
734 elem->reason, elem->status);
735 }
736 elem = (stat_elem_t *)dhd_ring_get_next(statlog->ringbuf, (void *)elem);
737 }
738 dhd_ring_whole_unlock(statlog->ringbuf);
739
740 return (!strbuf->size ? BCME_BUFTOOSHORT : strbuf->size);
741 }
742
743 int
dhd_statlog_write_logdump(dhd_pub_t * dhdp,const void * user_buf,void * fp,uint32 len,unsigned long * pos)744 dhd_statlog_write_logdump(dhd_pub_t *dhdp, const void *user_buf,
745 void *fp, uint32 len, unsigned long *pos)
746 {
747 dhd_statlog_t *statlog;
748 log_dump_section_hdr_t sec_hdr;
749 char *buf;
750 uint32 buflen;
751 int remain_len = 0;
752 int ret = BCME_OK;
753
754 if (!dhdp || !dhdp->statlog) {
755 DHD_STATLOG_ERR(("%s: dhdp or dhdp->statlog is NULL\n",
756 __FUNCTION__));
757 return BCME_ERROR;
758 }
759
760 statlog = (dhd_statlog_t *)(dhdp->statlog);
761 if (!statlog->logbuf) {
762 DHD_STATLOG_ERR(("%s: logbuf is NULL\n", __FUNCTION__));
763 return BCME_ERROR;
764 }
765
766 buf = statlog->logbuf;
767 buflen = statlog->logbuf_len;
768 bzero(buf, buflen);
769
770 remain_len = dhd_statlog_dump(statlog, buf, buflen);
771 if (remain_len < 0) {
772 DHD_STATLOG_ERR(("%s: failed to write stat info to buffer\n",
773 __FUNCTION__));
774 return BCME_ERROR;
775 }
776
777 DHD_STATLOG_INFO(("%s: Start to write statlog\n", __FUNCTION__));
778
779 /* write the section header first */
780 ret = dhd_export_debug_data(STATUS_LOG_HDR, fp, user_buf,
781 strlen(STATUS_LOG_HDR), pos);
782 if (ret < 0) {
783 goto exit;
784 }
785
786 dhd_init_sec_hdr(&sec_hdr);
787 sec_hdr.type = LOG_DUMP_SECTION_STATUS;
788 sec_hdr.length = buflen - remain_len;
789 ret = dhd_export_debug_data((char *)&sec_hdr, fp, user_buf,
790 sizeof(sec_hdr), pos);
791 if (ret < 0) {
792 goto exit;
793 }
794
795 /* write status log info */
796 ret = dhd_export_debug_data(buf, fp, user_buf, buflen - remain_len, pos);
797 if (ret < 0) {
798 DHD_STATLOG_ERR(("%s: failed to write stat info, err=%d\n",
799 __FUNCTION__, ret));
800 }
801
802 DHD_STATLOG_INFO(("%s: Complete to write statlog file, err=%d\n",
803 __FUNCTION__, ret));
804
805 exit:
806 return ret;
807 }
808 #endif /* DHD_LOG_DUMP */
809
810 int
dhd_statlog_generate_bdmask(dhd_pub_t * dhdp,void * reqbuf)811 dhd_statlog_generate_bdmask(dhd_pub_t *dhdp, void *reqbuf)
812 {
813 dhd_statlog_t *statlog;
814 stat_bdmask_req_t *query;
815 uint8 *req_buf;
816 uint32 req_buf_len;
817 int cnt;
818
819 if (!dhdp || !dhdp->statlog) {
820 DHD_STATLOG_ERR(("%s: dhdp or statlog is NULL\n", __FUNCTION__));
821 return BCME_ERROR;
822 }
823
824 if (!reqbuf) {
825 DHD_STATLOG_ERR(("%s: invalid query\n", __FUNCTION__));
826 return BCME_ERROR;
827 }
828
829 statlog = dhdp->statlog;
830 query = (stat_bdmask_req_t *)reqbuf;
831 req_buf = query->req_buf;
832 req_buf_len = query->req_buf_len;
833 if (!req_buf) {
834 DHD_STATLOG_ERR(("%s: invalid query\n", __FUNCTION__));
835 return BCME_ERROR;
836 }
837
838 bzero(statlog->bdmask, DHD_STAT_BDMASK_SIZE);
839 for (cnt = 0; cnt < req_buf_len; cnt++) {
840 if (DHD_STATLOG_VALID(req_buf[cnt])) {
841 setbit(statlog->bdmask, req_buf[cnt]);
842 }
843 }
844
845 return BCME_OK;
846 }
847
848 int
dhd_statlog_get_latest_info(dhd_pub_t * dhdp,void * reqbuf)849 dhd_statlog_get_latest_info(dhd_pub_t *dhdp, void *reqbuf)
850 {
851 dhd_statlog_t *statlog;
852 stat_query_t *query;
853 stat_elem_t *elem;
854 uint8 *req_buf, *resp_buf, *sp;
855 uint32 req_buf_len, resp_buf_len, req_num;
856 int i, remain_len, cpcnt = 0;
857 uint8 filter[DHD_STAT_BDMASK_SIZE];
858 bool query_bigdata = FALSE;
859 void *ringbuf;
860
861 if (!dhdp || !dhdp->statlog) {
862 DHD_STATLOG_ERR(("%s: dhdp or statlog is NULL\n",
863 __FUNCTION__));
864 return BCME_ERROR;
865 }
866
867 query = (stat_query_t *)reqbuf;
868 if (!query) {
869 DHD_STATLOG_ERR(("%s: invalid query\n", __FUNCTION__));
870 return BCME_ERROR;
871 }
872
873 statlog = (dhd_statlog_t *)(dhdp->statlog);
874 req_buf = query->req_buf;
875 req_buf_len = query->req_buf_len;
876 resp_buf = query->resp_buf;
877 resp_buf_len = query->resp_buf_len;
878 req_num = MIN(query->req_num, MAX_STATLOG_REQ_ITEM);
879 if (!resp_buf) {
880 DHD_STATLOG_ERR(("%s: invalid query\n", __FUNCTION__));
881 return BCME_ERROR;
882 }
883
884 bzero(filter, sizeof(filter));
885 if (!req_buf || !req_buf_len) {
886 query_bigdata = TRUE;
887 ringbuf = statlog->bdlog_ringbuf;
888 } else {
889 ringbuf = statlog->ringbuf;
890 /* build a filter from req_buf */
891 for (i = 0; i < req_buf_len; i++) {
892 if (DHD_STATLOG_VALID(req_buf[i])) {
893 setbit(filter, req_buf[i]);
894 }
895 }
896 }
897
898 sp = resp_buf;
899 remain_len = resp_buf_len;
900 dhd_ring_whole_lock(ringbuf);
901 elem = (stat_elem_t *)dhd_ring_get_last(ringbuf);
902 while (elem) {
903 if (query_bigdata || isset(filter, elem->stat)) {
904 /* found the status from the list of interests */
905 if (remain_len < sizeof(stat_elem_t)) {
906 dhd_ring_whole_unlock(ringbuf);
907 return BCME_BUFTOOSHORT;
908 }
909 bcopy((char *)elem, sp, sizeof(stat_elem_t));
910 sp += sizeof(stat_elem_t);
911 remain_len -= sizeof(stat_elem_t);
912 cpcnt++;
913 }
914
915 if (cpcnt >= req_num) {
916 break;
917 }
918
919 /* Proceed to next item */
920 elem = (stat_elem_t *)dhd_ring_get_prev(ringbuf, (void *)elem);
921 }
922 dhd_ring_whole_unlock(ringbuf);
923
924 return cpcnt;
925 }
926
927 int
dhd_statlog_query(dhd_pub_t * dhdp,char * cmd,int total_len)928 dhd_statlog_query(dhd_pub_t *dhdp, char *cmd, int total_len)
929 {
930 stat_elem_t *elem = NULL;
931 stat_query_t query;
932 char *pos, *token;
933 uint8 *req_buf = NULL, *resp_buf = NULL;
934 uint32 req_buf_len = 0, resp_buf_len = 0;
935 ulong req_num, stat_num, stat;
936 char stat_str[DHD_STATLOG_STATSTR_BUF_LEN];
937 uint64 sec = 0, usec = 0;
938 int i, resp_num, err = BCME_OK;
939 char ts_str[DHD_STATLOG_TZFMT_BUF_LEN];
940
941 /*
942 * DRIVER QUERY_STAT_LOG <total req num> <stat list num> <stat list>
943 * Note: use the defult status list if the 'stat list num' is zero
944 */
945 pos = cmd;
946 /* drop command */
947 token = bcmstrtok(&pos, " ", NULL);
948 /* total number of request */
949 token = bcmstrtok(&pos, " ", NULL);
950 if (!token) {
951 err = BCME_BADARG;
952 goto exit;
953 }
954
955 req_num = bcm_strtoul(token, NULL, 0);
956
957 /* total number of status list */
958 token = bcmstrtok(&pos, " ", NULL);
959 if (!token) {
960 err = BCME_BADARG;
961 goto exit;
962 }
963
964 stat_num = bcm_strtoul(token, NULL, 0);
965 if (stat_num) {
966 /* create a status list */
967 req_buf_len = (uint32)(stat_num * sizeof(uint8));
968 req_buf = (uint8 *)MALLOCZ(dhdp->osh, req_buf_len);
969 if (!req_buf) {
970 DHD_STATLOG_ERR(("%s: failed to allocate request buf\n",
971 __FUNCTION__));
972 err = BCME_NOMEM;
973 goto exit;
974 }
975
976 /* parse the status list and update to the request buffer */
977 for (i = 0; i < (uint32)stat_num; i++) {
978 token = bcmstrtok(&pos, " ", NULL);
979 if (!token) {
980 err = BCME_BADARG;
981 goto exit;
982 }
983 stat = bcm_strtoul(token, NULL, 0);
984 req_buf[i] = (uint8)stat;
985 }
986 }
987
988 /* creat a response list */
989 resp_buf_len = (uint32)DHD_STATLOG_RING_SIZE(req_num);
990 resp_buf = (uint8 *)MALLOCZ(dhdp->osh, resp_buf_len);
991 if (!resp_buf) {
992 DHD_STATLOG_ERR(("%s: failed to allocate response buf\n",
993 __FUNCTION__));
994 err = BCME_NOMEM;
995 goto exit;
996 }
997
998 /* create query format and query the status */
999 query.req_buf = req_buf;
1000 query.req_buf_len = req_buf_len;
1001 query.resp_buf = resp_buf;
1002 query.resp_buf_len = resp_buf_len;
1003 query.req_num = (uint32)req_num;
1004 resp_num = dhd_statlog_get_latest_info(dhdp, (void *)&query);
1005 if (resp_num < 0) {
1006 DHD_STATLOG_ERR(("%s: failed to query the status\n", __FUNCTION__));
1007 err = BCME_ERROR;
1008 goto exit;
1009 }
1010
1011 /* print out the results */
1012 DHD_STATLOG_PRINT(("=============== QUERY RESULT ===============\n"));
1013 if (resp_num > 0) {
1014 elem = (stat_elem_t *)resp_buf;
1015 for (i = 0; i < resp_num; i++) {
1016 if (DHD_STATLOG_VALID(elem->stat)) {
1017 dhd_statlog_stat_name(stat_str, sizeof(stat_str),
1018 elem->stat, elem->dir);
1019 dhd_statlog_get_timestamp(elem, &sec, &usec);
1020 dhd_statlog_convert_time(elem, ts_str, sizeof(ts_str));
1021 DHD_STATLOG_PRINT(("[RAWTS:%llu][%s][%5lu.%06lu] status=%s,"
1022 " ifidx=%d, reason=%d, status=%d\n", elem->ts_tz,
1023 ts_str, (unsigned long)sec, (unsigned long)usec,
1024 stat_str, elem->ifidx, elem->reason, elem->status));
1025 }
1026 elem++;
1027 }
1028 } else {
1029 DHD_STATLOG_PRINT(("No data found\n"));
1030 }
1031
1032 exit:
1033 if (resp_buf) {
1034 MFREE(dhdp->osh, resp_buf, resp_buf_len);
1035 }
1036
1037 if (req_buf) {
1038 MFREE(dhdp->osh, req_buf, req_buf_len);
1039 }
1040
1041 return err;
1042 }
1043
1044 void
dhd_statlog_dump_scr(dhd_pub_t * dhdp)1045 dhd_statlog_dump_scr(dhd_pub_t *dhdp)
1046 {
1047 dhd_statlog_t *statlog;
1048 stat_elem_t *elem;
1049 char stat_str[DHD_STATLOG_STATSTR_BUF_LEN];
1050 char ts_str[DHD_STATLOG_TZFMT_BUF_LEN];
1051 uint64 sec = 0, usec = 0;
1052
1053 if (!dhdp || !dhdp->statlog) {
1054 DHD_STATLOG_ERR(("%s: dhdp or statlog is NULL\n", __FUNCTION__));
1055 return;
1056 }
1057
1058 statlog = (dhd_statlog_t *)(dhdp->statlog);
1059 bzero(stat_str, sizeof(stat_str));
1060 bzero(ts_str, sizeof(ts_str));
1061
1062 DHD_STATLOG_PRINT(("=============== START OF CURRENT STATUS INFO ===============\n"));
1063 dhd_ring_whole_lock(statlog->ringbuf);
1064 elem = (stat_elem_t *)dhd_ring_get_first(statlog->ringbuf);
1065 while (elem) {
1066 if (DHD_STATLOG_VALID(elem->stat)) {
1067 dhd_statlog_stat_name(stat_str, sizeof(stat_str),
1068 elem->stat, elem->dir);
1069 dhd_statlog_get_timestamp(elem, &sec, &usec);
1070 dhd_statlog_convert_time(elem, ts_str, sizeof(ts_str));
1071 DHD_STATLOG_PRINT(("[RAWTS:%llu][%s][%5lu.%06lu] status=%s,"
1072 " ifidx=%d, reason=%d, status=%d\n", elem->ts_tz, ts_str,
1073 (unsigned long)sec, (unsigned long)usec, stat_str,
1074 elem->ifidx, elem->reason, elem->status));
1075 }
1076 elem = (stat_elem_t *)dhd_ring_get_next(statlog->ringbuf, (void *)elem);
1077 }
1078 dhd_ring_whole_unlock(statlog->ringbuf);
1079 DHD_STATLOG_PRINT(("=============== END OF CURRENT STATUS INFO ===============\n"));
1080 }
1081 #endif /* DHD_STATUS_LOGGING */
1082