Commit 87305c4c authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2016-11-18' of...

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 06a77b07 9853a55e
...@@ -826,7 +826,7 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 { ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment