b.a.t.m.a.n.lists.open-mesh.org archive mirror
 help / color / mirror / Atom feed
* [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware
@ 2013-06-04 10:11 Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry Antonio Quartulli
                   ` (12 more replies)
  0 siblings, 13 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

Hello people,

with this patchset I want to introduce a new feature in the TT code which makes
it VLAN aware. This means that now clients belonging to different VLANs created
on top of a generic bat0 are treated differently.

One of the major reason for bringing this change is to allow BLA to selectively
ignore TT entries belonging to a given VLAN.
To allow the latter behaviour, the CRC logic has been divided on a per-VLAN
basis. This means that the local TT table is logically divided in sub-tables
containing all the entries belonging to the same VLAN and the CRC is then
computed on each of them.
As a natural consequence, each node now stores a set of local CRCs instead of
one only. Due to this also the way the TVLV-TT object is built and announced has
been changed.


This patchset gives the possibility to:
- enable AP isolation only on a selected VLAN rather than on all the traffic
- make DAT work correctly when the same IP subnet is used on different VLANs
- make BLA refuse global entries from certain VLANs
- leave the possibility to future developers to implement more VLAN specific
  attributes


Somebody asked me to send the AP Isolation improvement in a separate patchset,
but I did not do that because it is only one patch and it is not worth.



This patchset is based on top of master plus these two patches:
"batman-adv: implement batadv_tt_entries"
"batman-adv: make batadv_tt_save_orig_buffer() generic"



Changes from v3:
- split the per-VLAN CRC patch in two:
	- generalise the VLAN structures to be used by the "untagged" lan
	- introduce per-VLAN CRC logic
- initialize sysfs earlier to allow the VLAN code to create the subfolders
  during soft_iface init
- changed path for ap_isolation in sysfs-class-net-mesh

Changes from v2:
- CRC logic divided on a VLAN-basis
- BLA can now select the TT entries to ignore based on the VLAN

Changes from v1:
- improved kernel doc
- created batadv_get_vid() function
- improved documentation for CRC computation
- added compat code for kfree_rcu (struct batadv_priv_vlan)



Cheers,

Antonio Quartulli (13):
  batman-adv: add the VLAN ID attribute to the TT entry
  batman-adv: use vid when computing local and global TT CRC
  batman-adv: print the VID together with the TT entries
  batman-adv: make the GW module correctly talk to the new VLAN-TT
  batman-adv: make the Distributed ARP Table vlan aware
  batman-adv: add per VLAN interface attribute framework
  batman-adv: initialise sysfs folder in softif_create()
  batman-adv: treat bat0 like yet another VLAN
  batman-adv: add sysfs framework for VLAN
  batman-adv: make the AP isolation attribute VLAN specific
  batman-adv: make the backbone gw check VLAN specific
  batman-adv: make the TT global purge routine VLAN specific
  batman-adv: make the TT CRC logic VLAN specific

 bridge_loop_avoidance.c |   58 ++-
 bridge_loop_avoidance.h |   10 +-
 compat.c                |   18 +
 compat.h                |   25 ++
 distributed-arp-table.c |  125 ++++--
 gateway_client.c        |   18 +-
 hard-interface.c        |    5 +-
 main.c                  |   72 +++-
 main.h                  |   13 +-
 originator.c            |  100 ++++-
 originator.h            |    7 +
 packet.h                |   32 +-
 routing.c               |   28 +-
 send.c                  |    8 +-
 send.h                  |   16 +-
 soft-interface.c        |  174 +++++++-
 sysfs-class-net-mesh    |    2 +-
 sysfs.c                 |  148 ++++++-
 sysfs.h                 |   10 +
 translation-table.c     | 1070 +++++++++++++++++++++++++++++++++++------------
 translation-table.h     |   23 +-
 types.h                 |   68 ++-
 22 files changed, 1613 insertions(+), 417 deletions(-)

-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 13:50   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC Antonio Quartulli
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

To make the translation table code VLAN-aware, each entry
must carry the VLAN ID which it belongs to. This patch adds
such attribute to the related TT structures.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bridge_loop_avoidance.c |  35 +++----
 distributed-arp-table.c |  11 ++-
 gateway_client.c        |   3 +-
 main.c                  |  30 +++++-
 main.h                  |   9 +-
 packet.h                |  14 ++-
 routing.c               |  26 ++++--
 send.c                  |   8 +-
 send.h                  |  16 ++--
 soft-interface.c        |  33 ++++---
 translation-table.c     | 239 +++++++++++++++++++++++++++++++++++++-----------
 translation-table.h     |  19 ++--
 types.h                 |   2 +
 13 files changed, 312 insertions(+), 133 deletions(-)

diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c
index ab537ec..02f6f81 100644
--- a/bridge_loop_avoidance.c
+++ b/bridge_loop_avoidance.c
@@ -858,27 +858,25 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv,
 				    struct batadv_hard_iface *primary_if,
 				    struct sk_buff *skb)
 {
-	struct ethhdr *ethhdr;
+	struct batadv_bla_claim_dst *bla_dst;
+	uint8_t *hw_src, *hw_dst;
 	struct vlan_ethhdr *vhdr;
+	struct ethhdr *ethhdr;
 	struct arphdr *arphdr;
-	uint8_t *hw_src, *hw_dst;
-	struct batadv_bla_claim_dst *bla_dst;
+	unsigned short vid;
 	__be16 proto;
 	int headlen;
-	unsigned short vid = BATADV_NO_FLAGS;
 	int ret;
 
+	vid = batadv_get_vid(skb, 0);
 	ethhdr = eth_hdr(skb);
 
-	if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
+	proto = ethhdr->h_proto;
+	headlen = ETH_HLEN;
+	if (vid & BATADV_VLAN_HAS_TAG) {
 		vhdr = (struct vlan_ethhdr *)ethhdr;
-		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
-		vid |= BATADV_VLAN_HAS_TAG;
 		proto = vhdr->h_vlan_encapsulated_proto;
-		headlen = sizeof(*vhdr);
-	} else {
-		proto = ethhdr->h_proto;
-		headlen = ETH_HLEN;
+		headlen += VLAN_HLEN;
 	}
 
 	if (proto != htons(ETH_P_ARP))
@@ -1361,10 +1359,8 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
 int batadv_bla_is_backbone_gw(struct sk_buff *skb,
 			      struct batadv_orig_node *orig_node, int hdr_size)
 {
-	struct ethhdr *ethhdr;
-	struct vlan_ethhdr *vhdr;
 	struct batadv_bla_backbone_gw *backbone_gw;
-	unsigned short vid = BATADV_NO_FLAGS;
+	unsigned short vid;
 
 	if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance))
 		return 0;
@@ -1373,16 +1369,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
 	if (!pskb_may_pull(skb, hdr_size + ETH_HLEN))
 		return 0;
 
-	ethhdr = (struct ethhdr *)(((uint8_t *)skb->data) + hdr_size);
-
-	if (ethhdr->h_proto == htons(ETH_P_8021Q)) {
-		if (!pskb_may_pull(skb, hdr_size + VLAN_ETH_HLEN))
-			return 0;
-
-		vhdr = (struct vlan_ethhdr *)(skb->data + hdr_size);
-		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
-		vid |= BATADV_VLAN_HAS_TAG;
-	}
+	vid = batadv_get_vid(skb, hdr_size);
 
 	/* see if this originator is a backbone gw for this VLAN */
 	backbone_gw = batadv_backbone_hash_find(orig_node->bat_priv,
diff --git a/distributed-arp-table.c b/distributed-arp-table.c
index 99da412..1b590f0 100644
--- a/distributed-arp-table.c
+++ b/distributed-arp-table.c
@@ -905,7 +905,8 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
 		 * additional DAT answer may trigger kernel warnings about
 		 * a packet coming from the wrong port.
 		 */
-		if (batadv_is_my_client(bat_priv, dat_entry->mac_addr)) {
+		if (batadv_is_my_client(bat_priv, dat_entry->mac_addr,
+					BATADV_NO_FLAGS)) {
 			ret = true;
 			goto out;
 		}
@@ -990,9 +991,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
 	 */
 	if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
 		err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
-						    BATADV_P_DAT_CACHE_REPLY);
+						    BATADV_P_DAT_CACHE_REPLY,
+						    BATADV_NO_FLAGS);
 	else
-		err = batadv_send_skb_unicast(bat_priv, skb_new);
+		err = batadv_send_skb_unicast(bat_priv, skb_new,
+					      BATADV_NO_FLAGS);
 
 	if (!err) {
 		batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
@@ -1080,7 +1083,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
 	/* if this REPLY is directed to a client of mine, let's deliver the
 	 * packet to the interface
 	 */
-	ret = !batadv_is_my_client(bat_priv, hw_dst);
+	ret = !batadv_is_my_client(bat_priv, hw_dst, BATADV_NO_FLAGS);
 out:
 	if (ret)
 		kfree_skb(skb);
diff --git a/gateway_client.c b/gateway_client.c
index 131136f..d0491fe 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -706,7 +706,8 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 		goto out;
 
 	orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
-						 ethhdr->h_dest);
+						 ethhdr->h_dest,
+						 BATADV_NO_FLAGS);
 	if (!orig_dst_node)
 		goto out;
 
diff --git a/main.c b/main.c
index 5d30fe0..7bd8618 100644
--- a/main.c
+++ b/main.c
@@ -19,6 +19,7 @@
 
 #include <linux/crc32c.h>
 #include <linux/highmem.h>
+#include <linux/if_vlan.h>
 #include "main.h"
 #include "sysfs.h"
 #include "debugfs.h"
@@ -127,7 +128,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
 		goto err;
 
 	batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
-			    BATADV_NULL_IFINDEX);
+			    BATADV_NULL_IFINDEX, BATADV_NO_FLAGS);
 
 	ret = batadv_bla_init(bat_priv);
 	if (ret < 0)
@@ -1087,6 +1088,33 @@ out:
 		batadv_orig_node_free_ref(orig_node);
 }
 
+/**
+ * batadv_get_vid - extract the VLAN identifier from skb if any
+ * @skb: the buffer containing the packet
+ * @header_len: length of the batman header preceding the Ethernet one
+ *
+ * If the packet contained in skb is vlan tagged then this function returns the
+ * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise returns BATADV_NO_FLAGS
+ */
+unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
+{
+	struct ethhdr *ethhdr = (struct ethhdr *)(skb->data + header_len);
+	struct vlan_ethhdr *vhdr;
+	unsigned short vid;
+
+	if (ethhdr->h_proto != htons(ETH_P_8021Q))
+		return BATADV_NO_FLAGS;
+
+	if (!pskb_may_pull(skb, header_len + VLAN_ETH_HLEN))
+		return BATADV_NO_FLAGS;
+
+	vhdr = (struct vlan_ethhdr *)(skb->data + header_len);
+	vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
+	vid |= BATADV_VLAN_HAS_TAG;
+
+	return vid;
+}
+
 static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
 {
 	struct batadv_algo_ops *bat_algo_ops;
diff --git a/main.h b/main.h
index 1f0b135..923edde 100644
--- a/main.h
+++ b/main.h
@@ -171,14 +171,6 @@ enum batadv_uev_type {
 
 #include "types.h"
 
-/**
- * batadv_vlan_flags - flags for the four MSB of any vlan ID field
- * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not
- */
-enum batadv_vlan_flags {
-	BATADV_VLAN_HAS_TAG	= BIT(15),
-};
-
 #define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \
 			       (int)(vid & VLAN_VID_MASK) : -1)
 
@@ -369,5 +361,6 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
 void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
 			      uint8_t *dst, uint8_t type, uint8_t version,
 			      void *tvlv_value, uint16_t tvlv_value_len);
+unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len);
 
 #endif /* _NET_BATMAN_ADV_MAIN_H_ */
diff --git a/packet.h b/packet.h
index e3ae41a..08e175a 100644
--- a/packet.h
+++ b/packet.h
@@ -122,6 +122,14 @@ enum batadv_tt_client_flags {
 	BATADV_TT_CLIENT_TEMP	 = BIT(11),
 };
 
+/**
+ * batadv_vlan_flags - flags for the four MSB of any vlan ID field
+ * @BATADV_VLAN_HAS_TAG: whether the field contains a valid vlan tag or not
+ */
+enum batadv_vlan_flags {
+	BATADV_VLAN_HAS_TAG	= BIT(15),
+};
+
 /* claim frame types for the bridge loop avoidance */
 enum batadv_bla_claimframe {
 	BATADV_CLAIM_TYPE_CLAIM		= 0x00,
@@ -399,21 +407,23 @@ struct batadv_tvlv_tt_data {
  *  batadv_tt_client_flags)
  * @reserved: reserved field
  * @addr: mac address of non-mesh client that triggered this tt change
+ * @vid: VLAN identifier
  */
 struct batadv_tvlv_tt_change {
 	uint8_t flags;
 	uint8_t reserved;
 	uint8_t addr[ETH_ALEN];
+	__be16 vid;
 };
 
 /**
  * struct batadv_tvlv_roam_adv - roaming advertisement
  * @client: mac address of roaming client
- * @reserved: field reserved for future use
+ * @vid: VLAN identifier
  */
 struct batadv_tvlv_roam_adv {
 	uint8_t  client[ETH_ALEN];
-	uint16_t reserved;
+	__be16 vid;
 };
 
 #endif /* _NET_BATMAN_ADV_PACKET_H_ */
diff --git a/routing.c b/routing.c
index 7b98c67..e63b05d 100644
--- a/routing.c
+++ b/routing.c
@@ -30,6 +30,8 @@
 #include "network-coding.h"
 #include "fragmentation.h"
 
+#include <linux/if_vlan.h>
+
 static int batadv_route_unicast_packet(struct sk_buff *skb,
 				       struct batadv_hard_iface *recv_if);
 
@@ -708,6 +710,7 @@ out:
  * @bat_priv: the bat priv with all the soft interface information
  * @unicast_packet: the unicast header to be updated
  * @dst_addr: the payload destination
+ * @vid: VLAN identifier
  *
  * Search the translation table for dst_addr and update the unicast header with
  * the new corresponding information (originator address where the destination
@@ -718,21 +721,22 @@ out:
 static bool
 batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
 			      struct batadv_unicast_packet *unicast_packet,
-			      uint8_t *dst_addr)
+			      uint8_t *dst_addr, unsigned short vid)
 {
 	struct batadv_orig_node *orig_node = NULL;
 	struct batadv_hard_iface *primary_if = NULL;
 	bool ret = false;
 	uint8_t *orig_addr, orig_ttvn;
 
-	if (batadv_is_my_client(bat_priv, dst_addr)) {
+	if (batadv_is_my_client(bat_priv, dst_addr, vid)) {
 		primary_if = batadv_primary_if_get_selected(bat_priv);
 		if (!primary_if)
 			goto out;
 		orig_addr = primary_if->net_dev->dev_addr;
 		orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
 	} else {
-		orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr);
+		orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr,
+						     vid);
 		if (!orig_node)
 			goto out;
 
@@ -759,11 +763,12 @@ out:
 
 static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 				     struct sk_buff *skb, int hdr_len) {
-	uint8_t curr_ttvn, old_ttvn;
+	struct batadv_unicast_packet *unicast_packet;
+	struct batadv_hard_iface *primary_if;
 	struct batadv_orig_node *orig_node;
+	uint8_t curr_ttvn, old_ttvn;
 	struct ethhdr *ethhdr;
-	struct batadv_hard_iface *primary_if;
-	struct batadv_unicast_packet *unicast_packet;
+	unsigned short vid;
 	int is_old_ttvn;
 
 	/* check if there is enough data before accessing it */
@@ -775,6 +780,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 		return 0;
 
 	unicast_packet = (struct batadv_unicast_packet *)skb->data;
+	vid = batadv_get_vid(skb, hdr_len);
 	ethhdr = (struct ethhdr *)(skb->data + hdr_len);
 
 	/* check if the destination client was served by this node and it is now
@@ -782,9 +788,9 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 	 * message and that it knows the new destination in the mesh to re-route
 	 * the packet to
 	 */
-	if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest)) {
+	if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) {
 		if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
-						  ethhdr->h_dest))
+						  ethhdr->h_dest, vid))
 			net_ratelimited_function(batadv_dbg, BATADV_DBG_TT,
 						 bat_priv,
 						 "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n",
@@ -830,7 +836,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 	 * target host
 	 */
 	if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
-					  ethhdr->h_dest)) {
+					  ethhdr->h_dest, vid)) {
 		net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv,
 					 "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
 					 unicast_packet->dest, ethhdr->h_dest,
@@ -842,7 +848,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
 	 * currently served by this node or there is no destination at all and
 	 * it is possible to drop the packet
 	 */
-	if (!batadv_is_my_client(bat_priv, ethhdr->h_dest))
+	if (!batadv_is_my_client(bat_priv, ethhdr->h_dest, vid))
 		return 0;
 
 	/* update the header in order to let the packet be delivered to this
diff --git a/send.c b/send.c
index d780b9d..b631355 100644
--- a/send.c
+++ b/send.c
@@ -241,12 +241,14 @@ out:
  * @packet_type: the batman unicast packet type to use
  * @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
  *  4addr packets)
+ * @vid: the vid to be used to search the translation table
  *
  * Returns 1 in case of error or 0 otherwise.
  */
 int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
 				    struct sk_buff *skb, int packet_type,
-				    int packet_subtype)
+				    int packet_subtype,
+				    unsigned short vid)
 {
 	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
 	struct batadv_unicast_packet *unicast_packet;
@@ -261,7 +263,7 @@ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
 		 * returns NULL in case of AP isolation
 		 */
 		orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
-						     ethhdr->h_dest);
+						     ethhdr->h_dest, vid);
 
 	if (!orig_node)
 		goto out;
@@ -288,7 +290,7 @@ int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
 	 * try to reroute it because the ttvn contained in the header is less
 	 * than the current one
 	 */
-	if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest))
+	if (batadv_tt_global_client_is_roaming(bat_priv, ethhdr->h_dest, vid))
 		unicast_packet->ttvn = unicast_packet->ttvn - 1;
 
 	if (batadv_send_skb_to_orig(skb, orig_node, NULL) != NET_XMIT_DROP)
diff --git a/send.h b/send.h
index ad63184..c030cb7 100644
--- a/send.h
+++ b/send.h
@@ -40,21 +40,23 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
 					   int packet_subtype);
 int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
 				    struct sk_buff *skb, int packet_type,
-				    int packet_subtype);
-
+				    int packet_subtype,
+				    unsigned short vid);
 
 /**
  * batadv_send_unicast_skb - send the skb encapsulated in a unicast packet
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the payload to send
+ * @vid: the vid to be used to search the translation table
  *
  * Returns 1 in case of error or 0 otherwise.
  */
 static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
-					  struct sk_buff *skb)
+					  struct sk_buff *skb,
+					  unsigned short vid)
 {
 	return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST,
-					       0);
+					       0, vid);
 }
 
 /**
@@ -63,16 +65,18 @@ static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
  * @bat_priv: the bat priv with all the soft interface information
  * @skb: the payload to send
  * @packet_subtype: the unicast 4addr packet subtype to use
+ * @vid: the vid to be used to search the translation table
  *
  * Returns 1 in case of error or 0 otherwise.
  */
 static inline int batadv_send_skb_unicast_4addr(struct batadv_priv *bat_priv,
 						struct sk_buff *skb,
-						int packet_subtype)
+						int packet_subtype,
+						unsigned short vid)
 {
 	return batadv_send_skb_generic_unicast(bat_priv, skb,
 					       BATADV_UNICAST_4ADDR,
-					       packet_subtype);
+					       packet_subtype, vid);
 }
 
 #endif /* _NET_BATMAN_ADV_SEND_H_ */
diff --git a/soft-interface.c b/soft-interface.c
index d4fdc61..43390d1 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -118,9 +118,10 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
 
 	/* only modify transtable if it has been initialized before */
 	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) {
-		batadv_tt_local_remove(bat_priv, old_addr,
+		batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS,
 				       "mac address changed", false);
-		batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX);
+		batadv_tt_local_add(dev, addr->sa_data, BATADV_NULL_IFINDEX,
+				    BATADV_NO_FLAGS);
 	}
 
 	return 0;
@@ -140,32 +141,33 @@ static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu)
 static int batadv_interface_tx(struct sk_buff *skb,
 			       struct net_device *soft_iface)
 {
-	struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
+	struct ethhdr *ethhdr;
 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 	struct batadv_hard_iface *primary_if = NULL;
 	struct batadv_bcast_packet *bcast_packet;
-	struct vlan_ethhdr *vhdr;
 	__be16 ethertype = htons(ETH_P_BATMAN);
 	static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00,
 						   0x00, 0x00};
 	static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00,
 						    0x00, 0x00};
+	struct vlan_ethhdr *vhdr;
 	unsigned int header_len = 0;
 	int data_len = skb->len, ret;
-	unsigned short vid __maybe_unused = BATADV_NO_FLAGS;
+	unsigned long brd_delay = 1;
 	bool do_bcast = false;
+	unsigned short vid;
 	uint32_t seqno;
-	unsigned long brd_delay = 1;
 
 	if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
 		goto dropped;
 
 	soft_iface->trans_start = jiffies;
+	vid = batadv_get_vid(skb, 0);
+	ethhdr = (struct ethhdr *)skb->data;
 
 	switch (ntohs(ethhdr->h_proto)) {
 	case ETH_P_8021Q:
 		vhdr = (struct vlan_ethhdr *)skb->data;
-		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
 
 		if (vhdr->h_vlan_encapsulated_proto != ethertype)
 			break;
@@ -180,7 +182,8 @@ static int batadv_interface_tx(struct sk_buff *skb,
 
 	/* Register the client MAC in the transtable */
 	if (!is_multicast_ether_addr(ethhdr->h_source))
-		batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
+		batadv_tt_local_add(soft_iface, ethhdr->h_source, vid,
+				    skb->skb_iif);
 
 	/* don't accept stp packets. STP does not help in meshes.
 	 * better use the bridge loop avoidance ...
@@ -274,7 +277,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
 
 		batadv_dat_snoop_outgoing_arp_reply(bat_priv, skb);
 
-		ret = batadv_send_skb_unicast(bat_priv, skb);
+		ret = batadv_send_skb_unicast(bat_priv, skb, vid);
 		if (ret != 0)
 			goto dropped_freed;
 	}
@@ -297,12 +300,12 @@ void batadv_interface_rx(struct net_device *soft_iface,
 			 struct sk_buff *skb, struct batadv_hard_iface *recv_if,
 			 int hdr_size, struct batadv_orig_node *orig_node)
 {
-	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
-	struct ethhdr *ethhdr;
-	struct vlan_ethhdr *vhdr;
 	struct batadv_header *batadv_header = (struct batadv_header *)skb->data;
-	unsigned short vid __maybe_unused = BATADV_NO_FLAGS;
+	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 	__be16 ethertype = htons(ETH_P_BATMAN);
+	struct vlan_ethhdr *vhdr;
+	struct ethhdr *ethhdr;
+	unsigned short vid;
 	bool is_bcast;
 
 	is_bcast = (batadv_header->packet_type == BATADV_BCAST);
@@ -314,12 +317,12 @@ void batadv_interface_rx(struct net_device *soft_iface,
 	skb_pull_rcsum(skb, hdr_size);
 	skb_reset_mac_header(skb);
 
+	vid = batadv_get_vid(skb, hdr_size);
 	ethhdr = eth_hdr(skb);
 
 	switch (ntohs(ethhdr->h_proto)) {
 	case ETH_P_8021Q:
 		vhdr = (struct vlan_ethhdr *)skb->data;
-		vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
 
 		if (vhdr->h_vlan_encapsulated_proto != ethertype)
 			break;
@@ -355,7 +358,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
 
 	if (orig_node)
 		batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
-						     ethhdr->h_source);
+						     ethhdr->h_source, vid);
 
 	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
 		goto dropped;
diff --git a/translation-table.c b/translation-table.c
index 891e053..708bafe 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -34,6 +34,7 @@ static struct lock_class_key batadv_tt_local_hash_lock_class_key;
 static struct lock_class_key batadv_tt_global_hash_lock_class_key;
 
 static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
+				 unsigned short vid,
 				 struct batadv_orig_node *orig_node);
 static void batadv_tt_purge(struct work_struct *work);
 static void
@@ -41,7 +42,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry);
 static void batadv_tt_global_del(struct batadv_priv *bat_priv,
 				 struct batadv_orig_node *orig_node,
 				 const unsigned char *addr,
-				 const char *message, bool roaming);
+				 unsigned short vid, const char *message,
+				 bool roaming);
 
 /* returns 1 if they are the same mac addr */
 static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
@@ -52,43 +54,93 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
+/**
+ * batadv_choose_tt - return the index of the tt entry in the hash table
+ * @data: pointer to the tt_common_entry object to map
+ * @size: the size of the hash table
+ *
+ * Return the index where the object represented by 'data' should be stored in
+ * the hash table
+ */
+static inline uint32_t batadv_choose_tt(const void *data, uint32_t size)
+{
+	struct batadv_tt_common_entry *tt;
+	uint32_t hash = 0;
+
+	tt = (struct batadv_tt_common_entry *)data;
+	hash = batadv_hash_bytes(hash, &tt->addr, ETH_ALEN);
+	hash = batadv_hash_bytes(hash, &tt->vid, sizeof(tt->vid));
+
+	hash += (hash << 3);
+	hash ^= (hash >> 11);
+	hash += (hash << 15);
+
+	return hash % size;
+}
+
+/**
+ * batadv_tt_hash_find - looks for a client in the given hash table
+ * @hash: the hash table to search
+ * @addr: the mac address of the client to look for
+ * @vid: VLAN identifier
+ *
+ * Return a pointer to the tt_common struct belonging to the searched client if
+ * found, NULL otherwise
+ */
 static struct batadv_tt_common_entry *
-batadv_tt_hash_find(struct batadv_hashtable *hash, const void *data)
+batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr,
+		    unsigned short vid)
 {
 	struct hlist_head *head;
-	struct batadv_tt_common_entry *tt_common_entry;
-	struct batadv_tt_common_entry *tt_common_entry_tmp = NULL;
+	struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL;
 	uint32_t index;
 
 	if (!hash)
 		return NULL;
 
-	index = batadv_choose_orig(data, hash->size);
+	memcpy(to_search.addr, addr, ETH_ALEN);
+	to_search.vid = vid;
+
+	index = batadv_choose_tt(&to_search, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
-	hlist_for_each_entry_rcu(tt_common_entry, head, hash_entry) {
-		if (!batadv_compare_eth(tt_common_entry, data))
+	hlist_for_each_entry_rcu(tt, head, hash_entry) {
+		if (!batadv_compare_eth(tt, addr))
+			continue;
+
+		if (tt->vid != vid)
 			continue;
 
-		if (!atomic_inc_not_zero(&tt_common_entry->refcount))
+		if (!atomic_inc_not_zero(&tt->refcount))
 			continue;
 
-		tt_common_entry_tmp = tt_common_entry;
+		tt_tmp = tt;
 		break;
 	}
 	rcu_read_unlock();
 
-	return tt_common_entry_tmp;
+	return tt_tmp;
 }
 
+/**
+ * batadv_tt_local_hash_find - Search the local table for a given client
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client to look for
+ * @vid: VLAN identifier
+ *
+ * Return a pointer to the corresponding tt_local_entry struct if the client is
+ * found, NULL otherwise
+ */
 static struct batadv_tt_local_entry *
-batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data)
+batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr,
+			  unsigned short vid)
 {
 	struct batadv_tt_common_entry *tt_common_entry;
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 
-	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, data);
+	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.local_hash, addr,
+					      vid);
 	if (tt_common_entry)
 		tt_local_entry = container_of(tt_common_entry,
 					      struct batadv_tt_local_entry,
@@ -96,13 +148,24 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const void *data)
 	return tt_local_entry;
 }
 
+/**
+ * batadv_tt_global_hash_find - Search the global table for a given client
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client to look for
+ * @vid: VLAN identifier
+ *
+ * Return a pointer to the corresponding tt_global_entry struct if the client is
+ * found, NULL otherwise
+ */
 static struct batadv_tt_global_entry *
-batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const void *data)
+batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr,
+			   unsigned short vid)
 {
 	struct batadv_tt_common_entry *tt_common_entry;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
 
-	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, data);
+	tt_common_entry = batadv_tt_hash_find(bat_priv->tt.global_hash, addr,
+					      vid);
 	if (tt_common_entry)
 		tt_global_entry = container_of(tt_common_entry,
 					       struct batadv_tt_global_entry,
@@ -178,6 +241,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
 	tt_change_node->change.flags = flags;
 	tt_change_node->change.reserved = 0;
 	memcpy(tt_change_node->change.addr, common->addr, ETH_ALEN);
+	tt_change_node->change.vid = htons(common->vid);
 
 	del_op_requested = flags & BATADV_TT_CLIENT_DEL;
 
@@ -268,12 +332,21 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
 		   tt_global->common.addr, message);
 
 	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
-			   batadv_choose_orig, tt_global->common.addr);
+			   batadv_choose_tt, &tt_global->common);
 	batadv_tt_global_entry_free_ref(tt_global);
 }
 
+/**
+ * batadv_tt_local_add - add a new client to the local table or update it if
+ *  already exists
+ * @soft_iface: netdev struct of the mesh interface
+ * @addr: the mac address of the client to add
+ * @vid: VLAN identifier
+ * @ifindex: index of the interface where the client is connected to (useful to
+ *  identify wireless clients)
+ */
 void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-			 int ifindex)
+			 unsigned short vid, int ifindex)
 {
 	struct batadv_priv *bat_priv = netdev_priv(soft_iface);
 	struct batadv_tt_local_entry *tt_local;
@@ -283,8 +356,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 	int hash_added;
 	bool roamed_back = false;
 
-	tt_local = batadv_tt_local_hash_find(bat_priv, addr);
-	tt_global = batadv_tt_global_hash_find(bat_priv, addr);
+	tt_local = batadv_tt_local_hash_find(bat_priv, addr, vid);
+	tt_global = batadv_tt_global_hash_find(bat_priv, addr, vid);
 
 	if (tt_local) {
 		tt_local->last_seen = jiffies;
@@ -329,6 +402,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 	 * (consistency check)
 	 */
 	tt_local->common.flags = BATADV_TT_CLIENT_NEW;
+	tt_local->common.vid = vid;
 	if (batadv_is_wifi_iface(ifindex))
 		tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
 	atomic_set(&tt_local->common.refcount, 2);
@@ -340,7 +414,7 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 		tt_local->common.flags |= BATADV_TT_CLIENT_NOPURGE;
 
 	hash_added = batadv_hash_add(bat_priv->tt.local_hash, batadv_compare_tt,
-				     batadv_choose_orig, &tt_local->common,
+				     batadv_choose_tt, &tt_local->common,
 				     &tt_local->common.hash_entry);
 
 	if (unlikely(hash_added != 0)) {
@@ -362,6 +436,7 @@ check_roaming:
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(orig_entry, head, list) {
 			batadv_send_roam_adv(bat_priv, tt_global->common.addr,
+					     tt_global->common.vid,
 					     orig_entry->orig_node);
 		}
 		rcu_read_unlock();
@@ -550,19 +625,20 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
  * batadv_tt_local_remove - logically remove an entry from the local table
  * @bat_priv: the bat priv with all the soft interface information
  * @addr: the MAC address of the client to remove
+ * @vid: VLAN identifier
  * @message: message to append to the log on deletion
  * @roaming: true if the deletion is due to a roaming event
  *
  * Returns the flags assigned to the local entry before being deleted
  */
 uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
-				const uint8_t *addr, const char *message,
-				bool roaming)
+				const uint8_t *addr, unsigned short vid,
+				const char *message, bool roaming)
 {
 	struct batadv_tt_local_entry *tt_local_entry;
 	uint16_t flags, curr_flags = BATADV_NO_FLAGS;
 
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
 	if (!tt_local_entry)
 		goto out;
 
@@ -798,6 +874,7 @@ out:
  * @bat_priv: the bat priv with all the soft interface information
  * @orig_node: the originator announcing the client
  * @tt_addr: the mac address of the non-mesh client
+ * @vid: VLAN identifier
  * @flags: TT flags that have to be set for this non-mesh client
  * @ttvn: the tt version number ever announcing this non-mesh client
  *
@@ -813,7 +890,8 @@ out:
  */
 static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 				 struct batadv_orig_node *orig_node,
-				 const unsigned char *tt_addr, uint16_t flags,
+				 const unsigned char *tt_addr,
+				 unsigned short vid, uint16_t flags,
 				 uint8_t ttvn)
 {
 	struct batadv_tt_global_entry *tt_global_entry;
@@ -823,8 +901,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 	struct batadv_tt_common_entry *common;
 	uint16_t local_flags;
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr);
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
 
 	/* if the node already has a local client for this entry, it has to wait
 	 * for a roaming advertisement instead of manually messing up the global
@@ -841,6 +919,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 
 		common = &tt_global_entry->common;
 		memcpy(common->addr, tt_addr, ETH_ALEN);
+		common->vid = vid;
 
 		common->flags = flags;
 		tt_global_entry->roam_at = 0;
@@ -858,7 +937,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 
 		hash_added = batadv_hash_add(bat_priv->tt.global_hash,
 					     batadv_compare_tt,
-					     batadv_choose_orig, common,
+					     batadv_choose_tt, common,
 					     &common->hash_entry);
 
 		if (unlikely(hash_added != 0)) {
@@ -924,7 +1003,7 @@ add_orig_entry:
 out_remove:
 
 	/* remove address from local hash if present */
-	local_flags = batadv_tt_local_remove(bat_priv, tt_addr,
+	local_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,
 					     "global tt received",
 					     flags & BATADV_TT_CLIENT_ROAM);
 	tt_global_entry->common.flags |= local_flags & BATADV_TT_CLIENT_WIFI;
@@ -1147,17 +1226,25 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
 						orig_node, message);
 }
 
-
-
+/**
+ * batadv_tt_global_del - remove a client from the global table
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: an originator serving this client
+ * @addr: the mac address of the client
+ * @vid: VLAN identifier
+ * @message: a message explaining the reason for deleting the client to print
+ *  for debugging purpose
+ * @roaming: true if the deletion has been triggered by a roaming event
+ */
 static void batadv_tt_global_del(struct batadv_priv *bat_priv,
 				 struct batadv_orig_node *orig_node,
-				 const unsigned char *addr,
+				 const unsigned char *addr, unsigned short vid,
 				 const char *message, bool roaming)
 {
 	struct batadv_tt_global_entry *tt_global_entry;
 	struct batadv_tt_local_entry *local_entry = NULL;
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
 	if (!tt_global_entry)
 		goto out;
 
@@ -1186,7 +1273,8 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
 	 *    the global entry, since it is useless now.
 	 */
 	local_entry = batadv_tt_local_hash_find(bat_priv,
-						tt_global_entry->common.addr);
+						tt_global_entry->common.addr,
+						vid);
 	if (local_entry) {
 		/* local entry exists, case 2: client roamed to us. */
 		batadv_tt_global_del_orig_list(tt_global_entry);
@@ -1354,9 +1442,24 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
 	return ret;
 }
 
+/**
+ * batadv_transtable_search - get the mesh destination for a given client
+ * @bat_priv: the bat priv with all the soft interface information
+ * @src: mac address of the source client
+ * @addr: mac address of the destination client
+ * @vid: VLAN identifier
+ *
+ * Return a pointer to the originator being the node selected as destination in
+ * the mesh for contacting the client 'addr', NULL otherwise.
+ * In case of multiple originators serving the same client, the function returns
+ * the best one (best in terms of TQ).
+ *
+ * If the two clients are AP isolated the function returns NULL.
+ */
 struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 						  const uint8_t *src,
-						  const uint8_t *addr)
+						  const uint8_t *addr,
+						  unsigned short vid)
 {
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
@@ -1364,13 +1467,13 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 	struct batadv_tt_orig_list_entry *best_entry;
 
 	if (src && atomic_read(&bat_priv->ap_isolation)) {
-		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src);
+		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
 		if (!tt_local_entry ||
 		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
 			goto out;
 	}
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
 	if (!tt_global_entry)
 		goto out;
 
@@ -1649,6 +1752,7 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
 			memcpy(tt_change->addr, tt_common_entry->addr,
 			       ETH_ALEN);
 			tt_change->flags = tt_common_entry->flags;
+			tt_change->vid = htons(tt_common_entry->vid);
 			tt_change->reserved = 0;
 
 			tt_num_entries++;
@@ -1979,11 +2083,13 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
 			roams = (tt_change + i)->flags & BATADV_TT_CLIENT_ROAM;
 			batadv_tt_global_del(bat_priv, orig_node,
 					     (tt_change + i)->addr,
+					     ntohs((tt_change + i)->vid),
 					     "tt removed by changes",
 					     roams);
 		} else {
 			if (!batadv_tt_global_add(bat_priv, orig_node,
 						  (tt_change + i)->addr,
+						  ntohs((tt_change + i)->vid),
 						  (tt_change + i)->flags, ttvn))
 				/* In case of problem while storing a
 				 * global_entry, we stop the updating
@@ -2040,12 +2146,21 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv,
 	atomic_set(&orig_node->last_ttvn, ttvn);
 }
 
-bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr)
+/**
+ * batadv_is_my_client - check if a client is served by the local node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac adress of the client to check
+ * @vid: VLAN identifier
+ *
+ * Return true if the client is served by this node, false otherwise
+ */
+bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr,
+			 unsigned short vid)
 {
 	struct batadv_tt_local_entry *tt_local_entry;
 	bool ret = false;
 
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
 	if (!tt_local_entry)
 		goto out;
 	/* Check if the client has been logically deleted (but is kept for
@@ -2194,7 +2309,19 @@ unlock:
 	return ret;
 }
 
+/**
+ * batadv_send_roam_adv - send a roaming advertisement message
+ * @bat_priv: the bat priv with all the soft interface information
+ * @client: mac address of the roaming client
+ * @vid: VLAN identifier
+ * @orig_node: message destination
+ *
+ * Send a ROAMING_ADV message to the node which was previously serving this
+ * client. This is done to inform the originator that now all the traffic
+ * directed to the provided mac address has to be forwarded here
+ */
 static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
+				 unsigned short vid,
 				 struct batadv_orig_node *orig_node)
 {
 	struct batadv_hard_iface *primary_if;
@@ -2217,7 +2344,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
 
 	memcpy(tvlv_roam.client, client, sizeof(tvlv_roam.client));
-	tvlv_roam.reserved = 0;
+	tvlv_roam.vid = htons(vid);
 
 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
 				 orig_node->orig, BATADV_TVLV_ROAM, 1,
@@ -2383,11 +2510,13 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
 	if (!atomic_read(&bat_priv->ap_isolation))
 		goto out;
 
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst,
+						   BATADV_NO_FLAGS);
 	if (!tt_local_entry)
 		goto out;
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src,
+						     BATADV_NO_FLAGS);
 	if (!tt_global_entry)
 		goto out;
 
@@ -2482,17 +2611,23 @@ request_table:
 	}
 }
 
-/* returns true whether we know that the client has moved from its old
- * originator to another one. This entry is kept is still kept for consistency
- * purposes
+/**
+ * batadv_tt_global_client_is_roaming - check if a client is marked as roaming
+ * @bat_priv: the bat priv with all the soft interface information
+ * @addr: the mac address of the client to check
+ * @vid: VLAN identifier
+ *
+ * Return true whether we know that the client has moved from its old originator
+ * to another one. This entry is still kept for consistency purposes and will be
+ * deleted later by a DEL or because of timeout
  */
 bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
-					uint8_t *addr)
+					uint8_t *addr, unsigned short vid)
 {
 	struct batadv_tt_global_entry *tt_global_entry;
 	bool ret = false;
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
 	if (!tt_global_entry)
 		goto out;
 
@@ -2505,19 +2640,20 @@ out:
 /**
  * batadv_tt_local_client_is_roaming - tells whether the client is roaming
  * @bat_priv: the bat priv with all the soft interface information
- * @addr: the MAC address of the local client to query
+ * @addr: the mac address of the local client to query
+ * @vid: VLAN identifier
  *
  * Returns true if the local client is known to be roaming (it is not served by
  * this node anymore) or not. If yes, the client is still present in the table
  * to keep the latter consistent with the node TTVN
  */
 bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
-				       uint8_t *addr)
+				       uint8_t *addr, unsigned short vid)
 {
 	struct batadv_tt_local_entry *tt_local_entry;
 	bool ret = false;
 
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
 	if (!tt_local_entry)
 		goto out;
 
@@ -2529,7 +2665,8 @@ out:
 
 bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig_node,
-					  const unsigned char *addr)
+					  const unsigned char *addr,
+					  unsigned short vlan)
 {
 	bool ret = false;
 
@@ -2540,7 +2677,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
 		goto out;
 
-	if (!batadv_tt_global_add(bat_priv, orig_node, addr,
+	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vlan,
 				  BATADV_TT_CLIENT_TEMP,
 				  atomic_read(&orig_node->last_ttvn)))
 		goto out;
@@ -2706,7 +2843,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 		   src, roaming_adv->client);
 
 	batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client,
-			     BATADV_TT_CLIENT_ROAM,
+			     ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM,
 			     atomic_read(&orig_node->last_ttvn) + 1);
 
 out:
diff --git a/translation-table.h b/translation-table.h
index 015d8b9..1d9506d 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -22,10 +22,10 @@
 
 int batadv_tt_init(struct batadv_priv *bat_priv);
 void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
-			 int ifindex);
+			 unsigned short vid, int ifindex);
 uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
-				const uint8_t *addr, const char *message,
-				bool roaming);
+				const uint8_t *addr, unsigned short vid,
+				const char *message, bool roaming);
 int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
 void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
@@ -33,18 +33,21 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 			       const char *message);
 struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 						  const uint8_t *src,
-						  const uint8_t *addr);
+						  const uint8_t *addr,
+						  unsigned short vid);
 void batadv_tt_free(struct batadv_priv *bat_priv);
-bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr);
+bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr,
+			 unsigned short vid);
 bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
 			   uint8_t *dst);
 void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv);
 bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
-					uint8_t *addr);
+					uint8_t *addr, unsigned short vid);
 bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
-				       uint8_t *addr);
+				       uint8_t *addr, unsigned short vid);
 bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig_node,
-					  const unsigned char *addr);
+					  const unsigned char *addr,
+					  unsigned short vid);
 
 #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */
diff --git a/types.h b/types.h
index 304f3d0..7d8aa46 100644
--- a/types.h
+++ b/types.h
@@ -715,6 +715,7 @@ struct batadv_bla_claim {
 /**
  * struct batadv_tt_common_entry - tt local & tt global common data
  * @addr: mac address of non-mesh client
+ * @vid: VLAN identifier
  * @hash_entry: hlist node for batadv_priv_tt::local_hash or for
  *  batadv_priv_tt::global_hash
  * @flags: various state handling flags (see batadv_tt_client_flags)
@@ -724,6 +725,7 @@ struct batadv_bla_claim {
  */
 struct batadv_tt_common_entry {
 	uint8_t addr[ETH_ALEN];
+	unsigned short vid;
 	struct hlist_node hash_entry;
 	uint16_t flags;
 	unsigned long added_at;
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 13:55   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries Antonio Quartulli
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

now that each TT entry is characterised by a VLAN ID, the
latter has to be taken into consideration when computing the
local/global table CRC as it would be theoretically possible
to have the same client in two different VLANs

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 translation-table.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/translation-table.c b/translation-table.c
index 708bafe..0427d2f 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -1506,6 +1506,24 @@ out:
  * batadv_tt_global_crc - calculates the checksum of the local table belonging
  *  to the given orig_node
  * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: originator for which the CRC should be computed
+ *
+ * This function computes the checksum for the global table corresponding to a
+ * particular originator. In particular the checksum is computed as follows: for
+ * each client connected to the originator the CRC32C of the MAC address and the
+ * VID is computed and then all the CRC32Cs of the various clients are xor'ed
+ * together.
+ *
+ * The idea behind is that CRC32C should be used as much as possible in order to
+ * produce a unique hash of the table, but since the order which is used to feed
+ * the CRC32C function affects the result and since every node in the network
+ * probably sorts the clients differently, the hash function cannot be directly
+ * computed over the entire table. Hence the CRC32C is used only on
+ * the single client entry, while all the results are then xor'ed together
+ * because the XOR operation can combine them all while trying to reduce the
+ * noise as much as possible.
+ *
+ * Returns the checksum of the global table of a given originator
  */
 static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 				     struct batadv_orig_node *orig_node)
@@ -1514,7 +1532,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 	struct batadv_tt_common_entry *tt_common;
 	struct batadv_tt_global_entry *tt_global;
 	struct hlist_head *head;
-	uint32_t i, crc = 0;
+	uint32_t i, crc_tmp, crc = 0;
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -1545,7 +1563,9 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 							     orig_node))
 				continue;
 
-			crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
+			crc_tmp = crc32c(0, &tt_common->vid,
+					 sizeof(tt_common->vid));
+			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
 		}
 		rcu_read_unlock();
 	}
@@ -1556,13 +1576,18 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 /**
  * batadv_tt_local_crc - calculates the checksum of the local table
  * @bat_priv: the bat priv with all the soft interface information
+ *
+ * For details about the computation, please refer to the documentation for
+ * batadv_tt_global_crc().
+ *
+ * Returns the checksum of the local table
  */
 static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
 {
 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
 	struct batadv_tt_common_entry *tt_common;
 	struct hlist_head *head;
-	uint32_t i, crc = 0;
+	uint32_t i, crc_tmp, crc = 0;
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -1575,7 +1600,9 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
 			if (tt_common->flags & BATADV_TT_CLIENT_NEW)
 				continue;
 
-			crc ^= crc32c(0, tt_common->addr, ETH_ALEN);
+			crc_tmp = crc32c(0, &tt_common->vid,
+					 sizeof(tt_common->vid));
+			crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
 		}
 		rcu_read_unlock();
 	}
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 13:58   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT Antonio Quartulli
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 main.h              |  1 +
 translation-table.c | 82 ++++++++++++++++++++++++++++++++---------------------
 2 files changed, 51 insertions(+), 32 deletions(-)

diff --git a/main.h b/main.h
index 923edde..cfed2a3 100644
--- a/main.h
+++ b/main.h
@@ -167,6 +167,7 @@ enum batadv_uev_type {
 #include <net/rtnetlink.h>
 #include <linux/jiffies.h>
 #include <linux/seq_file.h>
+#include <linux/if_vlan.h>
 #include "compat.h"
 
 #include "types.h"
diff --git a/translation-table.c b/translation-table.c
index 0427d2f..dd573b9 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -328,8 +328,9 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
 				  const char *message)
 {
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Deleting global tt entry %pM: %s\n",
-		   tt_global->common.addr, message);
+		   "Deleting global tt entry %pM (vid: %d): %s\n",
+		   tt_global->common.addr,
+		   BATADV_PRINT_VID(tt_global->common.vid), message);
 
 	batadv_hash_remove(bat_priv->tt.global_hash, batadv_compare_tt,
 			   batadv_choose_tt, &tt_global->common);
@@ -363,7 +364,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 		tt_local->last_seen = jiffies;
 		if (tt_local->common.flags & BATADV_TT_CLIENT_PENDING) {
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "Re-adding pending client %pM\n", addr);
+				   "Re-adding pending client %pM (vid: %d)\n",
+				   addr, BATADV_PRINT_VID(vid));
 			/* whatever the reason why the PENDING flag was set,
 			 * this is a client which was enqueued to be removed in
 			 * this orig_interval. Since it popped up again, the
@@ -375,8 +377,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 
 		if (tt_local->common.flags & BATADV_TT_CLIENT_ROAM) {
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "Roaming client %pM came back to its original location\n",
-				   addr);
+				   "Roaming client %pM (vid: %d) came back to its original location\n",
+				   addr, BATADV_PRINT_VID(vid));
 			/* the ROAM flag is set because this client roamed away
 			 * and the node got a roaming_advertisement message. Now
 			 * that the client popped up again at its original
@@ -393,7 +395,8 @@ void batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 		goto out;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Creating new local tt entry: %pM (ttvn: %d)\n", addr,
+		   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
+		   addr, BATADV_PRINT_VID(vid),
 		   (uint8_t)atomic_read(&bat_priv->tt.vn));
 
 	memcpy(tt_local->common.addr, addr, ETH_ALEN);
@@ -562,8 +565,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.8x):\n",
 		   net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn),
 		   bat_priv->tt.local_crc);
-	seq_printf(seq, "       %-13s %-7s %-10s\n", "Client", "Flags",
-		   "Last seen");
+	seq_printf(seq, "       %-13s  %s %-7s %-10s\n", "Client", "VID",
+		   "Flags", "Last seen");
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -581,8 +584,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 
 			no_purge = tt_common_entry->flags & np_flag;
 
-			seq_printf(seq, " * %pM [%c%c%c%c%c] %3u.%03u\n",
+			seq_printf(seq, " * %pM %4i [%c%c%c%c%c] %3u.%03u\n",
 				   tt_common_entry->addr,
+				   BATADV_PRINT_VID(tt_common_entry->vid),
 				   (tt_common_entry->flags &
 				    BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
 				   no_purge ? 'P' : '.',
@@ -617,8 +621,9 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
 	tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Local tt entry (%pM) pending to be removed: %s\n",
-		   tt_local_entry->common.addr, message);
+		   "Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
+		   tt_local_entry->common.addr,
+		   BATADV_PRINT_VID(tt_local_entry->common.vid), message);
 }
 
 /**
@@ -996,8 +1001,9 @@ add_orig_entry:
 	batadv_tt_global_orig_entry_add(tt_global_entry, orig_node, ttvn);
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Creating new global tt entry: %pM (via %pM)\n",
-		   common->addr, orig_node->orig);
+		   "Creating new global tt entry: %pM (vid: %d, via %pM)\n",
+		   common->addr, BATADV_PRINT_VID(common->vid),
+		   orig_node->orig);
 	ret = true;
 
 out_remove:
@@ -1077,8 +1083,9 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
 	if (best_entry) {
 		last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
 		seq_printf(seq,
-			   " %c %pM  (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c]\n",
+			   " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c]\n",
 			   '*', tt_global_entry->common.addr,
+			   BATADV_PRINT_VID(tt_global_entry->common.vid),
 			   best_entry->ttvn, best_entry->orig_node->orig,
 			   last_ttvn, best_entry->orig_node->tt_crc,
 			   (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
@@ -1093,8 +1100,10 @@ batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
 			continue;
 
 		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
-		seq_printf(seq,	" %c %pM  (%3u) via %pM     (%3u)   [%c%c%c]\n",
+		seq_printf(seq,
+			   " %c %pM %4d   (%3u) via %pM     (%3u)   [%c%c%c]\n",
 			   '+', tt_global_entry->common.addr,
+			   BATADV_PRINT_VID(tt_global_entry->common.vid),
 			   orig_entry->ttvn, orig_entry->orig_node->orig,
 			   last_ttvn,
 			   (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
@@ -1121,9 +1130,9 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset)
 	seq_printf(seq,
 		   "Globally announced TT entries received via the mesh %s\n",
 		   net_dev->name);
-	seq_printf(seq, "       %-13s %s       %-15s %s (%-10s) %s\n",
-		   "Client", "(TTVN)", "Originator", "(Curr TTVN)", "CRC",
-		   "Flags");
+	seq_printf(seq, "       %-13s  %s  %s       %-15s %s (%-10s) %s\n",
+		   "Client", "VID", "(TTVN)", "Originator", "(Curr TTVN)",
+		   "CRC", "Flags");
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -1170,15 +1179,18 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
 	struct hlist_head *head;
 	struct hlist_node *safe;
 	struct batadv_tt_orig_list_entry *orig_entry;
+	unsigned short vid;
 
 	spin_lock_bh(&tt_global_entry->list_lock);
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
 		if (orig_entry->orig_node == orig_node) {
+			vid = tt_global_entry->common.vid;
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "Deleting %pM from global tt entry %pM: %s\n",
+				   "Deleting %pM from global tt entry %pM (vid: %d): %s\n",
 				   orig_node->orig,
-				   tt_global_entry->common.addr, message);
+				   tt_global_entry->common.addr,
+				   BATADV_PRINT_VID(vid), message);
 			hlist_del_rcu(&orig_entry->list);
 			batadv_tt_orig_list_entry_free_ref(orig_entry);
 		}
@@ -1303,6 +1315,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 	struct hlist_node *safe;
 	struct hlist_head *head;
 	spinlock_t *list_lock; /* protects write access to the hash lists */
+	unsigned short vid;
 
 	if (!hash)
 		return;
@@ -1322,9 +1335,11 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 							orig_node, message);
 
 			if (hlist_empty(&tt_global->orig_list)) {
+				vid = tt_global->common.vid;
 				batadv_dbg(BATADV_DBG_TT, bat_priv,
-					   "Deleting global tt entry %pM: %s\n",
-					   tt_global->common.addr, message);
+					   "Deleting global tt entry %pM (vid: %d): %s\n",
+					   tt_global->common.addr,
+					   BATADV_PRINT_VID(vid), message);
 				hlist_del_rcu(&tt_common_entry->hash_entry);
 				batadv_tt_global_entry_free_ref(tt_global);
 			}
@@ -1382,8 +1397,10 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv)
 				continue;
 
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "Deleting global tt entry (%pM): %s\n",
-				   tt_global->common.addr, msg);
+				   "Deleting global tt entry %pM (vid: %d): %s\n",
+				   tt_global->common.addr,
+				   BATADV_PRINT_VID(tt_global->common.vid),
+				   msg);
 
 			hlist_del_rcu(&tt_common->hash_entry);
 
@@ -2365,8 +2382,8 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client,
 		goto out;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Sending ROAMING_ADV to %pM (client %pM)\n",
-		   orig_node->orig, client);
+		   "Sending ROAMING_ADV to %pM (client %pM, vid: %d)\n",
+		   orig_node->orig, client, BATADV_PRINT_VID(vid));
 
 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_ROAM_ADV_TX);
 
@@ -2479,8 +2496,9 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
 				continue;
 
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "Deleting local tt entry (%pM): pending\n",
-				   tt_common->addr);
+				   "Deleting local tt entry (%pM, vid: %d): pending\n",
+				   tt_common->addr,
+				   BATADV_PRINT_VID(tt_common->vid));
 
 			atomic_dec(&bat_priv->tt.local_entry_num);
 			hlist_del_rcu(&tt_common->hash_entry);
@@ -2693,7 +2711,7 @@ out:
 bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig_node,
 					  const unsigned char *addr,
-					  unsigned short vlan)
+					  unsigned short vid)
 {
 	bool ret = false;
 
@@ -2704,14 +2722,14 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
 		goto out;
 
-	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vlan,
+	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
 				  BATADV_TT_CLIENT_TEMP,
 				  atomic_read(&orig_node->last_ttvn)))
 		goto out;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
-		   "Added temporary global client (addr: %pM orig: %pM)\n",
-		   addr, orig_node->orig);
+		   "Added temporary global client (addr: %pM, vid: %d, orig: %pM)\n",
+		   addr, BATADV_PRINT_VID(vid), orig_node->orig);
 	ret = true;
 out:
 	return ret;
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (2 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 14:02   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware Antonio Quartulli
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

The gateway code is now adapted in order to correctly
interact with the Translation Table component by using the
vlan ID

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 gateway_client.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/gateway_client.c b/gateway_client.c
index d0491fe..278e8f6 100644
--- a/gateway_client.c
+++ b/gateway_client.c
@@ -691,6 +691,19 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
 	return true;
 }
 
+/**
+ * batadv_gw_out_of_range - check if the dhcp request destination the best gw
+ * @bat_priv: the bat priv with all the soft interface information
+ * @skb: the outgoing packet
+ * @ethhdr: the inner Ethernet header
+ *
+ * Check if the skb is a DHCP request and if it is being sent to the current
+ * best GW server. Due to topology changes it may be the case that the
+ * GW server previously selected is not the best one anymore.
+ *
+ * Return true if the packet destination is unicast and it is not the best gw,
+ * false otherwise
+ */
 bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 			    struct sk_buff *skb, struct ethhdr *ethhdr)
 {
@@ -700,14 +713,16 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 	bool ret, out_of_range = false;
 	unsigned int header_len = 0;
 	uint8_t curr_tq_avg;
+	unsigned short vid;
+
+	vid = batadv_get_vid(skb, 0);
 
 	ret = batadv_gw_is_dhcp_target(skb, &header_len);
 	if (!ret)
 		goto out;
 
 	orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
-						 ethhdr->h_dest,
-						 BATADV_NO_FLAGS);
+						 ethhdr->h_dest, vid);
 	if (!orig_dst_node)
 		goto out;
 
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (3 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 14:11   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 06/13] batman-adv: add per VLAN interface attribute framework Antonio Quartulli
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

The same IP subnet can be used on different VLANs, therefore
DAT has to differentiate whether the IP to resolve belongs
to one or the other virtual LAN.
To accomplish this task DAT has to deal with the VLAN tag
and store it together with each ARP entry.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 distributed-arp-table.c | 122 ++++++++++++++++++++++++++++++++----------------
 types.h                 |   2 +
 2 files changed, 85 insertions(+), 39 deletions(-)

diff --git a/distributed-arp-table.c b/distributed-arp-table.c
index 1b590f0..a365e14 100644
--- a/distributed-arp-table.c
+++ b/distributed-arp-table.c
@@ -19,6 +19,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
+#include <linux/if_vlan.h>
 #include <net/arp.h>
 
 #include "main.h"
@@ -205,15 +206,11 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
  */
 static uint32_t batadv_hash_dat(const void *data, uint32_t size)
 {
-	const unsigned char *key = data;
 	uint32_t hash = 0;
-	size_t i;
+	const struct batadv_dat_entry *dat = data;
 
-	for (i = 0; i < 4; i++) {
-		hash += key[i];
-		hash += (hash << 10);
-		hash ^= (hash >> 6);
-	}
+	hash = batadv_hash_bytes(hash, &dat->ip, sizeof(dat->ip));
+	hash = batadv_hash_bytes(hash, &dat->vid, sizeof(dat->vid));
 
 	hash += (hash << 3);
 	hash ^= (hash >> 11);
@@ -227,21 +224,26 @@ static uint32_t batadv_hash_dat(const void *data, uint32_t size)
  * table
  * @bat_priv: the bat priv with all the soft interface information
  * @ip: search key
+ * @vid: VLAN identifier
  *
  * Returns the dat_entry if found, NULL otherwise.
  */
 static struct batadv_dat_entry *
-batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip)
+batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
+			   unsigned short vid)
 {
 	struct hlist_head *head;
-	struct batadv_dat_entry *dat_entry, *dat_entry_tmp = NULL;
+	struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL;
 	struct batadv_hashtable *hash = bat_priv->dat.hash;
 	uint32_t index;
 
 	if (!hash)
 		return NULL;
 
-	index = batadv_hash_dat(&ip, hash->size);
+	to_find.ip = ip;
+	to_find.vid = vid;
+
+	index = batadv_hash_dat(&to_find, hash->size);
 	head = &hash->table[index];
 
 	rcu_read_lock();
@@ -267,20 +269,20 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip)
  * @mac_addr: mac address to assign to the given ipv4
  */
 static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
-				 uint8_t *mac_addr)
+				 uint8_t *mac_addr, unsigned short vid)
 {
 	struct batadv_dat_entry *dat_entry;
 	int hash_added;
 
-	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip);
+	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
 	/* if this entry is already known, just update it */
 	if (dat_entry) {
 		if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
 			memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
 		dat_entry->last_update = jiffies;
 		batadv_dbg(BATADV_DBG_DAT, bat_priv,
-			   "Entry updated: %pI4 %pM\n", &dat_entry->ip,
-			   dat_entry->mac_addr);
+			   "Entry updated: %pI4 %pM (vid: %u)\n",
+			   &dat_entry->ip, dat_entry->mac_addr, vid);
 		goto out;
 	}
 
@@ -289,12 +291,13 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
 		goto out;
 
 	dat_entry->ip = ip;
+	dat_entry->vid = vid;
 	memcpy(dat_entry->mac_addr, mac_addr, ETH_ALEN);
 	dat_entry->last_update = jiffies;
 	atomic_set(&dat_entry->refcount, 2);
 
 	hash_added = batadv_hash_add(bat_priv->dat.hash, batadv_compare_dat,
-				     batadv_hash_dat, &dat_entry->ip,
+				     batadv_hash_dat, dat_entry,
 				     &dat_entry->hash_entry);
 
 	if (unlikely(hash_added != 0)) {
@@ -303,8 +306,8 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
 		goto out;
 	}
 
-	batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM\n",
-		   &dat_entry->ip, dat_entry->mac_addr);
+	batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %u)\n",
+		   &dat_entry->ip, dat_entry->mac_addr, vid);
 
 out:
 	if (dat_entry)
@@ -858,6 +861,31 @@ out:
 }
 
 /**
+ * batadv_dat_get_vid - extract the VLAN identifier from skb if any
+ * @skb: the buffer containing the packet to extract the VID from
+ * @hdr_size: the size of the batman-adv header encapsulating the packet
+ *
+ * If the packet contained in skb is vlan tagged then this function returns the
+ * VID with the BATADV_VLAN_HAS_TAG flag. Otherwise returns BATADV_NO_FLAGS
+ */
+static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size)
+{
+	unsigned short vid;
+
+	vid = batadv_get_vid(skb, *hdr_size);
+
+	/* ARP parsing functions jump forward of hdr_size + ETH_HLEN.
+	 * If the header contained in the packet is a VLAN one (which is longer)
+	 * hdr_size is updated so that the functions will still jump the
+	 * correct amount of bytes
+	 */
+	if (vid & BATADV_VLAN_HAS_TAG)
+		*hdr_size += VLAN_HLEN;
+
+	return vid;
+}
+
+/**
  * batadv_dat_snoop_outgoing_arp_request - snoop the ARP request and try to
  * answer using DAT
  * @bat_priv: the bat priv with all the soft interface information
@@ -876,11 +904,15 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
 	bool ret = false;
 	struct batadv_dat_entry *dat_entry = NULL;
 	struct sk_buff *skb_new;
+	int hdr_size = 0;
+	unsigned short vid;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
 
-	type = batadv_arp_get_type(bat_priv, skb, 0);
+	vid = batadv_dat_get_vid(skb, &hdr_size);
+
+	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
 	/* If the node gets an ARP_REQUEST it has to send a DHT_GET unicast
 	 * message to the selected DHT candidates
 	 */
@@ -893,9 +925,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
 	hw_src = batadv_arp_hw_src(skb, 0);
 	ip_dst = batadv_arp_ip_dst(skb, 0);
 
-	batadv_dat_entry_add(bat_priv, ip_src, hw_src);
+	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
 
-	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
+	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
 	if (dat_entry) {
 		/* If the ARP request is destined for a local client the local
 		 * client will answer itself. DAT would only generate a
@@ -956,11 +988,14 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
 	struct sk_buff *skb_new;
 	struct batadv_dat_entry *dat_entry = NULL;
 	bool ret = false;
+	unsigned short vid;
 	int err;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
 
+	vid = batadv_dat_get_vid(skb, &hdr_size);
+
 	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
 	if (type != ARPOP_REQUEST)
 		goto out;
@@ -972,9 +1007,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
 	batadv_dbg_arp(bat_priv, skb, type, hdr_size,
 		       "Parsing incoming ARP REQUEST");
 
-	batadv_dat_entry_add(bat_priv, ip_src, hw_src);
+	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
 
-	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
+	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
 	if (!dat_entry)
 		goto out;
 
@@ -992,10 +1027,9 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
 	if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
 		err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
 						    BATADV_P_DAT_CACHE_REPLY,
-						    BATADV_NO_FLAGS);
+						    vid);
 	else
-		err = batadv_send_skb_unicast(bat_priv, skb_new,
-					      BATADV_NO_FLAGS);
+		err = batadv_send_skb_unicast(bat_priv, skb_new, vid);
 
 	if (!err) {
 		batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
@@ -1020,23 +1054,27 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
 	uint16_t type;
 	__be32 ip_src, ip_dst;
 	uint8_t *hw_src, *hw_dst;
+	int hdr_size = 0;
+	unsigned short vid;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		return;
 
-	type = batadv_arp_get_type(bat_priv, skb, 0);
+	vid = batadv_dat_get_vid(skb, &hdr_size);
+
+	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
 	if (type != ARPOP_REPLY)
 		return;
 
 	batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REPLY");
 
-	hw_src = batadv_arp_hw_src(skb, 0);
-	ip_src = batadv_arp_ip_src(skb, 0);
-	hw_dst = batadv_arp_hw_dst(skb, 0);
-	ip_dst = batadv_arp_ip_dst(skb, 0);
+	hw_src = batadv_arp_hw_src(skb, hdr_size);
+	ip_src = batadv_arp_ip_src(skb, hdr_size);
+	hw_dst = batadv_arp_hw_dst(skb, hdr_size);
+	ip_dst = batadv_arp_ip_dst(skb, hdr_size);
 
-	batadv_dat_entry_add(bat_priv, ip_src, hw_src);
-	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst);
+	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
 
 	/* Send the ARP reply to the candidates for both the IP addresses that
 	 * the node obtained from the ARP reply
@@ -1058,10 +1096,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
 	__be32 ip_src, ip_dst;
 	uint8_t *hw_src, *hw_dst;
 	bool ret = false;
+	unsigned short vid;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
 
+	vid = batadv_dat_get_vid(skb, &hdr_size);
+
 	type = batadv_arp_get_type(bat_priv, skb, hdr_size);
 	if (type != ARPOP_REPLY)
 		goto out;
@@ -1077,13 +1118,13 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
 	/* Update our internal cache with both the IP addresses the node got
 	 * within the ARP reply
 	 */
-	batadv_dat_entry_add(bat_priv, ip_src, hw_src);
-	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst);
+	batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid);
+	batadv_dat_entry_add(bat_priv, ip_dst, hw_dst, vid);
 
 	/* if this REPLY is directed to a client of mine, let's deliver the
 	 * packet to the interface
 	 */
-	ret = !batadv_is_my_client(bat_priv, hw_dst, BATADV_NO_FLAGS);
+	ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
 out:
 	if (ret)
 		kfree_skb(skb);
@@ -1106,7 +1147,8 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 	__be32 ip_dst;
 	struct batadv_dat_entry *dat_entry = NULL;
 	bool ret = false;
-	const size_t bcast_len = sizeof(struct batadv_bcast_packet);
+	int hdr_size = sizeof(struct batadv_bcast_packet);
+	unsigned short vid;
 
 	if (!atomic_read(&bat_priv->distributed_arp_table))
 		goto out;
@@ -1117,12 +1159,14 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv,
 	if (forw_packet->num_packets)
 		goto out;
 
-	type = batadv_arp_get_type(bat_priv, forw_packet->skb, bcast_len);
+	vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size);
+
+	type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size);
 	if (type != ARPOP_REQUEST)
 		goto out;
 
-	ip_dst = batadv_arp_ip_dst(forw_packet->skb, bcast_len);
-	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst);
+	ip_dst = batadv_arp_ip_dst(forw_packet->skb, hdr_size);
+	dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
 	/* check if the node already got this entry */
 	if (!dat_entry) {
 		batadv_dbg(BATADV_DBG_DAT, bat_priv,
diff --git a/types.h b/types.h
index 7d8aa46..20a1bef 100644
--- a/types.h
+++ b/types.h
@@ -933,6 +933,7 @@ struct batadv_algo_ops {
  * is used to stored ARP entries needed for the global DAT cache
  * @ip: the IPv4 corresponding to this DAT/ARP entry
  * @mac_addr: the MAC address associated to the stored IPv4
+ * @vid: the vlan ID associated to this entry
  * @last_update: time in jiffies when this entry was refreshed last time
  * @hash_entry: hlist node for batadv_priv_dat::hash
  * @refcount: number of contexts the object is used
@@ -941,6 +942,7 @@ struct batadv_algo_ops {
 struct batadv_dat_entry {
 	__be32 ip;
 	uint8_t mac_addr[ETH_ALEN];
+	unsigned short vid;
 	unsigned long last_update;
 	struct hlist_node hash_entry;
 	atomic_t refcount;
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 06/13] batman-adv: add per VLAN interface attribute framework
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (4 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 07/13] batman-adv: initialise sysfs folder in softif_create() Antonio Quartulli
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Since batman-adv is now fully VLAN-aware, a proper framework
able to handle per-vlan-interface attributes is needed.

Those attributes will affect the associated VLAN interface
only, rather than the real soft_iface (which would result
in every vlan interface having the same attribute
configuration)

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 compat.c         |  9 ++++++
 compat.h         | 24 +++++++++++++++
 main.c           | 44 ++++++++++++++++++++++++++++
 main.h           |  3 ++
 soft-interface.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 types.h          | 21 +++++++++++++
 6 files changed, 190 insertions(+)

diff --git a/compat.c b/compat.c
index da556a4..0a98fb7 100644
--- a/compat.c
+++ b/compat.c
@@ -27,6 +27,15 @@
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
 
+void batadv_free_rcu_softif_vlan(struct rcu_head *rcu)
+{
+	struct batadv_softif_vlan *vlan;
+
+	vlan = container_of(rcu, struct batadv_softif_vlan, rcu);
+
+	kfree(vlan);
+}
+
 void batadv_free_rcu_tt_global_entry(struct rcu_head *rcu)
 {
 	struct batadv_tt_global_entry *global;
diff --git a/compat.h b/compat.h
index dbf1926..1ee0467 100644
--- a/compat.h
+++ b/compat.h
@@ -182,6 +182,7 @@ static const struct { \
 #define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, batadv_free_rcu_##ptr)
 #define vlan_insert_tag(skb, proto, vid) __vlan_put_tag(skb, vid)
 
+void batadv_free_rcu_softif_vlan(struct rcu_head *rcu);
 void batadv_free_rcu_tt_global_entry(struct rcu_head *rcu);
 void batadv_free_rcu_gw_node(struct rcu_head *rcu);
 void batadv_free_rcu_neigh_node(struct rcu_head *rcu);
@@ -300,6 +301,29 @@ static int __batadv_interface_set_mac_addr(x, y)
 #include <linux/if_vlan.h>
 #define vlan_insert_tag(skb, proto, vid) vlan_insert_tag(skb, vid)
 
+#define NETIF_F_HW_VLAN_CTAG_FILTER NETIF_F_HW_VLAN_FILTER
+
+#define batadv_interface_add_vid(x, y, z) \
+__batadv_interface_add_vid(struct net_device *dev, __be16 proto,\
+			   unsigned short vid);\
+static int batadv_interface_add_vid(struct net_device *dev, unsigned short vid)\
+{\
+	return __batadv_interface_add_vid(dev, htons(ETH_P_8021Q), vid);\
+} \
+static int __batadv_interface_add_vid(struct net_device *dev, __be16 proto,\
+				      unsigned short vid)
+
+#define batadv_interface_kill_vid(x, y, z) \
+__batadv_interface_kill_vid(struct net_device *dev, __be16 proto,\
+			    unsigned short vid);\
+static int batadv_interface_kill_vid(struct net_device *dev,\
+				     unsigned short vid)\
+{\
+	return __batadv_interface_kill_vid(dev, htons(ETH_P_8021Q), vid);\
+} \
+static int __batadv_interface_kill_vid(struct net_device *dev, __be16 proto,\
+				       unsigned short vid)
+
 #endif /* vlan_insert_tag */
 
 #endif /* < KERNEL_VERSION(3, 10, 0) */
diff --git a/main.c b/main.c
index 7bd8618..7525d96 100644
--- a/main.c
+++ b/main.c
@@ -109,6 +109,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	spin_lock_init(&bat_priv->gw.list_lock);
 	spin_lock_init(&bat_priv->tvlv.container_list_lock);
 	spin_lock_init(&bat_priv->tvlv.handler_list_lock);
+	spin_lock_init(&bat_priv->softif_vlan_list_lock);
 
 	INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
 	INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
@@ -118,6 +119,7 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	INIT_LIST_HEAD(&bat_priv->tt.roam_list);
 	INIT_HLIST_HEAD(&bat_priv->tvlv.container_list);
 	INIT_HLIST_HEAD(&bat_priv->tvlv.handler_list);
+	INIT_LIST_HEAD(&bat_priv->softif_vlan_list);
 
 	ret = batadv_originator_init(bat_priv);
 	if (ret < 0)
@@ -1115,6 +1117,48 @@ unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len)
 	return vid;
 }
 
+/**
+ * batadv_softif_vlan_free_ref - decrease vlan refcounter and possibly free it
+ * @softif_vlan: the vlan object to release
+ */
+void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan)
+{
+	if (atomic_dec_and_test(&softif_vlan->refcount))
+		kfree_rcu(softif_vlan, rcu);
+}
+
+/**
+ * batadv_softif_vlan_get - get VLAN priv data
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the identifier of the VLAN data to retrieve
+ *
+ * Return the private data of the VLAN matching vid and increments its
+ * refcounter or NULL otherwise.
+ */
+struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
+						  unsigned short vid)
+{
+	struct batadv_softif_vlan *vlan, *vlan_tmp = NULL;
+
+	if (!(vid & BATADV_VLAN_HAS_TAG))
+		return NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+		if (vlan->vid != (vid & VLAN_VID_MASK))
+			continue;
+
+		if (!atomic_inc_not_zero(&vlan->refcount))
+			continue;
+
+		vlan_tmp = vlan;
+		break;
+	}
+	rcu_read_unlock();
+
+	return vlan_tmp;
+}
+
 static int batadv_param_set_ra(const char *val, const struct kernel_param *kp)
 {
 	struct batadv_algo_ops *bat_algo_ops;
diff --git a/main.h b/main.h
index cfed2a3..fe9a952 100644
--- a/main.h
+++ b/main.h
@@ -199,6 +199,9 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops);
 int batadv_algo_select(struct batadv_priv *bat_priv, char *name);
 int batadv_algo_seq_print_text(struct seq_file *seq, void *offset);
 __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr);
+void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *softif_vlan);
+struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
+						  unsigned short vid);
 
 /**
  * enum batadv_dbg_level - available log levels
diff --git a/soft-interface.c b/soft-interface.c
index 43390d1..7b0d1aa 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -372,6 +372,92 @@ out:
 	return;
 }
 
+/**
+ * batadv_interface_add_vid - ndo_add_vid API implementation
+ * @dev: the netdev of the mesh interface
+ * @vid: identifier of the new VLAN
+ *
+ * Set up all the internal structures for handling the new VLAN on top of the
+ * mesh interface
+ *
+ * Return 0 on success or a negative error code in case of failure
+ */
+static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
+				    unsigned short vid)
+{
+	struct batadv_priv *bat_priv = netdev_priv(dev);
+	struct batadv_softif_vlan *vlan;
+
+	/* only 802.1Q vlans are supported. batman-adv does not know how to
+	 * handle other types
+	 */
+	if (proto != htons(ETH_P_8021Q))
+		return -EINVAL;
+
+	vlan = kmalloc(sizeof(*vlan), GFP_ATOMIC);
+	if (!vlan)
+		return -ENOMEM;
+
+	vlan->vid = vid;
+	atomic_set(&vlan->refcount, 1);
+
+	/* add a new TT local entry. This one will be marked with the NOPURGE
+	 * flag
+	 */
+	batadv_tt_local_add(dev, dev->dev_addr, vid | BATADV_VLAN_HAS_TAG,
+			    BATADV_NULL_IFINDEX);
+
+	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+	list_add_rcu(&vlan->list, &bat_priv->softif_vlan_list);
+	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
+
+	return 0;
+}
+
+/**
+ * batadv_interface_kill_vid - ndo_kill_vid API implementation
+ * @dev: the netdev of the mesh interface
+ * @vid: identifier of the deleted VLAN
+ *
+ * Destroy all the internal structures used to handle the VLAN identified by vid
+ * on top of the mesh interface
+ *
+ * Return 0 or -EINVAL if the specified prototype is not ETH_P_8021Q
+ */
+static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
+				     unsigned short vid)
+{
+	struct batadv_priv *bat_priv = netdev_priv(dev);
+	struct batadv_softif_vlan *vlan;
+
+	/* only 802.1Q vlans are supported. batman-adv does not know how to
+	 * handle other types
+	 */
+	if (proto != htons(ETH_P_8021Q))
+		return -EINVAL;
+
+	vlan = batadv_softif_vlan_get(bat_priv, vid & BATADV_VLAN_HAS_TAG);
+	if (!vlan)
+		return -EINVAL;
+
+	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
+	list_del_rcu(&vlan->list);
+	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
+
+	/* explicitly remove the associated TT local entry because it is marked
+	 * with the NOPURGE flag
+	 */
+	batadv_tt_local_remove(bat_priv, dev->dev_addr, vid,
+			       "vlan interface destroyed", false);
+
+	/* batadv_softif_vlan_get() increased the refcounter by 1 */
+	batadv_softif_vlan_free_ref(vlan);
+	/* finally free the vlan object */
+	batadv_softif_vlan_free_ref(vlan);
+
+	return 0;
+}
+
 /* batman-adv network devices have devices nesting below it and are a special
  * "super class" of normal network devices; split their locks off into a
  * separate class since they always nest.
@@ -573,6 +659,8 @@ static const struct net_device_ops batadv_netdev_ops = {
 	.ndo_open = batadv_interface_open,
 	.ndo_stop = batadv_interface_release,
 	.ndo_get_stats = batadv_interface_stats,
+	.ndo_vlan_rx_add_vid = batadv_interface_add_vid,
+	.ndo_vlan_rx_kill_vid = batadv_interface_kill_vid,
 	.ndo_set_mac_address = batadv_interface_set_mac_addr,
 	.ndo_change_mtu = batadv_interface_change_mtu,
 	.ndo_start_xmit = batadv_interface_tx,
@@ -611,6 +699,7 @@ static void batadv_softif_init_early(struct net_device *dev)
 
 	dev->netdev_ops = &batadv_netdev_ops;
 	dev->destructor = batadv_softif_free;
+	dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
 	dev->tx_queue_len = 0;
 
 	/* can't call min_mtu, because the needed variables
diff --git a/types.h b/types.h
index 20a1bef..9fdf2c2 100644
--- a/types.h
+++ b/types.h
@@ -530,6 +530,22 @@ struct batadv_priv_nc {
 	struct batadv_hashtable *decoding_hash;
 };
 
+/*
+ * struct batadv_softif_vlan - per VLAN attributes set
+ * @vid: VLAN identifier
+ * @kobj: kobject for sysfs vlan subdirectory
+ * @list: list node for bat_priv::softif_vlan_list
+ * @refcount: number of context where this object is currently in use
+ * @rcu: struct used for freeing in a RCU-safe manner
+ */
+struct batadv_softif_vlan {
+	unsigned short vid;
+	struct kobject *kobj;
+	struct list_head list;
+	atomic_t refcount;
+	struct rcu_head rcu;
+};
+
 /**
  * struct batadv_priv - per mesh interface data
  * @mesh_state: current status of the mesh (inactive/active/deactivating)
@@ -566,6 +582,9 @@ struct batadv_priv_nc {
  * @primary_if: one of the hard interfaces assigned to this mesh interface
  *  becomes the primary interface
  * @bat_algo_ops: routing algorithm used by this mesh interface
+ * @softif_vlan_list: a list of softif_vlan structs, one per VLAN created on top
+ *  of the mesh interface represented by this object
+ * @softif_vlan_list_lock: lock protecting softif_vlan_list
  * @bla: bridge loope avoidance data
  * @debug_log: holding debug logging relevant data
  * @gw: gateway data
@@ -613,6 +632,8 @@ struct batadv_priv {
 	struct work_struct cleanup_work;
 	struct batadv_hard_iface __rcu *primary_if;  /* rcu protected pointer */
 	struct batadv_algo_ops *bat_algo_ops;
+	struct list_head softif_vlan_list;
+	spinlock_t softif_vlan_list_lock; /* protects softif_vlan_list */
 #ifdef CONFIG_BATMAN_ADV_BLA
 	struct batadv_priv_bla bla;
 #endif
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 07/13] batman-adv: initialise sysfs folder in softif_create()
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (5 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 06/13] batman-adv: add per VLAN interface attribute framework Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN Antonio Quartulli
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Move the sysfs folder creation from the netdev event handler
to softif_create() so that it is created immediately after
netdev registration.

This change allows any other routine to create sysfs
subfolders and files during mesh initialisation.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 hard-interface.c |  5 ++---
 soft-interface.c | 14 ++++++++++++--
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/hard-interface.c b/hard-interface.c
index d564af2..1278a73 100644
--- a/hard-interface.c
+++ b/hard-interface.c
@@ -641,10 +641,9 @@ static int batadv_hard_if_event(struct notifier_block *this,
 	struct batadv_hard_iface *primary_if = NULL;
 	struct batadv_priv *bat_priv;
 
-	if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
-		batadv_sysfs_add_meshif(net_dev);
+	/* do not handle any event for any soft_iface */
+	if (batadv_softif_is_valid(net_dev))
 		return NOTIFY_DONE;
-	}
 
 	hard_iface = batadv_hardif_get_by_netdev(net_dev);
 	if (!hard_iface && event == NETDEV_REGISTER)
diff --git a/soft-interface.c b/soft-interface.c
index 7b0d1aa..414b4b1 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -720,6 +720,7 @@ static void batadv_softif_init_early(struct net_device *dev)
 struct net_device *batadv_softif_create(const char *name)
 {
 	struct net_device *soft_iface;
+	struct batadv_priv *bat_priv;
 	int ret;
 
 	soft_iface = alloc_netdev(sizeof(struct batadv_priv), name,
@@ -733,11 +734,20 @@ struct net_device *batadv_softif_create(const char *name)
 	if (ret < 0) {
 		pr_err("Unable to register the batman interface '%s': %i\n",
 		       name, ret);
-		free_netdev(soft_iface);
-		return NULL;
+		goto free_dev;
 	}
 
+	ret = batadv_sysfs_add_meshif(soft_iface);
+	if (ret < 0)
+		goto free_mesh;
+
 	return soft_iface;
+
+free_mesh:
+	batadv_mesh_free(soft_iface);
+free_dev:
+	free_netdev(soft_iface);
+	return NULL;
 }
 
 /**
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (6 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 07/13] batman-adv: initialise sysfs folder in softif_create() Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-09 14:13   ` Marek Lindner
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 09/13] batman-adv: add sysfs framework for VLAN Antonio Quartulli
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

