linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Mesh fixes and improvements
@ 2009-08-08  3:38 Javier Cardona
  2009-08-08  3:38 ` [PATCH 1/8] mac80211: Improve dequeing from mpath frame queue Javier Cardona
  2009-08-08  9:09 ` Mesh fixes and improvements Johannes Berg
  0 siblings, 2 replies; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: andrey, johannes, linville, devel

[Resent with proper patch numbering...]

This series includes some fixes, testing aids and improvements to the mesh
stack.  It is important to note that the patch
"Use-3-address-format-for-mesh-broadcast-frames" breaks compatibility with
previous versions.  This is unavoidable and will keep happening as new versions
of the 802.11s drafts are produced.

Also, I'm not sure if "Simulate-transmission-losses-on-plinks-to-..." should be
merged upstream, but we find it really useful to test mesh configurations.
Please comment if you have different opinions on its adequacy or
implementation.

Cheers,


Javier

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

* [PATCH 1/8] mac80211: Improve dequeing from mpath frame queue.
  2009-08-08  3:38 Mesh fixes and improvements Javier Cardona
@ 2009-08-08  3:38 ` Javier Cardona
  2009-08-08  3:38   ` [PATCH 2/8] mac80211: Use correct sign for mesh active path refresh Javier Cardona
  2009-08-08  9:09 ` Mesh fixes and improvements Johannes Berg
  1 sibling, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Andrey Yurovsky, Javier Cardona, johannes, linville, devel

From: Andrey Yurovsky <andrey@cozybit.com>

Also, fix typo in comment.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.h      |    2 +-
 net/mac80211/mesh_hwmp.c |    6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index ce53881..6aaf1ec 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -61,7 +61,7 @@ enum mesh_path_flags {
  * 	retry
  * @discovery_retries: number of discovery retries
  * @flags: mesh path flags, as specified on &enum mesh_path_flags
- * @state_lock: mesh pat state lock
+ * @state_lock: mesh path state lock
  *
  *
  * The combination of dst and sdata is unique in the mesh path table. Since the
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e1a763e..b54c21c 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -810,10 +810,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		}
 
 		if (skb_queue_len(&mpath->frame_queue) >=
-				MESH_FRAME_QUEUE_LEN) {
-			skb_to_free = mpath->frame_queue.next;
-			skb_unlink(skb_to_free, &mpath->frame_queue);
-		}
+				MESH_FRAME_QUEUE_LEN)
+			skb_to_free = skb_dequeue(&mpath->frame_queue);
 
 		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&mpath->frame_queue, skb);
-- 
1.5.4.3


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

* [PATCH 2/8] mac80211: Use correct sign for mesh active path refresh.
  2009-08-08  3:38 ` [PATCH 1/8] mac80211: Improve dequeing from mpath frame queue Javier Cardona
@ 2009-08-08  3:38   ` Javier Cardona
  2009-08-08  3:38     ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Andrey Yurovsky, Javier Cardona, johannes, linville, devel

From: Andrey Yurovsky <andrey@cozybit.com>

On locally originated traffic, we refresh active paths after a timeout.  The
decision to do this was using the wrong sign and therefore the refresh timer
was triggered for every frame.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh_hwmp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b54c21c..1cd1e72 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -791,7 +791,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 	}
 
 	if (mpath->flags & MESH_PATH_ACTIVE) {
-		if (time_after(jiffies, mpath->exp_time -
+		if (time_after(jiffies, mpath->exp_time +
 			msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time))
 				&& !memcmp(sdata->dev->dev_addr, hdr->addr4,
 					   ETH_ALEN)
-- 
1.5.4.3


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

* [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics.
  2009-08-08  3:38   ` [PATCH 2/8] mac80211: Use correct sign for mesh active path refresh Javier Cardona
@ 2009-08-08  3:38     ` Javier Cardona
  2009-08-08  3:38       ` [PATCH 4/8] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
  2009-08-08  8:09       ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Kalle Valo
  0 siblings, 2 replies; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Andrey Yurovsky, johannes, linville, devel

This enables us to specify a simulated loss probability per mesh peer link.
Useful to simulate and test different mesh topologies and test different mesh
metrics.

The simulated loss rate setting can be configured as a plink action.  The
intended use is:

iw dev mesh station set <MAC> plink_action loss 25

Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 include/linux/nl80211.h   |    4 +++
 include/net/cfg80211.h    |    4 +++
 net/mac80211/cfg.c        |    6 +++++
 net/mac80211/mesh.c       |    1 +
 net/mac80211/mesh.h       |    1 +
 net/mac80211/mesh_hwmp.c  |    1 +
 net/mac80211/mesh_plink.c |    6 +++++
 net/mac80211/sta_info.h   |    1 +
 net/mac80211/tx.c         |   54 +++++++++++++++++++++++++++++++++++++++++++-
 net/wireless/nl80211.c    |    9 +++++++
 10 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index a8d71ed..3de615b 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -713,6 +713,7 @@ enum nl80211_attrs {
 	NL80211_ATTR_KEYS,
 
 	NL80211_ATTR_PID,
+	NL80211_ATTR_SIM_LOSS,
 
 	/* add attributes here, update the policy in nl80211.c */
 
@@ -1198,6 +1199,8 @@ enum nl80211_mntr_flags {
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
+ * @NL80211_MESHCONF_SIM_LOSS_RATE: simulated loss rate at this MP.
+ *
  * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_meshconf_params {
@@ -1215,6 +1218,7 @@ enum nl80211_meshconf_params {
 	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
 	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
 	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+	NL80211_MESHCONF_SIM_LOSS_RATE,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d5756c9..6bc5957 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -265,6 +265,7 @@ enum plink_actions {
 	PLINK_ACTION_INVALID,
 	PLINK_ACTION_OPEN,
 	PLINK_ACTION_BLOCK,
+	PLINK_ACTION_LOSS,
 };
 
 /**
@@ -282,6 +283,7 @@ enum plink_actions {
  *	(bitmask of BIT(NL80211_STA_FLAG_...))
  * @listen_interval: listen interval or -1 for no change
  * @aid: AID or zero for no change
+ * @sim_loss_rate: simulated TX probable loss percentage
  */
 struct station_parameters {
 	u8 *supported_rates;
@@ -292,6 +294,7 @@ struct station_parameters {
 	u8 supported_rates_len;
 	u8 plink_action;
 	struct ieee80211_ht_cap *ht_capa;
+	u8 sim_loss_rate;
 };
 
 /**
@@ -508,6 +511,7 @@ struct mesh_config {
 	u32 dot11MeshHWMPactivePathTimeout;
 	u16 dot11MeshHWMPpreqMinInterval;
 	u16 dot11MeshHWMPnetDiameterTraversalTime;
+	u8 dot11MeshSimLossRate;
 };
 
 /**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5608f6c..8067f66 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -693,6 +693,9 @@ static void sta_apply_parameters(struct ieee80211_local *local,
 		case PLINK_ACTION_BLOCK:
 			mesh_plink_block(sta);
 			break;
+		case PLINK_ACTION_LOSS:
+			mesh_plink_sim_loss(sta, params->sim_loss_rate);
+			break;
 		}
 	}
 }
@@ -1043,6 +1046,9 @@ static int ieee80211_set_mesh_params(struct wiphy *wiphy,
 			   mask))
 		conf->dot11MeshHWMPnetDiameterTraversalTime =
 			nconf->dot11MeshHWMPnetDiameterTraversalTime;
+	if (_chg_mesh_attr(NL80211_MESHCONF_SIM_LOSS_RATE, mask))
+		conf->dot11MeshSimLossRate =
+			nconf->dot11MeshSimLossRate;
 	return 0;
 }
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8c068e2..d9292a9 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -653,6 +653,7 @@ void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata)
 		MESH_PATH_REFRESH_TIME;
 	ifmsh->mshcfg.min_discovery_timeout =
 		MESH_MIN_DISCOVERY_TIMEOUT;
+	ifmsh->mshcfg.dot11MeshSimLossRate = 0;
 	ifmsh->accepting_plinks = true;
 	ifmsh->preq_id = 0;
 	ifmsh->dsn = 0;
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6aaf1ec..8e70dae 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -238,6 +238,7 @@ void mesh_plink_broken(struct sta_info *sta);
 void mesh_plink_deactivate(struct sta_info *sta);
 int mesh_plink_open(struct sta_info *sta);
 void mesh_plink_block(struct sta_info *sta);
+void mesh_plink_sim_loss(struct sta_info *sta, u8 rate);
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
 			 struct ieee80211_mgmt *mgmt, size_t len,
 			 struct ieee80211_rx_status *rx_status);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 1cd1e72..b4309b2 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -272,6 +272,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
 	}
 
 	last_hop_metric = airtime_link_metric_get(local, sta);
+	printk("XXX: last_hop_metric = %d\n", last_hop_metric);
 	/* Update and check originator routing info */
 	fresh_info = true;
 
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index cb14253..7c49c95 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -382,6 +382,12 @@ void mesh_plink_block(struct sta_info *sta)
 	spin_unlock_bh(&sta->lock);
 }
 
+void mesh_plink_sim_loss(struct sta_info *sta, u8 rate)
+{
+	spin_lock_bh(&sta->lock);
+	sta->plink_sim_loss = rate;
+	spin_unlock_bh(&sta->lock);
+}
 
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
 			 size_t len, struct ieee80211_rx_status *rx_status)
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index ccc3adf..a248a8b 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -294,6 +294,7 @@ struct sta_info {
 	bool ignore_plink_timer;
 	bool plink_timer_was_running;
 	enum plink_state plink_state;
+	u8 plink_sim_loss;
 	u32 plink_timeout;
 	struct timer_list plink_timer;
 #endif
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c9be9dc..0df5a96 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -18,6 +18,7 @@
 #include <linux/etherdevice.h>
 #include <linux/bitmap.h>
 #include <linux/rcupdate.h>
+#include <linux/random.h>
 #include <net/net_namespace.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
@@ -39,6 +40,47 @@
 
 /* misc utils */
 
+/* Decide whether we should simulate the loss of a frame based on the simulated
+ * plink loss probability and the frame's destination.  Used for testing.
+ *
+ * Must be invoked with the rcu read lock held.
+ * */
+static int random_tx_loss(struct ieee80211_sub_if_data *sdata, struct
+		ieee80211_hdr *hdr)
+{
+	struct sta_info *sta;
+	u8 r = 0;
+
+	get_random_bytes(&r, sizeof(r));
+
+	list_for_each_entry(sta, &sdata->local->sta_list, list) {
+		if (!memcmp(sta->sta.addr, hdr->addr1, 6))
+			if (r*25 < sta->plink_sim_loss*64)
+				return 1;
+	}
+
+	return 0;
+}
+
+
+static int simulate_tx_loss(struct ieee80211_sub_if_data *sdata,
+		struct ieee80211_hdr *hdr, struct sk_buff *skb)
+{
+	struct ieee80211_hw *hw = &sdata->local->hw;
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	ieee80211_tx_info_clear_status(info);
+	info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS;
+
+	info->status.rates[0].idx = 0;
+	info->status.rates[0].count = hw->max_rate_tries;
+
+	ieee80211_tx_status_irqsafe(hw, skb);
+
+	/* this will ensure that the frame is not queued in the tx path */
+	return IEEE80211_TX_OK;
+}
+
 static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr,
 				 int next_frag_len)
 {
@@ -1244,6 +1286,7 @@ static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 	struct ieee80211_tx_data tx;
 	ieee80211_tx_result res_prepare;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 	struct sk_buff *next;
 	unsigned long flags;
 	int ret, retries;
@@ -1278,7 +1321,10 @@ static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
 
 	retries = 0;
  retry:
-	ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
+	if (ieee80211_vif_is_mesh(&sdata->vif) && random_tx_loss(sdata, hdr))
+		ret = simulate_tx_loss(sdata, hdr, skb);
+	else
+		ret = __ieee80211_tx(local, &tx.skb, tx.sta, txpending);
 	switch (ret) {
 	case IEEE80211_TX_OK:
 		break;
@@ -1857,7 +1903,11 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
 		hdr = (struct ieee80211_hdr *)skb->data;
 		sta = sta_info_get(local, hdr->addr1);
 
-		ret = __ieee80211_tx(local, &skb, sta, true);
+		if (ieee80211_vif_is_mesh(&sdata->vif) &&
+				random_tx_loss(sdata, hdr))
+			ret = simulate_tx_loss(sdata, hdr, skb);
+		else
+			ret = __ieee80211_tx(local, &skb, sta, true);
 		if (ret != IEEE80211_TX_OK)
 			result = false;
 	}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 667a87d..1dfe8ea 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1878,6 +1878,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
 		params.plink_action =
 		    nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
 
+	if (info->attrs[NL80211_ATTR_SIM_LOSS])
+		params.sim_loss_rate =
+			nla_get_u8(info->attrs[NL80211_ATTR_SIM_LOSS]);
+
 	rtnl_lock();
 
 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev);
@@ -2619,6 +2623,8 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
 			cur_params.dot11MeshHWMPpreqMinInterval);
 	NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
 			cur_params.dot11MeshHWMPnetDiameterTraversalTime);
+	NLA_PUT_U8(msg, NL80211_MESHCONF_SIM_LOSS_RATE,
+			cur_params.dot11MeshSimLossRate);
 	nla_nest_end(msg, pinfoattr);
 	genlmsg_end(msg, hdr);
 	err = genlmsg_reply(msg, info);
@@ -2661,6 +2667,7 @@ nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = {
 	[NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 },
 	[NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 },
 	[NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 },
+	[NL80211_MESHCONF_SIM_LOSS_RATE] = { .type = NLA_U8 },
 };
 
 static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
@@ -2729,6 +2736,8 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
 			dot11MeshHWMPnetDiameterTraversalTime,
 			mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
 			nla_get_u16);
+	FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshSimLossRate,
+			mask, NL80211_MESHCONF_SIM_LOSS_RATE, nla_get_u8);
 
 	/* Apply changes */
 	err = rdev->ops->set_mesh_params(&rdev->wiphy, dev, &cfg, mask);
-- 
1.5.4.3


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

* [PATCH 4/8] mac80211: Use 3-address format for mesh broadcast frames.
  2009-08-08  3:38     ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Javier Cardona
@ 2009-08-08  3:38       ` Javier Cardona
  2009-08-08  3:38         ` [PATCH 5/8] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
  2009-08-08  8:09       ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Kalle Valo
  1 sibling, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

The 11s task group recently changed the frame mesh multicast/broadcast frame
format to use 3-address.  This was done to avoid interactions with widely
deployed lazy-WDS access points.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++---
 net/mac80211/mesh.h |    5 +++-
 net/mac80211/rx.c   |   45 ++++++++++++++++++++++-------------
 net/mac80211/tx.c   |   64 +++++++++++++++++++++++++++------------------------
 net/wireless/util.c |   16 +++++++++---
 5 files changed, 136 insertions(+), 56 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index d9292a9..5202d7c 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -399,21 +399,75 @@ endgrow:
 }
 
 /**
+ * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
+ * @hdr:    	802.11 frame header
+ * @fc:		frame control field
+ * @meshda:	destination address in the mesh
+ * @meshsa:	source address address in the mesh.  Same as TA, as frame is
+ *              locally originated.
+ *
+ * Return the length of the 802.11 (does not include a mesh control header)
+ */
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
+		*meshda, char *meshsa) {
+	if (is_multicast_ether_addr(meshda)) {
+		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+		/* DA TA SA */
+		memcpy(hdr->addr1, meshda, ETH_ALEN);
+		memcpy(hdr->addr2, meshsa, ETH_ALEN);
+		memcpy(hdr->addr3, meshsa, ETH_ALEN);
+		return 24;
+	} else {
+		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+				IEEE80211_FCTL_TODS);
+		/* RA TA DA SA */
+		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
+		memcpy(hdr->addr2, meshsa, ETH_ALEN);
+		memcpy(hdr->addr3, meshda, ETH_ALEN);
+		memcpy(hdr->addr4, meshsa, ETH_ALEN);
+		return 30;
+	}
+}
+
+/**
  * ieee80211_new_mesh_header - create a new mesh header
  * @meshhdr:    uninitialized mesh header
  * @sdata:	mesh interface to be used
+ * @addr4:	addr4 of the mesh frame (1st in ae header)
+ *              may be NULL
+ * @addr5:	addr5 of the mesh frame (1st or 2nd in ae header)
+ *              may be NULL unless addr6 is present
+ * @addr6:	addr6 of the mesh frame (2nd or 3rd in ae header)
+ * 		may be NULL unless addr5 is present
  *
  * Return the header length.
  */
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
-		struct ieee80211_sub_if_data *sdata)
+		struct ieee80211_sub_if_data *sdata, char *addr4,
+		char *addr5, char *addr6)
 {
-	meshhdr->flags = 0;
+	int aelen = 0;
+	memset(meshhdr, 0, sizeof(meshhdr));
 	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
 	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
 	sdata->u.mesh.mesh_seqnum++;
-
-	return 6;
+	if (addr4) {
+		meshhdr->flags |= MESH_FLAGS_AE_A4;
+		aelen += ETH_ALEN;
+		memcpy(meshhdr->eaddr1, addr4, ETH_ALEN);
+	}
+	if (addr5 && addr6) {
+		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
+		aelen += 2 * ETH_ALEN;
+		if (!addr4) {
+			memcpy(meshhdr->eaddr1, addr5, ETH_ALEN);
+			memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
+		} else {
+			memcpy(meshhdr->eaddr2, addr5, ETH_ALEN);
+			memcpy(meshhdr->eaddr3, addr6, ETH_ALEN);
+		}
+	}
+	return 6 + aelen;
 }
 
 static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 8e70dae..6cb3db8 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -193,8 +193,11 @@ struct mesh_rmc {
 
 /* Public interfaces */
 /* Various */
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
+		char *da, char *sa);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
-		struct ieee80211_sub_if_data *sdata);
+		struct ieee80211_sub_if_data *sdata, char *addr4,
+		char *addr5, char *addr6);
 int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
 		struct ieee80211_sub_if_data *sdata);
 bool mesh_matches_local(struct ieee802_11_elems *ie,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 25a669c..e7d8895 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 	unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	char *dev_addr = rx->dev->dev_addr;
 
 	if (ieee80211_is_data(hdr->frame_control)) {
-		if (!ieee80211_has_a4(hdr->frame_control))
-			return RX_DROP_MONITOR;
-		if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
-			return RX_DROP_MONITOR;
+		if (is_multicast_ether_addr(hdr->addr1)) {
+			if (ieee80211_has_tods(hdr->frame_control) ||
+				!ieee80211_has_fromds(hdr->frame_control))
+				return RX_DROP_MONITOR;
+			if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+				return RX_DROP_MONITOR;
+		} else {
+			if (!ieee80211_has_a4(hdr->frame_control))
+				return RX_DROP_MONITOR;
+			if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+				return RX_DROP_MONITOR;
+		}
 	}
 
 	/* If there is not an established peer link and this is not a peer link
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
 	if (ieee80211_is_data(hdr->frame_control) &&
 	    is_multicast_ether_addr(hdr->addr1) &&
-	    mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
+	    mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
 		return RX_DROP_MONITOR;
 #undef msh_h_get
 
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		/* illegal frame */
 		return RX_DROP_MONITOR;
 
-	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
+	if (!is_multicast_ether_addr(hdr->addr1) && 
+			(mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) {
 		struct mesh_path *mppath;
 
 		rcu_read_lock();
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		rcu_read_unlock();
 	}
 
-	if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+	/* Frame has reached destination.  Don't forward */
+	if (!is_multicast_ether_addr(hdr->addr1) &&
+			compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
 		return RX_CONTINUE;
 
 	mesh_hdr->ttl--;
@@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 						   rx->dev->name);
 
 			fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-			/*
-			 * Save TA to addr1 to send TA a path error if a
-			 * suitable next hop is not found
-			 */
-			memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
 			memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
 			info = IEEE80211_SKB_CB(fwd_skb);
 			memset(info, 0, sizeof(*info));
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			info->control.vif = &rx->sdata->vif;
 			ieee80211_select_queue(local, fwd_skb);
-			if (is_multicast_ether_addr(fwd_hdr->addr3))
-				memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+			if (!is_multicast_ether_addr(fwd_hdr->addr1)) {
+				int err;
+				/*
+				 * Save TA to addr1 to send TA a path error if a
+				 * suitable next hop is not found
+				 */
+				memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
 						ETH_ALEN);
-			else {
-				int err = mesh_nexthop_lookup(fwd_skb, sdata);
+				err = mesh_nexthop_lookup(fwd_skb, sdata);
 				/* Failed to immediately resolve next hop:
 				 * fwded frame was dropped or will be added
 				 * later to the pending skb queue.  */
@@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		}
 	}
 
-	if (is_multicast_ether_addr(hdr->addr3) ||
+	if (is_multicast_ether_addr(hdr->addr1) ||
 	    rx->dev->flags & IFF_PROMISC)
 		return RX_CONTINUE;
 	else
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0df5a96..a97d541 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1461,9 +1461,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) &&
 	    ieee80211_is_data(hdr->frame_control)) {
-		if (is_multicast_ether_addr(hdr->addr3))
-			memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
-		else
+		if (!is_multicast_ether_addr(hdr->addr1))
 			if (mesh_nexthop_lookup(skb, sdata)) {
 				dev_put(sdata->dev);
 				return;
@@ -1666,52 +1664,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		break;
 #ifdef CONFIG_MAC80211_MESH
 	case NL80211_IFTYPE_MESH_POINT:
-		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
 			/* Do not send frames with mesh_ttl == 0 */
 			sdata->u.mesh.mshstats.dropped_frames_ttl++;
 			ret = 0;
 			goto fail;
 		}
-		memset(&mesh_hdr, 0, sizeof(mesh_hdr));
 
 		if (compare_ether_addr(dev->dev_addr,
 					  skb->data + ETH_ALEN) == 0) {
-			/* RA TA DA SA */
-			memset(hdr.addr1, 0, ETH_ALEN);
-			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-			memcpy(hdr.addr3, skb->data, ETH_ALEN);
-			memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
+			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
+					skb->data, skb->data + ETH_ALEN);
+			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+					sdata, NULL, NULL, NULL);
 		} else {
 			/* packet from other interface */
 			struct mesh_path *mppath;
+			int is_mesh_mcast = 1;
+			char *mesh_da;
 
-			memset(hdr.addr1, 0, ETH_ALEN);
-			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-			memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
-
+			rcu_read_lock();
 			if (is_multicast_ether_addr(skb->data))
-				memcpy(hdr.addr3, skb->data, ETH_ALEN);
+				/* DA TA mSA AE:SA */
+				mesh_da = skb->data;
 			else {
-				rcu_read_lock();
 				mppath = mpp_path_lookup(skb->data, sdata);
-				if (mppath)
-					memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
-				else
-					memset(hdr.addr3, 0xff, ETH_ALEN);
-				rcu_read_unlock();
+				if (mppath) {
+					/* RA TA mDA mSA AE:DA SA */
+					mesh_da = mppath->mpp;
+					is_mesh_mcast = 0;
+				} else
+					/* DA TA mSA AE:SA */
+					mesh_da = dev->broadcast;
 			}
+			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
+					mesh_da, dev->dev_addr);
+			rcu_read_unlock();
+			if (is_mesh_mcast)
+				meshhdrlen =
+					ieee80211_new_mesh_header(&mesh_hdr,
+							sdata,
+							skb->data + ETH_ALEN,
+							NULL,
+							NULL);
+			else
+				meshhdrlen =
+					ieee80211_new_mesh_header(&mesh_hdr,
+							sdata,
+							NULL,
+							skb->data,
+							skb->data + ETH_ALEN);
 
