summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2007-06-11 03:36:55 +0000
committersam <sam@FreeBSD.org>2007-06-11 03:36:55 +0000
commit6a8b18f11591df29764d02a686661d87559bf7f6 (patch)
treee13543d4810ca316d27ca22651054eea880c1d34 /sys/dev
parenta9a2aaf8ad63975b1a3595ae20df675a7c6336c6 (diff)
downloadFreeBSD-src-6a8b18f11591df29764d02a686661d87559bf7f6.zip
FreeBSD-src-6a8b18f11591df29764d02a686661d87559bf7f6.tar.gz
Update 802.11 wireless support:
o major overhaul of the way channels are handled: channels are now fully enumerated and uniquely identify the operating characteristics; these changes are visible to user applications which require changes o make scanning support independent of the state machine to enable background scanning and roaming o move scanning support into loadable modules based on the operating mode to enable different policies and reduce the memory footprint on systems w/ constrained resources o add background scanning in station mode (no support for adhoc/ibss mode yet) o significantly speedup sta mode scanning with a variety of techniques o add roaming support when background scanning is supported; for now we use a simple algorithm to trigger a roam: we threshold the rssi and tx rate, if either drops too low we try to roam to a new ap o add tx fragmentation support o add first cut at 802.11n support: this code works with forthcoming drivers but is incomplete; it's included now to establish a baseline for other drivers to be developed and for user applications o adjust max_linkhdr et. al. to reflect 802.11 requirements; this eliminates prepending mbufs for traffic generated locally o add support for Atheros protocol extensions; mainly the fast frames encapsulation (note this can be used with any card that can tx+rx large frames correctly) o add sta support for ap's that beacon both WPA1+2 support o change all data types from bsd-style to posix-style o propagate noise floor data from drivers to net80211 and on to user apps o correct various issues in the sta mode state machine related to handling authentication and association failures o enable the addition of sta mode power save support for drivers that need net80211 support (not in this commit) o remove old WI compatibility ioctls (wicontrol is officially dead) o change the data structures returned for get sta info and get scan results so future additions will not break user apps o fixed tx rate is now maintained internally as an ieee rate and not an index into the rate set; this needs to be extended to deal with multi-mode operation o add extended channel specifications to radiotap to enable 11n sniffing Drivers: o ath: add support for bg scanning, tx fragmentation, fast frames, dynamic turbo (lightly tested), 11n (sniffing only and needs new hal) o awi: compile tested only o ndis: lightly tested o ipw: lightly tested o iwi: add support for bg scanning (well tested but may have some rough edges) o ral, ural, rum: add suppoort for bg scanning, calibrate rssi data o wi: lightly tested This work is based on contributions by Atheros, kmacy, sephe, thompsa, mlaier, kevlo, and others. Much of the scanning work was supported by Atheros. The 11n work was supported by Marvell.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ath/ath_rate/amrr/amrr.c20
-rw-r--r--sys/dev/ath/ath_rate/onoe/onoe.c20
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.c21
-rw-r--r--sys/dev/ath/if_ath.c1089
-rw-r--r--sys/dev/ath/if_athioctl.h38
-rw-r--r--sys/dev/ath/if_athvar.h56
-rw-r--r--sys/dev/awi/awi.c55
-rw-r--r--sys/dev/awi/awivar.h2
-rw-r--r--sys/dev/if_ndis/if_ndis.c35
-rw-r--r--sys/dev/ipw/if_ipw.c37
-rw-r--r--sys/dev/iwi/if_iwi.c866
-rw-r--r--sys/dev/iwi/if_iwireg.h6
-rw-r--r--sys/dev/iwi/if_iwivar.h74
-rw-r--r--sys/dev/ral/if_ral_pci.c16
-rw-r--r--sys/dev/ral/rt2560.c318
-rw-r--r--sys/dev/ral/rt2560reg.h4
-rw-r--r--sys/dev/ral/rt2560var.h13
-rw-r--r--sys/dev/ral/rt2661.c304
-rw-r--r--sys/dev/ral/rt2661reg.h2
-rw-r--r--sys/dev/ral/rt2661var.h10
-rw-r--r--sys/dev/usb/if_rum.c272
-rw-r--r--sys/dev/usb/if_rumreg.h2
-rw-r--r--sys/dev/usb/if_rumvar.h7
-rw-r--r--sys/dev/usb/if_ural.c230
-rw-r--r--sys/dev/usb/if_uralreg.h3
-rw-r--r--sys/dev/usb/if_uralvar.h9
-rw-r--r--sys/dev/wi/if_wi.c370
-rw-r--r--sys/dev/wi/if_wivar.h10
28 files changed, 2626 insertions, 1263 deletions
diff --git a/sys/dev/ath/ath_rate/amrr/amrr.c b/sys/dev/ath/ath_rate/amrr/amrr.c
index fc72abf..da564a8 100644
--- a/sys/dev/ath/ath_rate/amrr/amrr.c
+++ b/sys/dev/ath/ath_rate/amrr/amrr.c
@@ -297,27 +297,27 @@ ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
/* NB: the rate set is assumed sorted */
for (; srate >= 0 && RATE(srate) > 72; srate--)
;
- KASSERT(srate >= 0, ("bogus rate set"));
}
} else {
/*
- * A fixed rate is to be used; ic_fixed_rate is an
- * index into the supported rate set. Convert this
+ * A fixed rate is to be used; ic_fixed_rate is the
+ * IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node. We know the rate is there because the
* rate set is checked when the station associates.
*/
- const struct ieee80211_rateset *rs =
- &ic->ic_sup_rates[ic->ic_curmode];
- int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
- for (; srate >= 0 && RATE(srate) != r; srate--)
+ for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
- KASSERT(srate >= 0,
- ("fixed rate %d not in rate set", ic->ic_fixed_rate));
}
- ath_rate_update(sc, ni, srate);
+ /*
+ * The selected rate may not be available due to races
+ * and mode settings. Also orphaned nodes created in
+ * adhoc mode may not have any rate set so this lookup
+ * can fail. This is not fatal.
+ */
+ ath_rate_update(sc, ni, srate < 0 ? 0 : srate);
#undef RATE
}
diff --git a/sys/dev/ath/ath_rate/onoe/onoe.c b/sys/dev/ath/ath_rate/onoe/onoe.c
index b682a47..281e4f1 100644
--- a/sys/dev/ath/ath_rate/onoe/onoe.c
+++ b/sys/dev/ath/ath_rate/onoe/onoe.c
@@ -274,27 +274,27 @@ ath_rate_ctl_start(struct ath_softc *sc, struct ieee80211_node *ni)
/* NB: the rate set is assumed sorted */
for (; srate >= 0 && RATE(srate) > 72; srate--)
;
- KASSERT(srate >= 0, ("bogus rate set"));
}
} else {
/*
- * A fixed rate is to be used; ic_fixed_rate is an
- * index into the supported rate set. Convert this
+ * A fixed rate is to be used; ic_fixed_rate is the
+ * IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node. We know the rate is there because the
* rate set is checked when the station associates.
*/
- const struct ieee80211_rateset *rs =
- &ic->ic_sup_rates[ic->ic_curmode];
- int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
- for (; srate >= 0 && RATE(srate) != r; srate--)
+ for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
- KASSERT(srate >= 0,
- ("fixed rate %d not in rate set", ic->ic_fixed_rate));
}
- ath_rate_update(sc, ni, srate);
+ /*
+ * The selected rate may not be available due to races
+ * and mode settings. Also orphaned nodes created in
+ * adhoc mode may not have any rate set so this lookup
+ * can fail. This is not fatal.
+ */
+ ath_rate_update(sc, ni, srate < 0 ? 0 : srate);
#undef RATE
}
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c
index 6cf564e..180ef82 100644
--- a/sys/dev/ath/ath_rate/sample/sample.c
+++ b/sys/dev/ath/ath_rate/sample/sample.c
@@ -32,6 +32,7 @@
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
+ *
*/
#include <sys/cdefs.h>
@@ -680,21 +681,23 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
sn->static_rate_ndx = -1;
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
/*
- * A fixed rate is to be used; ic_fixed_rate is an
- * index into the supported rate set. Convert this
+ * A fixed rate is to be used; ic_fixed_rate is the
+ * IEEE code for this rate (sans basic bit). Convert this
* to the index into the negotiated rate set for
* the node.
*/
- const struct ieee80211_rateset *rs =
- &ic->ic_sup_rates[ic->ic_curmode];
- int r = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* NB: the rate set is assumed sorted */
srate = ni->ni_rates.rs_nrates - 1;
- for (; srate >= 0 && RATE(srate) != r; srate--)
+ for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
;
- KASSERT(srate >= 0,
- ("fixed rate %d not in rate set", ic->ic_fixed_rate));
- sn->static_rate_ndx = srate;
+ /*
+ * The fixed rate may not be available due to races
+ * and mode settings. Also orphaned nodes created in
+ * adhoc mode may not have any rate set so this lookup
+ * can fail.
+ */
+ if (srate >= 0)
+ sn->static_rate_ndx = srate;
}
DPRINTF(sc, ATH_DEBUG_RATE, "%s: %s size 1600 rate/tt",
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index caaa939..2841e8e 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -135,11 +135,13 @@ static int ath_desc_alloc(struct ath_softc *);
static void ath_desc_free(struct ath_softc *);
static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
static void ath_node_free(struct ieee80211_node *);
-static u_int8_t ath_node_getrssi(const struct ieee80211_node *);
+static int8_t ath_node_getrssi(const struct ieee80211_node *);
+static void ath_node_getsignal(const struct ieee80211_node *,
+ int8_t *, int8_t *);
static int ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
static void ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
struct ieee80211_node *ni,
- int subtype, int rssi, u_int32_t rstamp);
+ int subtype, int rssi, int noise, u_int32_t rstamp);
static void ath_setdefantenna(struct ath_softc *, u_int);
static void ath_rx_proc(void *, int);
static void ath_txq_init(struct ath_softc *sc, struct ath_txq *, int);
@@ -148,6 +150,7 @@ static int ath_tx_setup(struct ath_softc *, int, int);
static int ath_wme_update(struct ieee80211com *);
static void ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
static void ath_tx_cleanup(struct ath_softc *);
+static void ath_freetx(struct mbuf *);
static int ath_tx_start(struct ath_softc *, struct ieee80211_node *,
struct ath_buf *, struct mbuf *);
static void ath_tx_proc_q0(void *, int);
@@ -158,7 +161,9 @@ static void ath_draintxq(struct ath_softc *);
static void ath_stoprecv(struct ath_softc *);
static int ath_startrecv(struct ath_softc *);
static void ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
-static void ath_next_scan(void *);
+static void ath_scan_start(struct ieee80211com *);
+static void ath_scan_end(struct ieee80211com *);
+static void ath_set_channel(struct ieee80211com *);
static void ath_calibrate(void *);
static int ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
static void ath_setup_stationkey(struct ieee80211_node *);
@@ -180,9 +185,6 @@ static void ath_announce(struct ath_softc *);
SYSCTL_DECL(_hw_ath);
/* XXX validate sysctl values */
-static int ath_dwelltime = 200; /* 5 channels/second */
-SYSCTL_INT(_hw_ath, OID_AUTO, dwell, CTLFLAG_RW, &ath_dwelltime,
- 0, "channel dwell time (ms) for AP/station scanning");
static int ath_calinterval = 30; /* calibrate every 30 secs */
SYSCTL_INT(_hw_ath, OID_AUTO, calibrate, CTLFLAG_RW, &ath_calinterval,
0, "chip calibration interval (secs)");
@@ -345,7 +347,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
* like the phy mode.
*/
error = ath_getchannels(sc, ath_regdomain, ath_countrycode,
- ath_xchanmode != 0, ath_outdoor != 0);
+ ath_outdoor != 0, ath_xchanmode != 0);
if (error != 0)
goto bad;
@@ -357,6 +359,9 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ath_rate_setup(sc, IEEE80211_MODE_11G);
ath_rate_setup(sc, IEEE80211_MODE_TURBO_A);
ath_rate_setup(sc, IEEE80211_MODE_TURBO_G);
+ ath_rate_setup(sc, IEEE80211_MODE_STURBO_A);
+ ath_rate_setup(sc, IEEE80211_MODE_11NA);
+ ath_rate_setup(sc, IEEE80211_MODE_11NG);
ath_rate_setup(sc, IEEE80211_MODE_HALF);
ath_rate_setup(sc, IEEE80211_MODE_QUARTER);
@@ -371,7 +376,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if_printf(ifp, "failed to allocate descriptors: %d\n", error);
goto bad;
}
- callout_init(&sc->sc_scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE);
callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE);
@@ -419,7 +423,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
if (!ath_tx_setup(sc, WME_AC_BE, HAL_WME_AC_BE) ||
!ath_tx_setup(sc, WME_AC_VI, HAL_WME_AC_VI) ||
!ath_tx_setup(sc, WME_AC_VO, HAL_WME_AC_VO)) {
- /*
+ /*
* Not enough hardware tx queues to properly do WME;
* just punt and assign them all to the same h/w queue.
* We could do a better job of this if, for example,
@@ -435,7 +439,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
sc->sc_ac2q[WME_AC_VO] = sc->sc_ac2q[WME_AC_BK];
}
- /*
+ /*
* Special case certain configurations. Note the
* CAB queue is handled by these specially so don't
* include them when checking the txq setup mask.
@@ -507,6 +511,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
| IEEE80211_C_SHPREAMBLE /* short preamble supported */
| IEEE80211_C_SHSLOT /* short slot time supported */
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ | IEEE80211_C_BGSCAN /* capable of bg scanning */
+ | IEEE80211_C_TXFRAG /* handle tx frags */
;
/*
* Query the hal to figure out h/w crypto support.
@@ -571,6 +577,10 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
*/
if (ath_hal_hasbursting(ah))
ic->ic_caps |= IEEE80211_C_BURST;
+ if (ath_hal_hasfastframes(ah))
+ ic->ic_caps |= IEEE80211_C_FF;
+ if (ath_hal_getwirelessmodes(ah, ath_countrycode) & (HAL_MODE_108G|HAL_MODE_TURBO))
+ ic->ic_caps |= IEEE80211_C_TURBOP;
/*
* Indicate we need the 802.11 header padded to a
@@ -600,10 +610,14 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = ath_node_free;
ic->ic_node_getrssi = ath_node_getrssi;
+ ic->ic_node_getsignal = ath_node_getsignal;
sc->sc_recv_mgmt = ic->ic_recv_mgmt;
ic->ic_recv_mgmt = ath_recv_mgmt;
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = ath_newstate;
+ ic->ic_scan_start = ath_scan_start;
+ ic->ic_scan_end = ath_scan_end;
+ ic->ic_set_channel = ath_set_channel;
ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
ic->ic_crypto.cs_key_alloc = ath_key_alloc;
ic->ic_crypto.cs_key_delete = ath_key_delete;
@@ -736,8 +750,10 @@ ath_intr(void *arg)
}
if (!ath_hal_intrpend(ah)) /* shared irq, not for us */
return;
- if (!((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags &
- IFF_DRV_RUNNING))) {
+ if ((ifp->if_flags & IFF_UP) == 0 ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
+ HAL_INT status;
+
DPRINTF(sc, ATH_DEBUG_ANY, "%s: if_flags 0x%x\n",
__func__, ifp->if_flags);
ath_hal_getisr(ah, &status); /* clear ISR */
@@ -817,6 +833,7 @@ ath_fatal_proc(void *arg, int pending)
struct ifnet *ifp = sc->sc_ifp;
u_int32_t *state;
u_int32_t len;
+ void *sp;
if_printf(ifp, "hardware error; resetting\n");
/*
@@ -824,8 +841,9 @@ ath_fatal_proc(void *arg, int pending)
* are caused by DMA errors. Collect h/w state from
* the hal so we can diagnose what's going on.
*/
- if (ath_hal_getfatalstate(sc->sc_ah, &state, &len)) {
+ if (ath_hal_getfatalstate(sc->sc_ah, &sp, &len)) {
KASSERT(len >= 6*sizeof(u_int32_t), ("len %u bytes", len));
+ state = sp;
if_printf(ifp, "0x%08x 0x%08x 0x%08x, 0x%08x 0x%08x 0x%08x\n",
state[0], state[1] , state[2], state[3],
state[4], state[5]);
@@ -885,20 +903,22 @@ ath_bmiss_proc(void *arg, int pending)
* the frequency possibly mapped for GSM channels.
*/
static void
-ath_mapchan(struct ieee80211com *ic, HAL_CHANNEL *hc,
- const struct ieee80211_channel *chan)
+ath_mapchan(HAL_CHANNEL *hc, const struct ieee80211_channel *chan)
{
#define N(a) (sizeof(a) / sizeof(a[0]))
- static const u_int modeflags[] = {
+ static const u_int modeflags[IEEE80211_MODE_MAX] = {
0, /* IEEE80211_MODE_AUTO */
CHANNEL_A, /* IEEE80211_MODE_11A */
CHANNEL_B, /* IEEE80211_MODE_11B */
CHANNEL_PUREG, /* IEEE80211_MODE_11G */
0, /* IEEE80211_MODE_FH */
- CHANNEL_ST, /* IEEE80211_MODE_TURBO_A */
- CHANNEL_108G /* IEEE80211_MODE_TURBO_G */
+ CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */
+ CHANNEL_108G, /* IEEE80211_MODE_TURBO_G */
+ CHANNEL_ST, /* IEEE80211_MODE_STURBO_A */
+ CHANNEL_A, /* IEEE80211_MODE_11NA */
+ CHANNEL_PUREG, /* IEEE80211_MODE_11NG */
};
- enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan);
+ enum ieee80211_phymode mode = ieee80211_chan2mode(chan);
KASSERT(mode < N(modeflags), ("unexpected phy mode %u", mode));
KASSERT(modeflags[mode] != 0, ("mode %u undefined", mode));
@@ -907,6 +927,12 @@ ath_mapchan(struct ieee80211com *ic, HAL_CHANNEL *hc,
hc->channelFlags |= CHANNEL_HALF;
if (IEEE80211_IS_CHAN_QUARTER(chan))
hc->channelFlags |= CHANNEL_QUARTER;
+ if (IEEE80211_IS_CHAN_HT20(chan))
+ hc->channelFlags |= CHANNEL_HT20;
+ if (IEEE80211_IS_CHAN_HT40D(chan))
+ hc->channelFlags |= CHANNEL_HT40MINUS;
+ if (IEEE80211_IS_CHAN_HT40U(chan))
+ hc->channelFlags |= CHANNEL_HT40PLUS;
hc->channel = IEEE80211_IS_CHAN_GSM(chan) ?
2422 + (922 - chan->ic_freq) : chan->ic_freq;
@@ -939,7 +965,7 @@ ath_init(void *arg)
* be followed by initialization of the appropriate bits
* and then setup of the interrupt mask.
*/
- ath_mapchan(ic, &sc->sc_curchan, ic->ic_curchan);
+ ath_mapchan(&sc->sc_curchan, ic->ic_curchan);
if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
if_printf(ifp, "unable to reset hardware; hal status %u\n",
status);
@@ -1103,7 +1129,7 @@ ath_reset(struct ifnet *ifp)
* Convert to a HAL channel description with the flags
* constrained to reflect the current operating mode.
*/
- ath_mapchan(ic, &sc->sc_curchan, ic->ic_curchan);
+ ath_mapchan(&sc->sc_curchan, ic->ic_curchan);
ath_hal_intrset(ah, 0); /* disable interrupts */
ath_draintxq(sc); /* stop xmit side */
@@ -1116,14 +1142,14 @@ ath_reset(struct ifnet *ifp)
sc->sc_diversity = ath_hal_getdiversity(ah);
sc->sc_calinterval = 1;
sc->sc_caltries = 0;
+ if (ath_startrecv(sc) != 0) /* restart recv */
+ if_printf(ifp, "%s: unable to start recv logic\n", __func__);
/*
* We may be doing a reset in response to an ioctl
* that changes the channel so update any state that
* might change as a result.
*/
ath_chan_change(sc, ic->ic_curchan);
- if (ath_startrecv(sc) != 0) /* restart recv */
- if_printf(ifp, "%s: unable to start recv logic\n", __func__);
if (ic->ic_state == IEEE80211_S_RUN)
ath_beacon_config(sc); /* restart beacons */
ath_hal_intrset(ah, sc->sc_imask);
@@ -1132,6 +1158,369 @@ ath_reset(struct ifnet *ifp)
return 0;
}
+static int
+ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
+{
+ return 0;
+}
+
+#if 0
+static int
+ath_ff_ageflushtestdone(struct ath_txq *txq, struct ath_buf *bf)
+{
+ return (txq->axq_curage - bf->bf_age) < ATH_FF_STAGEMAX;
+}
+#endif
+
+/*
+ * Flush FF staging queue.
+ */
+static void
+ath_ff_stageq_flush(struct ath_softc *sc, struct ath_txq *txq,
+ int (*ath_ff_flushdonetest)(struct ath_txq *txq, struct ath_buf *bf))
+{
+ struct ath_buf *bf;
+ struct ieee80211_node *ni;
+ int pktlen, pri;
+
+ for (;;) {
+ ATH_TXQ_LOCK(txq);
+ /*
+ * Go from the back (oldest) to front so we can
+ * stop early based on the age of the entry.
+ */
+ bf = TAILQ_LAST(&txq->axq_stageq, axq_headtype);
+ if (bf == NULL || ath_ff_flushdonetest(txq, bf)) {
+ ATH_TXQ_UNLOCK(txq);
+ break;
+ }
+
+ ni = bf->bf_node;
+ pri = M_WME_GETAC(bf->bf_m);
+ KASSERT(ATH_NODE(ni)->an_ff_buf[pri],
+ ("no bf on staging queue %p", bf));
+ ATH_NODE(ni)->an_ff_buf[pri] = NULL;
+ TAILQ_REMOVE(&txq->axq_stageq, bf, bf_stagelist);
+
+ ATH_TXQ_UNLOCK(txq);
+
+ DPRINTF(sc, ATH_DEBUG_FF, "%s: flush frame, age %u\n",
+ __func__, bf->bf_age);
+
+ sc->sc_stats.ast_ff_flush++;
+
+ /* encap and xmit */
+ bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni);
+ if (bf->bf_m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+ "%s: discard, encapsulation failure\n",
+ __func__);
+ sc->sc_stats.ast_tx_encap++;
+ goto bad;
+ }
+ pktlen = bf->bf_m->m_pkthdr.len; /* NB: don't reference below */
+ if (ath_tx_start(sc, ni, bf, bf->bf_m) == 0) {
+#if 0 /*XXX*/
+ ifp->if_opackets++;
+#endif
+ continue;
+ }
+ bad:
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ bf->bf_node = NULL;
+ if (bf->bf_m != NULL) {
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+ }
+
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ }
+}
+
+static __inline u_int32_t
+ath_ff_approx_txtime(struct ath_softc *sc, struct ath_node *an, struct mbuf *m)
+{
+ u_int32_t framelen;
+ struct ath_buf *bf;
+
+ /*
+ * Approximate the frame length to be transmitted. A swag to add
+ * the following maximal values to the skb payload:
+ * - 32: 802.11 encap + CRC
+ * - 24: encryption overhead (if wep bit)
+ * - 4 + 6: fast-frame header and padding
+ * - 16: 2 LLC FF tunnel headers
+ * - 14: 1 802.3 FF tunnel header (skb already accounts for 2nd)
+ */
+ framelen = m->m_pkthdr.len + 32 + 4 + 6 + 16 + 14;
+ if (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY)
+ framelen += 24;
+ bf = an->an_ff_buf[M_WME_GETAC(m)];
+ if (bf != NULL)
+ framelen += bf->bf_m->m_pkthdr.len;
+ return ath_hal_computetxtime(sc->sc_ah, sc->sc_currates, framelen,
+ sc->sc_lastdatarix, AH_FALSE);
+}
+
+/*
+ * Determine if a data frame may be aggregated via ff tunnelling.
+ * Note the caller is responsible for checking if the destination
+ * supports fast frames.
+ *
+ * NB: allowing EAPOL frames to be aggregated with other unicast traffic.
+ * Do 802.1x EAPOL frames proceed in the clear? Then they couldn't
+ * be aggregated with other types of frames when encryption is on?
+ *
+ * NB: assumes lock on an_ff_buf effectively held by txq lock mechanism.
+ */
+static __inline int
+ath_ff_can_aggregate(struct ath_softc *sc,
+ struct ath_node *an, struct mbuf *m, int *flushq)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ath_txq *txq;
+ u_int32_t txoplimit;
+ u_int pri;
+
+ *flushq = 0;
+
+ /*
+ * If there is no frame to combine with and the txq has
+ * fewer frames than the minimum required; then do not
+ * attempt to aggregate this frame.
+ */
+ pri = M_WME_GETAC(m);
+ txq = sc->sc_ac2q[pri];
+ if (an->an_ff_buf[pri] == NULL && txq->axq_depth < sc->sc_fftxqmin)
+ return 0;
+ /*
+ * When not in station mode never aggregate a multicast
+ * frame; this insures, for example, that a combined frame
+ * does not require multiple encryption keys when using
+ * 802.1x/WPA.
+ */
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ ETHER_IS_MULTICAST(mtod(m, struct ether_header *)->ether_dhost))
+ return 0;
+ /*
+ * Consult the max bursting interval to insure a combined
+ * frame fits within the TxOp window.
+ */
+ txoplimit = IEEE80211_TXOP_TO_US(
+ ic->ic_wme.wme_chanParams.cap_wmeParams[pri].wmep_txopLimit);
+ if (txoplimit != 0 && ath_ff_approx_txtime(sc, an, m) > txoplimit) {
+ DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+ "%s: FF TxOp violation\n", __func__);
+ if (an->an_ff_buf[pri] != NULL)
+ *flushq = 1;
+ return 0;
+ }
+ return 1; /* try to aggregate */
+}
+
+/*
+ * Check if the supplied frame can be partnered with an existing
+ * or pending frame. Return a reference to any frame that should be
+ * sent on return; otherwise return NULL.
+ */
+static struct mbuf *
+ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
+ struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_node *an = ATH_NODE(ni);
+ struct ath_buf *bfstaged;
+ int ff_flush, pri;
+
+ /*
+ * Check if the supplied frame can be aggregated.
+ *
+ * NB: we use the txq lock to protect references to
+ * an->an_ff_txbuf in ath_ff_can_aggregate().
+ */
+ ATH_TXQ_LOCK(txq);
+ pri = M_WME_GETAC(m);
+ if (ath_ff_can_aggregate(sc, an, m, &ff_flush)) {
+ struct ath_buf *bfstaged = an->an_ff_buf[pri];
+ if (bfstaged != NULL) {
+ /*
+ * A frame is available for partnering; remove
+ * it, chain it to this one, and encapsulate.
+ */
+ an->an_ff_buf[pri] = NULL;
+ TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
+ ATH_TXQ_UNLOCK(txq);
+
+ /*
+ * Chain mbufs and add FF magic.
+ */
+ DPRINTF(sc, ATH_DEBUG_FF,
+ "[%s] aggregate fast-frame, age %u\n",
+ ether_sprintf(ni->ni_macaddr), txq->axq_curage);
+ m->m_nextpkt = NULL;
+ bfstaged->bf_m->m_nextpkt = m;
+ m = bfstaged->bf_m;
+ bfstaged->bf_m = NULL;
+ m->m_flags |= M_FF;
+ /*
+ * Release the node reference held while
+ * the packet sat on an_ff_buf[]
+ */
+ bfstaged->bf_node = NULL;
+ ieee80211_free_node(ni);
+
+ /*
+ * Return bfstaged to the free list.
+ */
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bfstaged, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+
+ return m; /* ready to go */
+ } else {
+ /*
+ * No frame available, queue this frame to wait
+ * for a partner. Note that we hold the buffer
+ * and a reference to the node; we need the
+ * buffer in particular so we're certain we
+ * can flush the frame at a later time.
+ */
+ DPRINTF(sc, ATH_DEBUG_FF,
+ "[%s] stage fast-frame, age %u\n",
+ ether_sprintf(ni->ni_macaddr), txq->axq_curage);
+
+ bf->bf_m = m;
+ bf->bf_node = ni; /* NB: held reference */
+ bf->bf_age = txq->axq_curage;
+ an->an_ff_buf[pri] = bf;
+ TAILQ_INSERT_HEAD(&txq->axq_stageq, bf, bf_stagelist);
+ ATH_TXQ_UNLOCK(txq);
+
+ return NULL; /* consumed */
+ }
+ }
+ /*
+ * Frame could not be aggregated, it needs to be returned
+ * to the caller for immediate transmission. In addition
+ * we check if we should first flush a frame from the
+ * staging queue before sending this one.
+ *
+ * NB: ath_ff_can_aggregate only marks ff_flush if a frame
+ * is present to flush.
+ */
+ if (ff_flush) {
+ int pktlen;
+
+ bfstaged = an->an_ff_buf[pri];
+ an->an_ff_buf[pri] = NULL;
+ TAILQ_REMOVE(&txq->axq_stageq, bfstaged, bf_stagelist);
+ ATH_TXQ_UNLOCK(txq);
+
+ DPRINTF(sc, ATH_DEBUG_FF, "[%s] flush staged frame\n",
+ ether_sprintf(an->an_node.ni_macaddr));
+
+ /* encap and xmit */
+ bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni);
+ if (bfstaged->bf_m == NULL) {
+ DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
+ "%s: discard, encap failure\n", __func__);
+ sc->sc_stats.ast_tx_encap++;
+ goto ff_flushbad;
+ }
+ pktlen = bfstaged->bf_m->m_pkthdr.len;
+ if (ath_tx_start(sc, ni, bfstaged, bfstaged->bf_m)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: discard, xmit failure\n", __func__);
+ ff_flushbad:
+ /*
+ * Unable to transmit frame that was on the staging
+ * queue. Reclaim the node reference and other
+ * resources.
+ */
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ bfstaged->bf_node = NULL;
+ if (bfstaged->bf_m != NULL) {
+ m_freem(bfstaged->bf_m);
+ bfstaged->bf_m = NULL;
+ }
+
+ ATH_TXBUF_LOCK(sc);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bfstaged, bf_list);
+ ATH_TXBUF_UNLOCK(sc);
+ } else {
+#if 0
+ ifp->if_opackets++;
+#endif
+ }
+ } else {
+ if (an->an_ff_buf[pri] != NULL) {
+ /*
+ * XXX: out-of-order condition only occurs for AP
+ * mode and multicast. There may be no valid way
+ * to get this condition.
+ */
+ DPRINTF(sc, ATH_DEBUG_FF, "[%s] out-of-order frame\n",
+ ether_sprintf(an->an_node.ni_macaddr));
+ /* XXX stat */
+ }
+ ATH_TXQ_UNLOCK(txq);
+ }
+ return m;
+}
+
+/*
+ * Cleanup driver resources when we run out of buffers
+ * while processing fragments; return the tx buffers
+ * allocated and drop node references.
+ */
+static void
+ath_txfrag_cleanup(struct ath_softc *sc,
+ ath_bufhead *frags, struct ieee80211_node *ni)
+{
+ struct ath_buf *bf, *next;
+
+ ATH_TXBUF_LOCK_ASSERT(sc);
+
+ STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
+ /* NB: bf assumed clean */
+ STAILQ_REMOVE_HEAD(frags, bf_list);
+ STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ieee80211_node_decref(ni);
+ }
+}
+
+/*
+ * Setup xmit of a fragmented frame. Allocate a buffer
+ * for each frag and bump the node reference count to
+ * reflect the held reference to be setup by ath_tx_start.
+ */
+static int
+ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
+ struct mbuf *m0, struct ieee80211_node *ni)
+{
+ struct mbuf *m;
+ struct ath_buf *bf;
+
+ ATH_TXBUF_LOCK(sc);
+ for (m = m0->m_nextpkt; m != NULL; m = m->m_nextpkt) {
+ bf = STAILQ_FIRST(&sc->sc_txbuf);
+ if (bf == NULL) { /* out of buffers, cleanup */
+ ath_txfrag_cleanup(sc, frags, ni);
+ break;
+ }
+ STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list);
+ ieee80211_node_incref(ni);
+ STAILQ_INSERT_TAIL(frags, bf, bf_list);
+ }
+ ATH_TXBUF_UNLOCK(sc);
+
+ return !STAILQ_EMPTY(frags);
+}
+
static void
ath_start(struct ifnet *ifp)
{
@@ -1140,9 +1529,12 @@ ath_start(struct ifnet *ifp)
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ath_buf *bf;
- struct mbuf *m;
+ struct mbuf *m, *next;
struct ieee80211_frame *wh;
struct ether_header *eh;
+ struct ath_txq *txq;
+ ath_bufhead frags;
+ int pri;
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
return;
@@ -1189,7 +1581,8 @@ ath_start(struct ifnet *ifp)
ATH_TXBUF_UNLOCK(sc);
break;
}
- /*
+ STAILQ_INIT(&frags);
+ /*
* Find the node for the destination so we can do
* things like power save and fast frames aggregation.
*/
@@ -1213,7 +1606,16 @@ ath_start(struct ifnet *ifp)
* to the 802.11 layer and continue. We'll get
* the frame back when the time is right.
*/
- ieee80211_pwrsave(ic, ni, m);
+ ieee80211_pwrsave(ni, m);
+ /*
+ * If we're in power save mode 'cuz of a bg
+ * scan cancel it so the traffic can flow.
+ * The packet we just queued will automatically
+ * get sent when we drop out of power save.
+ * XXX locking
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_scan(ic);
goto reclaim;
}
/* calculate priority so we can find the tx queue */
@@ -1224,6 +1626,28 @@ ath_start(struct ifnet *ifp)
m_freem(m);
goto bad;
}
+ pri = M_WME_GETAC(m);
+ txq = sc->sc_ac2q[pri];
+ if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
+ /*
+ * Check queue length; if too deep drop this
+ * frame (tail drop considered good).
+ */
+ if (txq->axq_depth >= sc->sc_fftxqmax) {
+ DPRINTF(sc, ATH_DEBUG_FF,
+ "[%s] tail drop on q %u depth %u\n",
+ ether_sprintf(ni->ni_macaddr),
+ txq->axq_qnum, txq->axq_depth);
+ sc->sc_stats.ast_tx_qfull++;
+ m_freem(m);
+ goto reclaim;
+ }
+ m = ath_ff_check(sc, txq, bf, m, ni);
+ if (m == NULL) {
+ /* NB: ni ref & bf held on stageq */
+ continue;
+ }
+ }
ifp->if_opackets++;
BPF_MTAP(ifp, m);
/*
@@ -1237,6 +1661,20 @@ ath_start(struct ifnet *ifp)
sc->sc_stats.ast_tx_encap++;
goto bad;
}
+ /*
+ * Check for fragmentation. If this frame
+ * has been broken up verify we have enough
+ * buffers to send all the fragments so all
+ * go out or none...
+ */
+ if ((m->m_flags & M_FRAG) &&
+ !ath_txfrag_setup(sc, &frags, m, ni)) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: out of txfrag buffers\n", __func__);
+ ic->ic_stats.is_tx_nobuf++; /* XXX */
+ ath_freetx(m);
+ goto bad;
+ }
} else {
/*
* Hack! The referenced node pointer is in the
@@ -1267,20 +1705,62 @@ ath_start(struct ifnet *ifp)
sc->sc_stats.ast_tx_mgmt++;
}
+ nextfrag:
+ /*
+ * Pass the frame to the h/w for transmission.
+ * Fragmented frames have each frag chained together
+ * with m_nextpkt. We know there are sufficient ath_buf's
+ * to send all the frags because of work done by
+ * ath_txfrag_setup. We leave m_nextpkt set while
+ * calling ath_tx_start so it can use it to extend the
+ * the tx duration to cover the subsequent frag and
+ * so it can reclaim all the mbufs in case of an error;
+ * ath_tx_start clears m_nextpkt once it commits to
+ * handing the frame to the hardware.
+ */
+ next = m->m_nextpkt;
if (ath_tx_start(sc, ni, bf, m)) {
bad:
ifp->if_oerrors++;
reclaim:
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
+ ath_txfrag_cleanup(sc, &frags, ni);
ATH_TXBUF_UNLOCK(sc);
if (ni != NULL)
ieee80211_free_node(ni);
continue;
}
+ if (next != NULL) {
+ /*
+ * Beware of state changing between frags.
+ * XXX check sta power-save state?
+ */
+ if (ic->ic_state != IEEE80211_S_RUN) {
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: flush fragmented packet, state %s\n",
+ __func__,
+ ieee80211_state_name[ic->ic_state]);
+ ath_freetx(next);
+ goto reclaim;
+ }
+ m = next;
+ bf = STAILQ_FIRST(&frags);
+ KASSERT(bf != NULL, ("no buf for txfrag"));
+ STAILQ_REMOVE_HEAD(&frags, bf_list);
+ goto nextfrag;
+ }
- sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
+ ifp->if_timer = 5;
+#if 0
+ /*
+ * Flush stale frames from the fast-frame staging queue.
+ */
+ if (ic->ic_opmode != IEEE80211_M_STA)
+ ath_ff_stageq_flush(sc, txq, ath_ff_ageflushtestdone);
+#endif
}
}
@@ -1306,7 +1786,7 @@ ath_media_change(struct ifnet *ifp)
} else
sc->sc_opmode = ic->ic_opmode;
if (IS_UP(ifp))
- ath_init(ifp->if_softc); /* XXX lose error */
+ ath_init(sc); /* XXX lose error */
error = 0;
}
return error;
@@ -1770,7 +2250,7 @@ ath_key_update_end(struct ieee80211com *ic)
* - when in monitor mode
*/
static u_int32_t
-ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state)
+ath_calcrxfilter(struct ath_softc *sc)
{
#define RX_FILTER_PRESERVE (HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)
struct ieee80211com *ic = &sc->sc_ic;
@@ -1787,7 +2267,7 @@ ath_calcrxfilter(struct ath_softc *sc, enum ieee80211_state state)
rfilt |= HAL_RX_FILTER_PROM;
if (ic->ic_opmode == IEEE80211_M_STA ||
ic->ic_opmode == IEEE80211_M_IBSS ||
- state == IEEE80211_S_SCAN)
+ sc->sc_scanning)
rfilt |= HAL_RX_FILTER_BEACON;
if (ic->ic_opmode == IEEE80211_M_MONITOR)
rfilt |= HAL_RX_FILTER_CONTROL;
@@ -1806,7 +2286,7 @@ ath_mode_init(struct ath_softc *sc)
struct ifmultiaddr *ifma;
/* configure rx filter */
- rfilt = ath_calcrxfilter(sc, ic->ic_state);
+ rfilt = ath_calcrxfilter(sc);
ath_hal_setrxfilter(ah, rfilt);
/* configure operational mode */
@@ -2381,9 +2861,7 @@ ath_beacon_config(struct ath_softc *sc)
#endif
/*
* Calculate the number of consecutive beacons to miss
- * before taking a BMISS interrupt. The configuration
- * is specified in ms, so we need to convert that to
- * TU's and then calculate based on the beacon interval.
+ * before taking a BMISS interrupt.
* Note that we clamp the result to at most 10 beacons.
*/
bs.bs_bmissthreshold = ic->ic_bmissthreshold;
@@ -2406,7 +2884,7 @@ ath_beacon_config(struct ath_softc *sc)
if (bs.bs_sleepduration > bs.bs_dtimperiod)
bs.bs_sleepduration = roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
- DPRINTF(sc, ATH_DEBUG_BEACON,
+ DPRINTF(sc, ATH_DEBUG_BEACON,
"%s: tsf %ju tsf:tu %u intval %u nexttbtt %u dtim %u nextdtim %u bmiss %u sleep %u cfp:period %u maxdur %u next %u timoffset %u\n"
, __func__
, tsf, tsftu
@@ -2699,7 +3177,7 @@ ath_node_free(struct ieee80211_node *ni)
sc->sc_node_free(ni);
}
-static u_int8_t
+static int8_t
ath_node_getrssi(const struct ieee80211_node *ni)
{
#define HAL_EP_RND(x, mul) \
@@ -2719,6 +3197,22 @@ ath_node_getrssi(const struct ieee80211_node *ni)
#undef HAL_EP_RND
}
+static void
+ath_node_getsignal(const struct ieee80211_node *ni, int8_t *rssi, int8_t *noise)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ath_softc *sc = ic->ic_ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ HAL_CHANNEL hchan;
+
+ *rssi = ath_node_getrssi(ni);
+ if (ni->ni_chan != IEEE80211_CHAN_ANYC) {
+ ath_mapchan(&hchan, ni->ni_chan);
+ *noise = ath_hal_getchannoise(ah, &hchan);
+ } else
+ *noise = -95; /* nominally correct */
+}
+
static int
ath_rxbuf_init(struct ath_softc *sc, struct ath_buf *bf)
{
@@ -2811,7 +3305,7 @@ ath_extend_tsf(u_int32_t rstamp, u_int64_t tsf)
static void
ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
struct ieee80211_node *ni,
- int subtype, int rssi, u_int32_t rstamp)
+ int subtype, int rssi, int noise, u_int32_t rstamp)
{
struct ath_softc *sc = ic->ic_ifp->if_softc;
@@ -2819,7 +3313,7 @@ ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
* Call up first so subsequent work can use information
* potentially stored in the node (e.g. for ibss merge).
*/
- sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, rstamp);
+ sc->sc_recv_mgmt(ic, m, ni, subtype, rssi, noise, rstamp);
switch (subtype) {
case IEEE80211_FC0_SUBTYPE_BEACON:
/* update rssi statistics for use by the hal */
@@ -2880,6 +3374,7 @@ static int
ath_rx_tap(struct ath_softc *sc, struct mbuf *m,
const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
{
+#define CHANNEL_HT (CHANNEL_HT20|CHANNEL_HT40PLUS|CHANNEL_HT40MINUS)
u_int8_t rix;
KASSERT(sc->sc_drvbpf != NULL, ("no tap"));
@@ -2893,13 +3388,33 @@ ath_rx_tap(struct ath_softc *sc, struct mbuf *m,
sc->sc_stats.ast_rx_tooshort++;
return 0;
}
- sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf));
rix = rs->rs_rate;
+ sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate;
sc->sc_rx_th.wr_flags = sc->sc_hwmap[rix].rxflags;
+#if HAL_ABI_VERSION >= 0x07050400
+ if (sc->sc_curchan.channelFlags & CHANNEL_HT) {
+ /*
+ * For HT operation we must specify the channel
+ * attributes for each packet since they vary.
+ * We deduce this by from HT40 bit in the rx
+ * status and the MCS/legacy rate bit.
+ */
+ sc->sc_rx_th.wr_chan_flags &= ~IEEE80211_CHAN_HT;
+ if (sc->sc_rx_th.wr_rate & 0x80) { /* HT rate */
+ /* XXX 40U/40D */
+ sc->sc_rx_th.wr_chan_flags |=
+ (rs->rs_flags & HAL_RX_2040) ?
+ IEEE80211_CHAN_HT40U : IEEE80211_CHAN_HT20;
+ if ((rs->rs_flags & HAL_RX_GI) == 0)
+ sc->sc_rx_th.wr_flags |=
+ IEEE80211_RADIOTAP_F_SHORTGI;
+ }
+ }
+#endif
+ sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(rs->rs_tstamp, tsf));
if (rs->rs_status & HAL_RXERR_CRC)
sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
/* XXX propagate other error flags from descriptor */
- sc->sc_rx_th.wr_rate = sc->sc_hwmap[rix].ieeerate;
sc->sc_rx_th.wr_antsignal = rs->rs_rssi + nf;
sc->sc_rx_th.wr_antnoise = nf;
sc->sc_rx_th.wr_antenna = rs->rs_antenna;
@@ -2907,6 +3422,7 @@ ath_rx_tap(struct ath_softc *sc, struct mbuf *m,
bpf_mtap2(sc->sc_drvbpf, &sc->sc_rx_th, sc->sc_rx_th_len, m);
return 1;
+#undef CHANNEL_HT
}
static void
@@ -2976,24 +3492,12 @@ ath_rx_proc(void *arg, int npending)
bf->bf_daddr, PA2DESC(sc, ds->ds_link), rs);
#ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RECV_DESC)
- ath_printrxbuf(bf, 0, status == HAL_OK);
+ ath_printrxbuf(bf, 0, status == HAL_OK);
#endif
if (status == HAL_EINPROGRESS)
break;
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
- if (rs->rs_more) {
- /*
- * Frame spans multiple descriptors; this
- * cannot happen yet as we don't support
- * jumbograms. If not in monitor mode,
- * discard the frame.
- */
- if (ic->ic_opmode != IEEE80211_M_MONITOR) {
- sc->sc_stats.ast_rx_toobig++;
- goto rx_next;
- }
- /* fall thru for monitor mode handling... */
- } else if (rs->rs_status != 0) {
+ if (rs->rs_status != 0) {
if (rs->rs_status & HAL_RXERR_CRC)
sc->sc_stats.ast_rx_crcerr++;
if (rs->rs_status & HAL_RXERR_FIFO)
@@ -3002,7 +3506,7 @@ ath_rx_proc(void *arg, int npending)
sc->sc_stats.ast_rx_phyerr++;
phyerr = rs->rs_phyerr & 0x1f;
sc->sc_stats.ast_rx_phy[phyerr]++;
- goto rx_next;
+ goto rx_error; /* NB: don't count in ierrors */
}
if (rs->rs_status & HAL_RXERR_DECRYPT) {
/*
@@ -3039,6 +3543,14 @@ ath_rx_proc(void *arg, int npending)
}
}
ifp->if_ierrors++;
+rx_error:
+ /*
+ * Cleanup any pending partial frame.
+ */
+ if (sc->sc_rxpending != NULL) {
+ m_freem(sc->sc_rxpending);
+ sc->sc_rxpending = NULL;
+ }
/*
* When a tap is present pass error frames
* that have been requested. By default we
@@ -3070,9 +3582,42 @@ rx_accept:
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
bf->bf_m = NULL;
- m->m_pkthdr.rcvif = ifp;
len = rs->rs_datalen;
- m->m_pkthdr.len = m->m_len = len;
+ m->m_len = len;
+
+ if (rs->rs_more) {
+ /*
+ * Frame spans multiple descriptors; save
+ * it for the next completed descriptor, it
+ * will be used to construct a jumbogram.
+ */
+ if (sc->sc_rxpending != NULL) {
+ /* NB: max frame size is currently 2 clusters */
+ sc->sc_stats.ast_rx_toobig++;
+ m_freem(sc->sc_rxpending);
+ }
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ sc->sc_rxpending = m;
+ goto rx_next;
+ } else if (sc->sc_rxpending != NULL) {
+ /*
+ * This is the second part of a jumbogram,
+ * chain it to the first mbuf, adjust the
+ * frame length, and clear the rxpending state.
+ */
+ sc->sc_rxpending->m_next = m;
+ sc->sc_rxpending->m_pkthdr.len += len;
+ m = sc->sc_rxpending;
+ sc->sc_rxpending = NULL;
+ } else {
+ /*
+ * Normal single-descriptor receive; setup
+ * the rcvif and packet length.
+ */
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ }
sc->sc_stats.ast_ant_rx[rs->rs_antenna]++;
@@ -3095,7 +3640,7 @@ rx_accept:
}
if (IFF_DUMPPKTS(sc, ATH_DEBUG_RECV)) {
- ieee80211_dump_pkt(mtod(m, caddr_t), len,
+ ieee80211_dump_pkt(ic, mtod(m, caddr_t), len,
sc->sc_hwmap[rs->rs_rate].ieeerate,
rs->rs_rssi);
}
@@ -3120,7 +3665,8 @@ rx_accept:
/*
* Send frame up for processing.
*/
- type = ieee80211_input(ic, m, ni, rs->rs_rssi, rs->rs_tstamp);
+ type = ieee80211_input(ic, m, ni,
+ rs->rs_rssi, nf, rs->rs_tstamp);
ieee80211_free_node(ni);
if (sc->sc_diversity) {
/*
@@ -3182,6 +3728,8 @@ ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
txq->axq_link = NULL;
STAILQ_INIT(&txq->axq_q);
ATH_TXQ_LOCK_INIT(sc, txq);
+ TAILQ_INIT(&txq->axq_stageq);
+ txq->axq_curage = 0;
}
/*
@@ -3282,7 +3830,7 @@ ath_txq_update(struct ath_softc *sc, int ac)
ath_hal_gettxqueueprops(ah, txq->axq_qnum, &qi);
qi.tqi_aifs = wmep->wmep_aifsn;
qi.tqi_cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin);
- qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
+ qi.tqi_cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax);
qi.tqi_burstTime = ATH_TXOP_TO_US(wmep->wmep_txopLimit);
if (!ath_hal_settxqueueprops(ah, txq->axq_qnum, &qi)) {
@@ -3437,6 +3985,22 @@ ath_tx_findrix(const HAL_RATE_TABLE *rt, int rate)
return 0; /* NB: lowest rate */
}
+/*
+ * Reclaim mbuf resources. For fragmented frames we
+ * need to claim each frag chained with m_nextpkt.
+ */
+static void
+ath_freetx(struct mbuf *m)
+{
+ struct mbuf *next;
+
+ do {
+ next = m->m_nextpkt;
+ m->m_nextpkt = NULL;
+ m_freem(m);
+ } while ((m = next) != NULL);
+}
+
static int
ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
{
@@ -3455,7 +4019,7 @@ ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
bf->bf_nseg = ATH_TXDESC+1;
} else if (error != 0) {
sc->sc_stats.ast_tx_busdma++;
- m_freem(m0);
+ ath_freetx(m0);
return error;
}
/*
@@ -3467,7 +4031,7 @@ ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
sc->sc_stats.ast_tx_linear++;
m = ath_defrag(m0, M_DONTWAIT, ATH_TXDESC);
if (m == NULL) {
- m_freem(m0);
+ ath_freetx(m0);
sc->sc_stats.ast_tx_nombuf++;
return ENOMEM;
}
@@ -3477,14 +4041,14 @@ ath_tx_dmasetup(struct ath_softc *sc, struct ath_buf *bf, struct mbuf *m0)
BUS_DMA_NOWAIT);
if (error != 0) {
sc->sc_stats.ast_tx_busdma++;
- m_freem(m0);
+ ath_freetx(m0);
return error;
}
KASSERT(bf->bf_nseg <= ATH_TXDESC,
("too many segments after defrag; nseg %u", bf->bf_nseg));
} else if (bf->bf_nseg == 0) { /* null packet, discard */
sc->sc_stats.ast_tx_nodata++;
- m_freem(m0);
+ ath_freetx(m0);
return EIO;
}
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: m %p len %u\n",
@@ -3565,7 +4129,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
struct ath_hal *ah = sc->sc_ah;
struct ifnet *ifp = sc->sc_ifp;
const struct chanAccParams *cap = &ic->ic_wme.wme_chanParams;
- int error, iswep, ismcast, ismrr;
+ int error, iswep, ismcast, isfrag, ismrr;
int keyix, hdrlen, pktlen, try0;
u_int8_t rix, txrate, ctsrate;
u_int8_t cix = 0xff; /* NB: silence compiler */
@@ -3582,6 +4146,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
wh = mtod(m0, struct ieee80211_frame *);
iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+ isfrag = m0->m_flags & M_FRAG;
hdrlen = ieee80211_anyhdrsize(wh);
/*
* Packet length must not include any
@@ -3606,21 +4171,22 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
* 802.11 layer counts failures and provides
* debugging/diagnostics.
*/
- m_freem(m0);
+ ath_freetx(m0);
return EIO;
}
/*
* Adjust the packet + header lengths for the crypto
* additions and calculate the h/w key index. When
* a s/w mic is done the frame will have had any mic
- * added to it prior to entry so m0->m_pkthdr.len above will
+ * added to it prior to entry so m0->m_pkthdr.len will
* account for it. Otherwise we need to add it to the
* packet length.
*/
cip = k->wk_cipher;
hdrlen += cip->ic_header;
pktlen += cip->ic_header + cip->ic_trailer;
- if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
+ /* NB: frags always have any TKIP MIC done in s/w */
+ if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && !isfrag)
pktlen += cip->ic_miclen;
keyix = k->wk_keyix;
@@ -3739,6 +4305,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
ath_rate_findrate(sc, an, shortPreamble, pktlen,
&rix, &try0, &txrate);
sc->sc_txrate = txrate; /* for LED blinking */
+ sc->sc_lastdatarix = rix; /* for fast frames */
if (try0 != ATH_TXMAXTRY)
ismrr = 1;
}
@@ -3750,7 +4317,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
if_printf(ifp, "bogus frame type 0x%x (%s)\n",
wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK, __func__);
/* XXX statistic */
- m_freem(m0);
+ ath_freetx(m0);
return EIO;
}
txq = sc->sc_ac2q[pri];
@@ -3771,7 +4338,8 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
*/
if (ismcast) {
flags |= HAL_TXDESC_NOACK; /* no ack on broad/multicast */
- } else if (pktlen > ic->ic_rtsthreshold) {
+ } else if (pktlen > ic->ic_rtsthreshold &&
+ (ni->ni_ath_flags & IEEE80211_NODE_FF) == 0) {
flags |= HAL_TXDESC_RTSENA; /* RTS based on frame length */
cix = rt->info[rix].controlRate;
sc->sc_stats.ast_tx_rts++;
@@ -3792,7 +4360,17 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
flags |= HAL_TXDESC_RTSENA;
else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
flags |= HAL_TXDESC_CTSENA;
- cix = rt->info[sc->sc_protrix].controlRate;
+ if (isfrag) {
+ /*
+ * For frags it would be desirable to use the
+ * highest CCK rate for RTS/CTS. But stations
+ * farther away may detect it at a lower CCK rate
+ * so use the configured protection rate instead
+ * (for now).
+ */
+ cix = rt->info[sc->sc_protrix].controlRate;
+ } else
+ cix = rt->info[sc->sc_protrix].controlRate;
sc->sc_stats.ast_tx_protect++;
}
@@ -3803,13 +4381,31 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
if ((flags & HAL_TXDESC_NOACK) == 0 &&
(wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
u_int16_t dur;
- /*
- * XXX not right with fragmentation.
- */
if (shortPreamble)
dur = rt->info[rix].spAckDuration;
else
dur = rt->info[rix].lpAckDuration;
+ if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) {
+ dur += dur; /* additional SIFS+ACK */
+ KASSERT(m0->m_nextpkt != NULL, ("no fragment"));
+ /*
+ * Include the size of next fragment so NAV is
+ * updated properly. The last fragment uses only
+ * the ACK duration
+ */
+ dur += ath_hal_computetxtime(ah, rt,
+ m0->m_nextpkt->m_pkthdr.len,
+ rix, shortPreamble);
+ }
+ if (isfrag) {
+ /*
+ * Force hardware to use computed duration for next
+ * fragment by disabling multi-rate retry which updates
+ * duration based on the multi-rate duration table.
+ */
+ ismrr = 0;
+ try0 = ATH_TXMGTTRY; /* XXX? */
+ }
*(u_int16_t *)wh->i_dur = htole16(dur);
}
@@ -3859,8 +4455,15 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
} else
ctsrate = 0;
+ /*
+ * At this point we are committed to sending the frame
+ * and we don't need to look at m_nextpkt; clear it in
+ * case this frame is part of frag chain.
+ */
+ m0->m_nextpkt = NULL;
+
if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
- ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len,
+ ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
sc->sc_hwmap[txrate].ieeerate, -1);
if (bpf_peers_present(ic->ic_rawbpf))
@@ -3872,6 +4475,8 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
sc->sc_tx_th.wt_flags = sc->sc_hwmap[txrate].txflags;
if (iswep)
sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+ if (isfrag)
+ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_FRAG;
sc->sc_tx_th.wt_rate = sc->sc_hwmap[txrate].ieeerate;
sc->sc_tx_th.wt_txpower = ni->ni_txpower;
sc->sc_tx_th.wt_antenna = sc->sc_txantenna;
@@ -3880,7 +4485,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
&sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
- /*
+ /*
* Determine if a tx interrupt should be generated for
* this descriptor. We take a tx interrupt to reap
* descriptors when the h/w hits an EOL condition or
@@ -4002,6 +4607,8 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
sc->sc_stats.ast_tx_fifoerr++;
if (ts->ts_status & HAL_TXERR_FILT)
sc->sc_stats.ast_tx_filtered++;
+ if (bf->bf_m->m_flags & M_FF)
+ sc->sc_stats.ast_ff_txerr++;
}
sr = ts->ts_shortretry;
lr = ts->ts_longretry;
@@ -4021,6 +4628,13 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ath_rate_tx_complete(sc, an, bf);
}
/*
+ * Do any tx complete callback. Note this must
+ * be done before releasing the node reference.
+ */
+ if (bf->bf_m->m_flags & M_TXCB)
+ ieee80211_process_callback(ni, bf->bf_m,
+ ts->ts_status);
+ /*
* Reclaim reference to node.
*
* NB: the node may be reclaimed here if, for example
@@ -4032,6 +4646,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
+
m_freem(bf->bf_m);
bf->bf_m = NULL;
bf->bf_node = NULL;
@@ -4040,6 +4655,11 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc);
}
+ /*
+ * Flush fast-frame staging queue when traffic slows.
+ */
+ if (txq->axq_depth <= 1)
+ ath_ff_stageq_flush(sc, txq, ath_ff_always);
return nacked;
}
@@ -4066,7 +4686,7 @@ ath_tx_proc_q0(void *arg, int npending)
if (txqactive(sc->sc_ah, sc->sc_cabq->axq_qnum))
ath_tx_processq(sc, sc->sc_cabq);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->sc_tx_timer = 0;
+ ifp->if_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, ATH_LED_TX);
@@ -4103,7 +4723,7 @@ ath_tx_proc_q0123(void *arg, int npending)
sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->sc_tx_timer = 0;
+ ifp->if_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, ATH_LED_TX);
@@ -4132,7 +4752,7 @@ ath_tx_proc(void *arg, int npending)
sc->sc_lastrx = ath_hal_gettsf64(sc->sc_ah);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->sc_tx_timer = 0;
+ ifp->if_timer = 0;
if (sc->sc_softled)
ath_led_event(sc, ATH_LED_TX);
@@ -4169,13 +4789,11 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
ath_printtxbuf(bf, txq->axq_qnum, ix,
ath_hal_txprocdesc(ah, bf->bf_desc,
&bf->bf_status.ds_txstat) == HAL_OK);
- ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t),
+ ieee80211_dump_pkt(&sc->sc_ic, mtod(bf->bf_m, caddr_t),
bf->bf_m->m_len, 0, -1);
}
#endif /* ATH_DEBUG */
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
- m_freem(bf->bf_m);
- bf->bf_m = NULL;
ni = bf->bf_node;
bf->bf_node = NULL;
if (ni != NULL) {
@@ -4184,6 +4802,9 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
*/
ieee80211_free_node(ni);
}
+ m_freem(bf->bf_m);
+ bf->bf_m = NULL;
+
ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc);
@@ -4235,13 +4856,13 @@ ath_draintxq(struct ath_softc *sc)
ath_printtxbuf(bf, sc->sc_bhalq, 0,
ath_hal_txprocdesc(ah, bf->bf_desc,
&bf->bf_status.ds_txstat) == HAL_OK);
- ieee80211_dump_pkt(mtod(bf->bf_m, caddr_t),
+ ieee80211_dump_pkt(&sc->sc_ic, mtod(bf->bf_m, caddr_t),
bf->bf_m->m_len, 0, -1);
}
}
#endif /* ATH_DEBUG */
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- sc->sc_tx_timer = 0;
+ ifp->if_timer = 0;
}
/*
@@ -4278,6 +4899,10 @@ ath_stoprecv(struct ath_softc *sc)
}
}
#endif
+ if (sc->sc_rxpending != NULL) {
+ m_freem(sc->sc_rxpending);
+ sc->sc_rxpending = NULL;
+ }
sc->sc_rxlink = NULL; /* just in case */
#undef PA2DESC
}
@@ -4292,6 +4917,7 @@ ath_startrecv(struct ath_softc *sc)
struct ath_buf *bf;
sc->sc_rxlink = NULL;
+ sc->sc_rxpending = NULL;
STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
int error = ath_rxbuf_init(sc, bf);
if (error != 0) {
@@ -4316,9 +4942,7 @@ ath_startrecv(struct ath_softc *sc)
static void
ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
{
- struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_phymode mode;
- u_int16_t flags;
/*
* Change channels and update the h/w rate map
@@ -4329,30 +4953,18 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
else if (IEEE80211_IS_CHAN_QUARTER(chan))
mode = IEEE80211_MODE_QUARTER;
else
- mode = ieee80211_chan2mode(ic, chan);
+ mode = ieee80211_chan2mode(chan);
if (mode != sc->sc_curmode)
ath_setcurmode(sc, mode);
- /*
- * Update BPF state. NB: ethereal et. al. don't handle
- * merged flags well so pick a unique mode for their use.
- */
- if (IEEE80211_IS_CHAN_A(chan))
- flags = IEEE80211_CHAN_A;
- /* XXX 11g schizophrenia */
- else if (IEEE80211_IS_CHAN_ANYG(chan))
- flags = IEEE80211_CHAN_G;
- else
- flags = IEEE80211_CHAN_B;
- if (IEEE80211_IS_CHAN_T(chan))
- flags |= IEEE80211_CHAN_TURBO;
- if (IEEE80211_IS_CHAN_HALF(chan))
- flags |= IEEE80211_CHAN_HALF;
- if (IEEE80211_IS_CHAN_QUARTER(chan))
- flags |= IEEE80211_CHAN_QUARTER;
- sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
- htole16(chan->ic_freq);
- sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
- htole16(flags);
+
+ sc->sc_rx_th.wr_chan_flags = htole32(chan->ic_flags);
+ sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags;
+ sc->sc_rx_th.wr_chan_freq = htole16(chan->ic_freq);
+ sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq;
+ sc->sc_rx_th.wr_chan_ieee = chan->ic_ieee;
+ sc->sc_tx_th.wt_chan_ieee = sc->sc_rx_th.wr_chan_ieee;
+ sc->sc_rx_th.wr_chan_maxpow = chan->ic_maxregpower;
+ sc->sc_tx_th.wt_chan_maxpow = sc->sc_rx_th.wr_chan_maxpow;
}
/*
@@ -4409,7 +5021,7 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
* the flags constrained to reflect the current
* operating mode.
*/
- ath_mapchan(ic, &hchan, chan);
+ ath_mapchan(&hchan, chan);
DPRINTF(sc, ATH_DEBUG_RESET,
"%s: %u (%u MHz, hal flags 0x%x) -> %u (%u MHz, hal flags 0x%x)\n",
@@ -4458,7 +5070,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
* Change channels and update the h/w rate map
* if we're switching; e.g. 11a to 11b/g.
*/
- ic->ic_ibss_chan = chan;
ath_chan_change(sc, chan);
/*
@@ -4488,16 +5099,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
return 0;
}
-static void
-ath_next_scan(void *arg)
-{
- struct ath_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_next_scan(ic);
-}
-
/*
* Periodically recalibrate the PHY to account
* for temperature/environment changes.
@@ -4533,7 +5134,7 @@ ath_calibrate(void *arg)
ath_hal_process_noisefloor(ah);
/*
* Poll more frequently when the IQ calibration is in
- * progress to speedup loading the final settings.
+ * progress to speedup loading the final settings.
* We temper this aggressive polling with an exponential
* back off after 4 tries up to ath_calinterval.
*/
@@ -4557,6 +5158,63 @@ ath_calibrate(void *arg)
ath_calibrate, sc);
}
+static void
+ath_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t rfilt;
+
+ /* XXX calibration timer? */
+
+ sc->sc_scanning = 1;
+ sc->sc_syncbeacon = 0;
+ rfilt = ath_calcrxfilter(sc);
+ ath_hal_setrxfilter(ah, rfilt);
+ ath_hal_setassocid(ah, ifp->if_broadcastaddr, 0);
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0\n",
+ __func__, rfilt, ether_sprintf(ifp->if_broadcastaddr));
+}
+
+static void
+ath_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+ struct ath_hal *ah = sc->sc_ah;
+ u_int32_t rfilt;
+
+ sc->sc_scanning = 0;
+ rfilt = ath_calcrxfilter(sc);
+ ath_hal_setrxfilter(ah, rfilt);
+ ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid);
+
+ ath_hal_process_noisefloor(ah);
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n",
+ __func__, rfilt, ether_sprintf(sc->sc_curbssid),
+ sc->sc_curaid);
+}
+
+static void
+ath_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct ath_softc *sc = ifp->if_softc;
+
+ (void) ath_chan_set(sc, ic->ic_curchan);
+ /*
+ * If we are returning to our bss channel then mark state
+ * so the next recv'd beacon's tsf will be used to sync the
+ * beacon timers. Note that since we only hear beacons in
+ * sta/ibss mode this has no effect in other operating modes.
+ */
+ if (!sc->sc_scanning && ic->ic_curchan == ic->ic_bsschan)
+ sc->sc_syncbeacon = 1;
+}
+
static int
ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
@@ -4564,8 +5222,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
struct ath_softc *sc = ifp->if_softc;
struct ath_hal *ah = sc->sc_ah;
struct ieee80211_node *ni;
- int i, error;
- const u_int8_t *bssid;
+ int i, error, stamode;
u_int32_t rfilt;
static const HAL_LED_STATE leds[] = {
HAL_LED_INIT, /* IEEE80211_S_INIT */
@@ -4579,7 +5236,6 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
ieee80211_state_name[ic->ic_state],
ieee80211_state_name[nstate]);
- callout_stop(&sc->sc_scan_ch);
callout_stop(&sc->sc_cal_ch);
callout_stop(&sc->sc_dfs_ch);
ath_hal_setledstate(ah, leds[nstate]); /* set LED */
@@ -4604,26 +5260,28 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
goto done;
}
ni = ic->ic_bss;
- error = ath_chan_set(sc, ic->ic_curchan);
- if (error != 0)
- goto bad;
- rfilt = ath_calcrxfilter(sc, nstate);
- if (nstate == IEEE80211_S_SCAN)
- bssid = ifp->if_broadcastaddr;
- else
- bssid = ni->ni_bssid;
+
+ rfilt = ath_calcrxfilter(sc);
+ stamode = (sc->sc_opmode == HAL_M_STA || sc->sc_opmode == HAL_M_IBSS);
+ if (stamode && nstate == IEEE80211_S_RUN) {
+ sc->sc_curaid = ni->ni_associd;
+ IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid);
+ } else
+ sc->sc_curaid = 0;
+
+ DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n",
+ __func__, rfilt, ether_sprintf(sc->sc_curbssid),
+ sc->sc_curaid);
+
ath_hal_setrxfilter(ah, rfilt);
- DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s\n",
- __func__, rfilt, ether_sprintf(bssid));
+ if (stamode)
+ ath_hal_setassocid(ah, sc->sc_curbssid, ni->ni_associd);
- if (nstate == IEEE80211_S_RUN && ic->ic_opmode == IEEE80211_M_STA)
- ath_hal_setassocid(ah, bssid, ni->ni_associd);
- else
- ath_hal_setassocid(ah, bssid, 0);
- if (ic->ic_flags & IEEE80211_F_PRIVACY) {
+ if (ic->ic_opmode != IEEE80211_M_STA &&
+ (ic->ic_flags & IEEE80211_F_PRIVACY)) {
for (i = 0; i < IEEE80211_WEP_NKID; i++)
if (ath_hal_keyisvalid(ah, i))
- ath_hal_keysetmac(ah, i, bssid);
+ ath_hal_keysetmac(ah, i, ni->ni_bssid);
}
/*
@@ -4632,9 +5290,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
*/
ath_rate_newstate(sc, nstate);
- if (ic->ic_opmode == IEEE80211_M_MONITOR) {
- /* nothing to do */;
- } else if (nstate == IEEE80211_S_RUN) {
+ if (nstate == IEEE80211_S_RUN) {
DPRINTF(sc, ATH_DEBUG_STATE,
"%s(RUN): ic_flags=0x%08x iv=%d bssid=%s "
"capinfo=0x%04x chan=%d\n"
@@ -4692,7 +5348,6 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
default:
break;
}
-
/*
* Let the hal process statistics collected during a
* scan so it can provide calibrated noise floor data.
@@ -4706,7 +5361,7 @@ ath_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
} else {
ath_hal_intrset(ah,
- sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
+ sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
}
done:
@@ -4721,10 +5376,6 @@ done:
/* start periodic recalibration timer */
callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
ath_calibrate, sc);
- } else if (nstate == IEEE80211_S_SCAN) {
- /* start ap/neighbor scan timer */
- callout_reset(&sc->sc_scan_ch, (ath_dwelltime * hz) / 1000,
- ath_next_scan, sc);
}
bad:
return error;
@@ -4786,16 +5437,11 @@ static int
ath_getchannels(struct ath_softc *sc,
HAL_REG_DOMAIN rd, HAL_CTRY_CODE cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
{
-#define COMPAT \
- (CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE|CHANNEL_HALF|CHANNEL_QUARTER)
-#define IS_CHAN_PUBLIC_SAFETY(_c) \
- (((_c)->channelFlags & CHANNEL_5GHZ) && \
- ((_c)->channel > 4940 && (_c)->channel < 4990))
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = sc->sc_ifp;
struct ath_hal *ah = sc->sc_ah;
HAL_CHANNEL *chans;
- int i, ix, nchan;
+ int i, nchan;
u_int32_t regdomain;
chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
@@ -4814,70 +5460,49 @@ ath_getchannels(struct ath_softc *sc,
}
/*
- * Convert HAL channels to ieee80211 ones and insert
- * them in the table according to their channel number.
+ * Convert HAL channels to ieee80211 ones.
*/
memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
for (i = 0; i < nchan; i++) {
HAL_CHANNEL *c = &chans[i];
- u_int16_t flags;
+ struct ieee80211_channel *ichan = &ic->ic_channels[i];
- /*
- * XXX we're not ready to handle the ieee number mapping
- * for public safety channels as they overlap with any
- * 2GHz channels; for now use a non-public safety
- * numbering that is non-overlapping.
- */
- ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
- if (IS_CHAN_PUBLIC_SAFETY(c))
- ix += 37; /* XXX */
- if (ix > IEEE80211_CHAN_MAX) {
- if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n",
- ix, c->channel, c->channelFlags);
- continue;
- }
- if (ix < 0) {
- /* XXX can't handle stuff <2400 right now */
- if (bootverbose)
- if_printf(ifp, "hal channel %d (%u/%x) "
- "cannot be handled; ignored\n",
- ix, c->channel, c->channelFlags);
- continue;
- }
+ ichan->ic_ieee = ath_hal_mhz2ieee(ah, c->channel,
+ c->channelFlags);
if (bootverbose)
if_printf(ifp, "hal channel %u/%x -> %u\n",
- c->channel, c->channelFlags, ix);
- /*
- * Calculate net80211 flags; most are compatible
- * but some need massaging. Note the static turbo
- * conversion can be removed once net80211 is updated
- * to understand static vs. dynamic turbo.
- */
- flags = c->channelFlags & COMPAT;
- if (c->channelFlags & CHANNEL_STURBO)
- flags |= IEEE80211_CHAN_TURBO;
+ c->channel, c->channelFlags, ichan->ic_ieee);
+ ichan->ic_freq = c->channel;
+
+ if ((c->channelFlags & CHANNEL_PUREG) == CHANNEL_PUREG) {
+ /*
+ * Except for AR5211, HAL's PUREG means mixed
+ * DSSS and OFDM.
+ */
+ ichan->ic_flags = c->channelFlags &~ CHANNEL_PUREG;
+ ichan->ic_flags |= IEEE80211_CHAN_G;
+ } else {
+ ichan->ic_flags = c->channelFlags;
+ }
+
if (ath_hal_isgsmsku(ah)) {
/* remap to true frequencies */
- c->channel = 922 + (2422 - c->channel);
- flags |= IEEE80211_CHAN_GSM;
- ix = ieee80211_mhz2ieee(c->channel, flags);
- }
- if (ic->ic_channels[ix].ic_freq == 0) {
- ic->ic_channels[ix].ic_freq = c->channel;
- ic->ic_channels[ix].ic_flags = flags;
- } else {
- /* channels overlap; e.g. 11g and 11b */
- ic->ic_channels[ix].ic_flags |= flags;
+ ichan->ic_freq = 922 + (2422 - ichan->ic_freq);
+ ichan->ic_flags |= IEEE80211_CHAN_GSM;
+ ichan->ic_ieee = ieee80211_mhz2ieee(ichan->ic_freq,
+ ichan->ic_flags);
}
+ ichan->ic_maxregpower = c->maxRegTxPower; /* dBm */
+ ichan->ic_maxpower = c->maxTxPower; /* 1/2 dBm */
+ ichan->ic_minpower = c->minTxPower; /* 1/2 dBm */
}
+ ic->ic_nchans = nchan;
free(chans, M_TEMP);
(void) ath_hal_getregdomain(ah, &sc->sc_regdomain);
ath_hal_getcountrycode(ah, &sc->sc_countrycode);
sc->sc_xchanmode = xchanmode;
sc->sc_outdoor = outdoor;
return 0;
-#undef IS_CHAN_PUBLIC_SAFETY
-#undef COMPAT
}
static void
@@ -4950,7 +5575,7 @@ ath_update_txpow(struct ath_softc *sc)
if (ath_hal_gettxpowlimit(ah, &txpow))
ic->ic_txpowlimit = sc->sc_curtxpow = txpow;
}
- /*
+ /*
* Fetch max tx power level for status requests.
*/
if (ath_hal_getmaxtxpow(sc->sc_ah, &txpow))
@@ -4980,12 +5605,20 @@ ath_rate_setup(struct ath_softc *sc, u_int mode)
rt = ath_hal_getratetable(ah, HAL_MODE_11G);
break;
case IEEE80211_MODE_TURBO_A:
- /* XXX until static/dynamic turbo is fixed */
- rt = ath_hal_getratetable(ah, HAL_MODE_TURBO);
+ rt = ath_hal_getratetable(ah, HAL_MODE_108A);
break;
case IEEE80211_MODE_TURBO_G:
rt = ath_hal_getratetable(ah, HAL_MODE_108G);
break;
+ case IEEE80211_MODE_STURBO_A:
+ rt = ath_hal_getratetable(ah, HAL_MODE_TURBO);
+ break;
+ case IEEE80211_MODE_11NA:
+ rt = ath_hal_getratetable(ah, HAL_MODE_11NA_HT20);
+ break;
+ case IEEE80211_MODE_11NG:
+ rt = ath_hal_getratetable(ah, HAL_MODE_11NG_HT20);
+ break;
default:
DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid mode %u\n",
__func__, mode);
@@ -5039,6 +5672,8 @@ ath_setcurmode(struct ath_softc *sc, enum ieee80211_phymode mode)
}
sc->sc_hwmap[i].ieeerate =
rt->info[ix].dot11Rate & IEEE80211_RATE_VAL;
+ if (rt->info[ix].phy == IEEE80211_T_HT)
+ sc->sc_hwmap[i].ieeerate |= 0x80; /* MCS */
sc->sc_hwmap[i].txflags = IEEE80211_RADIOTAP_F_DATAPAD;
if (rt->info[ix].shortPreamble ||
rt->info[ix].phy == IEEE80211_T_OFDM)
@@ -5120,21 +5755,13 @@ static void
ath_watchdog(struct ifnet *ifp)
{
struct ath_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- ifp->if_timer = 0;
- if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
- return;
- if (sc->sc_tx_timer) {
- if (--sc->sc_tx_timer == 0) {
- if_printf(ifp, "device timeout\n");
- ath_reset(ifp);
- ifp->if_oerrors++;
- sc->sc_stats.ast_watchdog++;
- } else
- ifp->if_timer = 1;
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && !sc->sc_invalid) {
+ if_printf(ifp, "device timeout\n");
+ ath_reset(ifp);
+ ifp->if_oerrors++;
+ sc->sc_stats.ast_watchdog++;
}
- ieee80211_watchdog(ic);
}
#ifdef ATH_DIAGAPI
@@ -5249,9 +5876,8 @@ ath_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
/* NB: embed these numbers to get a consistent view */
sc->sc_stats.ast_tx_packets = ifp->if_opackets;
sc->sc_stats.ast_rx_packets = ifp->if_ipackets;
- sc->sc_stats.ast_rx_rssi = ieee80211_getrssi(ic);
- sc->sc_stats.ast_rx_noise =
- ath_hal_getchannoise(sc->sc_ah, &sc->sc_curchan);
+ ieee80211_getsignal(ic, &sc->sc_stats.ast_rx_rssi,
+ &sc->sc_stats.ast_rx_noise);
sc->sc_stats.ast_tx_rate = sc->sc_hwmap[sc->sc_txrate].ieeerate;
ATH_UNLOCK(sc);
/*
@@ -5514,7 +6140,7 @@ ath_sysctl_countrycode(SYSCTL_HANDLER_ARGS)
if (error || !req->newptr)
return error;
error = ath_getchannels(sc, sc->sc_regdomain, cc,
- sc->sc_outdoor, sc->sc_xchanmode);
+ sc->sc_outdoor != 0, sc->sc_xchanmode != 0);
if (error != 0)
return error;
ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
@@ -5536,7 +6162,7 @@ ath_sysctl_regdomain(SYSCTL_HANDLER_ARGS)
if (!ath_hal_setregdomain(sc->sc_ah, rd))
return EINVAL;
error = ath_getchannels(sc, rd, sc->sc_countrycode,
- sc->sc_outdoor, sc->sc_xchanmode);
+ sc->sc_outdoor != 0, sc->sc_xchanmode != 0);
if (error != 0)
return error;
ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
@@ -5643,6 +6269,16 @@ ath_sysctlattach(struct ath_softc *sc)
"tpcts", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
ath_sysctl_tpcts, "I", "tx power for cts frames");
}
+ if (ath_hal_hasfastframes(sc->sc_ah)) {
+ sc->sc_fftxqmin = ATH_FF_TXQMIN;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "fftxqmin", CTLFLAG_RW, &sc->sc_fftxqmin, 0,
+ "min frames before fast-frame staging");
+ sc->sc_fftxqmax = ATH_FF_TXQMAX;
+ SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
+ "fftxqmax", CTLFLAG_RW, &sc->sc_fftxqmax, 0,
+ "max queued frames before tail drop");
+ }
if (ath_hal_hasrfsilent(ah)) {
SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO,
"rfsilent", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
@@ -5771,7 +6407,7 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
atype = HAL_PKT_TYPE_PSPOLL;
if (IFF_DUMPPKTS(sc, ATH_DEBUG_XMIT))
- ieee80211_dump_pkt(mtod(m0, caddr_t), m0->m_len,
+ ieee80211_dump_pkt(ic, mtod(m0, caddr_t), m0->m_len,
sc->sc_hwmap[txrate].ieeerate, -1);
if (bpf_peers_present(ic->ic_rawbpf))
@@ -5899,8 +6535,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
if (ath_tx_raw_start(sc, ni, bf, m, params))
goto bad;
}
- sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
+ ifp->if_timer = 5;
return 0;
bad:
diff --git a/sys/dev/ath/if_athioctl.h b/sys/dev/ath/if_athioctl.h
index 9f48ac2..ccd7220 100644
--- a/sys/dev/ath/if_athioctl.h
+++ b/sys/dev/ath/if_athioctl.h
@@ -69,8 +69,8 @@ struct ath_stats {
u_int32_t ast_tx_shortpre;/* tx frames with short preamble */
u_int32_t ast_tx_altrate; /* tx frames with alternate rate */
u_int32_t ast_tx_protect; /* tx frames with protection */
- u_int32_t ast_unused1;
- u_int32_t ast_unused2;
+ u_int32_t ast_tx_ctsburst;/* tx frames with cts and bursting */
+ u_int32_t ast_tx_ctsext; /* tx frames with cts extension */
u_int32_t ast_rx_nombuf; /* rx setup failed 'cuz no mbuf */
u_int32_t ast_rx_busdma; /* rx setup failed for dma resrcs */
u_int32_t ast_rx_orn; /* rx failed 'cuz of desc overrun */
@@ -87,7 +87,6 @@ struct ath_stats {
u_int32_t ast_rx_ctl; /* rx discarded 'cuz ctl frame */
int8_t ast_tx_rssi; /* tx rssi of last ack */
int8_t ast_rx_rssi; /* rx rssi from histogram */
- int8_t ast_rx_noise; /* rx noise floor */
u_int8_t ast_tx_rate; /* IEEE rate of last unicast tx */
u_int32_t ast_be_xmit; /* beacons transmitted */
u_int32_t ast_be_nombuf; /* beacon setup failed 'cuz no mbuf */
@@ -104,7 +103,13 @@ struct ath_stats {
u_int32_t ast_cabq_xmit; /* cabq frames transmitted */
u_int32_t ast_cabq_busy; /* cabq found busy */
u_int32_t ast_tx_raw; /* tx frames through raw api */
- u_int32_t ast_pad[29];
+ u_int32_t ast_ff_txok; /* fast frames tx'd successfully */
+ u_int32_t ast_ff_txerr; /* fast frames tx'd w/ error */
+ u_int32_t ast_ff_rx; /* fast frames rx'd */
+ u_int32_t ast_ff_flush; /* fast frames flushed from staging q */
+ u_int32_t ast_tx_qfull; /* tx dropped 'cuz of queue limit */
+ int8_t ast_rx_noise; /* rx noise floor */
+ u_int32_t ast_pad[22];
};
#define SIOCGATHSTATS _IOWR('i', 137, struct ifreq)
@@ -131,10 +136,10 @@ struct ath_diag {
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
- (1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct ath_rx_radiotap_header {
@@ -142,20 +147,23 @@ struct ath_rx_radiotap_header {
u_int64_t wr_tsf;
u_int8_t wr_flags;
u_int8_t wr_rate;
- u_int16_t wr_chan_freq;
- u_int16_t wr_chan_flags;
- u_int8_t wr_antsignal;
- u_int8_t wr_antnoise;
+ int8_t wr_antsignal;
+ int8_t wr_antnoise;
u_int8_t wr_antenna;
-};
+ u_int8_t wr_pad[3];
+ u_int32_t wr_chan_flags;
+ u_int16_t wr_chan_freq;
+ u_int8_t wr_chan_ieee;
+ int8_t wr_chan_maxpow;
+} __packed;
#define ATH_TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
- (1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct ath_tx_radiotap_header {
@@ -163,10 +171,12 @@ struct ath_tx_radiotap_header {
u_int64_t wt_tsf;
u_int8_t wt_flags;
u_int8_t wt_rate;
- u_int16_t wt_chan_freq;
- u_int16_t wt_chan_flags;
u_int8_t wt_txpower;
u_int8_t wt_antenna;
-};
+ u_int32_t wt_chan_flags;
+ u_int16_t wt_chan_freq;
+ u_int8_t wt_chan_ieee;
+ int8_t wt_chan_maxpow;
+} __packed;
#endif /* _DEV_ATH_ATHIOCTL_H */
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index 7fd700e..af1045d 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -35,8 +35,6 @@
#ifndef _DEV_ATH_ATHVAR_H
#define _DEV_ATH_ATHVAR_H
-#include <sys/taskqueue.h>
-
#include <contrib/dev/ath/ah.h>
#include <contrib/dev/ath/ah_desc.h>
#include <net80211/ieee80211_radiotap.h>
@@ -49,7 +47,7 @@
#define ATH_RXBUF 40 /* number of RX buffers */
#endif
#ifndef ATH_TXBUF
-#define ATH_TXBUF 100 /* number of TX buffers */
+#define ATH_TXBUF 200 /* number of TX buffers */
#endif
#define ATH_TXDESC 10 /* number of descriptors per buffer */
#define ATH_TXMAXTRY 11 /* max number of transmit attempts */
@@ -71,10 +69,19 @@
#define ATH_KEYMAX 128 /* max key cache size we handle */
#define ATH_KEYBYTES (ATH_KEYMAX/NBBY) /* storage space in bytes */
+#define ATH_FF_TXQMIN 2 /* min txq depth for staging */
+#define ATH_FF_TXQMAX 50 /* maximum # of queued frames allowed */
+#define ATH_FF_STAGEMAX 5 /* max waiting period for staged frame*/
+
+struct taskqueue;
+struct kthread;
+struct ath_buf;
+
/* driver-specific node state */
struct ath_node {
struct ieee80211_node an_node; /* base class */
u_int32_t an_avgrssi; /* average rssi over all rx frames */
+ struct ath_buf *an_ff_buf[WME_NUM_AC]; /* ff staging area */
/* variable-length rate control state follows */
};
#define ATH_NODE(ni) ((struct ath_node *)(ni))
@@ -93,6 +100,8 @@ struct ath_node {
struct ath_buf {
STAILQ_ENTRY(ath_buf) bf_list;
+ TAILQ_ENTRY(ath_buf) bf_stagelist; /* stage queue list */
+ u_int32_t bf_age; /* age when placed on stageq */
int bf_nseg;
int bf_flags; /* tx descriptor flags */
struct ath_desc *bf_desc; /* virtual addr of desc */
@@ -138,6 +147,13 @@ struct ath_txq {
STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */
struct mtx axq_lock; /* lock on q and link */
char axq_name[12]; /* e.g. "ath0_txq4" */
+ /*
+ * Fast-frame state. The staging queue holds awaiting
+ * a fast-frame pairing. Buffers on this queue are
+ * assigned an ``age'' and flushed when they wait too long.
+ */
+ TAILQ_HEAD(axq_headtype, ath_buf) axq_stageq;
+ u_int32_t axq_curage; /* queue age */
};
#define ATH_TXQ_LOCK_INIT(_sc, _tq) do { \
@@ -153,6 +169,7 @@ struct ath_txq {
#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \
+ (_tq)->axq_curage++; \
} while (0)
#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \
STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \
@@ -172,7 +189,7 @@ struct ath_softc {
void (*sc_recv_mgmt)(struct ieee80211com *,
struct mbuf *,
struct ieee80211_node *,
- int, int, u_int32_t);
+ int, int, int, u_int32_t);
int (*sc_newstate)(struct ieee80211com *,
enum ieee80211_state, int);
void (*sc_node_free)(struct ieee80211_node *);
@@ -196,10 +213,12 @@ struct ath_softc {
sc_ledstate: 1, /* LED on/off state */
sc_blinking: 1, /* LED blink operation active */
sc_mcastkey: 1, /* mcast key cache search */
+ sc_scanning: 1, /* scanning active */
sc_syncbeacon:1,/* sync/resync beacon timers */
sc_hasclrkey:1, /* CLR key supported */
sc_xchanmode: 1,/* extended channel mode */
- sc_outdoor : 1;/* outdoor operation */
+ sc_outdoor : 1,/* outdoor operation */
+ sc_dturbo : 1; /* dynamic turbo in use */
/* rate tables */
#define IEEE80211_MODE_HALF (IEEE80211_MODE_MAX+0)
#define IEEE80211_MODE_QUARTER (IEEE80211_MODE_MAX+1)
@@ -208,7 +227,9 @@ struct ath_softc {
enum ieee80211_phymode sc_curmode; /* current phy mode */
HAL_OPMODE sc_opmode; /* current operating mode */
u_int16_t sc_curtxpow; /* current tx power limit */
+ u_int16_t sc_curaid; /* current association id */
HAL_CHANNEL sc_curchan; /* current h/w channel */
+ u_int8_t sc_curbssid[IEEE80211_ADDR_LEN];
u_int8_t sc_rixmap[256]; /* IEEE to h/w rate table ix */
struct {
u_int8_t ieeerate; /* IEEE rate */
@@ -220,7 +241,10 @@ struct ath_softc {
u_int8_t sc_minrateix; /* min h/w rate index */
u_int8_t sc_mcastrix; /* mcast h/w rate index */
u_int8_t sc_protrix; /* protection rate index */
+ u_int8_t sc_lastdatarix; /* last data frame rate index */
u_int sc_mcastrate; /* ieee rate for mcastrateix */
+ u_int sc_fftxqmin; /* min frames before staging */
+ u_int sc_fftxqmax; /* max frames before drop */
u_int sc_txantenna; /* tx antenna (fixed or auto) */
HAL_INT sc_imask; /* interrupt mask copy */
u_int sc_keymax; /* size of key cache */
@@ -253,6 +277,7 @@ struct ath_softc {
struct ath_descdma sc_rxdma; /* RX descriptos */
ath_bufhead sc_rxbuf; /* receive buffer */
+ struct mbuf *sc_rxpending; /* pending receive data */
u_int32_t *sc_rxlink; /* link ptr in last RX desc */
struct task sc_rxtask; /* rx int processing */
struct task sc_rxorntask; /* rxorn int processing */
@@ -264,7 +289,6 @@ struct ath_softc {
ath_bufhead sc_txbuf; /* transmit buffer */
struct mtx sc_txbuflock; /* txbuf lock */
char sc_txname[12]; /* e.g. "ath0_buf" */
- int sc_tx_timer; /* transmit timeout */
u_int sc_txqsetup; /* h/w queues setup */
u_int sc_txintrperiod;/* tx interrupt batching */
struct ath_txq sc_txq[HAL_NUM_TX_QUEUES];
@@ -291,7 +315,6 @@ struct ath_softc {
int sc_calinterval; /* current polling interval */
int sc_caltries; /* cals at current interval */
HAL_NODE_STATS sc_halstats; /* station-mode rssi stats */
- struct callout sc_scan_ch; /* callout handle for scan */
struct callout sc_dfs_ch; /* callout handle for dfs */
};
#define sc_tx_th u_tx_rt.th
@@ -418,7 +441,7 @@ void ath_intr(void *);
((*(_ah)->ah_getDiagState)((_ah), (_id), \
(_indata), (_insize), (_outdata), (_outsize)))
#define ath_hal_getfatalstate(_ah, _outdata, _outsize) \
- ath_hal_getdiagstate(_ah, 29, NULL, 0, (void **)(_outdata), _outsize)
+ ath_hal_getdiagstate(_ah, 29, NULL, 0, (_outdata), _outsize)
#define ath_hal_setuptxqueue(_ah, _type, _irq) \
((*(_ah)->ah_setupTxQueue)((_ah), (_type), (_irq)))
#define ath_hal_resettxqueue(_ah, _q) \
@@ -517,6 +540,8 @@ void ath_intr(void *);
#else
#define ath_hal_getmcastkeysearch(_ah) 0
#endif
+#define ath_hal_hasfastframes(_ah) \
+ (ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK)
#define ath_hal_hasrfsilent(_ah) \
(ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK)
#define ath_hal_getrfkill(_ah) \
@@ -535,15 +560,8 @@ void ath_intr(void *);
(ath_hal_getcapability(_ah, HAL_CAP_TPC_CTS, 0, _ptpcts) == HAL_OK)
#define ath_hal_settpcts(_ah, _tpcts) \
ath_hal_setcapability(_ah, HAL_CAP_TPC_CTS, 0, _tpcts, NULL)
-#if HAL_ABI_VERSION < 0x05120700
-#define ath_hal_process_noisefloor(_ah)
-#define ath_hal_getchannoise(_ah, _c) (-96)
-#define HAL_CAP_TPC_ACK 100
-#define HAL_CAP_TPC_CTS 101
-#else
#define ath_hal_getchannoise(_ah, _c) \
((*(_ah)->ah_getChanNoise)((_ah), (_c)))
-#endif
#if HAL_ABI_VERSION < 0x05122200
#define HAL_TXQ_TXOKINT_ENABLE TXQ_FLAG_TXOKINT_ENABLE
#define HAL_TXQ_TXERRINT_ENABLE TXQ_FLAG_TXERRINT_ENABLE
@@ -561,6 +579,14 @@ void ath_intr(void *);
#define ath_hal_isgsmsku(ah) \
((ah)->ah_countryCode == 843)
#endif
+#if HAL_ABI_VERSION < 0x07050400
+/* compat shims so code compilers--it won't work though */
+#define CHANNEL_HT20 0x10000
+#define CHANNEL_HT40PLUS 0x20000
+#define CHANNEL_HT40MINUS 0x40000
+#define HAL_MODE_11NG_HT20 0x008000
+#define HAL_MODE_11NA_HT20 0x010000
+#endif
#define ath_hal_setuprxdesc(_ah, _ds, _size, _intreq) \
((*(_ah)->ah_setupRxDesc)((_ah), (_ds), (_size), (_intreq)))
diff --git a/sys/dev/awi/awi.c b/sys/dev/awi/awi.c
index 6b14f46..33f0a90 100644
--- a/sys/dev/awi/awi.c
+++ b/sys/dev/awi/awi.c
@@ -181,7 +181,7 @@ static int awi_intr_lock(struct awi_softc *);
static void awi_intr_unlock(struct awi_softc *);
static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int);
static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *,
- struct ieee80211_node *, int, int, u_int32_t);
+ struct ieee80211_node *, int, int, int, u_int32_t);
static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int,
int);
static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *);
@@ -525,9 +525,10 @@ awi_intr(void *arg)
if (status & AWI_INT_CMD)
awi_cmd_done(sc);
if (status & AWI_INT_SCAN_CMPLT) {
+ /* XXX revisit scanning */
if (sc->sc_ic.ic_state == IEEE80211_S_SCAN &&
sc->sc_substate == AWI_ST_NONE)
- ieee80211_next_scan(&sc->sc_ic);
+ ;
}
}
sc->sc_cansleep = ocansleep;
@@ -589,6 +590,7 @@ awi_init(struct ifnet *ifp)
sc->sc_mib_local.Acting_as_AP = 1;
break;
case IEEE80211_M_MONITOR:
+ case IEEE80211_M_WDS:
return ENODEV;
}
#if 0
@@ -596,9 +598,9 @@ awi_init(struct ifnet *ifp)
#endif
memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE);
sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID;
- sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen;
- memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid,
- ic->ic_des_esslen);
+ sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_ssid[0].len;
+ memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
/* configure basic rate */
if (ic->ic_phytype == IEEE80211_T_FH)
@@ -606,7 +608,7 @@ awi_init(struct ifnet *ifp)
else
rs = &ic->ic_sup_rates[IEEE80211_MODE_11B];
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
- rate = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ rate = ic->ic_fixed_rate;
} else {
rate = 0;
for (i = 0; i < rs->rs_nrates; i++) {
@@ -659,18 +661,18 @@ awi_init(struct ifnet *ifp)
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
ic->ic_opmode == IEEE80211_M_HOSTAP) {
- ni->ni_chan = ic->ic_ibss_chan;
+ ni->ni_chan = ic->ic_des_chan; /* XXX? */
ni->ni_intval = ic->ic_bintval;
ni->ni_rssi = 0;
ni->ni_rstamp = 0;
memset(&ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
ni->ni_rates =
- ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
+ ic->ic_sup_rates[ieee80211_chan2mode(ni->ni_chan)];
IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
- ni->ni_esslen = ic->ic_des_esslen;
- memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
+ ni->ni_esslen = ic->ic_des_ssid[0].len;
+ memcpy(ni->ni_essid, ic->ic_des_ssid[0].ssid, ni->ni_esslen);
ni->ni_capinfo = IEEE80211_CAPINFO_ESS;
if (ic->ic_phytype == IEEE80211_T_FH) {
ni->ni_fhdwell = 200; /* XXX */
@@ -812,7 +814,7 @@ awi_start(struct ifnet *ifp)
goto bad;
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
(m0->m_flags & M_PWR_SAV) == 0) {
- ieee80211_pwrsave(ic, ni, m0);
+ ieee80211_pwrsave(ni, m0);
continue;
}
m0 = ieee80211_encap(ic, m0, ni);
@@ -865,7 +867,7 @@ awi_start(struct ifnet *ifp)
#endif
if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2))
- ieee80211_dump_pkt(m0->m_data, m0->m_len,
+ ieee80211_dump_pkt(ic, m0->m_data, m0->m_len,
ic->ic_bss->ni_rates.
rs_rates[ic->ic_bss->ni_txrate] &
IEEE80211_RATE_VAL, -1);
@@ -930,7 +932,6 @@ awi_watchdog(struct ifnet *ifp)
ifp->if_timer = 1;
}
/* TODO: rate control */
- ieee80211_watchdog(&sc->sc_ic);
out:
sc->sc_cansleep = ocansleep;
}
@@ -1016,6 +1017,7 @@ awi_media_change(struct ifnet *ifp)
ime = ic->ic_media.ifm_cur;
if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) {
i = -1;
+ rate = ic->ic_fixed_rate;
} else {
struct ieee80211_rateset *rs =
&ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH)
@@ -1030,8 +1032,8 @@ awi_media_change(struct ifnet *ifp)
if (i == rs->rs_nrates)
return EINVAL;
}
- if (ic->ic_fixed_rate != i) {
- ic->ic_fixed_rate = i;
+ if (ic->ic_fixed_rate != rate) {
+ ic->ic_fixed_rate = rate;
error = ENETRESET;
}
@@ -1098,12 +1100,12 @@ awi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rate = 0;
else
- rate = ic->ic_sup_rates[mode].
- rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
+ rate = ic->ic_fixed_rate;
}
imr->ifm_active |= ieee80211_rate2media(ic, rate, mode);
switch (ic->ic_opmode) {
case IEEE80211_M_MONITOR: /* we should never reach here */
+ case IEEE80211_M_WDS:
break;
case IEEE80211_M_STA:
break;
@@ -1240,7 +1242,8 @@ awi_rx_int(struct awi_softc *sc)
}
if ((ifp->if_flags & IFF_DEBUG) &&
(ifp->if_flags & IFF_LINK2))
- ieee80211_dump_pkt(m->m_data, m->m_len,
+ ieee80211_dump_pkt(ic,
+ m->m_data, m->m_len,
rate / 5, rssi);
if ((ifp->if_flags & IFF_LINK0) ||
sc->sc_adhoc_ap)
@@ -1254,7 +1257,8 @@ awi_rx_int(struct awi_softc *sc)
}
ni = ieee80211_find_rxnode(ic,
mtod(m, struct ieee80211_frame_min *));
- ieee80211_input(ic, m, ni, rssi, rstamp);
+ /* XXX 0 for noise floor */
+ ieee80211_input(ic, m, ni, rssi, 0, rstamp);
ieee80211_free_node(ni);
} else
sc->sc_rxpend = m;
@@ -1337,7 +1341,6 @@ awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len)
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = len;
m->m_len = MHLEN;
- m->m_flags |= M_HASFCS;
} else {
MGET(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
@@ -1367,6 +1370,10 @@ awi_devget(struct awi_softc *sc, u_int32_t off, u_int16_t len)
*mp = m;
mp = &m->m_next;
}
+ if (top != NULL) {
+ /* Strip trailing 802.11 MAC FCS. */
+ m_adj(top, -IEEE80211_CRC_LEN);
+ }
return top;
}
@@ -1534,7 +1541,7 @@ awi_init_mibs(struct awi_softc *sc)
}
}
sc->sc_cur_chan = cs->cs_def;
- ic->ic_ibss_chan = &ic->ic_channels[cs->cs_def];
+ ic->ic_curchan = &ic->ic_channels[cs->cs_def]; /* XXX? */
sc->sc_mib_local.Fragmentation_Dis = 1;
sc->sc_mib_local.Add_PLCP_Dis = 0;
@@ -1942,7 +1949,7 @@ awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
case IEEE80211_S_INIT:
- ieee80211_begin_scan(ic, 0);
+ /* XXX revisit scanning */;
break;
case IEEE80211_S_SCAN:
/* scan next */
@@ -2112,14 +2119,14 @@ out:
static void
awi_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
struct ieee80211_node *ni,
- int subtype, int rssi, u_int32_t rstamp)
+ int subtype, int rssi, int nf, u_int32_t rstamp)
{
struct awi_softc *sc = ic->ic_ifp->if_softc;
/* probe request is handled by hardware */
if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_REQ)
return;
- (*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, rstamp);
+ (*sc->sc_recv_mgmt)(ic, m0, ni, subtype, rssi, nf, rstamp);
}
static int
diff --git a/sys/dev/awi/awivar.h b/sys/dev/awi/awivar.h
index f805b8f..762d1da 100644
--- a/sys/dev/awi/awivar.h
+++ b/sys/dev/awi/awivar.h
@@ -92,7 +92,7 @@ struct awi_softc {
enum ieee80211_state, int);
void (*sc_recv_mgmt)(struct ieee80211com *,
struct mbuf *, struct ieee80211_node *,
- int, int, u_int32_t);
+ int, int, int, u_int32_t);
int (*sc_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);
diff --git a/sys/dev/if_ndis/if_ndis.c b/sys/dev/if_ndis/if_ndis.c
index 0366398..f4a3e8c 100644
--- a/sys/dev/if_ndis/if_ndis.c
+++ b/sys/dev/if_ndis/if_ndis.c
@@ -478,7 +478,7 @@ ndis_attach(dev)
device_object *pdo;
struct ifnet *ifp = NULL;
int error = 0, len;
- int i;
+ int i, j;
sc = device_get_softc(dev);
#if __FreeBSD_version < 600031
@@ -817,10 +817,11 @@ nonettypes:
}
#undef SETRATE
#undef INCRATE
+ ic->ic_nchans = 12;
/*
* Taking yet more guesses here.
*/
- for (i = 1; i < IEEE80211_CHAN_MAX; i++) {
+ for (j = 0, i = 1; i <= 12; i++, j++) {
int chanflag = 0;
if (ic->ic_sup_rates[IEEE80211_MODE_11G].rs_nrates)
@@ -829,12 +830,11 @@ nonettypes:
chanflag |= IEEE80211_CHAN_B;
if (ic->ic_sup_rates[IEEE80211_MODE_11A].rs_nrates &&
i > 14)
- chanflag = IEEE80211_CHAN_A;
+ chanflag = IEEE80211_CHAN_A;
if (chanflag == 0)
break;
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, chanflag);
- ic->ic_channels[i].ic_flags = chanflag;
+ ic->ic_channels[j].ic_freq = ieee80211_ieee2mhz(i, chanflag);
+ ic->ic_channels[j].ic_flags = chanflag;
}
/*
@@ -897,8 +897,8 @@ got_crypto:
ieee80211_media_init(ic, ieee80211_media_change,
ndis_media_status);
#endif
- ic->ic_ibss_chan = IEEE80211_CHAN_ANYC;
- ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+ ic->ic_bsschan = IEEE80211_CHAN_ANYC;
+ ic->ic_bss->ni_chan = ic->ic_bsschan;
#ifdef IEEE80211_F_WPA
/* install key handing routines */
ic->ic_crypto.cs_key_set = ndis_add_key;
@@ -2392,16 +2392,16 @@ ndis_setstate_80211(sc)
config.nc_atimwin = 100;
if (config.nc_fhconfig.ncf_dwelltime == 0)
config.nc_fhconfig.ncf_dwelltime = 200;
- if (rval == 0 && ic->ic_ibss_chan != IEEE80211_CHAN_ANYC) {
+ if (rval == 0 && ic->ic_bsschan != IEEE80211_CHAN_ANYC) {
int chan, chanflag;
- chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
+ chan = ieee80211_chan2ieee(ic, ic->ic_bsschan);
chanflag = config.nc_dsconfig > 2500000 ? IEEE80211_CHAN_2GHZ :
IEEE80211_CHAN_5GHZ;
if (chan != ieee80211_mhz2ieee(config.nc_dsconfig / 1000, 0)) {
config.nc_dsconfig =
- ic->ic_ibss_chan->ic_freq * 1000;
- ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+ ic->ic_bsschan->ic_freq * 1000;
+ ic->ic_bss->ni_chan = ic->ic_bsschan;
len = sizeof(config);
config.nc_length = len;
config.nc_fhconfig.ncf_length =
@@ -2447,11 +2447,11 @@ ndis_setstate_80211(sc)
len = sizeof(ssid);
bzero((char *)&ssid, len);
- ssid.ns_ssidlen = ic->ic_des_esslen;
+ ssid.ns_ssidlen = ic->ic_des_ssid[0].len;
if (ssid.ns_ssidlen == 0) {
ssid.ns_ssidlen = 1;
} else
- bcopy(ic->ic_des_essid, ssid.ns_ssid, ssid.ns_ssidlen);
+ bcopy(ic->ic_des_ssid[0].ssid, ssid.ns_ssid, ssid.ns_ssidlen);
rval = ndis_set_info(sc, OID_802_11_SSID, &ssid, &len);
@@ -2497,6 +2497,9 @@ ndis_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
break;
+ case IEEE80211_M_WDS:
+ printf("WARNING: WDS operation mode not supported by NDIS\n");
+ break;
}
switch (ic->ic_curmode) {
case IEEE80211_MODE_11A:
@@ -2682,7 +2685,7 @@ ndis_getstate_80211(sc)
ic->ic_bss->ni_chan = &ic->ic_channels[chan];
ic->ic_des_chan = &ic->ic_channels[chan];
- ic->ic_ibss_chan = &ic->ic_channels[chan];
+ ic->ic_bsschan = &ic->ic_channels[chan];
#if __FreeBSD_version >= 600007
ic->ic_curchan = &ic->ic_channels[chan];
#endif
@@ -3190,6 +3193,8 @@ ndis_80211_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data)
bcopy((char *)wb->nwbx_ies +
sizeof(struct ndis_80211_fixed_ies),
cp, sr->isr_ie_len);
+ } else {
+ sr->isr_ie_len = 0;
}
sr->isr_len = roundup(sizeof(*sr) + sr->isr_ssid_len
+ sr->isr_ie_len, sizeof(uint32_t));
diff --git a/sys/dev/ipw/if_ipw.c b/sys/dev/ipw/if_ipw.c
index 974bcc9..2dca3cd 100644
--- a/sys/dev/ipw/if_ipw.c
+++ b/sys/dev/ipw/if_ipw.c
@@ -197,6 +197,7 @@ ipw_attach(device_t dev)
struct ipw_softc *sc = device_get_softc(dev);
struct ifnet *ifp;
struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_channel *c;
uint16_t val;
int error, i;
@@ -287,11 +288,17 @@ ipw_attach(device_t dev)
ic->ic_myaddr[4] = val >> 8;
ic->ic_myaddr[5] = val & 0xff;
- /* set supported .11b channels */
- for (i = 1; i < 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
+ /* set supported .11b channels (read from EEPROM) */
+ if ((val = ipw_read_prom_word(sc, IPW_EEPROM_CHANNEL_LIST)) == 0)
+ val = 0x7ff; /* default to channels 1-11 */
+ val <<= 1;
+ for (i = 1; i < 16; i++) {
+ if (val & (1 << i)) {
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+ c->ic_flags = IEEE80211_CHAN_B;
+ c->ic_ieee = i;
+ }
}
/* check support for radio transmitter switch in EEPROM */
@@ -791,6 +798,7 @@ ipw_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_AHDEMO:
case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_WDS:
/* should not get there */
break;
}
@@ -802,7 +810,6 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ifnet *ifp = ic->ic_ifp;
struct ipw_softc *sc = ifp->if_softc;
- struct ieee80211_node *ni;
uint8_t macaddr[IEEE80211_ADDR_LEN];
uint32_t len;
@@ -813,6 +820,7 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
len = IEEE80211_ADDR_LEN;
ipw_read_table2(sc, IPW_INFO_CURRENT_BSSID, macaddr, &len);
+#if 0
ni = ieee80211_find_node(&ic->ic_scan, macaddr);
if (ni == NULL)
break;
@@ -823,6 +831,7 @@ ipw_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
if (ic->ic_opmode == IEEE80211_M_STA)
ieee80211_notify_node_join(ic, ni, 1);
+#endif
break;
case IEEE80211_S_INIT:
@@ -980,7 +989,9 @@ ipw_fix_channel(struct ieee80211com *ic, struct mbuf *m)
#if IEEE80211_CHAN_MAX < 255
if (frm[2] <= IEEE80211_CHAN_MAX)
#endif
- ic->ic_curchan = &ic->ic_channels[frm[2]];
+ ic->ic_bsschan = ieee80211_find_channel(ic,
+ ieee80211_ieee2mhz(frm[2], 0),
+ IEEE80211_MODE_AUTO);
frm += frm[1] + 2;
}
@@ -1069,7 +1080,7 @@ ipw_data_intr(struct ipw_softc *sc, struct ipw_status *status,
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, status->rssi, 0);
+ ieee80211_input(ic, m, ni, status->rssi, -95/*XXX*/, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@@ -1162,6 +1173,8 @@ ipw_release_sbd(struct ipw_softc *sc, struct ipw_soft_bd *sbd)
bus_dmamap_unload(sc->txbuf_dmat, sbuf->map);
SLIST_INSERT_HEAD(&sc->free_sbuf, sbuf, next);
+ if (sbuf->m->m_flags & M_TXCB)
+ ieee80211_process_callback(sbuf->ni, sbuf->m, 0/*XXX*/);
m_freem(sbuf->m);
ieee80211_free_node(sbuf->ni);
@@ -1514,7 +1527,6 @@ static void
ipw_watchdog(struct ifnet *ifp)
{
struct ipw_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
mtx_lock(&sc->sc_mtx);
@@ -1532,8 +1544,6 @@ ipw_watchdog(struct ifnet *ifp)
ifp->if_timer = 1;
}
- ieee80211_watchdog(ic);
-
mtx_unlock(&sc->sc_mtx);
}
@@ -1744,6 +1754,7 @@ ipw_config(struct ipw_softc *sc)
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_WDS: /* XXX */
data = htole32(IPW_MODE_BSS);
break;
case IEEE80211_M_IBSS:
@@ -1839,8 +1850,8 @@ ipw_config(struct ipw_softc *sc)
printf("\n");
}
#endif
- error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_essid,
- ic->ic_des_esslen);
+ error = ipw_cmd(sc, IPW_CMD_SET_ESSID, ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
if (error != 0)
return error;
diff --git a/sys/dev/iwi/if_iwi.c b/sys/dev/iwi/if_iwi.c
index c694c92..ae9aeb6 100644
--- a/sys/dev/iwi/if_iwi.c
+++ b/sys/dev/iwi/if_iwi.c
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -137,7 +138,7 @@ static int iwi_media_change(struct ifnet *);
static void iwi_media_status(struct ifnet *, struct ifmediareq *);
static int iwi_newstate(struct ieee80211com *, enum ieee80211_state, int);
static void iwi_wme_init(struct iwi_softc *);
-static void iwi_wme_setparams(void *, int);
+static int iwi_wme_setparams(struct iwi_softc *);
static int iwi_wme_update(struct ieee80211com *);
static uint16_t iwi_read_prom_word(struct iwi_softc *, uint8_t);
static void iwi_frame_intr(struct iwi_softc *, struct iwi_rx_data *, int,
@@ -151,7 +152,7 @@ static void iwi_write_ibssnode(struct iwi_softc *, const u_int8_t [], int);
static int iwi_tx_start(struct ifnet *, struct mbuf *,
struct ieee80211_node *, int);
static void iwi_start(struct ifnet *);
-static void iwi_watchdog(struct ifnet *);
+static void iwi_watchdog(void *);
static int iwi_ioctl(struct ifnet *, u_long, caddr_t);
static void iwi_stop_master(struct iwi_softc *);
static int iwi_reset(struct iwi_softc *);
@@ -161,13 +162,22 @@ static void iwi_release_fw_dma(struct iwi_softc *sc);
static int iwi_config(struct iwi_softc *);
static int iwi_get_firmware(struct iwi_softc *);
static void iwi_put_firmware(struct iwi_softc *);
+static int iwi_scanchan(struct iwi_softc *, unsigned long, int);
+static void iwi_scan_start(struct ieee80211com *);
+static void iwi_scan_end(struct ieee80211com *);
static void iwi_scanabort(void *, int);
-static void iwi_scandone(void *, int);
-static void iwi_scanstart(void *, int);
-static void iwi_scanchan(void *, int);
+static void iwi_set_channel(struct ieee80211com *);
+static void iwi_scan_curchan(struct ieee80211com *, unsigned long maxdwell);
+#if 0
+static void iwi_scan_allchan(struct ieee80211com *, unsigned long maxdwell);
+#endif
+static void iwi_scan_mindwell(struct ieee80211com *);
+static void iwi_assoc(struct ieee80211com *ic);
+static void iwi_disassoc(struct ieee80211com *);
+static void iwi_ops(void *, int);
+static int iwi_queue_cmd(struct iwi_softc *, int);
static int iwi_auth_and_assoc(struct iwi_softc *);
static int iwi_disassociate(struct iwi_softc *, int quiet);
-static void iwi_down(void *, int);
static void iwi_init(void *);
static void iwi_init_locked(void *, int);
static void iwi_stop(void *);
@@ -247,35 +257,32 @@ iwi_attach(device_t dev)
struct ifnet *ifp;
struct ieee80211com *ic = &sc->sc_ic;
uint16_t val;
- int error, i;
+ int i, error, bands;
sc->sc_dev = dev;
- mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
- MTX_DEF);
+ IWI_LOCK_INIT(sc);
+ IWI_CMD_LOCK_INIT(sc);
sc->sc_unr = new_unrhdr(1, IWI_MAX_IBSSNODE-1, &sc->sc_mtx);
#if __FreeBSD_version >= 700000
- sc->sc_tq = taskqueue_create("iwi_taskq", M_NOWAIT,
+ sc->sc_tq = taskqueue_create("iwi_taskq", M_NOWAIT | M_ZERO,
taskqueue_thread_enqueue, &sc->sc_tq);
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, "%s taskq",
device_get_nameunit(dev));
#else
- sc->sc_tq = taskqueue_create("iwi_taskq", M_NOWAIT,
+ sc->sc_tq = taskqueue_create("iwi_taskq", M_NOWAIT | M_ZERO,
taskqueue_thread_enqueue, &sc->sc_tq, &sc->sc_tqproc);
kthread_create(taskqueue_thread_loop, &sc->sc_tq, &sc->sc_tqproc,
0, 0, "%s taskq", device_get_nameunit(dev));
#endif
TASK_INIT(&sc->sc_radiontask, 0, iwi_radio_on, sc);
TASK_INIT(&sc->sc_radiofftask, 0, iwi_radio_off, sc);
- TASK_INIT(&sc->sc_scanstarttask, 0, iwi_scanstart, sc);
- TASK_INIT(&sc->sc_scanaborttask, 0, iwi_scanabort, sc);
- TASK_INIT(&sc->sc_scandonetask, 0, iwi_scandone, sc);
- TASK_INIT(&sc->sc_scantask, 0, iwi_scanchan, sc);
- TASK_INIT(&sc->sc_setwmetask, 0, iwi_wme_setparams, sc);
- TASK_INIT(&sc->sc_downtask, 0, iwi_down, sc);
TASK_INIT(&sc->sc_restarttask, 0, iwi_restart, sc);
+ TASK_INIT(&sc->sc_opstask, 0, iwi_ops, sc);
+ TASK_INIT(&sc->sc_scanaborttask, 0, iwi_scanabort, sc);
+ callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
device_printf(dev, "chip is in D%d power mode "
@@ -343,18 +350,17 @@ iwi_attach(device_t dev)
device_printf(dev, "can not if_alloc()\n");
goto fail;
}
+ ic->ic_ifp = ifp;
ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_init = iwi_init;
ifp->if_ioctl = iwi_ioctl;
ifp->if_start = iwi_start;
- ifp->if_watchdog = iwi_watchdog;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
IFQ_SET_READY(&ifp->if_snd);
- ic->ic_ifp = ifp;
ic->ic_wme.wme_update = iwi_wme_update;
ic->ic_phytype = IEEE80211_T_OFDM; /* not only, but not used */
ic->ic_opmode = IEEE80211_M_STA; /* default to BSS mode */
@@ -362,12 +368,14 @@ iwi_attach(device_t dev)
/* set device capabilities */
ic->ic_caps =
- IEEE80211_C_IBSS | /* IBSS mode supported */
- IEEE80211_C_MONITOR | /* monitor mode supported */
- IEEE80211_C_PMGT | /* power save supported */
- IEEE80211_C_SHPREAMBLE | /* short preamble supported */
- IEEE80211_C_WPA | /* 802.11i */
- IEEE80211_C_WME; /* 802.11e */
+ IEEE80211_C_IBSS /* IBSS mode supported */
+ | IEEE80211_C_MONITOR /* monitor mode supported */
+ | IEEE80211_C_PMGT /* power save supported */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_WPA /* 802.11i */
+ | IEEE80211_C_WME /* 802.11e */
+ | IEEE80211_C_BGSCAN /* capable of bg scanning */
+ ;
/* read MAC address from EEPROM */
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 0);
@@ -379,29 +387,13 @@ iwi_attach(device_t dev)
val = iwi_read_prom_word(sc, IWI_EEPROM_MAC + 2);
ic->ic_myaddr[4] = val & 0xff;
ic->ic_myaddr[5] = val >> 8;
-
- if (pci_get_device(dev) >= 0x4223) {
- /* set supported .11a channels */
- for (i = 36; i <= 64; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 149; i <= 165; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- }
-
- /* set supported .11b and .11g channels (1 through 14) */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
+
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ if (pci_get_device(dev) >= 0x4223)
+ setbit(&bands, IEEE80211_MODE_11A);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_bmissthreshold = 10; /* override default */
@@ -409,6 +401,12 @@ iwi_attach(device_t dev)
ic->ic_node_alloc = iwi_node_alloc;
sc->sc_node_free = ic->ic_node_free;
ic->ic_node_free = iwi_node_free;
+ ic->ic_scan_start = iwi_scan_start;
+ ic->ic_scan_end = iwi_scan_end;
+ ic->ic_set_channel = iwi_set_channel;
+ ic->ic_scan_curchan = iwi_scan_curchan;
+ ic->ic_scan_mindwell = iwi_scan_mindwell;
+
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = iwi_newstate;
@@ -454,12 +452,17 @@ iwi_detach(device_t dev)
struct iwi_softc *sc = device_get_softc(dev);
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
+ IWI_LOCK_DECL;
if (ifp != NULL) {
+ IWI_LOCK(sc);
iwi_stop(sc);
+ IWI_UNLOCK(sc);
bpfdetach(ifp);
ieee80211_ifdetach(ic);
}
+
+ callout_drain(&sc->sc_wdtimer);
iwi_put_firmware(sc);
iwi_release_fw_dma(sc);
@@ -486,7 +489,8 @@ iwi_detach(device_t dev)
if (sc->sc_unr != NULL)
delete_unrhdr(sc->sc_unr);
- mtx_destroy(&sc->sc_mtx);
+ IWI_LOCK_DESTROY(sc);
+ IWI_CMD_LOCK_DESTROY(sc);
return 0;
}
@@ -793,8 +797,11 @@ static int
iwi_shutdown(device_t dev)
{
struct iwi_softc *sc = device_get_softc(dev);
+ IWI_LOCK_DECL;
+ IWI_LOCK(sc);
iwi_stop(sc);
+ IWI_UNLOCK(sc);
iwi_put_firmware(sc); /* ??? XXX */
return 0;
@@ -804,8 +811,11 @@ static int
iwi_suspend(device_t dev)
{
struct iwi_softc *sc = device_get_softc(dev);
+ IWI_LOCK_DECL;
+ IWI_LOCK(sc);
iwi_stop(sc);
+ IWI_UNLOCK(sc);
return 0;
}
@@ -935,38 +945,18 @@ iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ifnet *ifp = ic->ic_ifp;
struct iwi_softc *sc = ifp->if_softc;
+ int error = 0;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
DPRINTF(("%s: %s -> %s flags 0x%x\n", __func__,
ieee80211_state_name[ic->ic_state],
ieee80211_state_name[nstate], sc->flags));
/* XXX state change race with taskqueue */
switch (nstate) {
- case IEEE80211_S_SCAN:
- if (ic->ic_state == IEEE80211_S_RUN) {
- /*
- * Beacon miss, send disassoc and wait for a reply
- * from the card; we'll start a scan then. Note
- * this only happens with auto roaming; otherwise
- * just notify users and wait to be directed.
- */
- /* notify directly as we bypass net80211 */
- ieee80211_sta_leave(ic, ic->ic_bss);
- if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_downtask);
- break;
- }
- if ((sc->flags & IWI_FLAG_SCANNING) == 0) {
- sc->flags |= IWI_FLAG_SCANNING;
- taskqueue_enqueue(sc->sc_tq, &sc->sc_scanstarttask);
- }
- break;
-
case IEEE80211_S_AUTH:
- iwi_auth_and_assoc(sc);
+ iwi_assoc(ic);
break;
-
case IEEE80211_S_RUN:
if (ic->ic_opmode == IEEE80211_M_IBSS) {
/*
@@ -978,17 +968,9 @@ iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
* This is all totally bogus and needs to be redone.
*/
if (ic->ic_state == IEEE80211_S_SCAN)
- iwi_auth_and_assoc(sc);
- } else if (ic->ic_opmode == IEEE80211_M_MONITOR)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_scantask);
-
- /* XXX way wrong */
- return sc->sc_newstate(ic, nstate,
- IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
-
- case IEEE80211_S_ASSOC:
+ iwi_assoc(ic);
+ }
break;
-
case IEEE80211_S_INIT:
/*
* NB: don't try to do this if iwi_stop_master has
@@ -996,12 +978,24 @@ iwi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
*/
if (ic->ic_state == IEEE80211_S_RUN &&
(sc->flags & IWI_FLAG_FW_INITED))
- taskqueue_enqueue(sc->sc_tq, &sc->sc_downtask);
+ iwi_disassoc(ic);
+ if (ic->ic_state == IEEE80211_S_SCAN &&
+ (sc->fw_state == IWI_FW_SCANNING))
+ ieee80211_cancel_scan(ic);
+ break;
+ case IEEE80211_S_ASSOC:
+ /*
+ * If we are not transitioning from AUTH the resend the
+ * association request.
+ */
+ if (ic->ic_state != IEEE80211_S_AUTH)
+ iwi_assoc(ic);
+ break;
+ default:
break;
}
+ return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
- ic->ic_state = nstate;
- return 0;
}
/*
@@ -1052,7 +1046,7 @@ iwi_wme_init(struct iwi_softc *sc)
}
static int
-iwi_wme_setparams_locked(struct iwi_softc *sc)
+iwi_wme_setparams(struct iwi_softc *sc)
{
struct ieee80211com *ic = &sc->sc_ic;
const struct wmeParams *wmep;
@@ -1071,17 +1065,6 @@ iwi_wme_setparams_locked(struct iwi_softc *sc)
DPRINTF(("Setting WME parameters\n"));
return iwi_cmd(sc, IWI_CMD_SET_WME_PARAMS, sc->wme, sizeof sc->wme);
}
-
-static void
-iwi_wme_setparams(void *arg, int npending)
-{
- struct iwi_softc *sc = arg;
- IWI_LOCK_DECL;
-
- IWI_LOCK(sc);
- (void) iwi_wme_setparams_locked(sc);
- IWI_UNLOCK(sc);
-}
#undef IWI_USEC
#undef IWI_EXP2
@@ -1098,9 +1081,7 @@ iwi_wme_update(struct ieee80211com *ic)
* will get sent down to the adapter as part of the
* work iwi_auth_and_assoc does.
*/
- if (ic->ic_state == IEEE80211_S_RUN)
- taskqueue_enqueue(sc->sc_tq, &sc->sc_setwmetask);
- return 0;
+ return (iwi_queue_cmd(sc, IWI_SET_WME));
}
static int
@@ -1183,8 +1164,6 @@ iwi_setcurchan(struct iwi_softc *sc, int chan)
{
struct ieee80211com *ic = &sc->sc_ic;
- IWI_LOCK_CHECK(sc);
- ic->ic_curchan = &ic->ic_channels[chan];
sc->curchan = chan;
sc->sc_rxtap.wr_chan_freq = sc->sc_txtap.wt_chan_freq =
@@ -1288,7 +1267,7 @@ iwi_frame_intr(struct iwi_softc *sc, struct iwi_rx_data *data, int i,
ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *));
/* send the frame to the 802.11 layer */
- type = ieee80211_input(ic, m, ni, frame->rssi_dbm, 0);
+ type = ieee80211_input(ic, m, ni, frame->rssi_dbm, 0, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@@ -1347,6 +1326,7 @@ iwi_checkforqos(struct iwi_softc *sc, const struct ieee80211_frame *wh, int len)
#define SUBTYPE(wh) ((wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
const uint8_t *frm, *efrm, *wme;
struct ieee80211_node *ni;
+ uint16_t capinfo, status, associd;
/* NB: +8 for capinfo, status, associd, and first ie */
if (!(sizeof(*wh)+8 < len && len < IEEE80211_MAX_LEN) ||
@@ -1363,7 +1343,13 @@ iwi_checkforqos(struct iwi_softc *sc, const struct ieee80211_frame *wh, int len)
*/
frm = (const uint8_t *)&wh[1];
efrm = ((const uint8_t *) wh) + len;
- frm += 6;
+
+ capinfo = le16toh(*(const uint16_t *)frm);
+ frm += 2;
+ status = le16toh(*(const uint16_t *)frm);
+ frm += 2;
+ associd = le16toh(*(const uint16_t *)frm);
+ frm += 2;
wme = NULL;
while (frm < efrm) {
@@ -1378,6 +1364,8 @@ iwi_checkforqos(struct iwi_softc *sc, const struct ieee80211_frame *wh, int len)
}
ni = sc->sc_ic.ic_bss;
+ ni->ni_capinfo = capinfo;
+ ni->ni_associd = associd;
if (wme != NULL)
ni->ni_flags |= IEEE80211_NODE_QOS;
else
@@ -1400,7 +1388,10 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
chan = (struct iwi_notif_scan_channel *)(notif + 1);
DPRINTFN(3, ("Scan of channel %u complete (%u)\n",
- ic->ic_channels[chan->nchan].ic_freq, chan->nchan));
+ ieee80211_ieee2mhz(chan->nchan, 0), chan->nchan));
+
+ /* Reset the timer, the scan is still going */
+ sc->sc_state_timer = 3;
break;
case IWI_NOTIF_TYPE_SCAN_COMPLETE:
@@ -1409,21 +1400,11 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
DPRINTFN(2, ("Scan completed (%u, %u)\n", scan->nchan,
scan->status));
- sc->sc_scan_timer = 0;
+ IWI_STATE_END(sc, IWI_FW_SCANNING);
+
+ if (scan->status == IWI_SCAN_COMPLETED)
+ ieee80211_scan_next(ic);
- if (ic->ic_opmode == IEEE80211_M_MONITOR) {
- /*
- * Monitor mode works by doing a passive scan to set
- * the channel and enable rx. Because we don't want
- * to abort a scan lest the firmware crash we scan
- * for a short period of time and automatically restart
- * the scan when notified the sweep has completed.
- */
- taskqueue_enqueue(sc->sc_tq, &sc->sc_scantask);
- } else {
- sc->flags &= ~IWI_FLAG_SCANNING;
- taskqueue_enqueue(sc->sc_tq, &sc->sc_scandonetask);
- }
break;
case IWI_NOTIF_TYPE_AUTHENTICATION:
@@ -1439,6 +1420,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
case IWI_AUTH_FAIL:
DPRINTFN(2, ("Authentication failed\n"));
sc->flags &= ~IWI_FLAG_ASSOCIATED;
+ IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
/* XXX */
break;
@@ -1450,6 +1432,7 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
case IWI_AUTH_SEQ1_FAIL:
DPRINTFN(2, ("Initial authentication handshake failed; "
"you probably need shared key\n"));
+ IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
/* XXX retry shared key when in auto */
break;
@@ -1470,16 +1453,29 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
case IWI_ASSOC_SUCCESS:
DPRINTFN(2, ("Association succeeded\n"));
sc->flags |= IWI_FLAG_ASSOCIATED;
+ IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
iwi_checkforqos(sc,
(const struct ieee80211_frame *)(assoc+1),
le16toh(notif->len) - sizeof(*assoc));
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
break;
- case IWI_ASSOC_FAIL:
- DPRINTFN(2, ("Association failed\n"));
+ case IWI_ASSOC_INIT:
+ switch (sc->fw_state) {
+ case IWI_FW_ASSOCIATING:
+ DPRINTFN(2, ("Association failed\n"));
+ IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
+ ieee80211_new_state(ic,
+ IEEE80211_S_SCAN, -1);
+ break;
+
+ case IWI_FW_DISASSOCIATING:
+ DPRINTFN(2, ("Dissassociated\n"));
+ IWI_STATE_END(sc,
+ IWI_FW_DISASSOCIATING);
+ break;
+ }
sc->flags &= ~IWI_FLAG_ASSOCIATED;
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
break;
default:
@@ -1496,15 +1492,6 @@ iwi_notification_intr(struct iwi_softc *sc, struct iwi_notif *notif)
beacon->state, le32toh(beacon->number)));
if (beacon->state == IWI_BEACON_MISS) {
-#if 0
- if (sc->flags & IWI_FLAG_SCANNING) {
- /* XXX terminate scan, linux driver
- says fw can get stuck */
- /* XXX should be handled in iwi_newstate */
- taskqueue_enqueue(sc->sc_tq,
- &sc->sc_scanaborttask);
- }
-#endif
/*
* The firmware notifies us of every beacon miss
* so we need to track the count against the
@@ -1592,6 +1579,8 @@ iwi_tx_intr(struct iwi_softc *sc, struct iwi_tx_ring *txq)
bus_dmamap_sync(txq->data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(txq->data_dmat, data->map);
+ if (data->m->m_flags & M_TXCB)
+ ieee80211_process_callback(data->ni, data->m, 0/*XXX*/);
m_freem(data->m);
data->m = NULL;
ieee80211_free_node(data->ni);
@@ -1633,7 +1622,13 @@ iwi_intr(void *arg)
if (r & IWI_INTR_FATAL_ERROR) {
device_printf(sc->sc_dev, "firmware error\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
+ /* don't restart if the interface isn't up */
+ if (sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING)
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
+
+ sc->flags &= ~IWI_FLAG_BUSY;
+ sc->sc_busy_timer = 0;
+ wakeup(sc);
}
if (r & IWI_INTR_FW_INITED) {
@@ -1646,6 +1641,7 @@ iwi_intr(void *arg)
if (r & IWI_INTR_CMD_DONE) {
sc->flags &= ~IWI_FLAG_BUSY;
+ sc->sc_busy_timer = 0;
wakeup(sc);
}
@@ -1677,7 +1673,7 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len)
{
struct iwi_cmd_desc *desc;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
if (sc->flags & IWI_FLAG_BUSY) {
device_printf(sc->sc_dev, "%s: cmd %d not sent, busy\n",
@@ -1685,6 +1681,7 @@ iwi_cmd(struct iwi_softc *sc, uint8_t type, void *data, uint8_t len)
return EAGAIN;
}
sc->flags |= IWI_FLAG_BUSY;
+ sc->sc_busy_timer = 2;
desc = &sc->cmdq.desc[sc->cmdq.cur];
@@ -1741,7 +1738,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m0, struct ieee80211_node *ni,
int error, nsegs, hdrlen, i;
int ismcast, flags, xflags, staid;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
wh = mtod(m0, const struct ieee80211_frame *);
/* NB: only data frames use this path */
hdrlen = ieee80211_hdrsize(wh);
@@ -1972,20 +1969,18 @@ iwi_start(struct ifnet *ifp)
}
sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
}
IWI_UNLOCK(sc);
}
static void
-iwi_watchdog(struct ifnet *ifp)
+iwi_watchdog(void *arg)
{
- struct iwi_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- IWI_LOCK_DECL;
+ struct iwi_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
- IWI_LOCK(sc);
+ IWI_LOCK_ASSERT(sc);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
@@ -2007,22 +2002,25 @@ iwi_watchdog(struct ifnet *ifp)
sc->sc_rfkill_timer = 2;
}
}
- if (sc->sc_scan_timer > 0) {
- if (--sc->sc_scan_timer == 0) {
- if (sc->flags & IWI_FLAG_SCANNING) {
- if_printf(ifp, "scan stuck\n");
- taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
- }
+ if (sc->sc_state_timer > 0) {
+ if (--sc->sc_state_timer == 0) {
+ if_printf(ifp, "firmware stuck in state %d, resetting\n",
+ sc->fw_state);
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
+ if (sc->fw_state == IWI_FW_SCANNING)
+ ieee80211_cancel_scan(&sc->sc_ic);
+ sc->sc_state_timer = 3;
+ }
+ }
+ if (sc->sc_busy_timer > 0) {
+ if (--sc->sc_busy_timer == 0) {
+ if_printf(ifp, "firmware command timeout, resetting\n");
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_restarttask);
}
}
- if (sc->sc_tx_timer || sc->sc_rfkill_timer || sc->sc_scan_timer)
- ifp->if_timer = 1;
- else
- ifp->if_timer = 0;
-
- ieee80211_watchdog(ic);
- IWI_UNLOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc);
}
static int
@@ -2084,8 +2082,6 @@ iwi_stop_master(struct iwi_softc *sc)
uint32_t tmp;
int ntries;
- IWI_LOCK_CHECK(sc);
-
/* disable interrupts */
CSR_WRITE_4(sc, IWI_CSR_INTR_MASK, 0);
@@ -2352,7 +2348,7 @@ iwi_load_ucode(struct iwi_softc *sc, const struct iwi_fw *fw)
size_t size = fw->size;
int i, ntries, error;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
error = 0;
CSR_WRITE_4(sc, IWI_CSR_RST, CSR_READ_4(sc, IWI_CSR_RST) |
IWI_RST_STOP_MASTER);
@@ -2425,7 +2421,7 @@ iwi_load_firmware(struct iwi_softc *sc, const struct iwi_fw *fw)
uint32_t sentinel, ctl, src, dst, sum, len, mlen, tmp;
int ntries, error;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
/* copy firmware image to DMA memory */
memcpy(sc->fw_virtaddr, fw->data, fw->size);
@@ -2567,7 +2563,7 @@ iwi_config(struct iwi_softc *sc)
struct iwi_txpower power;
uint32_t data;
int error, i;
- IWI_LOCK_CHECK(sc);
+ IWI_LOCK_ASSERT(sc);
IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
DPRINTF(("Setting MAC address to %6D\n", ic->ic_myaddr, ":"));
@@ -2645,17 +2641,17 @@ iwi_config(struct iwi_softc *sc)
return error;
/* if we have a desired ESSID, set it now */
- if (ic->ic_des_esslen != 0) {
+ if (ic->ic_des_ssid[0].len != 0) {
#ifdef IWI_DEBUG
if (iwi_debug > 0) {
printf("Setting desired ESSID to ");
- ieee80211_print_essid(ic->ic_des_essid,
- ic->ic_des_esslen);
+ ieee80211_print_essid(ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
printf("\n");
}
#endif
- error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_essid,
- ic->ic_des_esslen);
+ error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
if (error != 0)
return error;
}
@@ -2686,94 +2682,142 @@ set_scan_type(struct iwi_scan_ext *scan, int ix, int scan_type)
}
static int
-iwi_scan(struct iwi_softc *sc)
+scan_type(const struct ieee80211_scan_state *ss,
+ const struct ieee80211_channel *chan)
{
- struct ieee80211com *ic = &sc->sc_ic;
- const struct ieee80211_channel *c;
- struct iwi_scan_ext scan;
- int i, ix, start, scan_type, error;
+ /* We can only set one essid for a directed scan */
+ if (ss->ss_nssid != 0)
+ return IWI_SCAN_TYPE_BDIRECTED;
+ if ((ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
+ (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
+ return IWI_SCAN_TYPE_BROADCAST;
+ return IWI_SCAN_TYPE_PASSIVE;
+}
- IWI_LOCK_CHECK(sc);
+static __inline int
+scan_band(const struct ieee80211_channel *c)
+{
+ return IEEE80211_IS_CHAN_5GHZ(c) ? IWI_CHAN_5GHZ : IWI_CHAN_2GHZ;
+}
- memset(&scan, 0, sizeof scan);
+/*
+ * Start a scan on the current channel or all channels.
+ */
+static int
+iwi_scanchan(struct iwi_softc *sc, unsigned long maxdwell, int mode)
+{
+ struct ieee80211com *ic;
+ struct ieee80211_channel *chan;
+ struct ieee80211_scan_state *ss;
+ struct iwi_scan_ext scan;
+ int error = 0;
- /* XXX different dwell times for different scan types */
- scan.dwell_time[IWI_SCAN_TYPE_PASSIVE] = htole16(sc->dwelltime);
- scan.dwell_time[IWI_SCAN_TYPE_BROADCAST] = htole16(sc->dwelltime);
- scan.dwell_time[IWI_SCAN_TYPE_BDIRECTED] = htole16(sc->dwelltime);
+ IWI_LOCK_ASSERT(sc);
+ if (sc->fw_state == IWI_FW_SCANNING) {
+ /*
+ * This should not happen as we only trigger scan_next after
+ * completion
+ */
+ DPRINTF(("%s: called too early - still scanning\n", __func__));
+ return (EBUSY);
+ }
+ IWI_STATE_BEGIN(sc, IWI_FW_SCANNING);
- scan.full_scan_index = htole32(ic->ic_scan.nt_scangen);
+ ic = &sc->sc_ic;
+ ss = ic->ic_scan;
- if (ic->ic_des_esslen != 0) {
- scan_type = IWI_SCAN_TYPE_BDIRECTED;
-#ifdef IWI_DEBUG
- if (iwi_debug > 0) {
- printf("Setting desired ESSID to ");
- ieee80211_print_essid(ic->ic_des_essid,
- ic->ic_des_esslen);
- printf("\n");
- }
-#endif
- error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ic->ic_des_essid,
- ic->ic_des_esslen);
- if (error != 0)
- return error;
- } else
- scan_type = IWI_SCAN_TYPE_BROADCAST;
+ memset(&scan, 0, sizeof scan);
+ scan.full_scan_index = htole32(++sc->sc_scangen);
+ scan.dwell_time[IWI_SCAN_TYPE_PASSIVE] = htole16(maxdwell);
+ if (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) {
+ /*
+ * Use very short dwell times for when we send probe request
+ * frames. Without this bg scans hang. Ideally this should
+ * be handled with early-termination as done by net80211 but
+ * that's not feasible (aborting a scan is problematic).
+ */
+ scan.dwell_time[IWI_SCAN_TYPE_BROADCAST] = htole16(30);
+ scan.dwell_time[IWI_SCAN_TYPE_BDIRECTED] = htole16(30);
+ } else {
+ scan.dwell_time[IWI_SCAN_TYPE_BROADCAST] = htole16(maxdwell);
+ scan.dwell_time[IWI_SCAN_TYPE_BDIRECTED] = htole16(maxdwell);
+ }
- ix = 0;
- if (isset(ic->ic_modecaps, IEEE80211_MODE_11A)) {
- start = ix;
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- c = &ic->ic_channels[i];
- /*
- * NB: ieee80211_next_scan clears curchan from the
- * channel list so we must explicitly check; this
- * will be fixed when the new scanning support arrives.
- */
- if (!IEEE80211_IS_CHAN_5GHZ(c) ||
- !(isset(ic->ic_chan_scan,i) || c == ic->ic_curchan))
- continue;
- ix++;
- scan.channels[ix] = i;
- if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
- set_scan_type(&scan, ix, IWI_SCAN_TYPE_PASSIVE);
- else
- set_scan_type(&scan, ix, scan_type);
- }
- if (start != ix) {
- scan.channels[start] = IWI_CHAN_5GHZ | (ix - start);
- ix++;
- }
+ /* We can only set one essid for a directed scan */
+ if (ss->ss_nssid != 0) {
+ error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ss->ss_ssid[0].ssid,
+ ss->ss_ssid[0].len);
+ if (error)
+ return (error);
}
- if (isset(ic->ic_modecaps, IEEE80211_MODE_11B)) {
- start = ix;
- for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
- c = &ic->ic_channels[i];
- /* NB: see above */
- if (!IEEE80211_IS_CHAN_2GHZ(c) ||
- !(isset(ic->ic_chan_scan,i) || c == ic->ic_curchan))
- continue;
- ix++;
- scan.channels[ix] = i;
- if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
- set_scan_type(&scan, ix, IWI_SCAN_TYPE_PASSIVE);
- else
- set_scan_type(&scan, ix, scan_type);
+
+ if (mode == IWI_SCAN_ALLCHAN) {
+ int i, next, band, b, bstart;
+ /*
+ * Convert scan list to run-length encoded channel list
+ * the firmware requires (preserving the order setup by
+ * net80211). The first entry in each run specifies the
+ * band and the count of items in the run.
+ */
+ next = 0; /* next open slot */
+ bstart = 0; /* NB: not needed, silence compiler */
+ band = -1; /* NB: impossible value */
+ KASSERT(ss->ss_last > 0, ("no channels"));
+ for (i = 0; i < ss->ss_last; i++) {
+ chan = ss->ss_chans[i];
+ b = scan_band(chan);
+ if (b != band) {
+ if (band != -1)
+ scan.channels[bstart] =
+ (next - bstart) | band;
+ /* NB: this allocates a slot for the run-len */
+ band = b, bstart = next++;
+ }
+ if (next >= IWI_SCAN_CHANNELS) {
+ DPRINTF(("truncating scan list\n"));
+ break;
+ }
+ scan.channels[next] = ieee80211_chan2ieee(ic, chan);
+ set_scan_type(&scan, next, scan_type(ss, chan));
+ next++;
}
- if (start != ix)
- scan.channels[start] = IWI_CHAN_2GHZ | (ix - start);
+ scan.channels[bstart] = (next - bstart) | band;
+ } else {
+ /* Scan the current channel only */
+ chan = ic->ic_curchan;
+ scan.channels[0] = 1 | scan_band(chan);
+ scan.channels[1] = ieee80211_chan2ieee(ic, chan);
+ set_scan_type(&scan, 1, scan_type(ss, chan));
}
+#ifdef IWI_DEBUG
+ if (iwi_debug > 0) {
+ static const char *scantype[8] =
+ { "PSTOP", "PASV", "DIR", "BCAST", "BDIR", "5", "6", "7" };
+ int i;
+ printf("Scan request: index %u dwell %d/%d/%d\n"
+ , le32toh(scan.full_scan_index)
+ , le16toh(scan.dwell_time[IWI_SCAN_TYPE_PASSIVE])
+ , le16toh(scan.dwell_time[IWI_SCAN_TYPE_BROADCAST])
+ , le16toh(scan.dwell_time[IWI_SCAN_TYPE_BDIRECTED])
+ );
+ i = 0;
+ do {
+ int run = scan.channels[i];
+ if (run == 0)
+ break;
+ printf("Scan %d %s channels:", run & 0x3f,
+ run & IWI_CHAN_2GHZ ? "2.4GHz" : "5GHz");
+ for (run &= 0x3f, i++; run > 0; run--, i++) {
+ uint8_t type = scan.scan_type[i/2];
+ printf(" %u/%s", scan.channels[i],
+ scantype[(i & 1 ? type : type>>4) & 7]);
+ }
+ printf("\n");
+ } while (i < IWI_SCAN_CHANNELS);
+ }
+#endif
- DPRINTF(("Start scanning\n"));
- /*
- * With 100ms/channel dwell time and a max of ~20 channels
- * 5 seconds may be too tight; leave a bit more slack.
- */
- sc->sc_scan_timer = 7; /* seconds to complete */
- sc->sc_ifp->if_timer = 1;
- sc->flags |= IWI_FLAG_SCANNING;
- return iwi_cmd(sc, IWI_CMD_SCAN_EXT, &scan, sizeof scan);
+ return (iwi_cmd(sc, IWI_CMD_SCAN_EXT, &scan, sizeof scan));
}
static void
@@ -2783,94 +2827,13 @@ iwi_scanabort(void *arg, int npending)
IWI_LOCK_DECL;
IWI_LOCK(sc);
+ sc->flags &= ~IWI_FLAG_CHANNEL_SCAN;
/* NB: make sure we're still scanning */
- if (sc->flags & IWI_FLAG_SCANNING)
+ if (sc->fw_state == IWI_FW_SCANNING)
iwi_cmd(sc, IWI_CMD_ABORT_SCAN, NULL, 0);
IWI_UNLOCK(sc);
}
-static void
-iwi_scanstart(void *arg, int npending)
-{
- struct iwi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- IWI_LOCK_DECL;
-
- IWI_LOCK(sc);
- /*
- * Tell the card to kick off a scan. We guard this
- * by checking IWI_FLAG_SCANNING as otherwise we'll
- * do this twice because ieee80211_begin_scan will
- * immediately call us back to scan the first channel
- * in the list.
- */
- if (sc->flags & IWI_FLAG_SCANNING) {
- ieee80211_begin_scan(ic, 1);
- if (iwi_scan(sc) != 0) {
- /* XXX should not happen */
- sc->flags &= ~IWI_FLAG_SCANNING;
- ieee80211_new_state(ic, IEEE80211_S_INIT, 0);
- }
- }
- IWI_UNLOCK(sc);
-}
-
-static void
-iwi_scandone(void *arg, int npending)
-{
- struct iwi_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- IWI_LOCK_DECL;
-
- IWI_LOCK(sc);
- if (sc->flags & IWI_FLAG_ASSOCIATED)
- iwi_disassociate(sc, 0);
- ieee80211_end_scan(ic);
- IWI_UNLOCK(sc);
-}
-
-/*
- * Set the current channel by doing a passive scan. Note this
- * is explicitly for monitor mode operation; do not use it for
- * anything else (sigh).
- */
-static void
-iwi_scanchan(void *arg, int npending)
-{
- struct iwi_softc *sc = arg;
- struct ieee80211com *ic;
- struct ieee80211_channel *chan;
- struct iwi_scan_ext scan;
- IWI_LOCK_DECL;
-
- IWI_LOCK(sc);
- ic = &sc->sc_ic;
- KASSERT(ic->ic_opmode == IEEE80211_M_MONITOR,
- ("opmode %u", ic->ic_opmode));
- chan = ic->ic_ibss_chan;
-
- memset(&scan, 0, sizeof scan);
- /*
- * Set the dwell time to a fairly small value. The firmware
- * is prone to crash when aborting a scan so it's better to
- * let a scan complete before changing channels--such as when
- * channel hopping in monitor mode.
- */
- scan.dwell_time[IWI_SCAN_TYPE_PASSIVE] = htole16(2000);
- scan.full_scan_index = htole32(ic->ic_scan.nt_scangen);
- if (IEEE80211_IS_CHAN_5GHZ(chan))
- scan.channels[0] = 1 | IWI_CHAN_5GHZ;
- else
- scan.channels[0] = 1 | IWI_CHAN_2GHZ;
- scan.channels[1] = ieee80211_chan2ieee(ic, chan);
- set_scan_type(&scan, 1, IWI_SCAN_TYPE_PASSIVE);
-
- DPRINTF(("Setting channel to %u\n", ieee80211_chan2ieee(ic, chan)));
- sc->flags |= IWI_FLAG_SCANNING;
- (void) iwi_cmd(sc, IWI_CMD_SCAN_EXT, &scan, sizeof scan);
- IWI_UNLOCK(sc);
-}
-
static int
iwi_set_sensitivity(struct iwi_softc *sc, int8_t rssi_dbm)
{
@@ -2894,9 +2857,17 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
struct iwi_rateset rs;
uint16_t capinfo;
int error;
-
- IWI_LOCK_CHECK(sc);
- if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
+
+ IWI_LOCK_ASSERT(sc);
+
+ if (sc->flags & IWI_FLAG_ASSOCIATED) {
+ DPRINTF(("Already associated\n"));
+ return (-1);
+ }
+
+ IWI_STATE_BEGIN(sc, IWI_FW_ASSOCIATING);
+ error = 0;
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
memset(&config, 0, sizeof config);
config.bluetooth_coexistence = sc->bluetooth;
config.antenna = sc->antenna;
@@ -2909,7 +2880,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
DPRINTF(("Configuring adapter\n"));
error = iwi_cmd(sc, IWI_CMD_SET_CONFIG, &config, sizeof config);
if (error != 0)
- return error;
+ goto done;
}
#ifdef IWI_DEBUG
@@ -2921,11 +2892,16 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
#endif
error = iwi_cmd(sc, IWI_CMD_SET_ESSID, ni->ni_essid, ni->ni_esslen);
if (error != 0)
- return error;
+ goto done;
/* the rate set has already been "negotiated" */
- rs.mode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? IWI_MODE_11A :
- IWI_MODE_11G;
+ if (IEEE80211_IS_CHAN_A(ic->ic_curchan))
+ rs.mode = IWI_MODE_11A;
+ else if (IEEE80211_IS_CHAN_G(ic->ic_curchan))
+ rs.mode = IWI_MODE_11G;
+ if (IEEE80211_IS_CHAN_B(ic->ic_curchan))
+ rs.mode = IWI_MODE_11B;
+
rs.type = IWI_RATESET_TYPE_NEGOTIATED;
rs.nrates = ni->ni_rates.rs_nrates;
if (rs.nrates > IWI_RATESET_SIZE) {
@@ -2937,13 +2913,13 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
DPRINTF(("Setting negotiated rates (%u)\n", rs.nrates));
error = iwi_cmd(sc, IWI_CMD_SET_RATES, &rs, sizeof rs);
if (error != 0)
- return error;
+ goto done;
memset(assoc, 0, sizeof *assoc);
if ((ic->ic_flags & IEEE80211_F_WME) && ni->ni_wme_ie != NULL) {
/* NB: don't treat WME setup as failure */
- if (iwi_wme_setparams_locked(sc) == 0 && iwi_wme_setie(sc) == 0)
+ if (iwi_wme_setparams(sc) == 0 && iwi_wme_setie(sc) == 0)
assoc->policy |= htole16(IWI_POLICY_WME);
/* XXX complain on failure? */
}
@@ -2953,21 +2929,21 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
error = iwi_cmd(sc, IWI_CMD_SET_OPTIE, ic->ic_opt_ie,
ic->ic_opt_ie_len);
if (error != 0)
- return error;
+ goto done;
}
error = iwi_set_sensitivity(sc, ni->ni_rssi);
if (error != 0)
- return error;
+ goto done;
- if (IEEE80211_IS_CHAN_A(ni->ni_chan))
+ if (IEEE80211_IS_CHAN_A(ic->ic_curchan))
assoc->mode = IWI_MODE_11A;
- else if (IEEE80211_IS_CHAN_G(ni->ni_chan))
+ else if (IEEE80211_IS_CHAN_G(ic->ic_curchan))
assoc->mode = IWI_MODE_11G;
- else if (IEEE80211_IS_CHAN_B(ni->ni_chan))
+ else if (IEEE80211_IS_CHAN_B(ic->ic_curchan))
assoc->mode = IWI_MODE_11B;
- /* XXX else error */
- assoc->chan = ieee80211_chan2ieee(ic, ni->ni_chan);
+
+ assoc->chan = ic->ic_curchan->ic_ieee;
/*
* NB: do not arrange for shared key auth w/o privacy
* (i.e. a wep key); it causes a firmware error.
@@ -2986,7 +2962,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
error = iwi_setwepkeys(sc);
if (error != 0)
- return error;
+ goto done;
}
if (ic->ic_flags & IEEE80211_F_WPA)
assoc->policy |= htole16(IWI_POLICY_WPA);
@@ -3003,7 +2979,7 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
if (ic->ic_flags & IEEE80211_F_PRIVACY)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
- IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME)
capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
@@ -3024,7 +3000,12 @@ iwi_auth_and_assoc(struct iwi_softc *sc)
assoc->chan, le16toh(assoc->policy), assoc->auth,
le16toh(assoc->capinfo), le16toh(assoc->lintval),
le16toh(assoc->intval)));
- return iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc);
+ error = iwi_cmd(sc, IWI_CMD_ASSOCIATE, assoc, sizeof *assoc);
+done:
+ if (error)
+ IWI_STATE_END(sc, IWI_FW_ASSOCIATING);
+
+ return (error);
}
static int
@@ -3032,6 +3013,13 @@ iwi_disassociate(struct iwi_softc *sc, int quiet)
{
struct iwi_associate *assoc = &sc->assoc;
+ if ((sc->flags & IWI_FLAG_ASSOCIATED) == 0) {
+ DPRINTF(("Not associated\n"));
+ return (-1);
+ }
+
+ IWI_STATE_BEGIN(sc, IWI_FW_DISASSOCIATING);
+
if (quiet)
assoc->type = IWI_HC_DISASSOC_QUIET;
else
@@ -3043,17 +3031,6 @@ iwi_disassociate(struct iwi_softc *sc, int quiet)
}
static void
-iwi_down(void *arg, int npending)
-{
- struct iwi_softc *sc = arg;
- IWI_LOCK_DECL;
-
- IWI_LOCK(sc);
- iwi_disassociate(sc, 0);
- IWI_UNLOCK(sc);
-}
-
-static void
iwi_init(void *priv)
{
struct iwi_softc *sc = priv;
@@ -3134,21 +3111,20 @@ iwi_init_locked(void *priv, int force)
int i;
IWI_LOCK_DECL;
- IWI_LOCK_CHECK(sc);
- if (sc->flags & IWI_FLAG_FW_LOADING) {
+ IWI_LOCK_ASSERT(sc);
+ if (sc->fw_state == IWI_FW_LOADING) {
device_printf(sc->sc_dev, "%s: already loading\n", __func__);
return; /* XXX: condvar? */
}
iwi_stop(sc);
+ IWI_STATE_BEGIN(sc, IWI_FW_LOADING);
if (iwi_reset(sc) != 0) {
device_printf(sc->sc_dev, "could not reset adapter\n");
goto fail;
}
- sc->flags |= IWI_FLAG_FW_LOADING;
-
IWI_UNLOCK(sc);
if (iwi_get_firmware(sc)) {
IWI_LOCK(sc);
@@ -3233,14 +3209,15 @@ iwi_init_locked(void *priv, int force)
} else
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ callout_reset(&sc->sc_wdtimer, hz, iwi_watchdog, sc);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
- sc->flags &= ~IWI_FLAG_FW_LOADING;
+ IWI_STATE_END(sc, IWI_FW_LOADING);
return;
fail: ifp->if_flags &= ~IFF_UP;
- sc->flags &= ~IWI_FLAG_FW_LOADING;
+ IWI_STATE_END(sc, IWI_FW_LOADING);
iwi_stop(sc);
iwi_put_firmware(sc);
}
@@ -3252,12 +3229,13 @@ iwi_stop(void *priv)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
- IWI_LOCK_CHECK(sc); /* XXX: pretty sure this triggers */
+ IWI_LOCK_ASSERT(sc);
if (sc->sc_softled) {
callout_stop(&sc->sc_ledtimer);
sc->sc_blinking = 0;
}
+ callout_stop(&sc->sc_wdtimer);
iwi_stop_master(sc);
CSR_WRITE_4(sc, IWI_CSR_RST, IWI_RST_SOFT_RESET);
@@ -3270,13 +3248,15 @@ iwi_stop(void *priv)
iwi_reset_tx_ring(sc, &sc->txq[3]);
iwi_reset_rx_ring(sc, &sc->rxq);
- ifp->if_timer = 0;
ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
sc->sc_tx_timer = 0;
sc->sc_rfkill_timer = 0;
- sc->sc_scan_timer = 0;
- sc->flags &= ~(IWI_FLAG_BUSY | IWI_FLAG_SCANNING | IWI_FLAG_ASSOCIATED);
+ sc->sc_state_timer = 0;
+ sc->sc_busy_timer = 0;
+ sc->flags &= ~(IWI_FLAG_BUSY | IWI_FLAG_ASSOCIATED);
+ sc->fw_state = IWI_FW_IDLE;
+ wakeup(sc);
ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
}
@@ -3315,11 +3295,13 @@ static void
iwi_radio_off(void *arg, int pending)
{
struct iwi_softc *sc = arg;
+ IWI_LOCK_DECL;
device_printf(sc->sc_dev, "radio turned off\n");
+ IWI_LOCK(sc);
iwi_stop(sc);
sc->sc_rfkill_timer = 2;
- sc->sc_ifp->if_timer = 1;
+ IWI_UNLOCK(sc);
}
static int
@@ -3365,11 +3347,6 @@ iwi_sysctlattach(struct iwi_softc *sc)
CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0, iwi_sysctl_stats, "S",
"statistics");
- sc->dwelltime = 100;
- SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "dwell",
- CTLFLAG_RW, &sc->dwelltime, 0,
- "channel dwell time (ms) for AP/station scanning");
-
sc->bluetooth = 0;
SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "bluetooth",
CTLFLAG_RW, &sc->bluetooth, 0, "bluetooth coexistence");
@@ -3568,3 +3545,154 @@ iwi_ledattach(struct iwi_softc *sc)
sc->sc_ledpin = IWI_RST_LED_ASSOCIATED;
}
}
+
+static void
+iwi_ops(void *arg, int npending)
+{
+ struct iwi_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ IWI_LOCK_DECL;
+ int cmd;
+
+again:
+ IWI_CMD_LOCK(sc);
+ cmd = sc->sc_cmd[sc->sc_cmd_cur];
+ if (cmd == 0) {
+ /* No more commands to process */
+ IWI_CMD_UNLOCK(sc);
+ return;
+ }
+ sc->sc_cmd[sc->sc_cmd_cur] = 0; /* free the slot */
+ sc->sc_cmd_cur = (sc->sc_cmd_cur + 1) % IWI_CMD_MAXOPS;
+ IWI_CMD_UNLOCK(sc);
+
+ IWI_LOCK(sc);
+ while (sc->fw_state != IWI_FW_IDLE || (sc->flags & IWI_FLAG_BUSY)) {
+ msleep(sc, &sc->sc_mtx, 0, "iwicmd", hz/10);
+ }
+
+ if (!(sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING))
+ goto done;
+
+ switch (cmd) {
+ case IWI_ASSOC:
+ iwi_auth_and_assoc(sc);
+ break;
+ case IWI_DISASSOC:
+ iwi_disassociate(sc, 0);
+ break;
+ case IWI_SET_WME:
+ if (ic->ic_state == IEEE80211_S_RUN)
+ (void) iwi_wme_setparams(sc);
+ break;
+ case IWI_SCAN_START:
+ sc->flags |= IWI_FLAG_CHANNEL_SCAN;
+ break;
+ case IWI_SCAN_CURCHAN:
+ case IWI_SCAN_ALLCHAN:
+ if (!(sc->flags & IWI_FLAG_CHANNEL_SCAN)) {
+ DPRINTF(("%s: ic_scan_curchan while not scanning\n",
+ __func__));
+ goto done;
+ }
+ if (iwi_scanchan(sc, sc->sc_maxdwell, cmd))
+ ieee80211_cancel_scan(ic);
+
+ break;
+ }
+done:
+ IWI_UNLOCK(sc);
+
+ /* Take another pass */
+ goto again;
+}
+
+static int
+iwi_queue_cmd(struct iwi_softc *sc, int cmd)
+{
+ IWI_CMD_LOCK(sc);
+ if (sc->sc_cmd[sc->sc_cmd_next] != 0) {
+ IWI_CMD_UNLOCK(sc);
+ DPRINTF(("%s: command %d dropped\n", __func__, cmd));
+ return (EBUSY);
+ }
+
+ sc->sc_cmd[sc->sc_cmd_next] = cmd;
+ sc->sc_cmd_next = (sc->sc_cmd_next + 1) % IWI_CMD_MAXOPS;
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_opstask);
+ IWI_CMD_UNLOCK(sc);
+ return (0);
+}
+
+static void
+iwi_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ iwi_queue_cmd(sc, IWI_SCAN_START);
+}
+
+static void
+iwi_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+ if (sc->fw_state == IWI_FW_IDLE)
+ iwi_setcurchan(sc, ic->ic_curchan->ic_ieee);
+}
+
+static void
+iwi_scan_curchan(struct ieee80211com *ic, unsigned long maxdwell)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ sc->sc_maxdwell = maxdwell;
+ iwi_queue_cmd(sc, IWI_SCAN_CURCHAN);
+}
+
+#if 0
+static void
+iwi_scan_allchan(struct ieee80211com *ic, unsigned long maxdwell)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ sc->sc_maxdwell = maxdwell;
+ iwi_queue_cmd(sc, IWI_SCAN_ALLCHAN);
+}
+#endif
+
+static void
+iwi_scan_mindwell(struct ieee80211com *ic)
+{
+ /* NB: don't try to abort scan; wait for firmware to finish */
+}
+
+static void
+iwi_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_scanaborttask);
+}
+
+static void
+iwi_assoc(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ iwi_queue_cmd(sc, IWI_ASSOC);
+}
+
+static void
+iwi_disassoc(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct iwi_softc *sc = ifp->if_softc;
+
+ iwi_queue_cmd(sc, IWI_DISASSOC);
+}
diff --git a/sys/dev/iwi/if_iwireg.h b/sys/dev/iwi/if_iwireg.h
index 5c7435e..fb56fa5 100644
--- a/sys/dev/iwi/if_iwireg.h
+++ b/sys/dev/iwi/if_iwireg.h
@@ -213,7 +213,7 @@ struct iwi_notif_authentication {
/* structure for notification IWI_NOTIF_TYPE_ASSOCIATION */
struct iwi_notif_association {
uint8_t state;
-#define IWI_ASSOC_FAIL 0
+#define IWI_ASSOC_INIT 0
#define IWI_ASSOC_SUCCESS 12
uint8_t pad[11];
} __packed;
@@ -417,6 +417,10 @@ struct iwi_scan {
#define IWI_SCAN_TYPE_BDIRECTED 4 /* active, directed+bcast probe */
#define IWI_SCAN_TYPES 5
+/* scan result codes */
+#define IWI_SCAN_COMPLETED 1 /* scan compeleted sucessfully */
+#define IWI_SCAN_ABORTED 2 /* scan was aborted by the driver */
+
/* structure for command IWI_CMD_SCAN_EXT */
struct iwi_scan_ext {
uint32_t full_scan_index;
diff --git a/sys/dev/iwi/if_iwivar.h b/sys/dev/iwi/if_iwivar.h
index f652c4d..a1c3915 100644
--- a/sys/dev/iwi/if_iwivar.h
+++ b/sys/dev/iwi/if_iwivar.h
@@ -123,6 +123,8 @@ struct iwi_softc {
device_t sc_dev;
struct mtx sc_mtx;
+ struct mtx sc_cmdlock;
+ char sc_cmdname[12]; /* e.g. "iwi0_cmd" */
uint8_t sc_mcast[IEEE80211_ADDR_LEN];
struct unrhdr *sc_unr;
struct taskqueue *sc_tq; /* private task queue */
@@ -132,11 +134,15 @@ struct iwi_softc {
uint32_t flags;
#define IWI_FLAG_FW_INITED (1 << 0)
-#define IWI_FLAG_SCANNING (1 << 1)
-#define IWI_FLAG_FW_LOADING (1 << 2)
#define IWI_FLAG_BUSY (1 << 3) /* busy sending a command */
#define IWI_FLAG_ASSOCIATED (1 << 4) /* currently associated */
-
+#define IWI_FLAG_CHANNEL_SCAN (1 << 5)
+ uint32_t fw_state;
+#define IWI_FW_IDLE 0
+#define IWI_FW_LOADING 1
+#define IWI_FW_ASSOCIATING 2
+#define IWI_FW_DISASSOCIATING 3
+#define IWI_FW_SCANNING 4
struct iwi_cmd_ring cmdq;
struct iwi_tx_ring txq[WME_NUM_AC];
struct iwi_rx_ring rxq;
@@ -176,20 +182,16 @@ struct iwi_softc {
int curchan; /* current h/w channel # */
int antenna;
- int dwelltime;
int bluetooth;
struct iwi_associate assoc;
struct iwi_wme_params wme[3];
+ u_int sc_scangen;
struct task sc_radiontask; /* radio on processing */
struct task sc_radiofftask; /* radio off processing */
- struct task sc_scanstarttask;/* scan start processing */
- struct task sc_scanaborttask;/* scan abort processing */
- struct task sc_scandonetask;/* scan completed processing */
- struct task sc_scantask; /* scan channel processing */
- struct task sc_setwmetask; /* set wme params processing */
- struct task sc_downtask; /* disassociate processing */
+ struct task sc_scanaborttask; /* cancel active scan */
struct task sc_restarttask; /* restart adapter processing */
+ struct task sc_opstask; /* scan / auth processing */
unsigned int sc_softled : 1, /* enable LED gpio status */
sc_ledstate: 1, /* LED on/off state */
@@ -204,11 +206,26 @@ struct iwi_softc {
u_int8_t sc_txrix;
u_int16_t sc_ledoff; /* off time for current blink */
struct callout sc_ledtimer; /* led off timer */
+ struct callout sc_wdtimer; /* watchdog timer */
int sc_tx_timer;
int sc_rfkill_timer;/* poll for rfkill change */
- int sc_scan_timer; /* scan request timeout */
+ int sc_state_timer; /* firmware state timer */
+ int sc_busy_timer; /* firmware cmd timer */
+#define IWI_SCAN_START (1 << 0)
+#define IWI_SET_CHANNEL (1 << 1)
+#define IWI_SCAN_END (1 << 2)
+#define IWI_ASSOC (1 << 3)
+#define IWI_DISASSOC (1 << 4)
+#define IWI_SCAN_CURCHAN (1 << 5)
+#define IWI_SCAN_ALLCHAN (1 << 6)
+#define IWI_SET_WME (1 << 7)
+#define IWI_CMD_MAXOPS 10
+ int sc_cmd[IWI_CMD_MAXOPS];
+ int sc_cmd_cur; /* current queued scan task */
+ int sc_cmd_next; /* last queued scan task */
+ unsigned long sc_maxdwell; /* max dwell time for curchan */
struct bpf_if *sc_drvbpf;
union {
@@ -226,15 +243,34 @@ struct iwi_softc {
int sc_txtap_len;
};
+#define IWI_STATE_BEGIN(_sc, _state) do { \
+ KASSERT(_sc->fw_state == IWI_FW_IDLE, \
+ ("iwi firmware not idle")); \
+ _sc->fw_state = _state; \
+ _sc->sc_state_timer = 5; \
+ DPRINTF(("enter FW state %d\n", _state)); \
+} while (0)
+
+#define IWI_STATE_END(_sc, _state) do { \
+ if (_sc->fw_state == _state) \
+ DPRINTF(("exit FW state %d\n", _state)); \
+ else \
+ DPRINTF(("expected FW state %d, got %d\n", \
+ _state, _sc->fw_state)); \
+ _sc->fw_state = IWI_FW_IDLE; \
+ wakeup(_sc); \
+ _sc->sc_state_timer = 0; \
+} while (0)
/*
* NB.: This models the only instance of async locking in iwi_init_locked
* and must be kept in sync.
*/
+#define IWI_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \
+ MTX_NETWORK_LOCK, MTX_DEF)
+#define IWI_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
#define IWI_LOCK_DECL int __waslocked = 0
-#define IWI_LOCK_CHECK(sc) do { \
- if (!mtx_owned(&(sc)->sc_mtx)) \
- DPRINTF(("%s iwi_lock not held\n", __func__)); \
-} while (0)
+#define IWI_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
#define IWI_LOCK(sc) do { \
if (!(__waslocked = mtx_owned(&(sc)->sc_mtx))) \
mtx_lock(&(sc)->sc_mtx); \
@@ -243,3 +279,11 @@ struct iwi_softc {
if (!__waslocked) \
mtx_unlock(&(sc)->sc_mtx); \
} while (0)
+#define IWI_CMD_LOCK_INIT(sc) do { \
+ snprintf((sc)->sc_cmdname, sizeof((sc)->sc_cmdname), "%s_cmd", \
+ device_get_nameunit((sc)->sc_dev)); \
+ mtx_init(&(sc)->sc_cmdlock, (sc)->sc_cmdname, NULL, MTX_DEF); \
+} while (0)
+#define IWI_CMD_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_cmdlock)
+#define IWI_CMD_LOCK(sc) mtx_lock(&(sc)->sc_cmdlock)
+#define IWI_CMD_UNLOCK(sc) mtx_unlock(&(sc)->sc_cmdlock)
diff --git a/sys/dev/ral/if_ral_pci.c b/sys/dev/ral/if_ral_pci.c
index 3d9976d..2ceafe4 100644
--- a/sys/dev/ral/if_ral_pci.c
+++ b/sys/dev/ral/if_ral_pci.c
@@ -87,8 +87,8 @@ static struct ral_opns {
} ral_rt2560_opns = {
rt2560_attach,
rt2560_detach,
- rt2560_shutdown,
- rt2560_suspend,
+ rt2560_stop,
+ rt2560_stop,
rt2560_resume,
rt2560_intr
@@ -192,7 +192,8 @@ ral_pci_attach(device_t dev)
sc->sc_st = rman_get_bustag(psc->mem);
sc->sc_sh = rman_get_bushandle(psc->mem);
-
+ sc->sc_invalid = 1;
+
psc->irq_rid = 0;
psc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &psc->irq_rid,
RF_ACTIVE | RF_SHAREABLE);
@@ -214,7 +215,8 @@ ral_pci_attach(device_t dev)
device_printf(dev, "could not set up interrupt\n");
return error;
}
-
+ sc->sc_invalid = 0;
+
return 0;
}
@@ -222,7 +224,11 @@ static int
ral_pci_detach(device_t dev)
{
struct ral_pci_softc *psc = device_get_softc(dev);
-
+ struct rt2560_softc *sc = &psc->u.sc_rt2560;
+
+ /* check if device was removed */
+ sc->sc_invalid = !bus_child_present(dev);
+
(*psc->sc_opns->detach)(psc);
bus_generic_detach(dev);
diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c
index 36a849d..f09c4f3 100644
--- a/sys/dev/ral/rt2560.c
+++ b/sys/dev/ral/rt2560.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -64,6 +65,10 @@ __FBSDID("$FreeBSD$");
#include <dev/ral/rt2560reg.h>
#include <dev/ral/rt2560var.h>
+#define RT2560_RSSI(sc, rssi) \
+ ((rssi) > (RT2560_NOISE_FLOOR + (sc)->rssi_corr) ? \
+ ((rssi) - RT2560_NOISE_FLOOR - (sc)->rssi_corr) : 0)
+
#ifdef RAL_DEBUG
#define DPRINTF(x) do { if (ral_debug > 0) printf x; } while (0)
#define DPRINTFN(n, x) do { if (ral_debug >= (n)) printf x; } while (0)
@@ -90,7 +95,6 @@ static void rt2560_free_rx_ring(struct rt2560_softc *,
static struct ieee80211_node *rt2560_node_alloc(
struct ieee80211_node_table *);
static int rt2560_media_change(struct ifnet *);
-static void rt2560_next_scan(void *);
static void rt2560_iter_func(void *, struct ieee80211_node *);
static void rt2560_update_rssadapt(void *);
static int rt2560_newstate(struct ieee80211com *,
@@ -105,6 +109,9 @@ static void rt2560_beacon_expire(struct rt2560_softc *);
static void rt2560_wakeup_expire(struct rt2560_softc *);
static uint8_t rt2560_rxrate(struct rt2560_rx_desc *);
static int rt2560_ack_rate(struct ieee80211com *, int);
+static void rt2560_scan_start(struct ieee80211com *);
+static void rt2560_scan_end(struct ieee80211com *);
+static void rt2560_set_channel(struct ieee80211com *);
static uint16_t rt2560_txtime(int, int, uint32_t);
static uint8_t rt2560_plcp_signal(int);
static void rt2560_setup_tx_desc(struct rt2560_softc *,
@@ -137,7 +144,7 @@ static void rt2560_update_plcp(struct rt2560_softc *);
static void rt2560_update_slot(struct ifnet *);
static void rt2560_set_basicrates(struct rt2560_softc *);
static void rt2560_update_led(struct rt2560_softc *, int, int);
-static void rt2560_set_bssid(struct rt2560_softc *, uint8_t *);
+static void rt2560_set_bssid(struct rt2560_softc *, const uint8_t *);
static void rt2560_set_macaddr(struct rt2560_softc *, uint8_t *);
static void rt2560_get_macaddr(struct rt2560_softc *, uint8_t *);
static void rt2560_update_promisc(struct rt2560_softc *);
@@ -147,7 +154,6 @@ static int rt2560_bbp_init(struct rt2560_softc *);
static void rt2560_set_txantenna(struct rt2560_softc *, int);
static void rt2560_set_rxantenna(struct rt2560_softc *, int);
static void rt2560_init(void *);
-static void rt2560_stop(void *);
static int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
@@ -187,7 +193,7 @@ rt2560_attach(device_t dev, int id)
struct rt2560_softc *sc = device_get_softc(dev);
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp;
- int error, i;
+ int error, bands;
sc->sc_dev = dev;
@@ -195,7 +201,6 @@ rt2560_attach(device_t dev, int id)
MTX_DEF | MTX_RECURSE);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
- callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE);
/* retrieve RT2560 rev. no */
@@ -272,37 +277,20 @@ rt2560_attach(device_t dev, int id)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
+ IEEE80211_C_BGSCAN | /* bg scanning support */
IEEE80211_C_WPA; /* 802.11i */
- if (sc->rf_rev == RT2560_RF_5222) {
- /* set supported .11a channels */
- for (i = 36; i <= 64; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 100; i <= 140; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 149; i <= 161; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- }
-
- /* set supported .11b and .11g channels (1 through 14) */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ if (sc->rf_rev == RT2560_RF_5222)
+ setbit(&bands, IEEE80211_MODE_11A);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
+ ic->ic_scan_start = rt2560_scan_start;
+ ic->ic_scan_end = rt2560_scan_end;
+ ic->ic_set_channel = rt2560_set_channel;
ic->ic_node_alloc = rt2560_node_alloc;
ic->ic_updateslot = rt2560_update_slot;
ic->ic_reset = rt2560_reset;
@@ -365,10 +353,9 @@ rt2560_detach(void *xsc)
struct rt2560_softc *sc = xsc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
-
+
rt2560_stop(sc);
callout_stop(&sc->watchdog_ch);
- callout_stop(&sc->scan_ch);
callout_stop(&sc->rssadapt_ch);
bpfdetach(ifp);
@@ -388,22 +375,6 @@ rt2560_detach(void *xsc)
}
void
-rt2560_shutdown(void *xsc)
-{
- struct rt2560_softc *sc = xsc;
-
- rt2560_stop(sc);
-}
-
-void
-rt2560_suspend(void *xsc)
-{
- struct rt2560_softc *sc = xsc;
-
- rt2560_stop(sc);
-}
-
-void
rt2560_resume(void *xsc)
{
struct rt2560_softc *sc = xsc;
@@ -733,28 +704,13 @@ rt2560_media_change(struct ifnet *ifp)
int error;
error = ieee80211_media_change(ifp);
- if (error != ENETRESET)
- return error;
-
- if ((ifp->if_flags & IFF_UP) &&
- (ifp->if_drv_flags & IFF_DRV_RUNNING))
- rt2560_init(sc);
-
- return 0;
-}
-
-/*
- * This function is called periodically (every 200ms) during scanning to
- * switch from one channel to another.
- */
-static void
-rt2560_next_scan(void *arg)
-{
- struct rt2560_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_next_scan(ic);
+ if (error == ENETRESET) {
+ if ((ifp->if_flags & IFF_UP) &&
+ (ifp->if_drv_flags & IFF_DRV_RUNNING))
+ rt2560_init(sc);
+ }
+ return error;
}
/*
@@ -796,7 +752,6 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
int error = 0;
ostate = ic->ic_state;
- callout_stop(&sc->scan_ch);
switch (nstate) {
case IEEE80211_S_INIT:
@@ -810,24 +765,7 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2560_update_led(sc, 0, 0);
}
break;
-
- case IEEE80211_S_SCAN:
- rt2560_set_chan(sc, ic->ic_curchan);
- callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000,
- rt2560_next_scan, sc);
- break;
-
- case IEEE80211_S_AUTH:
- rt2560_set_chan(sc, ic->ic_curchan);
- break;
-
- case IEEE80211_S_ASSOC:
- rt2560_set_chan(sc, ic->ic_curchan);
- break;
-
case IEEE80211_S_RUN:
- rt2560_set_chan(sc, ic->ic_curchan);
-
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@@ -862,6 +800,10 @@ rt2560_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2560_enable_tsf_sync(sc);
}
break;
+ case IEEE80211_S_SCAN:
+ case IEEE80211_S_AUTH:
+ case IEEE80211_S_ASSOC:
+ break;
}
return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
@@ -1060,6 +1002,9 @@ rt2560_prio_intr(struct rt2560_softc *sc)
struct ifnet *ifp = ic->ic_ifp;
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+ int flags;
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
BUS_DMASYNC_POSTREAD);
@@ -1068,18 +1013,18 @@ rt2560_prio_intr(struct rt2560_softc *sc)
desc = &sc->prioq.desc[sc->prioq.next];
data = &sc->prioq.data[sc->prioq.next];
- if ((le32toh(desc->flags) & RT2560_TX_BUSY) ||
- !(le32toh(desc->flags) & RT2560_TX_VALID))
+ flags = le32toh(desc->flags);
+ if ((flags & RT2560_TX_BUSY) || (flags & RT2560_TX_VALID) == 0)
break;
- switch (le32toh(desc->flags) & RT2560_TX_RESULT_MASK) {
+ switch (flags & RT2560_TX_RESULT_MASK) {
case RT2560_TX_SUCCESS:
DPRINTFN(10, ("mgt frame sent successfully\n"));
break;
case RT2560_TX_SUCCESS_RETRY:
DPRINTFN(9, ("mgt frame sent after %u retries\n",
- (le32toh(desc->flags) >> 5) & 0x7));
+ (flags >> 5) & 0x7));
break;
case RT2560_TX_FAIL_RETRY:
@@ -1091,15 +1036,17 @@ rt2560_prio_intr(struct rt2560_softc *sc)
case RT2560_TX_FAIL_OTHER:
default:
device_printf(sc->sc_dev, "sending mgt frame failed "
- "0x%08x\n", le32toh(desc->flags));
+ "0x%08x\n", flags);
+ break;
}
bus_dmamap_sync(sc->prioq.data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->prioq.data_dmat, data->map);
- m_freem(data->m);
+
+ m = data->m;
data->m = NULL;
- ieee80211_free_node(data->ni);
+ ni = data->ni;
data->ni = NULL;
/* descriptor is no longer valid */
@@ -1109,6 +1056,13 @@ rt2560_prio_intr(struct rt2560_softc *sc)
sc->prioq.queued--;
sc->prioq.next = (sc->prioq.next + 1) % RT2560_PRIO_RING_COUNT;
+
+ if (m->m_flags & M_TXCB)
+ ieee80211_process_callback(ni, m,
+ (flags & RT2560_TX_RESULT_MASK) &~
+ (RT2560_TX_SUCCESS | RT2560_TX_SUCCESS_RETRY));
+ m_freem(m);
+ ieee80211_free_node(ni);
}
bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map,
@@ -1227,25 +1181,31 @@ rt2560_decryption_intr(struct rt2560_softc *sc)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
- tap->wr_antsignal = desc->rssi;
+ tap->wr_antsignal = RT2560_RSSI(sc, desc->rssi);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
+ sc->sc_flags |= RAL_INPUT_RUNNING;
+ RAL_UNLOCK(sc);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic,
(struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, desc->rssi, 0);
+ ieee80211_input(ic, m, ni, RT2560_RSSI(sc, desc->rssi),
+ RT2560_NOISE_FLOOR, 0);
/* give rssi to the rate adatation algorithm */
rn = (struct rt2560_node *)ni;
- ral_rssadapt_input(ic, ni, &rn->rssadapt, desc->rssi);
+ ral_rssadapt_input(ic, ni, &rn->rssadapt,
+ RT2560_RSSI(sc, desc->rssi));
/* node is no longer needed */
ieee80211_free_node(ni);
+ RAL_LOCK(sc);
+ sc->sc_flags &= ~RAL_INPUT_RUNNING;
skip: desc->flags = htole32(RT2560_RX_BUSY);
DPRINTFN(15, ("decryption done idx=%u\n", sc->rxq.cur_decrypt));
@@ -1324,9 +1284,14 @@ rt2560_beacon_expire(struct rt2560_softc *sc)
if (ic->ic_opmode != IEEE80211_M_IBSS &&
ic->ic_opmode != IEEE80211_M_HOSTAP)
- return;
+ return;
data = &sc->bcnq.data[sc->bcnq.next];
+ /*
+ * Don't send beacon if bsschan isn't set
+ */
+ if (data->ni == NULL)
+ return;
bus_dmamap_sync(sc->bcnq.data_dmat, data->map, BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(sc->bcnq.data_dmat, data->map);
@@ -1808,7 +1773,6 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
struct rt2560_tx_desc *desc;
struct rt2560_tx_data *data;
struct rt2560_node *rn;
- struct ieee80211_rateset *rs;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
struct mbuf *mnew;
@@ -1820,9 +1784,10 @@ rt2560_tx_data(struct rt2560_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
- rs = &ic->ic_sup_rates[ic->ic_curmode];
- rate = rs->rs_rates[ic->ic_fixed_rate];
+ rate = ic->ic_fixed_rate;
} else {
+ struct ieee80211_rateset *rs;
+
rs = &ni->ni_rates;
rn = (struct rt2560_node *)ni;
ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs, wh,
@@ -2020,9 +1985,10 @@ rt2560_start(struct ifnet *ifp)
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
- if (rt2560_tx_mgt(sc, m0, ni) != 0)
+ if (rt2560_tx_mgt(sc, m0, ni) != 0) {
+ ieee80211_free_node(ni);
break;
-
+ }
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
@@ -2045,6 +2011,28 @@ rt2560_start(struct ifnet *ifp)
m_freem(m0);
continue;
}
+ if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
+ (m0->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.
+ */
+ ieee80211_pwrsave(ni, m0);
+ /*
+ * If we're in power save mode 'cuz of a bg
+ * scan cancel it so the traffic can flow.
+ * The packet we just queued will automatically
+ * get sent when we drop out of power save.
+ * XXX locking
+ */
+ if (ic->ic_flags & IEEE80211_F_SCAN)
+ ieee80211_cancel_scan(ic);
+ ieee80211_free_node(ni);
+ continue;
+
+ }
+
BPF_MTAP(ifp, m0);
m0 = ieee80211_encap(ic, m0, ni);
@@ -2052,7 +2040,7 @@ rt2560_start(struct ifnet *ifp)
ieee80211_free_node(ni);
continue;
}
-
+
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
@@ -2074,7 +2062,6 @@ static void
rt2560_watchdog(void *arg)
{
struct rt2560_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
@@ -2085,8 +2072,6 @@ rt2560_watchdog(void *arg)
}
callout_reset(&sc->watchdog_ch, hz, rt2560_watchdog, sc);
}
-
- ieee80211_watchdog(ic);
}
/*
@@ -2115,19 +2100,22 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ieee80211com *ic = &sc->sc_ic;
int error = 0;
- RAL_LOCK(sc);
+
switch (cmd) {
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
+ RAL_LOCK(sc);
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2560_update_promisc(sc);
else
rt2560_init(sc);
+ RAL_UNLOCK(sc);
} else {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
rt2560_stop(sc);
}
+
break;
default:
@@ -2142,7 +2130,6 @@ rt2560_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
}
- RAL_UNLOCK(sc);
return error;
}
@@ -2295,6 +2282,8 @@ rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c)
rt2560_rf_write(sc, RAL_RF3, power << 7 | 0x00040);
rt2560_rf_write(sc, RAL_RF4, rt2560_rf5222[i].r4);
break;
+ default:
+ printf("unknown ral rev=%d\n", sc->rf_rev);
}
if (ic->ic_state != IEEE80211_S_SCAN) {
@@ -2312,6 +2301,18 @@ rt2560_set_chan(struct rt2560_softc *sc, struct ieee80211_channel *c)
}
}
+static void
+rt2560_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2560_softc *sc = ifp->if_softc;
+
+ RAL_LOCK(sc);
+ rt2560_set_chan(sc, ic->ic_curchan);
+ RAL_UNLOCK(sc);
+
+}
+
#if 0
/*
* Disable RF auto-tuning.
@@ -2456,7 +2457,7 @@ rt2560_update_led(struct rt2560_softc *sc, int led1, int led2)
}
static void
-rt2560_set_bssid(struct rt2560_softc *sc, uint8_t *bssid)
+rt2560_set_bssid(struct rt2560_softc *sc, const uint8_t *bssid)
{
uint32_t tmp;
@@ -2559,6 +2560,37 @@ rt2560_read_eeprom(struct rt2560_softc *sc)
sc->txpow[i * 2] = val >> 8;
sc->txpow[i * 2 + 1] = val & 0xff;
}
+
+ val = rt2560_eeprom_read(sc, RT2560_EEPROM_CALIBRATE);
+ if ((val & 0xff) == 0xff)
+ sc->rssi_corr = RT2560_DEFAULT_RSSI_CORR;
+ else
+ sc->rssi_corr = val & 0xff;
+ DPRINTF(("rssi correction %d, calibrate 0x%02x\n",
+ sc->rssi_corr, val));
+}
+
+
+static void
+rt2560_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2560_softc *sc = ifp->if_softc;
+
+ /* abort TSF synchronization */
+ RAL_WRITE(sc, RT2560_CSR14, 0);
+ rt2560_set_bssid(sc, ifp->if_broadcastaddr);
+}
+
+static void
+rt2560_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2560_softc *sc = ifp->if_softc;
+
+ rt2560_enable_tsf_sync(sc);
+ /* XXX keep local copy */
+ rt2560_set_bssid(sc, ic->ic_bss->ni_bssid);
}
static int
@@ -2653,10 +2685,11 @@ rt2560_init(void *priv)
uint32_t tmp;
int i;
- RAL_LOCK(sc);
+
rt2560_stop(sc);
+ RAL_LOCK(sc);
/* setup tx rings */
tmp = RT2560_PRIO_RING_COUNT << 24 |
RT2560_ATIM_RING_COUNT << 16 |
@@ -2739,36 +2772,44 @@ rt2560_init(void *priv)
}
void
-rt2560_stop(void *priv)
+rt2560_stop(void *arg)
{
- struct rt2560_softc *sc = priv;
+ struct rt2560_softc *sc = arg;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
+ volatile int *flags = &sc->sc_flags;
- sc->sc_tx_timer = 0;
- ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
-
- /* abort Tx */
- RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX);
-
- /* disable Rx */
- RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX);
-
- /* reset ASIC (imply reset BBP) */
- RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
- RAL_WRITE(sc, RT2560_CSR1, 0);
-
- /* disable interrupts */
- RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
+ while (*flags & RAL_INPUT_RUNNING) {
+ tsleep(sc, 0, "ralrunning", hz/10);
+ }
- /* reset Tx and Rx rings */
- rt2560_reset_tx_ring(sc, &sc->txq);
- rt2560_reset_tx_ring(sc, &sc->atimq);
- rt2560_reset_tx_ring(sc, &sc->prioq);
- rt2560_reset_tx_ring(sc, &sc->bcnq);
- rt2560_reset_rx_ring(sc, &sc->rxq);
+ RAL_LOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ sc->sc_tx_timer = 0;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ /* abort Tx */
+ RAL_WRITE(sc, RT2560_TXCSR0, RT2560_ABORT_TX);
+
+ /* disable Rx */
+ RAL_WRITE(sc, RT2560_RXCSR0, RT2560_DISABLE_RX);
+
+ /* reset ASIC (imply reset BBP) */
+ RAL_WRITE(sc, RT2560_CSR1, RT2560_RESET_ASIC);
+ RAL_WRITE(sc, RT2560_CSR1, 0);
+
+ /* disable interrupts */
+ RAL_WRITE(sc, RT2560_CSR8, 0xffffffff);
+
+ /* reset Tx and Rx rings */
+ rt2560_reset_tx_ring(sc, &sc->txq);
+ rt2560_reset_tx_ring(sc, &sc->atimq);
+ rt2560_reset_tx_ring(sc, &sc->prioq);
+ rt2560_reset_tx_ring(sc, &sc->bcnq);
+ rt2560_reset_rx_ring(sc, &sc->rxq);
+ }
+ RAL_UNLOCK(sc);
}
static int
@@ -2828,3 +2869,4 @@ bad:
RAL_UNLOCK(sc);
return EIO; /* XXX */
}
+
diff --git a/sys/dev/ral/rt2560reg.h b/sys/dev/ral/rt2560reg.h
index 6b1cf0d..3871ed3 100644
--- a/sys/dev/ral/rt2560reg.h
+++ b/sys/dev/ral/rt2560reg.h
@@ -17,6 +17,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define RT2560_DEFAULT_RSSI_CORR 0x79
+#define RT2560_NOISE_FLOOR -95
+
#define RT2560_TX_RING_COUNT 48
#define RT2560_ATIM_RING_COUNT 4
#define RT2560_PRIO_RING_COUNT 16
@@ -296,6 +299,7 @@ struct rt2560_rx_desc {
#define RT2560_EEPROM_CONFIG0 16
#define RT2560_EEPROM_BBP_BASE 19
#define RT2560_EEPROM_TXPOWER 35
+#define RT2560_EEPROM_CALIBRATE 62
/*
* control and status registers access macros
diff --git a/sys/dev/ral/rt2560var.h b/sys/dev/ral/rt2560var.h
index 50112b5..c01abb1 100644
--- a/sys/dev/ral/rt2560var.h
+++ b/sys/dev/ral/rt2560var.h
@@ -109,14 +109,18 @@ struct rt2560_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
- struct callout scan_ch;
struct callout rssadapt_ch;
int sc_tx_timer;
-
+ int sc_invalid;
+/*
+ * The same in both up to here
+ * ------------------------------------------------
+ */
uint32_t asic_rev;
uint32_t eeprom_rev;
uint8_t rf_rev;
+ uint8_t rssi_corr;
struct rt2560_tx_ring txq;
struct rt2560_tx_ring prioq;
@@ -157,12 +161,13 @@ struct rt2560_softc {
} sc_txtapu;
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
+#define RAL_INPUT_RUNNING 1
+ int sc_flags;
};
int rt2560_attach(device_t, int);
int rt2560_detach(void *);
-void rt2560_shutdown(void *);
-void rt2560_suspend(void *);
+void rt2560_stop(void *);
void rt2560_resume(void *);
void rt2560_intr(void *);
diff --git a/sys/dev/ral/rt2661.c b/sys/dev/ral/rt2661.c
index 8f13eb6..224da32 100644
--- a/sys/dev/ral/rt2661.c
+++ b/sys/dev/ral/rt2661.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -92,7 +93,6 @@ static void rt2661_free_rx_ring(struct rt2661_softc *,
static struct ieee80211_node *rt2661_node_alloc(
struct ieee80211_node_table *);
static int rt2661_media_change(struct ifnet *);
-static void rt2661_next_scan(void *);
static int rt2661_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static uint16_t rt2661_eeprom_read(struct rt2661_softc *, uint8_t);
@@ -104,6 +104,9 @@ static void rt2661_mcu_beacon_expire(struct rt2661_softc *);
static void rt2661_mcu_wakeup(struct rt2661_softc *);
static void rt2661_mcu_cmd_intr(struct rt2661_softc *);
static int rt2661_ack_rate(struct ieee80211com *, int);
+static void rt2661_scan_start(struct ieee80211com *);
+static void rt2661_scan_end(struct ieee80211com *);
+static void rt2661_set_channel(struct ieee80211com *);
static uint16_t rt2661_txtime(int, int, uint32_t);
static uint8_t rt2661_rxrate(struct rt2661_rx_desc *);
static uint8_t rt2661_plcp_signal(int);
@@ -148,6 +151,7 @@ static void rt2661_read_eeprom(struct rt2661_softc *);
static int rt2661_bbp_init(struct rt2661_softc *);
static void rt2661_init(void *);
static void rt2661_stop(void *);
+static void rt2661_stop_locked(struct rt2661_softc *);
static int rt2661_load_microcode(struct rt2661_softc *,
const uint8_t *, int);
#ifdef notyet
@@ -190,7 +194,7 @@ rt2661_attach(device_t dev, int id)
struct ifnet *ifp;
uint32_t val;
const uint8_t *ucode = NULL;
- int error, i, ac, ntries, size = 0;
+ int bands, error, ac, ntries, size = 0;
sc->sc_dev = dev;
@@ -198,7 +202,6 @@ rt2661_attach(device_t dev, int id)
MTX_DEF | MTX_RECURSE);
callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
- callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
callout_init(&sc->rssadapt_ch, CALLOUT_MPSAFE);
/* wait for NIC to initialize */
@@ -302,39 +305,22 @@ rt2661_attach(device_t dev, int id)
#ifdef notyet
IEEE80211_C_WME | /* 802.11e */
#endif
+ IEEE80211_C_BGSCAN | /* bg scanning support */
IEEE80211_C_WPA; /* 802.11i */
- if (sc->rf_rev == RT2661_RF_5225 || sc->rf_rev == RT2661_RF_5325) {
- /* set supported .11a channels */
- for (i = 36; i <= 64; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 100; i <= 140; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 149; i <= 165; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- }
-
- /* set supported .11b and .11g channels (1 through 14) */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ if (sc->rf_rev == RT2661_RF_5225 || sc->rf_rev == RT2661_RF_5325)
+ setbit(&bands, IEEE80211_MODE_11A);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_node_alloc = rt2661_node_alloc;
/* ic->ic_wme.wme_update = rt2661_wme_update;*/
+ ic->ic_scan_start = rt2661_scan_start;
+ ic->ic_scan_end = rt2661_scan_end;
+ ic->ic_set_channel = rt2661_set_channel;
ic->ic_updateslot = rt2661_update_slot;
ic->ic_reset = rt2661_reset;
/* enable s/w bmiss handling in sta mode */
@@ -356,6 +342,7 @@ rt2661_attach(device_t dev, int id)
sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
sc->sc_txtap.wt_ihdr.it_present = htole32(RT2661_TX_RADIOTAP_PRESENT);
+
/*
* Add a few sysctl knobs.
*/
@@ -376,7 +363,6 @@ fail3: rt2661_free_tx_ring(sc, &sc->mgtq);
fail2: while (--ac >= 0)
rt2661_free_tx_ring(sc, &sc->txq[ac]);
fail1: mtx_destroy(&sc->sc_mtx);
-
return error;
}
@@ -386,10 +372,9 @@ rt2661_detach(void *xsc)
struct rt2661_softc *sc = xsc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
-
+
rt2661_stop(sc);
callout_stop(&sc->watchdog_ch);
- callout_stop(&sc->scan_ch);
callout_stop(&sc->rssadapt_ch);
bpfdetach(ifp);
@@ -759,20 +744,6 @@ rt2661_media_change(struct ifnet *ifp)
}
/*
- * This function is called periodically (every 200ms) during scanning to
- * switch from one channel to another.
- */
-static void
-rt2661_next_scan(void *arg)
-{
- struct rt2661_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_next_scan(ic);
-}
-
-/*
* This function is called for each node present in the node station table.
*/
static void
@@ -811,7 +782,6 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
int error = 0;
ostate = ic->ic_state;
- callout_stop(&sc->scan_ch);
switch (nstate) {
case IEEE80211_S_INIT:
@@ -823,21 +793,7 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0x00ffffff);
}
break;
-
- case IEEE80211_S_SCAN:
- rt2661_set_chan(sc, ic->ic_curchan);
- callout_reset(&sc->scan_ch, (sc->dwelltime * hz) / 1000,
- rt2661_next_scan, sc);
- break;
-
- case IEEE80211_S_AUTH:
- case IEEE80211_S_ASSOC:
- rt2661_set_chan(sc, ic->ic_curchan);
- break;
-
case IEEE80211_S_RUN:
- rt2661_set_chan(sc, ic->ic_curchan);
-
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@@ -859,6 +815,10 @@ rt2661_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
rt2661_enable_tsf_sync(sc);
}
break;
+ case IEEE80211_S_SCAN:
+ case IEEE80211_S_AUTH:
+ case IEEE80211_S_ASSOC:
+ break;
}
return (error != 0) ? error : sc->sc_newstate(ic, nstate, arg);
@@ -934,6 +894,9 @@ rt2661_tx_intr(struct rt2661_softc *sc)
int qid, retrycnt;
for (;;) {
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+
val = RAL_READ(sc, RT2661_STA_CSR4);
if (!(val & RT2661_TX_STAT_VALID))
break;
@@ -944,12 +907,17 @@ rt2661_tx_intr(struct rt2661_softc *sc)
/* retrieve rate control algorithm context */
data = &txq->data[txq->stat];
- rn = (struct rt2661_node *)data->ni;
+ m = data->m;
+ data->m = NULL;
+ ni = data->ni;
+ data->ni = NULL;
/* if no frame has been sent, ignore */
- if (rn == NULL)
+ if (ni == NULL)
continue;
+ rn = (struct rt2661_node *)ni;
+
switch (RT2661_TX_RESULT(val)) {
case RT2661_TX_SUCCESS:
retrycnt = RT2661_TX_RETRYCNT(val);
@@ -967,7 +935,7 @@ rt2661_tx_intr(struct rt2661_softc *sc)
DPRINTFN(9, ("sending data frame failed (too much "
"retries)\n"));
if (data->id.id_node != NULL) {
- ral_rssadapt_lower_rate(ic, data->ni,
+ ral_rssadapt_lower_rate(ic, ni,
&rn->rssadapt, &data->id);
}
ifp->if_oerrors++;
@@ -980,14 +948,17 @@ rt2661_tx_intr(struct rt2661_softc *sc)
ifp->if_oerrors++;
}
- ieee80211_free_node(data->ni);
- data->ni = NULL;
-
DPRINTFN(15, ("tx done q=%d idx=%u\n", qid, txq->stat));
txq->queued--;
if (++txq->stat >= txq->count) /* faster than % count */
txq->stat = 0;
+
+ if (m->m_flags & M_TXCB)
+ ieee80211_process_callback(ni, m,
+ RT2661_TX_RESULT(val) != RT2661_TX_SUCCESS);
+ m_freem(m);
+ ieee80211_free_node(ni);
}
sc->sc_tx_timer = 0;
@@ -1014,9 +985,6 @@ rt2661_tx_dma_intr(struct rt2661_softc *sc, struct rt2661_tx_ring *txq)
bus_dmamap_sync(txq->data_dmat, data->map,
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(txq->data_dmat, data->map);
- m_freem(data->m);
- data->m = NULL;
- /* node reference is released in rt2661_tx_intr() */
/* descriptor is no longer valid */
desc->flags &= ~htole32(RT2661_TX_VALID);
@@ -1048,6 +1016,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
BUS_DMASYNC_POSTREAD);
for (;;) {
+ int rssi;
+
desc = &sc->rxq.desc[sc->rxq.cur];
data = &sc->rxq.data[sc->rxq.cur];
@@ -1120,6 +1090,8 @@ rt2661_rx_intr(struct rt2661_softc *sc)
m->m_pkthdr.len = m->m_len =
(le32toh(desc->flags) >> 16) & 0xfff;
+ rssi = rt2661_get_rssi(sc, desc->rssi);
+
if (bpf_peers_present(sc->sc_drvbpf)) {
struct rt2661_rx_radiotap_header *tap = &sc->sc_rxtap;
uint32_t tsf_lo, tsf_hi;
@@ -1134,22 +1106,28 @@ rt2661_rx_intr(struct rt2661_softc *sc)
tap->wr_rate = rt2661_rxrate(desc);
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
- tap->wr_antsignal = desc->rssi;
+ tap->wr_antsignal = rssi < 0 ? 0 : rssi;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
-
+ sc->sc_flags |= RAL_INPUT_RUNNING;
+ RAL_UNLOCK(sc);
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic,
(struct ieee80211_frame_min *)wh);
+ /* Error happened during RSSI conversion. */
+ if (rssi < 0)
+ rssi = ni->ni_rssi;
+
/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, desc->rssi, 0);
+ ieee80211_input(ic, m, ni, rssi, RT2661_NOISE_FLOOR, 0);
/* give rssi to the rate adatation algorithm */
rn = (struct rt2661_node *)ni;
- ral_rssadapt_input(ic, ni, &rn->rssadapt,
- rt2661_get_rssi(sc, desc->rssi));
+ RAL_LOCK(sc);
+ sc->sc_flags &= ~RAL_INPUT_RUNNING;
+ ral_rssadapt_input(ic, ni, &rn->rssadapt, rssi);
/* node is no longer needed */
ieee80211_free_node(ni);
@@ -1556,7 +1534,6 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
struct rt2661_tx_desc *desc;
struct rt2661_tx_data *data;
struct rt2661_node *rn;
- struct ieee80211_rateset *rs;
struct ieee80211_frame *wh;
struct ieee80211_key *k;
const struct chanAccParams *cap;
@@ -1569,9 +1546,10 @@ rt2661_tx_data(struct rt2661_softc *sc, struct mbuf *m0,
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
- rs = &ic->ic_sup_rates[ic->ic_curmode];
- rate = rs->rs_rates[ic->ic_fixed_rate];
+ rate = ic->ic_fixed_rate;
} else {
+ struct ieee80211_rateset *rs;
+
rs = &ni->ni_rates;
rn = (struct rt2661_node *)ni;
ni->ni_txrate = ral_rssadapt_choose(&rn->rssadapt, rs,
@@ -1753,7 +1731,7 @@ rt2661_start(struct ifnet *ifp)
RAL_LOCK(sc);
/* prevent management frames from being sent if we're not ready */
- if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || sc->sc_invalid) {
RAL_UNLOCK(sc);
return;
}
@@ -1773,9 +1751,10 @@ rt2661_start(struct ifnet *ifp)
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
- if (rt2661_tx_mgt(sc, m0, ni) != 0)
+ if (rt2661_tx_mgt(sc, m0, ni) != 0) {
+ ieee80211_free_node(ni);
break;
-
+ }
} else {
if (ic->ic_state != IEEE80211_S_RUN)
break;
@@ -1812,6 +1791,7 @@ rt2661_start(struct ifnet *ifp)
/* there is no place left in this ring */
IFQ_DRV_PREPEND(&ifp->if_snd, m0);
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ ieee80211_free_node(ni);
break;
}
@@ -1845,9 +1825,8 @@ static void
rt2661_watchdog(void *arg)
{
struct rt2661_softc *sc = (struct rt2661_softc *)arg;
- struct ieee80211com *ic = &sc->sc_ic;
- if (sc->sc_tx_timer > 0) {
+ if (sc->sc_tx_timer > 0 && !sc->sc_invalid) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
rt2661_init(sc);
@@ -1856,8 +1835,6 @@ rt2661_watchdog(void *arg)
}
callout_reset(&sc->watchdog_ch, hz, rt2661_watchdog, sc);
}
-
- ieee80211_watchdog(ic);
}
/*
@@ -1886,8 +1863,6 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct ieee80211com *ic = &sc->sc_ic;
int error = 0;
- RAL_LOCK(sc);
-
switch (cmd) {
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
@@ -1913,8 +1888,6 @@ rt2661_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
}
- RAL_UNLOCK(sc);
-
return error;
}
@@ -2066,6 +2039,12 @@ rt2661_set_txpreamble(struct rt2661_softc *sc)
RAL_WRITE(sc, RT2661_TXRX_CSR4, tmp);
}
+/*
+ * Supported rates for 802.11g. XXX should use ic_sup_rates.
+ */
+static const struct ieee80211_rateset rt2661_rateset_11g =
+ { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
+
static void
rt2661_set_basicrates(struct rt2661_softc *sc,
const struct ieee80211_rateset *rs)
@@ -2373,10 +2352,18 @@ rt2661_read_eeprom(struct rt2661_softc *sc)
if ((val & 0xff) != 0xff)
sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */
+ /* Only [-10, 10] is valid */
+ if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10)
+ sc->rssi_2ghz_corr = 0;
+
val = rt2661_eeprom_read(sc, RT2661_EEPROM_RSSI_5GHZ_OFFSET);
if ((val & 0xff) != 0xff)
sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */
+ /* Only [-10, 10] is valid */
+ if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10)
+ sc->rssi_5ghz_corr = 0;
+
/* adjust RSSI correction for external low-noise amplifier */
if (sc->ext_2ghz_lna)
sc->rssi_2ghz_corr -= 14;
@@ -2465,7 +2452,7 @@ rt2661_init(void *priv)
RAL_LOCK(sc);
- rt2661_stop(sc);
+ rt2661_stop_locked(sc);
/* initialize Tx rings */
RAL_WRITE(sc, RT2661_AC1_BASE_CSR, sc->txq[1].physaddr);
@@ -2525,13 +2512,13 @@ rt2661_init(void *priv)
}
if (ntries == 1000) {
printf("timeout waiting for BBP/RF to wakeup\n");
- rt2661_stop(sc);
+ rt2661_stop_locked(sc);
RAL_UNLOCK(sc);
return;
}
if (rt2661_bbp_init(sc) != 0) {
- rt2661_stop(sc);
+ rt2661_stop_locked(sc);
RAL_UNLOCK(sc);
return;
}
@@ -2572,6 +2559,7 @@ rt2661_init(void *priv)
/* kick Rx */
RAL_WRITE(sc, RT2661_RX_CNTL_CSR, 1);
+ RAL_UNLOCK(sc);
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
@@ -2582,7 +2570,7 @@ rt2661_init(void *priv)
} else
ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
- RAL_UNLOCK(sc);
+
#undef N
}
@@ -2590,41 +2578,57 @@ void
rt2661_stop(void *priv)
{
struct rt2661_softc *sc = priv;
+
+ RAL_LOCK(sc);
+ rt2661_stop_locked(sc);
+ RAL_UNLOCK(sc);
+}
+
+void
+rt2661_stop_locked(struct rt2661_softc *sc)
+{
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = ic->ic_ifp;
uint32_t tmp;
-
- sc->sc_tx_timer = 0;
- ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
-
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
-
- /* abort Tx (for all 5 Tx rings) */
- RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 0x1f << 16);
-
- /* disable Rx (value remains after reset!) */
- tmp = RAL_READ(sc, RT2661_TXRX_CSR0);
- RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp | RT2661_DISABLE_RX);
-
- /* reset ASIC */
- RAL_WRITE(sc, RT2661_MAC_CSR1, 3);
- RAL_WRITE(sc, RT2661_MAC_CSR1, 0);
-
- /* disable interrupts */
- RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0xffffffff);
- RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff);
-
- /* clear any pending interrupt */
- RAL_WRITE(sc, RT2661_INT_SOURCE_CSR, 0xffffffff);
- RAL_WRITE(sc, RT2661_MCU_INT_SOURCE_CSR, 0xffffffff);
-
- /* reset Tx and Rx rings */
- rt2661_reset_tx_ring(sc, &sc->txq[0]);
- rt2661_reset_tx_ring(sc, &sc->txq[1]);
- rt2661_reset_tx_ring(sc, &sc->txq[2]);
- rt2661_reset_tx_ring(sc, &sc->txq[3]);
- rt2661_reset_tx_ring(sc, &sc->mgtq);
- rt2661_reset_rx_ring(sc, &sc->rxq);
+ volatile int *flags = &sc->sc_flags;
+
+ while (*flags & RAL_INPUT_RUNNING) {
+ msleep(sc, &sc->sc_mtx, 0, "ralrunning", hz/10);
+ }
+
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ sc->sc_tx_timer = 0;
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+ /* abort Tx (for all 5 Tx rings) */
+ RAL_WRITE(sc, RT2661_TX_CNTL_CSR, 0x1f << 16);
+
+ /* disable Rx (value remains after reset!) */
+ tmp = RAL_READ(sc, RT2661_TXRX_CSR0);
+ RAL_WRITE(sc, RT2661_TXRX_CSR0, tmp | RT2661_DISABLE_RX);
+
+ /* reset ASIC */
+ RAL_WRITE(sc, RT2661_MAC_CSR1, 3);
+ RAL_WRITE(sc, RT2661_MAC_CSR1, 0);
+
+ /* disable interrupts */
+ RAL_WRITE(sc, RT2661_INT_MASK_CSR, 0xffffffff);
+ RAL_WRITE(sc, RT2661_MCU_INT_MASK_CSR, 0xffffffff);
+
+ /* clear any pending interrupt */
+ RAL_WRITE(sc, RT2661_INT_SOURCE_CSR, 0xffffffff);
+ RAL_WRITE(sc, RT2661_MCU_INT_SOURCE_CSR, 0xffffffff);
+
+ /* reset Tx and Rx rings */
+ rt2661_reset_tx_ring(sc, &sc->txq[0]);
+ rt2661_reset_tx_ring(sc, &sc->txq[1]);
+ rt2661_reset_tx_ring(sc, &sc->txq[2]);
+ rt2661_reset_tx_ring(sc, &sc->txq[3]);
+ rt2661_reset_tx_ring(sc, &sc->mgtq);
+ rt2661_reset_rx_ring(sc, &sc->rxq);
+ }
}
static int
@@ -2858,7 +2862,17 @@ rt2661_get_rssi(struct rt2661_softc *sc, uint8_t raw)
lna = (raw >> 5) & 0x3;
agc = raw & 0x1f;
- rssi = 2 * agc;
+ if (lna == 0) {
+ /*
+ * No mapping available.
+ *
+ * NB: Since RSSI is relative to noise floor, -1 is
+ * adequate for caller to know error happened.
+ */
+ return -1;
+ }
+
+ rssi = (2 * agc) - RT2661_NOISE_FLOOR;
if (IEEE80211_IS_CHAN_2GHZ(sc->sc_curchan)) {
rssi += sc->rssi_2ghz_corr;
@@ -2881,3 +2895,39 @@ rt2661_get_rssi(struct rt2661_softc *sc, uint8_t raw)
}
return rssi;
}
+
+static void
+rt2661_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2661_softc *sc = ifp->if_softc;
+ uint32_t tmp;
+
+ /* abort TSF synchronization */
+ tmp = RAL_READ(sc, RT2661_TXRX_CSR9);
+ RAL_WRITE(sc, RT2661_TXRX_CSR9, tmp & ~0xffffff);
+ rt2661_set_bssid(sc, ifp->if_broadcastaddr);
+}
+
+static void
+rt2661_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2661_softc *sc = ifp->if_softc;
+
+ rt2661_enable_tsf_sync(sc);
+ /* XXX keep local copy */
+ rt2661_set_bssid(sc, ic->ic_bss->ni_bssid);
+}
+
+static void
+rt2661_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct rt2661_softc *sc = ifp->if_softc;
+
+ RAL_LOCK(sc);
+ rt2661_set_chan(sc, ic->ic_curchan);
+ RAL_UNLOCK(sc);
+
+}
diff --git a/sys/dev/ral/rt2661reg.h b/sys/dev/ral/rt2661reg.h
index d79f926..b4325b0 100644
--- a/sys/dev/ral/rt2661reg.h
+++ b/sys/dev/ral/rt2661reg.h
@@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define RT2661_NOISE_FLOOR -95
+
#define RT2661_TX_RING_COUNT 32
#define RT2661_MGT_RING_COUNT 32
#define RT2661_RX_RING_COUNT 64
diff --git a/sys/dev/ral/rt2661var.h b/sys/dev/ral/rt2661var.h
index fab2892..9f12a15 100644
--- a/sys/dev/ral/rt2661var.h
+++ b/sys/dev/ral/rt2661var.h
@@ -102,11 +102,15 @@ struct rt2661_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
- struct callout scan_ch;
struct callout rssadapt_ch;
int sc_tx_timer;
-
+ int sc_invalid;
+/*
+ * The same in both up to here
+ * ------------------------------------------------
+ */
+
struct ieee80211_channel *sc_curchan;
uint8_t rf_rev;
@@ -159,6 +163,8 @@ struct rt2661_softc {
} sc_txtapu;
#define sc_txtap sc_txtapu.th
int sc_txtap_len;
+#define RAL_INPUT_RUNNING 1
+ int sc_flags;
};
int rt2661_attach(device_t, int);
diff --git a/sys/dev/usb/if_rum.c b/sys/dev/usb/if_rum.c
index 2f22117..16ed1ad 100644
--- a/sys/dev/usb/if_rum.c
+++ b/sys/dev/usb/if_rum.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -128,8 +129,8 @@ static void rum_free_tx_list(struct rum_softc *);
static int rum_alloc_rx_list(struct rum_softc *);
static void rum_free_rx_list(struct rum_softc *);
static int rum_media_change(struct ifnet *);
-static void rum_next_scan(void *);
static void rum_task(void *);
+static void rum_scantask(void *);
static int rum_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static void rum_txeof(usbd_xfer_handle, usbd_private_handle,
@@ -187,11 +188,15 @@ static int rum_load_microcode(struct rum_softc *, const u_char *,
static int rum_prepare_beacon(struct rum_softc *);
static int rum_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
+static void rum_scan_start(struct ieee80211com *);
+static void rum_scan_end(struct ieee80211com *);
+static void rum_set_channel(struct ieee80211com *);
+static int rum_get_rssi(struct rum_softc *, uint8_t);
static void rum_amrr_start(struct rum_softc *,
struct ieee80211_node *);
static void rum_amrr_timeout(void *);
static void rum_amrr_update(usbd_xfer_handle, usbd_private_handle,
- usbd_status status);
+ usbd_status);
static const struct {
uint32_t reg;
@@ -374,7 +379,7 @@ USB_ATTACH(rum)
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
- int i, ntries, size;
+ int i, ntries, size, bands;
uint32_t tmp;
sc->sc_udev = uaa->device;
@@ -426,9 +431,8 @@ USB_ATTACH(rum)
MTX_DEF | MTX_RECURSE);
usb_init_task(&sc->sc_task, rum_task, sc);
- callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
- callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
-
+ usb_init_task(&sc->sc_scantask, rum_scantask, sc);
+ callout_init(&sc->watchdog_ch, 0);
callout_init(&sc->amrr_ch, 0);
/* retrieve RT2573 rev. no */
@@ -490,42 +494,49 @@ USB_ATTACH(rum)
IEEE80211_C_TXPMGT | /* tx power management */
IEEE80211_C_SHPREAMBLE | /* short preamble supported */
IEEE80211_C_SHSLOT | /* short slot time supported */
+ IEEE80211_C_BGSCAN | /* bg scanning supported */
IEEE80211_C_WPA; /* 802.11i */
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
+
if (sc->rf_rev == RT2573_RF_5225 || sc->rf_rev == RT2573_RF_5226) {
+ struct ieee80211_channel *c;
+
/* set supported .11a channels */
for (i = 34; i <= 46; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+ c->ic_flags = IEEE80211_CHAN_A;
+ c->ic_ieee = i;
}
for (i = 36; i <= 64; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+ c->ic_flags = IEEE80211_CHAN_A;
+ c->ic_ieee = i;
}
for (i = 100; i <= 140; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+ c->ic_flags = IEEE80211_CHAN_A;
+ c->ic_ieee = i;
}
for (i = 149; i <= 165; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
+ c->ic_flags = IEEE80211_CHAN_A;
+ c->ic_ieee = i;
}
}
- /* set supported .11b and .11g channels (1 through 14) */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
-
ieee80211_ifattach(ic);
+ ic->ic_scan_start = rum_scan_start;
+ ic->ic_scan_end = rum_scan_end;
+ ic->ic_set_channel = rum_set_channel;
+
/* enable s/w bmiss handling in sta mode */
ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
@@ -535,7 +546,9 @@ USB_ATTACH(rum)
ic->ic_raw_xmit = rum_raw_xmit;
ieee80211_media_init(ic, rum_media_change, ieee80211_media_status);
- ieee80211_amrr_init(&sc->amrr, ic, 1, 10);
+ ieee80211_amrr_init(&sc->amrr, ic,
+ IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
+ IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD);
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
@@ -563,8 +576,8 @@ USB_DETACH(rum)
rum_stop(sc);
usb_rem_task(sc->sc_udev, &sc->sc_task);
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
callout_stop(&sc->watchdog_ch);
- callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
if (sc->amrr_xfer != NULL) {
@@ -737,20 +750,6 @@ rum_media_change(struct ifnet *ifp)
return 0;
}
-/*
- * This function is called periodically (every 200ms) during scanning to
- * switch from one channel to another.
- */
-static void
-rum_next_scan(void *arg)
-{
- struct rum_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_next_scan(ic);
-}
-
static void
rum_task(void *arg)
{
@@ -773,22 +772,7 @@ rum_task(void *arg)
}
break;
- case IEEE80211_S_SCAN:
- rum_set_chan(sc, ic->ic_curchan);
- callout_reset(&sc->scan_ch, hz / 5, rum_next_scan, sc);
- break;
-
- case IEEE80211_S_AUTH:
- rum_set_chan(sc, ic->ic_curchan);
- break;
-
- case IEEE80211_S_ASSOC:
- rum_set_chan(sc, ic->ic_curchan);
- break;
-
case IEEE80211_S_RUN:
- rum_set_chan(sc, ic->ic_curchan);
-
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@@ -811,6 +795,8 @@ rum_task(void *arg)
ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rum_amrr_start(sc, ni);
break;
+ default:
+ break;
}
RUM_UNLOCK(sc);
@@ -823,7 +809,6 @@ rum_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct rum_softc *sc = ic->ic_ifp->if_softc;
- callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
/* do it in a process context */
@@ -851,6 +836,10 @@ rum_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct rum_softc *sc = data->sc;
struct ifnet *ifp = sc->sc_ic.ic_ifp;
+ if (data->m->m_flags & M_TXCB)
+ ieee80211_process_callback(data->ni, data->m,
+ status == USBD_NORMAL_COMPLETION ? 0 : ETIMEDOUT);
+
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
@@ -891,7 +880,7 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct mbuf *mnew, *m;
- int len;
+ int len, rssi;
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
@@ -938,6 +927,15 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
m->m_data = (caddr_t)(desc + 1);
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
+ rssi = rum_get_rssi(sc, desc->rssi);
+
+ wh = mtod(m, struct ieee80211_frame *);
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
+
+ /* Error happened during RSSI conversion. */
+ if (rssi < 0)
+ rssi = ni->ni_rssi;
+
if (bpf_peers_present(sc->sc_drvbpf)) {
struct rum_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -946,16 +944,13 @@ rum_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
- tap->wr_antsignal = desc->rssi;
+ tap->wr_antsignal = rssi;
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
- wh = mtod(m, struct ieee80211_frame *);
- ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
-
/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, desc->rssi, 0);
+ ieee80211_input(ic, m, ni, rssi, RT2573_NOISE_FLOOR, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@@ -1293,7 +1288,7 @@ rum_tx_data(struct rum_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
- rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
+ rate = ic->ic_fixed_rate;
else
rate = ni->ni_rates.rs_rates[ni->ni_txrate];
@@ -1378,8 +1373,6 @@ rum_start(struct ifnet *ifp)
struct mbuf *m0;
struct ether_header *eh;
- RUM_LOCK(sc);
-
for (;;) {
IF_POLL(&ic->ic_mgtq, m0);
if (m0 != NULL) {
@@ -1442,27 +1435,27 @@ rum_start(struct ifnet *ifp)
sc->sc_tx_timer = 5;
callout_reset(&sc->watchdog_ch, hz, rum_watchdog, sc);
}
-
- RUM_UNLOCK(sc);
}
static void
rum_watchdog(void *arg)
{
- struct rum_softc *sc = (struct rum_softc *)arg;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct rum_softc *sc = arg;
+
+ RUM_LOCK(sc);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
/*rum_init(ifp); XXX needs a process context! */
sc->sc_ifp->if_oerrors++;
+ RUM_UNLOCK(sc);
return;
}
callout_reset(&sc->watchdog_ch, hz, rum_watchdog, sc);
}
- ieee80211_watchdog(ic);
+ RUM_UNLOCK(sc);
}
static int
@@ -1984,11 +1977,24 @@ rum_read_eeprom(struct rum_softc *sc)
if ((val & 0xff) != 0xff)
sc->rssi_2ghz_corr = (int8_t)(val & 0xff); /* signed */
+ /* Only [-10, 10] is valid */
+ if (sc->rssi_2ghz_corr < -10 || sc->rssi_2ghz_corr > 10)
+ sc->rssi_2ghz_corr = 0;
+
rum_eeprom_read(sc, RT2573_EEPROM_RSSI_5GHZ_OFFSET, &val, 2);
val = le16toh(val);
if ((val & 0xff) != 0xff)
sc->rssi_5ghz_corr = (int8_t)(val & 0xff); /* signed */
+ /* Only [-10, 10] is valid */
+ if (sc->rssi_5ghz_corr < -10 || sc->rssi_5ghz_corr > 10)
+ sc->rssi_5ghz_corr = 0;
+
+ if (sc->ext_2ghz_lna)
+ sc->rssi_2ghz_corr -= 14;
+ if (sc->ext_5ghz_lna)
+ sc->rssi_5ghz_corr -= 14;
+
DPRINTF(("RSSI 2GHz corr=%d\nRSSI 5GHz corr=%d\n",
sc->rssi_2ghz_corr, sc->rssi_5ghz_corr));
@@ -2407,4 +2413,124 @@ rum_amrr_update(usbd_xfer_handle xfer, usbd_private_handle priv,
callout_reset(&sc->amrr_ch, hz, rum_amrr_timeout, sc);
}
+static void
+rum_scan_start(struct ieee80211com *ic)
+{
+ struct rum_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = RUM_SCAN_START;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+}
+
+static void
+rum_scan_end(struct ieee80211com *ic)
+{
+ struct rum_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = RUM_SCAN_END;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+}
+
+static void
+rum_set_channel(struct ieee80211com *ic)
+{
+ struct rum_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = RUM_SET_CHANNEL;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+}
+
+static void
+rum_scantask(void *arg)
+{
+ struct rum_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ uint32_t tmp;
+
+ RUM_LOCK(sc);
+
+ switch (sc->sc_scan_action) {
+ case RUM_SCAN_START:
+ /* abort TSF synchronization */
+ tmp = rum_read(sc, RT2573_TXRX_CSR9);
+ rum_write(sc, RT2573_TXRX_CSR9, tmp & ~0x00ffffff);
+ rum_set_bssid(sc, ifp->if_broadcastaddr);
+ break;
+
+ case RUM_SCAN_END:
+ rum_enable_tsf_sync(sc);
+ /* XXX keep local copy */
+ rum_set_bssid(sc, ic->ic_bss->ni_bssid);
+ break;
+
+ case RUM_SET_CHANNEL:
+ mtx_lock(&Giant);
+ rum_set_chan(sc, ic->ic_curchan);
+ mtx_unlock(&Giant);
+ break;
+
+ default:
+ panic("unknown scan action %d\n", sc->sc_scan_action);
+ /* NEVER REACHED */
+ break;
+ }
+
+ RUM_UNLOCK(sc);
+}
+
+static int
+rum_get_rssi(struct rum_softc *sc, uint8_t raw)
+{
+ int lna, agc, rssi;
+
+ lna = (raw >> 5) & 0x3;
+ agc = raw & 0x1f;
+
+ if (lna == 0) {
+ /*
+ * No RSSI mapping
+ *
+ * NB: Since RSSI is relative to noise floor, -1 is
+ * adequate for caller to know error happened.
+ */
+ return -1;
+ }
+
+ rssi = (2 * agc) - RT2573_NOISE_FLOOR;
+
+ if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_curchan)) {
+ rssi += sc->rssi_2ghz_corr;
+
+ if (lna == 1)
+ rssi -= 64;
+ else if (lna == 2)
+ rssi -= 74;
+ else if (lna == 3)
+ rssi -= 90;
+ } else {
+ rssi += sc->rssi_5ghz_corr;
+
+ if (!sc->ext_5ghz_lna && lna != 1)
+ rssi += 4;
+
+ if (lna == 1)
+ rssi -= 64;
+ else if (lna == 2)
+ rssi -= 86;
+ else if (lna == 3)
+ rssi -= 100;
+ }
+ return rssi;
+}
+
DRIVER_MODULE(rum, uhub, rum_driver, rum_devclass, usbd_driver_load, 0);
diff --git a/sys/dev/usb/if_rumreg.h b/sys/dev/usb/if_rumreg.h
index 7827775..75a51bc 100644
--- a/sys/dev/usb/if_rumreg.h
+++ b/sys/dev/usb/if_rumreg.h
@@ -17,6 +17,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define RT2573_NOISE_FLOOR -95
+
#define RT2573_TX_DESC_SIZE (sizeof (struct rum_tx_desc))
#define RT2573_RX_DESC_SIZE (sizeof (struct rum_rx_desc))
diff --git a/sys/dev/usb/if_rumvar.h b/sys/dev/usb/if_rumvar.h
index 1577c6c..e7d6d15 100644
--- a/sys/dev/usb/if_rumvar.h
+++ b/sys/dev/usb/if_rumvar.h
@@ -97,6 +97,12 @@ struct rum_softc {
struct ieee80211_amrr amrr;
struct ieee80211_amrr_node amn;
+ struct usb_task sc_scantask;
+ int sc_scan_action;
+#define RUM_SCAN_START 0
+#define RUM_SCAN_END 1
+#define RUM_SET_CHANNEL 2
+
struct rum_rx_data rx_data[RUM_RX_LIST_COUNT];
struct rum_tx_data tx_data[RUM_TX_LIST_COUNT];
int tx_queued;
@@ -106,7 +112,6 @@ struct rum_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
- struct callout scan_ch;
struct callout amrr_ch;
int sc_tx_timer;
diff --git a/sys/dev/usb/if_ural.c b/sys/dev/usb/if_ural.c
index 46e2f58..4ca311b 100644
--- a/sys/dev/usb/if_ural.c
+++ b/sys/dev/usb/if_ural.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_amrr.h>
#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -73,6 +74,10 @@ SYSCTL_INT(_hw_usb_ural, OID_AUTO, debug, CTLFLAG_RW, &uraldebug, 0,
#define DPRINTFN(n, x)
#endif
+#define URAL_RSSI(rssi) \
+ ((rssi) > (RAL_NOISE_FLOOR + RAL_RSSI_CORR) ? \
+ ((rssi) - RAL_NOISE_FLOOR + RAL_RSSI_CORR) : 0)
+
/* various supported device vendors/products */
static const struct usb_devno ural_devs[] = {
{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_WL167G },
@@ -113,8 +118,8 @@ static void ural_free_tx_list(struct ural_softc *);
static int ural_alloc_rx_list(struct ural_softc *);
static void ural_free_rx_list(struct ural_softc *);
static int ural_media_change(struct ifnet *);
-static void ural_next_scan(void *);
static void ural_task(void *);
+static void ural_scantask(void *);
static int ural_newstate(struct ieee80211com *,
enum ieee80211_state, int);
static int ural_rxrate(struct ural_rx_desc *);
@@ -149,6 +154,9 @@ static void ural_write_multi(struct ural_softc *, uint16_t, void *,
static void ural_bbp_write(struct ural_softc *, uint8_t, uint8_t);
static uint8_t ural_bbp_read(struct ural_softc *, uint8_t);
static void ural_rf_write(struct ural_softc *, uint8_t, uint32_t);
+static void ural_scan_start(struct ieee80211com *);
+static void ural_scan_end(struct ieee80211com *);
+static void ural_set_channel(struct ieee80211com *);
static void ural_set_chan(struct ural_softc *,
struct ieee80211_channel *);
static void ural_disable_rf_tune(struct ural_softc *);
@@ -156,7 +164,7 @@ static void ural_enable_tsf_sync(struct ural_softc *);
static void ural_update_slot(struct ifnet *);
static void ural_set_txpreamble(struct ural_softc *);
static void ural_set_basicrates(struct ural_softc *);
-static void ural_set_bssid(struct ural_softc *, uint8_t *);
+static void ural_set_bssid(struct ural_softc *, const uint8_t *);
static void ural_set_macaddr(struct ural_softc *, uint8_t *);
static void ural_update_promisc(struct ural_softc *);
static const char *ural_get_rf(int);
@@ -357,7 +365,7 @@ USB_ATTACH(ural)
usb_interface_descriptor_t *id;
usb_endpoint_descriptor_t *ed;
usbd_status error;
- int i;
+ int i, bands;
sc->sc_udev = uaa->device;
sc->sc_dev = self;
@@ -399,7 +407,8 @@ USB_ATTACH(ural)
sc->sc_tx_no = ed->bEndpointAddress;
}
if (sc->sc_rx_no == -1 || sc->sc_tx_no == -1) {
- printf("%s: missing endpoint\n", device_get_nameunit(sc->sc_dev));
+ printf("%s: missing endpoint\n",
+ device_get_nameunit(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
@@ -407,8 +416,8 @@ USB_ATTACH(ural)
MTX_DEF | MTX_RECURSE);
usb_init_task(&sc->sc_task, ural_task, sc);
- callout_init_mtx(&sc->watchdog_ch, &sc->sc_mtx, 0);
- callout_init(&sc->scan_ch, debug_mpsafenet ? CALLOUT_MPSAFE : 0);
+ usb_init_task(&sc->sc_scantask, ural_scantask, sc);
+ callout_init(&sc->watchdog_ch, 0);
callout_init(&sc->amrr_ch, 0);
/* retrieve RT2570 rev. no */
@@ -418,11 +427,13 @@ USB_ATTACH(ural)
ural_read_eeprom(sc);
printf("%s: MAC/BBP RT2570 (rev 0x%02x), RF %s\n",
- device_get_nameunit(sc->sc_dev), sc->asic_rev, ural_get_rf(sc->rf_rev));
+ device_get_nameunit(sc->sc_dev), sc->asic_rev,
+ ural_get_rf(sc->rf_rev));
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
- printf("%s: can not if_alloc()\n", device_get_nameunit(sc->sc_dev));
+ printf("%s: can not if_alloc()\n",
+ device_get_nameunit(sc->sc_dev));
USB_ATTACH_ERROR_RETURN;
}
@@ -444,46 +455,30 @@ USB_ATTACH(ural)
/* set device capabilities */
ic->ic_caps =
- IEEE80211_C_IBSS | /* IBSS mode supported */
- IEEE80211_C_MONITOR | /* monitor mode supported */
- IEEE80211_C_HOSTAP | /* HostAp mode supported */
- IEEE80211_C_TXPMGT | /* tx power management */
- IEEE80211_C_SHPREAMBLE | /* short preamble supported */
- IEEE80211_C_SHSLOT | /* short slot time supported */
- IEEE80211_C_WPA; /* 802.11i */
-
- if (sc->rf_rev == RAL_RF_5222) {
- /* set supported .11a channels */
- for (i = 36; i <= 64; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 100; i <= 140; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- for (i = 149; i <= 161; i += 4) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_5GHZ);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_A;
- }
- }
-
- /* set supported .11b and .11g channels (1 through 14) */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
+ IEEE80211_C_IBSS /* IBSS mode supported */
+ | IEEE80211_C_MONITOR /* monitor mode supported */
+ | IEEE80211_C_HOSTAP /* HostAp mode supported */
+ | IEEE80211_C_TXPMGT /* tx power management */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_SHSLOT /* short slot time supported */
+ | IEEE80211_C_BGSCAN /* bg scanning supported */
+ | IEEE80211_C_WPA /* 802.11i */
+ ;
+
+ bands = 0;
+ setbit(&bands, IEEE80211_MODE_11B);
+ setbit(&bands, IEEE80211_MODE_11G);
+ if (sc->rf_rev == RAL_RF_5222)
+ setbit(&bands, IEEE80211_MODE_11A);
+ ieee80211_init_channels(ic, 0, CTRY_DEFAULT, bands, 0, 1);
ieee80211_ifattach(ic);
ic->ic_reset = ural_reset;
/* enable s/w bmiss handling in sta mode */
ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS;
+ ic->ic_scan_start = ural_scan_start;
+ ic->ic_scan_end = ural_scan_end;
+ ic->ic_set_channel = ural_set_channel;
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
@@ -491,7 +486,9 @@ USB_ATTACH(ural)
ic->ic_raw_xmit = ural_raw_xmit;
ieee80211_media_init(ic, ural_media_change, ieee80211_media_status);
- ieee80211_amrr_init(&sc->amrr, ic, 1, 15);
+ ieee80211_amrr_init(&sc->amrr, ic,
+ IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
+ IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD);
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
sizeof (struct ieee80211_frame) + 64, &sc->sc_drvbpf);
@@ -519,7 +516,6 @@ USB_DETACH(ural)
ural_stop(sc);
usb_rem_task(sc->sc_udev, &sc->sc_task);
callout_stop(&sc->watchdog_ch);
- callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
if (sc->amrr_xfer != NULL) {
@@ -694,24 +690,10 @@ ural_media_change(struct ifnet *ifp)
return 0;
}
-/*
- * This function is called periodically (every 200ms) during scanning to
- * switch from one channel to another.
- */
-static void
-ural_next_scan(void *arg)
-{
- struct ural_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
-
- if (ic->ic_state == IEEE80211_S_SCAN)
- ieee80211_next_scan(ic);
-}
-
static void
-ural_task(void *arg)
+ural_task(void *xarg)
{
- struct ural_softc *sc = arg;
+ struct ural_softc *sc = xarg;
struct ieee80211com *ic = &sc->sc_ic;
enum ieee80211_state ostate;
struct ieee80211_node *ni;
@@ -720,7 +702,6 @@ ural_task(void *arg)
ostate = ic->ic_state;
RAL_LOCK(sc);
-
switch (sc->sc_state) {
case IEEE80211_S_INIT:
if (ostate == IEEE80211_S_RUN) {
@@ -732,22 +713,7 @@ ural_task(void *arg)
}
break;
- case IEEE80211_S_SCAN:
- ural_set_chan(sc, ic->ic_curchan);
- callout_reset(&sc->scan_ch, hz / 5, ural_next_scan, sc);
- break;
-
- case IEEE80211_S_AUTH:
- ural_set_chan(sc, ic->ic_curchan);
- break;
-
- case IEEE80211_S_ASSOC:
- ural_set_chan(sc, ic->ic_curchan);
- break;
-
case IEEE80211_S_RUN:
- ural_set_chan(sc, ic->ic_curchan);
-
ni = ic->ic_bss;
if (ic->ic_opmode != IEEE80211_M_MONITOR) {
@@ -785,18 +751,44 @@ ural_task(void *arg)
ural_amrr_start(sc, ni);
break;
+
+ default:
+ break;
}
RAL_UNLOCK(sc);
sc->sc_newstate(ic, sc->sc_state, sc->sc_arg);
}
+static void
+ural_scantask(void *arg)
+{
+ struct ural_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+
+ RAL_LOCK(sc);
+ if (sc->sc_scan_action == URAL_SCAN_START) {
+ /* abort TSF synchronization */
+ ural_write(sc, RAL_TXRX_CSR19, 0);
+ ural_set_bssid(sc, ifp->if_broadcastaddr);
+ } else if (sc->sc_scan_action == URAL_SET_CHANNEL) {
+ mtx_lock(&Giant);
+ ural_set_chan(sc, ic->ic_curchan);
+ mtx_unlock(&Giant);
+ } else {
+ ural_enable_tsf_sync(sc);
+ /* XXX keep local copy */
+ ural_set_bssid(sc, ic->ic_bss->ni_bssid);
+ }
+ RAL_UNLOCK(sc);
+}
+
static int
ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
struct ural_softc *sc = ic->ic_ifp->if_softc;
- callout_stop(&sc->scan_ch);
callout_stop(&sc->amrr_ch);
/* do it in a process context */
@@ -859,6 +851,9 @@ ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
struct ural_softc *sc = data->sc;
struct ifnet *ifp = sc->sc_ic.ic_ifp;
+ if (data->m->m_flags & M_TXCB)
+ ieee80211_process_callback(data->ni, data->m,
+ status == USBD_NORMAL_COMPLETION ? 0 : ETIMEDOUT);
if (status != USBD_NORMAL_COMPLETION) {
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
@@ -870,6 +865,7 @@ ural_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
usbd_clear_endpoint_stall_async(sc->sc_rx_pipeh);
ifp->if_oerrors++;
+ /* XXX mbuf leak? */
return;
}
@@ -946,7 +942,6 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
/* finalize mbuf */
m->m_pkthdr.rcvif = ifp;
m->m_pkthdr.len = m->m_len = (le32toh(desc->flags) >> 16) & 0xfff;
- m->m_flags |= M_HASFCS; /* h/w leaves FCS */
if (bpf_peers_present(sc->sc_drvbpf)) {
struct ural_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -956,16 +951,19 @@ ural_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
tap->wr_chan_freq = htole16(ic->ic_curchan->ic_freq);
tap->wr_chan_flags = htole16(ic->ic_curchan->ic_flags);
tap->wr_antenna = sc->rx_ant;
- tap->wr_antsignal = desc->rssi;
+ tap->wr_antsignal = URAL_RSSI(desc->rssi);
bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
}
+ /* Strip trailing 802.11 MAC FCS. */
+ m_adj(m, -IEEE80211_CRC_LEN);
+
wh = mtod(m, struct ieee80211_frame *);
ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
/* send the frame to the 802.11 layer */
- ieee80211_input(ic, m, ni, desc->rssi, 0);
+ ieee80211_input(ic, m, ni, URAL_RSSI(desc->rssi), RAL_NOISE_FLOOR, 0);
/* node is no longer needed */
ieee80211_free_node(ni);
@@ -1303,8 +1301,12 @@ ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
ural_txeof);
error = usbd_transfer(data->xfer);
- if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
+ if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS) {
+ m_freem(m0);
+ data->m = NULL;
+ data->ni = NULL;
return error;
+ }
sc->tx_queued++;
@@ -1327,7 +1329,7 @@ ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
wh = mtod(m0, struct ieee80211_frame *);
if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE)
- rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_fixed_rate];
+ rate = ic->ic_fixed_rate;
else
rate = ni->ni_rates.rs_rates[ni->ni_txrate];
@@ -1481,19 +1483,21 @@ static void
ural_watchdog(void *arg)
{
struct ural_softc *sc = (struct ural_softc *)arg;
- struct ieee80211com *ic = &sc->sc_ic;
+
+ RAL_LOCK(sc);
if (sc->sc_tx_timer > 0) {
if (--sc->sc_tx_timer == 0) {
device_printf(sc->sc_dev, "device timeout\n");
/*ural_init(sc); XXX needs a process context! */
sc->sc_ifp->if_oerrors++;
+ RAL_UNLOCK(sc);
return;
}
callout_reset(&sc->watchdog_ch, hz, ural_watchdog, sc);
}
- ieee80211_watchdog(ic);
+ RAL_UNLOCK(sc);
}
/*
@@ -1738,6 +1742,45 @@ ural_rf_write(struct ural_softc *sc, uint8_t reg, uint32_t val)
}
static void
+ural_scan_start(struct ieee80211com *ic)
+{
+ struct ural_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = URAL_SCAN_START;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+
+}
+
+static void
+ural_scan_end(struct ieee80211com *ic)
+{
+ struct ural_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = URAL_SCAN_END;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+
+}
+
+static void
+ural_set_channel(struct ieee80211com *ic)
+{
+
+ struct ural_softc *sc = ic->ic_ifp->if_softc;
+
+ usb_rem_task(sc->sc_udev, &sc->sc_scantask);
+
+ /* do it in a process context */
+ sc->sc_scan_action = URAL_SET_CHANNEL;
+ usb_add_task(sc->sc_udev, &sc->sc_scantask, USB_TASKQ_DRIVER);
+}
+
+static void
ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -1820,7 +1863,7 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
}
if (ic->ic_opmode != IEEE80211_M_MONITOR &&
- ic->ic_state != IEEE80211_S_SCAN) {
+ (ic->ic_flags & IEEE80211_F_SCAN) == 0) {
/* set Japan filter bit for channel 14 */
tmp = ural_bbp_read(sc, 70);
@@ -1836,6 +1879,18 @@ ural_set_chan(struct ural_softc *sc, struct ieee80211_channel *c)
DELAY(10000);
ural_disable_rf_tune(sc);
}
+
+ /* update basic rate set */
+ if (IEEE80211_IS_CHAN_B(c)) {
+ /* 11b basic rates: 1, 2Mbps */
+ ural_write(sc, RAL_TXRX_CSR11, 0x3);
+ } else if (IEEE80211_IS_CHAN_A(c)) {
+ /* 11a basic rates: 6, 12, 24Mbps */
+ ural_write(sc, RAL_TXRX_CSR11, 0x150);
+ } else {
+ /* 11g basic rates: 1, 2, 5.5, 11, 6, 12, 24Mbps */
+ ural_write(sc, RAL_TXRX_CSR11, 0x15f);
+ }
}
/*
@@ -1948,7 +2003,7 @@ ural_set_basicrates(struct ural_softc *sc)
}
static void
-ural_set_bssid(struct ural_softc *sc, uint8_t *bssid)
+ural_set_bssid(struct ural_softc *sc, const uint8_t *bssid)
{
uint16_t tmp;
@@ -2166,7 +2221,6 @@ ural_init(void *priv)
if (ural_bbp_init(sc) != 0)
goto fail;
- /* set default BSS channel */
ural_set_chan(sc, ic->ic_curchan);
/* clear statistic registers (STA_CSR0 to STA_CSR10) */
diff --git a/sys/dev/usb/if_uralreg.h b/sys/dev/usb/if_uralreg.h
index 70e06f1..428089f 100644
--- a/sys/dev/usb/if_uralreg.h
+++ b/sys/dev/usb/if_uralreg.h
@@ -17,6 +17,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define RAL_NOISE_FLOOR -95
+#define RAL_RSSI_CORR 120
+
#define RAL_RX_DESC_SIZE (sizeof (struct ural_rx_desc))
#define RAL_TX_DESC_SIZE (sizeof (struct ural_tx_desc))
diff --git a/sys/dev/usb/if_uralvar.h b/sys/dev/usb/if_uralvar.h
index 18b5cdf..665b05b 100644
--- a/sys/dev/usb/if_uralvar.h
+++ b/sys/dev/usb/if_uralvar.h
@@ -20,6 +20,11 @@
#define RAL_RX_LIST_COUNT 1
#define RAL_TX_LIST_COUNT 1
+#define URAL_SCAN_START 1
+#define URAL_SCAN_END 2
+#define URAL_SET_CHANNEL 3
+
+
struct ural_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint8_t wr_flags;
@@ -91,7 +96,9 @@ struct ural_softc {
enum ieee80211_state sc_state;
int sc_arg;
+ int sc_scan_action; /* should be an enum */
struct usb_task sc_task;
+ struct usb_task sc_scantask;
struct ieee80211_amrr amrr;
struct ieee80211_amrr_node amn;
@@ -105,9 +112,7 @@ struct ural_softc {
struct mtx sc_mtx;
struct callout watchdog_ch;
- struct callout scan_ch;
struct callout amrr_ch;
-
int sc_tx_timer;
uint16_t sta[11];
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index ebe35d2..aeb8a4e 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -118,7 +118,7 @@ static int wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr,
struct mbuf *m0);
static int wi_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
-static int wi_reset(struct wi_softc *);
+static int wi_reset(struct ifnet *);
static void wi_watchdog(void *);
static int wi_ioctl(struct ifnet *, u_long, caddr_t);
static int wi_media_change(struct ifnet *);
@@ -164,6 +164,14 @@ static int wi_symbol_write_firm(struct wi_softc *, const void *, int,
const void *, int);
static int wi_symbol_set_hcr(struct wi_softc *, int);
+static void wi_scan_start(struct ieee80211com *);
+static void wi_scan_end(struct ieee80211com *);
+static void wi_set_channel(struct ieee80211com *);
+static void wi_update_slot(struct ifnet *);
+static struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *);
+static int wi_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data);
+static int wi_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data);
+
static __inline int
wi_write_val(struct wi_softc *sc, int rid, u_int16_t val)
{
@@ -253,6 +261,7 @@ wi_attach(device_t dev)
int error;
ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
+ ifp->if_softc = sc;
if (ifp == NULL) {
device_printf(dev, "can not if_alloc\n");
wi_free(dev);
@@ -279,7 +288,7 @@ wi_attach(device_t dev)
sc->sc_firmware_type = WI_NOTYPE;
sc->wi_cmd_count = 500;
/* Reset the NIC. */
- if (wi_reset(sc) != 0)
+ if (wi_reset(ifp) != 0)
return ENXIO; /* XXX */
/*
@@ -308,7 +317,6 @@ wi_attach(device_t dev)
/* Read NIC identification */
wi_read_nicid(sc);
- ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = wi_ioctl;
@@ -338,11 +346,14 @@ wi_attach(device_t dev)
val <<= 1; /* shift for base 1 indices */
for (i = 1; i < 16; i++) {
+ struct ieee80211_channel *c;
+
if (!isset((u_int8_t*)&val, i))
continue;
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
- ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B;
+ c = &ic->ic_channels[ic->ic_nchans++];
+ c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
+ c->ic_flags = IEEE80211_CHAN_B;
+ c->ic_ieee = i;
}
/*
@@ -356,14 +367,14 @@ wi_attach(device_t dev)
buflen = sizeof(val);
if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0) {
val = le16toh(val);
- KASSERT(val < IEEE80211_CHAN_MAX &&
- ic->ic_channels[val].ic_flags != 0,
- ("wi_attach: invalid own channel %u!", val));
- ic->ic_ibss_chan = &ic->ic_channels[val];
+ ic->ic_bsschan = ieee80211_find_channel(ic,
+ ieee80211_ieee2mhz(val, IEEE80211_CHAN_B),
+ IEEE80211_MODE_AUTO);
+ /* XXX check return value */
} else {
device_printf(dev,
"WI_RID_OWN_CHNL failed, using first channel!\n");
- ic->ic_ibss_chan = &ic->ic_channels[0];
+ ic->ic_bsschan = &ic->ic_channels[0];
}
/*
@@ -469,7 +480,7 @@ wi_attach(device_t dev)
sc->sc_system_scale = 1;
sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
sc->sc_roaming_mode = 1;
-
+ sc->wi_channel = IEEE80211_CHAN_ANYC;
sc->sc_portnum = WI_DEFAULT_PORT;
sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
@@ -491,6 +502,14 @@ wi_attach(device_t dev)
ic->ic_crypto.cs_key_alloc = wi_key_alloc;
ic->ic_newstate = wi_newstate;
ic->ic_raw_xmit = wi_raw_xmit;
+
+ ic->ic_scan_start = wi_scan_start;
+ ic->ic_scan_end = wi_scan_end;
+ ic->ic_set_channel = wi_set_channel;
+ ic->ic_node_alloc = wi_node_alloc;
+ ic->ic_updateslot = wi_update_slot;
+ ic->ic_reset = wi_reset;
+
ieee80211_media_init(ic, wi_media_change, wi_media_status);
#if NBPFILTER > 0
@@ -650,19 +669,20 @@ wi_init(void *arg)
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = &sc->sc_ic;
struct wi_joinreq join;
+ struct ieee80211_channel *chan;
int i;
int error = 0, wasenabled;
- WI_LOCK(sc);
- if (sc->wi_gone) {
- WI_UNLOCK(sc);
+
+ if (sc->wi_gone)
return;
- }
if ((wasenabled = sc->sc_enabled))
wi_stop(ifp, 1);
- wi_reset(sc);
+
+ WI_LOCK(sc);
+ wi_reset(ifp);
/* common 802.11 configuration */
ic->ic_flags &= ~IEEE80211_F_IBSSON;
@@ -684,9 +704,9 @@ wi_init(void *arg)
* HostAP mode the controller will lock up otherwise.
*/
if (sc->sc_firmware_type == WI_INTERSIL &&
- ic->ic_des_esslen == 0) {
- ic->ic_des_essid[0] = ' ';
- ic->ic_des_esslen = 1;
+ ic->ic_des_ssid[0].len == 0) {
+ ic->ic_des_ssid[0].ssid[0] = ' ';
+ ic->ic_des_ssid[0].len = 1;
}
wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
break;
@@ -703,20 +723,24 @@ wi_init(void *arg)
wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
break;
+ case IEEE80211_M_WDS:
+ /* XXXX */
+ break;
}
/* Intersil interprets this RID as joining ESS even in IBSS mode */
if (sc->sc_firmware_type == WI_LUCENT &&
- (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0)
+ (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_ssid[0].len > 0)
wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
else
wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
- wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid,
- ic->ic_des_esslen);
+ wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
wi_write_val(sc, WI_RID_OWN_CHNL,
- ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
- wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen);
+ ieee80211_chan2ieee(ic, ic->ic_bsschan));
+ wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_ssid[0].ssid,
+ ic->ic_des_ssid[0].len);
IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
@@ -803,9 +827,11 @@ wi_init(void *arg)
if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
ic->ic_opmode == IEEE80211_M_IBSS ||
ic->ic_opmode == IEEE80211_M_MONITOR ||
- ic->ic_opmode == IEEE80211_M_HOSTAP)
- ieee80211_create_ibss(ic, ic->ic_ibss_chan);
-
+ ic->ic_opmode == IEEE80211_M_HOSTAP) {
+ chan = (sc->wi_channel == IEEE80211_CHAN_ANYC) ?
+ ic->ic_curchan : sc->wi_channel;
+ ieee80211_create_ibss(ic, chan);
+ }
/* Enable interrupts */
CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
@@ -851,11 +877,10 @@ wi_stop(struct ifnet *ifp, int disable)
struct wi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
- WI_LOCK(sc);
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
DELAY(100000);
-
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+ WI_LOCK(sc);
if (sc->sc_enabled && !sc->wi_gone) {
CSR_WRITE_2(sc, WI_INT_EN, 0);
wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0);
@@ -973,8 +998,7 @@ wi_start_locked(struct ifnet *ifp)
k = ieee80211_crypto_encap(ic, ni, m0);
if (k == NULL) {
- if (ni != NULL)
- ieee80211_free_node(ni);
+ ieee80211_free_node(ni);
m_freem(m0);
continue;
}
@@ -994,8 +1018,7 @@ wi_start_locked(struct ifnet *ifp)
frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
if (IFF_DUMPPKTS(ifp))
wi_dump_pkt(&frmhdr, NULL, -1);
- if (ni != NULL)
- ieee80211_free_node(ni);
+ ieee80211_free_node(ni);
if (wi_start_tx(ifp, &frmhdr, m0))
continue;
sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
@@ -1131,9 +1154,9 @@ out:
}
static int
-wi_reset(struct wi_softc *sc)
+wi_reset(struct ifnet *ifp)
{
- struct ifnet *ifp = sc->sc_ifp;
+ struct wi_softc *sc = ifp->if_softc;
#define WI_INIT_TRIES 3
int i;
int error = 0;
@@ -1196,7 +1219,6 @@ wi_watchdog(void *arg)
}
/* TODO: rate control */
- ieee80211_watchdog(&sc->sc_ic);
callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc);
}
@@ -1207,8 +1229,6 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct wi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
struct ifreq *ifr = (struct ifreq *)data;
- struct ieee80211req *ireq;
- u_int8_t nodename[IEEE80211_NWID_LEN];
int error = 0;
struct thread *td = curthread;
struct wi_req wreq;
@@ -1289,47 +1309,102 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
WI_UNLOCK(sc);
break;
case SIOCG80211:
- ireq = (struct ieee80211req *) data;
- if (ireq->i_type == IEEE80211_IOC_STATIONNAME) {
- ireq->i_len = sc->sc_nodelen + 1;
- error = copyout(sc->sc_nodename, ireq->i_data,
- ireq->i_len);
+ error = wi_ioctl_get(ifp, cmd, data);
+ break;
+ case SIOCS80211:
+ error = priv_check(td, PRIV_NET80211_MANAGE);
+ if (error)
+ break;
+ error = wi_ioctl_set(ifp, cmd, data);
+
+
break;
+ default:
+ error = ieee80211_ioctl(ic, cmd, data);
+ WI_LOCK(sc);
+ if (error == ENETRESET) {
+ if (sc->sc_enabled)
+ wi_init(sc); /* XXX no error return */
+ error = 0;
}
- goto ioctl_common;
- case SIOCS80211:
- ireq = (struct ieee80211req *) data;
- if (ireq->i_type == IEEE80211_IOC_STATIONNAME) {
- error = priv_check(td, PRIV_NET80211_MANAGE);
- if (error)
- break;
- if (ireq->i_val != 0 ||
- ireq->i_len > IEEE80211_NWID_LEN) {
- error = EINVAL;
- break;
- }
- memset(nodename, 0, IEEE80211_NWID_LEN);
- error = copyin(ireq->i_data, nodename, ireq->i_len);
- if (error)
- break;
- WI_LOCK(sc);
- if (sc->sc_enabled) {
- error = wi_write_ssid(sc, WI_RID_NODENAME,
- nodename, ireq->i_len);
- }
- if (error == 0) {
- memcpy(sc->sc_nodename, nodename,
- IEEE80211_NWID_LEN);
- sc->sc_nodelen = ireq->i_len;
- }
- WI_UNLOCK(sc);
+ WI_UNLOCK(sc);
+ break;
+ }
+ return (error);
+}
+
+static int
+wi_ioctl_get(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ int error;
+ struct wi_softc *sc;
+ struct ieee80211req *ireq;
+ struct ieee80211com *ic;
+
+
+ sc = ifp->if_softc;
+ ic = &sc->sc_ic;
+ ireq = (struct ieee80211req *) data;
+
+ switch (ireq->i_type) {
+ case IEEE80211_IOC_STATIONNAME:
+ ireq->i_len = sc->sc_nodelen + 1;
+ error = copyout(sc->sc_nodename, ireq->i_data,
+ ireq->i_len);
+ break;
+ default:
+ error = ieee80211_ioctl(ic, cmd, data);
+ WI_LOCK(sc);
+ if (error == ENETRESET) {
+ if (sc->sc_enabled)
+ wi_init(sc); /* XXX no error return */
+ error = 0;
+ }
+ WI_UNLOCK(sc);
+
+ break;
+ }
+
+ return (error);
+}
+
+static int
+wi_ioctl_set(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ int error;
+ struct wi_softc *sc;
+ struct ieee80211req *ireq;
+ u_int8_t nodename[IEEE80211_NWID_LEN];
+
+ sc = ifp->if_softc;
+ ireq = (struct ieee80211req *) data;
+ switch (ireq->i_type) {
+ case IEEE80211_IOC_STATIONNAME:
+ if (ireq->i_val != 0 ||
+ ireq->i_len > IEEE80211_NWID_LEN) {
+ error = EINVAL;
break;
}
- goto ioctl_common;
+ memset(nodename, 0, IEEE80211_NWID_LEN);
+ error = copyin(ireq->i_data, nodename, ireq->i_len);
+ if (error)
+ break;
+ WI_LOCK(sc);
+ if (sc->sc_enabled) {
+ error = wi_write_ssid(sc, WI_RID_NODENAME,
+ nodename, ireq->i_len);
+ }
+ if (error == 0) {
+ memcpy(sc->sc_nodename, nodename,
+ IEEE80211_NWID_LEN);
+ sc->sc_nodelen = ireq->i_len;
+ }
+ WI_UNLOCK(sc);
+
+ break;
default:
- ioctl_common:
+ error = ieee80211_ioctl(&sc->sc_ic, cmd, data);
WI_LOCK(sc);
- error = ieee80211_ioctl(ic, cmd, data);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
@@ -1338,9 +1413,21 @@ wi_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
WI_UNLOCK(sc);
break;
}
+
return (error);
}
+static struct ieee80211_node *
+wi_node_alloc(struct ieee80211_node_table *nt)
+{
+ struct wi_node *rn;
+
+ rn = malloc(sizeof (struct wi_node), M_80211_NODE,
+ M_NOWAIT | M_ZERO);
+
+ return (rn != NULL) ? &rn->ni : NULL;
+}
+
static int
wi_media_change(struct ifnet *ifp)
{
@@ -1413,6 +1500,9 @@ wi_media_status(struct ifnet *ifp, struct ifmediareq *imr)
case IEEE80211_M_MONITOR:
imr->ifm_active |= IFM_IEEE80211_MONITOR;
break;
+ case IEEE80211_M_WDS:
+ /* XXXX */
+ break;
}
}
@@ -1439,6 +1529,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
return;
sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1);
+#if 0
/*
* XXX hack; we should create a new node with the new bssid
* and replace the existing ic_bss with it but since we don't
@@ -1447,6 +1538,7 @@ wi_sync_bssid(struct wi_softc *sc, u_int8_t new_bssid[IEEE80211_ADDR_LEN])
* called and it will overwrite the node state.
*/
ieee80211_sta_join(ic, ieee80211_ref_node(ni));
+#endif
}
static void
@@ -1666,7 +1758,7 @@ wi_rx_intr(struct wi_softc *sc)
/*
* Send frame up for processing.
*/
- ieee80211_input(ic, m, ni, rssi, rstamp);
+ ieee80211_input(ic, m, ni, rssi, -95/*XXXXwi_rx_silence?*/, rstamp);
/*
* The frame may have caused the node to be marked for
* reclamation (e.g. in response to a DEAUTH message)
@@ -1826,8 +1918,9 @@ wi_info_intr(struct wi_softc *sc)
case WI_INFO_SCAN_RESULTS:
case WI_INFO_HOST_SCAN_RESULTS:
wi_scan_result(sc, fid, le16toh(ltbuf[0]));
+ ieee80211_notify_scan_done(ic);
break;
-
+
default:
DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid,
le16toh(ltbuf[1]), le16toh(ltbuf[0])));
@@ -1992,7 +2085,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
case WI_RID_TX_CRYPT_KEY:
case WI_RID_DEFLT_CRYPT_KEYS:
case WI_RID_TX_RATE:
- return ieee80211_cfgget(ic, cmd, data);
+ return ieee80211_ioctl(ic, cmd, data);
case WI_RID_MICROWAVE_OVEN:
if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) {
@@ -2046,7 +2139,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
case WI_RID_READ_APS:
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- return ieee80211_cfgget(ic, cmd, data);
+ return ieee80211_ioctl(ic, cmd, data);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@@ -2083,11 +2176,11 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
case WI_RID_READ_CACHE:
- return ieee80211_cfgget(ic, cmd, data);
+ return ieee80211_ioctl(ic, cmd, data);
case WI_RID_SCAN_RES: /* compatibility interface */
if (ic->ic_opmode == IEEE80211_M_HOSTAP)
- return ieee80211_cfgget(ic, cmd, data);
+ return ieee80211_ioctl(ic, cmd, data);
if (sc->sc_scan_timer > 0) {
error = EINPROGRESS;
break;
@@ -2169,7 +2262,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_nodelen);
break;
default:
- return ieee80211_cfgget(ic, cmd, data);
+ return ieee80211_ioctl(ic, cmd, data);
}
break;
}
@@ -2289,7 +2382,7 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
WI_UNLOCK(sc);
return EINVAL;
}
- ic->ic_fixed_rate = i;
+ ic->ic_fixed_rate = rs->rs_rates[i] & IEEE80211_RATE_VAL;
}
if (sc->sc_enabled)
error = wi_write_txrate(sc);
@@ -2347,9 +2440,10 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
WI_LOCK(sc);
- memset(ic->ic_des_essid, 0, IEEE80211_NWID_LEN);
- ic->ic_des_esslen = le16toh(wreq.wi_val[0]) * 2;
- memcpy(ic->ic_des_essid, &wreq.wi_val[1], ic->ic_des_esslen);
+ memset(ic->ic_des_ssid[0].ssid, 0, IEEE80211_NWID_LEN);
+ ic->ic_des_ssid[0].len = le16toh(wreq.wi_val[0]) * 2;
+ memcpy(ic->ic_des_ssid[0].ssid, &wreq.wi_val[1],
+ ic->ic_des_ssid[0].len);
if (sc->sc_enabled)
wi_init(sc); /* XXX no error return */
WI_UNLOCK(sc);
@@ -2361,8 +2455,8 @@ wi_set_cfg(struct ifnet *ifp, u_long cmd, caddr_t data)
error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val,
len);
if (error == 0) {
- /* XXX ieee80211_cfgset does a copyin */
- error = ieee80211_cfgset(ic, cmd, data);
+ /* XXX ieee80211_ioctl does a copyin */
+ error = ieee80211_ioctl(ic, cmd, data);
if (error == ENETRESET) {
if (sc->sc_enabled)
wi_init(sc);
@@ -2385,8 +2479,7 @@ wi_write_txrate(struct wi_softc *sc)
if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)
rate = 0; /* auto */
else
- rate = (ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates[ic->ic_fixed_rate] &
- IEEE80211_RATE_VAL) / 2;
+ rate = ic->ic_fixed_rate / 2;
/* rate: 0, 1, 2, 5, 11 */
@@ -2868,8 +2961,7 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen);
/* XXX validate channel */
ni->ni_chan = &ic->ic_channels[le16toh(val)];
- ic->ic_curchan = ni->ni_chan;
- ic->ic_ibss_chan = ni->ni_chan;
+ ic->ic_curchan = ic->ic_bsschan = ni->ni_chan;
#if NBPFILTER > 0
sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
htole16(ni->ni_chan->ic_freq);
@@ -2944,6 +3036,16 @@ wi_scan_result(struct wi_softc *sc, int fid, int cnt)
struct wi_scan_header ws_hdr; /* Prism2 header */
struct wi_scan_data_p2 ws_dat; /* Prism2 scantable*/
struct wi_apinfo *ap;
+ struct ieee80211_scanparams sp;
+ struct ieee80211_frame wh;
+ static long rstamp;
+ struct ieee80211com *ic;
+ uint8_t ssid[2+IEEE80211_NWID_LEN];
+
+ printf("wi_scan_result\n");
+ ic = &sc->sc_ic;
+ rstamp++;
+ memset(&sp, 0, sizeof(sp));
off = sizeof(u_int16_t) * 2;
memset(&ws_hdr, 0, sizeof(ws_hdr));
@@ -2973,25 +3075,45 @@ wi_scan_result(struct wi_softc *sc, int fid, int cnt)
/* Read Data */
ap = sc->sc_aps;
memset(&ws_dat, 0, sizeof(ws_dat));
+
for (i = 0; i < naps; i++, ap++) {
+ uint8_t rates[2];
+ uint16_t *bssid;
wi_read_bap(sc, fid, off, &ws_dat,
(sizeof(ws_dat) < szbuf ? sizeof(ws_dat) : szbuf));
DPRINTF2(("wi_scan_result: #%d: off %d bssid %s\n", i, off,
ether_sprintf(ws_dat.wi_bssid)));
+
off += szbuf;
- ap->scanreason = le16toh(ws_hdr.wi_reason);
+ ap->scanreason = le16toh(ws_hdr.wi_reason);
memcpy(ap->bssid, ws_dat.wi_bssid, sizeof(ap->bssid));
- ap->channel = le16toh(ws_dat.wi_chid);
+
+ bssid = (uint16_t *)&ap->bssid;
+ if (bssid[0] == 0 && bssid[1] == 0 && bssid[2] == 0)
+ break;
+
+ memcpy(wh.i_addr2, ws_dat.wi_bssid, sizeof(ap->bssid));
+ memcpy(wh.i_addr3, ws_dat.wi_bssid, sizeof(ap->bssid));
+ sp.chan = ap->channel = le16toh(ws_dat.wi_chid);
ap->signal = le16toh(ws_dat.wi_signal);
ap->noise = le16toh(ws_dat.wi_noise);
ap->quality = ap->signal - ap->noise;
- ap->capinfo = le16toh(ws_dat.wi_capinfo);
- ap->interval = le16toh(ws_dat.wi_interval);
- ap->rate = le16toh(ws_dat.wi_rate);
+ sp.capinfo = ap->capinfo = le16toh(ws_dat.wi_capinfo);
+ sp.bintval = ap->interval = le16toh(ws_dat.wi_interval);
+ ap->rate = le16toh(ws_dat.wi_rate);
+ rates[1] = 1;
+ rates[2] = (uint8_t)ap->rate;
ap->namelen = le16toh(ws_dat.wi_namelen);
if (ap->namelen > sizeof(ap->name))
ap->namelen = sizeof(ap->name);
memcpy(ap->name, ws_dat.wi_name, ap->namelen);
+ sp.ssid = (uint8_t *)&ssid[0];
+ memcpy(sp.ssid + 2, ap->name, ap->namelen);
+ sp.ssid[1] = ap->namelen;
+ sp.rates = &rates[0];
+ sp.tstamp = (uint8_t *)&rstamp;
+ printf("calling add_scan \n");
+ ieee80211_add_scan(ic, &sp, &wh, 0, ap->signal, ap->noise, rstamp);
}
done:
/* Done scanning */
@@ -3003,8 +3125,11 @@ done:
static void
wi_dump_pkt(struct wi_frame *wh, struct ieee80211_node *ni, int rssi)
{
- ieee80211_dump_pkt((u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
- ni ? ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL : -1, rssi);
+ if (ni != NULL)
+ ieee80211_dump_pkt(ni->ni_ic,
+ (u_int8_t *) &wh->wi_whdr, sizeof(wh->wi_whdr),
+ ni->ni_rates.rs_rates[ni->ni_txrate] & IEEE80211_RATE_VAL,
+ rssi);
printf(" status 0x%x rx_tstamp1 %u rx_tstamp0 0x%u rx_silence %u\n",
le16toh(wh->wi_status), le16toh(wh->wi_rx_tstamp1),
le16toh(wh->wi_rx_tstamp0), wh->wi_rx_silence);
@@ -3364,3 +3489,50 @@ wi_symbol_set_hcr(struct wi_softc *sc, int mode)
tsleep(sc, PWAIT, "wiinit", 1);
return 0;
}
+
+/*
+ * This function can be called by ieee80211_set_shortslottime(). Refer to
+ * IEEE Std 802.11-1999 pp. 85 to know how these values are computed.
+ */
+static void
+wi_update_slot(struct ifnet *ifp)
+{
+ DPRINTF(("wi update slot unimplemented\n"));
+}
+
+static void
+wi_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+
+ WI_LOCK(sc);
+ if (!(sc->sc_flags & WI_FLAGS_SCANNING)) {
+ sc->wi_channel = ic->ic_curchan;
+ }
+ WI_UNLOCK(sc);
+}
+
+static void
+wi_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+
+ WI_LOCK(sc);
+ sc->sc_flags |= WI_FLAGS_SCANNING;
+ wi_scan_ap(sc, 0x3fff, 0x000f);
+ WI_UNLOCK(sc);
+
+}
+
+static void
+wi_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+
+ WI_LOCK(sc);
+ sc->sc_flags &= ~WI_FLAGS_SCANNING;
+ WI_UNLOCK(sc);
+}
diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h
index f7159af..88238a3 100644
--- a/sys/dev/wi/if_wivar.h
+++ b/sys/dev/wi/if_wivar.h
@@ -100,6 +100,7 @@ struct wi_softc {
bus_space_handle_t wi_bmemhandle;
bus_space_tag_t wi_bmemtag;
void * wi_intrhand;
+ struct ieee80211_channel *wi_channel;
int wi_io_addr;
int wi_cmd_count;
@@ -108,7 +109,7 @@ struct wi_softc {
int sc_if_flags;
int sc_bap_id;
int sc_bap_off;
-
+
u_int16_t sc_procframe;
u_int16_t sc_portnum;
@@ -201,6 +202,13 @@ struct wi_softc {
#define WI_FLAGS_BUG_AUTOINC 0x0100
#define WI_FLAGS_HAS_FRAGTHR 0x0200
#define WI_FLAGS_HAS_DBMADJUST 0x0400
+#define WI_FLAGS_SCANNING 0x0800
+
+
+/* driver-specific node state */
+struct wi_node {
+ struct ieee80211_node ni; /* base class */
+};
struct wi_card_ident {
u_int16_t card_id;
OpenPOWER on IntegriCloud