Included changed:

- email addresses update in documentation, source files and MAINTAINERS
 - make the TT component distinguish non-mesh clients based on the VLAN they
   belong to
 - improve all the internal components to properly work on a per-VLAN basis
   (enabled by the new TT-VLAN feature)
 - enhance the sysfs interface in order to provide behaviour switches on a
   per-VLAN basis (enabled by the new TT-VLAN feature)
 - improve TT lock mechanism
 - improve unicast transmission APIs
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABCAAGBQJSYvnjAAoJEADl0hg6qKeOGFAQAK+P3XkProP+MWhgpQzWDc+F
 TCVvi3eQ9NKVzxVnglRTznEVqXePVArK9oWb39KbCeguoqsuo7T8I+oNK06qPCH6
 1aodkBqJLq0OT1EWIxMo+1eOHCevRRqBjS1Jh0DMxuugMsKZZu3/DrHK59ay/4y7
 8wRb8CqQrKpILsh43cKRm9SPNJj0nmFPIwoWmgu++ffPyfIPMnBHSowMEgxqJ3h4
 Vp4adjJQU2D3qa1Vln99MYzdJaUhRDVDjxdAroCbuk6M1bl9o88UjhFxRvZJN8JN
 HdxiMN1hvlDJ7OsiBGw42RROnibyqkui8BZl5hP85sjbKSSU9lCqMJ1XWW+gVNhx
 sKA7LIm7NPNW9Ysvgd3FhjX/cg18WgjC2HHU26uMhYmGrGUfP8eBw55XidabApgb
 TpGhKjFxhYqfGnPhAtarsqLYfxWh6vbb1G6cyaC5jJ4baIa5YKqt8tejHCNiFJLI
 WrVnmi0TJfGjdoULfUdkBOx/pI6zyZ3PWPISbIDUIslQXrnEzKUj37VbN3N0Qlj1
 QcVcC+iVd3/gJ/dnvKzmeGjsm2nKK5eEwewRtNuPkQSaM13/dN2CUQ4/+/6BSY1D
 wODn+Wc5zCoi8sxvVb7TcT+NLO27QkH0REJh4W9KxJx9NSws0BfiVBcTKPFCra+x
 gMsgNYNdgoCTLQBNj8KK
 =sEEg
 -----END PGP SIGNATURE-----

Merge tag 'batman-adv-for-davem' of git://git.open-mesh.org/linux-merge

Antonio Quartulli says:

====================
this is another batch intended for net-next/linux-3.13.

This pull request is a bit bigger than usual, but 6 patches are very small
(three of them are about email updates)..

Patch 1 is fixing a previous merge conflict resolution that went wrong
(I realised that only now while checking other patches..).
Patches from 2 to 4 that are updating our emails in all the proper files
(Documentation/, headers and MAINTAINERS).

Patches 5, 6 and 7 are bringing a big improvement to the TranslationTable
component: it is now able to group non-mesh clients based on the VLAN they
belong to. In this way a lot a new enhancements are now possible thanks to the
fact that each batman-adv behaviour can be applied on a per VLAN basis.

And, of course, in patches from 8 to 12 you have some of the enhancements I was
talking about:
- make the batman-Gateway selection VLAN dependent
- make DAT (Distributed ARP Table) group ARP entries on a VLAN basis (this
  allows DAT to work even when the admin decided to use the same IP subnet on
  different VLANs)
- make the AP-Isolation behaviour switchable on each VLAN independently
- export VLAN specific attributes via sysfs. Switches like the AP-Isolation are
  now exported once per VLAN (backward compatibility of the sysfs interface has
  been preserved)

Patches 13 and 14 are small code cleanups.
Patch 15 is a minor improvement in the TT locking mechanism.

Patches 16 and 17 are other enhancements to the TT component. Those allow a
node to parse a "non-mesh client announcement message" and accept only those
TT entries belonging to certain VLANs.

Patch 18 exploits this parse&accept mechanism to make the Bridge Loop Avoidance
component reject only TT entries connected to the VLAN where it is operating.
Previous to this change, BLA was rejecting all the entries coming from any other
Backbone node, regardless of the VLAN (for more details about how the Bridge
Loop Avoidance works please check [1]).

[1] http://www.open-mesh.org/projects/batman-adv/wiki/Bridge-loop-avoidance-II
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2013-10-19 19:52:42 -04:00
commit 5bf47256f5
24 changed files with 1854 additions and 490 deletions

