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