Change the way we process EAPOL-Key frames.
authordamien <damien@openbsd.org>
Tue, 12 Aug 2008 17:53:13 +0000 (17:53 +0000)
committerdamien <damien@openbsd.org>
Tue, 12 Aug 2008 17:53:13 +0000 (17:53 +0000)
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.

sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_pae_input.c
sys/net80211/ieee80211_proto.c
sys/net80211/ieee80211_proto.h
sys/net80211/ieee80211_var.h

index 255f7b2..e643380 100644 (file)
@@ -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;
index 606a088..ca08d4e 100644 (file)
@@ -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);
 }
 
 /*
index 5b8e801..cef25e1 100644 (file)
@@ -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
index 1a5698a..51863c2 100644 (file)
@@ -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 **);
index b1bb482..c50d8c6 100644 (file)
@@ -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 *,