diff --git a/wlantest/process.c b/wlantest/process.c index 6083390fe..7ca77b20d 100644 --- a/wlantest/process.c +++ b/wlantest/process.c @@ -21,6 +21,85 @@ #include "wlantest.h" +static int rx_duplicate(struct wlantest *wt, const struct ieee80211_hdr *hdr, + size_t len) +{ + u16 fc; + int tid = 16; + const u8 *sta_addr, *bssid; + struct wlantest_bss *bss; + struct wlantest_sta *sta; + int to_ap; + le16 *seq_ctrl; + + if (hdr->addr1[0] & 0x01) + return 0; /* Ignore group addressed frames */ + + fc = le_to_host16(hdr->frame_control); + if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) { + bssid = hdr->addr3; + if (os_memcmp(bssid, hdr->addr2, ETH_ALEN) == 0) { + sta_addr = hdr->addr1; + to_ap = 0; + } else { + if (os_memcmp(bssid, hdr->addr1, ETH_ALEN) != 0) + return 0; /* Unsupported STA-to-STA frame */ + sta_addr = hdr->addr2; + to_ap = 1; + } + } else { + switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) { + case 0: + return 0; /* IBSS not supported */ + case WLAN_FC_FROMDS: + sta_addr = hdr->addr1; + bssid = hdr->addr2; + to_ap = 0; + break; + case WLAN_FC_TODS: + sta_addr = hdr->addr2; + bssid = hdr->addr1; + to_ap = 1; + break; + case WLAN_FC_TODS | WLAN_FC_FROMDS: + return 0; /* WDS not supported */ + default: + return 0; + } + + if ((WLAN_FC_GET_STYPE(fc) & 0x08) && len >= 26) { + const u8 *qos = ((const u8 *) hdr) + 24; + tid = qos[0] & 0x0f; + } + } + + bss = bss_find(wt, bssid); + if (bss == NULL) + return 0; + sta = sta_find(bss, sta_addr); + if (sta == NULL) + return 0; + + if (to_ap) + seq_ctrl = &sta->seq_ctrl_to_ap[tid]; + else + seq_ctrl = &sta->seq_ctrl_to_sta[tid]; + + if ((fc & WLAN_FC_RETRY) && hdr->seq_ctrl == *seq_ctrl) { + u16 s = le_to_host16(hdr->seq_ctrl); + wpa_printf(MSG_MSGDUMP, "Ignore duplicated frame (seq=%u " + "frag=%u A1=" MACSTR " A2=" MACSTR ")", + WLAN_GET_SEQ_SEQ(s), WLAN_GET_SEQ_FRAG(s), + MAC2STR(hdr->addr1), MAC2STR(hdr->addr2)); + return 1; + } + + *seq_ctrl = hdr->seq_ctrl; + + return 0; +} + + static void rx_frame(struct wlantest *wt, const u8 *data, size_t len) { const struct ieee80211_hdr *hdr; @@ -40,14 +119,22 @@ static void rx_frame(struct wlantest *wt, const u8 *data, size_t len) switch (WLAN_FC_GET_TYPE(fc)) { case WLAN_FC_TYPE_MGMT: + if (len < 24) + break; + if (rx_duplicate(wt, hdr, len)) + break; rx_mgmt(wt, data, len); break; case WLAN_FC_TYPE_CTRL: if (len < 10) - return; + break; wt->rx_ctrl++; break; case WLAN_FC_TYPE_DATA: + if (len < 24) + break; + if (rx_duplicate(wt, hdr, len)) + break; rx_data(wt, data, len); break; default: diff --git a/wlantest/sta.c b/wlantest/sta.c index bec494dab..bfa6ee0b0 100644 --- a/wlantest/sta.c +++ b/wlantest/sta.c @@ -47,6 +47,8 @@ struct wlantest_sta * sta_get(struct wlantest_bss *bss, const u8 *addr) sta = os_zalloc(sizeof(*sta)); if (sta == NULL) return NULL; + os_memset(sta->seq_ctrl_to_sta, 0xff, sizeof(sta->seq_ctrl_to_sta)); + os_memset(sta->seq_ctrl_to_ap, 0xff, sizeof(sta->seq_ctrl_to_ap)); sta->bss = bss; os_memcpy(sta->addr, addr, ETH_ALEN); dl_list_add(&bss->sta, &sta->list); diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index 4899659c0..6bb8e1edb 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -79,6 +79,9 @@ struct wlantest_sta { u32 icmp_echo_req_dst; u16 icmp_echo_req_id; u16 icmp_echo_req_seq; + + le16 seq_ctrl_to_sta[17]; + le16 seq_ctrl_to_ap[17]; }; struct wlantest_bss {