View File

@ -1,13 +1,13 @@
What: /sys/class/net/<iface>/batman-adv/iface_status
Date: May 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Indicates the status of <iface> as it is seen by batman.
What: /sys/class/net/<iface>/batman-adv/mesh_iface
Date: May 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
The /sys/class/net/<iface>/batman-adv/mesh_iface file
displays the batman mesh interface this <iface>

View File

@ -1,22 +1,23 @@
What: /sys/class/net/<mesh_iface>/mesh/aggregated_ogms
Date: May 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
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>
Contact: Antonio Quartulli <antonio@meshcoding.com>
Description:
Indicates whether the data traffic going from a
wireless client to another wireless client will be
silently dropped.
silently dropped. <vlan_subdir> is empty when referring
to the untagged lan.
What: /sys/class/net/<mesh_iface>/mesh/bonding
Date: June 2010
Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Contact: Simon Wunderlich <sw@simonwunderlich.de>
Description:
Indicates whether the data traffic going through the
mesh will be sent using multiple interfaces at the
@ -24,7 +25,7 @@ Description:
What: /sys/class/net/<mesh_iface>/mesh/bridge_loop_avoidance
Date: November 2011
Contact: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Contact: Simon Wunderlich <sw@simonwunderlich.de>
Description:
Indicates whether the bridge loop avoidance feature
is enabled. This feature detects and avoids loops
@ -41,21 +42,21 @@ Description:
What: /sys/class/net/<mesh_iface>/mesh/gw_bandwidth
Date: October 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Defines the bandwidth which is propagated by this
node if gw_mode was set to 'server'.
What: /sys/class/net/<mesh_iface>/mesh/gw_mode
Date: October 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Defines the state of the gateway features. Can be
either 'off', 'client' or 'server'.
What: /sys/class/net/<mesh_iface>/mesh/gw_sel_class
Date: October 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Defines the selection criteria this node will use
to choose a gateway if gw_mode was set to 'client'.
@ -77,14 +78,14 @@ Description:
What: /sys/class/net/<mesh_iface>/mesh/orig_interval
Date: May 2010
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Defines the interval in milliseconds in which batman
sends its protocol messages.
What: /sys/class/net/<mesh_iface>/mesh/routing_algo
Date: Dec 2011
Contact: Marek Lindner <lindner_marek@yahoo.de>
Contact: Marek Lindner <mareklindner@neomailbox.ch>
Description:
Defines the routing procotol this mesh instance
uses to find the optimal paths through the mesh.

View File

