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);