Drop frames that are received unencrypted when WEP is on or when
authordamien <damien@openbsd.org>
Sat, 2 Aug 2008 08:20:16 +0000 (08:20 +0000)
committerdamien <damien@openbsd.org>
Sat, 2 Aug 2008 08:20:16 +0000 (08:20 +0000)
WPA is on and RX protection for TA is on.
Keep track of the TX/RX protection for each node when WPA is on.

tested by djm@ (ral+wpa), ckuethe@ (ath-noenc) and krw@ (wpi<->ral+wpa).
hints from bluhm@
has been in snaps for a few days.

pointed out by bluhm@ something like 1 year ago but we did not have
the right infrastructure to fix it properly at that time.

ok deraadt@

sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_node.c
sys/net80211/ieee80211_node.h
sys/net80211/ieee80211_output.c
sys/net80211/ieee80211_pae_input.c

index a9d0c14..9e69f36 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_input.c,v 1.87 2008/07/28 19:42:13 damien Exp $     */
+/*     $OpenBSD: ieee80211_input.c,v 1.88 2008/08/02 08:20:16 damien Exp $     */
 
 /*-
  * Copyright (c) 2001 Atsushi Onoe
@@ -331,22 +331,31 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
                        goto out;
                }
 
-               if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
-                       if (ic->ic_flags &
-                           (IEEE80211_F_WEPON | IEEE80211_F_RSNON)) {
+               if ((ic->ic_flags & IEEE80211_F_WEPON) ||
+                   ((ic->ic_flags & IEEE80211_F_RSNON) &&
+                    (ni->ni_flags & IEEE80211_NODE_RXPROT))) {
+                       /* protection is on for Rx */
+                       if (!(rxi->rxi_flags & IEEE80211_RXI_HWDEC)) {
+                               if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
+                                       /* drop unencrypted */
+                                       ic->ic_stats.is_rx_unencrypted++;
+                                       goto err;
+                               }
+                               /* do software decryption */
                                m = ieee80211_decrypt(ic, m, ni);
                                if (m == NULL) {
                                        ic->ic_stats.is_rx_wepfail++;
                                        goto err;
                                }
                                wh = mtod(m, struct ieee80211_frame *);
-                       } else {
-                               ic->ic_stats.is_rx_nowep++;
-                               goto out;
                        }
-               } else if (!(rxi->rxi_flags & IEEE80211_RXI_HWDEC)) {
-                       /* XXX */
+               } else if ((wh->i_fc[1] & IEEE80211_FC1_PROTECTED) ||
+                   (rxi->rxi_flags & IEEE80211_RXI_HWDEC)) {
+                       /* frame encrypted but protection off for Rx */
+                       ic->ic_stats.is_rx_nowep++;
+                       goto out;
                }
+
 #if NBPFILTER > 0
                /* copy to listener after decrypt */
                if (ic->ic_rawbpf)
@@ -361,7 +370,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
                }
                eh = mtod(m, struct ether_header *);
 
-               if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid &&
+               if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+                   !ni->ni_port_valid &&
                    eh->ether_type != htons(ETHERTYPE_PAE)) {
                        DPRINTF(("port not valid: %s\n",
                            ether_sprintf(wh->i_addr2)));
index ef24049..dfbcde2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_node.c,v 1.37 2008/07/28 19:42:13 damien Exp $      */
+/*     $OpenBSD: ieee80211_node.c,v 1.38 2008/08/02 08:20:16 damien Exp $      */
 /*     $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $       */
 
 /*-
@@ -329,6 +329,7 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
                 * multicast frames using the group key we've just configured.
                 */
                ni->ni_port_valid = 1;
+               ni->ni_flags |= IEEE80211_NODE_TXPROT;
 
                /* schedule a GTK rekeying after 3600s */
                timeout_add(&ic->ic_rsn_timeout, 3600 * hz);
@@ -1086,6 +1087,7 @@ ieee80211_node_join_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
 
        ni->ni_key_count = 0;
        ni->ni_port_valid = 0;
+       ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
        ni->ni_replaycnt = -1;  /* XXX */
        ni->ni_rsn_retries = 0;
        ni->ni_rsncipher = ni->ni_rsnciphers;
@@ -1222,6 +1224,7 @@ ieee80211_node_leave_rsn(struct ieee80211com *ic, struct ieee80211_node *ni)
 
        timeout_del(&ni->ni_rsn_timeout);
        ni->ni_rsn_retries = 0;
+       ni->ni_flags &= ~IEEE80211_NODE_TXRXPROT;
        ni->ni_port_valid = 0;
        (*ic->ic_delete_key)(ic, ni, &ni->ni_pairwise_key);
 }
