b.a.t.m.a.n.lists.open-mesh.org archive mirror
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients
@ 2011-05-05  7:13 Antonio Quartulli
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
                   ` (10 more replies)
  0 siblings, 11 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-05  7:13 UTC (permalink / raw)
  To: B.A.T.M.A.N

Three new features have been added:
1) generic uevent support
2) uevent triggering for gw state changes
3) gw propagation for clients

Patch summary:

- 1/3: a wrapper function that permits to trigger uevents has been added.
The function takes a "type", an "action" and a "data" as parameters which
will be used as uevent attributes. In particular they will respectively be
BATTYPE, BATACTION and BATDATA in the uevent environment.
The "type" and the "action" field are managed using two enum definitions and
two char arrais. Currently the supported "type" is 'gw' only and the supported
"actions" are 'add', 'change' and 'del'. The "data" parameter is a free field
which can be filled by the programmer to send any useful data to the userspace.
Uevents can be seen in userspace with the following command:
	"$ udevadm monitor --property"

- 2/3: on a gateway add/change/del event a corresponding uevent of type 'gw' is
triggered. In particular, in case of setting up a gw for the first time a
uevent with action 'add' is triggered. In case of changing the best gateway a
uevent with action 'change' is triggered. In case of deselection of any gateway
a uevent with action DEL is triggered.

- 3/3: a gw propagation feature for clients has been provided. The main target
of this patch is to make clients able to change L3 gateway as soon as the mesh
node currently serving them changes its default one at the batman layer.
For this target a passive approach has been followed: whenever a unicast
DHCPREQUEST for renewal is sent from a client, the node will inspect it and
check if it is directed to the current default gateway or not. If it is not
the case then the packet is dropped. In this way the client will get a
timeout and a new DHCPREQUEST for discover will be sent giving the possibility
to the node to select the best gw to forward this packet to (current gw
selection mode).


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

* [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
@ 2011-05-05  7:13 ` Antonio Quartulli
  2011-05-05 13:34   ` Andrew Lunn
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-05  7:13 UTC (permalink / raw)
  To: B.A.T.M.A.N

Using throw_uevent() is now possible to trigger uevent signal that can
be recognised in userspace. Uevents will be triggered through the
/devices/virtual/net/{MESH_IFACE} kobject.

A triggered uevent has three properties:
- type: the event class. Who generates the event (only 'gw' is currently
  defined). Corresponds to the BATTYPE uevent variable.
- action: the associated action with the event ('add'/'change'/'del' are
  currently defined). Corresponds to the BAACTION uevent variable.
- data: any useful data for the userspace. Corresponds to the BATDATA
  uevent variable.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 bat_sysfs.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bat_sysfs.h |    4 +++
 main.h      |   11 +++++++++
 3 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/bat_sysfs.c b/bat_sysfs.c
index 497a070..83c0980 100644
--- a/bat_sysfs.c
+++ b/bat_sysfs.c
@@ -32,6 +32,16 @@
 #define kobj_to_netdev(obj)	to_net_dev(to_dev(obj->parent))
 #define kobj_to_batpriv(obj)	netdev_priv(kobj_to_netdev(obj))
 
+static char *uev_action_str[] = {
+	"add",
+	"del",
+	"change"
+};
+
+static char *uev_type_str[] = {
+	"gw"
+};
+
 /* Use this, if you have customized show and store functions */
 #define BAT_ATTR(_name, _mode, _show, _store)	\
 struct bat_attribute bat_attr_##_name = {	\
@@ -594,3 +604,62 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
 	kobject_put(*hardif_obj);
 	*hardif_obj = NULL;
 }
+
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data)
+{
+	int ret = -1;
+	struct hard_iface *primary_if = NULL;
+	struct kobject *bat_kobj;
+	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
+
+	primary_if = primary_if_get_selected(bat_priv);
+	if (!primary_if)
+		goto out;
+
+	bat_kobj = &primary_if->soft_iface->dev.kobj;
+
+	uevent_env[0] = kmalloc(strlen("BATTYPE=") +
+				strlen(uev_type_str[type]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[0])
+		goto out;
+
+	sprintf(uevent_env[0], "BATTYPE=%s", uev_type_str[type]);
+
+	uevent_env[1] = kmalloc(strlen("BATACTION=") +
+				strlen(uev_action_str[action]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[1])
+		goto out;
+
+	sprintf(uevent_env[1], "BATACTION=%s", uev_action_str[action]);
+
+	/* If the event is DEL, ignore the data field */
+	if (action == UEV_DEL)
+		goto throw;
+
+	uevent_env[2] = kmalloc(strlen("BATDATA=") +
+				strlen(data) + 1, GFP_ATOMIC);
+	if (!uevent_env[2])
+		goto out;
+
+	sprintf(uevent_env[2], "BATDATA=%s", data);
+
+throw:
+	ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
+out:
+	kfree(uevent_env[0]);
+	kfree(uevent_env[1]);
+	kfree(uevent_env[2]);
+
+	if (primary_if)
+		hardif_free_ref(primary_if);
+
+	if (ret)
+		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
+			"uevent for (%s,%s,%s) event\n",
+			uev_type_str[type], uev_action_str[action],
+			(action == UEV_DEL ? "NULL" : data));
+	return ret;
+}
diff --git a/bat_sysfs.h b/bat_sysfs.h
index 02f1fa7..2b1a1d0 100644
--- a/bat_sysfs.h
+++ b/bat_sysfs.h
@@ -26,6 +26,8 @@
 #define SYSFS_IF_MESH_SUBDIR "mesh"
 #define SYSFS_IF_BAT_SUBDIR "batman_adv"
 
+struct bat_priv;
+
 struct bat_attribute {
 	struct attribute attr;
 	ssize_t (*show)(struct kobject *kobj, struct attribute *attr,
@@ -38,5 +40,7 @@ int sysfs_add_meshif(struct net_device *dev);
 void sysfs_del_meshif(struct net_device *dev);
 int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
 void sysfs_del_hardif(struct kobject **hardif_obj);
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data);
 
 #endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/main.h b/main.h
index 101d9dc..0dfb46e 100644
--- a/main.h
+++ b/main.h
@@ -78,6 +78,17 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
+
+enum uev_action {
+	UEV_ADD = 0,
+	UEV_DEL,
+	UEV_CHANGE
+};
+
+enum uev_type {
+	UEV_GW = 0
+};
+
 /*
  * Debug Messages
  */
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCH 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
@ 2011-05-05  7:13 ` Antonio Quartulli
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-05  7:13 UTC (permalink / raw)
  To: B.A.T.M.A.N

In case of new default gw, changing the default gw or deleting the default gw a
uevent is triggered with type=gw, action=add/change/del and
data={GW_ORIG_ADDRESS} (if any).

The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 gateway_client.c |   31 ++++++++++++++++++++++++-------
 main.c           |    1 +
 types.h          |    1 +
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 65f3953..8a7090c 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -20,6 +20,7 @@
  */
 
 #include "main.h"
+#include "bat_sysfs.h"
 #include "gateway_client.h"
 #include "gateway_common.h"
 #include "hard-interface.h"
@@ -105,17 +106,18 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 
 void gw_deselect(struct bat_priv *bat_priv)
 {
-	gw_select(bat_priv, NULL);
+	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
 void gw_election(struct bat_priv *bat_priv)
 {
 	struct hlist_node *node;
 	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
-	struct neigh_node *router;
+	struct neigh_node *router = NULL;
 	uint8_t max_tq = 0;
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
 	int down, up;
+	char gw_addr[18] = { '\0' };
 
 	/**
 	 * The batman daemon checks here if we already passed a full originator
@@ -127,7 +129,7 @@ void gw_election(struct bat_priv *bat_priv)
 		return;
 
 	curr_gw = gw_get_selected_gw_node(bat_priv);
-	if (curr_gw)
+	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
 		goto out;
 
 	rcu_read_lock();
@@ -186,9 +188,8 @@ void gw_election(struct bat_priv *bat_priv)
 	}
 
 	if (curr_gw != curr_gw_tmp) {
-		router = orig_node_get_router(curr_gw_tmp->orig_node);
-		if (!router)
-			goto unlock;
+		if (curr_gw_tmp)
+			router = orig_node_get_router(curr_gw_tmp->orig_node);
 
 		if ((curr_gw) && (!curr_gw_tmp))
 			bat_dbg(DBG_BATMAN, bat_priv,
@@ -209,8 +210,24 @@ void gw_election(struct bat_priv *bat_priv)
 				curr_gw_tmp->orig_node->gw_flags,
 				router->tq_avg);
 
-		neigh_node_free_ref(router);
+		if (router)
+			neigh_node_free_ref(router);
 		gw_select(bat_priv, curr_gw_tmp);
+		rcu_read_unlock();
+
+		/* Throw the gateway event to the userspace */
+		if (!curr_gw_tmp) {
+			throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+			goto out;
+		}
+
+		sprintf(gw_addr, "%pM", curr_gw_tmp->orig_node->orig);
+
+		if (curr_gw)
+			throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+		else
+			throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+		goto out;
 	}
 
 unlock:
diff --git a/main.c b/main.c
index 7edf8d7..792f682 100644
--- a/main.c
+++ b/main.c
@@ -111,6 +111,7 @@ int mesh_init(struct net_device *soft_iface)
 	if (vis_init(bat_priv) < 1)
 		goto err;
 
+	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 	goto end;
 
diff --git a/types.h b/types.h
index 9ae507a..e1f22b0 100644
--- a/types.h
+++ b/types.h
@@ -173,6 +173,7 @@ struct bat_priv {
 	struct delayed_work orig_work;
 	struct delayed_work vis_work;
 	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
+	atomic_t gw_reselect;
 	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct vis_info *my_vis_info;
 };
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
@ 2011-05-05  7:13 ` Antonio Quartulli
  2011-05-05 13:46   ` Andrew Lunn
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-05  7:13 UTC (permalink / raw)
  To: B.A.T.M.A.N

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 gateway_client.c |   28 ++++++++++++++++++++++++++--
 gateway_client.h |    3 ++-
 main.h           |    3 ++-
 soft-interface.c |   10 ++++++++--
 4 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 8a7090c..6b3b775 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,6 +25,7 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
@@ -505,14 +506,17 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr, *neigh_old;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -580,7 +584,27 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point it can only be a renewal packet (because it is the
+	 * only dhcp client message sent as unicast) and we have to decide
+	 * whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		/* If the dhcp packet has been sent to a different gw, we have
+		 * to evaluate whether the old gw is still enough reliable */
+		neigh_curr = find_router(bat_priv, curr_gw->orig_node, NULL);
+		neigh_old = find_router(bat_priv, old_gw, NULL);
+		if (!neigh_curr || !neigh_old)
+			goto free_neigh;
+		if (neigh_curr->tq_avg - neigh_old->tq_avg < GW_THRESHOLD)
+			ret = -1;
+free_neigh:
+		if (neigh_old)
+			neigh_node_free_ref(neigh_old);
+		if (neigh_curr)
+			neigh_node_free_ref(neigh_curr);
+	}
+
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 0dfb46e..b59bfad 100644
--- a/main.h
+++ b/main.h
@@ -78,7 +78,6 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -89,6 +88,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	25
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index 8023c4e..79d4012 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -569,6 +570,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -603,8 +605,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* TODO: check this for locks */
 	hna_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -612,6 +616,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret == 0)
 			do_bcast = true;
 	}
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-- 
1.7.3.4


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

