Skip to content

Commit

Permalink
Merge tag 'mac80211-for-davem-2016-11-18' of git://git.kernel.org/pub…
Browse files Browse the repository at this point in the history
…/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>
  • Loading branch information
David S. Miller committed Nov 18, 2016
2 parents 06a77b0 + 9853a55 commit 87305c4
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 7 deletions.
2 changes: 1 addition & 1 deletion drivers/net/wireless/mac80211_hwsim.c
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
data->bcn_delta = do_div(delta, bcn_int);
} else {
data->tsf_offset -= delta;
data->bcn_delta = -do_div(delta, bcn_int);
data->bcn_delta = -(s64)do_div(delta, bcn_int);
}
}

Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/sta_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
if (!local->ops->set_tim)
if (ieee80211_hw_check(&local->hw, AP_LINK_PS))
return;

if (sta->dead)
Expand Down
14 changes: 10 additions & 4 deletions net/mac80211/tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1501,7 +1501,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
struct sta_info *sta,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct fq *fq = &local->fq;
struct ieee80211_vif *vif;
struct txq_info *txqi;
Expand All @@ -1526,8 +1525,6 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
if (!txqi)
return false;

info->control.vif = vif;

spin_lock_bh(&fq->lock);
ieee80211_txq_enqueue(local, txqi, skb);
spin_unlock_bh(&fq->lock);
Expand Down Expand Up @@ -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)) {
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
*ieee80211_get_qos_ctl(hdr) = tid;
hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid);
} else {
info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ;
Expand Down Expand Up @@ -3338,6 +3334,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
(tid_tx ? IEEE80211_TX_CTL_AMPDU : 0);
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);

tx.flags = IEEE80211_TX_UNICAST;
Expand Down Expand Up @@ -3426,6 +3427,11 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
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) {
struct sta_info *sta = container_of(txq->sta, struct sta_info,
sta);
Expand Down
16 changes: 16 additions & 0 deletions net/mac80211/vht.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

/*
* 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 */
switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
Expand Down
1 change: 1 addition & 0 deletions net/wireless/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct cfg80211_registered_device {
struct list_head bss_list;
struct rb_root bss_tree;
u32 bss_generation;
u32 bss_entries;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
struct sk_buff *scan_msg;
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
Expand Down
69 changes: 69 additions & 0 deletions net/wireless/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@
* 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)

static void bss_free(struct cfg80211_internal_bss *bss)
Expand Down Expand Up @@ -137,6 +150,10 @@ static bool __cfg80211_unlink_bss(struct cfg80211_registered_device *rdev,

list_del_init(&bss->list);
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);
return true;
}
Expand All @@ -163,6 +180,40 @@ static void __cfg80211_bss_expire(struct cfg80211_registered_device *rdev,
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,
bool send_message)
{
Expand Down Expand Up @@ -689,6 +740,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
const u8 *ie;
int i, ssidlen;
u8 fold = 0;
u32 n_entries = 0;

ies = rcu_access_pointer(new->pub.beacon_ies);
if (WARN_ON(!ies))
Expand All @@ -712,6 +764,12 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
/* This is the bad part ... */

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))
continue;
if (bss->pub.channel != new->pub.channel)
Expand Down Expand Up @@ -740,6 +798,10 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
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;
}

Expand Down Expand Up @@ -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);
rdev->bss_entries++;
rb_insert_bss(rdev, new);
found = new;
}
Expand Down
3 changes: 2 additions & 1 deletion net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,7 +1158,8 @@ static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
58500000,
65000000,
78000000,
0,
/* not in the spec, but some devices use this: */
86500000,
},
{ 13500000,
27000000,
Expand Down

0 comments on commit 87305c4

Please sign in to comment.