diff options
Diffstat (limited to 'net/mac80211/mesh_plink.c')
| -rw-r--r-- | net/mac80211/mesh_plink.c | 70 |
1 files changed, 46 insertions, 24 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0f7c6e6a4248..ea13a80a476c 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * it under the terms of the GNU General Public License version 2 as | 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
| 8 | */ | 8 | */ |
| 9 | #include <linux/gfp.h> | ||
| 9 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 10 | #include <linux/random.h> | 11 | #include <linux/random.h> |
| 11 | #include "ieee80211_i.h" | 12 | #include "ieee80211_i.h" |
| @@ -64,7 +65,6 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
| 64 | { | 65 | { |
| 65 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
| 66 | mesh_accept_plinks_update(sdata); | 67 | mesh_accept_plinks_update(sdata); |
| 67 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static inline | 70 | static inline |
| @@ -72,7 +72,6 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
| 72 | { | 72 | { |
| 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
| 74 | mesh_accept_plinks_update(sdata); | 74 | mesh_accept_plinks_update(sdata); |
| 75 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 76 | } | 75 | } |
| 77 | 76 | ||
| 78 | /** | 77 | /** |
| @@ -102,7 +101,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 102 | if (local->num_sta >= MESH_MAX_PLINKS) | 101 | if (local->num_sta >= MESH_MAX_PLINKS) |
| 103 | return NULL; | 102 | return NULL; |
| 104 | 103 | ||
| 105 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 104 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
| 106 | if (!sta) | 105 | if (!sta) |
| 107 | return NULL; | 106 | return NULL; |
| 108 | 107 | ||
| @@ -114,7 +113,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 114 | } | 113 | } |
| 115 | 114 | ||
| 116 | /** | 115 | /** |
| 117 | * mesh_plink_deactivate - deactivate mesh peer link | 116 | * __mesh_plink_deactivate - deactivate mesh peer link |
| 118 | * | 117 | * |
| 119 | * @sta: mesh peer link to deactivate | 118 | * @sta: mesh peer link to deactivate |
| 120 | * | 119 | * |
| @@ -122,18 +121,23 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
| 122 | * | 121 | * |
| 123 | * Locking: the caller must hold sta->lock | 122 | * Locking: the caller must hold sta->lock |
| 124 | */ | 123 | */ |
| 125 | static void __mesh_plink_deactivate(struct sta_info *sta) | 124 | static bool __mesh_plink_deactivate(struct sta_info *sta) |
| 126 | { | 125 | { |
| 127 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 126 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
| 127 | bool deactivated = false; | ||
| 128 | 128 | ||
| 129 | if (sta->plink_state == PLINK_ESTAB) | 129 | if (sta->plink_state == PLINK_ESTAB) { |
| 130 | mesh_plink_dec_estab_count(sdata); | 130 | mesh_plink_dec_estab_count(sdata); |
| 131 | deactivated = true; | ||
| 132 | } | ||
| 131 | sta->plink_state = PLINK_BLOCKED; | 133 | sta->plink_state = PLINK_BLOCKED; |
| 132 | mesh_path_flush_by_nexthop(sta); | 134 | mesh_path_flush_by_nexthop(sta); |
| 135 | |||
| 136 | return deactivated; | ||
| 133 | } | 137 | } |
| 134 | 138 | ||
| 135 | /** | 139 | /** |
| 136 | * __mesh_plink_deactivate - deactivate mesh peer link | 140 | * mesh_plink_deactivate - deactivate mesh peer link |
| 137 | * | 141 | * |
| 138 | * @sta: mesh peer link to deactivate | 142 | * @sta: mesh peer link to deactivate |
| 139 | * | 143 | * |
| @@ -141,9 +145,15 @@ static void __mesh_plink_deactivate(struct sta_info *sta) | |||
| 141 | */ | 145 | */ |
| 142 | void mesh_plink_deactivate(struct sta_info *sta) | 146 | void mesh_plink_deactivate(struct sta_info *sta) |
| 143 | { | 147 | { |
| 148 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 149 | bool deactivated; | ||
| 150 | |||
| 144 | spin_lock_bh(&sta->lock); | 151 | spin_lock_bh(&sta->lock); |
| 145 | __mesh_plink_deactivate(sta); | 152 | deactivated = __mesh_plink_deactivate(sta); |
| 146 | spin_unlock_bh(&sta->lock); | 153 | spin_unlock_bh(&sta->lock); |
| 154 | |||
| 155 | if (deactivated) | ||
| 156 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 147 | } | 157 | } |
| 148 | 158 | ||
| 149 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 159 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
| @@ -169,9 +179,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
| 169 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 179 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
| 170 | IEEE80211_STYPE_ACTION); | 180 | IEEE80211_STYPE_ACTION); |
| 171 | memcpy(mgmt->da, da, ETH_ALEN); | 181 | memcpy(mgmt->da, da, ETH_ALEN); |
| 172 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 182 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
| 173 | /* BSSID is left zeroed, wildcard value */ | 183 | /* BSSID is left zeroed, wildcard value */ |
| 174 | mgmt->u.action.category = MESH_PLINK_CATEGORY; | 184 | mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK; |
| 175 | mgmt->u.action.u.plink_action.action_code = action; | 185 | mgmt->u.action.u.plink_action.action_code = action; |
| 176 | 186 | ||
| 177 | if (action == PLINK_CLOSE) | 187 | if (action == PLINK_CLOSE) |
| @@ -234,14 +244,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
| 234 | 244 | ||
| 235 | rcu_read_lock(); | 245 | rcu_read_lock(); |
| 236 | 246 | ||
| 237 | sta = sta_info_get(local, hw_addr); | 247 | sta = sta_info_get(sdata, hw_addr); |
| 238 | if (!sta) { | 248 | if (!sta) { |
| 249 | rcu_read_unlock(); | ||
| 250 | |||
| 239 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 251 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
| 240 | if (!sta) { | 252 | if (!sta) |
| 241 | rcu_read_unlock(); | ||
| 242 | return; | 253 | return; |
| 243 | } | 254 | if (sta_info_insert_rcu(sta)) { |
| 244 | if (sta_info_insert(sta)) { | ||
| 245 | rcu_read_unlock(); | 255 | rcu_read_unlock(); |
| 246 | return; | 256 | return; |
| 247 | } | 257 | } |
| @@ -380,10 +390,16 @@ int mesh_plink_open(struct sta_info *sta) | |||
| 380 | 390 | ||
| 381 | void mesh_plink_block(struct sta_info *sta) | 391 | void mesh_plink_block(struct sta_info *sta) |
| 382 | { | 392 | { |
| 393 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
| 394 | bool deactivated; | ||
| 395 | |||
| 383 | spin_lock_bh(&sta->lock); | 396 | spin_lock_bh(&sta->lock); |
| 384 | __mesh_plink_deactivate(sta); | 397 | deactivated = __mesh_plink_deactivate(sta); |
| 385 | sta->plink_state = PLINK_BLOCKED; | 398 | sta->plink_state = PLINK_BLOCKED; |
| 386 | spin_unlock_bh(&sta->lock); | 399 | spin_unlock_bh(&sta->lock); |
| 400 | |||
| 401 | if (deactivated) | ||
| 402 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 387 | } | 403 | } |
| 388 | 404 | ||
| 389 | 405 | ||
| @@ -396,6 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 396 | enum plink_event event; | 412 | enum plink_event event; |
| 397 | enum plink_frame_type ftype; | 413 | enum plink_frame_type ftype; |
| 398 | size_t baselen; | 414 | size_t baselen; |
| 415 | bool deactivated; | ||
| 399 | u8 ie_len; | 416 | u8 ie_len; |
| 400 | u8 *baseaddr; | 417 | u8 *baseaddr; |
| 401 | __le16 plid, llid, reason; | 418 | __le16 plid, llid, reason; |
| @@ -455,7 +472,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 455 | 472 | ||
| 456 | rcu_read_lock(); | 473 | rcu_read_lock(); |
| 457 | 474 | ||
| 458 | sta = sta_info_get(local, mgmt->sa); | 475 | sta = sta_info_get(sdata, mgmt->sa); |
| 459 | if (!sta && ftype != PLINK_OPEN) { | 476 | if (!sta && ftype != PLINK_OPEN) { |
| 460 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | 477 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); |
| 461 | rcu_read_unlock(); | 478 | rcu_read_unlock(); |
| @@ -485,9 +502,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 485 | } else if (!sta) { | 502 | } else if (!sta) { |
| 486 | /* ftype == PLINK_OPEN */ | 503 | /* ftype == PLINK_OPEN */ |
| 487 | u32 rates; | 504 | u32 rates; |
| 505 | |||
| 506 | rcu_read_unlock(); | ||
| 507 | |||
| 488 | if (!mesh_plink_free_count(sdata)) { | 508 | if (!mesh_plink_free_count(sdata)) { |
| 489 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 509 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
| 490 | rcu_read_unlock(); | ||
| 491 | return; | 510 | return; |
| 492 | } | 511 | } |
| 493 | 512 | ||
| @@ -495,10 +514,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 495 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 514 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
| 496 | if (!sta) { | 515 | if (!sta) { |
| 497 | mpl_dbg("Mesh plink error: plink table full\n"); | 516 | mpl_dbg("Mesh plink error: plink table full\n"); |
| 498 | rcu_read_unlock(); | ||
| 499 | return; | 517 | return; |
| 500 | } | 518 | } |
| 501 | if (sta_info_insert(sta)) { | 519 | if (sta_info_insert_rcu(sta)) { |
| 502 | rcu_read_unlock(); | 520 | rcu_read_unlock(); |
| 503 | return; | 521 | return; |
| 504 | } | 522 | } |
| @@ -649,8 +667,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 649 | case CNF_ACPT: | 667 | case CNF_ACPT: |
| 650 | del_timer(&sta->plink_timer); | 668 | del_timer(&sta->plink_timer); |
| 651 | sta->plink_state = PLINK_ESTAB; | 669 | sta->plink_state = PLINK_ESTAB; |
| 652 | mesh_plink_inc_estab_count(sdata); | ||
| 653 | spin_unlock_bh(&sta->lock); | 670 | spin_unlock_bh(&sta->lock); |
| 671 | mesh_plink_inc_estab_count(sdata); | ||
| 672 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 654 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 673 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
| 655 | sta->sta.addr); | 674 | sta->sta.addr); |
| 656 | break; | 675 | break; |
| @@ -682,8 +701,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 682 | case OPN_ACPT: | 701 | case OPN_ACPT: |
| 683 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
| 684 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = PLINK_ESTAB; |
| 685 | mesh_plink_inc_estab_count(sdata); | ||
| 686 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
| 705 | mesh_plink_inc_estab_count(sdata); | ||
| 706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 687 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 707 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
| 688 | sta->sta.addr); | 708 | sta->sta.addr); |
| 689 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, | 709 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, |
| @@ -700,11 +720,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 700 | case CLS_ACPT: | 720 | case CLS_ACPT: |
| 701 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 721 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
| 702 | sta->reason = reason; | 722 | sta->reason = reason; |
| 703 | __mesh_plink_deactivate(sta); | 723 | deactivated = __mesh_plink_deactivate(sta); |
| 704 | sta->plink_state = PLINK_HOLDING; | 724 | sta->plink_state = PLINK_HOLDING; |
| 705 | llid = sta->llid; | 725 | llid = sta->llid; |
| 706 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 726 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
| 707 | spin_unlock_bh(&sta->lock); | 727 | spin_unlock_bh(&sta->lock); |
| 728 | if (deactivated) | ||
| 729 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
| 708 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, | 730 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, |
| 709 | plid, reason); | 731 | plid, reason); |
| 710 | break; | 732 | break; |
| @@ -743,7 +765,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
| 743 | break; | 765 | break; |
| 744 | default: | 766 | default: |
| 745 | /* should not get here, PLINK_BLOCKED is dealt with at the | 767 | /* should not get here, PLINK_BLOCKED is dealt with at the |
| 746 | * beggining of the function | 768 | * beginning of the function |
| 747 | */ | 769 | */ |
| 748 | spin_unlock_bh(&sta->lock); | 770 | spin_unlock_bh(&sta->lock); |
| 749 | break; | 771 | break; |