@ -199,5 +199,5 @@ Mailing-list: b.a.t.m.a.n@open-mesh.org (optional subscription
You can also contact the Authors:
Marek Lindner <lindner_marek@yahoo.de>
Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
Marek Lindner <mareklindner@neomailbox.ch>
Simon Wunderlich <sw@simonwunderlich.de>

View File

@ -1653,7 +1653,7 @@ F: include/linux/backlight.h
BATMAN ADVANCED
M: Marek Lindner <mareklindner@neomailbox.ch>
M: Simon Wunderlich <siwu@hrz.tu-chemnitz.de>
M: Simon Wunderlich <sw@simonwunderlich.de>
M: Antonio Quartulli <antonio@meshcoding.com>
L: b.a.t.m.a.n@lists.open-mesh.org
W: http://www.open-mesh.org/

View File

@ -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);
}
@ -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 vlan_ethhdr *vhdr;
struct arphdr *arphdr;
uint8_t *hw_src, *hw_dst;
struct batadv_bla_claim_dst *bla_dst;
uint8_t *hw_src, *hw_dst;
struct vlan_ethhdr *vhdr;
struct ethhdr *ethhdr;
struct arphdr *arphdr;
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))
@ -1317,12 +1315,14 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
/* @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 the VLAN identified 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;
@ -1330,25 +1330,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;
}
@ -1365,10 +1366,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;
@ -1377,16 +1376,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,

View File

@ -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

View File

@ -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();
@ -265,22 +267,24 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip)
* @bat_priv: the bat priv with all the soft interface information
* @ip: ipv4 to add/edit
* @mac_addr: mac address to assign to the given ipv4
* @vid: VLAN identifier
*/
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: %d)\n",
&dat_entry->ip, dat_entry->mac_addr,
BATADV_PRINT_VID(vid));
goto out;
}
@ -289,12 +293,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 +308,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: %d)\n",
&dat_entry->ip, dat_entry->mac_addr, BATADV_PRINT_VID(vid));
out:
if (dat_entry)
@ -756,8 +761,8 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
goto out;
seq_printf(seq, "Distributed ARP Table (%s):\n", net_dev->name);
seq_printf(seq, " %-7s %-13s %5s\n", "IPv4", "MAC",
"last-seen");
seq_printf(seq, " %-7s %-9s %4s %11s\n", "IPv4",
"MAC", "VID", "last-seen");
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
@ -770,8 +775,9 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset)
last_seen_msecs = last_seen_msecs % 60000;
last_seen_secs = last_seen_msecs / 1000;
seq_printf(seq, " * %15pI4 %14pM %6i:%02i\n",
seq_printf(seq, " * %15pI4 %14pM %4i %6i:%02i\n",
&dat_entry->ip, dat_entry->mac_addr,
BATADV_PRINT_VID(dat_entry->vid),
last_seen_mins, last_seen_secs);
}
rcu_read_unlock();
@ -857,6 +863,31 @@ static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv,
return type;
}
/**
* 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 embedded in the skb is vlan tagged this function returns the
* VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned.
*/
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 skip 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
@ -876,26 +907,31 @@ 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
*/
if (type != ARPOP_REQUEST)
goto out;
batadv_dbg_arp(bat_priv, skb, type, 0, "Parsing outgoing ARP REQUEST");
batadv_dbg_arp(bat_priv, skb, type, hdr_size,
"Parsing outgoing ARP REQUEST");
ip_src = batadv_arp_ip_src(skb, 0);
hw_src = batadv_arp_hw_src(skb, 0);
ip_dst = batadv_arp_ip_dst(skb, 0);
ip_src = batadv_arp_ip_src(skb, hdr_size);
hw_src = batadv_arp_hw_src(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_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
@ -905,7 +941,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;
}
@ -916,11 +953,15 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
if (!skb_new)
goto out;
if (vid & BATADV_VLAN_HAS_TAG)
skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK);
skb_reset_mac_header(skb_new);
skb_new->protocol = eth_type_trans(skb_new,
bat_priv->soft_iface);
bat_priv->stats.rx_packets++;
bat_priv->stats.rx_bytes += skb->len + ETH_HLEN;
bat_priv->stats.rx_bytes += skb->len + ETH_HLEN + hdr_size;
bat_priv->soft_iface->last_rx = jiffies;
netif_rx(skb_new);
@ -955,11 +996,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;
@ -971,9 +1015,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;
@ -984,17 +1028,22 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!skb_new)
goto out;
if (vid & BATADV_VLAN_HAS_TAG)
skb_new = vlan_insert_tag(skb_new, htons(ETH_P_8021Q),
vid & VLAN_VID_MASK);
/* To preserve backwards compatibility, the node has choose the outgoing
* format based on the incoming request packet type. The assumption is
* that a node not using the 4addr packet format doesn't support it.
*/
if (hdr_size == sizeof(struct batadv_unicast_4addr_packet))
err = batadv_send_skb_unicast_4addr(bat_priv, skb_new,
BATADV_P_DAT_CACHE_REPLY);
err = batadv_send_skb_via_tt_4addr(bat_priv, skb_new,
BATADV_P_DAT_CACHE_REPLY,
vid);
else
err = batadv_send_skb_unicast(bat_priv, skb_new);
err = batadv_send_skb_via_tt(bat_priv, skb_new, vid);
if (!err) {
if (err != NET_XMIT_DROP) {
batadv_inc_counter(bat_priv, BATADV_CNT_DAT_CACHED_REPLY_TX);
ret = true;
}
@ -1017,23 +1066,28 @@ 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");
batadv_dbg_arp(bat_priv, skb, type, hdr_size,
"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
@ -1055,10 +1109,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;
@ -1074,13 +1131,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);
ret = !batadv_is_my_client(bat_priv, hw_dst, vid);
out:
if (ret)
kfree_skb(skb);
@ -1103,7 +1160,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;
@ -1114,12 +1172,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,

View File

@ -221,11 +221,6 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
struct batadv_neigh_node *router = NULL;
char gw_addr[18] = { '\0' };
/* The batman daemon checks here if we already passed a full originator
* cycle in order to make sure we don't choose the first gateway we
* hear about. This check is based on the daemon's uptime which we
* don't have.
*/
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
goto out;
@ -726,7 +721,20 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
return true;
}
/* this call might reallocate skb data */
/**
* batadv_gw_out_of_range - check if the dhcp request destination is the best gw
* @bat_priv: the bat priv with all the soft interface information
* @skb: the outgoing packet
*
* Check if the skb is a DHCP request and if it is 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.
*
* Returns true if the packet destination is unicast and it is not the best gw,
* false otherwise.
*
* This call might reallocate skb data.
*/
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
struct sk_buff *skb)
{
@ -737,6 +745,9 @@ 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)
@ -744,7 +755,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest);
ethhdr->h_dest, vid);
if (!orig_dst_node)
goto out;

