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