From 7594fa5c70305cda65deedc5cc7e08dc037727cd Mon Sep 17 00:00:00 2001 From: adrian Date: Sun, 28 Jul 2013 04:53:00 +0000 Subject: Refactor the VAP transmit path code into a utility function that both the normal and the mesh transmit paths can use. The API is a bit horrible because it both consumes the mbuf and frees the node reference regardless of whether it succeeds or not. It's a hold-over from how the code behaves; it'd be nice to have it not free the node reference / mbuf if TX fails and let the caller decide what to do. --- sys/net80211/ieee80211_mesh.c | 106 +--------------- sys/net80211/ieee80211_output.c | 266 ++++++++++++++++++++++------------------ 2 files changed, 155 insertions(+), 217 deletions(-) diff --git a/sys/net80211/ieee80211_mesh.c b/sys/net80211/ieee80211_mesh.c index 35b98fa..35da7bb 100644 --- a/sys/net80211/ieee80211_mesh.c +++ b/sys/net80211/ieee80211_mesh.c @@ -1042,12 +1042,9 @@ mesh_transmit_to_gate(struct ieee80211vap *vap, struct mbuf *m, struct ifnet *ifp = vap->iv_ifp; struct ieee80211com *ic = vap->iv_ic; struct ieee80211_node *ni; - struct ether_header *eh; - int error; IEEE80211_TX_UNLOCK_ASSERT(ic); - eh = mtod(m, struct ether_header *); ni = ieee80211_mesh_find_txnode(vap, rt_gate->rt_dest); if (ni == NULL) { ifp->if_oerrors++; @@ -1055,106 +1052,13 @@ mesh_transmit_to_gate(struct ieee80211vap *vap, struct mbuf *m, return; } - if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && - (m->m_flags & M_PWR_SAV) == 0) { - /* - * Station in power save mode; pass the frame - * to the 802.11 layer and continue. We'll get - * the frame back when the time is right. - * XXX lose WDS vap linkage? - */ - (void) ieee80211_pwrsave(ni, m); - ieee80211_free_node(ni); - return; - } - - /* calculate priority so drivers can find the tx queue */ - if (ieee80211_classify(ni, m)) { - IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, - eh->ether_dhost, NULL, - "%s", "classification failure"); - vap->iv_stats.is_tx_classify++; - ifp->if_oerrors++; - m_freem(m); - ieee80211_free_node(ni); - return; - } - /* - * Stash the node pointer. Note that we do this after - * any call to ieee80211_dwds_mcast because that code - * uses any existing value for rcvif to identify the - * interface it (might have been) received on. - */ - m->m_pkthdr.rcvif = (void *)ni; - - BPF_MTAP(ifp, m); /* 802.3 tx */ - /* - * Check if A-MPDU tx aggregation is setup or if we - * should try to enable it. The sta must be associated - * with HT and A-MPDU enabled for use. When the policy - * routine decides we should enable A-MPDU we issue an - * ADDBA request and wait for a reply. The frame being - * encapsulated will go out w/o using A-MPDU, or possibly - * it might be collected by the driver and held/retransmit. - * The default ic_ampdu_enable routine handles staggering - * ADDBA requests in case the receiver NAK's us or we are - * otherwise unable to establish a BA stream. + * Send through the VAP packet transmit path. + * This consumes the node ref grabbed above and + * the mbuf, regardless of whether there's a problem + * or not. */ - if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && - (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && - (m->m_flags & M_EAPOL) == 0) { - int tid = WME_AC_TO_TID(M_WME_GETAC(m)); - struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; - - ieee80211_txampdu_count_packet(tap); - if (IEEE80211_AMPDU_RUNNING(tap)) { - /* - * Operational, mark frame for aggregation. - * - * XXX do tx aggregation here - */ - m->m_flags |= M_AMPDU_MPDU; - } else if (!IEEE80211_AMPDU_REQUESTED(tap) && - ic->ic_ampdu_enable(ni, tap)) { - /* - * Not negotiated yet, request service. - */ - ieee80211_ampdu_request(ni, tap); - /* XXX hold frame for reply? */ - } - } -#ifdef IEEE80211_SUPPORT_SUPERG - else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { - m = ieee80211_ff_check(ni, m); - if (m == NULL) { - /* NB: any ni ref held on stageq */ - return; - } - } -#endif /* IEEE80211_SUPPORT_SUPERG */ - - IEEE80211_TX_LOCK(ic); - if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { - /* - * Encapsulate the packet in prep for transmission. - */ - m = ieee80211_encap(vap, ni, m); - if (m == NULL) { - /* NB: stat+msg handled in ieee80211_encap */ - IEEE80211_TX_UNLOCK(ic); - ieee80211_free_node(ni); - return; - } - } - error = ieee80211_parent_transmit(ic, m); - IEEE80211_TX_UNLOCK(ic); - if (error != 0) { - ieee80211_free_node(ni); - } else { - ifp->if_opackets++; - } - ic->ic_lastdata = ticks; + (void) ieee80211_vap_pkt_send_dest(vap, m, ni); } /* diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index 7e2ac83..3be382c 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -110,6 +110,153 @@ doprint(struct ieee80211vap *vap, int subtype) #endif /* + * Transmit a frame to the given destination on the given VAP. + * + * It's up to the caller to figure out the details of who this + * is going to and resolving the node. + * + * This routine takes care of queuing it for power save, + * A-MPDU state stuff, fast-frames state stuff, encapsulation + * if required, then passing it up to the driver layer. + * + * This routine (for now) consumes the mbuf and frees the node + * reference; it ideally will return a TX status which reflects + * whether the mbuf was consumed or not, so the caller can + * free the mbuf (if appropriate) and the node reference (again, + * if appropriate.) + */ +int +ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m, + struct ieee80211_node *ni) +{ + struct ieee80211com *ic = vap->iv_ic; + struct ifnet *ifp = vap->iv_ifp; + int error; + + if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && + (m->m_flags & M_PWR_SAV) == 0) { + /* + * Station in power save mode; pass the frame + * to the 802.11 layer and continue. We'll get + * the frame back when the time is right. + * XXX lose WDS vap linkage? + */ + (void) ieee80211_pwrsave(ni, m); + ieee80211_free_node(ni); + /* XXX better status? */ + return (ENOBUFS); + } + /* calculate priority so drivers can find the tx queue */ + if (ieee80211_classify(ni, m)) { + IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, + ni->ni_macaddr, NULL, + "%s", "classification failure"); + vap->iv_stats.is_tx_classify++; + ifp->if_oerrors++; + m_freem(m); + ieee80211_free_node(ni); + /* XXX better status? */ + return (ENOBUFS); + } + /* + * Stash the node pointer. Note that we do this after + * any call to ieee80211_dwds_mcast because that code + * uses any existing value for rcvif to identify the + * interface it (might have been) received on. + */ + m->m_pkthdr.rcvif = (void *)ni; + + BPF_MTAP(ifp, m); /* 802.3 tx */ + + + /* + * Check if A-MPDU tx aggregation is setup or if we + * should try to enable it. The sta must be associated + * with HT and A-MPDU enabled for use. When the policy + * routine decides we should enable A-MPDU we issue an + * ADDBA request and wait for a reply. The frame being + * encapsulated will go out w/o using A-MPDU, or possibly + * it might be collected by the driver and held/retransmit. + * The default ic_ampdu_enable routine handles staggering + * ADDBA requests in case the receiver NAK's us or we are + * otherwise unable to establish a BA stream. + */ + if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && + (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && + (m->m_flags & M_EAPOL) == 0) { + int tid = WME_AC_TO_TID(M_WME_GETAC(m)); + struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; + + ieee80211_txampdu_count_packet(tap); + if (IEEE80211_AMPDU_RUNNING(tap)) { + /* + * Operational, mark frame for aggregation. + * + * XXX do tx aggregation here + */ + m->m_flags |= M_AMPDU_MPDU; + } else if (!IEEE80211_AMPDU_REQUESTED(tap) && + ic->ic_ampdu_enable(ni, tap)) { + /* + * Not negotiated yet, request service. + */ + ieee80211_ampdu_request(ni, tap); + /* XXX hold frame for reply? */ + } + } + +#ifdef IEEE80211_SUPPORT_SUPERG + else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { + m = ieee80211_ff_check(ni, m); + if (m == NULL) { + /* NB: any ni ref held on stageq */ + /* XXX better status? */ + return (ENOBUFS); + } + } +#endif /* IEEE80211_SUPPORT_SUPERG */ + + /* + * Grab the TX lock - serialise the TX process from this + * point (where TX state is being checked/modified) + * through to driver queue. + */ + IEEE80211_TX_LOCK(ic); + + if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { + /* + * Encapsulate the packet in prep for transmission. + */ + m = ieee80211_encap(vap, ni, m); + if (m == NULL) { + /* NB: stat+msg handled in ieee80211_encap */ + IEEE80211_TX_UNLOCK(ic); + ieee80211_free_node(ni); + /* XXX better status? */ + return (ENOBUFS); + } + } + error = ieee80211_parent_transmit(ic, m); + + /* + * Unlock at this point - no need to hold it across + * ieee80211_free_node() (ie, the comlock) + */ + IEEE80211_TX_UNLOCK(ic); + if (error != 0) { + /* NB: IFQ_HANDOFF reclaims mbuf */ + ieee80211_free_node(ni); + } else { + ifp->if_opackets++; + } + ic->ic_lastdata = ticks; + + return (0); +} + + + +/* * Send the given mbuf through the given vap. * * This consumes the mbuf regardless of whether the transmit @@ -129,7 +276,6 @@ ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) struct ifnet *ifp = vap->iv_ifp; struct ieee80211_node *ni; struct ether_header *eh; - int error; /* * Cancel any background scan. @@ -236,124 +382,12 @@ ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) } } #endif - if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && - (m->m_flags & M_PWR_SAV) == 0) { - /* - * Station in power save mode; pass the frame - * to the 802.11 layer and continue. We'll get - * the frame back when the time is right. - * XXX lose WDS vap linkage? - */ - (void) ieee80211_pwrsave(ni, m); - ieee80211_free_node(ni); - /* XXX better status? */ - return (ENOBUFS); - } - /* calculate priority so drivers can find the tx queue */ - if (ieee80211_classify(ni, m)) { - IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, - eh->ether_dhost, NULL, - "%s", "classification failure"); - vap->iv_stats.is_tx_classify++; - ifp->if_oerrors++; - m_freem(m); - ieee80211_free_node(ni); - /* XXX better status? */ - return (ENOBUFS); - } - /* - * Stash the node pointer. Note that we do this after - * any call to ieee80211_dwds_mcast because that code - * uses any existing value for rcvif to identify the - * interface it (might have been) received on. - */ - m->m_pkthdr.rcvif = (void *)ni; - - BPF_MTAP(ifp, m); /* 802.3 tx */ - - - /* - * Check if A-MPDU tx aggregation is setup or if we - * should try to enable it. The sta must be associated - * with HT and A-MPDU enabled for use. When the policy - * routine decides we should enable A-MPDU we issue an - * ADDBA request and wait for a reply. The frame being - * encapsulated will go out w/o using A-MPDU, or possibly - * it might be collected by the driver and held/retransmit. - * The default ic_ampdu_enable routine handles staggering - * ADDBA requests in case the receiver NAK's us or we are - * otherwise unable to establish a BA stream. - */ - if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && - (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && - (m->m_flags & M_EAPOL) == 0) { - int tid = WME_AC_TO_TID(M_WME_GETAC(m)); - struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; - - ieee80211_txampdu_count_packet(tap); - if (IEEE80211_AMPDU_RUNNING(tap)) { - /* - * Operational, mark frame for aggregation. - * - * XXX do tx aggregation here - */ - m->m_flags |= M_AMPDU_MPDU; - } else if (!IEEE80211_AMPDU_REQUESTED(tap) && - ic->ic_ampdu_enable(ni, tap)) { - /* - * Not negotiated yet, request service. - */ - ieee80211_ampdu_request(ni, tap); - /* XXX hold frame for reply? */ - } - } - -#ifdef IEEE80211_SUPPORT_SUPERG - else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { - m = ieee80211_ff_check(ni, m); - if (m == NULL) { - /* NB: any ni ref held on stageq */ - /* XXX better status? */ - return (ENOBUFS); - } - } -#endif /* IEEE80211_SUPPORT_SUPERG */ - - /* - * Grab the TX lock - serialise the TX process from this - * point (where TX state is being checked/modified) - * through to driver queue. - */ - IEEE80211_TX_LOCK(ic); - - if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { - /* - * Encapsulate the packet in prep for transmission. - */ - m = ieee80211_encap(vap, ni, m); - if (m == NULL) { - /* NB: stat+msg handled in ieee80211_encap */ - IEEE80211_TX_UNLOCK(ic); - ieee80211_free_node(ni); - /* XXX better status? */ - return (ENOBUFS); - } - } - error = ieee80211_parent_transmit(ic, m); /* - * Unlock at this point - no need to hold it across - * ieee80211_free_node() (ie, the comlock) + * We've resolved the sender, so attempt to transmit it. */ - IEEE80211_TX_UNLOCK(ic); - if (error != 0) { - /* NB: IFQ_HANDOFF reclaims mbuf */ - ieee80211_free_node(ni); - } else { - ifp->if_opackets++; - } - ic->ic_lastdata = ticks; - + if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) + return (ENOBUFS); return (0); #undef IS_DWDS } -- cgit v1.1