All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 0/5] mesh join/leave API
@ 2010-12-01 20:59 Johannes Berg
  2010-12-01 20:59 ` [RFC 1/5] mac80211: use configured mesh TTL Johannes Berg
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

I'm heading to bed ... so the TTL thing will
have to be figured out later. I've also not
tested this at all, maybe you can :-)

Basically the idea is to decouple the state
of mesh from interface UP/DOWN and add new
commands to join/leave.

Then the beacon configuration can be part of
join -- I suppose things that can change on
the fly will be part of the mesh_config, and
things that can't will become part of a new
mesh_setup struct or so ... This way there's
no need for new commands or such, just add
new attributes to the join command...

Anyway, just an implementation of the ideas
I was toying with.

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 1/5] mac80211: use configured mesh TTL
  2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
@ 2010-12-01 20:59 ` Johannes Berg
  2010-12-01 20:59 ` [RFC 2/5] mac80211: move mesh filter adjusting Johannes Berg
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

It seems the configured mesh TTL should be used,
not the default value.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/mesh.h         |    2 ++
 net/mac80211/mesh_hwmp.c    |    5 +++--
 net/mac80211/mesh_pathtbl.c |    5 +++--
 3 files changed, 8 insertions(+), 4 deletions(-)

--- wireless-testing.orig/net/mac80211/mesh_pathtbl.c	2010-12-01 21:46:30.000000000 +0100
+++ wireless-testing/net/mac80211/mesh_pathtbl.c	2010-12-01 21:58:56.000000000 +0100
@@ -467,7 +467,7 @@ void mesh_plink_broken(struct sta_info *
 			mpath->flags &= ~MESH_PATH_ACTIVE;
 			++mpath->sn;
 			spin_unlock_bh(&mpath->state_lock);
-			mesh_path_error_tx(MESH_TTL, mpath->dst,
+			mesh_path_error_tx(MESH_DEFAULT_ELEMENT_TTL, mpath->dst,
 					cpu_to_le32(mpath->sn),
 					cpu_to_le16(PERR_RCODE_DEST_UNREACH),
 					bcast, sdata);
@@ -614,7 +614,8 @@ void mesh_path_discard_frame(struct sk_b
 		mpath = mesh_path_lookup(da, sdata);
 		if (mpath)
 			sn = ++mpath->sn;
-		mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn),
+		mesh_path_error_tx(MESH_DEFAULT_ELEMENT_TTL, skb->data,
+				   cpu_to_le32(sn),
 				   cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
 	}
 
--- wireless-testing.orig/net/mac80211/mesh_hwmp.c	2010-12-01 21:46:30.000000000 +0100
+++ wireless-testing/net/mac80211/mesh_hwmp.c	2010-12-01 21:49:23.000000000 +0100
@@ -232,7 +232,7 @@ int mesh_path_error_tx(u8 ttl, u8 *targe
 	*pos++ = WLAN_EID_PERR;
 	*pos++ = ie_len;
 	/* ttl */
-	*pos++ = MESH_TTL;
+	*pos++ = ttl;
 	/* number of destinations */
 	*pos++ = 1;
 	/*
@@ -1013,5 +1013,6 @@ mesh_path_tx_root_frame(struct ieee80211
 	mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
 			       cpu_to_le32(++ifmsh->sn),
 			       0, NULL, 0, broadcast_addr,
-			       0, MESH_TTL, 0, 0, 0, sdata);
+			       0, sdata->u.mesh.mshcfg.dot11MeshTTL,
+			       0, 0, 0, sdata);
 }
--- wireless-testing.orig/net/mac80211/mesh.h	2010-12-01 21:57:44.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.h	2010-12-01 21:58:01.000000000 +0100
@@ -216,6 +216,8 @@ struct mesh_rmc {
 #define PERR_RCODE_NO_ROUTE     12
 #define PERR_RCODE_DEST_UNREACH 13
 
+#define MESH_DEFAULT_ELEMENT_TTL 31
+
 /* Public interfaces */
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 2/5] mac80211: move mesh filter adjusting
  2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
  2010-12-01 20:59 ` [RFC 1/5] mac80211: use configured mesh TTL Johannes Berg
@ 2010-12-01 20:59 ` Johannes Berg
  2010-12-01 20:59 ` [RFC 3/5] cfg80211: require add_virtual_intf to return new dev Johannes Berg
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

Logically, the filter adjusting belongs with
starting/stopping mesh, not interface up/down,
so move it there.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/mac80211/iface.c |   18 +-----------------
 net/mac80211/mesh.c  |   11 +++++++++++
 2 files changed, 12 insertions(+), 17 deletions(-)

--- wireless-testing.orig/net/mac80211/iface.c	2010-12-01 20:24:46.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2010-12-01 20:28:08.000000000 +0100
@@ -197,11 +197,6 @@ static int ieee80211_do_open(struct net_
 		sdata->bss = &sdata->u.ap;
 		break;
 	case NL80211_IFTYPE_MESH_POINT:
-		if (!ieee80211_vif_is_mesh(&sdata->vif))
-			break;
-		/* mesh ifaces must set allmulti to forward mcast traffic */
-		atomic_inc(&local->iff_allmultis);
-		break;
 	case NL80211_IFTYPE_STATION:
 	case NL80211_IFTYPE_MONITOR:
 	case NL80211_IFTYPE_ADHOC:
@@ -274,9 +269,6 @@ static int ieee80211_do_open(struct net_
 		}
 
 		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			local->fif_other_bss++;
-			ieee80211_configure_filter(local);
-
 			ieee80211_start_mesh(sdata);
 		} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
 			local->fif_pspoll++;
@@ -504,16 +496,8 @@ static void ieee80211_do_stop(struct iee
 		ieee80211_configure_filter(local);
 		break;
 	case NL80211_IFTYPE_MESH_POINT:
-		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			/* other_bss and allmulti are always set on mesh
-			 * ifaces */
-			local->fif_other_bss--;
-			atomic_dec(&local->iff_allmultis);
-
-			ieee80211_configure_filter(local);
-
+		if (ieee80211_vif_is_mesh(&sdata->vif))
 			ieee80211_stop_mesh(sdata);
-		}
 		/* fall through */
 	default:
 		flush_work(&sdata->work);
--- wireless-testing.orig/net/mac80211/mesh.c	2010-12-01 20:24:46.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.c	2010-12-01 20:29:36.000000000 +0100
@@ -513,6 +513,11 @@ void ieee80211_start_mesh(struct ieee802
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_local *local = sdata->local;
 
+	local->fif_other_bss++;
+	/* mesh ifaces must set allmulti to forward mcast traffic */
+	atomic_inc(&local->iff_allmultis);
+	ieee80211_configure_filter(local);
+
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 	ieee80211_mesh_root_setup(ifmsh);
 	ieee80211_queue_work(&local->hw, &sdata->work);
@@ -524,6 +529,8 @@ void ieee80211_start_mesh(struct ieee802
 
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_local *local = sdata->local;
+
 	del_timer_sync(&sdata->u.mesh.housekeeping_timer);
 	del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
 	/*
@@ -534,6 +541,10 @@ void ieee80211_stop_mesh(struct ieee8021
 	 * it no longer is.
 	 */
 	cancel_work_sync(&sdata->work);
+
+	local->fif_other_bss--;
+	atomic_dec(&local->iff_allmultis);
+	ieee80211_configure_filter(local);
 }
 
 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 3/5] cfg80211: require add_virtual_intf to return new dev
  2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
  2010-12-01 20:59 ` [RFC 1/5] mac80211: use configured mesh TTL Johannes Berg
  2010-12-01 20:59 ` [RFC 2/5] mac80211: move mesh filter adjusting Johannes Berg
@ 2010-12-01 20:59 ` Johannes Berg
  2010-12-01 20:59 ` [RFC 4/5] nl80211: refactor mesh parameter parsing Johannes Berg
  2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
  4 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

cfg80211 used to do all its bookkeeping in
the notifier, but some new stuff will have
to use local variables so make the callback
return the netdev pointer.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/net/cfg80211.h |   11 +++++++----
 net/mac80211/cfg.c     |   20 ++++++++++++--------
 net/wireless/nl80211.c |    7 +++++--
 3 files changed, 24 insertions(+), 14 deletions(-)

--- wireless-testing.orig/include/net/cfg80211.h	2010-12-01 21:06:31.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2010-12-01 21:07:35.000000000 +0100
@@ -1031,7 +1031,8 @@ struct cfg80211_pmksa {
  *
  * @add_virtual_intf: create a new virtual interface with the given name,
  *	must set the struct wireless_dev's iftype. Beware: You must create
- *	the new netdev in the wiphy's network namespace!
+ *	the new netdev in the wiphy's network namespace! Returns the netdev,
+ *	or an ERR_PTR.
  *
  * @del_virtual_intf: remove the virtual interface determined by ifindex.
  *
@@ -1159,9 +1160,11 @@ struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy);
 	int	(*resume)(struct wiphy *wiphy);
 
-	int	(*add_virtual_intf)(struct wiphy *wiphy, char *name,
-				    enum nl80211_iftype type, u32 *flags,
-				    struct vif_params *params);
+	struct net_device * (*add_virtual_intf)(struct wiphy *wiphy,
+						char *name,
+						enum nl80211_iftype type,
+						u32 *flags,
+						struct vif_params *params);
 	int	(*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev);
 	int	(*change_virtual_intf)(struct wiphy *wiphy,
 				       struct net_device *dev,
--- wireless-testing.orig/net/mac80211/cfg.c	2010-12-01 21:08:42.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2010-12-01 21:10:10.000000000 +0100
@@ -19,9 +19,10 @@
 #include "rate.h"
 #include "mesh.h"
 
-static int ieee80211_add_iface(struct wiphy *wiphy, char *name,
-			       enum nl80211_iftype type, u32 *flags,
-			       struct vif_params *params)
+static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name,
+					      enum nl80211_iftype type,
+					      u32 *flags,
+					      struct vif_params *params)
 {
 	struct ieee80211_local *local = wiphy_priv(wiphy);
 	struct net_device *dev;
@@ -29,12 +30,15 @@ static int ieee80211_add_iface(struct wi
 	int err;
 
 	err = ieee80211_if_add(local, name, &dev, type, params);
-	if (err || type != NL80211_IFTYPE_MONITOR || !flags)
-		return err;
+	if (err)
+		return ERR_PTR(err);
 
-	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	sdata->u.mntr_flags = *flags;
-	return 0;
+	if (type == NL80211_IFTYPE_MONITOR && flags) {
+		sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+		sdata->u.mntr_flags = *flags;
+	}
+
+	return dev;
 }
 
 static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev)
--- wireless-testing.orig/net/wireless/nl80211.c	2010-12-01 21:07:56.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2010-12-01 21:08:25.000000000 +0100
@@ -1368,6 +1368,7 @@ static int nl80211_new_interface(struct
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct vif_params params;
+	struct net_device *dev;
 	int err;
 	enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED;
 	u32 flags;
@@ -1403,11 +1404,13 @@ static int nl80211_new_interface(struct
 	err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
 				  info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
 				  &flags);
-	err = rdev->ops->add_virtual_intf(&rdev->wiphy,
+	dev = rdev->ops->add_virtual_intf(&rdev->wiphy,
 		nla_data(info->attrs[NL80211_ATTR_IFNAME]),
 		type, err ? NULL : &flags, &params);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
 
-	return err;
+	return 0;
 }
 
 static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info)



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 4/5] nl80211: refactor mesh parameter parsing
  2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
                   ` (2 preceding siblings ...)
  2010-12-01 20:59 ` [RFC 3/5] cfg80211: require add_virtual_intf to return new dev Johannes Berg
@ 2010-12-01 20:59 ` Johannes Berg
  2010-12-02  8:34   ` [RFC 4/5 v2] " Johannes Berg
  2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
  4 siblings, 1 reply; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

I'm going to need this in a new place later.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 net/wireless/nl80211.c |   42 ++++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)

--- wireless-testing.orig/net/wireless/nl80211.c	2010-12-01 21:36:43.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2010-12-01 21:39:52.000000000 +0100
@@ -2614,7 +2614,7 @@ static int nl80211_get_mesh_params(struc
 #define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
 do {\
 	if (table[attr_num]) {\
-		cfg.param = nla_fn(table[attr_num]); \
+		cfg->param = nla_fn(table[attr_num]); \
 		mask |= (1 << (attr_num - 1)); \
 	} \
 } while (0);\
@@ -2636,31 +2636,25 @@ static const struct nla_policy nl80211_m
 	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
 };
 
-static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_mesh_params(struct genl_info *info,
+				     struct mesh_config *cfg,
+				     u32 *mask_out)
 {
-	u32 mask;
-	struct cfg80211_registered_device *rdev = info->user_ptr[0];
-	struct net_device *dev = info->user_ptr[1];
-	struct mesh_config cfg;
 	struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
-	struct nlattr *parent_attr;
+	u32 mask = 0;
 
-	parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS];
-	if (!parent_attr)
+	if (!info->attrs[NL80211_ATTR_MESH_PARAMS])
 		return -EINVAL;
 	if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
-			parent_attr, nl80211_meshconf_params_policy))
+			     info->attrs[NL80211_ATTR_MESH_PARAMS],
+			     nl80211_meshconf_params_policy))
 		return -EINVAL;
 
-	if (!rdev->ops->set_mesh_params)
-		return -EOPNOTSUPP;
-
 	/* This makes sure that there aren't more than 32 mesh config
 	 * parameters (otherwise our bitfield scheme would not work.) */
 	BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
 
 	/* Fill in the params struct */
-	mask = 0;
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
 			mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
@@ -2698,6 +2692,26 @@ static int nl80211_set_mesh_params(struc
 			NL80211_MESHCONF_HWMP_ROOTMODE,
 			nla_get_u8);
 
+	if (mask_out)
+		*mask_out = mask;
+	return 0;
+}
+
+static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct mesh_config cfg;
+	u32 mask;
+	int err;
+
+	if (!rdev->ops->set_mesh_params)
+		return -EOPNOTSUPP;
+
+	err = nl80211_parse_mesh_params(info, &cfg, &mask);
+	if (err)
+		return err;
+
 	/* Apply changes */
 	return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
 }



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands
  2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
                   ` (3 preceding siblings ...)
  2010-12-01 20:59 ` [RFC 4/5] nl80211: refactor mesh parameter parsing Johannes Berg
