iw.c revision 601c6ab203c52c038e1b3a34232486295a84a999
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
22#include "nl80211.h"
23#include "iw.h"
24#include "version.h"
25
26#ifndef CONFIG_LIBNL20
27/* libnl 2.0 compatibility code */
28
29static inline struct nl_handle *nl_socket_alloc(void)
30{
31	return nl_handle_alloc();
32}
33
34static inline void nl_socket_free(struct nl_sock *h)
35{
36	nl_handle_destroy(h);
37}
38
39static inline int __genl_ctrl_alloc_cache(struct nl_sock *h, struct nl_cache **cache)
40{
41	struct nl_cache *tmp = genl_ctrl_alloc_cache(h);
42	if (!tmp)
43		return -ENOMEM;
44	*cache = tmp;
45	return 0;
46}
47#define genl_ctrl_alloc_cache __genl_ctrl_alloc_cache
48#endif /* CONFIG_LIBNL20 */
49
50static int debug = 0;
51
52static int nl80211_init(struct nl80211_state *state)
53{
54	int err;
55
56	state->nl_sock = nl_socket_alloc();
57	if (!state->nl_sock) {
58		fprintf(stderr, "Failed to allocate netlink socket.\n");
59		return -ENOMEM;
60	}
61
62	if (genl_connect(state->nl_sock)) {
63		fprintf(stderr, "Failed to connect to generic netlink.\n");
64		err = -ENOLINK;
65		goto out_handle_destroy;
66	}
67
68	if (genl_ctrl_alloc_cache(state->nl_sock, &state->nl_cache)) {
69		fprintf(stderr, "Failed to allocate generic netlink cache.\n");
70		err = -ENOMEM;
71		goto out_handle_destroy;
72	}
73
74	state->nl80211 = genl_ctrl_search_by_name(state->nl_cache, "nl80211");
75	if (!state->nl80211) {
76		fprintf(stderr, "nl80211 not found.\n");
77		err = -ENOENT;
78		goto out_cache_free;
79	}
80
81	return 0;
82
83 out_cache_free:
84	nl_cache_free(state->nl_cache);
85 out_handle_destroy:
86	nl_socket_free(state->nl_sock);
87	return err;
88}
89
90static void nl80211_cleanup(struct nl80211_state *state)
91{
92	genl_family_put(state->nl80211);
93	nl_cache_free(state->nl_cache);
94	nl_socket_free(state->nl_sock);
95}
96
97__COMMAND(NULL, NULL, NULL, 0, 0, 0, CIB_NONE, NULL);
98__COMMAND(NULL, NULL, NULL, 1, 0, 0, CIB_NONE, NULL);
99
100static int cmd_size;
101
102static void usage(const char *argv0)
103{
104	struct cmd *cmd;
105
106	fprintf(stderr, "Usage:\t%s [options] command\n", argv0);
107	fprintf(stderr, "Options:\n");
108	fprintf(stderr, "\t--debug\t\tenable netlink debugging\n");
109	fprintf(stderr, "\t--version\tshow version\n");
110	fprintf(stderr, "Commands:\n");
111	fprintf(stderr, "\thelp\n");
112	fprintf(stderr, "\tevent\n");
113	for (cmd = &__start___cmd; cmd < &__stop___cmd;
114	     cmd = (struct cmd *)((char *)cmd + cmd_size)) {
115		if (!cmd->handler || cmd->hidden)
116			continue;
117		switch (cmd->idby) {
118		case CIB_NONE:
119			fprintf(stderr, "\t");
120			/* fall through */
121		case CIB_PHY:
122			if (cmd->idby == CIB_PHY)
123				fprintf(stderr, "\tphy <phyname> ");
124			/* fall through */
125		case CIB_NETDEV:
126			if (cmd->idby == CIB_NETDEV)
127				fprintf(stderr, "\tdev <devname> ");
128			if (cmd->section)
129				fprintf(stderr, "%s ", cmd->section);
130			fprintf(stderr, "%s", cmd->name);
131			if (cmd->args)
132				fprintf(stderr, " %s", cmd->args);
133			fprintf(stderr, "\n");
134			break;
135		}
136	}
137}
138
139static void version(void)
140{
141	printf("iw version " IW_VERSION "\n");
142}
143
144static int phy_lookup(char *name)
145{
146	char buf[200];
147	int fd, pos;
148
149	snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name);
150
151	fd = open(buf, O_RDONLY);
152	pos = read(fd, buf, sizeof(buf) - 1);
153	if (pos < 0)
154		return -1;
155	buf[pos] = '\0';
156	return atoi(buf);
157}
158
159static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
160			 void *arg)
161{
162	int *ret = arg;
163	*ret = err->error;
164	return NL_STOP;
165}
166
167static int finish_handler(struct nl_msg *msg, void *arg)
168{
169	int *ret = arg;
170	*ret = 0;
171	return NL_SKIP;
172}
173
174static int ack_handler(struct nl_msg *msg, void *arg)
175{
176	int *ret = arg;
177	*ret = 0;
178	return NL_STOP;
179}
180
181static int handle_cmd(struct nl80211_state *state,
182		      enum command_identify_by idby,
183		      int argc, char **argv)
184{
185	struct cmd *cmd;
186	struct nl_cb *cb = NULL;
187	struct nl_msg *msg;
188	int devidx = 0;
189	int err;
190	const char *command, *section;
191
192	if (argc <= 1 && idby != CIB_NONE)
193		return 1;
194
195	switch (idby) {
196	case CIB_PHY:
197		devidx = phy_lookup(*argv);
198		argc--;
199		argv++;
200		break;
201	case CIB_NETDEV:
202		devidx = if_nametoindex(*argv);
203		argc--;
204		argv++;
205		break;
206	default:
207		break;
208	}
209
210	section = command = *argv;
211	argc--;
212	argv++;
213
214	for (cmd = &__start___cmd; cmd < &__stop___cmd;
215	     cmd = (struct cmd *)((char *)cmd + cmd_size)) {
216		if (!cmd->handler)
217			continue;
218		if (cmd->idby != idby)
219			continue;
220		if (cmd->section) {
221			if (strcmp(cmd->section, section))
222				continue;
223			/* this is a bit icky ... */
224			if (command == section) {
225				if (argc <= 0)
226					return 1;
227				command = *argv;
228				argc--;
229				argv++;
230			}
231		} else if (section != command)
232			continue;
233		if (strcmp(cmd->name, command))
234			continue;
235		if (argc && !cmd->args)
236			continue;
237		break;
238	}
239
240	if (cmd >= &__stop___cmd)
241		return 1;
242
243	msg = nlmsg_alloc();
244	if (!msg) {
245		fprintf(stderr, "failed to allocate netlink message\n");
246		return 2;
247	}
248
249	cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
250	if (!cb) {
251		fprintf(stderr, "failed to allocate netlink callbacks\n");
252		err = 2;
253		goto out_free_msg;
254	}
255
256	genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
257		    cmd->nl_msg_flags, cmd->cmd, 0);
258
259	switch (idby) {
260	case CIB_PHY:
261		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx);
262		break;
263	case CIB_NETDEV:
264		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
265		break;
266	default:
267		break;
268	}
269
270	err = cmd->handler(cb, msg, argc, argv);
271	if (err)
272		goto out;
273
274	err = nl_send_auto_complete(state->nl_sock, msg);
275	if (err < 0)
276		goto out;
277
278	err = 1;
279
280	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
281	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
282	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
283
284	while (err > 0)
285		nl_recvmsgs(state->nl_sock, cb);
286 out:
287	nl_cb_put(cb);
288 out_free_msg:
289	nlmsg_free(msg);
290	return err;
291 nla_put_failure:
292	fprintf(stderr, "building message failed\n");
293	return 2;
294}
295
296static int no_seq_check(struct nl_msg *msg, void *arg)
297{
298	return NL_OK;
299}
300
301static int print_event(struct nl_msg *msg, void *arg)
302{
303	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
304	struct nlattr *tb[NL80211_ATTR_MAX + 1];
305	char ifname[100];
306	__u8 reg_type;
307
308	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
309		  genlmsg_attrlen(gnlh, 0), NULL);
310
311	switch (gnlh->cmd) {
312	case NL80211_CMD_NEW_WIPHY:
313		printf("wiphy rename: phy #%d to %s\n",
314		       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
315		       nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
316		break;
317	case NL80211_CMD_NEW_SCAN_RESULTS:
318		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
319		printf("scan finished on %s (phy #%d)\n",
320		       ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
321		break;
322	case NL80211_CMD_SCAN_ABORTED:
323		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
324		printf("scan aborted on %s (phy #%d)\n",
325		       ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
326		break;
327	case NL80211_CMD_REG_CHANGE:
328
329		printf("regulatory domain change: ");
330
331		reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
332
333		switch (reg_type) {
334		case NL80211_REGDOM_TYPE_COUNTRY:
335			printf("set to %s by %s request",
336			       nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
337			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
338			if (tb[NL80211_ATTR_WIPHY])
339				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
340			break;
341		case NL80211_REGDOM_TYPE_WORLD:
342			printf("set to world roaming by %s request",
343			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
344			break;
345		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
346			printf("custom world roaming rules in place on phy%d by %s request",
347			       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
348			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
349			break;
350		case NL80211_REGDOM_TYPE_INTERSECTION:
351			printf("intersection used due to a request made by %s",
352			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
353			if (tb[NL80211_ATTR_WIPHY])
354				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
355			break;
356		default:
357			printf("unknown source (upgrade this utility)");
358			break;
359		}
360
361		printf("\n");
362		break;
363	default:
364		printf("unknown event: %d\n", gnlh->cmd);
365		break;
366	}
367
368	return NL_SKIP;
369}
370
371static int listen_events(struct nl80211_state *state,
372			 int argc, char **argv)
373{
374	int mcid, ret;
375	struct nl_cb *cb = nl_cb_alloc(debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
376
377	if (!cb) {
378		fprintf(stderr, "failed to allocate netlink callbacks\n");
379		return -ENOMEM;
380	}
381
382	/* Configuration multicast group */
383	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
384	if (mcid < 0)
385		return mcid;
386
387	ret = nl_socket_add_membership(state->nl_sock, mcid);
388	if (ret)
389		return ret;
390
391	/* Scan multicast group */
392	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
393	if (mcid >= 0) {
394		ret = nl_socket_add_membership(state->nl_sock, mcid);
395		if (ret)
396			return ret;
397	}
398
399	/* Regulatory multicast group */
400	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
401	if (mcid >= 0) {
402		ret = nl_socket_add_membership(state->nl_sock, mcid);
403		if (ret)
404			return ret;
405	}
406
407	/* no sequence checking for multicast messages */
408	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
409	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, NULL);
410
411	while (1)
412		nl_recvmsgs(state->nl_sock, cb);
413
414	nl_cb_put(cb);
415
416	return 0;
417}
418
419int main(int argc, char **argv)
420{
421	struct nl80211_state nlstate;
422	int err;
423	const char *argv0;
424
425	/* calculate command size including padding */
426	cmd_size = abs((long)&__cmd_NULL_1_CIB_NONE_0
427	             - (long)&__cmd_NULL_0_CIB_NONE_0);
428	/* strip off self */
429	argc--;
430	argv0 = *argv++;
431
432	if (argc > 0 && strcmp(*argv, "--debug") == 0) {
433		debug = 1;
434		argc--;
435		argv++;
436	}
437
438	if (argc > 0 && strcmp(*argv, "--version") == 0) {
439		version();
440		return 0;
441	}
442
443	if (argc == 0 || strcmp(*argv, "help") == 0) {
444		usage(argv0);
445		return 0;
446	}
447
448	err = nl80211_init(&nlstate);
449	if (err)
450		return 1;
451
452	if (strcmp(*argv, "event") == 0) {
453		err = listen_events(&nlstate, argc, argv);
454	} else if (strcmp(*argv, "dev") == 0) {
455		argc--;
456		argv++;
457		err = handle_cmd(&nlstate, CIB_NETDEV, argc, argv);
458	} else if (strcmp(*argv, "phy") == 0) {
459		argc--;
460		argv++;
461		err = handle_cmd(&nlstate, CIB_PHY, argc, argv);
462	} else
463		err = handle_cmd(&nlstate, CIB_NONE, argc, argv);
464
465	if (err == 1)
466		usage(argv0);
467	if (err < 0)
468		fprintf(stderr, "command failed: %s (%d)\n", strerror(-err), err);
469
470	nl80211_cleanup(&nlstate);
471
472	return err;
473}
474