diff --git a/wlantest/bss.c b/wlantest/bss.c index a4a315533..34dee50b0 100644 --- a/wlantest/bss.c +++ b/wlantest/bss.c @@ -67,6 +67,13 @@ void pmk_deinit(struct wlantest_pmk *pmk) } +void tdls_deinit(struct wlantest_tdls *tdls) +{ + dl_list_del(&tdls->list); + os_free(tdls); +} + + void bss_deinit(struct wlantest_bss *bss) { struct wlantest_sta *sta, *n; @@ -77,7 +84,7 @@ void bss_deinit(struct wlantest_bss *bss) dl_list_for_each_safe(pmk, np, &bss->pmk, struct wlantest_pmk, list) pmk_deinit(pmk); dl_list_for_each_safe(tdls, nt, &bss->tdls, struct wlantest_tdls, list) - os_free(tdls); + tdls_deinit(tdls); dl_list_del(&bss->list); os_free(bss); } diff --git a/wlantest/ctrl.c b/wlantest/ctrl.c index 11a7dd40a..e97448d6b 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -444,8 +444,7 @@ static void ctrl_get_tdls_counter(struct wlantest *wt, int sock, u8 *cmd, } dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) { - if ((tdls->init == sta && tdls->resp == sta2) || - (tdls->init == sta2 && tdls->resp == sta)) { + if (tdls->init == sta && tdls->resp == sta2) { found = 1; break; } diff --git a/wlantest/rx_tdls.c b/wlantest/rx_tdls.c index fd18c0831..4e25ccedd 100644 --- a/wlantest/rx_tdls.c +++ b/wlantest/rx_tdls.c @@ -23,7 +23,8 @@ #include "wlantest.h" -static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid) +static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid, + int create_new) { struct wlantest_bss *bss; struct wlantest_sta *init, *resp; @@ -46,6 +47,9 @@ static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *linkid) return tdls; } + if (!create_new) + return NULL; + tdls = os_zalloc(sizeof(*tdls)); if (tdls == NULL) return NULL; @@ -202,7 +206,7 @@ static void rx_data_tdls_setup_request(struct wlantest *wt, const u8 *bssid, " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); - tdls = get_tdls(wt, elems.link_id); + tdls = get_tdls(wt, elems.link_id, 1); if (tdls) tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_REQ]++; } @@ -234,7 +238,7 @@ static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); - tdls = get_tdls(wt, elems.link_id); + tdls = get_tdls(wt, elems.link_id, 1); if (!tdls) return; if (status) @@ -259,6 +263,7 @@ static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid, u16 status; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; + u8 link_id[3 * ETH_ALEN]; if (len < 3) return; @@ -275,7 +280,7 @@ static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); - tdls = get_tdls(wt, elems.link_id); + tdls = get_tdls(wt, elems.link_id, 1); if (tdls == NULL) return; if (status) @@ -287,13 +292,32 @@ static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid, return; tdls->link_up = 1; - if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) + if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) { + if (elems.ftie == NULL) + goto remove_reverse; return; + } if (tdls_verify_mic(tdls, 3, &elems) == 0) { tdls->dialog_token = data[2]; wpa_printf(MSG_DEBUG, "TDLS: Dialog Token for the link: %u", tdls->dialog_token); } + +remove_reverse: + /* + * The TDLS link itself is bidirectional, but there is explicit + * initiator/responder roles. Remove the other direction of the link + * (if it exists) to make sure that the link counters are stored for + * the current TDLS entery. + */ + os_memcpy(link_id, elems.link_id, ETH_ALEN); + os_memcpy(link_id + ETH_ALEN, elems.link_id + 2 * ETH_ALEN, ETH_ALEN); + os_memcpy(link_id + 2 * ETH_ALEN, elems.link_id + ETH_ALEN, ETH_ALEN); + tdls = get_tdls(wt, link_id, 0); + if (tdls) { + wpa_printf(MSG_DEBUG, "TDLS: Remove reverse link entry"); + tdls_deinit(tdls); + } } @@ -377,7 +401,7 @@ static void rx_data_tdls_teardown(struct wlantest *wt, const u8 *bssid, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); - tdls = get_tdls(wt, elems.link_id); + tdls = get_tdls(wt, elems.link_id, 1); if (tdls) { tdls->link_up = 0; tdls_verify_mic_teardown(tdls, 4, data, &elems); diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 4301504e8..da63d2f57 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -212,6 +212,7 @@ void bss_flush(struct wlantest *wt); int bss_add_pmk_from_passphrase(struct wlantest_bss *bss, const char *passphrase); void pmk_deinit(struct wlantest_pmk *pmk); +void tdls_deinit(struct wlantest_tdls *tdls); struct wlantest_sta * sta_find(struct wlantest_bss *bss, const u8 *addr); struct wlantest_sta * sta_get(struct wlantest_bss *bss, const u8 *addr);