blob: e5d4a1051b5f38863b182c2c7f3bdb41de467c07 [file] [log] [blame]
developer0f312e82022-11-01 12:31:52 +08001// SPDX-License-Identifier: ISC
2/* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name> */
3#define _GNU_SOURCE
4
5#include <sys/types.h>
6#include <sys/uio.h>
7#include <arpa/inet.h>
8#include <netinet/in.h>
9#include <unistd.h>
10#include <stdio.h>
11#include <stdbool.h>
12#include <errno.h>
13#include <poll.h>
14#include <fcntl.h>
15#include <signal.h>
16#include "mt76-test.h"
17
18bool done = false;
19
20static const char *debugfs_path(const char *phyname, const char *file)
21{
22 static char path[256];
23
24 snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/mt76/%s", phyname, file);
25
26 return path;
27}
28
29static int mt76_set_fwlog_en(const char *phyname, bool en)
30{
31 FILE *f = fopen(debugfs_path(phyname, "fw_debug_bin"), "w");
32
33 if (!f) {
34 fprintf(stderr, "Could not open fw_debug_bin file\n");
35 return 1;
36 }
37
38 fprintf(f, "7");
39 fclose(f);
40
41 return 0;
42}
43
44int read_retry(int fd, void *buf, int len)
45{
46 int out_len = 0;
47 int r;
48
49 while (len > 0) {
50 if (done)
51 return -1;
52
53 r = read(fd, buf, len);
54 if (r < 0) {
55 if (errno == EINTR || errno == EAGAIN)
56 continue;
57
58 return -1;
59 }
60
61 if (!r)
62 return 0;
63
64 out_len += r;
65 len -= r;
66 buf += r;
67 }
68
69 return out_len;
70}
71
72static void handle_signal(int sig)
73{
74 done = true;
75}
76
77int mt76_fwlog(const char *phyname, int argc, char **argv)
78{
79 struct sockaddr_in local = {
80 .sin_family = AF_INET,
81 .sin_addr.s_addr = INADDR_ANY,
82 };
83 struct sockaddr_in remote = {
84 .sin_family = AF_INET,
85 .sin_port = htons(55688),
86 };
87 char buf[1504];
88 int ret = 0;
89 int yes = 1;
90 int s, fd;
91
92 if (argc < 1) {
93 fprintf(stderr, "need destination address\n");
94 return 1;
95 }
96
97 if (!inet_aton(argv[0], &remote.sin_addr)) {
98 fprintf(stderr, "invalid destination address\n");
99 return 1;
100 }
101
102 s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
103 if (s < 0) {
104 perror("socket");
105 return 1;
106 }
107
108 setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
109 if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
110 perror("bind");
111 return 1;
112 }
113
114 if (mt76_set_fwlog_en(phyname, true))
115 return 1;
116
117 fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY);
118 if (fd < 0) {
119 fprintf(stderr, "Could not open fwlog_data file: %s\n", strerror(errno));
120 ret = 1;
121 goto out;
122 }
123
124 signal(SIGTERM, handle_signal);
125 signal(SIGINT, handle_signal);
126 signal(SIGQUIT, handle_signal);
127
128 while (1) {
129 struct pollfd pfd = {
130 .fd = fd,
131 .events = POLLIN | POLLHUP | POLLERR,
132 };
133 uint32_t len;
134 int r;
135
136 if (done)
137 break;
138
139 poll(&pfd, 1, -1);
140
141 r = read_retry(fd, &len, sizeof(len));
142 if (r < 0)
143 break;
144
145 if (!r)
146 continue;
147
148 if (len > sizeof(buf)) {
149 fprintf(stderr, "Length error: %d > %d\n", len, (int)sizeof(buf));
150 ret = 1;
151 break;
152 }
153
154 if (done)
155 break;
156
157 r = read_retry(fd, buf, len);
158 if (done)
159 break;
160
161 if (r != len) {
162 fprintf(stderr, "Short read: %d < %d\n", r, len);
163 ret = 1;
164 break;
165 }
166
167 /* send buf */
168 sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote));
169 }
170
171 close(fd);
172
173out:
174 mt76_set_fwlog_en(phyname, false);
175
176 return ret;
177}