]> git.ipfire.org Git - thirdparty/iw.git/blob - event.c
print event on scan start
[thirdparty/iw.git] / event.c
1 #include <stdint.h>
2 #include <stdbool.h>
3 #include <net/if.h>
4 #include <errno.h>
5 #include "iw.h"
6
7 static int no_seq_check(struct nl_msg *msg, void *arg)
8 {
9 return NL_OK;
10 }
11
12 struct print_event_args {
13 bool frame, time;
14 };
15
16 static 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
75 static 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
207 struct wait_event {
208 int n_cmds;
209 const __u32 *cmds;
210 __u32 cmd;
211 };
212
213 static 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
228 static __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
301 static 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 }
329 TOPLEVEL(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.");