]> git.ipfire.org Git - thirdparty/iw.git/blob - phy.c
iw: fix some scan code indentation
[thirdparty/iw.git] / phy.c
1 #include <stdbool.h>
2 #include <errno.h>
3 #include <strings.h>
4 #include <sys/param.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
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
14 #include "nl80211.h"
15 #include "iw.h"
16
17 struct channels_ctx {
18 int last_band;
19 bool width_40;
20 bool width_80;
21 bool width_160;
22 };
23
24 static 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
38 static 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
153 static 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 }
167 TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
168
169 static int handle_name(struct nl80211_state *state,
170 struct nl_msg *msg,
171 int argc, char **argv,
172 enum id_input id)
173 {
174 if (argc != 1)
175 return 1;
176
177 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
178
179 return 0;
180 nla_put_failure:
181 return -ENOBUFS;
182 }
183 COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
184 "Rename this wireless device.");
185
186 static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
187 int argc, char **argv,
188 enum id_input id)
189 {
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);
198 }
199
200 COMMAND(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>]]",
203 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
204 "Set frequency/channel the hardware is using, including HT\n"
205 "configuration.");
206 COMMAND(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>]]",
209 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
210
211 static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
212 int argc, char **argv,
213 enum id_input id)
214 {
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);
223 }
224 COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
225 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
226 COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]",
227 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
228
229
230 struct cac_event {
231 int ret;
232 uint32_t freq;
233 };
234
235 static 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
278 static 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
303 static int no_seq_check(struct nl_msg *msg, void *arg)
304 {
305 return NL_OK;
306 }
307
308 static 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 }
362 TOPLEVEL(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);
366 COMMAND(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
374 static int handle_fragmentation(struct nl80211_state *state,
375 struct nl_msg *msg,
376 int argc, char **argv,
377 enum id_input id)
378 {
379 unsigned int frag;
380
381 if (argc != 1)
382 return 1;
383
384 if (strcmp("off", argv[0]) == 0)
385 frag = -1;
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 }
395
396 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
397
398 return 0;
399 nla_put_failure:
400 return -ENOBUFS;
401 }
402 COMMAND(set, frag, "<fragmentation threshold|off>",
403 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
404 "Set fragmentation threshold.");
405
406 static int handle_rts(struct nl80211_state *state,
407 struct nl_msg *msg,
408 int argc, char **argv,
409 enum id_input id)
410 {
411 unsigned int rts;
412
413 if (argc != 1)
414 return 1;
415
416 if (strcmp("off", argv[0]) == 0)
417 rts = -1;
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 }
427
428 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
429
430 return 0;
431 nla_put_failure:
432 return -ENOBUFS;
433 }
434 COMMAND(set, rts, "<rts threshold|off>",
435 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
436 "Set rts threshold.");
437
438 static int handle_retry(struct nl80211_state *state,
439 struct nl_msg *msg,
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 }
498 COMMAND(set, retry, "[short <limit>] [long <limit>]",
499 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
500 "Set retry limit.");
501
502 #ifndef NETNS_RUN_DIR
503 #define NETNS_RUN_DIR "/var/run/netns"
504 #endif
505 static int netns_get_fd(const char *name)
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
520 static int handle_netns(struct nl80211_state *state,
521 struct nl_msg *msg,
522 int argc, char **argv,
523 enum id_input id)
524 {
525 char *end;
526 int fd;
527
528 if (argc < 1 || !*argv[0])
529 return 1;
530
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"))
542 return 1;
543
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 }
550
551 return 1;
552
553 nla_put_failure:
554 return -ENOBUFS;
555 }
556 COMMAND(set, netns, "{ <pid> | name <nsname> }",
557 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
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");
562
563 static int handle_coverage(struct nl80211_state *state,
564 struct nl_msg *msg,
565 int argc, char **argv,
566 enum id_input id)
567 {
568 char *end;
569 unsigned int coverage;
570
571 if (argc != 1)
572 return 1;
573
574 if (!*argv[0])
575 return 1;
576 coverage = strtoul(argv[0], &end, 10);
577 if (coverage > 255)
578 return 1;
579
580 if (*end)
581 return 1;
582
583 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
584
585 return 0;
586 nla_put_failure:
587 return -ENOBUFS;
588 }
589 COMMAND(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
594 static int handle_distance(struct nl80211_state *state,
595 struct nl_msg *msg,
596 int argc, char **argv,
597 enum id_input id)
598 {
599 if (argc != 1)
600 return 1;
601
602 if (!*argv[0])
603 return 1;
604
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;
610
611 distance = strtoul(argv[0], &end, 10);
612
613 if (*end)
614 return 1;
615
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 }
629
630 return 0;
631 nla_put_failure:
632 return -ENOBUFS;
633 }
634 COMMAND(set, distance, "<auto|distance>",
635 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
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"
639 "Valid values: 0 - 114750");
640
641 static int handle_txpower(struct nl80211_state *state,
642 struct nl_msg *msg,
643 int argc, char **argv,
644 enum id_input id)
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) {
667 char *endptr;
668 if (argc != 2) {
669 printf("Missing TX power level argument.\n");
670 return 2;
671 }
672
673 mbm = strtol(argv[1], &endptr, 10);
674 if (*endptr)
675 return 2;
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 }
685 COMMAND(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.");
688 COMMAND(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.");
691
692 static int handle_antenna(struct nl80211_state *state,
693 struct nl_msg *msg,
694 int argc, char **argv,
695 enum id_input id)
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 }
726 COMMAND(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.");
730
731 static 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 }
766 COMMAND(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
772 static 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
833 static 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 }
843 COMMAND(get, txq, "",
844 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
845 "Get TXQ parameters.");