wlantest: Add counters and AP/direct path validation for TDLS
[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 #include <linux/if_ether.h>
17
18 #include "utils/common.h"
19 #include "common/defs.h"
20 #include "common/ieee802_11_defs.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_eth(struct wlantest *wt, const u8 *bssid,
63                         const u8 *sta_addr, const u8 *dst, const u8 *src,
64                         u16 ethertype, const u8 *data, size_t len, int prot)
65 {
66         switch (ethertype) {
67         case ETH_P_PAE:
68                 rx_data_eapol(wt, dst, src, data, len, prot);
69                 break;
70         case ETH_P_IP:
71                 rx_data_ip(wt, bssid, sta_addr, dst, src, data, len);
72                 break;
73         case 0x890d:
74                 rx_data_80211_encap(wt, bssid, sta_addr, dst, src, data, len);
75                 break;
76         }
77 }
78
79
80 static void rx_data_process(struct wlantest *wt, const u8 *bssid,
81                             const u8 *sta_addr,
82                             const u8 *dst, const u8 *src,
83                             const u8 *data, size_t len, int prot)
84 {
85         if (len == 0)
86                 return;
87
88         if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) {
89                 rx_data_eth(wt, bssid, sta_addr, dst, src,
90                             WPA_GET_BE16(data + 6), data + 8, len - 8, prot);
91                 return;
92         }
93
94         wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? 8 : len);
95 }
96
97
98 static void rx_data_bss_prot_group(struct wlantest *wt,
99                                    const struct ieee80211_hdr *hdr,
100                                    const u8 *qos, const u8 *dst, const u8 *src,
101                                    const u8 *data, size_t len)
102 {
103         struct wlantest_bss *bss;
104         int keyid;
105         u8 *decrypted;
106         size_t dlen;
107         u8 pn[6];
108
109         bss = bss_get(wt, hdr->addr2);
110         if (bss == NULL)
111                 return;
112         if (len < 4) {
113                 wpa_printf(MSG_INFO, "Too short group addressed data frame");
114                 return;
115         }
116
117         if (bss->group_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
118             !(data[3] & 0x20)) {
119                     wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from "
120                                MACSTR " did not have ExtIV bit set to 1",
121                                MAC2STR(bss->bssid));
122                     return;
123         }
124
125         if (bss->group_cipher == WPA_CIPHER_TKIP) {
126                 if (data[3] & 0x1f) {
127                         wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
128                                    "non-zero reserved bit",
129                                    MAC2STR(bss->bssid));
130                 }
131                 if (data[1] != ((data[0] | 0x20) & 0x7f)) {
132                         wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
133                                    "incorrect WEPSeed[1] (was 0x%x, expected "
134                                    "0x%x)",
135                                    MAC2STR(bss->bssid), data[1],
136                                    (data[0] | 0x20) & 0x7f);
137                 }
138         } else if (bss->group_cipher == WPA_CIPHER_CCMP) {
139                 if (data[2] != 0 || (data[3] & 0x1f) != 0) {
140                         wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used "
141                                    "non-zero reserved bit",
142                                    MAC2STR(bss->bssid));
143                 }
144         }
145
146         keyid = data[3] >> 6;
147         if (bss->gtk_len[keyid] == 0) {
148                 wpa_printf(MSG_MSGDUMP, "No GTK known to decrypt the frame "
149                            "(A2=" MACSTR " KeyID=%d)",
150                            MAC2STR(hdr->addr2), keyid);
151                 return;
152         }
153
154         if (bss->group_cipher == WPA_CIPHER_TKIP)
155                 tkip_get_pn(pn, data);
156         else
157                 ccmp_get_pn(pn, data);
158         if (os_memcmp(pn, bss->rsc[keyid], 6) <= 0) {
159                 wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: SA=" MACSTR,
160                            MAC2STR(hdr->addr2));
161                 wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
162                 wpa_hexdump(MSG_INFO, "RSC", bss->rsc[keyid], 6);
163         }
164
165         if (bss->group_cipher == WPA_CIPHER_TKIP)
166                 decrypted = tkip_decrypt(bss->gtk[keyid], hdr, data, len,
167                                          &dlen);
168         else
169                 decrypted = ccmp_decrypt(bss->gtk[keyid], hdr, data, len,
170                                          &dlen);
171         if (decrypted) {
172                 rx_data_process(wt, bss->bssid, NULL, dst, src, decrypted,
173                                 dlen, 1);
174                 os_memcpy(bss->rsc[keyid], pn, 6);
175                 write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
176                                      decrypted, dlen);
177         }
178         os_free(decrypted);
179 }
180
181
182 static void rx_data_bss_prot(struct wlantest *wt,
183                              const struct ieee80211_hdr *hdr, const u8 *qos,
184                              const u8 *dst, const u8 *src, const u8 *data,
185                              size_t len)
186 {
187         struct wlantest_bss *bss;
188         struct wlantest_sta *sta, *sta2;
189         int keyid;
190         u16 fc = le_to_host16(hdr->frame_control);
191         u8 *decrypted;
192         size_t dlen;
193         int tid;
194         u8 pn[6], *rsc;
195         struct wlantest_tdls *tdls = NULL;
196         const u8 *tk = NULL;
197
198         if (hdr->addr1[0] & 0x01) {
199                 rx_data_bss_prot_group(wt, hdr, qos, dst, src, data, len);
200                 return;
201         }
202
203         if (fc & WLAN_FC_TODS) {
204                 bss = bss_get(wt, hdr->addr1);
205                 if (bss == NULL)
206                         return;
207                 sta = sta_get(bss, hdr->addr2);
208         } else if (fc & WLAN_FC_FROMDS) {
209                 bss = bss_get(wt, hdr->addr2);
210                 if (bss == NULL)
211                         return;
212                 sta = sta_get(bss, hdr->addr1);
213         } else {
214                 bss = bss_get(wt, hdr->addr3);
215                 if (bss == NULL)
216                         return;
217                 sta = sta_find(bss, hdr->addr2);
218                 sta2 = sta_find(bss, hdr->addr1);
219                 if (sta == NULL || sta2 == NULL)
220                         return;
221                 dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list)
222                 {
223                         if ((tdls->init == sta && tdls->resp == sta2) ||
224                             (tdls->init == sta2 && tdls->resp == sta)) {
225                                 if (!tdls->link_up)
226                                         wpa_printf(MSG_DEBUG, "TDLS: Link not "
227                                                    "up, but Data frame seen");
228                                 tk = tdls->tpk.tk;
229                                 break;
230                         }
231                 }
232         }
233         if ((sta == NULL || !sta->ptk_set) && tk == NULL) {
234                 wpa_printf(MSG_MSGDUMP, "No PTK known to decrypt the frame");
235                 return;
236         }
237
238         if (len < 4) {
239                 wpa_printf(MSG_INFO, "Too short encrypted data frame");
240                 return;
241         }
242
243         if (sta->pairwise_cipher & (WPA_CIPHER_TKIP | WPA_CIPHER_CCMP) &&
244             !(data[3] & 0x20)) {
245                     wpa_printf(MSG_INFO, "Expected TKIP/CCMP frame from "
246                                MACSTR " did not have ExtIV bit set to 1",
247                                MAC2STR(src));
248                     return;
249         }
250
251         if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP) {
252                 if (data[3] & 0x1f) {
253                         wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
254                                    "non-zero reserved bit",
255                                    MAC2STR(hdr->addr2));
256                 }
257                 if (data[1] != ((data[0] | 0x20) & 0x7f)) {
258                         wpa_printf(MSG_INFO, "TKIP frame from " MACSTR " used "
259                                    "incorrect WEPSeed[1] (was 0x%x, expected "
260                                    "0x%x)",
261                                    MAC2STR(hdr->addr2), data[1],
262                                    (data[0] | 0x20) & 0x7f);
263                 }
264         } else if (tk || sta->pairwise_cipher == WPA_CIPHER_CCMP) {
265                 if (data[2] != 0 || (data[3] & 0x1f) != 0) {
266                         wpa_printf(MSG_INFO, "CCMP frame from " MACSTR " used "
267                                    "non-zero reserved bit",
268                                    MAC2STR(hdr->addr2));
269                 }
270         }
271
272         keyid = data[3] >> 6;
273         if (keyid != 0) {
274                 wpa_printf(MSG_INFO, "Unexpected non-zero KeyID %d in "
275                            "individually addressed Data frame from " MACSTR,
276                            keyid, MAC2STR(hdr->addr2));
277         }
278
279         if (qos)
280                 tid = qos[0] & 0x0f;
281         else
282                 tid = 0;
283         if (tk) {
284                 if (os_memcmp(hdr->addr2, tdls->init->addr, ETH_ALEN) == 0)
285                         rsc = tdls->rsc_init[tid];
286                 else
287                         rsc = tdls->rsc_resp[tid];
288         } else if (fc & WLAN_FC_TODS)
289                 rsc = sta->rsc_tods[tid];
290         else
291                 rsc = sta->rsc_fromds[tid];
292
293
294         if (tk == NULL && sta->pairwise_cipher == WPA_CIPHER_TKIP)
295                 tkip_get_pn(pn, data);
296         else
297                 ccmp_get_pn(pn, data);
298         if (os_memcmp(pn, rsc, 6) <= 0) {
299                 wpa_printf(MSG_INFO, "CCMP/TKIP replay detected: SA=" MACSTR,
300                            MAC2STR(hdr->addr2));
301                 wpa_hexdump(MSG_INFO, "RX PN", pn, 6);
302                 wpa_hexdump(MSG_INFO, "RSC", rsc, 6);
303         }
304
305         if (tk)
306                 decrypted = ccmp_decrypt(tk, hdr, data, len, &dlen);
307         else if (sta->pairwise_cipher == WPA_CIPHER_TKIP)
308                 decrypted = tkip_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
309         else
310                 decrypted = ccmp_decrypt(sta->ptk.tk1, hdr, data, len, &dlen);
311         if (decrypted) {
312                 rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted,
313                                 dlen, 1);
314                 os_memcpy(rsc, pn, 6);
315                 write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
316                                      decrypted, dlen);
317         }
318         os_free(decrypted);
319 }
320
321
322 static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr,
323                         const u8 *qos, const u8 *dst, const u8 *src,
324                         const u8 *data, size_t len)
325 {
326         u16 fc = le_to_host16(hdr->frame_control);
327         int prot = !!(fc & WLAN_FC_ISWEP);
328
329         if (qos) {
330                 u8 ack = (qos[0] & 0x60) >> 5;
331                 wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
332                            " len=%u%s tid=%u%s%s",
333                            MAC2STR(src), MAC2STR(dst), (unsigned int) len,
334                            prot ? " Prot" : "", qos[0] & 0x0f,
335                            (qos[0] & 0x10) ? " EOSP" : "",
336                            ack == 0 ? "" :
337                            (ack == 1 ? " NoAck" :
338                             (ack == 2 ? " NoExpAck" : " BA")));
339         } else {
340                 wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
341                            " len=%u%s",
342                            MAC2STR(src), MAC2STR(dst), (unsigned int) len,
343                            prot ? " Prot" : "");
344         }
345
346         if (prot)
347                 rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
348         else {
349                 const u8 *bssid, *sta_addr;
350                 if (fc & WLAN_FC_TODS) {
351                         bssid = hdr->addr1;
352                         sta_addr = hdr->addr2;
353                 } else {
354                         bssid = hdr->addr2;
355                         sta_addr = hdr->addr1;
356                 }
357                 rx_data_process(wt, bssid, sta_addr, dst, src, data, len, 0);
358         }
359 }
360
361
362 static struct wlantest_tdls * get_tdls(struct wlantest *wt, const u8 *bssid,
363                                        const u8 *sta1_addr,
364                                        const u8 *sta2_addr)
365 {
366         struct wlantest_bss *bss;
367         struct wlantest_sta *sta1, *sta2;
368         struct wlantest_tdls *tdls;
369
370         bss = bss_find(wt, bssid);
371         if (bss == NULL)
372                 return NULL;
373         sta1 = sta_find(bss, sta1_addr);
374         if (sta1 == NULL)
375                 return NULL;
376         sta2 = sta_find(bss, sta2_addr);
377         if (sta2 == NULL)
378                 return NULL;
379
380         dl_list_for_each(tdls, &bss->tdls, struct wlantest_tdls, list) {
381                 if ((tdls->init == sta1 && tdls->resp == sta2) ||
382                     (tdls->init == sta2 && tdls->resp == sta1))
383                         return tdls;
384         }
385
386         return NULL;
387 }
388
389
390 static void add_direct_link(struct wlantest *wt, const u8 *bssid,
391                             const u8 *sta1_addr, const u8 *sta2_addr)
392 {
393         struct wlantest_tdls *tdls;
394
395         tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr);
396         if (tdls == NULL)
397                 return;
398
399         if (tdls->link_up)
400                 tdls->counters[WLANTEST_TDLS_COUNTER_VALID_DIRECT_LINK]++;
401         else
402                 tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_DIRECT_LINK]++;
403 }
404
405
406 static void add_ap_path(struct wlantest *wt, const u8 *bssid,
407                         const u8 *sta1_addr, const u8 *sta2_addr)
408 {
409         struct wlantest_tdls *tdls;
410
411         tdls = get_tdls(wt, bssid, sta1_addr, sta2_addr);
412         if (tdls == NULL)
413                 return;
414
415         if (tdls->link_up)
416                 tdls->counters[WLANTEST_TDLS_COUNTER_INVALID_AP_PATH]++;
417         else
418                 tdls->counters[WLANTEST_TDLS_COUNTER_VALID_AP_PATH]++;
419 }
420
421
422 void rx_data(struct wlantest *wt, const u8 *data, size_t len)
423 {
424         const struct ieee80211_hdr *hdr;
425         u16 fc, stype;
426         size_t hdrlen;
427         const u8 *qos = NULL;
428
429         if (len < 24)
430                 return;
431
432         hdr = (const struct ieee80211_hdr *) data;
433         fc = le_to_host16(hdr->frame_control);
434         stype = WLAN_FC_GET_STYPE(fc);
435         hdrlen = 24;
436         if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
437             (WLAN_FC_TODS | WLAN_FC_FROMDS))
438                 hdrlen += ETH_ALEN;
439         if (stype & 0x08) {
440                 qos = data + hdrlen;
441                 hdrlen += 2;
442         }
443         if (len < hdrlen)
444                 return;
445         wt->rx_data++;
446
447         switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
448         case 0:
449                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s IBSS DA=" MACSTR " SA="
450                            MACSTR " BSSID=" MACSTR,
451                            data_stype(WLAN_FC_GET_STYPE(fc)),
452                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
453                            fc & WLAN_FC_ISWEP ? " Prot" : "",
454                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
455                            MAC2STR(hdr->addr3));
456                 add_direct_link(wt, hdr->addr3, hdr->addr1, hdr->addr2);
457                 rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
458                             data + hdrlen, len - hdrlen);
459                 break;
460         case WLAN_FC_FROMDS:
461                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s FromDS DA=" MACSTR
462                            " BSSID=" MACSTR " SA=" MACSTR,
463                            data_stype(WLAN_FC_GET_STYPE(fc)),
464                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
465                            fc & WLAN_FC_ISWEP ? " Prot" : "",
466                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
467                            MAC2STR(hdr->addr3));
468                 add_ap_path(wt, hdr->addr2, hdr->addr1, hdr->addr3);
469                 rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
470                             data + hdrlen, len - hdrlen);
471                 break;
472         case WLAN_FC_TODS:
473                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
474                            " SA=" MACSTR " DA=" MACSTR,
475                            data_stype(WLAN_FC_GET_STYPE(fc)),
476                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
477                            fc & WLAN_FC_ISWEP ? " Prot" : "",
478                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
479                            MAC2STR(hdr->addr3));
480                 add_ap_path(wt, hdr->addr1, hdr->addr3, hdr->addr2);
481                 rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2,
482                             data + hdrlen, len - hdrlen);
483                 break;
484         case WLAN_FC_TODS | WLAN_FC_FROMDS:
485                 wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="
486                            MACSTR " DA=" MACSTR " SA=" MACSTR,
487                            data_stype(WLAN_FC_GET_STYPE(fc)),
488                            fc & WLAN_FC_PWRMGT ? " PwrMgt" : "",
489                            fc & WLAN_FC_ISWEP ? " Prot" : "",
490                            MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
491                            MAC2STR(hdr->addr3),
492                            MAC2STR((const u8 *) (hdr + 1)));
493                 break;
494         }
495 }