summaryrefslogtreecommitdiffstats
path: root/sys/net80211
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2013-07-28 04:53:00 +0000
committeradrian <adrian@FreeBSD.org>2013-07-28 04:53:00 +0000
commit7594fa5c70305cda65deedc5cc7e08dc037727cd (patch)
treea6b4077cb0fc95447a6a23ba34674cdef32ca226 /sys/net80211
parent03e98d6f134feab2031878eb43dc371db8602c2c (diff)
downloadFreeBSD-src-7594fa5c70305cda65deedc5cc7e08dc037727cd.zip
FreeBSD-src-7594fa5c70305cda65deedc5cc7e08dc037727cd.tar.gz
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.
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_mesh.c106
-rw-r--r--sys/net80211/ieee80211_output.c266
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
}
OpenPOWER on IntegriCloud