@ 2010-12-01 20:59 ` Johannes Berg
  2010-12-01 21:15   ` Johannes Berg
                     ` (2 more replies)
  4 siblings, 3 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 20:59 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

Instead of tying mesh activity to interface up,
add join and leave commands for mesh. Since we
must be backward compatible, let cfg80211 handle
joining a mesh if a mesh ID was pre-configured
when the device goes up.

Note that this therefore must modify mac80211 as
well since mac80211 needs to lose the logic to
start the mesh on interface up.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
 include/linux/nl80211.h    |    7 ++
 include/net/cfg80211.h     |    9 +--
 net/mac80211/cfg.c         |   31 ++++++++--
 net/mac80211/ieee80211_i.h |   13 ----
 net/mac80211/iface.c       |   14 ----
 net/mac80211/mesh.c        |   20 ------
 net/mac80211/mesh.h        |   23 -------
 net/wireless/Makefile      |    2 
 net/wireless/core.c        |   14 ++++
 net/wireless/core.h        |   13 ++++
 net/wireless/mesh.c        |  133 +++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.c     |   84 +++++++++++++++++++++++++---
 12 files changed, 273 insertions(+), 90 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/include/linux/nl80211.h	2010-12-01 21:40:18.000000000 +0100
@@ -394,6 +394,10 @@
  *
  * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
  *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh  ...
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ *	network is determined by the network interface.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -500,6 +504,9 @@ enum nl80211_commands {
 
 	NL80211_CMD_FRAME_WAIT_CANCEL,
 
+	NL80211_CMD_JOIN_MESH,
+	NL80211_CMD_LEAVE_MESH,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
--- wireless-testing.orig/include/net/cfg80211.h	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2010-12-01 21:40:18.000000000 +0100
@@ -258,13 +258,9 @@ struct ieee80211_supported_band {
 
 /**
  * struct vif_params - describes virtual interface parameters
- * @mesh_id: mesh ID to use
- * @mesh_id_len: length of the mesh ID
  * @use_4addr: use 4-address frames
  */
 struct vif_params {
-       u8 *mesh_id;
-       int mesh_id_len;
        int use_4addr;
 };
 
@@ -1223,6 +1219,11 @@ struct cfg80211_ops {
 	int	(*set_mesh_params)(struct wiphy *wiphy,
 				struct net_device *dev,
 				const struct mesh_config *nconf, u32 mask);
+	int	(*join_mesh)(struct wiphy *wiphy, struct net_device *dev,
+			     const u8 *mesh_id, size_t mesh_id_len,
+			     const struct mesh_config *conf);
+	int	(*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
+
 	int	(*change_bss)(struct wiphy *wiphy, struct net_device *dev,
 			      struct bss_parameters *params);
 
--- wireless-testing.orig/net/wireless/Makefile	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/wireless/Makefile	2010-12-01 21:40:18.000000000 +0100
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
--- wireless-testing.orig/net/wireless/core.h	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/wireless/core.h	2010-12-01 21:45:44.000000000 +0100
@@ -285,6 +285,19 @@ void __cfg80211_ibss_joined(struct net_d
 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
 			    struct wireless_dev *wdev);
 
+/* mesh */
+extern const struct mesh_config default_mesh_config;
+int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+			 struct net_device *dev,
+			 const u8 *mesh_id, size_t mesh_id_len,
+			 const struct mesh_config *conf);
+int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+		       struct net_device *dev,
+		       const u8 *mesh_id, size_t mesh_id_len,
+		       const struct mesh_config *conf);
+int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+			struct net_device *dev);
+
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/wireless/mesh.c	2010-12-01 21:45:49.000000000 +0100
@@ -0,0 +1,133 @@
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+/* Default values, timeouts in ms */
+#define MESH_TTL 		31
+#define MESH_MAX_RETR	 	3
+#define MESH_RET_T 		100
+#define MESH_CONF_T 		100
+#define MESH_HOLD_T 		100
+
+#define MESH_PATH_TIMEOUT	5000
+/* Minimum interval between two consecutive PREQs originated by the same
+ * interface
+ */
+#define MESH_PREQ_MIN_INT	10
+#define MESH_DIAM_TRAVERSAL_TIME 50
+/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
+ * timing out.  This way it will remain ACTIVE and no data frames will be
+ * unnecesarily held in the pending queue.
+ */
+#define MESH_PATH_REFRESH_TIME			1000
+#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+
+/* Default maximum number of established plinks per interface */
+#define MESH_MAX_ESTAB_PLINKS	32
+
+#define MESH_MAX_PREQ_RETRIES 4
+
+
+const struct mesh_config default_mesh_config = {
+	.dot11MeshRetryTimeout = MESH_RET_T,
+	.dot11MeshConfirmTimeout = MESH_CONF_T,
+	.dot11MeshHoldingTimeout = MESH_HOLD_T,
+	.dot11MeshMaxRetries = MESH_MAX_RETR,
+	.dot11MeshTTL = MESH_TTL,
+	.auto_open_plinks = true,
+	.dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
+	.dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
+	.dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
+	.dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
+	.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
+	.path_refresh_time = MESH_PATH_REFRESH_TIME,
+	.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+};
+
+int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+			 struct net_device *dev,
+			 const u8 *mesh_id, size_t mesh_id_len,
+			 const struct mesh_config *conf)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	if (wdev->ssid_len)
+		return -EALREADY;
+
+	if (!mesh_id_len)
+		return -EINVAL;
+
+	if (!rdev->ops->join_mesh)
+		return -EOPNOTSUPP;
+
+	if (!conf)
+		conf = &default_mesh_config;
+
+	err = rdev->ops->join_mesh(&rdev->wiphy, dev, mesh_id, mesh_id_len,
+				   conf);
+	if (!err) {
+		memcpy(wdev->ssid, mesh_id, mesh_id_len);
+		wdev->ssid_len = mesh_id_len;
+	}
+
+	return err;
+}
+
+int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+		       struct net_device *dev,
+		       const u8 *mesh_id, size_t mesh_id_len,
+		       const struct mesh_config *conf)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	wdev_lock(wdev);
+	err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf);
+	wdev_unlock(wdev);
+
+	return err;
+}
+
+static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+				 struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	if (!rdev->ops->leave_mesh)
+		return -EOPNOTSUPP;
+
+	if (!wdev->ssid_len)
+		return -ENOTCONN;
+
+	err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
+	if (!err)
+		wdev->ssid_len = 0;
+	return err;
+}
+
+int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+			struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	wdev_lock(wdev);
+	err = __cfg80211_leave_mesh(rdev, dev);
+	wdev_unlock(wdev);
+
+	return err;
+}
--- wireless-testing.orig/net/wireless/nl80211.c	2010-12-01 21:39:52.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2010-12-01 21:43:32.000000000 +0100
@@ -668,6 +668,7 @@ static int nl80211_send_wiphy(struct sk_
 	CMD(deauth, DEAUTHENTICATE);
 	CMD(disassoc, DISASSOCIATE);
 	CMD(join_ibss, JOIN_IBSS);
+	CMD(join_mesh, JOIN_MESH);
 	CMD(set_pmksa, SET_PMKSA);
 	CMD(del_pmksa, DEL_PMKSA);
 	CMD(flush_pmksa, FLUSH_PMKSA);
@@ -1324,11 +1325,20 @@ static int nl80211_set_interface(struct
 	}
 
 	if (info->attrs[NL80211_ATTR_MESH_ID]) {
+		struct wireless_dev *wdev = dev->ieee80211_ptr;
+
 		if (ntype != NL80211_IFTYPE_MESH_POINT)
 			return -EINVAL;
-		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
-		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
-		change = true;
+		if (netif_running(dev))
+			return -EBUSY;
+
+		wdev_lock(wdev);
+		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
+			     IEEE80211_MAX_MESH_ID_LEN);
+		wdev->ssid_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+		       wdev->ssid_len);
+		wdev_unlock(wdev);
 	}
 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
@@ -1388,12 +1398,6 @@ static int nl80211_new_interface(struct
 	    !(rdev->wiphy.interface_modes & (1 << type)))
 		return -EOPNOTSUPP;
 
-	if (type == NL80211_IFTYPE_MESH_POINT &&
-	    info->attrs[NL80211_ATTR_MESH_ID]) {
-		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
-		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
-	}
-
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
 		err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
@@ -1410,6 +1414,19 @@ static int nl80211_new_interface(struct
 	if (IS_ERR(dev))
 		return PTR_ERR(dev);
 
+	if (type == NL80211_IFTYPE_MESH_POINT &&
+	    info->attrs[NL80211_ATTR_MESH_ID]) {
+		struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+		wdev_lock(wdev);
+		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
+			     IEEE80211_MAX_MESH_ID_LEN);
+		wdev->ssid_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+		       wdev->ssid_len);
+		wdev_unlock(wdev);
+	}
+
 	return 0;
 }
 
@@ -4499,6 +4516,39 @@ out:
 	return err;
 }
 
+static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct mesh_config cfg;
+	int err;
+
+	/* start with default */
+	memcpy(&cfg, &default_mesh_config, sizeof(cfg));
+
+	/* and parse other given info */
+	err = nl80211_parse_mesh_params(info, &cfg, NULL);
+	if (err)
+		return err;
+
+	if (!info->attrs[NL80211_ATTR_MESH_ID] ||
+	    !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
+		return -EINVAL;
+
+	return cfg80211_join_mesh(rdev, dev,
+				  nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+				  nla_len(info->attrs[NL80211_ATTR_MESH_ID]),
+				  &cfg);
+}
+
+static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+
+	return cfg80211_leave_mesh(rdev, dev);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -4981,6 +5031,22 @@ static struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_JOIN_MESH,
+		.doit = nl80211_join_mesh,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_LEAVE_MESH,
+		.doit = nl80211_leave_mesh,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
--- wireless-testing.orig/net/wireless/core.c	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/wireless/core.c	2010-12-01 21:45:22.000000000 +0100
@@ -332,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg
 	WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
 	WARN_ON(ops->add_station && !ops->del_station);
 	WARN_ON(ops->add_mpath && !ops->del_mpath);
+	WARN_ON(ops->join_mesh && !ops->leave_mesh);
 
 	alloc_size = sizeof(*rdev) + sizeof_priv;
 
@@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call
 			cfg80211_mlme_down(rdev, dev);
 			wdev_unlock(wdev);
 			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			cfg80211_leave_mesh(rdev, dev);
+			break;
 		default:
 			break;
 		}
@@ -775,20 +779,26 @@ static int cfg80211_netdev_notifier_call
 		}
 		cfg80211_lock_rdev(rdev);
 		mutex_lock(&rdev->devlist_mtx);
-#ifdef CONFIG_CFG80211_WEXT
 		wdev_lock(wdev);
 		switch (wdev->iftype) {
+#ifdef CONFIG_CFG80211_WEXT
 		case NL80211_IFTYPE_ADHOC:
 			cfg80211_ibss_wext_join(rdev, wdev);
 			break;
 		case NL80211_IFTYPE_STATION:
 			cfg80211_mgd_wext_connect(rdev, wdev);
 			break;
+#endif
+		case NL80211_IFTYPE_MESH_POINT:
+			/* backward compat code ... */
+			if (wdev->ssid_len)
+				__cfg80211_join_mesh(rdev, dev, wdev->ssid,
+						     wdev->ssid_len, NULL);
+			break;
 		default:
 			break;
 		}
 		wdev_unlock(wdev);
-#endif
 		rdev->opencount++;
 		mutex_unlock(&rdev->devlist_mtx);
 		cfg80211_unlock_rdev(rdev);
--- wireless-testing.orig/net/mac80211/cfg.c	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2010-12-01 21:40:18.000000000 +0100
@@ -60,11 +60,6 @@ static int ieee80211_change_iface(struct
 	if (ret)
 		return ret;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
-		ieee80211_sdata_set_mesh_id(sdata,
-					    params->mesh_id_len,
-					    params->mesh_id);
-
 	if (type == NL80211_IFTYPE_AP_VLAN &&
 	    params && params->use_4addr == 0)
 		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -1054,6 +1049,30 @@ static int ieee80211_set_mesh_params(str
 	return 0;
 }
 
+static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
+			       const u8 *mesh_id, size_t mesh_id_len,
+			       const struct mesh_config *conf)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+	memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config));
+	ifmsh->mesh_id_len = mesh_id_len;
+	memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
+
+	ieee80211_start_mesh(sdata);
+
+	return 0;
+}
+
+static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ieee80211_stop_mesh(sdata);
+
+	return 0;
+}
 #endif
 
 static int ieee80211_change_bss(struct wiphy *wiphy,
@@ -1760,6 +1779,8 @@ struct cfg80211_ops mac80211_config_ops
 	.dump_mpath = ieee80211_dump_mpath,
 	.set_mesh_params = ieee80211_set_mesh_params,
 	.get_mesh_params = ieee80211_get_mesh_params,
+	.join_mesh = ieee80211_join_mesh,
+	.leave_mesh = ieee80211_leave_mesh,
 #endif
 	.change_bss = ieee80211_change_bss,
 	.set_txq_params = ieee80211_set_txq_params,
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h	2010-12-01 21:40:18.000000000 +0100
@@ -608,19 +608,6 @@ struct ieee80211_sub_if_data *vif_to_sda
 	return container_of(p, struct ieee80211_sub_if_data, vif);
 }
 
-static inline void
-ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
-			    u8 mesh_id_len, u8 *mesh_id)
-{
-#ifdef CONFIG_MAC80211_MESH
-	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-	ifmsh->mesh_id_len = mesh_id_len;
-	memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
-#else
-	WARN_ON(1);
-#endif
-}
-
 enum sdata_queue_type {
 	IEEE80211_SDATA_QUEUE_TYPE_FRAME	= 0,
 	IEEE80211_SDATA_QUEUE_AGG_START		= 1,
--- wireless-testing.orig/net/mac80211/iface.c	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2010-12-01 21:40:18.000000000 +0100
@@ -268,9 +268,7 @@ static int ieee80211_do_open(struct net_
 				goto err_stop;
 		}
 
-		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			ieee80211_start_mesh(sdata);
-		} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		if (sdata->vif.type == NL80211_IFTYPE_AP) {
 			local->fif_pspoll++;
 			local->fif_probe_req++;
 
@@ -495,10 +493,6 @@ static void ieee80211_do_stop(struct iee
 		ieee80211_adjust_monitor_flags(sdata, -1);
 		ieee80211_configure_filter(local);
 		break;
-	case NL80211_IFTYPE_MESH_POINT:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			ieee80211_stop_mesh(sdata);
-		/* fall through */
 	default:
 		flush_work(&sdata->work);
 		/*
@@ -1188,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_lo
 	if (ret)
 		goto fail;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) &&
-	    params && params->mesh_id_len)
-		ieee80211_sdata_set_mesh_id(sdata,
-					    params->mesh_id_len,
-					    params->mesh_id);
-
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 	mutex_unlock(&local->iflist_mtx);
--- wireless-testing.orig/net/mac80211/mesh.c	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.c	2010-12-01 21:40:18.000000000 +0100
@@ -674,26 +674,6 @@ void ieee80211_mesh_init_sdata(struct ie
 		    ieee80211_mesh_housekeeping_timer,
 		    (unsigned long) sdata);
 
-	ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
-	ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
-	ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
-	ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
-	ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
-	ifmsh->mshcfg.auto_open_plinks = true;
-	ifmsh->mshcfg.dot11MeshMaxPeerLinks =
-		MESH_MAX_ESTAB_PLINKS;
-	ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
-		MESH_PATH_TIMEOUT;
-	ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
-		MESH_PREQ_MIN_INT;
-	ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
-		MESH_DIAM_TRAVERSAL_TIME;
-	ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
-		MESH_MAX_PREQ_RETRIES;
-	ifmsh->mshcfg.path_refresh_time =
-		MESH_PATH_REFRESH_TIME;
-	ifmsh->mshcfg.min_discovery_timeout =
-		MESH_MIN_DISCOVERY_TIMEOUT;
 	ifmsh->accepting_plinks = true;
 	ifmsh->preq_id = 0;
 	ifmsh->sn = 0;
--- wireless-testing.orig/net/mac80211/mesh.h	2010-12-01 21:36:33.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.h	2010-12-01 21:40:18.000000000 +0100
@@ -175,33 +175,10 @@ struct mesh_rmc {
  */
 #define MESH_CFG_CMP_LEN 	(IEEE80211_MESH_CONFIG_LEN - 2)
 
-/* Default values, timeouts in ms */
-#define MESH_TTL 		31
-#define MESH_MAX_RETR	 	3
-#define MESH_RET_T 		100
-#define MESH_CONF_T 		100
-#define MESH_HOLD_T 		100
-
-#define MESH_PATH_TIMEOUT	5000
-/* Minimum interval between two consecutive PREQs originated by the same
- * interface
- */
-#define MESH_PREQ_MIN_INT	10
-#define MESH_DIAM_TRAVERSAL_TIME 50
-/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
- * timing out.  This way it will remain ACTIVE and no data frames will be
- * unnecesarily held in the pending queue.
- */
-#define MESH_PATH_REFRESH_TIME			1000
-#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
 #define MESH_DEFAULT_BEACON_INTERVAL		1000 	/* in 1024 us units */
 
-#define MESH_MAX_PREQ_RETRIES 4
 #define MESH_PATH_EXPIRE (600 * HZ)
 
-/* Default maximum number of established plinks per interface */
-#define MESH_MAX_ESTAB_PLINKS	32
-
 /* Default maximum number of plinks per interface */
 #define MESH_MAX_PLINKS		256
 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands
  2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
@ 2010-12-01 21:15   ` Johannes Berg
  2010-12-02  0:23   ` Javier Cardona
  2010-12-02  8:45   ` [RFC 5/5 v2] " Johannes Berg
  2 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-01 21:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

