]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
update to version 3.17
[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>
0f55e0b8
JB
5
6#include <netlink/genl/genl.h>
7#include <netlink/genl/family.h>
8#include <netlink/genl/ctrl.h>
9#include <netlink/msg.h>
10#include <netlink/attr.h>
11
f408e01b 12#include "nl80211.h"
0f55e0b8
JB
13#include "iw.h"
14
7c37a24d
JB
15static int handle_name(struct nl80211_state *state,
16 struct nl_cb *cb,
0f55e0b8 17 struct nl_msg *msg,
05514f95
JB
18 int argc, char **argv,
19 enum id_input id)
0f55e0b8 20{
0f55e0b8 21 if (argc != 1)
5e75fd04 22 return 1;
0f55e0b8
JB
23
24 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
25
70391ccf 26 return 0;
0f55e0b8 27 nla_put_failure:
70391ccf 28 return -ENOBUFS;
0f55e0b8 29}
cea8fa1c
JB
30COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
31 "Rename this wireless device.");
b822cda9 32
7c60bb76
JB
33static int handle_freqs(struct nl_msg *msg, int argc, char **argv)
34{
35 static const struct {
36 const char *name;
37 unsigned int val;
38 } bwmap[] = {
39 { .name = "20", .val = NL80211_CHAN_WIDTH_20, },
40 { .name = "40", .val = NL80211_CHAN_WIDTH_40, },
41 { .name = "80", .val = NL80211_CHAN_WIDTH_80, },
42 { .name = "80+80", .val = NL80211_CHAN_WIDTH_80P80, },
43 { .name = "160", .val = NL80211_CHAN_WIDTH_160, },
44 };
45 uint32_t freq;
46 int i, bwval = NL80211_CHAN_WIDTH_20_NOHT;
47 char *end;
48
49 if (argc < 1)
50 return 1;
51
52 for (i = 0; i < ARRAY_SIZE(bwmap); i++) {
53 if (strcasecmp(bwmap[i].name, argv[0]) == 0) {
54 bwval = bwmap[i].val;
55 break;
56 }
57 }
58
59 if (bwval == NL80211_CHAN_WIDTH_20_NOHT)
60 return 1;
61
62 NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, bwval);
63
64 if (argc == 1)
65 return 0;
66
67 /* center freq 1 */
68 if (!*argv[1])
69 return 1;
70 freq = strtoul(argv[1], &end, 10);
71 if (*end)
72 return 1;
73 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq);
74
75 if (argc == 2)
76 return 0;
77
78 /* center freq 2 */
79 if (!*argv[2])
80 return 1;
81 freq = strtoul(argv[2], &end, 10);
82 if (*end)
83 return 1;
84 NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, freq);
85
86 return 0;
87 nla_put_failure:
88 return -ENOBUFS;
89}
90
379f8397
JB
91static int handle_freqchan(struct nl_msg *msg, bool chan,
92 int argc, char **argv)
b822cda9 93{
e86b7e02 94 char *end;
b822cda9
JB
95 static const struct {
96 const char *name;
97 unsigned int val;
98 } htmap[] = {
68632dc7
JB
99 { .name = "HT20", .val = NL80211_CHAN_HT20, },
100 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
101 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
b822cda9 102 };
68632dc7 103 unsigned int htval = NL80211_CHAN_NO_HT;
b822cda9
JB
104 unsigned int freq;
105 int i;
106
7c60bb76 107 if (!argc || argc > 4)
b822cda9
JB
108 return 1;
109
e86b7e02
JB
110 if (!*argv[0])
111 return 1;
112 freq = strtoul(argv[0], &end, 10);
113 if (*end)
114 return 1;
115
58b46da2
BR
116 if (chan) {
117 enum nl80211_band band;
118 band = freq <= 14 ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
119 freq = ieee80211_channel_to_frequency(freq, band);
120 }
b822cda9
JB
121
122 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
7c60bb76
JB
123
124 if (argc > 2) {
125 return handle_freqs(msg, argc - 1, argv + 1);
126 } else if (argc == 2) {
127 for (i = 0; i < ARRAY_SIZE(htmap); i++) {
128 if (strcasecmp(htmap[i].name, argv[1]) == 0) {
129 htval = htmap[i].val;
130 break;
131 }
132 }
133 if (htval == NL80211_CHAN_NO_HT)
134 return handle_freqs(msg, argc - 1, argv + 1);
135 }
136
68632dc7 137 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
b822cda9
JB
138
139 return 0;
140 nla_put_failure:
141 return -ENOBUFS;
142}
379f8397 143
7c37a24d
JB
144static int handle_freq(struct nl80211_state *state,
145 struct nl_cb *cb, 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
7c37a24d
JB
159static int handle_chan(struct nl80211_state *state,
160 struct nl_cb *cb, 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,
172 struct nl_cb *cb, 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,
204 struct nl_cb *cb, 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
UR
235static int handle_retry(struct nl80211_state *state,
236 struct nl_cb *cb, struct nl_msg *msg,
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
e960e066
JB
299static int handle_netns(struct nl80211_state *state,
300 struct nl_cb *cb,
301 struct nl_msg *msg,
05514f95
JB
302 int argc, char **argv,
303 enum id_input id)
e960e066
JB
304{
305 char *end;
306
307 if (argc != 1)
308 return 1;
309
e86b7e02
JB
310 if (!*argv[0])
311 return 1;
312
e960e066 313 NLA_PUT_U32(msg, NL80211_ATTR_PID,
c551449a 314 strtoul(argv[0], &end, 10));
e960e066
JB
315
316 if (*end != '\0')
317 return 1;
318
319 return 0;
320 nla_put_failure:
321 return -ENOBUFS;
322}
323COMMAND(set, netns, "<pid>",
324 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
325 "Put this wireless device into a different network namespace");
b2f92dd0
LT
326
327static int handle_coverage(struct nl80211_state *state,
328 struct nl_cb *cb,
329 struct nl_msg *msg,
05514f95
JB
330 int argc, char **argv,
331 enum id_input id)
b2f92dd0 332{
e86b7e02 333 char *end;
b2f92dd0
LT
334 unsigned int coverage;
335
336 if (argc != 1)
337 return 1;
338
e86b7e02
JB
339 if (!*argv[0])
340 return 1;
341 coverage = strtoul(argv[0], &end, 10);
b2f92dd0
LT
342 if (coverage > 255)
343 return 1;
344
e86b7e02
JB
345 if (*end)
346 return 1;
347
b2f92dd0
LT
348 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
349
350 return 0;
351 nla_put_failure:
352 return -ENOBUFS;
353}
354COMMAND(set, coverage, "<coverage class>",
355 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
356 "Set coverage class (1 for every 3 usec of air propagation time).\n"
357 "Valid values: 0 - 255.");
358
359static int handle_distance(struct nl80211_state *state,
360 struct nl_cb *cb,
361 struct nl_msg *msg,
05514f95
JB
362 int argc, char **argv,
363 enum id_input id)
b2f92dd0 364{
b2f92dd0
LT
365 if (argc != 1)
366 return 1;
367
e86b7e02
JB
368 if (!*argv[0])
369 return 1;
370
e642142d
LB
371 if (strcmp("auto", argv[0]) == 0) {
372 NLA_PUT_FLAG(msg, NL80211_ATTR_WIPHY_DYN_ACK);
373 } else {
374 char *end;
375 unsigned int distance, coverage;
e86b7e02 376
e642142d 377 distance = strtoul(argv[0], &end, 10);
b2f92dd0 378
e642142d
LB
379 if (*end)
380 return 1;
b2f92dd0 381
e642142d
LB
382 /*
383 * Divide double the distance by the speed of light
384 * in m/usec (300) to get round-trip time in microseconds
385 * and then divide the result by three to get coverage class
386 * as specified in IEEE 802.11-2007 table 7-27.
387 * Values are rounded upwards.
388 */
389 coverage = (distance + 449) / 450;
390 if (coverage > 255)
391 return 1;
392
393 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
394 }
b2f92dd0
LT
395
396 return 0;
397 nla_put_failure:
398 return -ENOBUFS;
399}
e642142d 400COMMAND(set, distance, "<auto|distance>",
b2f92dd0 401 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
e642142d
LB
402 "Enable ACK timeout estimation algorithm (dynack) or set appropriate\n"
403 "coverage class for given link distance in meters.\n"
404 "To disable dynack set valid value for coverage class.\n"
b2f92dd0 405 "Valid values: 0 - 114750");
a0b1f574
JO
406
407static int handle_txpower(struct nl80211_state *state,
408 struct nl_cb *cb,
409 struct nl_msg *msg,
05514f95
JB
410 int argc, char **argv,
411 enum id_input id)
a0b1f574
JO
412{
413 enum nl80211_tx_power_setting type;
414 int mbm;
415
416 /* get the required args */
417 if (argc != 1 && argc != 2)
418 return 1;
419
420 if (!strcmp(argv[0], "auto"))
421 type = NL80211_TX_POWER_AUTOMATIC;
422 else if (!strcmp(argv[0], "fixed"))
423 type = NL80211_TX_POWER_FIXED;
424 else if (!strcmp(argv[0], "limit"))
425 type = NL80211_TX_POWER_LIMITED;
426 else {
427 printf("Invalid parameter: %s\n", argv[0]);
428 return 2;
429 }
430
431 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
432
433 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 434 char *endptr;
a0b1f574
JO
435 if (argc != 2) {
436 printf("Missing TX power level argument.\n");
437 return 2;
438 }
439
18e05613 440 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 441 if (*endptr)
18e05613 442 return 2;
a0b1f574
JO
443 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
444 } else if (argc != 1)
445 return 1;
446
447 return 0;
448
449 nla_put_failure:
450 return -ENOBUFS;
451}
452COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
453 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
454 "Specify transmit power level and setting type.");
455COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
456 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
457 "Specify transmit power level and setting type.");
afce7986
BR
458
459static int handle_antenna(struct nl80211_state *state,
460 struct nl_cb *cb,
461 struct nl_msg *msg,
05514f95
JB
462 int argc, char **argv,
463 enum id_input id)
afce7986
BR
464{
465 char *end;
466 uint32_t tx_ant = 0, rx_ant = 0;
467
468 if (argc == 1 && strcmp(argv[0], "all") == 0) {
469 tx_ant = 0xffffffff;
470 rx_ant = 0xffffffff;
471 } else if (argc == 1) {
472 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
473 if (*end)
474 return 1;
475 }
476 else if (argc == 2) {
477 tx_ant = strtoul(argv[0], &end, 0);
478 if (*end)
479 return 1;
480 rx_ant = strtoul(argv[1], &end, 0);
481 if (*end)
482 return 1;
483 } else
484 return 1;
485
486 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
487 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
488
489 return 0;
490
491 nla_put_failure:
492 return -ENOBUFS;
493}
494COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
495 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
496 "Set a bitmap of allowed antennas to use for TX and RX.\n"
497 "The driver may reject antenna configurations it cannot support.");