-			mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
-			mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
-			put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
-			memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
-			memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
-			sdata->u.mesh.mesh_seqnum++;
-			meshhdrlen = 18;
 		}
-		hdrlen = 30;
 		break;
 #endif
 	case NL80211_IFTYPE_STATION:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ba387d8..693275a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 	switch (ae) {
 	case 0:
 		return 6;
-	case 1:
+	case MESH_FLAGS_AE_A4:
 		return 12;
-	case 2:
+	case MESH_FLAGS_AE_A5_A6:
 		return 18;
-	case 3:
+	case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
 		return 24;
 	default:
 		return 6;
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 		}
 		break;
 	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
-		if (iftype != NL80211_IFTYPE_STATION ||
+		if ((iftype != NL80211_IFTYPE_STATION &&
+		    iftype != NL80211_IFTYPE_MESH_POINT) ||
 		    (is_multicast_ether_addr(dst) &&
 		     !compare_ether_addr(src, addr)))
 			return -1;
+		if (iftype == NL80211_IFTYPE_MESH_POINT) {
+			struct ieee80211s_hdr *meshdr =
+				(struct ieee80211s_hdr *) (skb->data + hdrlen);
+			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+			if (meshdr->flags & MESH_FLAGS_AE_A4)
+				memcpy(src, meshdr->eaddr1, ETH_ALEN);
+		}
 		break;
 	case cpu_to_le16(0):
 		if (iftype != NL80211_IFTYPE_ADHOC)
-- 
1.5.4.3


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

* [PATCH 5/8] mac80211: Update the station failed frames average when minstrel is used.
  2009-08-08  3:38       ` [PATCH 4/8] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
@ 2009-08-08  3:38         ` Javier Cardona
  2009-08-08  3:38           ` [PATCH 6/8] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

The fail_avg value is used to compute the mesh metric, and was only being set
by the pid rate control module. This fixes the mesh path selection mechanism
for cards that use mistrel for rate control.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/rc80211_minstrel.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 7c51429..3ea9740 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -155,12 +155,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 		   struct sk_buff *skb)
 {
 	struct minstrel_sta_info *mi = priv_sta;
+	struct minstrel_priv *mp = (struct minstrel_priv *)priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *ar = info->status.rates;
+	struct ieee80211_local *local = hw_to_local(mp->hw);
+	struct sta_info *si;
 	int i, ndx;
 	int success;
 
 	success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+	si = sta_info_get(local, sta->addr);
 
 	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
 		if (ar[i].idx < 0)
@@ -172,8 +176,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 		mi->r[ndx].attempts += ar[i].count;
 
-		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
+		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) {
 			mi->r[ndx].success += success;
+			if (si)
+				si->fail_avg = (18050 - mi->r[ndx].probability)
+					/ 180;
+		}
 	}
 
 	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
-- 
1.5.4.3


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

* [PATCH 6/8] mac80211: Early detection of broken mesh paths when using minstrel.
  2009-08-08  3:38         ` [PATCH 5/8] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
@ 2009-08-08  3:38           ` Javier Cardona
  2009-08-08  3:38             ` [PATCH 7/8] mac80211: Assign a default mesh beaconing interval Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel


Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh_hwmp.c        |    1 -
 net/mac80211/rc80211_minstrel.c |    8 +++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b4309b2..1cd1e72 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -272,7 +272,6 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
 	}
 
 	last_hop_metric = airtime_link_metric_get(local, sta);
-	printk("XXX: last_hop_metric = %d\n", last_hop_metric);
 	/* Update and check originator routing info */
 	fresh_info = true;
 
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 3ea9740..0071649 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -51,6 +51,7 @@
 #include <linux/random.h>
 #include <linux/ieee80211.h>
 #include <net/mac80211.h>
+#include "mesh.h"
 #include "rate.h"
 #include "rc80211_minstrel.h"
 
@@ -178,9 +179,14 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) {
 			mi->r[ndx].success += success;
-			if (si)
+			if (si) {
 				si->fail_avg = (18050 - mi->r[ndx].probability)
 					/ 180;
+				WARN_ON(si->fail_avg > 100);
+				if (si->fail_avg == 100 &&
+					ieee80211_vif_is_mesh(&si->sdata->vif))
+					mesh_plink_broken(si);
+			}
 		}
 	}
 
-- 
1.5.4.3


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

* [PATCH 7/8] mac80211: Assign a default mesh beaconing interval.
  2009-08-08  3:38           ` [PATCH 6/8] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
@ 2009-08-08  3:38             ` Javier Cardona
  2009-08-08  3:38               ` [PATCH 8/8] mac80211: Moved mpath and mpp growth to mesh workqueue Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

Incidentally, this fixes mesh beaconing in mac80211_hwsim devices.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.c |    6 ++++--
 net/mac80211/mesh.h |    1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 5202d7c..3b49d39 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -525,9 +525,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_local *local = sdata->local;
 
 	ifmsh->housekeeping = true;
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	queue_work(local->hw, &ifmsh->work);
+	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
-						BSS_CHANGED_BEACON_ENABLED);
+						BSS_CHANGED_BEACON_ENABLED |
+						BSS_CHANGED_BEACON_INT);
 }
 
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6cb3db8..b6ea100 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -174,6 +174,7 @@ struct mesh_rmc {
  */
 #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)
-- 
1.5.4.3


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

* [PATCH 8/8] mac80211: Moved mpath and mpp growth to mesh workqueue.
  2009-08-08  3:38             ` [PATCH 7/8] mac80211: Assign a default mesh beaconing interval Javier Cardona
