diff options
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 157 |
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) | |||
249 | static struct mesh_path * | 251 | static 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 | ||
537 | static void mesh_path_free_rcu(struct mesh_table *tbl, | 523 | static 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 | ||
552 | static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) | 538 | static 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 | ||
597 | static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, | 571 | static 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 | ||
625 | static void table_flush_by_iface(struct mesh_table *tbl) | 586 | static 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 | ||
881 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) | 818 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata) |