summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 17:53:14 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2008-08-12 17:53:14 +0000
commit6fccd682905e04ff8ae8a517c028646215282faa (patch)
treeeada03d11501c8ec9cd80333d744136ec8f1606c
parent229c556bc1be3f39773166961e2989a17ab6aaa8 (diff)
Change the way we process EAPOL-Key frames.
Free the mbuf in the ieee80211_eapol_key_input() function. Do not assume the frame is contiguous, call m_pullup2() if it is not. We need the frame to be contiguous to process KDEs efficiently in EAPOL-Key frames (just like we process IEs in management frames). However, there are drivers like upgt(4) that use m_devget() in the RX path. m_devget() can return fragmented mbuf chains. Notice that we should do the same m_pullup2() for management frames. This will be done later. Remove the ic_recv_eapol callback.
-rw-r--r--sys/net80211/ieee80211_input.c9
-rw-r--r--sys/net80211/ieee80211_pae_input.c46
-rw-r--r--sys/net80211/ieee80211_proto.c5
-rw-r--r--sys/net80211/ieee80211_proto.h4
-rw-r--r--sys/net80211/ieee80211_var.h4
5 files changed, 41 insertions, 27 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 255f7b2352d..e643380dd14 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_input.c,v 1.89 2008/08/02 08:35:48 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.90 2008/08/12 17:53:13 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -426,10 +426,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
#endif
if ((ic->ic_flags & IEEE80211_F_RSNON) &&
- eh->ether_type == htons(ETHERTYPE_PAE)) {
- (*ic->ic_recv_eapol)(ic, m, ni);
- m_freem(m);
- } else
+ eh->ether_type == htons(ETHERTYPE_PAE))
+ ieee80211_eapol_key_input(ic, m, ni);
+ else
ether_input_mbuf(ifp, m);
}
return;
diff --git a/sys/net80211/ieee80211_pae_input.c b/sys/net80211/ieee80211_pae_input.c
index 606a088c415..ca08d4e8ad3 100644
--- a/sys/net80211/ieee80211_pae_input.c
+++ b/sys/net80211/ieee80211_pae_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_pae_input.c,v 1.7 2008/08/12 16:14:05 damien Exp $ */
+/* $OpenBSD: ieee80211_pae_input.c,v 1.8 2008/08/12 17:53:13 damien Exp $ */
/*-
* Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
@@ -66,55 +66,72 @@ void ieee80211_recv_eapol_key_req(struct ieee80211com *,
* EAPOL-Key frames with an IEEE 802.11 or WPA descriptor type.
*/
void
-ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
+ieee80211_eapol_key_input(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;
+ int totlen;
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;
+ goto done;
}
m_adj(m0, sizeof(*eh));
+
+ if (m0->m_pkthdr.len < sizeof(*key))
+ goto done;
+ if (m0->m_len < sizeof(*key) &&
+ (m0 = m_pullup(m0, sizeof(*key))) == NULL) {
+ ic->ic_stats.is_rx_nombuf++;
+ goto done;
+ }
+
+ ic->ic_stats.is_rx_eapol_key++;
key = mtod(m0, struct ieee80211_eapol_key *);
if (key->type != EAPOL_KEY)
- return;
+ goto done;
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;
+ goto done;
/* check packet body length */
if (m0->m_len < 4 + BE_READ_2(key->len))
- return;
+ goto done;
/* check key data length */
- if (m0->m_len < sizeof(*key) + BE_READ_2(key->paylen))
- return;
+ totlen = sizeof(*key) + BE_READ_2(key->paylen);
+ if (m0->m_pkthdr.len < totlen || totlen > MCLBYTES)
+ goto done;
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;
+ goto done;
if ((ni->ni_rsncipher == IEEE80211_CIPHER_CCMP ||
ni->ni_rsngroupcipher == IEEE80211_CIPHER_CCMP) &&
desc != EAPOL_KEY_DESC_V2)
- return;
+ goto done;
+
+ /* make sure the key data field is contiguous */
+ if (m0->m_len < totlen && (m0 = m_pullup2(m0, totlen)) == NULL) {
+ ic->ic_stats.is_rx_nombuf++;
+ goto done;
+ }
+ key = mtod(m0, struct ieee80211_eapol_key *);
/* determine message type (see 8.5.3.7) */
if (info & EAPOL_KEY_REQUEST) {
@@ -133,7 +150,7 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
} else {
/* Group Key Handshake */
if (!(info & EAPOL_KEY_KEYMIC))
- return;
+ goto done;
if (info & EAPOL_KEY_KEYACK) {
if (key->desc == EAPOL_KEY_DESC_WPA)
ieee80211_recv_wpa_group_msg1(ic, key, ni);
@@ -142,6 +159,9 @@ ieee80211_recv_eapol(struct ieee80211com *ic, struct mbuf *m0,
} else
ieee80211_recv_group_msg2(ic, key, ni);
}
+ done:
+ if (m0 != NULL)
+ m_freem(m0);
}
/*
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 5b8e8019b40..cef25e1495d 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.c,v 1.29 2008/08/12 16:14:05 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.c,v 1.30 2008/08/12 17:53:13 damien Exp $ */
/* $NetBSD: ieee80211_proto.c,v 1.8 2004/04/30 23:58:20 dyoung Exp $ */
/*-
@@ -114,9 +114,6 @@ ieee80211_proto_attach(struct ifnet *ifp)
/* initialize management frame handlers */
ic->ic_recv_mgmt = ieee80211_recv_mgmt;
ic->ic_send_mgmt = ieee80211_send_mgmt;
-
- /* initialize EAPOL frame handler */
- ic->ic_recv_eapol = ieee80211_recv_eapol;
}
void
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 1a5698a612e..51863c212cb 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.31 2008/07/21 19:05:21 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.32 2008/08/12 17:53:13 damien Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -68,7 +68,7 @@ extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *, struct ieee80211_rxinfo *, int);
extern int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
int, int);
-extern void ieee80211_recv_eapol(struct ieee80211com *, struct mbuf *,
+extern void ieee80211_eapol_key_input(struct ieee80211com *, struct mbuf *,
struct ieee80211_node *);
extern struct mbuf *ieee80211_encap(struct ifnet *, struct mbuf *,
struct ieee80211_node **);
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index b1bb482929b..c50d8c6257d 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_var.h,v 1.42 2008/07/28 19:42:13 damien Exp $ */
+/* $OpenBSD: ieee80211_var.h,v 1.43 2008/08/12 17:53:13 damien Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
/*-
@@ -178,8 +178,6 @@ struct ieee80211com {
struct ieee80211_rxinfo *, int);
int (*ic_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);
- void (*ic_recv_eapol)(struct ieee80211com *,
- struct mbuf *, struct ieee80211_node *);
int (*ic_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*ic_newassoc)(struct ieee80211com *,