On Wed, 2010-12-01 at 21:59 +0100, Johannes Berg wrote:
> plain text document attachment (022-cfg80211-start-stop-mesh.patch)
> From: Johannes Berg <johannes.berg@intel.com>
> 
> Instead of tying mesh activity to interface up,
> add join and leave commands for mesh. Since we
> must be backward compatible, let cfg80211 handle
> joining a mesh if a mesh ID was pre-configured
> when the device goes up.
> 
> Note that this therefore must modify mac80211 as
> well since mac80211 needs to lose the logic to
> start the mesh on interface up.

I just noticed that this will lose mesh parameters when you leave the
mesh, unlike previously where they would be kept. I'm not sure which
behaviour is more desirable though -- if I was doing this from scratch
I'd sure go with the reset behaviour, but we may need to keep the old
behaviour?

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands
  2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
  2010-12-01 21:15   ` Johannes Berg
@ 2010-12-02  0:23   ` Javier Cardona
  2010-12-02  6:57     ` Johannes Berg
  2010-12-02  8:45   ` [RFC 5/5 v2] " Johannes Berg
  2 siblings, 1 reply; 17+ messages in thread
From: Javier Cardona @ 2010-12-02  0:23 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Steve Derosier, devel

Wow, Johannes!

On Wed, Dec 1, 2010 at 12:59 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Instead of tying mesh activity to interface up,
> add join and leave commands for mesh. Since we
> must be backward compatible, let cfg80211 handle
> joining a mesh if a mesh ID was pre-configured
> when the device goes up.
>
> Note that this therefore must modify mac80211 as
> well since mac80211 needs to lose the logic to
> start the mesh on interface up.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>

Pretty impressive.  Comments below

+static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct mesh_config cfg;
+       int err;
+
+       /* start with default */
+       memcpy(&cfg, &default_mesh_config, sizeof(cfg));
+
+       /* and parse other given info */
+       err = nl80211_parse_mesh_params(info, &cfg, NULL);
+       if (err)
+               return err;

Only the mesh id should be mandatory for starting the mesh, and none
of the other mesh parameters.  Therefore I would change the above to:

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 75c501f..300835d 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4527,9 +4527,11 @@ static int nl80211_join_mesh(struct sk_buff
*skb, struct genl_info *info)
        memcpy(&cfg, &default_mesh_config, sizeof(cfg));

        /* and parse other given info */
-       err = nl80211_parse_mesh_params(info, &cfg, NULL);
-       if (err)
-               return err;
+       if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
+               err = nl80211_parse_mesh_params(info, &cfg, NULL);
+               if (err)
+                       return err;
+       }

        if (!info->attrs[NL80211_ATTR_MESH_ID] ||
            !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))

@@ -775,20 +779,26 @@ static int cfg80211_netdev_notifier_call
               }
               cfg80211_lock_rdev(rdev);
               mutex_lock(&rdev->devlist_mtx);
-#ifdef CONFIG_CFG80211_WEXT
               wdev_lock(wdev);
               switch (wdev->iftype) {
+#ifdef CONFIG_CFG80211_WEXT
               case NL80211_IFTYPE_ADHOC:
                       cfg80211_ibss_wext_join(rdev, wdev);
                       break;
               case NL80211_IFTYPE_STATION:
                       cfg80211_mgd_wext_connect(rdev, wdev);
                       break;
+#endif
+               case NL80211_IFTYPE_MESH_POINT:
+                       /* backward compat code ... */
+                       if (wdev->ssid_len)
+                               __cfg80211_join_mesh(rdev, dev, wdev->ssid,
+                                                    wdev->ssid_len, NULL);
+

This doesn't quite work:  when mesh interfaces are created with a mesh
id you set wdev->ssid_len.
Later, when the interface is brought up, the mesh won't start because
of the last check below:

+int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+                        struct net_device *dev,
+                        const u8 *mesh_id, size_t mesh_id_len,
+                        const struct mesh_config *conf)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       int err;
+
+       BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
+
+       ASSERT_WDEV_LOCK(wdev);
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
+
+       if (wdev->ssid_len)       <<<<<<
+               return -EALREADY;

If you want to keep working on this we'll be happy to test it again,
or if you want we can take it from here and finish this.
Let me know.

Regarding...

> I just noticed that this will lose mesh parameters when you leave the
> mesh, unlike previously where they would be kept.

...I don't think there's an issue.  I'll ask around.

Cheers,

Javier

-- 
Javier Cardona
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02  0:23   ` Javier Cardona
@ 2010-12-02  6:57     ` Johannes Berg
  0 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-02  6:57 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, Steve Derosier, devel

On Wed, 2010-12-01 at 16:23 -0800, Javier Cardona wrote:

> +static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct cfg80211_registered_device *rdev = info->user_ptr[0];
> +       struct net_device *dev = info->user_ptr[1];
> +       struct mesh_config cfg;
> +       int err;
> +
> +       /* start with default */
> +       memcpy(&cfg, &default_mesh_config, sizeof(cfg));
> +
> +       /* and parse other given info */
> +       err = nl80211_parse_mesh_params(info, &cfg, NULL);
> +       if (err)
> +               return err;
> 
> Only the mesh id should be mandatory for starting the mesh, and none
> of the other mesh parameters.  Therefore I would change the above to:
> 

> +       if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
> +               err = nl80211_parse_mesh_params(info, &cfg, NULL);
> +               if (err)
> +                       return err;
> +       }

Good point.

> +               case NL80211_IFTYPE_MESH_POINT:
> +                       /* backward compat code ... */
> +                       if (wdev->ssid_len)
> +                               __cfg80211_join_mesh(rdev, dev, wdev->ssid,
> +                                                    wdev->ssid_len, NULL);
> +
> 
> This doesn't quite work:  when mesh interfaces are created with a mesh
> id you set wdev->ssid_len.
> Later, when the interface is brought up, the mesh won't start because
> of the last check below:

Oops, good catch.

> If you want to keep working on this we'll be happy to test it again,
> or if you want we can take it from here and finish this.
> Let me know.

I'll finish it, shouldn't be too much.

> > I just noticed that this will lose mesh parameters when you leave the
> > mesh, unlike previously where they would be kept.
> 
> ...I don't think there's an issue.  I'll ask around.

Ok, I'll leave it as is for now.

Regarding this I also noticed something else: there's a bug still in the
patch -- if you attempt to set mesh parameters on an interface that's
down it'll go through to mac80211, but then the parameters will just be
overwritten upon joining. Clearly, that's not desirable, but I'm not
sure whether we need the ability to update mesh parameters while the
interface isn't joined to a mesh?

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 4/5 v2] nl80211: refactor mesh parameter parsing
  2010-12-01 20:59 ` [RFC 4/5] nl80211: refactor mesh parameter parsing Johannes Berg
@ 2010-12-02  8:34   ` Johannes Berg
  0 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-02  8:34 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

I'm going to need this in a new place later.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
v2: - reduce scope of macro

 net/wireless/nl80211.c |   61 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 38 insertions(+), 23 deletions(-)

--- wireless-testing.orig/net/wireless/nl80211.c	2010-12-02 08:19:44.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2010-12-02 09:12:45.000000000 +0100
@@ -2611,14 +2611,6 @@ static int nl80211_get_mesh_params(struc
 	return -ENOBUFS;
 }
 
-#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
-do {\
-	if (table[attr_num]) {\
-		cfg.param = nla_fn(table[attr_num]); \
-		mask |= (1 << (attr_num - 1)); \
-	} \
-} while (0);\
-
 static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] = {
 	[NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 },
 	[NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 },
@@ -2636,31 +2628,34 @@ static const struct nla_policy nl80211_m
 	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
 };
 
-static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_parse_mesh_params(struct genl_info *info,
+				     struct mesh_config *cfg,
+				     u32 *mask_out)
 {
-	u32 mask;
-	struct cfg80211_registered_device *rdev = info->user_ptr[0];
-	struct net_device *dev = info->user_ptr[1];
-	struct mesh_config cfg;
 	struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1];
-	struct nlattr *parent_attr;
+	u32 mask = 0;
+
+#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \
+do {\
+	if (table[attr_num]) {\
+		cfg->param = nla_fn(table[attr_num]); \
+		mask |= (1 << (attr_num - 1)); \
+	} \
+} while (0);\
+
 
-	parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS];
-	if (!parent_attr)
+	if (!info->attrs[NL80211_ATTR_MESH_PARAMS])
 		return -EINVAL;
 	if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX,
-			parent_attr, nl80211_meshconf_params_policy))
+			     info->attrs[NL80211_ATTR_MESH_PARAMS],
+			     nl80211_meshconf_params_policy))
 		return -EINVAL;
 
-	if (!rdev->ops->set_mesh_params)
-		return -EOPNOTSUPP;
-
 	/* This makes sure that there aren't more than 32 mesh config
 	 * parameters (otherwise our bitfield scheme would not work.) */
 	BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
 
 	/* Fill in the params struct */
-	mask = 0;
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout,
 			mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout,
@@ -2698,12 +2693,32 @@ static int nl80211_set_mesh_params(struc
 			NL80211_MESHCONF_HWMP_ROOTMODE,
 			nla_get_u8);
 
+	if (mask_out)
+		*mask_out = mask;
+	return 0;
+
+#undef FILL_IN_MESH_PARAM_IF_SET
+}
+
+static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct mesh_config cfg;
+	u32 mask;
+	int err;
+
+	if (!rdev->ops->set_mesh_params)
+		return -EOPNOTSUPP;
+
+	err = nl80211_parse_mesh_params(info, &cfg, &mask);
+	if (err)
+		return err;
+
 	/* Apply changes */
 	return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
 }
 