View File

@ -643,6 +643,8 @@ static int batadv_hard_if_event(struct notifier_block *this,
if (batadv_softif_is_valid(net_dev) && event == NETDEV_REGISTER) {
batadv_sysfs_add_meshif(net_dev);
bat_priv = netdev_priv(net_dev);
batadv_softif_create_vlan(bat_priv, BATADV_NO_FLAGS);
return NOTIFY_DONE;
}

View File

@ -110,9 +110,11 @@ int batadv_mesh_init(struct net_device *soft_iface)
spin_lock_init(&bat_priv->tt.req_list_lock);
spin_lock_init(&bat_priv->tt.roam_list_lock);
spin_lock_init(&bat_priv->tt.last_changeset_lock);
spin_lock_init(&bat_priv->tt.commit_lock);
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);
@ -122,6 +124,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_HLIST_HEAD(&bat_priv->softif_vlan_list);
ret = batadv_originator_init(bat_priv);
if (ret < 0)
@ -131,9 +134,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);
ret = batadv_bla_init(bat_priv);
if (ret < 0)
goto err;
@ -1144,6 +1144,33 @@ void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src,
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 header
*
* If the packet embedded in the skb is vlan tagged this function returns the
* VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS is returned.
*/
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;

View File

@ -20,8 +20,8 @@
#ifndef _NET_BATMAN_ADV_MAIN_H_
#define _NET_BATMAN_ADV_MAIN_H_
#define BATADV_DRIVER_AUTHOR "Marek Lindner <lindner_marek@yahoo.de>, " \
"Simon Wunderlich <siwu@hrz.tu-chemnitz.de>"
#define BATADV_DRIVER_AUTHOR "Marek Lindner <mareklindner@neomailbox.ch>, " \
"Simon Wunderlich <sw@simonwunderlich.de>"
#define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced"
#define BATADV_DRIVER_DEVICE "batman-adv"
@ -167,15 +167,9 @@ enum batadv_uev_type {
#include <net/rtnetlink.h>
#include <linux/jiffies.h>
#include <linux/seq_file.h>
#include "types.h"
#include <linux/if_vlan.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),
};
#include "types.h"
#define BATADV_PRINT_VID(vid) (vid & BATADV_VLAN_HAS_TAG ? \
(int)(vid & VLAN_VID_MASK) : -1)
@ -368,5 +362,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_ */

View File

@ -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 serving the VLAN
* @vid: the VLAN identifier
*
* Returns the vlan object identified by vid and belonging to orig_node 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 = NULL, *tmp;
rcu_read_lock();
list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) {
if (tmp->vid != vid)
continue;
if (!atomic_inc_not_zero(&tmp->refcount))
continue;
vlan = tmp;
break;
}
rcu_read_unlock();
return vlan;
}
/**
* 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
*
* Returns NULL in case of failure or the vlan object identified by vid and
* belonging to orig_node otherwise. The object is created and added to the list
* if it does not exist.
*
* The object is returned with refcounter increased by 1.
*/
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 */
vlan = batadv_orig_node_vlan_get(orig_node, vid);
if (vlan)
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;
}
/**
* batadv_orig_node_vlan_free_ref - decrement the refcounter and possibly free
* the originator-vlan object
* @orig_vlan: the originator-vlan object to release
*/
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)
@ -148,7 +230,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);
@ -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,13 @@ 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->tt_lock);
spin_lock_init(&orig_node->vlan_list_lock);
batadv_nc_init_orig(orig_node);
@ -250,22 +336,30 @@ 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;
/* batadv_orig_node_vlan_new() increases the refcounter.
* Immediately release vlan since it is not needed anymore in this
* context
*/
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 +384,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
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;

