Date: Tue, 19 Feb 2013 07:10:09 -0800 From: Adrian Chadd <adrian@freebsd.org> To: Monthadar Al Jaberi <monthadar@gmail.com> Cc: PseudoCylon <moonlightakkiy@yahoo.ca>, freebsd-wireless@freebsd.org Subject: Re: [RFC] serialising net80211 TX Message-ID: <CAJ-Vmon=SdO66j99dEPT1uSqhmJoNPYVexy-PT0__XTX3My%2BTQ@mail.gmail.com> In-Reply-To: <CAJ-VmomHCz2nEd-GEh2JKoYbfAdsG0xYbAt=j-BqW6D5jHxMeQ@mail.gmail.com> References: <CAFZ_MYJjV=5FtEmWkO7rRBtAuvn2R0Ec=O0ojhPxBfcBuLRUJQ@mail.gmail.com> <CAJ-VmonAXBxuD51y-j5PEt4uGHO_EX15C3inj9wTmR%2BJnb21LA@mail.gmail.com> <CAFZ_MYLswF_3OvEg=uc5GXUAi=EipXmqj-cAWjRC9xi93V-R1Q@mail.gmail.com> <CAJ-Vmon%2BuSKwkEkeiUsC=Gh%2Bk=uVpZdXM5kTKtP_cmfBD0nwjg@mail.gmail.com> <CAJ-VmomMnZ7EM=bgS9NpM_pYDaLQxFg5k2vd7vrdEa4oYx3XNw@mail.gmail.com> <CAJ-Vmo=g5F06dY0p9mOYxY_%2Bh1bLNdQ7%2BukQToU5eb4E%2BNuBuA@mail.gmail.com> <CA%2BsBSoJZ0uQm_M_OZ-eOSCVFtvu7DeboE28JNbLrY15BTcRRhA@mail.gmail.com> <CAJ-Vmo=sJ3Qh8VU%2B99bNr-a3wm5E6e9c=O_qy3w-6ERkVGj5MA@mail.gmail.com> <CAJ-VmomHCz2nEd-GEh2JKoYbfAdsG0xYbAt=j-BqW6D5jHxMeQ@mail.gmail.com>
index | next in thread | previous in thread | raw e-mail
[-- Attachment #1 --]
Here's my current patch. I've tested it lightly in AP mode.
Adrian
[-- Attachment #2 --]
Index: sys/net80211/ieee80211_hwmp.c
===================================================================
--- sys/net80211/ieee80211_hwmp.c (revision 246818)
+++ sys/net80211/ieee80211_hwmp.c (working copy)
@@ -592,6 +592,7 @@
struct ieee80211_bpf_params params;
struct mbuf *m;
uint8_t *frm;
+ int ret;
if (IEEE80211_IS_MULTICAST(da)) {
ni = ieee80211_ref_node(vap->iv_bss);
@@ -669,7 +670,10 @@
else
params.ibp_try0 = ni->ni_txparms->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
Index: sys/net80211/ieee80211_ht.c
===================================================================
--- sys/net80211/ieee80211_ht.c (revision 246818)
+++ sys/net80211/ieee80211_ht.c (working copy)
@@ -2392,7 +2392,9 @@
* ic_raw_xmit will free the node reference
* regardless of queue/TX success or failure.
*/
+ IEEE80211_VAP_TX_LOCK(vap);
ret = ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_VAP_TX_UNLOCK(vap);
if (ret != 0) {
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
ni, "send BAR: failed: (ret = %d)\n",
Index: sys/net80211/ieee80211_mesh.c
===================================================================
--- sys/net80211/ieee80211_mesh.c (revision 246861)
+++ sys/net80211/ieee80211_mesh.c (working copy)
@@ -1046,6 +1046,8 @@
struct ether_header *eh;
int error;
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
eh = mtod(m, struct ether_header *);
ni = ieee80211_mesh_find_txnode(vap, rt_gate->rt_dest);
if (ni == NULL) {
@@ -1132,6 +1134,7 @@
}
}
#endif /* IEEE80211_SUPPORT_SUPERG */
+ IEEE80211_VAP_TX_LOCK(vap);
if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) {
/*
* Encapsulate the packet in prep for transmission.
@@ -1139,11 +1142,13 @@
m = ieee80211_encap(vap, ni, m);
if (m == NULL) {
/* NB: stat+msg handled in ieee80211_encap */
+ IEEE80211_VAP_TX_UNLOCK(vap);
ieee80211_free_node(ni);
return;
}
}
error = parent->if_transmit(parent, m);
+ IEEE80211_VAP_TX_UNLOCK(vap);
if (error != 0) {
m_freem(m);
ieee80211_free_node(ni);
@@ -1174,6 +1179,8 @@
KASSERT( rt_dest->rt_flags == IEEE80211_MESHRT_FLAGS_DISCOVER,
("Route is not marked with IEEE80211_MESHRT_FLAGS_DISCOVER"));
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
/* XXX: send to more than one valid mash gate */
MESH_RT_LOCK(ms);
@@ -2743,6 +2750,7 @@
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_bpf_params params;
struct ieee80211_frame *wh;
+ int ret;
KASSERT(ni != NULL, ("null node"));
@@ -2778,7 +2786,10 @@
IEEE80211_NODE_STAT(ni, tx_mgmt);
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
Index: sys/net80211/ieee80211_wds.c
===================================================================
--- sys/net80211/ieee80211_wds.c (revision 246818)
+++ sys/net80211/ieee80211_wds.c (working copy)
@@ -254,6 +254,10 @@
if (ifp == m->m_pkthdr.rcvif)
continue;
/*
+ * Make sure we don't have the VAP TX lock held here.
+ */
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+ /*
* Duplicate the frame and send it.
*/
mcopy = m_copypacket(m, M_NOWAIT);
@@ -287,16 +291,23 @@
/*
* Encapsulate the packet in prep for transmission.
*/
+ IEEE80211_VAP_TX_LOCK(vap);
mcopy = ieee80211_encap(vap, ni, mcopy);
if (mcopy == NULL) {
/* NB: stat+msg handled in ieee80211_encap */
ieee80211_free_node(ni);
+ IEEE80211_VAP_TX_UNLOCK(vap);
continue;
}
mcopy->m_flags |= M_MCAST;
mcopy->m_pkthdr.rcvif = (void *) ni;
+ /*
+ * Serialise the encapsulation and transmit
+ * with the VAP TX lock.
+ */
err = parent->if_transmit(parent, mcopy);
+ IEEE80211_VAP_TX_UNLOCK(vap);
if (err) {
/* NB: IFQ_HANDOFF reclaims mbuf */
ifp->if_oerrors++;
Index: sys/net80211/ieee80211_output.c
===================================================================
--- sys/net80211/ieee80211_output.c (revision 246818)
+++ sys/net80211/ieee80211_output.c (working copy)
@@ -110,6 +110,252 @@
#endif
/*
+ * Send the given mbuf through the given vap.
+ *
+ * This consumes the mbuf regardless of whether the transmit
+ * was successful or not.
+ *
+ * This does none of the initial checks that ieee80211_start()
+ * does (eg CAC timeout, interface wakeup) - the caller must
+ * do this first.
+ */
+static int
+ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m)
+{
+#define IS_DWDS(vap) \
+ (vap->iv_opmode == IEEE80211_M_WDS && \
+ (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *parent = ic->ic_ifp;
+ struct ifnet *ifp = vap->iv_ifp;
+ struct ieee80211_node *ni;
+ struct ether_header *eh;
+ int error;
+
+ /*
+ * Sanitize mbuf flags for net80211 use. We cannot
+ * clear M_PWR_SAV or M_MORE_DATA because these may
+ * be set for frames that are re-submitted from the
+ * power save queue.
+ *
+ * NB: This must be done before ieee80211_classify as
+ * it marks EAPOL in frames with M_EAPOL.
+ */
+ m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
+ /*
+ * Cancel any background scan.
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_anyscan(vap);
+ /*
+ * Find the node for the destination so we can do
+ * things like power save and fast frames aggregation.
+ *
+ * NB: past this point various code assumes the first
+ * mbuf has the 802.3 header present (and contiguous).
+ */
+ ni = NULL;
+ if (m->m_len < sizeof(struct ether_header) &&
+ (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+ "discard frame, %s\n", "m_pullup failed");
+ vap->iv_stats.is_tx_nobuf++; /* XXX */
+ ifp->if_oerrors++;
+ return (ENOBUFS);
+ }
+ eh = mtod(m, struct ether_header *);
+ if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
+ if (IS_DWDS(vap)) {
+ /*
+ * Only unicast frames from the above go out
+ * DWDS vaps; multicast frames are handled by
+ * dispatching the frame as it comes through
+ * the AP vap (see below).
+ */
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
+ eh->ether_dhost, "mcast", "%s", "on DWDS");
+ vap->iv_stats.is_dwds_mcast++;
+ m_freem(m);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+ /*
+ * Spam DWDS vap's w/ multicast traffic.
+ */
+ /* XXX only if dwds in use? */
+ ieee80211_dwds_mcast(vap, m);
+ }
+ }
+#ifdef IEEE80211_SUPPORT_MESH
+ if (vap->iv_opmode != IEEE80211_M_MBSS) {
+#endif
+ ni = ieee80211_find_txnode(vap, eh->ether_dhost);
+ if (ni == NULL) {
+ /* NB: ieee80211_find_txnode does stat+msg */
+ ifp->if_oerrors++;
+ m_freem(m);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ if (ni->ni_associd == 0 &&
+ (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
+ IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
+ eh->ether_dhost, NULL,
+ "sta not associated (type 0x%04x)",
+ htons(eh->ether_type));
+ vap->iv_stats.is_tx_notassoc++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ ieee80211_free_node(ni);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+#ifdef IEEE80211_SUPPORT_MESH
+ } else {
+ if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
+ /*
+ * Proxy station only if configured.
+ */
+ if (!ieee80211_mesh_isproxyena(vap)) {
+ IEEE80211_DISCARD_MAC(vap,
+ IEEE80211_MSG_OUTPUT |
+ IEEE80211_MSG_MESH,
+ eh->ether_dhost, NULL,
+ "%s", "proxy not enabled");
+ vap->iv_stats.is_mesh_notproxy++;
+ ifp->if_oerrors++;
+ m_freem(m);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+ "forward frame from DS SA(%6D), DA(%6D)\n",
+ eh->ether_shost, ":",
+ eh->ether_dhost, ":");
+ ieee80211_mesh_proxy_check(vap, eh->ether_shost);
+ }
+ ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
+ if (ni == NULL) {
+ /*
+ * NB: ieee80211_mesh_discover holds/disposes
+ * frame (e.g. queueing on path discovery).
+ */
+ ifp->if_oerrors++;
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ }
+#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 */
+ IEEE80211_VAP_TX_LOCK(vap);
+ 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_VAP_TX_UNLOCK(vap);
+ ieee80211_free_node(ni);
+ /* XXX better status? */
+ return (ENOBUFS);
+ }
+ }
+ error = parent->if_transmit(parent, m);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ if (error != 0) {
+ /* NB: IFQ_HANDOFF reclaims mbuf */
+ ieee80211_free_node(ni);
+ } else {
+ ifp->if_opackets++;
+ }
+ ic->ic_lastdata = ticks;
+
+ return (0);
+#undef IS_DWDS
+}
+
+/*
* Start method for vap's. All packets from the stack come
* through here. We handle common processing of the packets
* before dispatching them to the underlying device.
@@ -117,16 +363,10 @@
void
ieee80211_start(struct ifnet *ifp)
{
-#define IS_DWDS(vap) \
- (vap->iv_opmode == IEEE80211_M_WDS && \
- (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0)
struct ieee80211vap *vap = ifp->if_softc;
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *parent = ic->ic_ifp;
- struct ieee80211_node *ni;
struct mbuf *m;
- struct ether_header *eh;
- int error;
/* NB: parent must be up and running */
if (!IFNET_IS_UP_RUNNING(parent)) {
@@ -165,218 +405,14 @@
}
IEEE80211_UNLOCK(ic);
}
+
for (;;) {
IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL)
break;
- /*
- * Sanitize mbuf flags for net80211 use. We cannot
- * clear M_PWR_SAV or M_MORE_DATA because these may
- * be set for frames that are re-submitted from the
- * power save queue.
- *
- * NB: This must be done before ieee80211_classify as
- * it marks EAPOL in frames with M_EAPOL.
- */
- m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA);
- /*
- * Cancel any background scan.
- */
- if (ic->ic_flags & IEEE80211_F_SCAN)
- ieee80211_cancel_anyscan(vap);
- /*
- * Find the node for the destination so we can do
- * things like power save and fast frames aggregation.
- *
- * NB: past this point various code assumes the first
- * mbuf has the 802.3 header present (and contiguous).
- */
- ni = NULL;
- if (m->m_len < sizeof(struct ether_header) &&
- (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
- "discard frame, %s\n", "m_pullup failed");
- vap->iv_stats.is_tx_nobuf++; /* XXX */
- ifp->if_oerrors++;
- continue;
- }
- eh = mtod(m, struct ether_header *);
- if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
- if (IS_DWDS(vap)) {
- /*
- * Only unicast frames from the above go out
- * DWDS vaps; multicast frames are handled by
- * dispatching the frame as it comes through
- * the AP vap (see below).
- */
- IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS,
- eh->ether_dhost, "mcast", "%s", "on DWDS");
- vap->iv_stats.is_dwds_mcast++;
- m_freem(m);
- continue;
- }
- if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
- /*
- * Spam DWDS vap's w/ multicast traffic.
- */
- /* XXX only if dwds in use? */
- ieee80211_dwds_mcast(vap, m);
- }
- }
-#ifdef IEEE80211_SUPPORT_MESH
- if (vap->iv_opmode != IEEE80211_M_MBSS) {
-#endif
- ni = ieee80211_find_txnode(vap, eh->ether_dhost);
- if (ni == NULL) {
- /* NB: ieee80211_find_txnode does stat+msg */
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
- if (ni->ni_associd == 0 &&
- (ni->ni_flags & IEEE80211_NODE_ASSOCID)) {
- IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT,
- eh->ether_dhost, NULL,
- "sta not associated (type 0x%04x)",
- htons(eh->ether_type));
- vap->iv_stats.is_tx_notassoc++;
- ifp->if_oerrors++;
- m_freem(m);
- ieee80211_free_node(ni);
- continue;
- }
-#ifdef IEEE80211_SUPPORT_MESH
- } else {
- if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) {
- /*
- * Proxy station only if configured.
- */
- if (!ieee80211_mesh_isproxyena(vap)) {
- IEEE80211_DISCARD_MAC(vap,
- IEEE80211_MSG_OUTPUT |
- IEEE80211_MSG_MESH,
- eh->ether_dhost, NULL,
- "%s", "proxy not enabled");
- vap->iv_stats.is_mesh_notproxy++;
- ifp->if_oerrors++;
- m_freem(m);
- continue;
- }
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
- "forward frame from DS SA(%6D), DA(%6D)\n",
- eh->ether_shost, ":",
- eh->ether_dhost, ":");
- ieee80211_mesh_proxy_check(vap, eh->ether_shost);
- }
- ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m);
- if (ni == NULL) {
- /*
- * NB: ieee80211_mesh_discover holds/disposes
- * frame (e.g. queueing on path discovery).
- */
- ifp->if_oerrors++;
- continue;
- }
- }
-#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);
- continue;
- }
- /* 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);
- continue;
- }
- /*
- * 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 */
- continue;
- }
- }
-#endif /* IEEE80211_SUPPORT_SUPERG */
- 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_free_node(ni);
- continue;
- }
- }
- error = parent->if_transmit(parent, m);
- if (error != 0) {
- /* NB: IFQ_HANDOFF reclaims mbuf */
- ieee80211_free_node(ni);
- } else {
- ifp->if_opackets++;
- }
- ic->ic_lastdata = ticks;
+ (void) ieee80211_start_pkt(vap, m);
+ /* mbuf is consumed here */
}
-#undef IS_DWDS
}
/*
@@ -393,6 +429,7 @@
struct ieee80211vap *vap;
struct ieee80211_frame *wh;
int error;
+ int ret;
IFQ_LOCK(&ifp->if_snd);
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
@@ -490,14 +527,24 @@
IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len);
/*
+ * Serialise the order of raw frames with the rest of
+ * the normal stack, so things such as sequence and
+ * crypto state assignment are done in the same order
+ * as are passed to the driver (either by if_transmit()
+ * or ic_raw_xmit()).
+ */
+ IEEE80211_VAP_TX_LOCK(vap);
+ /*
* NB: DLT_IEEE802_11_RADIO identifies the parameters are
* present by setting the sa_len field of the sockaddr (yes,
* this is a hack).
* NB: we assume sa_data is suitably aligned to cast.
*/
- return vap->iv_ic->ic_raw_xmit(ni, m,
+ ret = vap->iv_ic->ic_raw_xmit(ni, m,
(const struct ieee80211_bpf_params *)(dst->sa_len ?
dst->sa_data : NULL));
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
bad:
if (m != NULL)
m_freem(m);
@@ -621,6 +668,7 @@
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
+ int ret;
KASSERT(ni != NULL, ("null node"));
@@ -670,7 +718,11 @@
#endif
IEEE80211_NODE_STAT(ni, tx_mgmt);
- return ic->ic_raw_xmit(ni, m, params);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(ni, m, params);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+
+ return (ret);
}
/*
@@ -694,6 +746,7 @@
struct ieee80211_frame *wh;
int hdrlen;
uint8_t *frm;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH,
@@ -771,7 +824,10 @@
ieee80211_chan2ieee(ic, ic->ic_curchan),
wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
- return ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
}
/*
@@ -1035,6 +1091,8 @@
int meshhdrsize, meshae;
uint8_t *qos;
+ IEEE80211_VAP_TX_LOCK_ASSERT(vap);
+
/*
* Copy existing Ethernet header to a safe place. The
* rest of the code assumes it's ok to strip it when
@@ -1806,6 +1864,7 @@
const struct ieee80211_rateset *rs;
struct mbuf *m;
uint8_t *frm;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
@@ -1905,7 +1964,10 @@
} else
params.ibp_try0 = tp->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
}
/*
@@ -2474,6 +2536,7 @@
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_frame *wh;
struct mbuf *m;
+ int ret;
if (vap->iv_state == IEEE80211_S_CAC) {
IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss,
@@ -2517,7 +2580,10 @@
legacy ? " <legacy>" : "");
IEEE80211_NODE_STAT(bss, tx_mgmt);
- return ic->ic_raw_xmit(bss, m, NULL);
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = ic->ic_raw_xmit(bss, m, NULL);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ return (ret);
}
/*
Index: sys/net80211/ieee80211_superg.c
===================================================================
--- sys/net80211/ieee80211_superg.c (revision 246818)
+++ sys/net80211/ieee80211_superg.c (working copy)
@@ -382,6 +382,12 @@
struct mbuf *m;
int pad;
+ /*
+ * This is called from ieee80211_encap() - so the TX lock
+ * is required.
+ */
+ IEEE80211_VAP_TX_LOCK_ASSERT(vap);
+
m2 = m1->m_nextpkt;
if (m2 == NULL) {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
@@ -503,21 +509,27 @@
struct ieee80211vap *vap = ni->ni_vap;
int error;
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
/* encap and xmit */
+ IEEE80211_VAP_TX_LOCK(vap);
m = ieee80211_encap(vap, ni, m);
if (m != NULL) {
struct ifnet *ifp = vap->iv_ifp;
struct ifnet *parent = ni->ni_ic->ic_ifp;
error = parent->if_transmit(parent, m);
+ IEEE80211_VAP_TX_UNLOCK(vap);
if (error != 0) {
/* NB: IFQ_HANDOFF reclaims mbuf */
ieee80211_free_node(ni);
} else {
ifp->if_opackets++;
}
- } else
+ } else {
+ IEEE80211_VAP_TX_UNLOCK(vap);
ieee80211_free_node(ni);
+ }
}
/*
@@ -679,6 +691,8 @@
struct mbuf *mstaged;
uint32_t txtime, limit;
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
/*
* Check if the supplied frame can be aggregated.
*
Index: sys/net80211/ieee80211_freebsd.h
===================================================================
--- sys/net80211/ieee80211_freebsd.h (revision 246818)
+++ sys/net80211/ieee80211_freebsd.h (working copy)
@@ -160,6 +160,32 @@
#define IEEE80211_SCAN_TABLE_UNLOCK(_st) mtx_unlock(&(_st)->st_lock)
/*
+ * VAP transmit state lock definition.
+ */
+typedef struct {
+ char name[16]; /* e.g. "wlan0_tx_lock" */
+ struct mtx mtx;
+} ieee80211_vap_tx_lock_t;
+#define IEEE80211_VAP_TX_LOCK_INIT(_vap, _name) do { \
+ ieee80211_vap_tx_lock_t *txl = &(_vap)->iv_tx_lock; \
+ snprintf(txl->name, sizeof(txl->name), "%s_tx_lock", _name); \
+ mtx_init(&txl->mtx, txl->name, NULL, MTX_DEF); \
+} while (0)
+#define IEEE80211_VAP_TX_LOCK_OBJ(_txl) (&(_txl)->iv_tx_lock.mtx)
+#define IEEE80211_VAP_TX_LOCK_DESTROY(_txl) \
+ mtx_destroy(IEEE80211_VAP_TX_LOCK_OBJ(_txl))
+#define IEEE80211_VAP_TX_LOCK(_txl) \
+ mtx_lock(IEEE80211_VAP_TX_LOCK_OBJ(_txl))
+#define IEEE80211_VAP_TX_IS_LOCKED(_txl) \
+ mtx_owned(IEEE80211_VAP_TX_LOCK_OBJ(_txl))
+#define IEEE80211_VAP_TX_UNLOCK(_txl) \
+ mtx_unlock(IEEE80211_VAP_TX_LOCK_OBJ(_txl))
+#define IEEE80211_VAP_TX_LOCK_ASSERT(_txl) \
+ mtx_assert(IEEE80211_VAP_TX_LOCK_OBJ(_txl), MA_OWNED)
+#define IEEE80211_VAP_TX_UNLOCK_ASSERT(_txl) \
+ mtx_assert(IEEE80211_VAP_TX_LOCK_OBJ(_txl), MA_NOTOWNED)
+
+/*
* Node reference counting definitions.
*
* ieee80211_node_initref initialize the reference count to 1
Index: sys/net80211/ieee80211_power.c
===================================================================
--- sys/net80211/ieee80211_power.c (revision 246818)
+++ sys/net80211/ieee80211_power.c (working copy)
@@ -418,10 +418,13 @@
struct ifnet *parent, *ifp;
struct mbuf *parent_q = NULL, *ifp_q = NULL;
struct mbuf *m;
+ int ret;
IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
"flush ps queue, %u packets queued", psq->psq_len);
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
IEEE80211_PSQ_LOCK(psq);
qhead = &psq->psq_head[0]; /* 802.11 frames */
if (qhead->head != NULL) {
@@ -463,7 +466,10 @@
* For encaped frames, we need to free the node
* reference upon failure.
*/
- if (parent->if_transmit(parent, m) != 0)
+ IEEE80211_VAP_TX_LOCK(vap);
+ ret = parent->if_transmit(parent, m);
+ IEEE80211_VAP_TX_UNLOCK(vap);
+ if (ret != 0)
ieee80211_free_node(ni);
}
}
Index: sys/net80211/ieee80211_var.h
===================================================================
--- sys/net80211/ieee80211_var.h (revision 246818)
+++ sys/net80211/ieee80211_var.h (working copy)
@@ -342,6 +342,8 @@
struct sysctl_ctx_list *iv_sysctl; /* dynamic sysctl context */
struct sysctl_oid *iv_oid; /* net.wlan.X sysctl oid */
+ ieee80211_vap_tx_lock_t iv_tx_lock; /* per-VAP TX serialisation */
+
TAILQ_ENTRY(ieee80211vap) iv_next; /* list of vap instances */
struct ieee80211com *iv_ic; /* back ptr to common state */
uint32_t iv_debug; /* debug msg flags */
@@ -497,6 +499,7 @@
/* 802.3 output method for raw frame xmit */
int (*iv_output)(struct ifnet *, struct mbuf *,
struct sockaddr *, struct route *);
+
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);
Index: sys/net80211/ieee80211_hostap.c
===================================================================
--- sys/net80211/ieee80211_hostap.c (revision 246818)
+++ sys/net80211/ieee80211_hostap.c (working copy)
@@ -354,6 +354,8 @@
struct ether_header *eh = mtod(m, struct ether_header *);
struct ifnet *ifp = vap->iv_ifp;
+ IEEE80211_VAP_TX_UNLOCK_ASSERT(vap);
+
/* clear driver/net80211 flags before passing up */
m->m_flags &= ~(M_80211_RX | M_MCAST | M_BCAST);
@@ -412,6 +414,7 @@
if (mcopy != NULL) {
int len, err;
len = mcopy->m_pkthdr.len;
+ /* VAP transmit */
err = ifp->if_transmit(ifp, mcopy);
if (err) {
/* NB: IFQ_HANDOFF reclaims mcopy */
@@ -437,6 +440,7 @@
m->m_pkthdr.ether_vtag = ni->ni_vlan;
m->m_flags |= M_VLANTAG;
}
+ /* VAP transmit */
ifp->if_input(ifp, m);
}
}
Index: sys/net80211/ieee80211.c
===================================================================
--- sys/net80211/ieee80211.c (revision 246818)
+++ sys/net80211/ieee80211.c (working copy)
@@ -511,6 +511,8 @@
IEEE80211_ADDR_COPY(vap->iv_myaddr, macaddr);
+ IEEE80211_VAP_TX_LOCK_INIT(vap, if_name(vap->iv_ifp));
+
ieee80211_sysctl_vattach(vap);
ieee80211_crypto_vattach(vap);
ieee80211_node_vattach(vap);
@@ -657,6 +659,8 @@
ieee80211_node_vdetach(vap);
ieee80211_sysctl_vdetach(vap);
+ IEEE80211_VAP_TX_LOCK_DESTROY(vap);
+
if_free(ifp);
CURVNET_RESTORE();
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmon=SdO66j99dEPT1uSqhmJoNPYVexy-PT0__XTX3My%2BTQ>
