2013-11-05 19:22:39

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 01/17] mac80211: fix off-by-one in llid check.

From: Bob Copeland <[email protected]>

According to IEEE 802.11-2012 (8.4.2.104), no peering
management element exists with length 7. This code is checking
to see if llid is present to ignore close frames with different
llid, which would be IEs with length 8.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 4301aa5..a8c75c1 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -825,7 +825,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
event = CLS_ACPT;
else if (sta->plid != plid)
event = CLS_IGNR;
- else if (ie_len == 7 && sta->llid != llid)
+ else if (ie_len == 8 && sta->llid != llid)
event = CLS_IGNR;
else
event = CLS_ACPT;
--
1.8.4.rc3



2013-11-05 19:22:55

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 08/17] mac80211: mesh_plink: don't ignore holding timer

From: Bob Copeland <[email protected]>

The ignore_plink_timer flag is set when doing mod_timer() if
the timer was not previously active. This is to avoid executing
the timeout if del_timer() was subsequently called. However,
del_timer() only happens if we are moving to ESTAB state or
get a close frame while in HOLDING.

We cannot leave HOLDING and re-enter ESTAB unless we receive a
close frame (in which case ignore_plink_timer is already set) or
if the timeout expires, so there actually isn't a case where
this is needed on mod_timer().

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 8e23395..550ebc1 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -671,8 +671,7 @@ static void mesh_plink_close(struct ieee80211_sub_if_data *sdata,

sta->reason = reason;
sta->plink_state = NL80211_PLINK_HOLDING;
- if (!mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout))
- sta->ignore_plink_timer = true;
+ mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
}

static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
--
1.8.4.rc3


2013-11-05 19:23:06

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 14/17] mac80211: factor out peering FSM

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 296 ++++++++++++++++++++++++----------------------
1 file changed, 154 insertions(+), 142 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index fa86d35..e5d5c69 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -691,14 +691,165 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
return changed;
}

+/**
+ * mesh_plink_fsm - step @sta MPM based on @event
+ *
+ * @sdata: interface
+ * @sta: mesh neighbor
+ * @event: peering event
+ *
+ * Return: changed MBSS flags
+ */
+static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, enum plink_event event)
+{
+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+ enum ieee80211_self_protected_actioncode action = 0;
+ u32 changed = 0;
+
+ mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,
+ mplstates[sta->plink_state], mplevents[event]);
+
+ spin_lock_bh(&sta->lock);
+ switch (sta->plink_state) {
+ case NL80211_PLINK_LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mesh_plink_fsm_restart(sta);
+ break;
+ case OPN_ACPT:
+ sta->plink_state = NL80211_PLINK_OPN_RCVD;
+ get_random_bytes(&sta->llid, 2);
+ mesh_plink_timer_set(sta,
+ mshcfg->dot11MeshRetryTimeout);
+
+ /* set the non-peer mode to active during peering */
+ changed |= ieee80211_mps_local_status_update(sdata);
+ action = WLAN_SP_MESH_PEERING_OPEN;
+ break;
+ default:
+ break;
+ }
+ break;
+ case NL80211_PLINK_OPN_SNT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ case CLS_ACPT:
+ mesh_plink_close(sdata, sta, event);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ sta->plink_state = NL80211_PLINK_OPN_RCVD;
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
+ break;
+ case CNF_ACPT:
+ sta->plink_state = NL80211_PLINK_CNF_RCVD;
+ if (!mod_plink_timer(sta,
+ mshcfg->dot11MeshConfirmTimeout))
+ sta->ignore_plink_timer = true;
+ break;
+ default:
+ break;
+ }
+ break;
+ case NL80211_PLINK_OPN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ case CLS_ACPT:
+ mesh_plink_close(sdata, sta, event);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
+ break;
+ case OPN_ACPT:
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
+ break;
+ case CNF_ACPT:
+ changed |= mesh_plink_establish(sdata, sta);
+ break;
+ default:
+ break;
+ }
+ break;
+ case NL80211_PLINK_CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ case CLS_ACPT:
+ mesh_plink_close(sdata, sta, event);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
+ break;
+ case OPN_ACPT:
+ changed |= mesh_plink_establish(sdata, sta);
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
+ break;
+ default:
+ break;
+ }
+ break;
+ case NL80211_PLINK_ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ changed |= __mesh_plink_deactivate(sta);
+ changed |= mesh_set_ht_prot_mode(sdata);
+ changed |= mesh_set_short_slot_time(sdata);
+ mesh_plink_close(sdata, sta, event);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
+ break;
+ case OPN_ACPT:
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
+ break;
+ default:
+ break;
+ }
+ break;
+ case NL80211_PLINK_HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ if (del_timer(&sta->plink_timer))
+ sta->ignore_plink_timer = 1;
+ mesh_plink_fsm_restart(sta);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ action = WLAN_SP_MESH_PEERING_CLOSE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ /* should not get here, PLINK_BLOCKED is dealt with at the
+ * beginning of the function
+ */
+ break;
+ }
+ spin_unlock_bh(&sta->lock);
+ if (action) {
+ mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+ sta->llid, sta->plid, sta->reason);
+
+ /* also send confirm in open case */
+ if (action == WLAN_SP_MESH_PEERING_OPEN) {
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, sta->llid,
+ sta->plid, 0);
+ }
+ }
+
+ return changed;
+}
+
static void
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems)
{

- struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
- enum ieee80211_self_protected_actioncode action = 0;
struct sta_info *sta;
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
@@ -847,146 +998,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
sta->plid = plid;
}

- mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
- mplstates[sta->plink_state], mplevents[event]);
- spin_lock_bh(&sta->lock);
- switch (sta->plink_state) {
- case NL80211_PLINK_LISTEN:
- switch (event) {
- case CLS_ACPT:
- mesh_plink_fsm_restart(sta);
- break;
- case OPN_ACPT:
- sta->plink_state = NL80211_PLINK_OPN_RCVD;
- get_random_bytes(&llid, 2);
- sta->llid = llid;
- mesh_plink_timer_set(sta,
- mshcfg->dot11MeshRetryTimeout);
-
- /* set the non-peer mode to active during peering */
- changed |= ieee80211_mps_local_status_update(sdata);
-
- action = WLAN_SP_MESH_PEERING_OPEN;
- break;
- default:
- break;
- }
- break;
-
- case NL80211_PLINK_OPN_SNT:
- switch (event) {
- case OPN_RJCT:
- case CNF_RJCT:
- case CLS_ACPT:
- mesh_plink_close(sdata, sta, event);
- action = WLAN_SP_MESH_PEERING_CLOSE;
- break;
-
- case OPN_ACPT:
- /* retry timer is left untouched */
- sta->plink_state = NL80211_PLINK_OPN_RCVD;
- action = WLAN_SP_MESH_PEERING_CONFIRM;
- break;
- case CNF_ACPT:
- sta->plink_state = NL80211_PLINK_CNF_RCVD;
- if (!mod_plink_timer(sta,
- mshcfg->dot11MeshConfirmTimeout))
- sta->ignore_plink_timer = true;
-
- break;
- default:
- break;
- }
- break;
-
- case NL80211_PLINK_OPN_RCVD:
- switch (event) {
- case OPN_RJCT:
- case CNF_RJCT:
- case CLS_ACPT:
- mesh_plink_close(sdata, sta, event);
- action = WLAN_SP_MESH_PEERING_CLOSE;
- break;
- case OPN_ACPT:
- action = WLAN_SP_MESH_PEERING_CONFIRM;
- break;
- case CNF_ACPT:
- changed |= mesh_plink_establish(sdata, sta);
- break;
- default:
- break;
- }
- break;
-
- case NL80211_PLINK_CNF_RCVD:
- switch (event) {
- case OPN_RJCT:
- case CNF_RJCT:
- case CLS_ACPT:
- mesh_plink_close(sdata, sta, event);
- action = WLAN_SP_MESH_PEERING_CLOSE;
- break;
- case OPN_ACPT:
- changed |= mesh_plink_establish(sdata, sta);
- action = WLAN_SP_MESH_PEERING_CONFIRM;
- break;
- default:
- break;
- }
- break;
-
- case NL80211_PLINK_ESTAB:
- switch (event) {
- case CLS_ACPT:
- changed |= __mesh_plink_deactivate(sta);
- changed |= mesh_set_ht_prot_mode(sdata);
- changed |= mesh_set_short_slot_time(sdata);
- mesh_plink_close(sdata, sta, event);
- action = WLAN_SP_MESH_PEERING_CLOSE;
- break;
- case OPN_ACPT:
- action = WLAN_SP_MESH_PEERING_CONFIRM;
- break;
- default:
- break;
- }
- break;
- case NL80211_PLINK_HOLDING:
- switch (event) {
- case CLS_ACPT:
- if (del_timer(&sta->plink_timer))
- sta->ignore_plink_timer = 1;
- mesh_plink_fsm_restart(sta);
- break;
- case OPN_ACPT:
- case CNF_ACPT:
- case OPN_RJCT:
- case CNF_RJCT:
- action = WLAN_SP_MESH_PEERING_CLOSE;
- break;
- default:
- break;
- }
- break;
- default:
- /* should not get here, PLINK_BLOCKED is dealt with at the
- * beginning of the function
- */
- break;
- }
- spin_unlock_bh(&sta->lock);
- if (action) {
- mesh_plink_frame_tx(sdata, action, sta->sta.addr,
- sta->llid, sta->plid, sta->reason);
-
- /* also send confirm in open case */
- if (action == WLAN_SP_MESH_PEERING_OPEN) {
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, sta->llid,
- sta->plid, 0);
- }
- }
+ changed |= mesh_plink_fsm(sdata, sta, event);

unlock_rcu:
rcu_read_unlock();
--
1.8.4.rc3


2013-11-05 19:22:41

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 02/17] mac80211: consolidate calls to plink_frame_tx

Do all frame transfers in one place at the end of the
big switch statements. sta->plid and sta->reason can
be passed in any case, since they are only used for
the frames that need them. Remove assignments to locals
for values already stored in the sta structure.

Signed-off-by: Thomas Pedersen <[email protected]>
Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 72 +++++++++++++++++++----------------------------
1 file changed, 29 insertions(+), 43 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a8c75c1..d45826e 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -533,6 +533,7 @@ static void mesh_plink_timer(unsigned long data)
__le16 llid, plid, reason;
struct ieee80211_sub_if_data *sdata;
struct mesh_config *mshcfg;
+ enum ieee80211_self_protected_actioncode action = 0;

/*
* This STA is valid because sta_info_destroy() will
@@ -575,8 +576,7 @@ static void mesh_plink_timer(unsigned long data)
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
- sta->sta.addr, llid, 0, 0);
+ action = WLAN_SP_MESH_PEERING_OPEN;
break;
}
reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
@@ -588,8 +588,7 @@ static void mesh_plink_timer(unsigned long data)
sta->plink_state = NL80211_PLINK_HOLDING;
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case NL80211_PLINK_HOLDING:
/* holding timer */
@@ -601,6 +600,9 @@ static void mesh_plink_timer(unsigned long data)
spin_unlock_bh(&sta->lock);
break;
}
+ if (action)
+ mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+ llid, plid, reason);
}

