diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c index 01449cbb5..11a7dd40a 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -192,6 +192,33 @@ static struct wlantest_sta * ctrl_get_sta(struct wlantest *wt, int sock, } +static struct wlantest_sta * ctrl_get_sta2(struct wlantest *wt, int sock, + u8 *cmd, size_t clen, + struct wlantest_bss *bss) +{ + struct wlantest_sta *sta; + u8 *pos; + size_t len; + + if (bss == NULL) + return NULL; + + pos = attr_get(cmd, clen, WLANTEST_ATTR_STA2_ADDR, &len); + if (pos == NULL || len != ETH_ALEN) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return NULL; + } + + sta = sta_find(bss, pos); + if (sta == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return NULL; + } + + return sta; +} + + static void ctrl_list_bss(struct wlantest *wt, int sock) { u8 buf[WLANTEST_CTRL_MAX_RESP_LEN], *pos, *len; @@ -263,8 +290,10 @@ static void ctrl_clear_sta_counters(struct wlantest *wt, int sock, u8 *cmd, bss = ctrl_get_bss(wt, sock, cmd, clen); sta = ctrl_get_sta(wt, sock, cmd, clen, bss); - if (sta == NULL) + 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); @@ -277,14 +306,41 @@ static void ctrl_clear_bss_counters(struct wlantest *wt, int sock, u8 *cmd, struct wlantest_bss *bss; bss = ctrl_get_bss(wt, sock, cmd, clen); - if (bss == NULL) + 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_clear_tdls_counters(struct wlantest *wt, int sock, u8 *cmd, + size_t clen) +{ + struct wlantest_bss *bss; + struct wlantest_sta *sta; + struct wlantest_sta *sta2; + struct wlantest_tdls *tdls; + + bss = ctrl_get_bss(wt, sock, cmd, clen); + sta = ctrl_get_sta(wt, sock, cmd, clen, bss); + sta2 = ctrl_get_sta2(wt, sock, cmd, clen, bss); + if (sta == NULL || sta2 == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { + if ((tdls->init == sta && tdls->resp == sta2) || + (tdls->init == sta2 && tdls->resp == sta)) + os_memset(tdls->counters, 0, sizeof(tdls->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) { @@ -355,6 +411,61 @@ static void ctrl_get_bss_counter(struct wlantest *wt, int sock, u8 *cmd, } +static void ctrl_get_tdls_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; + struct wlantest_sta *sta2; + struct wlantest_tdls *tdls; + u32 counter; + u8 buf[4 + 12], *end, *pos; + int found = 0; + + bss = ctrl_get_bss(wt, sock, cmd, clen); + sta = ctrl_get_sta(wt, sock, cmd, clen, bss); + sta2 = ctrl_get_sta2(wt, sock, cmd, clen, bss); + if (sta == NULL || sta2 == NULL) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + return; + } + + addr = attr_get(cmd, clen, WLANTEST_ATTR_TDLS_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_TDLS_COUNTER) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_INVALID_CMD); + return; + } + + dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { + if ((tdls->init == sta && tdls->resp == sta2) || + (tdls->init == sta2 && tdls->resp == sta)) { + found = 1; + break; + } + } + + if (!found) { + ctrl_send_simple(wt, sock, WLANTEST_CTRL_FAILURE); + 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, + tdls->counters[counter]); + ctrl_send(wt, sock, buf, pos - buf); +} + + static void build_mgmt_hdr(struct ieee80211_mgmt *mgmt, struct wlantest_bss *bss, struct wlantest_sta *sta, int sender_ap, int stype) @@ -1096,12 +1207,18 @@ static void ctrl_read(int sock, void *eloop_ctx, void *sock_ctx) case WLANTEST_CTRL_CLEAR_BSS_COUNTERS: ctrl_clear_bss_counters(wt, sock, buf + 4, len - 4); break; + case WLANTEST_CTRL_CLEAR_TDLS_COUNTERS: + ctrl_clear_tdls_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; + case WLANTEST_CTRL_GET_TDLS_COUNTER: + ctrl_get_tdls_counter(wt, sock, buf + 4, len - 4); + break; case WLANTEST_CTRL_INJECT: ctrl_inject(wt, sock, buf + 4, len - 4); break; diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c index c094929a1..0d74b089f 100644 --- a/wlantest/rx_data.c +++ b/wlantest/rx_data.c @@ -359,6 +359,66 @@ static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr, } +static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *bssid, + const u8 *sta1_addr, + const u8 *sta2_addr) +{ + struct wlantest_bss *bss; + struct wlantest_sta *sta1, *sta2; + struct wlantest_tdls *tdls; + + bss = bss_find(wt, bssid); + if (bss == NULL) + return NULL; + sta1 = sta_find(bss, sta1_addr); + if (sta1 == NULL) + return NULL; + sta2 = sta_find(bss, sta2_addr); + if (sta2 == NULL) + return NULL; + + dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { + if ((tdls->init == sta1 && tdls->resp == sta2) || + (tdls->init == sta2 && tdls->resp == sta1)) + return tdls; + } + + return NULL; +} + + +static void add_direct_link(struct wlantest *wt, const u8 *bssid, + const u8 *sta1_addr, const u8 *sta2_addr) +{ + struct wlantest_tdls *tdls; + + tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr); + if (tdls == NULL) + return; + + if (tdls->link_up) + tdls->counters[WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK]++; + else + tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK]++; +} + + +static void add_ap_path(struct wlantest *wt, const u8 *bssid, + const u8 *sta1_addr, const u8 *sta2_addr) +{ + struct wlantest_tdls *tdls; + + tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr); + if (tdls == NULL) + return; + + if (tdls->link_up) + tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_AP_PATH]++; + else + tdls->counters[WLANTEST_TDLS_COUNTER_VALID_AP_PATH]++; +} + + void rx_data(struct wlantest *wt, const u8 *data, size_t len) { const struct ieee80211_hdr *hdr; @@ -393,6 +453,7 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len) fc & WLAN_FC_ISWEP ? " Prot" : "", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + add_direct_link(wt, hdr->addr3, hdr->addr1, hdr->addr2); rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2, data + hdrlen, len - hdrlen); break; @@ -404,6 +465,7 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len) fc & WLAN_FC_ISWEP ? " Prot" : "", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + add_ap_path(wt, hdr->addr2, hdr->addr1, hdr->addr3); rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2, data + hdrlen, len - hdrlen); break; @@ -415,6 +477,7 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len) fc & WLAN_FC_ISWEP ? " Prot" : "", MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3)); + add_ap_path(wt, hdr->addr1, hdr->addr3, hdr->addr2); rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2, data + hdrlen, len - hdrlen); break; diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 0e21beb99..524790945 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -96,6 +96,7 @@ struct wlantest_tdls { u8 dialog_token; u8 rsc_init[16 + 1][6]; u8 rsc_resp[16 + 1][6]; + u32 counters[NUM_WLANTEST_TDLS_COUNTER]; }; struct wlantest_bss { diff --git a/wlantest/wlantest_cli.c b/wlantest/wlantest_cli.c index 81768a8bc..dac89e60c 100644 --- a/wlantest/wlantest_cli.c +++ b/wlantest/wlantest_cli.c @@ -430,6 +430,81 @@ static char ** complete_clear_bss_counters(int s, const char *str, int pos) } +static int cmd_clear_tdls_counters(int s, int argc, char *argv[]) +{ + u8 resp[WLANTEST_CTRL_MAX_RESP_LEN]; + u8 buf[100], *pos; + int rlen; + + if (argc < 3) { + printf("clear_tdls_counters needs three arguments: BSSID, " + "STA1 address, STA2 address\n"); + return -1; + } + + pos = buf; + WPA_PUT_BE32(pos, WLANTEST_CTRL_CLEAR_TDLS_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 STA1 address '%s'\n", argv[1]); + return -1; + } + pos += ETH_ALEN; + + WPA_PUT_BE32(pos, WLANTEST_ATTR_STA2_ADDR); + pos += 4; + WPA_PUT_BE32(pos, ETH_ALEN); + pos += 4; + if (hwaddr_aton(argv[2], pos) < 0) { + printf("Invalid STA2 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; + printf("OK\n"); + return 0; +} + + +static char ** complete_clear_tdls_counters(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: + case 3: + if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0) + break; + res = get_sta_list(s, addr, 0); + break; + } + + return res; +} + + struct sta_counters { const char *name; enum wlantest_sta_counter num; @@ -654,6 +729,120 @@ static char ** complete_get_bss_counter(int s, const char *str, int pos) } +struct tdls_counters { + const char *name; + enum wlantest_tdls_counter num; +}; + +static const struct tdls_counters tdls_counters[] = { + { "valid_direct_link", WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK }, + { "invalid_direct_link", WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK }, + { "valid_ap_path", WLANTEST_TDLS_COUNTER_VALID_AP_PATH }, + { "invalid_ap_path", WLANTEST_TDLS_COUNTER_INVALID_AP_PATH }, + { NULL, 0 } +}; + +static int cmd_get_tdls_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 != 4) { + printf("get_tdls_counter needs four arguments: " + "counter name, BSSID, STA1 address, STA2 address\n"); + return -1; + } + + pos = buf; + end = buf + sizeof(buf); + WPA_PUT_BE32(pos, WLANTEST_CTRL_GET_TDLS_COUNTER); + pos += 4; + + for (i = 0; tdls_counters[i].name; i++) { + if (os_strcasecmp(tdls_counters[i].name, argv[0]) == 0) + break; + } + if (tdls_counters[i].name == NULL) { + printf("Unknown TDLS counter '%s'\n", argv[0]); + printf("Counters:"); + for (i = 0; tdls_counters[i].name; i++) + printf(" %s", tdls_counters[i].name); + printf("\n"); + return -1; + } + + pos = attr_add_be32(pos, end, WLANTEST_ATTR_TDLS_COUNTER, + tdls_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 STA1 address '%s'\n", argv[2]); + return -1; + } + pos += ETH_ALEN; + + pos = attr_hdr_add(pos, end, WLANTEST_ATTR_STA2_ADDR, ETH_ALEN); + if (hwaddr_aton(argv[3], pos) < 0) { + printf("Invalid STA2 address '%s'\n", argv[3]); + 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; +} + + +static char ** complete_get_tdls_counter(int s, const char *str, int pos) +{ + int arg = get_cmd_arg_num(str, pos); + char **res = NULL; + int i, count; + u8 addr[ETH_ALEN]; + + switch (arg) { + case 1: + /* counter list */ + count = sizeof(tdls_counters) / sizeof(tdls_counters[0]); + res = os_zalloc(count * sizeof(char *)); + if (res == NULL) + return NULL; + for (i = 0; tdls_counters[i].name; i++) { + res[i] = os_strdup(tdls_counters[i].name); + if (res[i] == NULL) + break; + } + break; + case 2: + res = get_bssid_list(s); + break; + case 3: + case 4: + if (hwaddr_aton(&str[get_prev_arg_pos(str, pos)], addr) < 0) + break; + res = get_sta_list(s, addr, 0); + break; + } + + return res; +} + + struct inject_frames { const char *name; enum wlantest_inject_frame frame; @@ -1254,6 +1443,15 @@ static const struct wlantest_cli_cmd wlantest_cli_commands[] = { { "info_bss", cmd_info_bss, " = get BSS information", complete_info_bss }, + { "clear_tdls_counters", cmd_clear_tdls_counters, + " = clear TDLS counters", + complete_clear_tdls_counters }, + { "get_tdls_counter", cmd_get_tdls_counter, + " = get TDLS counter value", + complete_get_tdls_counter }, + { "get_bss_counter", cmd_get_bss_counter, + " = get BSS counter value", + complete_get_bss_counter }, { NULL, NULL, NULL, NULL } }; diff --git a/wlantest/wlantest_ctrl.h b/wlantest/wlantest_ctrl.h index cd13c1c73..c8a066e28 100644 --- a/wlantest/wlantest_ctrl.h +++ b/wlantest/wlantest_ctrl.h @@ -39,6 +39,8 @@ enum wlantest_ctrl_cmd { WLANTEST_CTRL_INFO_STA, WLANTEST_CTRL_INFO_BSS, WLANTEST_CTRL_SEND, + WLANTEST_CTRL_CLEAR_TDLS_COUNTERS, + WLANTEST_CTRL_GET_TDLS_COUNTER, }; enum wlantest_ctrl_attr { @@ -56,6 +58,8 @@ enum wlantest_ctrl_attr { WLANTEST_ATTR_BSS_INFO, WLANTEST_ATTR_INFO, WLANTEST_ATTR_FRAME, + WLANTEST_ATTR_TDLS_COUNTER, + WLANTEST_ATTR_STA2_ADDR, }; enum wlantest_bss_counter { @@ -95,6 +99,14 @@ enum wlantest_sta_counter { NUM_WLANTEST_STA_COUNTER }; +enum wlantest_tdls_counter { + WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK, + WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK, + WLANTEST_TDLS_COUNTER_VALID_AP_PATH, + WLANTEST_TDLS_COUNTER_INVALID_AP_PATH, + NUM_WLANTEST_TDLS_COUNTER +}; + enum wlantest_inject_frame { WLANTEST_FRAME_AUTH, WLANTEST_FRAME_ASSOCREQ,