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