blob: 68f40f6faefcc1f59591b2f764c699582940f1ab [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
235static int handle_netns(struct nl80211_state *state,
236 struct nl_cb *cb,
237 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200238 int argc, char **argv,
239 enum id_input id)
Johannes Berge960e062009-09-24 20:18:47 +0200240{
241 char *end;
242
243 if (argc != 1)
244 return 1;
245
Johannes Berge86b7e02010-04-01 18:49:21 +0200246 if (!*argv[0])
247 return 1;
248
Johannes Berge960e062009-09-24 20:18:47 +0200249 NLA_PUT_U32(msg, NL80211_ATTR_PID,
Johannes Bergc5514492011-12-07 09:08:40 +0100250 strtoul(argv[0], &end, 10));
Johannes Berge960e062009-09-24 20:18:47 +0200251
252 if (*end != '\0')
253 return 1;
254
255 return 0;
256 nla_put_failure:
257 return -ENOBUFS;
258}
259COMMAND(set, netns, "<pid>",
260 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
261 "Put this wireless device into a different network namespace");
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500262
263static int handle_coverage(struct nl80211_state *state,
264 struct nl_cb *cb,
265 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200266 int argc, char **argv,
267 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500268{
Johannes Berge86b7e02010-04-01 18:49:21 +0200269 char *end;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500270 unsigned int coverage;
271
272 if (argc != 1)
273 return 1;
274
Johannes Berge86b7e02010-04-01 18:49:21 +0200275 if (!*argv[0])
276 return 1;
277 coverage = strtoul(argv[0], &end, 10);
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500278 if (coverage > 255)
279 return 1;
280
Johannes Berge86b7e02010-04-01 18:49:21 +0200281 if (*end)
282 return 1;
283
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500284 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
285
286 return 0;
287 nla_put_failure:
288 return -ENOBUFS;
289}
290COMMAND(set, coverage, "<coverage class>",
291 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
292 "Set coverage class (1 for every 3 usec of air propagation time).\n"
293 "Valid values: 0 - 255.");
294
295static int handle_distance(struct nl80211_state *state,
296 struct nl_cb *cb,
297 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200298 int argc, char **argv,
299 enum id_input id)
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500300{
Johannes Berge86b7e02010-04-01 18:49:21 +0200301 char *end;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500302 unsigned int distance, coverage;
303
304 if (argc != 1)
305 return 1;
306
Johannes Berge86b7e02010-04-01 18:49:21 +0200307 if (!*argv[0])
308 return 1;
309
310 distance = strtoul(argv[0], &end, 10);
311
312 if (*end)
313 return 1;
Lukáš Turekb2f92dd2010-02-17 21:13:23 -0500314
315 /*
316 * Divide double the distance by the speed of light in m/usec (300) to
317 * get round-trip time in microseconds and then divide the result by
318 * three to get coverage class as specified in IEEE 802.11-2007 table
319 * 7-27. Values are rounded upwards.
320 */
321 coverage = (distance + 449) / 450;
322 if (coverage > 255)
323 return 1;
324
325 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
326
327 return 0;
328 nla_put_failure:
329 return -ENOBUFS;
330}
331COMMAND(set, distance, "<distance>",
332 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
333 "Set appropriate coverage class for given link distance in meters.\n"
334 "Valid values: 0 - 114750");
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300335
336static int handle_txpower(struct nl80211_state *state,
337 struct nl_cb *cb,
338 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200339 int argc, char **argv,
340 enum id_input id)
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300341{
342 enum nl80211_tx_power_setting type;
343 int mbm;
344
345 /* get the required args */
346 if (argc != 1 && argc != 2)
347 return 1;
348
349 if (!strcmp(argv[0], "auto"))
350 type = NL80211_TX_POWER_AUTOMATIC;
351 else if (!strcmp(argv[0], "fixed"))
352 type = NL80211_TX_POWER_FIXED;
353 else if (!strcmp(argv[0], "limit"))
354 type = NL80211_TX_POWER_LIMITED;
355 else {
356 printf("Invalid parameter: %s\n", argv[0]);
357 return 2;
358 }
359
360 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
361
362 if (type != NL80211_TX_POWER_AUTOMATIC) {
Johannes Berg18e05612011-04-28 19:41:04 +0200363 char *endptr;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300364 if (argc != 2) {
365 printf("Missing TX power level argument.\n");
366 return 2;
367 }
368
Johannes Berg18e05612011-04-28 19:41:04 +0200369 mbm = strtol(argv[1], &endptr, 10);
Felix Fietkau08ec4c62011-11-07 18:49:51 +0100370 if (*endptr)
Johannes Berg18e05612011-04-28 19:41:04 +0200371 return 2;
Juuso Oikarinena0b1f572010-06-23 12:12:57 +0300372 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
373 } else if (argc != 1)
374 return 1;
375
376 return 0;
377
378 nla_put_failure:
379 return -ENOBUFS;
380}
381COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
382 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
383 "Specify transmit power level and setting type.");
384COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
385 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
386 "Specify transmit power level and setting type.");
Bruno Randolfafce7982010-12-22 10:54:39 +0900387
388static int handle_antenna(struct nl80211_state *state,
389 struct nl_cb *cb,
390 struct nl_msg *msg,
Johannes Berg05514f92012-07-19 11:50:50 +0200391 int argc, char **argv,
392 enum id_input id)
Bruno Randolfafce7982010-12-22 10:54:39 +0900393{
394 char *end;
395 uint32_t tx_ant = 0, rx_ant = 0;
396
397 if (argc == 1 && strcmp(argv[0], "all") == 0) {
398 tx_ant = 0xffffffff;
399 rx_ant = 0xffffffff;
400 } else if (argc == 1) {
401 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
402 if (*end)
403 return 1;
404 }
405 else if (argc == 2) {
406 tx_ant = strtoul(argv[0], &end, 0);
407 if (*end)
408 return 1;
409 rx_ant = strtoul(argv[1], &end, 0);
410 if (*end)
411 return 1;
412 } else
413 return 1;
414
415 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
416 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
417
418 return 0;
419
420 nla_put_failure:
421 return -ENOBUFS;
422}
423COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
424 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
425 "Set a bitmap of allowed antennas to use for TX and RX.\n"
426 "The driver may reject antenna configurations it cannot support.");