View File

@ -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

View File

@ -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,
@ -383,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 tvlv container
* @crc: crc32 checksum of the entries belonging to this vlan
* @vid: vlan identifier
* @reserved: unused, useful for alignment purposes
*/
struct batadv_tvlv_tt_vlan_data {
__be32 crc;
__be16 vid;
uint16_t reserved;
__be32 crc;
};
/**
@ -399,21 +419,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_ */

View File

@ -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);
@ -45,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 */
@ -724,6 +726,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
* @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
@ -734,21 +737,22 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
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;
@ -775,11 +779,12 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
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_orig_node *orig_node;
struct ethhdr *ethhdr;
struct batadv_hard_iface *primary_if;
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;
unsigned short vid;
int is_old_ttvn;
/* check if there is enough data before accessing it */
@ -791,6 +796,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
@ -798,9 +804,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",
@ -846,7 +852,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,
@ -858,7 +864,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

View File

@ -234,44 +234,45 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
}
/**
* batadv_send_generic_unicast_skb - send an skb as unicast
* batadv_send_skb_unicast - encapsulate and send an skb via unicast
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
* @packet_type: the batman unicast packet type to use
* @packet_subtype: the unicast 4addr packet subtype (only relevant for unicast
* 4addr packets)
* @orig_node: the originator to send the packet to
* @vid: the vid to be used to search the translation table
*
* Returns 1 in case of error or 0 otherwise.
* Wrap the given skb into a batman-adv unicast or unicast-4addr header
* depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied
* as packet_type. Then send this frame to the given orig_node and release a
* reference to this orig_node.
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
int batadv_send_skb_generic_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype)
static int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype,
struct batadv_orig_node *orig_node,
unsigned short vid)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_unicast_packet *unicast_packet;
struct batadv_orig_node *orig_node;
int ret = NET_RX_DROP;
/* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest))
orig_node = batadv_gw_get_selected_orig(bat_priv);
else
/* check for tt host - increases orig_node refcount.
* returns NULL in case of AP isolation
*/
orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest);
int ret = NET_XMIT_DROP;
if (!orig_node)
goto out;
switch (packet_type) {
case BATADV_UNICAST:
batadv_send_skb_prepare_unicast(skb, orig_node);
if (!batadv_send_skb_prepare_unicast(skb, orig_node))
goto out;
break;
case BATADV_UNICAST_4ADDR:
batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, orig_node,
packet_subtype);
if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb,
orig_node,
packet_subtype))
goto out;
break;
default:
/* this function supports UNICAST and UNICAST_4ADDR only. It
@ -287,20 +288,71 @@ 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)
ret = 0;
ret = NET_XMIT_SUCCESS;
out:
if (orig_node)
batadv_orig_node_free_ref(orig_node);
if (ret == NET_RX_DROP)
if (ret == NET_XMIT_DROP)
kfree_skb(skb);
return ret;
}
/**
* batadv_send_skb_via_tt_generic - send an skb via TT lookup
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
* @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
*
* Look up the recipient node for the destination address in the ethernet
* header via the translation table. Wrap the given skb into a batman-adv
* unicast or unicast-4addr header depending on whether BATADV_UNICAST or
* BATADV_UNICAST_4ADDR was supplied as packet_type. Then send this frame
* to the according destination node.
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype, unsigned short vid)
{
struct ethhdr *ethhdr = (struct ethhdr *)skb->data;
struct batadv_orig_node *orig_node;
orig_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest, vid);
return batadv_send_skb_unicast(bat_priv, skb, packet_type,
packet_subtype, orig_node, vid);
}
/**
* batadv_send_skb_via_gw - send an skb via gateway lookup
* @bat_priv: the bat priv with all the soft interface information
* @skb: payload to send
* @vid: the vid to be used to search the translation table
*
* Look up the currently selected gateway. Wrap the given skb into a batman-adv
* unicast header and send this frame to this gateway node.
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid)
{
struct batadv_orig_node *orig_node;
orig_node = batadv_gw_get_selected_orig(bat_priv);
return batadv_send_skb_unicast(bat_priv, skb, BATADV_UNICAST, 0,
orig_node, vid);
}
void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);

View File

@ -38,41 +38,54 @@ bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
struct batadv_orig_node *orig_node,
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 batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,
struct sk_buff *skb, int packet_type,
int packet_subtype, unsigned short vid);
int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid);
/**
* batadv_send_unicast_skb - send the skb encapsulated in a unicast packet
* batadv_send_skb_via_tt - send an skb via TT lookup
* @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.
* Look up the recipient node for the destination address in the ethernet
* header via the translation table. Wrap the given skb into a batman-adv
* unicast header. Then send this frame to the according destination node.
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
static inline int batadv_send_skb_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb)
static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,
struct sk_buff *skb,
unsigned short vid)
{
return batadv_send_skb_generic_unicast(bat_priv, skb, BATADV_UNICAST,
0);
return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0,
vid);
}
/**
* batadv_send_4addr_unicast_skb - send the skb encapsulated in a unicast 4addr
* packet
* batadv_send_skb_via_tt_4addr - send an skb via TT lookup
* @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.
* Look up the recipient node for the destination address in the ethernet
* header via the translation table. Wrap the given skb into a batman-adv
* unicast-4addr header. Then send this frame to the according destination
* node.
*
* Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise.
*/
static inline int batadv_send_skb_unicast_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype)
static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv,
struct sk_buff *skb,
int packet_subtype,
unsigned short vid)
{
return batadv_send_skb_generic_unicast(bat_priv, skb,
BATADV_UNICAST_4ADDR,
packet_subtype);
return batadv_send_skb_via_tt_generic(bat_priv, skb,
BATADV_UNICAST_4ADDR,
packet_subtype, vid);
}
#endif /* _NET_BATMAN_ADV_SEND_H_ */

