event.c revision aea5dbd2fe8f70be333b008e64788c4b8410cbfa
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_NEW_SCAN_RESULTS: 109 printf("scan finished:"); 110 case NL80211_CMD_SCAN_ABORTED: 111 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) 112 printf("scan aborted:"); 113 if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { 114 nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst) 115 printf(" %d", nla_get_u32(nst)); 116 printf(","); 117 } 118 if (tb[NL80211_ATTR_SCAN_SSIDS]) { 119 nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) { 120 printf(" \""); 121 print_ssid_escaped(nla_len(nst), nla_data(nst)); 122 printf("\""); 123 } 124 } 125 printf("\n"); 126 break; 127 case NL80211_CMD_REG_CHANGE: 128 printf("regulatory domain change: "); 129 130 reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); 131 132 switch (reg_type) { 133 case NL80211_REGDOM_TYPE_COUNTRY: 134 printf("set to %s by %s request", 135 nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), 136 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 137 if (tb[NL80211_ATTR_WIPHY]) 138 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 139 break; 140 case NL80211_REGDOM_TYPE_WORLD: 141 printf("set to world roaming by %s request", 142 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 143 break; 144 case NL80211_REGDOM_TYPE_CUSTOM_WORLD: 145 printf("custom world roaming rules in place on phy%d by %s request", 146 nla_get_u32(tb[NL80211_ATTR_WIPHY]), 147 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 148 break; 149 case NL80211_REGDOM_TYPE_INTERSECTION: 150 printf("intersection used due to a request made by %s", 151 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 152 if (tb[NL80211_ATTR_WIPHY]) 153 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 154 break; 155 default: 156 printf("unknown source (upgrade this utility)"); 157 break; 158 } 159 160 printf("\n"); 161 break; 162 case NL80211_CMD_JOIN_IBSS: 163 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 164 printf("IBSS %s joined\n", macbuf); 165 break; 166 case NL80211_CMD_AUTHENTICATE: 167 printf("auth"); 168 if (tb[NL80211_ATTR_FRAME]) 169 print_frame(args, tb[NL80211_ATTR_FRAME]); 170 else if (tb[NL80211_ATTR_TIMED_OUT]) 171 printf(": timed out"); 172 else 173 printf(": unknown event"); 174 printf("\n"); 175 break; 176 case NL80211_CMD_ASSOCIATE: 177 printf("assoc"); 178 if (tb[NL80211_ATTR_FRAME]) 179 print_frame(args, tb[NL80211_ATTR_FRAME]); 180 else if (tb[NL80211_ATTR_TIMED_OUT]) 181 printf(": timed out"); 182 else 183 printf(": unknown event"); 184 printf("\n"); 185 break; 186 case NL80211_CMD_DEAUTHENTICATE: 187 printf("deauth"); 188 print_frame(args, tb[NL80211_ATTR_FRAME]); 189 printf("\n"); 190 break; 191 case NL80211_CMD_DISASSOCIATE: 192 printf("disassoc"); 193 print_frame(args, tb[NL80211_ATTR_FRAME]); 194 printf("\n"); 195 break; 196 default: 197 printf("unknown event %d\n", gnlh->cmd); 198 break; 199 } 200 201 return NL_SKIP; 202} 203 204struct wait_event { 205 int n_cmds; 206 const __u32 *cmds; 207 __u32 cmd; 208}; 209 210static int wait_event(struct nl_msg *msg, void *arg) 211{ 212 struct wait_event *wait = arg; 213 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 214 int i; 215 216 for (i = 0; i < wait->n_cmds; i++) { 217 if (gnlh->cmd == wait->cmds[i]) { 218 wait->cmd = gnlh->cmd; 219 } 220 } 221 222 return NL_SKIP; 223} 224 225static __u32 __listen_events(struct nl80211_state *state, 226 const int n_waits, const __u32 *waits, 227 struct print_event_args *args) 228{ 229 int mcid, ret; 230 struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 231 struct wait_event wait_ev; 232 233 if (!cb) { 234 fprintf(stderr, "failed to allocate netlink callbacks\n"); 235 return -ENOMEM; 236 } 237 238 /* Configuration multicast group */ 239 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config"); 240 if (mcid < 0) 241 return mcid; 242 243 ret = nl_socket_add_membership(state->nl_sock, mcid); 244 if (ret) 245 return ret; 246 247 /* Scan multicast group */ 248 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan"); 249 if (mcid >= 0) { 250 ret = nl_socket_add_membership(state->nl_sock, mcid); 251 if (ret) 252 return ret; 253 } 254 255 /* Regulatory multicast group */ 256 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory"); 257 if (mcid >= 0) { 258 ret = nl_socket_add_membership(state->nl_sock, mcid); 259 if (ret) 260 return ret; 261 } 262 263 /* MLME multicast group */ 264 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme"); 265 if (mcid >= 0) { 266 ret = nl_socket_add_membership(state->nl_sock, mcid); 267 if (ret) 268 return ret; 269 } 270 271 /* no sequence checking for multicast messages */ 272 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); 273 274 if (n_waits && waits) { 275 wait_ev.cmds = waits; 276 wait_ev.n_cmds = n_waits; 277 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev); 278 } else { 279 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args); 280 } 281 282 wait_ev.cmd = 0; 283 284 while (!wait_ev.cmd) 285 nl_recvmsgs(state->nl_sock, cb); 286 287 nl_cb_put(cb); 288 289 return wait_ev.cmd; 290} 291 292__u32 listen_events(struct nl80211_state *state, 293 const int n_waits, const __u32 *waits) 294{ 295 return __listen_events(state, n_waits, waits, NULL); 296} 297 298static int print_events(struct nl80211_state *state, 299 struct nl_cb *cb, 300 struct nl_msg *msg, 301 int argc, char **argv) 302{ 303 struct print_event_args args; 304 305 memset(&args, 0, sizeof(args)); 306 307 argc--; 308 argv++; 309 310 while (argc > 0) { 311 if (strcmp(argv[0], "-f") == 0) 312 args.frame = true; 313 else if (strcmp(argv[0], "-t") == 0) 314 args.time = true; 315 else 316 return 1; 317 argc--; 318 argv++; 319 } 320 321 if (argc) 322 return 1; 323 324 return __listen_events(state, 0, NULL, &args); 325} 326TOPLEVEL(event, "[-t] [-f]", 0, 0, CIB_NONE, print_events, 327 "Monitor events from the kernel.\n" 328 "-t - print timestamp\n" 329 "-f - print full frame for auth/assoc etc."); 330