]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
add "channels" PHY command listing frequencies with more details
[thirdparty/iw.git] / phy.c
CommitLineData
379f8397 1#include <stdbool.h>
0f55e0b8 2#include <errno.h>
d0260390 3#include <strings.h>
91454b65
VK
4#include <sys/param.h>
5#include <sys/stat.h>
6#include <fcntl.h>
0f55e0b8
JB
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
f408e01b 14#include "nl80211.h"
0f55e0b8
JB
15#include "iw.h"
16
db9d4050
RM
17struct channels_ctx {
18 int last_band;
19 bool width_40;
20 bool width_80;
21 bool width_160;
22};
23
24static 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
38static 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
153static 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}
167TOPLEVEL(channels, NULL, NL80211_CMD_GET_WIPHY, 0, CIB_PHY, handle_channels, "Show available channels.");
168
7c37a24d 169static int handle_name(struct nl80211_state *state,
0f55e0b8 170 struct nl_msg *msg,
05514f95
JB
171 int argc, char **argv,
172 enum id_input id)
0f55e0b8 173{
0f55e0b8 174 if (argc != 1)
5e75fd04 175 return 1;
0f55e0b8
JB
176
177 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
178
70391ccf 179 return 0;
0f55e0b8 180 nla_put_failure:
70391ccf 181 return -ENOBUFS;
0f55e0b8 182}
cea8fa1c
JB
183COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
184 "Rename this wireless device.");
b822cda9 185
7c60bb76
JB
186static int handle_freqs(struct nl_msg *msg, int argc, char **argv)
187{
188 static const struct {
189 const char *name;
190 unsigned int val;
191 } bwmap[] = {
192 { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
193 { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
194 { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
195 { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
196 { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
197 };
198 uint32_t freq;
0ee571d5 199 unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
7c60bb76
JB
200 char *end;
201
202 if (argc < 1)
203 return 1;
204
205 for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
206 if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
207 bwval = bwmap[i].val;
208 break;
209 }
210 }
211
212 if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
213 return 1;
214
215 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval);
216
217 if (argc == 1)
218 return 0;
219
220 /* center freq 1 */
221 if (!*argv[1])
222 return 1;
223 freq = strtoul(argv[1], &end, 10);
224 if (*end)
225 return 1;
226 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq);
227
228 if (argc == 2)
229 return 0;
230
231 /* center freq 2 */
232 if (!*argv[2])
233 return 1;
234 freq = strtoul(argv[2], &end, 10);
235 if (*end)
236 return 1;
237 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq);
238
239 return 0;
240 nla_put_failure:
241 return -ENOBUFS;
242}
243
379f8397
JB
244static int handle_freqchan(struct nl_msg *msg, bool chan,
245 int argc, char **argv)
b822cda9 246{
e86b7e02 247 char *end;
b822cda9
JB
248 static const struct {
249 const char *name;
250 unsigned int val;
251 } htmap[] = {
68632dc7
JB
252 { .name = "HT20", .val = NL80211_CHAN_HT20, },
253 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
254 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
b822cda9 255 };
68632dc7 256 unsigned int htval = NL80211_CHAN_NO_HT;
b822cda9 257 unsigned int freq;
0ee571d5 258 unsigned int i;
b822cda9 259
7c60bb76 260 if (!argc || argc > 4)
b822cda9
JB
261 return 1;
262
e86b7e02
JB
263 if (!*argv[0])
264 return 1;
265 freq = strtoul(argv[0], &end, 10);
266 if (*end)
267 return 1;
268
58b46da2
BR
269 if (chan) {
270 enum nl80211_band band;
271 band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
272 freq = ieee80211_channel_to_frequency(freq, band);
273 }
b822cda9
JB
274
275 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
7c60bb76
JB
276
277 if (argc > 2) {
278 return handle_freqs(msg, argc - 1, argv + 1);
279 } else if (argc == 2) {
280 for (i = 0; i < ARRAY_SIZE(htmap); i++) {
281 if (strcasecmp(htmap[i].name, argv[1]) == 0) {
282 htval = htmap[i].val;
283 break;
284 }
285 }
286 if (htval == NL80211_CHAN_NO_HT)
287 return handle_freqs(msg, argc - 1, argv + 1);
288 }
289
68632dc7 290 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
b822cda9
JB
291
292 return 0;
293 nla_put_failure:
294 return -ENOBUFS;
295}
379f8397 296
34b23014 297static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
298 int argc, char **argv,
299 enum id_input id)
379f8397
JB
300{
301 return handle_freqchan(msg, false, argc, argv);
302}
b822cda9 303COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
00c448b2
JB
304 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
305 "Set frequency/channel the hardware is using, including HT\n"
306 "configuration.");
7c60bb76
JB
307COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n"
308 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
01ae06f9 309 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 310
34b23014 311static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
312 int argc, char **argv,
313 enum id_input id)
379f8397
JB
314{
315 return handle_freqchan(msg, true, argc, argv);
316}
317COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 318 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
379f8397 319COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 320 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae
JB
321
322static int handle_fragmentation(struct nl80211_state *state,
34b23014 323 struct nl_msg *msg,
05514f95
JB
324 int argc, char **argv,
325 enum id_input id)
625aa4ae
JB
326{
327 unsigned int frag;
328
329 if (argc != 1)
330 return 1;
331
332 if (strcmp("off", argv[0]) == 0)
333 frag = -1;
e86b7e02
JB
334 else {
335 char *end;
336
337 if (!*argv[0])
338 return 1;
339 frag = strtoul(argv[0], &end, 10);
340 if (*end != '\0')
341 return 1;
342 }
625aa4ae
JB
343
344 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
345
346 return 0;
347 nla_put_failure:
348 return -ENOBUFS;
349}
350COMMAND(set, frag, "<fragmentation threshold|off>",
351 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
352 "Set fragmentation threshold.");
353
354static int handle_rts(struct nl80211_state *state,
34b23014 355 struct nl_msg *msg,
05514f95
JB
356 int argc, char **argv,
357 enum id_input id)
625aa4ae
JB
358{
359 unsigned int rts;
360
361 if (argc != 1)
362 return 1;
363
364 if (strcmp("off", argv[0]) == 0)
365 rts = -1;
e86b7e02
JB
366 else {
367 char *end;
368
369 if (!*argv[0])
370 return 1;
371 rts = strtoul(argv[0], &end, 10);
372 if (*end != '\0')
373 return 1;
374 }
625aa4ae
JB
375
376 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
377
378 return 0;
379 nla_put_failure:
380 return -ENOBUFS;
381}
382COMMAND(set, rts, "<rts threshold|off>",
383 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
384 "Set rts threshold.");
e960e066 385
c993e6e7 386static int handle_retry(struct nl80211_state *state,
34b23014 387 struct nl_msg *msg,
c993e6e7
UR
388 int argc, char **argv, enum id_input id)
389{
390 unsigned int retry_short = 0, retry_long = 0;
391 bool have_retry_s = false, have_retry_l = false;
392 int i;
393 enum {
394 S_NONE,
395 S_SHORT,
396 S_LONG,
397 } parser_state = S_NONE;
398
399 if (!argc || (argc != 2 && argc != 4))
400 return 1;
401
402 for (i = 0; i < argc; i++) {
403 char *end;
404 unsigned int tmpul;
405
406 if (strcmp(argv[i], "short") == 0) {
407 if (have_retry_s)
408 return 1;
409 parser_state = S_SHORT;
410 have_retry_s = true;
411 } else if (strcmp(argv[i], "long") == 0) {
412 if (have_retry_l)
413 return 1;
414 parser_state = S_LONG;
415 have_retry_l = true;
416 } else {
417 tmpul = strtoul(argv[i], &end, 10);
418 if (*end != '\0')
419 return 1;
420 if (!tmpul || tmpul > 255)
421 return -EINVAL;
422 switch (parser_state) {
423 case S_SHORT:
424 retry_short = tmpul;
425 break;
426 case S_LONG:
427 retry_long = tmpul;
428 break;
429 default:
430 return 1;
431 }
432 }
433 }
434
435 if (!have_retry_s && !have_retry_l)
436 return 1;
437 if (have_retry_s)
438 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
439 if (have_retry_l)
440 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
441
442 return 0;
443 nla_put_failure:
444 return -ENOBUFS;
445}
446COMMAND(set, retry, "[short <limit>] [long <limit>]",
447 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
448 "Set retry limit.");
449
91454b65
VK
450#ifndef NETNS_RUN_DIR
451#define NETNS_RUN_DIR "/var/run/netns"
452#endif
c0441e65 453static int netns_get_fd(const char *name)
91454b65
VK
454{
455 char pathbuf[MAXPATHLEN];
456 const char *path, *ptr;
457
458 path = name;
459 ptr = strchr(name, '/');
460 if (!ptr) {
461 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
462 NETNS_RUN_DIR, name );
463 path = pathbuf;
464 }
465 return open(path, O_RDONLY);
466}
467
e960e066 468static int handle_netns(struct nl80211_state *state,
e960e066 469 struct nl_msg *msg,
05514f95
JB
470 int argc, char **argv,
471 enum id_input id)
e960e066
JB
472{
473 char *end;
91454b65 474 int fd;
e960e066 475
91454b65 476 if (argc < 1 || !*argv[0])
e960e066
JB
477 return 1;
478
91454b65
VK
479 if (argc == 1) {
480 NLA_PUT_U32(msg, NL80211_ATTR_PID,
481 strtoul(argv[0], &end, 10));
482 if (*end != '\0') {
483 printf("Invalid parameter: pid(%s)\n", argv[0]);
484 return 1;
485 }
486 return 0;
487 }
488
489 if (argc != 2 || strcmp(argv[0], "name"))
e86b7e02
JB
490 return 1;
491
91454b65
VK
492 if ((fd = netns_get_fd(argv[1])) >= 0) {
493 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
494 return 0;
495 } else {
496 printf("Invalid parameter: nsname(%s)\n", argv[0]);
497 }
e960e066 498
91454b65 499 return 1;
e960e066 500
e960e066
JB
501 nla_put_failure:
502 return -ENOBUFS;
503}
91454b65 504COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 505 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
506 "Put this wireless device into a different network namespace:\n"
507 " <pid> - change network namespace by process id\n"
508 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
509 " or by absolute path (man ip-netns)\n");
b2f92dd0
LT
510
511static int handle_coverage(struct nl80211_state *state,
b2f92dd0 512 struct nl_msg *msg,
05514f95
JB
513 int argc, char **argv,
514 enum id_input id)
b2f92dd0 515{
e86b7e02 516 char *end;
b2f92dd0
LT
517 unsigned int coverage;
518
519 if (argc != 1)
520 return 1;
521
e86b7e02
JB
522 if (!*argv[0])
523 return 1;
524 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
525 if (coverage > 255)
526 return 1;
527
e86b7e02
JB
528 if (*end)
529 return 1;
530
b2f92dd0
LT
531 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
532
533 return 0;
534 nla_put_failure:
535 return -ENOBUFS;
536}
537COMMAND(set, coverage, "<coverage class>",
538 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
539 "Set coverage class (1 for every 3 usec of air propagation time).\n"
540 "Valid values: 0 - 255.");
541
542static int handle_distance(struct nl80211_state *state,
b2f92dd0 543 struct nl_msg *msg,
05514f95
JB
544 int argc, char **argv,
545 enum id_input id)
b2f92dd0 546{
b2f92dd0
LT
547 if (argc != 1)
548 return 1;
549
e86b7e02
JB
550 if (!*argv[0])
551 return 1;
552
e642142d
LB
553 if (strcmp("auto", argv[0]) == 0) {
554 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
555 } else {
556 char *end;
557 unsigned int distance, coverage;
e86b7e02 558
e642142d 559 distance = strtoul(argv[0], &end, 10);
b2f92dd0 560
e642142d
LB
561 if (*end)
562 return 1;
b2f92dd0 563
e642142d
LB
564 /*
565 * Divide double the distance by the speed of light
566 * in m/usec (300) to get round-trip time in microseconds
567 * and then divide the result by three to get coverage class
568 * as specified in IEEE 802.11-2007 table 7-27.
569 * Values are rounded upwards.
570 */
571 coverage = (distance + 449) / 450;
572 if (coverage > 255)
573 return 1;
574
575 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
576 }
b2f92dd0
LT
577
578 return 0;
579 nla_put_failure:
580 return -ENOBUFS;
581}
e642142d 582COMMAND(set, distance, "<auto|distance>",
b2f92dd0 583 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
584 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
585 "coverage class for given link distance in meters.\n"
586 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 587 "Valid values: 0 - 114750");
a0b1f574
JO
588
589static int handle_txpower(struct nl80211_state *state,
a0b1f574 590 struct nl_msg *msg,
05514f95
JB
591 int argc, char **argv,
592 enum id_input id)
a0b1f574
JO
593{
594 enum nl80211_tx_power_setting type;
595 int mbm;
596
597 /* get the required args */
598 if (argc != 1 && argc != 2)
599 return 1;
600
601 if (!strcmp(argv[0], "auto"))
602 type = NL80211_TX_POWER_AUTOMATIC;
603 else if (!strcmp(argv[0], "fixed"))
604 type = NL80211_TX_POWER_FIXED;
605 else if (!strcmp(argv[0], "limit"))
606 type = NL80211_TX_POWER_LIMITED;
607 else {
608 printf("Invalid parameter: %s\n", argv[0]);
609 return 2;
610 }
611
612 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
613
614 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 615 char *endptr;
a0b1f574
JO
616 if (argc != 2) {
617 printf("Missing TX power level argument.\n");
618 return 2;
619 }
620
18e05613 621 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 622 if (*endptr)
18e05613 623 return 2;
a0b1f574
JO
624 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
625 } else if (argc != 1)
626 return 1;
627
628 return 0;
629
630 nla_put_failure:
631 return -ENOBUFS;
632}
633COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
634 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
635 "Specify transmit power level and setting type.");
636COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
637 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
638 "Specify transmit power level and setting type.");
afce7986
BR
639
640static int handle_antenna(struct nl80211_state *state,
afce7986 641 struct nl_msg *msg,
05514f95
JB
642 int argc, char **argv,
643 enum id_input id)
afce7986
BR
644{
645 char *end;
646 uint32_t tx_ant = 0, rx_ant = 0;
647
648 if (argc == 1 && strcmp(argv[0], "all") == 0) {
649 tx_ant = 0xffffffff;
650 rx_ant = 0xffffffff;
651 } else if (argc == 1) {
652 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
653 if (*end)
654 return 1;
655 }
656 else if (argc == 2) {
657 tx_ant = strtoul(argv[0], &end, 0);
658 if (*end)
659 return 1;
660 rx_ant = strtoul(argv[1], &end, 0);
661 if (*end)
662 return 1;
663 } else
664 return 1;
665
666 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
667 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
668
669 return 0;
670
671 nla_put_failure:
672 return -ENOBUFS;
673}
674COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
675 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
676 "Set a bitmap of allowed antennas to use for TX and RX.\n"
677 "The driver may reject antenna configurations it cannot support.");