summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files4
-rw-r--r--sys/net80211/ieee80211_input.c882
-rw-r--r--sys/net80211/ieee80211_output.c566
-rw-r--r--sys/net80211/ieee80211_pae_input.c916
-rw-r--r--sys/net80211/ieee80211_pae_output.c607
-rw-r--r--sys/net80211/ieee80211_proto.h7
6 files changed, 1534 insertions, 1448 deletions
diff --git a/sys/conf/files b/sys/conf/files
index d599c5de112..95a4f23fd4a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $OpenBSD: files,v 1.437 2008/07/08 05:22:00 dlg Exp $
+# $OpenBSD: files,v 1.438 2008/07/21 19:05:21 damien Exp $
# $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -793,6 +793,8 @@ file net80211/ieee80211_input.c wlan
file net80211/ieee80211_ioctl.c wlan
file net80211/ieee80211_node.c wlan
file net80211/ieee80211_output.c wlan
+file net80211/ieee80211_pae_input.c wlan
+file net80211/ieee80211_pae_output.c wlan
file net80211/ieee80211_proto.c wlan
file net80211/ieee80211_rssadapt.c wlan
file net80211/ieee80211_regdomain.c wlan
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index de5744fc04d..0fa629c0a33 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,5 +1,5 @@
/* $NetBSD: ieee80211_input.c,v 1.24 2004/05/31 11:12:24 dyoung Exp $ */
-/* $OpenBSD: ieee80211_input.c,v 1.81 2008/07/21 18:43:18 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.82 2008/07/21 19:05:21 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -62,8 +62,6 @@
#include <net80211/ieee80211_var.h>
-#include <dev/rndvar.h>
-
int ieee80211_parse_edca_params_body(struct ieee80211com *,
const u_int8_t *);
int ieee80211_parse_edca_params(struct ieee80211com *, const u_int8_t *);
@@ -72,10 +70,6 @@ enum ieee80211_cipher ieee80211_parse_rsn_cipher(const u_int8_t[]);
enum ieee80211_akm ieee80211_parse_rsn_akm(const u_int8_t[]);
int ieee80211_parse_rsn_body(struct ieee80211com *, const u_int8_t *,
u_int, struct ieee80211_rsnparams *);
-int ieee80211_parse_rsn(struct ieee80211com *, const u_int8_t *,
- struct ieee80211_rsnparams *);
-int ieee80211_parse_wpa(struct ieee80211com *, const u_int8_t *,
- struct ieee80211_rsnparams *);
int ieee80211_save_ie(const u_int8_t *, u_int8_t **);
void ieee80211_recv_pspoll(struct ieee80211com *, struct mbuf *);
void ieee80211_recv_probe_resp(struct ieee80211com *, struct mbuf *,
@@ -94,25 +88,6 @@ void ieee80211_recv_disassoc(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
void ieee80211_recv_action(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
-void ieee80211_recv_4way_msg1(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_4way_msg2(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *,
- const u_int8_t *);
-void ieee80211_recv_4way_msg3(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_4way_msg4(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_4way_msg2or4(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_rsn_group_msg1(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_wpa_group_msg1(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_group_msg2(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
-void ieee80211_recv_eapol_key_req(struct ieee80211com *,
- struct ieee80211_eapol_key *, struct ieee80211_node *);
/*
* Retrieve the length in bytes of a 802.11 header.
@@ -1889,861 +1864,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
}
}
-/* unaligned big endian access */
-#define BE_READ_2(p) \
- ((u_int16_t)(p)[0] << 8 | (u_int16_t)(p)[1])
-
-#define BE_READ_8(p) \
- ((u_int64_t)(p)[0] << 56 | (u_int64_t)(p)[1] << 48 | \
- (u_int64_t)(p)[2] << 40 | (u_int64_t)(p)[3] << 32 | \
- (u_int64_t)(p)[4] << 24 | (u_int64_t)(p)[5] << 16 | \
- (u_int64_t)(p)[6] << 8 | (u_int64_t)(p)[7])
-
-/* unaligned little endian access */
-#define LE_READ_6(p) \
- ((u_int64_t)(p)[5] << 40 | (u_int64_t)(p)[4] << 32 | \
- (u_int64_t)(p)[3] << 24 | (u_int64_t)(p)[2] << 16 | \
- (u_int64_t)(p)[1] << 8 | (u_int64_t)(p)[0])
-
-/*
- * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
- * (see 8.5.3.1).
- */
-void
-ieee80211_recv_4way_msg1(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- struct ieee80211_ptk tptk;
- const u_int8_t *frm, *efrm;
- const u_int8_t *pmkid;
- const u_int8_t *pmk;
-
- if (ic->ic_opmode != IEEE80211_M_STA &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- if (ni->ni_replaycnt_ok &&
- BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
- /* save authenticator's nonce (ANonce) */
- memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN);
-
- /* parse key data field (may contain an encapsulated PMKID) */
- frm = (const u_int8_t *)&key[1];
- efrm = frm + BE_READ_2(key->paylen);
-
- pmkid = NULL;
- while (frm + 2 <= efrm) {
- if (frm + 2 + frm[1] > efrm)
- break;
- switch (frm[0]) {
- case IEEE80211_ELEMID_VENDOR:
- if (frm[1] < 4)
- break;
- if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
- switch (frm[5]) {
- case IEEE80211_KDE_PMKID:
- pmkid = frm;
- break;
- }
- }
- break;
- }
- frm += 2 + frm[1];
- }
- /* check that the PMKID KDE is valid (if present) */
- if (pmkid != NULL && pmkid[1] < 4 + 16)
- return;
-
- /* generate a new supplicant's nonce (SNonce) */
- arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
-
- /* retrieve PMK and derive TPTK */
- if ((pmk = ieee80211_get_pmk(ic, ni, pmkid)) == NULL) {
- /* no PMK configured for this STA/PMKID */
- return;
- }
- ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
- ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
- sizeof(tptk));
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 1, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 2 to authenticator using TPTK */
- (void)ieee80211_send_4way_msg2(ic, ni, key->replaycnt, &tptk);
-}
-
-/*
- * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
- * (see 8.5.3.2).
- */
-void
-ieee80211_recv_4way_msg2(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni,
- const u_int8_t *rsnie)
-{
- struct ieee80211_ptk tptk;
- const u_int8_t *pmk;
-
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- /* discard if we're not expecting this message */
- if (ni->ni_rsn_state != RSNA_PTKSTART &&
- ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING) {
- IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
- __func__, ni->ni_rsn_state));
- return;
- }
- ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING;
-
- /* replay counter has already been verified by caller */
-
- /* retrieve PMK and derive TPTK */
- if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
- /* no PMK configured for this STA */
- return; /* will timeout.. */
- }
- ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ic->ic_myaddr,
- ni->ni_macaddr, ni->ni_nonce, key->nonce, (u_int8_t *)&tptk,
- sizeof(tptk));
-
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return; /* will timeout.. */
- }
-
- timeout_del(&ni->ni_rsn_timeout);
- ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2;
- ni->ni_rsn_retries = 0;
-
- /* install TPTK as PTK now that MIC is verified */
- memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
-
- /*
- * The RSN IE must match bit-wise with what the STA included in its
- * (Re)Association Request.
- */
- if (ni->ni_rsnie == NULL || rsnie[1] != ni->ni_rsnie[1] ||
- memcmp(rsnie, ni->ni_rsnie, 2 + rsnie[1]) != 0) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_RSN_DIFFERENT_IE);
- ieee80211_node_leave(ic, ni);
- return;
- }
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 2, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 3 to supplicant */
- (void)ieee80211_send_4way_msg3(ic, ni);
-}
-
-/*
- * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
- * (see 8.5.3.3).
- */
-void
-ieee80211_recv_4way_msg3(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- struct ieee80211_ptk tptk;
- struct ieee80211_key *k;
- const u_int8_t *frm, *efrm;
- const u_int8_t *rsnie1, *rsnie2, *gtk;
- const u_int8_t *pmk;
- u_int16_t info, reason = 0;
-
- if (ic->ic_opmode != IEEE80211_M_STA &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- if (ni->ni_replaycnt_ok &&
- BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
-
- /* check that ANonce matches that of message 1 */
- if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0) {
- IEEE80211_DPRINTF(("%s: ANonce does not match msg 1/4\n",
- __func__));
- return;
- }
- /* retrieve PMK and derive TPTK */
- if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
- /* no PMK configured for this STA */
- return;
- }
- ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
- ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
- sizeof(tptk));
-
- info = BE_READ_2(key->info);
-
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return;
- }
- /* install TPTK as PTK now that MIC is verified */
- memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
-
- /* if encrypted, decrypt Key Data field using KEK */
- if ((info & EAPOL_KEY_ENCRYPTED) &&
- ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
- IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
- return;
- }
-
- /* parse key data field */
- frm = (const u_int8_t *)&key[1];
- efrm = frm + BE_READ_2(key->paylen);
-
- /*
- * Some WPA1+WPA2 APs (like hostapd) appear to include both WPA and
- * RSN IEs in message 3/4. We only take into account the IE of the
- * version of the protocol we negotiated at association time.
- */
- rsnie1 = rsnie2 = gtk = NULL;
- while (frm + 2 <= efrm) {
- if (frm + 2 + frm[1] > efrm)
- break;
- switch (frm[0]) {
- case IEEE80211_ELEMID_RSN:
- if (ni->ni_rsnprotos != IEEE80211_PROTO_RSN)
- break;
- if (rsnie1 == NULL)
- rsnie1 = frm;
- else if (rsnie2 == NULL)
- rsnie2 = frm;
- /* ignore others if more than two RSN IEs */
- break;
- case IEEE80211_ELEMID_VENDOR:
- if (frm[1] < 4)
- break;
- if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
- switch (frm[5]) {
- case IEEE80211_KDE_GTK:
- gtk = frm;
- break;
- }
- } else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
- switch (frm[5]) {
- case 1: /* WPA */
- if (ni->ni_rsnprotos !=
- IEEE80211_PROTO_WPA)
- break;
- rsnie1 = frm;
- break;
- }
- }
- break;
- }
- frm += 2 + frm[1];
- }
- /* first WPA/RSN IE is mandatory */
- if (rsnie1 == NULL) {
- IEEE80211_DPRINTF(("%s: missing RSN IE\n", __func__));
- return;
- }
- /* key data must be encrypted if GTK is included */
- if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED)) {
- IEEE80211_DPRINTF(("%s: GTK not encrypted\n", __func__));
- return;
- }
- /*
- * Check that first WPA/RSN IE is identical to the one received in
- * the beacon or probe response frame.
- */
- if (ni->ni_rsnie == NULL || rsnie1[1] != ni->ni_rsnie[1] ||
- memcmp(rsnie1, ni->ni_rsnie, 2 + rsnie1[1]) != 0) {
- reason = IEEE80211_REASON_RSN_DIFFERENT_IE;
- goto deauth;
- }
-
- /*
- * If a second RSN information element is present, use its pairwise
- * cipher suite or deauthenticate.
- */
- if (rsnie2 != NULL) {
- struct ieee80211_rsnparams rsn;
-
- if (ieee80211_parse_rsn(ic, rsnie2, &rsn) == 0) {
- if (rsn.rsn_akms != ni->ni_rsnakms ||
- rsn.rsn_groupcipher != ni->ni_rsngroupcipher ||
- rsn.rsn_nciphers != 1 ||
- !(rsn.rsn_ciphers & ic->ic_rsnciphers)) {
- reason = IEEE80211_REASON_BAD_PAIRWISE_CIPHER;
- goto deauth;
- }
- /* use pairwise cipher suite of second RSN IE */
- ni->ni_rsnciphers = rsn.rsn_ciphers;
- ni->ni_rsncipher = ni->ni_rsnciphers;
- }
- }
-
- /* update the last seen value of the key replay counter field */
- ni->ni_replaycnt = BE_READ_8(key->replaycnt);
- ni->ni_replaycnt_ok = 1;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 3, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 4 to authenticator */
- if (ieee80211_send_4way_msg4(ic, ni) != 0)
- return; /* ..authenticator will retry */
-
- if (info & EAPOL_KEY_INSTALL) {
- u_int64_t prsc;
-
- /* check that key length matches that of pairwise cipher */
- if (BE_READ_2(key->keylen) !=
- ieee80211_cipher_keylen(ni->ni_rsncipher)) {
- reason = IEEE80211_REASON_AUTH_LEAVE;
- goto deauth;
- }
- /* install the PTK */
- prsc = (gtk == NULL) ? LE_READ_6(key->rsc) : 0;
- k = &ni->ni_pairwise_key;
- ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, prsc, k);
- if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- reason = IEEE80211_REASON_AUTH_LEAVE;
- goto deauth;
- }
- }
- if (gtk != NULL) {
- u_int64_t rsc;
- u_int8_t kid;
-
- /* check that the GTK KDE is valid */
- if (gtk[1] < 4 + 2) {
- reason = IEEE80211_REASON_AUTH_LEAVE;
- goto deauth;
- }
- /* check that key length matches that of group cipher */
- if (gtk[1] - 6 !=
- ieee80211_cipher_keylen(ni->ni_rsngroupcipher)) {
- reason = IEEE80211_REASON_AUTH_LEAVE;
- goto deauth;
- }
- /* install the GTK */
- kid = gtk[6] & 3;
- rsc = LE_READ_6(key->rsc);
- k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
- gtk[6] & (1 << 2), rsc, k);
- if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- reason = IEEE80211_REASON_AUTH_LEAVE;
- goto deauth;
- }
- }
- if (info & EAPOL_KEY_SECURE) {
- if (ic->ic_opmode != IEEE80211_M_IBSS ||
- ++ni->ni_key_count == 2) {
- IEEE80211_DPRINTF(("%s: marking port %s valid\n",
- __func__, ether_sprintf(ni->ni_macaddr)));
- ni->ni_port_valid = 1;
- }
- }
- deauth:
- if (reason != 0) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- reason);
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- }
-}
-
-/*
- * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
- * (see 8.5.3.4).
- */
-void
-ieee80211_recv_4way_msg4(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- /* discard if we're not expecting this message */
- if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING) {
- IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
- __func__, ni->ni_rsn_state));
- return;
- }
-
- /* replay counter has already been verified by caller */
-
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return; /* will timeout.. */
- }
-
- timeout_del(&ni->ni_rsn_timeout);
- ni->ni_rsn_state = RSNA_PTKINITDONE;
- ni->ni_rsn_retries = 0;
-
- if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) {
- /* install the PTK */
- struct ieee80211_key *k = &ni->ni_pairwise_key;
- ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, 0, k);
- if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- IEEE80211_SEND_MGMT(ic, ni,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_ASSOC_TOOMANY);
- ieee80211_node_leave(ic, ni);
- return;
- }
- }
- if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) {
- IEEE80211_DPRINTF(("%s: marking port %s valid\n", __func__,
- ether_sprintf(ni->ni_macaddr)));
- ni->ni_port_valid = 1;
- }
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 4, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- /* initiate a group key handshake for WPA */
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA)
- (void)ieee80211_send_group_msg1(ic, ni);
- else
- ni->ni_rsn_gstate = RSNA_IDLE;
-}
-
-/*
- * Differentiate Message 2 from Message 4 of the 4-Way Handshake based on
- * the presence of an RSN or WPA Information Element.
- */
-void
-ieee80211_recv_4way_msg2or4(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- const u_int8_t *frm, *efrm;
- const u_int8_t *rsnie;
-
- if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
-
- /* parse key data field (check if an RSN IE is present) */
- frm = (const u_int8_t *)&key[1];
- efrm = frm + BE_READ_2(key->paylen);
-
- rsnie = NULL;
- while (frm + 2 <= efrm) {
- if (frm + 2 + frm[1] > efrm)
- break;
- switch (frm[0]) {
- case IEEE80211_ELEMID_RSN:
- rsnie = frm;
- break;
- case IEEE80211_ELEMID_VENDOR:
- if (frm[1] < 4)
- break;
- if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
- switch (frm[5]) {
- case 1: /* WPA */
- rsnie = frm;
- break;
- }
- }
- }
- frm += 2 + frm[1];
- }
- if (rsnie != NULL)
- ieee80211_recv_4way_msg2(ic, key, ni, rsnie);
- else
- ieee80211_recv_4way_msg4(ic, key, ni);
-}
-
-/*
- * Group Key Handshake Message 1 is sent by the authenticator to the
- * supplicant (see 8.5.4.1).
- */
-void
-ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- struct ieee80211_key *k;
- const u_int8_t *frm, *efrm;
- const u_int8_t *gtk;
- u_int64_t rsc;
- u_int16_t info;
- u_int8_t kid;
-
- if (ic->ic_opmode != IEEE80211_M_STA &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return;
- }
- info = BE_READ_2(key->info);
-
- /* check that encrypted and decrypt Key Data field using KEK */
- if (!(info & EAPOL_KEY_ENCRYPTED) ||
- ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
- IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
- return;
- }
-
- /* parse key data field (shall contain a GTK KDE) */
- frm = (const u_int8_t *)&key[1];
- efrm = frm + BE_READ_2(key->paylen);
-
- gtk = NULL;
- while (frm + 2 <= efrm) {
- if (frm + 2 + frm[1] > efrm)
- break;
- switch (frm[0]) {
- case IEEE80211_ELEMID_VENDOR:
- if (frm[1] < 4)
- break;
- if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
- switch (frm[5]) {
- case IEEE80211_KDE_GTK:
- gtk = frm;
- break;
- }
- }
- break;
- }
- frm += 2 + frm[1];
- }
- /* check that the GTK KDE is present and valid */
- if (gtk == NULL || gtk[1] < 4 + 2) {
- IEEE80211_DPRINTF(("%s: missing or invalid GTK KDE\n",
- __func__));
- return;
- }
-
- /* check that key length matches that of group cipher */
- if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_rsngroupcipher))
- return;
-
- /* install the GTK */
- kid = gtk[6] & 3;
- rsc = LE_READ_6(key->rsc);
- k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
- gtk[6] & (1 << 2), rsc, k);
- if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_LEAVE);
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- return;
- }
- if (info & EAPOL_KEY_SECURE) {
- if (ic->ic_opmode != IEEE80211_M_IBSS ||
- ++ni->ni_key_count == 2) {
- IEEE80211_DPRINTF(("%s: marking port %s valid\n",
- __func__, ether_sprintf(ni->ni_macaddr)));
- ni->ni_port_valid = 1;
- }
- }
- /* update the last seen value of the key replay counter field */
- ni->ni_replaycnt = BE_READ_8(key->replaycnt);
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 1, 2, "group key",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 2 to authenticator */
- (void)ieee80211_send_group_msg2(ic, ni, k);
-}
-
-void
-ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- struct ieee80211_key *k;
- const u_int8_t *frm;
- u_int64_t rsc;
- u_int16_t info;
- u_int8_t kid;
- int keylen;
-
- if (ic->ic_opmode != IEEE80211_M_STA &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return;
- }
- /*
- * EAPOL-Key data field is encrypted even though WPA doesn't set
- * the ENCRYPTED bit in the info field.
- */
- if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
- IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
- return;
- }
- info = BE_READ_2(key->info);
- keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher);
-
- /* check that key length matches that of group cipher */
- if (BE_READ_2(key->keylen) != keylen)
- return;
-
- /* check that the data length is large enough to hold the key */
- if (BE_READ_2(key->paylen) < keylen)
- return;
-
- /* key data field contains the GTK */
- frm = (const u_int8_t *)&key[1];
-
- /* install the GTK */
- kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3;
- rsc = LE_READ_6(key->rsc);
- k = &ic->ic_nw_keys[kid];
- ieee80211_map_gtk(frm, ni->ni_rsngroupcipher, kid,
- info & EAPOL_KEY_WPA_TX, rsc, k);
- if ((*ic->ic_set_key)(ic, ni, k) != 0) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_LEAVE);
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- return;
- }
- if (info & EAPOL_KEY_SECURE) {
- if (ic->ic_opmode != IEEE80211_M_IBSS ||
- ++ni->ni_key_count == 2) {
- IEEE80211_DPRINTF(("%s: marking port %s valid\n",
- __func__, ether_sprintf(ni->ni_macaddr)));
- ni->ni_port_valid = 1;
- }
- }
- /* update the last seen value of the key replay counter field */
- ni->ni_replaycnt = BE_READ_8(key->replaycnt);
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 1, 2, "group key",
- ether_sprintf(ni->ni_macaddr));
-
- /* send message 2 to authenticator */
- (void)ieee80211_send_group_msg2(ic, ni, k);
-}
-
-/*
- * Group Key Handshake Message 2 is sent by the supplicant to the
- * authenticator (see 8.5.4.2).
- */
-void
-ieee80211_recv_group_msg2(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- /* discard if we're not expecting this message */
- if (ni->ni_rsn_gstate != RSNA_REKEYNEGOTIATING) {
- IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
- __func__, ni->ni_rsn_state));
- return;
- }
- if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
- /* check Key MIC field using KCK */
- if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return;
- }
-
- timeout_del(&ni->ni_rsn_timeout);
- ni->ni_rsn_gstate = RSNA_REKEYESTABLISHED;
-
- if ((ni->ni_flags & IEEE80211_NODE_REKEY) &&
- --ic->ic_rsn_keydonesta == 0)
- ieee80211_setkeysdone(ic);
- ni->ni_flags &= ~IEEE80211_NODE_REKEY;
-
- ni->ni_rsn_gstate = RSNA_IDLE;
- ni->ni_rsn_retries = 0;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: received msg %d/%d of the %s handshake from %s\n",
- ic->ic_if.if_xname, 2, 2, "group key",
- ether_sprintf(ni->ni_macaddr));
-}
-
-/*
- * EAPOL-Key Request frames are sent by the supplicant to request that the
- * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
- * or to report a MIC failure in a TKIP MSDU.
- */
-void
-ieee80211_recv_eapol_key_req(struct ieee80211com *ic,
- struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
-{
- u_int16_t info;
-
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- ic->ic_opmode != IEEE80211_M_IBSS)
- return;
-
- info = BE_READ_2(key->info);
-
- /* enforce monotonicity of key request replay counter */
- if (ni->ni_reqreplaycnt_ok &&
- BE_READ_8(key->replaycnt) <= ni->ni_reqreplaycnt) {
- ic->ic_stats.is_rx_eapol_replay++;
- return;
- }
- if (!(info & EAPOL_KEY_KEYMIC) ||
- ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
- IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
- ic->ic_stats.is_rx_eapol_badmic++;
- return;
- }
- /* update key request replay counter now that MIC is verified */
- ni->ni_reqreplaycnt = BE_READ_8(key->replaycnt);
- ni->ni_reqreplaycnt_ok = 1;
-
- if (info & EAPOL_KEY_ERROR) { /* TKIP MIC failure */
- /* ignore reports from STAs not using TKIP */
- if (ic->ic_bss->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
- ni->ni_rsncipher != IEEE80211_CIPHER_TKIP) {
- IEEE80211_DPRINTF(("%s: MIC failure report from "
- "STA not using TKIP: %s\n", __func__,
- ether_sprintf(ni->ni_macaddr)));
- return;
- }
- ic->ic_stats.is_rx_remmicfail++;
- ieee80211_michael_mic_failure(ic, LE_READ_6(key->rsc));
-
- } else if (info & EAPOL_KEY_PAIRWISE) {
- /* initiate a 4-Way Handshake */
-
- } else {
- /*
- * Should change the GTK, initiate the 4-Way Handshake and
- * then execute a Group Key Handshake with all supplicants.
- */
- }
-}
-
-/*
- * Process an incoming EAPOL frame. Notice that we are only interested in
- * EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type.
- */
-void
-ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
- struct ieee80211_node *ni)
-{
- struct ifnet *ifp = &ic->ic_if;
- struct ether_header *eh;
- struct ieee80211_eapol_key *key;
- u_int16_t info, desc;
-
- ifp->if_ibytes += m0->m_pkthdr.len;
-
- if (m0->m_len < sizeof(*eh) + sizeof(*key))
- return;
- eh = mtod(m0, struct ether_header *);
- if (IEEE80211_IS_MULTICAST(eh->ether_dhost)) {
- ifp->if_imcasts++;
- return;
- }
- m_adj(m0, sizeof(*eh));
- key = mtod(m0, struct ieee80211_eapol_key *);
-
- if (key->type != EAPOL_KEY)
- return;
- ic->ic_stats.is_rx_eapol_key++;
-
- if ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
- key->desc != EAPOL_KEY_DESC_IEEE80211) ||
- (ni->ni_rsnprotos == IEEE80211_PROTO_WPA &&
- key->desc != EAPOL_KEY_DESC_WPA))
- return;
-
- /* check packet body length */
- if (m0->m_len < 4 + BE_READ_2(key->len))
- return;
-
- /* check key data length */
- if (m0->m_len < sizeof(*key) + BE_READ_2(key->paylen))
- return;
-
- info = BE_READ_2(key->info);
-
- /* discard EAPOL-Key frames with an unknown descriptor version */
- desc = info & EAPOL_KEY_VERSION_MASK;
- if (desc != EAPOL_KEY_DESC_V1 && desc != EAPOL_KEY_DESC_V2)
- return;
-
- if ((ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
- ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) &&
- desc != EAPOL_KEY_DESC_V2)
- return;
-
- /* determine message type (see 8.5.3.7) */
- if (info & EAPOL_KEY_REQUEST) {
- /* EAPOL-Key Request frame */
- ieee80211_recv_eapol_key_req(ic, key, ni);
-
- } else if (info & EAPOL_KEY_PAIRWISE) {
- /* 4-Way Handshake */
- if (info & EAPOL_KEY_KEYMIC) {
- if (info & EAPOL_KEY_KEYACK)
- ieee80211_recv_4way_msg3(ic, key, ni);
- else
- ieee80211_recv_4way_msg2or4(ic, key, ni);
- } else if (info & EAPOL_KEY_KEYACK)
- ieee80211_recv_4way_msg1(ic, key, ni);
- } else {
- /* Group Key Handshake */
- if (!(info & EAPOL_KEY_KEYMIC))
- return;
- if (info & EAPOL_KEY_KEYACK) {
- if (key->desc == EAPOL_KEY_DESC_WPA)
- ieee80211_recv_wpa_group_msg1(ic, key, ni);
- else
- ieee80211_recv_rsn_group_msg1(ic, key, ni);
- } else
- ieee80211_recv_group_msg2(ic, key, ni);
- }
-}
-
void
ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m0)
{
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 33654eb2d32..b18bcd351aa 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.59 2008/04/16 18:32:15 damien Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.60 2008/07/21 19:05:21 damien Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -86,13 +86,6 @@ struct mbuf *ieee80211_get_assoc_resp(struct ieee80211com *,
struct ieee80211_node *, u_int16_t);
struct mbuf *ieee80211_get_disassoc(struct ieee80211com *,
struct ieee80211_node *, u_int16_t);
-int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, const struct ieee80211_ptk *);
-u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *,
- const struct ieee80211_key *);
-u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *);
-struct mbuf *ieee80211_get_eapol_key(int, int, u_int);
-
/*
* IEEE 802.11 output routine. Normally this will directly call the
@@ -1501,563 +1494,6 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
return m;
}
-/* unaligned big endian access */
-#define BE_READ_2(p) \
- ((u_int16_t)(p)[0] << 8 | (u_int16_t)(p)[1])
-
-#define BE_WRITE_2(p, v) do { \
- (p)[0] = (v) >> 8; (p)[1] = (v); \
-} while (0)
-
-#define BE_WRITE_8(p, v) do { \
- (p)[0] = (v) >> 56; (p)[1] = (v) >> 48; \
- (p)[2] = (v) >> 40; (p)[3] = (v) >> 32; \
- (p)[4] = (v) >> 24; (p)[5] = (v) >> 16; \
- (p)[6] = (v) >> 8; (p)[7] = (v); \
-} while (0)
-
-/* unaligned little endian access */
-#define LE_WRITE_6(p, v) do { \
- (p)[5] = (v) >> 40; (p)[4] = (v) >> 32; \
- (p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \
- (p)[1] = (v) >> 8; (p)[0] = (v); \
-} while (0)
-
-/*
- * Handle EAPOL-Key timeouts (no answer from supplicant).
- */
-void
-ieee80211_eapol_timeout(void *arg)
-{
- struct ieee80211_node *ni = arg;
- struct ieee80211com *ic = ni->ni_ic;
- int s;
-
- IEEE80211_DPRINTF(("%s: no answer from station %s in state %d\n",
- __func__, ether_sprintf(ni->ni_macaddr), ni->ni_rsn_state));
-
- s = splnet();
-
- switch (ni->ni_rsn_state) {
- case RSNA_PTKSTART:
- case RSNA_PTKCALCNEGOTIATING:
- (void)ieee80211_send_4way_msg1(ic, ni);
- break;
- case RSNA_PTKINITNEGOTIATING:
- (void)ieee80211_send_4way_msg3(ic, ni);
- break;
- }
-
- switch (ni->ni_rsn_gstate) {
- case RSNA_REKEYNEGOTIATING:
- (void)ieee80211_send_group_msg1(ic, ni);
- break;
- }
-
- splx(s);
-}
-
-/*
- * Send an EAPOL-Key frame to node `ni'. If MIC or encryption is required,
- * the PTK must be passed (otherwise it can be set to NULL.)
- */
-int
-ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
- struct ieee80211_node *ni, const struct ieee80211_ptk *ptk)
-{
- struct ifnet *ifp = &ic->ic_if;
- struct ether_header *eh;
- struct ieee80211_eapol_key *key;
- u_int16_t len, info;
- int s, error;
-
- M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
- if (m == NULL)
- return ENOMEM;
- /* no need to m_pullup here (ok by construction) */
- eh = mtod(m, struct ether_header *);
- eh->ether_type = htons(ETHERTYPE_PAE);
- IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr);
- IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr);
-
- key = (struct ieee80211_eapol_key *)&eh[1];
- key->version = EAPOL_VERSION;
- key->type = EAPOL_KEY;
- key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
- EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA;
-
- info = BE_READ_2(key->info);
- /* use V2 descriptor if pairwise or group cipher is CCMP */
- if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
- ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP)
- info |= EAPOL_KEY_DESC_V2;
- else
- info |= EAPOL_KEY_DESC_V1;
- BE_WRITE_2(key->info, info);
-
- len = m->m_len - sizeof(struct ether_header);
- BE_WRITE_2(key->paylen, len - sizeof(*key));
- BE_WRITE_2(key->len, len - 4);
-
- if (info & EAPOL_KEY_ENCRYPTED) {
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- /* clear "Encrypted" bit for WPA */
- info &= ~EAPOL_KEY_ENCRYPTED;
- BE_WRITE_2(key->info, info);
- }
- ieee80211_eapol_key_encrypt(ic, key, ptk->kek);
-
- if ((info & EAPOL_KEY_VERSION_MASK) == EAPOL_KEY_DESC_V2) {
- /* AES Key Wrap adds 8 bytes + padding */
- m->m_pkthdr.len = m->m_len =
- sizeof(*eh) + 4 + BE_READ_2(key->len);
- }
- }
- if (info & EAPOL_KEY_KEYMIC)
- ieee80211_eapol_key_mic(key, ptk->kck);
-
- s = splnet();
- /* start a 100ms timeout if an answer is expected from supplicant */
- if (info & EAPOL_KEY_KEYACK)
- timeout_add(&ni->ni_rsn_timeout, hz / 10);
- IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
- if (error == 0) {
- ifp->if_obytes += m->m_pkthdr.len;
- if ((ifp->if_flags & IFF_OACTIVE) == 0)
- (*ifp->if_start)(ifp);
- }
- splx(s);
-
- return error;
-}
-
-/*
- * Add a GTK KDE to an EAPOL-Key frame (see Figure 144).
- */
-u_int8_t *
-ieee80211_add_gtk_kde(u_int8_t *frm, struct ieee80211_node *ni,
- const struct ieee80211_key *k)
-{
- KASSERT(k->k_flags & IEEE80211_KEY_GROUP);
-
- *frm++ = IEEE80211_ELEMID_VENDOR;
- *frm++ = 6 + k->k_len;
- memcpy(frm, IEEE80211_OUI, 3); frm += 3;
- *frm++ = IEEE80211_KDE_GTK;
- *frm = k->k_id & 3;
- /*
- * The TxRx flag for sending a GTK is always the opposite of whether
- * the pairwise key is used for data encryption/integrity or not.
- */
- if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
- *frm |= 1 << 2; /* set the Tx bit */
- frm++;
- *frm++ = 0; /* reserved */
- memcpy(frm, k->k_key, k->k_len);
- return frm + k->k_len;
-}
-
-/*
- * Add a PMKID KDE to an EAPOL-Key frame (see Figure 146).
- */
-u_int8_t *
-ieee80211_add_pmkid_kde(u_int8_t *frm, const u_int8_t *pmkid)
-{
- *frm++ = IEEE80211_ELEMID_VENDOR;
- *frm++ = 20;
- memcpy(frm, IEEE80211_OUI, 3); frm += 3;
- *frm++ = IEEE80211_KDE_PMKID;
- memcpy(frm, pmkid, IEEE80211_PMKID_LEN);
- return frm + IEEE80211_PMKID_LEN;
-}
-
-struct mbuf *
-ieee80211_get_eapol_key(int flags, int type, u_int pktlen)
-{
- struct mbuf *m;
-
- /* reserve space for 802.11 encapsulation and EAPOL-Key header */
- pktlen += sizeof(struct ieee80211_frame) + sizeof(struct llc) +
- sizeof(struct ieee80211_eapol_key);
-
- if (pktlen > MCLBYTES)
- panic("EAPOL-Key frame too large: %u", pktlen);
- MGETHDR(m, flags, type);
- if (m == NULL)
- return NULL;
- if (pktlen >= MINCLSIZE) {
- MCLGET(m, flags);
- if (!(m->m_flags & M_EXT))
- return m_free(m);
- }
- m->m_data += sizeof(struct ieee80211_frame) + sizeof(struct llc);
- return m;
-}
-
-/*
- * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
- * (see 8.5.3.1).
- */
-int
-ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
-{
- struct ieee80211_eapol_key *key;
- struct mbuf *m;
- u_int16_t info, keylen;
- u_int8_t *frm;
-
- ni->ni_rsn_state = RSNA_PTKSTART;
- if (++ni->ni_rsn_retries > 3) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_4WAY_TIMEOUT);
- ieee80211_node_leave(ic, ni);
- return 0;
- }
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
- BE_WRITE_2(key->info, info);
-
- /* copy the authenticator's nonce (ANonce) */
- memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
-
- keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
- BE_WRITE_2(key->keylen, keylen);
-
- frm = (u_int8_t *)&key[1];
- /* WPA does not have PMKID KDE */
- if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
- ni->ni_rsnakms == IEEE80211_AKM_IEEE8021X) {
- /* XXX retrieve PMKID from the PMKSA cache */
- /* frm = ieee80211_add_pmkid_kde(frm, pmkid); */
- }
-
- m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 1, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- ni->ni_replaycnt++;
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-
- return ieee80211_send_eapol_key(ic, m, ni, NULL);
-}
-
-/*
- * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
- * (see 8.5.3.2).
- */
-int
-ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
- const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk)
-{
- struct ieee80211_eapol_key *key;
- struct mbuf *m;
- u_int16_t info;
- u_int8_t *frm;
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- 2 + 48);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
- BE_WRITE_2(key->info, info);
-
- /* copy key replay counter from Message 1/4 */
- memcpy(key->replaycnt, replaycnt, 8);
-
- /* copy the supplicant's nonce (SNonce) */
- memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
-
- frm = (u_int8_t *)&key[1];
- /* add the WPA/RSN IE used in the (Re)Association Request */
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- u_int16_t keylen;
- frm = ieee80211_add_wpa(frm, ic, ni);
- /* WPA sets the key length field here */
- keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
- BE_WRITE_2(key->keylen, keylen);
- } else /* RSN */
- frm = ieee80211_add_rsn(frm, ic, ni);
-
- m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 2, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, tptk);
-}
-
-/*
- * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
- * (see 8.5.3.3).
- */
-int
-ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
-{
- struct ieee80211_eapol_key *key;
- struct ieee80211_key *k;
- struct mbuf *m;
- u_int16_t info, keylen;
- u_int8_t *frm;
-
- ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
- if (++ni->ni_rsn_retries > 3) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_4WAY_TIMEOUT);
- ieee80211_node_leave(ic, ni);
- return 0;
- }
- if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN)
- k = &ic->ic_nw_keys[ic->ic_def_txkey];
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- 2 + 48 +
- ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
- 2 + 6 + k->k_len : 0) +
- 8);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC;
- if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
- info |= EAPOL_KEY_INSTALL;
-
- /* use same nonce as in Message 1 */
- memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
-
- ni->ni_replaycnt++;
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-
- keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
- BE_WRITE_2(key->keylen, keylen);
-
- frm = (u_int8_t *)&key[1];
- /* add the WPA/RSN IE included in Beacon/Probe Response */
- if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
- frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
- /* encapsulate the GTK and ask for encryption */
- frm = ieee80211_add_gtk_kde(frm, ni, k);
- LE_WRITE_6(key->rsc, k->k_tsc);
- info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE;
- } else /* WPA */
- frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);
-
- /* write the key info field */
- BE_WRITE_2(key->info, info);
-
- m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 3, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
-}
-
-/*
- * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
- * (see 8.5.3.4).
- */
-int
-ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
-{
- struct ieee80211_eapol_key *key;
- struct mbuf *m;
- u_int16_t info;
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
-
- /* copy key replay counter from authenticator */
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- u_int16_t keylen;
- /* WPA sets the key length field here */
- keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
- BE_WRITE_2(key->keylen, keylen);
- } else
- info |= EAPOL_KEY_SECURE;
-
- /* write the key info field */
- BE_WRITE_2(key->info, info);
-
- /* empty key data field */
- m->m_pkthdr.len = m->m_len = sizeof(*key);
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 4, 4, "4-way",
- ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
-}
-
-/*
- * Group Key Handshake Message 1 is sent by the authenticator to the
- * supplicant (see 8.5.4.1).
- */
-int
-ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
-{
- struct ieee80211_eapol_key *key;
- const struct ieee80211_key *k;
- struct mbuf *m;
- u_int16_t info;
- u_int8_t *frm;
-
- ni->ni_rsn_gstate = RSNA_REKEYNEGOTIATING;
- if (++ni->ni_rsn_retries > 3) {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_GROUP_TIMEOUT);
- ieee80211_node_leave(ic, ni);
- return 0;
- }
- k = &ic->ic_nw_keys[ic->ic_def_txkey];
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
- ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
- k->k_len : 2 + 6 + k->k_len) +
- 8);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE |
- EAPOL_KEY_ENCRYPTED;
-
- ni->ni_replaycnt++;
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-
- frm = (u_int8_t *)&key[1];
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- /* WPA does not have GTK KDE */
- BE_WRITE_2(key->keylen, k->k_len);
- memcpy(frm, k->k_key, k->k_len);
- frm += k->k_len;
- info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT;
- if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
- info |= EAPOL_KEY_WPA_TX;
- } else /* RSN */
- frm = ieee80211_add_gtk_kde(frm, ni, k);
-
- /* RSC = last transmit sequence number for the GTK */
- LE_WRITE_6(key->rsc, k->k_tsc);
-
- /* write the key info field */
- BE_WRITE_2(key->info, info);
-
- m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 1, 2, "group key",
- ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
-}
-
-/*
- * Group Key Handshake Message 2 is sent by the supplicant to the
- * authenticator (see 8.5.4.2).
- */
-int
-ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
- const struct ieee80211_key *k)
-{
- struct ieee80211_eapol_key *key;
- u_int16_t info;
- struct mbuf *m;
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info = EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE;
-
- /* copy key replay counter from authenticator */
- BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
-
- if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
- /* WPA sets the key length and key id fields here */
- BE_WRITE_2(key->keylen, k->k_len);
- info |= (k->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT;
- }
-
- /* write the key info field */
- BE_WRITE_2(key->info, info);
-
- /* empty key data field */
- m->m_pkthdr.len = m->m_len = sizeof(*key);
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending msg %d/%d of the %s handshake to %s\n",
- ic->ic_if.if_xname, 2, 2, "group key",
- ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
-}
-
-/*
- * EAPOL-Key Request frames are sent by the supplicant to request that the
- * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
- * or to report a MIC failure in a TKIP MSDU.
- */
-int
-ieee80211_send_eapol_key_req(struct ieee80211com *ic,
- struct ieee80211_node *ni, u_int16_t info, u_int64_t tsc)
-{
- struct ieee80211_eapol_key *key;
- struct mbuf *m;
-
- m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
- if (m == NULL)
- return ENOMEM;
- key = mtod(m, struct ieee80211_eapol_key *);
- memset(key, 0, sizeof(*key));
-
- info |= EAPOL_KEY_REQUEST;
- BE_WRITE_2(key->info, info);
-
- /* in case of TKIP MIC failure, fill the RSC field */
- if (info & EAPOL_KEY_ERROR)
- LE_WRITE_6(key->rsc, tsc);
-
- /* use our separate key replay counter for key requests */
- BE_WRITE_8(key->replaycnt, ni->ni_reqreplaycnt);
- ni->ni_reqreplaycnt++;
-
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: sending EAPOL-Key request to %s\n",
- ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
-
- return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
-}
-
void
ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
struct mbuf *m)
diff --git a/sys/net80211/ieee80211_pae_input.c b/sys/net80211/ieee80211_pae_input.c
new file mode 100644
index 00000000000..b7338624d54
--- /dev/null
+++ b/sys/net80211/ieee80211_pae_input.c
@@ -0,0 +1,916 @@
+/*-
+ * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/rndvar.h>
+
+void ieee80211_recv_4way_msg1(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_4way_msg2(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *,
+ const u_int8_t *);
+void ieee80211_recv_4way_msg3(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_4way_msg4(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_4way_msg2or4(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_rsn_group_msg1(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_wpa_group_msg1(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_group_msg2(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+void ieee80211_recv_eapol_key_req(struct ieee80211com *,
+ struct ieee80211_eapol_key *, struct ieee80211_node *);
+
+/* unaligned big endian access */
+#define BE_READ_2(p) \
+ ((u_int16_t)(p)[0] << 8 | (u_int16_t)(p)[1])
+
+#define BE_READ_8(p) \
+ ((u_int64_t)(p)[0] << 56 | (u_int64_t)(p)[1] << 48 | \
+ (u_int64_t)(p)[2] << 40 | (u_int64_t)(p)[3] << 32 | \
+ (u_int64_t)(p)[4] << 24 | (u_int64_t)(p)[5] << 16 | \
+ (u_int64_t)(p)[6] << 8 | (u_int64_t)(p)[7])
+
+/* unaligned little endian access */
+#define LE_READ_6(p) \
+ ((u_int64_t)(p)[5] << 40 | (u_int64_t)(p)[4] << 32 | \
+ (u_int64_t)(p)[3] << 24 | (u_int64_t)(p)[2] << 16 | \
+ (u_int64_t)(p)[1] << 8 | (u_int64_t)(p)[0])
+
+/*
+ * Process an incoming EAPOL frame. Notice that we are only interested in
+ * EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type.
+ */
+void
+ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_node *ni)
+{
+ struct ifnet *ifp = &ic->ic_if;
+ struct ether_header *eh;
+ struct ieee80211_eapol_key *key;
+ u_int16_t info, desc;
+
+ ifp->if_ibytes += m0->m_pkthdr.len;
+
+ if (m0->m_len < sizeof(*eh) + sizeof(*key))
+ return;
+ eh = mtod(m0, struct ether_header *);
+ if (IEEE80211_IS_MULTICAST(eh->ether_dhost)) {
+ ifp->if_imcasts++;
+ return;
+ }
+ m_adj(m0, sizeof(*eh));
+ key = mtod(m0, struct ieee80211_eapol_key *);
+
+ if (key->type != EAPOL_KEY)
+ return;
+ ic->ic_stats.is_rx_eapol_key++;
+
+ if ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
+ key->desc != EAPOL_KEY_DESC_IEEE80211) ||
+ (ni->ni_rsnprotos == IEEE80211_PROTO_WPA &&
+ key->desc != EAPOL_KEY_DESC_WPA))
+ return;
+
+ /* check packet body length */
+ if (m0->m_len < 4 + BE_READ_2(key->len))
+ return;
+
+ /* check key data length */
+ if (m0->m_len < sizeof(*key) + BE_READ_2(key->paylen))
+ return;
+
+ info = BE_READ_2(key->info);
+
+ /* discard EAPOL-Key frames with an unknown descriptor version */
+ desc = info & EAPOL_KEY_VERSION_MASK;
+ if (desc != EAPOL_KEY_DESC_V1 && desc != EAPOL_KEY_DESC_V2)
+ return;
+
+ if ((ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) &&
+ desc != EAPOL_KEY_DESC_V2)
+ return;
+
+ /* determine message type (see 8.5.3.7) */
+ if (info & EAPOL_KEY_REQUEST) {
+ /* EAPOL-Key Request frame */
+ ieee80211_recv_eapol_key_req(ic, key, ni);
+
+ } else if (info & EAPOL_KEY_PAIRWISE) {
+ /* 4-Way Handshake */
+ if (info & EAPOL_KEY_KEYMIC) {
+ if (info & EAPOL_KEY_KEYACK)
+ ieee80211_recv_4way_msg3(ic, key, ni);
+ else
+ ieee80211_recv_4way_msg2or4(ic, key, ni);
+ } else if (info & EAPOL_KEY_KEYACK)
+ ieee80211_recv_4way_msg1(ic, key, ni);
+ } else {
+ /* Group Key Handshake */
+ if (!(info & EAPOL_KEY_KEYMIC))
+ return;
+ if (info & EAPOL_KEY_KEYACK) {
+ if (key->desc == EAPOL_KEY_DESC_WPA)
+ ieee80211_recv_wpa_group_msg1(ic, key, ni);
+ else
+ ieee80211_recv_rsn_group_msg1(ic, key, ni);
+ } else
+ ieee80211_recv_group_msg2(ic, key, ni);
+ }
+}
+
+/*
+ * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
+ * (see 8.5.3.1).
+ */
+void
+ieee80211_recv_4way_msg1(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ struct ieee80211_ptk tptk;
+ const u_int8_t *frm, *efrm;
+ const u_int8_t *pmkid;
+ const u_int8_t *pmk;
+
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ if (ni->ni_replaycnt_ok &&
+ BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ /* save authenticator's nonce (ANonce) */
+ memcpy(ni->ni_nonce, key->nonce, EAPOL_KEY_NONCE_LEN);
+
+ /* parse key data field (may contain an encapsulated PMKID) */
+ frm = (const u_int8_t *)&key[1];
+ efrm = frm + BE_READ_2(key->paylen);
+
+ pmkid = NULL;
+ while (frm + 2 <= efrm) {
+ if (frm + 2 + frm[1] > efrm)
+ break;
+ switch (frm[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (frm[1] < 4)
+ break;
+ if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case IEEE80211_KDE_PMKID:
+ pmkid = frm;
+ break;
+ }
+ }
+ break;
+ }
+ frm += 2 + frm[1];
+ }
+ /* check that the PMKID KDE is valid (if present) */
+ if (pmkid != NULL && pmkid[1] < 4 + 16)
+ return;
+
+ /* generate a new supplicant's nonce (SNonce) */
+ arc4random_buf(ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
+
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, pmkid)) == NULL) {
+ /* no PMK configured for this STA/PMKID */
+ return;
+ }
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
+ ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 1, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* send message 2 to authenticator using TPTK */
+ (void)ieee80211_send_4way_msg2(ic, ni, key->replaycnt, &tptk);
+}
+
+/*
+ * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
+ * (see 8.5.3.2).
+ */
+void
+ieee80211_recv_4way_msg2(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni,
+ const u_int8_t *rsnie)
+{
+ struct ieee80211_ptk tptk;
+ const u_int8_t *pmk;
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_state != RSNA_PTKSTART &&
+ ni->ni_rsn_state != RSNA_PTKCALCNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
+ return;
+ }
+ ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING;
+
+ /* replay counter has already been verified by caller */
+
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
+ /* no PMK configured for this STA */
+ return; /* will timeout.. */
+ }
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ic->ic_myaddr,
+ ni->ni_macaddr, ni->ni_nonce, key->nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
+
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return; /* will timeout.. */
+ }
+
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_state = RSNA_PTKCALCNEGOTIATING_2;
+ ni->ni_rsn_retries = 0;
+
+ /* install TPTK as PTK now that MIC is verified */
+ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
+
+ /*
+ * The RSN IE must match bit-wise with what the STA included in its
+ * (Re)Association Request.
+ */
+ if (ni->ni_rsnie == NULL || rsnie[1] != ni->ni_rsnie[1] ||
+ memcmp(rsnie, ni->ni_rsnie, 2 + rsnie[1]) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_RSN_DIFFERENT_IE);
+ ieee80211_node_leave(ic, ni);
+ return;
+ }
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 2, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* send message 3 to supplicant */
+ (void)ieee80211_send_4way_msg3(ic, ni);
+}
+
+/*
+ * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
+ * (see 8.5.3.3).
+ */
+void
+ieee80211_recv_4way_msg3(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ struct ieee80211_ptk tptk;
+ struct ieee80211_key *k;
+ const u_int8_t *frm, *efrm;
+ const u_int8_t *rsnie1, *rsnie2, *gtk;
+ const u_int8_t *pmk;
+ u_int16_t info, reason = 0;
+
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ if (ni->ni_replaycnt_ok &&
+ BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+
+ /* check that ANonce matches that of message 1 */
+ if (memcmp(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN) != 0) {
+ IEEE80211_DPRINTF(("%s: ANonce does not match msg 1/4\n",
+ __func__));
+ return;
+ }
+ /* retrieve PMK and derive TPTK */
+ if ((pmk = ieee80211_get_pmk(ic, ni, NULL)) == NULL) {
+ /* no PMK configured for this STA */
+ return;
+ }
+ ieee80211_derive_ptk(pmk, IEEE80211_PMK_LEN, ni->ni_macaddr,
+ ic->ic_myaddr, key->nonce, ic->ic_nonce, (u_int8_t *)&tptk,
+ sizeof(tptk));
+
+ info = BE_READ_2(key->info);
+
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, tptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+ /* install TPTK as PTK now that MIC is verified */
+ memcpy(&ni->ni_ptk, &tptk, sizeof(tptk));
+
+ /* if encrypted, decrypt Key Data field using KEK */
+ if ((info & EAPOL_KEY_ENCRYPTED) &&
+ ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
+ return;
+ }
+
+ /* parse key data field */
+ frm = (const u_int8_t *)&key[1];
+ efrm = frm + BE_READ_2(key->paylen);
+
+ /*
+ * Some WPA1+WPA2 APs (like hostapd) appear to include both WPA and
+ * RSN IEs in message 3/4. We only take into account the IE of the
+ * version of the protocol we negotiated at association time.
+ */
+ rsnie1 = rsnie2 = gtk = NULL;
+ while (frm + 2 <= efrm) {
+ if (frm + 2 + frm[1] > efrm)
+ break;
+ switch (frm[0]) {
+ case IEEE80211_ELEMID_RSN:
+ if (ni->ni_rsnprotos != IEEE80211_PROTO_RSN)
+ break;
+ if (rsnie1 == NULL)
+ rsnie1 = frm;
+ else if (rsnie2 == NULL)
+ rsnie2 = frm;
+ /* ignore others if more than two RSN IEs */
+ break;
+ case IEEE80211_ELEMID_VENDOR:
+ if (frm[1] < 4)
+ break;
+ if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case IEEE80211_KDE_GTK:
+ gtk = frm;
+ break;
+ }
+ } else if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case 1: /* WPA */
+ if (ni->ni_rsnprotos !=
+ IEEE80211_PROTO_WPA)
+ break;
+ rsnie1 = frm;
+ break;
+ }
+ }
+ break;
+ }
+ frm += 2 + frm[1];
+ }
+ /* first WPA/RSN IE is mandatory */
+ if (rsnie1 == NULL) {
+ IEEE80211_DPRINTF(("%s: missing RSN IE\n", __func__));
+ return;
+ }
+ /* key data must be encrypted if GTK is included */
+ if (gtk != NULL && !(info & EAPOL_KEY_ENCRYPTED)) {
+ IEEE80211_DPRINTF(("%s: GTK not encrypted\n", __func__));
+ return;
+ }
+ /*
+ * Check that first WPA/RSN IE is identical to the one received in
+ * the beacon or probe response frame.
+ */
+ if (ni->ni_rsnie == NULL || rsnie1[1] != ni->ni_rsnie[1] ||
+ memcmp(rsnie1, ni->ni_rsnie, 2 + rsnie1[1]) != 0) {
+ reason = IEEE80211_REASON_RSN_DIFFERENT_IE;
+ goto deauth;
+ }
+
+ /*
+ * If a second RSN information element is present, use its pairwise
+ * cipher suite or deauthenticate.
+ */
+ if (rsnie2 != NULL) {
+ struct ieee80211_rsnparams rsn;
+
+ if (ieee80211_parse_rsn(ic, rsnie2, &rsn) == 0) {
+ if (rsn.rsn_akms != ni->ni_rsnakms ||
+ rsn.rsn_groupcipher != ni->ni_rsngroupcipher ||
+ rsn.rsn_nciphers != 1 ||
+ !(rsn.rsn_ciphers & ic->ic_rsnciphers)) {
+ reason = IEEE80211_REASON_BAD_PAIRWISE_CIPHER;
+ goto deauth;
+ }
+ /* use pairwise cipher suite of second RSN IE */
+ ni->ni_rsnciphers = rsn.rsn_ciphers;
+ ni->ni_rsncipher = ni->ni_rsnciphers;
+ }
+ }
+
+ /* update the last seen value of the key replay counter field */
+ ni->ni_replaycnt = BE_READ_8(key->replaycnt);
+ ni->ni_replaycnt_ok = 1;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 3, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* send message 4 to authenticator */
+ if (ieee80211_send_4way_msg4(ic, ni) != 0)
+ return; /* ..authenticator will retry */
+
+ if (info & EAPOL_KEY_INSTALL) {
+ u_int64_t prsc;
+
+ /* check that key length matches that of pairwise cipher */
+ if (BE_READ_2(key->keylen) !=
+ ieee80211_cipher_keylen(ni->ni_rsncipher)) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ /* install the PTK */
+ prsc = (gtk == NULL) ? LE_READ_6(key->rsc) : 0;
+ k = &ni->ni_pairwise_key;
+ ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, prsc, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ }
+ if (gtk != NULL) {
+ u_int64_t rsc;
+ u_int8_t kid;
+
+ /* check that the GTK KDE is valid */
+ if (gtk[1] < 4 + 2) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ /* check that key length matches that of group cipher */
+ if (gtk[1] - 6 !=
+ ieee80211_cipher_keylen(ni->ni_rsngroupcipher)) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ /* install the GTK */
+ kid = gtk[6] & 3;
+ rsc = LE_READ_6(key->rsc);
+ k = &ic->ic_nw_keys[kid];
+ ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
+ gtk[6] & (1 << 2), rsc, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ reason = IEEE80211_REASON_AUTH_LEAVE;
+ goto deauth;
+ }
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+ }
+ deauth:
+ if (reason != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ reason);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ }
+}
+
+/*
+ * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
+ * (see 8.5.3.4).
+ */
+void
+ieee80211_recv_4way_msg4(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_state != RSNA_PTKINITNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
+ return;
+ }
+
+ /* replay counter has already been verified by caller */
+
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return; /* will timeout.. */
+ }
+
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_state = RSNA_PTKINITDONE;
+ ni->ni_rsn_retries = 0;
+
+ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP) {
+ /* install the PTK */
+ struct ieee80211_key *k = &ni->ni_pairwise_key;
+ ieee80211_map_ptk(&ni->ni_ptk, ni->ni_rsncipher, 0, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_ASSOC_TOOMANY);
+ ieee80211_node_leave(ic, ni);
+ return;
+ }
+ }
+ if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n", __func__,
+ ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 4, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* initiate a group key handshake for WPA */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA)
+ (void)ieee80211_send_group_msg1(ic, ni);
+ else
+ ni->ni_rsn_gstate = RSNA_IDLE;
+}
+
+/*
+ * Differentiate Message 2 from Message 4 of the 4-Way Handshake based on
+ * the presence of an RSN or WPA Information Element.
+ */
+void
+ieee80211_recv_4way_msg2or4(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ const u_int8_t *frm, *efrm;
+ const u_int8_t *rsnie;
+
+ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+
+ /* parse key data field (check if an RSN IE is present) */
+ frm = (const u_int8_t *)&key[1];
+ efrm = frm + BE_READ_2(key->paylen);
+
+ rsnie = NULL;
+ while (frm + 2 <= efrm) {
+ if (frm + 2 + frm[1] > efrm)
+ break;
+ switch (frm[0]) {
+ case IEEE80211_ELEMID_RSN:
+ rsnie = frm;
+ break;
+ case IEEE80211_ELEMID_VENDOR:
+ if (frm[1] < 4)
+ break;
+ if (memcmp(&frm[2], MICROSOFT_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case 1: /* WPA */
+ rsnie = frm;
+ break;
+ }
+ }
+ }
+ frm += 2 + frm[1];
+ }
+ if (rsnie != NULL)
+ ieee80211_recv_4way_msg2(ic, key, ni, rsnie);
+ else
+ ieee80211_recv_4way_msg4(ic, key, ni);
+}
+
+/*
+ * Group Key Handshake Message 1 is sent by the authenticator to the
+ * supplicant (see 8.5.4.1).
+ */
+void
+ieee80211_recv_rsn_group_msg1(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ struct ieee80211_key *k;
+ const u_int8_t *frm, *efrm;
+ const u_int8_t *gtk;
+ u_int64_t rsc;
+ u_int16_t info;
+ u_int8_t kid;
+
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+ info = BE_READ_2(key->info);
+
+ /* check that encrypted and decrypt Key Data field using KEK */
+ if (!(info & EAPOL_KEY_ENCRYPTED) ||
+ ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
+ return;
+ }
+
+ /* parse key data field (shall contain a GTK KDE) */
+ frm = (const u_int8_t *)&key[1];
+ efrm = frm + BE_READ_2(key->paylen);
+
+ gtk = NULL;
+ while (frm + 2 <= efrm) {
+ if (frm + 2 + frm[1] > efrm)
+ break;
+ switch (frm[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (frm[1] < 4)
+ break;
+ if (memcmp(&frm[2], IEEE80211_OUI, 3) == 0) {
+ switch (frm[5]) {
+ case IEEE80211_KDE_GTK:
+ gtk = frm;
+ break;
+ }
+ }
+ break;
+ }
+ frm += 2 + frm[1];
+ }
+ /* check that the GTK KDE is present and valid */
+ if (gtk == NULL || gtk[1] < 4 + 2) {
+ IEEE80211_DPRINTF(("%s: missing or invalid GTK KDE\n",
+ __func__));
+ return;
+ }
+
+ /* check that key length matches that of group cipher */
+ if (gtk[1] - 6 != ieee80211_cipher_keylen(ni->ni_rsngroupcipher))
+ return;
+
+ /* install the GTK */
+ kid = gtk[6] & 3;
+ rsc = LE_READ_6(key->rsc);
+ k = &ic->ic_nw_keys[kid];
+ ieee80211_map_gtk(&gtk[8], ni->ni_rsngroupcipher, kid,
+ gtk[6] & (1 << 2), rsc, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_LEAVE);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ return;
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+ }
+ /* update the last seen value of the key replay counter field */
+ ni->ni_replaycnt = BE_READ_8(key->replaycnt);
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 1, 2, "group key",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* send message 2 to authenticator */
+ (void)ieee80211_send_group_msg2(ic, ni, k);
+}
+
+void
+ieee80211_recv_wpa_group_msg1(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ struct ieee80211_key *k;
+ const u_int8_t *frm;
+ u_int64_t rsc;
+ u_int16_t info;
+ u_int8_t kid;
+ int keylen;
+
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ if (BE_READ_8(key->replaycnt) <= ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+ /*
+ * EAPOL-Key data field is encrypted even though WPA doesn't set
+ * the ENCRYPTED bit in the info field.
+ */
+ if (ieee80211_eapol_key_decrypt(key, ni->ni_ptk.kek) != 0) {
+ IEEE80211_DPRINTF(("%s: decryption failed\n", __func__));
+ return;
+ }
+ info = BE_READ_2(key->info);
+ keylen = ieee80211_cipher_keylen(ni->ni_rsngroupcipher);
+
+ /* check that key length matches that of group cipher */
+ if (BE_READ_2(key->keylen) != keylen)
+ return;
+
+ /* check that the data length is large enough to hold the key */
+ if (BE_READ_2(key->paylen) < keylen)
+ return;
+
+ /* key data field contains the GTK */
+ frm = (const u_int8_t *)&key[1];
+
+ /* install the GTK */
+ kid = (info >> EAPOL_KEY_WPA_KID_SHIFT) & 3;
+ rsc = LE_READ_6(key->rsc);
+ k = &ic->ic_nw_keys[kid];
+ ieee80211_map_gtk(frm, ni->ni_rsngroupcipher, kid,
+ info & EAPOL_KEY_WPA_TX, rsc, k);
+ if ((*ic->ic_set_key)(ic, ni, k) != 0) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_LEAVE);
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ return;
+ }
+ if (info & EAPOL_KEY_SECURE) {
+ if (ic->ic_opmode != IEEE80211_M_IBSS ||
+ ++ni->ni_key_count == 2) {
+ IEEE80211_DPRINTF(("%s: marking port %s valid\n",
+ __func__, ether_sprintf(ni->ni_macaddr)));
+ ni->ni_port_valid = 1;
+ }
+ }
+ /* update the last seen value of the key replay counter field */
+ ni->ni_replaycnt = BE_READ_8(key->replaycnt);
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 1, 2, "group key",
+ ether_sprintf(ni->ni_macaddr));
+
+ /* send message 2 to authenticator */
+ (void)ieee80211_send_group_msg2(ic, ni, k);
+}
+
+/*
+ * Group Key Handshake Message 2 is sent by the supplicant to the
+ * authenticator (see 8.5.4.2).
+ */
+void
+ieee80211_recv_group_msg2(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ /* discard if we're not expecting this message */
+ if (ni->ni_rsn_gstate != RSNA_REKEYNEGOTIATING) {
+ IEEE80211_DPRINTF(("%s: unexpected in state: %d\n",
+ __func__, ni->ni_rsn_state));
+ return;
+ }
+ if (BE_READ_8(key->replaycnt) != ni->ni_replaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ /* check Key MIC field using KCK */
+ if (ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+
+ timeout_del(&ni->ni_rsn_timeout);
+ ni->ni_rsn_gstate = RSNA_REKEYESTABLISHED;
+
+ if ((ni->ni_flags & IEEE80211_NODE_REKEY) &&
+ --ic->ic_rsn_keydonesta == 0)
+ ieee80211_setkeysdone(ic);
+ ni->ni_flags &= ~IEEE80211_NODE_REKEY;
+
+ ni->ni_rsn_gstate = RSNA_IDLE;
+ ni->ni_rsn_retries = 0;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: received msg %d/%d of the %s handshake from %s\n",
+ ic->ic_if.if_xname, 2, 2, "group key",
+ ether_sprintf(ni->ni_macaddr));
+}
+
+/*
+ * EAPOL-Key Request frames are sent by the supplicant to request that the
+ * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
+ * or to report a MIC failure in a TKIP MSDU.
+ */
+void
+ieee80211_recv_eapol_key_req(struct ieee80211com *ic,
+ struct ieee80211_eapol_key *key, struct ieee80211_node *ni)
+{
+ u_int16_t info;
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
+ ic->ic_opmode != IEEE80211_M_IBSS)
+ return;
+
+ info = BE_READ_2(key->info);
+
+ /* enforce monotonicity of key request replay counter */
+ if (ni->ni_reqreplaycnt_ok &&
+ BE_READ_8(key->replaycnt) <= ni->ni_reqreplaycnt) {
+ ic->ic_stats.is_rx_eapol_replay++;
+ return;
+ }
+ if (!(info & EAPOL_KEY_KEYMIC) ||
+ ieee80211_eapol_key_check_mic(key, ni->ni_ptk.kck) != 0) {
+ IEEE80211_DPRINTF(("%s: key MIC failed\n", __func__));
+ ic->ic_stats.is_rx_eapol_badmic++;
+ return;
+ }
+ /* update key request replay counter now that MIC is verified */
+ ni->ni_reqreplaycnt = BE_READ_8(key->replaycnt);
+ ni->ni_reqreplaycnt_ok = 1;
+
+ if (info & EAPOL_KEY_ERROR) { /* TKIP MIC failure */
+ /* ignore reports from STAs not using TKIP */
+ if (ic->ic_bss->ni_rsngroupcipher != IEEE80211_CIPHER_TKIP &&
+ ni->ni_rsncipher != IEEE80211_CIPHER_TKIP) {
+ IEEE80211_DPRINTF(("%s: MIC failure report from "
+ "STA not using TKIP: %s\n", __func__,
+ ether_sprintf(ni->ni_macaddr)));
+ return;
+ }
+ ic->ic_stats.is_rx_remmicfail++;
+ ieee80211_michael_mic_failure(ic, LE_READ_6(key->rsc));
+
+ } else if (info & EAPOL_KEY_PAIRWISE) {
+ /* initiate a 4-Way Handshake */
+
+ } else {
+ /*
+ * Should change the GTK, initiate the 4-Way Handshake and
+ * then execute a Group Key Handshake with all supplicants.
+ */
+ }
+}
diff --git a/sys/net80211/ieee80211_pae_output.c b/sys/net80211/ieee80211_pae_output.c
new file mode 100644
index 00000000000..30dc8b981fa
--- /dev/null
+++ b/sys/net80211/ieee80211_pae_output.c
@@ -0,0 +1,607 @@
+/* $OpenBSD: ieee80211_pae_output.c,v 1.1 2008/07/21 19:05:21 damien Exp $ */
+
+/*-
+ * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/proc.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_arp.h>
+#include <net/if_llc.h>
+#include <net/bpf.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#endif
+
+#include <net80211/ieee80211_var.h>
+
+int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_node *, const struct ieee80211_ptk *);
+u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, struct ieee80211_node *,
+ const struct ieee80211_key *);
+u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *);
+struct mbuf *ieee80211_get_eapol_key(int, int, u_int);
+
+/* unaligned big endian access */
+#define BE_READ_2(p) \
+ ((u_int16_t)(p)[0] << 8 | (u_int16_t)(p)[1])
+
+#define BE_WRITE_2(p, v) do { \
+ (p)[0] = (v) >> 8; (p)[1] = (v); \
+} while (0)
+
+#define BE_WRITE_8(p, v) do { \
+ (p)[0] = (v) >> 56; (p)[1] = (v) >> 48; \
+ (p)[2] = (v) >> 40; (p)[3] = (v) >> 32; \
+ (p)[4] = (v) >> 24; (p)[5] = (v) >> 16; \
+ (p)[6] = (v) >> 8; (p)[7] = (v); \
+} while (0)
+
+/* unaligned little endian access */
+#define LE_WRITE_6(p, v) do { \
+ (p)[5] = (v) >> 40; (p)[4] = (v) >> 32; \
+ (p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \
+ (p)[1] = (v) >> 8; (p)[0] = (v); \
+} while (0)
+
+/*
+ * Send an EAPOL-Key frame to node `ni'. If MIC or encryption is required,
+ * the PTK must be passed (otherwise it can be set to NULL.)
+ */
+int
+ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni, const struct ieee80211_ptk *ptk)
+{
+ struct ifnet *ifp = &ic->ic_if;
+ struct ether_header *eh;
+ struct ieee80211_eapol_key *key;
+ u_int16_t len, info;
+ int s, error;
+
+ M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
+ if (m == NULL)
+ return ENOMEM;
+ /* no need to m_pullup here (ok by construction) */
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = htons(ETHERTYPE_PAE);
+ IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr);
+ IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr);
+
+ key = (struct ieee80211_eapol_key *)&eh[1];
+ key->version = EAPOL_VERSION;
+ key->type = EAPOL_KEY;
+ key->desc = (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
+ EAPOL_KEY_DESC_IEEE80211 : EAPOL_KEY_DESC_WPA;
+
+ info = BE_READ_2(key->info);
+ /* use V2 descriptor if pairwise or group cipher is CCMP */
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
+ ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP)
+ info |= EAPOL_KEY_DESC_V2;
+ else
+ info |= EAPOL_KEY_DESC_V1;
+ BE_WRITE_2(key->info, info);
+
+ len = m->m_len - sizeof(struct ether_header);
+ BE_WRITE_2(key->paylen, len - sizeof(*key));
+ BE_WRITE_2(key->len, len - 4);
+
+ if (info & EAPOL_KEY_ENCRYPTED) {
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* clear "Encrypted" bit for WPA */
+ info &= ~EAPOL_KEY_ENCRYPTED;
+ BE_WRITE_2(key->info, info);
+ }
+ ieee80211_eapol_key_encrypt(ic, key, ptk->kek);
+
+ if ((info & EAPOL_KEY_VERSION_MASK) == EAPOL_KEY_DESC_V2) {
+ /* AES Key Wrap adds 8 bytes + padding */
+ m->m_pkthdr.len = m->m_len =
+ sizeof(*eh) + 4 + BE_READ_2(key->len);
+ }
+ }
+ if (info & EAPOL_KEY_KEYMIC)
+ ieee80211_eapol_key_mic(key, ptk->kck);
+
+ s = splnet();
+ /* start a 100ms timeout if an answer is expected from supplicant */
+ if (info & EAPOL_KEY_KEYACK)
+ timeout_add(&ni->ni_rsn_timeout, hz / 10);
+ IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
+ if (error == 0) {
+ ifp->if_obytes += m->m_pkthdr.len;
+ if ((ifp->if_flags & IFF_OACTIVE) == 0)
+ (*ifp->if_start)(ifp);
+ }
+ splx(s);
+
+ return error;
+}
+
+/*
+ * Handle EAPOL-Key timeouts (no answer from supplicant).
+ */
+void
+ieee80211_eapol_timeout(void *arg)
+{
+ struct ieee80211_node *ni = arg;
+ struct ieee80211com *ic = ni->ni_ic;
+ int s;
+
+ IEEE80211_DPRINTF(("%s: no answer from station %s in state %d\n",
+ __func__, ether_sprintf(ni->ni_macaddr), ni->ni_rsn_state));
+
+ s = splnet();
+
+ switch (ni->ni_rsn_state) {
+ case RSNA_PTKSTART:
+ case RSNA_PTKCALCNEGOTIATING:
+ (void)ieee80211_send_4way_msg1(ic, ni);
+ break;
+ case RSNA_PTKINITNEGOTIATING:
+ (void)ieee80211_send_4way_msg3(ic, ni);
+ break;
+ }
+
+ switch (ni->ni_rsn_gstate) {
+ case RSNA_REKEYNEGOTIATING:
+ (void)ieee80211_send_group_msg1(ic, ni);
+ break;
+ }
+
+ splx(s);
+}
+
+/*
+ * Add a GTK KDE to an EAPOL-Key frame (see Figure 144).
+ */
+u_int8_t *
+ieee80211_add_gtk_kde(u_int8_t *frm, struct ieee80211_node *ni,
+ const struct ieee80211_key *k)
+{
+ KASSERT(k->k_flags & IEEE80211_KEY_GROUP);
+
+ *frm++ = IEEE80211_ELEMID_VENDOR;
+ *frm++ = 6 + k->k_len;
+ memcpy(frm, IEEE80211_OUI, 3); frm += 3;
+ *frm++ = IEEE80211_KDE_GTK;
+ *frm = k->k_id & 3;
+ /*
+ * The TxRx flag for sending a GTK is always the opposite of whether
+ * the pairwise key is used for data encryption/integrity or not.
+ */
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
+ *frm |= 1 << 2; /* set the Tx bit */
+ frm++;
+ *frm++ = 0; /* reserved */
+ memcpy(frm, k->k_key, k->k_len);
+ return frm + k->k_len;
+}
+
+/*
+ * Add a PMKID KDE to an EAPOL-Key frame (see Figure 146).
+ */
+u_int8_t *
+ieee80211_add_pmkid_kde(u_int8_t *frm, const u_int8_t *pmkid)
+{
+ *frm++ = IEEE80211_ELEMID_VENDOR;
+ *frm++ = 20;
+ memcpy(frm, IEEE80211_OUI, 3); frm += 3;
+ *frm++ = IEEE80211_KDE_PMKID;
+ memcpy(frm, pmkid, IEEE80211_PMKID_LEN);
+ return frm + IEEE80211_PMKID_LEN;
+}
+
+struct mbuf *
+ieee80211_get_eapol_key(int flags, int type, u_int pktlen)
+{
+ struct mbuf *m;
+
+ /* reserve space for 802.11 encapsulation and EAPOL-Key header */
+ pktlen += sizeof(struct ieee80211_frame) + sizeof(struct llc) +
+ sizeof(struct ieee80211_eapol_key);
+
+ if (pktlen > MCLBYTES)
+ panic("EAPOL-Key frame too large: %u", pktlen);
+ MGETHDR(m, flags, type);
+ if (m == NULL)
+ return NULL;
+ if (pktlen >= MINCLSIZE) {
+ MCLGET(m, flags);
+ if (!(m->m_flags & M_EXT))
+ return m_free(m);
+ }
+ m->m_data += sizeof(struct ieee80211_frame) + sizeof(struct llc);
+ return m;
+}
+
+/*
+ * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
+ * (see 8.5.3.1).
+ */
+int
+ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ struct ieee80211_eapol_key *key;
+ struct mbuf *m;
+ u_int16_t info, keylen;
+ u_int8_t *frm;
+
+ ni->ni_rsn_state = RSNA_PTKSTART;
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_4WAY_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
+ (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ? 2 + 20 : 0);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
+ BE_WRITE_2(key->info, info);
+
+ /* copy the authenticator's nonce (ANonce) */
+ memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
+
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
+ BE_WRITE_2(key->keylen, keylen);
+
+ frm = (u_int8_t *)&key[1];
+ /* WPA does not have PMKID KDE */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN &&
+ ni->ni_rsnakms == IEEE80211_AKM_IEEE8021X) {
+ /* XXX retrieve PMKID from the PMKSA cache */
+ /* frm = ieee80211_add_pmkid_kde(frm, pmkid); */
+ }
+
+ m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 1, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ ni->ni_replaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ return ieee80211_send_eapol_key(ic, m, ni, NULL);
+}
+
+/*
+ * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
+ * (see 8.5.3.2).
+ */
+int
+ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
+ const u_int8_t *replaycnt, const struct ieee80211_ptk *tptk)
+{
+ struct ieee80211_eapol_key *key;
+ struct mbuf *m;
+ u_int16_t info;
+ u_int8_t *frm;
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
+ 2 + 48);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
+ BE_WRITE_2(key->info, info);
+
+ /* copy key replay counter from Message 1/4 */
+ memcpy(key->replaycnt, replaycnt, 8);
+
+ /* copy the supplicant's nonce (SNonce) */
+ memcpy(key->nonce, ic->ic_nonce, EAPOL_KEY_NONCE_LEN);
+
+ frm = (u_int8_t *)&key[1];
+ /* add the WPA/RSN IE used in the (Re)Association Request */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ u_int16_t keylen;
+ frm = ieee80211_add_wpa(frm, ic, ni);
+ /* WPA sets the key length field here */
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
+ BE_WRITE_2(key->keylen, keylen);
+ } else /* RSN */
+ frm = ieee80211_add_rsn(frm, ic, ni);
+
+ m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 2, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, tptk);
+}
+
+/*
+ * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
+ * (see 8.5.3.3).
+ */
+int
+ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ struct ieee80211_eapol_key *key;
+ struct ieee80211_key *k;
+ struct mbuf *m;
+ u_int16_t info, keylen;
+ u_int8_t *frm;
+
+ ni->ni_rsn_state = RSNA_PTKINITNEGOTIATING;
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_4WAY_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN)
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
+ 2 + 48 +
+ ((ni->ni_rsnprotos == IEEE80211_PROTO_RSN) ?
+ 2 + 6 + k->k_len : 0) +
+ 8);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC;
+ if (ni->ni_rsncipher != IEEE80211_CIPHER_USEGROUP)
+ info |= EAPOL_KEY_INSTALL;
+
+ /* use same nonce as in Message 1 */
+ memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
+
+ ni->ni_replaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
+ BE_WRITE_2(key->keylen, keylen);
+
+ frm = (u_int8_t *)&key[1];
+ /* add the WPA/RSN IE included in Beacon/Probe Response */
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_RSN) {
+ frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
+ /* encapsulate the GTK and ask for encryption */
+ frm = ieee80211_add_gtk_kde(frm, ni, k);
+ LE_WRITE_6(key->rsc, k->k_tsc);
+ info |= EAPOL_KEY_ENCRYPTED | EAPOL_KEY_SECURE;
+ } else /* WPA */
+ frm = ieee80211_add_wpa(frm, ic, ic->ic_bss);
+
+ /* write the key info field */
+ BE_WRITE_2(key->info, info);
+
+ m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 3, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
+}
+
+/*
+ * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
+ * (see 8.5.3.4).
+ */
+int
+ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ struct ieee80211_eapol_key *key;
+ struct mbuf *m;
+ u_int16_t info;
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
+
+ /* copy key replay counter from authenticator */
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ u_int16_t keylen;
+ /* WPA sets the key length field here */
+ keylen = ieee80211_cipher_keylen(ni->ni_rsncipher);
+ BE_WRITE_2(key->keylen, keylen);
+ } else
+ info |= EAPOL_KEY_SECURE;
+
+ /* write the key info field */
+ BE_WRITE_2(key->info, info);
+
+ /* empty key data field */
+ m->m_pkthdr.len = m->m_len = sizeof(*key);
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 4, 4, "4-way",
+ ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
+}
+
+/*
+ * Group Key Handshake Message 1 is sent by the authenticator to the
+ * supplicant (see 8.5.4.1).
+ */
+int
+ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
+{
+ struct ieee80211_eapol_key *key;
+ const struct ieee80211_key *k;
+ struct mbuf *m;
+ u_int16_t info;
+ u_int8_t *frm;
+
+ ni->ni_rsn_gstate = RSNA_REKEYNEGOTIATING;
+ if (++ni->ni_rsn_retries > 3) {
+ IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_GROUP_TIMEOUT);
+ ieee80211_node_leave(ic, ni);
+ return 0;
+ }
+ k = &ic->ic_nw_keys[ic->ic_def_txkey];
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
+ ((ni->ni_rsnprotos == IEEE80211_PROTO_WPA) ?
+ k->k_len : 2 + 6 + k->k_len) +
+ 8);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE |
+ EAPOL_KEY_ENCRYPTED;
+
+ ni->ni_replaycnt++;
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ frm = (u_int8_t *)&key[1];
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* WPA does not have GTK KDE */
+ BE_WRITE_2(key->keylen, k->k_len);
+ memcpy(frm, k->k_key, k->k_len);
+ frm += k->k_len;
+ info |= (k->k_id & 0x3) << EAPOL_KEY_WPA_KID_SHIFT;
+ if (ni->ni_rsncipher == IEEE80211_CIPHER_USEGROUP)
+ info |= EAPOL_KEY_WPA_TX;
+ } else /* RSN */
+ frm = ieee80211_add_gtk_kde(frm, ni, k);
+
+ /* RSC = last transmit sequence number for the GTK */
+ LE_WRITE_6(key->rsc, k->k_tsc);
+
+ /* write the key info field */
+ BE_WRITE_2(key->info, info);
+
+ m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 1, 2, "group key",
+ ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
+}
+
+/*
+ * Group Key Handshake Message 2 is sent by the supplicant to the
+ * authenticator (see 8.5.4.2).
+ */
+int
+ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
+ const struct ieee80211_key *k)
+{
+ struct ieee80211_eapol_key *key;
+ u_int16_t info;
+ struct mbuf *m;
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info = EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE;
+
+ /* copy key replay counter from authenticator */
+ BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
+
+ if (ni->ni_rsnprotos == IEEE80211_PROTO_WPA) {
+ /* WPA sets the key length and key id fields here */
+ BE_WRITE_2(key->keylen, k->k_len);
+ info |= (k->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT;
+ }
+
+ /* write the key info field */
+ BE_WRITE_2(key->info, info);
+
+ /* empty key data field */
+ m->m_pkthdr.len = m->m_len = sizeof(*key);
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending msg %d/%d of the %s handshake to %s\n",
+ ic->ic_if.if_xname, 2, 2, "group key",
+ ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
+}
+
+/*
+ * EAPOL-Key Request frames are sent by the supplicant to request that the
+ * authenticator initiates either a 4-Way Handshake or Group Key Handshake,
+ * or to report a MIC failure in a TKIP MSDU.
+ */
+int
+ieee80211_send_eapol_key_req(struct ieee80211com *ic,
+ struct ieee80211_node *ni, u_int16_t info, u_int64_t tsc)
+{
+ struct ieee80211_eapol_key *key;
+ struct mbuf *m;
+
+ m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
+ if (m == NULL)
+ return ENOMEM;
+ key = mtod(m, struct ieee80211_eapol_key *);
+ memset(key, 0, sizeof(*key));
+
+ info |= EAPOL_KEY_REQUEST;
+ BE_WRITE_2(key->info, info);
+
+ /* in case of TKIP MIC failure, fill the RSC field */
+ if (info & EAPOL_KEY_ERROR)
+ LE_WRITE_6(key->rsc, tsc);
+
+ /* use our separate key replay counter for key requests */
+ BE_WRITE_8(key->replaycnt, ni->ni_reqreplaycnt);
+ ni->ni_reqreplaycnt++;
+
+ if (ic->ic_if.if_flags & IFF_DEBUG)
+ printf("%s: sending EAPOL-Key request to %s\n",
+ ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
+
+ return ieee80211_send_eapol_key(ic, m, ni, &ni->ni_ptk);
+}
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 27c0b95bc8f..1a5698a612e 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.30 2008/07/21 18:43:18 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.31 2008/07/21 19:05:21 damien Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -58,6 +58,7 @@ extern void ieee80211_proto_detach(struct ifnet *);
struct ieee80211_node;
struct ieee80211_rxinfo;
+struct ieee80211_rsnparams;
extern u_int ieee80211_get_hdrlen(const void *);
extern void ieee80211_input(struct ifnet *, struct mbuf *,
struct ieee80211_node *, struct ieee80211_rxinfo *);
@@ -121,6 +122,10 @@ extern u_int8_t *ieee80211_add_wpa(u_int8_t *, struct ieee80211com *,
const struct ieee80211_node *);
extern u_int8_t *ieee80211_add_xrates(u_int8_t *,
const struct ieee80211_rateset *);
+extern int ieee80211_parse_rsn(struct ieee80211com *, const u_int8_t *,
+ struct ieee80211_rsnparams *);
+extern int ieee80211_parse_wpa(struct ieee80211com *, const u_int8_t *,
+ struct ieee80211_rsnparams *);
extern void ieee80211_print_essid(const u_int8_t *, int);
extern void ieee80211_dump_pkt(const u_int8_t *, int, int, int);
extern int ieee80211_ibss_merge(struct ieee80211com *,