Module Name:    src
Committed By:   maxv
Date:           Tue Jan 16 08:39:29 UTC 2018

Modified Files:
        src/sys/net80211: ieee80211_input.c

Log Message:
Split ieee80211_input into three sub-functions, that parse received
packets depending on their type:

        DATA       -> ieee80211_input_data
        MANAGEMENT -> ieee80211_input_management
        CONTROL    -> ieee80211_input_control

No real functional change, but makes the code much clearer.


To generate a diff of this commit:
cvs rdiff -u -r1.92 -r1.93 src/sys/net80211/ieee80211_input.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net80211/ieee80211_input.c
diff -u src/sys/net80211/ieee80211_input.c:1.92 src/sys/net80211/ieee80211_input.c:1.93
--- src/sys/net80211/ieee80211_input.c:1.92	Tue Jan 16 07:53:02 2018
+++ src/sys/net80211/ieee80211_input.c	Tue Jan 16 08:39:29 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ieee80211_input.c,v 1.92 2018/01/16 07:53:02 maxv Exp $	*/
+/*	$NetBSD: ieee80211_input.c,v 1.93 2018/01/16 08:39:29 maxv Exp $	*/
 
 /*
  * Copyright (c) 2001 Atsushi Onoe
@@ -37,7 +37,7 @@
 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_input.c,v 1.81 2005/08/10 16:22:29 sam Exp $");
 #endif
 #ifdef __NetBSD__
-__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.92 2018/01/16 07:53:02 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.93 2018/01/16 08:39:29 maxv Exp $");
 #endif
 
 #ifdef _KERNEL_OPT
@@ -148,6 +148,359 @@ static void ieee80211_update_adhoc_node(
     struct ieee80211_node *, struct ieee80211_frame *,
     struct ieee80211_scanparams *, int, u_int32_t);
 
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Input code for a DATA frame.
+ */
+static int
+ieee80211_input_data(struct ieee80211com *ic, struct mbuf **mp,
+    struct ieee80211_node *ni)
+{
+	struct ifnet *ifp = ic->ic_ifp;
+	struct ieee80211_key *key;
+	struct ieee80211_frame *wh;
+	u_int8_t dir, subtype;
+	struct ether_header *eh;
+	struct mbuf *m = *mp;
+	int hdrspace;
+
+	wh = mtod(m, struct ieee80211_frame *);
+	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
+	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+	hdrspace = ieee80211_hdrspace(ic, wh);
+
+	if (m->m_len < hdrspace &&
+	    (m = m_pullup(m, hdrspace)) == NULL) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, NULL,
+		    "data too short: expecting %u", hdrspace);
+		ic->ic_stats.is_rx_tooshort++;
+		goto out;		/* XXX */
+	}
+	wh = mtod(m, struct ieee80211_frame *);
+
+	switch (ic->ic_opmode) {
+	case IEEE80211_M_STA:
+		if (dir != IEEE80211_FC1_DIR_FROMDS) {
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "data", "%s", "unknown dir 0x%x", dir);
+			ic->ic_stats.is_rx_wrongdir++;
+			goto out;
+		}
+		if ((ifp->if_flags & IFF_SIMPLEX) &&
+		    IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+		    IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) {
+			/*
+			 * In IEEE802.11 network, multicast packet
+			 * sent from me is broadcast from AP.
+			 * It should be silently discarded for
+			 * SIMPLEX interface.
+			 */
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, NULL, "%s", "multicast echo");
+			ic->ic_stats.is_rx_mcastecho++;
+			goto out;
+		}
+		break;
+
+	case IEEE80211_M_IBSS:
+	case IEEE80211_M_AHDEMO:
+		if (dir != IEEE80211_FC1_DIR_NODS) {
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "data", "%s", "unknown dir 0x%x", dir);
+			ic->ic_stats.is_rx_wrongdir++;
+			goto out;
+		}
+		/* XXX no power-save support */
+		break;
+
+	case IEEE80211_M_HOSTAP:
+#ifndef IEEE80211_NO_HOSTAP
+		if (dir != IEEE80211_FC1_DIR_TODS) {
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "data", "%s", "unknown dir 0x%x", dir);
+			ic->ic_stats.is_rx_wrongdir++;
+			goto out;
+		}
+		/* check if source STA is associated */
+		if (ni == ic->ic_bss) {
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "data", "%s", "unknown src");
+			ieee80211_send_error(ic, ni, wh->i_addr2,
+			    IEEE80211_FC0_SUBTYPE_DEAUTH,
+			    IEEE80211_REASON_NOT_AUTHED);
+			ic->ic_stats.is_rx_notassoc++;
+			goto err;
+		}
+		if (ni->ni_associd == 0) {
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "data", "%s", "unassoc src");
+			IEEE80211_SEND_MGMT(ic, ni,
+			    IEEE80211_FC0_SUBTYPE_DISASSOC,
+			    IEEE80211_REASON_NOT_ASSOCED);
+			ic->ic_stats.is_rx_notassoc++;
+			goto err;
+		}
+
+		/*
+		 * Check for power save state change.
+		 */
+		if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^
+		    (ni->ni_flags & IEEE80211_NODE_PWR_MGT)))
+			ieee80211_node_pwrsave(ni,
+				wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);
+#endif /* !IEEE80211_NO_HOSTAP */
+		break;
+
+	default:
+		/* XXX here to keep compiler happy */
+		goto out;
+	}
+
+	/*
+	 * Handle privacy requirements.  Note that we
+	 * must not be preempted from here until after
+	 * we (potentially) call ieee80211_crypto_demic;
+	 * otherwise we may violate assumptions in the
+	 * crypto cipher modules used to do delayed update
+	 * of replay sequence numbers.
+	 */
+	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+		if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
+			/*
+			 * Discard encrypted frames when privacy is off.
+			 */
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "WEP", "%s", "PRIVACY off");
+			ic->ic_stats.is_rx_noprivacy++;
+			IEEE80211_NODE_STAT(ni, rx_noprivacy);
+			goto out;
+		}
+		key = ieee80211_crypto_decap(ic, ni, &m, hdrspace);
+		if (key == NULL) {
+			/* NB: stats+msgs handled in crypto_decap */
+			IEEE80211_NODE_STAT(ni, rx_wepfail);
+			goto out;
+		}
+		wh = mtod(m, struct ieee80211_frame *);
+		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+	} else {
+		key = NULL;
+	}
+
+	/*
+	 * Next up, any fragmentation.
+	 */
+	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+		m = ieee80211_defrag(ic, ni, m, hdrspace);
+		if (m == NULL) {
+			/* Fragment dropped or frame not complete yet */
+			goto out;
+		}
+	}
+	wh = NULL;		/* no longer valid, catch any uses */
+
+	/*
+	 * Next strip any MSDU crypto bits.
+	 */
+	if (key != NULL && !ieee80211_crypto_demic(ic, key, m, 0)) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
+		    ni->ni_macaddr, "data", "%s", "demic error");
+		IEEE80211_NODE_STAT(ni, rx_demicfail);
+		goto out;
+	}
+
+	/* copy to listener after decrypt */
+	bpf_mtap3(ic->ic_rawbpf, m);
+
+	/*
+	 * Finally, strip the 802.11 header.
+	 */
+	m = ieee80211_decap(ic, m, hdrspace);
+	if (m == NULL) {
+		/* don't count Null data frames as errors */
+		if (subtype == IEEE80211_FC0_SUBTYPE_NODATA)
+			goto out;
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
+		    ni->ni_macaddr, "data", "%s", "decap error");
+		ic->ic_stats.is_rx_decap++;
+		IEEE80211_NODE_STAT(ni, rx_decap);
+		goto err;
+	}
+
+	eh = mtod(m, struct ether_header *);
+	if (!ieee80211_node_is_authorized(ni)) {
+		/*
+		 * Deny any non-PAE frames received prior to
+		 * authorization.  For open/shared-key
+		 * authentication the port is mark authorized
+		 * after authentication completes.  For 802.1x
+		 * the port is not marked authorized by the
+		 * authenticator until the handshake has completed.
+		 */
+		if (eh->ether_type != htons(ETHERTYPE_PAE)) {
+			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
+			    eh->ether_shost, "data",
+			    "unauthorized port: ether type 0x%x len %u",
+			    eh->ether_type, m->m_pkthdr.len);
+			ic->ic_stats.is_rx_unauth++;
+			IEEE80211_NODE_STAT(ni, rx_unauth);
+			goto err;
+		}
+	} else {
+		/*
+		 * When denying unencrypted frames, discard
+		 * any non-PAE frames received without encryption.
+		 */
+		if ((ic->ic_flags & IEEE80211_F_DROPUNENC) &&
+		    key == NULL &&
+		    eh->ether_type != htons(ETHERTYPE_PAE)) {
+			/*
+			 * Drop unencrypted frames.
+			 */
+			ic->ic_stats.is_rx_unencrypted++;
+			IEEE80211_NODE_STAT(ni, rx_unencrypted);
+			goto out;
+		}
+	}
+
+	ifp->if_ipackets++;
+	IEEE80211_NODE_STAT(ni, rx_data);
+	IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
+
+	ieee80211_deliver_data(ic, ni, m);
+
+	*mp = NULL;
+	return 0;
+
+err:
+	ifp->if_ierrors++;
+out:
+	*mp = m;
+	return -1;
+}
+
+/*
+ * Input code for a MANAGEMENT frame.
+ */
+static int
+ieee80211_input_management(struct ieee80211com *ic, struct mbuf **mp,
+    struct ieee80211_node *ni, int rssi, u_int32_t rstamp)
+{
+	IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
+	struct ifnet *ifp = ic->ic_ifp;
+	struct ieee80211_key *key;
+	struct ieee80211_frame *wh;
+	u_int8_t dir, subtype;
+	struct mbuf *m = *mp;
+	int hdrspace;
+
+	wh = mtod(m, struct ieee80211_frame *);
+	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
+	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+	IEEE80211_NODE_STAT(ni, rx_mgmt);
+	if (dir != IEEE80211_FC1_DIR_NODS) {
+		IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+		    wh, "data", "%s", "unknown dir 0x%x", dir);
+		ic->ic_stats.is_rx_wrongdir++;
+		goto err;
+	}
+	if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
+		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
+		    ni->ni_macaddr, "mgt", "too short: len %u",
+		    m->m_pkthdr.len);
+		ic->ic_stats.is_rx_tooshort++;
+		goto out;
+	}
+#ifdef IEEE80211_DEBUG
+	if ((ieee80211_msg_debug(ic) && doprint(ic, subtype)) ||
+	    ieee80211_msg_dumppkts(ic)) {
+		if_printf(ic->ic_ifp, "received %s from %s rssi %d\n",
+		    ieee80211_mgt_subtype_name[subtype >>
+			IEEE80211_FC0_SUBTYPE_SHIFT],
+		    ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2),
+		    rssi);
+	}
+#endif
+
+	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+		if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
+			/*
+			 * Only shared key auth frames with a challenge
+			 * should be encrypted, discard all others.
+			 */
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, ieee80211_mgt_subtype_name[subtype >>
+				IEEE80211_FC0_SUBTYPE_SHIFT],
+			    "%s", "WEP set but not permitted");
+			ic->ic_stats.is_rx_mgtdiscard++; /* XXX */
+			goto out;
+		}
+		if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
+			/*
+			 * Discard encrypted frames when privacy is off.
+			 */
+			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
+			    wh, "mgt", "%s", "WEP set but PRIVACY off");
+			ic->ic_stats.is_rx_noprivacy++;
+			goto out;
+		}
+		hdrspace = ieee80211_hdrspace(ic, wh);
+		key = ieee80211_crypto_decap(ic, ni, &m, hdrspace);
+		if (key == NULL) {
+			/* NB: stats+msgs handled in crypto_decap */
+			goto out;
+		}
+		wh = mtod(m, struct ieee80211_frame *);
+		wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
+	}
+
+	bpf_mtap3(ic->ic_rawbpf, m);
+	(*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
+	m_freem(m);
+
+	*mp = NULL;
+	return 0;
+
+err:
+	ifp->if_ierrors++;
+out:
+	*mp = m;
+	return -1;
+}
+
+/*
+ * Input code for a CONTROL frame.
+ */
+static void
+ieee80211_input_control(struct ieee80211com *ic, struct mbuf *m,
+    struct ieee80211_node *ni)
+{
+	IEEE80211_NODE_STAT(ni, rx_ctrl);
+	ic->ic_stats.is_rx_ctl++;
+
+#ifndef IEEE80211_NO_HOSTAP
+	if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
+		struct ieee80211_frame *wh;
+		u_int8_t subtype;
+
+		wh = mtod(m, struct ieee80211_frame *);
+		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
+
+		switch (subtype) {
+		case IEEE80211_FC0_SUBTYPE_PS_POLL:
+			ieee80211_recv_pspoll(ic, ni, m);
+			break;
+		}
+	}
+#endif
+}
+
+/* -------------------------------------------------------------------------- */
+
 /*
  * Process a received frame.  The node associated with the sender
  * should be supplied.  If nothing was found in the node table then
@@ -166,12 +519,10 @@ ieee80211_input(struct ieee80211com *ic,
 #define	HAS_SEQ(type)	((type & 0x4) == 0)
 	struct ifnet *ifp = ic->ic_ifp;
 	struct ieee80211_frame *wh;
-	struct ieee80211_key *key;
-	struct ether_header *eh;
-	int hdrspace;
-	u_int8_t dir, type, subtype;
+	u_int8_t dir, type;
 	u_int16_t rxseq;
 	IEEE80211_DEBUGVAR(char ebuf[3 * ETHER_ADDR_LEN]);
+	int ret;
 
 	KASSERT(!cpu_intr_p());
 
@@ -218,7 +569,6 @@ ieee80211_input(struct ieee80211com *ic,
 
 	dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
-	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
 
 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
 		u_int8_t *bssid;
@@ -366,284 +716,23 @@ ieee80211_input(struct ieee80211com *ic,
 
 	switch (type) {
 	case IEEE80211_FC0_TYPE_DATA:
-		hdrspace = ieee80211_hdrspace(ic, wh);
-		if (m->m_len < hdrspace &&
-		    (m = m_pullup(m, hdrspace)) == NULL) {
-			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
-			    ni->ni_macaddr, NULL,
-			    "data too short: expecting %u", hdrspace);
-			ic->ic_stats.is_rx_tooshort++;
-			goto out;		/* XXX */
-		}
-		wh = mtod(m, struct ieee80211_frame *);
-
-		switch (ic->ic_opmode) {
-		case IEEE80211_M_STA:
-			if (dir != IEEE80211_FC1_DIR_FROMDS) {
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "data", "%s", "unknown dir 0x%x", dir);
-				ic->ic_stats.is_rx_wrongdir++;
-				goto out;
-			}
-			if ((ifp->if_flags & IFF_SIMPLEX) &&
-			    IEEE80211_IS_MULTICAST(wh->i_addr1) &&
-			    IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) {
-				/*
-				 * In IEEE802.11 network, multicast packet
-				 * sent from me is broadcast from AP.
-				 * It should be silently discarded for
-				 * SIMPLEX interface.
-				 */
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, NULL, "%s", "multicast echo");
-				ic->ic_stats.is_rx_mcastecho++;
-				goto out;
-			}
-			break;
-
-		case IEEE80211_M_IBSS:
-		case IEEE80211_M_AHDEMO:
-			if (dir != IEEE80211_FC1_DIR_NODS) {
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "data", "%s", "unknown dir 0x%x", dir);
-				ic->ic_stats.is_rx_wrongdir++;
-				goto out;
-			}
-			/* XXX no power-save support */
-			break;
-
-		case IEEE80211_M_HOSTAP:
-#ifndef IEEE80211_NO_HOSTAP
-			if (dir != IEEE80211_FC1_DIR_TODS) {
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "data", "%s", "unknown dir 0x%x", dir);
-				ic->ic_stats.is_rx_wrongdir++;
-				goto out;
-			}
-			/* check if source STA is associated */
-			if (ni == ic->ic_bss) {
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "data", "%s", "unknown src");
-				ieee80211_send_error(ic, ni, wh->i_addr2,
-				    IEEE80211_FC0_SUBTYPE_DEAUTH,
-				    IEEE80211_REASON_NOT_AUTHED);
-				ic->ic_stats.is_rx_notassoc++;
-				goto err;
-			}
-			if (ni->ni_associd == 0) {
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "data", "%s", "unassoc src");
-				IEEE80211_SEND_MGMT(ic, ni,
-				    IEEE80211_FC0_SUBTYPE_DISASSOC,
-				    IEEE80211_REASON_NOT_ASSOCED);
-				ic->ic_stats.is_rx_notassoc++;
-				goto err;
-			}
-
-			/*
-			 * Check for power save state change.
-			 */
-			if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^
-			    (ni->ni_flags & IEEE80211_NODE_PWR_MGT)))
-				ieee80211_node_pwrsave(ni,
-					wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);
-#endif /* !IEEE80211_NO_HOSTAP */
-			break;
-
-		default:
-			/* XXX here to keep compiler happy */
-			goto out;
-		}
-
-		/*
-		 * Handle privacy requirements.  Note that we
-		 * must not be preempted from here until after
-		 * we (potentially) call ieee80211_crypto_demic;
-		 * otherwise we may violate assumptions in the
-		 * crypto cipher modules used to do delayed update
-		 * of replay sequence numbers.
-		 */
-		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
-			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
-				/*
-				 * Discard encrypted frames when privacy is off.
-				 */
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "WEP", "%s", "PRIVACY off");
-				ic->ic_stats.is_rx_noprivacy++;
-				IEEE80211_NODE_STAT(ni, rx_noprivacy);
-				goto out;
-			}
-			key = ieee80211_crypto_decap(ic, ni, &m, hdrspace);
-			if (key == NULL) {
-				/* NB: stats+msgs handled in crypto_decap */
-				IEEE80211_NODE_STAT(ni, rx_wepfail);
-				goto out;
-			}
-			wh = mtod(m, struct ieee80211_frame *);
-			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
-		} else {
-			key = NULL;
-		}
-
-		/*
-		 * Next up, any fragmentation.
-		 */
-		if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
-			m = ieee80211_defrag(ic, ni, m, hdrspace);
-			if (m == NULL) {
-				/* Fragment dropped or frame not complete yet */
-				goto out;
-			}
-		}
-		wh = NULL;		/* no longer valid, catch any uses */
-
-		/*
-		 * Next strip any MSDU crypto bits.
-		 */
-		if (key != NULL && !ieee80211_crypto_demic(ic, key, m, 0)) {
-			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
-			    ni->ni_macaddr, "data", "%s", "demic error");
-			IEEE80211_NODE_STAT(ni, rx_demicfail);
+		ret = ieee80211_input_data(ic, &m, ni);
+		if (ret == -1) {
 			goto out;
 		}
