Commit fe9066ad authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2015-05-26' of...

Merge tag 'mac80211-for-davem-2015-05-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
We have three more fixes:
 * AP_VLAN tailroom calculation fix, the bug leads to warnings
   along with dropped packets
 * NAPI context issue, calling napi_gro_receive() from a timer
   (obviously) can lead to crashes
 * remain-on-channel combining leads to dropped requests and not
   being able to finish certain operations, so remove it
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5f59102f f9dca80b
...@@ -2495,51 +2495,22 @@ static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local, ...@@ -2495,51 +2495,22 @@ static bool ieee80211_coalesce_started_roc(struct ieee80211_local *local,
struct ieee80211_roc_work *new_roc, struct ieee80211_roc_work *new_roc,
struct ieee80211_roc_work *cur_roc) struct ieee80211_roc_work *cur_roc)
{ {
unsigned long j = jiffies; unsigned long now = jiffies;
unsigned long cur_roc_end = cur_roc->hw_start_time + unsigned long remaining = cur_roc->hw_start_time +
msecs_to_jiffies(cur_roc->duration); msecs_to_jiffies(cur_roc->duration) -
struct ieee80211_roc_work *next_roc; now;
int new_dur;
if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun)) if (WARN_ON(!cur_roc->started || !cur_roc->hw_begun))
return false; return false;
if (time_after(j + IEEE80211_ROC_MIN_LEFT, cur_roc_end)) /* if it doesn't fit entirely, schedule a new one */
if (new_roc->duration > jiffies_to_msecs(remaining))
return false; return false;
ieee80211_handle_roc_started(new_roc); ieee80211_handle_roc_started(new_roc);
new_dur = new_roc->duration - jiffies_to_msecs(cur_roc_end - j); /* add to dependents so we send the expired event properly */
/* cur_roc is long enough - add new_roc to the dependents list. */
if (new_dur <= 0) {
list_add_tail(&new_roc->list, &cur_roc->dependents); list_add_tail(&new_roc->list, &cur_roc->dependents);
return true;
}
new_roc->duration = new_dur;
/*
* if cur_roc was already coalesced before, we might
* want to extend the next roc instead of adding
* a new one.
*/
next_roc = list_entry(cur_roc->list.next,
struct ieee80211_roc_work, list);
if (&next_roc->list != &local->roc_list &&
next_roc->chan == new_roc->chan &&
next_roc->sdata == new_roc->sdata &&
!WARN_ON(next_roc->started)) {
list_add_tail(&new_roc->list, &next_roc->dependents);
next_roc->duration = max(next_roc->duration,
new_roc->duration);
next_roc->type = max(next_roc->type, new_roc->type);
return true;
}
/* add right after cur_roc */
list_add(&new_roc->list, &cur_roc->list);
return true; return true;
} }
...@@ -2652,17 +2623,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, ...@@ -2652,17 +2623,9 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
* In the offloaded ROC case, if it hasn't begun, add * In the offloaded ROC case, if it hasn't begun, add
* this new one to the dependent list to be handled * this new one to the dependent list to be handled
* when the master one begins. If it has begun, * when the master one begins. If it has begun,
* check that there's still a minimum time left and * check if it fits entirely within the existing one,
* if so, start this one, transmitting the frame, but * in which case it will just be dependent as well.
* add it to the list directly after this one with * Otherwise, schedule it by itself.
* a reduced time so we'll ask the driver to execute
* it right after finishing the previous one, in the
* hope that it'll also be executed right afterwards,
* effectively extending the old one.
* If there's no minimum time left, just add it to the
* normal list.
* TODO: the ROC type is ignored here, assuming that it
* is better to immediately use the current ROC.
*/ */
if (!tmp->hw_begun) { if (!tmp->hw_begun) {
list_add_tail(&roc->list, &tmp->dependents); list_add_tail(&roc->list, &tmp->dependents);
......
...@@ -205,6 +205,8 @@ enum ieee80211_packet_rx_flags { ...@@ -205,6 +205,8 @@ enum ieee80211_packet_rx_flags {
* @IEEE80211_RX_CMNTR: received on cooked monitor already * @IEEE80211_RX_CMNTR: received on cooked monitor already
* @IEEE80211_RX_BEACON_REPORTED: This frame was already reported * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
* to cfg80211_report_obss_beacon(). * to cfg80211_report_obss_beacon().
* @IEEE80211_RX_REORDER_TIMER: this frame is released by the
* reorder buffer timeout timer, not the normal RX path
* *
* These flags are used across handling multiple interfaces * These flags are used across handling multiple interfaces
* for a single frame. * for a single frame.
...@@ -212,6 +214,7 @@ enum ieee80211_packet_rx_flags { ...@@ -212,6 +214,7 @@ enum ieee80211_packet_rx_flags {
enum ieee80211_rx_flags { enum ieee80211_rx_flags {
IEEE80211_RX_CMNTR = BIT(0), IEEE80211_RX_CMNTR = BIT(0),
IEEE80211_RX_BEACON_REPORTED = BIT(1), IEEE80211_RX_BEACON_REPORTED = BIT(1),
IEEE80211_RX_REORDER_TIMER = BIT(2),
}; };
struct ieee80211_rx_data { struct ieee80211_rx_data {
...@@ -325,12 +328,6 @@ struct mesh_preq_queue { ...@@ -325,12 +328,6 @@ struct mesh_preq_queue {
u8 flags; u8 flags;
}; };
#if HZ/100 == 0
#define IEEE80211_ROC_MIN_LEFT 1
#else
#define IEEE80211_ROC_MIN_LEFT (HZ/100)
#endif
struct ieee80211_roc_work { struct ieee80211_roc_work {
struct list_head list; struct list_head list;
struct list_head dependents; struct list_head dependents;
......
...@@ -522,6 +522,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) ...@@ -522,6 +522,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
memcpy(sdata->vif.hw_queue, master->vif.hw_queue, memcpy(sdata->vif.hw_queue, master->vif.hw_queue,
sizeof(sdata->vif.hw_queue)); sizeof(sdata->vif.hw_queue));
sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef; sdata->vif.bss_conf.chandef = master->vif.bss_conf.chandef;
mutex_lock(&local->key_mtx);
sdata->crypto_tx_tailroom_needed_cnt +=
master->crypto_tx_tailroom_needed_cnt;
mutex_unlock(&local->key_mtx);
break; break;
} }
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
......
...@@ -58,6 +58,22 @@ static void assert_key_lock(struct ieee80211_local *local) ...@@ -58,6 +58,22 @@ static void assert_key_lock(struct ieee80211_local *local)
lockdep_assert_held(&local->key_mtx); lockdep_assert_held(&local->key_mtx);
} }
static void
update_vlan_tailroom_need_count(struct ieee80211_sub_if_data *sdata, int delta)
{
struct ieee80211_sub_if_data *vlan;
if (sdata->vif.type != NL80211_IFTYPE_AP)
return;
mutex_lock(&sdata->local->mtx);
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
vlan->crypto_tx_tailroom_needed_cnt += delta;
mutex_unlock(&sdata->local->mtx);
}
static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
{ {
/* /*
...@@ -79,6 +95,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) ...@@ -79,6 +95,8 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
* http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net * http://mid.gmane.org/1308590980.4322.19.camel@jlt3.sipsolutions.net
*/ */
update_vlan_tailroom_need_count(sdata, 1);
if (!sdata->crypto_tx_tailroom_needed_cnt++) { if (!sdata->crypto_tx_tailroom_needed_cnt++) {
/* /*
* Flush all XMIT packets currently using HW encryption or no * Flush all XMIT packets currently using HW encryption or no
...@@ -88,6 +106,15 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata) ...@@ -88,6 +106,15 @@ static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
} }
} }
static void decrease_tailroom_need_count(struct ieee80211_sub_if_data *sdata,
int delta)
{
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt < delta);
update_vlan_tailroom_need_count(sdata, -delta);
sdata->crypto_tx_tailroom_needed_cnt -= delta;
}
static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
{ {
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
...@@ -144,7 +171,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) ...@@ -144,7 +171,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) || if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
(key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM))) (key->conf.flags & IEEE80211_KEY_FLAG_RESERVE_TAILROOM)))
sdata->crypto_tx_tailroom_needed_cnt--; decrease_tailroom_need_count(sdata, 1);
WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) && WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)); (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
...@@ -541,7 +568,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key, ...@@ -541,7 +568,7 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key,
schedule_delayed_work(&sdata->dec_tailroom_needed_wk, schedule_delayed_work(&sdata->dec_tailroom_needed_wk,
HZ/2); HZ/2);
} else { } else {
sdata->crypto_tx_tailroom_needed_cnt--; decrease_tailroom_need_count(sdata, 1);
} }
} }
...@@ -631,6 +658,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom) ...@@ -631,6 +658,7 @@ void ieee80211_key_free(struct ieee80211_key *key, bool delay_tailroom)
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
{ {
struct ieee80211_key *key; struct ieee80211_key *key;
struct ieee80211_sub_if_data *vlan;
ASSERT_RTNL(); ASSERT_RTNL();
...@@ -639,7 +667,14 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) ...@@ -639,7 +667,14 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
mutex_lock(&sdata->local->key_mtx); mutex_lock(&sdata->local->key_mtx);
sdata->crypto_tx_tailroom_needed_cnt = 0; WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
sdata->crypto_tx_tailroom_pending_dec);
if (sdata->vif.type == NL80211_IFTYPE_AP) {
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
vlan->crypto_tx_tailroom_pending_dec);
}
list_for_each_entry(key, &sdata->key_list, list) { list_for_each_entry(key, &sdata->key_list, list) {
increment_tailroom_need_count(sdata); increment_tailroom_need_count(sdata);
...@@ -649,6 +684,22 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) ...@@ -649,6 +684,22 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
mutex_unlock(&sdata->local->key_mtx); mutex_unlock(&sdata->local->key_mtx);
} }
void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_sub_if_data *vlan;
mutex_lock(&sdata->local->key_mtx);
sdata->crypto_tx_tailroom_needed_cnt = 0;
if (sdata->vif.type == NL80211_IFTYPE_AP) {
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
vlan->crypto_tx_tailroom_needed_cnt = 0;
}
mutex_unlock(&sdata->local->key_mtx);
}
void ieee80211_iter_keys(struct ieee80211_hw *hw, void ieee80211_iter_keys(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
void (*iter)(struct ieee80211_hw *hw, void (*iter)(struct ieee80211_hw *hw,
...@@ -688,8 +739,8 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata, ...@@ -688,8 +739,8 @@ static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
{ {
struct ieee80211_key *key, *tmp; struct ieee80211_key *key, *tmp;
sdata->crypto_tx_tailroom_needed_cnt -= decrease_tailroom_need_count(sdata,
sdata->crypto_tx_tailroom_pending_dec; sdata->crypto_tx_tailroom_pending_dec);
sdata->crypto_tx_tailroom_pending_dec = 0; sdata->crypto_tx_tailroom_pending_dec = 0;
ieee80211_debugfs_key_remove_mgmt_default(sdata); ieee80211_debugfs_key_remove_mgmt_default(sdata);
...@@ -709,6 +760,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, ...@@ -709,6 +760,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
{ {
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_sub_if_data *vlan; struct ieee80211_sub_if_data *vlan;
struct ieee80211_sub_if_data *master;
struct ieee80211_key *key, *tmp; struct ieee80211_key *key, *tmp;
LIST_HEAD(keys); LIST_HEAD(keys);
...@@ -728,8 +780,20 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, ...@@ -728,8 +780,20 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
list_for_each_entry_safe(key, tmp, &keys, list) list_for_each_entry_safe(key, tmp, &keys, list)
__ieee80211_key_destroy(key, false); __ieee80211_key_destroy(key, false);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
if (sdata->bss) {
master = container_of(sdata->bss,
struct ieee80211_sub_if_data,
u.ap);
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt !=
master->crypto_tx_tailroom_needed_cnt);
}
} else {
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt ||
sdata->crypto_tx_tailroom_pending_dec); sdata->crypto_tx_tailroom_pending_dec);
}
if (sdata->vif.type == NL80211_IFTYPE_AP) { if (sdata->vif.type == NL80211_IFTYPE_AP) {
list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt || WARN_ON_ONCE(vlan->crypto_tx_tailroom_needed_cnt ||
...@@ -793,8 +857,8 @@ void ieee80211_delayed_tailroom_dec(struct work_struct *wk) ...@@ -793,8 +857,8 @@ void ieee80211_delayed_tailroom_dec(struct work_struct *wk)
*/ */
mutex_lock(&sdata->local->key_mtx); mutex_lock(&sdata->local->key_mtx);
sdata->crypto_tx_tailroom_needed_cnt -= decrease_tailroom_need_count(sdata,
sdata->crypto_tx_tailroom_pending_dec; sdata->crypto_tx_tailroom_pending_dec);
sdata->crypto_tx_tailroom_pending_dec = 0; sdata->crypto_tx_tailroom_pending_dec = 0;
mutex_unlock(&sdata->local->key_mtx); mutex_unlock(&sdata->local->key_mtx);
} }
......
...@@ -161,6 +161,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata, ...@@ -161,6 +161,7 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
void ieee80211_free_sta_keys(struct ieee80211_local *local, void ieee80211_free_sta_keys(struct ieee80211_local *local,
struct sta_info *sta); struct sta_info *sta);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_reset_crypto_tx_tailroom(struct ieee80211_sub_if_data *sdata);
#define key_mtx_dereference(local, ref) \ #define key_mtx_dereference(local, ref) \
rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx))) rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
......
...@@ -2121,7 +2121,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) ...@@ -2121,7 +2121,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
/* deliver to local stack */ /* deliver to local stack */
skb->protocol = eth_type_trans(skb, dev); skb->protocol = eth_type_trans(skb, dev);
memset(skb->cb, 0, sizeof(skb->cb)); memset(skb->cb, 0, sizeof(skb->cb));
if (rx->local->napi) if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) &&
rx->local->napi)
napi_gro_receive(rx->local->napi, skb); napi_gro_receive(rx->local->napi, skb);
else else
netif_receive_skb(skb); netif_receive_skb(skb);
...@@ -3231,7 +3232,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) ...@@ -3231,7 +3232,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
/* This is OK -- must be QoS data frame */ /* This is OK -- must be QoS data frame */
.security_idx = tid, .security_idx = tid,
.seqno_idx = tid, .seqno_idx = tid,
.flags = 0, .flags = IEEE80211_RX_REORDER_TIMER,
}; };
struct tid_ampdu_rx *tid_agg_rx; struct tid_ampdu_rx *tid_agg_rx;
......
...@@ -2022,6 +2022,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) ...@@ -2022,6 +2022,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
/* add back keys */ /* add back keys */
list_for_each_entry(sdata, &local->interfaces, list)
ieee80211_reset_crypto_tx_tailroom(sdata);
list_for_each_entry(sdata, &local->interfaces, list) list_for_each_entry(sdata, &local->interfaces, list)
if (ieee80211_sdata_running(sdata)) if (ieee80211_sdata_running(sdata))
ieee80211_enable_keys(sdata); ieee80211_enable_keys(sdata);
......
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