To make the code simpler and easier to extend, treat the
normal LAN (bat0) like any other VLAN having vid 0
(untagged).

This change makes things simpler since bat0 is not a
particular case anymore but it is treated like any other
VLAN.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 main.c           |  8 +-------
 soft-interface.c | 61 +++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/main.c b/main.c
index 7525d96..455661b 100644
--- a/main.c
+++ b/main.c
@@ -129,9 +129,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
 	if (ret < 0)
 		goto err;
 
-	batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
-			    BATADV_NULL_IFINDEX, BATADV_NO_FLAGS);
-
 	ret = batadv_bla_init(bat_priv);
 	if (ret < 0)
 		goto err;
@@ -1140,12 +1137,9 @@ struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
 {
 	struct batadv_softif_vlan *vlan, *vlan_tmp = NULL;
 
-	if (!(vid & BATADV_VLAN_HAS_TAG))
-		return NULL;
-
 	rcu_read_lock();
 	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
-		if (vlan->vid != (vid & VLAN_VID_MASK))
+		if (vlan->vid != vid)
 			continue;
 
 		if (!atomic_inc_not_zero(&vlan->refcount))
diff --git a/soft-interface.c b/soft-interface.c
index 414b4b1..0280dfc 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -373,28 +373,18 @@ out:
 }
 
 /**
- * batadv_interface_add_vid - ndo_add_vid API implementation
- * @dev: the netdev of the mesh interface
- * @vid: identifier of the new VLAN
- *
- * Set up all the internal structures for handling the new VLAN on top of the
- * mesh interface
+ * batadv_create_vlan - allocate the needed resources for a new vlan
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the VLAN identifier
  *
- * Return 0 on success or a negative error code in case of failure
+ * Return 0 on success, a negative error otherwise.
  */