* Re: [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
@ 2011-05-05 13:34   ` Andrew Lunn
  2011-05-08 19:21     ` Antonio Quartulli
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2011-05-05 13:34 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Thu, May 05, 2011 at 09:13:07AM +0200, Antonio Quartulli wrote:
> Using throw_uevent() is now possible to trigger uevent signal that can
> be recognised in userspace. Uevents will be triggered through the
> /devices/virtual/net/{MESH_IFACE} kobject.
> 
> A triggered uevent has three properties:
> - type: the event class. Who generates the event (only 'gw' is currently
>   defined). Corresponds to the BATTYPE uevent variable.
> - action: the associated action with the event ('add'/'change'/'del' are
>   currently defined). Corresponds to the BAACTION uevent variable.
> - data: any useful data for the userspace. Corresponds to the BATDATA
>   uevent variable.
> 
> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
> ---
>  bat_sysfs.c |   69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  bat_sysfs.h |    4 +++
>  main.h      |   11 +++++++++
>  3 files changed, 84 insertions(+), 0 deletions(-)
> 
> diff --git a/bat_sysfs.c b/bat_sysfs.c
> index 497a070..83c0980 100644
> --- a/bat_sysfs.c
> +++ b/bat_sysfs.c
> @@ -32,6 +32,16 @@
>  #define kobj_to_netdev(obj)	to_net_dev(to_dev(obj->parent))
>  #define kobj_to_batpriv(obj)	netdev_priv(kobj_to_netdev(obj))
>  
> +static char *uev_action_str[] = {
> +	"add",
> +	"del",
> +	"change"
> +};
> +
> +static char *uev_type_str[] = {
> +	"gw"
> +};
> +
>  /* Use this, if you have customized show and store functions */
>  #define BAT_ATTR(_name, _mode, _show, _store)	\
>  struct bat_attribute bat_attr_##_name = {	\
> @@ -594,3 +604,62 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
>  	kobject_put(*hardif_obj);
>  	*hardif_obj = NULL;
>  }
> +
> +int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
> +		 enum uev_action action, char *data)
> +{
> +	int ret = -1;
> +	struct hard_iface *primary_if = NULL;
> +	struct kobject *bat_kobj;
> +	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
> +
> +	primary_if = primary_if_get_selected(bat_priv);
> +	if (!primary_if)
> +		goto out;
> +
> +	bat_kobj = &primary_if->soft_iface->dev.kobj;
> +
> +	uevent_env[0] = kmalloc(strlen("BATTYPE=") +
> +				strlen(uev_type_str[type]) + 1,
> +				GFP_ATOMIC);
> +	if (!uevent_env[0])
> +		goto out;
> +
> +	sprintf(uevent_env[0], "BATTYPE=%s", uev_type_str[type]);

Hi Antonio

I don't particularly like having BATTYPE= twice, once in the kmalloc
and a second time in the sprintf. Maybe somebody will decide that
BATUTYPE is a better name, change the sprintf, forget about the
kmalloc, and overflow the allocated memory by one byte. snprintf will
prevent the corruption. I've made this sort of stupid error myself,
and it takes longer to debug than to write a bit more defensive code
which prevents the error.

> +
> +	uevent_env[1] = kmalloc(strlen("BATACTION=") +
> +				strlen(uev_action_str[action]) + 1,
> +				GFP_ATOMIC);
> +	if (!uevent_env[1])
> +		goto out;
> +
> +	sprintf(uevent_env[1], "BATACTION=%s", uev_action_str[action]);
> +
> +	/* If the event is DEL, ignore the data field */
> +	if (action == UEV_DEL)
> +		goto throw;

I would replace this goto with a plain if statement. 

> +
> +	uevent_env[2] = kmalloc(strlen("BATDATA=") +
> +				strlen(data) + 1, GFP_ATOMIC);
> +	if (!uevent_env[2])
> +		goto out;
> +
> +	sprintf(uevent_env[2], "BATDATA=%s", data);
> +
> +throw:
> +	ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
> +out:
> +	kfree(uevent_env[0]);
> +	kfree(uevent_env[1]);
> +	kfree(uevent_env[2]);
> +
> +	if (primary_if)
> +		hardif_free_ref(primary_if);
> +
> +	if (ret)
> +		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
> +			"uevent for (%s,%s,%s) event\n",
> +			uev_type_str[type], uev_action_str[action],
> +			(action == UEV_DEL ? "NULL" : data));

The value of ret could be interesting here, especially if kobject_uevent_env() failed.

> +	return ret;
> +}

  Andrew

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