-#undef FILL_IN_MESH_PARAM_IF_SET
-
 static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
 {
 	struct sk_buff *msg;



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
  2010-12-01 21:15   ` Johannes Berg
  2010-12-02  0:23   ` Javier Cardona
@ 2010-12-02  8:45   ` Johannes Berg
  2010-12-02 20:09     ` Javier Cardona
  2 siblings, 1 reply; 17+ messages in thread
From: Johannes Berg @ 2010-12-02  8:45 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Steve Derosier, devel

From: Johannes Berg <johannes.berg@intel.com>

Instead of tying mesh activity to interface up,
add join and leave commands for mesh. Since we
must be backward compatible, let cfg80211 handle
joining a mesh if a mesh ID was pre-configured
when the device goes up.

Note that this therefore must modify mac80211 as
well since mac80211 needs to lose the logic to
start the mesh on interface up.

We now allow querying mesh parameters before the
mesh is connected, which simply returns defaults.
Setting them (internally renamed to "update") is
only allowed while connected. Specify them with
the new mesh join command instead where needed.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
v2: - fix join on netdev up (pointed out by Javier)
    - only require mesh ID (pointed out by Javier)
    - more sanity checking around get/set_mesh_params
    - rename set_mesh_params to update_mesh_params,
      disallow calling it before connected to mesh
    - add some mesh interface type checks
    - introduce mesh_setup struct for static config

I have lightly tested this. You can find a new
test branch of iw that includes support for the
new commands here:

http://git.sipsolutions.net/?p=iw.git;a=shortlog;h=refs/heads/mesh


I think this is about ready, maybe with some
minor issues still. I'd appreciate if you could
review and test it, and then we can add the IE
and path selection protocols to the mesh_setup
struct and the iw mesh join command.


 include/linux/nl80211.h    |    8 ++
 include/net/cfg80211.h     |   38 +++++++++---
 net/mac80211/cfg.c         |   39 +++++++++---
 net/mac80211/ieee80211_i.h |   13 ----
 net/mac80211/iface.c       |   14 ----
 net/mac80211/mesh.c        |   20 ------
 net/mac80211/mesh.h        |   23 -------
 net/wireless/Makefile      |    2 
 net/wireless/core.c        |   15 ++++
 net/wireless/core.h        |   13 ++++
 net/wireless/mesh.c        |  134 ++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.c     |  137 ++++++++++++++++++++++++++++++++++++++-------
 net/wireless/util.c        |    1 
 13 files changed, 346 insertions(+), 111 deletions(-)

--- wireless-testing.orig/include/linux/nl80211.h	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/include/linux/nl80211.h	2010-12-02 09:38:22.000000000 +0100
@@ -394,6 +394,11 @@
  *
  * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
  *
+ * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
+ *	mesh config parameters may be given.
+ * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
+ *	network is determined by the network interface.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -500,6 +505,9 @@ enum nl80211_commands {
 
 	NL80211_CMD_FRAME_WAIT_CANCEL,
 
+	NL80211_CMD_JOIN_MESH,
+	NL80211_CMD_LEAVE_MESH,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
--- wireless-testing.orig/include/net/cfg80211.h	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/include/net/cfg80211.h	2010-12-02 09:38:22.000000000 +0100
@@ -258,13 +258,9 @@ struct ieee80211_supported_band {
 
 /**
  * struct vif_params - describes virtual interface parameters
- * @mesh_id: mesh ID to use
- * @mesh_id_len: length of the mesh ID
  * @use_4addr: use 4-address frames
  */
 struct vif_params {
-       u8 *mesh_id;
-       int mesh_id_len;
        int use_4addr;
 };
 
@@ -615,6 +611,11 @@ struct bss_parameters {
 	int ap_isolate;
 };
 
+/*
+ * struct mesh_config - 802.11s mesh configuration
+ *
+ * These parameters can be changed while the mesh is active.
+ */
 struct mesh_config {
 	/* Timeouts in ms */
 	/* Mesh plink management parameters */
@@ -636,6 +637,18 @@ struct mesh_config {
 };
 
 /**
+ * struct mesh_setup - 802.11s mesh setup configuration
+ * @mesh_id: the mesh ID
+ * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
+ *
+ * These parameters are fixed when the mesh is created.
+ */
+struct mesh_setup {
+	const u8 *mesh_id;
+	u8 mesh_id_len;
+};
+
+/**
  * struct ieee80211_txq_params - TX queue parameters
  * @queue: TX queue identifier (NL80211_TXQ_Q_*)
  * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled
@@ -1076,7 +1089,7 @@ struct cfg80211_pmksa {
  *
  * @get_mesh_params: Put the current mesh parameters into *params
  *
- * @set_mesh_params: Set mesh parameters.
+ * @update_mesh_params: Update mesh parameters on a running mesh.
  *	The mask is a bitfield which tells us which parameters to
  *	set, and which to leave alone.
  *
@@ -1220,9 +1233,14 @@ struct cfg80211_ops {
 	int	(*get_mesh_params)(struct wiphy *wiphy,
 				struct net_device *dev,
 				struct mesh_config *conf);
-	int	(*set_mesh_params)(struct wiphy *wiphy,
-				struct net_device *dev,
-				const struct mesh_config *nconf, u32 mask);
+	int	(*update_mesh_params)(struct wiphy *wiphy,
+				      struct net_device *dev, u32 mask,
+				      const struct mesh_config *nconf);
+	int	(*join_mesh)(struct wiphy *wiphy, struct net_device *dev,
+			     const struct mesh_config *conf,
+			     const struct mesh_setup *setup);
+	int	(*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
+
 	int	(*change_bss)(struct wiphy *wiphy, struct net_device *dev,
 			      struct bss_parameters *params);
 
@@ -1638,6 +1656,8 @@ struct cfg80211_cached_keys;
  * @bssid: (private) Used by the internal configuration code
  * @ssid: (private) Used by the internal configuration code
  * @ssid_len: (private) Used by the internal configuration code
+ * @mesh_id_len: (private) Used by the internal configuration code
+ * @mesh_id_up_len: (private) Used by the internal configuration code
  * @wext: (private) Used by the internal wireless extensions compat code
  * @use_4addr: indicates 4addr mode is used on this interface, must be
  *	set by driver (if supported) on add_interface BEFORE registering the
@@ -1667,7 +1687,7 @@ struct wireless_dev {
 
 	/* currently used for IBSS and SME - might be rearranged later */
 	u8 ssid[IEEE80211_MAX_SSID_LEN];
-	u8 ssid_len;
+	u8 ssid_len, mesh_id_len, mesh_id_up_len;
 	enum {
 		CFG80211_SME_IDLE,
 		CFG80211_SME_CONNECTING,
--- wireless-testing.orig/net/wireless/Makefile	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/wireless/Makefile	2010-12-02 09:38:22.000000000 +0100
@@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
 obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
 
 cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
-cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
+cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
 cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
 cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
 cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
--- wireless-testing.orig/net/wireless/core.h	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/wireless/core.h	2010-12-02 09:38:22.000000000 +0100
@@ -285,6 +285,19 @@ void __cfg80211_ibss_joined(struct net_d
 int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
 			    struct wireless_dev *wdev);
 
+/* mesh */
+extern const struct mesh_config default_mesh_config;
+int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+			 struct net_device *dev,
+			 const u8 *mesh_id, u8 mesh_id_len,
+			 const struct mesh_config *conf);
+int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+		       struct net_device *dev,
+		       const u8 *mesh_id, u8 mesh_id_len,
+		       const struct mesh_config *conf);
+int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+			struct net_device *dev);
+
 /* MLME */
 int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 			 struct net_device *dev,
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ wireless-testing/net/wireless/mesh.c	2010-12-02 09:38:22.000000000 +0100
@@ -0,0 +1,134 @@
+#include <linux/ieee80211.h>
+#include <net/cfg80211.h>
+#include "core.h"
+
+/* Default values, timeouts in ms */
+#define MESH_TTL 		31
+#define MESH_MAX_RETR	 	3
+#define MESH_RET_T 		100
+#define MESH_CONF_T 		100
+#define MESH_HOLD_T 		100
+
+#define MESH_PATH_TIMEOUT	5000
+/* Minimum interval between two consecutive PREQs originated by the same
+ * interface
+ */
+#define MESH_PREQ_MIN_INT	10
+#define MESH_DIAM_TRAVERSAL_TIME 50
+/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
+ * timing out.  This way it will remain ACTIVE and no data frames will be
+ * unnecesarily held in the pending queue.
+ */
+#define MESH_PATH_REFRESH_TIME			1000
+#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
+
+/* Default maximum number of established plinks per interface */
+#define MESH_MAX_ESTAB_PLINKS	32
+
+#define MESH_MAX_PREQ_RETRIES 4
+
+
+const struct mesh_config default_mesh_config = {
+	.dot11MeshRetryTimeout = MESH_RET_T,
+	.dot11MeshConfirmTimeout = MESH_CONF_T,
+	.dot11MeshHoldingTimeout = MESH_HOLD_T,
+	.dot11MeshMaxRetries = MESH_MAX_RETR,
+	.dot11MeshTTL = MESH_TTL,
+	.auto_open_plinks = true,
+	.dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
+	.dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
+	.dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
+	.dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
+	.dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
+	.path_refresh_time = MESH_PATH_REFRESH_TIME,
+	.min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
+};
+
+
+int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+			 struct net_device *dev,
+			 const u8 *mesh_id, u8 mesh_id_len,
+			 const struct mesh_config *conf)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct mesh_setup setup = {
+		.mesh_id = mesh_id,
+		.mesh_id_len = mesh_id_len,
+	};
+	int err;
+
+	BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	if (wdev->mesh_id_len)
+		return -EALREADY;
+
+	if (!mesh_id_len)
+		return -EINVAL;
+
+	if (!rdev->ops->join_mesh)
+		return -EOPNOTSUPP;
+
+	err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, &setup);
+	if (!err) {
+		memcpy(wdev->ssid, mesh_id, mesh_id_len);
+		wdev->mesh_id_len = mesh_id_len;
+	}
+
+	return err;
+}
+
+int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
+		       struct net_device *dev,
+		       const u8 *mesh_id, u8 mesh_id_len,
+		       const struct mesh_config *conf)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	wdev_lock(wdev);
+	err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf);
+	wdev_unlock(wdev);
+
+	return err;
+}
+
+static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+				 struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	ASSERT_WDEV_LOCK(wdev);
+
+	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	if (!rdev->ops->leave_mesh)
+		return -EOPNOTSUPP;
+
+	if (!wdev->mesh_id_len)
+		return -ENOTCONN;
+
+	err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
+	if (!err)
+		wdev->mesh_id_len = 0;
+	return err;
+}
+
+int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
+			struct net_device *dev)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	int err;
+
+	wdev_lock(wdev);
+	err = __cfg80211_leave_mesh(rdev, dev);
+	wdev_unlock(wdev);
+
+	return err;
+}
--- wireless-testing.orig/net/wireless/nl80211.c	2010-12-02 09:38:20.000000000 +0100
+++ wireless-testing/net/wireless/nl80211.c	2010-12-02 09:38:31.000000000 +0100
@@ -661,13 +661,14 @@ static int nl80211_send_wiphy(struct sk_
 	CMD(add_beacon, NEW_BEACON);
 	CMD(add_station, NEW_STATION);
 	CMD(add_mpath, NEW_MPATH);
-	CMD(set_mesh_params, SET_MESH_PARAMS);
+	CMD(update_mesh_params, SET_MESH_PARAMS);
 	CMD(change_bss, SET_BSS);
 	CMD(auth, AUTHENTICATE);
 	CMD(assoc, ASSOCIATE);
 	CMD(deauth, DEAUTHENTICATE);
 	CMD(disassoc, DISASSOCIATE);
 	CMD(join_ibss, JOIN_IBSS);
+	CMD(join_mesh, JOIN_MESH);
 	CMD(set_pmksa, SET_PMKSA);
 	CMD(del_pmksa, DEL_PMKSA);
 	CMD(flush_pmksa, FLUSH_PMKSA);
@@ -1324,11 +1325,21 @@ static int nl80211_set_interface(struct
 	}
 
 	if (info->attrs[NL80211_ATTR_MESH_ID]) {
+		struct wireless_dev *wdev = dev->ieee80211_ptr;
+
 		if (ntype != NL80211_IFTYPE_MESH_POINT)
 			return -EINVAL;
-		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
-		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
-		change = true;
+		if (netif_running(dev))
+			return -EBUSY;
+
+		wdev_lock(wdev);
+		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
+			     IEEE80211_MAX_MESH_ID_LEN);
+		wdev->mesh_id_up_len =
+			nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+		       wdev->mesh_id_up_len);
+		wdev_unlock(wdev);
 	}
 
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
@@ -1388,12 +1399,6 @@ static int nl80211_new_interface(struct
 	    !(rdev->wiphy.interface_modes & (1 << type)))
 		return -EOPNOTSUPP;
 
-	if (type == NL80211_IFTYPE_MESH_POINT &&
-	    info->attrs[NL80211_ATTR_MESH_ID]) {
-		params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
-		params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
-	}
-
 	if (info->attrs[NL80211_ATTR_4ADDR]) {
 		params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
 		err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
@@ -1410,6 +1415,20 @@ static int nl80211_new_interface(struct
 	if (IS_ERR(dev))
 		return PTR_ERR(dev);
 
+	if (type == NL80211_IFTYPE_MESH_POINT &&
+	    info->attrs[NL80211_ATTR_MESH_ID]) {
+		struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+		wdev_lock(wdev);
+		BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
+			     IEEE80211_MAX_MESH_ID_LEN);
+		wdev->mesh_id_up_len =
+			nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
+		memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+		       wdev->mesh_id_up_len);
+		wdev_unlock(wdev);
+	}
+
 	return 0;
 }
 
@@ -2543,21 +2562,32 @@ static int nl80211_req_set_reg(struct sk
 }
 
 static int nl80211_get_mesh_params(struct sk_buff *skb,
-	struct genl_info *info)
+				   struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
-	struct mesh_config cur_params;
-	int err;
 	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+	struct mesh_config cur_params;
+	int err = 0;
 	void *hdr;
 	struct nlattr *pinfoattr;
 	struct sk_buff *msg;
 
+	if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
 	if (!rdev->ops->get_mesh_params)
 		return -EOPNOTSUPP;
 
-	/* Get the mesh params */
-	err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
+	wdev_lock(wdev);
+	/* If not connected, get default parameters */
+	if (!wdev->mesh_id_len)
+		memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
+	else
+		err = rdev->ops->get_mesh_params(&rdev->wiphy, dev,
+						 &cur_params);
+	wdev_unlock(wdev);
+
 	if (err)
 		return err;
 
@@ -2700,23 +2730,37 @@ do {\
 #undef FILL_IN_MESH_PARAM_IF_SET
 }
 
-static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
+static int nl80211_update_mesh_params(struct sk_buff *skb,
+				      struct genl_info *info)
 {
 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
 	struct net_device *dev = info->user_ptr[1];
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	struct mesh_config cfg;
 	u32 mask;
 	int err;
 
-	if (!rdev->ops->set_mesh_params)
+	if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
+		return -EOPNOTSUPP;
+
+	if (!rdev->ops->update_mesh_params)
 		return -EOPNOTSUPP;
 
 	err = nl80211_parse_mesh_params(info, &cfg, &mask);
 	if (err)
 		return err;
 
-	/* Apply changes */
-	return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
+	wdev_lock(wdev);
+	if (!wdev->mesh_id_len)
+		err = -ENOLINK;
+
+	if (!err)
+		err = rdev->ops->update_mesh_params(&rdev->wiphy, dev,
+						    mask, &cfg);
+
+	wdev_unlock(wdev);
+
+	return err;
 }
 
 static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
@@ -4500,6 +4544,41 @@ out:
 	return err;
 }
 
+static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+	struct mesh_config cfg;
+	int err;
+
+	/* start with default */
+	memcpy(&cfg, &default_mesh_config, sizeof(cfg));
+
+	if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
+		/* and parse parameters if given */
+		err = nl80211_parse_mesh_params(info, &cfg, NULL);
+		if (err)
+			return err;
+	}
+
+	if (!info->attrs[NL80211_ATTR_MESH_ID] ||
+	    !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
+		return -EINVAL;
+
+	return cfg80211_join_mesh(rdev, dev,
+				  nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
+				  nla_len(info->attrs[NL80211_ATTR_MESH_ID]),
+				  &cfg);
+}
+
+static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
+{
+	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+	struct net_device *dev = info->user_ptr[1];
+
+	return cfg80211_leave_mesh(rdev, dev);
+}
+
 #define NL80211_FLAG_NEED_WIPHY		0x01
 #define NL80211_FLAG_NEED_NETDEV	0x02
 #define NL80211_FLAG_NEED_RTNL		0x04
@@ -4764,10 +4843,10 @@ static struct genl_ops nl80211_ops[] = {
 	},
 	{
 		.cmd = NL80211_CMD_SET_MESH_PARAMS,
-		.doit = nl80211_set_mesh_params,
+		.doit = nl80211_update_mesh_params,
 		.policy = nl80211_policy,
 		.flags = GENL_ADMIN_PERM,
-		.internal_flags = NL80211_FLAG_NEED_NETDEV |
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
 				  NL80211_FLAG_NEED_RTNL,
 	},
 	{
@@ -4982,6 +5061,22 @@ static struct genl_ops nl80211_ops[] = {
 		.internal_flags = NL80211_FLAG_NEED_NETDEV |
 				  NL80211_FLAG_NEED_RTNL,
 	},
+	{
+		.cmd = NL80211_CMD_JOIN_MESH,
+		.doit = nl80211_join_mesh,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
+	{
+		.cmd = NL80211_CMD_LEAVE_MESH,
+		.doit = nl80211_leave_mesh,
+		.policy = nl80211_policy,
+		.flags = GENL_ADMIN_PERM,
+		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+				  NL80211_FLAG_NEED_RTNL,
+	},
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
--- wireless-testing.orig/net/wireless/core.c	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/wireless/core.c	2010-12-02 09:38:22.000000000 +0100
@@ -332,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg
 	WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
 	WARN_ON(ops->add_station && !ops->del_station);
 	WARN_ON(ops->add_mpath && !ops->del_mpath);
+	WARN_ON(ops->join_mesh && !ops->leave_mesh);
 
 	alloc_size = sizeof(*rdev) + sizeof_priv;
 
@@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call
 			cfg80211_mlme_down(rdev, dev);
 			wdev_unlock(wdev);
 			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			cfg80211_leave_mesh(rdev, dev);
+			break;
 		default:
 			break;
 		}
@@ -775,20 +779,27 @@ static int cfg80211_netdev_notifier_call
 		}
 		cfg80211_lock_rdev(rdev);
 		mutex_lock(&rdev->devlist_mtx);
-#ifdef CONFIG_CFG80211_WEXT
 		wdev_lock(wdev);
 		switch (wdev->iftype) {
+#ifdef CONFIG_CFG80211_WEXT
 		case NL80211_IFTYPE_ADHOC:
 			cfg80211_ibss_wext_join(rdev, wdev);
 			break;
 		case NL80211_IFTYPE_STATION:
 			cfg80211_mgd_wext_connect(rdev, wdev);
 			break;
+#endif
+		case NL80211_IFTYPE_MESH_POINT:
+			/* backward compat code ... */
+			if (wdev->mesh_id_up_len)
+				__cfg80211_join_mesh(rdev, dev, wdev->ssid,
+						     wdev->mesh_id_up_len,
+						     &default_mesh_config);
+			break;
 		default:
 			break;
 		}
 		wdev_unlock(wdev);
-#endif
 		rdev->opencount++;
 		mutex_unlock(&rdev->devlist_mtx);
 		cfg80211_unlock_rdev(rdev);
