X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fiw.git;a=blobdiff_plain;f=event.c;h=100f644d00d1a0ba41a30ea0c6376139ebf4a640;hp=507e3576338e46545f7434de0fb879a2dbe3398f;hb=HEAD;hpb=7c4e86ca4025f756ee359aea727d256d672e4000 diff --git a/event.c b/event.c old mode 100755 new mode 100644 index 507e357..fa2e125 --- a/event.c +++ b/event.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "iw.h" static int no_seq_check(struct nl_msg *msg, void *arg) @@ -122,17 +123,20 @@ static void parse_cqm_event(struct nlattr **attrs) if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]) { enum nl80211_cqm_rssi_threshold_event rssi_event; + int32_t rssi_level = -1; bool found_one = false; rssi_event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]); + if (cqm[NL80211_ATTR_CQM_RSSI_LEVEL]) + rssi_level = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_LEVEL]); switch (rssi_event) { case NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: - printf("RSSI went above threshold\n"); + printf("RSSI (%i dBm) went above threshold\n", rssi_level); found_one = true; break; case NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW: - printf("RSSI went below threshold\n"); + printf("RSSI (%i dBm) went below threshold\n", rssi_level); found_one = true; break; case NL80211_CQM_RSSI_BEACON_LOSS_EVENT: @@ -293,6 +297,51 @@ static void parse_wowlan_wake_event(struct nlattr **attrs) printf("\t* TCP connection ran out of tokens\n"); } +extern struct vendor_event *__start_vendor_event[]; +extern struct vendor_event *__stop_vendor_event; + +// Dummy to force the section to exist +VENDOR_EVENT(0xffffffff, 0xffffffff, NULL); + +static void parse_vendor_event(struct nlattr **attrs, bool dump) +{ + __u32 vendor_id, subcmd; + unsigned int i; + + if (!attrs[NL80211_ATTR_VENDOR_ID] || + !attrs[NL80211_ATTR_VENDOR_SUBCMD]) + return; + + vendor_id = nla_get_u32(attrs[NL80211_ATTR_VENDOR_ID]); + subcmd = nla_get_u32(attrs[NL80211_ATTR_VENDOR_SUBCMD]); + + printf("vendor event %.6x:%d", vendor_id, subcmd); + + for (i = 0; i < &__stop_vendor_event - __start_vendor_event; i++) { + struct vendor_event *ev = __start_vendor_event[i]; + + if (!ev) + continue; + + if (ev->vendor_id != vendor_id) + continue; + if (ev->subcmd != subcmd) + continue; + if (!ev->callback) + continue; + + ev->callback(vendor_id, subcmd, attrs[NL80211_ATTR_VENDOR_DATA]); + goto out; + } + + if (dump && attrs[NL80211_ATTR_VENDOR_DATA]) + iw_hexdump("vendor event", + nla_data(attrs[NL80211_ATTR_VENDOR_DATA]), + nla_len(attrs[NL80211_ATTR_VENDOR_DATA])); +out: + printf("\n"); +} + static void parse_nan_term(struct nlattr **attrs) { struct nlattr *func[NL80211_NAN_FUNC_ATTR_MAX + 1]; @@ -355,6 +404,205 @@ static void parse_nan_term(struct nlattr **attrs) } } +static const char *ftm_fail_reason(unsigned int reason) +{ +#define FTM_FAIL_REASON(x) case NL80211_PMSR_FTM_FAILURE_##x: return #x + switch (reason) { + FTM_FAIL_REASON(UNSPECIFIED); + FTM_FAIL_REASON(NO_RESPONSE); + FTM_FAIL_REASON(REJECTED); + FTM_FAIL_REASON(WRONG_CHANNEL); + FTM_FAIL_REASON(PEER_NOT_CAPABLE); + FTM_FAIL_REASON(INVALID_TIMESTAMP); + FTM_FAIL_REASON(PEER_BUSY); + FTM_FAIL_REASON(BAD_CHANGED_PARAMS); + default: + return "unknown"; + } +} + +static void parse_pmsr_ftm_data(struct nlattr *data) +{ + struct nlattr *ftm[NL80211_PMSR_FTM_RESP_ATTR_MAX + 1]; + + printf(" FTM"); + nla_parse_nested(ftm, NL80211_PMSR_FTM_RESP_ATTR_MAX, data, NULL); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON]) { + printf(" failed: %s (%d)", + ftm_fail_reason(nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])), + nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_FAIL_REASON])); + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME]) + printf(" retry after %us", + nla_get_u32(ftm[NL80211_PMSR_FTM_RESP_ATTR_BUSY_RETRY_TIME])); + printf("\n"); + return; + } + + printf("\n"); + +#define PFTM(tp, attr, sign) \ + do { \ + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr]) \ + printf(" " #attr ": %lld\n", \ + (sign long long)nla_get_##tp( \ + ftm[NL80211_PMSR_FTM_RESP_ATTR_##attr])); \ + } while (0) + + PFTM(u32, BURST_INDEX, unsigned); + PFTM(u32, NUM_FTMR_ATTEMPTS, unsigned); + PFTM(u32, NUM_FTMR_SUCCESSES, unsigned); + PFTM(u8, NUM_BURSTS_EXP, unsigned); + PFTM(u8, BURST_DURATION, unsigned); + PFTM(u8, FTMS_PER_BURST, unsigned); + PFTM(u32, RSSI_AVG, signed); + PFTM(u32, RSSI_SPREAD, unsigned); + PFTM(u64, RTT_AVG, signed); + PFTM(u64, RTT_VARIANCE, unsigned); + PFTM(u64, RTT_SPREAD, unsigned); + PFTM(u64, DIST_AVG, signed); + PFTM(u64, DIST_VARIANCE, unsigned); + PFTM(u64, DIST_SPREAD, unsigned); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE]) { + char buf[100]; + + parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_TX_RATE], + buf, sizeof(buf)); + printf(" TX bitrate: %s\n", buf); + } + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE]) { + char buf[100]; + + parse_bitrate(ftm[NL80211_PMSR_FTM_RESP_ATTR_RX_RATE], + buf, sizeof(buf)); + printf(" RX bitrate: %s\n", buf); + } + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]) + iw_hexdump(" LCI", + nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI]), + nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_LCI])); + + if (ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]) + iw_hexdump(" civic location", + nla_data(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC]), + nla_len(ftm[NL80211_PMSR_FTM_RESP_ATTR_CIVICLOC])); +} + +static const char *pmsr_status(unsigned int status) +{ +#define PMSR_STATUS(x) case NL80211_PMSR_STATUS_##x: return #x + switch (status) { + PMSR_STATUS(SUCCESS); + PMSR_STATUS(REFUSED); + PMSR_STATUS(TIMEOUT); + PMSR_STATUS(FAILURE); + default: + return "unknown"; + } +#undef PMSR_STATUS +} + +static void parse_pmsr_peer(struct nlattr *peer) +{ + struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1]; + struct nlattr *resp[NL80211_PMSR_RESP_ATTR_MAX + 1]; + struct nlattr *data[NL80211_PMSR_TYPE_MAX + 1]; + char macbuf[6*3]; + int err; + + err = nla_parse_nested(tb, NL80211_PMSR_PEER_ATTR_MAX, peer, NULL); + if (err) { + printf(" Peer: failed to parse!\n"); + return; + } + + if (!tb[NL80211_PMSR_PEER_ATTR_ADDR]) { + printf(" Peer: no MAC address\n"); + return; + } + + mac_addr_n2a(macbuf, nla_data(tb[NL80211_PMSR_PEER_ATTR_ADDR])); + printf(" Peer %s:", macbuf); + + if (!tb[NL80211_PMSR_PEER_ATTR_RESP]) { + printf(" no response!\n"); + return; + } + + err = nla_parse_nested(resp, NL80211_PMSR_RESP_ATTR_MAX, + tb[NL80211_PMSR_PEER_ATTR_RESP], NULL); + if (err) { + printf(" failed to parse response!\n"); + return; + } + + if (resp[NL80211_PMSR_RESP_ATTR_STATUS]) + printf(" status=%d (%s)", + nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]), + pmsr_status(nla_get_u32(resp[NL80211_PMSR_RESP_ATTR_STATUS]))); + if (resp[NL80211_PMSR_RESP_ATTR_HOST_TIME]) + printf(" @%llu", + (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_HOST_TIME])); + if (resp[NL80211_PMSR_RESP_ATTR_AP_TSF]) + printf(" tsf=%llu", + (unsigned long long)nla_get_u64(resp[NL80211_PMSR_RESP_ATTR_AP_TSF])); + if (resp[NL80211_PMSR_RESP_ATTR_FINAL]) + printf(" (final)"); + + if (!resp[NL80211_PMSR_RESP_ATTR_DATA]) { + printf(" - no data!\n"); + return; + } + + printf("\n"); + + nla_parse_nested(data, NL80211_PMSR_TYPE_MAX, + resp[NL80211_PMSR_RESP_ATTR_DATA], NULL); + + if (data[NL80211_PMSR_TYPE_FTM]) + parse_pmsr_ftm_data(data[NL80211_PMSR_TYPE_FTM]); +} + +static void parse_pmsr_result(struct nlattr **tb, + struct print_event_args *pargs) +{ + struct nlattr *pmsr[NL80211_PMSR_ATTR_MAX + 1]; + struct nlattr *peer; + unsigned long long cookie; + int err, i; + + if (!tb[NL80211_ATTR_COOKIE]) { + printf("Peer measurements: no cookie!\n"); + return; + } + cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]); + + if (!tb[NL80211_ATTR_PEER_MEASUREMENTS]) { + printf("Peer measurements: no measurement data!\n"); + return; + } + + err = nla_parse_nested(pmsr, NL80211_PMSR_ATTR_MAX, + tb[NL80211_ATTR_PEER_MEASUREMENTS], NULL); + if (err) { + printf("Peer measurements: failed to parse measurement data!\n"); + return; + } + + if (!pmsr[NL80211_PMSR_ATTR_PEERS]) { + printf("Peer measurements: no peer data!\n"); + return; + } + + printf("Peer measurements (cookie %llu):\n", cookie); + + nla_for_each_nested(peer, pmsr[NL80211_PMSR_ATTR_PEERS], i) + parse_pmsr_peer(peer); +} + static void parse_nan_match(struct nlattr **attrs) { char macbuf[6*3]; @@ -415,19 +663,19 @@ static void parse_nan_match(struct nlattr **attrs) if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == NL80211_NAN_FUNC_PUBLISH) { printf( - "NAN(cookie=0x%llx): DiscoveryResult, peer_id=%d, local_id=%d, peer_mac=%s, ", + "NAN(cookie=0x%llx): DiscoveryResult, peer_id=%d, local_id=%d, peer_mac=%s", cookie, nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), macbuf); if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO]) - printf("info=%.*s", + printf(", info=%.*s", nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]), (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO])); } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == NL80211_NAN_FUNC_SUBSCRIBE) { printf( - "NAN(cookie=0x%llx): Replied, peer_id=%d, local_id=%d, peer_mac=%s\n", + "NAN(cookie=0x%llx): Replied, peer_id=%d, local_id=%d, peer_mac=%s", cookie, nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), @@ -435,18 +683,229 @@ static void parse_nan_match(struct nlattr **attrs) } else if (nla_get_u8(peer_func[NL80211_NAN_FUNC_TYPE]) == NL80211_NAN_FUNC_FOLLOW_UP) { printf( - "NAN(cookie=0x%llx): FollowUpReceive, peer_id=%d, local_id=%d, peer_mac=%s, ", + "NAN(cookie=0x%llx): FollowUpReceive, peer_id=%d, local_id=%d, peer_mac=%s", cookie, nla_get_u8(peer_func[NL80211_NAN_FUNC_INSTANCE_ID]), nla_get_u8(local_func[NL80211_NAN_FUNC_INSTANCE_ID]), macbuf); if (peer_func[NL80211_NAN_FUNC_SERVICE_INFO]) - printf("info=%.*s", + printf(", info=%.*s", nla_len(peer_func[NL80211_NAN_FUNC_SERVICE_INFO]), (char *)nla_data(peer_func[NL80211_NAN_FUNC_SERVICE_INFO])); } else { - printf("NaN: Malformed event\n"); + printf("NaN: Malformed event"); + } + + printf("\n"); +} + +static void parse_new_peer_candidate(struct nlattr **attrs) +{ + char macbuf[ETH_ALEN * 3]; + int32_t sig_dbm; + + printf("new peer candidate"); + if (attrs[NL80211_ATTR_MAC]) { + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + printf(" %s", macbuf); + } + if (attrs[NL80211_ATTR_RX_SIGNAL_DBM]) { + sig_dbm = nla_get_u32(attrs[NL80211_ATTR_RX_SIGNAL_DBM]); + printf(" %d dBm", sig_dbm); + } + + printf("\n"); +} + +static void parse_recv_interface(struct nlattr **attrs, int command) +{ + switch (command) { + case NL80211_CMD_NEW_INTERFACE: + printf("new interface"); + break; + case NL80211_CMD_DEL_INTERFACE: + printf("del interface"); + break; + case NL80211_CMD_SET_INTERFACE: + printf("set interface"); + break; + default: + printf("unknown interface command (%i) received\n", command); + return; + } + + if (attrs[NL80211_ATTR_IFTYPE]) { + printf(" type "); + switch (nla_get_u32(attrs[NL80211_ATTR_IFTYPE])) { + case NL80211_IFTYPE_STATION: + printf("station"); + break; + case NL80211_IFTYPE_AP: + printf("access point"); + break; + case NL80211_IFTYPE_MESH_POINT: + printf("mesh point"); + break; + case NL80211_IFTYPE_ADHOC: + printf("IBSS"); + break; + case NL80211_IFTYPE_MONITOR: + printf("monitor"); + break; + case NL80211_IFTYPE_AP_VLAN: + printf("AP-VLAN"); + break; + case NL80211_IFTYPE_WDS: + printf("WDS"); + break; + case NL80211_IFTYPE_P2P_CLIENT: + printf("P2P-client"); + break; + case NL80211_IFTYPE_P2P_GO: + printf("P2P-GO"); + break; + case NL80211_IFTYPE_P2P_DEVICE: + printf("P2P-Device"); + break; + case NL80211_IFTYPE_OCB: + printf("OCB"); + break; + case NL80211_IFTYPE_NAN: + printf("NAN"); + break; + default: + printf("unknown (%d)", + nla_get_u32(attrs[NL80211_ATTR_IFTYPE])); + break; + } + } + + if (attrs[NL80211_ATTR_MESH_ID]) { + printf(" meshid "); + print_ssid_escaped(nla_len(attrs[NL80211_ATTR_MESH_ID]), + nla_data(attrs[NL80211_ATTR_MESH_ID])); + } + + if (attrs[NL80211_ATTR_4ADDR]) { + printf(" use 4addr %d", nla_get_u8(attrs[NL80211_ATTR_4ADDR])); + } + + printf("\n"); +} + +static void parse_sta_opmode_changed(struct nlattr **attrs) +{ + char macbuf[ETH_ALEN*3]; + + printf("sta opmode changed"); + + if (attrs[NL80211_ATTR_MAC]) { + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + printf(" %s", macbuf); + } + + if (attrs[NL80211_ATTR_SMPS_MODE]) + printf(" smps mode %d", nla_get_u8(attrs[NL80211_ATTR_SMPS_MODE])); + + if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) + printf(" chan width %d", nla_get_u8(attrs[NL80211_ATTR_CHANNEL_WIDTH])); + + if (attrs[NL80211_ATTR_NSS]) + printf(" nss %d", nla_get_u8(attrs[NL80211_ATTR_NSS])); + + printf("\n"); +} + +static void parse_ch_switch_notify(struct nlattr **attrs, int command) +{ + switch (command) { + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + printf("channel switch started"); + break; + case NL80211_CMD_CH_SWITCH_NOTIFY: + printf("channel switch"); + break; + default: + printf("unknown channel switch command (%i) received\n", command); + return; + } + + if (attrs[NL80211_ATTR_CH_SWITCH_COUNT]) + printf(" (count=%d)", nla_get_u32(attrs[NL80211_ATTR_CH_SWITCH_COUNT])); + + if (attrs[NL80211_ATTR_WIPHY_FREQ]) + printf(" freq=%d", nla_get_u32(attrs[NL80211_ATTR_WIPHY_FREQ])); + + if (attrs[NL80211_ATTR_CHANNEL_WIDTH]) { + printf(" width="); + switch(nla_get_u32(attrs[NL80211_ATTR_CHANNEL_WIDTH])) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + printf("\"20 MHz\""); + break; + case NL80211_CHAN_WIDTH_40: + printf("\"40 MHz\""); + break; + case NL80211_CHAN_WIDTH_80: + printf("\"80 MHz\""); + break; + case NL80211_CHAN_WIDTH_80P80: + printf("\"80+80 MHz\""); + break; + case NL80211_CHAN_WIDTH_160: + printf("\"160 MHz\""); + break; + case NL80211_CHAN_WIDTH_5: + printf("\"5 MHz\""); + break; + case NL80211_CHAN_WIDTH_10: + printf("\"10 MHz\""); + break; + default: + printf("\"unknown\""); + } } + + if (attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + printf(" type="); + switch(nla_get_u32(attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) { + case NL80211_CHAN_NO_HT: + printf("\"No HT\""); + break; + case NL80211_CHAN_HT20: + printf("\"HT20\""); + break; + case NL80211_CHAN_HT40MINUS: + printf("\"HT40-\""); + break; + case NL80211_CHAN_HT40PLUS: + printf("\"HT40+\""); + break; + } + } + + if (attrs[NL80211_ATTR_CENTER_FREQ1]) + printf(" freq1=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ1])); + + if (attrs[NL80211_ATTR_CENTER_FREQ2]) + printf(" freq2=%d", nla_get_u32(attrs[NL80211_ATTR_CENTER_FREQ2])); + + printf("\n"); +} + +static void parse_assoc_comeback(struct nlattr **attrs, int command) +{ + __u32 timeout = 0; + char macbuf[6 * 3] = ""; + + if (attrs[NL80211_ATTR_MAC]) + mac_addr_n2a(macbuf, nla_data(attrs[NL80211_ATTR_MAC])); + + if (attrs[NL80211_ATTR_TIMEOUT]) + timeout = nla_get_u32(attrs[NL80211_ATTR_TIMEOUT]); + + printf("assoc comeback bssid %s timeout %d\n", + macbuf, timeout); } static int print_event(struct nl_msg *msg, void *arg) @@ -462,12 +921,13 @@ static int print_event(struct nl_msg *msg, void *arg) int rem_nst; __u16 status; - if (args->time || args->reltime) { + if (args->time || args->reltime || args->ctime) { unsigned long long usecs, previous; previous = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; gettimeofday(&args->ts, NULL); usecs = 1000000ULL * args->ts.tv_sec + args->ts.tv_usec; + if (args->reltime) { if (!args->have_ts) { usecs = 0; @@ -475,15 +935,28 @@ static int print_event(struct nl_msg *msg, void *arg) } else usecs -= previous; } - printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); + + if (args->ctime) { + struct tm *tm = localtime(&args->ts.tv_sec); + char buf[255]; + + memset(buf, 0, 255); + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); + printf("[%s.%06lu]: ", buf, (unsigned long )args->ts.tv_usec); + } else { + printf("%llu.%06llu: ", usecs/1000000, usecs % 1000000); + } } nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL); if (tb[NL80211_ATTR_IFINDEX] && tb[NL80211_ATTR_WIPHY]) { - if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname); - printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); + /* if_indextoname may fails on delete interface/wiphy event */ + if (if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), ifname)) + printf("%s (phy #%d): ", ifname, nla_get_u32(tb[NL80211_ATTR_WIPHY])); + else + printf("phy #%d: ", nla_get_u32(tb[NL80211_ATTR_WIPHY])); } else if (tb[NL80211_ATTR_WDEV] && tb[NL80211_ATTR_WIPHY]) { printf("wdev 0x%llx (phy #%d): ", (unsigned long long)nla_get_u64(tb[NL80211_ATTR_WDEV]), @@ -533,8 +1006,12 @@ static int print_event(struct nl_msg *msg, void *arg) case NL80211_CMD_SCHED_SCAN_RESULTS: printf("got scheduled scan results\n"); break; + case NL80211_CMD_WIPHY_REG_CHANGE: case NL80211_CMD_REG_CHANGE: - printf("regulatory domain change: "); + if (gnlh->cmd == NL80211_CMD_WIPHY_REG_CHANGE) + printf("regulatory domain change (phy): "); + else + printf("regulatory domain change: "); reg_type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]); @@ -705,6 +1182,11 @@ static int print_event(struct nl_msg *msg, void *arg) nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); break; + case NL80211_CMD_FRAME_WAIT_CANCEL: + printf("frame wait cancel on freq %d (cookie %llx)\n", + nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]), + (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE])); + break; case NL80211_CMD_NOTIFY_CQM: parse_cqm_event(tb); break; @@ -716,6 +1198,11 @@ static int print_event(struct nl_msg *msg, void *arg) (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); break; + case NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: + printf("ctrl. port TX status (cookie %llx): %s\n", + (unsigned long long)nla_get_u64(tb[NL80211_ATTR_COOKIE]), + tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); + break; case NL80211_CMD_PMKSA_CANDIDATE: printf("PMKSA candidate found\n"); break; @@ -733,13 +1220,7 @@ static int print_event(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_ACK] ? "acked" : "no ack"); break; case NL80211_CMD_VENDOR: - printf("vendor event %.6x:%d\n", - nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]), - nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD])); - if (args->frame && tb[NL80211_ATTR_VENDOR_DATA]) - iw_hexdump("vendor event", - nla_data(tb[NL80211_ATTR_VENDOR_DATA]), - nla_len(tb[NL80211_ATTR_VENDOR_DATA])); + parse_vendor_event(tb, args->frame); break; case NL80211_CMD_RADAR_DETECT: { enum nl80211_radar_event event_type; @@ -767,6 +1248,12 @@ static int print_event(struct nl_msg *msg, void *arg) case NL80211_RADAR_NOP_FINISHED: printf("%d MHz: NOP finished\n", freq); break; + case NL80211_RADAR_PRE_CAC_EXPIRED: + printf("%d MHz: PRE-CAC expired\n", freq); + break; + case NL80211_RADAR_CAC_STARTED: + printf("%d MHz: CAC started\n", freq); + break; default: printf("%d MHz: unknown radar event\n", freq); } @@ -775,13 +1262,39 @@ static int print_event(struct nl_msg *msg, void *arg) case NL80211_CMD_DEL_WIPHY: printf("delete wiphy\n"); break; + case NL80211_CMD_PEER_MEASUREMENT_RESULT: + parse_pmsr_result(tb, args); + break; + case NL80211_CMD_PEER_MEASUREMENT_COMPLETE: + printf("peer measurement complete\n"); + break; case NL80211_CMD_DEL_NAN_FUNCTION: parse_nan_term(tb); break; - case NL80211_CMD_NAN_MATCH: { + case NL80211_CMD_NAN_MATCH: parse_nan_match(tb); break; - } + case NL80211_CMD_NEW_PEER_CANDIDATE: + parse_new_peer_candidate(tb); + break; + case NL80211_CMD_NEW_INTERFACE: + case NL80211_CMD_SET_INTERFACE: + case NL80211_CMD_DEL_INTERFACE: + parse_recv_interface(tb, gnlh->cmd); + break; + case NL80211_CMD_STA_OPMODE_CHANGED: + parse_sta_opmode_changed(tb); + break; + case NL80211_CMD_STOP_AP: + printf("stop ap\n"); + break; + case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: + case NL80211_CMD_CH_SWITCH_NOTIFY: + parse_ch_switch_notify(tb, gnlh->cmd); + break; + case NL80211_CMD_ASSOC_COMEBACK: /* 147 */ + parse_assoc_comeback(tb, gnlh->cmd); + break; default: printf("unknown event %d (%s)\n", gnlh->cmd, command_name(gnlh->cmd)); @@ -793,8 +1306,9 @@ static int print_event(struct nl_msg *msg, void *arg) } struct wait_event { - int n_cmds; + int n_cmds, n_prints; const __u32 *cmds; + const __u32 *prints; __u32 cmd; struct print_event_args *pargs; }; @@ -805,14 +1319,18 @@ static int wait_event(struct nl_msg *msg, void *arg) struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); int i; - for (i = 0; i < wait->n_cmds; i++) { - if (gnlh->cmd == wait->cmds[i]) { - wait->cmd = gnlh->cmd; - if (wait->pargs) + if (wait->pargs) { + for (i = 0; i < wait->n_prints; i++) { + if (gnlh->cmd == wait->prints[i]) print_event(msg, wait->pargs); } } + for (i = 0; i < wait->n_cmds; i++) { + if (gnlh->cmd == wait->cmds[i]) + wait->cmd = gnlh->cmd; + } + return NL_SKIP; } @@ -872,6 +1390,7 @@ int __prepare_listen_events(struct nl80211_state *state) __u32 __do_listen_events(struct nl80211_state *state, const int n_waits, const __u32 *waits, + const int n_prints, const __u32 *prints, struct print_event_args *args) { struct nl_cb *cb = nl_cb_alloc(iw_debug ? NL_CB_DEBUG : NL_CB_DEFAULT); @@ -889,6 +1408,8 @@ __u32 __do_listen_events(struct nl80211_state *state, if (n_waits && waits) { wait_ev.cmds = waits; wait_ev.n_cmds = n_waits; + wait_ev.prints = prints; + wait_ev.n_prints = n_prints; wait_ev.pargs = args; register_handler(wait_event, &wait_ev); } else @@ -913,7 +1434,7 @@ __u32 listen_events(struct nl80211_state *state, if (ret) return ret; - return __do_listen_events(state, n_waits, waits, NULL); + return __do_listen_events(state, n_waits, waits, 0, NULL, NULL); } static int print_events(struct nl80211_state *state, @@ -922,6 +1443,7 @@ static int print_events(struct nl80211_state *state, enum id_input id) { struct print_event_args args; + int num_time_formats = 0; int ret; memset(&args, 0, sizeof(args)); @@ -932,17 +1454,22 @@ static int print_events(struct nl80211_state *state, while (argc > 0) { if (strcmp(argv[0], "-f") == 0) args.frame = true; - else if (strcmp(argv[0], "-t") == 0) + else if (strcmp(argv[0], "-t") == 0) { + num_time_formats++; args.time = true; - else if (strcmp(argv[0], "-r") == 0) + } else if (strcmp(argv[0], "-T") == 0) { + num_time_formats++; + args.ctime = true; + } else if (strcmp(argv[0], "-r") == 0) { + num_time_formats++; args.reltime = true; - else + } else return 1; argc--; argv++; } - if (args.time && args.reltime) + if (num_time_formats > 1) return 1; if (argc) @@ -952,10 +1479,11 @@ static int print_events(struct nl80211_state *state, if (ret) return ret; - return __do_listen_events(state, 0, NULL, &args); + return __do_listen_events(state, 0, NULL, 0, NULL, &args); } -TOPLEVEL(event, "[-t|-r] [-f]", 0, 0, CIB_NONE, print_events, +TOPLEVEL(event, "[-t|-T|-r] [-f]", 0, 0, CIB_NONE, print_events, "Monitor events from the kernel.\n" "-t - print timestamp\n" - "-r - print relative timstamp\n" + "-T - print absolute, human-readable timestamp\n" + "-r - print relative timestamp\n" "-f - print full frame for auth/assoc etc.");