]> git.ipfire.org Git - thirdparty/iw.git/blame - interface.c
parse supported TX/RX frame types
[thirdparty/iw.git] / interface.c
CommitLineData
2ef1be68 1#include <net/if.h>
45c7212c 2#include <errno.h>
d5ac8ad3 3#include <string.h>
d17fe27e 4#include <stdbool.h>
2ef1be68 5
45c7212c
JB
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>
45c7212c 11
f408e01b 12#include "nl80211.h"
45c7212c
JB
13#include "iw.h"
14
1ae3d621
JB
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"
20
4698bfc2
JB
21SECTION(interface);
22
cd293761 23static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = {
dd65496b 24 "none",
cd293761
JB
25 "fcsfail",
26 "plcpfail",
27 "control",
28 "otherbss",
29 "cook",
30};
31
dd65496b
JB
32static int parse_mntr_flags(int *_argc, char ***_argv,
33 struct nl_msg *msg)
34{
35 struct nl_msg *flags;
36 int err = -ENOBUFS;
37 enum nl80211_mntr_flags flag;
38 int argc = *_argc;
39 char **argv = *_argv;
40
41 flags = nlmsg_alloc();
42 if (!flags)
43 return -ENOMEM;
44
45 while (argc) {
46 int ok = 0;
47 for (flag = __NL80211_MNTR_FLAG_INVALID;
e14cc99e 48 flag <= NL80211_MNTR_FLAG_MAX; flag++) {
dd65496b
JB
49 if (strcmp(*argv, mntr_flags[flag]) == 0) {
50 ok = 1;
4a3bf753
JB
51 /*
52 * This shouldn't be adding "flag" if that is
53 * zero, but due to a problem in the kernel's
54 * nl80211 code (using NLA_NESTED policy) it
55 * will reject an empty nested attribute but
56 * not one that contains an invalid attribute
57 */
dd65496b
JB
58 NLA_PUT_FLAG(flags, flag);
59 break;
60 }
61 }
62 if (!ok) {
63 err = -EINVAL;
64 goto out;
65 }
66 argc--;
67 argv++;
68 }
69
70 nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
71 err = 0;
72 nla_put_failure:
73 out:
74 nlmsg_free(flags);
75
76 *_argc = argc;
77 *_argv = argv;
78
79 return err;
80}
81
1ae3d621
JB
82/* for help */
83#define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds."
84
d17fe27e
JB
85/* return 0 if ok, internal error otherwise */
86static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type,
87 bool need_type)
45c7212c
JB
88{
89 char *tpstr;
90
d17fe27e
JB
91 if (*argc < 1 + !!need_type)
92 return 1;
45c7212c 93
d17fe27e
JB
94 if (need_type && strcmp((*argv)[0], "type"))
95 return 1;
45c7212c 96
d17fe27e
JB
97 tpstr = (*argv)[!!need_type];
98 *argc -= 1 + !!need_type;
99 *argv += 1 + !!need_type;
45c7212c
JB
100
101 if (strcmp(tpstr, "adhoc") == 0 ||
102 strcmp(tpstr, "ibss") == 0) {
103 *type = NL80211_IFTYPE_ADHOC;
d17fe27e 104 return 0;
45c7212c
JB
105 } else if (strcmp(tpstr, "monitor") == 0) {
106 *type = NL80211_IFTYPE_MONITOR;
d17fe27e 107 return 0;
c1d44a6c
JB
108 } else if (strcmp(tpstr, "master") == 0) {
109 *type = NL80211_IFTYPE_UNSPECIFIED;
110 fprintf(stderr, "See http://wireless.kernel.org/RTFM-AP.\n");
111 return 2;
112 } else if (strcmp(tpstr, "ap") == 0) {
113 *type = NL80211_IFTYPE_UNSPECIFIED;
114 fprintf(stderr, "See http://wireless.kernel.org/RTFM-AP.\n");
115 return 2;
4d3a72da 116 } else if (strcmp(tpstr, "__ap") == 0) {
45c7212c 117 *type = NL80211_IFTYPE_AP;
d17fe27e 118 return 0;
4d3a72da 119 } else if (strcmp(tpstr, "__ap_vlan") == 0) {
45c7212c 120 *type = NL80211_IFTYPE_AP_VLAN;
d17fe27e 121 return 0;
45c7212c
JB
122 } else if (strcmp(tpstr, "wds") == 0) {
123 *type = NL80211_IFTYPE_WDS;
d17fe27e 124 return 0;
a65df165
JB
125 } else if (strcmp(tpstr, "managed") == 0 ||
126 strcmp(tpstr, "mgd") == 0 ||
127 strcmp(tpstr, "station") == 0) {
45c7212c 128 *type = NL80211_IFTYPE_STATION;
d17fe27e 129 return 0;
3d1e8704 130 } else if (strcmp(tpstr, "mp") == 0 ||
a65df165 131 strcmp(tpstr, "mesh") == 0) {
3d1e8704 132 *type = NL80211_IFTYPE_MESH_POINT;
d17fe27e 133 return 0;
45c7212c
JB
134 }
135
45c7212c 136 fprintf(stderr, "invalid interface type %s\n", tpstr);
d17fe27e 137 return 2;
45c7212c
JB
138}
139
39566cca
FF
140static int parse_4addr_flag(const char *value, struct nl_msg *msg)
141{
142 if (strcmp(value, "on") == 0)
143 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 1);
144 else if (strcmp(value, "off") == 0)
145 NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, 0);
146 else
147 return 1;
148 return 0;
149
150nla_put_failure:
151 return 1;
152}
153
7c37a24d
JB
154static int handle_interface_add(struct nl80211_state *state,
155 struct nl_cb *cb,
bd396f2a
JB
156 struct nl_msg *msg,
157 int argc, char **argv)
45c7212c 158{
2dfd6bfa 159 char *name;
3d1e8704 160 char *mesh_id = NULL;
45c7212c 161 enum nl80211_iftype type;
70391ccf 162 int tpset;
45c7212c 163
bd396f2a 164 if (argc < 1)
5e75fd04 165 return 1;
45c7212c 166
2dfd6bfa 167 name = argv[0];
45c7212c
JB
168 argc--;
169 argv++;
170
d17fe27e
JB
171 tpset = get_if_type(&argc, &argv, &type, true);
172 if (tpset)
c1d44a6c 173 return tpset;
45c7212c 174
3d1e8704 175 if (argc) {
dd65496b
JB
176 if (strcmp(argv[0], "mesh_id") == 0) {
177 argc--;
178 argv++;
179
180 if (!argc)
181 return 1;
182 mesh_id = argv[0];
183 argc--;
184 argv++;
39566cca
FF
185 } else if (strcmp(argv[0], "4addr") == 0) {
186 argc--;
187 argv++;
188 if (parse_4addr_flag(argv[0], msg)) {
189 fprintf(stderr, "4addr error\n");
190 return 2;
191 }
192 argc--;
193 argv++;
dd65496b
JB
194 } else if (strcmp(argv[0], "flags") == 0) {
195 argc--;
196 argv++;
197 if (parse_mntr_flags(&argc, &argv, msg)) {
198 fprintf(stderr, "flags error\n");
199 return 2;
200 }
201 } else {
5e75fd04 202 return 1;
dd65496b 203 }
3d1e8704
LCC
204 }
205
5e75fd04
JB
206 if (argc)
207 return 1;
45c7212c 208
45c7212c 209 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
6d28ce25 210 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
3d1e8704
LCC
211 if (mesh_id)
212 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id);
45c7212c 213
70391ccf 214 return 0;
5e75fd04 215 nla_put_failure:
70391ccf 216 return -ENOBUFS;
45c7212c 217}
39566cca 218COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*]",
1ae3d621
JB
219 NL80211_CMD_NEW_INTERFACE, 0, CIB_PHY, handle_interface_add,
220 "Add a new virtual interface with the given configuration.\n"
221 IFACE_TYPES "\n\n"
222 "The flags are only used for monitor interfaces, valid flags are:\n"
223 VALID_FLAGS "\n\n"
224 "The mesh_id is used only for mesh mode.");
39566cca 225COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*]",
01ae06f9 226 NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL);
45c7212c 227
7c37a24d
JB
228static int handle_interface_del(struct nl80211_state *state,
229 struct nl_cb *cb,
bd396f2a
JB
230 struct nl_msg *msg,
231 int argc, char **argv)
3fcfe40e 232{
70391ccf 233 return 0;
3fcfe40e 234}
1ae3d621
JB
235TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del,
236 "Remove this virtual interface");
ce5af55c 237HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del);
3fcfe40e 238
541ef425
JB
239static int print_iface_handler(struct nl_msg *msg, void *arg)
240{
241 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
242 struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
674567b8
JB
243 unsigned int *wiphy = arg;
244 const char *indent = "";
541ef425
JB
245
246 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
247 genlmsg_attrlen(gnlh, 0), NULL);
248
674567b8
JB
249 if (wiphy && tb_msg[NL80211_ATTR_WIPHY]) {
250 unsigned int thiswiphy = nla_get_u32(tb_msg[NL80211_ATTR_WIPHY]);
251 indent = "\t";
252 if (*wiphy != thiswiphy)
253 printf("phy#%d\n", thiswiphy);
254 *wiphy = thiswiphy;
255 }
256
541ef425 257 if (tb_msg[NL80211_ATTR_IFNAME])
674567b8 258 printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
541ef425 259 if (tb_msg[NL80211_ATTR_IFINDEX])
674567b8 260 printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]));
541ef425 261 if (tb_msg[NL80211_ATTR_IFTYPE])
674567b8 262 printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE])));
541ef425
JB
263
264 return NL_SKIP;
265}
266
7c37a24d
JB
267static int handle_interface_info(struct nl80211_state *state,
268 struct nl_cb *cb,
bd396f2a
JB
269 struct nl_msg *msg,
270 int argc, char **argv)
541ef425 271{
541ef425 272 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL);
70391ccf 273 return 0;
541ef425 274}
1ae3d621
JB
275TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info,
276 "Show information for this interface.");
cd293761 277
7c37a24d
JB
278static int handle_interface_set(struct nl80211_state *state,
279 struct nl_cb *cb,
cd293761
JB
280 struct nl_msg *msg,
281 int argc, char **argv)
282{
cd293761
JB
283 if (!argc)
284 return 1;
285
cd293761
JB
286 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
287
dd65496b
JB
288 switch (parse_mntr_flags(&argc, &argv, msg)) {
289 case 0:
290 return 0;
291 case -ENOMEM:
292 fprintf(stderr, "failed to allocate flags\n");
293 return 2;
294 case -EINVAL:
295 fprintf(stderr, "unknown flag %s\n", *argv);
296 return 2;
297 default:
298 return 2;
cd293761 299 }
cd293761 300 nla_put_failure:
dd65496b 301 return -ENOBUFS;
cd293761 302}
1ae3d621
JB
303COMMAND(set, monitor, "<flag>*",
304 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_set,
305 "Set monitor flags. Valid flags are:\n"
306 VALID_FLAGS);
82d028d0 307
7c37a24d
JB
308static int handle_interface_meshid(struct nl80211_state *state,
309 struct nl_cb *cb,
82d028d0
JB
310 struct nl_msg *msg,
311 int argc, char **argv)
312{
313 char *mesh_id = NULL;
314
315 if (argc != 1)
316 return 1;
317
318 mesh_id = argv[0];
319
320 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id);
321
322 return 0;
323 nla_put_failure:
324 return -ENOBUFS;
325}
326COMMAND(set, meshid, "<meshid>",
01ae06f9 327 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL);
674567b8
JB
328
329static unsigned int dev_dump_wiphy;
330
331static int handle_dev_dump(struct nl80211_state *state,
332 struct nl_cb *cb,
333 struct nl_msg *msg,
334 int argc, char **argv)
335{
336 dev_dump_wiphy = -1;
337 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, &dev_dump_wiphy);
338 return 0;
339}
1ae3d621
JB
340TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump,
341 "List all network interfaces for wireless hardware.");
d17fe27e
JB
342
343static int handle_interface_type(struct nl80211_state *state,
344 struct nl_cb *cb,
345 struct nl_msg *msg,
346 int argc, char **argv)
347{
348 enum nl80211_iftype type;
349 int tpset;
350
351 tpset = get_if_type(&argc, &argv, &type, false);
352 if (tpset)
353 return tpset;
354
355 if (argc)
356 return 1;
357
358 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
359
360 return 0;
361 nla_put_failure:
362 return -ENOBUFS;
363}
364COMMAND(set, type, "<type>",
1ae3d621
JB
365 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type,
366 "Set interface type/mode.\n"
367 IFACE_TYPES);