]> git.ipfire.org Git - thirdparty/iw.git/blame - interface.c
don't emit usage to stderr
[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
cd293761 21static char *mntr_flags[NL80211_MNTR_FLAG_MAX + 1] = {
dd65496b 22 "none",
cd293761
JB
23 "fcsfail",
24 "plcpfail",
25 "control",
26 "otherbss",
27 "cook",
28};
29
dd65496b
JB
30static 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;
e14cc99e 46 flag <= NL80211_MNTR_FLAG_MAX; flag++) {
dd65496b
JB
47 if (strcmp(*argv, mntr_flags[flag]) == 0) {
48 ok = 1;
4a3bf753
JB
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 */
dd65496b
JB
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
1ae3d621
JB
80/* for help */
81#define IFACE_TYPES "Valid interface types are: managed, ibss, monitor, mesh, wds."
82
d17fe27e
JB
83/* return 0 if ok, internal error otherwise */
84static int get_if_type(int *argc, char ***argv, enum nl80211_iftype *type,
85 bool need_type)
45c7212c
JB
86{
87 char *tpstr;
88
d17fe27e
JB
89 if (*argc < 1 + !!need_type)
90 return 1;
45c7212c 91
d17fe27e
JB
92 if (need_type && strcmp((*argv)[0], "type"))
93 return 1;
45c7212c 94
d17fe27e
JB
95 tpstr = (*argv)[!!need_type];
96 *argc -= 1 + !!need_type;
97 *argv += 1 + !!need_type;
45c7212c
JB
98
99 if (strcmp(tpstr, "adhoc") == 0 ||
100 strcmp(tpstr, "ibss") == 0) {
101 *type = NL80211_IFTYPE_ADHOC;
d17fe27e 102 return 0;
45c7212c
JB
103 } else if (strcmp(tpstr, "monitor") == 0) {
104 *type = NL80211_IFTYPE_MONITOR;
d17fe27e 105 return 0;
c1d44a6c
JB
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;
4d3a72da 114 } else if (strcmp(tpstr, "__ap") == 0) {
45c7212c 115 *type = NL80211_IFTYPE_AP;
d17fe27e 116 return 0;
4d3a72da 117 } else if (strcmp(tpstr, "__ap_vlan") == 0) {
45c7212c 118 *type = NL80211_IFTYPE_AP_VLAN;
d17fe27e 119 return 0;
45c7212c
JB
120 } else if (strcmp(tpstr, "wds") == 0) {
121 *type = NL80211_IFTYPE_WDS;
d17fe27e 122 return 0;
a65df165
JB
123 } else if (strcmp(tpstr, "managed") == 0 ||
124 strcmp(tpstr, "mgd") == 0 ||
125 strcmp(tpstr, "station") == 0) {
45c7212c 126 *type = NL80211_IFTYPE_STATION;
d17fe27e 127 return 0;
3d1e8704 128 } else if (strcmp(tpstr, "mp") == 0 ||
a65df165 129 strcmp(tpstr, "mesh") == 0) {
3d1e8704 130 *type = NL80211_IFTYPE_MESH_POINT;
d17fe27e 131 return 0;
45c7212c
JB
132 }
133
45c7212c 134 fprintf(stderr, "invalid interface type %s\n", tpstr);
d17fe27e 135 return 2;
45c7212c
JB
136}
137
7c37a24d
JB
138static int handle_interface_add(struct nl80211_state *state,
139 struct nl_cb *cb,
bd396f2a
JB
140 struct nl_msg *msg,
141 int argc, char **argv)
45c7212c 142{
2dfd6bfa 143 char *name;
3d1e8704 144 char *mesh_id = NULL;
45c7212c 145 enum nl80211_iftype type;
70391ccf 146 int tpset;
45c7212c 147
bd396f2a 148 if (argc < 1)
5e75fd04 149 return 1;
45c7212c 150
2dfd6bfa 151 name = argv[0];
45c7212c
JB
152 argc--;
153 argv++;
154
d17fe27e
JB
155 tpset = get_if_type(&argc, &argv, &type, true);
156 if (tpset)
c1d44a6c 157 return tpset;
45c7212c 158
3d1e8704 159 if (argc) {
dd65496b
JB
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 {
5e75fd04 177 return 1;
dd65496b 178 }
3d1e8704
LCC
179 }
180
5e75fd04
JB
181 if (argc)
182 return 1;
45c7212c 183
45c7212c 184 NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, name);
6d28ce25 185 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, type);
3d1e8704
LCC
186 if (mesh_id)
187 NLA_PUT(msg, NL80211_ATTR_MESH_ID, strlen(mesh_id), mesh_id);
45c7212c 188
70391ccf 189 return 0;
5e75fd04 190 nla_put_failure:
70391ccf 191 return -ENOBUFS;
45c7212c 192}
1ae3d621
JB
193COMMAND(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.");
200COMMAND(interface, add, "<name> type <type> [mesh_id <meshid>] [flags <flag>*]",
01ae06f9 201 NL80211_CMD_NEW_INTERFACE, 0, CIB_NETDEV, handle_interface_add, NULL);
45c7212c 202
7c37a24d
JB
203static int handle_interface_del(struct nl80211_state *state,
204 struct nl_cb *cb,
bd396f2a
JB
205 struct nl_msg *msg,
206 int argc, char **argv)
3fcfe40e 207{
70391ccf 208 return 0;
3fcfe40e 209}
1ae3d621
JB
210TOPLEVEL(del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del,
211 "Remove this virtual interface");
ce5af55c 212HIDDEN(interface, del, NULL, NL80211_CMD_DEL_INTERFACE, 0, CIB_NETDEV, handle_interface_del);
3fcfe40e 213
541ef425
JB
214static 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];
674567b8
JB
218 unsigned int *wiphy = arg;
219 const char *indent = "";
541ef425
JB
220
221 nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
222 genlmsg_attrlen(gnlh, 0), NULL);
223
674567b8
JB
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
541ef425 232 if (tb_msg[NL80211_ATTR_IFNAME])
674567b8 233 printf("%sInterface %s\n", indent, nla_get_string(tb_msg[NL80211_ATTR_IFNAME]));
541ef425 234 if (tb_msg[NL80211_ATTR_IFINDEX])
674567b8 235 printf("%s\tifindex %d\n", indent, nla_get_u32(tb_msg[NL80211_ATTR_IFINDEX]));
541ef425 236 if (tb_msg[NL80211_ATTR_IFTYPE])
674567b8 237 printf("%s\ttype %s\n", indent, iftype_name(nla_get_u32(tb_msg[NL80211_ATTR_IFTYPE])));
541ef425
JB
238
239 return NL_SKIP;
240}
241
7c37a24d
JB
242static int handle_interface_info(struct nl80211_state *state,
243 struct nl_cb *cb,
bd396f2a
JB
244 struct nl_msg *msg,
245 int argc, char **argv)
541ef425 246{
541ef425 247 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_iface_handler, NULL);
70391ccf 248 return 0;
541ef425 249}
1ae3d621
JB
250TOPLEVEL(info, NULL, NL80211_CMD_GET_INTERFACE, 0, CIB_NETDEV, handle_interface_info,
251 "Show information for this interface.");
cd293761 252
7c37a24d
JB
253static int handle_interface_set(struct nl80211_state *state,
254 struct nl_cb *cb,
cd293761
JB
255 struct nl_msg *msg,
256 int argc, char **argv)
257{
cd293761
JB
258 if (!argc)
259 return 1;
260
cd293761
JB
261 NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);
262
dd65496b
JB
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;
cd293761 274 }
cd293761 275 nla_put_failure:
dd65496b 276 return -ENOBUFS;
cd293761 277}
1ae3d621
JB
278COMMAND(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);
82d028d0 282
7c37a24d
JB
283static int handle_interface_meshid(struct nl80211_state *state,
284 struct nl_cb *cb,
82d028d0
JB
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}
301COMMAND(set, meshid, "<meshid>",
01ae06f9 302 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_meshid, NULL);
674567b8
JB
303
304static unsigned int dev_dump_wiphy;
305
306static 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}
1ae3d621
JB
315TOPLEVEL(dev, NULL, NL80211_CMD_GET_INTERFACE, NLM_F_DUMP, CIB_NONE, handle_dev_dump,
316 "List all network interfaces for wireless hardware.");
d17fe27e
JB
317
318static 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}
339COMMAND(set, type, "<type>",
1ae3d621
JB
340 NL80211_CMD_SET_INTERFACE, 0, CIB_NETDEV, handle_interface_type,
341 "Set interface type/mode.\n"
342 IFACE_TYPES);