]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
iw: remove sizer section and related code
[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
a32046bc 194 res = parse_freqchan(&chandef, false, argc, argv, NULL, false);
159d5e42
BB
195 if (res)
196 return res;
197
198 return put_chandef(msg, &chandef);
379f8397 199}
159d5e42 200
cce98977 201COMMAND(set, freq, PARSE_FREQ_ARGS("", ""),
00c448b2 202 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
cce98977
JB
203 "Set frequency/channel configuration the hardware is using.");
204COMMAND(set, freq, PARSE_FREQ_ARGS("", ""),
01ae06f9 205 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 206
a32046bc
GI
207static int handle_freq_khz(struct nl80211_state *state, struct nl_msg *msg,
208 int argc, char **argv,
209 enum id_input id)
210{
211 struct chandef chandef;
212 int res;
213
214 res = parse_freqchan(&chandef, false, argc, argv, NULL, true);
215 if (res)
216 return res;
217
218 return put_chandef(msg, &chandef);
219}
220
cce98977 221COMMAND(set, freq_khz, PARSE_FREQ_KHZ_ARGS("", ""),
a32046bc
GI
222 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq_khz,
223 "Set frequency in kHz the hardware is using\n"
224 "configuration.");
cce98977 225COMMAND(set, freq_khz, PARSE_FREQ_KHZ_ARGS("", ""),
a32046bc
GI
226 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq_khz, NULL);
227
34b23014 228static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
229 int argc, char **argv,
230 enum id_input id)
379f8397 231{
159d5e42
BB
232 struct chandef chandef;
233 int res;
234
a32046bc 235 res = parse_freqchan(&chandef, true, argc, argv, NULL, false);
159d5e42
BB
236 if (res)
237 return res;
238
239 return put_chandef(msg, &chandef);
379f8397 240}
cce98977 241COMMAND(set, channel, PARSE_CHAN_ARGS(""),
01ae06f9 242 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
cce98977 243COMMAND(set, channel, PARSE_CHAN_ARGS(""),
01ae06f9 244 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae 245
2ba2f599
BB
246
247struct cac_event {
248 int ret;
249 uint32_t freq;
250};
251
252static int print_cac_event(struct nl_msg *msg, void *arg)
253{
254 struct nlattr *tb[NL80211_ATTR_MAX + 1];
255 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
256 enum nl80211_radar_event event_type;
257 struct cac_event *cac_event = arg;
258 uint32_t freq;
259
260 if (gnlh->cmd != NL80211_CMD_RADAR_DETECT)
261 return NL_SKIP;
262
263 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
264 genlmsg_attrlen(gnlh, 0), NULL);
265
266 if (!tb[NL80211_ATTR_RADAR_EVENT] || !tb[NL80211_ATTR_WIPHY_FREQ])
267 return NL_SKIP;
268
269 freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
270 event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
271 if (freq != cac_event->freq)
272 return NL_SKIP;
273
274 switch (event_type) {
275 case NL80211_RADAR_DETECTED:
276 printf("%d MHz: radar detected\n", freq);
277 break;
278 case NL80211_RADAR_CAC_FINISHED:
279 printf("%d MHz: CAC finished\n", freq);
280 break;
281 case NL80211_RADAR_CAC_ABORTED:
282 printf("%d MHz: CAC was aborted\n", freq);
283 break;
284 case NL80211_RADAR_NOP_FINISHED:
285 printf("%d MHz: NOP finished\n", freq);
286 break;
287 default:
288 printf("%d MHz: unknown radar event\n", freq);
289 }
290 cac_event->ret = 0;
291
292 return NL_SKIP;
293}
294
295static int handle_cac_trigger(struct nl80211_state *state,
296 struct nl_msg *msg,
297 int argc, char **argv,
298 enum id_input id)
299{
300 struct chandef chandef;
301 int res;
302
303 if (argc < 2)
304 return 1;
305
306 if (strcmp(argv[0], "channel") == 0) {
a32046bc 307 res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL, false);
2ba2f599 308 } else if (strcmp(argv[0], "freq") == 0) {
a32046bc 309 res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL, false);
2ba2f599
BB
310 } else {
311 return 1;
312 }
313
314 if (res)
315 return res;
316
317 return put_chandef(msg, &chandef);
318}
319
82e6fba0
JD
320static int handle_cac_background(struct nl80211_state *state,
321 struct nl_msg *msg,
322 int argc, char **argv,
323 enum id_input id)
324{
325 nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND);
326 return handle_cac_trigger(state, msg, argc, argv, id);
327}
328
2ba2f599
BB
329static int no_seq_check(struct nl_msg *msg, void *arg)
330{
331 return NL_OK;
332}
333
334static int handle_cac(struct nl80211_state *state,
335 struct nl_msg *msg,
336 int argc, char **argv,
337 enum id_input id)
338{
339 int err;
340 struct nl_cb *radar_cb;
341 struct chandef chandef;
342 struct cac_event cac_event;
343 char **cac_trigger_argv = NULL;
344
345 radar_cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
346 if (!radar_cb)
347 return 1;
348
349 if (argc < 3)
350 return 1;
351
352 if (strcmp(argv[2], "channel") == 0) {
a32046bc 353 err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL, false);
2ba2f599 354 } else if (strcmp(argv[2], "freq") == 0) {
a32046bc 355 err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL, false);
2ba2f599 356 } else {
6a7cc867 357 err = 1;
2ba2f599 358 }
71e6d184
JB
359 if (err)
360 goto err_out;
2ba2f599
BB
361
362 cac_trigger_argv = calloc(argc + 1, sizeof(char*));
6a7cc867
JC
363 if (!cac_trigger_argv) {
364 err = -ENOMEM;
365 goto err_out;
366 }
2ba2f599
BB
367
368 cac_trigger_argv[0] = argv[0];
369 cac_trigger_argv[1] = "cac";
370 cac_trigger_argv[2] = "trigger";
371 memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
372
373 err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
2ba2f599 374 if (err)
6a7cc867 375 goto err_out;
2ba2f599
BB
376
377 cac_event.ret = 1;
378 cac_event.freq = chandef.control_freq;
379
380 __prepare_listen_events(state);
381 nl_socket_set_cb(state->nl_sock, radar_cb);
382
383 /* need to turn off sequence number checking */
384 nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
385 nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
386 while (cac_event.ret > 0)
387 nl_recvmsgs(state->nl_sock, radar_cb);
388
6a7cc867
JC
389 err = 0;
390err_out:
391 if (radar_cb)
392 nl_cb_put(radar_cb);
393 if (cac_trigger_argv)
394 free(cac_trigger_argv);
395 return err;
2ba2f599 396}
cce98977
JB
397TOPLEVEL(cac, PARSE_CHAN_ARGS("channel ") "\n"
398 PARSE_FREQ_ARGS("freq ", ""),
2ba2f599
BB
399 0, 0, CIB_NETDEV, handle_cac, NULL);
400COMMAND(cac, trigger,
cce98977
JB
401 PARSE_CHAN_ARGS("channel ") "\n"
402 PARSE_FREQ_ARGS("freq ", ""),
2ba2f599
BB
403 NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
404 "Start or trigger a channel availability check (CAC) looking to look for\n"
405 "radars on the given channel.");
406
82e6fba0 407COMMAND(cac, background,
cce98977
JB
408 PARSE_CHAN_ARGS("channel ") "\n"
409 PARSE_FREQ_ARGS("freq ", ""),
82e6fba0
JD
410 NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_background,
411 "Start background channel availability check (CAC) looking to look for\n"
412 "radars on the given channel.");
413
625aa4ae 414static int handle_fragmentation(struct nl80211_state *state,
34b23014 415 struct nl_msg *msg,
05514f95
JB
416 int argc, char **argv,
417 enum id_input id)
625aa4ae
JB
418{
419 unsigned int frag;
420
421 if (argc != 1)
422 return 1;
423
424 if (strcmp("off", argv[0]) == 0)
425 frag = -1;
e86b7e02
JB
426 else {
427 char *end;
428
429 if (!*argv[0])
430 return 1;
431 frag = strtoul(argv[0], &end, 10);
432 if (*end != '\0')
433 return 1;
434 }
625aa4ae
JB
435
436 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
437
438 return 0;
439 nla_put_failure:
440 return -ENOBUFS;
441}
442COMMAND(set, frag, "<fragmentation threshold|off>",
443 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
444 "Set fragmentation threshold.");
445
446static int handle_rts(struct nl80211_state *state,
34b23014 447 struct nl_msg *msg,
05514f95
JB
448 int argc, char **argv,
449 enum id_input id)
625aa4ae
JB
450{
451 unsigned int rts;
452
453 if (argc != 1)
454 return 1;
455
456 if (strcmp("off", argv[0]) == 0)
457 rts = -1;
e86b7e02
JB
458 else {
459 char *end;
460
461 if (!*argv[0])
462 return 1;
463 rts = strtoul(argv[0], &end, 10);
464 if (*end != '\0')
465 return 1;
466 }
625aa4ae
JB
467
468 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
469
470 return 0;
471 nla_put_failure:
472 return -ENOBUFS;
473}
474COMMAND(set, rts, "<rts threshold|off>",
475 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
476 "Set rts threshold.");
e960e066 477
c993e6e7 478static int handle_retry(struct nl80211_state *state,
34b23014 479 struct nl_msg *msg,
c993e6e7
UR
480 int argc, char **argv, enum id_input id)
481{
482 unsigned int retry_short = 0, retry_long = 0;
483 bool have_retry_s = false, have_retry_l = false;
484 int i;
485 enum {
486 S_NONE,
487 S_SHORT,
488 S_LONG,
489 } parser_state = S_NONE;
490
491 if (!argc || (argc != 2 && argc != 4))
492 return 1;
493
494 for (i = 0; i < argc; i++) {
495 char *end;
496 unsigned int tmpul;
497
498 if (strcmp(argv[i], "short") == 0) {
499 if (have_retry_s)
500 return 1;
501 parser_state = S_SHORT;
502 have_retry_s = true;
503 } else if (strcmp(argv[i], "long") == 0) {
504 if (have_retry_l)
505 return 1;
506 parser_state = S_LONG;
507 have_retry_l = true;
508 } else {
509 tmpul = strtoul(argv[i], &end, 10);
510 if (*end != '\0')
511 return 1;
512 if (!tmpul || tmpul > 255)
513 return -EINVAL;
514 switch (parser_state) {
515 case S_SHORT:
516 retry_short = tmpul;
517 break;
518 case S_LONG:
519 retry_long = tmpul;
520 break;
521 default:
522 return 1;
523 }
524 }
525 }
526
527 if (!have_retry_s && !have_retry_l)
528 return 1;
529 if (have_retry_s)
530 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
531 if (have_retry_l)
532 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
533
534 return 0;
535 nla_put_failure:
536 return -ENOBUFS;
537}
538COMMAND(set, retry, "[short <limit>] [long <limit>]",
539 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
540 "Set retry limit.");
541
91454b65
VK
542#ifndef NETNS_RUN_DIR
543#define NETNS_RUN_DIR "/var/run/netns"
544#endif
c0441e65 545static int netns_get_fd(const char *name)
91454b65
VK
546{
547 char pathbuf[MAXPATHLEN];
548 const char *path, *ptr;
549
550 path = name;
551 ptr = strchr(name, '/');
552 if (!ptr) {
553 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
554 NETNS_RUN_DIR, name );
555 path = pathbuf;
556 }
557 return open(path, O_RDONLY);
558}
559
e960e066 560static int handle_netns(struct nl80211_state *state,
e960e066 561 struct nl_msg *msg,
05514f95
JB
562 int argc, char **argv,
563 enum id_input id)
e960e066
JB
564{
565 char *end;
3a51540c 566 int fd = -1;
e960e066 567
91454b65 568 if (argc < 1 || !*argv[0])
e960e066
JB
569 return 1;
570
91454b65
VK
571 if (argc == 1) {
572 NLA_PUT_U32(msg, NL80211_ATTR_PID,
573 strtoul(argv[0], &end, 10));
574 if (*end != '\0') {
575 printf("Invalid parameter: pid(%s)\n", argv[0]);
576 return 1;
577 }
578 return 0;
579 }
580
581 if (argc != 2 || strcmp(argv[0], "name"))
e86b7e02
JB
582 return 1;
583
91454b65
VK
584 if ((fd = netns_get_fd(argv[1])) >= 0) {
585 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
586 return 0;
587 } else {
588 printf("Invalid parameter: nsname(%s)\n", argv[0]);
589 }
e960e066 590
91454b65 591 return 1;
e960e066 592
e960e066 593 nla_put_failure:
3a51540c
JC
594 if (fd >= 0)
595 close(fd);
e960e066
JB
596 return -ENOBUFS;
597}
91454b65 598COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 599 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
600 "Put this wireless device into a different network namespace:\n"
601 " <pid> - change network namespace by process id\n"
602 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
603 " or by absolute path (man ip-netns)\n");
b2f92dd0
LT
604
605static int handle_coverage(struct nl80211_state *state,
b2f92dd0 606 struct nl_msg *msg,
05514f95
JB
607 int argc, char **argv,
608 enum id_input id)
b2f92dd0 609{
e86b7e02 610 char *end;
b2f92dd0
LT
611 unsigned int coverage;
612
613 if (argc != 1)
614 return 1;
615
e86b7e02
JB
616 if (!*argv[0])
617 return 1;
618 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
619 if (coverage > 255)
620 return 1;
621
e86b7e02
JB
622 if (*end)
623 return 1;
624
b2f92dd0
LT
625 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
626
627 return 0;
628 nla_put_failure:
629 return -ENOBUFS;
630}
631COMMAND(set, coverage, "<coverage class>",
632 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
633 "Set coverage class (1 for every 3 usec of air propagation time).\n"
634 "Valid values: 0 - 255.");
635
636static int handle_distance(struct nl80211_state *state,
b2f92dd0 637 struct nl_msg *msg,
05514f95
JB
638 int argc, char **argv,
639 enum id_input id)
b2f92dd0 640{
b2f92dd0
LT
641 if (argc != 1)
642 return 1;
643
e86b7e02
JB
644 if (!*argv[0])
645 return 1;
646
e642142d
LB
647 if (strcmp("auto", argv[0]) == 0) {
648 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
649 } else {
650 char *end;
651 unsigned int distance, coverage;
e86b7e02 652
e642142d 653 distance = strtoul(argv[0], &end, 10);
b2f92dd0 654
e642142d
LB
655 if (*end)
656 return 1;
b2f92dd0 657
e642142d
LB
658 /*
659 * Divide double the distance by the speed of light
660 * in m/usec (300) to get round-trip time in microseconds
661 * and then divide the result by three to get coverage class
662 * as specified in IEEE 802.11-2007 table 7-27.
663 * Values are rounded upwards.
664 */
665 coverage = (distance + 449) / 450;
666 if (coverage > 255)
667 return 1;
668
669 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
670 }
b2f92dd0
LT
671
672 return 0;
673 nla_put_failure:
674 return -ENOBUFS;
675}
e642142d 676COMMAND(set, distance, "<auto|distance>",
b2f92dd0 677 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
678 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
679 "coverage class for given link distance in meters.\n"
680 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 681 "Valid values: 0 - 114750");
a0b1f574
JO
682
683static int handle_txpower(struct nl80211_state *state,
a0b1f574 684 struct nl_msg *msg,
05514f95
JB
685 int argc, char **argv,
686 enum id_input id)
a0b1f574
JO
687{
688 enum nl80211_tx_power_setting type;
689 int mbm;
690
691 /* get the required args */
692 if (argc != 1 && argc != 2)
693 return 1;
694
695 if (!strcmp(argv[0], "auto"))
696 type = NL80211_TX_POWER_AUTOMATIC;
697 else if (!strcmp(argv[0], "fixed"))
698 type = NL80211_TX_POWER_FIXED;
699 else if (!strcmp(argv[0], "limit"))
700 type = NL80211_TX_POWER_LIMITED;
701 else {
702 printf("Invalid parameter: %s\n", argv[0]);
703 return 2;
704 }
705
706 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
707
708 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 709 char *endptr;
a0b1f574
JO
710 if (argc != 2) {
711 printf("Missing TX power level argument.\n");
712 return 2;
713 }
714
18e05613 715 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 716 if (*endptr)
18e05613 717 return 2;
a0b1f574
JO
718 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
719 } else if (argc != 1)
720 return 1;
721
722 return 0;
723
724 nla_put_failure:
725 return -ENOBUFS;
726}
727COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
728 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
729 "Specify transmit power level and setting type.");
730COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
731 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
732 "Specify transmit power level and setting type.");
afce7986
BR
733
734static int handle_antenna(struct nl80211_state *state,
afce7986 735 struct nl_msg *msg,
05514f95
JB
736 int argc, char **argv,
737 enum id_input id)
afce7986
BR
738{
739 char *end;
740 uint32_t tx_ant = 0, rx_ant = 0;
741
742 if (argc == 1 && strcmp(argv[0], "all") == 0) {
743 tx_ant = 0xffffffff;
744 rx_ant = 0xffffffff;
745 } else if (argc == 1) {
746 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
747 if (*end)
748 return 1;
749 }
750 else if (argc == 2) {
751 tx_ant = strtoul(argv[0], &end, 0);
752 if (*end)
753 return 1;
754 rx_ant = strtoul(argv[1], &end, 0);
755 if (*end)
756 return 1;
757 } else
758 return 1;
759
760 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
761 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
762
763 return 0;
764
765 nla_put_failure:
766 return -ENOBUFS;
767}
768COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
769 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
770 "Set a bitmap of allowed antennas to use for TX and RX.\n"
771 "The driver may reject antenna configurations it cannot support.");
1eb2f5c9
THJ
772
773static int handle_set_txq(struct nl80211_state *state,
774 struct nl_msg *msg,
775 int argc, char **argv,
776 enum id_input id)
777{
778 unsigned int argval;
779 char *end;
780
781 if (argc != 2)
782 return 1;
783
784 if (!*argv[0] || !*argv[1])
785 return 1;
786
787 argval = strtoul(argv[1], &end, 10);
788
789 if (*end)
790 return 1;
791
792 if (!argval)
793 return 1;
794
795 if (strcmp("limit", argv[0]) == 0)
796 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
797 else if (strcmp("memory_limit", argv[0]) == 0)
798 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
799 else if (strcmp("quantum", argv[0]) == 0)
800 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
801 else
802 return -1;
803
804 return 0;
805 nla_put_failure:
806 return -ENOBUFS;
807}
808COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
809 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
810 "Set TXQ parameters. The limit and memory_limit are global queue limits\n"
811 "for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
812 "Valid values: 1 - 2**32");
813
814static int print_txq_handler(struct nl_msg *msg, void *arg)
815{
816 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
817 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
818 struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
819 static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
820 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
821 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
822 [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
823 [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
824 [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
825 [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
826 };
827
828 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
829 genlmsg_attrlen(gnlh, 0), NULL);
830
831
832 if (attrs[NL80211_ATTR_TXQ_LIMIT])
833 printf("Packet limit:\t\t%u pkts\n",
834 nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
835 if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
836 printf("Memory limit:\t\t%u bytes\n",
837 nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
838 if (attrs[NL80211_ATTR_TXQ_QUANTUM])
839 printf("Quantum:\t\t%u bytes\n",
840 nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
841
842 if (attrs[NL80211_ATTR_TXQ_STATS]) {
843 if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
844 attrs[NL80211_ATTR_TXQ_STATS],
845 txqstats_policy)) {
846 printf("failed to parse nested TXQ stats attributes!");
847 return 0;
848 }
849 txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
850 if (txqinfo)
851 printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
852
853 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
854 if (txqinfo)
855 printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
856
857 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
858 if (txqinfo)
859 printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
860
861 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
862 if (txqinfo)
863 printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
864
865 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
866 if (txqinfo)
867 printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
868 txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
869 if (txqinfo)
870 printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
871 }
872 return NL_SKIP;
873}
874
875static int handle_get_txq(struct nl80211_state *state,
876 struct nl_msg *msg,
877 int argc, char **argv,
878 enum id_input id)
879{
880 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
881 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
882 register_handler(print_txq_handler, NULL);
883 return 0;
884}
885COMMAND(get, txq, "",
886 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
887 "Get TXQ parameters.");