aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/sta_info.c
diff options
context:
space:
mode:
authorGuy Eilam <guy@wizery.com>2011-08-17 08:18:14 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-08-26 10:47:55 -0400
commit8c71df7a2f6a5345d6cad34e810c50edeca81521 (patch)
treec64802718da405531fdf5e5c56028320ae449217 /net/mac80211/sta_info.c
parentdf766267c8d8d71acb0b23575250cac718c6b711 (diff)
mac80211: refactor sta_info_insert_rcu to 3 main stages
Divided the sta_info_insert_rcu function to 3 mini-functions: sta_info_insert_check - the initial checks done when inserting a new station sta_info_insert_ibss - the function that handles the station addition for IBSS interfaces sta_info_insert_non_ibss - the function that handles the station addition in other cases The outer API was not changed. The refactoring was done for better usage of the different stages in the station addition in new scenarios added in the next commit. 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.c148
1 files changed, 95 insertions, 53 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 5eaa1673a8f5..d469d9d2b499 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -368,93 +368,90 @@ static void sta_info_finish_work(struct work_struct *work)
368 mutex_unlock(&local->sta_mtx); 368 mutex_unlock(&local->sta_mtx);
369} 369}
370 370
371int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU) 371static int sta_info_insert_check(struct sta_info *sta)
372{ 372{
373 struct ieee80211_local *local = sta->local;
374 struct ieee80211_sub_if_data *sdata = sta->sdata; 373 struct ieee80211_sub_if_data *sdata = sta->sdata;
375 unsigned long flags;
376 int err = 0;
377 374
378 /* 375 /*
379 * Can't be a WARN_ON because it can be triggered through a race: 376 * Can't be a WARN_ON because it can be triggered through a race:
380 * something inserts a STA (on one CPU) without holding the RTNL 377 * something inserts a STA (on one CPU) without holding the RTNL
381 * and another CPU turns off the net device. 378 * and another CPU turns off the net device.
382 */ 379 */
383 if (unlikely(!ieee80211_sdata_running(sdata))) { 380 if (unlikely(!ieee80211_sdata_running(sdata)))
384 err = -ENETDOWN; 381 return -ENETDOWN;
385 rcu_read_lock();
386 goto out_free;
387 }
388 382
389 if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 || 383 if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
390 is_multicast_ether_addr(sta->sta.addr))) { 384 is_multicast_ether_addr(sta->sta.addr)))
391 err = -EINVAL; 385 return -EINVAL;
386
387 return 0;
388}
389
390static int sta_info_insert_ibss(struct sta_info *sta) __acquires(RCU)
391{
392 struct ieee80211_local *local = sta->local;
393 struct ieee80211_sub_if_data *sdata = sta->sdata;
394 unsigned long flags;
395
396 spin_lock_irqsave(&local->sta_lock, flags);
397 /* check if STA exists already */
398 if (sta_info_get_bss(sdata, sta->sta.addr)) {
399 spin_unlock_irqrestore(&local->sta_lock, flags);
392 rcu_read_lock(); 400 rcu_read_lock();
393 goto out_free; 401 return -EEXIST;
394 } 402 }
395 403
396 /* 404 local->num_sta++;
397 * In ad-hoc mode, we sometimes need to insert stations 405 local->sta_generation++;
398 * from tasklet context from the RX path. To avoid races, 406 smp_mb();
399 * always do so in that case -- see the comment below. 407 sta_info_hash_add(local, sta);
400 */
401 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
402 spin_lock_irqsave(&local->sta_lock, flags);
403 /* check if STA exists already */
404 if (sta_info_get_bss(sdata, sta->sta.addr)) {
405 spin_unlock_irqrestore(&local->sta_lock, flags);
406 rcu_read_lock();
407 err = -EEXIST;
408 goto out_free;
409 }
410
411 local->num_sta++;
412 local->sta_generation++;
413 smp_mb();
414 sta_info_hash_add(local, sta);
415 408
416 list_add_tail(&sta->list, &local->sta_pending_list); 409 list_add_tail(&sta->list, &local->sta_pending_list);
417 410
418 rcu_read_lock(); 411 rcu_read_lock();
419 spin_unlock_irqrestore(&local->sta_lock, flags); 412 spin_unlock_irqrestore(&local->sta_lock, flags);
420 413
421#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 414#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
422 wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n", 415 wiphy_debug(local->hw.wiphy, "Added IBSS STA %pM\n",
423 sta->sta.addr); 416 sta->sta.addr);
424#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 417#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
425 418
426 ieee80211_queue_work(&local->hw, &local->sta_finish_work); 419 ieee80211_queue_work(&local->hw, &local->sta_finish_work);
427 420
428 return 0; 421 return 0;
429 } 422}
423
424/*
425 * should be called with sta_mtx locked
426 * this function replaces the mutex lock
427 * with a RCU lock
428 */
429static int sta_info_insert_non_ibss(struct sta_info *sta) __acquires(RCU)
430{
431 struct ieee80211_local *local = sta->local;
432 struct ieee80211_sub_if_data *sdata = sta->sdata;
433 unsigned long flags;
434 int err = 0;
435
436 lockdep_assert_held(&local->sta_mtx);
430 437
431 /* 438 /*
432 * On first glance, this will look racy, because the code 439 * On first glance, this will look racy, because the code
433 * below this point, which inserts a station with sleeping, 440 * in this function, which inserts a station with sleeping,
434 * unlocks the sta_lock between checking existence in the 441 * unlocks the sta_lock between checking existence in the
435 * hash table and inserting into it. 442 * hash table and inserting into it.
436 * 443 *
437 * However, it is not racy against itself because it keeps 444 * However, it is not racy against itself because it keeps
438 * the mutex locked. It still seems to race against the 445 * the mutex locked.
439 * above code that atomically inserts the station... That,
440 * however, is not true because the above code can only
441 * be invoked for IBSS interfaces, and the below code will
442 * not be -- and the two do not race against each other as
443 * the hash table also keys off the interface.
444 */ 446 */
445 447
446 might_sleep();
447
448 mutex_lock(&local->sta_mtx);
449
450 spin_lock_irqsave(&local->sta_lock, flags); 448 spin_lock_irqsave(&local->sta_lock, flags);
451 /* check if STA exists already */ 449 /* check if STA exists already */
452 if (sta_info_get_bss(sdata, sta->sta.addr)) { 450 if (sta_info_get_bss(sdata, sta->sta.addr)) {
453 spin_unlock_irqrestore(&local->sta_lock, flags); 451 spin_unlock_irqrestore(&local->sta_lock, flags);
454 mutex_unlock(&local->sta_mtx); 452 mutex_unlock(&local->sta_mtx);
455 rcu_read_lock(); 453 rcu_read_lock();
456 err = -EEXIST; 454 return -EEXIST;
457 goto out_free;
458 } 455 }
459 456
460 spin_unlock_irqrestore(&local->sta_lock, flags); 457 spin_unlock_irqrestore(&local->sta_lock, flags);
@@ -463,7 +460,7 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
463 if (err) { 460 if (err) {
464 mutex_unlock(&local->sta_mtx); 461 mutex_unlock(&local->sta_mtx);
465 rcu_read_lock(); 462 rcu_read_lock();
466 goto out_free; 463 return err;
467 } 464 }
468 465
469#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 466#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -478,6 +475,51 @@ int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
478 mesh_accept_plinks_update(sdata); 475 mesh_accept_plinks_update(sdata);
479 476
480 return 0; 477 return 0;
478}
479
480int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU)
481{
482 struct ieee80211_local *local = sta->local;
483 struct ieee80211_sub_if_data *sdata = sta->sdata;
484 int err = 0;
485
486 err = sta_info_insert_check(sta);
487 if (err) {
488 rcu_read_lock();
489 goto out_free;
490 }
491
492 /*
493 * In ad-hoc mode, we sometimes need to insert stations
494 * from tasklet context from the RX path. To avoid races,
495 * always do so in that case -- see the comment below.
496 */
497 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
498 err = sta_info_insert_ibss(sta);
499 if (err)
500 goto out_free;
501
502 return 0;
503 }
504
505 /*
506 * It might seem that the function called below is in race against
507 * the function call above that atomically inserts the station... That,
508 * however, is not true because the above code can only
509 * be invoked for IBSS interfaces, and the below code will
510 * not be -- and the two do not race against each other as
511 * the hash table also keys off the interface.
512 */
513
514 might_sleep();
515
516 mutex_lock(&local->sta_mtx);
517
518 err = sta_info_insert_non_ibss(sta);
519 if (err)
520 goto out_free;
521
522 return 0;
481 out_free: 523 out_free:
482 BUG_ON(!err); 524 BUG_ON(!err);
483 __sta_info_free(local, sta); 525 __sta_info_free(local, sta);