View File

@ -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_NO_FLAGS,
BATADV_NULL_IFINDEX);
}
return 0;
@ -152,33 +153,33 @@ static void batadv_interface_set_rx_mode(struct net_device *dev)
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;
bool do_bcast = false;
uint32_t seqno;
unsigned long brd_delay = 1;
bool do_bcast = false;
unsigned short vid;
uint32_t seqno;
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;
vid |= BATADV_VLAN_HAS_TAG;
if (vhdr->h_vlan_encapsulated_proto != ethertype)
break;
@ -196,7 +197,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 ...
@ -296,8 +298,12 @@ 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);
if (ret != 0)
if (is_multicast_ether_addr(ethhdr->h_dest))
ret = batadv_send_skb_via_gw(bat_priv, skb, vid);
else
ret = batadv_send_skb_via_tt(bat_priv, skb, vid);
if (ret == NET_XMIT_DROP)
goto dropped_freed;
}
@ -319,12 +325,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);
@ -336,13 +342,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;
vid |= BATADV_VLAN_HAS_TAG;
if (vhdr->h_vlan_encapsulated_proto != ethertype)
break;
@ -378,9 +383,10 @@ 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))
if (batadv_is_ap_isolated(bat_priv, ethhdr->h_source, ethhdr->h_dest,
vid))
goto dropped;
netif_rx(skb);
@ -392,6 +398,177 @@ void batadv_interface_rx(struct net_device *soft_iface,
return;
}
/**
* batadv_softif_vlan_free_ref - decrease the vlan object 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 the vlan object for a specific vid
* @bat_priv: the bat priv with all the soft interface information
* @vid: the identifier of the vlan object to retrieve
*
* Returns the private data of the vlan matching the vid passed as argument or
* NULL otherwise. The refcounter of the returned object is incremented by 1.
*/
struct batadv_softif_vlan *batadv_softif_vlan_get(struct batadv_priv *bat_priv,
unsigned short vid)
{
struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
rcu_read_lock();
hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
if (vlan_tmp->vid != vid)
continue;
if (!atomic_inc_not_zero(&vlan_tmp->refcount))
continue;
vlan = vlan_tmp;
break;
}
rcu_read_unlock();
return vlan;
}
/**
* 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
*
* Returns 0 on success, a negative error otherwise.
*/
int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
{
struct batadv_softif_vlan *vlan;
int err;
vlan = batadv_softif_vlan_get(bat_priv, vid);
if (vlan) {
batadv_softif_vlan_free_ref(vlan);
return -EEXIST;
}
vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC);
if (!vlan)
return -ENOMEM;
vlan->vid = vid;
atomic_set(&vlan->refcount, 1);
atomic_set(&vlan->ap_isolation, 0);
err = batadv_sysfs_add_vlan(bat_priv->soft_iface, vlan);
if (err) {
kfree(vlan);
return err;
}
/* add a new TT local entry. This one will be marked with the NOPURGE
* flag
*/
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);
hlist_add_head_rcu(&vlan->list, &bat_priv->softif_vlan_list);
spin_unlock_bh(&bat_priv->softif_vlan_list_lock);
return 0;
}
/**
* batadv_softif_destroy_vlan - remove and destroy a softif_vlan object
* @bat_priv: the bat priv with all the soft interface information
* @vlan: the object to remove
*/
static void batadv_softif_destroy_vlan(struct batadv_priv *bat_priv,
struct batadv_softif_vlan *vlan)
{
spin_lock_bh(&bat_priv->softif_vlan_list_lock);
hlist_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
*/
batadv_tt_local_remove(bat_priv, bat_priv->soft_iface->dev_addr,
vlan->vid, "vlan interface destroyed", false);
batadv_softif_vlan_free_ref(vlan);
}
/**
* 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
*
* Returns 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);
/* 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
*
* Destroy all the internal structures used to handle the vlan identified by vid
* on top of the mesh interface
*
* Returns 0 on success, -EINVAL if the specified prototype is not ETH_P_8021Q
* or -ENOENT if the specified vlan id wasn't registered.
*/
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 -ENOENT;
batadv_softif_destroy_vlan(bat_priv, 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.
@ -431,6 +608,7 @@ static void batadv_set_lockdep_class(struct net_device *dev)
*/
static void batadv_softif_destroy_finish(struct work_struct *work)
{
struct batadv_softif_vlan *vlan;
struct batadv_priv *bat_priv;
struct net_device *soft_iface;
@ -438,6 +616,13 @@ static void batadv_softif_destroy_finish(struct work_struct *work)
cleanup_work);
soft_iface = bat_priv->soft_iface;
/* destroy the "untagged" VLAN */
vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
if (vlan) {
batadv_softif_destroy_vlan(bat_priv, vlan);
batadv_softif_vlan_free_ref(vlan);
}
batadv_sysfs_del_meshif(soft_iface);
rtnl_lock();
@ -479,7 +664,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);
@ -593,6 +777,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_set_rx_mode = batadv_interface_set_rx_mode,
@ -632,6 +818,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

