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