]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
info: macro-ify ext_feat_print()
[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 332 err = 1;
2ba2f599 333 }
71e6d184
JB
334 if (err)
335 goto err_out;
2ba2f599
BB
336
337 cac_trigger_argv = calloc(argc + 1, sizeof(char*));
6a7cc867
JC
338 if (!cac_trigger_argv) {
339 err = -ENOMEM;
340 goto err_out;
341 }
2ba2f599
BB
342
343 cac_trigger_argv[0] = argv[0];
344 cac_trigger_argv[1] = "cac";
345 cac_trigger_argv[2] = "trigger";
346 memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
347
348 err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
2ba2f599 349 if (err)
6a7cc867 350 goto err_out;
2ba2f599
BB
351
352 cac_event.ret = 1;
353 cac_event.freq = chandef.control_freq;
354
355 __prepare_listen_events(state);
356 nl_socket_set_cb(state->nl_sock, radar_cb);
357
358 /* need to turn off sequence number checking */
359 nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
360 nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
361 while (cac_event.ret > 0)
362 nl_recvmsgs(state->nl_sock, radar_cb);
363
6a7cc867
JC
364 err = 0;
365err_out:
366 if (radar_cb)
367 nl_cb_put(radar_cb);
368 if (cac_trigger_argv)
369 free(cac_trigger_argv);
370 return err;
2ba2f599
BB
371}
372TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
373 "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
374 "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
375 0, 0, CIB_NETDEV, handle_cac, NULL);
376COMMAND(cac, trigger,
377 "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
378 "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
379 "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
380 NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
381 "Start or trigger a channel availability check (CAC) looking to look for\n"
382 "radars on the given channel.");
383
625aa4ae 384static int handle_fragmentation(struct nl80211_state *state,
34b23014 385 struct nl_msg *msg,
05514f95
JB
386 int argc, char **argv,
387 enum id_input id)
625aa4ae
JB
388{
389 unsigned int frag;
390
391 if (argc != 1)
392 return 1;
393
394 if (strcmp("off", argv[0]) == 0)
395 frag = -1;
e86b7e02
JB
396 else {
397 char *end;
398
399 if (!*argv[0])
400 return 1;
401 frag = strtoul(argv[0], &end, 10);
402 if (*end != '\0')
403 return 1;
404 }
625aa4ae
JB
405
406 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
407
408 return 0;
409 nla_put_failure:
410 return -ENOBUFS;
411}
412COMMAND(set, frag, "<fragmentation threshold|off>",
413 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
414 "Set fragmentation threshold.");
415
416static int handle_rts(struct nl80211_state *state,
34b23014 417 struct nl_msg *msg,
05514f95
JB
418 int argc, char **argv,
419 enum id_input id)
625aa4ae
JB
420{
421 unsigned int rts;
422
423 if (argc != 1)
424 return 1;
425
426 if (strcmp("off", argv[0]) == 0)
427 rts = -1;
e86b7e02
JB
428 else {
429 char *end;
430
431 if (!*argv[0])
432 return 1;
433 rts = strtoul(argv[0], &end, 10);
434 if (*end != '\0')
435 return 1;
436 }
625aa4ae
JB
437
438 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
439
440 return 0;
441 nla_put_failure:
442 return -ENOBUFS;
443}
444COMMAND(set, rts, "<rts threshold|off>",
445 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
446 "Set rts threshold.");
e960e066 447
c993e6e7 448static int handle_retry(struct nl80211_state *state,
34b23014 449 struct nl_msg *msg,
c993e6e7
UR
450 int argc, char **argv, enum id_input id)
451{
452 unsigned int retry_short = 0, retry_long = 0;
453 bool have_retry_s = false, have_retry_l = false;
454 int i;
455 enum {
456 S_NONE,
457 S_SHORT,
458 S_LONG,
459 } parser_state = S_NONE;
460
461 if (!argc || (argc != 2 && argc != 4))
462 return 1;
463
464 for (i = 0; i < argc; i++) {
465 char *end;
466 unsigned int tmpul;
467
468 if (strcmp(argv[i], "short") == 0) {
469 if (have_retry_s)
470 return 1;
471 parser_state = S_SHORT;
472 have_retry_s = true;
473 } else if (strcmp(argv[i], "long") == 0) {
474 if (have_retry_l)
475 return 1;
476 parser_state = S_LONG;
477 have_retry_l = true;
478 } else {
479 tmpul = strtoul(argv[i], &end, 10);
480 if (*end != '\0')
481 return 1;
482 if (!tmpul || tmpul > 255)
483 return -EINVAL;
484 switch (parser_state) {
485 case S_SHORT:
486 retry_short = tmpul;
487 break;
488 case S_LONG:
489 retry_long = tmpul;
490 break;
491 default:
492 return 1;
493 }
494 }
495 }
496
497 if (!have_retry_s && !have_retry_l)
498 return 1;
499 if (have_retry_s)
500 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
501 if (have_retry_l)
502 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
503
504 return 0;
505 nla_put_failure:
506 return -ENOBUFS;
507}
508COMMAND(set, retry, "[short <limit>] [long <limit>]",
509 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
510 "Set retry limit.");
511
91454b65
VK
512#ifndef NETNS_RUN_DIR
513#define NETNS_RUN_DIR "/var/run/netns"
514#endif
c0441e65 515static int netns_get_fd(const char *name)
91454b65
VK
516{
517 char pathbuf[MAXPATHLEN];
518 const char *path, *ptr;
519
520 path = name;
521 ptr = strchr(name, '/');
522 if (!ptr) {
523 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
524 NETNS_RUN_DIR, name );
525 path = pathbuf;
526 }
527 return open(path, O_RDONLY);
528}
529
e960e066 530static int handle_netns(struct nl80211_state *state,
e960e066 531 struct nl_msg *msg,
05514f95
JB
532 int argc, char **argv,
533 enum id_input id)
e960e066
JB
534{
535 char *end;
3a51540c 536 int fd = -1;
e960e066 537
91454b65 538 if (argc < 1 || !*argv[0])
e960e066
JB
539 return 1;
540
91454b65
VK
541 if (argc == 1) {
542 NLA_PUT_U32(msg, NL80211_ATTR_PID,
543 strtoul(argv[0], &end, 10));
544 if (*end != '\0') {
545 printf("Invalid parameter: pid(%s)\n", argv[0]);
546 return 1;
547 }
548 return 0;
549 }
550
551 if (argc != 2 || strcmp(argv[0], "name"))
e86b7e02
JB
552 return 1;
553
91454b65
VK
554 if ((fd = netns_get_fd(argv[1])) >= 0) {
555 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
556 return 0;
557 } else {
558 printf("Invalid parameter: nsname(%s)\n", argv[0]);
559 }
e960e066 560
91454b65 561 return 1;
e960e066 562
e960e066 563 nla_put_failure:
3a51540c
JC
564 if (fd >= 0)
565 close(fd);
e960e066
JB
566 return -ENOBUFS;
567}
91454b65 568COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 569 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
570 "Put this wireless device into a different network namespace:\n"
571 " <pid> - change network namespace by process id\n"
572 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
573 " or by absolute path (man ip-netns)\n");
b2f92dd0
LT
574
575static int handle_coverage(struct nl80211_state *state,
b2f92dd0 576 struct nl_msg *msg,
05514f95
JB
577 int argc, char **argv,
578 enum id_input id)
b2f92dd0 579{
e86b7e02 580 char *end;
b2f92dd0
LT
581 unsigned int coverage;
582
583 if (argc != 1)
584 return 1;
585
e86b7e02
JB
586 if (!*argv[0])
587 return 1;
588 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
589 if (coverage > 255)
590 return 1;
591
e86b7e02
JB
592 if (*end)
593 return 1;
594
b2f92dd0
LT
595 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
596
597 return 0;
598 nla_put_failure:
599 return -ENOBUFS;
600}
601COMMAND(set, coverage, "<coverage class>",
602 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
603 "Set coverage class (1 for every 3 usec of air propagation time).\n"
604 "Valid values: 0 - 255.");
605
606static int handle_distance(struct nl80211_state *state,
b2f92dd0 607 struct nl_msg *msg,
05514f95
JB
608 int argc, char **argv,
609 enum id_input id)
b2f92dd0 610{
b2f92dd0
LT
611 if (argc != 1)
612 return 1;
613
e86b7e02
JB
614 if (!*argv[0])
615 return 1;
616
e642142d
LB
617 if (strcmp("auto", argv[0]) == 0) {
618 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
619 } else {
620 char *end;
621 unsigned int distance, coverage;
e86b7e02 622
e642142d 623 distance = strtoul(argv[0], &end, 10);
b2f92dd0 624
e642142d
LB
625 if (*end)
626 return 1;
b2f92dd0 627
e642142d
LB
628 /*
629 * Divide double the distance by the speed of light
630 * in m/usec (300) to get round-trip time in microseconds
631 * and then divide the result by three to get coverage class
632 * as specified in IEEE 802.11-2007 table 7-27.
633 * Values are rounded upwards.
634 */
635 coverage = (distance + 449) / 450;
636 if (coverage > 255)
637 return 1;
638
639 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
640 }
b2f92dd0
LT
641
642 return 0;
643 nla_put_failure:
644 return -ENOBUFS;
645}
e642142d 646COMMAND(set, distance, "<auto|distance>",
b2f92dd0 647 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
648 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
649 "coverage class for given link distance in meters.\n"
650 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 651 "Valid values: 0 - 114750");
a0b1f574
JO
652
653static int handle_txpower(struct nl80211_state *state,
a0b1f574 654 struct nl_msg *msg,
05514f95
JB
655 int argc, char **argv,
656 enum id_input id)
a0b1f574
JO
657{
658 enum nl80211_tx_power_setting type;
659 int mbm;
660
661 /* get the required args */
662 if (argc != 1 && argc != 2)
663 return 1;
664
665 if (!strcmp(argv[0], "auto"))
666 type = NL80211_TX_POWER_AUTOMATIC;
667 else if (!strcmp(argv[0], "fixed"))
668 type = NL80211_TX_POWER_FIXED;
669 else if (!strcmp(argv[0], "limit"))
670 type = NL80211_TX_POWER_LIMITED;
671 else {
672 printf("Invalid parameter: %s\n", argv[0]);
673 return 2;
674 }
675
676 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
677
678 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 679 char *endptr;
a0b1f574
JO
680 if (argc != 2) {
681 printf("Missing TX power level argument.\n");
682 return 2;
683 }
684
18e05613 685 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 686 if (*endptr)
18e05613 687 return 2;
a0b1f574
JO
688 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
689 } else if (argc != 1)
690 return 1;
691
692 return 0;
693
694 nla_put_failure:
695 return -ENOBUFS;
696}
697COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
698 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
699 "Specify transmit power level and setting type.");
700COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
701 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
702 "Specify transmit power level and setting type.");
afce7986
BR
703
704static int handle_antenna(struct nl80211_state *state,
afce7986 705 struct nl_msg *msg,
05514f95
JB
706 int argc, char **argv,
707 enum id_input id)
afce7986
BR
708{
709 char *end;
710 uint32_t tx_ant = 0, rx_ant = 0;
711
712 if (argc == 1 && strcmp(argv[0], "all") == 0) {
713 tx_ant = 0xffffffff;
714 rx_ant = 0xffffffff;
715 } else if (argc == 1) {
716 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
717 if (*end)
718 return 1;
719 }
720 else if (argc == 2) {
721 tx_ant = strtoul(argv[0], &end, 0);
722 if (*end)
723 return 1;
724 rx_ant = strtoul(argv[1], &end, 0);
725 if (*end)
726 return 1;
727 } else
728 return 1;
729
730 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
731 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
732
733 return 0;
734
735 nla_put_failure:
736 return -ENOBUFS;
737}
738COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
739 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
740 "Set a bitmap of allowed antennas to use for TX and RX.\n"
741 "The driver may reject antenna configurations it cannot support.");
1eb2f5c9
THJ
742
743static int handle_set_txq(struct nl80211_state *state,
744 struct nl_msg *msg,
745 int argc, char **argv,
746 enum id_input id)
747{
748 unsigned int argval;
749 char *end;
750
751 if (argc != 2)
752 return 1;
753
754 if (!*argv[0] || !*argv[1])
755 return 1;
756
757 argval = strtoul(argv[1], &end, 10);
758
759 if (*end)
760 return 1;
761
762 if (!argval)
763 return 1;
764
765 if (strcmp("limit", argv[0]) == 0)
766 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
767 else if (strcmp("memory_limit", argv[0]) == 0)
768 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
769 else if (strcmp("quantum", argv[0]) == 0)
770 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
771 else
772 return -1;
773
774 return 0;
775 nla_put_failure:
776 return -ENOBUFS;
777}
778COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
779 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
780 "Set TXQ parameters. The limit and memory_limit are global queue limits\n"
781 "for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
782 "Valid values: 1 - 2**32");
783
784static int print_txq_handler(struct nl_msg *msg, void *arg)
785{
786 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
787 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
788 struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
789 static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
790 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
791 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
792 [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
793 [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
794 [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
795 [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
796 };
797
798 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
799 genlmsg_attrlen(gnlh, 0), NULL);
800
801
802 if (attrs[NL80211_ATTR_TXQ_LIMIT])
803 printf("Packet limit:\t\t%u pkts\n",
804 nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
805 if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
806 printf("Memory limit:\t\t%u bytes\n",
807 nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
808 if (attrs[NL80211_ATTR_TXQ_QUANTUM])
809 printf("Quantum:\t\t%u bytes\n",
810 nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
811
812 if (attrs[NL80211_ATTR_TXQ_STATS]) {
813 if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
814 attrs[NL80211_ATTR_TXQ_STATS],
815 txqstats_policy)) {
816 printf("failed to parse nested TXQ stats attributes!");
817 return 0;
818 }
819 txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
820 if (txqinfo)
821 printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
822
823 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
824 if (txqinfo)
825 printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
826
827 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
828 if (txqinfo)
829 printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
830
831 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
832 if (txqinfo)
833 printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
834
835 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
836 if (txqinfo)
837 printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
838 txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
839 if (txqinfo)
840 printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
841 }
842 return NL_SKIP;
843}
844
845static int handle_get_txq(struct nl80211_state *state,
846 struct nl_msg *msg,
847 int argc, char **argv,
848 enum id_input id)
849{
850 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
851 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
852 register_handler(print_txq_handler, NULL);
853 return 0;
854}
855COMMAND(get, txq, "",
856 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
857 "Get TXQ parameters.");