2 * Received Data frame processing
3 * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
15 #include "utils/includes.h"
17 #include "utils/common.h"
18 #include "common/ieee802_11_defs.h"
19 #include "common/eapol_common.h"
20 #include "common/wpa_common.h"
24 static const char * data_stype(u16 stype)
27 case WLAN_FC_STYPE_DATA:
29 case WLAN_FC_STYPE_DATA_CFACK:
31 case WLAN_FC_STYPE_DATA_CFPOLL:
33 case WLAN_FC_STYPE_DATA_CFACKPOLL:
34 return "DATA-CFACKPOLL";
35 case WLAN_FC_STYPE_NULLFUNC:
37 case WLAN_FC_STYPE_CFACK:
39 case WLAN_FC_STYPE_CFPOLL:
41 case WLAN_FC_STYPE_CFACKPOLL:
43 case WLAN_FC_STYPE_QOS_DATA:
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:
53 case WLAN_FC_STYPE_QOS_CFPOLL:
55 case WLAN_FC_STYPE_QOS_CFACKPOLL:
56 return "QOS-CFACKPOLL";
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)
65 wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR,
66 MAC2STR(src), MAC2STR(dst));
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)
73 wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR,
74 MAC2STR(src), MAC2STR(dst));
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)
81 wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR,
82 MAC2STR(src), MAC2STR(dst));
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)
89 wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
90 MAC2STR(src), MAC2STR(dst));
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)
97 wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
98 MAC2STR(src), MAC2STR(dst));
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)
105 wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR,
106 MAC2STR(src), MAC2STR(dst));
110 static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
111 const u8 *src, const u8 *data, size_t len,
114 const struct wpa_eapol_key *hdr;
115 u16 key_info, key_length, ver, key_data_length;
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,
123 hdr = (const struct wpa_eapol_key *) data;
125 if (hdr->type == EAPOL_KEY_TYPE_RC4) {
126 /* TODO: EAPOL-Key RC4 for WEP */
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",
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 "
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" : "",
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 "
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",
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",
175 if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST))
178 if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
181 if (key_info & WPA_KEY_INFO_KEY_TYPE) {
182 /* 4-Way Handshake */
183 switch (key_info & (WPA_KEY_INFO_SECURE |
186 WPA_KEY_INFO_INSTALL)) {
187 case WPA_KEY_INFO_ACK:
188 rx_data_eapol_key_1_of_4(wt, dst, src, data, len);
190 case WPA_KEY_INFO_MIC:
191 rx_data_eapol_key_2_of_4(wt, dst, src, data, len);
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);
197 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
198 rx_data_eapol_key_4_of_4(wt, dst, src, data, len);
201 wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
205 /* Group Key Handshake */
206 switch (key_info & (WPA_KEY_INFO_SECURE |
209 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
211 rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
213 case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
214 rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
217 wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
224 static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
225 const u8 *data, size_t len, int prot)
227 const struct ieee802_1x_hdr *hdr;
231 wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len);
232 if (len < sizeof(*hdr)) {
233 wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR,
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 "
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,
250 if (sizeof(*hdr) + length < len) {
251 wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes",
252 (int) (len - sizeof(*hdr) - length));
254 p = (const u8 *) (hdr + 1);
257 case IEEE802_1X_TYPE_EAP_PACKET:
258 wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length);
260 case IEEE802_1X_TYPE_EAPOL_START:
261 wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length);
263 case IEEE802_1X_TYPE_EAPOL_LOGOFF:
264 wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
266 case IEEE802_1X_TYPE_EAPOL_KEY:
267 rx_data_eapol_key(wt, dst, src, p, length, prot);
269 case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
270 wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",
274 wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length);
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)
283 if (ethertype == ETH_P_PAE)
284 rx_data_eapol(wt, dst, src, data, len, prot);
288 static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src,
289 const u8 *data, size_t len, int prot)
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);
297 wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? len : 7);
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,
306 /* TODO: Try to decrypt and if success, call rx_data_process() with
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)
315 u16 fc = le_to_host16(hdr->frame_control);
316 int prot = !!(fc & WLAN_FC_ISWEP);
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" : "",
326 (ack == 1 ? " NoAck" :
327 (ack == 2 ? " NoExpAck" : " BA")));
329 wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
331 MAC2STR(src), MAC2STR(dst), (unsigned int) len,
332 prot ? " Prot" : "");
336 rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
338 rx_data_process(wt, dst, src, data, len, 0);
342 void rx_data(struct wlantest *wt, const u8 *data, size_t len)
344 const struct ieee80211_hdr *hdr;
347 const u8 *qos = NULL;
352 hdr = (const struct ieee80211_hdr *) data;
353 fc = le_to_host16(hdr->frame_control);
354 stype = WLAN_FC_GET_STYPE(fc);
356 if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
357 (WLAN_FC_TODS | WLAN_FC_FROMDS))
367 switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
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));
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);
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);
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),
407 MAC2STR((const u8 *) (hdr + 1)));