diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c index 86bd6720f..7507c2f81 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -290,6 +290,8 @@ static void ctrl_clear_sta_counters(struct wlantest *wt, int sock, u8 *cmd, } os_memset(sta->counters, 0, sizeof(sta->counters)); + os_memset(sta->tx_tid, 0, sizeof(sta->tx_tid)); + os_memset(sta->rx_tid, 0, sizeof(sta->rx_tid)); ctrl_send_simple(wt, sock, WLANTEST_CTRL_SUCCESS); } @@ -1195,6 +1197,76 @@ static void ctrl_relog(struct wlantest *wt, int sock) } +static void ctrl_get_tx_tid(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; + + bss = ctrl_get_bss(wt, sock, cmd, clen); + sta = ctrl_get_sta(wt, sock, cmd, clen, bss); + if (sta == NULL) + return; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_TID, &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 >= 16 + 1) { + 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->tx_tid[counter]); + ctrl_send(wt, sock, buf, pos - buf); +} + + +static void ctrl_get_rx_tid(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; + + bss = ctrl_get_bss(wt, sock, cmd, clen); + sta = ctrl_get_sta(wt, sock, cmd, clen, bss); + if (sta == NULL) + return; + + addr = attr_get(cmd, clen, WLANTEST_ATTR_TID, &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 >= 16 + 1) { + 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->rx_tid[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; @@ -1281,6 +1353,12 @@ static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx) case WLANTEST_CTRL_RELOG: ctrl_relog(wt, sock); break; + case WLANTEST_CTRL_GET_TX_TID: + ctrl_get_tx_tid(wt, sock, buf + 4, len - 4); + break; + case WLANTEST_CTRL_GET_RX_TID: + ctrl_get_rx_tid(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 eaa2b8691..d23425e4a 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -300,6 +300,8 @@ static void rx_data_bss_prot(struct wlantest *wt, return; } + if (sta == NULL) + return; if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) && !(data[3] & 0x20)) { add_note(wt, MSG_INFO, "Expected TKIP/CCMP frame from " @@ -336,10 +338,19 @@ static void rx_data_bss_prot(struct wlantest *wt, keyid, MAC2STR(hdr->addr2)); } - if (qos) + if (qos) { tid = qos[0] & 0x0f; - else + if (fc & WLAN_FC_TODS) + sta->tx_tid[tid]++; + else + sta->rx_tid[tid]++; + } else { tid = 0; + if (fc & WLAN_FC_TODS) + sta->tx_tid[16]++; + else + sta->rx_tid[16]++; + } if (tk) { if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0) rsc = tdls->rsc_init[tid]; @@ -434,6 +445,8 @@ static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr, rx_data_bss_prot(wt, hdr, qos, dst, src, data, len); else { const u8 *bssid, *sta_addr, *peer_addr; + struct wlantest_bss *bss; + if (fc & WLAN_FC_TODS) { bssid = hdr->addr1; sta_addr = hdr->addr2; @@ -447,6 +460,27 @@ static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr, sta_addr = hdr->addr2; peer_addr = hdr->addr1; } + + bss = bss_get(wt, bssid); + if (bss) { + struct wlantest_sta *sta = sta_get(bss, sta_addr); + + if (sta) { + if (qos) { + int tid = qos[0] & 0x0f; + if (fc & WLAN_FC_TODS) + sta->tx_tid[tid]++; + else + sta->rx_tid[tid]++; + } else { + if (fc & WLAN_FC_TODS) + sta->tx_tid[16]++; + else + sta->rx_tid[16]++; + } + } + } + rx_data_process(wt, bssid, sta_addr, dst, src, data, len, 0, peer_addr); } diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 60802d53f..68531d884 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -97,6 +97,9 @@ struct wlantest_sta { u8 gtk[32]; size_t gtk_len; int gtk_idx; + + u32 tx_tid[16 + 1]; + u32 rx_tid[16 + 1]; }; struct wlantest_tdls { diff --git a/wlantest/wlantest_cli.c b/wlantest/wlantest_cli.c index afe38c488..ae84102e5 100644 --- a/wlantest/wlantest_cli.c +++ b/wlantest/wlantest_cli.c @@ -1452,6 +1452,119 @@ static char ** complete_info_bss(int s, const char *str, int pos) } +static int cmd_get_tx_tid(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *end, *pos; + int rlen; + size_t len; + + if (argc != 3) { + printf("get_tx_tid needs three arguments: " + "BSSID, STA address, and TID\n"); + return -1; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_TX_TID); + pos += 4; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); + if (hwaddr_aton(argv[0], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[0]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); + if (hwaddr_aton(argv[1], pos) < 0) { + printf("Invalid STA address '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_add_be32(pos, end, WLANTEST_ATTR_TID, atoi(argv[2])); + + 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; +} + + +static int cmd_get_rx_tid(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *end, *pos; + int rlen; + size_t len; + + if (argc != 3) { + printf("get_tx_tid needs three arguments: " + "BSSID, STA address, and TID\n"); + return -1; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_RX_TID); + pos += 4; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_BSSID, ETH_ALEN); + if (hwaddr_aton(argv[0], pos) < 0) { + printf("Invalid BSSID '%s'\n", argv[0]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA_ADDR, ETH_ALEN); + if (hwaddr_aton(argv[1], pos) < 0) { + printf("Invalid STA address '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_add_be32(pos, end, WLANTEST_ATTR_TID, atoi(argv[2])); + + 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; +} + + +static char ** complete_get_tid(int s, const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + u8 addr[ETH_ALEN]; + + switch (arg) { + case 1: + res = get_bssid_list(s); + break; + case 2: + if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0) + break; + res = get_sta_list(s, addr, 0); + break; + } + + return res; +} + + struct wlantest_cli_cmd { const char *cmd; int (*handler)(int s, int argc, char *argv[]); @@ -1503,6 +1616,12 @@ static const struct wlantest_cli_cmd wlantest_cli_commands[] = { " = get BSS counter value", complete_get_bss_counter }, { "relog", cmd_relog, "= re-open log-file (allow rolling logs)", NULL }, + { "get_tx_tid", cmd_get_tx_tid, + " = get STA TX TID counter value", + complete_get_tid }, + { "get_rx_tid", cmd_get_rx_tid, + " = get STA RX TID counter value", + complete_get_tid }, { NULL, NULL, NULL, NULL } }; diff --git a/wlantest/wlantest_ctrl.h b/wlantest/wlantest_ctrl.h index 41b658356..8ecbaa7cd 100644 --- a/wlantest/wlantest_ctrl.h +++ b/wlantest/wlantest_ctrl.h @@ -36,6 +36,8 @@ enum wlantest_ctrl_cmd { WLANTEST_CTRL_CLEAR_TDLS_COUNTERS, WLANTEST_CTRL_GET_TDLS_COUNTER, WLANTEST_CTRL_RELOG, + WLANTEST_CTRL_GET_TX_TID, + WLANTEST_CTRL_GET_RX_TID, }; enum wlantest_ctrl_attr { @@ -56,6 +58,7 @@ enum wlantest_ctrl_attr { WLANTEST_ATTR_TDLS_COUNTER, WLANTEST_ATTR_STA2_ADDR, WLANTEST_ATTR_WEPKEY, + WLANTEST_ATTR_TID, }; enum wlantest_bss_counter {