event.c revision d516c5bc8cf32aab5cde9ed1aee4b2ae4794a917
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 ieee80211_beacon_channel { 13 __u16 center_freq; 14 bool no_ir; 15 bool no_ibss; 16}; 17 18static int parse_beacon_hint_chan(struct nlattr *tb, 19 struct ieee80211_beacon_channel *chan) 20{ 21 struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; 22 static struct nla_policy beacon_freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = { 23 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 }, 24 [NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG }, 25 [__NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG }, 26 }; 27 28 if (nla_parse_nested(tb_freq, 29 NL80211_FREQUENCY_ATTR_MAX, 30 tb, 31 beacon_freq_policy)) 32 return -EINVAL; 33 34 chan->center_freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); 35 36 if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) 37 chan->no_ir = true; 38 if (tb_freq[__NL80211_FREQUENCY_ATTR_NO_IBSS]) 39 chan->no_ibss = true; 40 41 return 0; 42} 43 44static void print_frame(struct print_event_args *args, struct nlattr *attr) 45{ 46 uint8_t *frame; 47 size_t len; 48 int i; 49 char macbuf[6*3]; 50 uint16_t tmp; 51 52 if (!attr) 53 printf(" [no frame]"); 54 55 frame = nla_data(attr); 56 len = nla_len(attr); 57 58 if (len < 26) { 59 printf(" [invalid frame: "); 60 goto print_frame; 61 } 62 63 mac_addr_n2a(macbuf, frame + 10); 64 printf(" %s -> ", macbuf); 65 mac_addr_n2a(macbuf, frame + 4); 66 printf("%s", macbuf); 67 68 switch (frame[0] & 0xfc) { 69 case 0x10: /* assoc resp */ 70 case 0x30: /* reassoc resp */ 71 /* status */ 72 tmp = (frame[27] << 8) + frame[26]; 73 printf(" status: %d: %s", tmp, get_status_str(tmp)); 74 break; 75 case 0x00: /* assoc req */ 76 case 0x20: /* reassoc req */ 77 break; 78 case 0xb0: /* auth */ 79 /* status */ 80 tmp = (frame[29] << 8) + frame[28]; 81 printf(" status: %d: %s", tmp, get_status_str(tmp)); 82 break; 83 case 0xa0: /* disassoc */ 84 case 0xc0: /* deauth */ 85 /* reason */ 86 tmp = (frame[25] << 8) + frame[24]; 87 printf(" reason %d: %s", tmp, get_reason_str(tmp)); 88 break; 89 } 90 91 if (!args->frame) 92 return; 93 94 printf(" [frame:"); 95 96 print_frame: 97 for (i = 0; i < len; i++) 98 printf(" %.02x", frame[i]); 99 printf("]"); 100} 101 102static void parse_cqm_event(struct nlattr **attrs) 103{ 104 static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = { 105 [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, 106 [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, 107 [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, 108 }; 109 struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1]; 110 struct nlattr *cqm_attr = attrs[NL80211_ATTR_CQM]; 111 112 printf("CQM event: "); 113 114 if (!cqm_attr || 115 nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, cqm_attr, cqm_policy)) { 116 printf("missing data!\n"); 117 return; 118 } 119 120 if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) { 121 enum nl80211_cqm_rssi_threshold_event rssi_event; 122 bool found_one = false; 123 124 rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); 125 126 switch (rssi_event) { 127 case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: 128 printf("RSSI went above threshold\n"); 129 found_one = true; 130 break; 131 case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: 132 printf("RSSI went below threshold\n"); 133 found_one = true; 134 break; 135 case NL80211_CQM_RSSI_BEACON_LOSS_EVENT: 136 printf("Beacon loss detected\n"); 137 found_one = true; 138 break; 139 } 140 141 if (!found_one) 142 printf("Unknown event type: %i\n", rssi_event); 143 } else if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT] && 144 attrs[NL80211_ATTR_MAC]) { 145 uint32_t frames; 146 char buf[3*6]; 147 148 frames = nla_get_u32(cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]); 149 mac_addr_n2a(buf, nla_data(attrs[NL80211_ATTR_MAC])); 150 printf("peer %s didn't ACK %d packets\n", buf, frames); 151 } else 152 printf("unknown event\n"); 153} 154 155static const char * key_type_str(enum nl80211_key_type key_type) 156{ 157 static char buf[30]; 158 switch (key_type) { 159 case NL80211_KEYTYPE_GROUP: 160 return "Group"; 161 case NL80211_KEYTYPE_PAIRWISE: 162 return "Pairwise"; 163 case NL80211_KEYTYPE_PEERKEY: 164 return "PeerKey"; 165 default: 166 snprintf(buf, sizeof(buf), "unknown(%d)", key_type); 167 return buf; 168 } 169} 170 171static void parse_mic_failure(struct nlattr **attrs) 172{ 173 printf("Michael MIC failure event:"); 174 175 if (attrs[NL80211_ATTR_MAC]) { 176 char addr[3 * ETH_ALEN]; 177 mac_addr_n2a(addr, nla_data(attrs[NL80211_ATTR_MAC])); 178 printf(" source MAC address %s", addr); 179 } 180 181 if (attrs[NL80211_ATTR_KEY_SEQ] && 182 nla_len(attrs[NL80211_ATTR_KEY_SEQ]) == 6) { 183 unsigned char *seq = nla_data(attrs[NL80211_ATTR_KEY_SEQ]); 184 printf(" seq=%02x%02x%02x%02x%02x%02x", 185 seq[0], seq[1], seq[2], seq[3], seq[4], seq[5]); 186 } 187 if (attrs[NL80211_ATTR_KEY_TYPE]) { 188 enum nl80211_key_type key_type = 189 nla_get_u32(attrs[NL80211_ATTR_KEY_TYPE]); 190 printf(" Key Type %s", key_type_str(key_type)); 191 } 192 193 if (attrs[NL80211_ATTR_KEY_IDX]) { 194 __u8 key_id = nla_get_u8(attrs[NL80211_ATTR_KEY_IDX]); 195 printf(" Key Id %d", key_id); 196 } 197 198 printf("\n"); 199} 200 201static void parse_wowlan_wake_event(struct nlattr **attrs) 202{ 203 struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG], 204 *tb_match[NUM_NL80211_ATTR]; 205 206 printf("WoWLAN wakeup\n"); 207 if (!attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { 208 printf("\twakeup not due to WoWLAN\n"); 209 return; 210 } 211 212 nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, 213 nla_data(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), 214 nla_len(attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), NULL); 215 216 if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) 217 printf("\t* was disconnected\n"); 218 if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) 219 printf("\t* magic packet received\n"); 220 if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) 221 printf("\t* pattern index: %u\n", 222 nla_get_u32(tb[NL80211_WOWLAN_TRIG_PKT_PATTERN])); 223 if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE]) 224 printf("\t* GTK rekey failure\n"); 225 if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) 226 printf("\t* EAP identity request\n"); 227 if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) 228 printf("\t* 4-way handshake\n"); 229 if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) 230 printf("\t* RF-kill released\n"); 231 if (tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS]) { 232 struct nlattr *match, *freq; 233 int rem_nst, rem_nst2; 234 235 printf("\t* network detected\n"); 236 nla_for_each_nested(match, 237 tb[NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS], 238 rem_nst) { 239 nla_parse(tb_match, NUM_NL80211_ATTR, nla_data(match), 240 nla_len(match), 241 NULL); 242 printf("\t\tSSID: \""); 243 print_ssid_escaped(nla_len(tb_match[NL80211_ATTR_SSID]), 244 nla_data(tb_match[NL80211_ATTR_SSID])); 245 printf("\""); 246 if (tb_match[NL80211_ATTR_SCAN_FREQUENCIES]) { 247 printf(" freq(s):"); 248 nla_for_each_nested(freq, 249 tb_match[NL80211_ATTR_SCAN_FREQUENCIES], 250 rem_nst2) 251 printf(" %d", nla_get_u32(freq)); 252 } 253 printf("\n"); 254 } 255 } 256 if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]) { 257 uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]); 258 int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_80211]); 259 int i; 260 printf("\t* packet (might be truncated): "); 261 for (i = 0; i < l; i++) { 262 if (i > 0) 263 printf(":"); 264 printf("%.2x", d[i]); 265 } 266 printf("\n"); 267 } 268 if (tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]) { 269 uint8_t *d = nla_data(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]); 270 int l = nla_len(tb[NL80211_WOWLAN_TRIG_WAKEUP_PKT_8023]); 271 int i; 272 printf("\t* packet (might be truncated): "); 273 for (i = 0; i < l; i++) { 274 if (i > 0) 275 printf(":"); 276 printf("%.2x", d[i]); 277 } 278 printf("\n"); 279 } 280 if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH]) 281 printf("\t* TCP connection wakeup received\n"); 282 if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST]) 283 printf("\t* TCP connection lost\n"); 284 if (tb[NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS]) 285 printf("\t* TCP connection ran out of tokens\n"); 286} 287 288static int print_event(struct nl_msg *msg, void *arg) 289{ 290 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 291 struct nlattr *tb[NL80211_ATTR_MAX + 1], *nst; 292 struct print_event_args *args = arg; 293 char ifname[100]; 294 char macbuf[6*3]; 295 __u8 reg_type; 296 struct ieee80211_beacon_channel chan_before_beacon, chan_after_beacon; 297 __u32 wiphy_idx = 0; 298 int rem_nst; 299 __u16 status; 300 301 if (args->time || args->reltime) { 302 unsigned long long usecs, previous; 303 304 previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; 305 gettimeofday(&args->ts, NULL); 306 usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; 307 if (args->reltime) { 308 if (!args->have_ts) { 309 usecs = 0; 310 args->have_ts = true; 311 } else 312 usecs -= previous; 313 } 314 printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); 315 } 316 317 nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 318 genlmsg_attrlen(gnlh, 0), NULL); 319 320 if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) { 321 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); 322 printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); 323 } else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY]) { 324 printf("wdev 0x%llx (phy #%d): ", 325 (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]), 326 nla_get_u32(tb[NL80211_ATTR_WIPHY])); 327 } else if (tb[NL80211_ATTR_IFINDEX]) { 328 if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); 329 printf("%s: ", ifname); 330 } else if (tb[NL80211_ATTR_WDEV]) { 331 printf("wdev 0x%llx: ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV])); 332 } else if (tb[NL80211_ATTR_WIPHY]) { 333 printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 334 } 335 336 switch (gnlh->cmd) { 337 case NL80211_CMD_NEW_WIPHY: 338 printf("renamed to %s\n", nla_get_string(tb[NL80211_ATTR_WIPHY_NAME])); 339 break; 340 case NL80211_CMD_TRIGGER_SCAN: 341 printf("scan started\n"); 342 break; 343 case NL80211_CMD_NEW_SCAN_RESULTS: 344 printf("scan finished:"); 345 case NL80211_CMD_SCAN_ABORTED: 346 if (gnlh->cmd == NL80211_CMD_SCAN_ABORTED) 347 printf("scan aborted:"); 348 if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { 349 nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem_nst) 350 printf(" %d", nla_get_u32(nst)); 351 printf(","); 352 } 353 if (tb[NL80211_ATTR_SCAN_SSIDS]) { 354 nla_for_each_nested(nst, tb[NL80211_ATTR_SCAN_SSIDS], rem_nst) { 355 printf(" \""); 356 print_ssid_escaped(nla_len(nst), nla_data(nst)); 357 printf("\""); 358 } 359 } 360 printf("\n"); 361 break; 362 case NL80211_CMD_REG_CHANGE: 363 printf("regulatory domain change: "); 364 365 reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); 366 367 switch (reg_type) { 368 case NL80211_REGDOM_TYPE_COUNTRY: 369 printf("set to %s by %s request", 370 nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]), 371 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 372 if (tb[NL80211_ATTR_WIPHY]) 373 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 374 break; 375 case NL80211_REGDOM_TYPE_WORLD: 376 printf("set to world roaming by %s request", 377 reg_initiator_to_string(nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]))); 378 break; 379 case NL80211_REGDOM_TYPE_CUSTOM_WORLD: 380 printf("custom world roaming rules in place on phy%d by %s request", 381 nla_get_u32(tb[NL80211_ATTR_WIPHY]), 382 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 383 break; 384 case NL80211_REGDOM_TYPE_INTERSECTION: 385 printf("intersection used due to a request made by %s", 386 reg_initiator_to_string(nla_get_u32(tb[NL80211_ATTR_REG_INITIATOR]))); 387 if (tb[NL80211_ATTR_WIPHY]) 388 printf(" on phy%d", nla_get_u32(tb[NL80211_ATTR_WIPHY])); 389 break; 390 default: 391 printf("unknown source (upgrade this utility)"); 392 break; 393 } 394 395 printf("\n"); 396 break; 397 case NL80211_CMD_REG_BEACON_HINT: 398 399 wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]); 400 401 memset(&chan_before_beacon, 0, sizeof(chan_before_beacon)); 402 memset(&chan_after_beacon, 0, sizeof(chan_after_beacon)); 403 404 if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_BEFORE], 405 &chan_before_beacon)) 406 break; 407 if (parse_beacon_hint_chan(tb[NL80211_ATTR_FREQ_AFTER], 408 &chan_after_beacon)) 409 break; 410 411 if (chan_before_beacon.center_freq != chan_after_beacon.center_freq) 412 break; 413 414 /* A beacon hint is sent _only_ if something _did_ change */ 415 printf("beacon hint:\n"); 416 417 printf("phy%d %d MHz [%d]:\n", 418 wiphy_idx, 419 chan_before_beacon.center_freq, 420 ieee80211_frequency_to_channel(chan_before_beacon.center_freq)); 421 422 if (chan_before_beacon.no_ir && !chan_after_beacon.no_ir) { 423 if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) 424 printf("\to Initiating radiation enabled\n"); 425 else 426 printf("\to active scan enabled\n"); 427 } else if (chan_before_beacon.no_ibss && !chan_after_beacon.no_ibss) { 428 printf("\to ibss enabled\n"); 429 } 430 431 break; 432 case NL80211_CMD_NEW_STATION: 433 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 434 printf("new station %s\n", macbuf); 435 break; 436 case NL80211_CMD_DEL_STATION: 437 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 438 printf("del station %s\n", macbuf); 439 break; 440 case NL80211_CMD_JOIN_IBSS: 441 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 442 printf("IBSS %s joined\n", macbuf); 443 break; 444 case NL80211_CMD_AUTHENTICATE: 445 printf("auth"); 446 if (tb[NL80211_ATTR_FRAME]) 447 print_frame(args, tb[NL80211_ATTR_FRAME]); 448 else if (tb[NL80211_ATTR_TIMED_OUT]) 449 printf(": timed out"); 450 else 451 printf(": unknown event"); 452 printf("\n"); 453 break; 454 case NL80211_CMD_ASSOCIATE: 455 printf("assoc"); 456 if (tb[NL80211_ATTR_FRAME]) 457 print_frame(args, tb[NL80211_ATTR_FRAME]); 458 else if (tb[NL80211_ATTR_TIMED_OUT]) 459 printf(": timed out"); 460 else 461 printf(": unknown event"); 462 printf("\n"); 463 break; 464 case NL80211_CMD_DEAUTHENTICATE: 465 printf("deauth"); 466 print_frame(args, tb[NL80211_ATTR_FRAME]); 467 printf("\n"); 468 break; 469 case NL80211_CMD_DISASSOCIATE: 470 printf("disassoc"); 471 print_frame(args, tb[NL80211_ATTR_FRAME]); 472 printf("\n"); 473 break; 474 case NL80211_CMD_UNPROT_DEAUTHENTICATE: 475 printf("unprotected deauth"); 476 print_frame(args, tb[NL80211_ATTR_FRAME]); 477 printf("\n"); 478 break; 479 case NL80211_CMD_UNPROT_DISASSOCIATE: 480 printf("unprotected disassoc"); 481 print_frame(args, tb[NL80211_ATTR_FRAME]); 482 printf("\n"); 483 break; 484 case NL80211_CMD_CONNECT: 485 status = 0; 486 if (!tb[NL80211_ATTR_STATUS_CODE]) 487 printf("unknown connect status"); 488 else if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == 0) 489 printf("connected"); 490 else { 491 status = nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]); 492 printf("failed to connect"); 493 } 494 if (tb[NL80211_ATTR_MAC]) { 495 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 496 printf(" to %s", macbuf); 497 } 498 if (status) 499 printf(", status: %d: %s", status, get_status_str(status)); 500 printf("\n"); 501 break; 502 case NL80211_CMD_ROAM: 503 printf("roamed"); 504 if (tb[NL80211_ATTR_MAC]) { 505 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 506 printf(" to %s", macbuf); 507 } 508 printf("\n"); 509 break; 510 case NL80211_CMD_DISCONNECT: 511 printf("disconnected"); 512 if (tb[NL80211_ATTR_DISCONNECTED_BY_AP]) 513 printf(" (by AP)"); 514 else 515 printf(" (local request)"); 516 if (tb[NL80211_ATTR_REASON_CODE]) 517 printf(" reason: %d: %s", nla_get_u16(tb[NL80211_ATTR_REASON_CODE]), 518 get_reason_str(nla_get_u16(tb[NL80211_ATTR_REASON_CODE]))); 519 printf("\n"); 520 break; 521 case NL80211_CMD_REMAIN_ON_CHANNEL: 522 printf("remain on freq %d (%dms, cookie %llx)\n", 523 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), 524 nla_get_u32(tb[NL80211_ATTR_DURATION]), 525 (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); 526 break; 527 case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: 528 printf("done with remain on freq %d (cookie %llx)\n", 529 nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), 530 (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); 531 break; 532 case NL80211_CMD_NOTIFY_CQM: 533 parse_cqm_event(tb); 534 break; 535 case NL80211_CMD_MICHAEL_MIC_FAILURE: 536 parse_mic_failure(tb); 537 break; 538 case NL80211_CMD_FRAME_TX_STATUS: 539 printf("mgmt TX status (cookie %llx): %s\n", 540 (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), 541 tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); 542 break; 543 case NL80211_CMD_PMKSA_CANDIDATE: 544 printf("PMKSA candidate found\n"); 545 break; 546 case NL80211_CMD_SET_WOWLAN: 547 parse_wowlan_wake_event(tb); 548 break; 549 case NL80211_CMD_PROBE_CLIENT: 550 if (tb[NL80211_ATTR_MAC]) 551 mac_addr_n2a(macbuf, nla_data(tb[NL80211_ATTR_MAC])); 552 else 553 strcpy(macbuf, "??"); 554 printf("probe client %s (cookie %llx): %s\n", 555 macbuf, 556 (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), 557 tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); 558 break; 559 case NL80211_CMD_VENDOR: 560 printf("vendor event %.6x:%d\n", 561 nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]), 562 nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD])); 563 if (args->frame && tb[NL80211_ATTR_VENDOR_DATA]) 564 iw_hexdump("vendor event", 565 nla_data(tb[NL80211_ATTR_VENDOR_DATA]), 566 nla_len(tb[NL80211_ATTR_VENDOR_DATA])); 567 break; 568 default: 569 printf("unknown event %d (%s)\n", 570 gnlh->cmd, command_name(gnlh->cmd)); 571 break; 572 } 573 574 fflush(stdout); 575 return NL_SKIP; 576} 577 578struct wait_event { 579 int n_cmds; 580 const __u32 *cmds; 581 __u32 cmd; 582 struct print_event_args *pargs; 583}; 584 585static int wait_event(struct nl_msg *msg, void *arg) 586{ 587 struct wait_event *wait = arg; 588 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 589 int i; 590 591 for (i = 0; i < wait->n_cmds; i++) { 592 if (gnlh->cmd == wait->cmds[i]) { 593 wait->cmd = gnlh->cmd; 594 if (wait->pargs) 595 print_event(msg, wait->pargs); 596 } 597 } 598 599 return NL_SKIP; 600} 601 602int __prepare_listen_events(struct nl80211_state *state) 603{ 604 int mcid, ret; 605 606 /* Configuration multicast group */ 607 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "config"); 608 if (mcid < 0) 609 return mcid; 610 611 ret = nl_socket_add_membership(state->nl_sock, mcid); 612 if (ret) 613 return ret; 614 615 /* Scan multicast group */ 616 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "scan"); 617 if (mcid >= 0) { 618 ret = nl_socket_add_membership(state->nl_sock, mcid); 619 if (ret) 620 return ret; 621 } 622 623 /* Regulatory multicast group */ 624 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "regulatory"); 625 if (mcid >= 0) { 626 ret = nl_socket_add_membership(state->nl_sock, mcid); 627 if (ret) 628 return ret; 629 } 630 631 /* MLME multicast group */ 632 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "mlme"); 633 if (mcid >= 0) { 634 ret = nl_socket_add_membership(state->nl_sock, mcid); 635 if (ret) 636 return ret; 637 } 638 639 mcid = nl_get_multicast_id(state->nl_sock, "nl80211", "vendor"); 640 if (mcid >= 0) { 641 ret = nl_socket_add_membership(state->nl_sock, mcid); 642 if (ret) 643 return ret; 644 } 645 646 return 0; 647} 648 649__u32 __do_listen_events(struct nl80211_state *state, 650 const int n_waits, const __u32 *waits, 651 struct print_event_args *args) 652{ 653 struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); 654 struct wait_event wait_ev; 655 656 if (!cb) { 657 fprintf(stderr, "failed to allocate netlink callbacks\n"); 658 return -ENOMEM; 659 } 660 661 /* no sequence checking for multicast messages */ 662 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL); 663 664 if (n_waits && waits) { 665 wait_ev.cmds = waits; 666 wait_ev.n_cmds = n_waits; 667 wait_ev.pargs = args; 668 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, wait_event, &wait_ev); 669 } else 670 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, print_event, args); 671 672 wait_ev.cmd = 0; 673 674 while (!wait_ev.cmd) 675 nl_recvmsgs(state->nl_sock, cb); 676 677 nl_cb_put(cb); 678 679 return wait_ev.cmd; 680} 681 682__u32 listen_events(struct nl80211_state *state, 683 const int n_waits, const __u32 *waits) 684{ 685 int ret; 686 687 ret = __prepare_listen_events(state); 688 if (ret) 689 return ret; 690 691 return __do_listen_events(state, n_waits, waits, NULL); 692} 693 694static int print_events(struct nl80211_state *state, 695 struct nl_cb *cb, 696 struct nl_msg *msg, 697 int argc, char **argv, 698 enum id_input id) 699{ 700 struct print_event_args args; 701 int ret; 702 703 memset(&args, 0, sizeof(args)); 704 705 argc--; 706 argv++; 707 708 while (argc > 0) { 709 if (strcmp(argv[0], "-f") == 0) 710 args.frame = true; 711 else if (strcmp(argv[0], "-t") == 0) 712 args.time = true; 713 else if (strcmp(argv[0], "-r") == 0) 714 args.reltime = true; 715 else 716 return 1; 717 argc--; 718 argv++; 719 } 720 721 if (args.time && args.reltime) 722 return 1; 723 724 if (argc) 725 return 1; 726 727 ret = __prepare_listen_events(state); 728 if (ret) 729 return ret; 730 731 return __do_listen_events(state, 0, NULL, &args); 732} 733TOPLEVEL(event, "[-t] [-r] [-f]", 0, 0, CIB_NONE, print_events, 734 "Monitor events from the kernel.\n" 735 "-t - print timestamp\n" 736 "-r - print relative timstamp\n" 737 "-f - print full frame for auth/assoc etc."); 738