This file implements mesh discovery and peer link establishment support using
the mesh peer link table provided in mesh_plinktbl.c.
Secure peer links have not been implemented yet.
Signed-off-by: Luis Carlos Cobo <[email protected]>
---
net/mac80211/mesh_plinkfsm.c | 742 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 742 insertions(+), 0 deletions(-)
create mode 100644 net/mac80211/mesh_plinkfsm.c
diff --git a/net/mac80211/mesh_plinkfsm.c b/net/mac80211/mesh_plinkfsm.c
new file mode 100644
index 0000000..e657edd
--- /dev/null
+++ b/net/mac80211/mesh_plinkfsm.c
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2008 open80211s Ltd.
+ * Author: Luis Carlos Cobo <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "ieee80211_i.h"
+#include "mesh.h"
+#include <linux/random.h>
+
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args)
+#else
+#define mpl_dbg(fmt, args...) do { (void)(0); } while (0)
+#endif
+
+#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype)
+#define PLINK_GET_FRAME_SUBTYPE(p) (p)
+#define PLINK_GET_LLID(p) (p + 1)
+#define PLINK_GET_PLID(p) (p + 3)
+
+#define mod_plink_timer(m, t) (mod_timer(&m->timer, jiffies + HZ * t / 1000))
+
+/* Peer link cancel reasons, all subject to ANA approval */
+#define MESH_LINK_CANCELLED 2
+#define MESH_MAX_NEIGHBORS 3
+#define MESH_CAPABILITY_POLICY_VIOLATION 4
+#define MESH_CLOSE_RCVD 5
+#define MESH_MAX_RETRIES 6
+#define MESH_CONFIRM_TIMEOUT 7
+#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8
+#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
+#define MESH_SECURITY_FAILED_VERIFICATION 10
+
+#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries)
+#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout)
+#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout)
+#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout)
+#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks)
+
+enum plink_frame_type {
+ PLINK_OPEN = 0,
+ PLINK_CONFIRM,
+ PLINK_CLOSE
+};
+
+enum plink_event {
+ PLINK_UNDEFINED,
+ OPN_ACPT,
+ OPN_RJCT,
+ OPN_IGNR,
+ CNF_ACPT,
+ CNF_RJCT,
+ CNF_IGNR,
+ CLS_ACPT,
+ CLS_IGNR
+};
+
+int mesh_plink_open(u8 *hw_addr, struct net_device *dev);
+
+static int mesh_send_plink_frame(struct net_device *dev,
+ enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
+ __le16 reason) {
+ struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+ struct ieee80211_mgmt *mgmt;
+ bool include_plid = false;
+ u8 *pos;
+ int ie_len;
+
+ if (!skb)
+ return -1;
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+ /* 25 is the size of the common mgmt part (24) plus the size of the
+ * common action part (1)
+ */
+ mgmt = (struct ieee80211_mgmt *)
+ skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
+ memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
+ mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT,
+ IEEE80211_STYPE_ACTION);
+ memcpy(mgmt->da, da, ETH_ALEN);
+ memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN);
+ /* BSSID is left zeroed, wildcard value */
+ mgmt->u.action.category = PLINK_CATEGORY;
+ mgmt->u.action.u.plink_action.action_code = action;
+
+ if (action == PLINK_CLOSE)
+ mgmt->u.action.u.plink_action.aux = reason;
+ else {
+ mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
+ if (action == PLINK_CONFIRM) {
+ pos = skb_put(skb, 4);
+ /* two-byte status code followed by two-byte AID */
+ memset(pos, 0, 4);
+ }
+ mesh_add_mgmt_ies(skb, dev);
+ }
+
+ /* Add Peer Link Management element */
+ switch (action) {
+ case PLINK_OPEN:
+ ie_len = 3;
+ break;
+ case PLINK_CONFIRM:
+ ie_len = 5;
+ include_plid = true;
+ break;
+ case PLINK_CLOSE:
+ default:
+ if (!plid)
+ ie_len = 5;
+ else {
+ ie_len = 7;
+ include_plid = true;
+ }
+ break;
+ }
+
+ pos = skb_put(skb, 2 + ie_len);
+ *pos++ = WLAN_EID_PEER_LINK;
+ *pos++ = ie_len;
+ *pos++ = action;
+ memcpy(pos, &llid, 2);
+ if (include_plid) {
+ pos += 2;
+ memcpy(pos, &plid, 2);
+ }
+ if (action == PLINK_CLOSE) {
+ pos += 2;
+ memcpy(pos, &reason, 2);
+ }
+
+ ieee80211_sta_tx(dev, skb, 0);
+ return 0;
+}
+
+void update_mesh_neighbour(u8 *hw_addr, struct net_device *dev, bool add)
+{
+ struct mesh_plink *mpl;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ if (mpl) {
+ mpl->last_active = jiffies;
+ rcu_read_unlock();
+ } else if (add && plink_capacity(sdata)) {
+ rcu_read_unlock();
+ add_mesh_neighbour(hw_addr, dev);
+ } else
+ rcu_read_unlock();
+}
+
+
+
+int add_mesh_neighbour(u8 *hw_addr, struct net_device *dev)
+{
+ int err;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ err = add_mesh_plink(hw_addr, dev);
+ if (err)
+ return err;
+
+ if (sdata->u.sta.mshcfg.auto_open_plinks)
+ return mesh_plink_open(hw_addr, dev);
+
+ return err;
+}
+
+bool is_estab_plink(u8 *hw_addr, struct net_device *dev)
+{
+ struct mesh_plink *mpl;
+ bool ret;
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ if (!mpl) {
+ ret = false;
+ goto endestab;
+ }
+
+ mpl->last_active = jiffies;
+ ret = mpl->state == ESTAB;
+
+endestab:
+ rcu_read_unlock();
+ return ret;
+}
+
+static void plink_timer(unsigned long data)
+{
+ struct mesh_plink *mpl;
+ __le16 llid, plid, reason;
+ bool del_mpl = false;
+ struct net_device *dev = NULL;
+ struct ieee80211_sub_if_data *sdata;
+ u8 ha[ETH_ALEN];
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ rcu_read_lock();
+ mpl = (struct mesh_plink *) data;
+ mpl = rcu_dereference(mpl);
+ if (!mpl) {
+ mpl_dbg("Mesh plink: timer's mpl vanished\n");
+ goto endpltimer;
+ }
+ spin_lock_bh(&mpl->state_lock);
+ if (mpl->ignore_timer) {
+ mpl->ignore_timer = false;
+ spin_unlock_bh(&mpl->state_lock);
+ goto endpltimer;
+ }
+ mpl_dbg("Mesh plink timer for %s fired on state %d\n",
+ print_mac(mac, mpl->ha), mpl->state);
+ reason = 0;
+ llid = mpl->llid;
+ plid = mpl->plid;
+ dev = mpl->dev;
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ switch (mpl->state) {
+ case OPN_RCVD:
+ case OPN_SNT:
+ /* retry timer */
+ if (mpl->retries < dot11MeshMaxRetries(sdata)) {
+ u32 rand;
+ mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n",
+ print_mac(mac, mpl->ha),
+ mpl->retries, mpl->timeout);
+ get_random_bytes(&rand, sizeof(u32));
+ mpl->timeout = mpl->timeout + rand % mpl->timeout;
+ ++mpl->retries;
+ mod_plink_timer(mpl, mpl->timeout);
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_OPEN,
+ mpl->ha, llid, 0, 0);
+ break;
+ }
+ reason = cpu_to_le16(MESH_MAX_RETRIES);
+ /* fall through on else */
+ case CNF_RCVD:
+ /* confirm timer */
+ if (!reason)
+ reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
+ mpl->state = HOLDING;
+ mod_plink_timer(mpl, dot11MeshHoldingTimeout(sdata));
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ break;
+ case HOLDING:
+ /* holding timer */
+ del_timer(&mpl->timer);
+ spin_unlock_bh(&mpl->state_lock);
+ del_mpl = true;
+ memcpy(ha, mpl->ha, ETH_ALEN);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+
+endpltimer:
+ rcu_read_unlock();
+ if (del_mpl)
+ del_mesh_plink(ha, dev);
+}
+
+
+static void set_plink_timer(struct mesh_plink *mpl, int timeout)
+{
+ mpl->timer.expires = jiffies + (HZ * timeout / 1000);
+ mpl->timer.data = (unsigned long) mpl;
+ mpl->timer.function = plink_timer;
+ mpl->timeout = timeout;
+ add_timer(&mpl->timer);
+}
+
+int mesh_plink_open(u8 *hw_addr, struct net_device *dev)
+{
+ struct mesh_plink *mpl;
+ __le16 llid;
+ int err;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ if (!mpl) {
+ err = -ENXIO;
+ goto endopen;
+ }
+
+ spin_lock_bh(&mpl->state_lock);
+ get_random_bytes(&llid, 2);
+ mpl->llid = llid;
+ if (mpl->state != LISTEN) {
+ err = -EBUSY;
+ spin_unlock_bh(&mpl->state_lock);
+ goto endopen;
+ }
+ mpl->state = OPN_SNT;
+ set_plink_timer(mpl, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&mpl->state_lock);
+ mpl_dbg("Mesh plink: starting establishment with %s\n",
+ print_mac(mac, mpl->ha));
+
+ err = mesh_send_plink_frame(dev, PLINK_OPEN, hw_addr, llid, 0, 0);
+
+endopen:
+ rcu_read_unlock();
+ return err;
+}
+
+int mesh_plink_block(u8 *hw_addr, struct net_device *dev)
+{
+ struct mesh_plink *mpl;
+ int err = 0;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ if (!mpl) {
+ rcu_read_unlock();
+ add_mesh_plink(hw_addr, dev);
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ }
+
+ if (!mpl) {
+ err = -ENXIO;
+ goto endblock;
+ }
+
+ spin_lock_bh(&mpl->state_lock);
+ deactivate_plink(mpl);
+ mpl->state = BLOCKED;
+ spin_unlock_bh(&mpl->state_lock);
+
+endblock:
+ rcu_read_unlock();
+ return err;
+}
+
+int mesh_plink_close(u8 *hw_addr, struct net_device *dev)
+{
+ struct mesh_plink *mpl;
+ int err = 0;
+ int llid, plid, reason;
+ bool del_mpl = false;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(hw_addr, dev);
+ if (!mpl) {
+ err = -ENXIO;
+ goto endclose;
+ }
+
+ mpl_dbg("Mesh plink: closing link with %s\n", print_mac(mac, mpl->ha));
+ spin_lock_bh(&mpl->state_lock);
+ mpl->reason = cpu_to_le16(MESH_LINK_CANCELLED);
+ reason = mpl->reason;
+ if (mpl->state == LISTEN || mpl->state == BLOCKED)
+ del_mpl = true;
+ else if (mpl->state == ESTAB) {
+ deactivate_plink(mpl);
+ mod_plink_timer(mpl, dot11MeshHoldingTimeout(sdata));
+ } else if (!mod_plink_timer(mpl, dot11MeshHoldingTimeout(sdata)))
+ mpl->ignore_timer = true;
+ mpl->state = HOLDING;
+ llid = mpl->llid;
+ plid = mpl->plid;
+ spin_unlock_bh(&mpl->state_lock);
+ if (!del_mpl)
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+endclose:
+ rcu_read_unlock();
+ if (del_mpl)
+ del_mesh_plink(hw_addr, dev);
+ return err;
+}
+
+void mesh_rx_plink_frame(struct net_device *dev,
+ struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee802_11_elems elems;
+ struct mesh_plink *mpl;
+ enum plink_event event;
+ enum plink_frame_type ftype;
+ size_t baselen;
+ bool del_mpl = false;
+ u8 ie_len;
+ u8 *baseaddr;
+ __le16 plid, llid, reason;
+#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
+ DECLARE_MAC_BUF(mac);
+#endif
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (is_multicast_ether_addr(mgmt->da)) {
+ mpl_dbg("Mesh plink: ignore frame from multicast address");
+ return;
+ }
+
+ baseaddr = mgmt->u.action.u.plink_action.variable;
+ baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
+ if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
+ baseaddr += 4;
+ baselen -= 4;
+ }
+ ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
+ if (!elems.peer_link) {
+ mpl_dbg("Mesh plink: missing necessary peer link ie\n");
+ return;
+ }
+
+ ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
+ ie_len = elems.peer_link_len;
+ if ((ftype == PLINK_OPEN && ie_len != 3) ||
+ (ftype == PLINK_CONFIRM && ie_len != 5) ||
+ (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) {
+ mpl_dbg("Mesh plink: incorrect plink ie length\n");
+ return;
+ }
+
+ if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
+ mpl_dbg("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.peer_link), 2);
+ if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
+ memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
+
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(mgmt->sa, dev);
+ if (mpl)
+ mpl->last_active = jiffies;
+ if (!mpl && ftype != PLINK_OPEN) {
+ mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
+ rcu_read_unlock();
+ return;
+ }
+
+ if (mpl && mpl->state == BLOCKED) {
+ rcu_read_unlock();
+ return;
+ }
+
+ /* Now we will figure out the appropriate event... */
+ event = PLINK_UNDEFINED;
+ if (ftype != PLINK_CLOSE && (!same_mesh(mgmt, &elems, dev))) {
+ switch (ftype) {
+ case PLINK_OPEN:
+ event = OPN_RJCT;
+ break;
+ case PLINK_CONFIRM:
+ event = CNF_RJCT;
+ break;
+ case PLINK_CLOSE:
+ /* avoid warning */
+ break;
+ }
+ spin_lock_bh(&mpl->state_lock);
+ } else if (!mpl) {
+ /* ftype == PLINK_OPEN */
+ if (!plink_capacity(sdata)) {
+ mpl_dbg("Mesh plink error: no more free plinks\n");
+ return;
+ }
+ rcu_read_unlock();
+ add_mesh_neighbour(mgmt->sa, dev);
+ rcu_read_lock();
+ mpl = mesh_plink_lookup(mgmt->sa, dev);
+ if (!mpl) {
+ mpl_dbg("Mesh plink error: plink table full\n");
+ rcu_read_unlock();
+ return;
+ }
+ event = OPN_ACPT;
+ spin_lock_bh(&mpl->state_lock);
+ } else {
+ spin_lock_bh(&mpl->state_lock);
+ switch (ftype) {
+ case PLINK_OPEN:
+ if (!plink_capacity(sdata) ||
+ (mpl->plid && mpl->plid != plid))
+ event = OPN_IGNR;
+ else
+ event = OPN_ACPT;
+ break;
+ case PLINK_CONFIRM:
+ if (!plink_capacity(sdata) ||
+ (mpl->llid != llid || mpl->plid != plid))
+ event = CNF_IGNR;
+ else
+ event = CNF_ACPT;
+ break;
+ case PLINK_CLOSE:
+ if (mpl->state == ESTAB)
+ /* This does not follow the standard, but it is
+ * necessary to avoid a livelock when node sees
+ * the link as ESTAB and the other does not,
+ * without having to support multiple plinks
+ * per peer
+ */
+ event = CLS_ACPT;
+ else if (mpl->plid != plid)
+ event = CLS_IGNR;
+ else if (ie_len == 7 && mpl->llid != llid)
+ event = CLS_IGNR;
+ else
+ event = CLS_ACPT;
+ break;
+ default:
+ mpl_dbg("Mesh plink: unknown frame subtype\n");
+ spin_unlock_bh(&mpl->state_lock);
+ rcu_read_unlock();
+ return;
+ }
+ }
+
+ mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n",
+ print_mac(mac, mgmt->sa), mpl->state,
+ __le16_to_cpu(mpl->llid), __le16_to_cpu(mpl->plid),
+ event);
+ reason = 0;
+ switch (mpl->state) {
+ /* spin_unlock as soon as state is updated at each case */
+ case LISTEN:
+ switch (event) {
+ case CLS_ACPT:
+ mpl->state = BLOCKED;
+ spin_unlock_bh(&mpl->state_lock);
+ del_mpl = true;
+ break;
+ case OPN_ACPT:
+ mpl->state = OPN_RCVD;
+ mpl->plid = plid;
+ get_random_bytes(&llid, 2);
+ mpl->llid = llid;
+ set_plink_timer(mpl, dot11MeshRetryTimeout(sdata));
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_OPEN,
+ mpl->ha, llid, 0, 0);
+ mesh_send_plink_frame(dev, PLINK_CONFIRM,
+ mpl->ha, llid, plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ break;
+
+ case OPN_SNT:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ mpl->reason = reason;
+ mpl->state = HOLDING;
+ if (!mod_plink_timer(mpl,
+ dot11MeshHoldingTimeout(sdata)))
+ mpl->ignore_timer = true;
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ break;
+ case OPN_ACPT:
+ /* retry timer is left untouched */
+ mpl->state = OPN_RCVD;
+ mpl->plid = plid;
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CONFIRM,
+ mpl->ha, llid, plid, 0);
+ break;
+ case CNF_ACPT:
+ mpl->state = CNF_RCVD;
+ if (!mod_plink_timer(mpl,
+ dot11MeshConfirmTimeout(sdata)))
+ mpl->ignore_timer = true;
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ break;
+
+ case OPN_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ mpl->reason = reason;
+ mpl->state = HOLDING;
+ if (!mod_plink_timer(mpl,
+ dot11MeshHoldingTimeout(sdata)))
+ mpl->ignore_timer = true;
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CONFIRM,
+ mpl->ha, llid, plid, 0);
+ break;
+ case CNF_ACPT:
+ del_timer(&mpl->timer);
+ mpl->state = ESTAB;
+ plink_inc(sdata);
+ spin_unlock_bh(&mpl->state_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, mpl->ha));
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ break;
+
+ case CNF_RCVD:
+ switch (event) {
+ case OPN_RJCT:
+ case CNF_RJCT:
+ reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
+ case CLS_ACPT:
+ if (!reason)
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ mpl->reason = reason;
+ mpl->state = HOLDING;
+ if (!mod_plink_timer(mpl,
+ dot11MeshHoldingTimeout(sdata)))
+ mpl->ignore_timer = 1;
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ case OPN_ACPT:
+ del_timer(&mpl->timer);
+ mpl->state = ESTAB;
+ plink_inc(sdata);
+ spin_unlock_bh(&mpl->state_lock);
+ mpl_dbg("Mesh plink with %s ESTABLISHED\n",
+ print_mac(mac, mpl->ha));
+ mesh_send_plink_frame(dev, PLINK_CONFIRM,
+ mpl->ha, llid, plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ break;
+
+ case ESTAB:
+ switch (event) {
+ case CLS_ACPT:
+ reason = cpu_to_le16(MESH_CLOSE_RCVD);
+ mpl->reason = reason;
+ deactivate_plink(mpl);
+ mpl->state = HOLDING;
+ llid = mpl->llid;
+ mod_plink_timer(mpl, dot11MeshHoldingTimeout(sdata));
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ break;
+ case OPN_ACPT:
+ llid = mpl->llid;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CONFIRM,
+ mpl->ha, llid, plid, 0);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ break;
+ case HOLDING:
+ switch (event) {
+ case CLS_ACPT:
+ if (!del_timer(&mpl->timer))
+ mpl->ignore_timer = 1;
+ del_mpl = true;
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ case OPN_ACPT:
+ case CNF_ACPT:
+ case OPN_RJCT:
+ case CNF_RJCT:
+ llid = mpl->llid;
+ reason = mpl->reason;
+ spin_unlock_bh(&mpl->state_lock);
+ mesh_send_plink_frame(dev, PLINK_CLOSE,
+ mpl->ha, llid, plid, reason);
+ break;
+ default:
+ spin_unlock_bh(&mpl->state_lock);
+ }
+ break;
+ default:
+ /* should not get here, BLOCKED is dealt with at the beggining
+ * of the function
+ */
+ spin_unlock_bh(&mpl->state_lock);
+ break;
+ }
+ rcu_read_unlock();
+
+ if (del_mpl)
+ del_mesh_plink(mgmt->sa, dev);
+}
--
1.5.2.5
On Mon, 2008-02-04 at 11:34 -0800, Luis Carlos Cobo wrote:
> This file implements mesh discovery and peer link establishment support using
> the mesh peer link table provided in mesh_plinktbl.c.
>
> Secure peer links have not been implemented yet.
How would you design implementing support secure peer links? It seems
that to do that much of the mesh bookkeeping would need to be done by
wpa_supplicant instead of the kernel. In fact, maybe it should always do
it and much of this code be migrated into wpa_supplicant's userspace
MLME?
Peer link establishment, mesh path updating etc. could all be done in
wpa_supplicant's userspace MLME, no? If we add all this to the kernel
now, would we have to reimplement it in the userspace MLME to support
secure peer links?
johannes
On Thu, 2008-02-07 at 02:13 +0100, Johannes Berg wrote:
> How would you design implementing support secure peer links? It seems
> that to do that much of the mesh bookkeeping would need to be done by
> wpa_supplicant instead of the kernel. In fact, maybe it should always do
> it and much of this code be migrated into wpa_supplicant's userspace
> MLME?
We definitely would implement security in user space but have not
decided yet were to draw the line. I think that it makes sense at least
to have path discovery in-kernel, since there is a lot of activity on
them (each path is rebuilt every few seconds and there can be many of
them) and many path discovery frames just need to be forwarded and do
not have to be transferred to user space.
> Peer link establishment, mesh path updating etc. could all be done in
> wpa_supplicant's userspace MLME, no? If we add all this to the kernel
> now, would we have to reimplement it in the userspace MLME to support
> secure peer links?
AFAIK, it would only be necessary to move part of the peer link
establishment to user space. Path discovery takes place after the peer
links have been established.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.
--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.