diff options
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ffcbad75e09b..7b7080e2b49f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -1,11 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008 open80211s Ltd. | 2 | * Copyright (c) 2008, 2009 open80211s Ltd. |
3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> | 3 | * Author: Luis Carlos Cobo <luisca@cozybit.com> |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
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" |
@@ -18,9 +19,8 @@ | |||
18 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) | 19 | #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) |
19 | #endif | 20 | #endif |
20 | 21 | ||
21 | #define PLINK_GET_FRAME_SUBTYPE(p) (p) | 22 | #define PLINK_GET_LLID(p) (p + 4) |
22 | #define PLINK_GET_LLID(p) (p + 1) | 23 | #define PLINK_GET_PLID(p) (p + 6) |
23 | #define PLINK_GET_PLID(p) (p + 3) | ||
24 | 24 | ||
25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ | 25 | #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ |
26 | jiffies + HZ * t / 1000)) | 26 | jiffies + HZ * t / 1000)) |
@@ -65,6 +65,7 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
65 | { | 65 | { |
66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
67 | mesh_accept_plinks_update(sdata); | 67 | mesh_accept_plinks_update(sdata); |
68 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
68 | } | 69 | } |
69 | 70 | ||
70 | static inline | 71 | static inline |
@@ -72,12 +73,13 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
72 | { | 73 | { |
73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 74 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
74 | mesh_accept_plinks_update(sdata); | 75 | mesh_accept_plinks_update(sdata); |
76 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
75 | } | 77 | } |
76 | 78 | ||
77 | /** | 79 | /** |
78 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine | 80 | * mesh_plink_fsm_restart - restart a mesh peer link finite state machine |
79 | * | 81 | * |
80 | * @sta: mes peer link to restart | 82 | * @sta: mesh peer link to restart |
81 | * | 83 | * |
82 | * Locking: this function must be called holding sta->lock | 84 | * Locking: this function must be called holding sta->lock |
83 | */ | 85 | */ |
@@ -101,7 +103,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
101 | if (local->num_sta >= MESH_MAX_PLINKS) | 103 | if (local->num_sta >= MESH_MAX_PLINKS) |
102 | return NULL; | 104 | return NULL; |
103 | 105 | ||
104 | sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); | 106 | sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); |
105 | if (!sta) | 107 | if (!sta) |
106 | return NULL; | 108 | return NULL; |
107 | 109 | ||
@@ -152,6 +154,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
152 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); | 154 | struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); |
153 | struct ieee80211_mgmt *mgmt; | 155 | struct ieee80211_mgmt *mgmt; |
154 | bool include_plid = false; | 156 | bool include_plid = false; |
157 | static const u8 meshpeeringproto[] = { 0x00, 0x0F, 0xAC, 0x2A }; | ||
155 | u8 *pos; | 158 | u8 *pos; |
156 | int ie_len; | 159 | int ie_len; |
157 | 160 | ||
@@ -167,9 +170,9 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
167 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | 170 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | |
168 | IEEE80211_STYPE_ACTION); | 171 | IEEE80211_STYPE_ACTION); |
169 | memcpy(mgmt->da, da, ETH_ALEN); | 172 | memcpy(mgmt->da, da, ETH_ALEN); |
170 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | 173 | memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); |
171 | /* BSSID is left zeroed, wildcard value */ | 174 | /* BSSID is left zeroed, wildcard value */ |
172 | mgmt->u.action.category = PLINK_CATEGORY; | 175 | mgmt->u.action.category = MESH_PLINK_CATEGORY; |
173 | mgmt->u.action.u.plink_action.action_code = action; | 176 | mgmt->u.action.u.plink_action.action_code = action; |
174 | 177 | ||
175 | if (action == PLINK_CLOSE) | 178 | if (action == PLINK_CLOSE) |
@@ -179,7 +182,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
179 | if (action == PLINK_CONFIRM) { | 182 | if (action == PLINK_CONFIRM) { |
180 | pos = skb_put(skb, 4); | 183 | pos = skb_put(skb, 4); |
181 | /* two-byte status code followed by two-byte AID */ | 184 | /* two-byte status code followed by two-byte AID */ |
182 | memset(pos, 0, 4); | 185 | memset(pos, 0, 2); |
186 | memcpy(pos + 2, &plid, 2); | ||
183 | } | 187 | } |
184 | mesh_mgmt_ies_add(skb, sdata); | 188 | mesh_mgmt_ies_add(skb, sdata); |
185 | } | 189 | } |
@@ -187,18 +191,18 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
187 | /* Add Peer Link Management element */ | 191 | /* Add Peer Link Management element */ |
188 | switch (action) { | 192 | switch (action) { |
189 | case PLINK_OPEN: | 193 | case PLINK_OPEN: |
190 | ie_len = 3; | 194 | ie_len = 6; |
191 | break; | 195 | break; |
192 | case PLINK_CONFIRM: | 196 | case PLINK_CONFIRM: |
193 | ie_len = 5; | 197 | ie_len = 8; |
194 | include_plid = true; | 198 | include_plid = true; |
195 | break; | 199 | break; |
196 | case PLINK_CLOSE: | 200 | case PLINK_CLOSE: |
197 | default: | 201 | default: |
198 | if (!plid) | 202 | if (!plid) |
199 | ie_len = 5; | 203 | ie_len = 8; |
200 | else { | 204 | else { |
201 | ie_len = 7; | 205 | ie_len = 10; |
202 | include_plid = true; | 206 | include_plid = true; |
203 | } | 207 | } |
204 | break; | 208 | break; |
@@ -207,7 +211,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
207 | pos = skb_put(skb, 2 + ie_len); | 211 | pos = skb_put(skb, 2 + ie_len); |
208 | *pos++ = WLAN_EID_PEER_LINK; | 212 | *pos++ = WLAN_EID_PEER_LINK; |
209 | *pos++ = ie_len; | 213 | *pos++ = ie_len; |
210 | *pos++ = action; | 214 | memcpy(pos, meshpeeringproto, sizeof(meshpeeringproto)); |
215 | pos += 4; | ||
211 | memcpy(pos, &llid, 2); | 216 | memcpy(pos, &llid, 2); |
212 | if (include_plid) { | 217 | if (include_plid) { |
213 | pos += 2; | 218 | pos += 2; |
@@ -218,7 +223,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | |||
218 | memcpy(pos, &reason, 2); | 223 | memcpy(pos, &reason, 2); |
219 | } | 224 | } |
220 | 225 | ||
221 | ieee80211_tx_skb(sdata, skb, 1); | 226 | ieee80211_tx_skb(sdata, skb); |
222 | return 0; | 227 | return 0; |
223 | } | 228 | } |
224 | 229 | ||
@@ -230,14 +235,14 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data | |||
230 | 235 | ||
231 | rcu_read_lock(); | 236 | rcu_read_lock(); |
232 | 237 | ||
233 | sta = sta_info_get(local, hw_addr); | 238 | sta = sta_info_get(sdata, hw_addr); |
234 | if (!sta) { | 239 | if (!sta) { |
240 | rcu_read_unlock(); | ||
241 | |||
235 | sta = mesh_plink_alloc(sdata, hw_addr, rates); | 242 | sta = mesh_plink_alloc(sdata, hw_addr, rates); |
236 | if (!sta) { | 243 | if (!sta) |
237 | rcu_read_unlock(); | ||
238 | return; | 244 | return; |
239 | } | 245 | if (sta_info_insert_rcu(sta)) { |
240 | if (sta_info_insert(sta)) { | ||
241 | rcu_read_unlock(); | 246 | rcu_read_unlock(); |
242 | return; | 247 | return; |
243 | } | 248 | } |
@@ -395,6 +400,17 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
395 | u8 ie_len; | 400 | u8 ie_len; |
396 | u8 *baseaddr; | 401 | u8 *baseaddr; |
397 | __le16 plid, llid, reason; | 402 | __le16 plid, llid, reason; |
403 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | ||
404 | static const char *mplstates[] = { | ||
405 | [PLINK_LISTEN] = "LISTEN", | ||
406 | [PLINK_OPN_SNT] = "OPN-SNT", | ||
407 | [PLINK_OPN_RCVD] = "OPN-RCVD", | ||
408 | [PLINK_CNF_RCVD] = "CNF_RCVD", | ||
409 | [PLINK_ESTAB] = "ESTAB", | ||
410 | [PLINK_HOLDING] = "HOLDING", | ||
411 | [PLINK_BLOCKED] = "BLOCKED" | ||
412 | }; | ||
413 | #endif | ||
398 | 414 | ||
399 | /* need action_code, aux */ | 415 | /* need action_code, aux */ |
400 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) | 416 | if (len < IEEE80211_MIN_ACTION_SIZE + 3) |
@@ -417,12 +433,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
417 | return; | 433 | return; |
418 | } | 434 | } |
419 | 435 | ||
420 | ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); | 436 | ftype = mgmt->u.action.u.plink_action.action_code; |
421 | ie_len = elems.peer_link_len; | 437 | ie_len = elems.peer_link_len; |
422 | if ((ftype == PLINK_OPEN && ie_len != 3) || | 438 | if ((ftype == PLINK_OPEN && ie_len != 6) || |
423 | (ftype == PLINK_CONFIRM && ie_len != 5) || | 439 | (ftype == PLINK_CONFIRM && ie_len != 8) || |
424 | (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { | 440 | (ftype == PLINK_CLOSE && ie_len != 8 && ie_len != 10)) { |
425 | mpl_dbg("Mesh plink: incorrect plink ie length\n"); | 441 | mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", |
442 | ftype, ie_len); | ||
426 | return; | 443 | return; |
427 | } | 444 | } |
428 | 445 | ||
@@ -434,12 +451,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
434 | * from the point of view of this host. | 451 | * from the point of view of this host. |
435 | */ | 452 | */ |
436 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); | 453 | memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); |
437 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) | 454 | if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 10)) |
438 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); | 455 | memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); |
439 | 456 | ||
440 | rcu_read_lock(); | 457 | rcu_read_lock(); |
441 | 458 | ||
442 | sta = sta_info_get(local, mgmt->sa); | 459 | sta = sta_info_get(sdata, mgmt->sa); |
443 | if (!sta && ftype != PLINK_OPEN) { | 460 | if (!sta && ftype != PLINK_OPEN) { |
444 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); | 461 | mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); |
445 | rcu_read_unlock(); | 462 | rcu_read_unlock(); |
@@ -469,9 +486,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
469 | } else if (!sta) { | 486 | } else if (!sta) { |
470 | /* ftype == PLINK_OPEN */ | 487 | /* ftype == PLINK_OPEN */ |
471 | u32 rates; | 488 | u32 rates; |
489 | |||
490 | rcu_read_unlock(); | ||
491 | |||
472 | if (!mesh_plink_free_count(sdata)) { | 492 | if (!mesh_plink_free_count(sdata)) { |
473 | mpl_dbg("Mesh plink error: no more free plinks\n"); | 493 | mpl_dbg("Mesh plink error: no more free plinks\n"); |
474 | rcu_read_unlock(); | ||
475 | return; | 494 | return; |
476 | } | 495 | } |
477 | 496 | ||
@@ -479,10 +498,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
479 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); | 498 | sta = mesh_plink_alloc(sdata, mgmt->sa, rates); |
480 | if (!sta) { | 499 | if (!sta) { |
481 | mpl_dbg("Mesh plink error: plink table full\n"); | 500 | mpl_dbg("Mesh plink error: plink table full\n"); |
482 | rcu_read_unlock(); | ||
483 | return; | 501 | return; |
484 | } | 502 | } |
485 | if (sta_info_insert(sta)) { | 503 | if (sta_info_insert_rcu(sta)) { |
486 | rcu_read_unlock(); | 504 | rcu_read_unlock(); |
487 | return; | 505 | return; |
488 | } | 506 | } |
@@ -532,8 +550,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
532 | } | 550 | } |
533 | } | 551 | } |
534 | 552 | ||
535 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n", | 553 | mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", |
536 | mgmt->sa, sta->plink_state, | 554 | mgmt->sa, mplstates[sta->plink_state], |
537 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), | 555 | le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), |
538 | event); | 556 | event); |
539 | reason = 0; | 557 | reason = 0; |
@@ -727,7 +745,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
727 | break; | 745 | break; |
728 | default: | 746 | default: |
729 | /* should not get here, PLINK_BLOCKED is dealt with at the | 747 | /* should not get here, PLINK_BLOCKED is dealt with at the |
730 | * beggining of the function | 748 | * beginning of the function |
731 | */ | 749 | */ |
732 | spin_unlock_bh(&sta->lock); | 750 | spin_unlock_bh(&sta->lock); |
733 | break; | 751 | break; |