]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
add a few new commands/events
[thirdparty/iw.git] / phy.c
CommitLineData
379f8397 1#include <stdbool.h>
0f55e0b8 2#include <errno.h>
0f55e0b8 3#include <net/if.h>
d0260390 4#include <strings.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
7c37a24d 18static int handle_name(struct nl80211_state *state,
0f55e0b8 19 struct nl_msg *msg,
05514f95
JB
20 int argc, char **argv,
21 enum id_input id)
0f55e0b8 22{
0f55e0b8 23 if (argc != 1)
5e75fd04 24 return 1;
0f55e0b8
JB
25
26 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
27
70391ccf 28 return 0;
0f55e0b8 29 nla_put_failure:
70391ccf 30 return -ENOBUFS;
0f55e0b8 31}
cea8fa1c
JB
32COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
33 "Rename this wireless device.");
b822cda9 34
7c60bb76
JB
35static int handle_freqs(struct nl_msg *msg, int argc, char **argv)
36{
37 static const struct {
38 const char *name;
39 unsigned int val;
40 } bwmap[] = {
41 { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
42 { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
43 { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
44 { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
45 { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
46 };
47 uint32_t freq;
48 int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
49 char *end;
50
51 if (argc < 1)
52 return 1;
53
54 for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
55 if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
56 bwval = bwmap[i].val;
57 break;
58 }
59 }
60
61 if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
62 return 1;
63
64 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval);
65
66 if (argc == 1)
67 return 0;
68
69 /* center freq 1 */
70 if (!*argv[1])
71 return 1;
72 freq = strtoul(argv[1], &end, 10);
73 if (*end)
74 return 1;
75 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq);
76
77 if (argc == 2)
78 return 0;
79
80 /* center freq 2 */
81 if (!*argv[2])
82 return 1;
83 freq = strtoul(argv[2], &end, 10);
84 if (*end)
85 return 1;
86 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq);
87
88 return 0;
89 nla_put_failure:
90 return -ENOBUFS;
91}
92
379f8397
JB
93static int handle_freqchan(struct nl_msg *msg, bool chan,
94 int argc, char **argv)
b822cda9 95{
e86b7e02 96 char *end;
b822cda9
JB
97 static const struct {
98 const char *name;
99 unsigned int val;
100 } htmap[] = {
68632dc7
JB
101 { .name = "HT20", .val = NL80211_CHAN_HT20, },
102 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
103 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
b822cda9 104 };
68632dc7 105 unsigned int htval = NL80211_CHAN_NO_HT;
b822cda9
JB
106 unsigned int freq;
107 int i;
108
7c60bb76 109 if (!argc || argc > 4)
b822cda9
JB
110 return 1;
111
e86b7e02
JB
112 if (!*argv[0])
113 return 1;
114 freq = strtoul(argv[0], &end, 10);
115 if (*end)
116 return 1;
117
58b46da2
BR
118 if (chan) {
119 enum nl80211_band band;
120 band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
121 freq = ieee80211_channel_to_frequency(freq, band);
122 }
b822cda9
JB
123
124 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
7c60bb76
JB
125
126 if (argc > 2) {
127 return handle_freqs(msg, argc - 1, argv + 1);
128 } else if (argc == 2) {
129 for (i = 0; i < ARRAY_SIZE(htmap); i++) {
130 if (strcasecmp(htmap[i].name, argv[1]) == 0) {
131 htval = htmap[i].val;
132 break;
133 }
134 }
135 if (htval == NL80211_CHAN_NO_HT)
136 return handle_freqs(msg, argc - 1, argv + 1);
137 }
138
68632dc7 139 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
b822cda9
JB
140
141 return 0;
142 nla_put_failure:
143 return -ENOBUFS;
144}
379f8397 145
34b23014 146static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
147 int argc, char **argv,
148 enum id_input id)
379f8397
JB
149{
150 return handle_freqchan(msg, false, argc, argv);
151}
b822cda9 152COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
00c448b2
JB
153 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
154 "Set frequency/channel the hardware is using, including HT\n"
155 "configuration.");
7c60bb76
JB
156COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n"
157 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
01ae06f9 158 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 159
34b23014 160static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
161 int argc, char **argv,
162 enum id_input id)
379f8397
JB
163{
164 return handle_freqchan(msg, true, argc, argv);
165}
166COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 167 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
379f8397 168COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 169 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae
JB
170
171static int handle_fragmentation(struct nl80211_state *state,
34b23014 172 struct nl_msg *msg,
05514f95
JB
173 int argc, char **argv,
174 enum id_input id)
625aa4ae
JB
175{
176 unsigned int frag;
177
178 if (argc != 1)
179 return 1;
180
181 if (strcmp("off", argv[0]) == 0)
182 frag = -1;
e86b7e02
JB
183 else {
184 char *end;
185
186 if (!*argv[0])
187 return 1;
188 frag = strtoul(argv[0], &end, 10);
189 if (*end != '\0')
190 return 1;
191 }
625aa4ae
JB
192
193 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
194
195 return 0;
196 nla_put_failure:
197 return -ENOBUFS;
198}
199COMMAND(set, frag, "<fragmentation threshold|off>",
200 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
201 "Set fragmentation threshold.");
202
203static int handle_rts(struct nl80211_state *state,
34b23014 204 struct nl_msg *msg,
05514f95
JB
205 int argc, char **argv,
206 enum id_input id)
625aa4ae
JB
207{
208 unsigned int rts;
209
210 if (argc != 1)
211 return 1;
212
213 if (strcmp("off", argv[0]) == 0)
214 rts = -1;
e86b7e02
JB
215 else {
216 char *end;
217
218 if (!*argv[0])
219 return 1;
220 rts = strtoul(argv[0], &end, 10);
221 if (*end != '\0')
222 return 1;
223 }
625aa4ae
JB
224
225 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
226
227 return 0;
228 nla_put_failure:
229 return -ENOBUFS;
230}
231COMMAND(set, rts, "<rts threshold|off>",
232 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
233 "Set rts threshold.");
e960e066 234
c993e6e7 235static int handle_retry(struct nl80211_state *state,
34b23014 236 struct nl_msg *msg,
c993e6e7
UR
237 int argc, char **argv, enum id_input id)
238{
239 unsigned int retry_short = 0, retry_long = 0;
240 bool have_retry_s = false, have_retry_l = false;
241 int i;
242 enum {
243 S_NONE,
244 S_SHORT,
245 S_LONG,
246 } parser_state = S_NONE;
247
248 if (!argc || (argc != 2 && argc != 4))
249 return 1;
250
251 for (i = 0; i < argc; i++) {
252 char *end;
253 unsigned int tmpul;
254
255 if (strcmp(argv[i], "short") == 0) {
256 if (have_retry_s)
257 return 1;
258 parser_state = S_SHORT;
259 have_retry_s = true;
260 } else if (strcmp(argv[i], "long") == 0) {
261 if (have_retry_l)
262 return 1;
263 parser_state = S_LONG;
264 have_retry_l = true;
265 } else {
266 tmpul = strtoul(argv[i], &end, 10);
267 if (*end != '\0')
268 return 1;
269 if (!tmpul || tmpul > 255)
270 return -EINVAL;
271 switch (parser_state) {
272 case S_SHORT:
273 retry_short = tmpul;
274 break;
275 case S_LONG:
276 retry_long = tmpul;
277 break;
278 default:
279 return 1;
280 }
281 }
282 }
283
284 if (!have_retry_s && !have_retry_l)
285 return 1;
286 if (have_retry_s)
287 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_SHORT, retry_short);
288 if (have_retry_l)
289 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_RETRY_LONG, retry_long);
290
291 return 0;
292 nla_put_failure:
293 return -ENOBUFS;
294}
295COMMAND(set, retry, "[short <limit>] [long <limit>]",
296 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
297 "Set retry limit.");
298
91454b65
VK
299#ifndef NETNS_RUN_DIR
300#define NETNS_RUN_DIR "/var/run/netns"
301#endif
c0441e65 302static int netns_get_fd(const char *name)
91454b65
VK
303{
304 char pathbuf[MAXPATHLEN];
305 const char *path, *ptr;
306
307 path = name;
308 ptr = strchr(name, '/');
309 if (!ptr) {
310 snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
311 NETNS_RUN_DIR, name );
312 path = pathbuf;
313 }
314 return open(path, O_RDONLY);
315}
316
e960e066 317static int handle_netns(struct nl80211_state *state,
e960e066 318 struct nl_msg *msg,
05514f95
JB
319 int argc, char **argv,
320 enum id_input id)
e960e066
JB
321{
322 char *end;
91454b65 323 int fd;
e960e066 324
91454b65 325 if (argc < 1 || !*argv[0])
e960e066
JB
326 return 1;
327
91454b65
VK
328 if (argc == 1) {
329 NLA_PUT_U32(msg, NL80211_ATTR_PID,
330 strtoul(argv[0], &end, 10));
331 if (*end != '\0') {
332 printf("Invalid parameter: pid(%s)\n", argv[0]);
333 return 1;
334 }
335 return 0;
336 }
337
338 if (argc != 2 || strcmp(argv[0], "name"))
e86b7e02
JB
339 return 1;
340
91454b65
VK
341 if ((fd = netns_get_fd(argv[1])) >= 0) {
342 NLA_PUT_U32(msg, NL80211_ATTR_NETNS_FD, fd);
343 return 0;
344 } else {
345 printf("Invalid parameter: nsname(%s)\n", argv[0]);
346 }
e960e066 347
91454b65 348 return 1;
e960e066 349
e960e066
JB
350 nla_put_failure:
351 return -ENOBUFS;
352}
91454b65 353COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 354 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
355 "Put this wireless device into a different network namespace:\n"
356 " <pid> - change network namespace by process id\n"
357 " <nsname> - change network namespace by name from "NETNS_RUN_DIR"\n"
358 " or by absolute path (man ip-netns)\n");
b2f92dd0
LT
359
360static int handle_coverage(struct nl80211_state *state,
b2f92dd0 361 struct nl_msg *msg,
05514f95
JB
362 int argc, char **argv,
363 enum id_input id)
b2f92dd0 364{
e86b7e02 365 char *end;
b2f92dd0
LT
366 unsigned int coverage;
367
368 if (argc != 1)
369 return 1;
370
e86b7e02
JB
371 if (!*argv[0])
372 return 1;
373 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
374 if (coverage > 255)
375 return 1;
376
e86b7e02
JB
377 if (*end)
378 return 1;
379
b2f92dd0
LT
380 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
381
382 return 0;
383 nla_put_failure:
384 return -ENOBUFS;
385}
386COMMAND(set, coverage, "<coverage class>",
387 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
388 "Set coverage class (1 for every 3 usec of air propagation time).\n"
389 "Valid values: 0 - 255.");
390
391static int handle_distance(struct nl80211_state *state,
b2f92dd0 392 struct nl_msg *msg,
05514f95
JB
393 int argc, char **argv,
394 enum id_input id)
b2f92dd0 395{
b2f92dd0
LT
396 if (argc != 1)
397 return 1;
398
e86b7e02
JB
399 if (!*argv[0])
400 return 1;
401
e642142d
LB
402 if (strcmp("auto", argv[0]) == 0) {
403 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
404 } else {
405 char *end;
406 unsigned int distance, coverage;
e86b7e02 407
e642142d 408 distance = strtoul(argv[0], &end, 10);
b2f92dd0 409
e642142d
LB
410 if (*end)
411 return 1;
b2f92dd0 412
e642142d
LB
413 /*
414 * Divide double the distance by the speed of light
415 * in m/usec (300) to get round-trip time in microseconds
416 * and then divide the result by three to get coverage class
417 * as specified in IEEE 802.11-2007 table 7-27.
418 * Values are rounded upwards.
419 */
420 coverage = (distance + 449) / 450;
421 if (coverage > 255)
422 return 1;
423
424 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
425 }
b2f92dd0
LT
426
427 return 0;
428 nla_put_failure:
429 return -ENOBUFS;
430}
e642142d 431COMMAND(set, distance, "<auto|distance>",
b2f92dd0 432 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
433 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
434 "coverage class for given link distance in meters.\n"
435 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 436 "Valid values: 0 - 114750");
a0b1f574
JO
437
438static int handle_txpower(struct nl80211_state *state,
a0b1f574 439 struct nl_msg *msg,
05514f95
JB
440 int argc, char **argv,
441 enum id_input id)
a0b1f574
JO
442{
443 enum nl80211_tx_power_setting type;
444 int mbm;
445
446 /* get the required args */
447 if (argc != 1 && argc != 2)
448 return 1;
449
450 if (!strcmp(argv[0], "auto"))
451 type = NL80211_TX_POWER_AUTOMATIC;
452 else if (!strcmp(argv[0], "fixed"))
453 type = NL80211_TX_POWER_FIXED;
454 else if (!strcmp(argv[0], "limit"))
455 type = NL80211_TX_POWER_LIMITED;
456 else {
457 printf("Invalid parameter: %s\n", argv[0]);
458 return 2;
459 }
460
461 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
462
463 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 464 char *endptr;
a0b1f574
JO
465 if (argc != 2) {
466 printf("Missing TX power level argument.\n");
467 return 2;
468 }
469
18e05613 470 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 471 if (*endptr)
18e05613 472 return 2;
a0b1f574
JO
473 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
474 } else if (argc != 1)
475 return 1;
476
477 return 0;
478
479 nla_put_failure:
480 return -ENOBUFS;
481}
482COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
483 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
484 "Specify transmit power level and setting type.");
485COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
486 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
487 "Specify transmit power level and setting type.");
afce7986
BR
488
489static int handle_antenna(struct nl80211_state *state,
afce7986 490 struct nl_msg *msg,
05514f95
JB
491 int argc, char **argv,
492 enum id_input id)
afce7986
BR
493{
494 char *end;
495 uint32_t tx_ant = 0, rx_ant = 0;
496
497 if (argc == 1 && strcmp(argv[0], "all") == 0) {
498 tx_ant = 0xffffffff;
499 rx_ant = 0xffffffff;
500 } else if (argc == 1) {
501 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
502 if (*end)
503 return 1;
504 }
505 else if (argc == 2) {
506 tx_ant = strtoul(argv[0], &end, 0);
507 if (*end)
508 return 1;
509 rx_ant = strtoul(argv[1], &end, 0);
510 if (*end)
511 return 1;
512 } else
513 return 1;
514
515 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
516 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
517
518 return 0;
519
520 nla_put_failure:
521 return -ENOBUFS;
522}
523COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
524 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
525 "Set a bitmap of allowed antennas to use for TX and RX.\n"
526 "The driver may reject antenna configurations it cannot support.");