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