A few more bugfixes:
* limit # of scan results stored in memory - this is a long-standing bug Jouni and I only noticed while discussing other things in Santa Fe * revert AP_LINK_PS patch that was causing issues (Felix) * various A-MSDU/A-MPDU fixes for TXQ code (Felix) * interoperability workaround for peers with broken VHT capabilities (Filip Matusiak) * add bitrate definition for a VHT MCS that's supposed to be invalid but gets used by some hardware anyway (Thomas Pedersen) * beacon timer fix in hwsim (Benjamin Beichler) -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJYLrKJAAoJEGt7eEactAAdshYP/Rwi/k9WZ0RKQIA1QA0fnmwv TbUUvPHQ4LA39Czs0JwOPDIbter7TBzFXV5EK0y39jGm8St4a/oHuN072kzBYvob YbBzM0YKV2uQCAjH3AjWjS3RPOlTzfUqSRWgEqtgUTC5VZrpNfhd2r0q+jfwpQ7s +qUsdwqvVJMZKfOEngIXzNXdI95N1d8tpGwzkUqDbOJ+7amdriiJKyTsKEOMqREA 0Mdhu6roEcMDVO+xt5ZkilmpLZOUEHAzaWkwm7d6VToWi7k3pwMiEZ4fthvHZHEZ 6K2bn1UMLdKAExRcQBE3wrmn5jFfUbts1mhmoN1drHocI12epcgw5I4ZjEbfpqMB IBkOM+2hbSdUVfE4KVH6iubqiJwtHB8YSTdKFmMO4jPx7UshPF7YCny6XWC+EqQm ktjyG/lhlXJ0HaOKC/MAwd/KSzfH0eJWGNBDV5s/FIWiqu2oWn+ZIX7vGTpp4K1Z Rery/ZUiJGzVITNG1ka+GXq2tUvDXfkMApr+jFH4G6zioWovxB6+4uyMEeclvC5q zjgYEpZhbn2wQUNEJ8btDDgXkyDGh3UPjy93fO8fMEvv8d9CCOKTQkIUpjPp6jbZ EoLCTW0NNjnAmQRiUFF3vO2O7e3ZTJ4hyNEVkc7mJ2X3DllXRSelTIFSfZVHpb2k P+gY7uC0cAPZ4s6q8GSb =q2mI -----END PGP SIGNATURE----- Merge tag 'mac80211-for-davem-2016-11-18' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211 Johannes Berg says: ==================== A few more bugfixes: * limit # of scan results stored in memory - this is a long-standing bug Jouni and I only noticed while discussing other things in Santa Fe * revert AP_LINK_PS patch that was causing issues (Felix) * various A-MSDU/A-MPDU fixes for TXQ code (Felix) * interoperability workaround for peers with broken VHT capabilities (Filip Matusiak) * add bitrate definition for a VHT MCS that's supposed to be invalid but gets used by some hardware anyway (Thomas Pedersen) * beacon timer fix in hwsim (Benjamin Beichler) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
87305c4cd2
@ -826,7 +826,7 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
|
|||||||
data->bcn_delta = do_div(delta, bcn_int);
|
data->bcn_delta = do_div(delta, bcn_int);
|
||||||
} else {
|
} else {
|
||||||
data->tsf_offset -= delta;
|
data->tsf_offset -= delta;
|
||||||
data->bcn_delta = -do_div(delta, bcn_int);
|
data->bcn_delta = -(s64)do_div(delta, bcn_int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,7 +688,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* No need to do anything if the driver does all */
|
/* No need to do anything if the driver does all */
|
||||||
if (!local->ops->set_tim)
|
if (ieee80211_hw_check(&local->hw, AP_LINK_PS))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (sta->dead)
|
if (sta->dead)
|
||||||
|
@ -1501,7 +1501,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
|||||||
struct sta_info *sta,
|
struct sta_info *sta,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
||||||
struct fq *fq = &local->fq;
|
struct fq *fq = &local->fq;
|
||||||
struct ieee80211_vif *vif;
|
struct ieee80211_vif *vif;
|
||||||
struct txq_info *txqi;
|
struct txq_info *txqi;
|
||||||
@ -1526,8 +1525,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
|
|||||||
if (!txqi)
|
if (!txqi)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
info->control.vif = vif;
|
|
||||||
|
|
||||||
spin_lock_bh(&fq->lock);
|
spin_lock_bh(&fq->lock);
|
||||||
ieee80211_txq_enqueue(local, txqi, skb);
|
ieee80211_txq_enqueue(local, txqi, skb);
|
||||||
spin_unlock_bh(&fq->lock);
|
spin_unlock_bh(&fq->lock);
|
||||||
@ -3213,7 +3210,6 @@ static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
|
|||||||
|
|
||||||
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||||
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||||
*ieee80211_get_qos_ctl(hdr) = tid;
|
|
||||||
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
|
||||||
} else {
|
} else {
|
||||||
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
|
||||||
@ -3338,6 +3334,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
|
|||||||
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
|
||||||
info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
|
info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT;
|
||||||
|
|
||||||
|
if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
|
||||||
|
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
|
||||||
|
*ieee80211_get_qos_ctl(hdr) = tid;
|
||||||
|
}
|
||||||
|
|
||||||
__skb_queue_head_init(&tx.skbs);
|
__skb_queue_head_init(&tx.skbs);
|
||||||
|
|
||||||
tx.flags = IEEE80211_TX_UNICAST;
|
tx.flags = IEEE80211_TX_UNICAST;
|
||||||
@ -3426,6 +3427,11 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
|||||||
goto begin;
|
goto begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
|
||||||
|
info->flags |= IEEE80211_TX_CTL_AMPDU;
|
||||||
|
else
|
||||||
|
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
|
||||||
|
|
||||||
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
|
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
|
||||||
struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
struct sta_info *sta = container_of(txq->sta, struct sta_info,
|
||||||
sta);
|
sta);
|
||||||
|
@ -270,6 +270,22 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
|||||||
vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
|
vht_cap->vht_mcs.tx_mcs_map |= cpu_to_le16(peer_tx << i * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a workaround for VHT-enabled STAs which break the spec
|
||||||
|
* and have the VHT-MCS Rx map filled in with value 3 for all eight
|
||||||
|
* spacial streams, an example is AR9462.
|
||||||
|
*
|
||||||
|
* As per spec, in section 22.1.1 Introduction to the VHT PHY
|
||||||
|
* A VHT STA shall support at least single spactial stream VHT-MCSs
|
||||||
|
* 0 to 7 (transmit and receive) in all supported channel widths.
|
||||||
|
*/
|
||||||
|
if (vht_cap->vht_mcs.rx_mcs_map == cpu_to_le16(0xFFFF)) {
|
||||||
|
vht_cap->vht_supported = false;
|
||||||
|
sdata_info(sdata, "Ignoring VHT IE from %pM due to invalid rx_mcs_map\n",
|
||||||
|
sta->addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* finally set up the bandwidth */
|
/* finally set up the bandwidth */
|
||||||
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
|
||||||
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
|
||||||
|
@ -71,6 +71,7 @@ struct cfg80211_registered_device {
|
|||||||
struct list_head bss_list;
|
struct list_head bss_list;
|
||||||
struct rb_root bss_tree;
|
struct rb_root bss_tree;
|
||||||
u32 bss_generation;
|
u32 bss_generation;
|
||||||
|
u32 bss_entries;
|
||||||
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
|
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
|
||||||
struct sk_buff *scan_msg;
|
struct sk_buff *scan_msg;
|
||||||
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
|
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
|
||||||
|
@ -57,6 +57,19 @@
|
|||||||
* also linked into the probe response struct.
|
* also linked into the probe response struct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit the number of BSS entries stored in mac80211. Each one is
|
||||||
|
* a bit over 4k at most, so this limits to roughly 4-5M of memory.
|
||||||
|
* If somebody wants to really attack this though, they'd likely
|
||||||
|
* use small beacons, and only one type of frame, limiting each of
|
||||||
|
* the entries to a much smaller size (in order to generate more
|
||||||
|
* entries in total, so overhead is bigger.)
|
||||||
|
*/
|
||||||
|
static int bss_entries_limit = 1000;
|
||||||
|
module_param(bss_entries_limit, int, 0644);
|
||||||
|
MODULE_PARM_DESC(bss_entries_limit,
|
||||||
|
"limit to number of scan BSS entries (per wiphy, default 1000)");
|
||||||
|
|
||||||
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
|
#define IEEE80211_SCAN_RESULT_EXPIRE (30 * HZ)
|
||||||
|
|
||||||
static void bss_free(struct cfg80211_internal_bss *bss)
|
static void bss_free(struct cfg80211_internal_bss *bss)
|
||||||
@ -137,6 +150,10 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,
|
|||||||
|
|
||||||
list_del_init(&bss->list);
|
list_del_init(&bss->list);
|
||||||
rb_erase(&bss->rbn, &rdev->bss_tree);
|
rb_erase(&bss->rbn, &rdev->bss_tree);
|
||||||
|
rdev->bss_entries--;
|
||||||
|
WARN_ONCE((rdev->bss_entries == 0) ^ list_empty(&rdev->bss_list),
|
||||||
|
"rdev bss entries[%d]/list[empty:%d] corruption\n",
|
||||||
|
rdev->bss_entries, list_empty(&rdev->bss_list));
|
||||||
bss_ref_put(rdev, bss);
|
bss_ref_put(rdev, bss);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -163,6 +180,40 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
|
|||||||
rdev->bss_generation++;
|
rdev->bss_generation++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool cfg80211_bss_expire_oldest(struct cfg80211_registered_device *rdev)
|
||||||
|
{
|
||||||
|
struct cfg80211_internal_bss *bss, *oldest = NULL;
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
lockdep_assert_held(&rdev->bss_lock);
|
||||||
|
|
||||||
|
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||||
|
if (atomic_read(&bss->hold))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!list_empty(&bss->hidden_list) &&
|
||||||
|
!bss->pub.hidden_beacon_bss)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (oldest && time_before(oldest->ts, bss->ts))
|
||||||
|
continue;
|
||||||
|
oldest = bss;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (WARN_ON(!oldest))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The callers make sure to increase rdev->bss_generation if anything
|
||||||
|
* gets removed (and a new entry added), so there's no need to also do
|
||||||
|
* it here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = __cfg80211_unlink_bss(rdev, oldest);
|
||||||
|
WARN_ON(!ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
|
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev,
|
||||||
bool send_message)
|
bool send_message)
|
||||||
{
|
{
|
||||||
@ -689,6 +740,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
|
|||||||
const u8 *ie;
|
const u8 *ie;
|
||||||
int i, ssidlen;
|
int i, ssidlen;
|
||||||
u8 fold = 0;
|
u8 fold = 0;
|
||||||
|
u32 n_entries = 0;
|
||||||
|
|
||||||
ies = rcu_access_pointer(new->pub.beacon_ies);
|
ies = rcu_access_pointer(new->pub.beacon_ies);
|
||||||
if (WARN_ON(!ies))
|
if (WARN_ON(!ies))
|
||||||
@ -712,6 +764,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
|
|||||||
/* This is the bad part ... */
|
/* This is the bad part ... */
|
||||||
|
|
||||||
list_for_each_entry(bss, &rdev->bss_list, list) {
|
list_for_each_entry(bss, &rdev->bss_list, list) {
|
||||||
|
/*
|
||||||
|
* we're iterating all the entries anyway, so take the
|
||||||
|
* opportunity to validate the list length accounting
|
||||||
|
*/
|
||||||
|
n_entries++;
|
||||||
|
|
||||||
if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
|
if (!ether_addr_equal(bss->pub.bssid, new->pub.bssid))
|
||||||
continue;
|
continue;
|
||||||
if (bss->pub.channel != new->pub.channel)
|
if (bss->pub.channel != new->pub.channel)
|
||||||
@ -740,6 +798,10 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
|
|||||||
new->pub.beacon_ies);
|
new->pub.beacon_ies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WARN_ONCE(n_entries != rdev->bss_entries,
|
||||||
|
"rdev bss entries[%d]/list[len:%d] corruption\n",
|
||||||
|
rdev->bss_entries, n_entries);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,7 +956,14 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rdev->bss_entries >= bss_entries_limit &&
|
||||||
|
!cfg80211_bss_expire_oldest(rdev)) {
|
||||||
|
kfree(new);
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
|
||||||
list_add_tail(&new->list, &rdev->bss_list);
|
list_add_tail(&new->list, &rdev->bss_list);
|
||||||
|
rdev->bss_entries++;
|
||||||
rb_insert_bss(rdev, new);
|
rb_insert_bss(rdev, new);
|
||||||
found = new;
|
found = new;
|
||||||
}
|
}
|
||||||
|
@ -1158,7 +1158,8 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
|
|||||||
58500000,
|
58500000,
|
||||||
65000000,
|
65000000,
|
||||||
78000000,
|
78000000,
|
||||||
0,
|
/* not in the spec, but some devices use this: */
|
||||||
|
86500000,
|
||||||
},
|
},
|
||||||
{ 13500000,
|
{ 13500000,
|
||||||
27000000,
|
27000000,
|
||||||
|
Loading…
Reference in New Issue
Block a user