-
-		/* copy to listener after decrypt */
-		bpf_mtap3(ic->ic_rawbpf, m);
-
-		/*
-		 * Finally, strip the 802.11 header.
-		 */
-		m = ieee80211_decap(ic, m, hdrspace);
-		if (m == NULL) {
-			/* don't count Null data frames as errors */
-			if (subtype == IEEE80211_FC0_SUBTYPE_NODATA)
-				goto out;
-			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
-			    ni->ni_macaddr, "data", "%s", "decap error");
-			ic->ic_stats.is_rx_decap++;
-			IEEE80211_NODE_STAT(ni, rx_decap);
-			goto err;
-		}
-
-		eh = mtod(m, struct ether_header *);
-		if (!ieee80211_node_is_authorized(ni)) {
-			/*
-			 * Deny any non-PAE frames received prior to
-			 * authorization.  For open/shared-key
-			 * authentication the port is mark authorized
-			 * after authentication completes.  For 802.1x
-			 * the port is not marked authorized by the
-			 * authenticator until the handshake has completed.
-			 */
-			if (eh->ether_type != htons(ETHERTYPE_PAE)) {
-				IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_INPUT,
-				    eh->ether_shost, "data",
-				    "unauthorized port: ether type 0x%x len %u",
-				    eh->ether_type, m->m_pkthdr.len);
-				ic->ic_stats.is_rx_unauth++;
-				IEEE80211_NODE_STAT(ni, rx_unauth);
-				goto err;
-			}
-		} else {
-			/*
-			 * When denying unencrypted frames, discard
-			 * any non-PAE frames received without encryption.
-			 */
-			if ((ic->ic_flags & IEEE80211_F_DROPUNENC) &&
-			    key == NULL &&
-			    eh->ether_type != htons(ETHERTYPE_PAE)) {
-				/*
-				 * Drop unencrypted frames.
-				 */
-				ic->ic_stats.is_rx_unencrypted++;
-				IEEE80211_NODE_STAT(ni, rx_unencrypted);
-				goto out;
-			}
-		}
-
-		ifp->if_ipackets++;
-		IEEE80211_NODE_STAT(ni, rx_data);
-		IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
-
-		ieee80211_deliver_data(ic, ni, m);
 		return IEEE80211_FC0_TYPE_DATA;
 
 	case IEEE80211_FC0_TYPE_MGT:
