Browse Source

wlantest: Implement IEEE 802.11 duplicate detection

This cleans up debug logs by avoiding incorrect entries on TKIP/CCMP
replays and some state changes.
Jouni Malinen 14 years ago
parent
commit
a912dd16c5
3 changed files with 93 additions and 1 deletions
  1. 88 1
      wlantest/process.c
  2. 2 0
      wlantest/sta.c
  3. 3 0
      wlantest/wlantest.h

+ 88 - 1
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:

+ 2 - 0
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);

+ 3 - 0
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 {