|
@@ -665,6 +665,26 @@ static void ieee80211_authenticate(struct net_device *dev,
|
|
|
mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
|
|
|
}
|
|
|
|
|
|
+static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss,
|
|
|
+ struct ieee80211_supported_band *sband,
|
|
|
+ u64 *rates)
|
|
|
+{
|
|
|
+ int i, j, count;
|
|
|
+ *rates = 0;
|
|
|
+ count = 0;
|
|
|
+ for (i = 0; i < bss->supp_rates_len; i++) {
|
|
|
+ int rate = (bss->supp_rates[i] & 0x7F) * 5;
|
|
|
+
|
|
|
+ for (j = 0; j < sband->n_bitrates; j++)
|
|
|
+ if (sband->bitrates[j].bitrate == rate) {
|
|
|
+ *rates |= BIT(j);
|
|
|
+ count++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return count;
|
|
|
+}
|
|
|
|
|
|
static void ieee80211_send_assoc(struct net_device *dev,
|
|
|
struct ieee80211_if_sta *ifsta)
|
|
@@ -673,11 +693,12 @@ static void ieee80211_send_assoc(struct net_device *dev,
|
|
|
struct sk_buff *skb;
|
|
|
struct ieee80211_mgmt *mgmt;
|
|
|
u8 *pos, *ies;
|
|
|
- int i, len;
|
|
|
+ int i, len, count, rates_len, supp_rates_len;
|
|
|
u16 capab;
|
|
|
struct ieee80211_sta_bss *bss;
|
|
|
int wmm = 0;
|
|
|
struct ieee80211_supported_band *sband;
|
|
|
+ u64 rates = 0;
|
|
|
|
|
|
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
|
|
|
sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
|
|
@@ -740,24 +761,39 @@ static void ieee80211_send_assoc(struct net_device *dev,
|
|
|
*pos++ = ifsta->ssid_len;
|
|
|
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
|
|
|
|
|
|
+ /* all supported rates should be added here but some APs
|
|
|
+ * (e.g. D-Link DAP 1353 in b-only mode) don't like that
|
|
|
+ * Therefore only add rates the AP supports */
|
|
|
+ rates_len = ieee80211_compatible_rates(bss, sband, &rates);
|
|
|
+ supp_rates_len = rates_len;
|
|
|
+ if (supp_rates_len > 8)
|
|
|
+ supp_rates_len = 8;
|
|
|
+
|
|
|
len = sband->n_bitrates;
|
|
|
- if (len > 8)
|
|
|
- len = 8;
|
|
|
- pos = skb_put(skb, len + 2);
|
|
|
+ pos = skb_put(skb, supp_rates_len + 2);
|
|
|
*pos++ = WLAN_EID_SUPP_RATES;
|
|
|
- *pos++ = len;
|
|
|
- for (i = 0; i < len; i++) {
|
|
|
- int rate = sband->bitrates[i].bitrate;
|
|
|
- *pos++ = (u8) (rate / 5);
|
|
|
- }
|
|
|
+ *pos++ = supp_rates_len;
|
|
|
|
|
|
- if (sband->n_bitrates > len) {
|
|
|
- pos = skb_put(skb, sband->n_bitrates - len + 2);
|
|
|
- *pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
|
- *pos++ = sband->n_bitrates - len;
|
|
|
- for (i = len; i < sband->n_bitrates; i++) {
|
|
|
+ count = 0;
|
|
|
+ for (i = 0; i < sband->n_bitrates; i++) {
|
|
|
+ if (BIT(i) & rates) {
|
|
|
int rate = sband->bitrates[i].bitrate;
|
|
|
*pos++ = (u8) (rate / 5);
|
|
|
+ if (++count == 8)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (count == 8) {
|
|
|
+ pos = skb_put(skb, rates_len - count + 2);
|
|
|
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
|
|
|
+ *pos++ = rates_len - count;
|
|
|
+
|
|
|
+ for (i++; i < sband->n_bitrates; i++) {
|
|
|
+ if (BIT(i) & rates) {
|
|
|
+ int rate = sband->bitrates[i].bitrate;
|
|
|
+ *pos++ = (u8) (rate / 5);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|