diff options
author | Helmut Schaa <hschaa@suse.de> | 2008-05-08 07:34:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-05-12 21:22:19 -0400 |
commit | 36d16ae73becc5978fe22866e9ab66b509211afe (patch) | |
tree | c23a10e13d5e82d25900ee9a9ae6904ec4b0937a /net/mac80211/mlme.c | |
parent | c0186078b78839a8bdb385fa07a816c2f348a49d (diff) |
mac80211: fix association with some APs
Some APs refuse association if the supported rates contained in the
association request do not match its own supported rates. This patch
introduces a new function which builds the intersection between the AP's
supported rates and the client's supported rates to work around such
problems. The same approach is already used in ipw2200 for example.
Signed-off-by: Helmut Schaa <hschaa@suse.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 64 |
1 files changed, 50 insertions, 14 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a5e5c31c23ab..4adba09e80ca 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -665,6 +665,26 @@ static void ieee80211_authenticate(struct net_device *dev, | |||
665 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); | 665 | mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); |
666 | } | 666 | } |
667 | 667 | ||
668 | static int ieee80211_compatible_rates(struct ieee80211_sta_bss *bss, | ||
669 | struct ieee80211_supported_band *sband, | ||
670 | u64 *rates) | ||
671 | { | ||
672 | int i, j, count; | ||
673 | *rates = 0; | ||
674 | count = 0; | ||
675 | for (i = 0; i < bss->supp_rates_len; i++) { | ||
676 | int rate = (bss->supp_rates[i] & 0x7F) * 5; | ||
677 | |||
678 | for (j = 0; j < sband->n_bitrates; j++) | ||
679 | if (sband->bitrates[j].bitrate == rate) { | ||
680 | *rates |= BIT(j); | ||
681 | count++; | ||
682 | break; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | return count; | ||
687 | } | ||
668 | 688 | ||
669 | static void ieee80211_send_assoc(struct net_device *dev, | 689 | static void ieee80211_send_assoc(struct net_device *dev, |
670 | struct ieee80211_if_sta *ifsta) | 690 | struct ieee80211_if_sta *ifsta) |
@@ -673,11 +693,12 @@ static void ieee80211_send_assoc(struct net_device *dev, | |||
673 | struct sk_buff *skb; | 693 | struct sk_buff *skb; |
674 | struct ieee80211_mgmt *mgmt; | 694 | struct ieee80211_mgmt *mgmt; |
675 | u8 *pos, *ies; | 695 | u8 *pos, *ies; |
676 | int i, len; | 696 | int i, len, count, rates_len, supp_rates_len; |
677 | u16 capab; | 697 | u16 capab; |
678 | struct ieee80211_sta_bss *bss; | 698 | struct ieee80211_sta_bss *bss; |
679 | int wmm = 0; | 699 | int wmm = 0; |
680 | struct ieee80211_supported_band *sband; | 700 | struct ieee80211_supported_band *sband; |
701 | u64 rates = 0; | ||
681 | 702 | ||
682 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | 703 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + |
683 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + | 704 | sizeof(*mgmt) + 200 + ifsta->extra_ie_len + |
@@ -740,24 +761,39 @@ static void ieee80211_send_assoc(struct net_device *dev, | |||
740 | *pos++ = ifsta->ssid_len; | 761 | *pos++ = ifsta->ssid_len; |
741 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); | 762 | memcpy(pos, ifsta->ssid, ifsta->ssid_len); |
742 | 763 | ||
764 | /* all supported rates should be added here but some APs | ||
765 | * (e.g. D-Link DAP 1353 in b-only mode) don't like that | ||
766 | * Therefore only add rates the AP supports */ | ||
767 | rates_len = ieee80211_compatible_rates(bss, sband, &rates); | ||
768 | supp_rates_len = rates_len; | ||
769 | if (supp_rates_len > 8) | ||
770 | supp_rates_len = 8; | ||
771 | |||
743 | len = sband->n_bitrates; | 772 | len = sband->n_bitrates; |
744 | if (len > 8) | 773 | pos = skb_put(skb, supp_rates_len + 2); |
745 | len = 8; | ||
746 | pos = skb_put(skb, len + 2); | ||
747 | *pos++ = WLAN_EID_SUPP_RATES; | 774 | *pos++ = WLAN_EID_SUPP_RATES; |
748 | *pos++ = len; | 775 | *pos++ = supp_rates_len; |
749 | for (i = 0; i < len; i++) { | ||
750 | int rate = sband->bitrates[i].bitrate; | ||
751 | *pos++ = (u8) (rate / 5); | ||
752 | } | ||
753 | 776 | ||
754 | if (sband->n_bitrates > len) { | 777 | count = 0; |
755 | pos = skb_put(skb, sband->n_bitrates - len + 2); | 778 | for (i = 0; i < sband->n_bitrates; i++) { |
756 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | 779 | if (BIT(i) & rates) { |
757 | *pos++ = sband->n_bitrates - len; | ||
758 | for (i = len; i < sband->n_bitrates; i++) { | ||
759 | int rate = sband->bitrates[i].bitrate; | 780 | int rate = sband->bitrates[i].bitrate; |
760 | *pos++ = (u8) (rate / 5); | 781 | *pos++ = (u8) (rate / 5); |
782 | if (++count == 8) | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (count == 8) { | ||
788 | pos = skb_put(skb, rates_len - count + 2); | ||
789 | *pos++ = WLAN_EID_EXT_SUPP_RATES; | ||
790 | *pos++ = rates_len - count; | ||
791 | |||
792 | for (i++; i < sband->n_bitrates; i++) { | ||
793 | if (BIT(i) & rates) { | ||
794 | int rate = sband->bitrates[i].bitrate; | ||
795 | *pos++ = (u8) (rate / 5); | ||
796 | } | ||
761 | } | 797 | } |
762 | } | 798 | } |
763 | 799 | ||