@ 2009-08-08  3:38               ` Javier Cardona
  0 siblings, 0 replies; 22+ messages in thread
From: Javier Cardona @ 2009-08-08  3:38 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

This prevents calling rcu_synchronize from within the tx path.
Also, re-enable mesh in Kconfig

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/Kconfig        |    1 -
 net/mac80211/ieee80211_i.h  |    2 +-
 net/mac80211/mesh.c         |   75 +++-------------------
 net/mac80211/mesh.h         |   20 ++++++-
 net/mac80211/mesh_pathtbl.c |  146 ++++++++++++++++++++++++++++++++-----------
 5 files changed, 139 insertions(+), 105 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 7dd77b6..9b4fcbc 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -66,7 +66,6 @@ endmenu
 config MAC80211_MESH
 	bool "Enable mac80211 mesh networking (pre-802.11s) support"
 	depends on MAC80211 && EXPERIMENTAL
-	depends on BROKEN
 	---help---
 	 This options enables support of Draft 802.11s mesh networking.
 	 The implementation is based on Draft 1.08 of the Mesh Networking
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d6bd7dd..a6abc7d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -355,7 +355,7 @@ struct ieee80211_if_mesh {
 
 	unsigned long timers_running;
 
-	bool housekeeping;
+	unsigned long wrkq_flags;
 
 	u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
 	size_t mesh_id_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 3b49d39..619364c 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -47,7 +47,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	ifmsh->housekeeping = true;
+	ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
 
 	if (local->quiescing) {
 		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order)
 	return newtbl;
 }
 
-static void __mesh_table_free(struct mesh_table *tbl)
-{
-	kfree(tbl->hash_buckets);
-	kfree(tbl->hashwlock);
-	kfree(tbl);
-}
-
-void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
-{
-	struct hlist_head *mesh_hash;
-	struct hlist_node *p, *q;
-	int i;
-
-	mesh_hash = tbl->hash_buckets;
-	for (i = 0; i <= tbl->hash_mask; i++) {
-		spin_lock(&tbl->hashwlock[i]);
-		hlist_for_each_safe(p, q, &mesh_hash[i]) {
-			tbl->free_node(p, free_leafs);
-			atomic_dec(&tbl->entries);
-		}
-		spin_unlock(&tbl->hashwlock[i]);
-	}
-	__mesh_table_free(tbl);
-}
 
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
@@ -360,44 +336,6 @@ static void ieee80211_mesh_path_timer(unsigned long data)
 	ieee80211_queue_work(&local->hw, &ifmsh->work);
 }
 
-struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
-{
-	struct mesh_table *newtbl;
-	struct hlist_head *oldhash;
-	struct hlist_node *p, *q;
-	int i;
-
-	if (atomic_read(&tbl->entries)
-			< tbl->mean_chain_len * (tbl->hash_mask + 1))
-		goto endgrow;
-
-	newtbl = mesh_table_alloc(tbl->size_order + 1);
-	if (!newtbl)
-		goto endgrow;
-
-	newtbl->free_node = tbl->free_node;
-	newtbl->mean_chain_len = tbl->mean_chain_len;
-	newtbl->copy_node = tbl->copy_node;
-	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
-
-	oldhash = tbl->hash_buckets;
-	for (i = 0; i <= tbl->hash_mask; i++)
-		hlist_for_each(p, &oldhash[i])
-			if (tbl->copy_node(p, newtbl) < 0)
-				goto errcopy;
-
-	return newtbl;
-
-errcopy:
-	for (i = 0; i <= newtbl->hash_mask; i++) {
-		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
-			tbl->free_node(p, 0);
-	}
-	__mesh_table_free(newtbl);
-endgrow:
-	return NULL;
-}
-
 /**
  * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
  * @hdr:    	802.11 frame header
@@ -487,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 	if (free_plinks != sdata->u.mesh.accepting_plinks)
 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 
-	ifmsh->housekeeping = false;
 	mod_timer(&ifmsh->housekeeping_timer,
 		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
 }
@@ -524,7 +461,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_local *local = sdata->local;
 
-	ifmsh->housekeeping = true;
+	ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
 	queue_work(local->hw, &ifmsh->work);
 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
@@ -664,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work)
 		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
 		mesh_path_start_discovery(sdata);
 
-	if (ifmsh->housekeeping)
+	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
+		mesh_mpath_table_grow();
+
+	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
+		mesh_mpp_table_grow();
+
+	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
 		ieee80211_mesh_housekeeping(sdata, ifmsh);
 }
 
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index b6ea100..fd4031f 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -44,6 +44,23 @@ enum mesh_path_flags {
 };
 
 /**
+ * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks
+ *
+ *
+ *
+ * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks
+ * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs
+ * to grow.
+ * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to
+ * grow
+ */
+enum mesh_deferred_task_flags {
+	MESH_WORK_HOUSEKEEPING,
+	MESH_WORK_GROW_MPATH_TABLE,
+	MESH_WORK_GROW_MPP_TABLE,
+};
+
+/**
  * struct mesh_path - mac80211 mesh path structure
  *
  * @dst: mesh path destination mac address
@@ -251,7 +268,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
 /* Mesh tables */
 struct mesh_table *mesh_table_alloc(int size_order);
 void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
-struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
+void mesh_mpath_table_grow(void);
+void mesh_mpp_table_grow(void);
 u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
 		struct mesh_table *tbl);
 /* Mesh paths */
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 431865a..97e14bc 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -39,6 +39,69 @@ static struct mesh_table *mesh_paths;
 static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+	kfree(tbl->hash_buckets);
+	kfree(tbl->hashwlock);
+	kfree(tbl);
+}
+
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+{
+	struct hlist_head *mesh_hash;
+	struct hlist_node *p, *q;
+	int i;
+
+	mesh_hash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++) {
+		spin_lock(&tbl->hashwlock[i]);
+		hlist_for_each_safe(p, q, &mesh_hash[i]) {
+			tbl->free_node(p, free_leafs);
+			atomic_dec(&tbl->entries);
+		}
+		spin_unlock(&tbl->hashwlock[i]);
+	}
+	__mesh_table_free(tbl);
+}
+
+static struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+{
+	struct mesh_table *newtbl;
+	struct hlist_head *oldhash;
+	struct hlist_node *p, *q;
+	int i;
+
+	if (atomic_read(&tbl->entries)
+			< tbl->mean_chain_len * (tbl->hash_mask + 1))
+		goto endgrow;
+
+	newtbl = mesh_table_alloc(tbl->size_order + 1);
+	if (!newtbl)
+		goto endgrow;
+
+	newtbl->free_node = tbl->free_node;
+	newtbl->mean_chain_len = tbl->mean_chain_len;
+	newtbl->copy_node = tbl->copy_node;
+	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+
+	oldhash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++)
+		hlist_for_each(p, &oldhash[i])
+			if (tbl->copy_node(p, newtbl) < 0)
+				goto errcopy;
+
+	return newtbl;
+
+errcopy:
+	for (i = 0; i <= newtbl->hash_mask; i++) {
+		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+			tbl->free_node(p, 0);
+	}
+	__mesh_table_free(newtbl);
+endgrow:
+	return NULL;
+}
+
 
 /* This lock will have the grow table function as writer and add / delete nodes
  * as readers. When reading the table (i.e. doing lookups) we are well protected
@@ -187,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
  */
 int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
 	struct mesh_path *mpath, *new_mpath;
 	struct mpath_node *node, *new_node;
 	struct hlist_head *bucket;
@@ -195,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 	int err = 0;
 	u32 hash_idx;
 
-	might_sleep();
-
 	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* never add ourselves as neighbours */
 		return -ENOTSUPP;
@@ -208,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 		return -ENOSPC;
 
 	err = -ENOMEM;
-	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
 	if (!new_mpath)
 		goto err_path_alloc;
 
-	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
 	if (!new_node)
 		goto err_node_alloc;
 
@@ -250,20 +313,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 	spin_unlock(&mesh_paths->hashwlock[hash_idx]);
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
-		struct mesh_table *oldtbl, *newtbl;
-
-		write_lock(&pathtbl_resize_lock);
-		oldtbl = mesh_paths;
-		newtbl = mesh_table_grow(mesh_paths);
-		if (!newtbl) {
-			write_unlock(&pathtbl_resize_lock);
-			return 0;
-		}
-		rcu_assign_pointer(mesh_paths, newtbl);
-		write_unlock(&pathtbl_resize_lock);
-
-		synchronize_rcu();
-		mesh_table_free(oldtbl, false);
+		set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
+		queue_work(local->hw.workqueue, &ifmsh->work);
 	}
 	return 0;
 
@@ -278,9 +329,46 @@ err_path_alloc:
 	return err;
 }
 
+void mesh_mpath_table_grow(void)
+{
+	struct mesh_table *oldtbl, *newtbl;
+
+	write_lock(&pathtbl_resize_lock);
+	oldtbl = mesh_paths;
+	newtbl = mesh_table_grow(mesh_paths);
+	if (!newtbl) {
+		write_unlock(&pathtbl_resize_lock);
+		return;
+	}
+	rcu_assign_pointer(mesh_paths, newtbl);
+	write_unlock(&pathtbl_resize_lock);
+
+	synchronize_rcu();
+	mesh_table_free(oldtbl, false);
+}
+
+void mesh_mpp_table_grow(void)
+{
+	struct mesh_table *oldtbl, *newtbl;
+
+	write_lock(&pathtbl_resize_lock);
+	oldtbl = mpp_paths;
+	newtbl = mesh_table_grow(mpp_paths);
+	if (!newtbl) {
+		write_unlock(&pathtbl_resize_lock);
+		return;
+	}
+	rcu_assign_pointer(mpp_paths, newtbl);
+	write_unlock(&pathtbl_resize_lock);
+
+	synchronize_rcu();
+	mesh_table_free(oldtbl, false);
+}
 
 int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
 	struct mesh_path *mpath, *new_mpath;
 	struct mpath_node *node, *new_node;
 	struct hlist_head *bucket;
@@ -289,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 	int err = 0;
 	u32 hash_idx;
 
-	might_sleep();
-
 	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* never add ourselves as neighbours */
 		return -ENOTSUPP;
@@ -299,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 		return -ENOTSUPP;
 
 	err = -ENOMEM;
-	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
 	if (!new_mpath)
 		goto err_path_alloc;
 
-	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
 	if (!new_node)
 		goto err_node_alloc;
 
@@ -337,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 	spin_unlock(&mpp_paths->hashwlock[hash_idx]);
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
-		struct mesh_table *oldtbl, *newtbl;
-
-		write_lock(&pathtbl_resize_lock);
-		oldtbl = mpp_paths;
-		newtbl = mesh_table_grow(mpp_paths);
-		if (!newtbl) {
-			write_unlock(&pathtbl_resize_lock);
-			return 0;
-		}
-		rcu_assign_pointer(mpp_paths, newtbl);
-		write_unlock(&pathtbl_resize_lock);
-
-		synchronize_rcu();
-		mesh_table_free(oldtbl, false);
+		set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
+		queue_work(local->hw.workqueue, &ifmsh->work);
 	}
 	return 0;
 
-- 
1.5.4.3


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

* Re: [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics.
  2009-08-08  3:38     ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Javier Cardona
  2009-08-08  3:38       ` [PATCH 4/8] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
@ 2009-08-08  8:09       ` Kalle Valo
  2009-08-08  8:46         ` Johannes Berg
  1 sibling, 1 reply; 22+ messages in thread
From: Kalle Valo @ 2009-08-08  8:09 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, Andrey Yurovsky, johannes, linville, devel

Javier Cardona <javier@cozybit.com> writes:

> This enables us to specify a simulated loss probability per mesh peer link.
> Useful to simulate and test different mesh topologies and test different mesh
> metrics.
>
> The simulated loss rate setting can be configured as a plink action.  The
> intended use is:
>
> iw dev mesh station set <MAC> plink_action loss 25

I really would not like to see debug functionality in nl80211 just to
simplify the maintenance. Debugging belongs to debugfs or somewhere
else.

Disclaimer: I know nothing about mesh and I may have misunderstood
something.

-- 
Kalle Valo

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

