Commit f9dca80b authored by Michal Kazior's avatar Michal Kazior Committed by Johannes Berg

mac80211: fix AP_VLAN crypto tailroom calculation

Some splats I was seeing:

 (a) WARNING: CPU: 1 PID: 0 at /devel/src/linux/net/mac80211/wep.c:102 ieee80211_wep_add_iv
 (b) WARNING: CPU: 1 PID: 0 at /devel/src/linux/net/mac80211/wpa.c:73 ieee80211_tx_h_michael_mic_add
 (c) WARNING: CPU: 3 PID: 0 at /devel/src/linux/net/mac80211/wpa.c:433 ieee80211_crypto_ccmp_encrypt

I've seen (a) and (b) with ath9k hw crypto and (c)
with ath9k sw crypto. All of them were related to
insufficient skb tailroom and I was able to
trigger these with ping6 program.

AP_VLANs may inherit crypto keys from parent AP.
This wasn't considered and yielded problems in
some setups resulting in inability to transmit
data because mac80211 wouldn't resize skbs when
necessary and subsequently drop some packets due
to insufficient tailroom.

For efficiency purposes don't inspect both AP_VLAN
and AP sdata looking for tailroom counter. Instead
update AP_VLAN tailroom counters whenever their
master AP tailroom counter changes.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 252ec2b3
...@@ -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);
WARN_ON_ONCE(sdata->crypto_tx_tailroom_needed_cnt || if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
sdata->crypto_tx_tailroom_pending_dec); 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 ||
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)))
......
...@@ -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