]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
wlantest: Add BSS/STA statistics counters
authorJouni Malinen <jouni.malinen@atheros.com>
Thu, 18 Nov 2010 17:05:29 +0000 (19:05 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 18 Nov 2010 17:05:29 +0000 (19:05 +0200)
These counters can be cleared and queried from external programs to
script various testing tasks.

wlantest/ctrl.c
wlantest/rx_data.c
wlantest/rx_mgmt.c
wlantest/wlantest.h
wlantest/wlantest_cli.c
wlantest/wlantest_ctrl.h

index f2526eb2b1dbbe49a586e5e3e4e5cc58b14483c4..0ca720b9c9472d2088b8ff802baec5eeb539b9b1 100644 (file)
@@ -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;
index 487d0527b564ef12a33f41fbf4cda19e36ffbcc4..56c495470629f3d83c4e3e2a31e0b354a479e79e 100644 (file)
@@ -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);
index 4e00630e73b94d2b4fceb12c8068037b87db7c7b..45a0053ea3edb310f1bd521ed55ad5f060b28d34 100644 (file)
@@ -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;
 }
index 18c1ddd204be6a152801c3ea0af5c222a5bf84ac..49e468b43fc79dee0063c8a1abe283e31024d08b 100644 (file)
@@ -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 {
index ee8d0cc0a6b28095b6352cac6c41fe2c2cba6bc5..cfd48bafa118729e6becaada9303778eddda4545 100644 (file)
@@ -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, "<BSSID> = get STA list" },
        { "flush", cmd_flush, "= drop all collected BSS data" },
+       { "clear_sta_counters", cmd_clear_sta_counters,
+         "<BSSID> <STA> = clear STA counters" },
+       { "clear_bss_counters", cmd_clear_bss_counters,
+         "<BSSID> = clear BSS counters" },
+       { "get_sta_counter", cmd_get_sta_counter,
+         "<counter> <BSSID> <STA> = get STA counter value" },
+       { "get_bss_counter", cmd_get_bss_counter,
+         "<counter> <BSSID> = get BSS counter value" },
        { NULL, NULL, NULL }
 };
 
index 3e7d6cae9fc14e551c2cbe373c343c910a3fa67c..6a9c99a113799c0279ab028fc1c1b52b31560703 100644 (file)
@@ -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 */