-static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
-				    unsigned short vid)
+static int batadv_softif_create_vlan(struct batadv_priv *bat_priv,
+				     unsigned short vid)
 {
-	struct batadv_priv *bat_priv = netdev_priv(dev);
 	struct batadv_softif_vlan *vlan;
 
-	/* only 802.1Q vlans are supported. batman-adv does not know how to
-	 * handle other types
-	 */
-	if (proto != htons(ETH_P_8021Q))
-		return -EINVAL;
-
-	vlan = kmalloc(sizeof(*vlan), GFP_ATOMIC);
+	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
 	if (!vlan)
 		return -ENOMEM;
 
@@ -404,7 +394,8 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
 	/* add a new TT local entry. This one will be marked with the NOPURGE
 	 * flag
 	 */
-	batadv_tt_local_add(dev, dev->dev_addr, vid | BATADV_VLAN_HAS_TAG,
+	batadv_tt_local_add(bat_priv->soft_iface,
+			    bat_priv->soft_iface->dev_addr, vid,
 			    BATADV_NULL_IFINDEX);
 
 	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
@@ -415,6 +406,32 @@ static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
 }
 
 /**
+ * batadv_interface_add_vid - ndo_add_vid API implementation
+ * @dev: the netdev of the mesh interface
+ * @vid: identifier of the new VLAN
+ *
+ * Set up all the internal structures for handling the new VLAN on top of the
+ * mesh interface
+ *
+ * Return 0 on success or a negative error code otherwise
+ */
+static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,
+				    unsigned short vid)
+{
+	struct batadv_priv *bat_priv = netdev_priv(dev);
+
+	/* only 802.1Q vlans are supported.
+	 * batman-adv does not know how to handle other types
+	 */
+	if (proto != htons(ETH_P_8021Q))
+		return -EINVAL;
+
+	vid |= BATADV_VLAN_HAS_TAG;
+
+	return batadv_softif_create_vlan(bat_priv, vid);
+}
+
+/**
  * batadv_interface_kill_vid - ndo_kill_vid API implementation
  * @dev: the netdev of the mesh interface
  * @vid: identifier of the deleted VLAN
@@ -741,8 +758,16 @@ struct net_device *batadv_softif_create(const char *name)
 	if (ret < 0)
 		goto free_mesh;
 
+	bat_priv = netdev_priv(soft_iface);
+	/* add the "untagged" LAN */
+	ret = batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS);
+	if (ret < 0)
+		goto free_sysfs;
+
 	return soft_iface;
 
