// 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; }