wlantest: Add BSS/STA statistics counters

These counters can be cleared and queried from external programs to
script various testing tasks.
This commit is contained in:
Jouni Malinen 2010-11-18 19:05:29 +02:00 committed by Jouni Malinen
parent d356bd630b
commit 6d5ce9fc90
6 changed files with 585 additions and 26 deletions

View 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) static void ctrl_disconnect(struct wlantest *wt, int sock)
{ {
int i; 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) static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx)
{ {
struct wlantest *wt = eloop_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: case WLANTEST_CTRL_FLUSH:
ctrl_flush(wt, sock); ctrl_flush(wt, sock);
break; 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: default:
ctrl_send_simple(wt, sock, WLANTEST_CTRL_UNKNOWN_CMD); ctrl_send_simple(wt, sock, WLANTEST_CTRL_UNKNOWN_CMD);
break; break;

View 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, wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR,
MAC2STR(sta->addr), MAC2STR(bss->bssid)); MAC2STR(sta->addr), MAC2STR(bss->bssid));
sta->counters[WLANTEST_STA_COUNTER_PTK_LEARNED]++;
os_memcpy(&sta->ptk, &ptk, sizeof(ptk)); os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16); wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16); wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);

View file

@ -148,6 +148,11 @@ static void rx_mgmt_auth(struct wlantest *wt, const u8 *data, size_t len)
sta->state = STATE2; 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)); le_to_host16(mgmt->u.deauth.reason_code));
wpa_hexdump(MSG_MSGDUMP, "DEAUTH payload", data + 24, len - 24); 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) { if (!valid) {
wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State " wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
"since Disassociation frame was not protected " "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.capab_info),
le_to_host16(mgmt->u.assoc_req.listen_interval)); 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, if (ieee802_11_parse_elems(mgmt->u.assoc_req.variable,
len - (mgmt->u.assoc_req.variable - data), len - (mgmt->u.assoc_req.variable - data),
&elems, 0) == ParseFailed) { &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), le_to_host16(mgmt->u.reassoc_req.listen_interval),
MAC2STR(mgmt->u.reassoc_req.current_ap)); MAC2STR(mgmt->u.reassoc_req.current_ap));
sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX]++;
if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable, if (ieee802_11_parse_elems(mgmt->u.reassoc_req.variable,
len - (mgmt->u.reassoc_req.variable - data), len - (mgmt->u.reassoc_req.variable - data),
&elems, 0) == ParseFailed) { &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)); le_to_host16(mgmt->u.disassoc.reason_code));
wpa_hexdump(MSG_MSGDUMP, "DISASSOC payload", data + 24, len - 24); 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) { if (!valid) {
wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State " wpa_printf(MSG_INFO, "Do not change STA " MACSTR " State "
"since Disassociation frame was not protected " "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, static void rx_mgmt_action_sa_query(struct wlantest *wt,
struct wlantest_sta *sta, struct wlantest_sta *sta,
const struct ieee80211_mgmt *mgmt, const struct ieee80211_mgmt *mgmt,
size_t len, int valid) size_t len, int valid)
{ {
const u8 *rx_id;
u8 *id;
if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) { if (len < 24 + 2 + WLAN_SA_QUERY_TR_ID_LEN) {
wpa_printf(MSG_INFO, "Too short SA Query frame from " MACSTR, wpa_printf(MSG_INFO, "Too short SA Query frame from " MACSTR,
MAC2STR(mgmt->sa)); 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) { switch (mgmt->u.action.u.sa_query_req.action) {
case WLAN_SA_QUERY_REQUEST: case WLAN_SA_QUERY_REQUEST:
rx_id = (const u8 *) mgmt->u.action.u.sa_query_req.trans_id; rx_mgmt_action_sa_query_req(wt, sta, mgmt, len, valid);
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);
break; break;
case WLAN_SA_QUERY_RESPONSE: case WLAN_SA_QUERY_RESPONSE:
rx_id = (const u8 *) mgmt->u.action.u.sa_query_resp.trans_id; rx_mgmt_action_sa_query_resp(wt, sta, mgmt, len, valid);
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)");
break; break;
default: default:
wpa_printf(MSG_INFO, "Unexpected SA Query action value %u " 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 " wpa_printf(MSG_INFO, "Robust group-addressed "
"management frame sent without BIP by " "management frame sent without BIP by "
MACSTR, MAC2STR(mgmt->sa)); MACSTR, MAC2STR(mgmt->sa));
bss->counters[WLANTEST_BSS_COUNTER_MISSING_BIP_MMIE]++;
return -1; return -1;
} }
return 0; return 0;
@ -633,6 +693,7 @@ static int check_bip(struct wlantest *wt, const u8 *data, size_t len)
if (keyid < 4 || keyid > 5) { if (keyid < 4 || keyid > 5) {
wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR, wpa_printf(MSG_INFO, "Unexpected MMIE KeyID %u from " MACSTR,
keyid, MAC2STR(mgmt->sa)); keyid, MAC2STR(mgmt->sa));
bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
return 0; return 0;
} }
wpa_printf(MSG_DEBUG, "MMIE KeyID %u", keyid); 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) { if (check_mmie_mic(bss->igtk[keyid], data, len) < 0) {
wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from " wpa_printf(MSG_INFO, "Invalid MMIE MIC in a frame from "
MACSTR, MAC2STR(mgmt->sa)); MACSTR, MAC2STR(mgmt->sa));
bss->counters[WLANTEST_BSS_COUNTER_INVALID_BIP_MMIE]++;
return -1; return -1;
} }
wpa_printf(MSG_DEBUG, "Valid MMIE MIC"); wpa_printf(MSG_DEBUG, "Valid MMIE MIC");
os_memcpy(bss->ipn[keyid], mmie + 2, 6); os_memcpy(bss->ipn[keyid], mmie + 2, 6);
bss->counters[WLANTEST_BSS_COUNTER_VALID_BIP_MMIE]++;
return 0; return 0;
} }

