From: damien Date: Tue, 12 Aug 2008 17:53:13 +0000 (+0000) Subject: Change the way we process EAPOL-Key frames. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=5027974404f02fbfad7ba28a15a517bceb26ee9c;p=openbsd 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. --- 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 @@ -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 *,