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