-		IEEE80211_NODE_STAT(ni, rx_mgmt);
-		if (dir != IEEE80211_FC1_DIR_NODS) {
-			IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-			    wh, "data", "%s", "unknown dir 0x%x", dir);
-			ic->ic_stats.is_rx_wrongdir++;
-			goto err;
-		}
-		if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
-			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
-			    ni->ni_macaddr, "mgt", "too short: len %u",
-			    m->m_pkthdr.len);
-			ic->ic_stats.is_rx_tooshort++;
+		ret = ieee80211_input_management(ic, &m, ni, rssi, rstamp);
+		if (ret == -1) {
 			goto out;
 		}
-#ifdef IEEE80211_DEBUG
-		if ((ieee80211_msg_debug(ic) && doprint(ic, subtype)) ||
-		    ieee80211_msg_dumppkts(ic)) {
-			if_printf(ic->ic_ifp, "received %s from %s rssi %d\n",
-			    ieee80211_mgt_subtype_name[subtype >>
-				IEEE80211_FC0_SUBTYPE_SHIFT],
-			    ether_snprintf(ebuf, sizeof(ebuf), wh->i_addr2),
-			    rssi);
-		}
-#endif
-		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
-			if (subtype != IEEE80211_FC0_SUBTYPE_AUTH) {
-				/*
-				 * Only shared key auth frames with a challenge
-				 * should be encrypted, discard all others.
-				 */
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, ieee80211_mgt_subtype_name[subtype >>
-					IEEE80211_FC0_SUBTYPE_SHIFT],
-				    "%s", "WEP set but not permitted");
-				ic->ic_stats.is_rx_mgtdiscard++; /* XXX */
-				goto out;
-			}
-			if ((ic->ic_flags & IEEE80211_F_PRIVACY) == 0) {
-				/*
-				 * Discard encrypted frames when privacy is off.
-				 */
-				IEEE80211_DISCARD(ic, IEEE80211_MSG_INPUT,
-				    wh, "mgt", "%s", "WEP set but PRIVACY off");
-				ic->ic_stats.is_rx_noprivacy++;
-				goto out;
-			}
-			hdrspace = ieee80211_hdrspace(ic, wh);
-			key = ieee80211_crypto_decap(ic, ni, &m, hdrspace);
-			if (key == NULL) {
-				/* NB: stats+msgs handled in crypto_decap */
-				goto out;
-			}
-			wh = mtod(m, struct ieee80211_frame *);
-			wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
-		}
-
-		bpf_mtap3(ic->ic_rawbpf, m);
-		(*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
-		m_freem(m);
-		return type;
+		return IEEE80211_FC0_TYPE_MGT;
 
 	case IEEE80211_FC0_TYPE_CTL:
-		IEEE80211_NODE_STAT(ni, rx_ctrl);
-		ic->ic_stats.is_rx_ctl++;
-#ifndef IEEE80211_NO_HOSTAP
-		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
-			switch (subtype) {
-			case IEEE80211_FC0_SUBTYPE_PS_POLL:
-				ieee80211_recv_pspoll(ic, ni, m);
-				break;
-			}
-		}
-#endif /* !IEEE80211_NO_HOSTAP */
+		ieee80211_input_control(ic, m, ni);
 		goto out;
+
 	default:
 		IEEE80211_DISCARD(ic, IEEE80211_MSG_ANY,
 		    wh, NULL, "bad frame type 0x%x", type);

Reply via email to