]> git.ipfire.org Git - thirdparty/iw.git/blob - phy.c
iw: support setting vif MAC during creation
[thirdparty/iw.git] / phy.c
1 #include <stdbool.h>
2 #include <errno.h>
3 #include <net/if.h>
4 #include <strings.h>
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
12 #include "nl80211.h"
13 #include "iw.h"
14
15 static int handle_name(struct nl80211_state *state,
16 struct nl_cb *cb,
17 struct nl_msg *msg,
18 int argc, char **argv,
19 enum id_input id)
20 {
21 if (argc != 1)
22 return 1;
23
24 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
25
26 return 0;
27 nla_put_failure:
28 return -ENOBUFS;
29 }
30 COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
31 "Rename this wireless device.");
32
33 static 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
91 static int handle_freqchan(struct nl_msg *msg, bool chan,
92 int argc, char **argv)
93 {
94 char *end;
95 static const struct {
96 const char *name;
97 unsigned int val;
98 } htmap[] = {
99 { .name = "HT20", .val = NL80211_CHAN_HT20, },
100 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
101 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
102 };
103 unsigned int htval = NL80211_CHAN_NO_HT;
104 unsigned int freq;
105 int i;
106
107 if (!argc || argc > 4)
108 return 1;
109
110 if (!*argv[0])
111 return 1;
112 freq = strtoul(argv[0], &end, 10);
113 if (*end)
114 return 1;
115
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 }
121
122 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
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
137 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
138
139 return 0;
140 nla_put_failure:
141 return -ENOBUFS;
142 }
143
144 static int handle_freq(struct nl80211_state *state,
145 struct nl_cb *cb, 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,
160 struct nl_cb *cb, struct nl_msg *msg,
161 int argc, char **argv,
162 enum id_input id)
163 {
164 return handle_freqchan(msg, true, argc, argv);
165 }
166 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
167 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
168 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
169 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
170
171 static int handle_fragmentation(struct nl80211_state *state,
172 struct nl_cb *cb, struct nl_msg *msg,
173 int argc, char **argv,
174 enum id_input id)
175 {
176 unsigned int frag;
177
178 if (argc != 1)
179 return 1;
180
181 if (strcmp("off", argv[0]) == 0)
182 frag = -1;
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 }
192
193 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
194
195 return 0;
196 nla_put_failure:
197 return -ENOBUFS;
198 }
199 COMMAND(set, frag, "<fragmentation threshold|off>",
200 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
201 "Set fragmentation threshold.");
202
203 static int handle_rts(struct nl80211_state *state,
204 struct nl_cb *cb, struct nl_msg *msg,
205 int argc, char **argv,
206 enum id_input id)
207 {
208 unsigned int rts;
209
210 if (argc != 1)
211 return 1;
212
213 if (strcmp("off", argv[0]) == 0)
214 rts = -1;
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 }
224
225 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
226
227 return 0;
228 nla_put_failure:
229 return -ENOBUFS;
230 }
231 COMMAND(set, rts, "<rts threshold|off>",
232 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
233 "Set rts threshold.");
234
235 static 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 }
295 COMMAND(set, retry, "[short <limit>] [long <limit>]",
296 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_retry,
297 "Set retry limit.");
298
299 static int handle_netns(struct nl80211_state *state,
300 struct nl_cb *cb,
301 struct nl_msg *msg,
302 int argc, char **argv,
303 enum id_input id)
304 {
305 char *end;
306
307 if (argc != 1)
308 return 1;
309
310 if (!*argv[0])
311 return 1;
312
313 NLA_PUT_U32(msg, NL80211_ATTR_PID,
314 strtoul(argv[0], &end, 10));
315
316 if (*end != '\0')
317 return 1;
318
319 return 0;
320 nla_put_failure:
321 return -ENOBUFS;
322 }
323 COMMAND(set, netns, "<pid>",
324 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
325 "Put this wireless device into a different network namespace");
326
327 static int handle_coverage(struct nl80211_state *state,
328 struct nl_cb *cb,
329 struct nl_msg *msg,
330 int argc, char **argv,
331 enum id_input id)
332 {
333 char *end;
334 unsigned int coverage;
335
336 if (argc != 1)
337 return 1;
338
339 if (!*argv[0])
340 return 1;
341 coverage = strtoul(argv[0], &end, 10);
342 if (coverage > 255)
343 return 1;
344
345 if (*end)
346 return 1;
347
348 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
349
350 return 0;
351 nla_put_failure:
352 return -ENOBUFS;
353 }
354 COMMAND(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
359 static int handle_distance(struct nl80211_state *state,
360 struct nl_cb *cb,
361 struct nl_msg *msg,
362 int argc, char **argv,
363 enum id_input id)
364 {
365 if (argc != 1)
366 return 1;
367
368 if (!*argv[0])
369 return 1;
370
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;
376
377 distance = strtoul(argv[0], &end, 10);
378
379 if (*end)
380 return 1;
381
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 }
395
396 return 0;
397 nla_put_failure:
398 return -ENOBUFS;
399 }
400 COMMAND(set, distance, "<auto|distance>",
401 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
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"
405 "Valid values: 0 - 114750");
406
407 static int handle_txpower(struct nl80211_state *state,
408 struct nl_cb *cb,
409 struct nl_msg *msg,
410 int argc, char **argv,
411 enum id_input id)
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) {
434 char *endptr;
435 if (argc != 2) {
436 printf("Missing TX power level argument.\n");
437 return 2;
438 }
439
440 mbm = strtol(argv[1], &endptr, 10);
441 if (*endptr)
442 return 2;
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 }
452 COMMAND(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.");
455 COMMAND(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.");
458
459 static int handle_antenna(struct nl80211_state *state,
460 struct nl_cb *cb,
461 struct nl_msg *msg,
462 int argc, char **argv,
463 enum id_input id)
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 }
494 COMMAND(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.");