Imre Vadasz pointed out that rate sets managed by net80211 are sorted
by effective data rate speed, while the iwm_rates array sorts CCK rates
(1 - 11 Mbit/s) before OFDM rates (6Mbit/s - 54Mbit/s).

rate set (11g): 1, 2, 5.5, 6, 9, 11, 12, 18, 24, 36, 54
iwm_rates:      1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 54

The rate set is sorted at runtime and its length differs between 11a/11b/11g.
So let's add a mapping function and fill the ACK rate bitmap correctly
without making assumptions about the rate set.

Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.143
diff -u -p -r1.143 if_iwm.c
--- if_iwm.c    5 Oct 2016 18:13:25 -0000       1.143
+++ if_iwm.c    7 Oct 2016 11:50:19 -0000
@@ -398,6 +398,7 @@ int iwm_fill_probe_req(struct iwm_softc 
 int    iwm_lmac_scan(struct iwm_softc *);
 int    iwm_config_umac_scan(struct iwm_softc *);
 int    iwm_umac_scan(struct iwm_softc *);
+uint8_t        iwm_ridx2rate(struct ieee80211_rateset *, int);
 void   iwm_ack_rates(struct iwm_softc *, struct iwm_node *, int *, int *);
 void   iwm_mac_ctxt_cmd_common(struct iwm_softc *, struct iwm_node *,
            struct iwm_mac_ctx_cmd *, uint32_t, int);
@@ -4881,6 +4882,21 @@ iwm_umac_scan(struct iwm_softc *sc)
        return err;
 }
 
+uint8_t
+iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
+{
+       int i;
+       uint8_t rval;
+
+       for (i = 0; i < rs->rs_nrates; i++) {
+               rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
+               if (rval == iwm_rates[ridx].rate)
+                       return rs->rs_rates[i];
+       }
+
+       return 0;
+}
+
 void
 iwm_ack_rates(struct iwm_softc *sc, struct iwm_node *in, int *cck_rates,
     int *ofdm_rates)
@@ -4895,17 +4911,16 @@ iwm_ack_rates(struct iwm_softc *sc, stru
 
        if (ni->ni_chan == IEEE80211_CHAN_ANYC ||
            IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
-               for (i = 0; i < MIN(IWM_FIRST_OFDM_RATE, rs->rs_nrates); i++) {
-                       if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0)
+               for (i = IWM_FIRST_CCK_RATE; i < IWM_FIRST_OFDM_RATE; i++) {
+                       if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0)
                                continue;
                        cck |= (1 << i);
                        if (lowest_present_cck > i)
                                lowest_present_cck = i;
                }
        }
-       for (i = IWM_FIRST_OFDM_RATE;
-           i <= MIN(IWM_LAST_NON_HT_RATE, rs->rs_nrates - 1); i++) {
-               if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0)
+       for (i = IWM_FIRST_OFDM_RATE; i <= IWM_LAST_NON_HT_RATE; i++) {
+               if ((iwm_ridx2rate(rs, i) & IEEE80211_RATE_BASIC) == 0)
                        continue;       
                ofdm |= (1 << (i - IWM_FIRST_OFDM_RATE));
                if (lowest_present_ofdm > i)

Reply via email to