View File

@ -28,5 +28,9 @@ struct net_device *batadv_softif_create(const char *name);
void batadv_softif_destroy_sysfs(struct net_device *soft_iface);
int batadv_softif_is_valid(const struct net_device *net_dev);
extern struct rtnl_link_ops batadv_link_ops;
int batadv_softif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid);
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);
#endif /* _NET_BATMAN_ADV_SOFT_INTERFACE_H_ */

View File

@ -24,6 +24,7 @@
#include "network-coding.h"
#include "originator.h"
#include "hard-interface.h"
#include "soft-interface.h"
#include "gateway_common.h"
#include "gateway_client.h"
@ -39,6 +40,53 @@ static struct batadv_priv *batadv_kobj_to_batpriv(struct kobject *obj)
return netdev_priv(net_dev);
}
/**
* batadv_vlan_kobj_to_batpriv - convert a vlan kobj in the associated batpriv
* @obj: kobject to covert
*
* Returns the associated batadv_priv struct.
*/
static struct batadv_priv *batadv_vlan_kobj_to_batpriv(struct kobject *obj)
{
/* VLAN specific attributes are located in the root sysfs folder if they
* refer to the untagged VLAN..
*/
if (!strcmp(BATADV_SYSFS_IF_MESH_SUBDIR, obj->name))
return batadv_kobj_to_batpriv(obj);
/* ..while the attributes for the tagged vlans are located in
* the in the corresponding "vlan%VID" subfolder
*/
return batadv_kobj_to_batpriv(obj->parent);
}
/**
* batadv_kobj_to_vlan - convert a kobj in the associated softif_vlan struct
* @obj: kobject to covert
*
* Returns the associated softif_vlan struct if found, NULL otherwise.
*/
static struct batadv_softif_vlan *
batadv_kobj_to_vlan(struct batadv_priv *bat_priv, struct kobject *obj)
{
struct batadv_softif_vlan *vlan_tmp, *vlan = NULL;
rcu_read_lock();
hlist_for_each_entry_rcu(vlan_tmp, &bat_priv->softif_vlan_list, list) {
if (vlan_tmp->kobj != obj)
continue;
if (!atomic_inc_not_zero(&vlan_tmp->refcount))
continue;
vlan = vlan_tmp;
break;
}
rcu_read_unlock();
return vlan;
}
#define BATADV_UEV_TYPE_VAR "BATTYPE="
#define BATADV_UEV_ACTION_VAR "BATACTION="
#define BATADV_UEV_DATA_VAR "BATDATA="
@ -53,6 +101,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 +179,41 @@ 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_vlan_kobj_to_batpriv(kobj);\
struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
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_priv *bat_priv = batadv_vlan_kobj_to_batpriv(kobj);\
struct batadv_softif_vlan *vlan = batadv_kobj_to_vlan(bat_priv, \
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,
@ -361,7 +453,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);
@ -391,7 +482,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,
@ -407,6 +497,16 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
NULL,
};
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,
};
int batadv_sysfs_add_meshif(struct net_device *dev)
{
struct kobject *batif_kobject = &dev->dev.kobj;
@ -457,6 +557,80 @@ 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
*
* Returns 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)
{
char vlan_subdir[sizeof(BATADV_SYSFS_VLAN_SUBDIR_PREFIX) + 5];
struct batadv_priv *bat_priv = netdev_priv(dev);
struct batadv_attribute **bat_attr;
int err;
if (vlan->vid & BATADV_VLAN_HAS_TAG) {
sprintf(vlan_subdir, BATADV_SYSFS_VLAN_SUBDIR_PREFIX "%hu",
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;
}
} else {
/* the untagged LAN uses the root folder to store its "VLAN
* specific attributes"
*/
vlan->kobj = bat_priv->mesh_obj;
kobject_get(bat_priv->mesh_obj);
}
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)
{

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -22,29 +22,32 @@
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,
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);
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);
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);
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_ */

