aboutsummaryrefslogtreecommitdiffstats
path: root/wlantest/rx_data.c
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2010-11-06 19:49:57 (GMT)
committerJouni Malinen <j@w1.fi>2010-11-07 21:29:01 (GMT)
commit32234bba52d5ad370b91bb2cbd6b2c24b03c2512 (patch)
treeebb7c08e513dec8c3f2216a598bef3f47a38b11f /wlantest/rx_data.c
parent021a6fe49954768221f025d644851579b1aa6c6c (diff)
downloadhostap-32234bba52d5ad370b91bb2cbd6b2c24b03c2512.zip
hostap-32234bba52d5ad370b91bb2cbd6b2c24b03c2512.tar.gz
hostap-32234bba52d5ad370b91bb2cbd6b2c24b03c2512.tar.bz2
wlantest: Parse EAPOL-Key frames
Diffstat (limited to 'wlantest/rx_data.c')
-rw-r--r--wlantest/rx_data.c301
1 files changed, 300 insertions, 1 deletions
diff --git a/wlantest/rx_data.c b/wlantest/rx_data.c
index e6b1d61..f674982 100644
--- a/wlantest/rx_data.c
+++ b/wlantest/rx_data.c
@@ -16,6 +16,8 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
#include "wlantest.h"
@@ -57,16 +59,309 @@ static const char * data_stype(u16 stype)
}
+static void rx_data_eapol_key_1_of_4(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 1/4 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 2/4 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 3/4 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_1_of_2(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 1/2 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key_2_of_2(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len)
+{
+ wpa_printf(MSG_DEBUG, "EAPOL-Key 2/2 " MACSTR " -> " MACSTR,
+ MAC2STR(src), MAC2STR(dst));
+}
+
+
+static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
+ const u8 *src, const u8 *data, size_t len,
+ int prot)
+{
+ const struct wpa_eapol_key *hdr;
+ u16 key_info, key_length, ver, key_data_length;
+
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key", data, len);
+ if (len < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "Too short EAPOL-Key frame from " MACSTR,
+ MAC2STR(src));
+ return;
+ }
+ hdr = (const struct wpa_eapol_key *) data;
+
+ if (hdr->type == EAPOL_KEY_TYPE_RC4) {
+ /* TODO: EAPOL-Key RC4 for WEP */
+ return;
+ }
+
+ if (hdr->type != EAPOL_KEY_TYPE_RSN &&
+ hdr->type != EAPOL_KEY_TYPE_WPA) {
+ wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key type %u",
+ hdr->type);
+ return;
+ }
+
+ key_info = WPA_GET_BE16(hdr->key_info);
+ key_length = WPA_GET_BE16(hdr->key_length);
+ key_data_length = WPA_GET_BE16(hdr->key_data_length);
+ ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+ wpa_printf(MSG_DEBUG, "EAPOL-Key ver=%u %c idx=%u%s%s%s%s%s%s%s%s "
+ "datalen=%u",
+ ver, key_info & WPA_KEY_INFO_KEY_TYPE ? 'P' : 'G',
+ (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+ WPA_KEY_INFO_KEY_INDEX_SHIFT,
+ (key_info & WPA_KEY_INFO_INSTALL) ? " Install" : "",
+ (key_info & WPA_KEY_INFO_ACK) ? " ACK" : "",
+ (key_info & WPA_KEY_INFO_MIC) ? " MIC" : "",
+ (key_info & WPA_KEY_INFO_SECURE) ? " Secure" : "",
+ (key_info & WPA_KEY_INFO_ERROR) ? " Error" : "",
+ (key_info & WPA_KEY_INFO_REQUEST) ? " Request" : "",
+ (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) ? " Encr" : "",
+ (key_info & WPA_KEY_INFO_SMK_MESSAGE) ? " SMK" : "",
+ key_data_length);
+
+ if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key Key Descriptor "
+ "Version %u", ver);
+ return;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Replay Counter",
+ hdr->replay_counter, WPA_REPLAY_COUNTER_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Nonce",
+ hdr->key_nonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key IV",
+ hdr->key_iv, 16);
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key RSC",
+ hdr->key_nonce, WPA_KEY_RSC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key MIC",
+ hdr->key_mic, 16);
+
+ if (key_info & (WPA_KEY_INFO_ERROR | WPA_KEY_INFO_REQUEST))
+ return;
+
+ if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+ return;
+
+ if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+ /* 4-Way Handshake */
+ switch (key_info & (WPA_KEY_INFO_SECURE |
+ WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK |
+ WPA_KEY_INFO_INSTALL)) {
+ case WPA_KEY_INFO_ACK:
+ rx_data_eapol_key_1_of_4(wt, dst, src, data, len);
+ break;
+ case WPA_KEY_INFO_MIC:
+ rx_data_eapol_key_2_of_4(wt, dst, src, data, len);
+ break;
+ case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL:
+ rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
+ break;
+ case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+ rx_data_eapol_key_4_of_4(wt, dst, src, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+ break;
+ }
+ } else {
+ /* Group Key Handshake */
+ switch (key_info & (WPA_KEY_INFO_SECURE |
+ WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK)) {
+ case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_ACK:
+ rx_data_eapol_key_1_of_2(wt, dst, src, data, len);
+ break;
+ case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
+ rx_data_eapol_key_2_of_2(wt, dst, src, data, len);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
+ break;
+ }
+ }
+}
+
+
+static void rx_data_eapol(struct wlantest *wt, const u8 *dst, const u8 *src,
+ const u8 *data, size_t len, int prot)
+{
+ const struct ieee802_1x_hdr *hdr;
+ u16 length;
+ const u8 *p;
+
+ wpa_hexdump(MSG_EXCESSIVE, "EAPOL", data, len);
+ if (len < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "Too short EAPOL frame from " MACSTR,
+ MAC2STR(src));
+ return;
+ }
+
+ hdr = (const struct ieee802_1x_hdr *) data;
+ length = be_to_host16(hdr->length);
+ wpa_printf(MSG_DEBUG, "RX EAPOL: " MACSTR " -> " MACSTR "%s ver=%u "
+ "type=%u len=%u",
+ MAC2STR(src), MAC2STR(dst), prot ? " Prot" : "",
+ hdr->version, hdr->type, length);
+ if (sizeof(*hdr) + length > len) {
+ wpa_printf(MSG_INFO, "Truncated EAPOL frame from " MACSTR,
+ MAC2STR(src));
+ return;
+ }
+
+ if (sizeof(*hdr) + length < len) {
+ wpa_printf(MSG_INFO, "EAPOL frame with %d extra bytes",
+ (int) (len - sizeof(*hdr) - length));
+ }
+ p = (const u8 *) (hdr + 1);
+
+ switch (hdr->type) {
+ case IEEE802_1X_TYPE_EAP_PACKET:
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL - EAP packet", p, length);
+ break;
+ case IEEE802_1X_TYPE_EAPOL_START:
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Start", p, length);
+ break;
+ case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL-Logoff", p, length);
+ break;
+ case IEEE802_1X_TYPE_EAPOL_KEY:
+ rx_data_eapol_key(wt, dst, src, p, length, prot);
+ break;
+ case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+ wpa_hexdump(MSG_MSGDUMP, "EAPOL - Encapsulated ASF alert",
+ p, length);
+ break;
+ default:
+ wpa_hexdump(MSG_MSGDUMP, "Unknown EAPOL payload", p, length);
+ break;
+ }
+}
+
+
+static void rx_data_eth(struct wlantest *wt, const u8 *dst, const u8 *src,
+ u16 ethertype, const u8 *data, size_t len, int prot)
+{
+ if (ethertype == ETH_P_PAE)
+ rx_data_eapol(wt, dst, src, data, len, prot);
+}
+
+
+static void rx_data_process(struct wlantest *wt, const u8 *dst, const u8 *src,
+ const u8 *data, size_t len, int prot)
+{
+ if (len >= 8 && os_memcmp(data, "\xaa\xaa\x03\x00\x00\x00", 6) == 0) {
+ rx_data_eth(wt, dst, src, WPA_GET_BE16(data + 6),
+ data + 8, len - 8, prot);
+ return;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "Unrecognized LLC", data, len > 8 ? len : 7);
+}
+
+
+static void rx_data_bss_prot(struct wlantest *wt,
+ const struct ieee80211_hdr *hdr, const u8 *qos,
+ const u8 *dst, const u8 *src, const u8 *data,
+ size_t len)
+{
+ /* TODO: Try to decrypt and if success, call rx_data_process() with
+ * prot = 1 */
+}
+
+
+static void rx_data_bss(struct wlantest *wt, const struct ieee80211_hdr *hdr,
+ const u8 *qos, const u8 *dst, const u8 *src,
+ const u8 *data, size_t len)
+{
+ u16 fc = le_to_host16(hdr->frame_control);
+ int prot = !!(fc & WLAN_FC_ISWEP);
+
+ if (qos) {
+ u8 ack = (qos[0] & 0x60) >> 5;
+ wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+ " len=%u%s tid=%u%s%s",
+ MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+ prot ? " Prot" : "", qos[0] & 0x0f,
+ (qos[0] & 0x10) ? " EOSP" : "",
+ ack == 0 ? "" :
+ (ack == 1 ? " NoAck" :
+ (ack == 2 ? " NoExpAck" : " BA")));
+ } else {
+ wpa_printf(MSG_MSGDUMP, "BSS DATA: " MACSTR " -> " MACSTR
+ " len=%u%s",
+ MAC2STR(src), MAC2STR(dst), (unsigned int) len,
+ prot ? " Prot" : "");
+ }
+
+ if (prot)
+ rx_data_bss_prot(wt, hdr, qos, dst, src, data, len);
+ else
+ rx_data_process(wt, dst, src, data, len, 0);
+}
+
+
void rx_data(struct wlantest *wt, const u8 *data, size_t len)
{
const struct ieee80211_hdr *hdr;
- u16 fc;
+ u16 fc, stype;
+ size_t hdrlen;
+ const u8 *qos = NULL;
if (len < 24)
return;
hdr = (const struct ieee80211_hdr *) data;
fc = le_to_host16(hdr->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+ hdrlen = 24;
+ if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
+ (WLAN_FC_TODS | WLAN_FC_FROMDS))
+ hdrlen += ETH_ALEN;
+ if (stype & 0x08) {
+ qos = data + hdrlen;
+ hdrlen += 2;
+ }
+ if (len < hdrlen)
+ return;
wt->rx_data++;
switch (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
@@ -87,6 +382,8 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len)
fc & WLAN_FC_ISWEP ? " Prot" : "",
MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
MAC2STR(hdr->addr3));
+ rx_data_bss(wt, hdr, qos, hdr->addr1, hdr->addr2,
+ data + hdrlen, len - hdrlen);
break;
case WLAN_FC_TODS:
wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s ToDS BSSID=" MACSTR
@@ -96,6 +393,8 @@ void rx_data(struct wlantest *wt, const u8 *data, size_t len)
fc & WLAN_FC_ISWEP ? " Prot" : "",
MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
MAC2STR(hdr->addr3));
+ rx_data_bss(wt, hdr, qos, hdr->addr3, hdr->addr2,
+ data + hdrlen, len - hdrlen);
break;
case WLAN_FC_TODS | WLAN_FC_FROMDS:
wpa_printf(MSG_EXCESSIVE, "DATA %s%s%s WDS RA=" MACSTR " TA="