blob: 699a9eea625a3b478cd2b677f7a904cf761665fa [file] [log] [blame]
developerb11a5392022-03-31 00:34:47 +08001// SPDX-License-Identifier: ISC
2/* Copyright (C) 2020 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
18struct unl unl;
19static uint32_t tm_changed[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)];
20static const char *progname;
21
22static int phy_lookup_idx(const char *name)
23{
24 char buf[128];
25 FILE *f;
26 int len;
27
28 snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
29 f = fopen(buf, "r");
30 if (!f)
31 return -1;
32
33 len = fread(buf, 1, sizeof(buf) - 1, f);
34 fclose(f);
35
36 if (!len)
37 return -1;
38
39 buf[len] = 0;
40 return atoi(buf);
41}
42
43void usage(void)
44{
45 static const char *const commands[] = {
46 "set <var>=<val> [...]",
47 "dump [stats]",
48 "eeprom file",
49 "eeprom set <addr>=<val> [...]",
50 "eeprom changes",
51 "eeprom reset",
52 };
53 int i;
54
55 fprintf(stderr, "Usage:\n");
56 for (i = 0; i < ARRAY_SIZE(commands); i++)
57 printf(" %s phyX %s\n", progname, commands[i]);
58
59 exit(1);
60}
61
62static int mt76_dump_cb(struct nl_msg *msg, void *arg)
63{
64 struct nlattr *attr;
65
66 attr = unl_find_attr(&unl, msg, NL80211_ATTR_TESTDATA);
67 if (!attr) {
68 fprintf(stderr, "Testdata attribute not found\n");
69 return NL_SKIP;
70 }
71
72 msg_field.print(&msg_field, attr);
73
74 return NL_SKIP;
75}
76
77static int mt76_dump(int phy, int argc, char **argv)
78{
79 struct nl_msg *msg;
80 void *data;
81
82 msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, true);
83 nla_put_u32(msg, NL80211_ATTR_WIPHY, phy);
84
85 data = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
86
87 for (; argc > 0; argc--, argv++) {
88 if (!strcmp(argv[0], "stats"))
89 nla_put_flag(msg, MT76_TM_ATTR_STATS);
90 }
91
92 nla_nest_end(msg, data);
93
94 unl_genl_request(&unl, msg, mt76_dump_cb, NULL);
95
96 return 0;
97}
98
99static inline void tm_set_changed(uint32_t id)
100{
101 tm_changed[id / 32] |= (1U << (id % 32));
102}
103
104static inline bool tm_is_changed(uint32_t id)
105{
106 return tm_changed[id / 32] & (1U << (id % 32));
107}
108
109static int mt76_set(int phy, int argc, char **argv)
110{
111 const struct tm_field *fields = msg_field.fields;
112 struct nl_msg *msg;
113 void *data;
114 int i, ret;
115
116 if (argc < 1)
117 return 1;
118
119 msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, false);
120 nla_put_u32(msg, NL80211_ATTR_WIPHY, phy);
121
122 data = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
123 for (; argc > 0; argc--, argv++) {
124 char *name = argv[0];
125 char *val = strchr(name, '=');
126
127 if (!val) {
128 fprintf(stderr, "Invalid argument: %s\n", name);
129 return 1;
130 }
131
132 *(val++) = 0;
133
134 for (i = 0; i < msg_field.len; i++) {
135 if (!fields[i].parse)
136 continue;
137
138 if (!strcmp(fields[i].name, name))
139 break;
140 }
141
142 if (i == msg_field.len) {
143 fprintf(stderr, "Unknown field: %s\n", name);
144 return 1;
145 }
146
147 if (tm_is_changed(i)) {
148 fprintf(stderr, "Duplicate field '%s'\n", name);
149 return 1;
150 }
151
152 if (!fields[i].parse(&fields[i], i, msg, val))
153 return 1;
154
155 tm_set_changed(i);
156 }
157
158 nla_nest_end(msg, data);
159
160 ret = unl_genl_request(&unl, msg, NULL, NULL);
161 if (ret)
162 fprintf(stderr, "nl80211 call failed: %s\n", strerror(-ret));
163
164 return ret;
165}
166
167int main(int argc, char **argv)
168{
169 const char *cmd, *phyname;
170 int phy;
171 int ret = 0;
172
173 progname = argv[0];
174 if (argc < 3)
175 usage();
176
177 if (unl_genl_init(&unl, "nl80211") < 0) {
178 fprintf(stderr, "Failed to connect to nl80211\n");
179 return 2;
180 }
181
182 phyname = argv[1];
183 phy = phy_lookup_idx(phyname);
184 if (phy < 0) {
185 fprintf(stderr, "Could not find phy '%s'\n", argv[1]);
186 return 2;
187 }
188
189 cmd = argv[2];
190 argv += 3;
191 argc -= 3;
192
193 if (!strcmp(cmd, "dump"))
194 ret = mt76_dump(phy, argc, argv);
195 else if (!strcmp(cmd, "set"))
196 ret = mt76_set(phy, argc, argv);
197 else if (!strcmp(cmd, "eeprom"))
198 ret = mt76_eeprom(phy, argc, argv);
199 else if (!strcmp(cmd, "fwlog"))
200 ret = mt76_fwlog(phyname, argc, argv);
201 else
202 usage();
203
204 unl_free(&unl);
205
206 return ret;
207}