On Sat, Dec 19, 2015 at 01:08:26PM +0100, Stefan Sperling wrote:
> On Fri, Dec 18, 2015 at 05:40:39PM -0500, David Hill wrote:
> > With sthen@'s patch I can associate, dhcp, and use net.
>
> Here's an updated iwn diff with a better approach for Stuart's fix.
>
> Thanks for helping, Stuart, and to everyone who sent beacons which
> allowed us to narrow this problem down to protection settings being
> set up the wrong way in iwn_run().
And another update (hopefully) fixing some reported issues, with some
uncommitted net80211 changes included.
I haven't put these diffs in yet because I'm still hearing about regressions
in some form or another. Sometimes it's unclear what people are running,
so I hope this version will linger for a bit and get tested.
Thanks for all the help so far from more people than I expected!
Index: dev/pci/if_iwn.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwn.c,v
retrieving revision 1.148
diff -u -p -r1.148 if_iwn.c
--- dev/pci/if_iwn.c 25 Nov 2015 03:09:59 -0000 1.148
+++ dev/pci/if_iwn.c 20 Dec 2015 11:18:52 -0000
@@ -148,7 +148,7 @@ int iwn_newstate(struct ieee80211com *,
void iwn_iter_func(void *, struct ieee80211_node *);
void iwn_calib_timeout(void *);
int iwn_ccmp_decap(struct iwn_softc *, struct mbuf *,
- struct ieee80211_key *);
+ struct ieee80211_node *);
void iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
void iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
@@ -189,7 +189,7 @@ int iwn5000_add_node(struct iwn_softc *
int);
int iwn_set_link_quality(struct iwn_softc *,
struct ieee80211_node *);
-int iwn_add_broadcast_node(struct iwn_softc *, int);
+int iwn_add_broadcast_node(struct iwn_softc *, int, int);
void iwn_updateedca(struct ieee80211com *);
void iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
int iwn_set_critical_temp(struct iwn_softc *);
@@ -280,7 +280,7 @@ void iwn_stop(struct ifnet *, int);
#ifdef IWN_DEBUG
#define DPRINTF(x) do { if (iwn_debug > 0) printf x; } while (0)
#define DPRINTFN(n, x) do { if (iwn_debug >= (n)) printf x; } while (0)
-int iwn_debug = 0;
+int iwn_debug = 1;
#else
#define DPRINTF(x)
#define DPRINTFN(n, x)
@@ -458,6 +458,15 @@ iwn_attach(struct device *parent, struct
IEEE80211_C_PMGT; /* power saving supported */
#ifndef IEEE80211_NO_HT
+ /* No optional HT features supported for now, */
+ ic->ic_htcaps = 0;
+ ic->ic_htxcaps = 0;
+ ic->ic_txbfcaps = 0;
+ ic->ic_aselcaps = 0;
+#endif
+
+#ifdef notyet
+#ifndef IEEE80211_NO_HT
if (sc->sc_flags & IWN_FLAG_HAS_11N) {
/* Set HT capabilities. */
ic->ic_htcaps =
@@ -475,6 +484,7 @@ iwn_attach(struct device *parent, struct
ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DIS;
}
#endif /* !IEEE80211_NO_HT */
+#endif /* notyet */
/* Set supported legacy rates. */
ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
@@ -487,10 +497,12 @@ iwn_attach(struct device *parent, struct
if (sc->sc_flags & IWN_FLAG_HAS_11N) {
/* Set supported HT rates. */
ic->ic_sup_mcs[0] = 0xff; /* MCS 0-7 */
+#ifdef notyet
if (sc->nrxchains > 1)
- ic->ic_sup_mcs[1] = 0xff; /* MCS 7-15 */
+ ic->ic_sup_mcs[1] = 0xff; /* MCS 8-15 */
if (sc->nrxchains > 2)
ic->ic_sup_mcs[2] = 0xff; /* MCS 16-23 */
+#endif
}
#endif
@@ -515,9 +527,11 @@ iwn_attach(struct device *parent, struct
#ifndef IEEE80211_NO_HT
ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
+#ifdef notyet
ic->ic_ampdu_tx_start = iwn_ampdu_tx_start;
ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop;
#endif
+#endif
/* Override 802.11 state transition machine. */
sc->sc_newstate = ic->ic_newstate;
@@ -1635,6 +1649,11 @@ iwn_read_eeprom_channels(struct iwn_soft
/* Save maximum allowed TX power for this channel. */
sc->maxpwr[chan] = channels[i].maxpwr;
+#ifndef IEEE80211_NO_HT
+ if (sc->sc_flags & IWN_FLAG_HAS_11N)
+ ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT;
+#endif
+
DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n",
chan, channels[i].flags, sc->maxpwr[chan]));
}
@@ -1693,13 +1712,18 @@ iwn_newassoc(struct ieee80211com *ic, st
ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
/* Start at lowest available bit-rate, AMRR will raise. */
ni->ni_txrate = 0;
+#ifndef IEEE80211_NO_HT
+ ni->ni_txmcs = 0;
+#endif
for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
/* Map 802.11 rate to HW rate index. */
- for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++)
- if (iwn_rates[ridx].rate == rate)
+ for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) {
+ if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
+ iwn_rates[ridx].rate == rate)
break;
+ }
wn->ridx[i] = ridx;
}
}
@@ -1716,12 +1740,17 @@ iwn_media_change(struct ifnet *ifp)
if (error != ENETRESET)
return error;
+#ifndef IEEE80211_NO_HT
+ if (ic->ic_fixed_mcs != -1)
+ sc->fixed_ridx = iwn_mcs2ridx[ic->ic_fixed_mcs];
+#endif
if (ic->ic_fixed_rate != -1) {
rate = ic->ic_sup_rates[ic->ic_curmode].
rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
/* Map 802.11 rate to HW rate index. */
for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++)
- if (iwn_rates[ridx].rate == rate)
+ if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
+ iwn_rates[ridx].rate == rate)
break;
sc->fixed_ridx = ridx;
}
@@ -1828,13 +1857,14 @@ iwn_calib_timeout(void *arg)
}
int
-iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_key *k)
+iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
{
+ struct ieee80211_key *k = &ni->ni_pairwise_key;
struct ieee80211_frame *wh;
uint64_t pn, *prsc;
uint8_t *ivp;
uint8_t tid;
- int hdrlen;
+ int hdrlen, hasqos;
wh = mtod(m, struct ieee80211_frame *);
hdrlen = ieee80211_get_hdrlen(wh);
@@ -1845,8 +1875,8 @@ iwn_ccmp_decap(struct iwn_softc *sc, str
DPRINTF(("CCMP decap ExtIV not set\n"));
return 1;
}
- tid = ieee80211_has_qos(wh) ?
- ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
+ hasqos = ieee80211_has_qos(wh);
+ tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
prsc = &k->k_rsc[tid];
/* Extract the 48-bit PN from the CCMP header. */
@@ -1857,12 +1887,41 @@ iwn_ccmp_decap(struct iwn_softc *sc, str
(uint64_t)ivp[6] << 32 |
(uint64_t)ivp[7] << 40;
if (pn <= *prsc) {
- /*
- * Not necessarily a replayed frame since we did not check
- * the sequence number of the 802.11 header yet.
- */
- DPRINTF(("CCMP replayed\n"));
- return 1;
+ struct ieee80211_rx_ba *ba = NULL;
+#ifndef IEEE80211_NO_HT
+ ba = &ni->ni_rx_ba[tid];
+#endif
+ if (ba != NULL && ieee80211_has_qos(wh) &&
+ ba->ba_state == IEEE80211_BA_AGREED) {
+ /*
+ * This is an A-MPDU subframe.
+ * Such frames may be received out of order due to
+ * legitimate retransmissions of failed subframes
+ * in previous A-MPDUs. Duplicates will be handled
+ * in ieee80211_input() as part of A-MPDU reordering.
+ */
+ } else if (ieee80211_has_seq(wh)) {
+ /*
+ * Not necessarily a replayed frame since we did not
+ * check the sequence number of the 802.11 header yet.
+ */
+ int nrxseq, orxseq;
+
+ nrxseq = letoh16(*(u_int16_t *)wh->i_seq) >>
+ IEEE80211_SEQ_SEQ_SHIFT;
+ if (hasqos)
+ orxseq = ni->ni_qos_rxseqs[tid];
+ else
+ orxseq = ni->ni_rxseq;
+ if (nrxseq < orxseq) {
+ DPRINTF(("CCMP replayed (n=%d < o=%d)\n",
+ nrxseq, orxseq));
+ return 1;
+ }
+ } else {
+ DPRINTF(("CCMP replayed\n"));
+ return 1;
+ }
}
/* Update last seen packet number. */
*prsc = pn;
@@ -1922,8 +1981,14 @@ iwn_rx_done(struct iwn_softc *sc, struct
DPRINTF(("missing RX_PHY\n"));
return;
}
- sc->last_rx_valid = 0;
stat = &sc->last_rx_stat;
+
+ /*
+ * The firmware does not send separate RX_PHY
+ * notifications for A-MPDU subframes.
+ */
+ if ((stat->flags & htole16(IWN_STAT_FLAG_AGG)) == 0)
+ sc->last_rx_valid = 0;
} else
stat = (struct iwn_rx_stat *)(desc + 1);
@@ -2030,7 +2095,7 @@ iwn_rx_done(struct iwn_softc *sc, struct
m_freem(m);
return;
}
- if (iwn_ccmp_decap(sc, m, &ni->ni_pairwise_key) != 0) {
+ if (iwn_ccmp_decap(sc, m, ni) != 0) {
ifp->if_ierrors++;
m_freem(m);
return;
@@ -2281,9 +2346,10 @@ iwn_tx_done(struct iwn_softc *sc, struct
if (ackfailcnt > 0)
wn->amn.amn_retrycnt++;
- if (status != 1 && status != 2)
+ if (status != 1 && status != 2) {
+ DPRINTF(("%s: status=0x%x\n", __func__, status));
ifp->if_oerrors++;
- else
+ } else
ifp->if_opackets++;
/* Unmap and free mbuf. */
@@ -2397,7 +2463,7 @@ iwn_notif_intr(struct iwn_softc *sc)
* If more than 5 consecutive beacons are missed,
* reinitialize the sensitivity state machine.
*/
- DPRINTF(("beacons missed %d/%d\n",
+ DPRINTFN(2, ("beacons missed %d/%d\n",
letoh32(miss->consecutive), letoh32(miss->total)));
if (ic->ic_state == IEEE80211_S_RUN &&
letoh32(miss->consecutive) > 5)
@@ -2778,15 +2844,24 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
/* Choose a TX rate index. */
if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
- type != IEEE80211_FC0_TYPE_DATA) {
- ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
+ type != IEEE80211_FC0_TYPE_DATA)
+ ridx = (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) ?
IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
- } else if (ic->ic_fixed_rate != -1) {
+#ifndef IEEE80211_NO_HT
+ else if (ic->ic_fixed_mcs != -1)
ridx = sc->fixed_ridx;
- } else
- ridx = wn->ridx[ni->ni_txrate];
+#endif
+ else if (ic->ic_fixed_rate != -1)
+ ridx = sc->fixed_ridx;
+ else {
+#ifndef IEEE80211_NO_HT
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ ridx = iwn_mcs2ridx[ni->ni_txmcs];
+ else
+#endif
+ ridx = wn->ridx[ni->ni_txrate];
+ }
rinfo = &iwn_rates[ridx];
-
#if NBPFILTER > 0
if (sc->sc_drvbpf != NULL) {
struct mbuf mb;
@@ -2795,7 +2870,15 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
tap->wt_flags = 0;
tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags);
- tap->wt_rate = rinfo->rate;
+#ifndef IEEE80211_NO_HT
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ type == IEEE80211_FC0_TYPE_DATA) {
+ /* XXX need a way to pass current MCS in 11n mode */
+ tap->wt_rate = 0;
+ } else
+#endif
+ tap->wt_rate = rinfo->rate;
tap->wt_hwqueue = ac;
if ((ic->ic_flags & IEEE80211_F_WEPON) &&
(wh->i_fc[1] & IEEE80211_FC1_PROTECTED))
@@ -2857,7 +2940,7 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
/* Check if frame must be protected using RTS/CTS or CTS-to-self. */
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
- /* NB: Group frames are sent using CCK in 802.11b/g. */
+ /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */
if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) {
flags |= IWN_TX_NEED_RTS;
} else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
@@ -2867,6 +2950,10 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
flags |= IWN_TX_NEED_RTS;
}
+#ifndef IEEE80211_NO_HT
+ else if (ni->ni_flags & IEEE80211_NODE_HT)
+ flags |= IWN_TX_NEED_RTS;
+#endif
if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) {
if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
/* 5000 autoselects RTS/CTS or CTS-to-self. */
@@ -2911,8 +2998,22 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
tx->rts_ntries = 60;
tx->data_ntries = 15;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
- tx->plcp = rinfo->plcp;
- tx->rflags = rinfo->flags;
+
+#ifndef IEEE80211_NO_HT
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ tx->id != sc->broadcast_id)
+ tx->plcp = rinfo->ht_plcp;
+ else
+#endif
+ tx->plcp = rinfo->plcp;
+
+#ifndef IEEE80211_NO_HT
+ if ((ni->ni_flags & IEEE80211_NODE_HT) &&
+ tx->id != sc->broadcast_id)
+ tx->rflags = rinfo->ht_flags;
+ else
+#endif
+ tx->rflags = rinfo->flags;
if (tx->id == sc->broadcast_id) {
/* Group or management frame. */
tx->linkq = 0;
@@ -2920,7 +3021,12 @@ iwn_tx(struct iwn_softc *sc, struct mbuf
txant = IWN_LSB(sc->txchainmask);
tx->rflags |= IWN_RFLAG_ANT(txant);
} else {
- tx->linkq = ni->ni_rates.rs_nrates - ni->ni_txrate - 1;
+#ifndef IEEE80211_NO_HT
+ if (ni->ni_flags & IEEE80211_NODE_HT)
+ tx->linkq = 7 - ni->ni_txmcs; /* XXX revisit for MIMO */
+ else
+#endif
+ tx->linkq = ni->ni_rates.rs_nrates - ni->ni_txrate - 1;
flags |= IWN_TX_LINKQ; /* enable MRR */
}
/* Set physical address of "scratch area". */
@@ -3304,21 +3410,49 @@ iwn_set_link_quality(struct iwn_softc *s
linkq.id = wn->id;
linkq.antmsk_1stream = txant;
linkq.antmsk_2stream = IWN_ANT_AB;
- linkq.ampdu_max = 31;
+ linkq.ampdu_max = 32;
linkq.ampdu_threshold = 3;
linkq.ampdu_limit = htole16(4000); /* 4ms */
- /* Start at highest available bit-rate. */
- txrate = rs->rs_nrates - 1;
- for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
- rinfo = &iwn_rates[wn->ridx[txrate]];
- linkq.retry[i].plcp = rinfo->plcp;
- linkq.retry[i].rflags = rinfo->flags;
- linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
- /* Next retry at immediate lower bit-rate. */
- if (txrate > 0)
- txrate--;
+#ifndef IEEE80211_NO_HT
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ /* Fill LQ table with MCS 7 - 0 (XXX revisit for MIMO) */
+ i = 0;
+ for (txrate = 7; txrate >= 0; txrate--) {
+ rinfo = &iwn_rates[iwn_mcs2ridx[txrate]];
+ linkq.retry[i].plcp = rinfo->ht_plcp;
+ linkq.retry[i].rflags = rinfo->ht_flags;
+
+ /* XXX set correct ant mask for MIMO rates here */
+ linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
+
+ if (i++ >= IWN_MAX_TX_RETRIES)
+ break;
+ }
+ /* Fill the rest with MCS 0. */
+ rinfo = &iwn_rates[iwn_mcs2ridx[0]];
+ while (i < IWN_MAX_TX_RETRIES) {
+ linkq.retry[i].plcp = rinfo->ht_plcp;
+ linkq.retry[i].rflags = rinfo->ht_flags;
+ linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
+ i++;
+ }
+ } else
+#endif
+ {
+ /* Start at highest available bit-rate. */
+ txrate = rs->rs_nrates - 1;
+ for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
+ rinfo = &iwn_rates[wn->ridx[txrate]];
+ linkq.retry[i].plcp = rinfo->plcp;
+ linkq.retry[i].rflags = rinfo->flags;
+ linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
+ /* Next retry at immediate lower bit-rate. */
+ if (txrate > 0)
+ txrate--;
+ }
}
+
return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1);
}
@@ -3326,7 +3460,7 @@ iwn_set_link_quality(struct iwn_softc *s
* Broadcast node is used to send group-addressed and management frames.
*/
int
-iwn_add_broadcast_node(struct iwn_softc *sc, int async)
+iwn_add_broadcast_node(struct iwn_softc *sc, int async, int ridx)
{
struct iwn_ops *ops = &sc->ops;
struct iwn_node_info node;
@@ -3354,8 +3488,7 @@ iwn_add_broadcast_node(struct iwn_softc
linkq.ampdu_limit = htole16(4000); /* 4ms */
/* Use lowest mandatory bit-rate. */
- rinfo = (sc->sc_ic.ic_curmode != IEEE80211_MODE_11A) ?
- &iwn_rates[IWN_RIDX_CCK1] : &iwn_rates[IWN_RIDX_OFDM6];
+ rinfo = &iwn_rates[ridx];
linkq.retry[0].plcp = rinfo->plcp;
linkq.retry[0].rflags = rinfo->flags;
linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant);
@@ -3564,8 +3697,10 @@ iwn4965_set_txpower(struct iwn_softc *sc
for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) {
/* Convert dBm to half-dBm. */
maxchpwr = sc->maxpwr[chan] * 2;
- if ((ridx / 8) & 1)
+#ifdef notyet
+ if (ridx > iwn_mcs2ridx[7] && ridx < iwn_mcs2ridx[16])
maxchpwr -= 6; /* MIMO 2T: -3dB */
+#endif
pwr = maxpwr;
@@ -3584,7 +3719,7 @@ iwn4965_set_txpower(struct iwn_softc *sc
pwr = maxchpwr;
idx = gain - (pwr - power) - tdiff - vdiff;
- if ((ridx / 8) & 1) /* MIMO */
+ if (ridx > iwn_mcs2ridx[7]) /* MIMO */
idx += (int32_t)letoh32(uc->atten[grp][c]);
if (cmd.band == 0)
@@ -4277,7 +4412,7 @@ iwn_config(struct iwn_softc *sc)
struct ifnet *ifp = &ic->ic_if;
uint32_t txmask;
uint16_t rxchain;
- int error;
+ int error, ridx;
/* Set radio temperature sensor offset. */
if (sc->hw_type == IWN_HW_REV_TYPE_6005) {
@@ -4343,8 +4478,13 @@ iwn_config(struct iwn_softc *sc)
IEEE80211_ADDR_COPY(sc->rxon.wlap, ic->ic_myaddr);
sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
- if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan))
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) {
sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT);
+ DPRINTF(("%s: 2ghz prot 0x%x\n", __func__,
+ le32toh(sc->rxon.flags)));
+ }
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
sc->rxon.mode = IWN_MODE_STA;
@@ -4376,7 +4516,9 @@ iwn_config(struct iwn_softc *sc)
return error;
}
- if ((error = iwn_add_broadcast_node(sc, 0)) != 0) {
+ ridx = (sc->sc_ic.ic_curmode == IEEE80211_MODE_11A) ?
+ IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
+ if ((error = iwn_add_broadcast_node(sc, 0, ridx)) != 0) {
printf("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
return error;
@@ -4664,14 +4806,19 @@ iwn_auth(struct iwn_softc *sc)
struct iwn_ops *ops = &sc->ops;
struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni = ic->ic_bss;
- int error;
+ int error, ridx;
/* Update adapter configuration. */
IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid);
sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
- if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
+ if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
+ if (ic->ic_flags & IEEE80211_F_USEPROT)
+ sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT);
+ DPRINTF(("%s: 2ghz prot 0x%x\n", __func__,
+ le32toh(sc->rxon.flags)));
+ }
if (ic->ic_flags & IEEE80211_F_SHSLOT)
sc->rxon.flags |= htole32(IWN_RXON_SHSLOT);
if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
@@ -4685,12 +4832,13 @@ iwn_auth(struct iwn_softc *sc)
sc->rxon.cck_mask = 0x03;
sc->rxon.ofdm_mask = 0;
break;
- default: /* Assume 802.11b/g. */
+ default: /* Assume 802.11b/g/n. */
sc->rxon.cck_mask = 0x0f;
sc->rxon.ofdm_mask = 0x15;
}
- DPRINTF(("rxon chan %d flags %x cck %x ofdm %x\n", sc->rxon.chan,
- sc->rxon.flags, sc->rxon.cck_mask, sc->rxon.ofdm_mask));
+ DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__,
+ sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
+ sc->rxon.ofdm_mask));
error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
if (error != 0) {
printf("%s: RXON command failed\n", sc->sc_dev.dv_xname);
@@ -4706,7 +4854,9 @@ iwn_auth(struct iwn_softc *sc)
* Reconfiguring RXON clears the firmware nodes table so we must
* add the broadcast node again.
*/
- if ((error = iwn_add_broadcast_node(sc, 1)) != 0) {
+ ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
+ IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
+ if ((error = iwn_add_broadcast_node(sc, 1, ridx)) != 0) {
printf("%s: could not add broadcast node\n",
sc->sc_dev.dv_xname);
return error;
@@ -4742,7 +4892,40 @@ iwn_run(struct iwn_softc *sc)
if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE);
sc->rxon.filter |= htole32(IWN_FILTER_BSS);
- DPRINTF(("rxon chan %d flags %x\n", sc->rxon.chan, sc->rxon.flags));
+#ifndef IEEE80211_NO_HT
+ /* HT is negotiated when associating. */
+ if (ni->ni_flags & IEEE80211_NODE_HT) {
+ enum ieee80211_htprot htprot =
+ (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
+ DPRINTF(("%s: htprot = %d\n", __func__, htprot));
+ sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot));
+ } else
+ sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3));
+#endif
+ if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
+ /* 11a or 11n 5GHz */
+ sc->rxon.cck_mask = 0;
+ sc->rxon.ofdm_mask = 0x15;
+#ifndef IEEE80211_NO_HT
+ } else if (ni->ni_flags & IEEE80211_NODE_HT) {
+ /* 11n 2GHz */
+ sc->rxon.cck_mask = 0x0f;
+ sc->rxon.ofdm_mask = 0x15;
+#endif
+ } else {
+ if (ni->ni_rates.rs_nrates == 4) {
+ /* 11b */
+ sc->rxon.cck_mask = 0x03;
+ sc->rxon.ofdm_mask = 0;
+ } else {
+ /* assume 11g */
+ sc->rxon.cck_mask = 0x0f;
+ sc->rxon.ofdm_mask = 0x15;
+ }
+ }
+ DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__,
+ sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
+ sc->rxon.ofdm_mask));
error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
if (error != 0) {
printf("%s: could not update configuration\n",
Index: dev/pci/if_iwnreg.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwnreg.h,v
retrieving revision 1.49
diff -u -p -r1.49 if_iwnreg.h
--- dev/pci/if_iwnreg.h 9 Sep 2014 18:56:24 -0000 1.49
+++ dev/pci/if_iwnreg.h 20 Dec 2015 10:27:55 -0000
@@ -488,12 +488,17 @@ struct iwn_rxon {
#define IWN_RXON_24GHZ (1 << 0)
#define IWN_RXON_CCK (1 << 1)
#define IWN_RXON_AUTO (1 << 2)
+#define IWN_RXON_TGG_PROT (1 << 3)
#define IWN_RXON_SHSLOT (1 << 4)
#define IWN_RXON_SHPREAMBLE (1 << 5)
#define IWN_RXON_NODIVERSITY (1 << 7)
#define IWN_RXON_ANTENNA_A (1 << 8)
#define IWN_RXON_ANTENNA_B (1 << 9)
#define IWN_RXON_TSF (1 << 15)
+#define IWN_RXON_HT_HT40MINUS (1 << 22)
+#define IWN_RXON_HT_PROTMODE(x) ((x) << 23) /* 2 bits */
+#define IWN_RXON_HT_CHANMODE_PURE40 (1 << 25)
+#define IWN_RXON_HT_CHANMODE_MIXED2040 (2 << 25)
#define IWN_RXON_CTS_TO_SELF (1 << 30)
uint32_t filter;
@@ -630,7 +635,12 @@ struct iwn4965_node_info {
uint32_t reserved7;
} __packed;
+#define IWN_RFLAG_MCS (1 << 0)
#define IWN_RFLAG_CCK (1 << 1)
+#define IWN_RFLAG_GREENFIELD (1 << 2)
+#define IWN_RFLAG_HT40 (1 << 3)
+#define IWN_RFLAG_DUPLICATE (1 << 4)
+#define IWN_RFLAG_SGI (1 << 5)
#define IWN_RFLAG_ANT(x) ((x) << 6)
/* Structure for command IWN_CMD_TX_DATA. */
@@ -1222,7 +1232,12 @@ struct iwn_rx_stat {
uint64_t tstamp;
uint32_t beacon;
uint16_t flags;
+#define IWN_STAT_FLAG_24GHZ (1 << 0)
+#define IWN_STAT_FLAG_MOD_CCK (1 << 1)
#define IWN_STAT_FLAG_SHPREAMBLE (1 << 2)
+#define IWN_STAT_FLAG_NARROW_BAND (1 << 3)
+#define IWN_STAT_FLAG_ANT(x) ((x) << 4) /* 3 bits */
+#define IWN_STAT_FLAG_AGG (1 << 7)
uint16_t chan;
uint8_t phybuf[32];
@@ -1659,25 +1674,33 @@ static const struct iwn_chan_band {
#define IWN_RIDX_CCK1 0
#define IWN_RIDX_OFDM6 4
+#define IWN_PLCP_INVALID 0xff
+
static const struct iwn_rate {
uint8_t rate;
uint8_t plcp;
uint8_t flags;
+ uint8_t ht_plcp;
+ uint8_t ht_flags;
} iwn_rates[IWN_RIDX_MAX + 1] = {
- { 2, 10, IWN_RFLAG_CCK },
- { 4, 20, IWN_RFLAG_CCK },
- { 11, 55, IWN_RFLAG_CCK },
- { 22, 110, IWN_RFLAG_CCK },
- { 12, 0xd, 0 },
- { 18, 0xf, 0 },
- { 24, 0x5, 0 },
- { 36, 0x7, 0 },
- { 48, 0x9, 0 },
- { 72, 0xb, 0 },
- { 96, 0x1, 0 },
- { 108, 0x3, 0 },
- { 120, 0x3, 0 }
+ /* Legacy */ /* HT */
+ { 2, 10, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 },
+ { 4, 20, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 },
+ { 11, 55, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 },
+ { 22, 110, IWN_RFLAG_CCK, IWN_PLCP_INVALID, 0 },
+ { 12, 0xd, 0, 0, IWN_RFLAG_MCS },
+ { 18, 0xf, 0, IWN_PLCP_INVALID, 0 },
+ { 24, 0x5, 0, 1, IWN_RFLAG_MCS },
+ { 36, 0x7, 0, 2, IWN_RFLAG_MCS, },
+ { 48, 0x9, 0, 3, IWN_RFLAG_MCS, },
+ { 72, 0xb, 0, 4, IWN_RFLAG_MCS, },
+ { 96, 0x1, 0, 5, IWN_RFLAG_MCS, },
+ { 108, 0x3, 0, 6, IWN_RFLAG_MCS, },
+ { 128, IWN_PLCP_INVALID, 0, 7, IWN_RFLAG_MCS, }
};
+
+/* Convert an MCS index into an iwn_rates[] index. */
+const int iwn_mcs2ridx[] = { 4, 6, 7, 8, 9, 10, 11, 12 };
#define IWN4965_MAX_PWR_INDEX 107
Index: net80211/ieee80211.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211.c,v
retrieving revision 1.53
diff -u -p -r1.53 ieee80211.c
--- net80211/ieee80211.c 18 Dec 2015 07:42:24 -0000 1.53
+++ net80211/ieee80211.c 19 Dec 2015 11:14:02 -0000
@@ -875,6 +875,14 @@ ieee80211_next_mode(struct ifnet *ifp)
/* Wrap around and ignore turbo mode */
if (ic->ic_curmode == IEEE80211_MODE_TURBO)
continue;
+#ifndef IEEE80211_NO_HT
+ /*
+ * Skip over 11n mode. Its set of channels is the superset
+ * of all channels supported by the other modes.
+ */
+ if (ic->ic_curmode == IEEE80211_MODE_11N)
+ continue;
+#endif
if (ic->ic_curmode >= IEEE80211_MODE_MAX) {
ic->ic_curmode = IEEE80211_MODE_AUTO;
break;
@@ -894,6 +902,10 @@ ieee80211_next_mode(struct ifnet *ifp)
* caller can select a rate set. This is problematic and the
* work here assumes how things work elsewhere in this code.
*
+ * Because the result of this function is ultimately used to select a
+ * rate from the rate set of the returned mode, it must not return
+ * IEEE80211_MODE_11N, which uses MCS instead of rates for unicast frames.
+ *
* XXX never returns turbo modes -dcy
*/
enum ieee80211_phymode
@@ -904,19 +916,15 @@ ieee80211_chan2mode(struct ieee80211com
* NB: this assumes the channel would not be supplied to us
* unless it was already compatible with the current mode.
*/
- if (ic->ic_curmode != IEEE80211_MODE_AUTO ||
- chan == IEEE80211_CHAN_ANYC)
+ if (ic->ic_curmode != IEEE80211_MODE_11N &&
+ (ic->ic_curmode != IEEE80211_MODE_AUTO ||
+ chan == IEEE80211_CHAN_ANYC))
return ic->ic_curmode;
/*
- * In autoselect mode; deduce a mode based on the channel
+ * In autoselect or 11n mode; deduce a mode based on the channel
* characteristics. We assume that turbo-only channels
* are not considered when the channel set is constructed.
*/
-#ifndef IEEE80211_NO_HT
- if (IEEE80211_IS_CHAN_N(chan))
- return IEEE80211_MODE_11N;
- else
-#endif
if (IEEE80211_IS_CHAN_T(chan))
return IEEE80211_MODE_TURBO;
else if (IEEE80211_IS_CHAN_5GHZ(chan))
Index: net80211/ieee80211_input.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_input.c,v
retrieving revision 1.145
diff -u -p -r1.145 ieee80211_input.c
--- net80211/ieee80211_input.c 12 Dec 2015 13:56:10 -0000 1.145
+++ net80211/ieee80211_input.c 18 Dec 2015 13:35:17 -0000
@@ -210,8 +210,7 @@ ieee80211_input_print(struct ieee80211co
"%s: received %s from %s rssi %d mode %s\n", ifp->if_xname,
ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
ether_sprintf(wh->i_addr2), rxi->rxi_rssi,
- ieee80211_phymode_name[ieee80211_chan2mode(
- ic, ic->ic_bss->ni_chan)]);
+ ieee80211_phymode_name[ic->ic_curmode]);
task_set(&msg->task, ieee80211_input_print_task, msg);
task_add(systq, &msg->task);
@@ -2250,24 +2249,17 @@ ieee80211_recv_assoc_resp(struct ieee802
ieee80211_ht_negotiate(ic, ni);
/* Hop into 11n mode after associating to an HT AP in a non-11n mode. */
- if (ic->ic_curmode != IEEE80211_MODE_AUTO &&
- ic->ic_curmode != IEEE80211_MODE_11N &&
- (ni->ni_flags & IEEE80211_NODE_HT))
+ if (ni->ni_flags & IEEE80211_NODE_HT)
ieee80211_setmode(ic, IEEE80211_MODE_11N);
-
- /* Hop out of 11n mode after associating to a non-HT AP. */
- if (ic->ic_curmode == IEEE80211_MODE_11N &&
- (ni->ni_flags & IEEE80211_NODE_HT) == 0) {
- if (IEEE80211_IS_CHAN_T(ni->ni_chan))
- ieee80211_setmode(ic, IEEE80211_MODE_TURBO);
- else if (IEEE80211_IS_CHAN_A(ni->ni_chan))
- ieee80211_setmode(ic, IEEE80211_MODE_11A);
- else if (IEEE80211_IS_CHAN_G(ni->ni_chan))
- ieee80211_setmode(ic, IEEE80211_MODE_11G);
- else
- ieee80211_setmode(ic, IEEE80211_MODE_11B);
- }
+ else
#endif
+ ieee80211_setmode(ic, ieee80211_chan2mode(ic, ni->ni_chan));
+ /*
+ * Reset the erp state (mostly the slot time) now that
+ * our operating mode has been nailed down.
+ */
+ ieee80211_reset_erp(ic);
+
/*
* Configure state now that we are associated.
*/
Index: net80211/ieee80211_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_ioctl.c,v
retrieving revision 1.39
diff -u -p -r1.39 ieee80211_ioctl.c
--- net80211/ieee80211_ioctl.c 14 Mar 2015 03:38:51 -0000 1.39
+++ net80211/ieee80211_ioctl.c 20 Dec 2015 11:40:02 -0000
@@ -647,6 +647,19 @@ ieee80211_ioctl(struct ifnet *ifp, u_lon
ic->ic_scan_lock |= IEEE80211_SCAN_REQUEST;
if (ic->ic_state != IEEE80211_S_SCAN) {
ieee80211_clean_cached(ic);
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ ic->ic_state == IEEE80211_S_RUN &&
+ IFM_MODE(ic->ic_media.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ /*
+ * We're already associated to an AP.
+ * Make the scanning loop start off in
+ * auto mode so all supported bands
+ * get scanned.
+ */
+ ieee80211_setmode(ic,
+ IEEE80211_MODE_AUTO);
+ }
ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
}
}
Index: net80211/ieee80211_node.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_node.c,v
retrieving revision 1.93
diff -u -p -r1.93 ieee80211_node.c
--- net80211/ieee80211_node.c 12 Dec 2015 11:25:46 -0000 1.93
+++ net80211/ieee80211_node.c 18 Dec 2015 13:11:35 -0000
@@ -637,14 +637,6 @@ ieee80211_end_scan(struct ifnet *ifp)
(*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
ni = ic->ic_bss;
- /*
- * Set the erp state (mostly the slot time) to deal with
- * the auto-select case; this should be redundant if the
- * mode is locked.
- */
- ic->ic_curmode = ieee80211_chan2mode(ic, ni->ni_chan);
- ieee80211_reset_erp(ic);
-
if (ic->ic_flags & IEEE80211_F_RSNON)
ieee80211_choose_rsnparams(ic);
else if (ic->ic_flags & IEEE80211_F_WEPON)
Index: net80211/ieee80211_proto.c
===================================================================
RCS file: /cvs/src/sys/net80211/ieee80211_proto.c,v
retrieving revision 1.56
diff -u -p -r1.56 ieee80211_proto.c
--- net80211/ieee80211_proto.c 24 Nov 2015 13:45:06 -0000 1.56
+++ net80211/ieee80211_proto.c 18 Dec 2015 14:38:07 -0000
@@ -894,15 +894,8 @@ justcleanup:
/* initialize bss for probe request */
IEEE80211_ADDR_COPY(ni->ni_macaddr, etherbroadcastaddr);
IEEE80211_ADDR_COPY(ni->ni_bssid, etherbroadcastaddr);
-#ifndef IEEE80211_NO_HT
- if (ic->ic_curmode == IEEE80211_MODE_11N)
- ni->ni_rates = ic->ic_sup_rates[
- IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ?
- IEEE80211_MODE_11G : IEEE80211_MODE_11A];
- else
-#endif
- ni->ni_rates = ic->ic_sup_rates[
- ieee80211_chan2mode(ic, ni->ni_chan)];
+ ni->ni_rates = ic->ic_sup_rates[
+ ieee80211_chan2mode(ic, ni->ni_chan)];
ni->ni_associd = 0;
ni->ni_rstamp = 0;
switch (ostate) {