diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2e979f22..3a83e34d 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8) PROJECT(mt76-test C) ADD_DEFINITIONS(-Os -Wall -Werror --std=gnu99 -g3) -ADD_EXECUTABLE(mt76-test main.c fields.c eeprom.c) +ADD_EXECUTABLE(mt76-test main.c fields.c eeprom.c fwlog.c) TARGET_LINK_LIBRARIES(mt76-test nl-tiny) SET(CMAKE_INSTALL_PREFIX /usr) diff --git a/tools/fwlog.c b/tools/fwlog.c new file mode 100644 index 00000000..e5d4a105 --- /dev/null +++ b/tools/fwlog.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: ISC +/* Copyright (C) 2022 Felix Fietkau */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mt76-test.h" + +bool done = false; + +static const char *debugfs_path(const char *phyname, const char *file) +{ + static char path[256]; + + snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/mt76/%s", phyname, file); + + return path; +} + +static int mt76_set_fwlog_en(const char *phyname, bool en) +{ + FILE *f = fopen(debugfs_path(phyname, "fw_debug_bin"), "w"); + + if (!f) { + fprintf(stderr, "Could not open fw_debug_bin file\n"); + return 1; + } + + fprintf(f, "7"); + fclose(f); + + return 0; +} + +int read_retry(int fd, void *buf, int len) +{ + int out_len = 0; + int r; + + while (len > 0) { + if (done) + return -1; + + r = read(fd, buf, len); + if (r < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + + return -1; + } + + if (!r) + return 0; + + out_len += r; + len -= r; + buf += r; + } + + return out_len; +} + +static void handle_signal(int sig) +{ + done = true; +} + +int mt76_fwlog(const char *phyname, int argc, char **argv) +{ + struct sockaddr_in local = { + .sin_family = AF_INET, + .sin_addr.s_addr = INADDR_ANY, + }; + struct sockaddr_in remote = { + .sin_family = AF_INET, + .sin_port = htons(55688), + }; + char buf[1504]; + int ret = 0; + int yes = 1; + int s, fd; + + if (argc < 1) { + fprintf(stderr, "need destination address\n"); + return 1; + } + + if (!inet_aton(argv[0], &remote.sin_addr)) { + fprintf(stderr, "invalid destination address\n"); + return 1; + } + + s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s < 0) { + perror("socket"); + return 1; + } + + setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); + if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) { + perror("bind"); + return 1; + } + + if (mt76_set_fwlog_en(phyname, true)) + return 1; + + fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Could not open fwlog_data file: %s\n", strerror(errno)); + ret = 1; + goto out; + } + + signal(SIGTERM, handle_signal); + signal(SIGINT, handle_signal); + signal(SIGQUIT, handle_signal); + + while (1) { + struct pollfd pfd = { + .fd = fd, + .events = POLLIN | POLLHUP | POLLERR, + }; + uint32_t len; + int r; + + if (done) + break; + + poll(&pfd, 1, -1); + + r = read_retry(fd, &len, sizeof(len)); + if (r < 0) + break; + + if (!r) + continue; + + if (len > sizeof(buf)) { + fprintf(stderr, "Length error: %d > %d\n", len, (int)sizeof(buf)); + ret = 1; + break; + } + + if (done) + break; + + r = read_retry(fd, buf, len); + if (done) + break; + + if (r != len) { + fprintf(stderr, "Short read: %d < %d\n", r, len); + ret = 1; + break; + } + + /* send buf */ + sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote)); + } + + close(fd); + +out: + mt76_set_fwlog_en(phyname, false); + + return ret; +} diff --git a/tools/main.c b/tools/main.c index a76bf5d9..699a9eea 100644 --- a/tools/main.c +++ b/tools/main.c @@ -2,7 +2,17 @@ /* Copyright (C) 2020 Felix Fietkau */ #define _GNU_SOURCE +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include "mt76-test.h" struct unl unl; @@ -156,7 +166,7 @@ static int mt76_set(int phy, int argc, char **argv) int main(int argc, char **argv) { - const char *cmd; + const char *cmd, *phyname; int phy; int ret = 0; @@ -169,7 +179,8 @@ int main(int argc, char **argv) return 2; } - phy = phy_lookup_idx(argv[1]); + phyname = argv[1]; + phy = phy_lookup_idx(phyname); if (phy < 0) { fprintf(stderr, "Could not find phy '%s'\n", argv[1]); return 2; @@ -185,6 +196,8 @@ int main(int argc, char **argv) ret = mt76_set(phy, argc, argv); else if (!strcmp(cmd, "eeprom")) ret = mt76_eeprom(phy, argc, argv); + else if (!strcmp(cmd, "fwlog")) + ret = mt76_fwlog(phyname, argc, argv); else usage(); diff --git a/tools/mt76-test.h b/tools/mt76-test.h index e2668643..d2fafa86 100644 --- a/tools/mt76-test.h +++ b/tools/mt76-test.h @@ -60,5 +60,6 @@ extern unsigned char *eeprom_data; void usage(void); int mt76_eeprom(int phy, int argc, char **argv); +int mt76_fwlog(const char *phyname, int argc, char **argv); #endif