View file

@ -17,6 +17,7 @@
#include "utils/list.h" #include "utils/list.h"
#include "common/wpa_common.h" #include "common/wpa_common.h"
#include "wlantest_ctrl.h"
struct ieee802_11_elems; struct ieee802_11_elems;
struct radius_msg; struct radius_msg;
@ -67,6 +68,7 @@ struct wlantest_sta {
u8 rsc_fromds[16 + 1][6]; u8 rsc_fromds[16 + 1][6];
u8 ap_sa_query_tr[2]; u8 ap_sa_query_tr[2];
u8 sta_sa_query_tr[2]; u8 sta_sa_query_tr[2];
u32 counters[NUM_WLANTEST_STA_COUNTER];
}; };
struct wlantest_bss { struct wlantest_bss {
@ -93,6 +95,7 @@ struct wlantest_bss {
u8 igtk[6][16]; u8 igtk[6][16];
int igtk_set[6]; int igtk_set[6];
u8 ipn[6][6]; u8 ipn[6][6];
u32 counters[NUM_WLANTEST_BSS_COUNTER];
}; };
struct wlantest_radius { struct wlantest_radius {

View 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, static int cmd_send_and_recv(int s, const u8 *cmd, size_t cmd_len,
u8 *resp, size_t max_resp_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 { struct wlantest_cli_cmd {
const char *cmd; const char *cmd;
int (*handler)(int s, int argc, char *argv[]); 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_bss", cmd_list_bss, "= get BSS list" },
{ "list_sta", cmd_list_sta, "<BSSID> = get STA list" }, { "list_sta", cmd_list_sta, "<BSSID> = get STA list" },
{ "flush", cmd_flush, "= drop all collected BSS data" }, { "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 } { NULL, NULL, NULL }
}; };

View file

@ -29,11 +29,50 @@ enum wlantest_ctrl_cmd {
WLANTEST_CTRL_LIST_BSS, WLANTEST_CTRL_LIST_BSS,
WLANTEST_CTRL_LIST_STA, WLANTEST_CTRL_LIST_STA,
WLANTEST_CTRL_FLUSH, 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 { enum wlantest_ctrl_attr {
WLANTEST_ATTR_BSSID, WLANTEST_ATTR_BSSID,
WLANTEST_ATTR_STA_ADDR, 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 */ #endif /* WLANTEST_CTRL_H */