]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
update nl80211.h
[thirdparty/iw.git] / phy.c
CommitLineData
379f8397 1#include <stdbool.h>
0f55e0b8 2#include <errno.h>
d0260390 3#include <strings.h>
3a51540c 4#include <unistd.h>
91454b65
VK
5#include <sys/param.h>
6#include <sys/stat.h>
7#include <fcntl.h>
0f55e0b8
JB
8
9#include <netlink/genl/genl.h>
10#include <netlink/genl/family.h>
11#include <netlink/genl/ctrl.h>
12#include <netlink/msg.h>
13#include <netlink/attr.h>
14
f408e01b 15#include "nl80211.h"
0f55e0b8
JB
16#include "iw.h"
17
db9d4050
RM
18struct channels_ctx {
19 int last_band;
20 bool width_40;
21 bool width_80;
22 bool width_160;
23};
24
25static char *dfs_state_name(enum nl80211_dfs_state state)
26{
27 switch (state) {
28 case NL80211_DFS_USABLE:
29 return "usable";
30 case NL80211_DFS_AVAILABLE:
31 return "available";
32 case NL80211_DFS_UNAVAILABLE:
33 return "unavailable";
34 default:
35 return "unknown";
36 }
37}
38
39static int print_channels_handler(struct nl_msg *msg, void *arg)
40{
41 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
42 struct channels_ctx *ctx = arg;
43 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
44 struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
45 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
46 struct nlattr *nl_band;
47 struct nlattr *nl_freq;
48 int rem_band, rem_freq;
49
50 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
51
52 if (tb_msg[NL80211_ATTR_WIPHY_BANDS]) {
53 nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
54 if (ctx->last_band != nl_band->nla_type) {
55 printf("Band %d:\n", nl_band->nla_type + 1);
56 ctx->width_40 = false;
57 ctx->width_80 = false;
58 ctx->width_160 = false;
59 ctx->last_band = nl_band->nla_type;
60 }
61
62 nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band), nla_len(nl_band), NULL);
63
64 if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
65 __u16 cap = nla_get_u16(tb_band[NL80211_BAND_ATTR_HT_CAPA]);
66
67 if (cap & BIT(1))
68 ctx->width_40 = true;
69 }
70
71 if (tb_band[NL80211_BAND_ATTR_VHT_CAPA]) {
72 __u32 capa;
73
74 ctx->width_80 = true;
75
76 capa = nla_get_u32(tb_band[NL80211_BAND_ATTR_VHT_CAPA]);
77 switch ((capa >> 2) & 3) {
78 case 2:
79 /* width_80p80 = true; */
80 /* fall through */
81 case 1:
82 ctx->width_160 = true;
83 break;
84 }
85 }
86
87 if (tb_band[NL80211_BAND_ATTR_FREQS]) {
88 nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
89 uint32_t freq;
90
91 nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq), nla_len(nl_freq), NULL);
92
93 if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
94 continue;
95 freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
96 printf("\t* %d MHz [%d] ", freq, ieee80211_frequency_to_channel(freq));
97
98 if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) {
99 printf("(disabled)\n");
100 continue;
101 }
102 printf("\n");
103
104 if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
105 printf("\t Maximum TX power: %.1f dBm\n", 0.01 * nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
106
107 /* If both flags are set assume an new kernel */
108 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR] && tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) {
109 printf("\t No IR\n");
110 } else if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN]) {
111 printf("\t Passive scan\n");
112 } else if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]){
113 printf("\t No IBSS\n");
114 }
115
116 if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
117 printf("\t Radar detection\n");
118
119 printf("\t Channel widths:");
120 if (!tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ])
121 printf(" 20MHz");
122 if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS])
123 printf(" HT40-");
124 if (ctx->width_40 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS])
125 printf(" HT40+");
126 if (ctx->width_80 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ])
127 printf(" VHT80");
128 if (ctx->width_160 && !tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ])
129 printf(" VHT160");
130 printf("\n");
131
132 if (!tb_freq[NL80211_FREQUENCY_ATTR_DISABLED] && tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
133 enum nl80211_dfs_state state = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
134 unsigned long time;
135
136 printf("\t DFS state: %s", dfs_state_name(state));
137 if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]) {
138 time = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_TIME]);
139 printf(" (for %lu sec)", time / 1000);
140 }
141 printf("\n");
142 if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME])
143 printf("\t DFS CAC time: %u ms\n",
144 nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]));
145 }
146 }
147 }
148 }
149 }
150
151 return NL_SKIP;
152}
153
154static int handle_channels(struct nl80211_state *state, struct nl_msg *msg,
155 int argc, char **argv, enum id_input id)
156{
157 static struct channels_ctx ctx = {
158 .last_band = -1,
159 };
160
161 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
162 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
163
164 register_handler(print_channels_handler, &ctx);
165
166 return 0;
167}
168TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
169
7c37a24d 170static int handle_name(struct nl80211_state *state,
0f55e0b8 171 struct nl_msg *msg,
05514f95
JB
172 int argc, char **argv,
173 enum id_input id)
0f55e0b8 174{
0f55e0b8 175 if (argc != 1)
5e75fd04 176 return 1;
0f55e0b8
JB
177
178 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
179
70391ccf 180 return 0;
0f55e0b8 181 nla_put_failure:
70391ccf 182 return -ENOBUFS;
0f55e0b8 183}
cea8fa1c
JB
184COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
185 "Rename this wireless device.");
b822cda9 186
34b23014 187static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
188 int argc, char **argv,
189 enum id_input id)
379f8397 190{
159d5e42
BB
191 struct chandef chandef;
192 int res;
193
a32046bc 194 res = parse_freqchan(&chandef, false, argc, argv, NULL, false);
159d5e42
BB
195 if (res)
196 return res;
197
198 return put_chandef(msg, &chandef);
379f8397 199}
159d5e42
BB
200
201COMMAND(set, freq,
997e5f13 202 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz|320MHz]\n"
159d5e42 203 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
00c448b2
JB
204 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
205 "Set frequency/channel the hardware is using, including HT\n"
206 "configuration.");
159d5e42 207COMMAND(set, freq,
997e5f13 208 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz|320MHz]\n"
159d5e42 209 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
01ae06f9 210 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 211
a32046bc
GI
212static 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
226COMMAND(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.");
232COMMAND(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
34b23014 237static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
238 int argc, char **argv,
239 enum id_input id)
379f8397 240{
159d5e42
BB
241 struct chandef chandef;
242 int res;
243
a32046bc 244 res = parse_freqchan(&chandef, true, argc, argv, NULL, false);
159d5e42
BB
245 if (res)
246 return res;
247
248 return put_chandef(msg, &chandef);
379f8397 249}
b6f2dac4 250COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
01ae06f9 251 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
b6f2dac4 252COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
01ae06f9 253 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae 254
2ba2f599
BB
255
256struct cac_event {
257 int ret;
258 uint32_t freq;
259};
260
261static 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
304static 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) {
a32046bc 316 res = parse_freqchan(&chandef, true, argc - 1, argv + 1, NULL, false);
2ba2f599 317 } else if (strcmp(argv[0], "freq") == 0) {
a32046bc 318 res = parse_freqchan(&chandef, false, argc - 1, argv + 1, NULL, false);
2ba2f599
BB
319 } else {
320 return 1;
321 }
322
323 if (res)
324 return res;
325
326 return put_chandef(msg, &chandef);
327}
328
82e6fba0
JD
329static 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
2ba2f599
BB
338static int no_seq_check(struct nl_msg *msg, void *arg)
339{
340 return NL_OK;
341}
342
343static 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) {
a32046bc 362 err = parse_freqchan(&chandef, true, argc - 3, argv + 3, NULL, false);
2ba2f599 363 } else if (strcmp(argv[2], "freq") == 0) {
a32046bc 364 err = parse_freqchan(&chandef, false, argc - 3, argv + 3, NULL, false);
2ba2f599 365 } else {
6a7cc867 366 err = 1;
2ba2f599 367 }
71e6d184
JB
368 if (err)
369 goto err_out;
2ba2f599
BB
370
371 cac_trigger_argv = calloc(argc + 1, sizeof(char*));
6a7cc867
JC
372 if (!cac_trigger_argv) {
373 err = -ENOMEM;
374 goto err_out;
375 }
2ba2f599
BB
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);
2ba2f599 383 if (err)
6a7cc867 384 goto err_out;
2ba2f599
BB
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
6a7cc867
JC
398 err = 0;
399err_out:
400 if (radar_cb)
401 nl_cb_put(radar_cb);
402 if (cac_trigger_argv)
403 free(cac_trigger_argv);
404 return err;
2ba2f599
BB
405}
406TOPLEVEL(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);
410COMMAND(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
82e6fba0
JD
418COMMAND(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
625aa4ae 426static int handle_fragmentation(struct nl80211_state *state,
34b23014 427 struct nl_msg *msg,
05514f95
JB
428 int argc, char **argv,
429 enum id_input id)
625aa4ae
JB
430{
431 unsigned int frag;
432
433 if (argc != 1)
434 return 1;
435
436 if (strcmp("off", argv[0]) == 0)
437 frag = -1;
e86b7e02
JB
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 }
625aa4ae
JB
447
448 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
449
450 return 0;
451 nla_put_failure:
452 return -ENOBUFS;
453}
454COMMAND(set, frag, "<fragmentation threshold|off>",
455 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
456 "Set fragmentation threshold.");
457
458static int handle_rts(struct nl80211_state *state,
34b23014 459 struct nl_msg *msg,
05514f95
JB
460 int argc, char **argv,
461 enum id_input id)
625aa4ae
JB
462{
463 unsigned int rts;
464
465 if (argc != 1)
466 return 1;
467
468 if (strcmp("off", argv[0]) == 0)
469 rts = -1;
e86b7e02
JB
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 }
625aa4ae
JB
479
480 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
481
482 return 0;
483 nla_put_failure:
484 return -ENOBUFS;
485}
486COMMAND(set, rts, "<rts threshold|off>",
487 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
488 "Set rts threshold.");
e960e066 489
c993e6e7 490static int handle_retry(struct nl80211_state *state,
34b23014 491 struct nl_msg *msg,
c993e6e7
UR
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}
550COMMAND(set, retry, "[short <limit>] [long <limit>]",
551 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
552 "Set retry limit.");
553
91454b65
VK
554#ifndef NETNS_RUN_DIR
555#define NETNS_RUN_DIR "/var/run/netns"
556#endif
c0441e65 557static int netns_get_fd(const char *name)
91454b65
VK
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
e960e066 572static int handle_netns(struct nl80211_state *state,
e960e066 573 struct nl_msg *msg,
05514f95
JB
574 int argc, char **argv,
575 enum id_input id)
e960e066
JB
576{
577 char *end;
3a51540c 578 int fd = -1;
e960e066 579
91454b65 580 if (argc < 1 || !*argv[0])
e960e066
JB
581 return 1;
582
91454b65
VK
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"))
e86b7e02
JB
594 return 1;
595
91454b65
VK
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 }
e960e066 602
91454b65 603 return 1;
e960e066 604
e960e066 605 nla_put_failure:
3a51540c
JC
606 if (fd >= 0)
607 close(fd);
e960e066
JB
608 return -ENOBUFS;
609}
91454b65 610COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 611 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
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");
b2f92dd0
LT
616
617static int handle_coverage(struct nl80211_state *state,
b2f92dd0 618 struct nl_msg *msg,
05514f95
JB
619 int argc, char **argv,
620 enum id_input id)
b2f92dd0 621{
e86b7e02 622 char *end;
b2f92dd0
LT
623 unsigned int coverage;
624
625 if (argc != 1)
626 return 1;
627
e86b7e02
JB
628 if (!*argv[0])
629 return 1;
630 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
631 if (coverage > 255)
632 return 1;
633
e86b7e02
JB
634 if (*end)
635 return 1;
636
b2f92dd0
LT
637 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
638
639 return 0;
640 nla_put_failure:
641 return -ENOBUFS;
642}
643COMMAND(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
648static int handle_distance(struct nl80211_state *state,
b2f92dd0 649 struct nl_msg *msg,
05514f95
JB
650 int argc, char **argv,
651 enum id_input id)
b2f92dd0 652{
b2f92dd0
LT
653 if (argc != 1)
654 return 1;
655
e86b7e02
JB
656 if (!*argv[0])
657 return 1;
658
e642142d
LB
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;
e86b7e02 664
e642142d 665 distance = strtoul(argv[0], &end, 10);
b2f92dd0 666
e642142d
LB
667 if (*end)
668 return 1;
b2f92dd0 669
e642142d
LB
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 }
b2f92dd0
LT
683
684 return 0;
685 nla_put_failure:
686 return -ENOBUFS;
687}
e642142d 688COMMAND(set, distance, "<auto|distance>",
b2f92dd0 689 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
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"
b2f92dd0 693 "Valid values: 0 - 114750");
a0b1f574
JO
694
695static int handle_txpower(struct nl80211_state *state,
a0b1f574 696 struct nl_msg *msg,
05514f95
JB
697 int argc, char **argv,
698 enum id_input id)
a0b1f574
JO
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) {
18e05613 721 char *endptr;
a0b1f574
JO
722 if (argc != 2) {
723 printf("Missing TX power level argument.\n");
724 return 2;
725 }
726
18e05613 727 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 728 if (*endptr)
18e05613 729 return 2;
a0b1f574
JO
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}
739COMMAND(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.");
742COMMAND(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.");
afce7986
BR
745
746static int handle_antenna(struct nl80211_state *state,
afce7986 747 struct nl_msg *msg,
05514f95
JB
748 int argc, char **argv,
749 enum id_input id)
afce7986
BR
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}
780COMMAND(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.");
1eb2f5c9
THJ
784
785static 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}
820COMMAND(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
826static 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
887static 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}
897COMMAND(get, txq, "",
898 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
899 "Get TXQ parameters.");