View File

@ -106,6 +106,32 @@ struct batadv_frag_list_entry {
uint8_t no;
};
/**
* 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
@ -120,14 +146,16 @@ 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
* @tt_lock: prevents from updating the table while reading it. Table update is
* made up by two operations (data structure update and metdata -CRC/TTVN-
* recalculation) and they have to be executed atomically in order to avoid
* another thread to read the table/metadata between those.
* @last_real_seqno: last and best known sequence number
* @last_ttl: ttl of last received packet
* @bcast_bits: bitfield containing the info which payload broadcast originated
@ -150,6 +178,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,12 +196,12 @@ 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;
/* prevents from changing the table while reading it */
spinlock_t tt_lock;
uint32_t last_real_seqno;
uint8_t last_ttl;
DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE);
@ -197,6 +228,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 */
};
/**
@ -383,11 +416,14 @@ enum batadv_counters {
* @changes_list_lock: lock protecting changes_list
* @req_list_lock: lock protecting req_list
* @roam_list_lock: lock protecting roam_list
* @local_entry_num: number of entries in the local hash table
* @local_crc: Checksum of the local table, recomputed before sending a new OGM
* @last_changeset: last tt changeset this host has generated
* @last_changeset_len: length of last tt changeset this host has generated
* @last_changeset_lock: lock protecting last_changeset & last_changeset_len
* @commit_lock: prevents from executing a local TT commit while reading the
* local table. The local TT commit is made up by two operations (data
* structure update and metdata -CRC/TTVN- recalculation) and they have to be
* executed atomically in order to avoid another thread to read the
* table/metadata between those.
* @work: work queue callback item for translation table purging
*/
struct batadv_priv_tt {
@ -402,12 +438,12 @@ 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 */
spinlock_t last_changeset_lock;
/* prevents from executing a commit while reading the table */
spinlock_t commit_lock;
struct delayed_work work;
};
@ -530,6 +566,26 @@ 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
* @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
*/
struct batadv_softif_vlan {
unsigned short vid;
struct kobject *kobj;
atomic_t ap_isolation; /* boolean */
struct batadv_vlan_tt tt;
struct hlist_node 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)
@ -540,7 +596,6 @@ struct batadv_priv_nc {
* @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
@ -566,6 +621,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
@ -584,7 +642,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
@ -613,6 +670,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 hlist_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
@ -715,6 +774,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 +784,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;
@ -931,6 +992,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
@ -939,6 +1001,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;