Index: sys/dev/iwn/if_iwn.c =================================================================== --- sys/dev/iwn/if_iwn.c (revision 257035) +++ sys/dev/iwn/if_iwn.c (working copy) @@ -3476,7 +3476,54 @@ } #endif +/* + * Check whether OFDM 11g protection will be enabled for the given rate. + * + * The original driver code only enabled protection for OFDM rates. + * It didn't check to see whether it was operating in 11a or 11bg mode. + */ static int +iwn_check_rate_needs_protection(struct iwn_softc *sc, + struct ieee80211vap *vap, uint8_t rate) +{ + struct ieee80211com *ic = vap->iv_ic; + + /* + * Not in 2GHz mode? Then there's no need to enable OFDM + * 11bg protection. + */ + if (! IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) { + return (0); + } + + /* + * 11bg protection not enabled? Then don't use it. + */ + if ((ic->ic_flags & IEEE80211_F_USEPROT) == 0) + return (0); + + /* + * If it's an 11n rate, then for now we enable + * protection. + */ + if (rate & IEEE80211_RATE_MCS) { + return (1); + } + + /* + * Do a rate table lookup. If the PHY is CCK, + * don't do protection. + */ + if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_CCK) + return (0); + + /* + * Yup, enable protection. + */ + return (1); +} + +static int iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni) { struct iwn_ops *ops = &sc->ops; @@ -3496,7 +3543,7 @@ uint16_t qos; u_int hdrlen; bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER]; - uint8_t tid, ridx, txant, type; + uint8_t tid, type; int ac, i, totlen, error, pad, nsegs = 0, rate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -3546,8 +3593,6 @@ (void) ieee80211_ratectl_rate(ni, NULL, 0); rate = ni->ni_txrate; } - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); /* Encrypt the frame if need be. */ if (wh->i_fc[1] & IEEE80211_FC1_WEP) { @@ -3604,13 +3649,15 @@ /* NB: Group frames are sent using CCK in 802.11b/g. */ if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) { flags |= IWN_TX_NEED_RTS; - } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && - ridx >= IWN_RIDX_OFDM6) { + } else if (iwn_check_rate_needs_protection(sc, vap, rate)) { if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) flags |= IWN_TX_NEED_CTS; else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS) flags |= IWN_TX_NEED_RTS; } + + /* XXX HT protection? */ + 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. */ @@ -3654,6 +3701,7 @@ tx->data_ntries = 15; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); tx->rate = iwn_rate_to_plcp(sc, ni, rate); +#if 0 if (tx->id == sc->broadcast_id) { /* Group or management frame. */ tx->linkq = 0; @@ -3661,9 +3709,21 @@ txant = IWN_LSB(sc->txchainmask); tx->rate |= htole32(IWN_RFLAG_ANT(txant)); } else { + /* + * XXX This is no longer true. ni_rates may actually + * XXX need to be ni_htrates (for 11n rates) and thus + * XXX ridx is totally bogus here. + * + * XXX So, break this out into a function and look up + * XXX the correct place to start the MRR table rate + * XXX attempt. + */ tx->linkq = ni->ni_rates.rs_nrates - ridx - 1; flags |= IWN_TX_LINKQ; /* enable MRR */ } +#else + tx->linkq = 0; /* Don't enable MRR for now */ +#endif /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr)); tx->hiaddr = IWN_HIADDR(data->scratch_paddr); @@ -3756,9 +3816,9 @@ struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) { struct iwn_ops *ops = &sc->ops; - struct ifnet *ifp = sc->sc_ifp; +// struct ifnet *ifp = sc->sc_ifp; struct ieee80211vap *vap = ni->ni_vap; - struct ieee80211com *ic = ifp->if_l2com; +// struct ieee80211com *ic = ifp->if_l2com; struct iwn_tx_cmd *cmd; struct iwn_cmd_data *tx; struct ieee80211_frame *wh; @@ -3770,7 +3830,7 @@ uint32_t flags; u_int hdrlen; int ac, totlen, error, pad, nsegs = 0, i, rate; - uint8_t ridx, type, txant; + uint8_t type; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -3786,16 +3846,8 @@ desc = &ring->desc[ring->cur]; data = &ring->data[ring->cur]; - /* Choose a TX rate index. */ + /* Choose a TX rate. */ rate = params->ibp_rate0; - ridx = ieee80211_legacy_rate_lookup(ic->ic_rt, - rate & IEEE80211_RATE_VAL); - if (ridx == (uint8_t)-1) { - /* XXX fall back to mcast/mgmt rate? */ - m_freem(m); - return EINVAL; - } - totlen = m->m_pkthdr.len; /* Prepare TX firmware command. */ @@ -3865,17 +3917,10 @@ tx->rts_ntries = params->ibp_try1; tx->data_ntries = params->ibp_try0; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); + tx->rate = iwn_rate_to_plcp(sc, ni, rate); - /* XXX should just use iwn_rate_to_plcp() */ - tx->rate = htole32(rate2plcp(rate)); - if (ridx < IWN_RIDX_OFDM6 && - IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) - tx->rate |= htole32(IWN_RFLAG_CCK); - /* Group or management frame. */ tx->linkq = 0; - txant = IWN_LSB(sc->txchainmask); - tx->rate |= htole32(IWN_RFLAG_ANT(txant)); /* Set physical address of "scratch area". */ tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));