diff options
Diffstat (limited to 'net/mac80211/mesh_pathtbl.c')
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 56 |
1 files changed, 28 insertions, 28 deletions
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index dc7c8df40c2c..89aacfd2756d 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -493,7 +493,8 @@ int mesh_gate_num(struct ieee80211_sub_if_data *sdata) | |||
493 | * | 493 | * |
494 | * State: the initial state of the new path is set to 0 | 494 | * State: the initial state of the new path is set to 0 |
495 | */ | 495 | */ |
496 | int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) | 496 | struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, |
497 | const u8 *dst) | ||
497 | { | 498 | { |
498 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 499 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
499 | struct ieee80211_local *local = sdata->local; | 500 | struct ieee80211_local *local = sdata->local; |
@@ -502,18 +503,33 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) | |||
502 | struct mpath_node *node, *new_node; | 503 | struct mpath_node *node, *new_node; |
503 | struct hlist_head *bucket; | 504 | struct hlist_head *bucket; |
504 | int grow = 0; | 505 | int grow = 0; |
505 | int err = 0; | 506 | int err; |
506 | u32 hash_idx; | 507 | u32 hash_idx; |
507 | 508 | ||
508 | if (ether_addr_equal(dst, sdata->vif.addr)) | 509 | if (ether_addr_equal(dst, sdata->vif.addr)) |
509 | /* never add ourselves as neighbours */ | 510 | /* never add ourselves as neighbours */ |
510 | return -ENOTSUPP; | 511 | return ERR_PTR(-ENOTSUPP); |
511 | 512 | ||
512 | if (is_multicast_ether_addr(dst)) | 513 | if (is_multicast_ether_addr(dst)) |
513 | return -ENOTSUPP; | 514 | return ERR_PTR(-ENOTSUPP); |
514 | 515 | ||
515 | if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0) | 516 | if (atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS) == 0) |
516 | return -ENOSPC; | 517 | return ERR_PTR(-ENOSPC); |
518 | |||
519 | read_lock_bh(&pathtbl_resize_lock); | ||
520 | tbl = resize_dereference_mesh_paths(); | ||
521 | |||
522 | hash_idx = mesh_table_hash(dst, sdata, tbl); | ||
523 | bucket = &tbl->hash_buckets[hash_idx]; | ||
524 | |||
525 | spin_lock(&tbl->hashwlock[hash_idx]); | ||
526 | |||
527 | hlist_for_each_entry(node, bucket, list) { | ||
528 | mpath = node->mpath; | ||
529 | if (mpath->sdata == sdata && | ||
530 | ether_addr_equal(dst, mpath->dst)) | ||
531 | goto found; | ||
532 | } | ||
517 | 533 | ||
518 | err = -ENOMEM; | 534 | err = -ENOMEM; |
519 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); | 535 | new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC); |
@@ -524,7 +540,6 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) | |||
524 | if (!new_node) | 540 | if (!new_node) |
525 | goto err_node_alloc; | 541 | goto err_node_alloc; |
526 | 542 | ||
527 | read_lock_bh(&pathtbl_resize_lock); | ||
528 | memcpy(new_mpath->dst, dst, ETH_ALEN); | 543 | memcpy(new_mpath->dst, dst, ETH_ALEN); |
529 | eth_broadcast_addr(new_mpath->rann_snd_addr); | 544 | eth_broadcast_addr(new_mpath->rann_snd_addr); |
530 | new_mpath->is_root = false; | 545 | new_mpath->is_root = false; |
@@ -538,21 +553,6 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) | |||
538 | spin_lock_init(&new_mpath->state_lock); | 553 | spin_lock_init(&new_mpath->state_lock); |
539 | init_timer(&new_mpath->timer); | 554 | init_timer(&new_mpath->timer); |
540 | 555 | ||
541 | tbl = resize_dereference_mesh_paths(); | ||
542 | |||
543 | hash_idx = mesh_table_hash(dst, sdata, tbl); | ||
544 | bucket = &tbl->hash_buckets[hash_idx]; | ||
545 | |||
546 | spin_lock(&tbl->hashwlock[hash_idx]); | ||
547 | |||
548 | err = -EEXIST; | ||
549 | hlist_for_each_entry(node, bucket, list) { | ||
550 | mpath = node->mpath; | ||
551 | if (mpath->sdata == sdata && | ||
552 | ether_addr_equal(dst, mpath->dst)) | ||
553 | goto err_exists; | ||
554 | } | ||
555 | |||
556 | hlist_add_head_rcu(&new_node->list, bucket); | 556 | hlist_add_head_rcu(&new_node->list, bucket); |
557 | if (atomic_inc_return(&tbl->entries) >= | 557 | if (atomic_inc_return(&tbl->entries) >= |
558 | tbl->mean_chain_len * (tbl->hash_mask + 1)) | 558 | tbl->mean_chain_len * (tbl->hash_mask + 1)) |
@@ -560,23 +560,23 @@ int mesh_path_add(struct ieee80211_sub_if_data *sdata, const u8 *dst) | |||
560 | 560 | ||
561 | mesh_paths_generation++; | 561 | mesh_paths_generation++; |
562 | 562 | ||
563 | spin_unlock(&tbl->hashwlock[hash_idx]); | ||
564 | read_unlock_bh(&pathtbl_resize_lock); | ||
565 | if (grow) { | 563 | if (grow) { |
566 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); | 564 | set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags); |
567 | ieee80211_queue_work(&local->hw, &sdata->work); | 565 | ieee80211_queue_work(&local->hw, &sdata->work); |
568 | } | 566 | } |
569 | return 0; | 567 | mpath = new_mpath; |
570 | 568 | found: | |
571 | err_exists: | ||
572 | spin_unlock(&tbl->hashwlock[hash_idx]); | 569 | spin_unlock(&tbl->hashwlock[hash_idx]); |
573 | read_unlock_bh(&pathtbl_resize_lock); | 570 | read_unlock_bh(&pathtbl_resize_lock); |
574 | kfree(new_node); | 571 | return mpath; |
572 | |||
575 | err_node_alloc: | 573 | err_node_alloc: |
576 | kfree(new_mpath); | 574 | kfree(new_mpath); |
577 | err_path_alloc: | 575 | err_path_alloc: |
578 | atomic_dec(&sdata->u.mesh.mpaths); | 576 | atomic_dec(&sdata->u.mesh.mpaths); |
579 | return err; | 577 | spin_unlock(&tbl->hashwlock[hash_idx]); |
578 | read_unlock_bh(&pathtbl_resize_lock); | ||
579 | return ERR_PTR(err); | ||
580 | } | 580 | } |
581 | 581 | ||
582 | static void mesh_table_free_rcu(struct rcu_head *rcu) | 582 | static void mesh_table_free_rcu(struct rcu_head *rcu) |