* Re: [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics.
  2009-08-08  8:09       ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Kalle Valo
@ 2009-08-08  8:46         ` Johannes Berg
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Berg @ 2009-08-08  8:46 UTC (permalink / raw)
  To: Kalle Valo
  Cc: Javier Cardona, linux-wireless, Andrey Yurovsky, linville, devel

[-- Attachment #1: Type: text/plain, Size: 845 bytes --]

On Sat, 2009-08-08 at 11:09 +0300, Kalle Valo wrote:
> Javier Cardona <javier@cozybit.com> writes:
> 
> > This enables us to specify a simulated loss probability per mesh peer link.
> > Useful to simulate and test different mesh topologies and test different mesh
> > metrics.
> >
> > The simulated loss rate setting can be configured as a plink action.  The
> > intended use is:
> >
> > iw dev mesh station set <MAC> plink_action loss 25
> 
> I really would not like to see debug functionality in nl80211 just to
> simplify the maintenance. Debugging belongs to debugfs or somewhere
> else.

I agree, and I also don't think it belongs into mac80211. I think this
is a good case for actually finally writing the userspace frame
forwarding for hwsim, so you can simulate _anything_ with simple
userspace programs.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: Mesh fixes and improvements
  2009-08-08  3:38 Mesh fixes and improvements Javier Cardona
  2009-08-08  3:38 ` [PATCH 1/8] mac80211: Improve dequeing from mpath frame queue Javier Cardona
@ 2009-08-08  9:09 ` Johannes Berg
  2009-08-09  4:55   ` Javier Cardona
  1 sibling, 1 reply; 22+ messages in thread
From: Johannes Berg @ 2009-08-08  9:09 UTC (permalink / raw)
  To: Javier Cardona; +Cc: linux-wireless, andrey, linville, devel

[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]

On Fri, 2009-08-07 at 20:38 -0700, Javier Cardona wrote:
> [Resent with proper patch numbering...]
> 
> This series includes some fixes, testing aids and improvements to the mesh
> stack.  It is important to note that the patch
> "Use-3-address-format-for-mesh-broadcast-frames" breaks compatibility with
> previous versions.  This is unavoidable and will keep happening as new versions
> of the 802.11s drafts are produced.

That's ok, can you update the Kconfig though to indicate which draft
it's compatible with? It says 1.08 right now.

> Also, I'm not sure if "Simulate-transmission-losses-on-plinks-to-..." should be
> merged upstream, but we find it really useful to test mesh configurations.
> Please comment if you have different opinions on its adequacy or
> implementation.

As I said elsewhere in this thread I don't think that should be in,
especially not, as Kalle points out, using nl80211.

All the other patches look ok on a cursory look, I just wish you'd write
more detailed changelog entries.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: Mesh fixes and improvements
  2009-08-08  9:09 ` Mesh fixes and improvements Johannes Berg
@ 2009-08-09  4:55   ` Javier Cardona
  2009-08-10 17:52     ` John W. Linville
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-09  4:55 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, andrey, linville, devel

Johannes,

Thanks for the review.

On Sat, Aug 8, 2009 at 2:09 AM, Johannes Berg<johannes@sipsolutions.net> wrote:
>> This series includes some fixes, testing aids and improvements to the mesh
>> stack.  It is important to note that the patch
>> "Use-3-address-format-for-mesh-broadcast-frames" breaks compatibility with
>> previous versions.  This is unavoidable and will keep happening as new versions
>> of the 802.11s drafts are produced.
>
> That's ok, can you update the Kconfig though to indicate which draft
> it's compatible with? It says 1.08 right now.

Unfortunately I don't think it is fully compatible to one particular
version.  Furthermore, compliance with a Draft is not really
achievable:  a vast number of identifiers (reason codes, element ids,
status codes, ...) are not defined until the standard is ratified.

This particular change to the broadcast frame format was introduced
between D2.03 and D2.08.  Without it mesh networks will badly interact
with widely deployed lazy WDS APs.  It is not purely an
interoperability issue with other mesh implementations but a
requirement to achieve harmonious coexistence with deployed systems.
I don't think we should hold this change back until closer compliance
to a given draft version is implemented.

I'll still be happy to change the Kconfig, but bumping the version
number to, say D2.08, might be misleading.  I guess we should be more
verbose in the Kconfig description.

>> Also, I'm not sure if "Simulate-transmission-losses-on-plinks-to-..." should be
>> merged upstream, but we find it really useful to test mesh configurations.
>> Please comment if you have different opinions on its adequacy or
>> implementation.
>
> As I said elsewhere in this thread I don't think that should be in,
> especially not, as Kalle points out, using nl80211.

Understood.  I'll withdraw that patch and regenerate the series...

> All the other patches look ok on a cursory look, I just wish you'd write
> more detailed changelog entries.

... with more changelogs.

Cheers,

Javier

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

* Re: Mesh fixes and improvements
  2009-08-09  4:55   ` Javier Cardona
@ 2009-08-10 17:52     ` John W. Linville
  2009-08-10 19:15       ` Mesh fixes and improvements [v2] Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: John W. Linville @ 2009-08-10 17:52 UTC (permalink / raw)
  To: Javier Cardona; +Cc: Johannes Berg, linux-wireless, andrey, devel

On Sat, Aug 08, 2009 at 09:55:56PM -0700, Javier Cardona wrote:
> On Sat, Aug 8, 2009 at 2:09 AM, Johannes Berg<johannes@sipsolutions.net> wrote:
> >> Also, I'm not sure if "Simulate-transmission-losses-on-plinks-to-..." should be
> >> merged upstream, but we find it really useful to test mesh configurations.
> >> Please comment if you have different opinions on its adequacy or
> >> implementation.
> >
> > As I said elsewhere in this thread I don't think that should be in,
> > especially not, as Kalle points out, using nl80211.
> 
> Understood.  I'll withdraw that patch and regenerate the series...

Dropping the series based on the above comment...

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

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

* Mesh fixes and improvements [v2]
  2009-08-10 17:52     ` John W. Linville
@ 2009-08-10 19:15       ` Javier Cardona
  2009-08-10 19:15         ` [PATCH 1/7] mac80211: Improve dequeing from mpath frame queue Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: andrey, johannes, linville, devel

[v2]

Withdraw "Simulate-transmission-losses-on-plinks-to-...".
Add detail to changelogs and Kconfig.
Changed queue_work -> ieee80211_queue_work

[v1]

This series includes some fixes, testing aids and improvements to the mesh
stack.  It is important to note that the patch
"Use-3-address-format-for-mesh-broadcast-frames" breaks compatibility with
previous versions.  This is unavoidable and will keep happening as new versions
of the 802.11s drafts are produced.

Also, I'm not sure if "Simulate-transmission-losses-on-plinks-to-..." should be
merged upstream, but we find it really useful to test mesh configurations.
Please comment if you have different opinions on its adequacy or
implementation.

Cheers,

Javier


 include/linux/nl80211.h         |    4 +
 include/net/cfg80211.h          |    4 +
 net/mac80211/Kconfig            |    8 +-
 net/mac80211/cfg.c              |    6 ++
 net/mac80211/ieee80211_i.h      |    2 +-
 net/mac80211/mesh.c             |  136 ++++++++++++++++++------------------
 net/mac80211/mesh.h             |   29 +++++++-
 net/mac80211/mesh_hwmp.c        |    9 +--
 net/mac80211/mesh_pathtbl.c     |  146 +++++++++++++++++++++++++++++----------
 net/mac80211/mesh_plink.c       |    6 ++
 net/mac80211/rc80211_minstrel.c |   16 ++++-
 net/mac80211/rx.c               |   45 ++++++++-----
 net/mac80211/sta_info.h         |    1 +
 net/mac80211/tx.c               |  118 +++++++++++++++++++++++---------
 net/wireless/nl80211.c          |    9 +++
 net/wireless/util.c             |   16 +++-
 16 files changed, 384 insertions(+), 171 deletions(-)


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

* [PATCH 1/7] mac80211: Improve dequeing from mpath frame queue.
  2009-08-10 19:15       ` Mesh fixes and improvements [v2] Javier Cardona
@ 2009-08-10 19:15         ` Javier Cardona
  2009-08-10 19:15           ` [PATCH 2/7] mac80211: Use correct sign for mesh active path refresh Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

Also, fix typo in comment.

Signed-off-by: Javier Cardona <javier@cozybit.com>
Tested-by: Andrey Yurovsky <andrey@cozybit.com>
---
 net/mac80211/mesh.h      |    2 +-
 net/mac80211/mesh_hwmp.c |    6 ++----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index ce53881..6aaf1ec 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -61,7 +61,7 @@ enum mesh_path_flags {
  * 	retry
  * @discovery_retries: number of discovery retries
  * @flags: mesh path flags, as specified on &enum mesh_path_flags
- * @state_lock: mesh pat state lock
+ * @state_lock: mesh path state lock
  *
  *
  * The combination of dst and sdata is unique in the mesh path table. Since the
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e1a763e..b54c21c 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -810,10 +810,8 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 		}
 
 		if (skb_queue_len(&mpath->frame_queue) >=
-				MESH_FRAME_QUEUE_LEN) {
-			skb_to_free = mpath->frame_queue.next;
-			skb_unlink(skb_to_free, &mpath->frame_queue);
-		}
+				MESH_FRAME_QUEUE_LEN)
+			skb_to_free = skb_dequeue(&mpath->frame_queue);
 
 		info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 		skb_queue_tail(&mpath->frame_queue, skb);
-- 
1.5.4.3


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

* [PATCH 2/7] mac80211: Use correct sign for mesh active path refresh.
  2009-08-10 19:15         ` [PATCH 1/7] mac80211: Improve dequeing from mpath frame queue Javier Cardona
@ 2009-08-10 19:15           ` Javier Cardona
  2009-08-10 19:15             ` [PATCH 3/7] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Andrey Yurovsky, Javier Cardona, johannes, linville, devel

From: Andrey Yurovsky <andrey@cozybit.com>

On locally originated traffic, we refresh active paths after a timeout.  The
decision to do this was using the wrong sign and therefore the refresh timer
was triggered for every frame.

Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh_hwmp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index b54c21c..1cd1e72 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -791,7 +791,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
 	}
 
 	if (mpath->flags & MESH_PATH_ACTIVE) {
-		if (time_after(jiffies, mpath->exp_time -
+		if (time_after(jiffies, mpath->exp_time +
 			msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time))
 				&& !memcmp(sdata->dev->dev_addr, hdr->addr4,
 					   ETH_ALEN)
-- 
1.5.4.3


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

* [PATCH 3/7] mac80211: Use 3-address format for mesh broadcast frames.
  2009-08-10 19:15           ` [PATCH 2/7] mac80211: Use correct sign for mesh active path refresh Javier Cardona
@ 2009-08-10 19:15             ` Javier Cardona
  2009-08-10 19:15               ` [PATCH 4/7] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, Andrey Yurovsky, johannes, linville, devel

The 11s task group recently changed the frame mesh multicast/broadcast frame
format to use 3-address.  This was done to avoid interactions with widely
deployed lazy-WDS access points.

This patch changes the format of group addressed frames, both mesh-originated
and proxied, to use the data format defined in draft D2.08 and forward.  The
address fields used for group addressed frames is:

In 802.11 header
 ToDS:0  FromDS:1
 addr1: DA  (broadcast/multicast address)
 addr2: TA
 addr3: Mesh SA

In address extension header:
 addr4: SA  (only present if frame was proxied)

Note that this change breaks backward compatibility with earlier mesh stack
versions.

Signed-off-by: Andrey Yurovsky <andrey@cozybit.com>
Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.c |   62 ++++++++++++++++++++++++++++++++++++++++++++++---
 net/mac80211/mesh.h |    5 +++-
 net/mac80211/rx.c   |   45 ++++++++++++++++++++++-------------
 net/mac80211/tx.c   |   64 +++++++++++++++++++++++++++------------------------
 net/wireless/util.c |   16 +++++++++---
 5 files changed, 136 insertions(+), 56 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 8c068e2..10d9338 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -399,21 +399,75 @@ endgrow:
 }
 
 /**
+ * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
+ * @hdr:    	802.11 frame header
+ * @fc:		frame control field
+ * @meshda:	destination address in the mesh
+ * @meshsa:	source address address in the mesh.  Same as TA, as frame is
+ *              locally originated.
+ *
+ * Return the length of the 802.11 (does not include a mesh control header)
+ */
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc, char
+		*meshda, char *meshsa) {
+	if (is_multicast_ether_addr(meshda)) {
+		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
+		/* DA TA SA */
+		memcpy(hdr->addr1, meshda, ETH_ALEN);
+		memcpy(hdr->addr2, meshsa, ETH_ALEN);
+		memcpy(hdr->addr3, meshsa, ETH_ALEN);
+		return 24;
+	} else {
+		*fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS |
+				IEEE80211_FCTL_TODS);
+		/* RA TA DA SA */
+		memset(hdr->addr1, 0, ETH_ALEN);   /* RA is resolved later */
+		memcpy(hdr->addr2, meshsa, ETH_ALEN);
+		memcpy(hdr->addr3, meshda, ETH_ALEN);
+		memcpy(hdr->addr4, meshsa, ETH_ALEN);
+		return 30;
+	}
+}
+
+/**
  * ieee80211_new_mesh_header - create a new mesh header
  * @meshhdr:    uninitialized mesh header
  * @sdata:	mesh interface to be used
+ * @addr4:	addr4 of the mesh frame (1st in ae header)
+ *              may be NULL
+ * @addr5:	addr5 of the mesh frame (1st or 2nd in ae header)
+ *              may be NULL unless addr6 is present
+ * @addr6:	addr6 of the mesh frame (2nd or 3rd in ae header)
+ * 		may be NULL unless addr5 is present
  *
  * Return the header length.
  */
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
-		struct ieee80211_sub_if_data *sdata)
+		struct ieee80211_sub_if_data *sdata, char *addr4,
+		char *addr5, char *addr6)
 {
-	meshhdr->flags = 0;
+	int aelen = 0;
+	memset(meshhdr, 0, sizeof(meshhdr));
 	meshhdr->ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
 	put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &meshhdr->seqnum);
 	sdata->u.mesh.mesh_seqnum++;
