浏览代码

mac80211: free all AP/VLAN keys at once

When the AP interface is stopped, free all AP and VLAN keys at
once to only require synchronize_net() once. Since that does
synchronize_net(), also move two such calls into the function
(using the new force_synchronize parameter) to avoid doing it
twice.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Johannes Berg 11 年之前
父节点
当前提交
7907c7d33c
共有 4 个文件被更改,包括 43 次插入28 次删除
  1. 1 4
      net/mac80211/cfg.c
  2. 8 11
      net/mac80211/iface.c
  3. 32 12
      net/mac80211/key.c
  4. 2 1
      net/mac80211/key.h

+ 1 - 4
net/mac80211/cfg.c

@@ -1098,10 +1098,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 		kfree_rcu(old_probe_resp, rcu_head);
 		kfree_rcu(old_probe_resp, rcu_head);
 
 
 	__sta_info_flush(sdata, true);
 	__sta_info_flush(sdata, true);
-	synchronize_net();
-	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-		ieee80211_free_keys(vlan);
-	ieee80211_free_keys(sdata);
+	ieee80211_free_keys(sdata, true);
 
 
 	sdata->vif.bss_conf.enable_beacon = false;
 	sdata->vif.bss_conf.enable_beacon = false;
 	sdata->vif.bss_conf.ssid_len = 0;
 	sdata->vif.bss_conf.ssid_len = 0;

+ 8 - 11
net/mac80211/iface.c

@@ -889,18 +889,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
 		cancel_work_sync(&sdata->work);
 		cancel_work_sync(&sdata->work);
 		/*
 		/*
 		 * When we get here, the interface is marked down.
 		 * When we get here, the interface is marked down.
+		 * Free the remaining keys, if there are any
+		 * (shouldn't be, except maybe in WDS mode?)
 		 *
 		 *
-		 * We need synchronize_rcu() to wait for the RX path in
-		 * case it is using the interface and enqueuing frames
-		 * at this very time on another CPU.
+		 * Force the key freeing to always synchronize_net()
+		 * to wait for the RX path in case it is using this
+		 * interface enqueuing frames * at this very time on
+		 * another CPU.
 		 */
 		 */
-		synchronize_rcu();
-
-		/*
-		 * Free all remaining keys, there shouldn't be any,
-		 * except maybe in WDS mode?
-		 */
-		ieee80211_free_keys(sdata);
+		ieee80211_free_keys(sdata, true);
 
 
 		/* fall through */
 		/* fall through */
 	case NL80211_IFTYPE_AP:
 	case NL80211_IFTYPE_AP:
@@ -1026,7 +1023,7 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
 	int i;
 	int i;
 
 
 	/* free extra data */
 	/* free extra data */
-	ieee80211_free_keys(sdata);
+	ieee80211_free_keys(sdata, false);
 
 
 	ieee80211_debugfs_remove_netdev(sdata);
 	ieee80211_debugfs_remove_netdev(sdata);
 
 

+ 32 - 12
net/mac80211/key.c

@@ -589,14 +589,10 @@ void ieee80211_iter_keys(struct ieee80211_hw *hw,
 }
 }
 EXPORT_SYMBOL(ieee80211_iter_keys);
 EXPORT_SYMBOL(ieee80211_iter_keys);
 
 
-void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_free_keys_iface(struct ieee80211_sub_if_data *sdata,
+				      struct list_head *keys)
 {
 {
 	struct ieee80211_key *key, *tmp;
 	struct ieee80211_key *key, *tmp;
-	LIST_HEAD(keys);
-
-	cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
-
-	mutex_lock(&sdata->local->key_mtx);
 
 
 	sdata->crypto_tx_tailroom_needed_cnt -=
 	sdata->crypto_tx_tailroom_needed_cnt -=
 		sdata->crypto_tx_tailroom_pending_dec;
 		sdata->crypto_tx_tailroom_pending_dec;
@@ -608,21 +604,45 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
 		ieee80211_key_replace(key->sdata, key->sta,
 		ieee80211_key_replace(key->sdata, key->sta,
 				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
 				key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
 				key, NULL);
 				key, NULL);
-		list_add_tail(&key->list, &keys);
+		list_add_tail(&key->list, keys);
 	}
 	}
 
 
 	ieee80211_debugfs_key_update_default(sdata);
 	ieee80211_debugfs_key_update_default(sdata);
+}
 
 
-	if (!list_empty(&keys)) {
-		synchronize_net();
-		list_for_each_entry_safe(key, tmp, &keys, list)
-			__ieee80211_key_destroy(key, false);
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
+			 bool force_synchronize)
+{
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_sub_if_data *vlan;
+	struct ieee80211_key *key, *tmp;
+	LIST_HEAD(keys);
+
+	cancel_delayed_work_sync(&sdata->dec_tailroom_needed_wk);
+
+	mutex_lock(&local->key_mtx);
+
+	ieee80211_free_keys_iface(sdata, &keys);
+
+	if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
+			ieee80211_free_keys_iface(vlan, &keys);
 	}
 	}
 
 
+	if (!list_empty(&keys) || force_synchronize)
+		synchronize_net();
+	list_for_each_entry_safe(key, tmp, &keys, list)
+		__ieee80211_key_destroy(key, false);
+
 	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) {
+		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);
+	}
 
 
-	mutex_unlock(&sdata->local->key_mtx);
+	mutex_unlock(&local->key_mtx);
 }
 }
 
 
 void ieee80211_free_sta_keys(struct ieee80211_local *local,
 void ieee80211_free_sta_keys(struct ieee80211_local *local,

+ 2 - 1
net/mac80211/key.h

@@ -136,7 +136,8 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
 			       bool uni, bool multi);
 			       bool uni, bool multi);
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
 				    int idx);
 				    int idx);
-void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
+void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata,
+			 bool force_synchronize);
 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);