static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
@@ -662,6 +664,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_rx_status *rx_status)
{
struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+ enum ieee80211_self_protected_actioncode action = 0;
struct ieee802_11_elems elems;
struct sta_info *sta;
enum plink_event event;
@@ -872,12 +875,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
changed |= ieee80211_mps_local_status_update(sdata);

spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_OPEN,
- sta->sta.addr, llid, 0, 0);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, llid, plid, 0);
+ action = WLAN_SP_MESH_PEERING_OPEN;
break;
default:
spin_unlock_bh(&sta->lock);
@@ -899,21 +897,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
/* retry timer is left untouched */
sta->plink_state = NL80211_PLINK_OPN_RCVD;
sta->plid = plid;
- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, llid, plid, 0);
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
sta->plink_state = NL80211_PLINK_CNF_RCVD;
@@ -943,17 +935,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, llid, plid, 0);
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
del_timer(&sta->plink_timer);
@@ -988,11 +975,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
del_timer(&sta->plink_timer);
@@ -1003,9 +987,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
changed |= mesh_set_short_slot_time(sdata);
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, llid, plid, 0);
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
ieee80211_mps_sta_status_update(sta);
changed |= ieee80211_mps_set_sta_local_pm(sta,
mshcfg->power_mode);
@@ -1023,20 +1005,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
sta->reason = reason;
changed |= __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
- llid = sta->llid;
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
spin_unlock_bh(&sta->lock);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= mesh_set_short_slot_time(sdata);
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
- llid = sta->llid;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata,
- WLAN_SP_MESH_PEERING_CONFIRM,
- sta->sta.addr, llid, plid, 0);
+ action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
default:
spin_unlock_bh(&sta->lock);
@@ -1055,11 +1032,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
case CNF_ACPT:
case OPN_RJCT:
case CNF_RJCT:
- llid = sta->llid;
- reason = sta->reason;
spin_unlock_bh(&sta->lock);
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- sta->sta.addr, llid, plid, reason);
+ action = WLAN_SP_MESH_PEERING_CLOSE;
break;
default:
spin_unlock_bh(&sta->lock);
@@ -1072,6 +1046,18 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
spin_unlock_bh(&sta->lock);
break;
}
+ if (action) {
+ mesh_plink_frame_tx(sdata, action, sta->sta.addr,
+ sta->llid, sta->plid, sta->reason);
+
+ /* also send confirm in open case */
+ if (action == WLAN_SP_MESH_PEERING_OPEN) {
+ mesh_plink_frame_tx(sdata,
+ WLAN_SP_MESH_PEERING_CONFIRM,
+ sta->sta.addr, sta->llid,
+ sta->plid, 0);
+ }
+ }

rcu_read_unlock();

--
1.8.4.rc3


2013-11-05 19:23:10

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 16/17] mac80211: initialize llid

If the peer doesn't have an llid for us, the event
gathering function won't use it anyway (based on
frametype), but initialize it so gcc and coverity don't
complain.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c6d0917..e0528b9 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -960,7 +960,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode ftype;
u32 changed = 0;
u8 ie_len = elems->peering_len;
- __le16 plid, llid;
+ __le16 plid, llid = 0;

if (!elems->peering) {
mpl_dbg(sdata,
--
1.8.4.rc3


2013-11-05 19:23:08

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 15/17] mac80211: factor out plink event gathering

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 195 +++++++++++++++++++++++++++-------------------
1 file changed, 115 insertions(+), 80 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index e5d5c69..c6d0917 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -844,6 +844,111 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
return changed;
}

+/*
+ * mesh_plink_get_event - get correct MPM event
+ *
+ * @sdata: interface
+ * @sta: peer, leave NULL if processing a frame from a new suitable peer
+ * @elems: peering management IEs
+ * @ftype: frame type
+ * @llid: peer's peer link ID
+ * @plid: peer's local link ID
+ *
+ * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as
+ * an error.
+ */
+static enum plink_event
+mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct ieee802_11_elems *elems,
+ enum ieee80211_self_protected_actioncode ftype,
+ __le16 llid, __le16 plid)
+{
+ enum plink_event event = PLINK_UNDEFINED;
+ u8 ie_len = elems->peering_len;
+ bool matches_local;
+
+ matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
+ mesh_matches_local(sdata, elems));
+
+ /* deny open request from non-matching peer */
+ if (!matches_local && !sta) {
+ event = OPN_RJCT;
+ goto out;
+ }
+
+ if (!sta) {
+ if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
+ mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
+ goto out;
+ }
+ /* ftype == WLAN_SP_MESH_PEERING_OPEN */
+ if (!mesh_plink_free_count(sdata)) {
+ mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
+ goto out;
+ }
+ } else {
+ if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
+ mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
+ goto out;
+ }
+ if (sta->plink_state == NL80211_PLINK_BLOCKED)
+ goto out;
+ }
+
+ /* new matching peer */
+ if (!sta) {
+ event = OPN_ACPT;
+ goto out;
+ }
+
+ switch (ftype) {
+ case WLAN_SP_MESH_PEERING_OPEN:
+ if (!matches_local)
+ event = OPN_RJCT;
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->plid && sta->plid != plid))
+ event = OPN_IGNR;
+ else
+ event = OPN_ACPT;
+ break;
+ case WLAN_SP_MESH_PEERING_CONFIRM:
+ if (!matches_local)
+ event = CNF_RJCT;
+ if (!mesh_plink_free_count(sdata) ||
+ (sta->llid != llid || sta->plid != plid))
+ event = CNF_IGNR;
+ else
+ event = CNF_ACPT;
+ break;
+ case WLAN_SP_MESH_PEERING_CLOSE:
+ if (sta->plink_state == NL80211_PLINK_ESTAB)
+ /* Do not check for llid or plid. This does not
+ * follow the standard but since multiple plinks
+ * per sta are not supported, it is necessary in
+ * order to avoid a livelock when MP A sees an
+ * establish peer link to MP B but MP B does not
+ * see it. This can be caused by a timeout in
+ * B's peer link establishment or B beign
+ * restarted.
+ */
+ event = CLS_ACPT;
+ else if (sta->plid != plid)
+ event = CLS_IGNR;
+ else if (ie_len == 8 && sta->llid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
+ break;
+ }
+
+out:
+ return event;
+}
+
static void
mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
@@ -853,9 +958,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta;
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
- bool matches_local;
u32 changed = 0;
- u8 ie_len;
+ u8 ie_len = elems->peering_len;
__le16 plid, llid;

if (!elems->peering) {
@@ -872,7 +976,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
}

ftype = mgmt->u.action.u.self_prot.action_code;
- ie_len = elems->peering_len;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
@@ -901,9 +1004,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,

sta = sta_info_get(sdata, mgmt->sa);

- matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
- mesh_matches_local(sdata, elems));
-
if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
!rssi_threshold_check(sdata, sta)) {
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
@@ -911,81 +1011,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
goto unlock_rcu;
}

