[802.11] Fix erroneous handling of rates element in association request
authorJoshua Oreman <oremanj@xenon.get-linux.org>
Sat, 13 Jun 2009 01:14:13 +0000 (18:14 -0700)
committerJoshua Oreman <oremanj@xenon.get-linux.org>
Sat, 13 Jun 2009 01:14:13 +0000 (18:14 -0700)
When associating with an access point, the standard implies that
we are to send in our association request frame the intersection
between our hardware's supported rates and the rates the AP claimed
it supported in its beacon, marking as "basic" those rates that
were marked as "basic" in the AP's beacon to us. The previous code
erroneously sent simply the hardware's supported rates list, without
consideration to the AP's list and without marking any as "basic".
The AP I was testing with allowed this, but most will not.

src/net/net80211.c

index 686eb27..13ef3c2 100644 (file)
@@ -943,8 +943,8 @@ static int net80211_process_ie ( struct net80211_device *dev,
                for ( i = 0; i < dev->nr_rates; i++ ) {
                        int ok = 0;
                        for ( j = 0; j < dev->hw->nr_supported_rates; j++ ) {
-                               if ( dev->hw->supported_rates[i] ==
-                                    dev->rates[i] ) {
+                               if ( dev->hw->supported_rates[j] ==
+                                    NET80211_RATE_VALUE ( dev->rates[i] ) ) {
                                        ok = 1;
                                        break;
                                }
@@ -1010,27 +1010,31 @@ net80211_marshal_request_info ( struct net80211_device *dev,
        ie = ie_byte;
 
        ie->id = IEEE80211_IE_RATES;
-       ie->len = dev->hw->nr_supported_rates;
-       if ( ie->len > 8 )
-               ie->len = 8;
+       ie->len = dev->nr_rates;
        for ( i = 0; i < ie->len; i++ ) {
-               ie->rates[i] = dev->hw->supported_rates[i] / 5;
+               ie->rates[i] = NET80211_RATE_VALUE ( dev->rates[i] ) / 5;
+               if ( dev->basic_rates & ( 1 << i ) )
+                       ie->rates[i] |= 0x80;
        }
 
-       ie_byte += ie->len + 2;
-       ie = ie_byte;
+       if ( ie->len > 8 ) {
+               /* 802.11 requires we use an Extended Basic Rates IE
+                  for the rates beyond the eighth. */
+               int rates = ie->len;
 
-       if ( i < dev->hw->nr_supported_rates ) {
-               ie->id = IEEE80211_IE_EXT_RATES;
-               ie->len = dev->hw->nr_supported_rates - i;
-               for ( ; i < ie->len; i++ ) {
-                       ie->rates[i - 8] = dev->hw->supported_rates[i] / 5;
-               }
+               memmove ( ie_byte + 2 + 8 + 2, ie_byte + 2 + 8, rates - 8 );
+               ie->len = 8;
 
                ie_byte += ie->len + 2;
                ie = ie_byte;
+
+               ie->id = IEEE80211_IE_EXT_RATES;
+               ie->len = rates - 8;
        }
 
+       ie_byte += ie->len + 2;
+       ie = ie_byte;
+
        return ie;
 }