aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_pathtbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r--net/mac80211/mesh_pathtbl.c157
1 files changed, 47 insertions, 110 deletions
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index a5125624a76d..88a6d5e18ccc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -59,8 +59,10 @@ static struct mesh_table *mesh_table_alloc(void)
59 return NULL; 59 return NULL;
60 60
61 INIT_HLIST_HEAD(&newtbl->known_gates); 61 INIT_HLIST_HEAD(&newtbl->known_gates);
62 INIT_HLIST_HEAD(&newtbl->walk_head);
62 atomic_set(&newtbl->entries, 0); 63 atomic_set(&newtbl->entries, 0);
63 spin_lock_init(&newtbl->gates_lock); 64 spin_lock_init(&newtbl->gates_lock);
65 spin_lock_init(&newtbl->walk_lock);
64 66
65 return newtbl; 67 return newtbl;
66} 68}
@@ -249,28 +251,15 @@ mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
249static struct mesh_path * 251static struct mesh_path *
250__mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx) 252__mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
251{ 253{
252 int i = 0, ret; 254 int i = 0;
253 struct mesh_path *mpath = NULL; 255 struct mesh_path *mpath;
254 struct rhashtable_iter iter;
255
256 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
257 if (ret)
258 return NULL;
259
260 rhashtable_walk_start(&iter);
261 256
262 while ((mpath = rhashtable_walk_next(&iter))) { 257 hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) {
263 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
264 continue;
265 if (IS_ERR(mpath))
266 break;
267 if (i++ == idx) 258 if (i++ == idx)
268 break; 259 break;
269 } 260 }
270 rhashtable_walk_stop(&iter);
271 rhashtable_walk_exit(&iter);
272 261
273 if (IS_ERR(mpath) || !mpath) 262 if (!mpath)
274 return NULL; 263 return NULL;
275 264
276 if (mpath_expired(mpath)) { 265 if (mpath_expired(mpath)) {
@@ -432,6 +421,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
432 return ERR_PTR(-ENOMEM); 421 return ERR_PTR(-ENOMEM);
433 422
434 tbl = sdata->u.mesh.mesh_paths; 423 tbl = sdata->u.mesh.mesh_paths;
424 spin_lock_bh(&tbl->walk_lock);
435 do { 425 do {
436 ret = rhashtable_lookup_insert_fast(&tbl->rhead, 426 ret = rhashtable_lookup_insert_fast(&tbl->rhead,
437 &new_mpath->rhash, 427 &new_mpath->rhash,
@@ -441,20 +431,20 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
441 mpath = rhashtable_lookup_fast(&tbl->rhead, 431 mpath = rhashtable_lookup_fast(&tbl->rhead,
442 dst, 432 dst,
443 mesh_rht_params); 433 mesh_rht_params);
444 434 else if (!ret)
435 hlist_add_head(&new_mpath->walk_list, &tbl->walk_head);
445 } while (unlikely(ret == -EEXIST && !mpath)); 436 } while (unlikely(ret == -EEXIST && !mpath));
437 spin_unlock_bh(&tbl->walk_lock);
446 438
447 if (ret && ret != -EEXIST) 439 if (ret) {
448 return ERR_PTR(ret);
449
450 /* At this point either new_mpath was added, or we found a
451 * matching entry already in the table; in the latter case
452 * free the unnecessary new entry.
453 */
454 if (ret == -EEXIST) {
455 kfree(new_mpath); 440 kfree(new_mpath);
441
442 if (ret != -EEXIST)
443 return ERR_PTR(ret);
444
456 new_mpath = mpath; 445 new_mpath = mpath;
457 } 446 }
447
458 sdata->u.mesh.mesh_paths_generation++; 448 sdata->u.mesh.mesh_paths_generation++;
459 return new_mpath; 449 return new_mpath;
460} 450}
@@ -480,9 +470,17 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
480 470
481 memcpy(new_mpath->mpp, mpp, ETH_ALEN); 471 memcpy(new_mpath->mpp, mpp, ETH_ALEN);
482 tbl = sdata->u.mesh.mpp_paths; 472 tbl = sdata->u.mesh.mpp_paths;
473
474 spin_lock_bh(&tbl->walk_lock);
483 ret = rhashtable_lookup_insert_fast(&tbl->rhead, 475 ret = rhashtable_lookup_insert_fast(&tbl->rhead,
484 &new_mpath->rhash, 476 &new_mpath->rhash,
485 mesh_rht_params); 477 mesh_rht_params);
478 if (!ret)
479 hlist_add_head_rcu(&new_mpath->walk_list, &tbl->walk_head);
480 spin_unlock_bh(&tbl->walk_lock);
481
482 if (ret)
483 kfree(new_mpath);
486 484
487 sdata->u.mesh.mpp_paths_generation++; 485 sdata->u.mesh.mpp_paths_generation++;
488 return ret; 486 return ret;
@@ -503,20 +501,9 @@ void mesh_plink_broken(struct sta_info *sta)
503 struct mesh_table *tbl = sdata->u.mesh.mesh_paths; 501 struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
504 static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 502 static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
505 struct mesh_path *mpath; 503 struct mesh_path *mpath;
506 struct rhashtable_iter iter;
507 int ret;
508
509 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
510 if (ret)
511 return;
512 504
513 rhashtable_walk_start(&iter); 505 rcu_read_lock();
514 506 hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) {
515 while ((mpath = rhashtable_walk_next(&iter))) {
516 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
517 continue;
518 if (IS_ERR(mpath))
519 break;
520 if (rcu_access_pointer(mpath->next_hop) == sta && 507 if (rcu_access_pointer(mpath->next_hop) == sta &&
521 mpath->flags & MESH_PATH_ACTIVE && 508 mpath->flags & MESH_PATH_ACTIVE &&
522 !(mpath->flags & MESH_PATH_FIXED)) { 509 !(mpath->flags & MESH_PATH_FIXED)) {
@@ -530,8 +517,7 @@ void mesh_plink_broken(struct sta_info *sta)
530 WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); 517 WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
531 } 518 }
532 } 519 }
533 rhashtable_walk_stop(&iter); 520 rcu_read_unlock();
534 rhashtable_walk_exit(&iter);
535} 521}
536 522
537static void mesh_path_free_rcu(struct mesh_table *tbl, 523static void mesh_path_free_rcu(struct mesh_table *tbl,
@@ -551,6 +537,7 @@ static void mesh_path_free_rcu(struct mesh_table *tbl,
551 537
552static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) 538static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
553{ 539{
540 hlist_del_rcu(&mpath->walk_list);
554 rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params); 541 rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params);
555 mesh_path_free_rcu(tbl, mpath); 542 mesh_path_free_rcu(tbl, mpath);
556} 543}
@@ -571,27 +558,14 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
571 struct ieee80211_sub_if_data *sdata = sta->sdata; 558 struct ieee80211_sub_if_data *sdata = sta->sdata;
572 struct mesh_table *tbl = sdata->u.mesh.mesh_paths; 559 struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
573 struct mesh_path *mpath; 560 struct mesh_path *mpath;
574 struct rhashtable_iter iter; 561 struct hlist_node *n;
575 int ret;
576
577 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
578 if (ret)
579 return;
580
581 rhashtable_walk_start(&iter);
582
583 while ((mpath = rhashtable_walk_next(&iter))) {
584 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
585 continue;
586 if (IS_ERR(mpath))
587 break;
588 562
563 spin_lock_bh(&tbl->walk_lock);
564 hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
589 if (rcu_access_pointer(mpath->next_hop) == sta) 565 if (rcu_access_pointer(mpath->next_hop) == sta)
590 __mesh_path_del(tbl, mpath); 566 __mesh_path_del(tbl, mpath);
591 } 567 }
592 568 spin_unlock_bh(&tbl->walk_lock);
593 rhashtable_walk_stop(&iter);
594 rhashtable_walk_exit(&iter);
595} 569}
596 570
597static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, 571static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
@@ -599,51 +573,26 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
599{ 573{
600 struct mesh_table *tbl = sdata->u.mesh.mpp_paths; 574 struct mesh_table *tbl = sdata->u.mesh.mpp_paths;
601 struct mesh_path *mpath; 575 struct mesh_path *mpath;
602 struct rhashtable_iter iter; 576 struct hlist_node *n;
603 int ret;
604
605 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
606 if (ret)
607 return;
608
609 rhashtable_walk_start(&iter);
610
611 while ((mpath = rhashtable_walk_next(&iter))) {
612 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
613 continue;
614 if (IS_ERR(mpath))
615 break;
616 577
578 spin_lock_bh(&tbl->walk_lock);
579 hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
617 if (ether_addr_equal(mpath->mpp, proxy)) 580 if (ether_addr_equal(mpath->mpp, proxy))
618 __mesh_path_del(tbl, mpath); 581 __mesh_path_del(tbl, mpath);
619 } 582 }
620 583 spin_unlock_bh(&tbl->walk_lock);
621 rhashtable_walk_stop(&iter);
622 rhashtable_walk_exit(&iter);
623} 584}
624 585
625static void table_flush_by_iface(struct mesh_table *tbl) 586static void table_flush_by_iface(struct mesh_table *tbl)
626{ 587{
627 struct mesh_path *mpath; 588 struct mesh_path *mpath;
628 struct rhashtable_iter iter; 589 struct hlist_node *n;
629 int ret;
630
631 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
632 if (ret)
633 return;
634
635 rhashtable_walk_start(&iter);
636 590
637 while ((mpath = rhashtable_walk_next(&iter))) { 591 spin_lock_bh(&tbl->walk_lock);
638 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) 592 hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
639 continue;
640 if (IS_ERR(mpath))
641 break;
642 __mesh_path_del(tbl, mpath); 593 __mesh_path_del(tbl, mpath);
643 } 594 }
644 595 spin_unlock_bh(&tbl->walk_lock);
645 rhashtable_walk_stop(&iter);
646 rhashtable_walk_exit(&iter);
647} 596}
648 597
649/** 598/**
@@ -675,15 +624,15 @@ static int table_path_del(struct mesh_table *tbl,
675{ 624{
676 struct mesh_path *mpath; 625 struct mesh_path *mpath;
677 626
678 rcu_read_lock(); 627 spin_lock_bh(&tbl->walk_lock);
679 mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params); 628 mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params);
680 if (!mpath) { 629 if (!mpath) {
681 rcu_read_unlock(); 630 spin_unlock_bh(&tbl->walk_lock);
682 return -ENXIO; 631 return -ENXIO;
683 } 632 }
684 633
685 __mesh_path_del(tbl, mpath); 634 __mesh_path_del(tbl, mpath);
686 rcu_read_unlock(); 635 spin_unlock_bh(&tbl->walk_lock);
687 return 0; 636 return 0;
688} 637}
689 638
@@ -854,28 +803,16 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata,
854 struct mesh_table *tbl) 803 struct mesh_table *tbl)
855{ 804{
856 struct mesh_path *mpath; 805 struct mesh_path *mpath;
857 struct rhashtable_iter iter; 806 struct hlist_node *n;
858 int ret;
859 807
860 ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_KERNEL); 808 spin_lock_bh(&tbl->walk_lock);
861 if (ret) 809 hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
862 return;
863
864 rhashtable_walk_start(&iter);
865
866 while ((mpath = rhashtable_walk_next(&iter))) {
867 if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
868 continue;
869 if (IS_ERR(mpath))
870 break;
871 if ((!(mpath->flags & MESH_PATH_RESOLVING)) && 810 if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
872 (!(mpath->flags & MESH_PATH_FIXED)) && 811 (!(mpath->flags & MESH_PATH_FIXED)) &&
873 time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) 812 time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
874 __mesh_path_del(tbl, mpath); 813 __mesh_path_del(tbl, mpath);
875 } 814 }
876 815 spin_unlock_bh(&tbl->walk_lock);
877 rhashtable_walk_stop(&iter);
878 rhashtable_walk_exit(&iter);
879} 816}
880 817
881void mesh_path_expire(struct ieee80211_sub_if_data *sdata) 818void mesh_path_expire(struct ieee80211_sub_if_data *sdata)