1 /*
2  * Received Data frame processing for IPv4 packets
3  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "utils/includes.h"
10 #include <netinet/ip.h>
11 #include <netinet/ip_icmp.h>
12 
13 #include "utils/common.h"
14 #include "wlantest.h"
15 
16 
17 #ifndef __APPLE__
18 
ping_update(struct wlantest * wt,struct wlantest_sta * sta,int req,u32 src,u32 dst,u16 id,u16 seq)19 static void ping_update(struct wlantest *wt, struct wlantest_sta *sta, int req,
20 			u32 src, u32 dst, u16 id, u16 seq)
21 {
22 	if (req) {
23 		sta->icmp_echo_req_src = src;
24 		sta->icmp_echo_req_dst = dst;
25 		sta->icmp_echo_req_id = id;
26 		sta->icmp_echo_req_seq = seq;
27 		return;
28 	}
29 
30 	if (sta->icmp_echo_req_src == dst &&
31 	    sta->icmp_echo_req_dst == src &&
32 	    sta->icmp_echo_req_id == id &&
33 	    sta->icmp_echo_req_seq == seq) {
34 		sta->counters[WLANTEST_STA_COUNTER_PING_OK]++;
35 		if (sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX] == 0 &&
36 		    sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX] == 0)
37 			sta->counters[
38 				WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC]++;
39 		add_note(wt, MSG_DEBUG, "ICMP echo (ping) match for STA "
40 			 MACSTR, MAC2STR(sta->addr));
41 	}
42 }
43 
44 
rx_data_icmp(struct wlantest * wt,const u8 * bssid,const u8 * sta_addr,u32 dst,u32 src,const u8 * data,size_t len,const u8 * peer_addr)45 static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
46 			 const u8 *sta_addr, u32 dst, u32 src,
47 			 const u8 *data, size_t len, const u8 *peer_addr)
48 {
49 	struct in_addr addr;
50 	char buf[20];
51 	const struct icmphdr *hdr;
52 	u16 id, seq;
53 	struct wlantest_bss *bss;
54 	struct wlantest_sta *sta;
55 
56 	hdr = (const struct icmphdr *) data;
57 	if (len < 4)
58 		return;
59 
60 	/* TODO: check hdr->checksum */
61 
62 	if (hdr->type != ICMP_ECHOREPLY && hdr->type != ICMP_ECHO)
63 		return;
64 	if (len < 8)
65 		return;
66 
67 	id = ntohs(hdr->un.echo.id);
68 	seq = ntohs(hdr->un.echo.sequence);
69 
70 	addr.s_addr = dst;
71 	snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
72 	addr.s_addr = src;
73 	add_note(wt, MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
74 		 hdr->type == ICMP_ECHO ? "request" : "response",
75 		 inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
76 		 peer_addr ? " [DL]" : "");
77 
78 	bss = bss_find(wt, bssid);
79 	if (bss == NULL) {
80 		add_note(wt, MSG_INFO, "No BSS " MACSTR
81 			 " known for ICMP packet", MAC2STR(bssid));
82 		return;
83 	}
84 
85 	if (sta_addr == NULL)
86 		return; /* FromDS broadcast ping */
87 
88 	sta = sta_find(bss, sta_addr);
89 	if (sta == NULL) {
90 		add_note(wt, MSG_INFO, "No STA " MACSTR
91 			 " known for ICMP packet", MAC2STR(sta_addr));
92 		return;
93 	}
94 
95 	ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
96 	if (peer_addr && (sta = sta_find(bss, peer_addr)))
97 		ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
98 }
99 
100 #endif /* __APPLE__ */
101 
102 
hwsim_test_packet(const u8 * data,size_t len)103 static int hwsim_test_packet(const u8 *data, size_t len)
104 {
105 	size_t i;
106 
107 	if (len != 1500 - 14)
108 		return 0;
109 
110 	for (i = 0; i < len; i++) {
111 		if (data[i] != (i & 0xff))
112 			return 0;
113 	}
114 
115 	return 1;
116 }
117 
118 
rx_data_ip(struct wlantest * wt,const u8 * bssid,const u8 * sta_addr,const u8 * dst,const u8 * src,const u8 * data,size_t len,const u8 * peer_addr)119 void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
120 		const u8 *dst, const u8 *src, const u8 *data, size_t len,
121 		const u8 *peer_addr)
122 {
123 	struct ip ip;
124 	const u8 *payload;
125 	size_t plen;
126 	uint16_t frag_off, ip_len;
127 
128 	if (len < sizeof(ip))
129 		return;
130 	os_memcpy(&ip, data, sizeof(ip));
131 
132 	if (ip.ip_v != 4) {
133 		if (hwsim_test_packet(data, len)) {
134 			add_note(wt, MSG_INFO, "hwsim_test package");
135 			return;
136 		}
137 		add_note(wt, MSG_DEBUG, "Unexpected IP protocol version %u in "
138 			 "IPv4 packet (bssid=" MACSTR " str=" MACSTR
139 			 " dst=" MACSTR ")", ip.ip_v, MAC2STR(bssid),
140 			 MAC2STR(src), MAC2STR(dst));
141 		return;
142 	}
143 	if (ip.ip_hl * 4 < sizeof(ip)) {
144 		add_note(wt, MSG_DEBUG, "Unexpected IP header length %u in "
145 			 "IPv4 packet (bssid=" MACSTR " str=" MACSTR
146 			 " dst=" MACSTR ")", ip.ip_hl, MAC2STR(bssid),
147 			 MAC2STR(src), MAC2STR(dst));
148 		return;
149 	}
150 	if (ip.ip_hl * 4 > len) {
151 		add_note(wt, MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) "
152 			 "in IPv4 packet (bssid=" MACSTR " str=" MACSTR
153 			 " dst=" MACSTR ")", ip.ip_hl, (unsigned) len,
154 			 MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
155 		return;
156 	}
157 
158 	/* TODO: check header checksum in ip.ip_sum */
159 
160 	frag_off = be_to_host16(ip.ip_off);
161 	if (frag_off & 0x1fff) {
162 		wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
163 			   "supported");
164 		return;
165 	}
166 
167 	ip_len = be_to_host16(ip.ip_len);
168 	if (ip_len > len)
169 		return;
170 	if (ip_len < len)
171 		len = ip_len;
172 
173 	payload = data + 4 * ip.ip_hl;
174 	plen = len - 4 * ip.ip_hl;
175 
176 	switch (ip.ip_p) {
177 #ifndef __APPLE__
178 	case IPPROTO_ICMP:
179 		rx_data_icmp(wt, bssid, sta_addr, ip.ip_dst.s_addr,
180 			     ip.ip_src.s_addr, payload, plen, peer_addr);
181 		break;
182 #endif /* __APPLE__ */
183 	}
184 }
185