wlantest: Allow MSK/PMK list to be read from a text file
[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 program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include "utils/includes.h"
16 #include <netinet/ip.h>
17 #include <netinet/ip_icmp.h>
18
19 #include "utils/common.h"
20 #include "wlantest.h"
21
22
23 static void ping_update(struct wlantest_sta *sta, int req, u32 src, u32 dst,
24                         u16 id, u16 seq)
25 {
26         if (req) {
27                 sta->icmp_echo_req_src = src;
28                 sta->icmp_echo_req_dst = dst;
29                 sta->icmp_echo_req_id = id;
30                 sta->icmp_echo_req_seq = seq;
31                 return;
32         }
33
34         if (sta->icmp_echo_req_src == dst &&
35             sta->icmp_echo_req_dst == src &&
36             sta->icmp_echo_req_id == id &&
37             sta->icmp_echo_req_seq == seq) {
38                 sta->counters[WLANTEST_STA_COUNTER_PING_OK]++;
39                 if (sta->counters[WLANTEST_STA_COUNTER_ASSOCREQ_TX] == 0 &&
40                     sta->counters[WLANTEST_STA_COUNTER_REASSOCREQ_TX] == 0)
41                         sta->counters[
42                                 WLANTEST_STA_COUNTER_PING_OK_FIRST_ASSOC]++;
43                 wpa_printf(MSG_DEBUG, "ICMP echo (ping) match for STA " MACSTR,
44                            MAC2STR(sta->addr));
45         }
46 }
47
48
49 static void rx_data_icmp(struct wlantest *wt, const u8 *bssid,
50                          const u8 *sta_addr, u32 dst, u32 src,
51                          const u8 *data, size_t len, const u8 *peer_addr)
52 {
53         struct in_addr addr;
54         char buf[20];
55         const struct icmphdr *hdr;
56         u16 id, seq;
57         struct wlantest_bss *bss;
58         struct wlantest_sta *sta;
59
60         hdr = (const struct icmphdr *) data;
61         if (len < 4)
62                 return;
63
64         /* TODO: check hdr->checksum */
65
66         if (hdr->type != ICMP_ECHOREPLY && hdr->type != ICMP_ECHO)
67                 return;
68         if (len < 8)
69                 return;
70
71         id = ntohs(hdr->un.echo.id);
72         seq = ntohs(hdr->un.echo.sequence);
73
74         addr.s_addr = dst;
75         snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
76         addr.s_addr = src;
77         wpa_printf(MSG_DEBUG, "ICMP echo %s %s -> %s id=%04x seq=%u len=%u%s",
78                    hdr->type == ICMP_ECHO ? "request" : "response",
79                    inet_ntoa(addr), buf, id, seq, (unsigned) len - 8,
80                    peer_addr ? " [DL]" : "");
81
82         bss = bss_find(wt, bssid);
83         if (bss == NULL) {
84                 wpa_printf(MSG_INFO, "No BSS " MACSTR " known for ICMP packet",
85                            MAC2STR(bssid));
86                 return;
87         }
88
89         if (sta_addr == NULL)
90                 return; /* FromDS broadcast ping */
91
92         sta = sta_find(bss, sta_addr);
93         if (sta == NULL) {
94                 wpa_printf(MSG_INFO, "No STA " MACSTR " known for ICMP packet",
95                            MAC2STR(sta_addr));
96                 return;
97         }
98
99         ping_update(sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
100         if (peer_addr && (sta = sta_find(bss, peer_addr)))
101                 ping_update(sta, hdr->type == ICMP_ECHO, src, dst, id, seq);
102 }
103
104
105 void rx_data_ip(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr,
106                 const u8 *dst, const u8 *src, const u8 *data, size_t len,
107                 const u8 *peer_addr)
108 {
109         const struct iphdr *ip;
110         const u8 *payload;
111         size_t plen;
112         u16 frag_off, tot_len;
113
114         ip = (const struct iphdr *) data;
115         if (len < sizeof(*ip))
116                 return;
117         if (ip->version != 4) {
118                 wpa_printf(MSG_DEBUG, "Unexpected IP protocol version %u in "
119                            "IPv4 packet (bssid=" MACSTR " str=" MACSTR
120                            " dst=" MACSTR ")", ip->version, MAC2STR(bssid),
121                            MAC2STR(src), MAC2STR(dst));
122                 return;
123         }
124         if (ip->ihl * 4 < sizeof(*ip)) {
125                 wpa_printf(MSG_DEBUG, "Unexpected IP header length %u in "
126                            "IPv4 packet (bssid=" MACSTR " str=" MACSTR
127                            " dst=" MACSTR ")", ip->ihl, MAC2STR(bssid),
128                            MAC2STR(src), MAC2STR(dst));
129                 return;
130         }
131         if (ip->ihl * 4 > len) {
132                 wpa_printf(MSG_DEBUG, "Truncated IP header (ihl=%u len=%u) in "
133                            "IPv4 packet (bssid=" MACSTR " str=" MACSTR
134                            " dst=" MACSTR ")", ip->ihl, (unsigned) len,
135                            MAC2STR(bssid), MAC2STR(src), MAC2STR(dst));
136                 return;
137         }
138
139         /* TODO: check header checksum in ip->check */
140
141         frag_off = be_to_host16(ip->frag_off);
142         if (frag_off & 0x1fff) {
143                 wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
144                            "supported");
145                 return;
146         }
147
148         tot_len = be_to_host16(ip->tot_len);
149         if (tot_len > len)
150                 return;
151         if (tot_len < len)
152                 len = tot_len;
153
154         payload = data + 4 * ip->ihl;
155         plen = len - 4 * ip->ihl;
156
157         switch (ip->protocol) {
158         case IPPROTO_ICMP:
159                 rx_data_icmp(wt, bssid, sta_addr, ip->daddr, ip->saddr,
160                              payload, plen, peer_addr);
161                 break;
162         }
163 }