--- wireless-testing.orig/net/mac80211/cfg.c	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/mac80211/cfg.c	2010-12-02 09:38:22.000000000 +0100
@@ -60,11 +60,6 @@ static int ieee80211_change_iface(struct
 	if (ret)
 		return ret;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
-		ieee80211_sdata_set_mesh_id(sdata,
-					    params->mesh_id_len,
-					    params->mesh_id);
-
 	if (type == NL80211_IFTYPE_AP_VLAN &&
 	    params && params->use_4addr == 0)
 		rcu_assign_pointer(sdata->u.vlan.sta, NULL);
@@ -1003,9 +998,9 @@ static inline bool _chg_mesh_attr(enum n
 	return (mask >> (parm-1)) & 0x1;
 }
 
-static int ieee80211_set_mesh_params(struct wiphy *wiphy,
-				struct net_device *dev,
-				const struct mesh_config *nconf, u32 mask)
+static int ieee80211_update_mesh_params(struct wiphy *wiphy,
+					struct net_device *dev, u32 mask,
+					const struct mesh_config *nconf)
 {
 	struct mesh_config *conf;
 	struct ieee80211_sub_if_data *sdata;
@@ -1054,6 +1049,30 @@ static int ieee80211_set_mesh_params(str
 	return 0;
 }
 
+static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
+			       const struct mesh_config *conf,
+			       const struct mesh_setup *setup)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+	memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config));
+	ifmsh->mesh_id_len = setup->mesh_id_len;
+	memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
+
+	ieee80211_start_mesh(sdata);
+
+	return 0;
+}
+
+static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+	ieee80211_stop_mesh(sdata);
+
+	return 0;
+}
 #endif
 
 static int ieee80211_change_bss(struct wiphy *wiphy,
@@ -1758,8 +1777,10 @@ struct cfg80211_ops mac80211_config_ops
 	.change_mpath = ieee80211_change_mpath,
 	.get_mpath = ieee80211_get_mpath,
 	.dump_mpath = ieee80211_dump_mpath,
-	.set_mesh_params = ieee80211_set_mesh_params,
+	.update_mesh_params = ieee80211_update_mesh_params,
 	.get_mesh_params = ieee80211_get_mesh_params,
+	.join_mesh = ieee80211_join_mesh,
+	.leave_mesh = ieee80211_leave_mesh,
 #endif
 	.change_bss = ieee80211_change_bss,
 	.set_txq_params = ieee80211_set_txq_params,
--- wireless-testing.orig/net/mac80211/ieee80211_i.h	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/mac80211/ieee80211_i.h	2010-12-02 09:38:22.000000000 +0100
@@ -608,19 +608,6 @@ struct ieee80211_sub_if_data *vif_to_sda
 	return container_of(p, struct ieee80211_sub_if_data, vif);
 }
 
