blob: 2d489efd769037dd105deff32289e49ee6145c51 [file] [log] [blame]
Johannes Berg379f8392008-12-08 12:53:58 +01001#include <stdbool.h>
Johannes Berg0f55e0b2008-09-16 17:40:48 +02002#include <errno.h>
Johannes Bergd0260392010-09-22 11:33:28 +02003#include <strings.h>
Sunil Ravi44e0e582022-03-05 11:09:09 -08004#include <unistd.h>
Vadim Kochan91454b62015-02-14 09:33:12 +02005#include <sys/param.h>
6#include <sys/stat.h>
7#include <fcntl.h>
Johannes Berg0f55e0b2008-09-16 17:40:48 +02008
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
Johannes Bergf408e012008-09-18 19:32:11 +020015#include "nl80211.h"
Johannes Berg0f55e0b2008-09-16 17:40:48 +020016#include "iw.h"
17
Sunil Ravi44e0e582022-03-05 11:09:09 -080018struct 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
Johannes Berg7c37a242009-04-08 13:13:28 +0200170static int handle_name(struct nl80211_state *state,
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200171 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200172 int argc, char **argv,
173 enum id_input id)
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200174{
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200175 if (argc != 1)
Johannes Berg5e75fd02008-09-16 18:13:12 +0200176 return 1;
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200177
178 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
179
Johannes Berg70391cc2008-09-16 18:35:06 +0200180 return 0;
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200181 nla_put_failure:
Johannes Berg70391cc2008-09-16 18:35:06 +0200182 return -ENOBUFS;
Johannes Berg0f55e0b2008-09-16 17:40:48 +0200183}
Johannes Bergcea8fa12009-05-05 15:05:10 +0200184COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
185 "Rename this wireless device.");
Johannes Bergb822cda2008-12-08 12:43:42 +0100186
Sunil Ravi44e0e582022-03-05 11:09:09 -0800187static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200188 int argc, char **argv,
189 enum id_input id)
Johannes Berg379f8392008-12-08 12:53:58 +0100190{
Sunil Ravi44e0e582022-03-05 11:09:09 -0800191 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);
Johannes Berg379f8392008-12-08 12:53:58 +0100199}
Sunil Ravi44e0e582022-03-05 11:09:09 -0800200
201COMMAND(set, freq,
202 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
203 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
Johannes Berg00c448b2009-05-05 15:04:19 +0200204 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
205 "Set frequency/channel the hardware is using, including HT\n"
206 "configuration.");
Sunil Ravi44e0e582022-03-05 11:09:09 -0800207COMMAND(set, freq,
208 "<freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]\n"
209 "<control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200210 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
Johannes Berg379f8392008-12-08 12:53:58 +0100211
Sunil Ravi44e0e582022-03-05 11:09:09 -0800212static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200213 int argc, char **argv,
214 enum id_input id)
Johannes Berg379f8392008-12-08 12:53:58 +0100215{
Sunil Ravi44e0e582022-03-05 11:09:09 -0800216 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);
Johannes Berg379f8392008-12-08 12:53:58 +0100224}
Sunil Ravi44e0e582022-03-05 11:09:09 -0800225COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200226 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
Sunil Ravi44e0e582022-03-05 11:09:09 -0800227COMMAND(set, channel, "<channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz|160MHz]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200228 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
Johannes Berg625aa4a2009-08-11 11:26:42 +0200229
Sunil Ravi44e0e582022-03-05 11:09:09 -0800230
231struct cac_event {
232 int ret;
233 uint32_t freq;
234};
235
236static 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
279static 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
304static int no_seq_check(struct nl_msg *msg, void *arg)
305{
306 return NL_OK;
307}
308
309static 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 }
334 if (err)
335 goto err_out;
336
337 cac_trigger_argv = calloc(argc + 1, sizeof(char*));
338 if (!cac_trigger_argv) {
339 err = -ENOMEM;
340 goto err_out;
341 }
342
343 cac_trigger_argv[0] = argv[0];
344 cac_trigger_argv[1] = "cac";
345 cac_trigger_argv[2] = "trigger";
346 memcpy(&cac_trigger_argv[3], &argv[2], (argc - 2) * sizeof(char*));
347
348 err = handle_cmd(state, id, argc + 1, cac_trigger_argv);
349 if (err)
350 goto err_out;
351
352 cac_event.ret = 1;
353 cac_event.freq = chandef.control_freq;
354
355 __prepare_listen_events(state);
356 nl_socket_set_cb(state->nl_sock, radar_cb);
357
358 /* need to turn off sequence number checking */
359 nl_cb_set(radar_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
360 nl_cb_set(radar_cb, NL_CB_VALID, NL_CB_CUSTOM, print_cac_event, &cac_event);
361 while (cac_event.ret > 0)
362 nl_recvmsgs(state->nl_sock, radar_cb);
363
364 err = 0;
365err_out:
366 if (radar_cb)
367 nl_cb_put(radar_cb);
368 if (cac_trigger_argv)
369 free(cac_trigger_argv);
370 return err;
371}
372TOPLEVEL(cac, "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
373 "freq <freq> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
374 "freq <control freq> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
375 0, 0, CIB_NETDEV, handle_cac, NULL);
376COMMAND(cac, trigger,
377 "channel <channel> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
378 "freq <frequency> [NOHT|HT20|HT40+|HT40-|5MHz|10MHz|80MHz]\n"
379 "freq <frequency> [5|10|20|40|80|80+80|160] [<center1_freq> [<center2_freq>]]",
380 NL80211_CMD_RADAR_DETECT, 0, CIB_NETDEV, handle_cac_trigger,
381 "Start or trigger a channel availability check (CAC) looking to look for\n"
382 "radars on the given channel.");
383
Johannes Berg625aa4a2009-08-11 11:26:42 +0200384static int handle_fragmentation(struct nl80211_state *state,
Sunil Ravi44e0e582022-03-05 11:09:09 -0800385 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200386 int argc, char **argv,
387 enum id_input id)
Johannes Berg625aa4a2009-08-11 11:26:42 +0200388{
389 unsigned int frag;
390
391 if (argc != 1)
392 return 1;
393
394 if (strcmp("off", argv[0]) == 0)
395 frag = -1;
Johannes Berge86b7e02010-04-01 18:49:21 +0200396 else {
397 char *end;
398
399 if (!*argv[0])
400 return 1;
401 frag = strtoul(argv[0], &end, 10);
402 if (*end != '\0')
403 return 1;
404 }
Johannes Berg625aa4a2009-08-11 11:26:42 +0200405
406 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
407
408 return 0;
409 nla_put_failure:
410 return -ENOBUFS;
411}
412COMMAND(set, frag, "<fragmentation threshold|off>",
413 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
414 "Set fragmentation threshold.");
415
416static int handle_rts(struct nl80211_state *state,
Sunil Ravi44e0e582022-03-05 11:09:09 -0800417 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200418 int argc, char **argv,
419 enum id_input id)
Johannes Berg625aa4a2009-08-11 11:26:42 +0200420{
421 unsigned int rts;
422
423 if (argc != 1)
424 return 1;
425
426 if (strcmp("off", argv[0]) == 0)
427 rts = -1;
Johannes Berge86b7e02010-04-01 18:49:21 +0200428 else {
429 char *end;
430
431 if (!*argv[0])
432 return 1;
433 rts = strtoul(argv[0], &end, 10);
434 if (*end != '\0')
435 return 1;
436 }
Johannes Berg625aa4a2009-08-11 11:26:42 +0200437
438 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
439
440 return 0;
441 nla_put_failure:
442 return -ENOBUFS;
443}
444COMMAND(set, rts, "<rts threshold|off>",
445 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
446 "Set rts threshold.");
Johannes Berge960e062009-09-24 20:18:47 +0200447
Ujjal Royc993e6e2014-03-07 12:23:38 +0530448static int handle_retry(struct nl80211_state *state,
Sunil Ravi44e0e582022-03-05 11:09:09 -0800449 struct nl_msg *msg,
Ujjal Royc993e6e2014-03-07 12:23:38 +0530450 int argc, char **argv, enum id_input id)
451{
452 unsigned int retry_short = 0, retry_long = 0;
453 bool have_retry_s = false, have_retry_l = false;
454 int i;
455 enum {
456 S_NONE,
457 S_SHORT,
458 S_LONG,
459 } parser_state = S_NONE;
460
461 if (!argc || (argc != 2 && argc != 4))
462 return 1;
463
464 for (i = 0; i < argc; i++) {
465 char *end;
466 unsigned int tmpul;
467
468 if (strcmp(argv[i], "short") == 0) {
469 if (have_retry_s)
470 return 1;
471 parser_state = S_SHORT;
472 have_retry_s = true;
473 } else if (strcmp(argv[i], "long") == 0) {
474 if (have_retry_l)
475 return 1;
476 parser_state = S_LONG;
477 have_retry_l = true;
478 } else {
479 tmpul = strtoul(argv[i], &end, 10);
480 if (*end != '\0')
481 return 1;
482 if (!tmpul || tmpul > 255)
483 return -EINVAL;
484 switch (parser_state) {
485 case S_SHORT:
486 retry_short = tmpul;
487 break;
488 case S_LONG:
489 retry_long = tmpul;
490 break;
491 default:
492 return 1;
493 }
494 }
495 }
496
497 if (!have_retry_s && !have_retry_l)
498 return 1;
499 if (have_retry_s)
500 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
501 if (have_retry_l)
502 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
503
504 return 0;
505 nla_put_failure:
506 return -ENOBUFS;
507}
508COMMAND(set, retry, "[short <limit>] [long <limit>]",
509 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
510 "Set retry limit.");
511
Vadim Kochan91454b62015-02-14 09:33:12 +0200512#ifndef NETNS_RUN_DIR
513#define NETNS_RUN_DIR "/var/run/netns"
514#endif
Sunil Ravi44e0e582022-03-05 11:09:09 -0800515static int netns_get_fd(const char *name)
Vadim Kochan91454b62015-02-14 09:33:12 +0200516{
517 char pathbuf[MAXPATHLEN];
518 const char *path, *ptr;
519
520 path = name;
521 ptr = strchr(name, '/');
522 if (!ptr) {
523 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
524 NETNS_RUN_DIR, name );
525 path = pathbuf;
526 }
527 return open(path, O_RDONLY);
528}
529
Johannes Berge960e062009-09-24 20:18:47 +0200530static int handle_netns(struct nl80211_state *state,
Johannes Berge960e062009-09-24 20:18:47 +0200531 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200532 int argc, char **argv,
533 enum id_input id)
Johannes Berge960e062009-09-24 20:18:47 +0200534{
535 char *end;
Sunil Ravi44e0e582022-03-05 11:09:09 -0800536 int fd = -1;
Johannes Berge960e062009-09-24 20:18:47 +0200537
Vadim Kochan91454b62015-02-14 09:33:12 +0200538 if (argc < 1 || !*argv[0])
Johannes Berge960e062009-09-24 20:18:47 +0200539 return 1;
540
Vadim Kochan91454b62015-02-14 09:33:12 +0200541 if (argc == 1) {
542 NLA_PUT_U32(msg, NL80211_ATTR_PID,
543 strtoul(argv[0], &end, 10));
544 if (*end != '\0') {
545 printf("Invalid parameter: pid(%s)\n", argv[0]);
546 return 1;
547 }
548 return 0;
549 }
550
551 if (argc != 2 || strcmp(argv[0], "name"))
Johannes Berge86b7e02010-04-01 18:49:21 +0200552 return 1;
553
Vadim Kochan91454b62015-02-14 09:33:12 +0200554 if ((fd = netns_get_fd(argv[1])) >= 0) {
555 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
556 return 0;
557 } else {
558 printf("Invalid parameter: nsname(%s)\n", argv[0]);
559 }
Johannes Berge960e062009-09-24 20:18:47 +0200560
Vadim Kochan91454b62015-02-14 09:33:12 +0200561 return 1;
Johannes Berge960e062009-09-24 20:18:47 +0200562
Johannes Berge960e062009-09-24 20:18:47 +0200563 nla_put_failure:
Sunil Ravi44e0e582022-03-05 11:09:09 -0800564 if (fd >= 0)
565 close(fd);
Johannes Berge960e062009-09-24 20:18:47 +0200566 return -ENOBUFS;
567}
Vadim Kochan91454b62015-02-14 09:33:12 +0200568COMMAND(set, netns, "{ <pid> | name <nsname> }",
Johannes Berge960e062009-09-24 20:18:47 +0200569 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
Vadim Kochan91454b62015-02-14 09:33:12 +0200570 "Put this wireless device into a different network namespace:\n"
571 " <pid> - change network namespace by process id\n"
572 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
573 " or by absolute path (man ip-netns)\n");
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500574
575static int handle_coverage(struct nl80211_state *state,
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500576 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200577 int argc, char **argv,
578 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500579{
Johannes Berge86b7e02010-04-01 18:49:21 +0200580 char *end;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500581 unsigned int coverage;
582
583 if (argc != 1)
584 return 1;
585
Johannes Berge86b7e02010-04-01 18:49:21 +0200586 if (!*argv[0])
587 return 1;
588 coverage = strtoul(argv[0], &end, 10);
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500589 if (coverage > 255)
590 return 1;
591
Johannes Berge86b7e02010-04-01 18:49:21 +0200592 if (*end)
593 return 1;
594
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500595 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
596
597 return 0;
598 nla_put_failure:
599 return -ENOBUFS;
600}
601COMMAND(set, coverage, "<coverage class>",
602 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
603 "Set coverage class (1 for every 3 usec of air propagation time).\n"
604 "Valid values: 0 - 255.");
605
606static int handle_distance(struct nl80211_state *state,
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500607 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200608 int argc, char **argv,
609 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500610{
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500611 if (argc != 1)
612 return 1;
613
Johannes Berge86b7e02010-04-01 18:49:21 +0200614 if (!*argv[0])
615 return 1;
616
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200617 if (strcmp("auto", argv[0]) == 0) {
618 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
619 } else {
620 char *end;
621 unsigned int distance, coverage;
Johannes Berge86b7e02010-04-01 18:49:21 +0200622
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200623 distance = strtoul(argv[0], &end, 10);
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500624
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200625 if (*end)
626 return 1;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500627
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200628 /*
629 * Divide double the distance by the speed of light
630 * in m/usec (300) to get round-trip time in microseconds
631 * and then divide the result by three to get coverage class
632 * as specified in IEEE 802.11-2007 table 7-27.
633 * Values are rounded upwards.
634 */
635 coverage = (distance + 449) / 450;
636 if (coverage > 255)
637 return 1;
638
639 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
640 }
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500641
642 return 0;
643 nla_put_failure:
644 return -ENOBUFS;
645}
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200646COMMAND(set, distance, "<auto|distance>",
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500647 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200648 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
649 "coverage class for given link distance in meters.\n"
650 "To disable dynack set valid value for coverage class.\n"
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500651 "Valid values: 0 - 114750");
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300652
653static int handle_txpower(struct nl80211_state *state,
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300654 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200655 int argc, char **argv,
656 enum id_input id)
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300657{
658 enum nl80211_tx_power_setting type;
659 int mbm;
660
661 /* get the required args */
662 if (argc != 1 && argc != 2)
663 return 1;
664
665 if (!strcmp(argv[0], "auto"))
666 type = NL80211_TX_POWER_AUTOMATIC;
667 else if (!strcmp(argv[0], "fixed"))
668 type = NL80211_TX_POWER_FIXED;
669 else if (!strcmp(argv[0], "limit"))
670 type = NL80211_TX_POWER_LIMITED;
671 else {
672 printf("Invalid parameter: %s\n", argv[0]);
673 return 2;
674 }
675
676 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
677
678 if (type != NL80211_TX_POWER_AUTOMATIC) {
Johannes Berg18e05612011-04-28 19:41:04 +0200679 char *endptr;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300680 if (argc != 2) {
681 printf("Missing TX power level argument.\n");
682 return 2;
683 }
684
Johannes Berg18e05612011-04-28 19:41:04 +0200685 mbm = strtol(argv[1], &endptr, 10);
Felix Fietkau08ec4c62011-11-07 18:49:51 +0100686 if (*endptr)
Johannes Berg18e05612011-04-28 19:41:04 +0200687 return 2;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300688 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
689 } else if (argc != 1)
690 return 1;
691
692 return 0;
693
694 nla_put_failure:
695 return -ENOBUFS;
696}
697COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
698 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
699 "Specify transmit power level and setting type.");
700COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
701 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
702 "Specify transmit power level and setting type.");
Bruno Randolfafce7982010-12-22 10:54:39 +0900703
704static int handle_antenna(struct nl80211_state *state,
Bruno Randolfafce7982010-12-22 10:54:39 +0900705 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200706 int argc, char **argv,
707 enum id_input id)
Bruno Randolfafce7982010-12-22 10:54:39 +0900708{
709 char *end;
710 uint32_t tx_ant = 0, rx_ant = 0;
711
712 if (argc == 1 && strcmp(argv[0], "all") == 0) {
713 tx_ant = 0xffffffff;
714 rx_ant = 0xffffffff;
715 } else if (argc == 1) {
716 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
717 if (*end)
718 return 1;
719 }
720 else if (argc == 2) {
721 tx_ant = strtoul(argv[0], &end, 0);
722 if (*end)
723 return 1;
724 rx_ant = strtoul(argv[1], &end, 0);
725 if (*end)
726 return 1;
727 } else
728 return 1;
729
730 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
731 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
732
733 return 0;
734
735 nla_put_failure:
736 return -ENOBUFS;
737}
738COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
739 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
740 "Set a bitmap of allowed antennas to use for TX and RX.\n"
741 "The driver may reject antenna configurations it cannot support.");
Sunil Ravi44e0e582022-03-05 11:09:09 -0800742
743static int handle_set_txq(struct nl80211_state *state,
744 struct nl_msg *msg,
745 int argc, char **argv,
746 enum id_input id)
747{
748 unsigned int argval;
749 char *end;
750
751 if (argc != 2)
752 return 1;
753
754 if (!*argv[0] || !*argv[1])
755 return 1;
756
757 argval = strtoul(argv[1], &end, 10);
758
759 if (*end)
760 return 1;
761
762 if (!argval)
763 return 1;
764
765 if (strcmp("limit", argv[0]) == 0)
766 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_LIMIT, argval);
767 else if (strcmp("memory_limit", argv[0]) == 0)
768 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_MEMORY_LIMIT, argval);
769 else if (strcmp("quantum", argv[0]) == 0)
770 NLA_PUT_U32(msg, NL80211_ATTR_TXQ_QUANTUM, argval);
771 else
772 return -1;
773
774 return 0;
775 nla_put_failure:
776 return -ENOBUFS;
777}
778COMMAND(set, txq, "limit <packets> | memory_limit <bytes> | quantum <bytes>",
779 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_set_txq,
780 "Set TXQ parameters. The limit and memory_limit are global queue limits\n"
781 "for the whole phy. The quantum is the DRR scheduler quantum setting.\n"
782 "Valid values: 1 - 2**32");
783
784static int print_txq_handler(struct nl_msg *msg, void *arg)
785{
786 struct nlattr *attrs[NL80211_ATTR_MAX + 1];
787 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
788 struct nlattr *txqstats_info[NL80211_TXQ_STATS_MAX + 1], *txqinfo;
789 static struct nla_policy txqstats_policy[NL80211_TXQ_STATS_MAX + 1] = {
790 [NL80211_TXQ_STATS_BACKLOG_PACKETS] = { .type = NLA_U32 },
791 [NL80211_TXQ_STATS_BACKLOG_BYTES] = { .type = NLA_U32 },
792 [NL80211_TXQ_STATS_OVERLIMIT] = { .type = NLA_U32 },
793 [NL80211_TXQ_STATS_OVERMEMORY] = { .type = NLA_U32 },
794 [NL80211_TXQ_STATS_COLLISIONS] = { .type = NLA_U32 },
795 [NL80211_TXQ_STATS_MAX_FLOWS] = { .type = NLA_U32 },
796 };
797
798 nla_parse(attrs, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
799 genlmsg_attrlen(gnlh, 0), NULL);
800
801
802 if (attrs[NL80211_ATTR_TXQ_LIMIT])
803 printf("Packet limit:\t\t%u pkts\n",
804 nla_get_u32(attrs[NL80211_ATTR_TXQ_LIMIT]));
805 if (attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT])
806 printf("Memory limit:\t\t%u bytes\n",
807 nla_get_u32(attrs[NL80211_ATTR_TXQ_MEMORY_LIMIT]));
808 if (attrs[NL80211_ATTR_TXQ_QUANTUM])
809 printf("Quantum:\t\t%u bytes\n",
810 nla_get_u32(attrs[NL80211_ATTR_TXQ_QUANTUM]));
811
812 if (attrs[NL80211_ATTR_TXQ_STATS]) {
813 if (nla_parse_nested(txqstats_info, NL80211_TXQ_STATS_MAX,
814 attrs[NL80211_ATTR_TXQ_STATS],
815 txqstats_policy)) {
816 printf("failed to parse nested TXQ stats attributes!");
817 return 0;
818 }
819 txqinfo = txqstats_info[NL80211_TXQ_STATS_MAX_FLOWS];
820 if (txqinfo)
821 printf("Number of queues:\t%u\n", nla_get_u32(txqinfo));
822
823 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_PACKETS];
824 if (txqinfo)
825 printf("Backlog:\t\t%u pkts\n", nla_get_u32(txqinfo));
826
827 txqinfo = txqstats_info[NL80211_TXQ_STATS_BACKLOG_BYTES];
828 if (txqinfo)
829 printf("Memory usage:\t\t%u bytes\n", nla_get_u32(txqinfo));
830
831 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERLIMIT];
832 if (txqinfo)
833 printf("Packet limit overflows:\t%u\n", nla_get_u32(txqinfo));
834
835 txqinfo = txqstats_info[NL80211_TXQ_STATS_OVERMEMORY];
836 if (txqinfo)
837 printf("Memory limit overflows:\t%u\n", nla_get_u32(txqinfo));
838 txqinfo = txqstats_info[NL80211_TXQ_STATS_COLLISIONS];
839 if (txqinfo)
840 printf("Hash collisions:\t%u\n", nla_get_u32(txqinfo));
841 }
842 return NL_SKIP;
843}
844
845static int handle_get_txq(struct nl80211_state *state,
846 struct nl_msg *msg,
847 int argc, char **argv,
848 enum id_input id)
849{
850 nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
851 nlmsg_hdr(msg)->nlmsg_flags |= NLM_F_DUMP;
852 register_handler(print_txq_handler, NULL);
853 return 0;
854}
855COMMAND(get, txq, "",
856 NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_get_txq,
857 "Get TXQ parameters.");