+free_sysfs:
+	batadv_sysfs_del_meshif(soft_iface);
 free_mesh:
 	batadv_mesh_free(soft_iface);
 free_dev:
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 09/13] batman-adv: add sysfs framework for VLAN
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (7 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 10/13] batman-adv: make the AP isolation attribute VLAN specific Antonio Quartulli
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Each VLAN can now have its own set of attributes and these
are exported through a new subfolder in the sysfs
environment.

The subfolder is named "vlan%VID", there will be one per
VLAN, and it is created inside the "mesh" sysfs folder
belonging to batman-adv.

Create all the needed macros and data structures to easily
handle new attributes.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 soft-interface.c |   7 +++
 sysfs.c          | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sysfs.h          |  10 ++++
 3 files changed, 155 insertions(+)

diff --git a/soft-interface.c b/soft-interface.c
index 0280dfc..e6679e2 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -383,6 +383,7 @@ static int batadv_softif_create_vlan(struct batadv_priv *bat_priv,
 				     unsigned short vid)
 {
 	struct batadv_softif_vlan *vlan;
+	int err;
 
 	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
 	if (!vlan)
@@ -398,6 +399,10 @@ static int batadv_softif_create_vlan(struct batadv_priv *bat_priv,
 			    bat_priv->soft_iface->dev_addr, vid,
 			    BATADV_NULL_IFINDEX);
 
+	err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
+	if (err)
+		return err;
+
 	spin_lock_bh(&bat_priv->softif_vlan_list_lock);
 	list_add_rcu(&vlan->list, &bat_priv->softif_vlan_list);
 	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
@@ -461,6 +466,8 @@ static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,
 	list_del_rcu(&vlan->list);
 	spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
 
+	batadv_sysfs_del_vlan(bat_priv, vlan);
+
 	/* explicitly remove the associated TT local entry because it is marked
 	 * with the NOPURGE flag
 	 */
diff --git a/sysfs.c b/sysfs.c
index b70ae52..03285dd 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -39,6 +39,31 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)
 	return netdev_priv(net_dev);
 }
 
+/**
+ * batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
+ * @obj: kobject to covert
+ *
+ * Return the associated softif_vlan struct if cound, NULL otherwise
+ */
+static struct batadv_softif_vlan *batadv_kobj_to_vlan(struct kobject *obj)
+{
+	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(obj->parent);
+	struct batadv_softif_vlan *vlan, *vlan_tmp = NULL;
+
+	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+		if (vlan->kobj != obj)
+			continue;
+
+		if (!atomic_inc_not_zero(&vlan->refcount))
+			continue;
+
+		vlan_tmp = vlan;
+		break;
+	}
+
+	return vlan_tmp;
+}
+
 #define BATADV_UEV_TYPE_VAR	"BATTYPE="
 #define BATADV_UEV_ACTION_VAR	"BATACTION="
 #define BATADV_UEV_DATA_VAR	"BATDATA="
@@ -53,6 +78,15 @@ static char *batadv_uev_type_str[] = {
 	"gw"
 };
 
+/* Use this, if you have customized show and store functions for vlan attrs */
+#define BATADV_ATTR_VLAN(_name, _mode, _show, _store)	\
+struct batadv_attribute batadv_attr_vlan_##_name = {	\
+	.attr = {.name = __stringify(_name),		\
+		 .mode = _mode },			\
+	.show   = _show,				\
+	.store  = _store,				\
+};
+
 /* Use this, if you have customized show and store functions */
 #define BATADV_ATTR(_name, _mode, _show, _store)	\
 struct batadv_attribute batadv_attr_##_name = {		\
