]> git.ipfire.org Git - thirdparty/iw.git/blame - phy.c
iw: handle DFS CAC time param
[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{
e86b7e02 365 char *end;
b2f92dd0
LT
366 unsigned int distance, coverage;
367
368 if (argc != 1)
369 return 1;
370
e86b7e02
JB
371 if (!*argv[0])
372 return 1;
373
374 distance = strtoul(argv[0], &end, 10);
375
376 if (*end)
377 return 1;
b2f92dd0
LT
378
379 /*
380 * Divide double the distance by the speed of light in m/usec (300) to
381 * get round-trip time in microseconds and then divide the result by
382 * three to get coverage class as specified in IEEE 802.11-2007 table
383 * 7-27. Values are rounded upwards.
384 */
385 coverage = (distance + 449) / 450;
386 if (coverage > 255)
387 return 1;
388
389 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
390
391 return 0;
392 nla_put_failure:
393 return -ENOBUFS;
394}
395COMMAND(set, distance, "<distance>",
396 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
397 "Set appropriate coverage class for given link distance in meters.\n"
398 "Valid values: 0 - 114750");
a0b1f574
JO
399
400static int handle_txpower(struct nl80211_state *state,
401 struct nl_cb *cb,
402 struct nl_msg *msg,
05514f95
JB
403 int argc, char **argv,
404 enum id_input id)
a0b1f574
JO
405{
406 enum nl80211_tx_power_setting type;
407 int mbm;
408
409 /* get the required args */
410 if (argc != 1 && argc != 2)
411 return 1;
412
413 if (!strcmp(argv[0], "auto"))
414 type = NL80211_TX_POWER_AUTOMATIC;
415 else if (!strcmp(argv[0], "fixed"))
416 type = NL80211_TX_POWER_FIXED;
417 else if (!strcmp(argv[0], "limit"))
418 type = NL80211_TX_POWER_LIMITED;
419 else {
420 printf("Invalid parameter: %s\n", argv[0]);
421 return 2;
422 }
423
424 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
425
426 if (type != NL80211_TX_POWER_AUTOMATIC) {
18e05613 427 char *endptr;
a0b1f574
JO
428 if (argc != 2) {
429 printf("Missing TX power level argument.\n");
430 return 2;
431 }
432
18e05613 433 mbm = strtol(argv[1], &endptr, 10);
08ec4c6b 434 if (*endptr)
18e05613 435 return 2;
a0b1f574
JO
436 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
437 } else if (argc != 1)
438 return 1;
439
440 return 0;
441
442 nla_put_failure:
443 return -ENOBUFS;
444}
445COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
446 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
447 "Specify transmit power level and setting type.");
448COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
449 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
450 "Specify transmit power level and setting type.");
afce7986
BR
451
452static int handle_antenna(struct nl80211_state *state,
453 struct nl_cb *cb,
454 struct nl_msg *msg,
05514f95
JB
455 int argc, char **argv,
456 enum id_input id)
afce7986
BR
457{
458 char *end;
459 uint32_t tx_ant = 0, rx_ant = 0;
460
461 if (argc == 1 && strcmp(argv[0], "all") == 0) {
462 tx_ant = 0xffffffff;
463 rx_ant = 0xffffffff;
464 } else if (argc == 1) {
465 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
466 if (*end)
467 return 1;
468 }
469 else if (argc == 2) {
470 tx_ant = strtoul(argv[0], &end, 0);
471 if (*end)
472 return 1;
473 rx_ant = strtoul(argv[1], &end, 0);
474 if (*end)
475 return 1;
476 } else
477 return 1;
478
479 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
480 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
481
482 return 0;
483
484 nla_put_failure:
485 return -ENOBUFS;
486}
487COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
488 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
489 "Set a bitmap of allowed antennas to use for TX and RX.\n"
490 "The driver may reject antenna configurations it cannot support.");