iw.c revision 59c49f099cb590542a90347630951cef26f13fa7
1/*
2 * nl80211 userspace tool
3 *
4 * Copyright 2007, 2008	Johannes Berg <johannes@sipsolutions.net>
5 */
6
7#include <errno.h>
8#include <stdio.h>
9#include <string.h>
10#include <net/if.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <unistd.h>
15
16#include <netlink/genl/genl.h>
17#include <netlink/genl/family.h>
18#include <netlink/genl/ctrl.h>
19#include <netlink/msg.h>
20#include <netlink/attr.h>
21#include <linux/nl80211.h>
22
23#include "iw.h"
24
25int debug = 0;
26
27static int nl80211_init(struct nl80211_state *state)
28{
29	int err;
30
31	state->nl_handle = nl_handle_alloc();
32	if (!state->nl_handle) {
33		fprintf(stderr, "Failed to allocate netlink handle.\n");
34		return -ENOMEM;
35	}
36
37	if (genl_connect(state->nl_handle)) {
38		fprintf(stderr, "Failed to connect to generic netlink.\n");
39		err = -ENOLINK;
40		goto out_handle_destroy;
41	}
42
43	state->nl_cache = genl_ctrl_alloc_cache(state->nl_handle);
44	if (!state->nl_cache) {
45		fprintf(stderr, "Failed to allocate generic netlink cache.\n");
46		err = -ENOMEM;
47		goto out_handle_destroy;
48	}
49
50	state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
51	if (!state->nl80211) {
52		fprintf(stderr, "nl80211 not found.\n");
53		err = -ENOENT;
54		goto out_cache_free;
55	}
56
57	return 0;
58
59 out_cache_free:
60	nl_cache_free(state->nl_cache);
61 out_handle_destroy:
62	nl_handle_destroy(state->nl_handle);
63	return err;
64}
65
66static void nl80211_cleanup(struct nl80211_state *state)
67{
68	genl_family_put(state->nl80211);
69	nl_cache_free(state->nl_cache);
70	nl_handle_destroy(state->nl_handle);
71}
72
73static void usage(const char *argv0)
74{
75	struct cmd *cmd;
76
77	fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
78	fprintf(stderr, "Options:\n");
79	fprintf(stderr, "\t--debug\tenable netlink debugging\n");
80	fprintf(stderr, "Commands:\n");
81	for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) {
82		switch (cmd->idby) {
83		case CIB_NONE:
84			fprintf(stderr, "\t");
85			/* fall through */
86		case CIB_PHY:
87			if (cmd->idby == CIB_PHY)
88				fprintf(stderr, "\tphy <phyname> ");
89			/* fall through */
90		case CIB_NETDEV:
91			if (cmd->idby == CIB_NETDEV)
92				fprintf(stderr, "\tdev <devname> ");
93			if (cmd->section)
94				fprintf(stderr, "%s ", cmd->section);
95			fprintf(stderr, "%s", cmd->name);
96			if (cmd->args)
97				fprintf(stderr, " %s", cmd->args);
98			fprintf(stderr, "\n");
99			break;
100		}
101	}
102}
103
104static int phy_lookup(char *name)
105{
106	char buf[200];
107	int fd, pos;
108
109	snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
110
111	fd = open(buf, O_RDONLY);
112	pos = read(fd, buf, sizeof(buf) - 1);
113	if (pos < 0)
114		return -1;
115	buf[pos] = '\0';
116	return atoi(buf);
117}
118
119static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
120			 void *arg)
121{
122	int *ret = arg;
123	*ret = err->error;
124	return NL_STOP;
125}
126
127static int finish_handler(struct nl_msg *msg, void *arg)
128{
129	return NL_SKIP;
130}
131
132static int ack_handler(struct nl_msg *msg, void *arg)
133{
134	int *ret = arg;
135	*ret = 0;
136	return NL_STOP;
137}
138
139static int handle_cmd(struct nl80211_state *state,
140		      enum command_identify_by idby,
141		      int argc, char **argv)
142{
143	struct cmd *cmd;
144	struct nl_cb *cb = NULL;
145	struct nl_msg *msg;
146	int devidx = 0;
147	int err;
148	const char *command, *section;
149
150	if (argc <= 1 && idby != CIB_NONE)
151		return 1;
152
153	switch (idby) {
154	case CIB_PHY:
155		devidx = phy_lookup(*argv);
156		argc--;
157		argv++;
158		break;
159	case CIB_NETDEV:
160		devidx = if_nametoindex(*argv);
161		argc--;
162		argv++;
163		break;
164	default:
165		break;
166	}
167
168	section = command = *argv;
169	argc--;
170	argv++;
171
172	for (cmd = &__start___cmd; cmd < &__stop___cmd; cmd++) {
173		if (cmd->idby != idby)
174			continue;
175		if (cmd->section) {
176			if (strcmp(cmd->section, section))
177				continue;
178			/* this is a bit icky ... */
179			if (command == section) {
180				if (argc <= 0)
181					return 1;
182				command = *argv;
183				argc--;
184				argv++;
185			}
186		} else if (section != command)
187			continue;
188		if (strcmp(cmd->name, command))
189			continue;
190		if (argc && !cmd->args)
191			continue;
192		break;
193	}
194
195	if (cmd == &__stop___cmd)
196		return 1;
197
198	msg = nlmsg_alloc();
199	if (!msg) {
200		fprintf(stderr, "failed to allocate netlink message\n");
201		return 2;
202	}
203
204	cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
205	if (!cb) {
206		fprintf(stderr, "failed to allocate netlink callbacks\n");
207		err = 2;
208		goto out_free_msg;
209	}
210
211	genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
212		    cmd->nl_msg_flags, cmd->cmd, 0);
213
214	switch (idby) {
215	case CIB_PHY:
216		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
217		break;
218	case CIB_NETDEV:
219		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
220		break;
221	default:
222		break;
223	}
224
225	err = cmd->handler(cb, msg, argc, argv);
226	if (err)
227		goto out;
228
229	err = nl_send_auto_complete(state->nl_handle, msg);
230	if (err < 0)
231		goto out;
232
233	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
234	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, NULL);
235	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
236
237	nl_recvmsgs(state->nl_handle, cb);
238 out:
239	nl_cb_put(cb);
240 out_free_msg:
241	nlmsg_free(msg);
242	return err;
243 nla_put_failure:
244	fprintf(stderr, "building message failed\n");
245	return 2;
246}
247
248int main(int argc, char **argv)
249{
250	struct nl80211_state nlstate;
251	int err;
252	const char *argv0;
253
254	err = nl80211_init(&nlstate);
255	if (err)
256		return 1;
257
258	/* strip off self */
259	argc--;
260	argv0 = *argv++;
261
262	if (argc > 0 && strcmp(*argv, "--debug") == 0) {
263		debug = 1;
264		argc--;
265		argv++;
266	}
267
268	if (argc == 0 || strcmp(*argv, "help") == 0) {
269		usage(argv0);
270		goto out;
271	}
272
273	if (strcmp(*argv, "dev") == 0) {
274		argc--;
275		argv++;
276		err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
277	} else if (strcmp(*argv, "phy") == 0) {
278		argc--;
279		argv++;
280		err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
281	} else
282		err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
283
284	if (err == 1)
285		usage(argv0);
286	if (err < 0)
287		fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
288
289 out:
290	nl80211_cleanup(&nlstate);
291
292	return err;
293}
294