@@ -122,6 +156,38 @@ ssize_t batadv_show_##_name(struct kobject *kobj,			\
 	static BATADV_ATTR(_name, _mode, batadv_show_##_name,		\
 			   batadv_store_##_name)
 
+#define BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func)			\
+ssize_t batadv_store_vlan_##_name(struct kobject *kobj,			\
+				  struct attribute *attr, char *buff,	\
+				  size_t count)				\
+{									\
+	struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj->parent);\
+	struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(kobj);	\
+	size_t res = __batadv_store_bool_attr(buff, count, _post_func, attr,\
+					      &vlan->_name,		\
+					      bat_priv->soft_iface);	\
+	batadv_softif_vlan_free_ref(vlan);				\
+	return res;							\
+}
+
+#define BATADV_ATTR_VLAN_SHOW_BOOL(_name)				\
+ssize_t batadv_show_vlan_##_name(struct kobject *kobj,			\
+			    struct attribute *attr, char *buff)		\
+{									\
+	struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(kobj);	\
+	size_t res =  sprintf(buff, "%s\n",				\
+			      atomic_read(&vlan->_name) == 0 ?		\
+			      "disabled" : "enabled");			\
+	batadv_softif_vlan_free_ref(vlan);				\
+	return res;							\
+}
+
+/* Use this, if you are going to turn a [name] in the vlan struct on or off */
+#define BATADV_ATTR_VLAN_BOOL(_name, _mode, _post_func)			\
+	static BATADV_ATTR_VLAN_STORE_BOOL(_name, _post_func)		\
+	static BATADV_ATTR_VLAN_SHOW_BOOL(_name)			\
+	static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name,	\
+				batadv_store_vlan_##_name)
 
 static int batadv_store_bool_attr(char *buff, size_t count,
 				  struct net_device *net_dev,
@@ -403,6 +469,13 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 	NULL,
 };
 
+/**
+ * batadv_vlan_attrs - array of vlan specific sysfs attributes
+ */
+static struct batadv_attribute *batadv_vlan_attrs[] = {
+	NULL,
+};
+
 int batadv_sysfs_add_meshif(struct net_device *dev)
 {
 	struct kobject *batif_kobject = &dev->dev.kobj;
@@ -453,6 +526,71 @@ void batadv_sysfs_del_meshif(struct net_device *dev)
 	bat_priv->mesh_obj = NULL;
 }
 
+/**
+ * batadv_sysfs_add_vlan - add all the needed sysfs objects for the new vlan
+ * @dev: netdev of the mesh interface
+ * @vlan: private data of the newly added VLAN interface
+ *
+ * Return 0 on success and -ENOMEM if any of the structure allocations fails
+ */
+int batadv_sysfs_add_vlan(struct net_device *dev,
+			  struct batadv_softif_vlan *vlan)
+{
+	struct batadv_priv *bat_priv = netdev_priv(dev);
+	struct batadv_attribute **bat_attr;
+	char vlan_subdir[256];
+	int err;
+
+	sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%u",
+		vlan->vid & VLAN_VID_MASK);
+
+	vlan->kobj = kobject_create_and_add(vlan_subdir, bat_priv->mesh_obj);
+	if (!vlan->kobj) {
+		batadv_err(dev, "Can't add sysfs directory: %s/%s\n", dev->name,
+			   vlan_subdir);
+		goto out;
+	}
+
+	for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr) {
+		err = sysfs_create_file(vlan->kobj,
+					&((*bat_attr)->attr));
+		if (err) {
+			batadv_err(dev, "Can't add sysfs file: %s/%s/%s\n",
+				   dev->name, vlan_subdir,
+				   ((*bat_attr)->attr).name);
+			goto rem_attr;
+		}
+	}
+
+	return 0;
+
+rem_attr:
+	for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
+		sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
+
+	kobject_put(vlan->kobj);
+	vlan->kobj = NULL;
+out:
+	return -ENOMEM;
+}
+
+/**
+ * batadv_sysfs_del_vlan - remove all the sysfs objects for a given VLAN
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vlan: the private data of the VLAN to destroy
+ */
+void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
+			   struct batadv_softif_vlan *vlan)
+{
+	struct batadv_attribute **bat_attr;
+
+	for (bat_attr = batadv_vlan_attrs; *bat_attr; ++bat_attr)
+		sysfs_remove_file(vlan->kobj, &((*bat_attr)->attr));
+
+	kobject_put(vlan->kobj);
+	vlan->kobj = NULL;
+}
+
 static ssize_t batadv_show_mesh_iface(struct kobject *kobj,
 				      struct attribute *attr, char *buff)
 {
diff --git a/sysfs.h b/sysfs.h
index 479acf4..c4f96c1 100644
--- a/sysfs.h
+++ b/sysfs.h
@@ -22,6 +22,12 @@
 
 #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh"
 #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv"
+/**
+ * BATADV_SYSFS_VLAN_SUBDIR_PREFIX - prefix of the subfolder that will be
+ *  created in the sysfs hierarchy for each VLAN interface. The subfolder will
+ *  be named "BATADV_SYSFS_VLAN_SUBDIR_PREFIX%vid"
+ */
+#define BATADV_SYSFS_VLAN_SUBDIR_PREFIX "vlan"
 
 struct batadv_attribute {
 	struct attribute attr;
@@ -36,6 +42,10 @@ void batadv_sysfs_del_meshif(struct net_device *dev);
 int batadv_sysfs_add_hardif(struct kobject **hardif_obj,
 			    struct net_device *dev);
 void batadv_sysfs_del_hardif(struct kobject **hardif_obj);
+int batadv_sysfs_add_vlan(struct net_device *dev,
+			  struct batadv_softif_vlan *vlan);
+void batadv_sysfs_del_vlan(struct batadv_priv *bat_priv,
+			   struct batadv_softif_vlan *vlan);
 int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,
 			enum batadv_uev_action action, const char *data);
 
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 10/13] batman-adv: make the AP isolation attribute VLAN specific
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (8 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 09/13] batman-adv: add sysfs framework for VLAN Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 11/13] batman-adv: make the backbone gw check " Antonio Quartulli
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

AP isolation has to be enabled on one VLAN interface only.
This patch moves the AP isolation attribute to the per-vlan
interface attribute set, enabling it to have a different
value depending on the selected vlan.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 soft-interface.c     |  5 ++++-
 sysfs-class-net-mesh |  2 +-
 sysfs.c              |  4 ++++
 translation-table.c  | 21 +++++++++++++++------
 translation-table.h  |  2 +-
 types.h              |  2 ++
 6 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/soft-interface.c b/soft-interface.c
index e6679e2..17fa0f1 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/netdevice.h>
 #include <linux/if_vlan.h>
 #include "bridge_loop_avoidance.h"
 #include "network-coding.h"
@@ -360,7 +361,8 @@ void batadv_interface_rx(struct net_device *soft_iface,
 		batadv_tt_add_temporary_global_entry(bat_priv, orig_node,
 						     ethhdr->h_source, vid);
 
-	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest))
+	if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
+				  vid))
 		goto dropped;
 
 	netif_rx(skb);
@@ -398,6 +400,7 @@ static int batadv_softif_create_vlan(struct batadv_priv *bat_priv,
 	batadv_tt_local_add(bat_priv->soft_iface,
 			    bat_priv->soft_iface->dev_addr, vid,
 			    BATADV_NULL_IFINDEX);
+	atomic_set(&vlan->ap_isolation, 0);
 
 	err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
 	if (err)
diff --git a/sysfs-class-net-mesh b/sysfs-class-net-mesh
index f00a69b..3b1dd13 100644
--- a/sysfs-class-net-mesh
+++ b/sysfs-class-net-mesh
@@ -6,7 +6,7 @@ Description:
                 Indicates whether the batman protocol messages of the
                 mesh <mesh_iface> shall be aggregated or not.
 
-What:           /sys/class/net/<mesh_iface>/mesh/ap_isolation
+What:           /sys/class/net/<mesh_iface>/mesh/<vlan_subdir>/ap_isolation
 Date:           May 2011
 Contact:        Antonio Quartulli <ordex@autistici.org>
 Description:
diff --git a/sysfs.c b/sysfs.c
index 03285dd..09a4031 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -469,10 +469,14 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 	NULL,
 };
 
+/* vlan attributes below */
+BATADV_ATTR_VLAN_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
+
 /**
  * batadv_vlan_attrs - array of vlan specific sysfs attributes
  */
 static struct batadv_attribute *batadv_vlan_attrs[] = {
+	&batadv_attr_vlan_ap_isolation,
 	NULL,
 };
 
diff --git a/translation-table.c b/translation-table.c
index dd573b9..e600fea 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -1478,12 +1478,23 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 						  const uint8_t *addr,
 						  unsigned short vid)
 {
+	bool ap_isolation_enabled = atomic_read(&bat_priv->ap_isolation);
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
 	struct batadv_orig_node *orig_node = NULL;
 	struct batadv_tt_orig_list_entry *best_entry;
+	struct batadv_softif_vlan *vlan;
 
-	if (src && atomic_read(&bat_priv->ap_isolation)) {
+	/* if the AP isolation is requested on a VLAN, then check for the
+	 * its setting in the proper VLAN private data structure
+	 */
+	vlan = batadv_softif_vlan_get(bat_priv, vid);
+	if (vlan) {
+		ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
+		batadv_softif_vlan_free_ref(vlan);
+	}
+
+	if (src && ap_isolation_enabled) {
 		tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
 		if (!tt_local_entry ||
 		    (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
@@ -2546,7 +2557,7 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
 }
 
 bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
-			   uint8_t *dst)
+			   uint8_t *dst, unsigned short vid)
 {
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
@@ -2555,13 +2566,11 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
 	if (!atomic_read(&bat_priv->ap_isolation))
 		goto out;
 
-	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst,
-						   BATADV_NO_FLAGS);
+	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
 	if (!tt_local_entry)
 		goto out;
 
-	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src,
-						     BATADV_NO_FLAGS);
+	tt_global_entry = batadv_tt_global_hash_find(bat_priv, src, vid);
 	if (!tt_global_entry)
 		goto out;
 
diff --git a/translation-table.h b/translation-table.h
index 1d9506d..c6bf33c 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -39,7 +39,7 @@ void batadv_tt_free(struct batadv_priv *bat_priv);
 bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr,
 			 unsigned short vid);
 bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
-			   uint8_t *dst);
+			   uint8_t *dst, unsigned short vid);
 void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv);
 bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
 					uint8_t *addr, unsigned short vid);
diff --git a/types.h b/types.h
index 9fdf2c2..ad8671d 100644
--- a/types.h
+++ b/types.h
@@ -534,6 +534,7 @@ struct batadv_priv_nc {
  * struct batadv_softif_vlan - per VLAN attributes set
  * @vid: VLAN identifier
  * @kobj: kobject for sysfs vlan subdirectory
+ * @ap_isolation: AP isolation state
  * @list: list node for bat_priv::softif_vlan_list
  * @refcount: number of context where this object is currently in use
  * @rcu: struct used for freeing in a RCU-safe manner
@@ -541,6 +542,7 @@ struct batadv_priv_nc {
 struct batadv_softif_vlan {
 	unsigned short vid;
 	struct kobject *kobj;
+	atomic_t ap_isolation;		/* boolean */
 	struct list_head list;
 	atomic_t refcount;
 	struct rcu_head rcu;
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 11/13] batman-adv: make the backbone gw check VLAN specific
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (9 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 10/13] batman-adv: make the AP isolation attribute VLAN specific Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 12/13] batman-adv: make the TT global purge routine " Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 13/13] batman-adv: make the TT CRC logic " Antonio Quartulli
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Simon Wunderlich, Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

The backbone gw check has to be vlan specific so that code
using it can be aware of which is the VLAN connecting two of
them.

In the TT code, the check has been moved into the
tt_global_add() functions so that it can be performed on a
per-entry basis instead of ignoring all the TT data received
from another backbone node.

Moreover, batadv_bla_is_backbone_gw_orig() now returns bool
since it used to return only 1 or 0.

Cc: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bridge_loop_avoidance.c | 19 +++++++++++--------
 bridge_loop_avoidance.h | 10 ++++++----
 translation-table.c     | 35 ++++++-----------------------------
 3 files changed, 23 insertions(+), 41 deletions(-)

diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c
index 02f6f81..72df179 100644
--- a/bridge_loop_avoidance.c
+++ b/bridge_loop_avoidance.c
@@ -1311,12 +1311,14 @@ out:
 
 /* @bat_priv: the bat priv with all the soft interface information
  * @orig: originator mac address
+ * @vid: VLAN identifier
  *
- * check if the originator is a gateway for any VLAN ID.
+ * check if the originator is a gateway for VLAN idenfied by vid.
  *
- * returns 1 if it is found, 0 otherwise
+ * returns true if orig is a backbone for this vid, false otherwise
  */
-int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
+bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig,
+				    unsigned short vid)
 {
 	struct batadv_hashtable *hash = bat_priv->bla.backbone_hash;
 	struct hlist_head *head;
@@ -1324,25 +1326,26 @@ int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig)
 	int i;
 
 	if (!atomic_read(&bat_priv->bridge_loop_avoidance))
-		return 0;
+		return false;
 
 	if (!hash)
-		return 0;
+		return false;
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
-			if (batadv_compare_eth(backbone_gw->orig, orig)) {
+			if (batadv_compare_eth(backbone_gw->orig, orig) &&
+			    backbone_gw->vid == vid) {
 				rcu_read_unlock();
-				return 1;
+				return true;
 			}
 		}
 		rcu_read_unlock();
 	}
 
-	return 0;
+	return false;
 }
 
 
diff --git a/bridge_loop_avoidance.h b/bridge_loop_avoidance.h
index 4b102e7..da173e7 100644
--- a/bridge_loop_avoidance.h
+++ b/bridge_loop_avoidance.h
@@ -30,7 +30,8 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb,
 int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq,
 					     void *offset);
-int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig);
+bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig,
+				    unsigned short vid);
 int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
 				   struct sk_buff *skb);
 void batadv_bla_update_orig_address(struct batadv_priv *bat_priv,
@@ -74,10 +75,11 @@ static inline int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq,
 	return 0;
 }
 
-static inline int batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv,
-						 uint8_t *orig)
+static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv,
+						  uint8_t *orig,
+						  unsigned short vid)
 {
-	return 0;
+	return false;
 }
 
 static inline int
diff --git a/translation-table.c b/translation-table.c
index e600fea..4ced045 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -906,6 +906,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
 	struct batadv_tt_common_entry *common;
 	uint16_t local_flags;
 
+	/* ignore global entries from backbone nodes */
+	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
+		return true;
+
 	tt_global_entry = batadv_tt_global_hash_find(bat_priv, tt_addr, vid);
 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, tt_addr, vid);
 
@@ -2113,16 +2117,11 @@ static bool batadv_send_tt_response(struct batadv_priv *bat_priv,
 				    struct batadv_tvlv_tt_data *tt_data,
 				    uint8_t *req_src, uint8_t *req_dst)
 {
-	if (batadv_is_my_mac(bat_priv, req_dst)) {
-		/* don't answer backbone gws! */
-		if (batadv_bla_is_backbone_gw_orig(bat_priv, req_src))
-			return true;
-
+	if (batadv_is_my_mac(bat_priv, req_dst))
 		return batadv_send_my_tt_response(bat_priv, tt_data, req_src);
-	} else {
+	else
 		return batadv_send_other_tt_response(bat_priv, tt_data,
 						     req_src, req_dst);
-	}
 }
 
 static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
@@ -2251,10 +2250,6 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
 		   resp_src, tt_data->ttvn, num_entries,
 		   (tt_data->flags & BATADV_TT_FULL_TABLE ? 'F' : '.'));
 
-	/* we should have never asked a backbone gw */
-	if (batadv_bla_is_backbone_gw_orig(bat_priv, resp_src))
-		goto out;
-
 	orig_node = batadv_orig_hash_find(bat_priv, resp_src);
 	if (!orig_node)
 		goto out;
@@ -2607,10 +2602,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 	bool full_table = true;
 	struct batadv_tvlv_tt_change *tt_change;
 
-	/* don't care about a backbone gateways updates. */
-	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
-		return;
-
 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
 	 * increased by one -> we can apply the attached changes
 	 */
@@ -2724,13 +2715,6 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,
 {
 	bool ret = false;
 
-	/* if the originator is a backbone node (meaning it belongs to the same
-	 * LAN of this node) the temporary client must not be added because to
-	 * reach such destination the node must use the LAN instead of the mesh
-	 */
-	if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig))
-		goto out;
-
 	if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid,
 				  BATADV_TT_CLIENT_TEMP,
 				  atomic_read(&orig_node->last_ttvn)))
@@ -2875,13 +2859,6 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 	if (!batadv_is_my_mac(bat_priv, dst))
 		return NET_RX_DROP;
 
-	/* check if it is a backbone gateway. we don't accept
-	 * roaming advertisement from it, as it has the same
-	 * entries as we have.
-	 */
-	if (batadv_bla_is_backbone_gw_orig(bat_priv, src))
-		goto out;
-
 	if (tvlv_value_len < sizeof(*roaming_adv))
 		goto out;
 
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 12/13] batman-adv: make the TT global purge routine VLAN specific
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (10 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 11/13] batman-adv: make the backbone gw check " Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 13/13] batman-adv: make the TT CRC logic " Antonio Quartulli
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Simon Wunderlich, Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Instead of unconditionally remove all the TT entries
served by a given originator, make tt_global_orig_del()
remove only entries matching a given VLAN identifier
provided as argument.

If such argument is negative then all the global entries
served by the originator are removed.

This change is used into the BLA code to purge entries
served by a newly discovered Backbone node, but limiting
the operation only to those connected to the VLAN where the
backbone has been discovered.

Cc: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 bridge_loop_avoidance.c |  4 ++--
 originator.c            |  2 +-
 routing.c               |  2 +-
 translation-table.c     | 19 ++++++++++++++++++-
 translation-table.h     |  2 +-
 5 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c
index 72df179..4418534 100644
--- a/bridge_loop_avoidance.c
+++ b/bridge_loop_avoidance.c
@@ -411,10 +411,10 @@ batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig,
 		return NULL;
 	}
 
-	/* this is a gateway now, remove any tt entries */
+	/* this is a gateway now, remove any TT entry on this VLAN */
 	orig_node = batadv_orig_hash_find(bat_priv, orig);
 	if (orig_node) {
-		batadv_tt_global_del_orig(bat_priv, orig_node,
+		batadv_tt_global_del_orig(bat_priv, orig_node, vid,
 					  "became a backbone gateway");
 		batadv_orig_node_free_ref(orig_node);
 	}
diff --git a/originator.c b/originator.c
index a591dc5..e910fc6 100644
--- a/originator.c
+++ b/originator.c
@@ -148,7 +148,7 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
 
 	batadv_frag_purge_orig(orig_node, NULL);
 
-	batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
+	batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, -1,
 				  "originator timed out");
 
 	kfree(orig_node->tt_buff);
diff --git a/routing.c b/routing.c
index e63b05d..2b35205 100644
--- a/routing.c
+++ b/routing.c
@@ -47,7 +47,7 @@ static void _batadv_update_route(struct batadv_priv *bat_priv,
 	if ((curr_router) && (!neigh_node)) {
 		batadv_dbg(BATADV_DBG_ROUTES, bat_priv,
 			   "Deleting route towards: %pM\n", orig_node->orig);
-		batadv_tt_global_del_orig(bat_priv, orig_node,
+		batadv_tt_global_del_orig(bat_priv, orig_node, -1,
 					  "Deleted route towards originator");
 
 	/* route added */
diff --git a/translation-table.c b/translation-table.c
index 4ced045..8c11644 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -1169,6 +1169,7 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
 		hlist_del_rcu(&orig_entry->list);
+		atomic_dec(&orig_entry->orig_node->tt_size);
 		batadv_tt_orig_list_entry_free_ref(orig_entry);
 	}
 	spin_unlock_bh(&tt_global_entry->list_lock);
@@ -1196,6 +1197,7 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
 				   tt_global_entry->common.addr,
 				   BATADV_PRINT_VID(vid), message);
 			hlist_del_rcu(&orig_entry->list);
+			atomic_dec(&orig_entry->orig_node->tt_size);
 			batadv_tt_orig_list_entry_free_ref(orig_entry);
 		}
 	}
@@ -1308,8 +1310,18 @@ out:
 		batadv_tt_local_entry_free_ref(local_entry);
 }
 
+/**
+ * batadv_tt_global_del_orig - remove all the TT global entries belonging to the
+ *  given originator matching the provided vid
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the originator owning the entries to remove
+ * @match_vid: the VLAN identifier to match. If negative all the entries will be
+ *  removed
+ * @message: debug message to print as "reason"
+ */
 void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 			       struct batadv_orig_node *orig_node,
+			       int32_t match_vid,
 			       const char *message)
 {
 	struct batadv_tt_global_entry *tt_global;
@@ -1331,6 +1343,10 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 		spin_lock_bh(list_lock);
 		hlist_for_each_entry_safe(tt_common_entry, safe,
 					  head, hash_entry) {
+			/* remove only matching entries */
+			if (match_vid >= 0 && tt_common_entry->vid != match_vid)
+				continue;
+
 			tt_global = container_of(tt_common_entry,
 						 struct batadv_tt_global_entry,
 						 common);
@@ -2168,7 +2184,8 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
 		goto out;
 
 	/* Purge the old table first.. */
-	batadv_tt_global_del_orig(bat_priv, orig_node, "Received full table");
+	batadv_tt_global_del_orig(bat_priv, orig_node, -1,
+				  "Received full table");
 
 	_batadv_tt_update_changes(bat_priv, orig_node,
 				  (struct batadv_tvlv_tt_change *)(tt_data + 1),
diff --git a/translation-table.h b/translation-table.h
index c6bf33c..dc6db4e 100644
--- a/translation-table.h
+++ b/translation-table.h
@@ -30,7 +30,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset);
 void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
 			       struct batadv_orig_node *orig_node,
-			       const char *message);
+			       int32_t match_vid, const char *message);
 struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 						  const uint8_t *src,
 						  const uint8_t *addr,
-- 
1.8.1.5


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

* [B.A.T.M.A.N.] [PATCHv4 13/13] batman-adv: make the TT CRC logic VLAN specific
  2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
                   ` (11 preceding siblings ...)
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 12/13] batman-adv: make the TT global purge routine " Antonio Quartulli
@ 2013-06-04 10:11 ` Antonio Quartulli
  12 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-04 10:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli

From: Antonio Quartulli <antonio@open-mesh.com>

Nodes may need to handle the TT table on a per-VLAN basis,
meaning that a node may want to filter a received table and
get only entries belonging to certain VLANs.

When doing so, such node would re-create only a partial
global table and would not be able to compute a correct CRC
anymore.

This patch splits the logic and introduces one CRC per VLAN.
In this way a node fetching only some entries belonging to
some VLANs is still able to compute the specific CRCs and
check table correctness.

