aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/cfg.c
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2010-07-30 02:16:01 -0400
committerJohn W. Linville <linville@tuxdriver.com>2010-08-05 16:05:26 -0400
commit197575393713eba035925e4bfdee407f473e5057 (patch)
tree7328fc8f629dcaa0b3c638ad6b01854b70938799 /drivers/net/wireless/libertas/cfg.c
parentaebb628f39ccf67fe9ed888c7f80926fc1070ce5 (diff)
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>
Diffstat (limited to 'drivers/net/wireless/libertas/cfg.c')
-rw-r--r--drivers/net/wireless/libertas/cfg.c56
1 files changed, 40 insertions, 16 deletions
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index b60f6611506..6b35d057426 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -257,6 +257,29 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
257 return sizeof(rate_tlv->header) + i; 257 return sizeof(rate_tlv->header) + i;
258} 258}
259 259
260/* Add common rates from a TLV and return the new end of the TLV */
261static u8 *
262add_ie_rates(u8 *tlv, const u8 *ie, int *nrates)
263{
264 int hw, ap, ap_max = ie[1];
265 u8 hw_rate;
266
267 /* Advance past IE header */
268 ie += 2;
269
270 lbs_deb_hex(LBS_DEB_ASSOC, "AP IE Rates", (u8 *) ie, ap_max);
271
272 for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
273 hw_rate = lbs_rates[hw].bitrate / 5;
274 for (ap = 0; ap < ap_max; ap++) {
275 if (hw_rate == (ie[ap] & 0x7f)) {
276 *tlv++ = ie[ap];
277 *nrates = *nrates + 1;
278 }
279 }
280 }
281 return tlv;
282}
260 283
261/* 284/*
262 * Adds a TLV with all rates the hardware *and* BSS supports. 285 * Adds a TLV with all rates the hardware *and* BSS supports.
@@ -264,8 +287,11 @@ static int lbs_add_supported_rates_tlv(u8 *tlv)
264static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss) 287static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
265{ 288{
266 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv; 289 struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;
267 const u8 *rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES); 290 const u8 *rates_eid, *ext_rates_eid;
268 int n; 291 int n = 0;
292
293 rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
294 ext_rates_eid = ieee80211_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
269 295
270 /* 296 /*
271 * 01 00 TLV_TYPE_RATES 297 * 01 00 TLV_TYPE_RATES
@@ -275,26 +301,21 @@ static int lbs_add_common_rates_tlv(u8 *tlv, struct cfg80211_bss *bss)
275 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES); 301 rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);
276 tlv += sizeof(rate_tlv->header); 302 tlv += sizeof(rate_tlv->header);
277 303
278 if (!rates_eid) { 304 /* Add basic rates */
305 if (rates_eid) {
306 tlv = add_ie_rates(tlv, rates_eid, &n);
307
308 /* Add extended rates, if any */
309 if (ext_rates_eid)
310 tlv = add_ie_rates(tlv, ext_rates_eid, &n);
311 } else {
312 lbs_deb_assoc("assoc: bss had no basic rate IE\n");
279 /* Fallback: add basic 802.11b rates */ 313 /* Fallback: add basic 802.11b rates */
280 *tlv++ = 0x82; 314 *tlv++ = 0x82;
281 *tlv++ = 0x84; 315 *tlv++ = 0x84;
282 *tlv++ = 0x8b; 316 *tlv++ = 0x8b;
283 *tlv++ = 0x96; 317 *tlv++ = 0x96;
284 n = 4; 318 n = 4;
285 } else {
286 int hw, ap;
287 u8 ap_max = rates_eid[1];
288 n = 0;
289 for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
290 u8 hw_rate = lbs_rates[hw].bitrate / 5;
291 for (ap = 0; ap < ap_max; ap++) {
292 if (hw_rate == (rates_eid[ap+2] & 0x7f)) {
293 *tlv++ = rates_eid[ap+2];
294 n++;
295 }
296 }
297 }
298 } 319 }
299 320
300 rate_tlv->header.len = cpu_to_le16(n); 321 rate_tlv->header.len = cpu_to_le16(n);
@@ -1008,6 +1029,7 @@ static int lbs_associate(struct lbs_private *priv,
1008 int status; 1029 int status;
1009 int ret; 1030 int ret;
1010 u8 *pos = &(cmd->iebuf[0]); 1031 u8 *pos = &(cmd->iebuf[0]);
1032 u8 *tmp;
1011 1033
1012 lbs_deb_enter(LBS_DEB_CFG80211); 1034 lbs_deb_enter(LBS_DEB_CFG80211);
1013 1035
@@ -1052,7 +1074,9 @@ static int lbs_associate(struct lbs_private *priv,
1052 pos += lbs_add_cf_param_tlv(pos); 1074 pos += lbs_add_cf_param_tlv(pos);
1053 1075
1054 /* add rates TLV */ 1076 /* add rates TLV */
1077 tmp = pos + 4; /* skip Marvell IE header */
1055 pos += lbs_add_common_rates_tlv(pos, bss); 1078 pos += lbs_add_common_rates_tlv(pos, bss);
1079 lbs_deb_hex(LBS_DEB_ASSOC, "Common Rates", tmp, pos - tmp);
1056 1080
1057 /* add auth type TLV */ 1081 /* add auth type TLV */
1058 if (priv->fwrelease >= 0x09000000) 1082 if (priv->fwrelease >= 0x09000000)