* Re: [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
@ 2011-05-05 13:46   ` Andrew Lunn
  2011-05-08 20:57     ` Antonio Quartulli
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2011-05-05 13:46 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Thu, May 05, 2011 at 09:13:09AM +0200, Antonio Quartulli wrote:
> +	/* If old_gw != NULL then this packet is unicast.
> +	 * So, at this point it can only be a renewal packet (because it is the
> +	 * only dhcp client message sent as unicast) and we have to decide
> +	 * whether to drop it or not */

What about the release message? Is that not also unicast? 

> +	if (old_gw && curr_gw->orig_node != old_gw) {
> +		/* If the dhcp packet has been sent to a different gw, we have
> +		 * to evaluate whether the old gw is still enough reliable */

still reliable enough.

      Andrew

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

* Re: [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-05 13:34   ` Andrew Lunn
@ 2011-05-08 19:21     ` Antonio Quartulli
  2011-05-08 20:11       ` Andrew Lunn
  0 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-08 19:21 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On gio, mag 05, 2011 at 03:34:24 +0200, Andrew Lunn wrote:
> > +	uevent_env[0] = kmalloc(strlen("BATTYPE=") +
> > +				strlen(uev_type_str[type]) + 1,
> > +				GFP_ATOMIC);
> > +	if (!uevent_env[0])
> > +		goto out;
> > +
> > +	sprintf(uevent_env[0], "BATTYPE=%s", uev_type_str[type]);
> 
> Hi Antonio
> 

Hi Andrew,

> I don't particularly like having BATTYPE= twice, once in the kmalloc
> and a second time in the sprintf. Maybe somebody will decide that
> BATUTYPE is a better name, change the sprintf, forget about the
> kmalloc, and overflow the allocated memory by one byte. snprintf will
> prevent the corruption. I've made this sort of stupid error myself,
> and it takes longer to debug than to write a bit more defensive code
> which prevents the error.

I definitely agree. I thin that using a define like
#define UEV_TYPE_VAR "BATTYPE="
would be more elegant.
In this case I can avoid to use snprintf. Do you agree on this?

> > +	/* If the event is DEL, ignore the data field */
> > +	if (action == UEV_DEL)
> > +		goto throw;
> 
> I would replace this goto with a plain if statement. 

Mh..ok. I abused of this if->goto style even if not really needed

> > +	if (ret)
> > +		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
> > +			"uevent for (%s,%s,%s) event\n",
> > +			uev_type_str[type], uev_action_str[action],
> > +			(action == UEV_DEL ? "NULL" : data));
> 
> The value of ret could be interesting here, especially if kobject_uevent_env() failed.

Mh, Ok. I can print it into the message. Is there a function in the kernel to
transform it in a proper string?

Thank you very much.

Regards,

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

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

* Re: [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-08 19:21     ` Antonio Quartulli
@ 2011-05-08 20:11       ` Andrew Lunn
  2011-05-08 20:13         ` Antonio Quartulli
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2011-05-08 20:11 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

> I definitely agree. I thin that using a define like
> #define UEV_TYPE_VAR "BATTYPE="
> would be more elegant.
> In this case I can avoid to use snprintf. Do you agree on this?

Yes, that is safer. 
 
> > > +	if (ret)
> > > +		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
> > > +			"uevent for (%s,%s,%s) event\n",
> > > +			uev_type_str[type], uev_action_str[action],
> > > +			(action == UEV_DEL ? "NULL" : data));
> > 
> > The value of ret could be interesting here, especially if kobject_uevent_env() failed.
> 
> Mh, Ok. I can print it into the message. Is there a function in the kernel to
> transform it in a proper string?

I don't think so. At least i cannot find a kstrerror(). It is messy,
since each architecture can define its own numbers for the
symbols. Most don't and use asm-generic/errno.h, but Sparc for example
has an errno.h which is compatible to SunOS.

Just print the decimal value. Anybody who is competent enough to debug
the code should be able to map a value back to a symbol.

    Andrew

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

* Re: [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-08 20:11       ` Andrew Lunn
@ 2011-05-08 20:13         ` Antonio Quartulli
  0 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-08 20:13 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On dom, mag 08, 2011 at 10:11:48 +0200, Andrew Lunn wrote:
> > I definitely agree. I thin that using a define like
> > #define UEV_TYPE_VAR "BATTYPE="
> > would be more elegant.
> > In this case I can avoid to use snprintf. Do you agree on this?
> 
> Yes, that is safer. 
>  
> > > > +	if (ret)
> > > > +		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
> > > > +			"uevent for (%s,%s,%s) event\n",
> > > > +			uev_type_str[type], uev_action_str[action],
> > > > +			(action == UEV_DEL ? "NULL" : data));
> > > 
> > > The value of ret could be interesting here, especially if kobject_uevent_env() failed.
> > 
> > Mh, Ok. I can print it into the message. Is there a function in the kernel to
> > transform it in a proper string?
> 
> I don't think so. At least i cannot find a kstrerror(). It is messy,
> since each architecture can define its own numbers for the
> symbols. Most don't and use asm-generic/errno.h, but Sparc for example
> has an errno.h which is compatible to SunOS.
> 
> Just print the decimal value. Anybody who is competent enough to debug
> the code should be able to map a value back to a symbol.
> 

Ok!


Thanks again,

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

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

* Re: [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05 13:46   ` Andrew Lunn
@ 2011-05-08 20:57     ` Antonio Quartulli
  0 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-08 20:57 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On gio, mag 05, 2011 at 03:46:49 +0200, Andrew Lunn wrote:
> On Thu, May 05, 2011 at 09:13:09AM +0200, Antonio Quartulli wrote:
> > +	/* If old_gw != NULL then this packet is unicast.
> > +	 * So, at this point it can only be a renewal packet (because it is the
> > +	 * only dhcp client message sent as unicast) and we have to decide
> > +	 * whether to drop it or not */
> 
> What about the release message? Is that not also unicast? 
> 

You are right (dhcpdecline is unicast too).
I have to inspect the dhcp header and look at the message type option.

> > +	if (old_gw && curr_gw->orig_node != old_gw) {
> > +		/* If the dhcp packet has been sent to a different gw, we have
> > +		 * to evaluate whether the old gw is still enough reliable */
> 
> still reliable enough.
> 

Thanks!

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

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

* [B.A.T.M.A.N.] [PATCHv2 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (2 preceding siblings ...)
  2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
@ 2011-05-09  9:52 ` Antonio Quartulli
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09  9:52 UTC (permalink / raw)
  To: B.A.T.M.A.N

Using throw_uevent() is now possible to trigger uevent signal that can
be recognised in userspace. Uevents will be triggered through the
/devices/virtual/net/{MESH_IFACE} kobject.

A triggered uevent has three properties:
- type: the event class. Who generates the event (only 'gw' is currently
  defined). Corresponds to the BATTYPE uevent variable.
- action: the associated action with the event ('add'/'change'/'del' are
  currently defined). Corresponds to the BAACTION uevent variable.
- data: any useful data for the userspace. Corresponds to the BATDATA
  uevent variable.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 1) BAT*= strings have been substituted by macros.
 2) the return value of kobject_uevent is now included in the error message
 
 bat_sysfs.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bat_sysfs.h |    2 +
 main.h      |   11 +++++++++
 3 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/bat_sysfs.c b/bat_sysfs.c
index 497a070..5bb9b34 100644
--- a/bat_sysfs.c
+++ b/bat_sysfs.c
@@ -32,6 +32,20 @@
 #define kobj_to_netdev(obj)	to_net_dev(to_dev(obj->parent))
 #define kobj_to_batpriv(obj)	netdev_priv(kobj_to_netdev(obj))
 
+#define UEV_TYPE_VAR	"BATTYPE="
+#define UEV_ACTION_VAR	"BATACTION="
+#define UEV_DATA_VAR	"BATDATA="
+
+static char *uev_action_str[] = {
+	"add",
+	"del",
+	"change"
+};
+
+static char *uev_type_str[] = {
+	"gw"
+};
+
 /* Use this, if you have customized show and store functions */
 #define BAT_ATTR(_name, _mode, _show, _store)	\
 struct bat_attribute bat_attr_##_name = {	\
@@ -594,3 +608,60 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
 	kobject_put(*hardif_obj);
 	*hardif_obj = NULL;
 }
+
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data)
+{
+	int ret = -1;
+	struct hard_iface *primary_if = NULL;
+	struct kobject *bat_kobj;
+	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
+
+	primary_if = primary_if_get_selected(bat_priv);
+	if (!primary_if)
+		goto out;
+
+	bat_kobj = &primary_if->soft_iface->dev.kobj;
+
+	uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
+				strlen(uev_type_str[type]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[0])
+		goto out;
+
+	sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
+
+	uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
+				strlen(uev_action_str[action]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[1])
+		goto out;
+
+	sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
+
+	/* If the event is DEL, ignore the data field */
+	if (action != UEV_DEL) {
+		uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
+					strlen(data) + 1, GFP_ATOMIC);
+		if (!uevent_env[2])
+			goto out;
+
+		sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
+	}
+
+	ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
+out:
+	kfree(uevent_env[0]);
+	kfree(uevent_env[1]);
+	kfree(uevent_env[2]);
+
+	if (primary_if)
+		hardif_free_ref(primary_if);
+
+	if (ret)
+		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
+			"uevent for (%s,%s,%s) event (err: %d)\n",
+			uev_type_str[type], uev_action_str[action],
+			(action == UEV_DEL ? "NULL" : data), ret);
+	return ret;
+}
diff --git a/bat_sysfs.h b/bat_sysfs.h
index 02f1fa7..e48ed9a 100644
--- a/bat_sysfs.h
+++ b/bat_sysfs.h
@@ -38,5 +38,7 @@ int sysfs_add_meshif(struct net_device *dev);
 void sysfs_del_meshif(struct net_device *dev);
 int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
 void sysfs_del_hardif(struct kobject **hardif_obj);
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data);
 
 #endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/main.h b/main.h
index 3ca3941..4f9991d 100644
--- a/main.h
+++ b/main.h
@@ -79,6 +79,17 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
+
+enum uev_action {
+	UEV_ADD = 0,
+	UEV_DEL,
+	UEV_CHANGE
+};
+
+enum uev_type {
+	UEV_GW = 0
+};
+
 /*
  * Debug Messages
  */
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv2 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (3 preceding siblings ...)
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
@ 2011-05-09  9:52 ` Antonio Quartulli
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09  9:52 UTC (permalink / raw)
  To: B.A.T.M.A.N

In case of new default gw, changing the default gw or deleting the default gw a
uevent is triggered with type=gw, action=add/change/del and
data={GW_ORIG_ADDRESS} (if any).

The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 gateway_client.c |   31 ++++++++++++++++++++++++-------
 main.c           |    1 +
 types.h          |    1 +
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 65f3953..8a7090c 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -20,6 +20,7 @@
  */
 
 #include "main.h"
+#include "bat_sysfs.h"
 #include "gateway_client.h"
 #include "gateway_common.h"
 #include "hard-interface.h"
@@ -105,17 +106,18 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 
 void gw_deselect(struct bat_priv *bat_priv)
 {
-	gw_select(bat_priv, NULL);
+	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
 void gw_election(struct bat_priv *bat_priv)
 {
 	struct hlist_node *node;
 	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
-	struct neigh_node *router;
+	struct neigh_node *router = NULL;
 	uint8_t max_tq = 0;
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
 	int down, up;
+	char gw_addr[18] = { '\0' };
 
 	/**
 	 * The batman daemon checks here if we already passed a full originator
@@ -127,7 +129,7 @@ void gw_election(struct bat_priv *bat_priv)
 		return;
 
 	curr_gw = gw_get_selected_gw_node(bat_priv);
-	if (curr_gw)
+	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
 		goto out;
 
 	rcu_read_lock();
@@ -186,9 +188,8 @@ void gw_election(struct bat_priv *bat_priv)
 	}
 
 	if (curr_gw != curr_gw_tmp) {
-		router = orig_node_get_router(curr_gw_tmp->orig_node);
-		if (!router)
-			goto unlock;
+		if (curr_gw_tmp)
+			router = orig_node_get_router(curr_gw_tmp->orig_node);
 
 		if ((curr_gw) && (!curr_gw_tmp))
 			bat_dbg(DBG_BATMAN, bat_priv,
@@ -209,8 +210,24 @@ void gw_election(struct bat_priv *bat_priv)
 				curr_gw_tmp->orig_node->gw_flags,
 				router->tq_avg);
 
-		neigh_node_free_ref(router);
+		if (router)
+			neigh_node_free_ref(router);
 		gw_select(bat_priv, curr_gw_tmp);
+		rcu_read_unlock();
+
+		/* Throw the gateway event to the userspace */
+		if (!curr_gw_tmp) {
+			throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+			goto out;
+		}
+
+		sprintf(gw_addr, "%pM", curr_gw_tmp->orig_node->orig);
+
+		if (curr_gw)
+			throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+		else
+			throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+		goto out;
 	}
 
 unlock:
diff --git a/main.c b/main.c
index 0a7cee0..ca060a9 100644
--- a/main.c
+++ b/main.c
@@ -111,6 +111,7 @@ int mesh_init(struct net_device *soft_iface)
 	if (vis_init(bat_priv) < 1)
 		goto err;
 
+	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 	goto end;
 
diff --git a/types.h b/types.h
index fab70e8..87b890e 100644
--- a/types.h
+++ b/types.h
@@ -173,6 +173,7 @@ struct bat_priv {
 	struct delayed_work orig_work;
 	struct delayed_work vis_work;
 	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
+	atomic_t gw_reselect;
 	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct vis_info *my_vis_info;
 };
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv2 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (4 preceding siblings ...)
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
@ 2011-05-09  9:52 ` Antonio Quartulli
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09  9:52 UTC (permalink / raw)
  To: B.A.T.M.A.N

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
1) Following Andrew's suggestion, the dhcp unicast packet type is now checked
   to ensure it is a DHCPREQUEST.

2) Comments corrections

Thanks

 gateway_client.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gateway_client.h |    3 +-
 main.h           |    3 +-
 soft-interface.c |   10 ++++-
 4 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 8a7090c..da2bc8d 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,11 +25,17 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
 static void gw_node_free_rcu(struct rcu_head *rcu)
 {
 	struct gw_node *gw_node;
@@ -505,14 +511,75 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+	int ret = false;
+	unsigned char *p;
+	int pkt_len;
+
+	if (skb_linearize(skb) < 0)
+		goto out;
+
+	pkt_len = skb_headlen(skb);
+
+	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+		goto out;
+
+	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+	/* Access the dhcp option lists. Each entry is made up by:
+	 * - octect 1: option type
+	 * - octect 2: option data len (only if type != 255 and 0)
+	 * - octect 3: option data */
+	while (*p != 255 && !ret) {
+		/* p now points to the first octect: option type */
+		if (*p == 53) {
+			/* type 53 is the message type option.
+			 * Jump the len octect and go to the data octect */
+			if (pkt_len < 2)
+				goto out;
+			pkt_len -= 2;
+			p += 2;
+
+			/* check if the message type is what we need */
+			if (*p == DHCP_REQUEST)
+				ret = true;
+		} else if (*p == 0) {
+			/* option type 0 (padding), just go forward */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+		} else {
+			/* This is any other option. So we get the length... */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+
+			/* ...and then we jump over the data */
+			if (pkt_len < *p)
+				goto out;
+			pkt_len -= *p;
+			p += (*p);
+		}
+	}
+out:
+	return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -580,7 +647,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point we have to check the message type: if it is a
+	 * DHCPREQUEST we have to decide whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		if (is_type_dhcprequest(skb, header_len)) {
+			/* If the dhcp packet has been sent to a different gw,
+			 * we have to evaluate whether the old gw is still
+			 * reliable enough */
+			neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+						 NULL);
+			neigh_old = find_router(bat_priv, old_gw, NULL);
+			if (!neigh_curr || !neigh_old)
+				goto free_neigh;
+			if (neigh_curr->tq_avg - neigh_old->tq_avg <
+								GW_THRESHOLD)
+				ret = -1;
+		}
+	}
+free_neigh:
+	if (neigh_old)
+		neigh_node_free_ref(neigh_old);
+	if (neigh_curr)
+		neigh_node_free_ref(neigh_curr);
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 4f9991d..fbd7d37 100644
--- a/main.h
+++ b/main.h
@@ -79,7 +79,6 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -90,6 +89,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	25
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index c76a33e..6d02d92 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -569,6 +570,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -603,8 +605,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* TODO: check this for locks */
 	tt_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -612,6 +616,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret == 0)
 			do_bcast = true;
 	}
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (5 preceding siblings ...)
  2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
@ 2011-05-09 13:02 ` Antonio Quartulli
  2011-05-10  5:08   ` Andrew Lunn
  2011-06-11 10:07   ` Marek Lindner
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
                   ` (3 subsequent siblings)
  10 siblings, 2 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 13:02 UTC (permalink / raw)
  To: B.A.T.M.A.N

Using throw_uevent() is now possible to trigger uevent signal that can
be recognised in userspace. Uevents will be triggered through the
/devices/virtual/net/{MESH_IFACE} kobject.

A triggered uevent has three properties:
- type: the event class. Who generates the event (only 'gw' is currently
  defined). Corresponds to the BATTYPE uevent variable.
- action: the associated action with the event ('add'/'change'/'del' are
  currently defined). Corresponds to the BAACTION uevent variable.
- data: any useful data for the userspace. Corresponds to the BATDATA
  uevent variable.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 bat_sysfs.c |   71 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bat_sysfs.h |    2 +
 main.h      |   11 +++++++++
 3 files changed, 84 insertions(+), 0 deletions(-)

diff --git a/bat_sysfs.c b/bat_sysfs.c
index 497a070..5bb9b34 100644
--- a/bat_sysfs.c
+++ b/bat_sysfs.c
@@ -32,6 +32,20 @@
 #define kobj_to_netdev(obj)	to_net_dev(to_dev(obj->parent))
 #define kobj_to_batpriv(obj)	netdev_priv(kobj_to_netdev(obj))
 
+#define UEV_TYPE_VAR	"BATTYPE="
+#define UEV_ACTION_VAR	"BATACTION="
+#define UEV_DATA_VAR	"BATDATA="
+
+static char *uev_action_str[] = {
+	"add",
+	"del",
+	"change"
+};
+
+static char *uev_type_str[] = {
+	"gw"
+};
+
 /* Use this, if you have customized show and store functions */
 #define BAT_ATTR(_name, _mode, _show, _store)	\
 struct bat_attribute bat_attr_##_name = {	\
@@ -594,3 +608,60 @@ void sysfs_del_hardif(struct kobject **hardif_obj)
 	kobject_put(*hardif_obj);
 	*hardif_obj = NULL;
 }
+
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data)
+{
+	int ret = -1;
+	struct hard_iface *primary_if = NULL;
+	struct kobject *bat_kobj;
+	char *uevent_env[4] = { NULL, NULL, NULL, NULL };
+
+	primary_if = primary_if_get_selected(bat_priv);
+	if (!primary_if)
+		goto out;
+
+	bat_kobj = &primary_if->soft_iface->dev.kobj;
+
+	uevent_env[0] = kmalloc(strlen(UEV_TYPE_VAR) +
+				strlen(uev_type_str[type]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[0])
+		goto out;
+
+	sprintf(uevent_env[0], "%s%s", UEV_TYPE_VAR, uev_type_str[type]);
+
+	uevent_env[1] = kmalloc(strlen(UEV_ACTION_VAR) +
+				strlen(uev_action_str[action]) + 1,
+				GFP_ATOMIC);
+	if (!uevent_env[1])
+		goto out;
+
+	sprintf(uevent_env[1], "%s%s", UEV_ACTION_VAR, uev_action_str[action]);
+
+	/* If the event is DEL, ignore the data field */
+	if (action != UEV_DEL) {
+		uevent_env[2] = kmalloc(strlen(UEV_DATA_VAR) +
+					strlen(data) + 1, GFP_ATOMIC);
+		if (!uevent_env[2])
+			goto out;
+
+		sprintf(uevent_env[2], "%s%s", UEV_DATA_VAR, data);
+	}
+
+	ret = kobject_uevent_env(bat_kobj, KOBJ_CHANGE, uevent_env);
+out:
+	kfree(uevent_env[0]);
+	kfree(uevent_env[1]);
+	kfree(uevent_env[2]);
+
+	if (primary_if)
+		hardif_free_ref(primary_if);
+
+	if (ret)
+		bat_dbg(DBG_BATMAN, bat_priv, "Impossible to send "
+			"uevent for (%s,%s,%s) event (err: %d)\n",
+			uev_type_str[type], uev_action_str[action],
+			(action == UEV_DEL ? "NULL" : data), ret);
+	return ret;
+}
diff --git a/bat_sysfs.h b/bat_sysfs.h
index 02f1fa7..e48ed9a 100644
--- a/bat_sysfs.h
+++ b/bat_sysfs.h
@@ -38,5 +38,7 @@ int sysfs_add_meshif(struct net_device *dev);
 void sysfs_del_meshif(struct net_device *dev);
 int sysfs_add_hardif(struct kobject **hardif_obj, struct net_device *dev);
 void sysfs_del_hardif(struct kobject **hardif_obj);
+int throw_uevent(struct bat_priv *bat_priv, enum uev_type type,
+		 enum uev_action action, char *data);
 
 #endif /* _NET_BATMAN_ADV_SYSFS_H_ */
diff --git a/main.h b/main.h
index 3ca3941..4f9991d 100644
--- a/main.h
+++ b/main.h
@@ -79,6 +79,17 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
+
+enum uev_action {
+	UEV_ADD = 0,
+	UEV_DEL,
+	UEV_CHANGE
+};
+
+enum uev_type {
+	UEV_GW = 0
+};
+
 /*
  * Debug Messages
  */
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv3 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (6 preceding siblings ...)
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
@ 2011-05-09 13:02 ` Antonio Quartulli
  2011-06-11 10:15   ` [B.A.T.M.A.N.] [PATCHv4 " Marek Lindner
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 13:02 UTC (permalink / raw)
  To: B.A.T.M.A.N

In case of new default gw, changing the default gw or deleting the default gw a
uevent is triggered with type=gw, action=add/change/del and
data={GW_ORIG_ADDRESS} (if any).

The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
a NULL check on "router" in gw_election() has been added

 gateway_client.c |   33 +++++++++++++++++++++++++++------
 main.c           |    1 +
 types.h          |    1 +
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 65f3953..761dcfb 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -20,6 +20,7 @@
  */
 
 #include "main.h"
+#include "bat_sysfs.h"
 #include "gateway_client.h"
 #include "gateway_common.h"
 #include "hard-interface.h"
@@ -105,17 +106,18 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 
 void gw_deselect(struct bat_priv *bat_priv)
 {
-	gw_select(bat_priv, NULL);
+	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
 void gw_election(struct bat_priv *bat_priv)
 {
 	struct hlist_node *node;
 	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
-	struct neigh_node *router;
+	struct neigh_node *router = NULL;
 	uint8_t max_tq = 0;
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
 	int down, up;
+	char gw_addr[18] = { '\0' };
 
 	/**
 	 * The batman daemon checks here if we already passed a full originator
@@ -127,7 +129,7 @@ void gw_election(struct bat_priv *bat_priv)
 		return;
 
 	curr_gw = gw_get_selected_gw_node(bat_priv);
-	if (curr_gw)
+	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
 		goto out;
 
 	rcu_read_lock();
@@ -186,9 +188,12 @@ void gw_election(struct bat_priv *bat_priv)
 	}
 
 	if (curr_gw != curr_gw_tmp) {
-		router = orig_node_get_router(curr_gw_tmp->orig_node);
-		if (!router)
+		if (curr_gw_tmp)
+			router = orig_node_get_router(curr_gw_tmp->orig_node);
+		if (!router) {
+			gw_deselect(bat_priv);
 			goto unlock;
+		}
 
 		if ((curr_gw) && (!curr_gw_tmp))
 			bat_dbg(DBG_BATMAN, bat_priv,
@@ -209,8 +214,24 @@ void gw_election(struct bat_priv *bat_priv)
 				curr_gw_tmp->orig_node->gw_flags,
 				router->tq_avg);
 
-		neigh_node_free_ref(router);
+		if (router)
+			neigh_node_free_ref(router);
 		gw_select(bat_priv, curr_gw_tmp);
+		rcu_read_unlock();
+
+		/* Throw the gateway event to the userspace */
+		if (!curr_gw_tmp) {
+			throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+			goto out;
+		}
+
+		sprintf(gw_addr, "%pM", curr_gw_tmp->orig_node->orig);
+
+		if (curr_gw)
+			throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+		else
+			throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+		goto out;
 	}
 
 unlock:
diff --git a/main.c b/main.c
index 0a7cee0..ca060a9 100644
--- a/main.c
+++ b/main.c
@@ -111,6 +111,7 @@ int mesh_init(struct net_device *soft_iface)
 	if (vis_init(bat_priv) < 1)
 		goto err;
 
+	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 	goto end;
 
diff --git a/types.h b/types.h
index fab70e8..87b890e 100644
--- a/types.h
+++ b/types.h
@@ -173,6 +173,7 @@ struct bat_priv {
 	struct delayed_work orig_work;
 	struct delayed_work vis_work;
 	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
+	atomic_t gw_reselect;
 	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct vis_info *my_vis_info;
 };
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (7 preceding siblings ...)
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
@ 2011-05-09 13:02 ` Antonio Quartulli
  2011-05-09 14:48   ` Andrew Lunn
  2011-05-09 20:30 ` [B.A.T.M.A.N.] [PATCHv4 " Antonio Quartulli
  2011-05-09 21:15 ` [B.A.T.M.A.N.] [PATCHv5 " Antonio Quartulli
  10 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 13:02 UTC (permalink / raw)
  To: B.A.T.M.A.N

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
 gateway_client.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gateway_client.h |    3 +-
 main.h           |    3 +-
 soft-interface.c |   10 ++++-
 4 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 761dcfb..33bceee 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,11 +25,17 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
 static void gw_node_free_rcu(struct rcu_head *rcu)
 {
 	struct gw_node *gw_node;
@@ -509,14 +515,75 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+	int ret = false;
+	unsigned char *p;
+	int pkt_len;
+
+	if (skb_linearize(skb) < 0)
+		goto out;
+
+	pkt_len = skb_headlen(skb);
+
+	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+		goto out;
+
+	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+	/* Access the dhcp option lists. Each entry is made up by:
+	 * - octect 1: option type
+	 * - octect 2: option data len (only if type != 255 and 0)
+	 * - octect 3: option data */
+	while (*p != 255 && !ret) {
+		/* p now points to the first octect: option type */
+		if (*p == 53) {
+			/* type 53 is the message type option.
+			 * Jump the len octect and go to the data octect */
+			if (pkt_len < 2)
+				goto out;
+			pkt_len -= 2;
+			p += 2;
+
+			/* check if the message type is what we need */
+			if (*p == DHCP_REQUEST)
+				ret = true;
+		} else if (*p == 0) {
+			/* option type 0 (padding), just go forward */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+		} else {
+			/* This is any other option. So we get the length... */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+
+			/* ...and then we jump over the data */
+			if (pkt_len < *p)
+				goto out;
+			pkt_len -= *p;
+			p += (*p);
+		}
+	}
+out:
+	return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -584,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point we have to check the message type: if it is a
+	 * DHCPREQUEST we have to decide whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		if (is_type_dhcprequest(skb, header_len)) {
+			/* If the dhcp packet has been sent to a different gw,
+			 * we have to evaluate whether the old gw is still
+			 * reliable enough */
+			neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+						 NULL);
+			neigh_old = find_router(bat_priv, old_gw, NULL);
+			if (!neigh_curr || !neigh_old)
+				goto free_neigh;
+			if (neigh_curr->tq_avg - neigh_old->tq_avg <
+								GW_THRESHOLD)
+				ret = -1;
+		}
+	}
+free_neigh:
+	if (neigh_old)
+		neigh_node_free_ref(neigh_old);
+	if (neigh_curr)
+		neigh_node_free_ref(neigh_curr);
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 4f9991d..fbd7d37 100644
--- a/main.h
+++ b/main.h
@@ -79,7 +79,6 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -90,6 +89,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	25
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index c76a33e..6d02d92 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -569,6 +570,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -603,8 +605,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* TODO: check this for locks */
 	tt_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -612,6 +616,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret == 0)
 			do_bcast = true;
 	}
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-- 
1.7.3.4


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

* Re: [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
@ 2011-05-09 14:48   ` Andrew Lunn
  2011-05-09 20:26     ` Antonio Quartulli
  0 siblings, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2011-05-09 14:48 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Mon, May 09, 2011 at 03:02:30PM +0200, Antonio Quartulli wrote:
> If a client issues a DHCPREQUEST for renewal, the packet is dropped
> if the old destination (the old gateway for the client) TQ is smaller
> than the current best gateway TQ less GW_THRESHOLD
> 
> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
> ---
>  gateway_client.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  gateway_client.h |    3 +-
>  main.h           |    3 +-
>  soft-interface.c |   10 ++++-
>  4 files changed, 104 insertions(+), 6 deletions(-)
> 
> diff --git a/gateway_client.c b/gateway_client.c
> index 761dcfb..33bceee 100644
> --- a/gateway_client.c
> +++ b/gateway_client.c
> @@ -25,11 +25,17 @@
>  #include "gateway_common.h"
>  #include "hard-interface.h"
>  #include "originator.h"
> +#include "routing.h"
>  #include <linux/ip.h>
>  #include <linux/ipv6.h>
>  #include <linux/udp.h>
>  #include <linux/if_vlan.h>
>  
> +/* This is the offset of the options field in a dhcp packet starting at
> + * the beginning of the dhcp header */
> +#define DHCP_OPTIONS_OFFSET 240
> +#define DHCP_REQUEST 3
> +
>  static void gw_node_free_rcu(struct rcu_head *rcu)
>  {
>  	struct gw_node *gw_node;
> @@ -509,14 +515,75 @@ out:
>  	return ret;
>  }
>  
> -int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
> +static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
> +{
> +	int ret = false;
> +	unsigned char *p;
> +	int pkt_len;
> +
> +	if (skb_linearize(skb) < 0)
> +		goto out;
> +
> +	pkt_len = skb_headlen(skb);
> +
> +	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
> +		goto out;
> +
> +	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
> +	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
> +
> +	/* Access the dhcp option lists. Each entry is made up by:
> +	 * - octect 1: option type
> +	 * - octect 2: option data len (only if type != 255 and 0)
> +	 * - octect 3: option data */
> +	while (*p != 255 && !ret) {
> +		/* p now points to the first octect: option type */
> +		if (*p == 53) {
> +			/* type 53 is the message type option.
> +			 * Jump the len octect and go to the data octect */
> +			if (pkt_len < 2)
> +				goto out;
> +			pkt_len -= 2;
> +			p += 2;
> +
> +			/* check if the message type is what we need */
> +			if (*p == DHCP_REQUEST)
> +				ret = true;

Why do you continue parsing the options if it is not a DHCP_REQUEST?
Do you think there will be a second, third, fourth option information
element 53?

	Andrew

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

* Re: [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection
  2011-05-09 14:48   ` Andrew Lunn
@ 2011-05-09 20:26     ` Antonio Quartulli
  0 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 20:26 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

Hi Andrew, hi everyone,

On lun, mag 09, 2011 at 04:48:12 +0200, Andrew Lunn wrote:
> > +	while (*p != 255 && !ret) {
> > +		/* p now points to the first octect: option type */
> > +		if (*p == 53) {
> > +			/* type 53 is the message type option.
> > +			 * Jump the len octect and go to the data octect */
> > +			if (pkt_len < 2)
> > +				goto out;
> > +			pkt_len -= 2;
> > +			p += 2;
> > +
> > +			/* check if the message type is what we need */
> > +			if (*p == DHCP_REQUEST)
> > +				ret = true;
> 
> Why do you continue parsing the options if it is not a DHCP_REQUEST?
> Do you think there will be a second, third, fourth option information
> element 53?

No. There is no reason to continue parsing the options. 
I'll modify the if so that I can exit the while loop as soon as I
find the option 53.

Thanks for finding this detail!

Regards,

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

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

* [B.A.T.M.A.N.] [PATCHv4 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (8 preceding siblings ...)
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
@ 2011-05-09 20:30 ` Antonio Quartulli
  2011-05-09 21:15 ` [B.A.T.M.A.N.] [PATCHv5 " Antonio Quartulli
  10 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 20:30 UTC (permalink / raw)
  To: B.A.T.M.A.N

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
Corrected while loop in is_type_dhcprequest(): if we find option 53, we exit
the loop without going through the rest of the option list.

 gateway_client.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gateway_client.h |    3 +-
 main.h           |    3 +-
 soft-interface.c |   10 ++++-
 4 files changed, 105 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 761dcfb..616d43c 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,11 +25,17 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
 static void gw_node_free_rcu(struct rcu_head *rcu)
 {
 	struct gw_node *gw_node;
@@ -509,14 +515,76 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+	int ret = false;
+	unsigned char *p;
+	int pkt_len;
+
+	if (skb_linearize(skb) < 0)
+		goto out;
+
+	pkt_len = skb_headlen(skb);
+
+	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+		goto out;
+
+	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+	/* Access the dhcp option lists. Each entry is made up by:
+	 * - octect 1: option type
+	 * - octect 2: option data len (only if type != 255 and 0)
+	 * - octect 3: option data */
+	while (*p != 255 && !ret) {
+		/* p now points to the first octect: option type */
+		if (*p == 53) {
+			/* type 53 is the message type option.
+			 * Jump the len octect and go to the data octect */
+			if (pkt_len < 2)
+				goto out;
+			pkt_len -= 2;
+			p += 2;
+
+			/* check if the message type is what we need */
+			if (*p == DHCP_REQUEST)
+				ret = true;
+			break;
+		} else if (*p == 0) {
+			/* option type 0 (padding), just go forward */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+		} else {
+			/* This is any other option. So we get the length... */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+
+			/* ...and then we jump over the data */
+			if (pkt_len < *p)
+				goto out;
+			pkt_len -= *p;
+			p += (*p);
+		}
+	}
+out:
+	return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -584,7 +652,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point we have to check the message type: if it is a
+	 * DHCPREQUEST we have to decide whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		if (is_type_dhcprequest(skb, header_len)) {
+			/* If the dhcp packet has been sent to a different gw,
+			 * we have to evaluate whether the old gw is still
+			 * reliable enough */
+			neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+						 NULL);
+			neigh_old = find_router(bat_priv, old_gw, NULL);
+			if (!neigh_curr || !neigh_old)
+				goto free_neigh;
+			if (neigh_curr->tq_avg - neigh_old->tq_avg <
+								GW_THRESHOLD)
+				ret = -1;
+		}
+	}
+free_neigh:
+	if (neigh_old)
+		neigh_node_free_ref(neigh_old);
+	if (neigh_curr)
+		neigh_node_free_ref(neigh_curr);
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 4f9991d..5b7ad0a 100644
--- a/main.h
+++ b/main.h
@@ -79,7 +79,6 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -90,6 +89,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	50
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index c76a33e..6d02d92 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -569,6 +570,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -603,8 +605,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* TODO: check this for locks */
 	tt_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -612,6 +616,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret == 0)
 			do_bcast = true;
 	}
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-- 
1.7.3.4


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

* [B.A.T.M.A.N.] [PATCHv5 3/3] batman-adv: improved gateway tq-based selection
  2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
                   ` (9 preceding siblings ...)
  2011-05-09 20:30 ` [B.A.T.M.A.N.] [PATCHv4 " Antonio Quartulli
@ 2011-05-09 21:15 ` Antonio Quartulli
  2011-06-11 10:25   ` [B.A.T.M.A.N.] [PATCHv6 " Marek Lindner
  10 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-09 21:15 UTC (permalink / raw)
  To: B.A.T.M.A.N

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
---
Removed a useless decrement in is_type_dhcprequest()

 gateway_client.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gateway_client.h |    3 +-
 main.h           |    3 +-
 soft-interface.c |   10 ++++-
 4 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 761dcfb..3b43781 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,11 +25,17 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
 static void gw_node_free_rcu(struct rcu_head *rcu)
 {
 	struct gw_node *gw_node;
@@ -509,14 +515,75 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+	int ret = false;
+	unsigned char *p;
+	int pkt_len;
+
+	if (skb_linearize(skb) < 0)
+		goto out;
+
+	pkt_len = skb_headlen(skb);
+
+	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+		goto out;
+
+	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+	/* Access the dhcp option lists. Each entry is made up by:
+	 * - octect 1: option type
+	 * - octect 2: option data len (only if type != 255 and 0)
+	 * - octect 3: option data */
+	while (*p != 255 && !ret) {
+		/* p now points to the first octect: option type */
+		if (*p == 53) {
+			/* type 53 is the message type option.
+			 * Jump the len octect and go to the data octect */
+			if (pkt_len < 2)
+				goto out;
+			p += 2;
+
+			/* check if the message type is what we need */
+			if (*p == DHCP_REQUEST)
+				ret = true;
+			break;
+		} else if (*p == 0) {
+			/* option type 0 (padding), just go forward */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+		} else {
+			/* This is any other option. So we get the length... */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+
+			/* ...and then we jump over the data */
+			if (pkt_len < *p)
+				goto out;
+			pkt_len -= *p;
+			p += (*p);
+		}
+	}
+out:
+	return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -584,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point we have to check the message type: if it is a
+	 * DHCPREQUEST we have to decide whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		if (is_type_dhcprequest(skb, header_len)) {
+			/* If the dhcp packet has been sent to a different gw,
+			 * we have to evaluate whether the old gw is still
+			 * reliable enough */
+			neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+						 NULL);
+			neigh_old = find_router(bat_priv, old_gw, NULL);
+			if (!neigh_curr || !neigh_old)
+				goto free_neigh;
+			if (neigh_curr->tq_avg - neigh_old->tq_avg <
+								GW_THRESHOLD)
+				ret = -1;
+		}
+	}
+free_neigh:
+	if (neigh_old)
+		neigh_node_free_ref(neigh_old);
+	if (neigh_curr)
+		neigh_node_free_ref(neigh_curr);
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 4f9991d..5b7ad0a 100644
--- a/main.h
+++ b/main.h
@@ -79,7 +79,6 @@
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -90,6 +89,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	50
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index c76a33e..6d02d92 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -569,6 +570,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -603,8 +605,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* TODO: check this for locks */
 	tt_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -612,6 +616,8 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 		if (ret == 0)
 			do_bcast = true;
 	}
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 
 	/* ethernet packet should be broadcasted */
 	if (do_bcast) {
-- 
1.7.3.4


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

* Re: [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
@ 2011-05-10  5:08   ` Andrew Lunn
  2011-05-10  6:29     ` Antonio Quartulli
  2011-06-11 10:07   ` Marek Lindner
  1 sibling, 1 reply; 30+ messages in thread
From: Andrew Lunn @ 2011-05-10  5:08 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Mon, May 09, 2011 at 03:02:28PM +0200, Antonio Quartulli wrote:
> Using throw_uevent() is now possible to trigger uevent signal that can
> be recognised in userspace. Uevents will be triggered through the
> /devices/virtual/net/{MESH_IFACE} kobject.

Hi Antonio

Since this is part of sysfs you should add a description to
Documentation/networking/batman-adv.txt.

	Andrew

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

* Re: [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-10  5:08   ` Andrew Lunn
@ 2011-05-10  6:29     ` Antonio Quartulli
  2011-06-11 10:10       ` Marek Lindner
  0 siblings, 1 reply; 30+ messages in thread
From: Antonio Quartulli @ 2011-05-10  6:29 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On mar, mag 10, 2011 at 07:08:03 +0200, Andrew Lunn wrote:
> On Mon, May 09, 2011 at 03:02:28PM +0200, Antonio Quartulli wrote:
> > Using throw_uevent() is now possible to trigger uevent signal that can
> > be recognised in userspace. Uevents will be triggered through the
> > /devices/virtual/net/{MESH_IFACE} kobject.
> 
> Hi Antonio
> 
> Since this is part of sysfs you should add a description to
> Documentation/networking/batman-adv.txt.

Ah ok, I didn't know this.
I think Marek already planned to instruct me on this part. Thank you for
reminding me!

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara

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

* Re: [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
  2011-05-10  5:08   ` Andrew Lunn
@ 2011-06-11 10:07   ` Marek Lindner
  1 sibling, 0 replies; 30+ messages in thread
From: Marek Lindner @ 2011-06-11 10:07 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Monday, May 09, 2011 03:02:28 PM Antonio Quartulli wrote:
> Using throw_uevent() is now possible to trigger uevent signal that can
> be recognised in userspace. Uevents will be triggered through the
> /devices/virtual/net/{MESH_IFACE} kobject.
> 
> A triggered uevent has three properties:
> - type: the event class. Who generates the event (only 'gw' is currently
>   defined). Corresponds to the BATTYPE uevent variable.
> - action: the associated action with the event ('add'/'change'/'del' are
>   currently defined). Corresponds to the BAACTION uevent variable.
> - data: any useful data for the userspace. Corresponds to the BATDATA
>   uevent variable.

Applied in revision d2586d6.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-05-10  6:29     ` Antonio Quartulli
@ 2011-06-11 10:10       ` Marek Lindner
  2011-06-11 12:45         ` Antonio Quartulli
  0 siblings, 1 reply; 30+ messages in thread
From: Marek Lindner @ 2011-06-11 10:10 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Tuesday, May 10, 2011 08:29:28 AM Antonio Quartulli wrote:
> > Since this is part of sysfs you should add a description to
> > Documentation/networking/batman-adv.txt.
> 
> Ah ok, I didn't know this.
> I think Marek already planned to instruct me on this part. Thank you for
> reminding me!

I believe we still lack some documentation here or did I overlook something ?

Regards,
Marek

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

* [B.A.T.M.A.N.] [PATCHv4 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
@ 2011-06-11 10:15   ` Marek Lindner
  2011-06-11 10:21     ` [B.A.T.M.A.N.] [PATCHv5 " Marek Lindner
  0 siblings, 1 reply; 30+ messages in thread
From: Marek Lindner @ 2011-06-11 10:15 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner

From: Antonio Quartulli <ordex@autistici.org>

In case of new default gw, changing the default gw or deleting the default gw a
uevent is triggered with type=gw, action=add/change/del and
data={GW_ORIG_ADDRESS} (if any).

The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
* gw_election() code refactored to increase readability
* bug fixed: if curr_gw_tmp is NULL the uevent would never be triggered
  because the variable "router" would also be NULL

 gateway_client.c |  143 ++++++++++++++++++++++++++++++++---------------------
 main.c           |    1 +
 types.h          |    1 +
 3 files changed, 88 insertions(+), 57 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 24aee56..964a27e 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -20,6 +20,7 @@
  */
 
 #include "main.h"
+#include "bat_sysfs.h"
 #include "gateway_client.h"
 #include "gateway_common.h"
 #include "hard-interface.h"
@@ -97,40 +98,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 
 void gw_deselect(struct bat_priv *bat_priv)
 {
-	gw_select(bat_priv, NULL);
+	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
-void gw_election(struct bat_priv *bat_priv)
+static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 {
-	struct hlist_node *node;
-	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
 	struct neigh_node *router;
-	uint8_t max_tq = 0;
+	struct hlist_node *node;
+	struct gw_node *gw_node, *curr_gw = NULL;
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
+	uint8_t max_tq = 0;
 	int down, up;
 
-	/**
-	 * The batman daemon checks here if we already passed a full originator
-	 * cycle in order to make sure we don't choose the first gateway we
-	 * hear about. This check is based on the daemon's uptime which we
-	 * don't have.
-	 **/
-	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
-		return;
-
-	curr_gw = gw_get_selected_gw_node(bat_priv);
-	if (curr_gw)
-		goto out;
-
 	rcu_read_lock();
-	if (hlist_empty(&bat_priv->gw_list)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Removing selected gateway - "
-			"no gateway in range\n");
-		gw_deselect(bat_priv);
-		goto unlock;
-	}
-
 	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
 		if (gw_node->deleted)
 			continue;
@@ -139,6 +119,9 @@ void gw_election(struct bat_priv *bat_priv)
 		if (!router)
 			continue;
 
+		if (!atomic_inc_not_zero(&gw_node->refcount))
+			goto next;
+
 		switch (atomic_read(&bat_priv->gw_sel_class)) {
 		case 1: /* fast connection */
 			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +134,12 @@ void gw_election(struct bat_priv *bat_priv)
 
 			if ((tmp_gw_factor > max_gw_factor) ||
 			    ((tmp_gw_factor == max_gw_factor) &&
-			     (router->tq_avg > max_tq)))
-				curr_gw_tmp = gw_node;
+			     (router->tq_avg > max_tq))) {
+				if (curr_gw)
+					gw_node_free_ref(curr_gw);
+				curr_gw = gw_node;
+				atomic_inc(&curr_gw->refcount);
+			}
 			break;
 
 		default: /**
@@ -163,8 +150,12 @@ void gw_election(struct bat_priv *bat_priv)
 			  *     soon as a better gateway appears which has
 			  *     $routing_class more tq points)
 			  **/
-			if (router->tq_avg > max_tq)
-				curr_gw_tmp = gw_node;
+			if (router->tq_avg > max_tq) {
+				if (curr_gw)
+					gw_node_free_ref(curr_gw);
+				curr_gw = gw_node;
+				atomic_inc(&curr_gw->refcount);
+			}
 			break;
 		}
 
@@ -174,42 +165,80 @@ void gw_election(struct bat_priv *bat_priv)
 		if (tmp_gw_factor > max_gw_factor)
 			max_gw_factor = tmp_gw_factor;
 
+next:
 		neigh_node_free_ref(router);
+		gw_node_free_ref(gw_node);
 	}
+	rcu_read_unlock();
 
-	if (curr_gw != curr_gw_tmp) {
-		router = orig_node_get_router(curr_gw_tmp->orig_node);
-		if (!router)
-			goto unlock;
+	return curr_gw;
+}
 
-		if ((curr_gw) && (!curr_gw_tmp))
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Removing selected gateway - "
-				"no gateway in range\n");
-		else if ((!curr_gw) && (curr_gw_tmp))
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Adding route to gateway %pM "
-				"(gw_flags: %i, tq: %i)\n",
-				curr_gw_tmp->orig_node->orig,
-				curr_gw_tmp->orig_node->gw_flags,
-				router->tq_avg);
-		else
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Changing route to gateway %pM "
-				"(gw_flags: %i, tq: %i)\n",
-				curr_gw_tmp->orig_node->orig,
-				curr_gw_tmp->orig_node->gw_flags,
-				router->tq_avg);
+void gw_election(struct bat_priv *bat_priv)
+{
+	struct gw_node *curr_gw = NULL, *next_gw = NULL;
+	struct neigh_node *router = NULL;
+	char gw_addr[18] = { '\0' };
 
-		neigh_node_free_ref(router);
-		gw_select(bat_priv, curr_gw_tmp);
+	/**
+	 * The batman daemon checks here if we already passed a full originator
+	 * cycle in order to make sure we don't choose the first gateway we
+	 * hear about. This check is based on the daemon's uptime which we
+	 * don't have.
+	 **/
+	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
+		goto out;
+
+	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
+		goto out;
+
+	curr_gw = gw_get_selected_gw_node(bat_priv);
+
+	next_gw = gw_get_best_gw_node(bat_priv);
+
+	if (curr_gw == next_gw)
+		goto out;
+
+	if (next_gw) {
+		sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
+
+		router = orig_node_get_router(next_gw->orig_node);
+		if (!router) {
+			gw_deselect(bat_priv);
+			goto out;
+		}
 	}
 
-unlock:
-	rcu_read_unlock();
+	if ((curr_gw) && (!next_gw)) {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Removing selected gateway - no gateway in range\n");
+		throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+	} else if ((!curr_gw) && (next_gw)) {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+			next_gw->orig_node->orig,
+			next_gw->orig_node->gw_flags,
+			router->tq_avg);
+		throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+	} else {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Changing route to gateway %pM "
+			"(gw_flags: %i, tq: %i)\n",
+			next_gw->orig_node->orig,
+			next_gw->orig_node->gw_flags,
+			router->tq_avg);
+		throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+	}
+
+	gw_select(bat_priv, next_gw);
+
 out:
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
+	if (next_gw)
+		gw_node_free_ref(next_gw);
+	if (router)
+		neigh_node_free_ref(router);
 }
 
 void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
diff --git a/main.c b/main.c
index c2b06b7..e367e69 100644
--- a/main.c
+++ b/main.c
@@ -113,6 +113,7 @@ int mesh_init(struct net_device *soft_iface)
 	if (vis_init(bat_priv) < 1)
 		goto err;
 
+	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 	goto end;
 
diff --git a/types.h b/types.h
index 11e8569..85cf122 100644
--- a/types.h
+++ b/types.h
@@ -201,6 +201,7 @@ struct bat_priv {
 	struct delayed_work orig_work;
 	struct delayed_work vis_work;
 	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
+	atomic_t gw_reselect;
 	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct vis_info *my_vis_info;
 };
-- 
1.7.5.3


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

* [B.A.T.M.A.N.] [PATCHv5 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-06-11 10:15   ` [B.A.T.M.A.N.] [PATCHv4 " Marek Lindner
@ 2011-06-11 10:21     ` Marek Lindner
  2011-06-12 10:09       ` Marek Lindner
  0 siblings, 1 reply; 30+ messages in thread
From: Marek Lindner @ 2011-06-11 10:21 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner

From: Antonio Quartulli <ordex@autistici.org>

In case of new default gw, changing the default gw or deleting the default gw a
uevent is triggered with type=gw, action=add/change/del and
data={GW_ORIG_ADDRESS} (if any).

The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
* gw_get_best_gw_node() should not call gw_node_free_ref() if 
  atomic_inc_not_zero() failed

 gateway_client.c |  148 ++++++++++++++++++++++++++++++++---------------------
 main.c           |    1 +
 types.h          |    1 +
 3 files changed, 91 insertions(+), 59 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 24aee56..64505ee 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -20,6 +20,7 @@
  */
 
 #include "main.h"
+#include "bat_sysfs.h"
 #include "gateway_client.h"
 #include "gateway_common.h"
 #include "hard-interface.h"
@@ -97,40 +98,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)
 
 void gw_deselect(struct bat_priv *bat_priv)
 {
-	gw_select(bat_priv, NULL);
+	atomic_set(&bat_priv->gw_reselect, 1);
 }
 
-void gw_election(struct bat_priv *bat_priv)
+static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
 {
-	struct hlist_node *node;
-	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
 	struct neigh_node *router;
-	uint8_t max_tq = 0;
+	struct hlist_node *node;
+	struct gw_node *gw_node, *curr_gw = NULL;
 	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
+	uint8_t max_tq = 0;
 	int down, up;
 
-	/**
-	 * The batman daemon checks here if we already passed a full originator
-	 * cycle in order to make sure we don't choose the first gateway we
-	 * hear about. This check is based on the daemon's uptime which we
-	 * don't have.
-	 **/
-	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
-		return;
-
-	curr_gw = gw_get_selected_gw_node(bat_priv);
-	if (curr_gw)
-		goto out;
-
 	rcu_read_lock();
-	if (hlist_empty(&bat_priv->gw_list)) {
-		bat_dbg(DBG_BATMAN, bat_priv,
-			"Removing selected gateway - "
-			"no gateway in range\n");
-		gw_deselect(bat_priv);
-		goto unlock;
-	}
-
 	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
 		if (gw_node->deleted)
 			continue;
@@ -139,6 +119,9 @@ void gw_election(struct bat_priv *bat_priv)
 		if (!router)
 			continue;
 
+		if (!atomic_inc_not_zero(&gw_node->refcount))
+			goto next;
+
 		switch (atomic_read(&bat_priv->gw_sel_class)) {
 		case 1: /* fast connection */
 			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +134,12 @@ void gw_election(struct bat_priv *bat_priv)
 
 			if ((tmp_gw_factor > max_gw_factor) ||
 			    ((tmp_gw_factor == max_gw_factor) &&
-			     (router->tq_avg > max_tq)))
-				curr_gw_tmp = gw_node;
+			     (router->tq_avg > max_tq))) {
+				if (curr_gw)
+					gw_node_free_ref(curr_gw);
+				curr_gw = gw_node;
+				atomic_inc(&curr_gw->refcount);
+			}
 			break;
 
 		default: /**
@@ -163,8 +150,12 @@ void gw_election(struct bat_priv *bat_priv)
 			  *     soon as a better gateway appears which has
 			  *     $routing_class more tq points)
 			  **/
-			if (router->tq_avg > max_tq)
-				curr_gw_tmp = gw_node;
+			if (router->tq_avg > max_tq) {
+				if (curr_gw)
+					gw_node_free_ref(curr_gw);
+				curr_gw = gw_node;
+				atomic_inc(&curr_gw->refcount);
+			}
 			break;
 		}
 
@@ -174,42 +165,81 @@ void gw_election(struct bat_priv *bat_priv)
 		if (tmp_gw_factor > max_gw_factor)
 			max_gw_factor = tmp_gw_factor;
 
-		neigh_node_free_ref(router);
-	}
-
-	if (curr_gw != curr_gw_tmp) {
-		router = orig_node_get_router(curr_gw_tmp->orig_node);
-		if (!router)
-			goto unlock;
-
-		if ((curr_gw) && (!curr_gw_tmp))
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Removing selected gateway - "
-				"no gateway in range\n");
-		else if ((!curr_gw) && (curr_gw_tmp))
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Adding route to gateway %pM "
-				"(gw_flags: %i, tq: %i)\n",
-				curr_gw_tmp->orig_node->orig,
-				curr_gw_tmp->orig_node->gw_flags,
-				router->tq_avg);
-		else
-			bat_dbg(DBG_BATMAN, bat_priv,
-				"Changing route to gateway %pM "
-				"(gw_flags: %i, tq: %i)\n",
-				curr_gw_tmp->orig_node->orig,
-				curr_gw_tmp->orig_node->gw_flags,
-				router->tq_avg);
+		gw_node_free_ref(gw_node);
 
+next:
 		neigh_node_free_ref(router);
-		gw_select(bat_priv, curr_gw_tmp);
 	}
-
-unlock:
 	rcu_read_unlock();
+
+	return curr_gw;
+}
+
+void gw_election(struct bat_priv *bat_priv)
+{
+	struct gw_node *curr_gw = NULL, *next_gw = NULL;
+	struct neigh_node *router = NULL;
+	char gw_addr[18] = { '\0' };
+
+	/**
+	 * The batman daemon checks here if we already passed a full originator
+	 * cycle in order to make sure we don't choose the first gateway we
+	 * hear about. This check is based on the daemon's uptime which we
+	 * don't have.
+	 **/
+	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
+		goto out;
+
+	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
+		goto out;
+
+	curr_gw = gw_get_selected_gw_node(bat_priv);
+
+	next_gw = gw_get_best_gw_node(bat_priv);
+
+	if (curr_gw == next_gw)
+		goto out;
+
+	if (next_gw) {
+		sprintf(gw_addr, "%pM", next_gw->orig_node->orig);
+
+		router = orig_node_get_router(next_gw->orig_node);
+		if (!router) {
+			gw_deselect(bat_priv);
+			goto out;
+		}
+	}
+
+	if ((curr_gw) && (!next_gw)) {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Removing selected gateway - no gateway in range\n");
+		throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL);
+	} else if ((!curr_gw) && (next_gw)) {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
+			next_gw->orig_node->orig,
+			next_gw->orig_node->gw_flags,
+			router->tq_avg);
+		throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr);
+	} else {
+		bat_dbg(DBG_BATMAN, bat_priv,
+			"Changing route to gateway %pM "
+			"(gw_flags: %i, tq: %i)\n",
+			next_gw->orig_node->orig,
+			next_gw->orig_node->gw_flags,
+			router->tq_avg);
+		throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr);
+	}
+
+	gw_select(bat_priv, next_gw);
+
 out:
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
+	if (next_gw)
+		gw_node_free_ref(next_gw);
+	if (router)
+		neigh_node_free_ref(router);
 }
 
 void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
diff --git a/main.c b/main.c
index c2b06b7..e367e69 100644
--- a/main.c
+++ b/main.c
@@ -113,6 +113,7 @@ int mesh_init(struct net_device *soft_iface)
 	if (vis_init(bat_priv) < 1)
 		goto err;
 
+	atomic_set(&bat_priv->gw_reselect, 0);
 	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
 	goto end;
 
diff --git a/types.h b/types.h
index 11e8569..85cf122 100644
--- a/types.h
+++ b/types.h
@@ -201,6 +201,7 @@ struct bat_priv {
 	struct delayed_work orig_work;
 	struct delayed_work vis_work;
 	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
+	atomic_t gw_reselect;
 	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct vis_info *my_vis_info;
 };
-- 
1.7.5.3


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

* [B.A.T.M.A.N.] [PATCHv6 3/3] batman-adv: improved gateway tq-based selection
  2011-05-09 21:15 ` [B.A.T.M.A.N.] [PATCHv5 " Antonio Quartulli
@ 2011-06-11 10:25   ` Marek Lindner
  2011-06-12 10:11     ` Marek Lindner
  0 siblings, 1 reply; 30+ messages in thread
From: Marek Lindner @ 2011-06-11 10:25 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Marek Lindner

From: Antonio Quartulli <ordex@autistici.org>

If a client issues a DHCPREQUEST for renewal, the packet is dropped
if the old destination (the old gateway for the client) TQ is smaller
than the current best gateway TQ less GW_THRESHOLD

Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
---
* if gw_is_target() returns a value smaller than zero in interface_tx()
  the code does not decrement orig_node's refcount

 gateway_client.c |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gateway_client.h |    3 +-
 main.h           |    3 +-
 soft-interface.c |   10 ++++-
 4 files changed, 104 insertions(+), 6 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index 64505ee..d90463a 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -25,11 +25,17 @@
 #include "gateway_common.h"
 #include "hard-interface.h"
 #include "originator.h"
+#include "routing.h"
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <linux/udp.h>
 #include <linux/if_vlan.h>
 
+/* This is the offset of the options field in a dhcp packet starting at
+ * the beginning of the dhcp header */
+#define DHCP_OPTIONS_OFFSET 240
+#define DHCP_REQUEST 3
+
 static void gw_node_free_ref(struct gw_node *gw_node)
 {
 	if (atomic_dec_and_test(&gw_node->refcount))
@@ -509,14 +515,75 @@ out:
 	return ret;
 }
 
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
+static bool is_type_dhcprequest(struct sk_buff *skb, int header_len)
+{
+	int ret = false;
+	unsigned char *p;
+	int pkt_len;
+
+	if (skb_linearize(skb) < 0)
+		goto out;
+
+	pkt_len = skb_headlen(skb);
+
+	if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1)
+		goto out;
+
+	p = skb->data + header_len + DHCP_OPTIONS_OFFSET;
+	pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1;
+
+	/* Access the dhcp option lists. Each entry is made up by:
+	 * - octect 1: option type
+	 * - octect 2: option data len (only if type != 255 and 0)
+	 * - octect 3: option data */
+	while (*p != 255 && !ret) {
+		/* p now points to the first octect: option type */
+		if (*p == 53) {
+			/* type 53 is the message type option.
+			 * Jump the len octect and go to the data octect */
+			if (pkt_len < 2)
+				goto out;
+			p += 2;
+
+			/* check if the message type is what we need */
+			if (*p == DHCP_REQUEST)
+				ret = true;
+			break;
+		} else if (*p == 0) {
+			/* option type 0 (padding), just go forward */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+		} else {
+			/* This is any other option. So we get the length... */
+			if (pkt_len < 1)
+				goto out;
+			pkt_len--;
+			p++;
+
+			/* ...and then we jump over the data */
+			if (pkt_len < *p)
+				goto out;
+			pkt_len -= *p;
+			p += (*p);
+		}
+	}
+out:
+	return ret;
+}
+
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw)
 {
 	struct ethhdr *ethhdr;
 	struct iphdr *iphdr;
 	struct ipv6hdr *ipv6hdr;
 	struct udphdr *udphdr;
 	struct gw_node *curr_gw;
+	struct neigh_node *neigh_curr = NULL, *neigh_old = NULL;
 	unsigned int header_len = 0;
+	int ret = 1;
 
 	if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF)
 		return 0;
@@ -584,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb)
 	if (!curr_gw)
 		return 0;
 
+	/* If old_gw != NULL then this packet is unicast.
+	 * So, at this point we have to check the message type: if it is a
+	 * DHCPREQUEST we have to decide whether to drop it or not */
+	if (old_gw && curr_gw->orig_node != old_gw) {
+		if (is_type_dhcprequest(skb, header_len)) {
+			/* If the dhcp packet has been sent to a different gw,
+			 * we have to evaluate whether the old gw is still
+			 * reliable enough */
+			neigh_curr = find_router(bat_priv, curr_gw->orig_node,
+						 NULL);
+			neigh_old = find_router(bat_priv, old_gw, NULL);
+			if (!neigh_curr || !neigh_old)
+				goto free_neigh;
+			if (neigh_curr->tq_avg - neigh_old->tq_avg <
+								GW_THRESHOLD)
+				ret = -1;
+		}
+	}
+free_neigh:
+	if (neigh_old)
+		neigh_node_free_ref(neigh_old);
+	if (neigh_curr)
+		neigh_node_free_ref(neigh_curr);
 	if (curr_gw)
 		gw_node_free_ref(curr_gw);
-	return 1;
+	return ret;
 }
diff --git a/gateway_client.h b/gateway_client.h
index 1ce8c60..b9b983c 100644
--- a/gateway_client.h
+++ b/gateway_client.h
@@ -31,6 +31,7 @@ void gw_node_update(struct bat_priv *bat_priv,
 void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node);
 void gw_node_purge(struct bat_priv *bat_priv);
 int gw_client_seq_print_text(struct seq_file *seq, void *offset);
-int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb);
+int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb,
+		 struct orig_node *old_gw);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
diff --git a/main.h b/main.h
index 7f3768e..059866c 100644
--- a/main.h
+++ b/main.h
@@ -91,7 +91,6 @@ enum mesh_state {
 #define BCAST_QUEUE_LEN		256
 #define BATMAN_QUEUE_LEN	256
 
-
 enum uev_action {
 	UEV_ADD = 0,
 	UEV_DEL,
@@ -102,6 +101,8 @@ enum uev_type {
 	UEV_GW = 0
 };
 
+#define GW_THRESHOLD	50
+
 /*
  * Debug Messages
  */
diff --git a/soft-interface.c b/soft-interface.c
index b268f85..7aeed0d 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -30,6 +30,7 @@
 #include "gateway_common.h"
 #include "gateway_client.h"
 #include "bat_sysfs.h"
+#include "originator.h"
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
@@ -561,6 +562,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	struct bcast_packet *bcast_packet;
 	struct vlan_ethhdr *vhdr;
 	struct softif_neigh *curr_softif_neigh = NULL;
+	struct orig_node *orig_node = NULL;
 	int data_len = skb->len, ret;
 	short vid = -1;
 	bool do_bcast = false;
@@ -595,8 +597,10 @@ int interface_tx(struct sk_buff *skb, struct net_device *soft_iface)
 	/* Register the client MAC in the transtable */
 	tt_local_add(soft_iface, ethhdr->h_source);
 
-	if (is_multicast_ether_addr(ethhdr->h_dest)) {
-		ret = gw_is_target(bat_priv, skb);
+	orig_node = transtable_search(bat_priv, ethhdr->h_dest);
+	if (is_multicast_ether_addr(ethhdr->h_dest) ||
+				(orig_node && orig_node->gw_flags)) {
+		ret = gw_is_target(bat_priv, skb, orig_node);
 
 		if (ret < 0)
 			goto dropped;
@@ -656,6 +660,8 @@ end:
 		softif_neigh_free_ref(curr_softif_neigh);
 	if (primary_if)
 		hardif_free_ref(primary_if);
+	if (orig_node)
+		orig_node_free_ref(orig_node);
 	return NETDEV_TX_OK;
 }
 
-- 
1.7.5.3


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

* Re: [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace
  2011-06-11 10:10       ` Marek Lindner
@ 2011-06-11 12:45         ` Antonio Quartulli
  0 siblings, 0 replies; 30+ messages in thread
From: Antonio Quartulli @ 2011-06-11 12:45 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Sat, Jun 11, 2011 at 12:10:24PM +0200, Marek Lindner wrote:
> On Tuesday, May 10, 2011 08:29:28 AM Antonio Quartulli wrote:
> > > Since this is part of sysfs you should add a description to
> > > Documentation/networking/batman-adv.txt.
> > 
> > Ah ok, I didn't know this.
> > I think Marek already planned to instruct me on this part. Thank you for
> > reminding me!
> 
> I believe we still lack some documentation here or did I overlook something ?

Yes, we still lack documentation. I can send some text in the next
days... :)

Thanks,

-- 
Antonio Quartulli

..each of us alone is worth nothing..
Ernesto "Che" Guevara ☭

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

* Re: [B.A.T.M.A.N.] [PATCHv5 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event
  2011-06-11 10:21     ` [B.A.T.M.A.N.] [PATCHv5 " Marek Lindner
@ 2011-06-12 10:09       ` Marek Lindner
  0 siblings, 0 replies; 30+ messages in thread
From: Marek Lindner @ 2011-06-12 10:09 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Saturday, June 11, 2011 12:21:28 PM Marek Lindner wrote:
> In case of new default gw, changing the default gw or deleting the default
> gw a uevent is triggered with type=gw, action=add/change/del and
> data={GW_ORIG_ADDRESS} (if any).
> 
> The gateway election mechanism has been a little revised. Now the
> gw_election is trigered by an atomic_t flag (gw_reselect) which is is set
> to 1 in case of election needed, avoding to set curr_gw to NULL.

Sven suggested splitting this patch, therefore I applied this in revision 
6a17ecc and c792264.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv6 3/3] batman-adv: improved gateway tq-based selection
  2011-06-11 10:25   ` [B.A.T.M.A.N.] [PATCHv6 " Marek Lindner
@ 2011-06-12 10:11     ` Marek Lindner
  0 siblings, 0 replies; 30+ messages in thread
From: Marek Lindner @ 2011-06-12 10:11 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Saturday, June 11, 2011 12:25:58 PM Marek Lindner wrote:
> From: Antonio Quartulli <ordex@autistici.org>
> 
> If a client issues a DHCPREQUEST for renewal, the packet is dropped
> if the old destination (the old gateway for the client) TQ is smaller
> than the current best gateway TQ less GW_THRESHOLD

Applied in revision 17852fa.

Thanks,
Marek

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

end of thread, other threads:[~2011-06-12 10:11 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-05  7:13 [B.A.T.M.A.N.] batman-adv: added uevent support for gw and gw propagation for clients Antonio Quartulli
2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
2011-05-05 13:34   ` Andrew Lunn
2011-05-08 19:21     ` Antonio Quartulli
2011-05-08 20:11       ` Andrew Lunn
2011-05-08 20:13         ` Antonio Quartulli
2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
2011-05-05  7:13 ` [B.A.T.M.A.N.] [PATCH 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
2011-05-05 13:46   ` Andrew Lunn
2011-05-08 20:57     ` Antonio Quartulli
2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
2011-05-09  9:52 ` [B.A.T.M.A.N.] [PATCHv2 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 1/3] batman-adv: add wrapper function to throw uevent in userspace Antonio Quartulli
2011-05-10  5:08   ` Andrew Lunn
2011-05-10  6:29     ` Antonio Quartulli
2011-06-11 10:10       ` Marek Lindner
2011-06-11 12:45         ` Antonio Quartulli
2011-06-11 10:07   ` Marek Lindner
2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 2/3] batman-adv: throw uevent in userspace on gateway add/change/del event Antonio Quartulli
2011-06-11 10:15   ` [B.A.T.M.A.N.] [PATCHv4 " Marek Lindner
2011-06-11 10:21     ` [B.A.T.M.A.N.] [PATCHv5 " Marek Lindner
2011-06-12 10:09       ` Marek Lindner
2011-05-09 13:02 ` [B.A.T.M.A.N.] [PATCHv3 3/3] batman-adv: improved gateway tq-based selection Antonio Quartulli
2011-05-09 14:48   ` Andrew Lunn
2011-05-09 20:26     ` Antonio Quartulli
2011-05-09 20:30 ` [B.A.T.M.A.N.] [PATCHv4 " Antonio Quartulli
2011-05-09 21:15 ` [B.A.T.M.A.N.] [PATCHv5 " Antonio Quartulli
2011-06-11 10:25   ` [B.A.T.M.A.N.] [PATCHv6 " Marek Lindner
2011-06-12 10:11     ` Marek Lindner

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).