aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_plink.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r--net/mac80211/mesh_plink.c84
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
70static inline 71static 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;