Browse Source

mac80211: properly deal with station hashtable insert errors

The original hand-implemented hash-table in mac80211 couldn't result
in insertion errors, and while converting to rhashtable I evidently
forgot to check the errors.

This surfaced now only because Ben is adding many identical keys and
that resulted in hidden insertion errors.

Cc: stable@vger.kernel.org
Fixes: 7bedd0cfad4e1 ("mac80211: use rhashtable for station table")
Reported-by: Ben Greear <greearb@candelatech.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Johannes Berg 9 years ago
parent
commit
62b14b241c
1 changed files with 8 additions and 5 deletions
  1. 8 5
      net/mac80211/sta_info.c

+ 8 - 5
net/mac80211/sta_info.c

@@ -258,11 +258,11 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
 }
 }
 
 
 /* Caller must hold local->sta_mtx */
 /* Caller must hold local->sta_mtx */
-static void sta_info_hash_add(struct ieee80211_local *local,
-			      struct sta_info *sta)
+static int sta_info_hash_add(struct ieee80211_local *local,
+			     struct sta_info *sta)
 {
 {
-	rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
-			       sta_rht_params);
+	return rhashtable_insert_fast(&local->sta_hash, &sta->hash_node,
+				      sta_rht_params);
 }
 }
 
 
 static void sta_deliver_ps_frames(struct work_struct *wk)
 static void sta_deliver_ps_frames(struct work_struct *wk)
@@ -524,7 +524,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
 	set_sta_flag(sta, WLAN_STA_BLOCK_BA);
 	set_sta_flag(sta, WLAN_STA_BLOCK_BA);
 
 
 	/* make the station visible */
 	/* make the station visible */
-	sta_info_hash_add(local, sta);
+	err = sta_info_hash_add(local, sta);
+	if (err)
+		goto out_drop_sta;
 
 
 	list_add_tail_rcu(&sta->list, &local->sta_list);
 	list_add_tail_rcu(&sta->list, &local->sta_list);
 
 
@@ -557,6 +559,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
  out_remove:
  out_remove:
 	sta_info_hash_del(local, sta);
 	sta_info_hash_del(local, sta);
 	list_del_rcu(&sta->list);
 	list_del_rcu(&sta->list);
+ out_drop_sta:
 	local->num_sta--;
 	local->num_sta--;
 	synchronize_net();
 	synchronize_net();
 	__cleanup_single_sta(sta);
 	__cleanup_single_sta(sta);