]> git.ipfire.org Git - thirdparty/iw.git/blob - phy.c
support TCP wakeup API
[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 freq = ieee80211_channel_to_frequency(freq);
118
119 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
120
121 if (argc > 2) {
122 return handle_freqs(msg, argc - 1, argv + 1);
123 } else if (argc == 2) {
124 for (i = 0; i < ARRAY_SIZE(htmap); i++) {
125 if (strcasecmp(htmap[i].name, argv[1]) == 0) {
126 htval = htmap[i].val;
127 break;
128 }
129 }
130 if (htval == NL80211_CHAN_NO_HT)
131 return handle_freqs(msg, argc - 1, argv + 1);
132 }
133
134 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, htval);
135
136 return 0;
137 nla_put_failure:
138 return -ENOBUFS;
139 }
140
141 static int handle_freq(struct nl80211_state *state,
142 struct nl_cb *cb, struct nl_msg *msg,
143 int argc, char **argv,
144 enum id_input id)
145 {
146 return handle_freqchan(msg, false, argc, argv);
147 }
148 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]",
149 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_freq,
150 "Set frequency/channel the hardware is using, including HT\n"
151 "configuration.");
152 COMMAND(set, freq, "<freq> [HT20|HT40+|HT40-]\n"
153 "<control freq> [20|40|80|80+80|160] [<center freq 1>] [<center freq 2>]",
154 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_freq, NULL);
155
156 static int handle_chan(struct nl80211_state *state,
157 struct nl_cb *cb, struct nl_msg *msg,
158 int argc, char **argv,
159 enum id_input id)
160 {
161 return handle_freqchan(msg, true, argc, argv);
162 }
163 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
164 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_chan, NULL);
165 COMMAND(set, channel, "<channel> [HT20|HT40+|HT40-]",
166 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_chan, NULL);
167
168 static int handle_fragmentation(struct nl80211_state *state,
169 struct nl_cb *cb, struct nl_msg *msg,
170 int argc, char **argv,
171 enum id_input id)
172 {
173 unsigned int frag;
174
175 if (argc != 1)
176 return 1;
177
178 if (strcmp("off", argv[0]) == 0)
179 frag = -1;
180 else {
181 char *end;
182
183 if (!*argv[0])
184 return 1;
185 frag = strtoul(argv[0], &end, 10);
186 if (*end != '\0')
187 return 1;
188 }
189
190 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, frag);
191
192 return 0;
193 nla_put_failure:
194 return -ENOBUFS;
195 }
196 COMMAND(set, frag, "<fragmentation threshold|off>",
197 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_fragmentation,
198 "Set fragmentation threshold.");
199
200 static int handle_rts(struct nl80211_state *state,
201 struct nl_cb *cb, struct nl_msg *msg,
202 int argc, char **argv,
203 enum id_input id)
204 {
205 unsigned int rts;
206
207 if (argc != 1)
208 return 1;
209
210 if (strcmp("off", argv[0]) == 0)
211 rts = -1;
212 else {
213 char *end;
214
215 if (!*argv[0])
216 return 1;
217 rts = strtoul(argv[0], &end, 10);
218 if (*end != '\0')
219 return 1;
220 }
221
222 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, rts);
223
224 return 0;
225 nla_put_failure:
226 return -ENOBUFS;
227 }
228 COMMAND(set, rts, "<rts threshold|off>",
229 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_rts,
230 "Set rts threshold.");
231
232 static int handle_netns(struct nl80211_state *state,
233 struct nl_cb *cb,
234 struct nl_msg *msg,
235 int argc, char **argv,
236 enum id_input id)
237 {
238 char *end;
239
240 if (argc != 1)
241 return 1;
242
243 if (!*argv[0])
244 return 1;
245
246 NLA_PUT_U32(msg, NL80211_ATTR_PID,
247 strtoul(argv[0], &end, 10));
248
249 if (*end != '\0')
250 return 1;
251
252 return 0;
253 nla_put_failure:
254 return -ENOBUFS;
255 }
256 COMMAND(set, netns, "<pid>",
257 NL80211_CMD_SET_WIPHY_NETNS, 0, CIB_PHY, handle_netns,
258 "Put this wireless device into a different network namespace");
259
260 static int handle_coverage(struct nl80211_state *state,
261 struct nl_cb *cb,
262 struct nl_msg *msg,
263 int argc, char **argv,
264 enum id_input id)
265 {
266 char *end;
267 unsigned int coverage;
268
269 if (argc != 1)
270 return 1;
271
272 if (!*argv[0])
273 return 1;
274 coverage = strtoul(argv[0], &end, 10);
275 if (coverage > 255)
276 return 1;
277
278 if (*end)
279 return 1;
280
281 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
282
283 return 0;
284 nla_put_failure:
285 return -ENOBUFS;
286 }
287 COMMAND(set, coverage, "<coverage class>",
288 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_coverage,
289 "Set coverage class (1 for every 3 usec of air propagation time).\n"
290 "Valid values: 0 - 255.");
291
292 static int handle_distance(struct nl80211_state *state,
293 struct nl_cb *cb,
294 struct nl_msg *msg,
295 int argc, char **argv,
296 enum id_input id)
297 {
298 char *end;
299 unsigned int distance, coverage;
300
301 if (argc != 1)
302 return 1;
303
304 if (!*argv[0])
305 return 1;
306
307 distance = strtoul(argv[0], &end, 10);
308
309 if (*end)
310 return 1;
311
312 /*
313 * Divide double the distance by the speed of light in m/usec (300) to
314 * get round-trip time in microseconds and then divide the result by
315 * three to get coverage class as specified in IEEE 802.11-2007 table
316 * 7-27. Values are rounded upwards.
317 */
318 coverage = (distance + 449) / 450;
319 if (coverage > 255)
320 return 1;
321
322 NLA_PUT_U8(msg, NL80211_ATTR_WIPHY_COVERAGE_CLASS, coverage);
323
324 return 0;
325 nla_put_failure:
326 return -ENOBUFS;
327 }
328 COMMAND(set, distance, "<distance>",
329 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_distance,
330 "Set appropriate coverage class for given link distance in meters.\n"
331 "Valid values: 0 - 114750");
332
333 static int handle_txpower(struct nl80211_state *state,
334 struct nl_cb *cb,
335 struct nl_msg *msg,
336 int argc, char **argv,
337 enum id_input id)
338 {
339 enum nl80211_tx_power_setting type;
340 int mbm;
341
342 /* get the required args */
343 if (argc != 1 && argc != 2)
344 return 1;
345
346 if (!strcmp(argv[0], "auto"))
347 type = NL80211_TX_POWER_AUTOMATIC;
348 else if (!strcmp(argv[0], "fixed"))
349 type = NL80211_TX_POWER_FIXED;
350 else if (!strcmp(argv[0], "limit"))
351 type = NL80211_TX_POWER_LIMITED;
352 else {
353 printf("Invalid parameter: %s\n", argv[0]);
354 return 2;
355 }
356
357 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_SETTING, type);
358
359 if (type != NL80211_TX_POWER_AUTOMATIC) {
360 char *endptr;
361 if (argc != 2) {
362 printf("Missing TX power level argument.\n");
363 return 2;
364 }
365
366 mbm = strtol(argv[1], &endptr, 10);
367 if (*endptr)
368 return 2;
369 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_TX_POWER_LEVEL, mbm);
370 } else if (argc != 1)
371 return 1;
372
373 return 0;
374
375 nla_put_failure:
376 return -ENOBUFS;
377 }
378 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
379 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_txpower,
380 "Specify transmit power level and setting type.");
381 COMMAND(set, txpower, "<auto|fixed|limit> [<tx power in mBm>]",
382 NL80211_CMD_SET_WIPHY, 0, CIB_NETDEV, handle_txpower,
383 "Specify transmit power level and setting type.");
384
385 static int handle_antenna(struct nl80211_state *state,
386 struct nl_cb *cb,
387 struct nl_msg *msg,
388 int argc, char **argv,
389 enum id_input id)
390 {
391 char *end;
392 uint32_t tx_ant = 0, rx_ant = 0;
393
394 if (argc == 1 && strcmp(argv[0], "all") == 0) {
395 tx_ant = 0xffffffff;
396 rx_ant = 0xffffffff;
397 } else if (argc == 1) {
398 tx_ant = rx_ant = strtoul(argv[0], &end, 0);
399 if (*end)
400 return 1;
401 }
402 else if (argc == 2) {
403 tx_ant = strtoul(argv[0], &end, 0);
404 if (*end)
405 return 1;
406 rx_ant = strtoul(argv[1], &end, 0);
407 if (*end)
408 return 1;
409 } else
410 return 1;
411
412 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_TX, tx_ant);
413 NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_RX, rx_ant);
414
415 return 0;
416
417 nla_put_failure:
418 return -ENOBUFS;
419 }
420 COMMAND(set, antenna, "<bitmap> | all | <tx bitmap> <rx bitmap>",
421 NL80211_CMD_SET_WIPHY, 0, CIB_PHY, handle_antenna,
422 "Set a bitmap of allowed antennas to use for TX and RX.\n"
423 "The driver may reject antenna configurations it cannot support.");