On Mon, Jan 09, 2017 at 01:54:55PM +0100, Stefan Sperling wrote: > This diff adds 11n support to the athn(4) driver. > Requires -current net80211 code from today.
A better diff which fixes several bugs. Most notably this should fix a crash in hostap mode triggered by clients joining and leaving in a loop. This is fixed by making sure timeout handlers managed by mira aren't overwritten when a client rejoins, and by cancelling these timeouts properly. I'd like to rename some mira API functions for better clarity but that's left for later. This also restores USB device firmware rate scaling in client mode which was disabled by commits I made in 2015. I found a missing 'usc->nnodes--;' in the code from before those commits, and I hope adding that is a proper fix for the problems we were hunting back then. Known issues (not blocking issues IMO): - The athn(4) driver selects low transmit rates relative to what iwn(4) and iwm(4) clients select. - USB client in 11n mode only sends with legacy rates (up to 54Mbit/s). Technically this is legal behaviour, and receiving MCS sent by the AP works. Rate selection is done in firmware so this isn't straightforward to debug. Index: dev/cardbus/if_athn_cardbus.c =================================================================== RCS file: /cvs/src/sys/dev/cardbus/if_athn_cardbus.c,v retrieving revision 1.14 diff -u -p -r1.14 if_athn_cardbus.c --- dev/cardbus/if_athn_cardbus.c 24 Nov 2015 17:11:39 -0000 1.14 +++ dev/cardbus/if_athn_cardbus.c 8 Jan 2017 09:31:28 -0000 @@ -43,6 +43,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar5008.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5008.c,v retrieving revision 1.37 diff -u -p -r1.37 ar5008.c --- dev/ic/ar5008.c 29 Nov 2016 10:22:30 -0000 1.37 +++ dev/ic/ar5008.c 9 Jan 2017 22:30:38 -0000 @@ -51,6 +51,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> @@ -217,7 +218,7 @@ ar5008_attach(struct athn_softc *sc) sc->flags |= ATHN_FLAG_11A; if (base->opCapFlags & AR_OPFLAGS_11G) sc->flags |= ATHN_FLAG_11G; - if (base->opCapFlags & AR_OPFLAGS_11N) + if ((base->opCapFlags & AR_OPFLAGS_11N_DISABLED) == 0) sc->flags |= ATHN_FLAG_11N; IEEE80211_ADDR_COPY(ic->ic_myaddr, base->macAddr); @@ -952,9 +953,11 @@ ar5008_tx_process(struct athn_softc *sc, struct ifnet *ifp = &ic->ic_if; struct athn_txq *txq = &sc->txq[qid]; struct athn_node *an; + struct ieee80211_node *ni; struct athn_tx_buf *bf; struct ar_tx_desc *ds; uint8_t failcnt; + int txfail; bf = SIMPLEQ_FIRST(&txq->head); if (bf == NULL) @@ -970,13 +973,16 @@ ar5008_tx_process(struct athn_softc *sc, sc->sc_tx_timer = 0; - if (ds->ds_status1 & AR_TXS1_EXCESSIVE_RETRIES) + txfail = (ds->ds_status1 & AR_TXS1_EXCESSIVE_RETRIES); + if (txfail) ifp->if_oerrors++; if (ds->ds_status1 & AR_TXS1_UNDERRUN) athn_inc_tx_trigger_level(sc); an = (struct athn_node *)bf->bf_ni; + ni = (struct ieee80211_node *)bf->bf_ni; + /* * NB: the data fail count contains the number of un-acked tries * for the final series used. We must add the number of tries for @@ -987,10 +993,26 @@ ar5008_tx_process(struct athn_softc *sc, failcnt += MS(ds->ds_status9, AR_TXS9_FINAL_IDX) * 2; /* Update rate control statistics. */ - an->amn.amn_txcnt++; - if (failcnt > 0) - an->amn.amn_retrycnt++; - + if (ni->ni_flags & IEEE80211_NODE_HT) { + an->mn.frames++; + an->mn.ampdu_size = bf->bf_m->m_pkthdr.len + IEEE80211_CRC_LEN; + an->mn.agglen = 1; /* XXX We do not yet support Tx agg. */ + if (failcnt > 0) + an->mn.retries++; + if (txfail) + an->mn.txfail++; + if (ic->ic_state == IEEE80211_S_RUN) { +#ifndef IEEE80211_STA_ONLY + if (ic->ic_opmode != IEEE80211_M_HOSTAP || + ni->ni_state == IEEE80211_STA_ASSOC) +#endif + ieee80211_mira_choose(&an->mn, ic, ni); + } + } else { + an->amn.amn_txcnt++; + if (failcnt > 0) + an->amn.amn_retrycnt++; + } DPRINTFN(5, ("Tx done qid=%d status1=%d fail count=%d\n", qid, ds->ds_status1, failcnt)); @@ -1110,7 +1132,7 @@ ar5008_swba_intr(struct athn_softc *sc) ds->ds_ctl2 = SM(AR_TXC2_XMIT_DATA_TRIES0, 1); /* Write Tx rate. */ - ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? + ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; hwrate = athn_rates[ridx].hwrate; ds->ds_ctl3 = SM(AR_TXC3_XMIT_RATE0, hwrate); @@ -1315,15 +1337,25 @@ ar5008_tx(struct athn_softc *sc, struct IEEE80211_FC0_TYPE_DATA) { /* Use lowest rate for all tries. */ ridx[0] = ridx[1] = ridx[2] = ridx[3] = - (ic->ic_curmode == IEEE80211_MODE_11A) ? - ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; + (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? + ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1); + } else if ((ni->ni_flags & IEEE80211_NODE_HT) && + ic->ic_fixed_mcs != -1) { + /* Use same fixed rate for all tries. */ + ridx[0] = ridx[1] = ridx[2] = ridx[3] = + ATHN_RIDX_MCS0 + ic->ic_fixed_mcs; } else if (ic->ic_fixed_rate != -1) { /* Use same fixed rate for all tries. */ ridx[0] = ridx[1] = ridx[2] = ridx[3] = sc->fixed_ridx; } else { - int txrate = ni->ni_txrate; /* Use fallback table of the node. */ + int txrate; + + if (ni->ni_flags & IEEE80211_NODE_HT) + txrate = ATHN_NUM_LEGACY_RATES + ni->ni_txmcs; + else + txrate = ni->ni_txrate; for (i = 0; i < 4; i++) { ridx[i] = an->ridx[txrate]; txrate = an->fallback[txrate]; @@ -1337,7 +1369,10 @@ ar5008_tx(struct athn_softc *sc, struct tap->wt_flags = 0; /* Use initial transmit rate. */ - tap->wt_rate = athn_rates[ridx[0]].rate; + if (athn_rates[ridx[0]].hwrate & 0x80) /* MCS */ + tap->wt_rate = athn_rates[ridx[0]].hwrate; + else + tap->wt_rate = athn_rates[ridx[0]].rate; tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq); tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags); tap->wt_hwqueue = qid; @@ -1455,11 +1490,16 @@ ar5008_tx(struct athn_softc *sc, struct /* Check if frame must be protected using RTS/CTS or CTS-to-self. */ if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { + enum ieee80211_htprot htprot; + + htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK); /* NB: Group frames are sent using CCK in 802.11b/g. */ if (totlen > ic->ic_rtsthreshold) { ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE; - } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) { + } else if (((ic->ic_flags & IEEE80211_F_USEPROT) && + athn_rates[ridx[0]].phy == IEEE80211_T_OFDM) || + ((ic->ic_flags & IEEE80211_F_HTON) && + htprot != IEEE80211_HTPROT_NONE)) { if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) ds->ds_ctl0 |= AR_TXC0_RTS_ENABLE; else if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) @@ -1525,7 +1565,7 @@ ar5008_tx(struct athn_softc *sc, struct SM(AR_TXC7_CHAIN_SEL3, sc->txchainmask); #ifdef notyet /* Use the same short GI setting for all tries. */ - if (ic->ic_flags & IEEE80211_F_SHGI) + if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20) ds->ds_ctl7 |= AR_TXC7_GI0123; /* Use the same channel width for all tries. */ if (ic->ic_flags & IEEE80211_F_CBW40) @@ -1542,8 +1582,8 @@ ar5008_tx(struct athn_softc *sc, struct ds->ds_ctl5 |= AR_TXC5_RTSCTS_QUAL23; } /* Select protection rate (suboptimal but ok). */ - protridx = (ic->ic_curmode == IEEE80211_MODE_11A) ? - ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK2; + protridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? + ATHN_RIDX_OFDM6 : ATHN_RIDX_CCK1; if (ds->ds_ctl0 & AR_TXC0_RTS_ENABLE) { /* Account for CTS duration. */ dur += athn_txtime(sc, IEEE80211_ACK_LEN, Index: dev/ic/ar5008reg.h =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5008reg.h,v retrieving revision 1.3 diff -u -p -r1.3 ar5008reg.h --- dev/ic/ar5008reg.h 31 Dec 2010 17:50:48 -0000 1.3 +++ dev/ic/ar5008reg.h 8 Jan 2017 15:08:19 -0000 @@ -950,12 +950,13 @@ struct ar_base_eep_header { uint8_t opCapFlags; #define AR_OPFLAGS_11A 0x01 #define AR_OPFLAGS_11G 0x02 +/* NB: If set, 11n is _disabled_ in the corresponding mode: */ #define AR_OPFLAGS_11N_5G40 0x04 #define AR_OPFLAGS_11N_2G40 0x08 #define AR_OPFLAGS_11N_5G20 0x10 #define AR_OPFLAGS_11N_2G20 0x20 -/* Shortcut. */ -#define AR_OPFLAGS_11N 0x3c +/* Shortcut for "all of 11n is disabled". */ +#define AR_OPFLAGS_11N_DISABLED 0x3c uint8_t eepMisc; uint16_t regDmn[2]; Index: dev/ic/ar5416.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar5416.c,v retrieving revision 1.19 diff -u -p -r1.19 ar5416.c --- dev/ic/ar5416.c 5 Jan 2016 18:41:15 -0000 1.19 +++ dev/ic/ar5416.c 8 Jan 2017 09:29:59 -0000 @@ -51,6 +51,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar9003.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar9003.c,v retrieving revision 1.41 diff -u -p -r1.41 ar9003.c --- dev/ic/ar9003.c 29 Nov 2016 10:22:30 -0000 1.41 +++ dev/ic/ar9003.c 8 Jan 2017 09:30:50 -0000 @@ -51,6 +51,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar9280.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar9280.c,v retrieving revision 1.25 diff -u -p -r1.25 ar9280.c --- dev/ic/ar9280.c 5 Jan 2016 18:41:15 -0000 1.25 +++ dev/ic/ar9280.c 8 Jan 2017 09:30:11 -0000 @@ -51,6 +51,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar9285.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar9285.c,v retrieving revision 1.26 diff -u -p -r1.26 ar9285.c --- dev/ic/ar9285.c 5 Jan 2016 18:41:15 -0000 1.26 +++ dev/ic/ar9285.c 8 Jan 2017 09:30:24 -0000 @@ -52,6 +52,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar9287.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar9287.c,v retrieving revision 1.24 diff -u -p -r1.24 ar9287.c --- dev/ic/ar9287.c 5 Jan 2016 18:41:15 -0000 1.24 +++ dev/ic/ar9287.c 8 Jan 2017 09:30:37 -0000 @@ -51,6 +51,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/ar9380.c =================================================================== RCS file: /cvs/src/sys/dev/ic/ar9380.c,v retrieving revision 1.24 diff -u -p -r1.24 ar9380.c --- dev/ic/ar9380.c 5 Jan 2016 18:41:15 -0000 1.24 +++ dev/ic/ar9380.c 8 Jan 2017 15:10:10 -0000 @@ -49,6 +49,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/ic/athn.c =================================================================== RCS file: /cvs/src/sys/dev/ic/athn.c,v retrieving revision 1.93 diff -u -p -r1.93 athn.c --- dev/ic/athn.c 13 Apr 2016 10:49:26 -0000 1.93 +++ dev/ic/athn.c 9 Jan 2017 22:35:29 -0000 @@ -53,6 +53,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> @@ -93,7 +94,7 @@ int athn_set_key(struct ieee80211com *, struct ieee80211_key *); void athn_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); -void athn_iter_func(void *, struct ieee80211_node *); +void athn_iter_calib(void *, struct ieee80211_node *); void athn_calib_to(void *); int athn_init_calib(struct athn_softc *, struct ieee80211_channel *, struct ieee80211_channel *); @@ -122,8 +123,11 @@ int athn_hw_reset(struct athn_softc *, struct ieee80211_node *athn_node_alloc(struct ieee80211com *); void athn_newassoc(struct ieee80211com *, struct ieee80211_node *, int); +void athn_node_leave(struct ieee80211com *, struct ieee80211_node *); int athn_media_change(struct ifnet *); void athn_next_scan(void *); +void athn_iter_mira_delete(void *, struct ieee80211_node *); +void athn_delete_mira_nodes(struct athn_softc *); int athn_newstate(struct ieee80211com *, enum ieee80211_state, int); void athn_updateedca(struct ieee80211com *); @@ -289,11 +293,15 @@ athn_attach(struct athn_softc *sc) int i, ntxstreams, nrxstreams; /* Set HT capabilities. */ - ic->ic_htcaps = - IEEE80211_HTCAP_SMPS_DIS | - IEEE80211_HTCAP_CBW20_40 | + ic->ic_htcaps = (IEEE80211_HTCAP_SMPS_DIS << + IEEE80211_HTCAP_SMPS_SHIFT); +#ifdef notyet + ic->ic_htcaps |= IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_SGI40 | IEEE80211_HTCAP_DSSSCCK40; +#endif + ic->ic_htxcaps = 0; +#ifdef notyet if (AR_SREV_9271(sc) || AR_SREV_9287_10_OR_LATER(sc)) ic->ic_htcaps |= IEEE80211_HTCAP_SGI20; if (AR_SREV_9380_10_OR_LATER(sc)) @@ -302,6 +310,7 @@ athn_attach(struct athn_softc *sc) ic->ic_htcaps |= IEEE80211_HTCAP_TXSTBC; ic->ic_htcaps |= 1 << IEEE80211_HTCAP_RXSTBC_SHIFT; } +#endif ntxstreams = sc->ntxchains; nrxstreams = sc->nrxchains; if (!AR_SREV_9380_10_OR_LATER(sc)) { @@ -346,6 +355,9 @@ athn_attach(struct athn_softc *sc) if_attach(ifp); ieee80211_ifattach(ifp); ic->ic_node_alloc = athn_node_alloc; +#ifndef IEEE80211_STA_ONLY + ic->ic_node_leave = athn_node_leave; +#endif ic->ic_newassoc = athn_newassoc; ic->ic_updateslot = athn_updateslot; ic->ic_updateedca = athn_updateedca; @@ -370,10 +382,13 @@ void athn_detach(struct athn_softc *sc) { struct ifnet *ifp = &sc->sc_ic.ic_if; + struct ieee80211com *ic = &sc->sc_ic; int qid; timeout_del(&sc->scan_to); timeout_del(&sc->calib_to); + if (ic->ic_flags & IEEE80211_F_HTON) + athn_delete_mira_nodes(sc); if (!(sc->flags & ATHN_FLAG_USB)) { for (qid = 0; qid < ATHN_QID_COUNT; qid++) @@ -425,6 +440,9 @@ athn_get_chanlist(struct athn_softc *sc) ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; + if (sc->flags & ATHN_FLAG_11N) + ic->ic_channels[chan].ic_flags |= + IEEE80211_CHAN_HT; } } if (sc->flags & ATHN_FLAG_11A) { @@ -433,6 +451,9 @@ athn_get_chanlist(struct athn_softc *sc) ic->ic_channels[chan].ic_freq = ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ); ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A; + if (sc->flags & ATHN_FLAG_11N) + ic->ic_channels[chan].ic_flags |= + IEEE80211_CHAN_HT; } } } @@ -1206,12 +1227,13 @@ athn_btcoex_disable(struct athn_softc *s #endif void -athn_iter_func(void *arg, struct ieee80211_node *ni) +athn_iter_calib(void *arg, struct ieee80211_node *ni) { struct athn_softc *sc = arg; struct athn_node *an = (struct athn_node *)ni; - ieee80211_amrr_choose(&sc->amrr, ni, &an->amn); + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) + ieee80211_amrr_choose(&sc->amrr, ni, &an->amn); } void @@ -1251,9 +1273,9 @@ athn_calib_to(void *arg) #endif if (ic->ic_fixed_rate == -1) { if (ic->ic_opmode == IEEE80211_M_STA) - athn_iter_func(sc, ic->ic_bss); + athn_iter_calib(sc, ic->ic_bss); else - ieee80211_iterate_nodes(ic, athn_iter_func, sc); + ieee80211_iterate_nodes(ic, athn_iter_calib, sc); } timeout_add_msec(&sc->calib_to, 500); splx(s); @@ -1377,7 +1399,7 @@ athn_ani_ofdm_err_trigger(struct athn_so ani->firstep_level++; ops->set_firstep_level(sc, ani->firstep_level); } - } else if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) { + } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) { /* * Beacon RSSI is low, if in b/g mode, turn off OFDM weak * signal detection and zero first step level to maximize @@ -1427,7 +1449,7 @@ athn_ani_cck_err_trigger(struct athn_sof ani->firstep_level++; ops->set_firstep_level(sc, ani->firstep_level); } - } else if (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) { + } else if (IEEE80211_IS_CHAN_2GHZ(sc->sc_ic.ic_bss->ni_chan)) { /* * Beacon RSSI is low, zero first step level to maximize * CCK sensitivity. @@ -1790,11 +1812,17 @@ athn_stop_tx_dma(struct athn_softc *sc, int athn_txtime(struct athn_softc *sc, int len, int ridx, u_int flags) { + struct ieee80211com *ic = &sc->sc_ic; #define divround(a, b) (((a) + (b) - 1) / (b)) int txtime; - /* XXX HT. */ - if (athn_rates[ridx].phy == IEEE80211_T_OFDM) { + if (athn_rates[ridx].hwrate & 0x80) { /* MCS */ + /* Assumes a 20MHz channel, HT-mixed frame format, no STBC. */ + txtime = 8 + 8 + 4 + 4 + 4 * 4 + 8 /* HT PLCP */ + + 4 * ((8 * len + 16 + 6) / (athn_rates[ridx].rate * 2)); + if (IEEE80211_IS_CHAN_2GHZ(ic->ic_bss->ni_chan)) + txtime += 6; /* aSignalExtension */ + } else if (athn_rates[ridx].phy == IEEE80211_T_OFDM) { txtime = divround(8 + 4 * len + 3, athn_rates[ridx].rate); /* SIFS is 10us for 11g but Signal Extension adds 6us. */ txtime = 16 + 4 + 4 * txtime + 16; @@ -2306,7 +2334,12 @@ athn_hw_reset(struct athn_softc *sc, str struct ieee80211_node * athn_node_alloc(struct ieee80211com *ic) { - return (malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO)); + struct athn_node *an; + + an = malloc(sizeof(struct athn_node), M_DEVBUF, M_NOWAIT | M_ZERO); + if (ic->ic_flags & IEEE80211_F_HTON) + ieee80211_mira_node_init(&an->mn); + return (struct ieee80211_node *)an; } void @@ -2318,7 +2351,11 @@ athn_newassoc(struct ieee80211com *ic, s uint8_t rate; int ridx, i, j; - ieee80211_amrr_node_init(&sc->amrr, &an->amn); + if ((ni->ni_flags & IEEE80211_NODE_HT) == 0) + ieee80211_amrr_node_init(&sc->amrr, &an->amn); + else if (ic->ic_opmode == IEEE80211_M_STA) + ieee80211_mira_node_init(&an->mn); + /* Start at lowest available bit-rate, AMRR will raise. */ ni->ni_txrate = 0; @@ -2343,8 +2380,47 @@ athn_newassoc(struct ieee80211com *ic, s } DPRINTFN(2, ("%d fallbacks to %d\n", i, an->fallback[i])); } + + /* In 11n mode, start at lowest available bit-rate, MiRA will raise. */ + ni->ni_txmcs = 0; + + for (i = 0; i <= ATHN_MCS_MAX; i++) { + /* Map MCS index to HW rate index. */ + ridx = ATHN_NUM_LEGACY_RATES + i; + an->ridx[ridx] = ATHN_RIDX_MCS0 + i; + + DPRINTFN(2, ("mcs %d index %d ", i, ridx)); + /* Compute fallback rate for retries. */ + if (i == 0 || i == 8) { + /* MCS 0 and 8 fall back to the lowest legacy rate. */ + if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) + an->fallback[ridx] = ATHN_RIDX_OFDM6; + else + an->fallback[ridx] = ATHN_RIDX_CCK1; + } else { + /* Other MCS fall back to next supported lower MCS. */ + an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + i; + for (j = i - 1; j >= 0; j--) { + if (!isset(ni->ni_rxmcs, j)) + continue; + an->fallback[ridx] = ATHN_NUM_LEGACY_RATES + j; + break; + } + } + DPRINTFN(2, (" fallback to %d\n", an->fallback[ridx])); + } } +#ifndef IEEE80211_STA_ONLY +void +athn_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct athn_node *an = (void *)ni; + if (ic->ic_flags & IEEE80211_F_HTON) + ieee80211_mira_node_destroy(&an->mn); +} +#endif + int athn_media_change(struct ifnet *ifp) { @@ -2387,6 +2463,26 @@ athn_next_scan(void *arg) splx(s); } +void +athn_iter_mira_delete(void *arg, struct ieee80211_node *ni) +{ + struct athn_node *an = (struct athn_node *)ni; + ieee80211_mira_node_destroy(&an->mn); +} + +/* Delete pending timeouts managed by MiRA. */ +void +athn_delete_mira_nodes(struct athn_softc *sc) +{ + struct ieee80211com *ic = &sc->sc_ic; + + if (ic->ic_opmode == IEEE80211_M_STA) { + struct athn_node *an = (struct athn_node *)ic->ic_bss; + ieee80211_mira_node_destroy(&an->mn); + } else + ieee80211_iterate_nodes(ic, athn_iter_mira_delete, sc); +} + int athn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) { @@ -2397,6 +2493,10 @@ athn_newstate(struct ieee80211com *ic, e timeout_del(&sc->calib_to); + if ((ic->ic_flags & IEEE80211_F_HTON) && + ic->ic_state == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) + athn_delete_mira_nodes(sc); + switch (nstate) { case IEEE80211_S_INIT: athn_set_led(sc, 0); @@ -2497,7 +2597,7 @@ athn_clock_rate(struct athn_softc *sc) struct ieee80211com *ic = &sc->sc_ic; int clockrate; /* MHz. */ - if (ic->ic_curmode == IEEE80211_MODE_11A) { + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) { if (sc->flags & ATHN_FLAG_FAST_PLL_CLOCK) clockrate = AR_CLOCK_RATE_FAST_5GHZ_OFDM; else Index: dev/ic/athnvar.h =================================================================== RCS file: /cvs/src/sys/dev/ic/athnvar.h,v retrieving revision 1.36 diff -u -p -r1.36 athnvar.h --- dev/ic/athnvar.h 5 Jan 2016 18:41:15 -0000 1.36 +++ dev/ic/athnvar.h 9 Jan 2017 22:32:56 -0000 @@ -120,14 +120,18 @@ struct athn_rxq { #define ATHN_RIDX_CCK2 1 #define ATHN_RIDX_OFDM6 4 #define ATHN_RIDX_MCS0 12 +#define ATHN_RIDX_MCS8 (ATHN_RIDX_MCS0 + 8) #define ATHN_RIDX_MCS15 27 #define ATHN_RIDX_MAX 27 +#define ATHN_MCS_MAX 15 +#define ATHN_NUM_MCS (ATHN_MCS_MAX + 1) #define ATHN_IS_HT_RIDX(ridx) ((ridx) >= ATHN_RIDX_MCS0) +#define ATHN_IS_MIMO_RIDX(ridx) ((ridx) >= ATHN_RIDX_MCS8) static const struct athn_rate { - uint8_t rate; /* Rate in 500Kbps unit or MCS if 0x80. */ - uint8_t hwrate; /* HW representation. */ - uint8_t rspridx; /* Control Response Frame rate index. */ + uint16_t rate; /* Rate in 500Kbps unit. */ + uint8_t hwrate; /* HW representation. */ + uint8_t rspridx; /* Control Response Frame rate index. */ enum ieee80211_phytype phy; } athn_rates[] = { { 2, 0x1b, 0, IEEE80211_T_DS }, @@ -142,22 +146,22 @@ static const struct athn_rate { { 72, 0x0d, 8, IEEE80211_T_OFDM }, { 96, 0x08, 8, IEEE80211_T_OFDM }, { 108, 0x0c, 8, IEEE80211_T_OFDM }, - { 0x80, 0x80, 8, IEEE80211_T_OFDM }, - { 0x81, 0x81, 8, IEEE80211_T_OFDM }, - { 0x82, 0x82, 8, IEEE80211_T_OFDM }, - { 0x83, 0x83, 8, IEEE80211_T_OFDM }, - { 0x84, 0x84, 8, IEEE80211_T_OFDM }, - { 0x85, 0x85, 8, IEEE80211_T_OFDM }, - { 0x86, 0x86, 8, IEEE80211_T_OFDM }, - { 0x87, 0x87, 8, IEEE80211_T_OFDM }, - { 0x88, 0x88, 8, IEEE80211_T_OFDM }, - { 0x89, 0x89, 8, IEEE80211_T_OFDM }, - { 0x8a, 0x8a, 8, IEEE80211_T_OFDM }, - { 0x8b, 0x8b, 8, IEEE80211_T_OFDM }, - { 0x8c, 0x8c, 8, IEEE80211_T_OFDM }, - { 0x8d, 0x8d, 8, IEEE80211_T_OFDM }, - { 0x8e, 0x8e, 8, IEEE80211_T_OFDM }, - { 0x8f, 0x8f, 8, IEEE80211_T_OFDM } + { 13, 0x80, 4, IEEE80211_T_OFDM }, + { 26, 0x81, 6, IEEE80211_T_OFDM }, + { 39, 0x82, 6, IEEE80211_T_OFDM }, + { 52, 0x83, 8, IEEE80211_T_OFDM }, + { 78, 0x84, 8, IEEE80211_T_OFDM }, + { 104, 0x85, 8, IEEE80211_T_OFDM }, + { 117, 0x86, 8, IEEE80211_T_OFDM }, + { 130, 0x87, 8, IEEE80211_T_OFDM }, + { 26, 0x88, 4, IEEE80211_T_OFDM }, + { 52, 0x89, 6, IEEE80211_T_OFDM }, + { 78, 0x8a, 8, IEEE80211_T_OFDM }, + { 104, 0x8b, 8, IEEE80211_T_OFDM }, + { 156, 0x8c, 8, IEEE80211_T_OFDM }, + { 208, 0x8d, 8, IEEE80211_T_OFDM }, + { 234, 0x8e, 8, IEEE80211_T_OFDM }, + { 260, 0x8f, 8, IEEE80211_T_OFDM } }; struct athn_series { @@ -288,11 +292,14 @@ static const uint16_t ar_mcs_ndbps[][2] #define ATHN_POWER_OFDM_EXT 67 #define ATHN_POWER_COUNT 68 +#define ATHN_NUM_LEGACY_RATES IEEE80211_RATE_MAXSIZE +#define ATHN_NUM_RATES (ATHN_NUM_LEGACY_RATES + ATHN_NUM_MCS) struct athn_node { struct ieee80211_node ni; struct ieee80211_amrr_node amn; - uint8_t ridx[IEEE80211_RATE_MAXSIZE]; - uint8_t fallback[IEEE80211_RATE_MAXSIZE]; + struct ieee80211_mira_node mn; + uint8_t ridx[ATHN_NUM_RATES]; + uint8_t fallback[ATHN_NUM_RATES]; uint8_t sta_index; }; Index: dev/pci/if_athn_pci.c =================================================================== RCS file: /cvs/src/sys/dev/pci/if_athn_pci.c,v retrieving revision 1.18 diff -u -p -r1.18 if_athn_pci.c --- dev/pci/if_athn_pci.c 24 Nov 2015 17:11:39 -0000 1.18 +++ dev/pci/if_athn_pci.c 8 Jan 2017 09:31:15 -0000 @@ -43,6 +43,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> Index: dev/usb/if_athn_usb.c =================================================================== RCS file: /cvs/src/sys/dev/usb/if_athn_usb.c,v retrieving revision 1.43 diff -u -p -r1.43 if_athn_usb.c --- dev/usb/if_athn_usb.c 29 Nov 2016 10:22:30 -0000 1.43 +++ dev/usb/if_athn_usb.c 9 Jan 2017 23:21:57 -0000 @@ -48,6 +48,7 @@ #include <net80211/ieee80211_var.h> #include <net80211/ieee80211_amrr.h> +#include <net80211/ieee80211_mira.h> #include <net80211/ieee80211_radiotap.h> #include <dev/ic/athnreg.h> @@ -1023,9 +1024,7 @@ athn_usb_newstate_cb(struct athn_usb_sof struct ieee80211com *ic = &sc->sc_ic; enum ieee80211_state ostate; uint32_t reg, imask; -#ifndef IEEE80211_STA_ONLY uint8_t sta_index; -#endif int s, error; timeout_del(&sc->calib_to); @@ -1035,14 +1034,10 @@ athn_usb_newstate_cb(struct athn_usb_sof DPRINTF(("newstate %d -> %d\n", ostate, cmd->state)); if (ostate == IEEE80211_S_RUN) { -#ifndef IEEE80211_STA_ONLY - if (ic->ic_opmode == IEEE80211_M_HOSTAP) { - /* XXX really needed? */ - sta_index = ((struct athn_node *)ic->ic_bss)->sta_index; - (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, - &sta_index, sizeof(sta_index), NULL); - } -#endif + sta_index = ((struct athn_node *)ic->ic_bss)->sta_index; + (void)athn_usb_wmi_xcmd(usc, AR_WMI_CMD_NODE_REMOVE, + &sta_index, sizeof(sta_index), NULL); + usc->nnodes--; reg = AR_READ(sc, AR_RX_FILTER); reg = (reg & ~AR_RX_FILTER_MYBEACON) | AR_RX_FILTER_BEACON; @@ -1072,13 +1067,8 @@ athn_usb_newstate_cb(struct athn_usb_sof if (ic->ic_opmode == IEEE80211_M_MONITOR) break; -#ifndef IEEE80211_STA_ONLY - if (ic->ic_opmode == IEEE80211_M_HOSTAP) { - /* Create node entry for our BSS */ - /* XXX really needed? breaks station mode on down/up */ - error = athn_usb_create_node(usc, ic->ic_bss); - } -#endif + /* Create node entry for our BSS */ + error = athn_usb_create_node(usc, ic->ic_bss); athn_set_bss(sc, ic->ic_bss); athn_usb_wmi_cmd(usc, AR_WMI_CMD_DISABLE_INTR); @@ -1132,7 +1122,7 @@ athn_usb_newassoc_cb(struct athn_usb_sof s = splnet(); /* NB: Node may have left before we got scheduled. */ - if (ni->ni_associd != 0) + if (ni->ni_associd != 0 && ni->ni_state == IEEE80211_STA_ASSOC) (void)athn_usb_create_node(usc, ni); ieee80211_release_node(ic, ni); splx(s); @@ -1224,7 +1214,7 @@ athn_usb_create_node(struct athn_usb_sof struct athn_node *an = (struct athn_node *)ni; struct ar_htc_target_sta sta; struct ar_htc_target_rate rate; - int error; + int error, i, j; /* Firmware cannot handle more than 8 STAs. */ if (usc->nnodes > AR_USB_MAX_STA) @@ -1257,8 +1247,19 @@ athn_usb_create_node(struct athn_usb_sof ni->ni_rates.rs_nrates); if (ni->ni_flags & IEEE80211_NODE_HT) { rate.capflags |= htobe32(AR_RC_HT_FLAG); + /* Setup HT rates. */ + for (i = 0, j = 0; i < IEEE80211_HT_NUM_MCS; i++) { + if (!isset(ni->ni_rxmcs, i)) + continue; + if (j >= AR_HTC_RATE_MAX) + break; + rate.ht_rates.rs_rates[j++] = i; + } + rate.ht_rates.rs_nrates = j; + + if (ni->ni_rxmcs[1]) /* dual-stream MIMO rates */ + rate.capflags |= htobe32(AR_RC_DS_FLAG); #ifdef notyet - /* XXX setup HT rates */ if (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_40) rate.capflags |= htobe32(AR_RC_40_FLAG); if (ni->ni_htcaps & IEEE80211_HTCAP_SGI40) Index: dev/usb/if_athn_usb.h =================================================================== RCS file: /cvs/src/sys/dev/usb/if_athn_usb.h,v retrieving revision 1.6 diff -u -p -r1.6 if_athn_usb.h --- dev/usb/if_athn_usb.h 2 Mar 2015 14:46:02 -0000 1.6 +++ dev/usb/if_athn_usb.h 9 Jan 2017 22:59:18 -0000 @@ -141,10 +141,10 @@ struct ar_htc_target_rate { uint8_t isnew; uint32_t capflags; #define AR_RC_DS_FLAG 0x00000001 -#define AR_RC_TS_FLAG 0x00000002 -#define AR_RC_40_FLAG 0x00000004 -#define AR_RC_SGI_FLAG 0x00000008 -#define AR_RC_HT_FLAG 0x00000010 +#define AR_RC_40_FLAG 0x00000002 +#define AR_RC_SGI_FLAG 0x00000004 +#define AR_RC_HT_FLAG 0x00000008 +#define AR_RC_STBC_FLAG 0x00000020 struct ar_htc_rateset lg_rates; struct ar_htc_rateset ht_rates;