With this patch the shape of the TVLV-TT is changed too
because now a node needs to advertise all the CRCs of all
the VLANs that it is wired to.

To make the code simpler, also the normal LAN (bat0) is now
considered to be a VLAN having no tag.

Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
---
 compat.c            |   9 +
 compat.h            |   1 +
 originator.c        |  98 +++++++-
 originator.h        |   7 +
 packet.h            |  18 +-
 soft-interface.c    |   1 -
 sysfs.c             |  12 +-
 translation-table.c | 663 ++++++++++++++++++++++++++++++++++++++++------------
 types.h             |  41 +++-
 9 files changed, 685 insertions(+), 165 deletions(-)

diff --git a/compat.c b/compat.c
index 0a98fb7..fcd5bec 100644
--- a/compat.c
+++ b/compat.c
@@ -27,6 +27,15 @@
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
 
+void batadv_free_rcu_orig_vlan(struct rcu_head *rcu)
+{
+	struct batadv_orig_node_vlan *vlan;
+
+	vlan = container_of(rcu, structbatadv_orig_node_vlan, rcu);
+
+	kfree(vlan);
+}
+
 void batadv_free_rcu_softif_vlan(struct rcu_head *rcu)
 {
 	struct batadv_softif_vlan *vlan;
diff --git a/compat.h b/compat.h
index 1ee0467..38c9b1a 100644
--- a/compat.h
+++ b/compat.h
@@ -182,6 +182,7 @@ static const struct { \
 #define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, batadv_free_rcu_##ptr)
 #define vlan_insert_tag(skb, proto, vid) __vlan_put_tag(skb, vid)
 
+void batadv_free_rcu_orig_vlan(struct rcu_head *rcu);
 void batadv_free_rcu_softif_vlan(struct rcu_head *rcu);
 void batadv_free_rcu_tt_global_entry(struct rcu_head *rcu);
 void batadv_free_rcu_gw_node(struct rcu_head *rcu);
diff --git a/originator.c b/originator.c
index e910fc6..c878a00 100644
--- a/originator.c
+++ b/originator.c
@@ -44,6 +44,88 @@ static int batadv_compare_orig(const struct hlist_node *node, const void *data2)
 	return (memcmp(data1, data2, ETH_ALEN) == 0 ? 1 : 0);
 }
 
+/**
+ * batadv_orig_node_vlan_get - get an orig_node_vlan object
+ * @orig_node: the originator servin the VLAN
+ * @vid: the VLAN identifier
+ *
+ * Return the orig_node_vlan for the VLAN identified by vid or NULL if it does
+ * not exist.
+ */
+struct batadv_orig_node_vlan *
+batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
+			  unsigned short vid)
+{
+	struct batadv_orig_node_vlan *vlan;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
+		if (!atomic_inc_not_zero(&vlan->refcount))
+			continue;
+
+		if (vlan->vid != vid)
+			continue;
+
+		rcu_read_unlock();
+
+		return vlan;
+	}
+	rcu_read_unlock();
+
+	return NULL;
+}
+
+/**
+ * batadv_orig_node_vlan_new - search and possibly create an orig_node_vlan
+ *  object
+ * @orig_node: the originator serving the VLAN
+ * @vid: the VLAN identifier
+ *
+ * Return NULL in case of failure or the orig_node_vlan object for the VLAN
+ * identified by vid otherwise. The object is created and added to the list
+ * if it does not exist.
+ */
+struct batadv_orig_node_vlan *
+batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
+			  unsigned short vid)
+{
+	struct batadv_orig_node_vlan *vlan;
+
+	spin_lock_bh(&orig_node->vlan_list_lock);
+
+	/* first look if an object for this vid already exists */
+	list_for_each_entry(vlan, &orig_node->vlan_list, list) {
+		if (!atomic_inc_not_zero(&vlan->refcount))
+			continue;
+
+		if (vlan->vid != vid)
+			continue;
+
+		/* there is already an entry for this vid: return it */
+		goto out;
+	}
+
+	vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
+	if (!vlan)
+		goto out;
+
+	atomic_set(&vlan->refcount, 2);
+	vlan->vid = vid;
+
+	list_add_rcu(&vlan->list, &orig_node->vlan_list);
+
+out:
+	spin_unlock_bh(&orig_node->vlan_list_lock);
+
+	return vlan;
+}
+
+void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan)
+{
+	if (atomic_dec_and_test(&orig_vlan->refcount))
+		kfree_rcu(orig_vlan, rcu);
+}
+
 int batadv_originator_init(struct batadv_priv *bat_priv)
 {
 	if (bat_priv->orig_hash)
@@ -218,6 +300,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
 					      const uint8_t *addr)
 {
 	struct batadv_orig_node *orig_node;
+	struct batadv_orig_node_vlan *vlan;
 	int size, i;
 	int hash_added;
 	unsigned long reset_time;
@@ -235,10 +318,12 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
 
 	INIT_HLIST_HEAD(&orig_node->neigh_list);
 	INIT_LIST_HEAD(&orig_node->bond_list);
+	INIT_LIST_HEAD(&orig_node->vlan_list);
 	spin_lock_init(&orig_node->ogm_cnt_lock);
 	spin_lock_init(&orig_node->bcast_seqno_lock);
 	spin_lock_init(&orig_node->neigh_list_lock);
 	spin_lock_init(&orig_node->tt_buff_lock);
+	spin_lock_init(&orig_node->vlan_list_lock);
 
 	batadv_nc_init_orig(orig_node);
 
@@ -250,22 +335,27 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
 	memcpy(orig_node->orig, addr, ETH_ALEN);
 	batadv_dat_init_orig_node_addr(orig_node);
 	orig_node->router = NULL;
-	orig_node->tt_crc = 0;
 	atomic_set(&orig_node->last_ttvn, 0);
 	orig_node->tt_buff = NULL;
 	orig_node->tt_buff_len = 0;
-	atomic_set(&orig_node->tt_size, 0);
 	reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
 	orig_node->bcast_seqno_reset = reset_time;
 	orig_node->batman_seqno_reset = reset_time;
 
 	atomic_set(&orig_node->bond_candidates, 0);
 
+	/* create a vlan object for the "untagged" LAN */
+	vlan = batadv_orig_node_vlan_new(orig_node, BATADV_NO_FLAGS);
+	if (!vlan)
+		goto free_orig_node;
+	/* there is nothing else to do with the vlan.. */
+	batadv_orig_node_vlan_free_ref(vlan);
+
 	size = bat_priv->num_ifaces * sizeof(unsigned long) * BATADV_NUM_WORDS;
 
 	orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
 	if (!orig_node->bcast_own)
-		goto free_orig_node;
+		goto free_vlan;
 
 	size = bat_priv->num_ifaces * sizeof(uint8_t);
 	orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
@@ -290,6 +380,8 @@ free_bcast_own_sum:
 	kfree(orig_node->bcast_own_sum);
 free_bcast_own:
 	kfree(orig_node->bcast_own);
+free_vlan:
+	batadv_orig_node_vlan_free_ref(vlan);
 free_orig_node:
 	kfree(orig_node);
 	return NULL;
diff --git a/originator.h b/originator.h
index 7887b84..cc6d686 100644
--- a/originator.h
+++ b/originator.h
@@ -40,6 +40,13 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
 			    int max_if_num);
 int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
 			    int max_if_num);
+struct batadv_orig_node_vlan *
+batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
+			  unsigned short vid);
+struct batadv_orig_node_vlan *
+batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,
+			  unsigned short vid);
+void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan);
 
 
 /* hashfunction to choose an entry in a hash table of given size
diff --git a/packet.h b/packet.h
index 08e175a..1249290 100644
--- a/packet.h
+++ b/packet.h
@@ -391,14 +391,26 @@ struct batadv_tvlv_gateway_data {
  * struct batadv_tvlv_tt_data - tt data propagated through the tt tvlv container
  * @flags: translation table flags (see batadv_tt_data_flags)
  * @ttvn: translation table version number
- * @reserved: field reserved for future use
- * @crc: crc32 checksum of the local translation table
+ * @vlan_num: number of announced VLANs. In the TVLV this struct is followed by
+ *  one batadv_tvlv_tt_vlan_data object per announced vlan
  */
 struct batadv_tvlv_tt_data {
 	uint8_t flags;
 	uint8_t ttvn;
+	__be16  num_vlan;
+};
+
+/**
+ * struct batadv_tvlv_tt_vlan_data - vlan specific tt data propagated through
+ *  the tt vlv container
+ * @vid: vlan identifier
+ * @reserved: unused, useful for alignment purposes
+ * @crc: crc32 checksum of the entries belonging to this vlan
+ */
+struct batadv_tvlv_tt_vlan_data {
+	__be32	crc;
+	__be16	vid;
 	uint16_t reserved;
-	__be32  crc;
 };
 
 /**
diff --git a/soft-interface.c b/soft-interface.c
index 17fa0f1..df16580 100644
--- a/soft-interface.c
+++ b/soft-interface.c
@@ -572,7 +572,6 @@ static int batadv_softif_init_late(struct net_device *dev)
 #ifdef CONFIG_BATMAN_ADV_DAT
 	atomic_set(&bat_priv->distributed_arp_table, 1);
 #endif
-	atomic_set(&bat_priv->ap_isolation, 0);
 	atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
 	atomic_set(&bat_priv->gw_sel_class, 20);
 	atomic_set(&bat_priv->gw.bandwidth_down, 100);
diff --git a/sysfs.c b/sysfs.c
index 09a4031..125154a 100644
--- a/sysfs.c
+++ b/sysfs.c
@@ -423,7 +423,6 @@ BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR,
 		     batadv_dat_status_update);
 #endif
 BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu);
-BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
 static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);
 static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,
 		   batadv_store_gw_mode);
@@ -453,7 +452,6 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
 	&batadv_attr_distributed_arp_table,
 #endif
 	&batadv_attr_fragmentation,
-	&batadv_attr_ap_isolation,
 	&batadv_attr_routing_algo,
 	&batadv_attr_gw_mode,
 	&batadv_attr_orig_interval,
@@ -542,11 +540,15 @@ int batadv_sysfs_add_vlan(struct net_device *dev,
 {
 	struct batadv_priv *bat_priv = netdev_priv(dev);
 	struct batadv_attribute **bat_attr;
-	char vlan_subdir[256];
+	char vlan_subdir_str[256], *vlan_subdir;
 	int err;
 
-	sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%u",
-		vlan->vid & VLAN_VID_MASK);
+	vlan_subdir = "novlan";
+	if (vlan->vid & BATADV_VLAN_HAS_TAG) {
+		sprintf(vlan_subdir_str, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%u",
+			vlan->vid & VLAN_VID_MASK);
+		vlan_subdir = vlan_subdir_str;
+	}
 
 	vlan->kobj = kobject_create_and_add(vlan_subdir, bat_priv->mesh_obj);
 	if (!vlan->kobj) {
diff --git a/translation-table.c b/translation-table.c
index 8c11644..6b6106b 100644
--- a/translation-table.c
+++ b/translation-table.c
@@ -208,13 +208,58 @@ static void batadv_tt_orig_list_entry_free_rcu(struct rcu_head *rcu)
 	kfree(orig_entry);
 }
 
+/**
+ * batadv_tt_local_size_add - change the local table size for the given vid
+ * @bat_priv: the bat priv with all the soft interface information
+ * @vid: the VLAN identifier
+ * @v: the value to add to the table size
+ *
+ * Add v to the current local table size. v can be either positive or negative
+ */
+static void batadv_tt_local_size_add(struct batadv_priv *bat_priv,
+				     unsigned short vid, int v)
+{
+	struct batadv_softif_vlan *vlan;
+
+	vlan = batadv_softif_vlan_get(bat_priv, vid);
+	if (!vlan)
+		return;
+
+	atomic_add(v, &vlan->tt.num_entries);
+
+	batadv_softif_vlan_free_ref(vlan);
+}
+
+/**
+ * batadv_tt_global_size_add - change the global table size for the given vid
+ * @orig_node: the originator which global table size has to be decreased
+ * @vid: the vlan identifier
+ * @v: the value to add to the table size
+ *
+ * Add v to the current global table size. v can be either positive or negative
+ */
+static void batadv_tt_global_size_add(struct batadv_orig_node *orig_node,
+				      unsigned short vid, int v)
+{
+	struct batadv_orig_node_vlan *vlan;
+
+	vlan = batadv_orig_node_vlan_new(orig_node, vid);
+	if (!vlan)
+		return;
+
+	/* if there are no more entries for these VLAN, it can be deleted */
+	if (atomic_add_return(v, &vlan->tt.num_entries) == 0)
+		batadv_orig_node_vlan_free_ref(vlan);
+
+	batadv_orig_node_vlan_free_ref(vlan);
+}
+
 static void
 batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry)
 {
 	if (!atomic_dec_and_test(&orig_entry->refcount))
 		return;
-	/* to avoid race conditions, immediately decrease the tt counter */
-	atomic_dec(&orig_entry->orig_node->tt_size);
+
 	call_rcu(&orig_entry->rcu, batadv_tt_orig_list_entry_free_rcu);
 }
 
@@ -464,6 +509,122 @@ out:
 }
 
 /**
+ * batadv_tt_prepare_tvlv_global_data - prepare the TVLV TT header to send
+ *  within a TT Response directed to another node
+ * @orig_node: originator for which the TT data has to be prepared
+ * @tt_data: uninitialised pointer to the address of the TVLV buffer
+ * @tt_len: space to reserve for the TT entries. If negative, this function will
+ *  allocate as much space is needed for the full table
+ *
+ * Allocate the needed amount of memory for the entire TT TVLV and write its
+ * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
+ * objects, one per active VLAN served by the originator node.
+ *
+ * Return the size of the allocated buffer or 0 in case of failure.
+ */
+static uint16_t
+batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,
+				   struct batadv_tvlv_tt_data **tt_data,
+				   int32_t tt_len)
+{
+	struct batadv_tvlv_tt_vlan_data *tt_vlan;
+	struct batadv_orig_node_vlan *vlan;
+	uint16_t num_vlan = 0, num_entries = 0;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
+		num_vlan++;
+		num_entries += atomic_read(&vlan->tt.num_entries);
+	}
+
+	/* if tt_len is negative, allocate the space needed by the full table */
+	if (tt_len < 0)
+		tt_len = batadv_tt_len(num_entries);
+
+	tt_len += sizeof(**tt_data);
+	tt_len += sizeof(*tt_vlan) * num_vlan;
+
+	*tt_data = kmalloc(tt_len, GFP_ATOMIC);
+	if (!*tt_data) {
+		tt_len = 0;
+		goto out;
+	}
+
+	(*tt_data)->flags = BATADV_NO_FLAGS;
+	(*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn);
+	(*tt_data)->num_vlan = htons(num_vlan);
+
+	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
+	list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
+		tt_vlan->vid = htons(vlan->vid);
+		tt_vlan->crc = htonl(vlan->tt.crc);
+
+		tt_vlan++;
+	}
+out:
+	rcu_read_unlock();
+	return tt_len;
+}
+
+/**
+ * batadv_tt_prepare_tvlv_local_data - allocate and prepare the TT TVLV for this
+ *  node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @tt_data: uninitialised pointer to the address of the TVLV buffer
+ * @tt_len: length to reserve to the tt_change. if -1 this function reserves
+ *  the amount of space needed to send the entire local TT table
+ *
+ * Allocate the needed amount of memory for the entire TT TVLV and write its
+ * header made up by one tvlv_tt_data object and a series of tvlv_tt_vlan_data
+ * objects, one per active VLAN.
+ *
+ * Return the size of the allocated buffer or 0 in case of failure.
+ */
+static uint16_t
+batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,
+				  struct batadv_tvlv_tt_data **tt_data,
+				  int32_t tt_len)
+{
+	struct batadv_tvlv_tt_vlan_data *tt_vlan;
+	struct batadv_softif_vlan *vlan;
+	uint16_t num_vlan = 0, num_entries = 0;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+		num_vlan++;
+		num_entries += atomic_read(&vlan->tt.num_entries);
+	}
+
+	/* if tt_len is negative, allocate the space needed by the full table */
+	if (tt_len < 0)
+		tt_len = batadv_tt_len(num_entries);
+
+	tt_len += sizeof(**tt_data);
+	tt_len += sizeof(*tt_vlan) * num_vlan;
+
+	*tt_data = kmalloc(tt_len, GFP_ATOMIC);
+	if (!*tt_data) {
+		tt_len = 0;
+		goto out;
+	}
+
+	(*tt_data)->flags = BATADV_NO_FLAGS;
+	(*tt_data)->ttvn = atomic_read(&bat_priv->tt.vn);
+	(*tt_data)->num_vlan = htons(num_vlan);
+
+	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1);
+	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+		tt_vlan->vid = htons(vlan->vid);
+		tt_vlan->crc = htonl(vlan->tt.crc);
+
+		tt_vlan++;
+	}
+out:
+	rcu_read_unlock();
+	return tt_len;
+}
+
+/**
  * batadv_tt_tvlv_container_update - update the translation table tvlv container
  *  after local tt changes have been committed
  * @bat_priv: the bat priv with all the soft interface information
@@ -473,10 +634,11 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
 	struct batadv_tt_change_node *entry, *safe;
 	struct batadv_tvlv_tt_data *tt_data;
 	struct batadv_tvlv_tt_change *tt_change;
-	int tt_diff_len = 0, tt_change_len = 0;
+	int tt_diff_len, tt_change_len = 0;
 	int tt_diff_entries_num = 0, tt_diff_entries_count = 0;
+	uint16_t tt_len, change_offset;
 
-	tt_diff_len += batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
+	tt_diff_len = batadv_tt_len(atomic_read(&bat_priv->tt.local_changes));
 
 	/* if we have too many changes for one packet don't send any
 	 * and wait for the tt table request which will be fragmented
@@ -484,13 +646,16 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
 	if (tt_diff_len > bat_priv->soft_iface->mtu)
 		tt_diff_len = 0;
 
-	tt_data = kzalloc(sizeof(*tt_data) + tt_diff_len, GFP_ATOMIC);
-	if (!tt_data)
+	tt_len = batadv_tt_prepare_tvlv_local_data(bat_priv, &tt_data,
+						   tt_diff_len);
+	if (!tt_len)
 		return;
 
 	tt_data->flags = BATADV_TT_OGM_DIFF;
-	tt_data->ttvn = atomic_read(&bat_priv->tt.vn);
-	tt_data->crc = htonl(bat_priv->tt.local_crc);
+
+	change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+	change_offset *= ntohs(tt_data->num_vlan);
+	change_offset += sizeof(*tt_data);
 
 	if (tt_diff_len == 0)
 		goto container_register;
@@ -500,7 +665,8 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
 	spin_lock_bh(&bat_priv->tt.changes_list_lock);
 	atomic_set(&bat_priv->tt.local_changes, 0);
 
-	tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
+	tt_change = (struct batadv_tvlv_tt_change *)((uint8_t *)tt_data +
+						     change_offset);
 
 	list_for_each_entry_safe(entry, safe, &bat_priv->tt.changes_list,
 				 list) {
@@ -537,7 +703,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)
 
 container_register:
 	batadv_tvlv_container_register(bat_priv, BATADV_TVLV_TT, 1, tt_data,
-				       sizeof(*tt_data) + tt_change_len);
+				       tt_len);
 	kfree(tt_data);
 }
 
@@ -549,7 +715,9 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 	struct batadv_tt_common_entry *tt_common_entry;
 	struct batadv_tt_local_entry *tt_local;
 	struct batadv_hard_iface *primary_if;
+	struct batadv_softif_vlan *vlan;
 	struct hlist_head *head;
+	unsigned short vid;
 	uint32_t i;
 	int last_seen_secs;
 	int last_seen_msecs;
@@ -562,11 +730,10 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 		goto out;
 
 	seq_printf(seq,
-		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u CRC: %#.8x):\n",
-		   net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn),
-		   bat_priv->tt.local_crc);
-	seq_printf(seq, "       %-13s  %s %-7s %-10s\n", "Client", "VID",
-		   "Flags", "Last seen");
+		   "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n",
+		   net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn));
+	seq_printf(seq, "       %-13s  %s %-7s %-9s (%-10s)\n", "Client", "VID",
+		   "Flags", "Last seen", "CRC");
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -577,6 +744,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 			tt_local = container_of(tt_common_entry,
 						struct batadv_tt_local_entry,
 						common);
+			vid = tt_common_entry->vid;
 			last_seen_jiffies = jiffies - tt_local->last_seen;
 			last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
 			last_seen_secs = last_seen_msecs / 1000;
@@ -584,7 +752,15 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 
 			no_purge = tt_common_entry->flags & np_flag;
 
-			seq_printf(seq, " * %pM %4i [%c%c%c%c%c] %3u.%03u\n",
+			vlan = batadv_softif_vlan_get(bat_priv, vid);
+			if (!vlan) {
+				seq_printf(seq, "Cannot retrieve VLAN %d\n",
+					   BATADV_PRINT_VID(vid));
+				continue;
+			}
+
+			seq_printf(seq,
+				   " * %pM %4i [%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
 				   tt_common_entry->addr,
 				   BATADV_PRINT_VID(tt_common_entry->vid),
 				   (tt_common_entry->flags &
@@ -597,7 +773,8 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
 				   (tt_common_entry->flags &
 				    BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
 				   no_purge ? 0 : last_seen_secs,
-				   no_purge ? 0 : last_seen_msecs);
+				   no_purge ? 0 : last_seen_msecs,
+				   vlan->tt.crc);
 		}
 		rcu_read_unlock();
 	}
@@ -860,7 +1037,7 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,
 
 	INIT_HLIST_NODE(&orig_entry->list);
 	atomic_inc(&orig_node->refcount);
-	atomic_inc(&orig_node->tt_size);
+	batadv_tt_global_size_add(orig_node, tt_global->common.vid, 1);
 	orig_entry->orig_node = orig_node;
 	orig_entry->ttvn = ttvn;
 	atomic_set(&orig_entry->refcount, 2);
@@ -1074,35 +1251,49 @@ static void
 batadv_tt_global_print_entry(struct batadv_tt_global_entry *tt_global_entry,
 			     struct seq_file *seq)
 {
-	struct hlist_head *head;
 	struct batadv_tt_orig_list_entry *orig_entry, *best_entry;
 	struct batadv_tt_common_entry *tt_common_entry;
-	uint16_t flags;
+	struct batadv_orig_node_vlan *vlan;
+	struct hlist_head *head;
 	uint8_t last_ttvn;
+	uint16_t flags;
 
 	tt_common_entry = &tt_global_entry->common;
 	flags = tt_common_entry->flags;
-
 	best_entry = batadv_transtable_best_orig(tt_global_entry);
 	if (best_entry) {
+		vlan = batadv_orig_node_vlan_get(best_entry->orig_node,
+						 tt_common_entry->vid);
+		if (!vlan) {
+			seq_printf(seq,
+				   " * Cannot retrieve VLAN %d for originator %pM\n",
+				   BATADV_PRINT_VID(tt_common_entry->vid),
+				   best_entry->orig_node->orig);
+			goto print_list;
+		}
+
 		last_ttvn = atomic_read(&best_entry->orig_node->last_ttvn);
 		seq_printf(seq,
 			   " %c %pM %4i   (%3u) via %pM     (%3u)   (%#.8x) [%c%c%c]\n",
 			   '*', tt_global_entry->common.addr,
 			   BATADV_PRINT_VID(tt_global_entry->common.vid),
 			   best_entry->ttvn, best_entry->orig_node->orig,
-			   last_ttvn, best_entry->orig_node->tt_crc,
+			   last_ttvn, vlan->tt.crc,
 			   (flags & BATADV_TT_CLIENT_ROAM ? 'R' : '.'),
 			   (flags & BATADV_TT_CLIENT_WIFI ? 'W' : '.'),
 			   (flags & BATADV_TT_CLIENT_TEMP ? 'T' : '.'));
 	}
 
+print_list:
 	head = &tt_global_entry->orig_list;
 
 	hlist_for_each_entry_rcu(orig_entry, head, list) {
 		if (best_entry == orig_entry)
 			continue;
 
+		vlan = batadv_orig_node_vlan_get(orig_entry->orig_node,
+						 tt_common_entry->vid);
+
 		last_ttvn = atomic_read(&orig_entry->orig_node->last_ttvn);
 		seq_printf(seq,
 			   " %c %pM %4d   (%3u) via %pM     (%3u)   [%c%c%c]\n",
@@ -1169,7 +1360,8 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry)
 	head = &tt_global_entry->orig_list;
 	hlist_for_each_entry_safe(orig_entry, safe, head, list) {
 		hlist_del_rcu(&orig_entry->list);
-		atomic_dec(&orig_entry->orig_node->tt_size);
+		batadv_tt_global_size_add(orig_entry->orig_node,
+					  tt_global_entry->common.vid, -1);
 		batadv_tt_orig_list_entry_free_ref(orig_entry);
 	}
 	spin_unlock_bh(&tt_global_entry->list_lock);
@@ -1197,7 +1389,9 @@ batadv_tt_global_del_orig_entry(struct batadv_priv *bat_priv,
 				   tt_global_entry->common.addr,
 				   BATADV_PRINT_VID(vid), message);
 			hlist_del_rcu(&orig_entry->list);
-			atomic_dec(&orig_entry->orig_node->tt_size);
+			batadv_tt_global_size_add(orig_node,
+						  tt_global_entry->common.vid,
+						  -1);
 			batadv_tt_orig_list_entry_free_ref(orig_entry);
 		}
 	}
@@ -1498,12 +1692,12 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
 						  const uint8_t *addr,
 						  unsigned short vid)
 {
-	bool ap_isolation_enabled = atomic_read(&bat_priv->ap_isolation);
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
 	struct batadv_orig_node *orig_node = NULL;
 	struct batadv_tt_orig_list_entry *best_entry;
 	struct batadv_softif_vlan *vlan;
+	bool ap_isolation_enabled = false;
 
 	/* if the AP isolation is requested on a VLAN, then check for the
 	 * its setting in the proper VLAN private data structure
@@ -1555,6 +1749,7 @@ out:
  *  to the given orig_node
  * @bat_priv: the bat priv with all the soft interface information
  * @orig_node: originator for which the CRC should be computed
+ * @vid: VLAN identifier for which the CRC32 has to be computed
  *
  * This function computes the checksum for the global table corresponding to a
  * particular originator. In particular the checksum is computed as follows: for
@@ -1574,7 +1769,8 @@ out:
  * Returns the checksum of the global table of a given originator
  */
 static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
