]> git.ipfire.org Git - thirdparty/iw.git/blame - measurements.c
iw: fix ftm_request missing arguments segfault
[thirdparty/iw.git] / measurements.c
CommitLineData
8ddb960e
JB
1#include <errno.h>
2
3#include "nl80211.h"
4#include "iw.h"
5#include <unistd.h>
6
7SECTION(measurement);
8
9static int put_preamble(struct nl_msg *msg, char *s)
10{
11 static const struct {
12 const char *name;
13 unsigned int val;
14 } preamble_map[] = {
15 { .name = "legacy", .val = NL80211_PREAMBLE_LEGACY, },
16 { .name = "ht", .val = NL80211_PREAMBLE_HT, },
17 { .name = "vht", .val = NL80211_PREAMBLE_VHT, },
18 { .name = "dmg", .val = NL80211_PREAMBLE_DMG, },
19 };
20 unsigned int i;
21
22 for (i = 0; i < ARRAY_SIZE(preamble_map); i++) {
23 if (strcasecmp(preamble_map[i].name, s) == 0) {
24 NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE,
25 preamble_map[i].val);
26 return 0;
27 }
28 }
29
30nla_put_failure:
31 return -1;
32}
33
34static int parse_ftm_target(struct nl_msg *msg, char *str, int peer_index)
35{
36 unsigned char addr[ETH_ALEN];
37 int res, consumed;
38 char *bw = NULL, *pos, *tmp, *save_ptr, *delims = " \t\n";
39 struct nlattr *peer, *req, *reqdata, *ftm, *chan;
40 bool report_ap_tsf = false, preamble = false;
41 unsigned int freq = 0, cf1 = 0, cf2 = 0;
42
43 res = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx%n",
44 &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5],
45 &consumed);
46
47 if (res != ETH_ALEN) {
48 printf("Invalid MAC address\n");
49 return HANDLER_RET_USAGE;
50 }
51
52 peer = nla_nest_start(msg, peer_index);
53
54 NLA_PUT(msg, NL80211_PMSR_PEER_ATTR_ADDR, ETH_ALEN, addr);
55
56 req = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_REQ);
57 if (!req)
58 goto nla_put_failure;
59 reqdata = nla_nest_start(msg, NL80211_PMSR_REQ_ATTR_DATA);
60 if (!reqdata)
61 goto nla_put_failure;
62 ftm = nla_nest_start(msg, NL80211_PMSR_TYPE_FTM);
63 if (!ftm)
64 goto nla_put_failure;
65
66 str += consumed;
67 pos = strtok_r(str, delims, &save_ptr);
68
69 while (pos) {
70 if (strncmp(pos, "cf=", 3) == 0) {
71 freq = strtol(pos + 3, &tmp, 0);
72 if (*tmp) {
73 printf("Invalid cf value!\n");
74 return HANDLER_RET_USAGE;
75 }
76 } else if (strncmp(pos, "bw=", 3) == 0) {
77 bw = pos + 3;
78 } else if (strncmp(pos, "cf1=", 4) == 0) {
79 cf1 = strtol(pos + 4, &tmp, 0);
80 if (*tmp) {
81 printf("Invalid cf1 value!\n");
82 return HANDLER_RET_USAGE;
83 }
84 } else if (strncmp(pos, "cf2=", 4) == 0) {
85 cf2 = strtol(pos + 4, &tmp, 0);
86 if (*tmp) {
87 printf("Invalid cf2 value!\n");
88 return HANDLER_RET_USAGE;
89 }
90 } else if (strncmp(pos, "bursts_exp=", 11) == 0) {
91 NLA_PUT_U8(msg,
92 NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP,
93 strtol(pos + 11, &tmp, 0));
94 if (*tmp) {
95 printf("Invalid bursts_exp value!\n");
96 return HANDLER_RET_USAGE;
97 }
98 } else if (strncmp(pos, "burst_period=", 13) == 0) {
99 NLA_PUT_U16(msg, NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD,
100 strtol(pos + 13, &tmp, 0));
101 if (*tmp) {
102 printf("Invalid burst_period value!\n");
103 return HANDLER_RET_USAGE;
104 }
105 } else if (strncmp(pos, "retries=", 8) == 0) {
106 NLA_PUT_U8(msg,
107 NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES,
108 strtol(pos + 8, &tmp, 0));
109 if (*tmp) {
110 printf("Invalid retries value!\n");
111 return HANDLER_RET_USAGE;
112 }
113 } else if (strncmp(pos, "burst_duration=", 15) == 0) {
114 NLA_PUT_U8(msg,
115 NL80211_PMSR_FTM_REQ_ATTR_BURST_DURATION,
116 strtol(pos + 15, &tmp, 0));
117 if (*tmp) {
118 printf("Invalid burst_duration value!\n");
119 return HANDLER_RET_USAGE;
120 }
121 } else if (strncmp(pos, "ftms_per_burst=", 15) == 0) {
122 NLA_PUT_U8(msg,
123 NL80211_PMSR_FTM_REQ_ATTR_FTMS_PER_BURST,
124 strtol(pos + 15, &tmp, 0));
125 if (*tmp) {
126 printf("Invalid ftms_per_burst value!\n");
127 return HANDLER_RET_USAGE;
128 }
129 } else if (strcmp(pos, "asap") == 0) {
130 NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_ASAP);
131 } else if (strcmp(pos, "ap-tsf") == 0) {
132 report_ap_tsf = true;
133 } else if (strcmp(pos, "civic") == 0) {
134 NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC);
135 } else if (strcmp(pos, "lci") == 0) {
136 NLA_PUT_FLAG(msg, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI);
137 } else if (strncmp(pos, "preamble=", 9) == 0) {
138 if (put_preamble(msg, pos + 9)) {
139 printf("Invalid preamble %s\n", pos + 9);
140 return HANDLER_RET_USAGE;
141 }
142 preamble = true;
125abec7
AS
143 } else if (strncmp(pos, "tb", 2) == 0) {
144 NLA_PUT_FLAG(msg,
145 NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED);
146 NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE,
147 NL80211_PREAMBLE_HE);
148 preamble = true;
149 } else if (strncmp(pos, "non_tb", 6) == 0) {
150 NLA_PUT_FLAG(msg,
151 NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED);
152 NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE,
153 NL80211_PREAMBLE_HE);
154 preamble = true;
8ddb960e
JB
155 } else {
156 printf("Unknown parameter %s\n", pos);
157 return HANDLER_RET_USAGE;
158 }
159
160 pos = strtok_r(NULL, delims, &save_ptr);
161 }
162
163 if (!preamble) {
164 int preamble = -1;
165
166 switch (str_to_bw(bw)) {
167 case NL80211_CHAN_WIDTH_20_NOHT:
168 case NL80211_CHAN_WIDTH_5:
169 case NL80211_CHAN_WIDTH_10:
170 preamble = NL80211_PREAMBLE_LEGACY;
171 break;
172 case NL80211_CHAN_WIDTH_20:
173 case NL80211_CHAN_WIDTH_40:
174 preamble = NL80211_PREAMBLE_HT;
175 break;
176 case NL80211_CHAN_WIDTH_80:
177 case NL80211_CHAN_WIDTH_80P80:
178 case NL80211_CHAN_WIDTH_160:
179 preamble = NL80211_PREAMBLE_VHT;
180 break;
f718f11d
JB
181 default:
182 return HANDLER_RET_USAGE;
8ddb960e
JB
183 }
184
185 NLA_PUT_U32(msg, NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE, preamble);
186 }
187
188 nla_nest_end(msg, ftm);
189 if (report_ap_tsf)
190 NLA_PUT_FLAG(msg, NL80211_PMSR_REQ_ATTR_GET_AP_TSF);
191 nla_nest_end(msg, reqdata);
192 nla_nest_end(msg, req);
193
194 /* set the channel */
195 chan = nla_nest_start(msg, NL80211_PMSR_PEER_ATTR_CHAN);
196 if (!chan)
197 goto nla_put_failure;
198 if (freq)
199 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
200 if (cf1)
201 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, cf1);
202 if (cf2)
203 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, cf2);
204 if (bw)
205 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
206 str_to_bw(bw));
207 nla_nest_end(msg, chan);
208
209 nla_nest_end(msg, peer);
210 return 0;
211nla_put_failure:
212 return -ENOBUFS;
213}
214
215static int parse_ftm_config(struct nl_msg *msg, const char *file)
216{
217 FILE *input;
218 char line[256];
219 int line_num;
220
221 input = fopen(file, "r");
222 if (!input) {
223 int err = errno;
224
225 printf("Failed to open file: %s\n", strerror(err));
226 return -err;
227 }
228
229 for (line_num = 1; fgets(line, sizeof(line), input); line_num++) {
230 if (line[0] == '#')
231 continue;
232
233 if (parse_ftm_target(msg, line, line_num)) {
234 printf("Invalid FTM configuration at line %d!\n",
235 line_num);
236 return HANDLER_RET_USAGE;
237 }
238 }
239
240 return 0;
241}
242
243static int handle_ftm_req(struct nl80211_state *state, struct nl_msg *msg,
244 int argc, char **argv, enum id_input id)
245{
246 int err, i;
247 static char **req_argv;
248 static const __u32 wait[] = {
249 NL80211_CMD_PEER_MEASUREMENT_COMPLETE,
250 };
251 static const __u32 print[] = {
252 NL80211_CMD_PEER_MEASUREMENT_RESULT,
253 NL80211_CMD_PEER_MEASUREMENT_COMPLETE,
254 };
255 struct print_event_args printargs = { };
256
257 req_argv = calloc(argc + 1, sizeof(req_argv[0]));
258 req_argv[0] = argv[0];
259 req_argv[1] = "measurement";
260 req_argv[2] = "ftm_request_send";
261 for (i = 3; i < argc; i++)
262 req_argv[i] = argv[i];
263
264 err = handle_cmd(state, id, argc, req_argv);
265
266 free(req_argv);
267
268 if (err)
269 return err;
270
271 __do_listen_events(state,
272 ARRAY_SIZE(wait), wait,
273 ARRAY_SIZE(print), print,
274 &printargs);
275 return 0;
276}
277
278static int handle_ftm_req_send(struct nl80211_state *state, struct nl_msg *msg,
279 int argc, char **argv, enum id_input id)
280{
281 struct nlattr *pmsr, *peers;
282 const char *file;
283 int err;
284
8fab0c9e
BA
285 if (argc < 1)
286 return HANDLER_RET_USAGE;
287
8ddb960e
JB
288 file = argv[0];
289 argc--;
290 argv++;
291 while (argc) {
292 if (strncmp(argv[0], "randomise", 9) == 0 ||
293 strncmp(argv[0], "randomize", 9) == 0) {
294 err = parse_random_mac_addr(msg, argv[0] + 9);
295 if (err)
296 return err;
297 } else if (strncmp(argv[0], "timeout=", 8) == 0) {
298 char *end;
299
300 NLA_PUT_U32(msg, NL80211_ATTR_TIMEOUT,
301 strtoul(argv[0] + 8, &end, 0));
302 if (*end)
303 return HANDLER_RET_USAGE;
304 } else {
305 return HANDLER_RET_USAGE;
306 }
307
308 argc--;
309 argv++;
310 }
311
312 pmsr = nla_nest_start(msg, NL80211_ATTR_PEER_MEASUREMENTS);
313 if (!pmsr)
314 goto nla_put_failure;
315 peers = nla_nest_start(msg, NL80211_PMSR_ATTR_PEERS);
316 if (!peers)
317 goto nla_put_failure;
318
319 err = parse_ftm_config(msg, file);
320 if (err)
321 return err;
322
323 nla_nest_end(msg, peers);
324 nla_nest_end(msg, pmsr);
325
326 return 0;
327
328nla_put_failure:
329 return -ENOBUFS;
330}
331COMMAND(measurement, ftm_request, "<config-file> [timeout=<seconds>] [randomise[=<addr>/<mask>]]", 0, 0,
332 CIB_NETDEV, handle_ftm_req,
333 "Send an FTM request to the targets supplied in the config file.\n"
334 "Each line in the file represents a target, with the following format:\n"
125abec7 335 "<addr> bw=<[20|40|80|80+80|160]> cf=<center_freq> [cf1=<center_freq1>] [cf2=<center_freq2>] [ftms_per_burst=<samples per burst>] [ap-tsf] [asap] [bursts_exp=<num of bursts exponent>] [burst_period=<burst period>] [retries=<num of retries>] [burst_duration=<burst duration>] [preamble=<legacy,ht,vht,dmg>] [lci] [civic] [tb] [non_tb]");
8ddb960e
JB
336HIDDEN(measurement, ftm_request_send, "", NL80211_CMD_PEER_MEASUREMENT_START,
337 0, CIB_NETDEV, handle_ftm_req_send);