diff options
| author | Nagaraj <c_lnun@qca.qualcomm.com> | 2014-08-29 15:47:02 -0700 |
|---|---|---|
| committer | Akash Patel <c_akashp@qca.qualcomm.com> | 2014-09-02 10:59:42 -0700 |
| commit | 176fb240520d688e7638dcf057ac8f8a3a9b4355 (patch) | |
| tree | 36e2b5baae9d423b8367bf07486717325ddc0884 /tools/fwdebuglog | |
| parent | 1a8f91fd9256a2648002939254812bb24897c73d (diff) | |
cnss_diag new firmware logging
Firmware logging enhancement from static way to dynamic.
USer space changes
1) Send Driver load and unload information to QXDM.
2) Firmware logging changed to Dynamic way.Still the old
logging is supported for compatbility point
3) To receive SSR command from QXDM and execute
WLAN SSR
4) Fixed the memory leak
Change-Id: I7d255d867875fe870fa41e1d405c943d930120ad
CRs-Fixed: 713200
Diffstat (limited to 'tools/fwdebuglog')
| -rw-r--r-- | tools/fwdebuglog/Android.mk | 4 | ||||
| -rw-r--r-- | tools/fwdebuglog/cld-diag-parser.c | 1012 | ||||
| -rw-r--r-- | tools/fwdebuglog/cld-diag-parser.h | 257 | ||||
| -rw-r--r-- | tools/fwdebuglog/cld-fwlog-netlink.c | 319 |
4 files changed, 1416 insertions, 176 deletions
diff --git a/tools/fwdebuglog/Android.mk b/tools/fwdebuglog/Android.mk index 93e370d8d5fa..ff8560d8dc0a 100644 --- a/tools/fwdebuglog/Android.mk +++ b/tools/fwdebuglog/Android.mk @@ -15,7 +15,7 @@ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/common/inc \ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../wlan/utils/asf/inc \ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../CORE/SERVICES/COMMON LOCAL_SHARED_LIBRARIES := libc libcutils libdiag libhardware_legacy -LOCAL_SRC_FILES := cld-fwlog-netlink.c parser.c nan-parser.c +LOCAL_SRC_FILES := cld-fwlog-netlink.c parser.c nan-parser.c cld-diag-parser.c LOCAL_CFLAGS += -DCONFIG_ANDROID_LOG LOCAL_CFLAGS += -DANDROID LOCAL_LDLIBS += -llog @@ -29,7 +29,7 @@ LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/common/inc \ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../../../wlan/utils/asf/inc \ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../CORE/SERVICES/COMMON LOCAL_SHARED_LIBRARIES := libc libcutils libdiag libhardware_legacy -LOCAL_SRC_FILES := cld-fwlog-netlink.c parser.c nan-parser.c +LOCAL_SRC_FILES := cld-fwlog-netlink.c parser.c nan-parser.c cld-diag-parser.c LOCAL_CFLAGS += -DCONFIG_ANDROID_LOG LOCAL_CFLAGS += -DANDROID LOCAL_LDLIBS += -llog diff --git a/tools/fwdebuglog/cld-diag-parser.c b/tools/fwdebuglog/cld-diag-parser.c new file mode 100644 index 000000000000..323b6436077e --- /dev/null +++ b/tools/fwdebuglog/cld-diag-parser.c @@ -0,0 +1,1012 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/socket.h> +#include <linux/netlink.h> +#include "cld-diag-parser.h" +#include "diaglogi.h" +#ifdef CONFIG_ANDROID_LOG +#include <android/log.h> + +#define FWDEBUG_LOG_NAME "ROME" +#define android_printf(...) \ + __android_log_print(ANDROID_LOG_INFO, FWDEBUG_LOG_NAME, __VA_ARGS__); +#endif + +typedef struct diag_entry{ + uint32_t id; + boolean isUsed; + + /* database - userspace */ + char *format; + char *pack; + + /* runtime message - generated by target */ + char *msg; + uint32_t msg_len; +}diag_entry; + +typedef struct file_header { + int32_t file_version; + int32_t n_entries; + int32_t n_usedEntries; + int32_t hash; +}file_header; + +static diag_entry *gdiag_db = NULL; +static file_header *gdiag_header = NULL; +static int32_t gisdiag_init = FALSE; +static int gdiag_sock_fd = 0, goptionflag = 0; + +/* + * macros to safely extract 8, 16, 32, or 64-bit values from byte buffer + */ +#define GET_8(v, msg, msg_len) do { \ + if (msg_len < sizeof(uint8_t)) { \ + goto msg_error; \ + } \ + v = *msg; \ + msg += sizeof(uint8_t); \ + msg_len -= sizeof(uint8_t); \ +} while (0) + +#define _GET_LE16(a) ( \ + (((uint16_t)(a)[1]) << 8) | \ + ((uint16_t)(a)[0])) +#define GET_LE16(v, msg, msg_len) do { \ + if (msg_len < sizeof(uint16_t)) { \ + goto msg_error; \ + } \ + v = _GET_LE16(msg); \ + msg += sizeof(uint16_t); \ + msg_len -= sizeof(uint16_t); \ +} while (0) + +#define _GET_LE32(a) ( \ + (((uint32_t)(a)[3]) << 24) | \ + (((uint32_t)(a)[2]) << 16) | \ + (((uint32_t)(a)[1]) << 8) | \ + ((uint32_t)(a)[0])) +#define GET_LE32(v, msg, msg_len) do { \ + if (msg_len < sizeof(uint32_t)) { \ + goto msg_error; \ + } \ + v = _GET_LE32(msg); \ + msg += sizeof(uint32_t); \ + msg_len -= sizeof(uint32_t); \ +} while (0) + +#define _GET_LE64(a) ( \ + (((uint64_t)(a)[7]) << 56) | \ + (((uint64_t)(a)[6]) << 48) | \ + (((uint64_t)(a)[5]) << 40) | \ + (((uint64_t)(a)[4]) << 32) | \ + (((uint64_t)(a)[3]) << 24) | \ + (((uint64_t)(a)[2]) << 16) | \ + (((uint64_t)(a)[1]) << 8) | \ + ((uint64_t)(a)[0])) +#define GET_LE64(v, msg, msg_len) do { \ + if (msg_len < sizeof(uint64_t)) { \ + goto msg_error; \ + } \ + v = _GET_LE64(msg); \ + msg += sizeof(uint64_t); \ + msg_len -= sizeof(uint64_t); \ +} while (0) + +/* + * pack_printf derived from Rome FW's cmnos_vprintf + * + */ + +#define is_digit(c) ((c >= '0') && (c <= '9')) + +static int _cvt(uint64_t val, char *buf, long radix, char *digits) +{ + char temp[80]; + char *cp = temp; + int32_t length = 0; + + if (val == 0) { + /* Special case */ + *cp++ = '0'; + } else { + while (val) { + *cp++ = digits[val % (int)radix]; + val /= (int)radix; + } + } + while (cp != temp) { + *buf++ = *--cp; + length++; + } + *buf = '\0'; + return (length); +} + +/* Return successive characters in a format string. */ +char fmt_next_char(const char **fmtptr) +{ + char ch; + + ch = **fmtptr; + + if (ch != '\0') { + (*fmtptr)++; + } + + return ch; +} + +static int +pack_printf( + void (*putc)(char **pbs, char *be, char c), + char **pbuf_start, + char *buf_end, + const char *fmt, + const char *pack, + uint8_t *msg, + uint32_t msg_len) +{ + char buf[sizeof(long long)*8]; + char c, sign, *cp=buf; + int32_t left_prec, right_prec, zero_fill, pad, pad_on_right, + i, islong, islonglong; + long long val = 0; + int32_t res = 0, length = 0; + + while ((c = fmt_next_char(&fmt)) != '\0') { + if (c == '%') { + c = fmt_next_char(&fmt); + left_prec = right_prec = pad_on_right = islong = islonglong = 0; + if (c == '-') { + c = fmt_next_char(&fmt); + pad_on_right++; + } + if (c == '0') { + zero_fill = 1; + c = fmt_next_char(&fmt); + } else { + zero_fill = 0; + } + while (is_digit(c)) { + left_prec = (left_prec * 10) + (c - '0'); + c = fmt_next_char(&fmt); + } + if (c == '.') { + c = fmt_next_char(&fmt); + zero_fill++; + while (is_digit(c)) { + right_prec = (right_prec * 10) + (c - '0'); + c = fmt_next_char(&fmt); + } + } else { + right_prec = left_prec; + } + sign = '\0'; + if (c == 'l') { + /* 'long' qualifier */ + c = fmt_next_char(&fmt); + islong = 1; + if (c == 'l') { + /* long long qualifier */ + c = fmt_next_char(&fmt); + islonglong = 1; + } + } + /* Fetch value [numeric descriptors only] */ + switch (c) { + case 'p': + islong = 1; + case 'd': + case 'D': + case 'x': + case 'X': + case 'u': + case 'U': + case 'b': + case 'B': + switch (fmt_next_char(&pack)) { + case 'b': + GET_8(val, msg, msg_len); + break; + case 'h': + GET_LE16(val, msg, msg_len); + break; + case 'i': + case 'I': + GET_LE32(val, msg, msg_len); + break; + case 'q': + GET_LE64(val, msg, msg_len); + break; + default: + c = 0; + break; + } + if ((c == 'd') || (c == 'D')) { + if (val < 0) { + sign = '-'; + val = -val; + } + } else { + /* Mask to unsigned, sized quantity */ + if (!islonglong) { + if (islong) { + val &= ((long long)1 << (sizeof(long) * 8)) - 1; + } else{ + val &= ((long long)1 << (sizeof(int) * 8)) - 1; + } + } + } + break; + default: + break; + } + /* Process output */ + switch (c) { + case 'p': /* Pointer */ + (*putc)(pbuf_start, buf_end,'0'); + (*putc)(pbuf_start, buf_end,'x'); + zero_fill = 1; + left_prec = sizeof(unsigned long)*2; + case 'd': + case 'D': + case 'u': + case 'U': + case 'x': + case 'X': + switch (c) { + case 'd': + case 'D': + case 'u': + case 'U': + length = _cvt(val, buf, 10, "0123456789"); + break; + case 'p': + case 'x': + length = _cvt(val, buf, 16, "0123456789abcdef"); + break; + case 'X': + length = _cvt(val, buf, 16, "0123456789ABCDEF"); + break; + } + cp = buf; + break; + case 's': + case 'S': + cp = NULL; /* TODO string literals not supported yet */ + if (cp == NULL) { + cp = "<null>"; + } + length = 0; + while (cp[length] != '\0') length++; + break; + case 'c': + case 'C': + switch (fmt_next_char(&pack)) { + case 'b': + GET_8(c, msg, msg_len); + break; + case 'h': + GET_LE16(c, msg, msg_len); + break; + case 'i': + case 'I': + GET_LE32(c, msg, msg_len); + break; + case 'q': + GET_LE64(c, msg, msg_len); + break; + default: + c = 0; + break; + } + (*putc)(pbuf_start, buf_end,c); + res++; + continue; + case 'b': + case 'B': + length = left_prec; + if (left_prec == 0) { + if (islonglong) + length = sizeof(long long)*8; + else if (islong) + length = sizeof(long)*8; + else + length = sizeof(uint32_t)*8; + } + for (i = 0; i < length-1; i++) { + buf[i] = ((val & ((long long)1<<i)) ? '1' : '.'); + } + cp = buf; + break; + case '%': + (*putc)(pbuf_start, buf_end,'%'); + break; + default: + (*putc)(pbuf_start, buf_end,'%'); + (*putc)(pbuf_start, buf_end,c); + res += 2; + } + pad = left_prec - length; + if (sign != '\0') { + pad--; + } + if (zero_fill) { + c = '0'; + if (sign != '\0') { + (*putc)(pbuf_start, buf_end,sign); + res++; + sign = '\0'; + } + } else { + c = ' '; + } + if (!pad_on_right) { + while (pad-- > 0) { + (*putc)(pbuf_start, buf_end,c); + res++; + } + } + if (sign != '\0') { + (*putc)(pbuf_start, buf_end,sign); + res++; + } + while (length-- > 0) { + c = *cp++; + (*putc)(pbuf_start, buf_end,c); + res++; + } + if (pad_on_right) { + while (pad-- > 0) { + (*putc)(pbuf_start, buf_end,' '); + res++; + } + } + } else { + (*putc)(pbuf_start, buf_end,c); + res++; + } + } + (*putc)(pbuf_start, buf_end, '\0'); +msg_error: + return (res); +} + +static void +format_pack( const char *pack, char *buf, uint32_t buflen) +{ + char c; + uint32_t num = 0,index = 0; + memset(buf, 0 , buflen); + while ((c = fmt_next_char(&pack)) != '\0') { + if (index >= buflen -1) + break; + if (is_digit(c)) { + num = (num* 10) + (c - '0'); + c = fmt_next_char(&pack); + while(num--) { + buf[index++] = c; + if(index >= buflen -1) + break; + } + } + else + buf[index++] = c; + } + buf[index] = '\0'; +} + +static void +diag_printf(const char *buf, uint16_t vdevid, uint16_t level, + uint32_t optionflag, uint32_t timestamp) +{ + char pbuf[512]; + if (vdevid < DBGLOG_MAX_VDEVID) + snprintf(pbuf, 512, "FWMSG: [%u] vap-%u %s", timestamp, vdevid, buf); + else + snprintf(pbuf, 512, "FWMSG: [%u] %s", timestamp, buf); + + if (optionflag & QXDM_FLAG) { + switch(level) { + case DBGLOG_VERBOSE: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_LOW, "%s", pbuf); + break; + case DBGLOG_INFO: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_MED , "%s", pbuf); + break; + case DBGLOG_INFO_LVL_1: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_MED , "%s", pbuf); + break; + case DBGLOG_INFO_LVL_2: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_MED , "%s", pbuf); + break; + case DBGLOG_WARN: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_HIGH, "%s", pbuf); + break; + case DBGLOG_ERR: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_HIGH, "%s", pbuf); + break; + case DBGLOG_LVL_MAX: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_FATAL, "%s", pbuf); + break; + default: + MSG_SPRINTF_1(MSG_SSID_WLAN, MSG_LEGACY_FATAL, "%s", pbuf); + break; + } + } else + android_printf("%s\n", pbuf); +} + +/* + * database initialization + */ +static void +diag_create_db(uint32_t n_entries) +{ + gdiag_header = calloc(1, sizeof(*gdiag_header)); + if (!gdiag_header) + return; + gdiag_header->n_entries = n_entries; + gdiag_db = calloc(gdiag_header->n_entries, sizeof(*gdiag_db)); + if (!gdiag_db) + return; + /* hash */ + gdiag_header->hash = (gdiag_header->n_entries % 2 == 0) ? \ + gdiag_header->n_entries / 2 : \ + (gdiag_header->n_entries + 1) / 2; +} + +/* + * database free + */ +static void +diag_free_db() +{ + int32_t count = 0; + if (gdiag_db && gdiag_header) { + for (count = 0; count < gdiag_header->n_entries; count++) { + if (gdiag_db[count].isUsed){ + if (gdiag_db[count].format) + free(gdiag_db[count].format); + if (gdiag_db[count].pack) + free(gdiag_db[count].pack); + } + } + } + if (gdiag_db) + free(gdiag_db); + gdiag_db = NULL; + if (gdiag_header) + free(gdiag_header); + gdiag_header = NULL; + gisdiag_init = FALSE; +} + +/* + * insert into database + */ +static int32_t +diag_insert_db(char *format, char *pack, int32_t id) +{ + /* Double Hashing */ + int32_t i = id % gdiag_header->n_entries; + int32_t j = gdiag_header->hash - (id % gdiag_header->hash); + if (gdiag_header->n_entries == gdiag_header->n_usedEntries) { + debug_printf("db is full"); + return 0; + } + /* search */ + while (gdiag_db[i].isUsed) { + i = (i + j)%gdiag_header->n_entries; + } + + gdiag_db[i].id = id; + gdiag_db[i].format = format; + gdiag_db[i].pack = pack; + gdiag_db[i].isUsed = TRUE; + gdiag_header->n_usedEntries++; + return 1; +} + +/* + * parser looks up entry at runtime based on 'id' extracted from FW + * message + */ +static diag_entry* +diag_find_by_id( uint32_t id) +{ + boolean isfound = FALSE; + int32_t count = 0; + int32_t i = id % gdiag_header->n_entries; + int32_t j = gdiag_header->hash - (id % gdiag_header->hash); + if (gdiag_header->n_usedEntries == 0) { + return NULL; + } + while (gdiag_db[i].isUsed != 0 && count <= gdiag_header->n_entries) { + if (gdiag_db[i].id == id) { + isfound = TRUE; + break; + } + i = (i + j) % gdiag_header->n_entries; + count++; + } + if (!isfound) { + debug_printf("Not found in data base\n"); + return NULL; + } + return &gdiag_db[i]; +} + +/* user supply their own function to build string in temporary + * buffer + */ +static void dbg_write_char(char **pbuf_start, char *buf_end, char c) +{ + if ( *pbuf_start < buf_end) { + *(*pbuf_start) = c; + ++(*pbuf_start); + } +} + +static uint32_t +get_numberofentries() +{ + FILE* fd; + char line[1024]; + int32_t n_entries = 0, i = 0; + boolean isfound = FALSE; + if ((fd = fopen(DB_FILE_PATH, "r")) == NULL) { + diag_printf("[Error] : While opening the file\n", + 0, 4, goptionflag, 0); + return 0; + } + while ( fgets (line, sizeof(line), fd) != NULL ) { + n_entries++; + } + /* Decrement 1 for version and the last line /r/n */ + n_entries-= 2; + + /* check if n_entries is prime number else change to prime number */ + while (1) { + for (i = 2; i<n_entries; i++) { + if ( n_entries % i == 0 ) { + /* n_entries is divisible, break for loop */ + isfound = TRUE; + break; + } + } + if (!isfound && n_entries > 2) + break; + isfound = FALSE; + /* Increment n_entries and check is it prime number */ + n_entries++; + } + fclose(fd); + debug_printf( "Number of entries is %d\n", n_entries); + return n_entries; +} + +static uint32_t +parse_dbfile() +{ + FILE* fd; + uint32_t n_entries = 0; + uint32_t id = 0; + char line[1024], *p = NULL, *pack = NULL, *format = NULL; + char pbuf[128], *q = NULL; + char *save; + n_entries = get_numberofentries( ); + diag_create_db(n_entries ); + n_entries = 0; + /*Open the data.msc file*/ + if ((fd = fopen(DB_FILE_PATH , "r")) == NULL) { + diag_printf("[Error] : While opening the file\n", + 0, 4, goptionflag, 0); + return 0; + } + memset(line, 0 , sizeof(line)); + while ( fgets (line, sizeof(line), fd) != NULL ) { + n_entries++; + if (n_entries == 1) { + /* Parse for the version */ + p = strstr(line, "VERSION:"); + if (p) { + p += strlen("VERSION:"); + gdiag_header->file_version = atoi(p); + } + else + return 0; + } + else { + p = strtok_r(line, ",", &save); + if (p) + id = atoi(p); + else + continue; + + p = strtok_r(NULL, ",", &save); + if (p) + pack = strdup(p); + else + continue; + + p = strtok_r(NULL, "\r", &save); + if (p) { + format = strdup(p); + if (format) { + /* Check for CR */ + p = strstr(format, "\r"); + if (p) + *p = '\0'; + else { + p = strstr(format, "\n"); + if (p) + *p = '\0'; + } + } + } + else { + /* Else CASE for pack specifier is 0 */ + if (pack) { + /* Check for CR */ + p = strstr(pack, "\r"); + if (p) + *p = '\0'; + else { + p = strstr(pack, "\n"); + if (p) + *p = '\0'; + } + format = pack; + pack = NULL; + } + } + /* Go through the pack specifier, to find pack with number */ + if (pack) { + q = pack; + format_pack(pack, pbuf, sizeof(pbuf)); + pack = strdup(pbuf); + free(q); + } + if (!diag_insert_db(format, pack, id)) + return 0; + } + memset(line, 0 , sizeof(line)); + } + fclose(fd); + return n_entries; +} + +static int32_t +sendcnss_cmd(int sock_fd, int32_t cmd) +{ + struct dbglog_slot slot; + struct sockaddr_nl src_addr, dest_addr; + struct nlmsghdr *nlh = NULL; + struct msghdr msg; + struct iovec iov; + int32_t ret; + + memset(&slot, 0 , sizeof(struct dbglog_slot)); + slot.diag_type = cmd; + memset(&dest_addr, 0, sizeof(dest_addr)); + dest_addr.nl_family = AF_NETLINK; + dest_addr.nl_pid = 0; /* For Linux Kernel */ + dest_addr.nl_groups = 0; /* unicast */ + + nlh = malloc(NLMSG_SPACE(sizeof(struct dbglog_slot))); + if (nlh == NULL) { + fprintf(stderr, "Cannot allocate memory \n"); + close(sock_fd); + return -1; + } + memset(nlh, 0, NLMSG_SPACE(sizeof(struct dbglog_slot))); + nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct dbglog_slot)); + nlh->nlmsg_pid = getpid(); + nlh->nlmsg_type = WLAN_NL_MSG_CNSS_DIAG; + nlh->nlmsg_flags = NLM_F_REQUEST; + + memcpy(NLMSG_DATA(nlh), &slot, sizeof(struct dbglog_slot)); + + iov.iov_base = (void *)nlh; + iov.iov_len = nlh->nlmsg_len; + msg.msg_name = (void *)&dest_addr; + msg.msg_namelen = sizeof(dest_addr); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ret = sendmsg(sock_fd, &msg, 0); + free(nlh); + return ret; +} + + +void +diag_initialize(boolean isDriverLoaded, int sock_fd, uint32_t optionflag) +{ + if (isDriverLoaded) { + if (!gisdiag_init) { + uint32_t ret; + goptionflag = optionflag; + diag_free_db(); + ret = parse_dbfile(); + if (ret > 1) + gisdiag_init = TRUE; + gdiag_sock_fd = sock_fd; + } + } else { + gdiag_sock_fd = 0; + gisdiag_init = FALSE; + } +} + +void +process_diaghost_msg(uint8_t *datap, uint16_t len) +{ + uint8_t *payload; + event_report_t *pEvent_report =(event_report_t *)datap ; + debug_printf("\n %s diag_type = %d event_id =%d\n", + __func__, pEvent_report->diag_type, + pEvent_report->event_id); + if (pEvent_report->diag_type == DIAG_TYPE_EVENTS) { + payload = datap + sizeof(event_report_t); + wlan_bringup_t *pwlan_bringup_status = (wlan_bringup_t *)payload ; + event_report_payload(pEvent_report->event_id, + pEvent_report->length, payload); + } +} + +uint32_t +process_diagfw_msg(uint8_t *datap, uint16_t len, uint32_t optionflag, + FILE *log_out, int32_t *record, int32_t max_records, int32_t version, + int sock_fd) +{ + uint32_t count = 0, index = 0; + uint32_t timestamp = 0; + uint32_t diagid = 0, id = 0; + uint32_t moduleid = 0, res = 0; + uint32_t num_buf = 0, payloadlen = 0; + uint16_t vdevid = 0, vdevlevel = 0; + uint16_t numargs = 0; + uint32_t *buffer; + uint32_t header1 = 0, header2 = 0; + int32_t lrecord = 0; + char *payload; + char buf[BUF_SIZ], payload_buf[BUF_SIZ]; + char *start = buf; + int32_t hashInd = 0, i =0; + diag_entry *entry = NULL; + + if (!gisdiag_init) { + /* If cnss_diag is started if WIFI already ON, + * then turn on event not received hence + * before throwing out error initialize again + */ + diag_initialize(1, sock_fd, optionflag); + if (!gisdiag_init) { + diag_printf("**ERROR** Diag not Initialized", 0, 4, optionflag, 0); + return -1; + } + + } + if (gdiag_header->file_version != version) { + snprintf(buf, BUF_SIZ, "**ERROR**" + " Data.msc Version %d doesn't match" + " with Firmware version %d", + gdiag_header->file_version, version); + diag_printf(buf, 0, 4, optionflag, 0); + return -1; + } + buffer = (uint32_t *)datap ; + buffer ++; /* increment 1 to skip dropped */ + num_buf = len - 4; + debug_printf("\n --%s-- %d\n", __FUNCTION__, optionflag); + + while (num_buf > count) { + + header1 = *(buffer + index); + header2 = *(buffer + 1 + index); + payload = (char *)(buffer + 2 + index); + diagid = DIAG_GET_TYPE(header1); + timestamp = DIAG_GET_TIME_STAMP(header1); + payloadlen = 0; + debug_printf("\n diagid = %d timestamp = %d" + " header1 = %x heade2 = %x\n", + diagid, timestamp, header1, header2); + switch (diagid) { + case WLAN_DIAG_TYPE_EVENT: + { + id = DIAG_GET_ID(header2); + payloadlen = DIAG_GET_PAYLEN16(header2); + debug_printf("DIAG_TYPE_FW_EVENT: id = %d" + " payloadlen = %d \n", id, payloadlen); + if (optionflag == QXDM_FLAG) { + if (payloadlen) + event_report_payload(id, payloadlen, payload); + else + event_report(id); + } + } + break; + case WLAN_DIAG_TYPE_LOG: + { + id = DIAG_GET_ID(header2); + payloadlen = DIAG_GET_PAYLEN16(header2); + debug_printf("DIAG_TYPE_FW_LOG: id = %d" + " payloadlen = %d \n", id, payloadlen); + if (optionflag == QXDM_FLAG) { + log_header_type *pHdr = (log_header_type*)(payload); + if (log_status(pHdr->code)) { + log_set_timestamp(pHdr); + log_submit(pHdr); + } + } + } + break; + case WLAN_DIAG_TYPE_MSG: + { + id = DIAG_GET_ID(header2); + payloadlen = DIAG_GET_PAYLEN(header2); + vdevid = DIAG_GET_VDEVID(header2); + vdevlevel = DIAG_GET_VDEVLEVEL(header2); + memset(buf, 0, BUF_SIZ); + memset(payload_buf, 0, BUF_SIZ); + debug_printf(" DIAG_TYPE_FW_DEBUG_MSG: " + " vdevid %d vdevlevel %d payloadlen = %d id = %d\n", + vdevid, vdevlevel, payloadlen, id); + entry = diag_find_by_id(id); + if (entry) { + debug_printf(" entry->format = %s pack = %s\n", + entry->format, entry->pack); + if ((payloadlen > 0) && entry->pack) { + if (payloadlen < BUF_SIZ) + memcpy(payload_buf, payload, payloadlen); + else + memcpy(payload_buf, payload, BUF_SIZ); + /* Sending with BUF_SIZ to pack_printf + * because some times payloadlen received + * doesnt match with the pack specifier, in + * that case just print the zero + */ + entry->msg_len = BUF_SIZ; + entry->msg = payload_buf; + start = buf; + pack_printf( + dbg_write_char, + &start, + start + sizeof(buf), + entry->format, + entry->pack, + (uint8_t*)entry->msg, + entry->msg_len + ); + } + else + strlcpy(buf, entry->format, strlen(entry->format)); + + debug_printf("\n buf = %s \n", buf); + if (optionflag & LOGFILE_FLAG) { + lrecord = *record; + lrecord++; + if (!((optionflag & SILENT_FLAG) == SILENT_FLAG)) + printf("%d: %s\n", lrecord, buf); + + res = fprintf(log_out, "%s\n", buf); + //fseek(log_out, lrecord * res, SEEK_SET); + if (lrecord == max_records) { + lrecord = 0; + fseek(log_out, lrecord * res, SEEK_SET); + } + *record = lrecord; + } + if (optionflag & (CONSOLE_FLAG | QXDM_FLAG)) + diag_printf( + buf, vdevid, vdevlevel, optionflag, timestamp + ); + } + else { + snprintf(buf, BUF_SIZ, + "****WARNING****, FWMSG ID %d not found", id); + diag_printf(buf, 0, 4, optionflag, timestamp); + printf( "NOT found id = %d\n", id); + } + } + break; + default: + diag_printf(" ****WARNING**** WRONG DIAG ID", 0, + 4, optionflag, timestamp); + return 0; + } + count += payloadlen + 8; + index = count >> 2; + debug_printf("Loope end:id = %d payloadlen = %d count = %d index = %d\n", + id, payloadlen, count, index); + } + + return (0); +} + +/* +WLAN trigger command from QXDM + +1) SSR + send_data 75 41 7 0 1 0 253 1 25 +2) log level + send_data 75 41 7 0 2 0 253 1 25 + +75 - DIAG_SUBSYS_CMD_F +41 - DIAG_SUBSYS_WLAN +0007 - CNSS_WLAN_DIAG +1 - CMD type +FC00 - VS Command OpCode + +*/ + +PACK(void *) cnss_wlan_handle(PACK(void *)req_pkt, uint16_t pkt_len) +{ + PACK(void *)rsp = NULL; + uint8_t *pkt_ptr = (uint8_t *)req_pkt + 4; + uint16_t p_len, p_opcode; + int32_t ret = 0; + + /* Allocate the same length as the request + */ + rsp = diagpkt_subsys_alloc( DIAG_SUBSYS_WLAN, CNSS_WLAN_DIAG, pkt_len); + if (rsp != NULL) + { + p_len = *(pkt_ptr+3); /* VS Command packet length */ + p_opcode = (*(pkt_ptr+2) << 8) | *(pkt_ptr+1); + debug_printf( + "%s : p_len: %d, pkt_len -8: %d, p_opcode:%.04x cmd = %d\n", + __func__, p_len, pkt_len -8, p_opcode, *pkt_ptr + ); + if (p_len !=(pkt_len - 8) || ( p_opcode != 0xFD00)) + return rsp; + memcpy(rsp, req_pkt, pkt_len); + if (*pkt_ptr == CNSS_WLAN_SSR_TYPE) { + if ((ret = system(RESTART_LEVEL))){ + if (ret < 0) { + return rsp; + } + } + if (gdiag_sock_fd > 0) + sendcnss_cmd(gdiag_sock_fd, DIAG_TYPE_CRASH_INJECT); + } + } + else + debug_printf("%s:Allocate response buffer error", __func__ ); + return rsp; +} diff --git a/tools/fwdebuglog/cld-diag-parser.h b/tools/fwdebuglog/cld-diag-parser.h new file mode 100644 index 000000000000..5770d33bd0e5 --- /dev/null +++ b/tools/fwdebuglog/cld-diag-parser.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _CLD_DIAG_PARSER_H +#define _CLD_DIAG_PARSER_H + +#include <stdint.h> +#include "event.h" +#include "msg.h" +#include "log.h" +#include "diag_lsm.h" +#include "diagpkt.h" +#include "diagcmd.h" +#include "diag.h" +#include "diagi.h" + +/* KERNEL DEFS START */ +#define DBGLOG_MAX_VDEVID 15 /* 0-15 */ +#define DBGLOG_TIMESTAMP_OFFSET 0 +#define DBGLOG_TIMESTAMP_MASK 0xFFFFFFFF /* Bit 0-15. Contains bit + 8-23 of the LF0 timer */ +#define DBGLOG_DBGID_OFFSET 0 +#define DBGLOG_DBGID_MASK 0x000003FF /* Bit 0-9 */ +#define DBGLOG_DBGID_NUM_MAX 256 /* Upper limit is width of mask */ + +#define DBGLOG_MODULEID_OFFSET 10 +#define DBGLOG_MODULEID_MASK 0x0003FC00 /* Bit 10-17 */ +#define DBGLOG_MODULEID_NUM_MAX 32 /* Upper limit is width of mask */ + +#define DBGLOG_VDEVID_OFFSET 18 +#define DBGLOG_VDEVID_MASK 0x03FC0000 /* Bit 20-25*/ +#define DBGLOG_VDEVID_NUM_MAX 16 + +#define DBGLOG_NUM_ARGS_OFFSET 26 +#define DBGLOG_NUM_ARGS_MASK 0xFC000000 /* Bit 26-31 */ +#define DBGLOG_NUM_ARGS_MAX 5 /* it is limited bcoz of limitations + with Xtensa tool */ + +#define DBGLOG_LOG_BUFFER_SIZE 1500 +#define DBGLOG_DBGID_DEFINITION_LEN_MAX 90 + +#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE + +#define DBGLOG_GET_DBGID(arg) \ + ((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET) + +#define DBGLOG_GET_MODULEID(arg) \ + ((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET) + +#define DBGLOG_GET_VDEVID(arg) \ + ((arg & DBGLOG_VDEVID_MASK) >> DBGLOG_VDEVID_OFFSET) + +#define DBGLOG_GET_NUMARGS(arg) \ + ((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET) + +#define DBGLOG_GET_TIME_STAMP(arg) \ + ((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET) + + +#define DIAG_FWID_OFFSET 24 +#define DIAG_FWID_MASK 0xFF000000 /* Bit 24-31 */ + +#define DIAG_TIMESTAMP_OFFSET 0 +#define DIAG_TIMESTAMP_MASK 0x00FFFFFF /* Bit 0-23 */ + +#define DIAG_ID_OFFSET 16 +#define DIAG_ID_MASK 0xFFFF0000 /* Bit 16-31 */ + +#define DIAG_VDEVID_OFFSET 11 +#define DIAG_VDEVID_MASK 0x0000F800 /* Bit 11-15 */ +#define DIAG_VDEVID_NUM_MAX 16 + +#define DIAG_VDEVLEVEL_OFFSET 8 +#define DIAG_VDEVLEVEL_MASK 0x00000700 /* Bit 8-10 */ + +#define DIAG_PAYLEN_OFFSET 0 +#define DIAG_PAYLEN_MASK 0x000000FF /* Bit 0-7 */ + +#define DIAG_PAYLEN_OFFSET16 0 +#define DIAG_PAYLEN_MASK16 0x0000FFFF /* Bit 0-16 */ + +#define DIAG_GET_TYPE(arg) \ + ((arg & DIAG_FWID_MASK) >> DIAG_FWID_OFFSET) + +#define DIAG_GET_TIME_STAMP(arg) \ + ((arg & DIAG_TIMESTAMP_MASK) >> DIAG_TIMESTAMP_OFFSET) + +#define DIAG_GET_ID(arg) \ + ((arg & DIAG_ID_MASK) >> DIAG_ID_OFFSET) + +#define DIAG_GET_VDEVID(arg) \ + ((arg & DIAG_VDEVID_MASK) >> DIAG_VDEVID_OFFSET) + +#define DIAG_GET_VDEVLEVEL(arg) \ + ((arg & DIAG_VDEVLEVEL_MASK) >> DIAG_VDEVLEVEL_OFFSET) + +#define DIAG_GET_PAYLEN(arg) \ + ((arg & DIAG_PAYLEN_MASK) >> DIAG_PAYLEN_OFFSET) + +#define DIAG_GET_PAYLEN16(arg) \ + ((arg & DIAG_PAYLEN_MASK16) >> DIAG_PAYLEN_OFFSET16) + +#define LOGFILE_FLAG 0x01 +#define CONSOLE_FLAG 0x02 +#define QXDM_FLAG 0x04 +#define SILENT_FLAG 0x08 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define HDRLEN 16 +#define RECLEN (HDRLEN + ATH6KL_FWLOG_PAYLOAD_SIZE) +#define SIZEOF_NL_MSG_LOAD 28 /* sizeof nlmsg and load length */ +#define SIZEOF_NL_MSG_UNLOAD 28 /* sizeof nlmsg and Unload length */ +#define DIAG_TYPE_LOGS 1 +#define DIAG_TYPE_EVENTS 2 + +/* Debug Log levels*/ + +typedef enum { + DBGLOG_VERBOSE = 0, + DBGLOG_INFO, + DBGLOG_INFO_LVL_1, + DBGLOG_INFO_LVL_2, + DBGLOG_WARN, + DBGLOG_ERR, + DBGLOG_LVL_MAX +}DBGLOG_LOG_LVL; + +enum cnss_diag_type { + DIAG_TYPE_FW_EVENT, /* send fw event- to diag*/ + DIAG_TYPE_FW_LOG, /* send log event- to diag*/ + DIAG_TYPE_FW_DEBUG_MSG, /* send dbg message- to diag*/ + DIAG_TYPE_INIT_REQ, /* cnss_diag nitialization- from diag */ + DIAG_TYPE_FW_MSG, /* fw msg command-to diag */ + DIAG_TYPE_HOST_MSG, /* host command-to diag */ + DIAG_TYPE_CRASH_INJECT, /*crash inject-from diag */ + DIAG_TYPE_DBG_LEVEL, /* DBG LEVEL-from diag */ +}; + +enum wlan_diag_frame_type { + WLAN_DIAG_TYPE_CONFIG, + WLAN_DIAG_TYPE_EVENT, + WLAN_DIAG_TYPE_LOG, + WLAN_DIAG_TYPE_MSG, + WLAN_DIAG_TYPE_LEGACY_MSG, +}; + +struct dbglog_slot { + unsigned int diag_type; + unsigned int timestamp; + unsigned int length; + unsigned int dropped; + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + u_int8_t payload[0]; +}__packed; + +typedef struct event_report_s { + unsigned int diag_type; + unsigned short event_id; + unsigned short length; +} event_report_t; + +typedef struct wlan_bringup_s { + unsigned short wlanStatus; + char driverVersion[10]; +} wlan_bringup_t; + +static inline unsigned int get_32(const unsigned char *pos) +{ + return pos[0] | (pos[1] << 8) | (pos[2] << 16) | (pos[3] << 24); +} + +/* KENEL DEFS END */ + +#define WLAN_NL_MSG_CNSS_DIAG 27 /* Msg type between user space/wlan driver */ +#define WLAN_NL_MSG_CNSS_MSG 28 +#define CNSS_WLAN_DIAG 0x07 +#define CNSS_WLAN_SSR_TYPE 0x01 +#define CNSS_WLAN_LEVEL_TYPE 0x02 +/* NL messgage Carries actual Logs from Driver */ +#define ANI_NL_MSG_LOG_MSG_TYPE 89 +/* NL message Registration Req/Response to and from Driver */ +#define ANI_NL_MSG_LOG_REG_TYPE 1 +#define MAX_MSG_SIZE 8192 +#define DIAG_MSG_MAX_LEN 4096 +#define DIAG_MSG_OVERHEAD_LEN 48 + +#define RESTART_LEVEL \ + "echo related > /sys/bus/msm_subsys/devices/subsys4/restart_level" +#define DB_FILE_PATH "/firmware/image/Data.msc" +#define debug_printf +#define BUF_SIZ 256 + +#define WLAN_LOG_TO_DIAG(xx_ss_id, xx_ss_mask, xx_fmt) \ + do { \ + if (xx_ss_mask & (MSG_BUILD_MASK_ ## xx_ss_id)) { \ + msg_const_type xx_msg = { \ + {__LINE__, (xx_ss_id), (xx_ss_mask)}, (NULL), msg_file}; \ + xx_msg.fmt = xx_fmt; \ + msg_send (&xx_msg); \ + } \ + } while (0); \ + +/* General purpose MACROS to handle the WNI Netlink msgs */ +#define ANI_NL_MASK 3 + + +PACK(void *)cnss_wlan_handle(PACK(void *)req_pkt, uint16_t pkt_len); + +static const diagpkt_user_table_entry_type cnss_wlan_tbl[] = +{ /* susbsys_cmd_code lo = 7 , susbsys_cmd_code hi = 7, call back function */ + {CNSS_WLAN_DIAG, CNSS_WLAN_DIAG,cnss_wlan_handle}, +}; + +int32_t parser_init(); + +int32_t +dbglog_parse_debug_logs(u_int8_t *datap, u_int16_t len, u_int16_t dropped); + +void +diag_initialize(boolean isDriverLoaded, int sock_fd, uint32_t optionflag); + +void +process_diaghost_msg(uint8_t *datap, uint16_t len); + + +uint32_t +process_diagfw_msg(uint8_t *datap, uint16_t len, uint32_t optionflag, + FILE *log_out, int32_t *record, int32_t max_records, int32_t version, + int sock_fd); + +#endif + diff --git a/tools/fwdebuglog/cld-fwlog-netlink.c b/tools/fwdebuglog/cld-fwlog-netlink.c index 764b162ed60c..38a21f9ff743 100644 --- a/tools/fwdebuglog/cld-fwlog-netlink.c +++ b/tools/fwdebuglog/cld-fwlog-netlink.c @@ -47,12 +47,6 @@ #endif #include <sys/socket.h> #include <linux/netlink.h> - -#include <athdefs.h> -#include <a_types.h> -#include "dbglog.h" -#include "dbglog_host.h" - #include "event.h" #include "msg.h" #include "log.h" @@ -61,6 +55,7 @@ #include "diagpkt.h" #include "diagcmd.h" #include "diag.h" +#include "cld-diag-parser.h" #ifdef ANDROID #include "aniNlMsg.h" @@ -71,7 +66,7 @@ * CAP_NET_RAW : Use RAW and packet socket * CAP_NET_ADMIN : NL broadcast receive */ -const unsigned int capabilities = (1 << CAP_NET_RAW) | (1 << CAP_NET_ADMIN); +const uint32_t capabilities = (1 << CAP_NET_RAW) | (1 << CAP_NET_ADMIN); /* Groups needed * AID_INET : Open INET socket @@ -82,8 +77,6 @@ const unsigned int capabilities = (1 << CAP_NET_RAW) | (1 << CAP_NET_ADMIN); const gid_t groups[] = {AID_INET, AID_NET_ADMIN, AID_QCOM_DIAG, AID_WIFI}; #endif -#define WLAN_NL_MSG_CNSS_DIAG 27 /* Msg type between user space/wlan driver */ - const char options[] = "Options:\n\ -f, --logfile=<Output log file> [Mandotory]\n\ @@ -102,16 +95,16 @@ struct msghdr msg; static FILE *fwlog_res; static FILE *log_out; const char *fwlog_res_file; -int max_records; -int record; +int32_t max_records; +int32_t record = 0; const char *progname; char dbglogoutfile[PATH_MAX]; -int optionflag = 0; -int isDriverLoaded = FALSE; +int32_t optionflag = 0; +boolean isDriverLoaded = FALSE; const char driverLoaded[] = "KNLREADY"; const char driverUnLoaded[] = "KNLCLOSE"; -int rec_limit = 100000000; /* Million records is a good default */ +int32_t rec_limit = 100000000; /* Million records is a good default */ static void usage(void) @@ -121,31 +114,25 @@ usage(void) exit(-1); } -extern int parser_init(); - - -extern int -dbglog_parse_debug_logs(u_int8_t *datap, u_int16_t len, u_int16_t dropped); - -static unsigned int get_le32(const unsigned char *pos) +static uint32_t get_le32(const uint8_t *pos) { return pos[0] | (pos[1] << 8) | (pos[2] << 16) | (pos[3] << 24); } static size_t reorder(FILE *log_in, FILE *log_out) { - unsigned char buf[RECLEN]; + uint8_t buf[RECLEN]; size_t res; - unsigned int timestamp = 0, min_timestamp = -1; - int pos = 0, min_pos = 0; + uint32_t timestamp = 0, min_timestamp = -1; + int32_t pos = 0, min_pos = 0; struct dbglog_slot *slot; - unsigned int length = 0; + uint32_t length = 0; pos = 0; while ((res = fread(buf, RECLEN, 1, log_in)) == 1) { slot = (struct dbglog_slot *)buf; - timestamp = get_le32((unsigned char *)&slot->timestamp); - length = get_le32((unsigned char *)&slot->length); + timestamp = get_le32((uint8_t *)&slot->timestamp); + length = get_le32((uint8_t *)&slot->length); if (timestamp < min_timestamp) { min_timestamp = timestamp; min_pos = pos; @@ -157,8 +144,8 @@ static size_t reorder(FILE *log_in, FILE *log_out) fseek(log_in, min_pos * RECLEN, SEEK_SET); while ((res = fread(buf, RECLEN, 1, log_in)) == 1) { slot = (struct dbglog_slot *)buf; - timestamp = get_le32((unsigned char *)&slot->timestamp); - length = get_le32((unsigned char *)&slot->length); + timestamp = get_le32((uint8_t *)&slot->timestamp); + length = get_le32((uint8_t *)&slot->length); printf("Read record timestamp=%u length=%u\n", timestamp, length); if (fwrite(buf, RECLEN, res, log_out) != res) @@ -169,8 +156,8 @@ static size_t reorder(FILE *log_in, FILE *log_out) pos = min_pos; while (pos > 0 && (res = fread(buf, RECLEN, 1, log_out)) == 1) { slot = (struct dbglog_slot *)buf; - timestamp = get_le32((unsigned char *)&slot->timestamp); - length = get_le32((unsigned char *)&slot->length); + timestamp = get_le32((uint8_t *)&slot->timestamp); + length = get_le32((uint8_t *)&slot->length); pos--; printf("Read record timestamp=%u length=%u\n", timestamp, length); @@ -187,11 +174,11 @@ static size_t reorder(FILE *log_in, FILE *log_out) * the service will run only in system or diag mode * */ -int +int32_t cnssdiagservice_cap_handle(void) { - int i; - int err; + int32_t i; + int32_t err; struct __user_cap_header_struct cap_header_data; cap_user_header_t cap_header = &cap_header_data; @@ -257,7 +244,7 @@ static void cleanup(void) { fclose(log_out); } -static void stop(int signum) +static void stop(int32_t signum) { if(optionflag & LOGFILE_FLAG){ @@ -266,48 +253,90 @@ static void stop(int signum) } exit(0); } + +void process_cnss_log_file(uint8_t *dbgbuf) +{ + uint16_t length = 0; + uint32_t dropped = 0; + uint32_t timestamp = 0; + uint32_t res =0; + struct dbglog_slot *slot = (struct dbglog_slot *)dbgbuf; + fseek(log_out, record * RECLEN, SEEK_SET); + record++; + timestamp = get_le32((uint8_t *)&slot->timestamp); + length = get_le32((uint8_t *)&slot->length); + dropped = get_le32((uint8_t *)&slot->dropped); + if (!((optionflag & SILENT_FLAG) == SILENT_FLAG)) { + /* don't like this have to fix it */ + printf("Read record %d timestamp=%u length=%u fw dropped=%u\n", + record, timestamp, length, dropped); + } + if ((res = fwrite(dbgbuf, RECLEN, 1, log_out)) != 1){ + perror("fwrite"); + return; + } + fflush(log_out); + if (record == max_records) + record = 0; +} /* * Process FW debug, FW event and FW log messages * Read the payload and process accordingly. * */ -void process_cnss_diag_msg(unsigned char *eventbuf) +void process_cnss_diag_msg(uint8_t *eventbuf) { - unsigned char *dbgbuf; - unsigned short diag_type = 0; - unsigned int event_id = 0; - unsigned short length = 0; + uint8_t *dbgbuf; + tAniNlHdr *wnl = (tAniNlHdr *)eventbuf; + uint16_t diag_type = 0; + uint32_t event_id = 0; + uint16_t length = 0; struct dbglog_slot *slot; - unsigned int dropped = 0; + uint32_t dropped = 0; dbgbuf = eventbuf; - diag_type = *(unsigned short *)eventbuf; - eventbuf += sizeof(unsigned short); + diag_type = *(uint16_t *)eventbuf; + eventbuf += sizeof(uint16_t); - length = *(unsigned short *)eventbuf; - eventbuf += sizeof(unsigned short); + length = *(uint16_t *)eventbuf; + eventbuf += sizeof(uint16_t); if (diag_type == DIAG_TYPE_FW_EVENT) { - eventbuf += sizeof(unsigned int); - - event_id = *(unsigned int *)eventbuf; - eventbuf += sizeof(unsigned int); - - if (length) - event_report_payload(event_id, length, eventbuf); - else - event_report(event_id); + eventbuf += sizeof(uint32_t); + event_id = *(uint32_t *)eventbuf; + eventbuf += sizeof(uint32_t); + if (optionflag & QXDM_FLAG) { + if (length) + event_report_payload(event_id, length, eventbuf); + else + event_report(event_id); + } } else if (diag_type == DIAG_TYPE_FW_LOG) { /* Do nothing for now */ } else if (diag_type == DIAG_TYPE_FW_DEBUG_MSG) { slot =(struct dbglog_slot *)dbgbuf; - length = get_le32((unsigned char *)&slot->length); - dropped = get_le32((unsigned char *)&slot->dropped); - dbglog_parse_debug_logs(slot->payload, length, dropped); + length = get_le32((uint8_t *)&slot->length); + dropped = get_le32((uint8_t *)&slot->dropped); + if (optionflag & LOGFILE_FLAG) + process_cnss_log_file(dbgbuf); + else if (optionflag & (CONSOLE_FLAG | QXDM_FLAG)) + dbglog_parse_debug_logs(&slot->payload[0], length, dropped); + } else if (diag_type == DIAG_TYPE_FW_MSG) { + uint32_t version = 0; + slot = (struct dbglog_slot *)dbgbuf; + length = get_32((uint8_t *)&slot->length); + version = get_le32((uint8_t *)&slot->dropped); + process_diagfw_msg(&slot->payload[0], length, optionflag, log_out, + &record, max_records, version, sock_fd); + } else if (diag_type == DIAG_TYPE_HOST_MSG) { + slot = (struct dbglog_slot *)dbgbuf; + length = get_32((uint8_t *)&slot->length); + process_diaghost_msg(slot->payload, length); } else { /* Do nothing for now */ } + } /* @@ -315,10 +344,10 @@ void process_cnss_diag_msg(unsigned char *eventbuf) * address. Return the socket fd if sucess. * */ -static int create_nl_socket() +static int32_t create_nl_socket() { - int ret; - int sock_fd; + int32_t ret; + int32_t sock_fd; sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USERSOCK); if (sock_fd < 0) { @@ -340,7 +369,7 @@ static int create_nl_socket() return sock_fd; } -static unsigned int initialize(int sock_fd) +static uint32_t initialize(int32_t sock_fd) { char *mesg = "Hello"; @@ -349,6 +378,8 @@ static unsigned int initialize(int sock_fd) dest_addr.nl_pid = 0; /* For Linux Kernel */ dest_addr.nl_groups = 0; /* unicast */ + if (nlh) + free(nlh); nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(RECLEN)); if (nlh == NULL) { fprintf(stderr, "Cannot allocate memory \n"); @@ -374,21 +405,17 @@ static unsigned int initialize(int sock_fd) return 0; } -int main(int argc, char *argv[]) +int32_t main(int32_t argc, char *argv[]) { - unsigned int res =0; - unsigned char *eventbuf = NULL; - unsigned char *dbgbuf = NULL; - int c; + uint32_t res =0; + uint8_t *eventbuf = NULL; + uint8_t *dbgbuf = NULL; + int32_t c; struct dbglog_slot *slot; progname = argv[0]; - unsigned short diag_type = 0; - unsigned short length = 0; - unsigned int dropped = 0; - unsigned int timestamp = 0; - - int option_index = 0; + uint16_t diag_type = 0; + int32_t option_index = 0; static struct option long_options[] = { {"logfile", 1, NULL, 'f'}, {"reclimit", 1, NULL, 'r'}, @@ -441,7 +468,8 @@ int main(int argc, char *argv[]) perror("Failed on Diag_LSM_Init\n"); return -1; } - + /* Register CALLABACK for QXDM input data */ + DIAGPKT_DISPATCH_TABLE_REGISTER(DIAG_SUBSYS_WLAN, cnss_wlan_tbl); #ifdef ANDROID if(cnssdiagservice_cap_handle()) { printf("Cap bouncing failed EXIT!!!"); @@ -482,110 +510,53 @@ int main(int argc, char *argv[]) } fwlog_res_file = "./reorder"; - - /* Read message from kernel */ - while ((res = recvmsg(sock_fd, &msg, 0)) > 0) { - if (res > sizeof(struct dbglog_slot) && - (res == SIZEOF_NL_MSG_DBG_MSG)) { - dbgbuf = (unsigned char *)NLMSG_DATA(nlh); - } else { - continue; - } - slot = (struct dbglog_slot *)dbgbuf; - diag_type = *(unsigned short*)dbgbuf; - - if (diag_type == DIAG_TYPE_FW_DEBUG_MSG) { - fseek(log_out, record * RECLEN, SEEK_SET); - record++; - timestamp = get_le32((unsigned char *)&slot->timestamp); - length = get_le32((unsigned char *)&slot->length); - dropped = get_le32((unsigned char *)&slot->dropped); - if (!((optionflag & SILENT_FLAG) == SILENT_FLAG)) { - /* don't like this have to fix it */ - printf("Read record %d timestamp=%u length=%u fw dropped=%u\n", - record, timestamp, length, dropped); - } - if ((res = fwrite(dbgbuf, RECLEN, 1, log_out)) != 1){ - perror("fwrite"); - break; - } - fflush(log_out); - if (record == max_records) - record = 0; - } - } - printf("Incomplete read: %d bytes\n", (int) res); - cleanup(); } - if (optionflag & CONSOLE_FLAG) { - - parser_init(); - - while ((res = recvmsg(sock_fd, &msg, 0)) > 0) { - if ((res > sizeof(struct dbglog_slot)) && - (res == SIZEOF_NL_MSG_DBG_MSG)) { - dbgbuf = (unsigned char *)NLMSG_DATA(nlh); - } else { - continue; - } - slot = (struct dbglog_slot *)dbgbuf; - diag_type = *(unsigned short*)dbgbuf; - if (diag_type == DIAG_TYPE_FW_DEBUG_MSG) { - length = get_le32((unsigned char *)&slot->length); - dropped = get_le32((unsigned char *)&slot->dropped); - dbglog_parse_debug_logs(slot->payload, length, dropped); - } - } - close(sock_fd); - free(nlh); - } - if (optionflag & QXDM_FLAG) { - - parser_init(); - - while ((res = recvmsg(sock_fd, &msg, 0)) > 0) { - eventbuf = (unsigned char *)NLMSG_DATA(nlh); - - if ((isDriverLoaded == FALSE) && - (res == SIZEOF_NL_MSG_LOAD)) { - eventbuf = (unsigned char *)NLMSG_DATA(nlh); - if (0 == strncmp(driverLoaded, (const char *)eventbuf, - strlen(driverLoaded))) { - isDriverLoaded = TRUE; - close(sock_fd); - /* Wait for driver to Load */ - sleep(5); - sock_fd = create_nl_socket(); - if (sock_fd < 0) { - printf("create nl sock failed ret %d \n", sock_fd); - return -1; - } - initialize(sock_fd); - } - } else if ((isDriverLoaded == TRUE) && - (res == SIZEOF_NL_MSG_UNLOAD)) { - eventbuf = (unsigned char *)NLMSG_DATA(nlh); - if (0 == strncmp(driverUnLoaded, (const char *)eventbuf, - strlen(driverUnLoaded))) { - isDriverLoaded = FALSE; - } - } else if((res >= sizeof(struct dbglog_slot)) && - ((res != SIZEOF_NL_MSG_LOAD) && - (res != SIZEOF_NL_MSG_UNLOAD))) { - isDriverLoaded = TRUE; - eventbuf = (unsigned char *)NLMSG_DATA(nlh); - process_cnss_diag_msg(eventbuf); - } else { - /* Ignore other messages that might be broadcast */ - continue; - } - } - /* Release the handle to Diag*/ - Diag_LSM_DeInit(); - close(sock_fd); - free(nlh); + parser_init(); + + while ((res = recvmsg(sock_fd, &msg, 0)) > 0) { + if ((isDriverLoaded == FALSE) && + (res == SIZEOF_NL_MSG_LOAD)) { + eventbuf = (uint8_t *)NLMSG_DATA(nlh); + if (0 == strncmp(driverLoaded, (const char *)eventbuf, + strlen(driverLoaded))) { + isDriverLoaded = TRUE; + close(sock_fd); + /* Wait for driver to Load */ + sleep(5); + sock_fd = create_nl_socket(); + if (sock_fd < 0) { + printf("create nl sock failed ret %d \n", sock_fd); + return -1; + } + initialize(sock_fd); + diag_initialize(isDriverLoaded, sock_fd, optionflag); + } + } else if ((isDriverLoaded == TRUE) && + (res == SIZEOF_NL_MSG_UNLOAD)) { + eventbuf = (uint8_t *)NLMSG_DATA(nlh); + if (0 == strncmp(driverUnLoaded, (const char *)eventbuf, + strlen(driverUnLoaded))) { + isDriverLoaded = FALSE; + diag_initialize(isDriverLoaded, sock_fd, optionflag); + } + } else if((res >= sizeof(struct dbglog_slot)) && + ((res != SIZEOF_NL_MSG_LOAD) && + (res != SIZEOF_NL_MSG_UNLOAD))) { + isDriverLoaded = TRUE; + eventbuf = (uint8_t *)NLMSG_DATA(nlh); + process_cnss_diag_msg(eventbuf); + } else { + /* Ignore other messages that might be broadcast */ + continue; + } } + /* Release the handle to Diag*/ + Diag_LSM_DeInit(); + if (optionflag & LOGFILE_FLAG) + cleanup(); + close(sock_fd); + free(nlh); return 0; } |
