aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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);