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