-				     struct batadv_orig_node *orig_node)
+				     struct batadv_orig_node *orig_node,
+				     unsigned short vid)
 {
 	struct batadv_hashtable *hash = bat_priv->tt.global_hash;
 	struct batadv_tt_common_entry *tt_common;
@@ -1590,6 +1786,12 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 			tt_global = container_of(tt_common,
 						 struct batadv_tt_global_entry,
 						 common);
+			/* compute the CRC only for entries belonging to the
+			 * VLAN identified by the vid passed as parameter
+			 */
+			if (tt_common->vid != vid)
+				continue;
+
 			/* Roaming clients are in the global table for
 			 * consistency only. They don't have to be
 			 * taken into account while computing the
@@ -1624,13 +1826,15 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv,
 /**
  * batadv_tt_local_crc - calculates the checksum of the local table
  * @bat_priv: the bat priv with all the soft interface information
+ * @vid: VLAN identifier for which the CRC32 has to be computed
  *
  * For details about the computation, please refer to the documentation for
  * batadv_tt_global_crc().
  *
  * Returns the checksum of the local table
  */
-static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
+static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv,
+				    unsigned short vid)
 {
 	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
 	struct batadv_tt_common_entry *tt_common;
@@ -1642,6 +1846,12 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv)
 
 		rcu_read_lock();
 		hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+			/* compute the CRC only for entries belonging to the
+			 * VLAN identified by vid
+			 */
+			if (tt_common->vid != vid)
+				continue;
+
 			/* not yet committed clients have not to be taken into
 			 * account while computing the CRC
 			 */
@@ -1773,44 +1983,30 @@ static int batadv_tt_global_valid(const void *entry_ptr,
 }
 
 /**
- * batadv_tt_tvlv_generate - creates tvlv tt data buffer to fill it with the
- *  tt entries from the specified tt hash
+ * batadv_tt_tvlv_generate - fill the tvlv buff it with the tt entries from the
+ *  specified tt hash
  * @bat_priv: the bat priv with all the soft interface information
  * @hash: hash table containing the tt entries
  * @tt_len: expected tvlv tt data buffer length in number of bytes
+ * @tvlv_buff: pointer to the buffer to fill with the TT data
  * @valid_cb: function to filter tt change entries
  * @cb_data: data passed to the filter function as argument
- *
- * Returns pointer to allocated tvlv tt data buffer if operation was
- * successful or NULL otherwise.
  */
-static struct batadv_tvlv_tt_data *
-batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
-			struct batadv_hashtable *hash, uint16_t tt_len,
-			int (*valid_cb)(const void *, const void *),
-			void *cb_data)
+static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
+				    struct batadv_hashtable *hash,
+				    void *tvlv_buff, uint16_t tt_len,
+				    int (*valid_cb)(const void *, const void *),
+				    void *cb_data)
 {
 	struct batadv_tt_common_entry *tt_common_entry;
-	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
 	struct batadv_tvlv_tt_change *tt_change;
 	struct hlist_head *head;
 	uint16_t tt_tot, tt_num_entries = 0;
-	ssize_t tvlv_tt_size = sizeof(struct batadv_tvlv_tt_data);
 	uint32_t i;
 
-	if (tvlv_tt_size + tt_len > bat_priv->soft_iface->mtu) {
-		tt_len = bat_priv->soft_iface->mtu - tvlv_tt_size;
-		tt_len -= tt_len % sizeof(struct batadv_tvlv_tt_change);
-	}
-
 	tt_tot = batadv_tt_entries(tt_len);
 
-	tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
-			       GFP_ATOMIC);
-	if (!tvlv_tt_data)
-		goto out;
-
-	tt_change = (struct batadv_tvlv_tt_change *)(tvlv_tt_data + 1);
+	tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff;
 
 	rcu_read_lock();
 	for (i = 0; i < hash->size; i++) {
@@ -1835,9 +2031,91 @@ batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
 		}
 	}
 	rcu_read_unlock();
+}
 
-out:
-	return tvlv_tt_data;
+/**
+ * batadv_tt_global_check_crc - check if all the CRCs are correct
+ * @orig_node: originator for which the CRCs have to be checked
+ * @tt_vlan: pointer to the first tvlv VLAN entry
+ * @num_vlan: number of tvlv VLAN entries
+ * @create: if true, create VLAN objects if not found
+ *
+ * Return true if all the received CRCs match the locally stored ones, false
+ * otherwise
+ */
+static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node,
+				       struct batadv_tvlv_tt_vlan_data *tt_vlan,
+				       uint16_t num_vlan)
+{
+	struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp;
+	struct batadv_orig_node_vlan *vlan;
+	int i;
+
+	/* check if each received CRC matches the locally stored one */
+	for (i = 0; i < num_vlan; i++) {
+		tt_vlan_tmp = tt_vlan + i;
+
+		/* if orig_node is a backbone node for this VLAN, don't check
+		 * the CRC as we ignore all the global entries over it
+		 */
+		if (batadv_bla_is_backbone_gw_orig(orig_node->bat_priv,
+						   orig_node->orig,
+						   ntohs(tt_vlan_tmp->vid)))
+			continue;
+
+		vlan = batadv_orig_node_vlan_get(orig_node,
+						 ntohs(tt_vlan_tmp->vid));
+		if (!vlan)
+			return false;
+
+		if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc))
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * batadv_tt_local_update_crc - update all the local CRCs
+ * @bat_priv: the bat priv with all the soft interface information
+ */
+static void batadv_tt_local_update_crc(struct batadv_priv *bat_priv)
+{
+	struct batadv_softif_vlan *vlan;
+
+	/* recompute the global CRC for each VLAN */
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) {
+		vlan->tt.crc = batadv_tt_local_crc(bat_priv, vlan->vid);
+	}
+	rcu_read_unlock();
+}
+
+/**
+ * batadv_tt_global_update_crc - update all the global CRCs for this orig_node
+ * @bat_priv: the bat priv with all the soft interface information
+ * @orig_node: the orig_node for which the CRCs have to be updated
+ */
+static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv,
+					struct batadv_orig_node *orig_node)
+{
+	struct batadv_orig_node_vlan *vlan;
+	uint32_t crc;
+
+	/* recompute the global CRC for each VLAN */
+	rcu_read_lock();
+	list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) {
+		/* if orig_node is a backbone node for this VLAN, don't compute
+		 * the CRC as we ignore all the global entries over it
+		 */
+		if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig,
+						   vlan->vid))
+			continue;
+
+		crc = batadv_tt_global_crc(bat_priv, orig_node, vlan->vid);
+		vlan->tt.crc = crc;
+	}
+	rcu_read_unlock();
 }
 
 /**
@@ -1845,19 +2123,23 @@ out:
  * @bat_priv: the bat priv with all the soft interface information
  * @dst_orig_node: the destination of the message
  * @ttvn: the version number that the source of the message is looking for
- * @tt_crc: the CRC associated with the version number
+ * @tt_vlan: pointer to the first tvlv VLAN object to request
+ * @num_vlan: number of tvlv VLAN entries
  * @full_table: ask for the entire translation table if true, while only for the
  *  last TT diff otherwise
  */
 static int batadv_send_tt_request(struct batadv_priv *bat_priv,
 				  struct batadv_orig_node *dst_orig_node,
-				  uint8_t ttvn, uint32_t tt_crc,
-				  bool full_table)
+				  uint8_t ttvn,
+				  struct batadv_tvlv_tt_vlan_data *tt_vlan,
+				  uint16_t num_vlan, bool full_table)
 {
 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
-	struct batadv_hard_iface *primary_if;
 	struct batadv_tt_req_node *tt_req_node = NULL;
+	struct batadv_tvlv_tt_vlan_data *tt_vlan_req;
+	struct batadv_hard_iface *primary_if;
 	bool ret = false;
+	int i, size;
 
 	primary_if = batadv_primary_if_get_selected(bat_priv);
 	if (!primary_if)
@@ -1870,13 +2152,26 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv,
 	if (!tt_req_node)
 		goto out;
 
-	tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data), GFP_ATOMIC);
+	size = sizeof(*tvlv_tt_data) + sizeof(*tt_vlan_req) * num_vlan;
+	tvlv_tt_data = kzalloc(size, GFP_ATOMIC);
 	if (!tvlv_tt_data)
 		goto out;
 
 	tvlv_tt_data->flags = BATADV_TT_REQUEST;
 	tvlv_tt_data->ttvn = ttvn;
-	tvlv_tt_data->crc = htonl(tt_crc);
+	tvlv_tt_data->num_vlan = htons(num_vlan);
+
+	/* send all the CRCs within the request. This is needed by intermediate
+	 * node to ensure they have the correct table before replying
+	 */
+	tt_vlan_req = (struct batadv_tvlv_tt_vlan_data *)(tvlv_tt_data + 1);
+	for (i = 0; i < num_vlan; i++) {
+		tt_vlan_req->vid = tt_vlan->vid;
+		tt_vlan_req->crc = tt_vlan->crc;
+
+		tt_vlan_req++;
+		tt_vlan++;
+	}
 
 	if (full_table)
 		tvlv_tt_data->flags |= BATADV_TT_FULL_TABLE;
@@ -1887,7 +2182,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv,
 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_REQUEST_TX);
 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
 				 dst_orig_node->orig, BATADV_TVLV_TT, 1,
-				 tvlv_tt_data, sizeof(*tvlv_tt_data));
+				 tvlv_tt_data, size);
 	ret = true;
 
 out:
@@ -1919,9 +2214,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
 {
 	struct batadv_orig_node *req_dst_orig_node;
 	struct batadv_orig_node *res_dst_orig_node = NULL;
+	struct batadv_tvlv_tt_change *tt_change;
 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
-	uint8_t orig_ttvn, req_ttvn;
-	uint16_t tt_len;
+	struct batadv_tvlv_tt_vlan_data *tt_vlan;
+	uint16_t change_offset, tt_len;
+	uint8_t orig_ttvn, req_ttvn, *tvlv_ptr;
 	bool ret = false, full_table;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -1941,9 +2238,11 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
 	orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn);
 	req_ttvn = tt_data->ttvn;
 
+	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
 	/* this node doesn't have the requested data */
 	if (orig_ttvn != req_ttvn ||
-	    tt_data->crc != htonl(req_dst_orig_node->tt_crc))
+	    !batadv_tt_global_check_crc(req_dst_orig_node, tt_vlan,
+					ntohs(tt_data->num_vlan)))
 		goto out;
 
 	/* If the full table has been explicitly requested */
@@ -1960,26 +2259,42 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
 		spin_lock_bh(&req_dst_orig_node->tt_buff_lock);
 		tt_len = req_dst_orig_node->tt_buff_len;
 
-		tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
-				       GFP_ATOMIC);
-		if (!tvlv_tt_data)
+		tt_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
+							    &tvlv_tt_data,
+							    tt_len);
+		if (!tt_len)
 			goto unlock;
 
+		change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+		change_offset *= ntohs(tvlv_tt_data->num_vlan);
+		change_offset += sizeof(*tvlv_tt_data);
+
+		tvlv_ptr = (uint8_t *)tvlv_tt_data + change_offset;
+		tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
 		/* Copy the last orig_node's OGM buffer */
-		memcpy(tvlv_tt_data + 1, req_dst_orig_node->tt_buff,
+		memcpy(tt_change, req_dst_orig_node->tt_buff,
 		       req_dst_orig_node->tt_buff_len);
 		spin_unlock_bh(&req_dst_orig_node->tt_buff_lock);
 	} else {
-		tt_len = (uint16_t)atomic_read(&req_dst_orig_node->tt_size);
-		tt_len = batadv_tt_len(tt_len);
-
-		tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
-						       bat_priv->tt.global_hash,
-						       tt_len,
-						       batadv_tt_global_valid,
-						       req_dst_orig_node);
-		if (!tvlv_tt_data)
+		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
+		 * in the initial part
+		 */
+		tt_len = batadv_tt_prepare_tvlv_global_data(req_dst_orig_node,
+							    &tvlv_tt_data, -1);
+		if (!tt_len)
 			goto out;
+
+		change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+		change_offset *= ntohs(tvlv_tt_data->num_vlan);
+		change_offset += sizeof(*tvlv_tt_data);
+
+		tvlv_ptr = (uint8_t *)tvlv_tt_data + change_offset;
+		tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
+		/* fill the rest of the tvlv with the real TT entries */
+		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.global_hash,
+					tt_change, tt_len - change_offset,
+					batadv_tt_global_valid,
+					req_dst_orig_node);
 	}
 
 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
@@ -1996,8 +2311,8 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,
 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
 
 	batadv_tvlv_unicast_send(bat_priv, req_dst_orig_node->orig,
-				 req_src, BATADV_TVLV_TT, 1,
-				 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
+				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
+				 tt_len);
 
 	ret = true;
 	goto out;
@@ -2028,11 +2343,12 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
 				       uint8_t *req_src)
 {
 	struct batadv_tvlv_tt_data *tvlv_tt_data = NULL;
-	struct batadv_orig_node *orig_node;
 	struct batadv_hard_iface *primary_if = NULL;
-	uint8_t my_ttvn, req_ttvn;
+	struct batadv_tvlv_tt_change *tt_change;
+	struct batadv_orig_node *orig_node;
+	uint8_t my_ttvn, req_ttvn, *tvlv_ptr;
 	bool full_table;
-	uint16_t tt_len;
+	uint16_t tt_len, change_offset;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
 		   "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n",
@@ -2065,29 +2381,45 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
 	 */
 	if (!full_table) {
 		spin_lock_bh(&bat_priv->tt.last_changeset_lock);
-		tt_len = bat_priv->tt.last_changeset_len;
 
-		tvlv_tt_data = kzalloc(sizeof(*tvlv_tt_data) + tt_len,
-				       GFP_ATOMIC);
-		if (!tvlv_tt_data)
+		tt_len = bat_priv->tt.last_changeset_len;
+		tt_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
+							   &tvlv_tt_data,
+							   tt_len);
+		if (!tt_len)
 			goto unlock;
 
+		change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+		change_offset *= ntohs(tvlv_tt_data->num_vlan);
+		change_offset += sizeof(*tvlv_tt_data);
+
+		tvlv_ptr = (uint8_t *)tvlv_tt_data + change_offset;
+		tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
 		/* Copy the last orig_node's OGM buffer */
-		memcpy(tvlv_tt_data + 1, bat_priv->tt.last_changeset,
+		memcpy(tt_change, bat_priv->tt.last_changeset,
 		       bat_priv->tt.last_changeset_len);
 		spin_unlock_bh(&bat_priv->tt.last_changeset_lock);
 	} else {
-		tt_len = (uint16_t)atomic_read(&bat_priv->tt.local_entry_num);
-		tt_len = batadv_tt_len(tt_len);
 		req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn);
 
-		tvlv_tt_data = batadv_tt_tvlv_generate(bat_priv,
-						       bat_priv->tt.local_hash,
-						       tt_len,
-						       batadv_tt_local_valid,
-						       NULL);
-		if (!tvlv_tt_data)
+		/* allocate the tvlv, put the tt_data and all the tt_vlan_data
+		 * in the initial part
+		 */
+		tt_len = batadv_tt_prepare_tvlv_local_data(bat_priv,
+							   &tvlv_tt_data, -1);
+		if (!tt_len)
 			goto out;
+
+		change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+		change_offset *= ntohs(tvlv_tt_data->num_vlan);
+		change_offset += sizeof(*tvlv_tt_data);
+
+		tvlv_ptr = (uint8_t *)tvlv_tt_data + change_offset;
+		tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
+		/* fill the rest of the tvlv with the real TT entries */
+		batadv_tt_tvlv_generate(bat_priv, bat_priv->tt.local_hash,
+					tt_change, tt_len - change_offset,
+					batadv_tt_local_valid, NULL);
 	}
 
 	tvlv_tt_data->flags = BATADV_TT_RESPONSE;
@@ -2103,8 +2435,8 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,
 	batadv_inc_counter(bat_priv, BATADV_CNT_TT_RESPONSE_TX);
 
 	batadv_tvlv_unicast_send(bat_priv, primary_if->net_dev->dev_addr,
-				 req_src, BATADV_TVLV_TT, 1,
-				 tvlv_tt_data, sizeof(*tvlv_tt_data) + tt_len);
+				 req_src, BATADV_TVLV_TT, 1, tvlv_tt_data,
+				 tt_len);
 
 	goto out;
 
@@ -2174,8 +2506,9 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
 }
 
 static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
-				  struct batadv_tvlv_tt_data *tt_data,
-				  uint8_t *resp_src, uint16_t num_entries)
+				  struct batadv_tvlv_tt_change *tt_change,
+				  uint8_t ttvn, uint8_t *resp_src,
+				  uint16_t num_entries)
 {
 	struct batadv_orig_node *orig_node;
 
@@ -2187,9 +2520,8 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
 	batadv_tt_global_del_orig(bat_priv, orig_node, -1,
 				  "Received full table");
 
-	_batadv_tt_update_changes(bat_priv, orig_node,
-				  (struct batadv_tvlv_tt_change *)(tt_data + 1),
-				  num_entries, tt_data->ttvn);
+	_batadv_tt_update_changes(bat_priv, orig_node, tt_change, num_entries,
+				  ttvn);
 
 	spin_lock_bh(&orig_node->tt_buff_lock);
 	kfree(orig_node->tt_buff);
@@ -2197,7 +2529,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
 	orig_node->tt_buff = NULL;
 	spin_unlock_bh(&orig_node->tt_buff_lock);
 
-	atomic_set(&orig_node->last_ttvn, tt_data->ttvn);
+	atomic_set(&orig_node->last_ttvn, ttvn);
 
 out:
 	if (orig_node)
@@ -2261,6 +2593,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
 	struct batadv_tt_req_node *node, *safe;
 	struct batadv_orig_node *orig_node = NULL;
 	struct batadv_tvlv_tt_change *tt_change;
+	uint8_t *tvlv_ptr = (uint8_t *)tt_data;
+	uint16_t change_offset;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
 		   "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n",
@@ -2271,10 +2605,16 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
 	if (!orig_node)
 		goto out;
 
+	change_offset = sizeof(struct batadv_tvlv_tt_vlan_data);
+	change_offset *= ntohs(tt_data->num_vlan);
+	change_offset += sizeof(*tt_data);
+	tvlv_ptr += change_offset;
+
+	tt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;
 	if (tt_data->flags & BATADV_TT_FULL_TABLE) {
-		batadv_tt_fill_gtable(bat_priv, tt_data, resp_src, num_entries);
+		batadv_tt_fill_gtable(bat_priv, tt_change, tt_data->ttvn,
+				      resp_src, num_entries);
 	} else {
-		tt_change = (struct batadv_tvlv_tt_change *)(tt_data + 1);
 		batadv_tt_update_changes(bat_priv, orig_node, num_entries,
 					 tt_data->ttvn, tt_change);
 	}
@@ -2290,7 +2630,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
 	spin_unlock_bh(&bat_priv->tt.req_list_lock);
 
 	/* Recalculate the CRC for this orig_node and store it */
-	orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
+	batadv_tt_global_update_crc(bat_priv, orig_node);
 out:
 	if (orig_node)
 		batadv_orig_node_free_ref(orig_node);
@@ -2457,19 +2797,25 @@ void batadv_tt_free(struct batadv_priv *bat_priv)
 	kfree(bat_priv->tt.last_changeset);
 }
 
