nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | #include <net/if.h> |
2 | #include <errno.h> |
||
3 | #include <string.h> |
||
4 | #include <stdbool.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 | #define VALID_FLAGS "none: no special flags\n"\ |
||
16 | "fcsfail: show frames with FCS errors\n"\ |
||
17 | "control: show control frames\n"\ |
||
18 | "otherbss: show frames from other BSSes\n"\ |
||
19 | "cook: use cooked mode\n"\ |
||
20 | "active: use active mode (ACK incoming unicast packets)" |
||
21 | |||
22 | SECTION(interface); |
||
23 | |||
24 | static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = { |
||
25 | "none", |
||
26 | "fcsfail", |
||
27 | "plcpfail", |
||
28 | "control", |
||
29 | "otherbss", |
||
30 | "cook", |
||
31 | "active", |
||
32 | }; |
||
33 | |||
34 | static int parse_mntr_flags(int *_argc, char ***_argv, |
||
35 | struct nl_msg *msg) |
||
36 | { |
||
37 | struct nl_msg *flags; |
||
38 | int err = -ENOBUFS; |
||
39 | enum nl80211_mntr_flags flag; |
||
40 | int argc = *_argc; |
||
41 | char **argv = *_argv; |
||
42 | |||
43 | flags = nlmsg_alloc(); |
||
44 | if (!flags) |
||
45 | return -ENOMEM; |
||
46 | |||
47 | while (argc) { |
||
48 | int ok = 0; |
||
49 | for (flag = __NL80211_MNTR_FLAG_INVALID; |
||
50 | flag <= NL80211_MNTR_FLAG_MAX; flag++) { |
||
51 | if (strcmp(*argv, mntr_flags[flag]) == 0) { |
||
52 | ok = 1; |
||
53 | /* |
||
54 | * This shouldn't be adding "flag" if that is |
||
55 | * zero, but due to a problem in the kernel's |
||
56 | * nl80211 code (using NLA_NESTED policy) it |
||
57 | * will reject an empty nested attribute but |
||
58 | * not one that contains an invalid attribute |
||
59 | */ |
||
60 | NLA_PUT_FLAG(flags, flag); |
||
61 | break; |
||
62 | } |
||
63 | } |
||
64 | if (!ok) { |
||
65 | err = -EINVAL; |
||
66 | goto out; |
||
67 | } |
||
68 | argc--; |
||
69 | argv++; |
||
70 | } |
||
71 | |||
72 | nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); |
||
73 | err = 0; |
||
74 | nla_put_failure: |
||
75 | out: |
||
76 | nlmsg_free(flags); |
||
77 | |||
78 | *_argc = argc; |
||
79 | *_argv = argv; |
||
80 | |||
81 | return err; |
||
82 | } |
||
83 | |||
84 | /* for help */ |
||
85 | #define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds." |
||
86 | |||
87 | /* return 0 if ok, internal error otherwise */ |
||
88 | static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type, |
||
89 | bool need_type) |
||
90 | { |
||
91 | char *tpstr; |
||
92 | |||
93 | if (*argc < 1 + !!need_type) |
||
94 | return 1; |
||
95 | |||
96 | if (need_type && strcmp((*argv)[0], "type")) |
||
97 | return 1; |
||
98 | |||
99 | tpstr = (*argv)[!!need_type]; |
||
100 | *argc -= 1 + !!need_type; |
||
101 | *argv += 1 + !!need_type; |
||
102 | |||
103 | if (strcmp(tpstr, "adhoc") == 0 || |
||
104 | strcmp(tpstr, "ibss") == 0) { |
||
105 | *type = NL80211_IFTYPE_ADHOC; |
||
106 | return 0; |
||
107 | } else if (strcmp(tpstr, "ocb") == 0) { |
||
108 | *type = NL80211_IFTYPE_OCB; |
||
109 | return 0; |
||
110 | } else if (strcmp(tpstr, "monitor") == 0) { |
||
111 | *type = NL80211_IFTYPE_MONITOR; |
||
112 | return 0; |
||
113 | } else if (strcmp(tpstr, "master") == 0 || |
||
114 | strcmp(tpstr, "ap") == 0) { |
||
115 | *type = NL80211_IFTYPE_UNSPECIFIED; |
||
116 | fprintf(stderr, "You need to run a management daemon, e.g. hostapd,\n"); |
||
117 | fprintf(stderr, "see http://wireless.kernel.org/en/users/Documentation/hostapd\n"); |
||
118 | fprintf(stderr, "for more information on how to do that.\n"); |
||
119 | return 2; |
||
120 | } else if (strcmp(tpstr, "__ap") == 0) { |
||
121 | *type = NL80211_IFTYPE_AP; |
||
122 | return 0; |
||
123 | } else if (strcmp(tpstr, "__ap_vlan") == 0) { |
||
124 | *type = NL80211_IFTYPE_AP_VLAN; |
||
125 | return 0; |
||
126 | } else if (strcmp(tpstr, "wds") == 0) { |
||
127 | *type = NL80211_IFTYPE_WDS; |
||
128 | return 0; |
||
129 | } else if (strcmp(tpstr, "managed") == 0 || |
||
130 | strcmp(tpstr, "mgd") == 0 || |
||
131 | strcmp(tpstr, "station") == 0) { |
||
132 | *type = NL80211_IFTYPE_STATION; |
||
133 | return 0; |
||
134 | } else if (strcmp(tpstr, "mp") == 0 || |
||
135 | strcmp(tpstr, "mesh") == 0) { |
||
136 | *type = NL80211_IFTYPE_MESH_POINT; |
||
137 | return 0; |
||
138 | } else if (strcmp(tpstr, "__p2pcl") == 0) { |
||
139 | *type = NL80211_IFTYPE_P2P_CLIENT; |
||
140 | return 0; |
||
141 | } else if (strcmp(tpstr, "__p2pdev") == 0) { |
||
142 | *type = NL80211_IFTYPE_P2P_DEVICE; |
||
143 | return 0; |
||
144 | } else if (strcmp(tpstr, "__p2pgo") == 0) { |
||
145 | *type = NL80211_IFTYPE_P2P_GO; |
||
146 | return 0; |
||
147 | } |
||
148 | |||
149 | fprintf(stderr, "invalid interface type %s\n", tpstr); |
||
150 | return 2; |
||
151 | } |
||
152 | |||
153 | static int parse_4addr_flag(const char *value, struct nl_msg *msg) |
||
154 | { |
||
155 | if (strcmp(value, "on") == 0) |
||
156 | NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1); |
||
157 | else if (strcmp(value, "off") == 0) |
||
158 | NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0); |
||
159 | else |
||
160 | return 1; |
||
161 | return 0; |
||
162 | |||
163 | nla_put_failure: |
||
164 | return 1; |
||
165 | } |
||
166 | |||
167 | static int handle_interface_add(struct nl80211_state *state, |
||
168 | struct nl_cb *cb, |
||
169 | struct nl_msg *msg, |
||
170 | int argc, char **argv, |
||
171 | enum id_input id) |
||
172 | { |
||
173 | char *name; |
||
174 | char *mesh_id = NULL; |
||
175 | enum nl80211_iftype type; |
||
176 | int tpset; |
||
177 | unsigned char mac_addr[ETH_ALEN]; |
||
178 | int found_mac = 0; |
||
179 | |||
180 | if (argc < 1) |
||
181 | return 1; |
||
182 | |||
183 | name = argv[0]; |
||
184 | argc--; |
||
185 | argv++; |
||
186 | |||
187 | tpset = get_if_type(&argc, &argv, &type, true); |
||
188 | if (tpset) |
||
189 | return tpset; |
||
190 | |||
191 | try_another: |
||
192 | if (argc) { |
||
193 | if (strcmp(argv[0], "mesh_id") == 0) { |
||
194 | argc--; |
||
195 | argv++; |
||
196 | |||
197 | if (!argc) |
||
198 | return 1; |
||
199 | mesh_id = argv[0]; |
||
200 | argc--; |
||
201 | argv++; |
||
202 | } else if (strcmp(argv[0], "addr") == 0) { |
||
203 | argc--; |
||
204 | argv++; |
||
205 | if (mac_addr_a2n(mac_addr, argv[0])) { |
||
206 | fprintf(stderr, "Invalid MAC address\n"); |
||
207 | return 2; |
||
208 | } |
||
209 | argc--; |
||
210 | argv++; |
||
211 | found_mac = 1; |
||
212 | goto try_another; |
||
213 | } else if (strcmp(argv[0], "4addr") == 0) { |
||
214 | argc--; |
||
215 | argv++; |
||
216 | if (parse_4addr_flag(argv[0], msg)) { |
||
217 | fprintf(stderr, "4addr error\n"); |
||
218 | return 2; |
||
219 | } |
||
220 | argc--; |
||
221 | argv++; |
||
222 | } else if (strcmp(argv[0], "flags") == 0) { |
||
223 | argc--; |
||
224 | argv++; |
||
225 | if (parse_mntr_flags(&argc, &argv, msg)) { |
||
226 | fprintf(stderr, "flags error\n"); |
||
227 | return 2; |
||
228 | } |
||
229 | } else { |
||
230 | return 1; |
||
231 | } |
||
232 | } |
||
233 | |||
234 | if (argc) |
||
235 | return 1; |
||
236 | |||
237 | NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name); |
||
238 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); |
||
239 | if (mesh_id) |
||
240 | NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); |
||
241 | if (found_mac) |
||
242 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
||
243 | |||
244 | return 0; |
||
245 | nla_put_failure: |
||
246 | return -ENOBUFS; |
||
247 | } |
||
248 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]", |
||
249 | NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add, |
||
250 | "Add a new virtual interface with the given configuration.\n" |
||
251 | IFACE_TYPES "\n\n" |
||
252 | "The flags are only used for monitor interfaces, valid flags are:\n" |
||
253 | VALID_FLAGS "\n\n" |
||
254 | "The mesh_id is used only for mesh mode."); |
||
255 | COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] [addr <mac-addr>]", |
||
256 | NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL); |
||
257 | |||
258 | static int handle_interface_del(struct nl80211_state *state, |
||
259 | struct nl_cb *cb, |
||
260 | struct nl_msg *msg, |
||
261 | int argc, char **argv, |
||
262 | enum id_input id) |
||
263 | { |
||
264 | return 0; |
||
265 | } |
||
266 | TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del, |
||
267 | "Remove this virtual interface"); |
||
268 | HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del); |
||
269 | |||
270 | static char *channel_type_name(enum nl80211_channel_type channel_type) |
||
271 | { |
||
272 | switch (channel_type) { |
||
273 | case NL80211_CHAN_NO_HT: |
||
274 | return "NO HT"; |
||
275 | case NL80211_CHAN_HT20: |
||
276 | return "HT20"; |
||
277 | case NL80211_CHAN_HT40MINUS: |
||
278 | return "HT40-"; |
||
279 | case NL80211_CHAN_HT40PLUS: |
||
280 | return "HT40+"; |
||
281 | default: |
||
282 | return "unknown"; |
||
283 | } |
||
284 | } |
||
285 | |||
286 | char *channel_width_name(enum nl80211_chan_width width) |
||
287 | { |
||
288 | switch (width) { |
||
289 | case NL80211_CHAN_WIDTH_20_NOHT: |
||
290 | return "20 MHz (no HT)"; |
||
291 | case NL80211_CHAN_WIDTH_20: |
||
292 | return "20 MHz"; |
||
293 | case NL80211_CHAN_WIDTH_40: |
||
294 | return "40 MHz"; |
||
295 | case NL80211_CHAN_WIDTH_80: |
||
296 | return "80 MHz"; |
||
297 | case NL80211_CHAN_WIDTH_80P80: |
||
298 | return "80+80 MHz"; |
||
299 | case NL80211_CHAN_WIDTH_160: |
||
300 | return "160 MHz"; |
||
301 | default: |
||
302 | return "unknown"; |
||
303 | } |
||
304 | } |
||
305 | |||
306 | static int print_iface_handler(struct nl_msg *msg, void *arg) |
||
307 | { |
||
308 | struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); |
||
309 | struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; |
||
310 | unsigned int *wiphy = arg; |
||
311 | const char *indent = ""; |
||
312 | |||
313 | nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), |
||
314 | genlmsg_attrlen(gnlh, 0), NULL); |
||
315 | |||
316 | if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) { |
||
317 | unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]); |
||
318 | indent = "\t"; |
||
319 | if (*wiphy != thiswiphy) |
||
320 | printf("phy#%d\n", thiswiphy); |
||
321 | *wiphy = thiswiphy; |
||
322 | } |
||
323 | |||
324 | if (tb_msg[NL80211_ATTR_IFNAME]) |
||
325 | printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME])); |
||
326 | else |
||
327 | printf("%sUnnamed/non-netdev interface\n", indent); |
||
328 | if (tb_msg[NL80211_ATTR_IFINDEX]) |
||
329 | printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX])); |
||
330 | if (tb_msg[NL80211_ATTR_WDEV]) |
||
331 | printf("%s\twdev 0x%llx\n", indent, |
||
332 | (unsigned long long)nla_get_u64(tb_msg[NL80211_ATTR_WDEV])); |
||
333 | if (tb_msg[NL80211_ATTR_MAC]) { |
||
334 | char mac_addr[20]; |
||
335 | mac_addr_n2a(mac_addr, nla_data(tb_msg[NL80211_ATTR_MAC])); |
||
336 | printf("%s\taddr %s\n", indent, mac_addr); |
||
337 | } |
||
338 | if (tb_msg[NL80211_ATTR_SSID]) { |
||
339 | printf("%s\tssid ", indent); |
||
340 | print_ssid_escaped(nla_len(tb_msg[NL80211_ATTR_SSID]), |
||
341 | nla_data(tb_msg[NL80211_ATTR_SSID])); |
||
342 | printf("\n"); |
||
343 | } |
||
344 | if (tb_msg[NL80211_ATTR_IFTYPE]) |
||
345 | printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE]))); |
||
346 | if (!wiphy && tb_msg[NL80211_ATTR_WIPHY]) |
||
347 | printf("%s\twiphy %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_WIPHY])); |
||
348 | if (tb_msg[NL80211_ATTR_WIPHY_FREQ]) { |
||
349 | uint32_t freq = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_FREQ]); |
||
350 | |||
351 | printf("%s\tchannel %d (%d MHz)", indent, |
||
352 | ieee80211_frequency_to_channel(freq), freq); |
||
353 | |||
354 | if (tb_msg[NL80211_ATTR_CHANNEL_WIDTH]) { |
||
355 | printf(", width: %s", |
||
356 | channel_width_name(nla_get_u32(tb_msg[NL80211_ATTR_CHANNEL_WIDTH]))); |
||
357 | if (tb_msg[NL80211_ATTR_CENTER_FREQ1]) |
||
358 | printf(", center1: %d MHz", |
||
359 | nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ1])); |
||
360 | if (tb_msg[NL80211_ATTR_CENTER_FREQ2]) |
||
361 | printf(", center2: %d MHz", |
||
362 | nla_get_u32(tb_msg[NL80211_ATTR_CENTER_FREQ2])); |
||
363 | } else if (tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { |
||
364 | enum nl80211_channel_type channel_type; |
||
365 | |||
366 | channel_type = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); |
||
367 | printf(" %s", channel_type_name(channel_type)); |
||
368 | } |
||
369 | |||
370 | printf("\n"); |
||
371 | } |
||
372 | |||
373 | return NL_SKIP; |
||
374 | } |
||
375 | |||
376 | static int handle_interface_info(struct nl80211_state *state, |
||
377 | struct nl_cb *cb, |
||
378 | struct nl_msg *msg, |
||
379 | int argc, char **argv, |
||
380 | enum id_input id) |
||
381 | { |
||
382 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL); |
||
383 | return 0; |
||
384 | } |
||
385 | TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info, |
||
386 | "Show information for this interface."); |
||
387 | |||
388 | static int handle_interface_set(struct nl80211_state *state, |
||
389 | struct nl_cb *cb, |
||
390 | struct nl_msg *msg, |
||
391 | int argc, char **argv, |
||
392 | enum id_input id) |
||
393 | { |
||
394 | if (!argc) |
||
395 | return 1; |
||
396 | |||
397 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR); |
||
398 | |||
399 | switch (parse_mntr_flags(&argc, &argv, msg)) { |
||
400 | case 0: |
||
401 | return 0; |
||
402 | case -ENOMEM: |
||
403 | fprintf(stderr, "failed to allocate flags\n"); |
||
404 | return 2; |
||
405 | case -EINVAL: |
||
406 | fprintf(stderr, "unknown flag %s\n", *argv); |
||
407 | return 2; |
||
408 | default: |
||
409 | return 2; |
||
410 | } |
||
411 | nla_put_failure: |
||
412 | return -ENOBUFS; |
||
413 | } |
||
414 | COMMAND(set, monitor, "<flag>*", |
||
415 | NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set, |
||
416 | "Set monitor flags. Valid flags are:\n" |
||
417 | VALID_FLAGS); |
||
418 | |||
419 | static int handle_interface_meshid(struct nl80211_state *state, |
||
420 | struct nl_cb *cb, |
||
421 | struct nl_msg *msg, |
||
422 | int argc, char **argv, |
||
423 | enum id_input id) |
||
424 | { |
||
425 | char *mesh_id = NULL; |
||
426 | |||
427 | if (argc != 1) |
||
428 | return 1; |
||
429 | |||
430 | mesh_id = argv[0]; |
||
431 | |||
432 | NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id); |
||
433 | |||
434 | return 0; |
||
435 | nla_put_failure: |
||
436 | return -ENOBUFS; |
||
437 | } |
||
438 | COMMAND(set, meshid, "<meshid>", |
||
439 | NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL); |
||
440 | |||
441 | static unsigned int dev_dump_wiphy; |
||
442 | |||
443 | static int handle_dev_dump(struct nl80211_state *state, |
||
444 | struct nl_cb *cb, |
||
445 | struct nl_msg *msg, |
||
446 | int argc, char **argv, |
||
447 | enum id_input id) |
||
448 | { |
||
449 | dev_dump_wiphy = -1; |
||
450 | nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, &dev_dump_wiphy); |
||
451 | return 0; |
||
452 | } |
||
453 | TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump, |
||
454 | "List all network interfaces for wireless hardware."); |
||
455 | |||
456 | static int handle_interface_type(struct nl80211_state *state, |
||
457 | struct nl_cb *cb, |
||
458 | struct nl_msg *msg, |
||
459 | int argc, char **argv, |
||
460 | enum id_input id) |
||
461 | { |
||
462 | enum nl80211_iftype type; |
||
463 | int tpset; |
||
464 | |||
465 | tpset = get_if_type(&argc, &argv, &type, false); |
||
466 | if (tpset) |
||
467 | return tpset; |
||
468 | |||
469 | if (argc) |
||
470 | return 1; |
||
471 | |||
472 | NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type); |
||
473 | |||
474 | return 0; |
||
475 | nla_put_failure: |
||
476 | return -ENOBUFS; |
||
477 | } |
||
478 | COMMAND(set, type, "<type>", |
||
479 | NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type, |
||
480 | "Set interface type/mode.\n" |
||
481 | IFACE_TYPES); |
||
482 | |||
483 | static int handle_interface_4addr(struct nl80211_state *state, |
||
484 | struct nl_cb *cb, |
||
485 | struct nl_msg *msg, |
||
486 | int argc, char **argv, |
||
487 | enum id_input id) |
||
488 | { |
||
489 | if (argc != 1) |
||
490 | return 1; |
||
491 | return parse_4addr_flag(argv[0], msg); |
||
492 | } |
||
493 | COMMAND(set, 4addr, "<on|off>", |
||
494 | NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_4addr, |
||
495 | "Set interface 4addr (WDS) mode."); |
||
496 | |||
497 | static int handle_interface_noack_map(struct nl80211_state *state, |
||
498 | struct nl_cb *cb, |
||
499 | struct nl_msg *msg, |
||
500 | int argc, char **argv, |
||
501 | enum id_input id) |
||
502 | { |
||
503 | uint16_t noack_map; |
||
504 | char *end; |
||
505 | |||
506 | if (argc != 1) |
||
507 | return 1; |
||
508 | |||
509 | noack_map = strtoul(argv[0], &end, 16); |
||
510 | if (*end) |
||
511 | return 1; |
||
512 | |||
513 | NLA_PUT_U16(msg, NL80211_ATTR_NOACK_MAP, noack_map); |
||
514 | |||
515 | return 0; |
||
516 | nla_put_failure: |
||
517 | return -ENOBUFS; |
||
518 | |||
519 | } |
||
520 | COMMAND(set, noack_map, "<map>", |
||
521 | NL80211_CMD_SET_NOACK_MAP, 0, CIB_NETDEV, handle_interface_noack_map, |
||
522 | "Set the NoAck map for the TIDs. (0x0009 = BE, 0x0006 = BK, 0x0030 = VI, 0x00C0 = VO)"); |
||
523 | |||
524 | |||
525 | static int handle_interface_wds_peer(struct nl80211_state *state, |
||
526 | struct nl_cb *cb, |
||
527 | struct nl_msg *msg, |
||
528 | int argc, char **argv, |
||
529 | enum id_input id) |
||
530 | { |
||
531 | unsigned char mac_addr[ETH_ALEN]; |
||
532 | |||
533 | if (argc < 1) |
||
534 | return 1; |
||
535 | |||
536 | if (mac_addr_a2n(mac_addr, argv[0])) { |
||
537 | fprintf(stderr, "Invalid MAC address\n"); |
||
538 | return 2; |
||
539 | } |
||
540 | |||
541 | argc--; |
||
542 | argv++; |
||
543 | |||
544 | if (argc) |
||
545 | return 1; |
||
546 | |||
547 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); |
||
548 | |||
549 | return 0; |
||
550 | nla_put_failure: |
||
551 | return -ENOBUFS; |
||
552 | } |
||
553 | COMMAND(set, peer, "<MAC address>", |
||
554 | NL80211_CMD_SET_WDS_PEER, 0, CIB_NETDEV, handle_interface_wds_peer, |
||
555 | "Set interface WDS peer."); |
||
556 | |||
557 | static int set_mcast_rate(struct nl80211_state *state, |
||
558 | struct nl_cb *cb, |
||
559 | struct nl_msg *msg, |
||
560 | int argc, char **argv, |
||
561 | enum id_input id) |
||
562 | { |
||
563 | float rate; |
||
564 | char *end; |
||
565 | |||
566 | if (argc != 1) { |
||
567 | printf("Invalid parameters!\n"); |
||
568 | return 2; |
||
569 | } |
||
570 | |||
571 | rate = strtod(argv[0], &end); |
||
572 | if (*end != '\0') |
||
573 | return 1; |
||
574 | |||
575 | NLA_PUT_U32(msg, NL80211_ATTR_MCAST_RATE, (int)(rate * 10)); |
||
576 | |||
577 | return 0; |
||
578 | nla_put_failure: |
||
579 | return -ENOBUFS; |
||
580 | } |
||
581 | |||
582 | COMMAND(set, mcast_rate, "<rate in Mbps>", |
||
583 | NL80211_CMD_SET_MCAST_RATE, 0, CIB_NETDEV, set_mcast_rate, |
||
584 | "Set the multicast bitrate."); |