event.c revision e67be81550a52dfc04fa7c3167824f0fd62eb627
1#include <stdint.h>
2#include <stdbool.h>
3#include <net/if.h>
4#include <errno.h>
5#include "iw.h"
6
7static int no_seq_check(struct nl_msg *msg, void *arg)
8{
9	return NL_OK;
10}
11
12struct print_event_args {
13	bool frame, time;
14};
15
16static void print_frame(struct print_event_args *args, struct nlattr *attr)
17{
18	uint8_t *frame;
19	size_t len;
20	int i;
21	char macbuf[6*3];
22	uint16_t tmp;
23
24	if (!attr)
25		printf(" [no frame]");
26
27	frame = nla_data(attr);
28	len = nla_len(attr);
29
30	if (len < 26) {
31		printf(" [invalid frame: ");
32		goto print_frame;
33	}
34
35	mac_addr_n2a(macbuf, frame + 10);
36	printf(" %s -> ", macbuf);
37	mac_addr_n2a(macbuf, frame + 4);
38	printf("%s", macbuf);
39
40	switch (frame[0] & 0xfc) {
41	case 0x10: /* assoc resp */
42	case 0x30: /* reassoc resp */
43		/* status */
44		tmp = (frame[27] << 8) + frame[26];
45		printf(" status: %d: %s", tmp, get_status_str(tmp));
46		break;
47	case 0x00: /* assoc req */
48	case 0x20: /* reassoc req */
49		break;
50	case 0xb0: /* auth */
51		/* status */
52		tmp = (frame[29] << 8) + frame[28];
53		printf(" status: %d: %s", tmp, get_status_str(tmp));
54		break;
55		break;
56	case 0xa0: /* disassoc */
57	case 0xc0: /* deauth */
58		/* reason */
59		tmp = (frame[25] << 8) + frame[24];
60		printf(" reason %d: %s", tmp, get_reason_str(tmp));
61		break;
62	}
63
64	if (!args->frame)
65		return;
66
67	printf(" [frame:");
68
69 print_frame:
70	for (i = 0; i < len; i++)
71		printf(" %.02x", frame[i]);
72	printf("]");
73}
74
75static int print_event(struct nl_msg *msg, void *arg)
76{
77	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
78	struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst;
79	struct print_event_args *args = arg;
80	char ifname[100];
81	char macbuf[6*3];
82	__u8 reg_type;
83	int rem_nst;
84
85	if (args->time) {
86		struct timeval tv;
87		gettimeofday(&tv, NULL);
88		printf("%ld.%06u: ", (long) tv.tv_sec, (unsigned int) tv.tv_usec);
89	}
90
91	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
92		  genlmsg_attrlen(gnlh, 0), NULL);
93
94	if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) {
95		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
96		printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY]));
97	} else if (tb[NL80211_ATTR_IFINDEX]) {
98		if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname);
99		printf("%s: ", ifname);
100	} else if (tb[NL80211_ATTR_WIPHY]) {
101		printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
102	}
103
104	switch (gnlh->cmd) {
105	case NL80211_CMD_NEW_WIPHY:
106		printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]));
107		break;
108	case NL80211_CMD_TRIGGER_SCAN:
109		printf("scan started\n");
110		break;
111	case NL80211_CMD_NEW_SCAN_RESULTS:
112		printf("scan finished:");
113	case NL80211_CMD_SCAN_ABORTED:
114		if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED)
115			printf("scan aborted:");
116		if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
117			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst)
118				printf(" %d", nla_get_u32(nst));
119			printf(",");
120		}
121		if (tb[NL80211_ATTR_SCAN_SSIDS]) {
122			nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) {
123				printf(" \"");
124				print_ssid_escaped(nla_len(nst), nla_data(nst));
125				printf("\"");
126			}
127		}
128		printf("\n");
129		break;
130	case NL80211_CMD_REG_CHANGE:
131		printf("regulatory domain change: ");
132
133		reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
134
135		switch (reg_type) {
136		case NL80211_REGDOM_TYPE_COUNTRY:
137			printf("set to %s by %s request",
138			       nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
139			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
140			if (tb[NL80211_ATTR_WIPHY])
141				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
142			break;
143		case NL80211_REGDOM_TYPE_WORLD:
144			printf("set to world roaming by %s request",
145			       reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])));
146			break;
147		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
148			printf("custom world roaming rules in place on phy%d by %s request",
149			       nla_get_u32(tb[NL80211_ATTR_WIPHY]),
150			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
151			break;
152		case NL80211_REGDOM_TYPE_INTERSECTION:
153			printf("intersection used due to a request made by %s",
154			       reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR])));
155			if (tb[NL80211_ATTR_WIPHY])
156				printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY]));
157			break;
158		default:
159			printf("unknown source (upgrade this utility)");
160			break;
161		}
162
163		printf("\n");
164		break;
165	case NL80211_CMD_JOIN_IBSS:
166		mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC]));
167		printf("IBSS %s joined\n", macbuf);
168		break;
169	case NL80211_CMD_AUTHENTICATE:
170		printf("auth");
171		if (tb[NL80211_ATTR_FRAME])
172			print_frame(args, tb[NL80211_ATTR_FRAME]);
173		else if (tb[NL80211_ATTR_TIMED_OUT])
174			printf(": timed out");
175		else
176			printf(": unknown event");
177		printf("\n");
178		break;
179	case NL80211_CMD_ASSOCIATE:
180		printf("assoc");
181		if (tb[NL80211_ATTR_FRAME])
182			print_frame(args, tb[NL80211_ATTR_FRAME]);
183		else if (tb[NL80211_ATTR_TIMED_OUT])
184			printf(": timed out");
185		else
186			printf(": unknown event");
187		printf("\n");
188		break;
189	case NL80211_CMD_DEAUTHENTICATE:
190		printf("deauth");
191		print_frame(args, tb[NL80211_ATTR_FRAME]);
192		printf("\n");
193		break;
194	case NL80211_CMD_DISASSOCIATE:
195		printf("disassoc");
196		print_frame(args, tb[NL80211_ATTR_FRAME]);
197		printf("\n");
198		break;
199	default:
200		printf("unknown event %d\n", gnlh->cmd);
201		break;
202	}
203
204	return NL_SKIP;
205}
206
207struct wait_event {
208	int n_cmds;
209	const __u32 *cmds;
210	__u32 cmd;
211};
212
213static int wait_event(struct nl_msg *msg, void *arg)
214{
215	struct wait_event *wait = arg;
216	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
217	int i;
218
219	for (i = 0; i < wait->n_cmds; i++) {
220		if (gnlh->cmd == wait->cmds[i]) {
221			wait->cmd = gnlh->cmd;
222		}
223	}
224
225	return NL_SKIP;
226}
227
228static __u32 __listen_events(struct nl80211_state *state,
229			     const int n_waits, const __u32 *waits,
230			     struct print_event_args *args)
231{
232	int mcid, ret;
233	struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
234	struct wait_event wait_ev;
235
236	if (!cb) {
237		fprintf(stderr, "failed to allocate netlink callbacks\n");
238		return -ENOMEM;
239	}
240
241	/* Configuration multicast group */
242	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config");
243	if (mcid < 0)
244		return mcid;
245
246	ret = nl_socket_add_membership(state->nl_sock, mcid);
247	if (ret)
248		return ret;
249
250	/* Scan multicast group */
251	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan");
252	if (mcid >= 0) {
253		ret = nl_socket_add_membership(state->nl_sock, mcid);
254		if (ret)
255			return ret;
256	}
257
258	/* Regulatory multicast group */
259	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory");
260	if (mcid >= 0) {
261		ret = nl_socket_add_membership(state->nl_sock, mcid);
262		if (ret)
263			return ret;
264	}
265
266	/* MLME multicast group */
267	mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme");
268	if (mcid >= 0) {
269		ret = nl_socket_add_membership(state->nl_sock, mcid);
270		if (ret)
271			return ret;
272	}
273
274	/* no sequence checking for multicast messages */
275	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
276
277	if (n_waits && waits) {
278		wait_ev.cmds = waits;
279		wait_ev.n_cmds = n_waits;
280		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev);
281	} else {
282		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args);
283	}
284
285	wait_ev.cmd = 0;
286
287	while (!wait_ev.cmd)
288		nl_recvmsgs(state->nl_sock, cb);
289
290	nl_cb_put(cb);
291
292	return wait_ev.cmd;
293}
294
295__u32 listen_events(struct nl80211_state *state,
296		    const int n_waits, const __u32 *waits)
297{
298	return __listen_events(state, n_waits, waits, NULL);
299}
300
301static int print_events(struct nl80211_state *state,
302			struct nl_cb *cb,
303			struct nl_msg *msg,
304			int argc, char **argv)
305{
306	struct print_event_args args;
307
308	memset(&args, 0, sizeof(args));
309
310	argc--;
311	argv++;
312
313	while (argc > 0) {
314		if (strcmp(argv[0], "-f") == 0)
315			args.frame = true;
316		else if (strcmp(argv[0], "-t") == 0)
317			args.time = true;
318		else
319			return 1;
320		argc--;
321		argv++;
322	}
323
324	if (argc)
325		return 1;
326
327	return __listen_events(state, 0, NULL, &args);
328}
329TOPLEVEL(event, "[-t] [-f]", 0, 0, CIB_NONE, print_events,
330	"Monitor events from the kernel.\n"
331	"-t - print timestamp\n"
332	"-f - print full frame for auth/assoc etc.");
333