-static inline void
-ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
-			    u8 mesh_id_len, u8 *mesh_id)
-{
-#ifdef CONFIG_MAC80211_MESH
-	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
-	ifmsh->mesh_id_len = mesh_id_len;
-	memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
-#else
-	WARN_ON(1);
-#endif
-}
-
 enum sdata_queue_type {
 	IEEE80211_SDATA_QUEUE_TYPE_FRAME	= 0,
 	IEEE80211_SDATA_QUEUE_AGG_START		= 1,
--- wireless-testing.orig/net/mac80211/iface.c	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/mac80211/iface.c	2010-12-02 09:38:22.000000000 +0100
@@ -268,9 +268,7 @@ static int ieee80211_do_open(struct net_
 				goto err_stop;
 		}
 
-		if (ieee80211_vif_is_mesh(&sdata->vif)) {
-			ieee80211_start_mesh(sdata);
-		} else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+		if (sdata->vif.type == NL80211_IFTYPE_AP) {
 			local->fif_pspoll++;
 			local->fif_probe_req++;
 
@@ -495,10 +493,6 @@ static void ieee80211_do_stop(struct iee
 		ieee80211_adjust_monitor_flags(sdata, -1);
 		ieee80211_configure_filter(local);
 		break;
-	case NL80211_IFTYPE_MESH_POINT:
-		if (ieee80211_vif_is_mesh(&sdata->vif))
-			ieee80211_stop_mesh(sdata);
-		/* fall through */
 	default:
 		flush_work(&sdata->work);
 		/*
@@ -1188,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_lo
 	if (ret)
 		goto fail;
 
-	if (ieee80211_vif_is_mesh(&sdata->vif) &&
-	    params && params->mesh_id_len)
-		ieee80211_sdata_set_mesh_id(sdata,
-					    params->mesh_id_len,
-					    params->mesh_id);
-
 	mutex_lock(&local->iflist_mtx);
 	list_add_tail_rcu(&sdata->list, &local->interfaces);
 	mutex_unlock(&local->iflist_mtx);
--- wireless-testing.orig/net/mac80211/mesh.c	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.c	2010-12-02 09:38:22.000000000 +0100
@@ -674,26 +674,6 @@ void ieee80211_mesh_init_sdata(struct ie
 		    ieee80211_mesh_housekeeping_timer,
 		    (unsigned long) sdata);
 
-	ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
-	ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
-	ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
-	ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
-	ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
-	ifmsh->mshcfg.auto_open_plinks = true;
-	ifmsh->mshcfg.dot11MeshMaxPeerLinks =
-		MESH_MAX_ESTAB_PLINKS;
-	ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
-		MESH_PATH_TIMEOUT;
-	ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
-		MESH_PREQ_MIN_INT;
-	ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
-		MESH_DIAM_TRAVERSAL_TIME;
-	ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
-		MESH_MAX_PREQ_RETRIES;
-	ifmsh->mshcfg.path_refresh_time =
-		MESH_PATH_REFRESH_TIME;
-	ifmsh->mshcfg.min_discovery_timeout =
-		MESH_MIN_DISCOVERY_TIMEOUT;
 	ifmsh->accepting_plinks = true;
 	ifmsh->preq_id = 0;
 	ifmsh->sn = 0;
--- wireless-testing.orig/net/mac80211/mesh.h	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/mac80211/mesh.h	2010-12-02 09:38:22.000000000 +0100
@@ -175,33 +175,10 @@ struct mesh_rmc {
  */
 #define MESH_CFG_CMP_LEN 	(IEEE80211_MESH_CONFIG_LEN - 2)
 
-/* Default values, timeouts in ms */
-#define MESH_TTL 		31
-#define MESH_MAX_RETR	 	3
-#define MESH_RET_T 		100
-#define MESH_CONF_T 		100
-#define MESH_HOLD_T 		100
-
-#define MESH_PATH_TIMEOUT	5000
-/* Minimum interval between two consecutive PREQs originated by the same
- * interface
- */
-#define MESH_PREQ_MIN_INT	10
-#define MESH_DIAM_TRAVERSAL_TIME 50
-/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
- * timing out.  This way it will remain ACTIVE and no data frames will be
- * unnecesarily held in the pending queue.
- */
-#define MESH_PATH_REFRESH_TIME			1000
-#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
 #define MESH_DEFAULT_BEACON_INTERVAL		1000 	/* in 1024 us units */
 
-#define MESH_MAX_PREQ_RETRIES 4
 #define MESH_PATH_EXPIRE (600 * HZ)
 
-/* Default maximum number of established plinks per interface */
-#define MESH_MAX_ESTAB_PLINKS	32
-
 /* Default maximum number of plinks per interface */
 #define MESH_MAX_PLINKS		256
 
--- wireless-testing.orig/net/wireless/util.c	2010-12-02 09:32:13.000000000 +0100
+++ wireless-testing/net/wireless/util.c	2010-12-02 09:38:22.000000000 +0100
@@ -792,6 +792,7 @@ int cfg80211_change_iface(struct cfg8021
 
 	if (ntype != otype) {
 		dev->ieee80211_ptr->use_4addr = false;
+		dev->ieee80211_ptr->mesh_id_up_len = 0;
 
 		switch (otype) {
 		case NL80211_IFTYPE_ADHOC:



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02  8:45   ` [RFC 5/5 v2] " Johannes Berg
@ 2010-12-02 20:09     ` Javier Cardona
  2010-12-02 20:14       ` Johannes Berg
  0 siblings, 1 reply; 17+ messages in thread
From: Javier Cardona @ 2010-12-02 20:09 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Steve Derosier, devel

Johannes,

Looks good from this end, including the new iw commands.  The only
issue that we observed is that now that we can leave and join a new
mesh, we need to do some more state cleanup on stop_mesh.  Otherwise
we could move to a new mesh and still talk to the previous peers.  I
think this would be sufficient:

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 107a0cb..b1242b6 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -246,7 +246,6 @@ void ieee80211_bss_info_change_notify(struct
ieee80211_sub_if_data *sdata,
                                        !!sdata->u.ibss.presp;
                                break;
                        case NL80211_IFTYPE_MESH_POINT:
-                               sdata->vif.bss_conf.enable_beacon = true;
                                break;
                        default:
                                /* not reached */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d814fab..cc458dd 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -522,6 +522,7 @@ void ieee80211_start_mesh(struct
ieee80211_sub_if_data *sdata)
        ieee80211_mesh_root_setup(ifmsh);
        ieee80211_queue_work(&local->hw, &sdata->work);
        sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
+       sdata->vif.bss_conf.enable_beacon = true;
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
                                                BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_BEACON_INT);
@@ -530,6 +531,13 @@ void ieee80211_start_mesh(struct
ieee80211_sub_if_data *sdata)
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+       ifmsh->mesh_id_len = 0;
+       memset(ifmsh->mesh_id, 0, IEEE80211_MAX_MESH_ID_LEN);
+       sdata->vif.bss_conf.enable_beacon = false;
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+       sta_info_flush(local, NULL);

        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);

Cheers,

Javier

On Thu, Dec 2, 2010 at 12:45 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> From: Johannes Berg <johannes.berg@intel.com>
>
> Instead of tying mesh activity to interface up,
> add join and leave commands for mesh. Since we
> must be backward compatible, let cfg80211 handle
> joining a mesh if a mesh ID was pre-configured
> when the device goes up.
>
> Note that this therefore must modify mac80211 as
> well since mac80211 needs to lose the logic to
> start the mesh on interface up.
>
> We now allow querying mesh parameters before the
> mesh is connected, which simply returns defaults.
> Setting them (internally renamed to "update") is
> only allowed while connected. Specify them with
> the new mesh join command instead where needed.
>
> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
> ---
> v2: - fix join on netdev up (pointed out by Javier)
>    - only require mesh ID (pointed out by Javier)
>    - more sanity checking around get/set_mesh_params
>    - rename set_mesh_params to update_mesh_params,
>      disallow calling it before connected to mesh
>    - add some mesh interface type checks
>    - introduce mesh_setup struct for static config
>
> I have lightly tested this. You can find a new
> test branch of iw that includes support for the
> new commands here:
>
> http://git.sipsolutions.net/?p=iw.git;a=shortlog;h=refs/heads/mesh
>
>
> I think this is about ready, maybe with some
> minor issues still. I'd appreciate if you could
> review and test it, and then we can add the IE
> and path selection protocols to the mesh_setup
> struct and the iw mesh join command.
>
>
>  include/linux/nl80211.h    |    8 ++
>  include/net/cfg80211.h     |   38 +++++++++---
>  net/mac80211/cfg.c         |   39 +++++++++---
>  net/mac80211/ieee80211_i.h |   13 ----
>  net/mac80211/iface.c       |   14 ----
>  net/mac80211/mesh.c        |   20 ------
>  net/mac80211/mesh.h        |   23 -------
>  net/wireless/Makefile      |    2
>  net/wireless/core.c        |   15 ++++
>  net/wireless/core.h        |   13 ++++
>  net/wireless/mesh.c        |  134 ++++++++++++++++++++++++++++++++++++++++++++
>  net/wireless/nl80211.c     |  137 ++++++++++++++++++++++++++++++++++++++-------
>  net/wireless/util.c        |    1
>  13 files changed, 346 insertions(+), 111 deletions(-)
>
> --- wireless-testing.orig/include/linux/nl80211.h       2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/include/linux/nl80211.h    2010-12-02 09:38:22.000000000 +0100
> @@ -394,6 +394,11 @@
>  *
>  * @NL80211_CMD_SET_WDS_PEER: Set the MAC address of the peer on a WDS interface.
>  *
> + * @NL80211_CMD_JOIN_MESH: Join a mesh. The mesh ID must be given, and initial
> + *     mesh config parameters may be given.
> + * @NL80211_CMD_LEAVE_MESH: Leave the mesh network -- no special arguments, the
> + *     network is determined by the network interface.
> + *
>  * @NL80211_CMD_MAX: highest used command number
>  * @__NL80211_CMD_AFTER_LAST: internal use
>  */
> @@ -500,6 +505,9 @@ enum nl80211_commands {
>
>        NL80211_CMD_FRAME_WAIT_CANCEL,
>
> +       NL80211_CMD_JOIN_MESH,
> +       NL80211_CMD_LEAVE_MESH,
> +
>        /* add new commands above here */
>
>        /* used to define NL80211_CMD_MAX below */
> --- wireless-testing.orig/include/net/cfg80211.h        2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/include/net/cfg80211.h     2010-12-02 09:38:22.000000000 +0100
> @@ -258,13 +258,9 @@ struct ieee80211_supported_band {
>
>  /**
>  * struct vif_params - describes virtual interface parameters
> - * @mesh_id: mesh ID to use
> - * @mesh_id_len: length of the mesh ID
>  * @use_4addr: use 4-address frames
>  */
>  struct vif_params {
> -       u8 *mesh_id;
> -       int mesh_id_len;
>        int use_4addr;
>  };
>
> @@ -615,6 +611,11 @@ struct bss_parameters {
>        int ap_isolate;
>  };
>
> +/*
> + * struct mesh_config - 802.11s mesh configuration
> + *
> + * These parameters can be changed while the mesh is active.
> + */
>  struct mesh_config {
>        /* Timeouts in ms */
>        /* Mesh plink management parameters */
> @@ -636,6 +637,18 @@ struct mesh_config {
>  };
>
>  /**
> + * struct mesh_setup - 802.11s mesh setup configuration
> + * @mesh_id: the mesh ID
> + * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
> + *
> + * These parameters are fixed when the mesh is created.
> + */
> +struct mesh_setup {
> +       const u8 *mesh_id;
> +       u8 mesh_id_len;
> +};
> +
> +/**
>  * struct ieee80211_txq_params - TX queue parameters
>  * @queue: TX queue identifier (NL80211_TXQ_Q_*)
>  * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled
> @@ -1076,7 +1089,7 @@ struct cfg80211_pmksa {
>  *
>  * @get_mesh_params: Put the current mesh parameters into *params
>  *
> - * @set_mesh_params: Set mesh parameters.
> + * @update_mesh_params: Update mesh parameters on a running mesh.
>  *     The mask is a bitfield which tells us which parameters to
>  *     set, and which to leave alone.
>  *
> @@ -1220,9 +1233,14 @@ struct cfg80211_ops {
>        int     (*get_mesh_params)(struct wiphy *wiphy,
>                                struct net_device *dev,
>                                struct mesh_config *conf);
> -       int     (*set_mesh_params)(struct wiphy *wiphy,
> -                               struct net_device *dev,
> -                               const struct mesh_config *nconf, u32 mask);
> +       int     (*update_mesh_params)(struct wiphy *wiphy,
> +                                     struct net_device *dev, u32 mask,
> +                                     const struct mesh_config *nconf);
> +       int     (*join_mesh)(struct wiphy *wiphy, struct net_device *dev,
> +                            const struct mesh_config *conf,
> +                            const struct mesh_setup *setup);
> +       int     (*leave_mesh)(struct wiphy *wiphy, struct net_device *dev);
> +
>        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
>                              struct bss_parameters *params);
>
> @@ -1638,6 +1656,8 @@ struct cfg80211_cached_keys;
>  * @bssid: (private) Used by the internal configuration code
>  * @ssid: (private) Used by the internal configuration code
>  * @ssid_len: (private) Used by the internal configuration code
> + * @mesh_id_len: (private) Used by the internal configuration code
> + * @mesh_id_up_len: (private) Used by the internal configuration code
>  * @wext: (private) Used by the internal wireless extensions compat code
>  * @use_4addr: indicates 4addr mode is used on this interface, must be
>  *     set by driver (if supported) on add_interface BEFORE registering the
> @@ -1667,7 +1687,7 @@ struct wireless_dev {
>
>        /* currently used for IBSS and SME - might be rearranged later */
>        u8 ssid[IEEE80211_MAX_SSID_LEN];
> -       u8 ssid_len;
> +       u8 ssid_len, mesh_id_len, mesh_id_up_len;
>        enum {
>                CFG80211_SME_IDLE,
>                CFG80211_SME_CONNECTING,
> --- wireless-testing.orig/net/wireless/Makefile 2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/wireless/Makefile      2010-12-02 09:38:22.000000000 +0100
> @@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o
>  obj-$(CONFIG_WEXT_PRIV) += wext-priv.o
>
>  cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o
> -cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o
> +cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o
>  cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
>  cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o
>  cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o
> --- wireless-testing.orig/net/wireless/core.h   2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/wireless/core.h        2010-12-02 09:38:22.000000000 +0100
> @@ -285,6 +285,19 @@ void __cfg80211_ibss_joined(struct net_d
>  int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
>                            struct wireless_dev *wdev);
>
> +/* mesh */
> +extern const struct mesh_config default_mesh_config;
> +int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
> +                        struct net_device *dev,
> +                        const u8 *mesh_id, u8 mesh_id_len,
> +                        const struct mesh_config *conf);
> +int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
> +                      struct net_device *dev,
> +                      const u8 *mesh_id, u8 mesh_id_len,
> +                      const struct mesh_config *conf);
> +int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
> +                       struct net_device *dev);
> +
>  /* MLME */
>  int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
>                         struct net_device *dev,
> --- /dev/null   1970-01-01 00:00:00.000000000 +0000
> +++ wireless-testing/net/wireless/mesh.c        2010-12-02 09:38:22.000000000 +0100
> @@ -0,0 +1,134 @@
> +#include <linux/ieee80211.h>
> +#include <net/cfg80211.h>
> +#include "core.h"
> +
> +/* Default values, timeouts in ms */
> +#define MESH_TTL               31
> +#define MESH_MAX_RETR          3
> +#define MESH_RET_T             100
> +#define MESH_CONF_T            100
> +#define MESH_HOLD_T            100
> +
> +#define MESH_PATH_TIMEOUT      5000
> +/* Minimum interval between two consecutive PREQs originated by the same
> + * interface
> + */
> +#define MESH_PREQ_MIN_INT      10
> +#define MESH_DIAM_TRAVERSAL_TIME 50
> +/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
> + * timing out.  This way it will remain ACTIVE and no data frames will be
> + * unnecesarily held in the pending queue.
> + */
> +#define MESH_PATH_REFRESH_TIME                 1000
> +#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
> +
> +/* Default maximum number of established plinks per interface */
> +#define MESH_MAX_ESTAB_PLINKS  32
> +
> +#define MESH_MAX_PREQ_RETRIES 4
> +
> +
> +const struct mesh_config default_mesh_config = {
> +       .dot11MeshRetryTimeout = MESH_RET_T,
> +       .dot11MeshConfirmTimeout = MESH_CONF_T,
> +       .dot11MeshHoldingTimeout = MESH_HOLD_T,
> +       .dot11MeshMaxRetries = MESH_MAX_RETR,
> +       .dot11MeshTTL = MESH_TTL,
> +       .auto_open_plinks = true,
> +       .dot11MeshMaxPeerLinks = MESH_MAX_ESTAB_PLINKS,
> +       .dot11MeshHWMPactivePathTimeout = MESH_PATH_TIMEOUT,
> +       .dot11MeshHWMPpreqMinInterval = MESH_PREQ_MIN_INT,
> +       .dot11MeshHWMPnetDiameterTraversalTime = MESH_DIAM_TRAVERSAL_TIME,
> +       .dot11MeshHWMPmaxPREQretries = MESH_MAX_PREQ_RETRIES,
> +       .path_refresh_time = MESH_PATH_REFRESH_TIME,
> +       .min_discovery_timeout = MESH_MIN_DISCOVERY_TIMEOUT,
> +};
> +
> +
> +int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
> +                        struct net_device *dev,
> +                        const u8 *mesh_id, u8 mesh_id_len,
> +                        const struct mesh_config *conf)
> +{
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct mesh_setup setup = {
> +               .mesh_id = mesh_id,
> +               .mesh_id_len = mesh_id_len,
> +       };
> +       int err;
> +
> +       BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN);
> +
> +       ASSERT_WDEV_LOCK(wdev);
> +
> +       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
> +               return -EOPNOTSUPP;
> +
> +       if (wdev->mesh_id_len)
> +               return -EALREADY;
> +
> +       if (!mesh_id_len)
> +               return -EINVAL;
> +
> +       if (!rdev->ops->join_mesh)
> +               return -EOPNOTSUPP;
> +
> +       err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, &setup);
> +       if (!err) {
> +               memcpy(wdev->ssid, mesh_id, mesh_id_len);
> +               wdev->mesh_id_len = mesh_id_len;
> +       }
> +
> +       return err;
> +}
> +
> +int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
> +                      struct net_device *dev,
> +                      const u8 *mesh_id, u8 mesh_id_len,
> +                      const struct mesh_config *conf)
> +{
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       int err;
> +
> +       wdev_lock(wdev);
> +       err = __cfg80211_join_mesh(rdev, dev, mesh_id, mesh_id_len, conf);
> +       wdev_unlock(wdev);
> +
> +       return err;
> +}
> +
> +static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
> +                                struct net_device *dev)
> +{
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       int err;
> +
> +       ASSERT_WDEV_LOCK(wdev);
> +
> +       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
> +               return -EOPNOTSUPP;
> +
> +       if (!rdev->ops->leave_mesh)
> +               return -EOPNOTSUPP;
> +
> +       if (!wdev->mesh_id_len)
> +               return -ENOTCONN;
> +
> +       err = rdev->ops->leave_mesh(&rdev->wiphy, dev);
> +       if (!err)
> +               wdev->mesh_id_len = 0;
> +       return err;
> +}
> +
> +int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
> +                       struct net_device *dev)
> +{
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       int err;
> +
> +       wdev_lock(wdev);
> +       err = __cfg80211_leave_mesh(rdev, dev);
> +       wdev_unlock(wdev);
> +
> +       return err;
> +}
> --- wireless-testing.orig/net/wireless/nl80211.c        2010-12-02 09:38:20.000000000 +0100
> +++ wireless-testing/net/wireless/nl80211.c     2010-12-02 09:38:31.000000000 +0100
> @@ -661,13 +661,14 @@ static int nl80211_send_wiphy(struct sk_
>        CMD(add_beacon, NEW_BEACON);
>        CMD(add_station, NEW_STATION);
>        CMD(add_mpath, NEW_MPATH);
> -       CMD(set_mesh_params, SET_MESH_PARAMS);
> +       CMD(update_mesh_params, SET_MESH_PARAMS);
>        CMD(change_bss, SET_BSS);
>        CMD(auth, AUTHENTICATE);
>        CMD(assoc, ASSOCIATE);
>        CMD(deauth, DEAUTHENTICATE);
>        CMD(disassoc, DISASSOCIATE);
>        CMD(join_ibss, JOIN_IBSS);
> +       CMD(join_mesh, JOIN_MESH);
>        CMD(set_pmksa, SET_PMKSA);
>        CMD(del_pmksa, DEL_PMKSA);
>        CMD(flush_pmksa, FLUSH_PMKSA);
> @@ -1324,11 +1325,21 @@ static int nl80211_set_interface(struct
>        }
>
>        if (info->attrs[NL80211_ATTR_MESH_ID]) {
> +               struct wireless_dev *wdev = dev->ieee80211_ptr;
> +
>                if (ntype != NL80211_IFTYPE_MESH_POINT)
>                        return -EINVAL;
> -               params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
> -               params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
> -               change = true;
> +               if (netif_running(dev))
> +                       return -EBUSY;
> +
> +               wdev_lock(wdev);
> +               BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
> +                            IEEE80211_MAX_MESH_ID_LEN);
> +               wdev->mesh_id_up_len =
> +                       nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
> +               memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
> +                      wdev->mesh_id_up_len);
> +               wdev_unlock(wdev);
>        }
>
>        if (info->attrs[NL80211_ATTR_4ADDR]) {
> @@ -1388,12 +1399,6 @@ static int nl80211_new_interface(struct
>            !(rdev->wiphy.interface_modes & (1 << type)))
>                return -EOPNOTSUPP;
>
> -       if (type == NL80211_IFTYPE_MESH_POINT &&
> -           info->attrs[NL80211_ATTR_MESH_ID]) {
> -               params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]);
> -               params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
> -       }
> -
>        if (info->attrs[NL80211_ATTR_4ADDR]) {
>                params.use_4addr = !!nla_get_u8(info->attrs[NL80211_ATTR_4ADDR]);
>                err = nl80211_valid_4addr(rdev, NULL, params.use_4addr, type);
> @@ -1410,6 +1415,20 @@ static int nl80211_new_interface(struct
>        if (IS_ERR(dev))
>                return PTR_ERR(dev);
>
> +       if (type == NL80211_IFTYPE_MESH_POINT &&
> +           info->attrs[NL80211_ATTR_MESH_ID]) {
> +               struct wireless_dev *wdev = dev->ieee80211_ptr;
> +
> +               wdev_lock(wdev);
> +               BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN !=
> +                            IEEE80211_MAX_MESH_ID_LEN);
> +               wdev->mesh_id_up_len =
> +                       nla_len(info->attrs[NL80211_ATTR_MESH_ID]);
> +               memcpy(wdev->ssid, nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
> +                      wdev->mesh_id_up_len);
> +               wdev_unlock(wdev);
> +       }
> +
>        return 0;
>  }
>
> @@ -2543,21 +2562,32 @@ static int nl80211_req_set_reg(struct sk
>  }
>
>  static int nl80211_get_mesh_params(struct sk_buff *skb,
> -       struct genl_info *info)
> +                                  struct genl_info *info)
>  {
>        struct cfg80211_registered_device *rdev = info->user_ptr[0];
> -       struct mesh_config cur_params;
> -       int err;
>        struct net_device *dev = info->user_ptr[1];
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
> +       struct mesh_config cur_params;
> +       int err = 0;
>        void *hdr;
>        struct nlattr *pinfoattr;
>        struct sk_buff *msg;
>
> +       if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
> +               return -EOPNOTSUPP;
> +
>        if (!rdev->ops->get_mesh_params)
>                return -EOPNOTSUPP;
>
> -       /* Get the mesh params */
> -       err = rdev->ops->get_mesh_params(&rdev->wiphy, dev, &cur_params);
> +       wdev_lock(wdev);
> +       /* If not connected, get default parameters */
> +       if (!wdev->mesh_id_len)
> +               memcpy(&cur_params, &default_mesh_config, sizeof(cur_params));
> +       else
> +               err = rdev->ops->get_mesh_params(&rdev->wiphy, dev,
> +                                                &cur_params);
> +       wdev_unlock(wdev);
> +
>        if (err)
>                return err;
>
> @@ -2700,23 +2730,37 @@ do {\
>  #undef FILL_IN_MESH_PARAM_IF_SET
>  }
>
> -static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
> +static int nl80211_update_mesh_params(struct sk_buff *skb,
> +                                     struct genl_info *info)
>  {
>        struct cfg80211_registered_device *rdev = info->user_ptr[0];
>        struct net_device *dev = info->user_ptr[1];
> +       struct wireless_dev *wdev = dev->ieee80211_ptr;
>        struct mesh_config cfg;
>        u32 mask;
>        int err;
>
> -       if (!rdev->ops->set_mesh_params)
> +       if (wdev->iftype != NL80211_IFTYPE_MESH_POINT)
> +               return -EOPNOTSUPP;
> +
> +       if (!rdev->ops->update_mesh_params)
>                return -EOPNOTSUPP;
>
>        err = nl80211_parse_mesh_params(info, &cfg, &mask);
>        if (err)
>                return err;
>
> -       /* Apply changes */
> -       return rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
> +       wdev_lock(wdev);
> +       if (!wdev->mesh_id_len)
> +               err = -ENOLINK;
> +
> +       if (!err)
> +               err = rdev->ops->update_mesh_params(&rdev->wiphy, dev,
> +                                                   mask, &cfg);
> +
> +       wdev_unlock(wdev);
> +
> +       return err;
>  }
>
>  static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
> @@ -4500,6 +4544,41 @@ out:
>        return err;
>  }
>
> +static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct cfg80211_registered_device *rdev = info->user_ptr[0];
> +       struct net_device *dev = info->user_ptr[1];
> +       struct mesh_config cfg;
> +       int err;
> +
> +       /* start with default */
> +       memcpy(&cfg, &default_mesh_config, sizeof(cfg));
> +
> +       if (info->attrs[NL80211_ATTR_MESH_PARAMS]) {
> +               /* and parse parameters if given */
> +               err = nl80211_parse_mesh_params(info, &cfg, NULL);
> +               if (err)
> +                       return err;
> +       }
> +
> +       if (!info->attrs[NL80211_ATTR_MESH_ID] ||
> +           !nla_len(info->attrs[NL80211_ATTR_MESH_ID]))
> +               return -EINVAL;
> +
> +       return cfg80211_join_mesh(rdev, dev,
> +                                 nla_data(info->attrs[NL80211_ATTR_MESH_ID]),
> +                                 nla_len(info->attrs[NL80211_ATTR_MESH_ID]),
> +                                 &cfg);
> +}
> +
> +static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct cfg80211_registered_device *rdev = info->user_ptr[0];
> +       struct net_device *dev = info->user_ptr[1];
> +
> +       return cfg80211_leave_mesh(rdev, dev);
> +}
> +
>  #define NL80211_FLAG_NEED_WIPHY                0x01
>  #define NL80211_FLAG_NEED_NETDEV       0x02
>  #define NL80211_FLAG_NEED_RTNL         0x04
> @@ -4764,10 +4843,10 @@ static struct genl_ops nl80211_ops[] = {
>        },
>        {
>                .cmd = NL80211_CMD_SET_MESH_PARAMS,
> -               .doit = nl80211_set_mesh_params,
> +               .doit = nl80211_update_mesh_params,
>                .policy = nl80211_policy,
>                .flags = GENL_ADMIN_PERM,
> -               .internal_flags = NL80211_FLAG_NEED_NETDEV |
> +               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
>                                  NL80211_FLAG_NEED_RTNL,
>        },
>        {
> @@ -4982,6 +5061,22 @@ static struct genl_ops nl80211_ops[] = {
>                .internal_flags = NL80211_FLAG_NEED_NETDEV |
>                                  NL80211_FLAG_NEED_RTNL,
>        },
> +       {
> +               .cmd = NL80211_CMD_JOIN_MESH,
> +               .doit = nl80211_join_mesh,
> +               .policy = nl80211_policy,
> +               .flags = GENL_ADMIN_PERM,
> +               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> +                                 NL80211_FLAG_NEED_RTNL,
> +       },
> +       {
> +               .cmd = NL80211_CMD_LEAVE_MESH,
> +               .doit = nl80211_leave_mesh,
> +               .policy = nl80211_policy,
> +               .flags = GENL_ADMIN_PERM,
> +               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
> +                                 NL80211_FLAG_NEED_RTNL,
> +       },
>  };
>
>  static struct genl_multicast_group nl80211_mlme_mcgrp = {
> --- wireless-testing.orig/net/wireless/core.c   2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/wireless/core.c        2010-12-02 09:38:22.000000000 +0100
> @@ -332,6 +332,7 @@ struct wiphy *wiphy_new(const struct cfg
>        WARN_ON(ops->add_virtual_intf && !ops->del_virtual_intf);
>        WARN_ON(ops->add_station && !ops->del_station);
>        WARN_ON(ops->add_mpath && !ops->del_mpath);
> +       WARN_ON(ops->join_mesh && !ops->leave_mesh);
>
>        alloc_size = sizeof(*rdev) + sizeof_priv;
>
> @@ -752,6 +753,9 @@ static int cfg80211_netdev_notifier_call
>                        cfg80211_mlme_down(rdev, dev);
>                        wdev_unlock(wdev);
>                        break;
> +               case NL80211_IFTYPE_MESH_POINT:
> +                       cfg80211_leave_mesh(rdev, dev);
> +                       break;
>                default:
>                        break;
>                }
> @@ -775,20 +779,27 @@ static int cfg80211_netdev_notifier_call
>                }
>                cfg80211_lock_rdev(rdev);
>                mutex_lock(&rdev->devlist_mtx);
> -#ifdef CONFIG_CFG80211_WEXT
>                wdev_lock(wdev);
>                switch (wdev->iftype) {
> +#ifdef CONFIG_CFG80211_WEXT
>                case NL80211_IFTYPE_ADHOC:
>                        cfg80211_ibss_wext_join(rdev, wdev);
>                        break;
>                case NL80211_IFTYPE_STATION:
>                        cfg80211_mgd_wext_connect(rdev, wdev);
>                        break;
> +#endif
> +               case NL80211_IFTYPE_MESH_POINT:
> +                       /* backward compat code ... */
> +                       if (wdev->mesh_id_up_len)
> +                               __cfg80211_join_mesh(rdev, dev, wdev->ssid,
> +                                                    wdev->mesh_id_up_len,
> +                                                    &default_mesh_config);
> +                       break;
>                default:
>                        break;
>                }
>                wdev_unlock(wdev);
> -#endif
>                rdev->opencount++;
>                mutex_unlock(&rdev->devlist_mtx);
>                cfg80211_unlock_rdev(rdev);
> --- wireless-testing.orig/net/mac80211/cfg.c    2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/mac80211/cfg.c 2010-12-02 09:38:22.000000000 +0100
> @@ -60,11 +60,6 @@ static int ieee80211_change_iface(struct
>        if (ret)
>                return ret;
>
> -       if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len)
> -               ieee80211_sdata_set_mesh_id(sdata,
> -                                           params->mesh_id_len,
> -                                           params->mesh_id);
> -
>        if (type == NL80211_IFTYPE_AP_VLAN &&
>            params && params->use_4addr == 0)
>                rcu_assign_pointer(sdata->u.vlan.sta, NULL);
> @@ -1003,9 +998,9 @@ static inline bool _chg_mesh_attr(enum n
>        return (mask >> (parm-1)) & 0x1;
>  }
>
> -static int ieee80211_set_mesh_params(struct wiphy *wiphy,
> -                               struct net_device *dev,
> -                               const struct mesh_config *nconf, u32 mask)
> +static int ieee80211_update_mesh_params(struct wiphy *wiphy,
> +                                       struct net_device *dev, u32 mask,
> +                                       const struct mesh_config *nconf)
>  {
>        struct mesh_config *conf;
>        struct ieee80211_sub_if_data *sdata;
> @@ -1054,6 +1049,30 @@ static int ieee80211_set_mesh_params(str
>        return 0;
>  }
>
> +static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
> +                              const struct mesh_config *conf,
> +                              const struct mesh_setup *setup)
> +{
> +       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
> +
> +       memcpy(&sdata->u.mesh.mshcfg, conf, sizeof(struct mesh_config));
> +       ifmsh->mesh_id_len = setup->mesh_id_len;
> +       memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
> +
> +       ieee80211_start_mesh(sdata);
> +
> +       return 0;
> +}
> +
> +static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
> +{
> +       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
> +
> +       ieee80211_stop_mesh(sdata);
> +
> +       return 0;
> +}
>  #endif
>
>  static int ieee80211_change_bss(struct wiphy *wiphy,
> @@ -1758,8 +1777,10 @@ struct cfg80211_ops mac80211_config_ops
>        .change_mpath = ieee80211_change_mpath,
>        .get_mpath = ieee80211_get_mpath,
>        .dump_mpath = ieee80211_dump_mpath,
> -       .set_mesh_params = ieee80211_set_mesh_params,
> +       .update_mesh_params = ieee80211_update_mesh_params,
>        .get_mesh_params = ieee80211_get_mesh_params,
> +       .join_mesh = ieee80211_join_mesh,
> +       .leave_mesh = ieee80211_leave_mesh,
>  #endif
>        .change_bss = ieee80211_change_bss,
>        .set_txq_params = ieee80211_set_txq_params,
> --- wireless-testing.orig/net/mac80211/ieee80211_i.h    2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/mac80211/ieee80211_i.h 2010-12-02 09:38:22.000000000 +0100
> @@ -608,19 +608,6 @@ struct ieee80211_sub_if_data *vif_to_sda
>        return container_of(p, struct ieee80211_sub_if_data, vif);
>  }
>
> -static inline void
> -ieee80211_sdata_set_mesh_id(struct ieee80211_sub_if_data *sdata,
> -                           u8 mesh_id_len, u8 *mesh_id)
> -{
> -#ifdef CONFIG_MAC80211_MESH
> -       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
> -       ifmsh->mesh_id_len = mesh_id_len;
> -       memcpy(ifmsh->mesh_id, mesh_id, mesh_id_len);
> -#else
> -       WARN_ON(1);
> -#endif
> -}
> -
>  enum sdata_queue_type {
>        IEEE80211_SDATA_QUEUE_TYPE_FRAME        = 0,
>        IEEE80211_SDATA_QUEUE_AGG_START         = 1,
> --- wireless-testing.orig/net/mac80211/iface.c  2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/mac80211/iface.c       2010-12-02 09:38:22.000000000 +0100
> @@ -268,9 +268,7 @@ static int ieee80211_do_open(struct net_
>                                goto err_stop;
>                }
>
> -               if (ieee80211_vif_is_mesh(&sdata->vif)) {
> -                       ieee80211_start_mesh(sdata);
> -               } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
> +               if (sdata->vif.type == NL80211_IFTYPE_AP) {
>                        local->fif_pspoll++;
>                        local->fif_probe_req++;
>
> @@ -495,10 +493,6 @@ static void ieee80211_do_stop(struct iee
>                ieee80211_adjust_monitor_flags(sdata, -1);
>                ieee80211_configure_filter(local);
>                break;
> -       case NL80211_IFTYPE_MESH_POINT:
> -               if (ieee80211_vif_is_mesh(&sdata->vif))
> -                       ieee80211_stop_mesh(sdata);
> -               /* fall through */
>        default:
>                flush_work(&sdata->work);
>                /*
> @@ -1188,12 +1182,6 @@ int ieee80211_if_add(struct ieee80211_lo
>        if (ret)
>                goto fail;
>
> -       if (ieee80211_vif_is_mesh(&sdata->vif) &&
> -           params && params->mesh_id_len)
> -               ieee80211_sdata_set_mesh_id(sdata,
> -                                           params->mesh_id_len,
> -                                           params->mesh_id);
> -
>        mutex_lock(&local->iflist_mtx);
>        list_add_tail_rcu(&sdata->list, &local->interfaces);
>        mutex_unlock(&local->iflist_mtx);
> --- wireless-testing.orig/net/mac80211/mesh.c   2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/mac80211/mesh.c        2010-12-02 09:38:22.000000000 +0100
> @@ -674,26 +674,6 @@ void ieee80211_mesh_init_sdata(struct ie
>                    ieee80211_mesh_housekeeping_timer,
>                    (unsigned long) sdata);
>
> -       ifmsh->mshcfg.dot11MeshRetryTimeout = MESH_RET_T;
> -       ifmsh->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T;
> -       ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
> -       ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
> -       ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
> -       ifmsh->mshcfg.auto_open_plinks = true;
> -       ifmsh->mshcfg.dot11MeshMaxPeerLinks =
> -               MESH_MAX_ESTAB_PLINKS;
> -       ifmsh->mshcfg.dot11MeshHWMPactivePathTimeout =
> -               MESH_PATH_TIMEOUT;
> -       ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval =
> -               MESH_PREQ_MIN_INT;
> -       ifmsh->mshcfg.dot11MeshHWMPnetDiameterTraversalTime =
> -               MESH_DIAM_TRAVERSAL_TIME;
> -       ifmsh->mshcfg.dot11MeshHWMPmaxPREQretries =
> -               MESH_MAX_PREQ_RETRIES;
> -       ifmsh->mshcfg.path_refresh_time =
> -               MESH_PATH_REFRESH_TIME;
> -       ifmsh->mshcfg.min_discovery_timeout =
> -               MESH_MIN_DISCOVERY_TIMEOUT;
>        ifmsh->accepting_plinks = true;
>        ifmsh->preq_id = 0;
>        ifmsh->sn = 0;
> --- wireless-testing.orig/net/mac80211/mesh.h   2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/mac80211/mesh.h        2010-12-02 09:38:22.000000000 +0100
> @@ -175,33 +175,10 @@ struct mesh_rmc {
>  */
>  #define MESH_CFG_CMP_LEN       (IEEE80211_MESH_CONFIG_LEN - 2)
>
> -/* Default values, timeouts in ms */
> -#define MESH_TTL               31
> -#define MESH_MAX_RETR          3
> -#define MESH_RET_T             100
> -#define MESH_CONF_T            100
> -#define MESH_HOLD_T            100
> -
> -#define MESH_PATH_TIMEOUT      5000
> -/* Minimum interval between two consecutive PREQs originated by the same
> - * interface
> - */
> -#define MESH_PREQ_MIN_INT      10
> -#define MESH_DIAM_TRAVERSAL_TIME 50
> -/* A path will be refreshed if it is used PATH_REFRESH_TIME milliseconds before
> - * timing out.  This way it will remain ACTIVE and no data frames will be
> - * unnecesarily held in the pending queue.
> - */
> -#define MESH_PATH_REFRESH_TIME                 1000
> -#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME)
>  #define MESH_DEFAULT_BEACON_INTERVAL           1000    /* in 1024 us units */
>
> -#define MESH_MAX_PREQ_RETRIES 4
>  #define MESH_PATH_EXPIRE (600 * HZ)
>
> -/* Default maximum number of established plinks per interface */
> -#define MESH_MAX_ESTAB_PLINKS  32
> -
>  /* Default maximum number of plinks per interface */
>  #define MESH_MAX_PLINKS                256
>
> --- wireless-testing.orig/net/wireless/util.c   2010-12-02 09:32:13.000000000 +0100
> +++ wireless-testing/net/wireless/util.c        2010-12-02 09:38:22.000000000 +0100
> @@ -792,6 +792,7 @@ int cfg80211_change_iface(struct cfg8021
>
>        if (ntype != otype) {
>                dev->ieee80211_ptr->use_4addr = false;
> +               dev->ieee80211_ptr->mesh_id_up_len = 0;
>
>                switch (otype) {
>                case NL80211_IFTYPE_ADHOC:
>
>
>



-- 
Javier Cardona
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02 20:09     ` Javier Cardona
@ 2010-12-02 20:14       ` Johannes Berg
  2010-12-02 21:24         ` Javier Cardona
  0 siblings, 1 reply; 17+ messages in thread
From: Johannes Berg @ 2010-12-02 20:14 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, Steve Derosier, devel

Javier,

> Looks good from this end, including the new iw commands.  

Thanks!

> The only
> issue that we observed is that now that we can leave and join a new
> mesh, we need to do some more state cleanup on stop_mesh.  Otherwise
> we could move to a new mesh and still talk to the previous peers.  I
> think this would be sufficient:
> 
> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
> index 107a0cb..b1242b6 100644
> --- a/net/mac80211/main.c
> +++ b/net/mac80211/main.c
> @@ -246,7 +246,6 @@ void ieee80211_bss_info_change_notify(struct
> ieee80211_sub_if_data *sdata,
>                                         !!sdata->u.ibss.presp;
>                                 break;
>                         case NL80211_IFTYPE_MESH_POINT:
> -                               sdata->vif.bss_conf.enable_beacon = true;
>                                 break;
>                         default:

Oh, indeed. I think this should be
	sdata->vif.bss_conf.enable_beacon = !!mesh_id_len;

though.

> diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
> index d814fab..cc458dd 100644
> --- a/net/mac80211/mesh.c
> +++ b/net/mac80211/mesh.c
> @@ -522,6 +522,7 @@ void ieee80211_start_mesh(struct
> ieee80211_sub_if_data *sdata)
>         ieee80211_mesh_root_setup(ifmsh);
>         ieee80211_queue_work(&local->hw, &sdata->work);
>         sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
> +       sdata->vif.bss_conf.enable_beacon = true;

Because otherwise, if you just do this, scanning will stop beaconing
forever...

>         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
>                                                 BSS_CHANGED_BEACON_ENABLED |
>                                                 BSS_CHANGED_BEACON_INT);
> @@ -530,6 +531,13 @@ void ieee80211_start_mesh(struct
> ieee80211_sub_if_data *sdata)
>  void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
>  {
>         struct ieee80211_local *local = sdata->local;
> +       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
> +
> +       ifmsh->mesh_id_len = 0;

Yeah good catch.

> +       memset(ifmsh->mesh_id, 0, IEEE80211_MAX_MESH_ID_LEN);

That shouldn't really be necessary.

> +       sdata->vif.bss_conf.enable_beacon = false;

Nor would that with the change I proposed, I think.

> +       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
> +       sta_info_flush(local, NULL);

Yup, good changes.

Would you mind briefly testing the beacon change I proposed above?

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02 20:14       ` Johannes Berg
@ 2010-12-02 21:24         ` Javier Cardona
  2010-12-02 21:38           ` Johannes Berg
  0 siblings, 1 reply; 17+ messages in thread
From: Javier Cardona @ 2010-12-02 21:24 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Steve Derosier, devel

Johannes,

Thanks for reviewing.  You were right: scanning did stop beaconing
forever and your suggested fix resolved that.  So the patch is now:

diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 107a0cb..2de6976 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -246,7 +246,8 @@ void ieee80211_bss_info_change_notify(struct
ieee80211_sub_if_data *sdata,
                                        !!sdata->u.ibss.presp;
                                break;
                        case NL80211_IFTYPE_MESH_POINT:
-                               sdata->vif.bss_conf.enable_beacon = true;
+                               sdata->vif.bss_conf.enable_beacon =
+                                       !!sdata->u.mesh.mesh_id_len;
                                break;
                        default:
                                /* not reached */
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d814fab..63e1188 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -530,6 +530,11 @@ void ieee80211_start_mesh(struct
ieee80211_sub_if_data *sdata)
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+       ifmsh->mesh_id_len = 0;
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
+       sta_info_flush(local, NULL);

        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);

We have not run our full suite but we tested legacy interface mesh up,
joining, leaving and rejoining different meshes and all seems to work.
 Feel free to add my tested-by or signoff tags.

Thanks!

Javier


On Thu, Dec 2, 2010 at 12:14 PM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> Javier,
>
>> Looks good from this end, including the new iw commands.
>
> Thanks!
>
>> The only
>> issue that we observed is that now that we can leave and join a new
>> mesh, we need to do some more state cleanup on stop_mesh.  Otherwise
>> we could move to a new mesh and still talk to the previous peers.  I
>> think this would be sufficient:
>>
>> diff --git a/net/mac80211/main.c b/net/mac80211/main.c
>> index 107a0cb..b1242b6 100644
>> --- a/net/mac80211/main.c
>> +++ b/net/mac80211/main.c
>> @@ -246,7 +246,6 @@ void ieee80211_bss_info_change_notify(struct
>> ieee80211_sub_if_data *sdata,
>>                                         !!sdata->u.ibss.presp;
>>                                 break;
>>                         case NL80211_IFTYPE_MESH_POINT:
>> -                               sdata->vif.bss_conf.enable_beacon = true;
>>                                 break;
>>                         default:
>
> Oh, indeed. I think this should be
>        sdata->vif.bss_conf.enable_beacon = !!mesh_id_len;
>
> though.
>
>> diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
>> index d814fab..cc458dd 100644
>> --- a/net/mac80211/mesh.c
>> +++ b/net/mac80211/mesh.c
>> @@ -522,6 +522,7 @@ void ieee80211_start_mesh(struct
>> ieee80211_sub_if_data *sdata)
>>         ieee80211_mesh_root_setup(ifmsh);
>>         ieee80211_queue_work(&local->hw, &sdata->work);
>>         sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
>> +       sdata->vif.bss_conf.enable_beacon = true;
>
> Because otherwise, if you just do this, scanning will stop beaconing
> forever...
>
>>         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
>>                                                 BSS_CHANGED_BEACON_ENABLED |
>>                                                 BSS_CHANGED_BEACON_INT);
>> @@ -530,6 +531,13 @@ void ieee80211_start_mesh(struct
>> ieee80211_sub_if_data *sdata)
>>  void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
>>  {
>>         struct ieee80211_local *local = sdata->local;
>> +       struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
>> +
>> +       ifmsh->mesh_id_len = 0;
>
> Yeah good catch.
>
>> +       memset(ifmsh->mesh_id, 0, IEEE80211_MAX_MESH_ID_LEN);
>
> That shouldn't really be necessary.
>
>> +       sdata->vif.bss_conf.enable_beacon = false;
>
> Nor would that with the change I proposed, I think.
>
>> +       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
>> +       sta_info_flush(local, NULL);
>
> Yup, good changes.
>
> Would you mind briefly testing the beacon change I proposed above?
>
> johannes
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



-- 
Javier Cardona
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02 21:24         ` Javier Cardona
@ 2010-12-02 21:38           ` Johannes Berg
  2010-12-02 23:08             ` Javier Cardona
  0 siblings, 1 reply; 17+ messages in thread
From: Johannes Berg @ 2010-12-02 21:38 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, Steve Derosier, devel

On Thu, 2010-12-02 at 13:24 -0800, Javier Cardona wrote:
> Johannes,
> 
> Thanks for reviewing.  You were right: scanning did stop beaconing
> forever and your suggested fix resolved that.  So the patch is now:

Thanks for that.

> We have not run our full suite but we tested legacy interface mesh up,
> joining, leaving and rejoining different meshes and all seems to work.

Great.

>  Feel free to add my tested-by or signoff tags.

So you're happy with the 1/5 patch as well now?

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02 21:38           ` Johannes Berg
@ 2010-12-02 23:08             ` Javier Cardona
  2010-12-03  8:13               ` Johannes Berg
  0 siblings, 1 reply; 17+ messages in thread
From: Javier Cardona @ 2010-12-02 23:08 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Steve Derosier, devel

Johannes,

On Thu, Dec 2, 2010 at 1:38 PM, Johannes Berg <johannes@sipsolutions.net> wrote:
> So you're happy with the 1/5 patch as well now?

Not really.  Maybe this as PATCH 1/5 v3?


>From e2c1b17a9170580001643cef1ccba3ace8e1f23f Mon Sep 17 00:00:00 2001
From: Javier Cardona <javier@cozybit.com>
Date: Thu, 2 Dec 2010 14:57:20 -0800
Subject: [PATCH] mac80211: Define element TTL for HWMP path selection elements

The TTL in path selection information elements is different from the
mesh ttl used in mesh data frames.  Version 7.03 of the 11s draft calls this
ttl 'Element TTL'.
---
 include/linux/nl80211.h       |    4 ++++
 include/net/cfg80211.h        |    2 ++
 net/mac80211/cfg.c            |    2 ++
 net/mac80211/debugfs_netdev.c |    2 ++
 net/mac80211/mesh.c           |    1 +
 net/mac80211/mesh.h           |    2 ++
 net/mac80211/mesh_hwmp.c      |    9 +++++----
 net/mac80211/mesh_pathtbl.c   |    7 ++++---
 net/wireless/nl80211.c        |    5 +++++
 9 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 5cfa579..d8884e2 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1547,6 +1547,9 @@ enum nl80211_mntr_flags {
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
  * point.
  *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
  * open peer links when we detect compatible mesh peers.
  *
@@ -1585,6 +1588,7 @@ enum nl80211_meshconf_params {
 	NL80211_MESHCONF_MAX_PEER_LINKS,
 	NL80211_MESHCONF_MAX_RETRIES,
 	NL80211_MESHCONF_TTL,
+	NL80211_MESHCONF_ELEMENT_TTL,
 	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
 	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
 	NL80211_MESHCONF_PATH_REFRESH_TIME,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 49a7c53..b34dbc5 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -624,6 +624,8 @@ struct mesh_config {
 	u16 dot11MeshMaxPeerLinks;
 	u8  dot11MeshMaxRetries;
 	u8  dot11MeshTTL;
+	/* ttl used in path selection information elements */
+	u8  element_ttl;
 	bool auto_open_plinks;
 	/* HWMP parameters */
 	u8  dot11MeshHWMPmaxPREQretries;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index db134b5..ce69368 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1024,6 +1024,8 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy,
 		conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries;
 	if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask))
 		conf->dot11MeshTTL = nconf->dot11MeshTTL;
+	if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask))
+		conf->dot11MeshTTL = nconf->element_ttl;
 	if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask))
 		conf->auto_open_plinks = nconf->auto_open_plinks;
 	if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask))
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index cbdf36d..2dabdf7 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -251,6 +251,7 @@ IEEE80211_IF_FILE(dot11MeshConfirmTimeout,
 IEEE80211_IF_FILE(dot11MeshHoldingTimeout,
 		u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC);
 IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC);
+IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC);
 IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC);
 IEEE80211_IF_FILE(dot11MeshMaxPeerLinks,
 		u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC);
@@ -355,6 +356,7 @@ static void add_mesh_config(struct
ieee80211_sub_if_data *sdata)
 	MESHPARAMS_ADD(dot11MeshConfirmTimeout);
 	MESHPARAMS_ADD(dot11MeshHoldingTimeout);
 	MESHPARAMS_ADD(dot11MeshTTL);
+	MESHPARAMS_ADD(element_ttl);
 	MESHPARAMS_ADD(auto_open_plinks);
 	MESHPARAMS_ADD(dot11MeshMaxPeerLinks);
 	MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index c8a4f19..78a36c7 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -668,6 +668,7 @@ void ieee80211_mesh_init_sdata(struct
ieee80211_sub_if_data *sdata)
 	ifmsh->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T;
 	ifmsh->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR;
 	ifmsh->mshcfg.dot11MeshTTL = MESH_TTL;
+	ifmsh->mshcfg.element_ttl = MESH_DEFAULT_ELEMENT_TTL;
 	ifmsh->mshcfg.auto_open_plinks = true;
 	ifmsh->mshcfg.dot11MeshMaxPeerLinks =
 		MESH_MAX_ESTAB_PLINKS;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 58e7411..182942e 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -216,6 +216,8 @@ struct mesh_rmc {
 #define PERR_RCODE_NO_ROUTE     12
 #define PERR_RCODE_DEST_UNREACH 13

+#define MESH_DEFAULT_ELEMENT_TTL 31
+
 /* Public interfaces */
 /* Various */
 int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 829e08a..5bf64d7 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -232,7 +232,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
 	*pos++ = WLAN_EID_PERR;
 	*pos++ = ie_len;
 	/* ttl */
-	*pos++ = MESH_TTL;
+	*pos++ = ttl;
 	/* number of destinations */
 	*pos++ = 1;
 	/*
@@ -522,7 +522,7 @@ static void hwmp_preq_frame_process(struct
ieee80211_sub_if_data *sdata,

 	if (reply) {
 		lifetime = PREQ_IE_LIFETIME(preq_elem);
-		ttl = ifmsh->mshcfg.dot11MeshTTL;
+		ttl = ifmsh->mshcfg.element_ttl;
 		if (ttl != 0) {
 			mhwmp_dbg("replying to the PREQ\n");
 			mesh_path_sel_frame_tx(MPATH_PREP, 0, target_addr,
@@ -877,7 +877,7 @@ void mesh_path_start_discovery(struct
ieee80211_sub_if_data *sdata)
 		sdata->u.mesh.last_sn_update = jiffies;
 	}
 	lifetime = default_lifetime(sdata);
-	ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
+	ttl = sdata->u.mesh.mshcfg.element_ttl;
 	if (ttl == 0) {
 		sdata->u.mesh.mshstats.dropped_frames_ttl++;
 		spin_unlock_bh(&mpath->state_lock);
@@ -1013,5 +1013,6 @@ mesh_path_tx_root_frame(struct
ieee80211_sub_if_data *sdata)
 	mesh_path_sel_frame_tx(MPATH_RANN, 0, sdata->vif.addr,
 			       cpu_to_le32(++ifmsh->sn),
 			       0, NULL, 0, broadcast_addr,
-			       0, MESH_TTL, 0, 0, 0, sdata);
+			       0, sdata->u.mesh.mshcfg.element_ttl,
+			       0, 0, 0, sdata);
 }
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 349e466..8d65b47 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -467,8 +467,8 @@ void mesh_plink_broken(struct sta_info *sta)
 			mpath->flags &= ~MESH_PATH_ACTIVE;
 			++mpath->sn;
 			spin_unlock_bh(&mpath->state_lock);
-			mesh_path_error_tx(MESH_TTL, mpath->dst,
-					cpu_to_le32(mpath->sn),
+			mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl,
+					mpath->dst, cpu_to_le32(mpath->sn),
 					cpu_to_le16(PERR_RCODE_DEST_UNREACH),
 					bcast, sdata);
 		} else
@@ -614,7 +614,8 @@ void mesh_path_discard_frame(struct sk_buff *skb,
 		mpath = mesh_path_lookup(da, sdata);
 		if (mpath)
 			sn = ++mpath->sn;
-		mesh_path_error_tx(MESH_TTL, skb->data, cpu_to_le32(sn),
+		mesh_path_error_tx(sdata->u.mesh.mshcfg.element_ttl, skb->data,
+				   cpu_to_le32(sn),
 				   cpu_to_le16(PERR_RCODE_NO_ROUTE), ra, sdata);
 	}

diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 960be4e..0b90cab 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2582,6 +2582,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
 			cur_params.dot11MeshMaxRetries);
 	NLA_PUT_U8(msg, NL80211_MESHCONF_TTL,
 			cur_params.dot11MeshTTL);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_ELEMENT_TTL,
+			cur_params.element_ttl);
 	NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS,
 			cur_params.auto_open_plinks);
 	NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
@@ -2623,6 +2625,7 @@ static const struct nla_policy
nl80211_meshconf_params_policy[NL80211_MESHCONF_A
 	[NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 },
 	[NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_TTL] = { .type = NLA_U8 },
+	[NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 },
 	[NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 },

 	[NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 },
@@ -2670,6 +2673,8 @@ static int nl80211_set_mesh_params(struct
sk_buff *skb, struct genl_info *info)
 			mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL,
 			mask, NL80211_MESHCONF_TTL, nla_get_u8);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl,
+			mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks,
 			mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8);
 	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries,
-- 
1.7.1



-- 
Javier Cardona
cozybit Inc.
http://www.cozybit.com

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [RFC 5/5 v2] cfg80211/mac80211: add mesh join/leave commands
  2010-12-02 23:08             ` Javier Cardona
@ 2010-12-03  8:13               ` Johannes Berg
  0 siblings, 0 replies; 17+ messages in thread
From: Johannes Berg @ 2010-12-03  8:13 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, Steve Derosier, devel

On Thu, 2010-12-02 at 15:08 -0800, Javier Cardona wrote:

> Not really.  Maybe this as PATCH 1/5 v3?

Sure, looks good.

> @@ -1585,6 +1588,7 @@ enum nl80211_meshconf_params {
>  	NL80211_MESHCONF_MAX_PEER_LINKS,
>  	NL80211_MESHCONF_MAX_RETRIES,
>  	NL80211_MESHCONF_TTL,
> +	NL80211_MESHCONF_ELEMENT_TTL,
>  	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
>  	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
>  	NL80211_MESHCONF_PATH_REFRESH_TIME,

except for this bit of course, it breaks ABI. I've fixed it up.

johannes


^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2010-12-03  8:13 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-12-01 20:59 [RFC 0/5] mesh join/leave API Johannes Berg
2010-12-01 20:59 ` [RFC 1/5] mac80211: use configured mesh TTL Johannes Berg
2010-12-01 20:59 ` [RFC 2/5] mac80211: move mesh filter adjusting Johannes Berg
2010-12-01 20:59 ` [RFC 3/5] cfg80211: require add_virtual_intf to return new dev Johannes Berg
2010-12-01 20:59 ` [RFC 4/5] nl80211: refactor mesh parameter parsing Johannes Berg
2010-12-02  8:34   ` [RFC 4/5 v2] " Johannes Berg
2010-12-01 20:59 ` [RFC 5/5] cfg80211/mac80211: add mesh join/leave commands Johannes Berg
2010-12-01 21:15   ` Johannes Berg
2010-12-02  0:23   ` Javier Cardona
2010-12-02  6:57     ` Johannes Berg
2010-12-02  8:45   ` [RFC 5/5 v2] " Johannes Berg
2010-12-02 20:09     ` Javier Cardona
2010-12-02 20:14       ` Johannes Berg
2010-12-02 21:24         ` Javier Cardona
2010-12-02 21:38           ` Johannes Berg
2010-12-02 23:08             ` Javier Cardona
2010-12-03  8:13               ` Johannes Berg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.