blob: aab462d2ed41b0285b5aef56b4cae09ace580d54 [file] [log] [blame]
Johannes Berg379f8392008-12-08 12:53:58 +01001#include <stdbool.h>
Johannes Berg0f55e0b2008-09-16 17:40:48 +02002#include <errno.h>
Johannes Berg0f55e0b2008-09-16 17:40:48 +02003#include <net/if.h>
Johannes Bergd0260392010-09-22 11:33:28 +02004#include <strings.h>
Johannes Berg0f55e0b2008-09-16 17:40:48 +02005
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
Johannes Bergf408e012008-09-18 19:32:11 +020012#include "nl80211.h"
Johannes Berg0f55e0b2008-09-16 17:40:48 +020013#include "iw.h"
14
Johannes Berg7c37a242009-04-08 13:13:28 +020015static int handle_name(struct nl80211_state *state,
16 struct nl_cb *cb,
Johannes Berg0f55e0b2008-09-16 17:40:48 +020017 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +020018 int argc, char **argv,
19 enum id_input id)
Johannes Berg0f55e0b2008-09-16 17:40:48 +020020{
Johannes Berg0f55e0b2008-09-16 17:40:48 +020021 if (argc != 1)
Johannes Berg5e75fd02008-09-16 18:13:12 +020022 return 1;
Johannes Berg0f55e0b2008-09-16 17:40:48 +020023
24 NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, *argv);
25
Johannes Berg70391cc2008-09-16 18:35:06 +020026 return 0;
Johannes Berg0f55e0b2008-09-16 17:40:48 +020027 nla_put_failure:
Johannes Berg70391cc2008-09-16 18:35:06 +020028 return -ENOBUFS;
Johannes Berg0f55e0b2008-09-16 17:40:48 +020029}
Johannes Bergcea8fa12009-05-05 15:05:10 +020030COMMAND(set, name, "<new name>", NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_name,
31 "Rename this wireless device.");
Johannes Bergb822cda2008-12-08 12:43:42 +010032
Johannes Berg7c60bb72012-11-20 16:52:12 +010033static 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
Johannes Berg379f8392008-12-08 12:53:58 +010091static int handle_freqchan(struct nl_msg *msg, bool chan,
92 int argc, char **argv)
Johannes Bergb822cda2008-12-08 12:43:42 +010093{
Johannes Berge86b7e02010-04-01 18:49:21 +020094 char *end;
Johannes Bergb822cda2008-12-08 12:43:42 +010095 static const struct {
96 const char *name;
97 unsigned int val;
98 } htmap[] = {
Johannes Berg68632dc2008-12-12 22:40:45 +010099 { .name = "HT20", .val = NL80211_CHAN_HT20, },
100 { .name = "HT40+", .val = NL80211_CHAN_HT40PLUS, },
101 { .name = "HT40-", .val = NL80211_CHAN_HT40MINUS, },
Johannes Bergb822cda2008-12-08 12:43:42 +0100102 };
Johannes Berg68632dc2008-12-12 22:40:45 +0100103 unsigned int htval = NL80211_CHAN_NO_HT;
Johannes Bergb822cda2008-12-08 12:43:42 +0100104 unsigned int freq;
105 int i;
106
Johannes Berg7c60bb72012-11-20 16:52:12 +0100107 if (!argc || argc > 4)
Johannes Bergb822cda2008-12-08 12:43:42 +0100108 return 1;
109
Johannes Berge86b7e02010-04-01 18:49:21 +0200110 if (!*argv[0])
111 return 1;
112 freq = strtoul(argv[0], &end, 10);
113 if (*end)
114 return 1;
115
Bruno Randolf58b46da2013-09-26 17:45:45 +0100116 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 }
Johannes Bergb822cda2008-12-08 12:43:42 +0100121
122 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
Johannes Berg7c60bb72012-11-20 16:52:12 +0100123
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
Johannes Berg68632dc2008-12-12 22:40:45 +0100137 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
Johannes Bergb822cda2008-12-08 12:43:42 +0100138
139 return 0;
140 nla_put_failure:
141 return -ENOBUFS;
142}
Johannes Berg379f8392008-12-08 12:53:58 +0100143
Johannes Berg7c37a242009-04-08 13:13:28 +0200144static int handle_freq(struct nl80211_state *state,
145 struct nl_cb *cb, struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200146 int argc, char **argv,
147 enum id_input id)
Johannes Berg379f8392008-12-08 12:53:58 +0100148{
149 return handle_freqchan(msg, false, argc, argv);
150}
Johannes Bergb822cda2008-12-08 12:43:42 +0100151COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
Johannes Berg00c448b2009-05-05 15:04:19 +0200152 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
153 "Set frequency/channel the hardware is using, including HT\n"
154 "configuration.");
Johannes Berg7c60bb72012-11-20 16:52:12 +0100155COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n"
156 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200157 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
Johannes Berg379f8392008-12-08 12:53:58 +0100158
Johannes Berg7c37a242009-04-08 13:13:28 +0200159static int handle_chan(struct nl80211_state *state,
160 struct nl_cb *cb, struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200161 int argc, char **argv,
162 enum id_input id)
Johannes Berg379f8392008-12-08 12:53:58 +0100163{
164 return handle_freqchan(msg, true, argc, argv);
165}
166COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200167 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
Johannes Berg379f8392008-12-08 12:53:58 +0100168COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
Johannes Berg01ae06f2009-05-05 14:48:16 +0200169 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
Johannes Berg625aa4a2009-08-11 11:26:42 +0200170
171static int handle_fragmentation(struct nl80211_state *state,
172 struct nl_cb *cb, struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200173 int argc, char **argv,
174 enum id_input id)
Johannes Berg625aa4a2009-08-11 11:26:42 +0200175{
176 unsigned int frag;
177
178 if (argc != 1)
179 return 1;
180
181 if (strcmp("off", argv[0]) == 0)
182 frag = -1;
Johannes Berge86b7e02010-04-01 18:49:21 +0200183 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 }
Johannes Berg625aa4a2009-08-11 11:26:42 +0200192
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,
Johannes Berg05514f92012-07-19 11:50:50 +0200205 int argc, char **argv,
206 enum id_input id)
Johannes Berg625aa4a2009-08-11 11:26:42 +0200207{
208 unsigned int rts;
209
210 if (argc != 1)
211 return 1;
212
213 if (strcmp("off", argv[0]) == 0)
214 rts = -1;
Johannes Berge86b7e02010-04-01 18:49:21 +0200215 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 }
Johannes Berg625aa4a2009-08-11 11:26:42 +0200224
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.");
Johannes Berge960e062009-09-24 20:18:47 +0200234
Ujjal Royc993e6e2014-03-07 12:23:38 +0530235static 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
Johannes Berge960e062009-09-24 20:18:47 +0200299static int handle_netns(struct nl80211_state *state,
300 struct nl_cb *cb,
301 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200302 int argc, char **argv,
303 enum id_input id)
Johannes Berge960e062009-09-24 20:18:47 +0200304{
305 char *end;
306
307 if (argc != 1)
308 return 1;
309
Johannes Berge86b7e02010-04-01 18:49:21 +0200310 if (!*argv[0])
311 return 1;
312
Johannes Berge960e062009-09-24 20:18:47 +0200313 NLA_PUT_U32(msg, NL80211_ATTR_PID,
Johannes Bergc5514492011-12-07 09:08:40 +0100314 strtoul(argv[0], &end, 10));
Johannes Berge960e062009-09-24 20:18:47 +0200315
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");
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500326
327static int handle_coverage(struct nl80211_state *state,
328 struct nl_cb *cb,
329 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200330 int argc, char **argv,
331 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500332{
Johannes Berge86b7e02010-04-01 18:49:21 +0200333 char *end;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500334 unsigned int coverage;
335
336 if (argc != 1)
337 return 1;
338
Johannes Berge86b7e02010-04-01 18:49:21 +0200339 if (!*argv[0])
340 return 1;
341 coverage = strtoul(argv[0], &end, 10);
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500342 if (coverage > 255)
343 return 1;
344
Johannes Berge86b7e02010-04-01 18:49:21 +0200345 if (*end)
346 return 1;
347
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500348 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,
Johannes Berg05514f92012-07-19 11:50:50 +0200362 int argc, char **argv,
363 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500364{
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500365 if (argc != 1)
366 return 1;
367
Johannes Berge86b7e02010-04-01 18:49:21 +0200368 if (!*argv[0])
369 return 1;
370
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200371 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;
Johannes Berge86b7e02010-04-01 18:49:21 +0200376
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200377 distance = strtoul(argv[0], &end, 10);
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500378
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200379 if (*end)
380 return 1;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500381
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200382 /*
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 }
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500395
396 return 0;
397 nla_put_failure:
398 return -ENOBUFS;
399}
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200400COMMAND(set, distance, "<auto|distance>",
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500401 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
Lorenzo Bianconie6421422014-09-07 19:32:20 +0200402 "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"
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500405 "Valid values: 0 - 114750");
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300406
407static int handle_txpower(struct nl80211_state *state,
408 struct nl_cb *cb,
409 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200410 int argc, char **argv,
411 enum id_input id)
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300412{
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) {
Johannes Berg18e05612011-04-28 19:41:04 +0200434 char *endptr;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300435 if (argc != 2) {
436 printf("Missing TX power level argument.\n");
437 return 2;
438 }
439
Johannes Berg18e05612011-04-28 19:41:04 +0200440 mbm = strtol(argv[1], &endptr, 10);
Felix Fietkau08ec4c62011-11-07 18:49:51 +0100441 if (*endptr)
Johannes Berg18e05612011-04-28 19:41:04 +0200442 return 2;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300443 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.");
Bruno Randolfafce7982010-12-22 10:54:39 +0900458
459static int handle_antenna(struct nl80211_state *state,
460 struct nl_cb *cb,
461 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200462 int argc, char **argv,
463 enum id_input id)
Bruno Randolfafce7982010-12-22 10:54:39 +0900464{
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.");