-
-	return 6;
+	if (addr4) {
+		meshhdr->flags |= MESH_FLAGS_AE_A4;
+		aelen += ETH_ALEN;
+		memcpy(meshhdr->eaddr1, addr4, ETH_ALEN);
+	}
+	if (addr5 && addr6) {
+		meshhdr->flags |= MESH_FLAGS_AE_A5_A6;
+		aelen += 2 * ETH_ALEN;
+		if (!addr4) {
+			memcpy(meshhdr->eaddr1, addr5, ETH_ALEN);
+			memcpy(meshhdr->eaddr2, addr6, ETH_ALEN);
+		} else {
+			memcpy(meshhdr->eaddr2, addr5, ETH_ALEN);
+			memcpy(meshhdr->eaddr3, addr6, ETH_ALEN);
+		}
+	}
+	return 6 + aelen;
 }
 
 static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 6aaf1ec..2ebd74c 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -193,8 +193,11 @@ struct mesh_rmc {
 
 /* Public interfaces */
 /* Various */
+int ieee80211_fill_mesh_addresses(struct ieee80211_hdr *hdr, __le16 *fc,
+		char *da, char *sa);
 int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
-		struct ieee80211_sub_if_data *sdata);
+		struct ieee80211_sub_if_data *sdata, char *addr4,
+		char *addr5, char *addr6);
 int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
 		struct ieee80211_sub_if_data *sdata);
 bool mesh_matches_local(struct ieee802_11_elems *ie,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 25a669c..e7d8895 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -489,12 +489,21 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
 	unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control);
+	char *dev_addr = rx->dev->dev_addr;
 
 	if (ieee80211_is_data(hdr->frame_control)) {
-		if (!ieee80211_has_a4(hdr->frame_control))
-			return RX_DROP_MONITOR;
-		if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0)
-			return RX_DROP_MONITOR;
+		if (is_multicast_ether_addr(hdr->addr1)) {
+			if (ieee80211_has_tods(hdr->frame_control) ||
+				!ieee80211_has_fromds(hdr->frame_control))
+				return RX_DROP_MONITOR;
+			if (memcmp(hdr->addr3, dev_addr, ETH_ALEN) == 0)
+				return RX_DROP_MONITOR;
+		} else {
+			if (!ieee80211_has_a4(hdr->frame_control))
+				return RX_DROP_MONITOR;
+			if (memcmp(hdr->addr4, dev_addr, ETH_ALEN) == 0)
+				return RX_DROP_MONITOR;
+		}
 	}
 
 	/* If there is not an established peer link and this is not a peer link
@@ -527,7 +536,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 
 	if (ieee80211_is_data(hdr->frame_control) &&
 	    is_multicast_ether_addr(hdr->addr1) &&
-	    mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->sdata))
+	    mesh_rmc_check(hdr->addr3, msh_h_get(hdr, hdrlen), rx->sdata))
 		return RX_DROP_MONITOR;
 #undef msh_h_get
 
@@ -1495,7 +1504,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		/* illegal frame */
 		return RX_DROP_MONITOR;
 
-	if (mesh_hdr->flags & MESH_FLAGS_AE_A5_A6){
+	if (!is_multicast_ether_addr(hdr->addr1) &&
+			(mesh_hdr->flags & MESH_FLAGS_AE_A5_A6)) {
 		struct mesh_path *mppath;
 
 		rcu_read_lock();
@@ -1512,7 +1522,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		rcu_read_unlock();
 	}
 
-	if (compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
+	/* Frame has reached destination.  Don't forward */
+	if (!is_multicast_ether_addr(hdr->addr1) &&
+			compare_ether_addr(rx->dev->dev_addr, hdr->addr3) == 0)
 		return RX_CONTINUE;
 
 	mesh_hdr->ttl--;
@@ -1532,22 +1544,21 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 						   rx->dev->name);
 
 			fwd_hdr =  (struct ieee80211_hdr *) fwd_skb->data;
-			/*
-			 * Save TA to addr1 to send TA a path error if a
-			 * suitable next hop is not found
-			 */
-			memcpy(fwd_hdr->addr1, fwd_hdr->addr2, ETH_ALEN);
 			memcpy(fwd_hdr->addr2, rx->dev->dev_addr, ETH_ALEN);
 			info = IEEE80211_SKB_CB(fwd_skb);
 			memset(info, 0, sizeof(*info));
 			info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
 			info->control.vif = &rx->sdata->vif;
 			ieee80211_select_queue(local, fwd_skb);
-			if (is_multicast_ether_addr(fwd_hdr->addr3))
-				memcpy(fwd_hdr->addr1, fwd_hdr->addr3,
+			if (!is_multicast_ether_addr(fwd_hdr->addr1)) {
+				int err;
+				/*
+				 * Save TA to addr1 to send TA a path error if a
+				 * suitable next hop is not found
+				 */
+				memcpy(fwd_hdr->addr1, fwd_hdr->addr2,
 						ETH_ALEN);
-			else {
-				int err = mesh_nexthop_lookup(fwd_skb, sdata);
+				err = mesh_nexthop_lookup(fwd_skb, sdata);
 				/* Failed to immediately resolve next hop:
 				 * fwded frame was dropped or will be added
 				 * later to the pending skb queue.  */
@@ -1560,7 +1571,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
 		}
 	}
 
-	if (is_multicast_ether_addr(hdr->addr3) ||
+	if (is_multicast_ether_addr(hdr->addr1) ||
 	    rx->dev->flags & IFF_PROMISC)
 		return RX_CONTINUE;
 	else
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index c9be9dc..b9f5be6 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1415,9 +1415,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
 
 	if (ieee80211_vif_is_mesh(&sdata->vif) &&
 	    ieee80211_is_data(hdr->frame_control)) {
-		if (is_multicast_ether_addr(hdr->addr3))
-			memcpy(hdr->addr1, hdr->addr3, ETH_ALEN);
-		else
+		if (!is_multicast_ether_addr(hdr->addr1))
 			if (mesh_nexthop_lookup(skb, sdata)) {
 				dev_put(sdata->dev);
 				return;
@@ -1620,52 +1618,58 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
 		break;
 #ifdef CONFIG_MAC80211_MESH
 	case NL80211_IFTYPE_MESH_POINT:
-		fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
 		if (!sdata->u.mesh.mshcfg.dot11MeshTTL) {
 			/* Do not send frames with mesh_ttl == 0 */
 			sdata->u.mesh.mshstats.dropped_frames_ttl++;
 			ret = 0;
 			goto fail;
 		}
-		memset(&mesh_hdr, 0, sizeof(mesh_hdr));
 
 		if (compare_ether_addr(dev->dev_addr,
 					  skb->data + ETH_ALEN) == 0) {
-			/* RA TA DA SA */
-			memset(hdr.addr1, 0, ETH_ALEN);
-			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-			memcpy(hdr.addr3, skb->data, ETH_ALEN);
-			memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN);
-			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, sdata);
+			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
+					skb->data, skb->data + ETH_ALEN);
+			meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
+					sdata, NULL, NULL, NULL);
 		} else {
 			/* packet from other interface */
 			struct mesh_path *mppath;
+			int is_mesh_mcast = 1;
+			char *mesh_da;
 
-			memset(hdr.addr1, 0, ETH_ALEN);
-			memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN);
-			memcpy(hdr.addr4, dev->dev_addr, ETH_ALEN);
-
+			rcu_read_lock();
 			if (is_multicast_ether_addr(skb->data))
-				memcpy(hdr.addr3, skb->data, ETH_ALEN);
+				/* DA TA mSA AE:SA */
+				mesh_da = skb->data;
 			else {
-				rcu_read_lock();
 				mppath = mpp_path_lookup(skb->data, sdata);
-				if (mppath)
-					memcpy(hdr.addr3, mppath->mpp, ETH_ALEN);
-				else
-					memset(hdr.addr3, 0xff, ETH_ALEN);
-				rcu_read_unlock();
+				if (mppath) {
+					/* RA TA mDA mSA AE:DA SA */
+					mesh_da = mppath->mpp;
+					is_mesh_mcast = 0;
+				} else
+					/* DA TA mSA AE:SA */
+					mesh_da = dev->broadcast;
 			}
+			hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
+					mesh_da, dev->dev_addr);
+			rcu_read_unlock();
+			if (is_mesh_mcast)
+				meshhdrlen =
+					ieee80211_new_mesh_header(&mesh_hdr,
+							sdata,
+							skb->data + ETH_ALEN,
+							NULL,
+							NULL);
+			else
+				meshhdrlen =
+					ieee80211_new_mesh_header(&mesh_hdr,
+							sdata,
+							NULL,
+							skb->data,
+							skb->data + ETH_ALEN);
 
-			mesh_hdr.flags |= MESH_FLAGS_AE_A5_A6;
-			mesh_hdr.ttl = sdata->u.mesh.mshcfg.dot11MeshTTL;
-			put_unaligned(cpu_to_le32(sdata->u.mesh.mesh_seqnum), &mesh_hdr.seqnum);
-			memcpy(mesh_hdr.eaddr1, skb->data, ETH_ALEN);
-			memcpy(mesh_hdr.eaddr2, skb->data + ETH_ALEN, ETH_ALEN);
-			sdata->u.mesh.mesh_seqnum++;
-			meshhdrlen = 18;
 		}
-		hdrlen = 30;
 		break;
 #endif
 	case NL80211_IFTYPE_STATION:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index ba387d8..693275a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -274,11 +274,11 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 	switch (ae) {
 	case 0:
 		return 6;
-	case 1:
+	case MESH_FLAGS_AE_A4:
 		return 12;
-	case 2:
+	case MESH_FLAGS_AE_A5_A6:
 		return 18;
-	case 3:
+	case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
 		return 24;
 	default:
 		return 6;
@@ -333,10 +333,18 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 		}
 		break;
 	case cpu_to_le16(IEEE80211_FCTL_FROMDS):
