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