1 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions
5 * are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "sync.h"
30
31 #include "wifi_hal.h"
32 #include "common.h"
33 #include "cpp_bindings.h"
34 #include <errno.h>
35 #include <utils/Log.h>
36 #include "wifiloggercmd.h"
37 #include "rb_wrapper.h"
38 #include <stdlib.h>
39
40 #define LOGGER_MEMDUMP_FILENAME "/proc/debug/fwdump"
41 #define LOGGER_MEMDUMP_CHUNKSIZE (4 * 1024)
42
43 char power_events_ring_name[] = "power_events_rb";
44 char connectivity_events_ring_name[] = "connectivity_events_rb";
45 char pkt_stats_ring_name[] = "pkt_stats_rb";
46 char driver_prints_ring_name[] = "driver_prints_rb";
47 char firmware_prints_ring_name[] = "firmware_prints_rb";
48
get_ring_id(hal_info * info,char * ring_name)49 static int get_ring_id(hal_info *info, char *ring_name)
50 {
51 int rb_id;
52
53 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
54 if (is_rb_name_match(&info->rb_infos[rb_id], ring_name)) {
55 return rb_id;
56 }
57 }
58 return -1;
59 }
60
61 //Implementation of the functions exposed in wifi_logger.h
62
63 /* Function to intiate logging */
wifi_start_logging(wifi_interface_handle iface,u32 verbose_level,u32 flags,u32 max_interval_sec,u32 min_data_size,char * buffer_name)64 wifi_error wifi_start_logging(wifi_interface_handle iface,
65 u32 verbose_level, u32 flags,
66 u32 max_interval_sec, u32 min_data_size,
67 char *buffer_name)
68 {
69 int requestId, ret = 0;
70 WifiLoggerCommand *wifiLoggerCommand = NULL;
71 struct nlattr *nlData;
72 interface_info *ifaceInfo = getIfaceInfo(iface);
73 wifi_handle wifiHandle = getWifiHandle(iface);
74 hal_info *info = getHalInfo(wifiHandle);
75 int ring_id = 0;
76
77 /*
78 * No request id from caller, so generate one and pass it on to the driver.
79 * Generate one randomly.
80 */
81 requestId = get_requestid();
82
83 if (buffer_name == NULL) {
84 ALOGE("%s: Invalid Ring Name. \n", __FUNCTION__);
85 return WIFI_ERROR_UNKNOWN;
86 }
87
88 ring_id = get_ring_id(info, buffer_name);
89 if (ring_id < 0) {
90 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__);
91 return WIFI_ERROR_UNKNOWN;
92 }
93
94 if ((ring_id == POWER_EVENTS_RB_ID) ||
95 (ring_id == PKT_STATS_RB_ID)) {
96 wifiLoggerCommand = new WifiLoggerCommand(
97 wifiHandle,
98 requestId,
99 OUI_QCA,
100 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START);
101
102 if (wifiLoggerCommand == NULL) {
103 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
104 return WIFI_ERROR_UNKNOWN;
105 }
106 /* Create the NL message. */
107 ret = wifiLoggerCommand->create();
108
109 if (ret < 0)
110 goto cleanup;
111
112 /* Set the interface Id of the message. */
113 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
114
115 if (ret < 0)
116 goto cleanup;
117
118 /* Add the vendor specific attributes for the NL command. */
119 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
120
121 if (!nlData)
122 goto cleanup;
123
124 if (wifiLoggerCommand->put_u32(
125 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID, ring_id))
126 {
127 goto cleanup;
128 }
129 if (wifiLoggerCommand->put_u32(
130 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL,
131 verbose_level))
132 {
133 goto cleanup;
134 }
135 if (wifiLoggerCommand->put_u32(
136 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS,
137 flags))
138 {
139 goto cleanup;
140 }
141
142 wifiLoggerCommand->attr_end(nlData);
143
144 /* Send the msg and wait for a response. */
145 ret = wifiLoggerCommand->requestResponse();
146 if (ret) {
147 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
148 }
149
150 }
151 ALOGV("%s: Logging Started for %s.", __FUNCTION__, buffer_name);
152 rb_start_logging(&info->rb_infos[ring_id], verbose_level,
153 flags, max_interval_sec, min_data_size);
154 cleanup:
155 if (wifiLoggerCommand)
156 delete wifiLoggerCommand;
157 return (wifi_error)ret;
158
159 }
160
161 /* Function to get each ring related info */
wifi_get_ring_buffers_status(wifi_interface_handle iface,u32 * num_buffers,wifi_ring_buffer_status * status)162 wifi_error wifi_get_ring_buffers_status(wifi_interface_handle iface,
163 u32 *num_buffers,
164 wifi_ring_buffer_status *status)
165 {
166 int ret = 0;
167 interface_info *ifaceInfo = getIfaceInfo(iface);
168 wifi_handle wifiHandle = getWifiHandle(iface);
169 hal_info *info = getHalInfo(wifiHandle);
170 wifi_ring_buffer_status *rbs;
171 struct rb_info *rb_info;
172 int rb_id;
173
174 if ((*num_buffers) < NUM_RING_BUFS) {
175 ALOGE("%s: Input num_buffers:%d cannot be accommodated, "
176 "Total ring buffer num:%d", __FUNCTION__, num_buffers,
177 NUM_RING_BUFS);
178 *num_buffers = 0;
179 return WIFI_ERROR_OUT_OF_MEMORY;
180 }
181 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
182 rb_info = &info->rb_infos[rb_id];
183 rbs = status + rb_id;
184
185 get_rb_status(rb_info, rbs);
186 }
187 *num_buffers = NUM_RING_BUFS;
188 return (wifi_error)ret;
189 }
190
push_out_all_ring_buffers(hal_info * info)191 void push_out_all_ring_buffers(hal_info *info)
192 {
193 int rb_id;
194
195 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
196 push_out_rb_data(&info->rb_infos[rb_id]);
197 }
198 }
199
send_alert(hal_info * info,int reason_code)200 void send_alert(hal_info *info, int reason_code)
201 {
202 wifi_alert_handler handler;
203
204 pthread_mutex_lock(&info->ah_lock);
205 handler.on_alert = info->on_alert;
206 pthread_mutex_unlock(&info->ah_lock);
207
208 if (handler.on_alert) {
209 handler.on_alert(0, NULL, 0, reason_code);
210 }
211 }
212
setFeatureSet(u32 * support)213 void WifiLoggerCommand::setFeatureSet(u32 *support) {
214 mSupportedSet = support;
215 }
216
217 /* Function to get the supported feature set for logging.*/
wifi_get_logger_supported_feature_set(wifi_interface_handle iface,u32 * support)218 wifi_error wifi_get_logger_supported_feature_set(wifi_interface_handle iface,
219 u32 *support)
220 {
221
222 int requestId, ret = 0;
223 WifiLoggerCommand *wifiLoggerCommand;
224 struct nlattr *nlData;
225 interface_info *ifaceInfo = getIfaceInfo(iface);
226 wifi_handle wifiHandle = getWifiHandle(iface);
227 hal_info *info = getHalInfo(wifiHandle);
228
229 /* No request id from caller, so generate one and pass it on to the driver.
230 * Generate one randomly.
231 */
232 requestId = get_requestid();
233
234 wifiLoggerCommand = new WifiLoggerCommand(
235 wifiHandle,
236 requestId,
237 OUI_QCA,
238 QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET);
239
240 if (wifiLoggerCommand == NULL) {
241 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
242 return WIFI_ERROR_UNKNOWN;
243 }
244 /* Create the NL message. */
245 ret = wifiLoggerCommand->create();
246
247 if (ret < 0)
248 goto cleanup;
249
250 /* Set the interface Id of the message. */
251 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
252
253 if (ret < 0)
254 goto cleanup;
255
256 /* Add the vendor specific attributes for the NL command. */
257 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
258
259 if (!nlData)
260 goto cleanup;
261
262 if (wifiLoggerCommand->put_u32(
263 QCA_WLAN_VENDOR_ATTR_FEATURE_SET, requestId))
264 {
265 goto cleanup;
266 }
267 wifiLoggerCommand->attr_end(nlData);
268
269 wifiLoggerCommand->setFeatureSet(support);
270
271 /* Send the msg and wait for a response. */
272 ret = wifiLoggerCommand->requestResponse();
273 if (ret) {
274 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
275 }
276
277 cleanup:
278 delete wifiLoggerCommand;
279 return (wifi_error)ret;
280 }
281
282 /* Function to get the data in each ring for the given ring ID.*/
wifi_get_ring_data(wifi_interface_handle iface,char * ring_name)283 wifi_error wifi_get_ring_data(wifi_interface_handle iface,
284 char *ring_name)
285 {
286
287 int requestId, ret = 0;
288 WifiLoggerCommand *wifiLoggerCommand;
289 struct nlattr *nlData;
290 interface_info *ifaceInfo = getIfaceInfo(iface);
291 wifi_handle wifiHandle = getWifiHandle(iface);
292 hal_info *info = getHalInfo(wifiHandle);
293 int ring_id = 0;
294
295 ring_id = get_ring_id(info, ring_name);
296 if (ring_id < 0) {
297 ALOGE("%s: Invalid Ring Buffer Name ", __FUNCTION__);
298 return WIFI_ERROR_UNKNOWN;
299 }
300
301 requestId = get_requestid();
302
303 wifiLoggerCommand = new WifiLoggerCommand(
304 wifiHandle,
305 requestId,
306 OUI_QCA,
307 QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA);
308 if (wifiLoggerCommand == NULL) {
309 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
310 return WIFI_ERROR_UNKNOWN;
311 }
312 /* Create the NL message. */
313 ret = wifiLoggerCommand->create();
314
315 if (ret < 0)
316 goto cleanup;
317
318 /* Set the interface Id of the message. */
319 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
320
321 if (ret < 0)
322 goto cleanup;
323
324 /* Add the vendor specific attributes for the NL command. */
325 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
326
327 if (!nlData)
328 goto cleanup;
329
330 if (wifiLoggerCommand->put_u32(
331 QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID, ring_id))
332 {
333 goto cleanup;
334 }
335 wifiLoggerCommand->attr_end(nlData);
336
337 /* Send the msg and wait for a response. */
338 ret = wifiLoggerCommand->requestResponse();
339 if (ret) {
340 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
341 }
342
343 cleanup:
344 delete wifiLoggerCommand;
345 return (wifi_error)ret;
346 }
347
setVersionInfo(char * buffer,int buffer_size)348 void WifiLoggerCommand::setVersionInfo(char *buffer, int buffer_size) {
349 mVersion = buffer;
350 mVersionLen = buffer_size;
351 }
352
353 /* Function to send enable request to the wifi driver.*/
wifi_get_firmware_version(wifi_interface_handle iface,char * buffer,int buffer_size)354 wifi_error wifi_get_firmware_version(wifi_interface_handle iface,
355 char *buffer, int buffer_size)
356 {
357 int requestId, ret = 0;
358 WifiLoggerCommand *wifiLoggerCommand;
359 struct nlattr *nlData;
360 interface_info *ifaceInfo = getIfaceInfo(iface);
361 wifi_handle wifiHandle = getWifiHandle(iface);
362 hal_info *info = getHalInfo(wifiHandle);
363
364 /* No request id from caller, so generate one and pass it on to the driver.
365 * Generate one randomly.
366 */
367 requestId = get_requestid();
368
369 wifiLoggerCommand = new WifiLoggerCommand(
370 wifiHandle,
371 requestId,
372 OUI_QCA,
373 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO);
374 if (wifiLoggerCommand == NULL) {
375 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
376 return WIFI_ERROR_UNKNOWN;
377 }
378 /* Create the NL message. */
379 ret = wifiLoggerCommand->create();
380
381 if (ret < 0)
382 goto cleanup;
383
384 /* Set the interface Id of the message. */
385 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
386
387 if (ret < 0)
388 goto cleanup;
389
390 /* Add the vendor specific attributes for the NL command. */
391 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
392
393 if (!nlData)
394 goto cleanup;
395
396 if (wifiLoggerCommand->put_u32(
397 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION, requestId))
398 {
399 goto cleanup;
400 }
401 wifiLoggerCommand->attr_end(nlData);
402
403 wifiLoggerCommand->setVersionInfo(buffer, buffer_size);
404
405 /* Send the msg and wait for a response. */
406 ret = wifiLoggerCommand->requestResponse();
407 if (ret) {
408 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
409 }
410 cleanup:
411 delete wifiLoggerCommand;
412 return (wifi_error)ret;
413
414 }
415
416 /* Function to get wlan driver version.*/
wifi_get_driver_version(wifi_interface_handle iface,char * buffer,int buffer_size)417 wifi_error wifi_get_driver_version(wifi_interface_handle iface,
418 char *buffer, int buffer_size)
419 {
420
421 int requestId, ret = 0;
422 WifiLoggerCommand *wifiLoggerCommand;
423 struct nlattr *nlData;
424 interface_info *ifaceInfo = getIfaceInfo(iface);
425 wifi_handle wifiHandle = getWifiHandle(iface);
426 hal_info *info = getHalInfo(wifiHandle);
427
428 /* No request id from caller, so generate one and pass it on to the driver.
429 * Generate one randomly.
430 */
431 requestId = get_requestid();
432
433 wifiLoggerCommand = new WifiLoggerCommand(
434 wifiHandle,
435 requestId,
436 OUI_QCA,
437 QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO);
438 if (wifiLoggerCommand == NULL) {
439 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
440 return WIFI_ERROR_UNKNOWN;
441 }
442 /* Create the NL message. */
443 ret = wifiLoggerCommand->create();
444
445 if (ret < 0)
446 goto cleanup;
447
448 /* Set the interface Id of the message. */
449 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
450
451 if (ret < 0)
452 goto cleanup;
453
454 /* Add the vendor specific attributes for the NL command. */
455 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
456
457 if (!nlData)
458 goto cleanup;
459
460 if (wifiLoggerCommand->put_u32(
461 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION, requestId))
462 {
463 goto cleanup;
464 }
465 wifiLoggerCommand->attr_end(nlData);
466
467 wifiLoggerCommand->setVersionInfo(buffer, buffer_size);
468
469 /* Send the msg and wait for a response. */
470 ret = wifiLoggerCommand->requestResponse();
471 if (ret) {
472 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
473 }
474 cleanup:
475 delete wifiLoggerCommand;
476 return (wifi_error)ret;
477 }
478
479
480 /* Function to get the Firmware memory dump. */
wifi_get_firmware_memory_dump(wifi_interface_handle iface,wifi_firmware_memory_dump_handler handler)481 wifi_error wifi_get_firmware_memory_dump(wifi_interface_handle iface,
482 wifi_firmware_memory_dump_handler handler)
483 {
484 int requestId, ret = 0;
485 WifiLoggerCommand *wifiLoggerCommand;
486 struct nlattr *nlData;
487 interface_info *ifaceInfo = getIfaceInfo(iface);
488 wifi_handle wifiHandle = getWifiHandle(iface);
489 hal_info *info = getHalInfo(wifiHandle);
490
491 /* No request id from caller, so generate one and pass it on to the driver.
492 * Generate one randomly.
493 */
494 requestId = get_requestid();
495
496 wifiLoggerCommand = new WifiLoggerCommand(
497 wifiHandle,
498 requestId,
499 OUI_QCA,
500 QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP);
501 if (wifiLoggerCommand == NULL) {
502 ALOGE("%s: Error WifiLoggerCommand NULL", __FUNCTION__);
503 return WIFI_ERROR_UNKNOWN;
504 }
505 /* Create the NL message. */
506 ret = wifiLoggerCommand->create();
507
508 if (ret < 0)
509 goto cleanup;
510
511 /* Set the interface Id of the message. */
512 ret = wifiLoggerCommand->set_iface_id(ifaceInfo->name);
513
514 if (ret < 0)
515 goto cleanup;
516
517 /* Add the vendor specific attributes for the NL command. */
518 nlData = wifiLoggerCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
519
520 if (!nlData)
521 goto cleanup;
522
523 wifiLoggerCommand->attr_end(nlData);
524
525 /* copy the callback into callback handler */
526 WifiLoggerCallbackHandler callbackHandler;
527 memset(&callbackHandler, 0, sizeof(callbackHandler));
528 callbackHandler.on_firmware_memory_dump = \
529 handler.on_firmware_memory_dump;
530
531 ret = wifiLoggerCommand->setCallbackHandler(callbackHandler);
532 if (ret < 0)
533 goto cleanup;
534
535 /* Send the msg and wait for the memory dump response */
536 ret = wifiLoggerCommand->requestResponse();
537 if (ret) {
538 ALOGE("%s: Error %d happened. ", __FUNCTION__, ret);
539 }
540
541 cleanup:
542 delete wifiLoggerCommand;
543 return (wifi_error)ret;
544 }
545
wifi_set_log_handler(wifi_request_id id,wifi_interface_handle iface,wifi_ring_buffer_data_handler handler)546 wifi_error wifi_set_log_handler(wifi_request_id id,
547 wifi_interface_handle iface,
548 wifi_ring_buffer_data_handler handler)
549 {
550 wifi_handle wifiHandle = getWifiHandle(iface);
551 hal_info *info = getHalInfo(wifiHandle);
552
553 pthread_mutex_lock(&info->lh_lock);
554 info->on_ring_buffer_data = handler.on_ring_buffer_data;
555 pthread_mutex_unlock(&info->lh_lock);
556 if (handler.on_ring_buffer_data == NULL) {
557 ALOGE("Set log handler is NULL");
558 return WIFI_ERROR_UNKNOWN;
559 }
560 return WIFI_SUCCESS;
561 }
562
wifi_reset_log_handler(wifi_request_id id,wifi_interface_handle iface)563 wifi_error wifi_reset_log_handler(wifi_request_id id,
564 wifi_interface_handle iface)
565 {
566 wifi_handle wifiHandle = getWifiHandle(iface);
567 hal_info *info = getHalInfo(wifiHandle);
568
569 pthread_mutex_lock(&info->lh_lock);
570 info->on_ring_buffer_data = NULL;
571 pthread_mutex_unlock(&info->lh_lock);
572 return WIFI_SUCCESS;
573 }
574
wifi_set_alert_handler(wifi_request_id id,wifi_interface_handle iface,wifi_alert_handler handler)575 wifi_error wifi_set_alert_handler(wifi_request_id id,
576 wifi_interface_handle iface,
577 wifi_alert_handler handler)
578 {
579 wifi_handle wifiHandle = getWifiHandle(iface);
580 hal_info *info = getHalInfo(wifiHandle);
581
582 if (handler.on_alert == NULL) {
583 ALOGE("Set alert handler is NULL");
584 return WIFI_ERROR_UNKNOWN;
585 }
586 pthread_mutex_lock(&info->ah_lock);
587 info->on_alert = handler.on_alert;
588 pthread_mutex_unlock(&info->ah_lock);
589 return WIFI_SUCCESS;
590 }
591
wifi_reset_alert_handler(wifi_request_id id,wifi_interface_handle iface)592 wifi_error wifi_reset_alert_handler(wifi_request_id id,
593 wifi_interface_handle iface)
594 {
595 wifi_handle wifiHandle = getWifiHandle(iface);
596 hal_info *info = getHalInfo(wifiHandle);
597
598 pthread_mutex_lock(&info->ah_lock);
599 info->on_alert = NULL;
600 pthread_mutex_unlock(&info->ah_lock);
601 return WIFI_SUCCESS;
602 }
603
WifiLoggerCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)604 WifiLoggerCommand::WifiLoggerCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
605 : WifiVendorCommand(handle, id, vendor_id, subcmd)
606 {
607 ALOGV("WifiLoggerCommand %p constructed", this);
608 mVersion = NULL;
609 mVersionLen = 0;
610 mRequestId = id;
611 memset(&mHandler, 0,sizeof(mHandler));
612 mWaitforRsp = false;
613 mMoreData = false;
614 mSupportedSet = NULL;
615 }
616
~WifiLoggerCommand()617 WifiLoggerCommand::~WifiLoggerCommand()
618 {
619 ALOGV("WifiLoggerCommand %p destructor", this);
620 unregisterVendorHandler(mVendor_id, mSubcmd);
621 }
622
623 /* This function implements creation of Vendor command */
create()624 int WifiLoggerCommand::create() {
625 int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
626 if (ret < 0) {
627 return ret;
628 }
629
630 /* Insert the oui in the msg */
631 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
632 if (ret < 0)
633 goto out;
634 /* Insert the subcmd in the msg */
635 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
636 if (ret < 0)
637 goto out;
638
639 ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
640 __FUNCTION__, mVendor_id, mSubcmd);
641
642 out:
643 return ret;
644 }
645
rb_timerhandler(hal_info * info)646 void rb_timerhandler(hal_info *info)
647 {
648 struct timeval now;
649 int rb_id;
650
651 gettimeofday(&now,NULL);
652 for (rb_id = 0; rb_id < NUM_RING_BUFS; rb_id++) {
653 rb_check_for_timeout(&info->rb_infos[rb_id], &now);
654 }
655 }
656
wifi_logger_ring_buffers_init(hal_info * info)657 wifi_error wifi_logger_ring_buffers_init(hal_info *info)
658 {
659 wifi_error ret;
660
661 ret = rb_init(info, &info->rb_infos[POWER_EVENTS_RB_ID],
662 POWER_EVENTS_RB_ID,
663 POWER_EVENTS_RB_BUF_SIZE,
664 POWER_EVENTS_NUM_BUFS,
665 power_events_ring_name);
666 if (ret != WIFI_SUCCESS) {
667 ALOGE("Failed to initialize power events ring buffer");
668 goto cleanup;
669 }
670
671 ret = rb_init(info, &info->rb_infos[CONNECTIVITY_EVENTS_RB_ID],
672 CONNECTIVITY_EVENTS_RB_ID,
673 CONNECTIVITY_EVENTS_RB_BUF_SIZE,
674 CONNECTIVITY_EVENTS_NUM_BUFS,
675 connectivity_events_ring_name);
676 if (ret != WIFI_SUCCESS) {
677 ALOGE("Failed to initialize connectivity events ring buffer");
678 goto cleanup;
679 }
680
681 ret = rb_init(info, &info->rb_infos[PKT_STATS_RB_ID],
682 PKT_STATS_RB_ID,
683 PKT_STATS_RB_BUF_SIZE,
684 PKT_STATS_NUM_BUFS,
685 pkt_stats_ring_name);
686 if (ret != WIFI_SUCCESS) {
687 ALOGE("Failed to initialize per packet stats ring buffer");
688 goto cleanup;
689 }
690
691 ret = rb_init(info, &info->rb_infos[DRIVER_PRINTS_RB_ID],
692 DRIVER_PRINTS_RB_ID,
693 DRIVER_PRINTS_RB_BUF_SIZE,
694 DRIVER_PRINTS_NUM_BUFS,
695 driver_prints_ring_name);
696 if (ret != WIFI_SUCCESS) {
697 ALOGE("Failed to initialize driver prints ring buffer");
698 goto cleanup;
699 }
700
701 ret = rb_init(info, &info->rb_infos[FIRMWARE_PRINTS_RB_ID],
702 FIRMWARE_PRINTS_RB_ID,
703 FIRMWARE_PRINTS_RB_BUF_SIZE,
704 FIRMWARE_PRINTS_NUM_BUFS,
705 firmware_prints_ring_name);
706 if (ret != WIFI_SUCCESS) {
707 ALOGE("Failed to initialize firmware prints ring buffer");
708 goto cleanup;
709 }
710
711 pthread_mutex_init(&info->lh_lock, NULL);
712 pthread_mutex_init(&info->ah_lock, NULL);
713
714 return ret;
715
716 cleanup:
717 wifi_logger_ring_buffers_deinit(info);
718 return ret;
719 }
720
wifi_logger_ring_buffers_deinit(hal_info * info)721 void wifi_logger_ring_buffers_deinit(hal_info *info)
722 {
723 int i;
724
725 for (i = 0; i < NUM_RING_BUFS; i++) {
726 rb_deinit(&info->rb_infos[i]);
727 }
728 pthread_mutex_destroy(&info->lh_lock);
729 pthread_mutex_destroy(&info->ah_lock);
730 }
731
732
733 /* Callback handlers registered for nl message send */
error_handler_wifi_logger(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)734 static int error_handler_wifi_logger(struct sockaddr_nl *nla,
735 struct nlmsgerr *err,
736 void *arg)
737 {
738 struct sockaddr_nl *tmp;
739 int *ret = (int *)arg;
740 tmp = nla;
741 *ret = err->error;
742 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
743 return NL_STOP;
744 }
745
746 /* Callback handlers registered for nl message send */
ack_handler_wifi_logger(struct nl_msg * msg,void * arg)747 static int ack_handler_wifi_logger(struct nl_msg *msg, void *arg)
748 {
749 int *ret = (int *)arg;
750 struct nl_msg * a;
751
752 a = msg;
753 *ret = 0;
754 return NL_STOP;
755 }
756
757 /* Callback handlers registered for nl message send */
finish_handler_wifi_logger(struct nl_msg * msg,void * arg)758 static int finish_handler_wifi_logger(struct nl_msg *msg, void *arg)
759 {
760 int *ret = (int *)arg;
761 struct nl_msg * a;
762
763 a = msg;
764 *ret = 0;
765 return NL_SKIP;
766 }
767
requestEvent()768 int WifiLoggerCommand::requestEvent()
769 {
770 int res = -1;
771 struct nl_cb *cb;
772
773 cb = nl_cb_alloc(NL_CB_DEFAULT);
774 if (!cb) {
775 ALOGE("%s: Callback allocation failed",__FUNCTION__);
776 res = -1;
777 goto out;
778 }
779
780 /* Send message */
781 res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
782 if (res < 0)
783 goto out;
784 res = 1;
785
786 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_logger, &res);
787 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_logger, &res);
788 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_logger, &res);
789
790 /* Err is populated as part of finish_handler. */
791 while (res > 0){
792 nl_recvmsgs(mInfo->cmd_sock, cb);
793 }
794
795 ALOGV("%s: Msg sent, res=%d, mWaitForRsp=%d", __FUNCTION__, res, mWaitforRsp);
796 /* Only wait for the asynchronous event if HDD returns success, res=0 */
797 if (!res && (mWaitforRsp == true)) {
798 struct timespec abstime;
799 abstime.tv_sec = 4;
800 abstime.tv_nsec = 0;
801 res = mCondition.wait(abstime);
802 if (res == ETIMEDOUT)
803 {
804 ALOGE("%s: Time out happened.", __FUNCTION__);
805 }
806 ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
807 __FUNCTION__, res, mWaitforRsp);
808 }
809 out:
810 /* Cleanup the mMsg */
811 mMsg.destroy();
812 return res;
813 }
814
requestResponse()815 int WifiLoggerCommand::requestResponse()
816 {
817 return WifiCommand::requestResponse(mMsg);
818 }
819
handleResponse(WifiEvent & reply)820 int WifiLoggerCommand::handleResponse(WifiEvent &reply) {
821 u32 status;
822 int ret = WIFI_SUCCESS;
823 int i = 0;
824 int len = 0, version;
825 char version_type[20];
826 char* memBuffer = NULL;
827 FILE* memDumpFilePtr = NULL;
828 WifiVendorCommand::handleResponse(reply);
829
830 memset(version_type, 0, 20);
831 switch(mSubcmd)
832 {
833 case QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO:
834 {
835 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1];
836
837 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX,
838 (struct nlattr *)mVendorData, mDataLen, NULL);
839
840 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) {
841 len = nla_len(tb_vendor[
842 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]);
843 memcpy(version_type, "Driver", strlen("Driver"));
844 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION;
845 } else if (
846 tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) {
847 len = nla_len(
848 tb_vendor[
849 QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]);
850 memcpy(version_type, "Firmware", strlen("Firmware"));
851 version = QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION;
852 }
853 if (len && mVersion && mVersionLen) {
854 memset(mVersion, 0, mVersionLen);
855 /* if len is greater than the incoming length then
856 accommodate 1 lesser than mVersionLen to have the
857 string terminated with '\0' */
858 len = (len > mVersionLen)? (mVersionLen - 1) : len;
859 memcpy(mVersion, nla_data(tb_vendor[version]), len);
860 ALOGD("%s: WLAN version len : %d", __FUNCTION__, len);
861 ALOGD("%s: WLAN %s version : %s ", __FUNCTION__,
862 version_type, mVersion);
863 }
864 }
865 break;
866 case QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET:
867 {
868 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX + 1];
869
870 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX,
871 (struct nlattr *)mVendorData, mDataLen, NULL);
872
873 if (tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET]) {
874 *mSupportedSet =
875 nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET]);
876 ALOGD("%s: Supported Feature Set : val 0x%x",
877 __FUNCTION__, *mSupportedSet);
878 }
879 }
880 break;
881
882 case QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP:
883 {
884 int id = 0;
885 u32 memDumpSize = 0;
886 int numRecordsRead = 0;
887 u32 remaining = 0;
888 char* buffer = NULL;
889 struct nlattr *tbVendor[
890 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX + 1];
891
892 nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MAX,
893 (struct nlattr *)mVendorData,
894 mDataLen, NULL);
895
896 if (!tbVendor[
897 QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE]) {
898 ALOGE("%s: LOGGER_RESULTS_MEMDUMP_SIZE not"
899 "found", __FUNCTION__);
900 break;
901 }
902
903 memDumpSize = nla_get_u32(
904 tbVendor[QCA_WLAN_VENDOR_ATTR_LOGGER_RESULTS_MEMDUMP_SIZE]
905 );
906
907 /* Allocate the memory indicated in memDumpSize */
908 memBuffer = (char*) malloc(sizeof(char) * memDumpSize);
909 if (memBuffer == NULL) {
910 ALOGE("%s: No Memory for allocating Buffer ",
911 "size of %d", __func__, memDumpSize);
912 break;
913 }
914 memset(memBuffer, 0, sizeof(char) * memDumpSize);
915
916 ALOGI("%s: Memory Dump size: %u", __func__,
917 memDumpSize);
918
919 /* Open the proc or debugfs filesystem */
920 memDumpFilePtr = fopen(LOGGER_MEMDUMP_FILENAME, "r");
921 if (memDumpFilePtr == NULL) {
922 ALOGE("Failed to open %s file", LOGGER_MEMDUMP_FILENAME);
923 break;
924 }
925
926 /* Read the memDumpSize value at once */
927 numRecordsRead = fread(memBuffer, 1, memDumpSize,
928 memDumpFilePtr);
929 if (numRecordsRead <= 0 ||
930 numRecordsRead != (int) memDumpSize) {
931 ALOGE("%s: Read %d failed for reading at once.",
932 __func__, numRecordsRead);
933 /* Lets try to read in chunks */
934 rewind(memDumpFilePtr);
935 remaining = memDumpSize;
936 buffer = memBuffer;
937 while (remaining) {
938 u32 readSize = 0;
939 if (remaining >= LOGGER_MEMDUMP_CHUNKSIZE) {
940 readSize = LOGGER_MEMDUMP_CHUNKSIZE;
941 }
942 else {
943 readSize = remaining;
944 }
945 numRecordsRead = fread(buffer, 1,
946 readSize, memDumpFilePtr);
947 if (numRecordsRead) {
948 remaining -= readSize;
949 buffer += readSize;
950 ALOGV("%s: Read successful for size:%u "
951 "remaining:%u", __func__, readSize,
952 remaining);
953 }
954 else {
955 ALOGE("%s: Chunk read failed for size:%u",
956 __func__, readSize);
957 break;
958 }
959 }
960 }
961
962 /* After successful read, call the callback handler*/
963 if (mHandler.on_firmware_memory_dump) {
964 mHandler.on_firmware_memory_dump(memBuffer,
965 memDumpSize);
966
967 }
968 }
969 break;
970
971 default :
972 ALOGE("%s: Wrong Wifi Logger subcmd response received %d",
973 __FUNCTION__, mSubcmd);
974 }
975
976 /* free the allocated memory */
977 if (memBuffer) {
978 free(memBuffer);
979 }
980 if (memDumpFilePtr) {
981 fclose(memDumpFilePtr);
982 }
983 return NL_SKIP;
984 }
985
986 /* This function will be the main handler for incoming (from driver)
987 * WIFI_LOGGER_SUBCMD.
988 * Calls the appropriate callback handler after parsing the vendor data.
989 */
handleEvent(WifiEvent & event)990 int WifiLoggerCommand::handleEvent(WifiEvent &event)
991 {
992 WifiVendorCommand::handleEvent(event);
993
994 switch(mSubcmd)
995 {
996 default:
997 /* Error case should not happen print log */
998 ALOGE("%s: Wrong subcmd received %d", __func__, mSubcmd);
999 break;
1000 }
1001
1002 cleanup:
1003 return NL_SKIP;
1004 }
1005
setCallbackHandler(WifiLoggerCallbackHandler nHandler)1006 int WifiLoggerCommand::setCallbackHandler(WifiLoggerCallbackHandler nHandler)
1007 {
1008 int res = 0;
1009 mHandler = nHandler;
1010 res = registerVendorHandler(mVendor_id, mSubcmd);
1011 if (res != 0) {
1012 ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
1013 __FUNCTION__, mVendor_id, mSubcmd);
1014 }
1015 return res;
1016 }
1017
unregisterHandler(u32 subCmd)1018 void WifiLoggerCommand::unregisterHandler(u32 subCmd)
1019 {
1020 unregisterVendorHandler(mVendor_id, subCmd);
1021 }
1022
timed_wait(u16 wait_time)1023 int WifiLoggerCommand::timed_wait(u16 wait_time)
1024 {
1025 struct timespec absTime;
1026 int res;
1027 absTime.tv_sec = wait_time;
1028 absTime.tv_nsec = 0;
1029 return mCondition.wait(absTime);
1030 }
1031
waitForRsp(bool wait)1032 void WifiLoggerCommand::waitForRsp(bool wait)
1033 {
1034 mWaitforRsp = wait;
1035 }
1036
1037