-		if (iftype != NL80211_IFTYPE_STATION ||
+		if ((iftype != NL80211_IFTYPE_STATION &&
+		    iftype != NL80211_IFTYPE_MESH_POINT) ||
 		    (is_multicast_ether_addr(dst) &&
 		     !compare_ether_addr(src, addr)))
 			return -1;
+		if (iftype == NL80211_IFTYPE_MESH_POINT) {
+			struct ieee80211s_hdr *meshdr =
+				(struct ieee80211s_hdr *) (skb->data + hdrlen);
+			hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
+			if (meshdr->flags & MESH_FLAGS_AE_A4)
+				memcpy(src, meshdr->eaddr1, ETH_ALEN);
+		}
 		break;
 	case cpu_to_le16(0):
 		if (iftype != NL80211_IFTYPE_ADHOC)
-- 
1.5.4.3


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

* [PATCH 4/7] mac80211: Update the station failed frames average when minstrel is used.
  2009-08-10 19:15             ` [PATCH 3/7] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
@ 2009-08-10 19:15               ` Javier Cardona
  2009-08-10 19:15                 ` [PATCH 5/7] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

The fail_avg value is used to compute the mesh metric, and was only being set
by the pid rate control module. This fixes the mesh path selection mechanism
for cards that use mistrel for rate control.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/rc80211_minstrel.c |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 7c51429..3ea9740 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -155,12 +155,16 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 		   struct sk_buff *skb)
 {
 	struct minstrel_sta_info *mi = priv_sta;
+	struct minstrel_priv *mp = (struct minstrel_priv *)priv;
 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 	struct ieee80211_tx_rate *ar = info->status.rates;
+	struct ieee80211_local *local = hw_to_local(mp->hw);
+	struct sta_info *si;
 	int i, ndx;
 	int success;
 
 	success = !!(info->flags & IEEE80211_TX_STAT_ACK);
+	si = sta_info_get(local, sta->addr);
 
 	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
 		if (ar[i].idx < 0)
@@ -172,8 +176,12 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 		mi->r[ndx].attempts += ar[i].count;
 
-		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0))
+		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) {
 			mi->r[ndx].success += success;
+			if (si)
+				si->fail_avg = (18050 - mi->r[ndx].probability)
+					/ 180;
+		}
 	}
 
 	if ((info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) && (i >= 0))
-- 
1.5.4.3


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

* [PATCH 5/7] mac80211: Early detection of broken mesh paths when using minstrel.
  2009-08-10 19:15               ` [PATCH 4/7] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
@ 2009-08-10 19:15                 ` Javier Cardona
  2009-08-10 19:15                   ` [PATCH 6/7] mac80211: Assign a default mesh beaconing interval Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

This change triggers a path discovery as soon as the link quality degrades
below a certain threshold.  This results in a faster path recovery time than
by simply relying on the periodic path refresh mechanism to detect broken
links.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/rc80211_minstrel.c |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 3ea9740..0071649 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -51,6 +51,7 @@
 #include <linux/random.h>
 #include <linux/ieee80211.h>
 #include <net/mac80211.h>
+#include "mesh.h"
 #include "rate.h"
 #include "rc80211_minstrel.h"
 
@@ -178,9 +179,14 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 		if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) {
 			mi->r[ndx].success += success;
-			if (si)
+			if (si) {
 				si->fail_avg = (18050 - mi->r[ndx].probability)
 					/ 180;
+				WARN_ON(si->fail_avg > 100);
+				if (si->fail_avg == 100 &&
+					ieee80211_vif_is_mesh(&si->sdata->vif))
+					mesh_plink_broken(si);
+			}
 		}
 	}
 
-- 
1.5.4.3


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

* [PATCH 6/7] mac80211: Assign a default mesh beaconing interval.
  2009-08-10 19:15                 ` [PATCH 5/7] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
@ 2009-08-10 19:15                   ` Javier Cardona
  2009-08-10 19:15                     ` [PATCH 7/7] mac80211: Move mpath and mpp growth to mesh workqueue Javier Cardona
  0 siblings, 1 reply; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

The mesh stack was enabling beaconing without specifying an interval.  This
patch defines a default beaconing interval of 1s.

Incidentally, this fixes mesh beaconing in mac80211_hwsim devices.

Signed-off-by: Javier Cardona <javier@cozybit.com>
---
 net/mac80211/mesh.c |    6 ++++--
 net/mac80211/mesh.h |    1 +
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 10d9338..25d0065 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -525,9 +525,11 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_local *local = sdata->local;
 
 	ifmsh->housekeeping = true;
-	ieee80211_queue_work(&local->hw, &ifmsh->work);
+	queue_work(local->hw, &ifmsh->work);
+	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
-						BSS_CHANGED_BEACON_ENABLED);
+						BSS_CHANGED_BEACON_ENABLED |
+						BSS_CHANGED_BEACON_INT);
 }
 
 void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 2ebd74c..4241925 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -174,6 +174,7 @@ struct mesh_rmc {
  */
 #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)
-- 
1.5.4.3


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

* [PATCH 7/7] mac80211: Move mpath and mpp growth to mesh workqueue.
  2009-08-10 19:15                   ` [PATCH 6/7] mac80211: Assign a default mesh beaconing interval Javier Cardona
