aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
authorGuy Eilam <guy@wizery.com>2011-08-17 08:18:15 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-26 10:47:55 -0400
commit2a33bee2753bf28411de8822e3e3c7501966eb1b (patch)
treedac6419b65bdd79da56c6855bbf4a439f424e05c /net/mac80211/sta_info.c
parent8c71df7a2f6a5345d6cad34e810c50edeca81521 (diff)
mac80211: fix race condition between assoc_done and first EAP packet
When associating to an AP, the station might miss the first EAP packet that the AP sends due to a race condition between the association success procedure and the rx flow in mac80211. In such cases, the packet might fall in ieee80211_rx_h_check due to the fact that the relevant rx->sta wasn't allocated yet. Allocation of the relevant station info struct before actually sending the association request and setting it with a new dummy_sta flag solve this problem. The station will accept only EAP packets from the AP while it is in the pre-association/dummy state. This dummy station entry is not seen by normal sta_info_get() calls, only by sta_info_get_bss_rx(). The driver is not notified for the first insertion of the dummy station. The driver is notified only after the association is complete and the dummy flag is removed from the station entry. That way, all the rest of the code flow should be untouched by this change. Signed-off-by: Guy Eilam <guy@wizery.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/sta_info.c')
-rw-r--r--net/mac80211/sta_info.c186
1 files changed, 137 insertions, 49 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d469d9d2b499..17caba27040b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -100,6 +100,27 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
100 lockdep_is_held(&local->sta_lock) || 100 lockdep_is_held(&local->sta_lock) ||
101 lockdep_is_held(&local->sta_mtx)); 101 lockdep_is_held(&local->sta_mtx));
102 while (sta) { 102 while (sta) {
103 if (sta->sdata == sdata && !sta->dummy &&
104 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
105 break;
106 sta = rcu_dereference_check(sta->hnext,
107 lockdep_is_held(&local->sta_lock) ||
108 lockdep_is_held(&local->sta_mtx));
109 }
110 return sta;
111}
112
113/* get a station info entry even if it is a dummy station*/
114struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
115 const u8 *addr)
116{
117 struct ieee80211_local *local = sdata->local;
118 struct sta_info *sta;
119
120 sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
121 lockdep_is_held(&local->sta_lock) ||
122 lockdep_is_held(&local->sta_mtx));
123 while (sta) {
103 if (sta->sdata == sdata && 124 if (sta->sdata == sdata &&
104 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) 125 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
105 break; 126 break;
@@ -126,6 +147,32 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
126 while (sta) { 147 while (sta) {
127 if ((sta->sdata == sdata || 148 if ((sta->sdata == sdata ||
128 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) && 149 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
150 !sta->dummy &&
151 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
152 break;
153 sta = rcu_dereference_check(sta->hnext,
154 lockdep_is_held(&local->sta_lock) ||
155 lockdep_is_held(&local->sta_mtx));
156 }
157 return sta;
158}
159
160/*
161 * Get sta info either from the specified interface
162 * or from one of its vlans (including dummy stations)
163 */
164struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
165 const u8 *addr)
166{
167 struct ieee80211_local *local = sdata->local;
168 struct sta_info *sta;
169
170 sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
171 lockdep_is_held(&local->sta_lock) ||
172 lockdep_is_held(&local->sta_mtx));
173 while (sta) {
174 if ((sta->sdata == sdata ||
175 (sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
129 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0) 176 memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
130 break; 177 break;
131 sta = rcu_dereference_check(sta->hnext, 178 sta = rcu_dereference_check(sta->hnext,
@@ -280,7 +327,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
280 return sta; 327 return sta;
281} 328}
282 329
283static int sta_info_finish_insert(struct sta_info *sta, bool async) 330static int sta_info_finish_insert(struct sta_info *sta,
331 bool async, bool dummy_reinsert)
284{ 332{
285 struct ieee80211_local *local = sta->local; 333 struct ieee80211_local *local = sta->local;
286 struct ieee80211_sub_if_data *sdata = sta->sdata; 334 struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -290,51 +338,58 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async)
290 338
291 lockdep_assert_held(&local->sta_mtx); 339 lockdep_assert_held(&local->sta_mtx);
292 340
293 /* notify driver */ 341 if (!sta->dummy || dummy_reinsert) {
294 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) 342 /* notify driver */
295 sdata = container_of(sdata->bss, 343 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
296 struct ieee80211_sub_if_data, 344 sdata = container_of(sdata->bss,
297 u.ap); 345 struct ieee80211_sub_if_data,
298 err = drv_sta_add(local, sdata, &sta->sta); 346 u.ap);
299 if (err) { 347 err = drv_sta_add(local, sdata, &sta->sta);
300 if (!async) 348 if (err) {
301 return err; 349 if (!async)
302 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to driver (%d)" 350 return err;
303 " - keeping it anyway.\n", 351 printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
304 sdata->name, sta->sta.addr, err); 352 "driver (%d) - keeping it anyway.\n",
305 } else { 353 sdata->name, sta->sta.addr, err);
306 sta->uploaded = true; 354 } else {
355 sta->uploaded = true;
307#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 356#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
308 if (async) 357 if (async)
309 wiphy_debug(local->hw.wiphy, 358 wiphy_debug(local->hw.wiphy,
310 "Finished adding IBSS STA %pM\n", 359 "Finished adding IBSS STA %pM\n",
311 sta->sta.addr); 360 sta->sta.addr);
312#endif 361#endif
362 }
363
364 sdata = sta->sdata;
313 } 365 }
314 366
315 sdata = sta->sdata; 367 if (!dummy_reinsert) {
368 if (!async) {
369 local->num_sta++;
370 local->sta_generation++;
371 smp_mb();
316 372
317 if (!async) { 373 /* make the station visible */
318 local->num_sta++; 374 spin_lock_irqsave(&local->sta_lock, flags);
319 local->sta_generation++; 375 sta_info_hash_add(local, sta);
320 smp_mb(); 376 spin_unlock_irqrestore(&local->sta_lock, flags);
377 }
321 378
322 /* make the station visible */ 379 list_add(&sta->list, &local->sta_list);
323 spin_lock_irqsave(&local->sta_lock, flags); 380 } else {
324 sta_info_hash_add(local, sta); 381 sta->dummy = false;
325 spin_unlock_irqrestore(&local->sta_lock, flags);
326 } 382 }
327 383
328 list_add(&sta->list, &local->sta_list); 384 if (!sta->dummy) {
329 385 ieee80211_sta_debugfs_add(sta);
330 ieee80211_sta_debugfs_add(sta); 386 rate_control_add_sta_debugfs(sta);
331 rate_control_add_sta_debugfs(sta);
332
333 memset(&sinfo, 0, sizeof(sinfo));
334 sinfo.filled = 0;
335 sinfo.generation = local->sta_generation;
336 cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
337 387
388 memset(&sinfo, 0, sizeof(sinfo));
389 sinfo.filled = 0;
390 sinfo.generation = local->sta_generation;
391 cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
392 }
338 393
339 return 0; 394 return 0;
340} 395}
@@ -351,7 +406,7 @@ static void sta_info_finish_pending(struct ieee80211_local *local)
351 list_del(&sta->list); 406 list_del(&sta->list);
352 spin_unlock_irqrestore(&local->sta_lock, flags); 407 spin_unlock_irqrestore(&local->sta_lock, flags);
353 408
354 sta_info_finish_insert(sta, true); 409 sta_info_finish_insert(sta, true, false);
355 410
356 spin_lock_irqsave(&local->sta_lock, flags); 411 spin_lock_irqsave(&local->sta_lock, flags);
357 } 412 }
@@ -395,7 +450,7 @@ static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
395 450
396 spin_lock_irqsave(&local->sta_lock, flags); 451 spin_lock_irqsave(&local->sta_lock, flags);
397 /* check if STA exists already */ 452 /* check if STA exists already */
398 if (sta_info_get_bss(sdata, sta->sta.addr)) { 453 if (sta_info_get_bss_rx(sdata, sta->sta.addr)) {
399 spin_unlock_irqrestore(&local->sta_lock, flags); 454 spin_unlock_irqrestore(&local->sta_lock, flags);
400 rcu_read_lock(); 455 rcu_read_lock();
401 return -EEXIST; 456 return -EEXIST;
@@ -431,6 +486,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
431 struct ieee80211_local *local = sta->local; 486 struct ieee80211_local *local = sta->local;
432 struct ieee80211_sub_if_data *sdata = sta->sdata; 487 struct ieee80211_sub_if_data *sdata = sta->sdata;
433 unsigned long flags; 488 unsigned long flags;
489 struct sta_info *exist_sta;
490 bool dummy_reinsert = false;
434 int err = 0; 491 int err = 0;
435 492
436 lockdep_assert_held(&local->sta_mtx); 493 lockdep_assert_held(&local->sta_mtx);
@@ -446,17 +503,28 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
446 */ 503 */
447 504
448 spin_lock_irqsave(&local->sta_lock, flags); 505 spin_lock_irqsave(&local->sta_lock, flags);
449 /* check if STA exists already */ 506 /*
450 if (sta_info_get_bss(sdata, sta->sta.addr)) { 507 * check if STA exists already.
451 spin_unlock_irqrestore(&local->sta_lock, flags); 508 * only accept a scenario of a second call to sta_info_insert_non_ibss
452 mutex_unlock(&local->sta_mtx); 509 * with a dummy station entry that was inserted earlier
453 rcu_read_lock(); 510 * in that case - assume that the dummy station flag should
454 return -EEXIST; 511 * be removed.
512 */
513 exist_sta = sta_info_get_bss_rx(sdata, sta->sta.addr);
514 if (exist_sta) {
515 if (exist_sta == sta && sta->dummy) {
516 dummy_reinsert = true;
517 } else {
518 spin_unlock_irqrestore(&local->sta_lock, flags);
519 mutex_unlock(&local->sta_mtx);
520 rcu_read_lock();
521 return -EEXIST;
522 }
455 } 523 }
456 524
457 spin_unlock_irqrestore(&local->sta_lock, flags); 525 spin_unlock_irqrestore(&local->sta_lock, flags);
458 526
459 err = sta_info_finish_insert(sta, false); 527 err = sta_info_finish_insert(sta, false, dummy_reinsert);
460 if (err) { 528 if (err) {
461 mutex_unlock(&local->sta_mtx); 529 mutex_unlock(&local->sta_mtx);
462 rcu_read_lock(); 530 rcu_read_lock();
@@ -464,7 +532,8 @@ static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
464 } 532 }
465 533
466#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 534#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
467 wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); 535 wiphy_debug(local->hw.wiphy, "Inserted %sSTA %pM\n",
536 sta->dummy ? "dummy " : "", sta->sta.addr);
468#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 537#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
469 538
470 /* move reference to rcu-protected */ 539 /* move reference to rcu-protected */
@@ -535,6 +604,25 @@ int sta_info_insert(struct sta_info *sta)
535 return err; 604 return err;
536} 605}
537 606
607/* Caller must hold sta->local->sta_mtx */
608int sta_info_reinsert(struct sta_info *sta)
609{
610 struct ieee80211_local *local = sta->local;
611 int err = 0;
612
613 err = sta_info_insert_check(sta);
614 if (err) {
615 mutex_unlock(&local->sta_mtx);
616 return err;
617 }
618
619 might_sleep();
620
621 err = sta_info_insert_non_ibss(sta);
622 rcu_read_unlock();
623 return err;
624}
625
538static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) 626static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid)
539{ 627{
540 /* 628 /*
@@ -775,7 +863,7 @@ int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata, const u8 *addr)
775 int ret; 863 int ret;
776 864
777 mutex_lock(&sdata->local->sta_mtx); 865 mutex_lock(&sdata->local->sta_mtx);
778 sta = sta_info_get(sdata, addr); 866 sta = sta_info_get_rx(sdata, addr);
779 ret = __sta_info_destroy(sta); 867 ret = __sta_info_destroy(sta);
780 mutex_unlock(&sdata->local->sta_mtx); 868 mutex_unlock(&sdata->local->sta_mtx);
781 869
@@ -789,7 +877,7 @@ int sta_info_destroy_addr_bss(struct ieee80211_sub_if_data *sdata,
789 int ret; 877 int ret;
790 878
791 mutex_lock(&sdata->local->sta_mtx); 879 mutex_lock(&sdata->local->sta_mtx);
792 sta = sta_info_get_bss(sdata, addr); 880 sta = sta_info_get_bss_rx(sdata, addr);
793 ret = __sta_info_destroy(sta); 881 ret = __sta_info_destroy(sta);
794 mutex_unlock(&sdata->local->sta_mtx); 882 mutex_unlock(&sdata->local->sta_mtx);
795 883