]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
iw: don't use NULL pointer in nla_nest_end()
[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
7c37a24d 17static int handle_name(struct nl80211_state *state,
0f55e0b8 18 struct nl_msg *msg,
05514f95
JB
19 int argc, char **argv,
20 enum id_input id)
0f55e0b8 21{
0f55e0b8 22 if (argc != 1)
5e75fd04 23 return 1;
0f55e0b8
JB
24
25 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
26
70391ccf 27 return 0;
0f55e0b8 28 nla_put_failure:
70391ccf 29 return -ENOBUFS;
0f55e0b8 30}
cea8fa1c
JB
31COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
32 "Rename this wireless device.");
b822cda9 33
7c60bb76
JB
34static 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;
0ee571d5 47 unsigned int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
7c60bb76
JB
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
379f8397
JB
92static int handle_freqchan(struct nl_msg *msg, bool chan,
93 int argc, char **argv)
b822cda9 94{
e86b7e02 95 char *end;
b822cda9
JB
96 static const struct {
97 const char *name;
98 unsigned int val;
99 } htmap[] = {
68632dc7
JB
100 { .name = "HT20", .val = NL80211_CHAN_HT20, },
101 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
102 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
b822cda9 103 };
68632dc7 104 unsigned int htval = NL80211_CHAN_NO_HT;
b822cda9 105 unsigned int freq;
0ee571d5 106 unsigned int i;
b822cda9 107
7c60bb76 108 if (!argc || argc > 4)
b822cda9
JB
109 return 1;
110
e86b7e02
JB
111 if (!*argv[0])
112 return 1;
113 freq = strtoul(argv[0], &end, 10);
114 if (*end)
115 return 1;
116
58b46da2
BR
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 }
b822cda9
JB
122
123 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
7c60bb76
JB
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
68632dc7 138 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
b822cda9
JB
139
140 return 0;
141 nla_put_failure:
142 return -ENOBUFS;
143}
379f8397 144
34b23014 145static int handle_freq(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
146 int argc, char **argv,
147 enum id_input id)
379f8397
JB
148{
149 return handle_freqchan(msg, false, argc, argv);
150}
b822cda9 151COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
00c448b2
JB
152 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
153 "Set frequency/channel the hardware is using, including HT\n"
154 "configuration.");
7c60bb76
JB
155COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n"
156 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
01ae06f9 157 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
379f8397 158
34b23014 159static int handle_chan(struct nl80211_state *state, struct nl_msg *msg,
05514f95
JB
160 int argc, char **argv,
161 enum id_input id)
379f8397
JB
162{
163 return handle_freqchan(msg, true, argc, argv);
164}
165COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 166 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
379f8397 167COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
01ae06f9 168 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
625aa4ae
JB
169
170static int handle_fragmentation(struct nl80211_state *state,
34b23014 171 struct nl_msg *msg,
05514f95
JB
172 int argc, char **argv,
173 enum id_input id)
625aa4ae
JB
174{
175 unsigned int frag;
176
177 if (argc != 1)
178 return 1;
179
180 if (strcmp("off", argv[0]) == 0)
181 frag = -1;
e86b7e02
JB
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 }
625aa4ae
JB
191
192 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
193
194 return 0;
195 nla_put_failure:
196 return -ENOBUFS;
197}
198COMMAND(set, frag, "<fragmentation threshold|off>",
199 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
200 "Set fragmentation threshold.");
201
202static int handle_rts(struct nl80211_state *state,
34b23014 203 struct nl_msg *msg,
05514f95
JB
204 int argc, char **argv,
205 enum id_input id)
625aa4ae
JB
206{
207 unsigned int rts;
208
209 if (argc != 1)
210 return 1;
211
212 if (strcmp("off", argv[0]) == 0)
213 rts = -1;
e86b7e02
JB
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 }
625aa4ae
JB
223
224 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
225
226 return 0;
227 nla_put_failure:
228 return -ENOBUFS;
229}
230COMMAND(set, rts, "<rts threshold|off>",
231 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
232 "Set rts threshold.");
e960e066 233
c993e6e7 234static int handle_retry(struct nl80211_state *state,
34b23014 235 struct nl_msg *msg,
c993e6e7
UR
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}
294COMMAND(set, retry, "[short <limit>] [long <limit>]",
295 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
296 "Set retry limit.");
297
91454b65
VK
298#ifndef NETNS_RUN_DIR
299#define NETNS_RUN_DIR "/var/run/netns"
300#endif
c0441e65 301static int netns_get_fd(const char *name)
91454b65
VK
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
e960e066 316static int handle_netns(struct nl80211_state *state,
e960e066 317 struct nl_msg *msg,
05514f95
JB
318 int argc, char **argv,
319 enum id_input id)
e960e066
JB
320{
321 char *end;
91454b65 322 int fd;
e960e066 323
91454b65 324 if (argc < 1 || !*argv[0])
e960e066
JB
325 return 1;
326
91454b65
VK
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"))
e86b7e02
JB
338 return 1;
339
91454b65
VK
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 }
e960e066 346
91454b65 347 return 1;
e960e066 348
e960e066
JB
349 nla_put_failure:
350 return -ENOBUFS;
351}
91454b65 352COMMAND(set, netns, "{ <pid> | name <nsname> }",
e960e066 353 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
91454b65
VK
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");
b2f92dd0
LT
358
359static int handle_coverage(struct nl80211_state *state,
b2f92dd0 360 struct nl_msg *msg,
05514f95
JB
361 int argc, char **argv,
362 enum id_input id)
b2f92dd0 363{
e86b7e02 364 char *end;
b2f92dd0
LT
365 unsigned int coverage;
366
367 if (argc != 1)
368 return 1;
369
e86b7e02
JB
370 if (!*argv[0])
371 return 1;
372 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
373 if (coverage > 255)
374 return 1;
375
e86b7e02
JB
376 if (*end)
377 return 1;
378
b2f92dd0
LT
379 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
380
381 return 0;
382 nla_put_failure:
383 return -ENOBUFS;
384}
385COMMAND(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
390static int handle_distance(struct nl80211_state *state,
b2f92dd0 391 struct nl_msg *msg,
05514f95
JB
392 int argc, char **argv,
393 enum id_input id)
b2f92dd0 394{
b2f92dd0
LT
395 if (argc != 1)
396 return 1;
397
e86b7e02
JB
398 if (!*argv[0])
399 return 1;
400
e642142d
LB
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;
e86b7e02 406
e642142d 407 distance = strtoul(argv[0], &end, 10);
b2f92dd0 408
e642142d
LB
409 if (*end)
410 return 1;
b2f92dd0 411
e642142d
LB
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 }
b2f92dd0
LT
425
426 return 0;
427 nla_put_failure:
428 return -ENOBUFS;
429}
e642142d 430COMMAND(set, distance, "<auto|distance>",
b2f92dd0 431 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
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"
b2f92dd0 435 "Valid values: 0 - 114750");
a0b1f574
JO
436
437static int handle_txpower(struct nl80211_state *state,
a0b1f574 438 struct nl_msg *msg,
05514f95
JB
439 int argc, char **argv,
440 enum id_input id)
a0b1f574
JO
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) {
18e05613 463 char *endptr;
a0b1f574
JO
464 if (argc != 2) {
465 printf("Missing TX power level argument.\n");
466 return 2;
467 }
468
18e05613 469 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 470 if (*endptr)
18e05613 471 return 2;
a0b1f574
JO
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}
481COMMAND(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.");
484COMMAND(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.");
afce7986
BR
487
488static int handle_antenna(struct nl80211_state *state,
afce7986 489 struct nl_msg *msg,
05514f95
JB
490 int argc, char **argv,
491 enum id_input id)
afce7986
BR
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}
522COMMAND(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.");