]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
iw: fix memory leaks inside handle_scan
[thirdparty/iw.git] / phy.c
CommitLineData
379f8397 1#include <stdbool.h>
0f55e0b8 2#include <errno.h>
d0260390 3#include <strings.h>
3a51540c 4#include <unistd.h>
91454b65
VK
5#include <sys/param.h>
6#include <sys/stat.h>
7#include <fcntl.h>
0f55e0b8
JB
8
9#include <netlink/genl/genl.h>
10#include <netlink/genl/family.h>
11#include <netlink/genl/ctrl.h>
12#include <netlink/msg.h>
13#include <netlink/attr.h>
14
f408e01b 15#include "nl80211.h"
0f55e0b8
JB
16#include "iw.h"
17
db9d4050
RM
18struct channels_ctx {
19 int last_band;
20 bool width_40;
21 bool width_80;
22 bool width_160;
23};
24
25static char *dfs_state_name(enum nl80211_dfs_state state)
26{
27 switch (state) {
28 case NL80211_DFS_USABLE:
29 return "usable";
30 case NL80211_DFS_AVAILABLE:
31 return "available";
32 case NL80211_DFS_UNAVAILABLE:
33 return "unavailable";
34 default:
35 return "unknown";
36 }
37}
38
39static int print_channels_handler(struct nl_msg *msg, void *arg)
40{
41 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
42 struct channels_ctx *ctx = arg;
43 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
44 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
45 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
46 struct nlattr *nl_band;
47 struct nlattr *nl_freq;
48 int rem_band, rem_freq;
49
50 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
51
52 if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
53 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
54 if (ctx->last_band != nl_band->nla_type) {
55 printf("Band %d:\n", nl_band->nla_type + 1);
56 ctx->width_40 = false;
57 ctx->width_80 = false;
58 ctx->width_160 = false;
59 ctx->last_band = nl_band->nla_type;
60 }
61
62 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL);
63
64 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
65 __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
66
67 if (cap & BIT(1))
68 ctx->width_40 = true;
69 }
70
71 if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
72 __u32 capa;
73
74 ctx->width_80 = true;
75
76 capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
77 switch ((capa >> 2) & 3) {
78 case 2:
79 /* width_80p80 = true; */
80 /* fall through */
81 case 1:
82 ctx->width_160 = true;
83 break;
84 }
85 }
86
87 if (tb_band[NL80211_BAND_ATTR_FREQS]) {
88 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
89 uint32_t freq;
90
91 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL);
92
93 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
94 continue;
95 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
96 printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq));
97
98 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
99 printf("(disabled)\n");
100 continue;
101 }
102 printf("\n");
103
104 if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
105 printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
106
107 /* If both flags are set assume an new kernel */
108 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) {
109 printf("\t No IR\n");
110 } else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) {
111 printf("\t Passive scan\n");
112 } else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){
113 printf("\t No IBSS\n");
114 }
115
116 if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
117 printf("\t Radar detection\n");
118
119 printf("\t Channel widths:");
120 if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
121 printf(" 20MHz");
122 if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
123 printf(" HT40-");
124 if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
125 printf(" HT40+");
126 if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
127 printf(" VHT80");
128 if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
129 printf(" VHT160");
130 printf("\n");
131
132 if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
133 enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
134 unsigned long time;
135
136 printf("\t DFS state: %s", dfs_state_name(state));
137 if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) {
138 time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]);
139 printf(" (for %lu sec)", time / 1000);
140 }
141 printf("\n");
142 if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])
143 printf("\t DFS CAC time: %u ms\n",
144 nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]));
145 }
146 }
147 }
148 }
149 }
150
151 return NL_SKIP;
152}
153
154static int handle_channels(struct nl80211_state *state, struct nl_msg *msg,
155 int argc, char **argv, enum id_input id)
156{
157 static struct channels_ctx ctx = {
158 .last_band = -1,
159 };
160
161 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
162 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
163
164 register_handler(print_channels_handler, &ctx);
165
166 return 0;
167}
168TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
169
7c37a24d 170static int handle_name(struct nl80211_state *state,
0f55e0b8 171 struct nl_msg *msg,
05514f95
JB
172 int argc, char **argv,
173 enum id_input id)
0f55e0b8 174{
0f55e0b8 175 if (argc != 1)
5e75fd04 176 return 1;
0f55e0b8
JB
177
178 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
179
70391ccf 180 return 0;
0f55e0b8 181 nla_put_failure:
70391ccf 182 return -ENOBUFS;
0f55e0b8 183}
cea8fa1c
JB
184COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
185 "Rename this wireless device.");
b822cda9 186
34b23014 187static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
188 int argc, char **argv,
189 enum id_input id)
379f8397 190{
159d5e42
BB
191 struct chandef chandef;
192 int res;
193
194 res = parse_freqchan(&chandef, false, argc, argv, NULL);
195 if (res)
196 return res;
197
198 return put_chandef(msg, &chandef);
379f8397 199}
159d5e42
BB
200
201COMMAND(set, freq,
202 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
203 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
00c448b2
JB
204 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
205 "Set frequency/channel the hardware is using, including HT\n"
206 "configuration.");
159d5e42
BB
207COMMAND(set, freq,
208 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
209 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
01ae06f9 210 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 211
34b23014 212static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
213 int argc, char **argv,
214 enum id_input id)
379f8397 215{
159d5e42
BB
216 struct chandef chandef;
217 int res;
218
219 res = parse_freqchan(&chandef, true, argc, argv, NULL);
220 if (res)
221 return res;
222
223 return put_chandef(msg, &chandef);
379f8397 224}
159d5e42 225COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
01ae06f9 226 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
159d5e42 227COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
01ae06f9 228 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae 229
2ba2f599
BB
230
231struct cac_event {
232 int ret;
233 uint32_t freq;
234};
235
236static int print_cac_event(struct nl_msg *msg, void *arg)
237{
238 struct nlattr *tb[NL80211_ATTR_MAX + 1];
239 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
240 enum nl80211_radar_event event_type;
241 struct cac_event *cac_event = arg;
242 uint32_t freq;
243
244 if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
245 return NL_SKIP;
246
247 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
248 genlmsg_attrlen(gnlh, 0), NULL);
249
250 if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
251 return NL_SKIP;
252
253 freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
254 event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
255 if (freq != cac_event->freq)
256 return NL_SKIP;
257
258 switch (event_type) {
259 case NL80211_RADAR_DETECTED:
260 printf("%d MHz: radar detected\n", freq);
261 break;
262 case NL80211_RADAR_CAC_FINISHED:
263 printf("%d MHz: CAC finished\n", freq);
264 break;
265 case NL80211_RADAR_CAC_ABORTED:
266 printf("%d MHz: CAC was aborted\n", freq);
267 break;
268 case NL80211_RADAR_NOP_FINISHED:
269 printf("%d MHz: NOP finished\n", freq);
270 break;
271 default:
272 printf("%d MHz: unknown radar event\n", freq);
273 }
274 cac_event->ret = 0;
275
276 return NL_SKIP;
277}
278
279static int handle_cac_trigger(struct nl80211_state *state,
280 struct nl_msg *msg,
281 int argc, char **argv,
282 enum id_input id)
283{
284 struct chandef chandef;
285 int res;
286
287 if (argc < 2)
288 return 1;
289
290 if (strcmp(argv[0], "channel") == 0) {
291 res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL);
292 } else if (strcmp(argv[0], "freq") == 0) {
293 res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL);
294 } else {
295 return 1;
296 }
297
298 if (res)
299 return res;
300
301 return put_chandef(msg, &chandef);
302}
303
304static int no_seq_check(struct nl_msg *msg, void *arg)
305{
306 return NL_OK;
307}
308
309static int handle_cac(struct nl80211_state *state,
310 struct nl_msg *msg,
311 int argc, char **argv,
312 enum id_input id)
313{
314 int err;
315 struct nl_cb *radar_cb;
316 struct chandef chandef;
317 struct cac_event cac_event;
318 char **cac_trigger_argv = NULL;
319
320 radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
321 if (!radar_cb)
322 return 1;
323
324 if (argc < 3)
325 return 1;
326
327 if (strcmp(argv[2], "channel") == 0) {
328 err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL);
329 } else if (strcmp(argv[2], "freq") == 0) {
330 err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL);
331 } else {
6a7cc867
JC
332 err = 1;
333 goto err_out;
2ba2f599
BB
334 }
335
336 cac_trigger_argv = calloc(argc + 1, sizeof(char*));
6a7cc867
JC
337 if (!cac_trigger_argv) {
338 err = -ENOMEM;
339 goto err_out;
340 }
2ba2f599
BB
341
342 cac_trigger_argv[0] = argv[0];
343 cac_trigger_argv[1] = "cac";
344 cac_trigger_argv[2] = "trigger";
345 memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
346
347 err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
2ba2f599 348 if (err)
6a7cc867 349 goto err_out;
2ba2f599
BB
350
351 cac_event.ret = 1;
352 cac_event.freq = chandef.control_freq;
353
354 __prepare_listen_events(state);
355 nl_socket_set_cb(state->nl_sock, radar_cb);
356
357 /* need to turn off sequence number checking */
358 nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
359 nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
360 while (cac_event.ret > 0)
361 nl_recvmsgs(state->nl_sock, radar_cb);
362
6a7cc867
JC
363 err = 0;
364err_out:
365 if (radar_cb)
366 nl_cb_put(radar_cb);
367 if (cac_trigger_argv)
368 free(cac_trigger_argv);
369 return err;
2ba2f599
BB
370}
371TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
372 "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
373 "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
374 0, 0, CIB_NETDEV, handle_cac, NULL);
375COMMAND(cac, trigger,
376 "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
377 "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
378 "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
379 NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
380 "Start or trigger a channel availability check (CAC) looking to look for\n"
381 "radars on the given channel.");
382
625aa4ae 383static int handle_fragmentation(struct nl80211_state *state,
34b23014 384 struct nl_msg *msg,
05514f95
JB
385 int argc, char **argv,
386 enum id_input id)
625aa4ae
JB
387{
388 unsigned int frag;
389
390 if (argc != 1)
391 return 1;
392
393 if (strcmp("off", argv[0]) == 0)
394 frag = -1;
e86b7e02
JB
395 else {
396 char *end;
397
398 if (!*argv[0])
399 return 1;
400 frag = strtoul(argv[0], &end, 10);
401 if (*end != '\0')
402 return 1;
403 }
625aa4ae
JB
404
405 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
406
407 return 0;
408 nla_put_failure:
409 return -ENOBUFS;
410}
411COMMAND(set, frag, "<fragmentation threshold|off>",
412 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
413 "Set fragmentation threshold.");
414
415static int handle_rts(struct nl80211_state *state,
34b23014 416 struct nl_msg *msg,
05514f95
JB
417 int argc, char **argv,
418 enum id_input id)
625aa4ae
JB
419{
420 unsigned int rts;
421
422 if (argc != 1)
423 return 1;
424
425 if (strcmp("off", argv[0]) == 0)
426 rts = -1;
e86b7e02
JB
427 else {
428 char *end;
429
430 if (!*argv[0])
431 return 1;
432 rts = strtoul(argv[0], &end, 10);
433 if (*end != '\0')
434 return 1;
435 }
625aa4ae
JB
436
437 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
438
439 return 0;
440 nla_put_failure:
441 return -ENOBUFS;
442}
443COMMAND(set, rts, "<rts threshold|off>",
444 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
445 "Set rts threshold.");
e960e066 446
c993e6e7 447static int handle_retry(struct nl80211_state *state,
34b23014 448 struct nl_msg *msg,
c993e6e7
UR
449 int argc, char **argv, enum id_input id)
450{
451 unsigned int retry_short = 0, retry_long = 0;
452 bool have_retry_s = false, have_retry_l = false;
453 int i;
454 enum {
455 S_NONE,
456 S_SHORT,
457 S_LONG,
458 } parser_state = S_NONE;
459
460 if (!argc || (argc != 2 && argc != 4))
461 return 1;
462
463 for (i = 0; i < argc; i++) {
464 char *end;
465 unsigned int tmpul;
466
467 if (strcmp(argv[i], "short") == 0) {
468 if (have_retry_s)
469 return 1;
470 parser_state = S_SHORT;
471 have_retry_s = true;
472 } else if (strcmp(argv[i], "long") == 0) {
473 if (have_retry_l)
474 return 1;
475 parser_state = S_LONG;
476 have_retry_l = true;
477 } else {
478 tmpul = strtoul(argv[i], &end, 10);
479 if (*end != '\0')
480 return 1;
481 if (!tmpul || tmpul > 255)
482 return -EINVAL;
483 switch (parser_state) {
484 case S_SHORT:
485 retry_short = tmpul;
486 break;
487 case S_LONG:
488 retry_long = tmpul;
489 break;
490 default:
491 return 1;
492 }
493 }
494 }
495
496 if (!have_retry_s && !have_retry_l)
497 return 1;
498 if (have_retry_s)
499 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
500 if (have_retry_l)
501 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
502
503 return 0;
504 nla_put_failure:
505 return -ENOBUFS;
506}
507COMMAND(set, retry, "[short <limit>] [long <limit>]",
508 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
509 "Set retry limit.");
510
91454b65
VK
511#ifndef NETNS_RUN_DIR
512#define NETNS_RUN_DIR "/var/run/netns"
513#endif
c0441e65 514static int netns_get_fd(const char *name)
91454b65
VK
515{
516 char pathbuf[MAXPATHLEN];
517 const char *path, *ptr;
518
519 path = name;
520 ptr = strchr(name, '/');
521 if (!ptr) {
522 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
523 NETNS_RUN_DIR, name );
524 path = pathbuf;
525 }
526 return open(path, O_RDONLY);
527}
528
e960e066 529static int handle_netns(struct nl80211_state *state,
e960e066 530 struct nl_msg *msg,
05514f95
JB
531 int argc, char **argv,
532 enum id_input id)
e960e066
JB
533{
534 char *end;
3a51540c 535 int fd = -1;
e960e066 536
91454b65 537 if (argc < 1 || !*argv[0])
e960e066
JB
538 return 1;
539
91454b65
VK
540 if (argc == 1) {
541 NLA_PUT_U32(msg, NL80211_ATTR_PID,
542 strtoul(argv[0], &end, 10));
543 if (*end != '\0') {
544 printf("Invalid parameter: pid(%s)\n", argv[0]);
545 return 1;
546 }
547 return 0;
548 }
549
550 if (argc != 2 || strcmp(argv[0], "name"))
e86b7e02
JB
551 return 1;
552
91454b65
VK
553 if ((fd = netns_get_fd(argv[1])) >= 0) {
554 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
555 return 0;
556 } else {
557 printf("Invalid parameter: nsname(%s)\n", argv[0]);
558 }
e960e066 559
91454b65 560 return 1;
e960e066 561
e960e066 562 nla_put_failure:
3a51540c
JC
563 if (fd >= 0)
564 close(fd);
e960e066
JB
565 return -ENOBUFS;
566}
91454b65 567COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 568 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
569 "Put this wireless device into a different network namespace:\n"
570 " <pid> - change network namespace by process id\n"
571 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
572 " or by absolute path (man ip-netns)\n");
b2f92dd0
LT
573
574static int handle_coverage(struct nl80211_state *state,
b2f92dd0 575 struct nl_msg *msg,
05514f95
JB
576 int argc, char **argv,
577 enum id_input id)
b2f92dd0 578{
e86b7e02 579 char *end;
b2f92dd0
LT
580 unsigned int coverage;
581
582 if (argc != 1)
583 return 1;
584
e86b7e02
JB
585 if (!*argv[0])
586 return 1;
587 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
588 if (coverage > 255)
589 return 1;
590
e86b7e02
JB
591 if (*end)
592 return 1;
593
b2f92dd0
LT
594 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
595
596 return 0;
597 nla_put_failure:
598 return -ENOBUFS;
599}
600COMMAND(set, coverage, "<coverage class>",
601 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
602 "Set coverage class (1 for every 3 usec of air propagation time).\n"
603 "Valid values: 0 - 255.");
604
605static int handle_distance(struct nl80211_state *state,
b2f92dd0 606 struct nl_msg *msg,
05514f95
JB
607 int argc, char **argv,
608 enum id_input id)
b2f92dd0 609{
b2f92dd0
LT
610 if (argc != 1)
611 return 1;
612
e86b7e02
JB
613 if (!*argv[0])
614 return 1;
615
e642142d
LB
616 if (strcmp("auto", argv[0]) == 0) {
617 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
618 } else {
619 char *end;
620 unsigned int distance, coverage;
e86b7e02 621
e642142d 622 distance = strtoul(argv[0], &end, 10);
b2f92dd0 623
e642142d
LB
624 if (*end)
625 return 1;
b2f92dd0 626
e642142d
LB
627 /*
628 * Divide double the distance by the speed of light
629 * in m/usec (300) to get round-trip time in microseconds
630 * and then divide the result by three to get coverage class
631 * as specified in IEEE 802.11-2007 table 7-27.
632 * Values are rounded upwards.
633 */
634 coverage = (distance + 449) / 450;
635 if (coverage > 255)
636 return 1;
637
638 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
639 }
b2f92dd0
LT
640
641 return 0;
642 nla_put_failure:
643 return -ENOBUFS;
644}
e642142d 645COMMAND(set, distance, "<auto|distance>",
b2f92dd0 646 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
647 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
648 "coverage class for given link distance in meters.\n"
649 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 650 "Valid values: 0 - 114750");
a0b1f574
JO
651
652static int handle_txpower(struct nl80211_state *state,
a0b1f574 653 struct nl_msg *msg,
05514f95
JB
654 int argc, char **argv,
655 enum id_input id)
a0b1f574
JO
656{
657 enum nl80211_tx_power_setting type;
658 int mbm;
659
660 /* get the required args */
661 if (argc != 1 && argc != 2)
662 return 1;
663
664 if (!strcmp(argv[0], "auto"))
665 type = NL80211_TX_POWER_AUTOMATIC;
666 else if (!strcmp(argv[0], "fixed"))
667 type = NL80211_TX_POWER_FIXED;
668 else if (!strcmp(argv[0], "limit"))
669 type = NL80211_TX_POWER_LIMITED;
670 else {
671 printf("Invalid parameter: %s\n", argv[0]);
672 return 2;
673 }
674
675 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
676
677 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 678 char *endptr;
a0b1f574
JO
679 if (argc != 2) {
680 printf("Missing TX power level argument.\n");
681 return 2;
682 }
683
18e05613 684 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 685 if (*endptr)
18e05613 686 return 2;
a0b1f574
JO
687 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
688 } else if (argc != 1)
689 return 1;
690
691 return 0;
692
693 nla_put_failure:
694 return -ENOBUFS;
695}
696COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
697 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
698 "Specify transmit power level and setting type.");
699COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
700 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
701 "Specify transmit power level and setting type.");
afce7986
BR
702
703static int handle_antenna(struct nl80211_state *state,
afce7986 704 struct nl_msg *msg,
05514f95
JB
705 int argc, char **argv,
706 enum id_input id)
afce7986
BR
707{
708 char *end;
709 uint32_t tx_ant = 0, rx_ant = 0;
710
711 if (argc == 1 && strcmp(argv[0], "all") == 0) {
712 tx_ant = 0xffffffff;
713 rx_ant = 0xffffffff;
714 } else if (argc == 1) {
715 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
716 if (*end)
717 return 1;
718 }
719 else if (argc == 2) {
720 tx_ant = strtoul(argv[0], &end, 0);
721 if (*end)
722 return 1;
723 rx_ant = strtoul(argv[1], &end, 0);
724 if (*end)
725 return 1;
726 } else
727 return 1;
728
729 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
730 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
731
732 return 0;
733
734 nla_put_failure:
735 return -ENOBUFS;
736}
737COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
738 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
739 "Set a bitmap of allowed antennas to use for TX and RX.\n"
740 "The driver may reject antenna configurations it cannot support.");
1eb2f5c9
THJ
741
742static int handle_set_txq(struct nl80211_state *state,
743 struct nl_msg *msg,
744 int argc, char **argv,
745 enum id_input id)
746{
747 unsigned int argval;
748 char *end;
749
750 if (argc != 2)
751 return 1;
752
753 if (!*argv[0] || !*argv[1])
754 return 1;
755
756 argval = strtoul(argv[1], &end, 10);
757
758 if (*end)
759 return 1;
760
761 if (!argval)
762 return 1;
763
764 if (strcmp("limit", argv[0]) == 0)
765 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
766 else if (strcmp("memory_limit", argv[0]) == 0)
767 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
768 else if (strcmp("quantum", argv[0]) == 0)
769 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
770 else
771 return -1;
772
773 return 0;
774 nla_put_failure:
775 return -ENOBUFS;
776}
777COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
778 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
779 "Set TXQ parameters. The limit and memory_limit are global queue limits\n"
780 "for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
781 "Valid values: 1 - 2**32");
782
783static int print_txq_handler(struct nl_msg *msg, void *arg)
784{
785 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
786 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
787 struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
788 static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
789 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
790 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
791 [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
792 [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
793 [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
794 [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
795 };
796
797 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
798 genlmsg_attrlen(gnlh, 0), NULL);
799
800
801 if (attrs[NL80211_ATTR_TXQ_LIMIT])
802 printf("Packet limit:\t\t%u pkts\n",
803 nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
804 if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
805 printf("Memory limit:\t\t%u bytes\n",
806 nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
807 if (attrs[NL80211_ATTR_TXQ_QUANTUM])
808 printf("Quantum:\t\t%u bytes\n",
809 nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
810
811 if (attrs[NL80211_ATTR_TXQ_STATS]) {
812 if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
813 attrs[NL80211_ATTR_TXQ_STATS],
814 txqstats_policy)) {
815 printf("failed to parse nested TXQ stats attributes!");
816 return 0;
817 }
818 txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
819 if (txqinfo)
820 printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
821
822 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
823 if (txqinfo)
824 printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
825
826 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
827 if (txqinfo)
828 printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
829
830 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
831 if (txqinfo)
832 printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
833
834 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
835 if (txqinfo)
836 printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
837 txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
838 if (txqinfo)
839 printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
840 }
841 return NL_SKIP;
842}
843
844static int handle_get_txq(struct nl80211_state *state,
845 struct nl_msg *msg,
846 int argc, char **argv,
847 enum id_input id)
848{
849 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
850 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
851 register_handler(print_txq_handler, NULL);
852 return 0;
853}
854COMMAND(get, txq, "",
855 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
856 "Get TXQ parameters.");