libertas: fix association with some APs by using extended rates

Some APs get pissy if you don't send the firmware the extended rates
in the association request's rates TLV.  Found this on a Linksys
WRT54G v2; it denies association with status code 18 unless you
add the extended rates too.  The old driver did this, but it got
lost in the cfg80211 conversion.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
Dan Williams 2010-07-29 23:16:01 -07:00 committed by John W. Linville
parent aebb628f39
commit 1975753937

View File

@ -257,6 +257,29 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
return sizeof(rate_tlv->header) + i;
}
/* Add common rates from a TLV and return the new end of the TLV */
static u8 *
add_ie_rates(u8 *tlv, const u8 *ie, int *nrates)
{
int hw, ap, ap_max = ie[1];
u8 hw_rate;
/* Advance past IE header */
ie += 2;
lbs_deb_hex(LBS_DEB_ASSOC, "AP IE Rates", (u8 *) ie, ap_max);
for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
hw_rate = lbs_rates[hw].bitrate / 5;
for (ap = 0; ap < ap_max; ap++) {
if (hw_rate == (ie[ap] & 0x7f)) {
*tlv++ = ie[ap];
*nrates = *nrates + 1;
}
}
}
return tlv;
}
/*
* Adds a TLV with all rates the hardware *and* BSS supports.
@ -264,8 +287,11 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
{
struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
int n;
const u8 *rates_eid, *ext_rates_eid;
int n = 0;
rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
/*
* 01 00 TLV_TYPE_RATES
@ -275,26 +301,21 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
tlv += sizeof(rate_tlv->header);
if (!rates_eid) {
/* Add basic rates */
if (rates_eid) {
tlv = add_ie_rates(tlv, rates_eid, &n);
/* Add extended rates, if any */
if (ext_rates_eid)
tlv = add_ie_rates(tlv, ext_rates_eid, &n);
} else {
lbs_deb_assoc("assoc: bss had no basic rate IE\n");
/* Fallback: add basic 802.11b rates */
*tlv++ = 0x82;
*tlv++ = 0x84;
*tlv++ = 0x8b;
*tlv++ = 0x96;
n = 4;
} else {
int hw, ap;
u8 ap_max = rates_eid[1];
n = 0;
for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
u8 hw_rate = lbs_rates[hw].bitrate / 5;
for (ap = 0; ap < ap_max; ap++) {
if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
*tlv++ = rates_eid[ap+2];
n++;
}
}
}
}
rate_tlv->header.len = cpu_to_le16(n);
@ -1008,6 +1029,7 @@ static int lbs_associate(struct lbs_private *priv,
int status;
int ret;
u8 *pos = &(cmd->iebuf[0]);
u8 *tmp;
lbs_deb_enter(LBS_DEB_CFG80211);
@ -1052,7 +1074,9 @@ static int lbs_associate(struct lbs_private *priv,
pos += lbs_add_cf_param_tlv(pos);
/* add rates TLV */
tmp = pos + 4; /* skip Marvell IE header */
pos += lbs_add_common_rates_tlv(pos, bss);
lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
/* add auth type TLV */
if (priv->fwrelease >= 0x09000000)