mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
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:
parent
aebb628f39
commit
1975753937
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user