- if (!sta) {
- if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
- mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
- goto unlock_rcu;
- }
- /* ftype == WLAN_SP_MESH_PEERING_OPEN */
- if (!mesh_plink_free_count(sdata)) {
- mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
- goto unlock_rcu;
- }
- /* deny open request from non-matching peer */
- if (!matches_local) {
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- mgmt->sa, 0, plid,
- cpu_to_le16(WLAN_REASON_MESH_CONFIG));
- goto unlock_rcu;
- }
- } else {
- if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
- mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
- goto unlock_rcu;
- }
- if (sta->plink_state == NL80211_PLINK_BLOCKED)
- goto unlock_rcu;
- }
-
/* Now we will figure out the appropriate event... */
- event = PLINK_UNDEFINED;
-
- if (!sta)
- event = OPN_ACPT;
- else {
- switch (ftype) {
- case WLAN_SP_MESH_PEERING_OPEN:
- if (!matches_local)
- event = OPN_RJCT;
- else if (!mesh_plink_free_count(sdata) ||
- (sta->plid && sta->plid != plid))
- event = OPN_IGNR;
- else
- event = OPN_ACPT;
- break;
- case WLAN_SP_MESH_PEERING_CONFIRM:
- if (!matches_local)
- event = CNF_RJCT;
- else if (!mesh_plink_free_count(sdata) ||
- (sta->llid != llid || sta->plid != plid))
- event = CNF_IGNR;
- else
- event = CNF_ACPT;
- break;
- case WLAN_SP_MESH_PEERING_CLOSE:
- if (sta->plink_state == NL80211_PLINK_ESTAB)
- /* Do not check for llid or plid. This does not
- * follow the standard but since multiple plinks
- * per sta are not supported, it is necessary in
- * order to avoid a livelock when MP A sees an
- * establish peer link to MP B but MP B does not
- * see it. This can be caused by a timeout in
- * B's peer link establishment or B beign
- * restarted.
- */
- event = CLS_ACPT;
- else if (sta->plid != plid)
- event = CLS_IGNR;
- else if (ie_len == 8 && sta->llid != llid)
- event = CLS_IGNR;
- else
- event = CLS_ACPT;
- break;
- default:
- mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
- goto unlock_rcu;
- }
- }
+ event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);

if (event == OPN_ACPT) {
rcu_read_unlock();
@@ -996,6 +1023,14 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
goto unlock_rcu;
}
sta->plid = plid;
+ } else if (!sta && event == OPN_RJCT) {
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ mgmt->sa, 0, plid,
+ cpu_to_le16(WLAN_REASON_MESH_CONFIG));
+ goto unlock_rcu;
+ } else if (!sta || event == PLINK_UNDEFINED) {
+ /* something went wrong */
+ goto unlock_rcu;
}

changed |= mesh_plink_fsm(sdata, sta, event);
--
1.8.4.rc3


2013-11-05 19:23:02

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 12/17] mac80211: consolidate rcu unlocks in plink frame rx

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 28 ++++++++++------------------
1 file changed, 10 insertions(+), 18 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c234ddb..e70f490 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -757,40 +757,33 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
!rssi_threshold_check(sdata, sta)) {
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
mgmt->sa);
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}

if (!sta) {
if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
if (!mesh_plink_free_count(sdata)) {
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}
/* deny open request from non-matching peer */
if (!matches_local) {
- rcu_read_unlock();
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
mgmt->sa, 0, plid,
cpu_to_le16(WLAN_REASON_MESH_CONFIG));
- return;
+ goto unlock_rcu;
}
} else {
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
- rcu_read_unlock();
- return;
- }
- if (sta->plink_state == NL80211_PLINK_BLOCKED) {
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}
+ if (sta->plink_state == NL80211_PLINK_BLOCKED)
+ goto unlock_rcu;
}

/* Now we will figure out the appropriate event... */
@@ -839,8 +832,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
break;
default:
mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}
}

@@ -850,8 +842,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
sta = mesh_sta_info_get(sdata, mgmt->sa, elems);
if (!sta) {
mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
- rcu_read_unlock();
- return;
+ goto unlock_rcu;
}
}

@@ -998,6 +989,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
}
}

+unlock_rcu:
rcu_read_unlock();

if (changed)
--
1.8.4.rc3


2013-11-05 19:22:48

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 05/17] mac80211: mesh_plink: group basic fitness checks

From: Bob Copeland <[email protected]>

The initial frame checks differ depending on whether this is
a new peer or not, but they were all intermixed with sta checks
as necessary. Group them together so the two cases are clearer.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 70 +++++++++++++++++++++++++----------------------
1 file changed, 37 insertions(+), 33 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 3bab76f..5048658 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -700,7 +700,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
size_t baselen;
- bool matches_local = true;
+ bool matches_local;
u8 ie_len;
u8 *baseaddr;
u32 changed = 0;
@@ -771,11 +771,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
rcu_read_lock();

sta = sta_info_get(sdata, mgmt->sa);
- if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
- mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
- rcu_read_unlock();
- return;
- }
+
+ matches_local = ftype == WLAN_SP_MESH_PEERING_CLOSE ||
+ mesh_matches_local(sdata, &elems);

if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
!rssi_threshold_check(sta, sdata)) {
@@ -785,22 +783,41 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
return;
}

- if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
- mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
- rcu_read_unlock();
- return;
- }
-
- if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
- rcu_read_unlock();
- return;
+ if (!sta) {
+ if (ftype != WLAN_SP_MESH_PEERING_OPEN) {
+ mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");
+ rcu_read_unlock();
+ return;
+ }
+ /* ftype == WLAN_SP_MESH_PEERING_OPEN */
+ if (!mesh_plink_free_count(sdata)) {
+ mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
+ rcu_read_unlock();
+ return;
+ }
+ /* deny open request from non-matching peer */
+ if (!matches_local) {
+ rcu_read_unlock();
+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+ mgmt->sa, 0, plid,
+ cpu_to_le16(WLAN_REASON_MESH_CONFIG));
+ return;
+ }
+ } else {
+ if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
+ mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
+ rcu_read_unlock();
+ return;
+ }
+ if (sta->plink_state == NL80211_PLINK_BLOCKED) {
+ rcu_read_unlock();
+ return;
+ }
}