@ 2009-08-10 19:15                     ` Javier Cardona
  0 siblings, 0 replies; 22+ messages in thread
From: Javier Cardona @ 2009-08-10 19:15 UTC (permalink / raw)
  To: linux-wireless; +Cc: Javier Cardona, andrey, johannes, linville, devel

This prevents calling rcu_synchronize from within the tx path by moving the
table growth code to the mesh workqueue.

Move mesh_table_free and mesh_table_grow from mesh.c to mesh_pathtbl.c and
declare them static.

Also, re-enable mesh in Kconfig and update the configuration description.

Signed-off-by: Javier Cardona <javier@cozybit.com>
Tested-by: Andrey Yurovsky <andrey@cozybit.com>
---
 net/mac80211/Kconfig        |    8 +-
 net/mac80211/ieee80211_i.h  |    2 +-
 net/mac80211/mesh.c         |   77 +++--------------------
 net/mac80211/mesh.h         |   20 ++++++-
 net/mac80211/mesh_pathtbl.c |  146 ++++++++++++++++++++++++++++++++-----------
 5 files changed, 144 insertions(+), 109 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 7dd77b6..9db4ff8 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -66,12 +66,12 @@ endmenu
 config MAC80211_MESH
 	bool "Enable mac80211 mesh networking (pre-802.11s) support"
 	depends on MAC80211 && EXPERIMENTAL
-	depends on BROKEN
 	---help---
 	 This options enables support of Draft 802.11s mesh networking.
-	 The implementation is based on Draft 1.08 of the Mesh Networking
-	 amendment. For more information visit http://o11s.org/.
-
+	 The implementation is based on Draft 2.08 of the Mesh Networking
+	 amendment.  However, no compliance with that draft is claimed or even
+	 possible, as drafts leave a number of identifiers to be defined after
+	 ratification.  For more information visit http://o11s.org/.
 
 config MAC80211_LEDS
 	bool "Enable LED triggers"
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d6bd7dd..a6abc7d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -355,7 +355,7 @@ struct ieee80211_if_mesh {
 
 	unsigned long timers_running;
 
-	bool housekeeping;
+	unsigned long wrkq_flags;
 
 	u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
 	size_t mesh_id_len;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 25d0065..3185e18 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -47,7 +47,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 
-	ifmsh->housekeeping = true;
+	ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
 
 	if (local->quiescing) {
 		set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
@@ -320,30 +320,6 @@ struct mesh_table *mesh_table_alloc(int size_order)
 	return newtbl;
 }
 
-static void __mesh_table_free(struct mesh_table *tbl)
-{
-	kfree(tbl->hash_buckets);
-	kfree(tbl->hashwlock);
-	kfree(tbl);
-}
-
-void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
-{
-	struct hlist_head *mesh_hash;
-	struct hlist_node *p, *q;
-	int i;
-
-	mesh_hash = tbl->hash_buckets;
-	for (i = 0; i <= tbl->hash_mask; i++) {
-		spin_lock(&tbl->hashwlock[i]);
-		hlist_for_each_safe(p, q, &mesh_hash[i]) {
-			tbl->free_node(p, free_leafs);
-			atomic_dec(&tbl->entries);
-		}
-		spin_unlock(&tbl->hashwlock[i]);
-	}
-	__mesh_table_free(tbl);
-}
 
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
@@ -360,44 +336,6 @@ static void ieee80211_mesh_path_timer(unsigned long data)
 	ieee80211_queue_work(&local->hw, &ifmsh->work);
 }
 
-struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
-{
-	struct mesh_table *newtbl;
-	struct hlist_head *oldhash;
-	struct hlist_node *p, *q;
-	int i;
-
-	if (atomic_read(&tbl->entries)
-			< tbl->mean_chain_len * (tbl->hash_mask + 1))
-		goto endgrow;
-
-	newtbl = mesh_table_alloc(tbl->size_order + 1);
-	if (!newtbl)
-		goto endgrow;
-
-	newtbl->free_node = tbl->free_node;
-	newtbl->mean_chain_len = tbl->mean_chain_len;
-	newtbl->copy_node = tbl->copy_node;
-	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
-
-	oldhash = tbl->hash_buckets;
-	for (i = 0; i <= tbl->hash_mask; i++)
-		hlist_for_each(p, &oldhash[i])
-			if (tbl->copy_node(p, newtbl) < 0)
-				goto errcopy;
-
-	return newtbl;
-
-errcopy:
-	for (i = 0; i <= newtbl->hash_mask; i++) {
-		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
-			tbl->free_node(p, 0);
-	}
-	__mesh_table_free(newtbl);
-endgrow:
-	return NULL;
-}
-
 /**
  * ieee80211_fill_mesh_addresses - fill addresses of a locally originated mesh frame
  * @hdr:    	802.11 frame header
@@ -487,7 +425,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
 	if (free_plinks != sdata->u.mesh.accepting_plinks)
 		ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
 
-	ifmsh->housekeeping = false;
 	mod_timer(&ifmsh->housekeeping_timer,
 		  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
 }
@@ -524,8 +461,8 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
 	struct ieee80211_local *local = sdata->local;
 
-	ifmsh->housekeeping = true;
-	queue_work(local->hw, &ifmsh->work);
+	ifmsh->wrkq_flags |= MESH_WORK_HOUSEKEEPING;
+	ieee80211_queue_work(&local->hw, &ifmsh->work);
 	sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL;
 	ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON |
 						BSS_CHANGED_BEACON_ENABLED |
@@ -664,7 +601,13 @@ static void ieee80211_mesh_work(struct work_struct *work)
 		       ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval)))
 		mesh_path_start_discovery(sdata);
 
-	if (ifmsh->housekeeping)
+	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
+		mesh_mpath_table_grow();
+
+	if (test_and_clear_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags))
+		mesh_mpp_table_grow();
+
+	if (test_and_clear_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags))
 		ieee80211_mesh_housekeeping(sdata, ifmsh);
 }
 
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 4241925..eb23fc6 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -44,6 +44,23 @@ enum mesh_path_flags {
 };
 
 /**
+ * enum mesh_deferred_task_flags - mac80211 mesh deferred tasks
+ *
+ *
+ *
+ * @MESH_WORK_HOUSEKEEPING: run the periodic mesh housekeeping tasks
+ * @MESH_WORK_GROW_MPATH_TABLE: the mesh path table is full and needs
+ * to grow.
+ * @MESH_WORK_GROW_MPP_TABLE: the mesh portals table is full and needs to
+ * grow
+ */
+enum mesh_deferred_task_flags {
+	MESH_WORK_HOUSEKEEPING,
+	MESH_WORK_GROW_MPATH_TABLE,
+	MESH_WORK_GROW_MPP_TABLE,
+};
+
+/**
  * struct mesh_path - mac80211 mesh path structure
  *
  * @dst: mesh path destination mac address
@@ -250,7 +267,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,
 /* Mesh tables */
 struct mesh_table *mesh_table_alloc(int size_order);
 void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
-struct mesh_table *mesh_table_grow(struct mesh_table *tbl);
+void mesh_mpath_table_grow(void);
+void mesh_mpp_table_grow(void);
 u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
 		struct mesh_table *tbl);
 /* Mesh paths */
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 431865a..751c4d0 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -39,6 +39,69 @@ static struct mesh_table *mesh_paths;
 static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
 
 int mesh_paths_generation;
+static void __mesh_table_free(struct mesh_table *tbl)
+{
+	kfree(tbl->hash_buckets);
+	kfree(tbl->hashwlock);
+	kfree(tbl);
+}
+
+void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+{
+	struct hlist_head *mesh_hash;
+	struct hlist_node *p, *q;
+	int i;
+
+	mesh_hash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++) {
+		spin_lock(&tbl->hashwlock[i]);
+		hlist_for_each_safe(p, q, &mesh_hash[i]) {
+			tbl->free_node(p, free_leafs);
+			atomic_dec(&tbl->entries);
+		}
+		spin_unlock(&tbl->hashwlock[i]);
+	}
+	__mesh_table_free(tbl);
+}
+
+static struct mesh_table *mesh_table_grow(struct mesh_table *tbl)
+{
+	struct mesh_table *newtbl;
+	struct hlist_head *oldhash;
+	struct hlist_node *p, *q;
+	int i;
+
+	if (atomic_read(&tbl->entries)
+			< tbl->mean_chain_len * (tbl->hash_mask + 1))
+		goto endgrow;
+
+	newtbl = mesh_table_alloc(tbl->size_order + 1);
+	if (!newtbl)
+		goto endgrow;
+
+	newtbl->free_node = tbl->free_node;
+	newtbl->mean_chain_len = tbl->mean_chain_len;
+	newtbl->copy_node = tbl->copy_node;
+	atomic_set(&newtbl->entries, atomic_read(&tbl->entries));
+
+	oldhash = tbl->hash_buckets;
+	for (i = 0; i <= tbl->hash_mask; i++)
+		hlist_for_each(p, &oldhash[i])
+			if (tbl->copy_node(p, newtbl) < 0)
+				goto errcopy;
+
+	return newtbl;
+
+errcopy:
+	for (i = 0; i <= newtbl->hash_mask; i++) {
+		hlist_for_each_safe(p, q, &newtbl->hash_buckets[i])
+			tbl->free_node(p, 0);
+	}
+	__mesh_table_free(newtbl);
+endgrow:
+	return NULL;
+}
+
 
 /* This lock will have the grow table function as writer and add / delete nodes
  * as readers. When reading the table (i.e. doing lookups) we are well protected
@@ -187,6 +250,8 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct ieee80211_sub_if_data
  */
 int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
 	struct mesh_path *mpath, *new_mpath;
 	struct mpath_node *node, *new_node;
 	struct hlist_head *bucket;
@@ -195,8 +260,6 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 	int err = 0;
 	u32 hash_idx;
 
-	might_sleep();
-
 	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* never add ourselves as neighbours */
 		return -ENOTSUPP;
@@ -208,11 +271,11 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 		return -ENOSPC;
 
 	err = -ENOMEM;
-	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
 	if (!new_mpath)
 		goto err_path_alloc;
 
-	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
 	if (!new_node)
 		goto err_node_alloc;
 
@@ -250,20 +313,8 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
 	spin_unlock(&mesh_paths->hashwlock[hash_idx]);
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
-		struct mesh_table *oldtbl, *newtbl;
-
-		write_lock(&pathtbl_resize_lock);
-		oldtbl = mesh_paths;
-		newtbl = mesh_table_grow(mesh_paths);
-		if (!newtbl) {
-			write_unlock(&pathtbl_resize_lock);
-			return 0;
-		}
-		rcu_assign_pointer(mesh_paths, newtbl);
-		write_unlock(&pathtbl_resize_lock);
-
-		synchronize_rcu();
-		mesh_table_free(oldtbl, false);
+		set_bit(MESH_WORK_GROW_MPATH_TABLE,  &ifmsh->wrkq_flags);
+		ieee80211_queue_work(&local->hw, &ifmsh->work);
 	}
 	return 0;
 
@@ -278,9 +329,46 @@ err_path_alloc:
 	return err;
 }
 
+void mesh_mpath_table_grow(void)
+{
+	struct mesh_table *oldtbl, *newtbl;
+
+	write_lock(&pathtbl_resize_lock);
+	oldtbl = mesh_paths;
+	newtbl = mesh_table_grow(mesh_paths);
+	if (!newtbl) {
+		write_unlock(&pathtbl_resize_lock);
+		return;
+	}
+	rcu_assign_pointer(mesh_paths, newtbl);
+	write_unlock(&pathtbl_resize_lock);
+
+	synchronize_rcu();
+	mesh_table_free(oldtbl, false);
+}
+
+void mesh_mpp_table_grow(void)
+{
+	struct mesh_table *oldtbl, *newtbl;
+
+	write_lock(&pathtbl_resize_lock);
+	oldtbl = mpp_paths;
+	newtbl = mesh_table_grow(mpp_paths);
+	if (!newtbl) {
+		write_unlock(&pathtbl_resize_lock);
+		return;
+	}
+	rcu_assign_pointer(mpp_paths, newtbl);
+	write_unlock(&pathtbl_resize_lock);
+
+	synchronize_rcu();
+	mesh_table_free(oldtbl, false);
+}
 
 int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 {
+	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+	struct ieee80211_local *local = sdata->local;
 	struct mesh_path *mpath, *new_mpath;
 	struct mpath_node *node, *new_node;
 	struct hlist_head *bucket;
@@ -289,8 +377,6 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 	int err = 0;
 	u32 hash_idx;
 
-	might_sleep();
-
 	if (memcmp(dst, sdata->dev->dev_addr, ETH_ALEN) == 0)
 		/* never add ourselves as neighbours */
 		return -ENOTSUPP;
@@ -299,11 +385,11 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 		return -ENOTSUPP;
 
 	err = -ENOMEM;
-	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL);
+	new_mpath = kzalloc(sizeof(struct mesh_path), GFP_ATOMIC);
 	if (!new_mpath)
 		goto err_path_alloc;
 
-	new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL);
+	new_node = kmalloc(sizeof(struct mpath_node), GFP_ATOMIC);
 	if (!new_node)
 		goto err_node_alloc;
 
@@ -337,20 +423,8 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
 	spin_unlock(&mpp_paths->hashwlock[hash_idx]);
 	read_unlock(&pathtbl_resize_lock);
 	if (grow) {
-		struct mesh_table *oldtbl, *newtbl;
-
-		write_lock(&pathtbl_resize_lock);
-		oldtbl = mpp_paths;
-		newtbl = mesh_table_grow(mpp_paths);
-		if (!newtbl) {
-			write_unlock(&pathtbl_resize_lock);
-			return 0;
-		}
-		rcu_assign_pointer(mpp_paths, newtbl);
-		write_unlock(&pathtbl_resize_lock);
-
-		synchronize_rcu();
-		mesh_table_free(oldtbl, false);
+		set_bit(MESH_WORK_GROW_MPP_TABLE,  &ifmsh->wrkq_flags);
+		ieee80211_queue_work(&local->hw, &ifmsh->work);
 	}
 	return 0;
 
-- 
1.5.4.3


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

end of thread, other threads:[~2009-08-10 19:27 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-08-08  3:38 Mesh fixes and improvements Javier Cardona
2009-08-08  3:38 ` [PATCH 1/8] mac80211: Improve dequeing from mpath frame queue Javier Cardona
2009-08-08  3:38   ` [PATCH 2/8] mac80211: Use correct sign for mesh active path refresh Javier Cardona
2009-08-08  3:38     ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Javier Cardona
2009-08-08  3:38       ` [PATCH 4/8] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
2009-08-08  3:38         ` [PATCH 5/8] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
2009-08-08  3:38           ` [PATCH 6/8] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
2009-08-08  3:38             ` [PATCH 7/8] mac80211: Assign a default mesh beaconing interval Javier Cardona
2009-08-08  3:38               ` [PATCH 8/8] mac80211: Moved mpath and mpp growth to mesh workqueue Javier Cardona
2009-08-08  8:09       ` [PATCH 3/8] mac80211: Simulate transmission losses on plinks to aid in testing mesh metrics Kalle Valo
2009-08-08  8:46         ` Johannes Berg
2009-08-08  9:09 ` Mesh fixes and improvements Johannes Berg
2009-08-09  4:55   ` Javier Cardona
2009-08-10 17:52     ` John W. Linville
2009-08-10 19:15       ` Mesh fixes and improvements [v2] Javier Cardona
2009-08-10 19:15         ` [PATCH 1/7] mac80211: Improve dequeing from mpath frame queue Javier Cardona
2009-08-10 19:15           ` [PATCH 2/7] mac80211: Use correct sign for mesh active path refresh Javier Cardona
2009-08-10 19:15             ` [PATCH 3/7] mac80211: Use 3-address format for mesh broadcast frames Javier Cardona
2009-08-10 19:15               ` [PATCH 4/7] mac80211: Update the station failed frames average when minstrel is used Javier Cardona
2009-08-10 19:15                 ` [PATCH 5/7] mac80211: Early detection of broken mesh paths when using minstrel Javier Cardona
2009-08-10 19:15                   ` [PATCH 6/7] mac80211: Assign a default mesh beaconing interval Javier Cardona
2009-08-10 19:15                     ` [PATCH 7/7] mac80211: Move mpath and mpp growth to mesh workqueue Javier Cardona

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).