Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: disable powersave for broken APs

Only AID values 1-2007 are valid, but some APs have been
found to send random bogus values, in the reported case an
AP that was sending the AID field value 0xffff, an AID of
0x3fff (16383).

There isn't much we can do but disable powersave since
there's no way it can work properly in this case.

Cc: stable@vger.kernel.org
Reported-by: Bill C Riemers <briemers@redhat.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Johannes Berg and committed by
John W. Linville
05cb9108 8a39ef8b

+17 -2
+1
net/mac80211/ieee80211_i.h
··· 389 389 390 390 unsigned long timers_running; /* used for quiesce/restart */ 391 391 bool powersave; /* powersave requested for this iface */ 392 + bool broken_ap; /* AP is broken -- turn off powersave */ 392 393 enum ieee80211_smps_mode req_smps, /* requested smps mode */ 393 394 ap_smps, /* smps mode AP thinks we're in */ 394 395 driver_smps_mode; /* smps mode request */
+16 -2
net/mac80211/mlme.c
··· 637 637 if (!mgd->powersave) 638 638 return false; 639 639 640 + if (mgd->broken_ap) 641 + return false; 642 + 640 643 if (!mgd->associated) 641 644 return false; 642 645 ··· 1492 1489 capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); 1493 1490 1494 1491 if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) 1495 - printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " 1496 - "set\n", sdata->name, aid); 1492 + printk(KERN_DEBUG 1493 + "%s: invalid AID value 0x%x; bits 15:14 not set\n", 1494 + sdata->name, aid); 1497 1495 aid &= ~(BIT(15) | BIT(14)); 1496 + 1497 + ifmgd->broken_ap = false; 1498 + 1499 + if (aid == 0 || aid > IEEE80211_MAX_AID) { 1500 + printk(KERN_DEBUG 1501 + "%s: invalid AID value %d (out of range), turn off PS\n", 1502 + sdata->name, aid); 1503 + aid = 0; 1504 + ifmgd->broken_ap = true; 1505 + } 1498 1506 1499 1507 pos = mgmt->u.assoc_resp.variable; 1500 1508 ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);