/* Now we will figure out the appropriate event... */
event = PLINK_UNDEFINED;
- if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
- !mesh_matches_local(sdata, &elems)) {
- matches_local = false;
+ if (!matches_local) {
switch (ftype) {
case WLAN_SP_MESH_PEERING_OPEN:
event = OPN_RJCT;
@@ -813,22 +830,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
}
}

- if (!sta && !matches_local) {
- rcu_read_unlock();
- llid = 0;
- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- mgmt->sa, llid, plid,
- cpu_to_le16(WLAN_REASON_MESH_CONFIG));
- return;
- } else if (!sta) {
- /* ftype == WLAN_SP_MESH_PEERING_OPEN */
- if (!mesh_plink_free_count(sdata)) {
- mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
- rcu_read_unlock();
- return;
- }
+ if (!sta)
event = OPN_ACPT;
- } else if (matches_local) {
+ else if (matches_local) {
switch (ftype) {
case WLAN_SP_MESH_PEERING_OPEN:
if (!mesh_plink_free_count(sdata) ||
--
1.8.4.rc3


2013-11-05 19:22:58

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 10/17] mac80211: remove unused mesh_mgmt_ies_add() prototype

From: Bob Copeland <[email protected]>

Said function was removed some time ago.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh.h | 2 --
1 file changed, 2 deletions(-)

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2bc7fd2..3f867e5 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -215,8 +215,6 @@ int mesh_rmc_check(struct ieee80211_sub_if_data *sdata,
bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *ie);
void mesh_ids_set_default(struct ieee80211_if_mesh *mesh);
-void mesh_mgmt_ies_add(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb);
int mesh_add_meshconf_ie(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
int mesh_add_meshid_ie(struct ieee80211_sub_if_data *sdata,
--
1.8.4.rc3


2013-11-05 19:22:50

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 06/17] mac80211: mesh: rewrite rssi_threshold_check in C

From: Bob Copeland <[email protected]>

Use C instead of cpp for type checking. Also swap the arguments
into the usual sdata -> sta order.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 5048658..36b6cff 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -19,12 +19,6 @@
#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
jiffies + HZ * t / 1000))

-/* We only need a valid sta if user configured a minimum rssi_threshold. */
-#define rssi_threshold_check(sta, sdata) \
- (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
- (sta && (s8) -ewma_read(&sta->avg_signal) > \
- sdata->u.mesh.mshcfg.rssi_threshold))
-
enum plink_event {
PLINK_UNDEFINED,
OPN_ACPT,
@@ -63,6 +57,16 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
enum ieee80211_self_protected_actioncode action,
u8 *da, __le16 llid, __le16 plid, __le16 reason);

+
+/* We only need a valid sta if user configured a minimum rssi_threshold. */
+static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
+{
+ s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;
+ return rssi_threshold == 0 ||
+ (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold);
+}
+
/**
* mesh_plink_fsm_restart - restart a mesh peer link finite state machine
*
@@ -518,7 +522,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
sta->plink_state == NL80211_PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks &&
- rssi_threshold_check(sta, sdata))
+ rssi_threshold_check(sdata, sta))
changed = mesh_plink_open(sta);

ieee80211_mps_frame_release(sta, elems);
@@ -776,7 +780,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mesh_matches_local(sdata, &elems);

if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
- !rssi_threshold_check(sta, sdata)) {
+ !rssi_threshold_check(sdata, sta)) {
mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",
mgmt->sa);
rcu_read_unlock();
--
1.8.4.rc3


2013-11-05 19:23:00

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 11/17] mac80211: factor peering frame processing into own function

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 88 ++++++++++++++++++++++++++---------------------
1 file changed, 48 insertions(+), 40 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 429f692..c234ddb 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -691,54 +691,29 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
return changed;
}

-
-void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_mgmt *mgmt, size_t len,
- struct ieee80211_rx_status *rx_status)
+static void
+mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems)
{
+
struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
enum ieee80211_self_protected_actioncode action = 0;
- struct ieee802_11_elems elems;
struct sta_info *sta;
enum plink_event event;
enum ieee80211_self_protected_actioncode ftype;
- size_t baselen;
bool matches_local;
- u8 ie_len;
- u8 *baseaddr;
u32 changed = 0;
+ u8 ie_len;
__le16 plid, llid;

- /* need action_code, aux */
- if (len < IEEE80211_MIN_ACTION_SIZE + 3)
- return;
-
- if (sdata->u.mesh.user_mpm)
- /* userspace must register for these */
- return;
-
- if (is_multicast_ether_addr(mgmt->da)) {
- mpl_dbg(sdata,
- "Mesh plink: ignore frame from multicast address\n");
- return;
- }
-
- baseaddr = mgmt->u.action.u.self_prot.variable;
- baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
- if (mgmt->u.action.u.self_prot.action_code ==
- WLAN_SP_MESH_PEERING_CONFIRM) {
- baseaddr += 4;
- baselen += 4;
- }
- ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
-
- if (!elems.peering) {
+ if (!elems->peering) {
mpl_dbg(sdata,
"Mesh plink: missing necessary peer link ie\n");
return;
}

- if (elems.rsn_len &&
+ if (elems->rsn_len &&
sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
mpl_dbg(sdata,
"Mesh plink: can't establish link with secure peer\n");
@@ -746,7 +721,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
}

ftype = mgmt->u.action.u.self_prot.action_code;
- ie_len = elems.peering_len;
+ ie_len = elems->peering_len;
if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
(ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
@@ -758,25 +733,25 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
}

if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
- (!elems.mesh_id || !elems.mesh_config)) {
+ (!elems->mesh_id || !elems->mesh_config)) {
mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");
return;
}
/* Note the lines below are correct, the llid in the frame is the plid
* from the point of view of this host.
*/
- memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
+ memcpy(&plid, PLINK_GET_LLID(elems->peering), 2);
if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
(ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
- memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
+ memcpy(&llid, PLINK_GET_PLID(elems->peering), 2);

/* WARNING: Only for sta pointer, is dropped & re-acquired */
rcu_read_lock();

sta = sta_info_get(sdata, mgmt->sa);

- matches_local = ftype == WLAN_SP_MESH_PEERING_CLOSE ||
- mesh_matches_local(sdata, &elems);
+ matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||
+ mesh_matches_local(sdata, elems));

if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
!rssi_threshold_check(sdata, sta)) {
@@ -872,7 +847,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (event == OPN_ACPT) {
rcu_read_unlock();
/* allocate sta entry if necessary and update info */
- sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);
+ sta = mesh_sta_info_get(sdata, mgmt->sa, elems);
if (!sta) {
mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
rcu_read_unlock();
@@ -1028,3 +1003,36 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (changed)
ieee80211_mbss_info_change_notify(sdata, changed);
}
+
+void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_mgmt *mgmt, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ u8 *baseaddr;
+
+ /* need action_code, aux */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 3)
+ return;
+
+ if (sdata->u.mesh.user_mpm)
+ /* userspace must register for these */
+ return;
+
+ if (is_multicast_ether_addr(mgmt->da)) {
+ mpl_dbg(sdata,
+ "Mesh plink: ignore frame from multicast address\n");
+ return;
+ }
+
+ baseaddr = mgmt->u.action.u.self_prot.variable;
+ baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
+ if (mgmt->u.action.u.self_prot.action_code ==
+ WLAN_SP_MESH_PEERING_CONFIRM) {
+ baseaddr += 4;
+ baselen += 4;
+ }
+ ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);
+ mesh_process_plink_frame(sdata, mgmt, &elems);
+}
--
1.8.4.rc3