index ab37a30..5816978 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_node.h,v 1.28 2008/07/27 18:24:01 damien Exp $      */
+/*     $OpenBSD: ieee80211_node.h,v 1.29 2008/08/02 08:20:16 damien Exp $      */
 /*     $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $        */
 
 /*-
@@ -181,7 +181,11 @@ struct ieee80211_node {
        u_int8_t                ni_flags;       /* special-purpose state */
 #define IEEE80211_NODE_ERP     0x01
 #define IEEE80211_NODE_QOS     0x02
-#define IEEE80211_NODE_REKEY   0x04
+#define IEEE80211_NODE_REKEY   0x04    /* GTK rekying in progress */
+#define IEEE80211_NODE_RXPROT  0x08    /* RX protection ON */
+#define IEEE80211_NODE_TXPROT  0x10    /* TX protection ON */
+#define IEEE80211_NODE_TXRXPROT        \
+       (IEEE80211_NODE_TXPROT | IEEE80211_NODE_RXPROT)
 };
 
 RB_HEAD(ieee80211_tree, ieee80211_node);
index 7ed7b2b..982d766 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_output.c,v 1.63 2008/07/27 14:21:15 damien Exp $    */
+/*     $OpenBSD: ieee80211_output.c,v 1.64 2008/08/02 08:20:16 damien Exp $    */
 /*     $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $     */
 
 /*-
@@ -501,7 +501,8 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
                goto bad;
        }
 
-       if ((ic->ic_flags & IEEE80211_F_RSNON) && !ni->ni_port_valid &&
+       if ((ic->ic_flags & IEEE80211_F_RSNON) &&
+           !ni->ni_port_valid &&
            eh.ether_type != htons(ETHERTYPE_PAE)) {
                DPRINTF(("port not valid: %s\n",
                    ether_sprintf(eh.ether_dhost)));
@@ -581,7 +582,8 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
        }
 
        if ((ic->ic_flags & IEEE80211_F_WEPON) ||
-           ((ic->ic_flags & IEEE80211_F_RSNON) && ni->ni_port_valid))
+           ((ic->ic_flags & IEEE80211_F_RSNON) &&
+            (ni->ni_flags & IEEE80211_NODE_TXPROT)))
                wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
 
        *pni = ni;
index 4461856..321f3a0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_pae_input.c,v 1.3 2008/07/27 14:21:15 damien Exp $  */
+/*     $OpenBSD: ieee80211_pae_input.c,v 1.4 2008/08/02 08:20:16 damien Exp $  */
 
 /*-
  * Copyright (c) 2007,2008 Damien Bergamini <damien.bergamini@free.fr>
@@ -461,6 +461,7 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
                        reason = IEEE80211_REASON_AUTH_LEAVE;
                        goto deauth;
                }
+               ni->ni_flags |= IEEE80211_NODE_RXPROT;
        }
        if (gtk != NULL) {
                u_int64_t rsc;
@@ -488,7 +489,11 @@ ieee80211_recv_4way_msg3(struct ieee80211com *ic,
                        goto deauth;
                }
        }
+       if (info & EAPOL_KEY_INSTALL)
+               ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
+
        if (info & EAPOL_KEY_SECURE) {
+               ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
                if (ic->ic_opmode != IEEE80211_M_IBSS ||
                    ++ni->ni_key_count == 2) {
                        DPRINTF(("marking port %s valid\n",
@@ -546,6 +551,7 @@ ieee80211_recv_4way_msg4(struct ieee80211com *ic,
                        ieee80211_node_leave(ic, ni);
                        return;
                }
+               ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
        }
        if (ic->ic_opmode != IEEE80211_M_IBSS || ++ni->ni_key_count == 2) {
                DPRINTF(("marking port %s valid\n",
@@ -829,6 +835,7 @@ ieee80211_recv_group_msg2(struct ieee80211com *ic,
            --ic->ic_rsn_keydonesta == 0)
                ieee80211_setkeysdone(ic);
        ni->ni_flags &= ~IEEE80211_NODE_REKEY;
+       ni->ni_flags |= IEEE80211_NODE_TXRXPROT;
 
        ni->ni_rsn_gstate = RSNA_IDLE;
        ni->ni_rsn_retries = 0;