svn commit: r247261 - in user/adrian/net80211_tx/sys: dev/ath dev/iwn net80211
Adrian Chadd
adrian at FreeBSD.org
Mon Feb 25 10:30:28 UTC 2013
Author: adrian
Date: Mon Feb 25 10:30:25 2013
New Revision: 247261
URL: http://svnweb.freebsd.org/changeset/base/247261
Log:
Introduce a new net80211 TX IC lock, to serialise both the VAP and
the IC frame processing.
This is a temporary(ish) thing, mostly to get the TX handling "correct"
for now.
The overview:
* The TX IC lock is grabbed before any vap or raw xmit calls occur that
invoke the 802.11 setup path;
* it explicitly occurs _before_ fast frame queuing and ampdu handling -
+ the ff queuing may or may not pair it with a second frame, and go
through the encap path;
+ the ampdu path can actually send a management frame at this point,
so this avoids a recursive call.
* modify iwn and ath TX path to grab the net80211 TX lock if the driver
TX start path is called deferred - eg, during reset, or TX completion.
This ensures that the same locking is done and in the same order.
It's inefficient but hopefully (!) correct enough to stop all of the
subtle races..
Modified:
user/adrian/net80211_tx/sys/dev/ath/if_ath.c
user/adrian/net80211_tx/sys/dev/ath/if_ath_misc.h
user/adrian/net80211_tx/sys/dev/ath/if_ath_tx.c
user/adrian/net80211_tx/sys/dev/iwn/if_iwn.c
user/adrian/net80211_tx/sys/net80211/ieee80211.c
user/adrian/net80211_tx/sys/net80211/ieee80211_freebsd.h
user/adrian/net80211_tx/sys/net80211/ieee80211_ht.c
user/adrian/net80211_tx/sys/net80211/ieee80211_hwmp.c
user/adrian/net80211_tx/sys/net80211/ieee80211_mesh.c
user/adrian/net80211_tx/sys/net80211/ieee80211_output.c
user/adrian/net80211_tx/sys/net80211/ieee80211_superg.c
user/adrian/net80211_tx/sys/net80211/ieee80211_var.h
Modified: user/adrian/net80211_tx/sys/dev/ath/if_ath.c
==============================================================================
--- user/adrian/net80211_tx/sys/dev/ath/if_ath.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/dev/ath/if_ath.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -2525,9 +2525,14 @@ static void
ath_start_queue(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ IEEE80211_TX_LOCK_ASSERT(ic);
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start_queue: start");
- ath_tx_kick(sc);
+ ATH_TX_LOCK(sc);
+ ath_start(ifp);
+ ATH_TX_UNLOCK(sc);
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start_queue: finished");
}
@@ -2535,6 +2540,7 @@ void
ath_start_task(void *arg, int npending)
{
struct ath_softc *sc = (struct ath_softc *) arg;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct ifnet *ifp = sc->sc_ifp;
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start_task: start");
@@ -2555,9 +2561,11 @@ ath_start_task(void *arg, int npending)
sc->sc_txstart_cnt++;
ATH_PCU_UNLOCK(sc);
+ IEEE80211_TX_LOCK(ic);
ATH_TX_LOCK(sc);
ath_start(sc->sc_ifp);
ATH_TX_UNLOCK(sc);
+ IEEE80211_TX_UNLOCK(ic);
ATH_PCU_LOCK(sc);
sc->sc_txstart_cnt--;
@@ -2569,6 +2577,7 @@ void
ath_start(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211_node *ni;
struct ath_buf *bf;
struct mbuf *m, *next;
@@ -2578,6 +2587,7 @@ ath_start(struct ifnet *ifp)
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
return;
+ IEEE80211_TX_LOCK_ASSERT(ic);
ATH_TX_LOCK_ASSERT(sc);
ATH_KTR(sc, ATH_KTR_TX, 0, "ath_start: called");
Modified: user/adrian/net80211_tx/sys/dev/ath/if_ath_misc.h
==============================================================================
--- user/adrian/net80211_tx/sys/dev/ath/if_ath_misc.h Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/dev/ath/if_ath_misc.h Mon Feb 25 10:30:25 2013 (r247261)
@@ -126,10 +126,16 @@ extern void ath_start_task(void *arg, in
static inline void
ath_tx_kick(struct ath_softc *sc)
{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+ ATH_TX_UNLOCK_ASSERT(sc);
+
+ IEEE80211_TX_LOCK(ic);
ATH_TX_LOCK(sc);
ath_start(sc->sc_ifp);
ATH_TX_UNLOCK(sc);
+ IEEE80211_TX_UNLOCK(ic);
}
/*
Modified: user/adrian/net80211_tx/sys/dev/ath/if_ath_tx.c
==============================================================================
--- user/adrian/net80211_tx/sys/dev/ath/if_ath_tx.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/dev/ath/if_ath_tx.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -1772,6 +1772,7 @@ ath_tx_start(struct ath_softc *sc, struc
struct ath_buf *bf, struct mbuf *m0)
{
struct ieee80211vap *vap = ni->ni_vap;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
struct ath_vap *avp = ATH_VAP(vap);
int r = 0;
u_int pri;
@@ -1784,6 +1785,7 @@ ath_tx_start(struct ath_softc *sc, struc
uint8_t type, subtype;
ATH_TX_LOCK_ASSERT(sc);
+ IEEE80211_TX_LOCK_ASSERT(ic);
/*
* Determine the target hardware queue.
@@ -1971,6 +1973,7 @@ ath_tx_raw_start(struct ath_softc *sc, s
int do_override;
ATH_TX_LOCK_ASSERT(sc);
+ IEEE80211_TX_LOCK_ASSERT(ic);
wh = mtod(m0, struct ieee80211_frame *);
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
@@ -4996,8 +4999,15 @@ void
ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_tid *tid, *next, *last;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
ATH_TX_LOCK_ASSERT(sc);
+ /*
+ * This shouldn't be directly called from the TX queue
+ * code path; it should be called from the TX completion
+ * or TX kick task.
+ */
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
/*
* Don't schedule if the hardware queue is busy.
Modified: user/adrian/net80211_tx/sys/dev/iwn/if_iwn.c
==============================================================================
--- user/adrian/net80211_tx/sys/dev/iwn/if_iwn.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/dev/iwn/if_iwn.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -2716,6 +2716,7 @@ iwn_tx_done(struct iwn_softc *sc, struct
struct mbuf *m;
struct ieee80211_node *ni;
struct ieee80211vap *vap;
+ struct ieee80211com *ic = ifp->if_l2com;
KASSERT(data->ni != NULL, ("no node"));
@@ -2770,7 +2771,16 @@ iwn_tx_done(struct iwn_softc *sc, struct
if (sc->qfullmsk == 0 &&
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ /*
+ * XXX turn this into a deferred taskqueue at some point.
+ */
+ IWN_UNLOCK(sc);
+
+ IEEE80211_TX_LOCK(ic);
+ IWN_LOCK(sc);
iwn_start_locked(ifp);
+ IWN_UNLOCK(sc);
+ IEEE80211_TX_UNLOCK(ic);
}
}
}
@@ -2807,6 +2817,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc,
{
struct iwn_ops *ops = &sc->ops;
struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
struct iwn_tx_ring *ring = &sc->txq[qid];
struct iwn_tx_data *data;
struct mbuf *m;
@@ -2903,6 +2914,18 @@ iwn_ampdu_tx_done(struct iwn_softc *sc,
if (sc->qfullmsk == 0 &&
(ifp->if_drv_flags & IFF_DRV_OACTIVE)) {
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ /*
+ * XXX turn this into a deferred taskqueue at some point.
+ */
+ IWN_UNLOCK(sc);
+
+ IEEE80211_TX_LOCK(ic);
+ IWN_LOCK(sc);
+ iwn_start_locked(ifp);
+ IWN_UNLOCK(sc);
+ IEEE80211_TX_UNLOCK(ic);
+
iwn_start_locked(ifp);
}
}
@@ -3850,6 +3873,9 @@ static void
iwn_start(struct ifnet *ifp)
{
struct iwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ IEEE80211_TX_LOCK_ASSERT(ic);
IWN_LOCK(sc);
iwn_start_locked(ifp);
@@ -3860,10 +3886,12 @@ static void
iwn_start_locked(struct ifnet *ifp)
{
struct iwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211_node *ni;
struct mbuf *m;
IWN_LOCK_ASSERT(sc);
+ IEEE80211_TX_LOCK_ASSERT(ic);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
(ifp->if_drv_flags & IFF_DRV_OACTIVE))
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -278,6 +278,7 @@ ieee80211_ifattach(struct ieee80211com *
KASSERT(ifp->if_type == IFT_IEEE80211, ("if_type %d", ifp->if_type));
IEEE80211_LOCK_INIT(ic, ifp->if_xname);
+ IEEE80211_TX_LOCK_INIT(ic, ifp->if_xname);
TAILQ_INIT(&ic->ic_vaps);
/* Create a taskqueue for all state changes */
@@ -385,6 +386,7 @@ ieee80211_ifdetach(struct ieee80211com *
ifmedia_removeall(&ic->ic_media);
taskqueue_free(ic->ic_tq);
+ IEEE80211_TX_LOCK_DESTROY(ic);
IEEE80211_LOCK_DESTROY(ic);
}
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_freebsd.h
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_freebsd.h Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_freebsd.h Mon Feb 25 10:30:25 2013 (r247261)
@@ -57,6 +57,30 @@ typedef struct {
mtx_assert(IEEE80211_LOCK_OBJ(_ic), MA_NOTOWNED)
/*
+ * Transmit lock.
+ *
+ * This is a (mostly) temporary lock designed to serialise all of the
+ * transmission operations throughout the stack.
+ */
+typedef struct {
+ char name[16]; /* e.g. "ath0_com_lock" */
+ struct mtx mtx;
+} ieee80211_tx_lock_t;
+#define IEEE80211_TX_LOCK_INIT(_ic, _name) do { \
+ ieee80211_tx_lock_t *cl = &(_ic)->ic_txlock; \
+ snprintf(cl->name, sizeof(cl->name), "%s_tx_lock", _name); \
+ mtx_init(&cl->mtx, cl->name, NULL, MTX_DEF); \
+} while (0)
+#define IEEE80211_TX_LOCK_OBJ(_ic) (&(_ic)->ic_txlock.mtx)
+#define IEEE80211_TX_LOCK_DESTROY(_ic) mtx_destroy(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_LOCK(_ic) mtx_lock(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_UNLOCK(_ic) mtx_unlock(IEEE80211_TX_LOCK_OBJ(_ic))
+#define IEEE80211_TX_LOCK_ASSERT(_ic) \
+ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_OWNED)
+#define IEEE80211_TX_UNLOCK_ASSERT(_ic) \
+ mtx_assert(IEEE80211_TX_LOCK_OBJ(_ic), MA_NOTOWNED)
+
+/*
* Node locking definitions.
*/
typedef struct {
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_ht.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_ht.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_ht.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -2392,7 +2392,9 @@ ieee80211_send_bar(struct ieee80211_node
* ic_raw_xmit will free the node reference
* regardless of queue/TX success or failure.
*/
+ IEEE80211_TX_LOCK(ic);
ret = ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
if (ret != 0) {
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
ni, "send BAR: failed: (ret = %d)\n",
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_hwmp.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_hwmp.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_hwmp.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -592,6 +592,7 @@ hwmp_send_action(struct ieee80211vap *va
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);
@@ -654,6 +655,9 @@ hwmp_send_action(struct ieee80211vap *va
vap->iv_stats.is_tx_nobuf++;
return ENOMEM;
}
+
+ IEEE80211_TX_LOCK(ic);
+
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
IEEE80211_NONQOS_TID, vap->iv_myaddr, da, vap->iv_myaddr);
@@ -669,7 +673,9 @@ hwmp_send_action(struct ieee80211vap *va
else
params.ibp_try0 = ni->ni_txparms->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_mesh.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_mesh.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_mesh.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -2743,6 +2743,7 @@ mesh_send_action(struct ieee80211_node *
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_bpf_params params;
struct ieee80211_frame *wh;
+ int ret;
KASSERT(ni != NULL, ("null node"));
@@ -2761,6 +2762,7 @@ mesh_send_action(struct ieee80211_node *
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ACTION,
@@ -2778,7 +2780,9 @@ mesh_send_action(struct ieee80211_node *
IEEE80211_NODE_STAT(ni, tx_mgmt);
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
#define ADDSHORT(frm, v) do { \
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_output.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_output.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_output.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -282,6 +282,7 @@ ieee80211_start_pkt(struct ieee80211vap
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
@@ -317,6 +318,7 @@ ieee80211_start_pkt(struct ieee80211vap
/* 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);
@@ -327,6 +329,14 @@ ieee80211_start_pkt(struct ieee80211vap
}
}
#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.
@@ -334,12 +344,19 @@ ieee80211_start_pkt(struct ieee80211vap
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 = parent->if_transmit(parent, 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);
@@ -425,7 +442,9 @@ ieee80211_output(struct ifnet *ifp, stru
struct ieee80211_node *ni = NULL;
struct ieee80211vap *vap;
struct ieee80211_frame *wh;
+ struct ieee80211com *ic = NULL;
int error;
+ int ret;
IFQ_LOCK(&ifp->if_snd);
if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
@@ -442,6 +461,7 @@ ieee80211_output(struct ifnet *ifp, stru
}
IFQ_UNLOCK(&ifp->if_snd);
vap = ifp->if_softc;
+ ic = vap->iv_ic;
/*
* Hand to the 802.3 code if not tagged as
* a raw 802.11 frame.
@@ -522,15 +542,19 @@ ieee80211_output(struct ifnet *ifp, stru
/* NB: ieee80211_encap does not include 802.11 header */
IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len);
+ IEEE80211_TX_LOCK(ic);
+
/*
* 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_TX_UNLOCK(ic);
+ return (ret);
bad:
if (m != NULL)
m_freem(m);
@@ -559,8 +583,11 @@ ieee80211_send_setup(
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211_tx_ampdu *tap;
struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *);
+ struct ieee80211com *ic = ni->ni_ic;
ieee80211_seq seqno;
+ IEEE80211_TX_LOCK_ASSERT(ic);
+
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
switch (vap->iv_opmode) {
@@ -654,6 +681,7 @@ ieee80211_mgmt_output(struct ieee80211_n
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211_frame *wh;
+ int ret;
KASSERT(ni != NULL, ("null node"));
@@ -675,6 +703,8 @@ ieee80211_mgmt_output(struct ieee80211_n
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
+
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID,
@@ -703,7 +733,9 @@ ieee80211_mgmt_output(struct ieee80211_n
#endif
IEEE80211_NODE_STAT(ni, tx_mgmt);
- return ic->ic_raw_xmit(ni, m, params);
+ ret = ic->ic_raw_xmit(ni, m, params);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -727,6 +759,7 @@ ieee80211_send_nulldata(struct ieee80211
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,
@@ -762,6 +795,8 @@ ieee80211_send_nulldata(struct ieee80211
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
+
wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */
if (ni->ni_flags & IEEE80211_NODE_QOS) {
const int tid = WME_AC_TO_TID(WME_AC_BE);
@@ -804,7 +839,9 @@ ieee80211_send_nulldata(struct ieee80211
ieee80211_chan2ieee(ic, ic->ic_curchan),
wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
- return ic->ic_raw_xmit(ni, m, NULL);
+ ret = ic->ic_raw_xmit(ni, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -1067,6 +1104,8 @@ ieee80211_encap(struct ieee80211vap *vap
ieee80211_seq seqno;
int meshhdrsize, meshae;
uint8_t *qos;
+
+ IEEE80211_TX_LOCK_ASSERT(ic);
/*
* Copy existing Ethernet header to a safe place. The
@@ -1839,6 +1878,7 @@ ieee80211_send_probereq(struct ieee80211
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,
@@ -1911,6 +1951,7 @@ ieee80211_send_probereq(struct ieee80211
return ENOMEM;
}
+ IEEE80211_TX_LOCK(ic);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(ni, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
@@ -1938,7 +1979,9 @@ ieee80211_send_probereq(struct ieee80211
} else
params.ibp_try0 = tp->maxretry;
params.ibp_power = ni->ni_txpower;
- return ic->ic_raw_xmit(ni, m, ¶ms);
+ ret = ic->ic_raw_xmit(ni, m, ¶ms);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
@@ -2507,6 +2550,7 @@ ieee80211_send_proberesp(struct ieee8021
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,
@@ -2535,6 +2579,7 @@ ieee80211_send_proberesp(struct ieee8021
M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT);
KASSERT(m != NULL, ("no room for header"));
+ IEEE80211_TX_LOCK(ic);
wh = mtod(m, struct ieee80211_frame *);
ieee80211_send_setup(bss, m,
IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP,
@@ -2550,7 +2595,9 @@ ieee80211_send_proberesp(struct ieee8021
legacy ? " <legacy>" : "");
IEEE80211_NODE_STAT(bss, tx_mgmt);
- return ic->ic_raw_xmit(bss, m, NULL);
+ ret = ic->ic_raw_xmit(bss, m, NULL);
+ IEEE80211_TX_UNLOCK(ic);
+ return (ret);
}
/*
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_superg.c
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_superg.c Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_superg.c Mon Feb 25 10:30:25 2013 (r247261)
@@ -503,6 +503,8 @@ ff_transmit(struct ieee80211_node *ni, s
struct ieee80211vap *vap = ni->ni_vap;
int error;
+ IEEE80211_TX_LOCK_ASSERT(vap->iv_ic);
+
/* encap and xmit */
m = ieee80211_encap(vap, ni, m);
if (m != NULL) {
@@ -532,6 +534,8 @@ ff_flush(struct mbuf *head, struct mbuf
struct ieee80211_node *ni;
struct ieee80211vap *vap;
+ IEEE80211_TX_LOCK_ASSERT(vap->iv_ic);
+
for (m = head; m != last; m = next) {
next = m->m_nextpkt;
m->m_nextpkt = NULL;
@@ -590,7 +594,9 @@ ieee80211_ff_age(struct ieee80211com *ic
M_AGE_SUB(m, quanta);
IEEE80211_UNLOCK(ic);
+ IEEE80211_TX_LOCK(ic);
ff_flush(head, m);
+ IEEE80211_TX_UNLOCK(ic);
}
static void
@@ -679,6 +685,8 @@ ieee80211_ff_check(struct ieee80211_node
struct mbuf *mstaged;
uint32_t txtime, limit;
+ IEEE80211_TX_UNLOCK_ASSERT(ic);
+
/*
* Check if the supplied frame can be aggregated.
*
@@ -734,10 +742,12 @@ ieee80211_ff_check(struct ieee80211_node
IEEE80211_UNLOCK(ic);
if (mstaged != NULL) {
+ IEEE80211_TX_LOCK(ic);
IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
"%s: flush staged frame", __func__);
/* encap and xmit */
ff_transmit(ni, mstaged);
+ IEEE80211_TX_UNLOCK(ic);
}
return m; /* NB: original frame */
}
Modified: user/adrian/net80211_tx/sys/net80211/ieee80211_var.h
==============================================================================
--- user/adrian/net80211_tx/sys/net80211/ieee80211_var.h Mon Feb 25 10:07:54 2013 (r247260)
+++ user/adrian/net80211_tx/sys/net80211/ieee80211_var.h Mon Feb 25 10:30:25 2013 (r247261)
@@ -118,6 +118,7 @@ struct ieee80211_frame;
struct ieee80211com {
struct ifnet *ic_ifp; /* associated device */
ieee80211_com_lock_t ic_comlock; /* state update lock */
+ ieee80211_tx_lock_t ic_txlock; /* ic/vap TX lock */
TAILQ_HEAD(, ieee80211vap) ic_vaps; /* list of vap instances */
int ic_headroom; /* driver tx headroom needs */
enum ieee80211_phytype ic_phytype; /* XXX wrong for multi-mode */
More information about the svn-src-user
mailing list