2013-11-06 15:14:24

by Thomas Pedersen

[permalink] [raw]
Subject: Re: [PATCH 01/17] mac80211: fix off-by-one in llid check.

On Wed, Nov 6, 2013 at 2:35 AM, Johannes Berg <[email protected]> wrote:
> Very nice. I've squashed the llid assignment into the patch that
> introduced the warning.

Hm, ok. Guess you can't get them all :)

Thanks!

--
Thomas

2013-11-05 19:22:52

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 07/17] mac80211: mesh_plink: collapse the two switch statements together

From: Bob Copeland <[email protected]>

The matches_local check can just be done when looking at the
individual action types.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 36b6cff..8e23395 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -821,33 +821,25 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,

/* Now we will figure out the appropriate event... */
event = PLINK_UNDEFINED;
- if (!matches_local) {
- switch (ftype) {
- case WLAN_SP_MESH_PEERING_OPEN:
- event = OPN_RJCT;
- break;
- case WLAN_SP_MESH_PEERING_CONFIRM:
- event = CNF_RJCT;
- break;
- default:
- break;
- }
- }

if (!sta)
event = OPN_ACPT;
- else if (matches_local) {
+ else {
switch (ftype) {
case WLAN_SP_MESH_PEERING_OPEN:
- if (!mesh_plink_free_count(sdata) ||
- (sta->plid && sta->plid != plid))
+ if (!matches_local)
+ event = OPN_RJCT;
+ else if (!mesh_plink_free_count(sdata) ||
+ (sta->plid && sta->plid != plid))
event = OPN_IGNR;
else
event = OPN_ACPT;
break;
case WLAN_SP_MESH_PEERING_CONFIRM:
- if (!mesh_plink_free_count(sdata) ||
- (sta->llid != llid || sta->plid != plid))
+ if (!matches_local)
+ event = CNF_RJCT;
+ else if (!mesh_plink_free_count(sdata) ||
+ (sta->llid != llid || sta->plid != plid))
event = CNF_IGNR;
else
event = CNF_ACPT;
--
1.8.4.rc3


2013-11-05 19:23:12

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 17/17] mac80211: clean up mesh local link ID generation

802.11-2012 13.3.1 implicitly limits the mesh local link
ID range to that of AID, since for mesh PS the local link
ID must be indicated in the TIM IE, which only holds
IEEE80211_MAX_AID bits.

Also the code was allowing a local link ID of 0, but this
is not correct since that TIM bit is used for indicating
buffered mcast frames.

Generate a random, unique, link ID from 1 - 2007, and drop
a modulo conversion for the local link ID, but keep it for
the peer link ID in case he chose something > MAX_AID.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 40 +++++++++++++++++++++++++++++++++++-----
net/mac80211/mesh_ps.c | 3 +--
net/mac80211/sta_info.c | 4 ++--
3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index e0528b9..4ea2f21 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -615,9 +615,40 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
add_timer(&sta->plink_timer);
}

+static bool llid_in_use(struct ieee80211_sub_if_data *sdata,
+ __le16 llid)
+{
+ struct ieee80211_local *local = sdata->local;
+ bool in_use = false;
+ struct sta_info *sta;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
+ if (!memcmp(&sta->llid, &llid, sizeof(llid))) {
+ in_use = true;
+ break;
+ }
+ }
+ rcu_read_unlock();
+
+ return in_use;
+}
+
+static __le16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)
+{
+ u16 llid;
+
+ do {
+ get_random_bytes(&llid, sizeof(llid));
+ /* for mesh PS we still only have the AID range for TIM bits */
+ llid = (llid % IEEE80211_MAX_AID) + 1;
+ } while (llid_in_use(sdata, cpu_to_le16(llid)));
+
+ return cpu_to_le16(llid);
+}
+
u32 mesh_plink_open(struct sta_info *sta)
{
- __le16 llid;
struct ieee80211_sub_if_data *sdata = sta->sdata;
u32 changed;

@@ -625,8 +656,7 @@ u32 mesh_plink_open(struct sta_info *sta)
return 0;

spin_lock_bh(&sta->lock);
- get_random_bytes(&llid, 2);
- sta->llid = llid;
+ sta->llid = mesh_get_new_llid(sdata);
if (sta->plink_state != NL80211_PLINK_LISTEN &&
sta->plink_state != NL80211_PLINK_BLOCKED) {
spin_unlock_bh(&sta->lock);
@@ -643,7 +673,7 @@ u32 mesh_plink_open(struct sta_info *sta)
changed = ieee80211_mps_local_status_update(sdata);

mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
- sta->sta.addr, llid, 0, 0);
+ sta->sta.addr, sta->llid, 0, 0);
return changed;
}

