#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
+#include <linux/moduleparam.h>
#include <linux/rtnetlink.h>
#include <linux/pm_qos.h>
#include <linux/crc32.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include <net/mac80211.h>
#include <asm/unaligned.h>
if (!mgd->powersave)
return false;
+ if (mgd->broken_ap)
+ return false;
+
if (!mgd->associated)
return false;
int i, j, err;
bool have_higher_than_11mbit = false;
u16 ap_ht_cap_flags;
+ int min_rate = INT_MAX, min_rate_index = -1;
/* AssocResp and ReassocResp have identical structure */
capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
- printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not "
- "set\n", sdata->name, aid);
+ printk(KERN_DEBUG
+ "%s: invalid AID value 0x%x; bits 15:14 not set\n",
+ sdata->name, aid);
aid &= ~(BIT(15) | BIT(14));
+ ifmgd->broken_ap = false;
+
+ if (aid == 0 || aid > IEEE80211_MAX_AID) {
+ printk(KERN_DEBUG
+ "%s: invalid AID value %d (out of range), turn off PS\n",
+ sdata->name, aid);
+ aid = 0;
+ ifmgd->broken_ap = true;
+ }
+
pos = mgmt->u.assoc_resp.variable;
ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
rates |= BIT(j);
if (is_basic)
basic_rates |= BIT(j);
+ if (rate < min_rate) {
+ min_rate = rate;
+ min_rate_index = j;
+ }
break;
}
}
rates |= BIT(j);
if (is_basic)
basic_rates |= BIT(j);
+ if (rate < min_rate) {
+ min_rate = rate;
+ min_rate_index = j;
+ }
break;
}
}
}
+ /*
+ * some buggy APs don't advertise basic_rates. use the lowest
+ * supported rate instead.
+ */
+ if (unlikely(!basic_rates) && min_rate_index >= 0) {
+ printk(KERN_DEBUG "%s: No basic rates in AssocResp. "
+ "Using min supported rate instead.\n", sdata->name);
+ basic_rates = BIT(min_rate_index);
+ }
+
sta->sta.supp_rates[wk->chan->band] = rates;
sdata->vif.bss_conf.basic_rates = basic_rates;
cancel_work_sync(&ifmgd->request_smps_work);
+ cancel_work_sync(&ifmgd->monitor_work);
cancel_work_sync(&ifmgd->beacon_connection_loss_work);
if (del_timer_sync(&ifmgd->timer))
set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
if (del_timer_sync(&ifmgd->chswitch_timer))
set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
- cancel_work_sync(&ifmgd->monitor_work);
/* these will just be re-established on connection */
del_timer_sync(&ifmgd->conn_mon_timer);
del_timer_sync(&ifmgd->bcn_mon_timer);