-/* This function will enable or disable the specified flags for all the entries
- * in the given hash table and returns the number of modified entries
+/**
+ * batadv_tt_local_set_flags - set or unset the specified flags on the local
+ *  table and possibly count them in the TT size
+ * @bat_priv: the bat priv with all the soft interface information
+ * @flags: the flag to switch
+ * @enable: whether to set or unset the flag
+ * @count: whether to increase the TT size by the number of changed entries
  */
-static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash,
-				    uint16_t flags, bool enable)
+static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv,
+				      uint16_t flags, bool enable, bool count)
 {
-	uint32_t i;
+	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
+	struct batadv_tt_common_entry *tt_common_entry;
 	uint16_t changed_num = 0;
 	struct hlist_head *head;
-	struct batadv_tt_common_entry *tt_common_entry;
+	uint32_t i;
 
 	if (!hash)
-		goto out;
+		return;
 
 	for (i = 0; i < hash->size; i++) {
 		head = &hash->table[i];
@@ -2487,11 +2833,15 @@ static uint16_t batadv_tt_set_flags(struct batadv_hashtable *hash,
 				tt_common_entry->flags &= ~flags;
 			}
 			changed_num++;
+
+			if (!count)
+				continue;
+
+			batadv_tt_local_size_add(bat_priv, tt_common_entry->vid,
+						 1);
 		}
 		rcu_read_unlock();
 	}
-out:
-	return changed_num;
 }
 
 /* Purge out all the tt local entries marked with BATADV_TT_CLIENT_PENDING */
@@ -2523,7 +2873,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
 				   tt_common->addr,
 				   BATADV_PRINT_VID(tt_common->vid));
 
-			atomic_dec(&bat_priv->tt.local_entry_num);
+			batadv_tt_local_size_add(bat_priv, tt_common->vid, -1);
 			hlist_del_rcu(&tt_common->hash_entry);
 			tt_local = container_of(tt_common,
 						struct batadv_tt_local_entry,
@@ -2541,21 +2891,16 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
  */
 void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv)
 {
-	uint16_t changed_num = 0;
-
 	if (atomic_read(&bat_priv->tt.local_changes) < 1) {
 		if (!batadv_atomic_dec_not_zero(&bat_priv->tt.ogm_append_cnt))
 			batadv_tt_tvlv_container_update(bat_priv);
 		return;
 	}
 
-	changed_num = batadv_tt_set_flags(bat_priv->tt.local_hash,
-					  BATADV_TT_CLIENT_NEW, false);
+	batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
 
-	/* all reset entries have to be counted as local entries */
-	atomic_add(changed_num, &bat_priv->tt.local_entry_num);
 	batadv_tt_local_purge_pending_clients(bat_priv);
-	bat_priv->tt.local_crc = batadv_tt_local_crc(bat_priv);
+	batadv_tt_local_update_crc(bat_priv);
 
 	/* Increment the TTVN only once per OGM interval */
 	atomic_inc(&bat_priv->tt.vn);
@@ -2573,9 +2918,16 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src,
 {
 	struct batadv_tt_local_entry *tt_local_entry = NULL;
 	struct batadv_tt_global_entry *tt_global_entry = NULL;
-	bool ret = false;
+	bool ap_isolation_enabled = false, ret = false;
+	struct batadv_softif_vlan *vlan;
 
-	if (!atomic_read(&bat_priv->ap_isolation))
+	vlan = batadv_softif_vlan_get(bat_priv, vid);
+	if (vlan) {
+		ap_isolation_enabled = atomic_read(&vlan->ap_isolation);
+		batadv_softif_vlan_free_ref(vlan);
+	}
+
+	if (ap_isolation_enabled)
 		goto out;
 
 	tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid);
@@ -2604,21 +2956,24 @@ out:
  *  information received via ogms
  * @bat_priv: the bat priv with all the soft interface information
  * @orig: the orig_node of the ogm
- * @tt_buff: buffer holding the tt information
+ * @tt_vlan: pointer to the first tvlv VLAN entry
+ * @tt_num_vlan: number of tvlv VLAN entries
+ * @tt_change: pointer to the first entry in the TT buffer
  * @tt_num_changes: number of tt changes inside the tt buffer
  * @ttvn: translation table version number of this changeset
  * @tt_crc: crc32 checksum of orig node's translation table
  */
 static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 				  struct batadv_orig_node *orig_node,
-				  const unsigned char *tt_buff,
-				  uint16_t tt_num_changes, uint8_t ttvn,
-				  uint32_t tt_crc)
+				  const void *tt_buff, uint16_t tt_num_vlan,
+				  struct batadv_tvlv_tt_change *tt_change,
+				  uint16_t tt_num_changes, uint8_t ttvn)
 {
 	uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn);
+	struct batadv_tvlv_tt_vlan_data *tt_vlan;
 	bool full_table = true;
-	struct batadv_tvlv_tt_change *tt_change;
 
+	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
 	/* orig table not initialised AND first diff is in the OGM OR the ttvn
 	 * increased by one -> we can apply the attached changes
 	 */
@@ -2634,7 +2989,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 			goto request_table;
 		}
 
-		tt_change = (struct batadv_tvlv_tt_change *)tt_buff;
 		batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes,
 					 ttvn, tt_change);
 
@@ -2642,7 +2996,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 		 * prefer to recompute it to spot any possible inconsistency
 		 * in the global table
 		 */
-		orig_node->tt_crc = batadv_tt_global_crc(bat_priv, orig_node);
+		batadv_tt_global_update_crc(bat_priv, orig_node);
 
 		/* The ttvn alone is not enough to guarantee consistency
 		 * because a single value could represent different states
@@ -2653,21 +3007,24 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
 		 * checking the CRC value is mandatory to detect the
 		 * inconsistency
 		 */
-		if (orig_node->tt_crc != tt_crc)
+		if (!batadv_tt_global_check_crc(orig_node, tt_vlan,
+						tt_num_vlan))
 			goto request_table;
 	} else {
 		/* if we missed more than one change or our tables are not
 		 * in sync anymore -> request fresh tt data
 		 */
 		if (!orig_node->tt_initialised || ttvn != orig_ttvn ||
-		    orig_node->tt_crc != tt_crc) {
+		    !batadv_tt_global_check_crc(orig_node, tt_vlan,
+						tt_num_vlan)) {
 request_table:
 			batadv_dbg(BATADV_DBG_TT, bat_priv,
-				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u crc: %#.8x last_crc: %#.8x num_changes: %u)\n",
-				   orig_node->orig, ttvn, orig_ttvn, tt_crc,
-				   orig_node->tt_crc, tt_num_changes);
+				   "TT inconsistency for %pM. Need to retrieve the correct information (ttvn: %u last_ttvn: %u num_changes: %u)\n",
+				   orig_node->orig, ttvn, orig_ttvn,
+				   tt_num_changes);
 			batadv_send_tt_request(bat_priv, orig_node, ttvn,
-					       tt_crc, full_table);
+					       tt_vlan, tt_num_vlan,
+					       full_table);
 			return;
 		}
 	}
@@ -2755,12 +3112,13 @@ out:
  */
 static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
 					  struct batadv_orig_node *orig,
-					  uint8_t flags,
-					  void *tvlv_value,
+					  uint8_t flags, void *tvlv_value,
 					  uint16_t tvlv_value_len)
 {
+	struct batadv_tvlv_tt_vlan_data *tt_vlan;
+	struct batadv_tvlv_tt_change *tt_change;
 	struct batadv_tvlv_tt_data *tt_data;
-	uint16_t num_entries;
+	uint16_t num_entries, num_vlan;
 
 	if (tvlv_value_len < sizeof(*tt_data))
 		return;
@@ -2768,11 +3126,19 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
 	tvlv_value_len -= sizeof(*tt_data);
 
+	num_vlan = ntohs(tt_data->num_vlan);
+
+	if (tvlv_value_len < sizeof(*tt_vlan) * num_vlan)
+		return;
+
+	tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1);
+	tt_change = (struct batadv_tvlv_tt_change *)(tt_vlan + num_vlan);
+	tvlv_value_len -= sizeof(*tt_vlan) * num_vlan;
+
 	num_entries = batadv_tt_entries(tvlv_value_len);
 
-	batadv_tt_update_orig(bat_priv, orig,
-			      (unsigned char *)(tt_data + 1),
-			      num_entries, tt_data->ttvn, ntohl(tt_data->crc));
+	batadv_tt_update_orig(bat_priv, orig, tt_vlan, num_vlan, tt_change,
+			      num_entries, tt_data->ttvn);
 }
 
 /**
@@ -2793,7 +3159,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 					     uint16_t tvlv_value_len)
 {
 	struct batadv_tvlv_tt_data *tt_data;
-	uint16_t num_entries;
+	uint16_t tt_vlan_len, tt_num_entries;
 	char tt_flag;
 	bool ret;
 
@@ -2803,7 +3169,14 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 	tt_data = (struct batadv_tvlv_tt_data *)tvlv_value;
 	tvlv_value_len -= sizeof(*tt_data);
 
-	num_entries = batadv_tt_entries(tvlv_value_len);
+	tt_vlan_len = sizeof(struct batadv_tvlv_tt_vlan_data);
+	tt_vlan_len *= ntohs(tt_data->num_vlan);
+
+	if (tvlv_value_len < tt_vlan_len)
+		return NET_RX_SUCCESS;
+
+	tvlv_value_len -= tt_vlan_len;
+	tt_num_entries = batadv_tt_entries(tvlv_value_len);
 
 	switch (tt_data->flags & BATADV_TT_DATA_TYPE_MASK) {
 	case BATADV_TT_REQUEST:
@@ -2831,7 +3204,7 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv,
 
 		if (batadv_is_my_mac(bat_priv, dst)) {
 			batadv_handle_tt_response(bat_priv, tt_data,
-						  src, num_entries);
+						  src, tt_num_entries);
 			return NET_RX_SUCCESS;
 		}
 
diff --git a/types.h b/types.h
index ad8671d..3f5ef9b 100644
--- a/types.h
+++ b/types.h
@@ -107,6 +107,32 @@ struct batadv_frag_list_entry {
 };
 
 /**
+ * struct batadv_vlan_tt - VLAN specific TT attributes
+ * @crc: CRC32 checksum of the entries belonging to this vlan
+ * @num_entries: number of TT entries for this VLAN
+ */
+struct batadv_vlan_tt {
+	uint32_t crc;
+	atomic_t num_entries;
+};
+
+/**
+ * batadv_orig_node_vlan - VLAN specific data per orig_node
+ * @vid: the VLAN identifier
+ * @tt: VLAN specific TT attributes
+ * @list: list node for orig_node::vlan_list
+ * @refcount: number of context where this object is currently in use
+ * @rcu: struct used for freeing in a RCU-safe manner
+ */
+struct batadv_orig_node_vlan {
+	unsigned short vid;
+	struct batadv_vlan_tt tt;
+	struct list_head list;
+	atomic_t refcount;
+	struct rcu_head rcu;
+};
+
+/**
  * struct batadv_orig_node - structure for orig_list maintaining nodes of mesh
  * @orig: originator ethernet address
  * @primary_addr: hosts primary interface address
@@ -120,12 +146,10 @@ struct batadv_frag_list_entry {
  * @batman_seqno_reset: time when the batman seqno window was reset
  * @capabilities: announced capabilities of this originator
  * @last_ttvn: last seen translation table version number
- * @tt_crc: CRC of the translation table
  * @tt_buff: last tt changeset this node received from the orig node
  * @tt_buff_len: length of the last tt changeset this node received from the
  *  orig node
  * @tt_buff_lock: lock that protects tt_buff and tt_buff_len
- * @tt_size: number of global TT entries announced by the orig node
  * @tt_initialised: bool keeping track of whether or not this node have received
  *  any translation table information from the orig node yet
  * @last_real_seqno: last and best known sequence number
@@ -150,6 +174,9 @@ struct batadv_frag_list_entry {
  * @in_coding_list_lock: protects in_coding_list
  * @out_coding_list_lock: protects out_coding_list
  * @fragments: array with heads for fragment chains
+ * @vlan_list: a list of orig_node_vlan structs, one per VLAN served by the
+ *  originator represented by this object
+ * @vlan_list_lock: lock protecting vlan_list
  */
 struct batadv_orig_node {
 	uint8_t orig[ETH_ALEN];
@@ -165,11 +192,9 @@ struct batadv_orig_node {
 	unsigned long batman_seqno_reset;
 	uint8_t capabilities;
 	atomic_t last_ttvn;
-	uint32_t tt_crc;
 	unsigned char *tt_buff;
 	int16_t tt_buff_len;
 	spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */
-	atomic_t tt_size;
 	bool tt_initialised;
 	uint32_t last_real_seqno;
 	uint8_t last_ttl;
@@ -197,6 +222,8 @@ struct batadv_orig_node {
 	spinlock_t out_coding_list_lock; /* Protects out_coding_list */
 #endif
 	struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT];
+	struct list_head vlan_list;
+	spinlock_t vlan_list_lock; /* protects vlan_list */
 };
 
 /**
@@ -402,8 +429,6 @@ struct batadv_priv_tt {
 	spinlock_t changes_list_lock; /* protects changes */
 	spinlock_t req_list_lock; /* protects req_list */
 	spinlock_t roam_list_lock; /* protects roam_list */
-	atomic_t local_entry_num;
-	uint32_t local_crc;
 	unsigned char *last_changeset;
 	int16_t last_changeset_len;
 	/* protects last_changeset & last_changeset_len */
@@ -535,6 +560,7 @@ struct batadv_priv_nc {
  * @vid: VLAN identifier
  * @kobj: kobject for sysfs vlan subdirectory
  * @ap_isolation: AP isolation state
+ * @tt: TT private attributes (VLAN specific)
  * @list: list node for bat_priv::softif_vlan_list
  * @refcount: number of context where this object is currently in use
  * @rcu: struct used for freeing in a RCU-safe manner
@@ -543,6 +569,7 @@ struct batadv_softif_vlan {
 	unsigned short vid;
 	struct kobject *kobj;
 	atomic_t ap_isolation;		/* boolean */
+	struct batadv_vlan_tt tt;
 	struct list_head list;
 	atomic_t refcount;
 	struct rcu_head rcu;
@@ -558,7 +585,6 @@ struct batadv_softif_vlan {
  * @bonding: bool indicating whether traffic bonding is enabled
  * @fragmentation: bool indicating whether traffic fragmentation is enabled
  * @frag_seqno: incremental counter to identify chains of egress fragments
- * @ap_isolation: bool indicating whether ap isolation is enabled
  * @bridge_loop_avoidance: bool indicating whether bridge loop avoidance is
  *  enabled
  * @distributed_arp_table: bool indicating whether distributed ARP table is
@@ -605,7 +631,6 @@ struct batadv_priv {
 	atomic_t bonding;
 	atomic_t fragmentation;
 	atomic_t frag_seqno;
-	atomic_t ap_isolation;
 #ifdef CONFIG_BATMAN_ADV_BLA
 	atomic_t bridge_loop_avoidance;
 #endif
-- 
1.8.1.5


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

* Re: [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry Antonio Quartulli
@ 2013-06-09 13:50   ` Marek Lindner
  0 siblings, 0 replies; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 13:50 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli, Antonio Quartulli

On Tuesday, June 04, 2013 18:11:39 Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> To make the translation table code VLAN-aware, each entry
> must carry the VLAN ID which it belongs to. This patch adds
> such attribute to the related TT structures.
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  bridge_loop_avoidance.c |  35 +++----
>  distributed-arp-table.c |  11 ++-
>  gateway_client.c        |   3 +-
>  main.c                  |  30 +++++-
>  main.h                  |   9 +-
>  packet.h                |  14 ++-
>  routing.c               |  26 ++++--
>  send.c                  |   8 +-
>  send.h                  |  16 ++--
>  soft-interface.c        |  33 ++++---
>  translation-table.c     | 239
> +++++++++++++++++++++++++++++++++++++-----------
> translation-table.h     |  19 ++--
>  types.h                 |   2 +
>  13 files changed, 312 insertions(+), 133 deletions(-)

Applied in revision 580d791.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC Antonio Quartulli
@ 2013-06-09 13:55   ` Marek Lindner
  0 siblings, 0 replies; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 13:55 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli, Antonio Quartulli

On Tuesday, June 04, 2013 18:11:40 Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> now that each TT entry is characterised by a VLAN ID, the
> latter has to be taken into consideration when computing the
> local/global table CRC as it would be theoretically possible
> to have the same client in two different VLANs
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  translation-table.c | 35 +++++++++++++++++++++++++++++++----
>  1 file changed, 31 insertions(+), 4 deletions(-)

Applied in revision 4af2a1b.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries Antonio Quartulli
@ 2013-06-09 13:58   ` Marek Lindner
  0 siblings, 0 replies; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 13:58 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli, Antonio Quartulli

On Tuesday, June 04, 2013 18:11:41 Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  main.h              |  1 +
>  translation-table.c | 82
> ++++++++++++++++++++++++++++++++--------------------- 2 files changed, 51
> insertions(+), 32 deletions(-)

Applied in revision 8fc2466.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT Antonio Quartulli
@ 2013-06-09 14:02   ` Marek Lindner
  0 siblings, 0 replies; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 14:02 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli, Antonio Quartulli

On Tuesday, June 04, 2013 18:11:42 Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> The gateway code is now adapted in order to correctly
> interact with the Translation Table component by using the
> vlan ID
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  gateway_client.c | 19 +++++++++++++++++--
>  1 file changed, 17 insertions(+), 2 deletions(-)

Applied in revision 9a40777.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware Antonio Quartulli
@ 2013-06-09 14:11   ` Marek Lindner
  0 siblings, 0 replies; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 14:11 UTC (permalink / raw)
  To: b.a.t.m.a.n; +Cc: Antonio Quartulli, Antonio Quartulli

On Tuesday, June 04, 2013 18:11:43 Antonio Quartulli wrote:
> From: Antonio Quartulli <antonio@open-mesh.com>
> 
> The same IP subnet can be used on different VLANs, therefore
> DAT has to differentiate whether the IP to resolve belongs
> to one or the other virtual LAN.
> To accomplish this task DAT has to deal with the VLAN tag
> and store it together with each ARP entry.
> 
> Signed-off-by: Antonio Quartulli <antonio@open-mesh.com>
> ---
>  distributed-arp-table.c | 122
> ++++++++++++++++++++++++++++++++----------------
> types.h                 |   2 +
>  2 files changed, 85 insertions(+), 39 deletions(-)

Applied in revision 3e26722.

Thanks,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN
  2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN Antonio Quartulli
@ 2013-06-09 14:13   ` Marek Lindner
  2013-06-09 14:20     ` Antonio Quartulli
  0 siblings, 1 reply; 21+ messages in thread
From: Marek Lindner @ 2013-06-09 14:13 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

On Tuesday, June 04, 2013 18:11:46 Antonio Quartulli wrote:
> To make the code simpler and easier to extend, treat the
> normal LAN (bat0) like any other VLAN having vid 0
> (untagged).
> 
> This change makes things simpler since bat0 is not a
> particular case anymore but it is treated like any other
> VLAN.

What makes you think "vid 0" is not a valid vlan tag ? If this patch is 
applied how can I create a VLAN 0 on top of batX ?

Cheers,
Marek

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

* Re: [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN
  2013-06-09 14:13   ` Marek Lindner
@ 2013-06-09 14:20     ` Antonio Quartulli
  0 siblings, 0 replies; 21+ messages in thread
From: Antonio Quartulli @ 2013-06-09 14:20 UTC (permalink / raw)
  To: The list for a Better Approach To Mobile Ad-hoc Networking

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

On Sun, Jun 09, 2013 at 10:13:59PM +0800, Marek Lindner wrote:
> On Tuesday, June 04, 2013 18:11:46 Antonio Quartulli wrote:
> > To make the code simpler and easier to extend, treat the
> > normal LAN (bat0) like any other VLAN having vid 0
> > (untagged).
> > 
> > This change makes things simpler since bat0 is not a
> > particular case anymore but it is treated like any other
> > VLAN.
> 
> What makes you think "vid 0" is not a valid vlan tag ? If this patch is 
> applied how can I create a VLAN 0 on top of batX ?

The commit message talks about the value of the vid variable (used to keep the
value of the VID, of course) and as introduced in a previous patch, if the
HAS_TAG bit is not set, then we don't consider the this variable to represent a
real VID.

VLAN 0 on top of batX will generate vid = (HAS_TAG | 0), while in this case I am
talking about vid = 0.

This is implicit in the vid variables semantic previously introduced and this
is what I meant with that "untagged" at the end of the sentence.

Maybe we should substitute "having vid 0" with "having vid with no HAS_TAG bit
set" ?


Cheers,



-- 
Antonio Quartulli

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

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

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

end of thread, other threads:[~2013-06-09 14:20 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-04 10:11 [B.A.T.M.A.N.] [PATCHv4 00/13] make the Translation Table component VLAN-aware Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 01/13] batman-adv: add the VLAN ID attribute to the TT entry Antonio Quartulli
2013-06-09 13:50   ` Marek Lindner
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 02/13] batman-adv: use vid when computing local and global TT CRC Antonio Quartulli
2013-06-09 13:55   ` Marek Lindner
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 03/13] batman-adv: print the VID together with the TT entries Antonio Quartulli
2013-06-09 13:58   ` Marek Lindner
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 04/13] batman-adv: make the GW module correctly talk to the new VLAN-TT Antonio Quartulli
2013-06-09 14:02   ` Marek Lindner
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 05/13] batman-adv: make the Distributed ARP Table vlan aware Antonio Quartulli
2013-06-09 14:11   ` Marek Lindner
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 06/13] batman-adv: add per VLAN interface attribute framework Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 07/13] batman-adv: initialise sysfs folder in softif_create() Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 08/13] batman-adv: treat bat0 like yet another VLAN Antonio Quartulli
2013-06-09 14:13   ` Marek Lindner
2013-06-09 14:20     ` Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 09/13] batman-adv: add sysfs framework for VLAN Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 10/13] batman-adv: make the AP isolation attribute VLAN specific Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 11/13] batman-adv: make the backbone gw check " Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 12/13] batman-adv: make the TT global purge routine " Antonio Quartulli
2013-06-04 10:11 ` [B.A.T.M.A.N.] [PATCHv4 13/13] batman-adv: make the TT CRC logic " Antonio Quartulli

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