@@ -719,7 +749,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,
break;
case OPN_ACPT:
sta->plink_state = NL80211_PLINK_OPN_RCVD;
- get_random_bytes(&sta->llid, 2);
+ sta->llid = mesh_get_new_llid(sdata);
mesh_plink_timer_set(sta,
mshcfg->dot11MeshRetryTimeout);

diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c
index 0f79b78..9493868 100644
--- a/net/mac80211/mesh_ps.c
+++ b/net/mac80211/mesh_ps.c
@@ -576,10 +576,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta,
int ac, buffer_local = 0;
bool has_buffered = false;

- /* TIM map only for LLID <= IEEE80211_MAX_AID */
if (sta->plink_state == NL80211_PLINK_ESTAB)
has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len,
- le16_to_cpu(sta->llid) % IEEE80211_MAX_AID);
+ le16_to_cpu(sta->llid));

if (has_buffered)
mps_dbg(sta->sdata, "%pM indicates buffered frames\n",
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 1eb66e2..7a91515 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -630,8 +630,8 @@ void sta_info_recalc_tim(struct sta_info *sta)
#ifdef CONFIG_MAC80211_MESH
} else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {
ps = &sta->sdata->u.mesh.ps;
- /* TIM map only for PLID <= IEEE80211_MAX_AID */
- id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;
+ /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */
+ id = le16_to_cpu(sta->plid) % (IEEE80211_MAX_AID + 1);
#endif
} else {
return;
--
1.8.4.rc3


2013-11-05 19:22:45

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 04/17] mac80211: mesh: factor out common plink close/estab code

From: Bob Copeland <[email protected]>

Reject and accepted close events always put the host in the
holding state and compute a reason code based only on the
current state. Likewise on establish we always do the same
setup. Put these in functions to save some duplicated code.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 98 +++++++++++++++++++++--------------------------
1 file changed, 43 insertions(+), 55 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index c3a3faf..3bab76f 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -655,6 +655,39 @@ u32 mesh_plink_block(struct sta_info *sta)
return changed;
}

+static void mesh_plink_close(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ enum plink_event event)
+{
+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+
+ __le16 reason = (event == CLS_ACPT) ?
+ cpu_to_le16(WLAN_REASON_MESH_CLOSE) :
+ cpu_to_le16(WLAN_REASON_MESH_CONFIG);
+
+ sta->reason = reason;
+ sta->plink_state = NL80211_PLINK_HOLDING;
+ if (!mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout))
+ sta->ignore_plink_timer = true;
+}
+
+static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta)
+{
+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
+ u32 changed = 0;
+
+ del_timer(&sta->plink_timer);
+ sta->plink_state = NL80211_PLINK_ESTAB;
+ changed |= mesh_plink_inc_estab_count(sdata);
+ changed |= mesh_set_ht_prot_mode(sdata);
+ changed |= mesh_set_short_slot_time(sdata);
+ mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr);
+ ieee80211_mps_sta_status_update(sta);
+ changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode);
+ return changed;
+}
+

void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len,
@@ -671,7 +704,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
u8 ie_len;
u8 *baseaddr;
u32 changed = 0;
- __le16 plid, llid, reason;
+ __le16 plid, llid;

/* need action_code, aux */
if (len < IEEE80211_MIN_ACTION_SIZE + 3)
@@ -782,10 +815,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,

if (!sta && !matches_local) {
rcu_read_unlock();
- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
llid = 0;
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
- mgmt->sa, llid, plid, reason);
+ mgmt->sa, llid, plid,
+ cpu_to_le16(WLAN_REASON_MESH_CONFIG));
return;
} else if (!sta) {
/* ftype == WLAN_SP_MESH_PEERING_OPEN */
@@ -850,7 +883,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,

mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
mplstates[sta->plink_state], mplevents[event]);
- reason = 0;
spin_lock_bh(&sta->lock);
switch (sta->plink_state) {
case NL80211_PLINK_LISTEN:
@@ -880,18 +912,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
- if (!reason)
- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
- sta->reason = reason;
- sta->plink_state = NL80211_PLINK_HOLDING;
- if (!mod_plink_timer(sta,
- mshcfg->dot11MeshHoldingTimeout))
- sta->ignore_plink_timer = true;
-
+ mesh_plink_close(sdata, sta, event);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
+
case OPN_ACPT:
/* retry timer is left untouched */
sta->plink_state = NL80211_PLINK_OPN_RCVD;
@@ -914,32 +939,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
- if (!reason)
- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
- sta->reason = reason;
- sta->plink_state = NL80211_PLINK_HOLDING;
- if (!mod_plink_timer(sta,
- mshcfg->dot11MeshHoldingTimeout))
- sta->ignore_plink_timer = true;
-
+ mesh_plink_close(sdata, sta, event);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
- del_timer(&sta->plink_timer);
- sta->plink_state = NL80211_PLINK_ESTAB;
- changed |= mesh_plink_inc_estab_count(sdata);
- changed |= mesh_set_ht_prot_mode(sdata);
- changed |= mesh_set_short_slot_time(sdata);
- mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
- sta->sta.addr);
- ieee80211_mps_sta_status_update(sta);
- changed |= ieee80211_mps_set_sta_local_pm(sta,
- mshcfg->power_mode);
+ changed |= mesh_plink_establish(sdata, sta);
break;
default:
break;
@@ -950,30 +958,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
case CLS_ACPT:
- if (!reason)
- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
- sta->reason = reason;
- sta->plink_state = NL80211_PLINK_HOLDING;
- if (!mod_plink_timer(sta,
- mshcfg->dot11MeshHoldingTimeout))
- sta->ignore_plink_timer = true;
-
+ mesh_plink_close(sdata, sta, event);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
- del_timer(&sta->plink_timer);
- sta->plink_state = NL80211_PLINK_ESTAB;
- changed |= mesh_plink_inc_estab_count(sdata);
- changed |= mesh_set_ht_prot_mode(sdata);
- changed |= mesh_set_short_slot_time(sdata);
- mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
- sta->sta.addr);
+ changed |= mesh_plink_establish(sdata, sta);
action = WLAN_SP_MESH_PEERING_CONFIRM;
- ieee80211_mps_sta_status_update(sta);
- changed |= ieee80211_mps_set_sta_local_pm(sta,
- mshcfg->power_mode);
break;
default:
break;
@@ -983,13 +974,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
case NL80211_PLINK_ESTAB:
switch (event) {
case CLS_ACPT:
- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
- sta->reason = reason;
changed |= __mesh_plink_deactivate(sta);
- sta->plink_state = NL80211_PLINK_HOLDING;
- mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= mesh_set_short_slot_time(sdata);
+ mesh_plink_close(sdata, sta, event);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
--
1.8.4.rc3


2013-11-06 10:36:01

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 01/17] mac80211: fix off-by-one in llid check.

