f67498200824e26c14b2d712bda856807c70d75f
[mech_eap.git] / wlantest / rx_data.c
1 /*
2  * Received Data frame processing
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
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
19 #include "common/eapol_common.h"
20 #include "common/wpa_common.h"
21 #include "wlantest.h"
22
23
24 static const char * data_stype(u16 stype)
25 {
26         switch (stype) {
27         case WLAN_FC_STYPE_DATA:
28                 return "DATA";
29         case WLAN_FC_STYPE_DATA_CFACK:
30                 return "DATA-CFACK";
31         case WLAN_FC_STYPE_DATA_CFPOLL:
32                 return "DATA-CFPOLL";
33         case WLAN_FC_STYPE_DATA_CFACKPOLL:
34                 return "DATA-CFACKPOLL";
35         case WLAN_FC_STYPE_NULLFUNC:
36                 return "NULLFUNC";
37         case WLAN_FC_STYPE_CFACK:
38                 return "CFACK";
39         case WLAN_FC_STYPE_CFPOLL:
40                 return "CFPOLL";
41         case WLAN_FC_STYPE_CFACKPOLL:
42                 return "CFACKPOLL";
43         case WLAN_FC_STYPE_QOS_DATA:
44                 return "QOSDATA";
45         case WLAN_FC_STYPE_QOS_DATA_CFACK:
46                 return "QOSDATA-CFACK";
47         case WLAN_FC_STYPE_QOS_DATA_CFPOLL:
48                 return "QOSDATA-CFPOLL";
49         case WLAN_FC_STYPE_QOS_DATA_CFACKPOLL:
50                 return "QOSDATA-CFACKPOLL";
51         case WLAN_FC_STYPE_QOS_NULL:
52                 return "QOS-NULL";
53         case WLAN_FC_STYPE_QOS_CFPOLL:
54                 return "QOS-CFPOLL";
55         case WLAN_FC_STYPE_QOS_CFACKPOLL:
56                 return "QOS-CFACKPOLL";
57         }
58         return "??";
59 }
60
61
62 static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
63                                      const u8 *src, const u8 *data, size_t len)
64 {
65         wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR,
66                    MAC2STR(src), MAC2STR(dst));
67 }
68
69
70 static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
71                                      const u8 *src, const u8 *data, size_t len)
72 {
73         wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR,
74                    MAC2STR(src), MAC2STR(dst));
75 }
76
77
78 static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
79                                      const u8 *src, const u8 *data, size_t len)
80 {
81         wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR,
82                    MAC2STR(src), MAC2STR(dst));
83 }
84
85
86 static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
87                                      const u8 *src, const u8 *data, size_t len)
88 {
89         wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
90                    MAC2STR(src), MAC2STR(dst));
91 }
92
93
94 static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
95                                      const u8 *src, const u8 *data, size_t len)
96 {
97         wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
98                    MAC2STR(src), MAC2STR(dst));
99 }
100
101
102 static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst,
103                                      const u8 *src, const u8 *data, size_t len)
104 {
105         wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR,
106                    MAC2STR(src), MAC2STR(dst));
107 }
108
109
110 static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
111                               const u8 *src, const u8 *data, size_t len,
112                               int prot)
113 {
114         const struct wpa_eapol_key *hdr;
115         u16 key_info, key_length, ver, key_data_length;
116
117         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key", data, len);
118         if (len < sizeof(*hdr)) {
119                 wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR,
120                            MAC2STR(src));
121                 return;
122         }
123         hdr = (const struct wpa_eapol_key *) data;
124
125         if (hdr->type == EAPOL_KEY_TYPE_RC4) {
126                 /* TODO: EAPOL-Key RC4 for WEP */
127                 return;
128         }
129
130         if (hdr->type != EAPOL_KEY_TYPE_RSN &&
131             hdr->type != EAPOL_KEY_TYPE_WPA) {
132                 wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key type %u",
133                            hdr->type);
134                 return;
135         }
136
137         key_info = WPA_GET_BE16(hdr->key_info);
138         key_length = WPA_GET_BE16(hdr->key_length);
139         key_data_length = WPA_GET_BE16(hdr->key_data_length);
140         ver = key_info & WPA_KEY_INFO_TYPE_MASK;
141         wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s "
142                    "datalen=%u",
143                    ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G',
144                    (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
145                    WPA_KEY_INFO_KEY_INDEX_SHIFT,
146                    (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "",
147                    (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "",
148                    (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "",
149                    (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "",
150                    (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "",
151                    (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "",
152                    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "",
153                    (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "",
154                    key_data_length);
155
156         if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
157             ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
158             ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
159                 wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key Key Descriptor "
160                            "Version %u", ver);
161                 return;
162         }
163
164         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter",
165                     hdr->replay_counter, WPA_REPLAY_COUNTER_LEN);
166         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce",
167                     hdr->key_nonce, WPA_NONCE_LEN);
168         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV",
169                     hdr->key_iv, 16);
170         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC",
171                     hdr->key_nonce, WPA_KEY_RSC_LEN);
172         wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC",
173                     hdr->key_mic, 16);
174
175         if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST))
176                 return;
177
178         if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
179                 return;
180
181         if (key_info & WPA_KEY_INFO_KEY_TYPE) {
182                 /* 4-Way Handshake */
183                 switch (key_info & (WPA_KEY_INFO_SECURE |
184                                     WPA_KEY_INFO_MIC |
185                                     WPA_KEY_INFO_ACK |
186                                     WPA_KEY_INFO_INSTALL)) {
187                 case WPA_KEY_INFO_ACK:
188                         rx_data_eapol_key_1_of_4(wt, dst, src, data, len);
189                         break;
190                 case WPA_KEY_INFO_MIC:
191                         rx_data_eapol_key_2_of_4(wt, dst, src, data, len);
192                         break;
193                 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
194                         WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
195                         rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
196                         break;
197                 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
198                         rx_data_eapol_key_4_of_4(wt, dst, src, data, len);
199                         break;
200                 default:
201                         wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
202                         break;
203                 }
204         } else {
205                 /* Group Key Handshake */
206                 switch (key_info & (WPA_KEY_INFO_SECURE |
207                                     WPA_KEY_INFO_MIC |
208                                     WPA_KEY_INFO_ACK)) {
209                 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
210                         WPA_KEY_INFO_ACK:
211                         rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
212                         break;
213                 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
214                         rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
215                         break;
216                 default:
217                         wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
218                         break;
219                 }
220         }
221 }
222
223
224 static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
225                           const u8 *data, size_t len, int prot)
226 {
227         const struct ieee802_1x_hdr *hdr;
228         u16 length;
229         const u8 *p;
230
231         wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len);
232         if (len < sizeof(*hdr)) {
233                 wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR,
234                            MAC2STR(src));
235                 return;
236         }
237
238         hdr = (const struct ieee802_1x_hdr *) data;
239         length = be_to_host16(hdr->length);
240         wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u "
241                    "type=%u len=%u",
242                    MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "",
243                    hdr->version, hdr->type, length);
244         if (sizeof(*hdr) + length > len) {
245                 wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR,
246                            MAC2STR(src));
247                 return;
248         }
249
250         if (sizeof(*hdr) + length < len) {
251                 wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes",
252                            (int) (len - sizeof(*hdr) - length));
253         }
254         p = (const u8 *) (hdr + 1);
255
256         switch (hdr->type) {
257         case IEEE802_1X_TYPE_EAP_PACKET:
258                 wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length);
259                 break;
260         case IEEE802_1X_TYPE_EAPOL_START:
261                 wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length);
262                 break;
263         case IEEE802_1X_TYPE_EAPOL_LOGOFF:
264                 wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
265                 break;
266         case IEEE802_1X_TYPE_EAPOL_KEY:
267                 rx_data_eapol_key(wt, dst, src, p, length, prot);
268                 break;
269         case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
270                 wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",
271                             p, length);
272                 break;
273         default:
274                 wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length);
275                 break;
276         }
277 }
278
279
280 static void rx_data_eth(struct wlantest *wt, const u8 *dst, const u8 *src,
281                         u16 ethertype, const u8 *data, size_t len, int prot)
282 {
283         if (ethertype == ETH_P_PAE)
284                 rx_data_eapol(wt, dst, src, data, len, prot);
285 }
286
287
288 static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src,
289                             const u8 *data, size_t len, int prot)
290 {
291         if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) {
292                 rx_data_eth(wt, dst, src, WPA_GET_BE16(data + 6),
293                             data + 8, len - 8, prot);
294                 return;
295         }
296
297         wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? len : 7);
298 }
299
300
301 static void rx_data_bss_prot(struct wlantest *wt,
302                              const struct ieee80211_hdr *hdr, const u8 *qos,
303                              const u8 *dst, const u8 *src, const u8 *data,
304                              size_t len)
305 {
306         /* TODO: Try to decrypt and if success, call rx_data_process() with
307          * prot = 1 */
308 }
309
310
311 static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr,
312                         const u8 *qos, const u8 *dst, const u8 *src,
313                         const u8 *data, size_t len)
314 {
315         u16 fc = le_to_host16(hdr->frame_control);
316         int prot = !!(fc & WLAN_FC_ISWEP);
317
318         if (qos) {
319                 u8 ack = (qos[0] & 0x60) >> 5;
320                 wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
321                            " len=%u%s tid=%u%s%s",
322                            MAC2STR(src), MAC2STR(dst), (unsigned int) len,
323                            prot ? " Prot" : "", qos[0] & 0x0f,
324                            (qos[0] & 0x10) ? " EOSP" : "",
325                            ack == 0 ? "" :
326                            (ack == 1 ? " NoAck" :
327                             (ack == 2 ? " NoExpAck" : " BA")));
328         } else {
329                 wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
330                            " len=%u%s",
331                            MAC2STR(src), MAC2STR(dst), (unsigned int) len,
332                            prot ? " Prot" : "");
333         }
334
335         if (prot)
336                 rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
337         else
338                 rx_data_process(wt, dst, src, data, len, 0);
339 }
340
341
342 void rx_data(struct wlantest *wt, const u8 *data, size_t len)
343 {
344         const struct ieee80211_hdr *hdr;
345         u16 fc, stype;
346         size_t hdrlen;
347         const u8 *qos = NULL;
348
349         if (len < 24)
350                 return;
351
352         hdr = (const struct ieee80211_hdr *) data;
353         fc = le_to_host16(hdr->frame_control);
354         stype = WLAN_FC_GET_STYPE(fc);
355         hdrlen = 24;
356         if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
357             (WLAN_FC_TODS | WLAN_FC_FROMDS))
358                 hdrlen += ETH_ALEN;
359         if (stype & 0x08) {
360                 qos = data + hdrlen;
361                 hdrlen += 2;
362         }
363         if (len < hdrlen)
364                 return;
365         wt->rx_data++;
366
367         switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
368         case 0:
369                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA="
370                            MACSTR " BSSID=" MACSTR,
371                            data_stype(WLAN_FC_GET_STYPE(fc)),
372                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
373                            fc & WLAN_FC_ISWEP ? " Prot" : "",
374                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
375                            MAC2STR(hdr->addr3));
376                 break;
377         case WLAN_FC_FROMDS:
378                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR
379                            " BSSID=" MACSTR " SA=" MACSTR,
380                            data_stype(WLAN_FC_GET_STYPE(fc)),
381                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
382                            fc & WLAN_FC_ISWEP ? " Prot" : "",
383                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
384                            MAC2STR(hdr->addr3));
385                 rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
386                             data + hdrlen, len - hdrlen);
387                 break;
388         case WLAN_FC_TODS:
389                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
390                            " SA=" MACSTR " DA=" MACSTR,
391                            data_stype(WLAN_FC_GET_STYPE(fc)),
392                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
393                            fc & WLAN_FC_ISWEP ? " Prot" : "",
394                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
395                            MAC2STR(hdr->addr3));
396                 rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2,
397                             data + hdrlen, len - hdrlen);
398                 break;
399         case WLAN_FC_TODS | WLAN_FC_FROMDS:
400                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="
401                            MACSTR " DA=" MACSTR " SA=" MACSTR,
402                            data_stype(WLAN_FC_GET_STYPE(fc)),
403                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
404                            fc & WLAN_FC_ISWEP ? " Prot" : "",
405                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
406                            MAC2STR(hdr->addr3),
407                            MAC2STR((const u8 *) (hdr + 1)));
408                 break;
409         }
410 }