From 6d5ce9fc90df8c7f27a80348e7362f930d28f987 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 18 Nov 2010 19:05:29 +0200 Subject: [PATCH] wlantest: Add BSS/STA statistics counters These counters can be cleared and queried from external programs to script various testing tasks. --- wlantest/ctrl.c | 185 +++++++++++++++++++++++++++ wlantest/rx_data.c | 1 + wlantest/rx_mgmt.c | 115 +++++++++++++---- wlantest/wlantest.h | 3 + wlantest/wlantest_cli.c | 268 +++++++++++++++++++++++++++++++++++++++ wlantest/wlantest_ctrl.h | 39 ++++++ 6 files changed, 585 insertions(+), 26 deletions(-) diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c index f2526eb2b..0ca720b9c 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -49,6 +49,21 @@ static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr, } +static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, + u32 val) +{ + if (pos == NULL || end - pos < 12) + return NULL; + WPA_PUT_BE32(pos, attr); + pos += 4; + WPA_PUT_BE32(pos, 4); + pos += 4; + WPA_PUT_BE32(pos, val); + pos += 4; + return pos; +} + + static void ctrl_disconnect(struct wlantest *wt, int sock) { int i; @@ -157,6 +172,164 @@ static void ctrl_flush(struct wlantest *wt, int sock) } +static void ctrl_clear_sta_counters(struct wlantest *wt, int sock, u8 *cmd, + size_t clen) +{ + u8 *addr; + size_t addr_len; + struct wlantest_bss *bss; + struct wlantest_sta *sta; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + bss = bss_get(wt, addr); + if (bss == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + addr = attr_get(cmd, clen, WLANTEST_ATTR_STA_ADDR, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + sta = sta_get(bss, addr); + if (sta == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + os_memset(sta->counters, 0, sizeof(sta->counters)); + ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS); +} + + +static void ctrl_clear_bss_counters(struct wlantest *wt, int sock, u8 *cmd, + size_t clen) +{ + u8 *addr; + size_t addr_len; + struct wlantest_bss *bss; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + bss = bss_get(wt, addr); + if (bss == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + os_memset(bss->counters, 0, sizeof(bss->counters)); + ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS); +} + + +static void ctrl_get_sta_counter(struct wlantest *wt, int sock, u8 *cmd, + size_t clen) +{ + u8 *addr; + size_t addr_len; + struct wlantest_bss *bss; + struct wlantest_sta *sta; + u32 counter; + u8 buf[4 + 12], *end, *pos; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + bss = bss_get(wt, addr); + if (bss == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + addr = attr_get(cmd, clen, WLANTEST_ATTR_STA_ADDR, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + sta = sta_get(bss, addr); + if (sta == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + addr = attr_get(cmd, clen, WLANTEST_ATTR_STA_COUNTER, &addr_len); + if (addr == NULL || addr_len != 4) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + counter = WPA_GET_BE32(addr); + if (counter >= NUM_WLANTEST_STA_COUNTER) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS); + pos += 4; + pos = attr_add_be32(pos, end, WLANTEST_ATTR_COUNTER, + sta->counters[counter]); + ctrl_send(wt, sock, buf, pos - buf); +} + + +static void ctrl_get_bss_counter(struct wlantest *wt, int sock, u8 *cmd, + size_t clen) +{ + u8 *addr; + size_t addr_len; + struct wlantest_bss *bss; + u32 counter; + u8 buf[4 + 12], *end, *pos; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_BSSID, &addr_len); + if (addr == NULL || addr_len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + bss = bss_get(wt, addr); + if (bss == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + addr = attr_get(cmd, clen, WLANTEST_ATTR_BSS_COUNTER, &addr_len); + if (addr == NULL || addr_len != 4) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + counter = WPA_GET_BE32(addr); + if (counter >= NUM_WLANTEST_BSS_COUNTER) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_SUCCESS); + pos += 4; + pos = attr_add_be32(pos, end, WLANTEST_ATTR_COUNTER, + bss->counters[counter]); + ctrl_send(wt, sock, buf, pos - buf); +} + + static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx) { struct wlantest *wt = eloop_ctx; @@ -204,6 +377,18 @@ static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx) case WLANTEST_CTRL_FLUSH: ctrl_flush(wt, sock); break; + case WLANTEST_CTRL_CLEAR_STA_COUNTERS: + ctrl_clear_sta_counters(wt, sock, buf + 4, len - 4); + break; + case WLANTEST_CTRL_CLEAR_BSS_COUNTERS: + ctrl_clear_bss_counters(wt, sock, buf + 4, len - 4); + break; + case WLANTEST_CTRL_GET_STA_COUNTER: + ctrl_get_sta_counter(wt, sock, buf + 4, len - 4); + break; + case WLANTEST_CTRL_GET_BSS_COUNTER: + ctrl_get_bss_counter(wt, sock, buf + 4, len - 4); + break; default: ctrl_send_simple(wt, sock, WLANTEST_CTRL_UNKNOWN_CMD); break; diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index 487d0527b..56c495470 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -149,6 +149,7 @@ static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta, wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR, MAC2STR(sta->addr), MAC2STR(bss->bssid)); + sta->counters[WLANTEST_STA_COUNTER_PTK_LEARNED]++; os_memcpy(&sta->ptk, &ptk, sizeof(ptk)); wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16); wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16); diff --git a/wlantest/rx_mgmt.c b/wlantest/rx_mgmt.c index 4e00630e7..45a0053ea 100644 --- a/wlantest/rx_mgmt.c +++ b/wlantest/rx_mgmt.c @@ -148,6 +148,11 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len) sta->state = STATE2; } } + + if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) + sta->counters[WLANTEST_STA_COUNTER_AUTH_RX]++; + else + sta->counters[WLANTEST_STA_COUNTER_AUTH_TX]++; } @@ -181,6 +186,13 @@ static void rx_mgmt_deauth(struct wlantest *wt, const u8 *data, size_t len, le_to_host16(mgmt->u.deauth.reason_code)); wpa_hexdump(MSG_MSGDUMP, "DEAUTH payload", data + 24, len - 24); + if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) + sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_RX : + WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX]++; + else + sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DEAUTH_TX : + WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX]++; + if (!valid) { wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State " "since Disassociation frame was not protected " @@ -224,6 +236,8 @@ static void rx_mgmt_assoc_req(struct wlantest *wt, const u8 *data, size_t len) le_to_host16(mgmt->u.assoc_req.capab_info), le_to_host16(mgmt->u.assoc_req.listen_interval)); + sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX]++; + if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable, len - (mgmt->u.assoc_req.variable - data), &elems, 0) == ParseFailed) { @@ -319,6 +333,8 @@ static void rx_mgmt_reassoc_req(struct wlantest *wt, const u8 *data, le_to_host16(mgmt->u.reassoc_req.listen_interval), MAC2STR(mgmt->u.reassoc_req.current_ap)); + sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX]++; + if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable, len - (mgmt->u.reassoc_req.variable - data), &elems, 0) == ParseFailed) { @@ -416,6 +432,13 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len, le_to_host16(mgmt->u.disassoc.reason_code)); wpa_hexdump(MSG_MSGDUMP, "DISASSOC payload", data + 24, len - 24); + if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) + sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_RX : + WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX]++; + else + sta->counters[valid ? WLANTEST_STA_COUNTER_VALID_DISASSOC_TX : + WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX]++; + if (!valid) { wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State " "since Disassociation frame was not protected " @@ -437,14 +460,71 @@ static void rx_mgmt_disassoc(struct wlantest *wt, const u8 *data, size_t len, } +static void rx_mgmt_action_sa_query_req(struct wlantest *wt, + struct wlantest_sta *sta, + const struct ieee80211_mgmt *mgmt, + size_t len, int valid) +{ + const u8 *rx_id; + u8 *id; + + rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id; + if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) + id = sta->ap_sa_query_tr; + else + id = sta->sta_sa_query_tr; + wpa_printf(MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR + " (trans_id=%02x%02x)%s", + MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1], + valid ? "" : " (invalid protection)"); + os_memcpy(id, mgmt->u.action.u.sa_query_req.trans_id, 2); + if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0) + sta->counters[valid ? + WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX : + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX]++; + else + sta->counters[valid ? + WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX : + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX]++; +} + + +static void rx_mgmt_action_sa_query_resp(struct wlantest *wt, + struct wlantest_sta *sta, + const struct ieee80211_mgmt *mgmt, + size_t len, int valid) +{ + const u8 *rx_id; + u8 *id; + int match; + + rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id; + if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) + id = sta->sta_sa_query_tr; + else + id = sta->ap_sa_query_tr; + match = os_memcmp(rx_id, id, 2) == 0; + wpa_printf(MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR + " (trans_id=%02x%02x; %s)%s", + MAC2STR(mgmt->sa), MAC2STR(mgmt->da), rx_id[0], rx_id[1], + match ? "match" : "mismatch", + valid ? "" : " (invalid protection)"); + if (os_memcmp(mgmt->sa, sta->addr, ETH_ALEN) == 0) + sta->counters[(valid && match) ? + WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX : + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX]++; + else + sta->counters[(valid && match) ? + WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX : + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX]++; +} + + static void rx_mgmt_action_sa_query(struct wlantest *wt, struct wlantest_sta *sta, const struct ieee80211_mgmt *mgmt, size_t len, int valid) { - const u8 *rx_id; - u8 *id; - if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) { wpa_printf(MSG_INFO, "Too short SA Query frame from " MACSTR, MAC2STR(mgmt->sa)); @@ -462,31 +542,10 @@ static void rx_mgmt_action_sa_query(struct wlantest *wt, switch (mgmt->u.action.u.sa_query_req.action) { case WLAN_SA_QUERY_REQUEST: - rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id; - if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) - id = sta->ap_sa_query_tr; - else - id = sta->sta_sa_query_tr; - wpa_printf(MSG_INFO, "SA Query Request " MACSTR " -> " MACSTR - " (trans_id=%02x%02x)%s", - MAC2STR(mgmt->sa), MAC2STR(mgmt->da), - rx_id[0], rx_id[1], - valid ? "" : " (invalid protection)"); - os_memcpy(id, mgmt->u.action.u.sa_query_req.trans_id, 2); + rx_mgmt_action_sa_query_req(wt, sta, mgmt, len, valid); break; case WLAN_SA_QUERY_RESPONSE: - rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id; - if (os_memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN) == 0) - id = sta->sta_sa_query_tr; - else - id = sta->ap_sa_query_tr; - wpa_printf(MSG_INFO, "SA Query Response " MACSTR " -> " MACSTR - " (trans_id=%02x%02x; %s)%s", - MAC2STR(mgmt->sa), MAC2STR(mgmt->da), - rx_id[0], rx_id[1], - os_memcmp(rx_id, id, 2) == 0 ? - "match" : "mismatch", - valid ? "" : " (invalid protection)"); + rx_mgmt_action_sa_query_resp(wt, sta, mgmt, len, valid); break; default: wpa_printf(MSG_INFO, "Unexpected SA Query action value %u " @@ -618,6 +677,7 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len) wpa_printf(MSG_INFO, "Robust group-addressed " "management frame sent without BIP by " MACSTR, MAC2STR(mgmt->sa)); + bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++; return -1; } return 0; @@ -633,6 +693,7 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len) if (keyid < 4 || keyid > 5) { wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR, keyid, MAC2STR(mgmt->sa)); + bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++; return 0; } wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid); @@ -654,11 +715,13 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len) if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) { wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from " MACSTR, MAC2STR(mgmt->sa)); + bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++; return -1; } wpa_printf(MSG_DEBUG, "Valid MMIE MIC"); os_memcpy(bss->ipn[keyid], mmie + 2, 6); + bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++; return 0; } diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 18c1ddd20..49e468b43 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -17,6 +17,7 @@ #include "utils/list.h" #include "common/wpa_common.h" +#include "wlantest_ctrl.h" struct ieee802_11_elems; struct radius_msg; @@ -67,6 +68,7 @@ struct wlantest_sta { u8 rsc_fromds[16 + 1][6]; u8 ap_sa_query_tr[2]; u8 sta_sa_query_tr[2]; + u32 counters[NUM_WLANTEST_STA_COUNTER]; }; struct wlantest_bss { @@ -93,6 +95,7 @@ struct wlantest_bss { u8 igtk[6][16]; int igtk_set[6]; u8 ipn[6][6]; + u32 counters[NUM_WLANTEST_BSS_COUNTER]; }; struct wlantest_radius { diff --git a/wlantest/wlantest_cli.c b/wlantest/wlantest_cli.c index ee8d0cc0a..cfd48bafa 100644 --- a/wlantest/wlantest_cli.c +++ b/wlantest/wlantest_cli.c @@ -46,6 +46,34 @@ static u8 * attr_get(u8 *buf, size_t buflen, enum wlantest_ctrl_attr attr, } +static u8 * attr_hdr_add(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, + size_t len) +{ + if (pos == NULL || end - pos < 8 + len) + return NULL; + WPA_PUT_BE32(pos, attr); + pos += 4; + WPA_PUT_BE32(pos, len); + pos += 4; + return pos; +} + + +static u8 * attr_add_be32(u8 *pos, u8 *end, enum wlantest_ctrl_attr attr, + u32 val) +{ + if (pos == NULL || end - pos < 12) + return NULL; + WPA_PUT_BE32(pos, attr); + pos += 4; + WPA_PUT_BE32(pos, 4); + pos += 4; + WPA_PUT_BE32(pos, val); + pos += 4; + return pos; +} + + static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len, u8 *resp, size_t max_resp_len) { @@ -169,6 +197,238 @@ static int cmd_flush(int s, int argc, char *argv[]) } +static int cmd_clear_sta_counters(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *pos; + int rlen; + + if (argc < 2) { + printf("clear_sta_counters needs two arguments: BSSID and " + "STA address\n"); + return -1; + } + + pos = buf; + WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_STA_COUNTERS); + pos += 4; + WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID); + pos += 4; + WPA_PUT_BE32(pos, ETH_ALEN); + pos += 4; + if (hwaddr_aton(argv[0], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[0]); + return -1; + } + pos += ETH_ALEN; + + WPA_PUT_BE32(pos, WLANTEST_ATTR_STA_ADDR); + pos += 4; + WPA_PUT_BE32(pos, ETH_ALEN); + pos += 4; + if (hwaddr_aton(argv[1], pos) < 0) { + printf("Invalid STA address '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); + if (rlen < 0) + return -1; + printf("OK\n"); + return 0; +} + + +static int cmd_clear_bss_counters(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *pos; + int rlen; + + if (argc < 1) { + printf("clear_bss_counters needs one argument: BSSID\n"); + return -1; + } + + pos = buf; + WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_BSS_COUNTERS); + pos += 4; + WPA_PUT_BE32(pos, WLANTEST_ATTR_BSSID); + pos += 4; + WPA_PUT_BE32(pos, ETH_ALEN); + pos += 4; + if (hwaddr_aton(argv[0], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[0]); + return -1; + } + pos += ETH_ALEN; + + rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); + if (rlen < 0) + return -1; + printf("OK\n"); + return 0; +} + + +struct sta_counters { + const char *name; + enum wlantest_sta_counter num; +}; + +static const struct sta_counters sta_counters[] = { + { "auth_tx", WLANTEST_STA_COUNTER_AUTH_TX }, + { "auth_rx", WLANTEST_STA_COUNTER_AUTH_RX }, + { "assocreq_tx", WLANTEST_STA_COUNTER_ASSOCREQ_TX }, + { "reassocreq_tx", WLANTEST_STA_COUNTER_REASSOCREQ_TX }, + { "ptk_learned", WLANTEST_STA_COUNTER_PTK_LEARNED }, + { "valid_deauth_tx", WLANTEST_STA_COUNTER_VALID_DEAUTH_TX }, + { "valid_deauth_rx", WLANTEST_STA_COUNTER_VALID_DEAUTH_RX }, + { "invalid_deauth_tx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX }, + { "invalid_deauth_rx", WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX }, + { "valid_disassoc_tx", WLANTEST_STA_COUNTER_VALID_DISASSOC_TX }, + { "valid_disassoc_rx", WLANTEST_STA_COUNTER_VALID_DISASSOC_RX }, + { "invalid_disassoc_tx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX }, + { "invalid_disassoc_rx", WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX }, + { "valid_saqueryreq_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX }, + { "valid_saqueryreq_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX }, + { "invalid_saqueryreq_tx", + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX }, + { "invalid_saqueryreq_rx", + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX }, + { "valid_saqueryresp_tx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX }, + { "valid_saqueryresp_rx", WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX }, + { "invalid_saqueryresp_tx", + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX }, + { "invalid_saqueryresp_rx", + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX }, + { NULL, 0 } +}; + +static int cmd_get_sta_counter(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *end, *pos; + int rlen, i; + size_t len; + + if (argc != 3) { + printf("get_sta_counter needs at three arguments: " + "counter name, BSSID, and STA address\n"); + return -1; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_STA_COUNTER); + pos += 4; + + for (i = 0; sta_counters[i].name; i++) { + if (os_strcasecmp(sta_counters[i].name, argv[0]) == 0) + break; + } + if (sta_counters[i].name == NULL) { + printf("Unknown STA counter '%s'\n", argv[0]); + printf("Counters:"); + for (i = 0; sta_counters[i].name; i++) + printf(" %s", sta_counters[i].name); + printf("\n"); + return -1; + } + + pos = attr_add_be32(pos, end, WLANTEST_ATTR_STA_COUNTER, + sta_counters[i].num); + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); + if (hwaddr_aton(argv[1], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); + if (hwaddr_aton(argv[2], pos) < 0) { + printf("Invalid STA address '%s'\n", argv[2]); + return -1; + } + pos += ETH_ALEN; + + rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); + if (rlen < 0) + return -1; + + pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len); + if (pos == NULL || len != 4) + return -1; + printf("%u\n", WPA_GET_BE32(pos)); + return 0; +} + + +struct bss_counters { + const char *name; + enum wlantest_bss_counter num; +}; + +static const struct bss_counters bss_counters[] = { + { "valid_bip_mmie", WLANTEST_BSS_COUNTER_VALID_BIP_MMIE }, + { "invalid_bip_mmie", WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE }, + { "missing_bip_mmie", WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE }, + { NULL, 0 } +}; + +static int cmd_get_bss_counter(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *end, *pos; + int rlen, i; + size_t len; + + if (argc != 2) { + printf("get_bss_counter needs at three arguments: " + "counter name and BSSID\n"); + return -1; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_BSS_COUNTER); + pos += 4; + + for (i = 0; bss_counters[i].name; i++) { + if (os_strcasecmp(bss_counters[i].name, argv[0]) == 0) + break; + } + if (bss_counters[i].name == NULL) { + printf("Unknown BSS counter '%s'\n", argv[0]); + printf("Counters:"); + for (i = 0; bss_counters[i].name; i++) + printf(" %s", bss_counters[i].name); + printf("\n"); + return -1; + } + + pos = attr_add_be32(pos, end, WLANTEST_ATTR_BSS_COUNTER, + bss_counters[i].num); + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); + if (hwaddr_aton(argv[1], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + rlen = cmd_send_and_recv(s, buf, pos - buf, resp, sizeof(resp)); + if (rlen < 0) + return -1; + + pos = attr_get(resp + 4, rlen - 4, WLANTEST_ATTR_COUNTER, &len); + if (pos == NULL || len != 4) + return -1; + printf("%u\n", WPA_GET_BE32(pos)); + return 0; +} + + struct wlantest_cli_cmd { const char *cmd; int (*handler)(int s, int argc, char *argv[]); @@ -181,6 +441,14 @@ static const struct wlantest_cli_cmd wlantest_cli_commands[] = { { "list_bss", cmd_list_bss, "= get BSS list" }, { "list_sta", cmd_list_sta, " = get STA list" }, { "flush", cmd_flush, "= drop all collected BSS data" }, + { "clear_sta_counters", cmd_clear_sta_counters, + " = clear STA counters" }, + { "clear_bss_counters", cmd_clear_bss_counters, + " = clear BSS counters" }, + { "get_sta_counter", cmd_get_sta_counter, + " = get STA counter value" }, + { "get_bss_counter", cmd_get_bss_counter, + " = get BSS counter value" }, { NULL, NULL, NULL } }; diff --git a/wlantest/wlantest_ctrl.h b/wlantest/wlantest_ctrl.h index 3e7d6cae9..6a9c99a11 100644 --- a/wlantest/wlantest_ctrl.h +++ b/wlantest/wlantest_ctrl.h @@ -29,11 +29,50 @@ enum wlantest_ctrl_cmd { WLANTEST_CTRL_LIST_BSS, WLANTEST_CTRL_LIST_STA, WLANTEST_CTRL_FLUSH, + WLANTEST_CTRL_CLEAR_STA_COUNTERS, + WLANTEST_CTRL_CLEAR_BSS_COUNTERS, + WLANTEST_CTRL_GET_STA_COUNTER, + WLANTEST_CTRL_GET_BSS_COUNTER, }; enum wlantest_ctrl_attr { WLANTEST_ATTR_BSSID, WLANTEST_ATTR_STA_ADDR, + WLANTEST_ATTR_STA_COUNTER, + WLANTEST_ATTR_BSS_COUNTER, + WLANTEST_ATTR_COUNTER, +}; + +enum wlantest_bss_counter { + WLANTEST_BSS_COUNTER_VALID_BIP_MMIE, + WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE, + WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE, + NUM_WLANTEST_BSS_COUNTER +}; + +enum wlantest_sta_counter { + WLANTEST_STA_COUNTER_AUTH_TX, + WLANTEST_STA_COUNTER_AUTH_RX, + WLANTEST_STA_COUNTER_ASSOCREQ_TX, + WLANTEST_STA_COUNTER_REASSOCREQ_TX, + WLANTEST_STA_COUNTER_PTK_LEARNED, + WLANTEST_STA_COUNTER_VALID_DEAUTH_TX, + WLANTEST_STA_COUNTER_VALID_DEAUTH_RX, + WLANTEST_STA_COUNTER_INVALID_DEAUTH_TX, + WLANTEST_STA_COUNTER_INVALID_DEAUTH_RX, + WLANTEST_STA_COUNTER_VALID_DISASSOC_TX, + WLANTEST_STA_COUNTER_VALID_DISASSOC_RX, + WLANTEST_STA_COUNTER_INVALID_DISASSOC_TX, + WLANTEST_STA_COUNTER_INVALID_DISASSOC_RX, + WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_TX, + WLANTEST_STA_COUNTER_VALID_SAQUERYREQ_RX, + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_TX, + WLANTEST_STA_COUNTER_INVALID_SAQUERYREQ_RX, + WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_TX, + WLANTEST_STA_COUNTER_VALID_SAQUERYRESP_RX, + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_TX, + WLANTEST_STA_COUNTER_INVALID_SAQUERYRESP_RX, + NUM_WLANTEST_STA_COUNTER }; #endif /* WLANTEST_CTRL_H */