wlantest: Use add_note() to annotate frames
[mech_eap.git] / wlantest / rx_ip.c
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 static void ping_update(struct wlantest *wt, struct wlantest_sta *sta, int req,
18                         u32 src, u32 dst, u16 id, u16 seq)
19 {
20         if (req) {
21                 sta->icmp_echo_req_src = src;
22                 sta->icmp_echo_req_dst = dst;
23                 sta->icmp_echo_req_id = id;
24                 sta->icmp_echo_req_seq = seq;
25                 return;
26         }
27
28         if (sta->icmp_echo_req_src == dst &&
29             sta->icmp_echo_req_dst == src &&
30             sta->icmp_echo_req_id == id &&
31             sta->icmp_echo_req_seq == seq) {
32                 sta->counters[WLANTEST_STA_COUNTER_PING_OK]++;
33                 if (sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX] == 0 &&
34                     sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX] == 0)
35                         sta->counters[
36                                 WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC]++;
37                 add_note(wt, MSG_DEBUG, "ICMP echo (ping) match for STA "
38                          MACSTR, MAC2STR(sta->addr));
39         }
40 }
41
42
43 static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
44                          const u8 *sta_addr, u32 dst, u32 src,
45                          const u8 *data, size_t len, const u8 *peer_addr)
46 {
47         struct in_addr addr;
48         char buf[20];
49         const struct icmphdr *hdr;
50         u16 id, seq;
51         struct wlantest_bss *bss;
52         struct wlantest_sta *sta;
53
54         hdr = (const struct icmphdr *) data;
55         if (len < 4)
56                 return;
57
58         /* TODO: check hdr->checksum */
59
60         if (hdr->type != ICMP_ECHOREPLY && hdr->type != ICMP_ECHO)
61                 return;
62         if (len < 8)
63                 return;
64
65         id = ntohs(hdr->un.echo.id);
66         seq = ntohs(hdr->un.echo.sequence);
67
68         addr.s_addr = dst;
69         snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
70         addr.s_addr = src;
71         add_note(wt, MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
72                  hdr->type == ICMP_ECHO ? "request" : "response",
73                  inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
74                  peer_addr ? " [DL]" : "");
75
76         bss = bss_find(wt, bssid);
77         if (bss == NULL) {
78                 add_note(wt, MSG_INFO, "No BSS " MACSTR
79                          " known for ICMP packet", MAC2STR(bssid));
80                 return;
81         }
82
83         if (sta_addr == NULL)
84                 return; /* FromDS broadcast ping */
85
86         sta = sta_find(bss, sta_addr);
87         if (sta == NULL) {
88                 add_note(wt, MSG_INFO, "No STA " MACSTR
89                          " known for ICMP packet", MAC2STR(sta_addr));
90                 return;
91         }
92
93         ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
94         if (peer_addr && (sta = sta_find(bss, peer_addr)))
95                 ping_update(wt, sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
96 }
97
98
99 void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
100                 const u8 *dst, const u8 *src, const u8 *data, size_t len,
101                 const u8 *peer_addr)
102 {
103         const struct iphdr *ip;
104         const u8 *payload;
105         size_t plen;
106         u16 frag_off, tot_len;
107
108         ip = (const struct iphdr *) data;
109         if (len < sizeof(*ip))
110                 return;
111         if (ip->version != 4) {
112                 add_note(wt, MSG_DEBUG, "Unexpected IP protocol version %u in "
113                          "IPv4 packet (bssid=" MACSTR " str=" MACSTR
114                          " dst=" MACSTR ")", ip->version, MAC2STR(bssid),
115                          MAC2STR(src), MAC2STR(dst));
116                 return;
117         }
118         if (ip->ihl * 4 < sizeof(*ip)) {
119                 add_note(wt, MSG_DEBUG, "Unexpected IP header length %u in "
120                          "IPv4 packet (bssid=" MACSTR " str=" MACSTR
121                          " dst=" MACSTR ")", ip->ihl, MAC2STR(bssid),
122                          MAC2STR(src), MAC2STR(dst));
123                 return;
124         }
125         if (ip->ihl * 4 > len) {
126                 add_note(wt, MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) "
127                          "in IPv4 packet (bssid=" MACSTR " str=" MACSTR
128                          " dst=" MACSTR ")", ip->ihl, (unsigned) len,
129                          MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
130                 return;
131         }
132
133         /* TODO: check header checksum in ip->check */
134
135         frag_off = be_to_host16(ip->frag_off);
136         if (frag_off & 0x1fff) {
137                 wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
138                            "supported");
139                 return;
140         }
141
142         tot_len = be_to_host16(ip->tot_len);
143         if (tot_len > len)
144                 return;
145         if (tot_len < len)
146                 len = tot_len;
147
148         payload = data + 4 * ip->ihl;
149         plen = len - 4 * ip->ihl;
150
151         switch (ip->protocol) {
152         case IPPROTO_ICMP:
153                 rx_data_icmp(wt, bssid, sta_addr, ip->daddr, ip->saddr,
154                              payload, plen, peer_addr);
155                 break;
156         }
157 }