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