Very nice. I've squashed the llid assignment into the patch that
introduced the warning.

johannes


2013-11-05 19:23:04

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 13/17] mac80211: assign sta plid early

If we store the peer link ID right after initializing a
new neighbor, there is no need to do it later in the
peering FSM.

Signed-off-by: Thomas Pedersen <[email protected]>
---
net/mac80211/mesh_plink.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index e70f490..fa86d35 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -844,6 +844,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");
goto unlock_rcu;
}
+ sta->plid = plid;
}

mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,
@@ -857,7 +858,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
break;
case OPN_ACPT:
sta->plink_state = NL80211_PLINK_OPN_RCVD;
- sta->plid = plid;
get_random_bytes(&llid, 2);
sta->llid = llid;
mesh_plink_timer_set(sta,
@@ -885,7 +885,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,
case OPN_ACPT:
/* retry timer is left untouched */
sta->plink_state = NL80211_PLINK_OPN_RCVD;
- sta->plid = plid;
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
--
1.8.4.rc3


2013-11-05 19:22:43

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 03/17] mac80211: hold sta->lock across plink switch statements

From: Bob Copeland <[email protected]>

Rather than unlock at the end of each case, do it once after
all is said and done.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 29 +++--------------------------
1 file changed, 3 insertions(+), 26 deletions(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index d45826e..c3a3faf 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -575,7 +575,6 @@ static void mesh_plink_timer(unsigned long data)
rand % sta->plink_timeout;
++sta->plink_retries;
mod_plink_timer(sta, sta->plink_timeout);
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_OPEN;
break;
}
@@ -587,19 +586,17 @@ static void mesh_plink_timer(unsigned long data)
reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
sta->plink_state = NL80211_PLINK_HOLDING;
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case NL80211_PLINK_HOLDING:
/* holding timer */
del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
+ spin_unlock_bh(&sta->lock);
if (action)
mesh_plink_frame_tx(sdata, action, sta->sta.addr,
llid, plid, reason);
@@ -856,12 +853,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
reason = 0;
spin_lock_bh(&sta->lock);
switch (sta->plink_state) {
- /* spin_unlock as soon as state is updated at each case */
case NL80211_PLINK_LISTEN:
switch (event) {
case CLS_ACPT:
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
sta->plink_state = NL80211_PLINK_OPN_RCVD;
@@ -874,11 +869,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
/* set the non-peer mode to active during peering */
changed |= ieee80211_mps_local_status_update(sdata);

- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_OPEN;
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -897,14 +890,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
/* retry timer is left untouched */
sta->plink_state = NL80211_PLINK_OPN_RCVD;
sta->plid = plid;
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
@@ -913,10 +904,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshConfirmTimeout))
sta->ignore_plink_timer = true;

- spin_unlock_bh(&sta->lock);
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -935,17 +924,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
case CNF_ACPT:
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
- spin_unlock_bh(&sta->lock);
changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= mesh_set_short_slot_time(sdata);
@@ -956,7 +942,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->power_mode);
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -975,13 +960,11 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->dot11MeshHoldingTimeout))
sta->ignore_plink_timer = true;

- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
- spin_unlock_bh(&sta->lock);
changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= mesh_set_short_slot_time(sdata);
@@ -993,7 +976,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
mshcfg->power_mode);
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -1006,17 +988,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
changed |= __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
- spin_unlock_bh(&sta->lock);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= mesh_set_short_slot_time(sdata);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
case OPN_ACPT:
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CONFIRM;
break;
default:
- spin_unlock_bh(&sta->lock);
break;
}
break;
@@ -1026,26 +1005,24 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
if (del_timer(&sta->plink_timer))
sta->ignore_plink_timer = 1;
mesh_plink_fsm_restart(sta);
- spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
case CNF_ACPT:
case OPN_RJCT:
case CNF_RJCT:
- spin_unlock_bh(&sta->lock);
action = WLAN_SP_MESH_PEERING_CLOSE;
break;
default:
- spin_unlock_bh(&sta->lock);
+ break;
}
break;
default:
/* should not get here, PLINK_BLOCKED is dealt with at the
* beginning of the function
*/
- spin_unlock_bh(&sta->lock);
break;
}
+ spin_unlock_bh(&sta->lock);
if (action) {
mesh_plink_frame_tx(sdata, action, sta->sta.addr,
sta->llid, sta->plid, sta->reason);
--
1.8.4.rc3


2013-11-05 19:22:56

by Thomas Pedersen

[permalink] [raw]
Subject: [PATCH 09/17] mac80211: return -ENOMEM in mesh_plink_frame_tx

From: Bob Copeland <[email protected]>

All other paths return an error code, do the same here.

Signed-off-by: Bob Copeland <[email protected]>
---
net/mac80211/mesh_plink.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 550ebc1..429f692 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -283,7 +283,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
2 + 8 + /* peering IE */
sdata->u.mesh.ie_len);
if (!skb)
- return -1;
+ return err;
info = IEEE80211_SKB_CB(skb);
skb_reserve(skb, local->tx_headroom);
mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
--
1.8.4.rc3