Commit 65dc5416 authored by David S. Miller's avatar David S. Miller

Merge tag 'batadv-next-for-davem-20190627v2' of git://git.open-mesh.org/linux-merge

Simon Wunderlich says:

====================
This feature/cleanup patchset includes the following patches:

 - bump version strings, by Simon Wunderlich

 - fix includes for _MAX constants, atomic functions and fwdecls,
   by Sven Eckelmann (3 patches)

 - shorten multicast tt/tvlv worker spinlock section, by Linus Luessing

 - routeable multicast preparations: implement MAC multicast filtering,
   by Linus Luessing (2 patches, David Millers comments integrated)

 - remove return value checks for debugfs_create, by Greg Kroah-Hartman

 - add routable multicast optimizations, by Linus Luessing (2 patches)
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents fcd71efd 11d458c1
...@@ -107,12 +107,20 @@ enum batadv_icmp_packettype { ...@@ -107,12 +107,20 @@ enum batadv_icmp_packettype {
* @BATADV_MCAST_WANT_ALL_UNSNOOPABLES: we want all packets destined for * @BATADV_MCAST_WANT_ALL_UNSNOOPABLES: we want all packets destined for
* 224.0.0.0/24 or ff02::1 * 224.0.0.0/24 or ff02::1
* @BATADV_MCAST_WANT_ALL_IPV4: we want all IPv4 multicast packets * @BATADV_MCAST_WANT_ALL_IPV4: we want all IPv4 multicast packets
* (both link-local and routable ones)
* @BATADV_MCAST_WANT_ALL_IPV6: we want all IPv6 multicast packets * @BATADV_MCAST_WANT_ALL_IPV6: we want all IPv6 multicast packets
* (both link-local and routable ones)
* @BATADV_MCAST_WANT_NO_RTR4: we have no IPv4 multicast router and therefore
* only need routable IPv4 multicast packets we signed up for explicitly
* @BATADV_MCAST_WANT_NO_RTR6: we have no IPv6 multicast router and therefore
* only need routable IPv6 multicast packets we signed up for explicitly
*/ */
enum batadv_mcast_flags { enum batadv_mcast_flags {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES = 1UL << 0, BATADV_MCAST_WANT_ALL_UNSNOOPABLES = 1UL << 0,
BATADV_MCAST_WANT_ALL_IPV4 = 1UL << 1, BATADV_MCAST_WANT_ALL_IPV4 = 1UL << 1,
BATADV_MCAST_WANT_ALL_IPV6 = 1UL << 2, BATADV_MCAST_WANT_ALL_IPV6 = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4 = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6 = 1UL << 4,
}; };
/* tt data subtypes */ /* tt data subtypes */
......
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
#include "main.h" #include "main.h"
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct netlink_callback;
struct seq_file;
struct sk_buff;
extern char batadv_routing_algo[]; extern char batadv_routing_algo[];
extern struct list_head batadv_hardif_list; extern struct list_head batadv_hardif_list;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -41,8 +42,6 @@ ...@@ -41,8 +42,6 @@
#include "netlink.h" #include "netlink.h"
#include "originator.h" #include "originator.h"
struct sk_buff;
static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface) static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
{ {
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include "main.h" #include "main.h"
struct sk_buff; #include <linux/skbuff.h>
struct work_struct; #include <linux/workqueue.h>
int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface); int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface); void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
#include "main.h" #include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct sk_buff;
int batadv_v_ogm_init(struct batadv_priv *bat_priv); int batadv_v_ogm_init(struct batadv_priv *bat_priv);
void batadv_v_ogm_free(struct batadv_priv *bat_priv); void batadv_v_ogm_free(struct batadv_priv *bat_priv);
int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface); int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface);
......
...@@ -10,14 +10,13 @@ ...@@ -10,14 +10,13 @@
#include "main.h" #include "main.h"
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
struct net_device;
struct netlink_callback;
struct seq_file;
struct sk_buff;
/** /**
* batadv_bla_is_loopdetect_mac() - check if the mac address is from a loop * batadv_bla_is_loopdetect_mac() - check if the mac address is from a loop
* detect frame sent by bridge loop avoidance * detect frame sent by bridge loop avoidance
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <asm/current.h> #include <asm/current.h>
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -293,31 +292,13 @@ static struct batadv_debuginfo *batadv_hardif_debuginfos[] = { ...@@ -293,31 +292,13 @@ static struct batadv_debuginfo *batadv_hardif_debuginfos[] = {
void batadv_debugfs_init(void) void batadv_debugfs_init(void)
{ {
struct batadv_debuginfo **bat_debug; struct batadv_debuginfo **bat_debug;
struct dentry *file;
batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL); batadv_debugfs = debugfs_create_dir(BATADV_DEBUGFS_SUBDIR, NULL);
if (batadv_debugfs == ERR_PTR(-ENODEV))
batadv_debugfs = NULL;
if (!batadv_debugfs)
goto err;
for (bat_debug = batadv_general_debuginfos; *bat_debug; ++bat_debug) {
file = debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
batadv_debugfs, NULL,
&(*bat_debug)->fops);
if (!file) {
pr_err("Can't add general debugfs file: %s\n",
((*bat_debug)->attr).name);
goto err;
}
}
return; for (bat_debug = batadv_general_debuginfos; *bat_debug; ++bat_debug)
err: debugfs_create_file(((*bat_debug)->attr).name,
debugfs_remove_recursive(batadv_debugfs); S_IFREG | ((*bat_debug)->attr).mode,
batadv_debugfs = NULL; batadv_debugfs, NULL, &(*bat_debug)->fops);
} }
/** /**
...@@ -333,42 +314,23 @@ void batadv_debugfs_destroy(void) ...@@ -333,42 +314,23 @@ void batadv_debugfs_destroy(void)
* batadv_debugfs_add_hardif() - creates the base directory for a hard interface * batadv_debugfs_add_hardif() - creates the base directory for a hard interface
* in debugfs. * in debugfs.
* @hard_iface: hard interface which should be added. * @hard_iface: hard interface which should be added.
*
* Return: 0 on success or negative error number in case of failure
*/ */
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) void batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
{ {
struct net *net = dev_net(hard_iface->net_dev); struct net *net = dev_net(hard_iface->net_dev);
struct batadv_debuginfo **bat_debug; struct batadv_debuginfo **bat_debug;
struct dentry *file;
if (!batadv_debugfs)
goto out;
if (net != &init_net) if (net != &init_net)
return 0; return;
hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name, hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
batadv_debugfs); batadv_debugfs);
if (!hard_iface->debug_dir)
goto out;
for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug) {
file = debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
hard_iface->debug_dir,
hard_iface->net_dev,
&(*bat_debug)->fops);
if (!file)
goto rem_attr;
}
return 0; for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug)
rem_attr: debugfs_create_file(((*bat_debug)->attr).name,
debugfs_remove_recursive(hard_iface->debug_dir); S_IFREG | ((*bat_debug)->attr).mode,
hard_iface->debug_dir = NULL; hard_iface->debug_dir, hard_iface->net_dev,
out: &(*bat_debug)->fops);
return -ENOMEM;
} }
/** /**
...@@ -379,15 +341,12 @@ void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface) ...@@ -379,15 +341,12 @@ void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface)
{ {
const char *name = hard_iface->net_dev->name; const char *name = hard_iface->net_dev->name;
struct dentry *dir; struct dentry *dir;
struct dentry *d;
dir = hard_iface->debug_dir; dir = hard_iface->debug_dir;
if (!dir) if (!dir)
return; return;
d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name); debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
if (!d)
pr_err("Can't rename debugfs dir to %s\n", name);
} }
/** /**
...@@ -419,44 +378,29 @@ int batadv_debugfs_add_meshif(struct net_device *dev) ...@@ -419,44 +378,29 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
struct batadv_priv *bat_priv = netdev_priv(dev); struct batadv_priv *bat_priv = netdev_priv(dev);
struct batadv_debuginfo **bat_debug; struct batadv_debuginfo **bat_debug;
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
struct dentry *file;
if (!batadv_debugfs)
goto out;
if (net != &init_net) if (net != &init_net)
return 0; return 0;
bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs); bat_priv->debug_dir = debugfs_create_dir(dev->name, batadv_debugfs);
if (!bat_priv->debug_dir)
goto out;
if (batadv_socket_setup(bat_priv) < 0) batadv_socket_setup(bat_priv);
goto rem_attr;
if (batadv_debug_log_setup(bat_priv) < 0) if (batadv_debug_log_setup(bat_priv) < 0)
goto rem_attr; goto rem_attr;
for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug) { for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug)
file = debugfs_create_file(((*bat_debug)->attr).name, debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode, S_IFREG | ((*bat_debug)->attr).mode,
bat_priv->debug_dir, bat_priv->debug_dir, dev,
dev, &(*bat_debug)->fops); &(*bat_debug)->fops);
if (!file) {
batadv_err(dev, "Can't add debugfs file: %s/%s\n",
dev->name, ((*bat_debug)->attr).name);
goto rem_attr;
}
}
if (batadv_nc_init_debugfs(bat_priv) < 0) batadv_nc_init_debugfs(bat_priv);
goto rem_attr;
return 0; return 0;
rem_attr: rem_attr:
debugfs_remove_recursive(bat_priv->debug_dir); debugfs_remove_recursive(bat_priv->debug_dir);
bat_priv->debug_dir = NULL; bat_priv->debug_dir = NULL;
out:
return -ENOMEM; return -ENOMEM;
} }
...@@ -469,15 +413,12 @@ void batadv_debugfs_rename_meshif(struct net_device *dev) ...@@ -469,15 +413,12 @@ void batadv_debugfs_rename_meshif(struct net_device *dev)
struct batadv_priv *bat_priv = netdev_priv(dev); struct batadv_priv *bat_priv = netdev_priv(dev);
const char *name = dev->name; const char *name = dev->name;
struct dentry *dir; struct dentry *dir;
struct dentry *d;
dir = bat_priv->debug_dir; dir = bat_priv->debug_dir;
if (!dir) if (!dir)
return; return;
d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name); debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
if (!d)
pr_err("Can't rename debugfs dir to %s\n", name);
} }
/** /**
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include "main.h" #include "main.h"
struct file; #include <linux/fs.h>
struct net_device; #include <linux/netdevice.h>
#define BATADV_DEBUGFS_SUBDIR "batman_adv" #define BATADV_DEBUGFS_SUBDIR "batman_adv"
...@@ -22,7 +22,7 @@ void batadv_debugfs_destroy(void); ...@@ -22,7 +22,7 @@ void batadv_debugfs_destroy(void);
int batadv_debugfs_add_meshif(struct net_device *dev); int batadv_debugfs_add_meshif(struct net_device *dev);
void batadv_debugfs_rename_meshif(struct net_device *dev); void batadv_debugfs_rename_meshif(struct net_device *dev);
void batadv_debugfs_del_meshif(struct net_device *dev); void batadv_debugfs_del_meshif(struct net_device *dev);
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface); void batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface);
void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface); void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface);
void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface); void batadv_debugfs_del_hardif(struct batadv_hard_iface *hard_iface);
...@@ -54,9 +54,8 @@ static inline void batadv_debugfs_del_meshif(struct net_device *dev) ...@@ -54,9 +54,8 @@ static inline void batadv_debugfs_del_meshif(struct net_device *dev)
} }
static inline static inline
int batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface) void batadv_debugfs_add_hardif(struct batadv_hard_iface *hard_iface)
{ {
return 0;
} }
static inline static inline
......
...@@ -11,15 +11,14 @@ ...@@ -11,15 +11,14 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h> #include <uapi/linux/batadv_packet.h>
#include "originator.h" #include "originator.h"
struct netlink_callback;
struct seq_file;
struct sk_buff;
#ifdef CONFIG_BATMAN_ADV_DAT #ifdef CONFIG_BATMAN_ADV_DAT
/* BATADV_DAT_ADDR_MAX - maximum address value in the DHT space */ /* BATADV_DAT_ADDR_MAX - maximum address value in the DHT space */
......
...@@ -11,11 +11,10 @@ ...@@ -11,11 +11,10 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
struct sk_buff;
void batadv_frag_purge_orig(struct batadv_orig_node *orig, void batadv_frag_purge_orig(struct batadv_orig_node *orig,
bool (*check_cb)(struct batadv_frag_table_entry *)); bool (*check_cb)(struct batadv_frag_table_entry *));
bool batadv_frag_skb_fwd(struct sk_buff *skb, bool batadv_frag_skb_fwd(struct sk_buff *skb,
......
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
#include "main.h" #include "main.h"
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
struct batadv_tvlv_gateway_data;
struct netlink_callback;
struct seq_file;
struct sk_buff;
void batadv_gw_check_client_stop(struct batadv_priv *bat_priv); void batadv_gw_check_client_stop(struct batadv_priv *bat_priv);
void batadv_gw_reselect(struct batadv_priv *bat_priv); void batadv_gw_reselect(struct batadv_priv *bat_priv);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/math64.h> #include <linux/math64.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/stddef.h> #include <linux/stddef.h>
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
#include "main.h" #include "main.h"
#include <linux/netdevice.h>
#include <linux/types.h> #include <linux/types.h>
struct net_device;
/** /**
* enum batadv_bandwidth_units - bandwidth unit types * enum batadv_bandwidth_units - bandwidth unit types
*/ */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/limits.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/printk.h> #include <linux/printk.h>
...@@ -920,9 +921,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) ...@@ -920,9 +921,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
hard_iface->soft_iface = NULL; hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE; hard_iface->if_status = BATADV_IF_NOT_IN_USE;
ret = batadv_debugfs_add_hardif(hard_iface); batadv_debugfs_add_hardif(hard_iface);
if (ret)
goto free_sysfs;
INIT_LIST_HEAD(&hard_iface->list); INIT_LIST_HEAD(&hard_iface->list);
INIT_HLIST_HEAD(&hard_iface->neigh_list); INIT_HLIST_HEAD(&hard_iface->neigh_list);
...@@ -944,8 +943,6 @@ batadv_hardif_add_interface(struct net_device *net_dev) ...@@ -944,8 +943,6 @@ batadv_hardif_add_interface(struct net_device *net_dev)
return hard_iface; return hard_iface;
free_sysfs:
batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
free_if: free_if:
kfree(hard_iface); kfree(hard_iface);
release_dev: release_dev:
......
...@@ -11,13 +11,12 @@ ...@@ -11,13 +11,12 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/net_namespace.h>
struct net_device;
struct net;
/** /**
* enum batadv_hard_if_state - State of a hard interface * enum batadv_hard_if_state - State of a hard interface
......
...@@ -12,13 +12,12 @@ ...@@ -12,13 +12,12 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/rculist.h> #include <linux/rculist.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
struct lock_class_key;
/* callback to a compare function. should compare 2 element datas for their /* callback to a compare function. should compare 2 element datas for their
* keys * keys
* *
......
...@@ -314,25 +314,11 @@ static const struct file_operations batadv_fops = { ...@@ -314,25 +314,11 @@ static const struct file_operations batadv_fops = {
/** /**
* batadv_socket_setup() - Create debugfs "socket" file * batadv_socket_setup() - Create debugfs "socket" file
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
*
* Return: 0 on success or negative error number in case of failure
*/ */
int batadv_socket_setup(struct batadv_priv *bat_priv) void batadv_socket_setup(struct batadv_priv *bat_priv)
{ {
struct dentry *d; debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir,
bat_priv, &batadv_fops);
if (!bat_priv->debug_dir)
goto err;
d = debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir,
bat_priv, &batadv_fops);
if (!d)
goto err;
return 0;
err:
return -ENOMEM;
} }
/** /**
......
...@@ -10,12 +10,11 @@ ...@@ -10,12 +10,11 @@
#include "main.h" #include "main.h"
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
struct batadv_icmp_header;
#define BATADV_ICMP_SOCKET "socket" #define BATADV_ICMP_SOCKET "socket"
int batadv_socket_setup(struct batadv_priv *bat_priv); void batadv_socket_setup(struct batadv_priv *bat_priv);
#ifdef CONFIG_BATMAN_ADV_DEBUGFS #ifdef CONFIG_BATMAN_ADV_DEBUGFS
......
...@@ -190,27 +190,16 @@ static const struct file_operations batadv_log_fops = { ...@@ -190,27 +190,16 @@ static const struct file_operations batadv_log_fops = {
*/ */
int batadv_debug_log_setup(struct batadv_priv *bat_priv) int batadv_debug_log_setup(struct batadv_priv *bat_priv)
{ {
struct dentry *d;
if (!bat_priv->debug_dir)
goto err;
bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC); bat_priv->debug_log = kzalloc(sizeof(*bat_priv->debug_log), GFP_ATOMIC);
if (!bat_priv->debug_log) if (!bat_priv->debug_log)
goto err; return -ENOMEM;
spin_lock_init(&bat_priv->debug_log->lock); spin_lock_init(&bat_priv->debug_log->lock);
init_waitqueue_head(&bat_priv->debug_log->queue_wait); init_waitqueue_head(&bat_priv->debug_log->queue_wait);
d = debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv, debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
&batadv_log_fops); &batadv_log_fops);
if (!d)
goto err;
return 0; return 0;
err:
return -ENOMEM;
} }
/** /**
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "main.h" #include "main.h"
#include <linux/atomic.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/printk.h> #include <linux/printk.h>
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv" #define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION #ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2019.2" #define BATADV_SOURCE_VERSION "2019.3"
#endif #endif
/* B.A.T.M.A.N. parameters */ /* B.A.T.M.A.N. parameters */
...@@ -205,20 +205,20 @@ enum batadv_uev_type { ...@@ -205,20 +205,20 @@ enum batadv_uev_type {
/* Kernel headers */ /* Kernel headers */
#include <linux/atomic.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h> #include <uapi/linux/batadv_packet.h>
#include "types.h" #include "types.h"
#include "main.h"
struct net_device;
struct packet_type;
struct seq_file;
struct sk_buff;
/** /**
* batadv_print_vid() - return printable version of vid information * batadv_print_vid() - return printable version of vid information
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/igmp.h> #include <linux/igmp.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/inetdevice.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
...@@ -98,69 +99,307 @@ static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface) ...@@ -98,69 +99,307 @@ static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface)
} }
/** /**
* batadv_mcast_addr_is_ipv4() - check if multicast MAC is IPv4 * batadv_mcast_mla_rtr_flags_softif_get_ipv4() - get mcast router flags from
* @addr: the MAC address to check * node for IPv4
* @dev: the interface to check
* *
* Return: True, if MAC address is one reserved for IPv4 multicast, false * Checks the presence of an IPv4 multicast router on this node.
* otherwise. *
* Caller needs to hold rcu read lock.
*
* Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR4 otherwise.
*/ */
static bool batadv_mcast_addr_is_ipv4(const u8 *addr) static u8 batadv_mcast_mla_rtr_flags_softif_get_ipv4(struct net_device *dev)
{ {
static const u8 prefix[] = {0x01, 0x00, 0x5E}; struct in_device *in_dev = __in_dev_get_rcu(dev);
return memcmp(prefix, addr, sizeof(prefix)) == 0; if (in_dev && IN_DEV_MFORWARD(in_dev))
return BATADV_NO_FLAGS;
else
return BATADV_MCAST_WANT_NO_RTR4;
} }
/** /**
* batadv_mcast_addr_is_ipv6() - check if multicast MAC is IPv6 * batadv_mcast_mla_rtr_flags_softif_get_ipv6() - get mcast router flags from
* @addr: the MAC address to check * node for IPv6
* @dev: the interface to check
* *
* Return: True, if MAC address is one reserved for IPv6 multicast, false * Checks the presence of an IPv6 multicast router on this node.
* otherwise. *
* Caller needs to hold rcu read lock.
*
* Return: BATADV_NO_FLAGS if present, BATADV_MCAST_WANT_NO_RTR6 otherwise.
*/ */
static bool batadv_mcast_addr_is_ipv6(const u8 *addr) #if IS_ENABLED(CONFIG_IPV6_MROUTE)
static u8 batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
{ {
static const u8 prefix[] = {0x33, 0x33}; struct inet6_dev *in6_dev = __in6_dev_get(dev);
return memcmp(prefix, addr, sizeof(prefix)) == 0; if (in6_dev && in6_dev->cnf.mc_forwarding)
return BATADV_NO_FLAGS;
else
return BATADV_MCAST_WANT_NO_RTR6;
} }
#else
static inline u8
batadv_mcast_mla_rtr_flags_softif_get_ipv6(struct net_device *dev)
{
return BATADV_MCAST_WANT_NO_RTR6;
}
#endif
/** /**
* batadv_mcast_mla_softif_get() - get softif multicast listeners * batadv_mcast_mla_rtr_flags_softif_get() - get mcast router flags from node
* @bat_priv: the bat priv with all the soft interface information
* @bridge: bridge interface on top of the soft_iface if present,
* otherwise pass NULL
*
* Checks the presence of IPv4 and IPv6 multicast routers on this
* node.
*
* Return:
* BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
* BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
* BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
* The former two OR'd: no multicast router is present
*/
static u8 batadv_mcast_mla_rtr_flags_softif_get(struct batadv_priv *bat_priv,
struct net_device *bridge)
{
struct net_device *dev = bridge ? bridge : bat_priv->soft_iface;
u8 flags = BATADV_NO_FLAGS;
rcu_read_lock();
flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv4(dev);
flags |= batadv_mcast_mla_rtr_flags_softif_get_ipv6(dev);
rcu_read_unlock();
return flags;
}
/**
* batadv_mcast_mla_rtr_flags_bridge_get() - get mcast router flags from bridge
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @bridge: bridge interface on top of the soft_iface if present,
* otherwise pass NULL
*
* Checks the presence of IPv4 and IPv6 multicast routers behind a bridge.
*
* Return:
* BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
* BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
* BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
* The former two OR'd: no multicast router is present
*/
#if IS_ENABLED(CONFIG_IPV6)
static u8 batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
struct net_device *bridge)
{
struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
struct net_device *dev = bat_priv->soft_iface;
struct br_ip_list *br_ip_entry, *tmp;
u8 flags = BATADV_MCAST_WANT_NO_RTR6;
int ret;
if (!bridge)
return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
/* TODO: ask the bridge if a multicast router is present (the bridge
* is capable of performing proper RFC4286 multicast multicast router
* discovery) instead of searching for a ff02::2 listener here
*/
ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
if (ret < 0)
return BATADV_NO_FLAGS;
list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
/* the bridge snooping does not maintain IPv4 link-local
* addresses - therefore we won't find any IPv4 multicast router
* address here, only IPv6 ones
*/
if (br_ip_entry->addr.proto == htons(ETH_P_IPV6) &&
ipv6_addr_is_ll_all_routers(&br_ip_entry->addr.u.ip6))
flags &= ~BATADV_MCAST_WANT_NO_RTR6;
list_del(&br_ip_entry->list);
kfree(br_ip_entry);
}
return flags;
}
#else
static inline u8
batadv_mcast_mla_rtr_flags_bridge_get(struct batadv_priv *bat_priv,
struct net_device *bridge)
{
if (bridge)
return BATADV_NO_FLAGS;
else
return BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
}
#endif
/**
* batadv_mcast_mla_rtr_flags_get() - get multicast router flags
* @bat_priv: the bat priv with all the soft interface information
* @bridge: bridge interface on top of the soft_iface if present,
* otherwise pass NULL
*
* Checks the presence of IPv4 and IPv6 multicast routers on this
* node or behind its bridge.
*
* Return:
* BATADV_NO_FLAGS: Both an IPv4 and IPv6 multicast router is present
* BATADV_MCAST_WANT_NO_RTR4: No IPv4 multicast router is present
* BATADV_MCAST_WANT_NO_RTR6: No IPv6 multicast router is present
* The former two OR'd: no multicast router is present
*/
static u8 batadv_mcast_mla_rtr_flags_get(struct batadv_priv *bat_priv,
struct net_device *bridge)
{
u8 flags = BATADV_MCAST_WANT_NO_RTR4 | BATADV_MCAST_WANT_NO_RTR6;
flags &= batadv_mcast_mla_rtr_flags_softif_get(bat_priv, bridge);
flags &= batadv_mcast_mla_rtr_flags_bridge_get(bat_priv, bridge);
return flags;
}
/**
* batadv_mcast_mla_flags_get() - get the new multicast flags
* @bat_priv: the bat priv with all the soft interface information
*
* Return: A set of flags for the current/next TVLV, querier and
* bridge state.
*/
static struct batadv_mcast_mla_flags
batadv_mcast_mla_flags_get(struct batadv_priv *bat_priv)
{
struct net_device *dev = bat_priv->soft_iface;
struct batadv_mcast_querier_state *qr4, *qr6;
struct batadv_mcast_mla_flags mla_flags;
struct net_device *bridge;
bridge = batadv_mcast_get_bridge(dev);
memset(&mla_flags, 0, sizeof(mla_flags));
mla_flags.enabled = 1;
mla_flags.tvlv_flags |= batadv_mcast_mla_rtr_flags_get(bat_priv,
bridge);
if (!bridge)
return mla_flags;
dev_put(bridge);
mla_flags.bridged = 1;
qr4 = &mla_flags.querier_ipv4;
qr6 = &mla_flags.querier_ipv6;
if (!IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING))
pr_warn_once("No bridge IGMP snooping compiled - multicast optimizations disabled\n");
qr4->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IP);
qr4->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IP);
qr6->exists = br_multicast_has_querier_anywhere(dev, ETH_P_IPV6);
qr6->shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IPV6);
mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
/* 1) If no querier exists at all, then multicast listeners on
* our local TT clients behind the bridge will keep silent.
* 2) If the selected querier is on one of our local TT clients,
* behind the bridge, then this querier might shadow multicast
* listeners on our local TT clients, behind this bridge.
*
* In both cases, we will signalize other batman nodes that
* we need all multicast traffic of the according protocol.
*/
if (!qr4->exists || qr4->shadowing) {
mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV4;
mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR4;
}
if (!qr6->exists || qr6->shadowing) {
mla_flags.tvlv_flags |= BATADV_MCAST_WANT_ALL_IPV6;
mla_flags.tvlv_flags &= ~BATADV_MCAST_WANT_NO_RTR6;
}
return mla_flags;
}
/**
* batadv_mcast_mla_is_duplicate() - check whether an address is in a list
* @mcast_addr: the multicast address to check
* @mcast_list: the list with multicast addresses to search in
*
* Return: true if the given address is already in the given list.
* Otherwise returns false.
*/
static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
struct hlist_head *mcast_list)
{
struct batadv_hw_addr *mcast_entry;
hlist_for_each_entry(mcast_entry, mcast_list, list)
if (batadv_compare_eth(mcast_entry->addr, mcast_addr))
return true;
return false;
}
/**
* batadv_mcast_mla_softif_get_ipv4() - get softif IPv4 multicast listeners
* @dev: the device to collect multicast addresses from * @dev: the device to collect multicast addresses from
* @mcast_list: a list to put found addresses into * @mcast_list: a list to put found addresses into
* @flags: flags indicating the new multicast state
* *
* Collects multicast addresses of multicast listeners residing * Collects multicast addresses of IPv4 multicast listeners residing
* on this kernel on the given soft interface, dev, in * on this kernel on the given soft interface, dev, in
* the given mcast_list. In general, multicast listeners provided by * the given mcast_list. In general, multicast listeners provided by
* your multicast receiving applications run directly on this node. * your multicast receiving applications run directly on this node.
* *
* If there is a bridge interface on top of dev, collects from that one
* instead. Just like with IP addresses and routes, multicast listeners
* will(/should) register to the bridge interface instead of an
* enslaved bat0.
*
* Return: -ENOMEM on memory allocation error or the number of * Return: -ENOMEM on memory allocation error or the number of
* items added to the mcast_list otherwise. * items added to the mcast_list otherwise.
*/ */
static int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv, static int
struct net_device *dev, batadv_mcast_mla_softif_get_ipv4(struct net_device *dev,
struct hlist_head *mcast_list) struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{ {
bool all_ipv4 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV4;
bool all_ipv6 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV6;
struct net_device *bridge = batadv_mcast_get_bridge(dev);
struct netdev_hw_addr *mc_list_entry;
struct batadv_hw_addr *new; struct batadv_hw_addr *new;
struct in_device *in_dev;
u8 mcast_addr[ETH_ALEN];
struct ip_mc_list *pmc;
int ret = 0; int ret = 0;
netif_addr_lock_bh(bridge ? bridge : dev); if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
netdev_for_each_mc_addr(mc_list_entry, bridge ? bridge : dev) { return 0;
if (all_ipv4 && batadv_mcast_addr_is_ipv4(mc_list_entry->addr))
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
if (!in_dev) {
rcu_read_unlock();
return 0;
}
for (pmc = rcu_dereference(in_dev->mc_list); pmc;
pmc = rcu_dereference(pmc->next_rcu)) {
if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
ipv4_is_local_multicast(pmc->multiaddr))
continue; continue;
if (all_ipv6 && batadv_mcast_addr_is_ipv6(mc_list_entry->addr)) if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
!ipv4_is_local_multicast(pmc->multiaddr))
continue;
ip_eth_mc_map(pmc->multiaddr, mcast_addr);
if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
continue; continue;
new = kmalloc(sizeof(*new), GFP_ATOMIC); new = kmalloc(sizeof(*new), GFP_ATOMIC);
...@@ -169,36 +408,142 @@ static int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv, ...@@ -169,36 +408,142 @@ static int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv,
break; break;
} }
ether_addr_copy(new->addr, mc_list_entry->addr); ether_addr_copy(new->addr, mcast_addr);
hlist_add_head(&new->list, mcast_list); hlist_add_head(&new->list, mcast_list);
ret++; ret++;
} }
netif_addr_unlock_bh(bridge ? bridge : dev); rcu_read_unlock();
if (bridge) return ret;
dev_put(bridge); }
/**
* batadv_mcast_mla_softif_get_ipv6() - get softif IPv6 multicast listeners
* @dev: the device to collect multicast addresses from
* @mcast_list: a list to put found addresses into
* @flags: flags indicating the new multicast state
*
* Collects multicast addresses of IPv6 multicast listeners residing
* on this kernel on the given soft interface, dev, in
* the given mcast_list. In general, multicast listeners provided by
* your multicast receiving applications run directly on this node.
*
* Return: -ENOMEM on memory allocation error or the number of
* items added to the mcast_list otherwise.
*/
#if IS_ENABLED(CONFIG_IPV6)
static int
batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
struct batadv_hw_addr *new;
struct inet6_dev *in6_dev;
u8 mcast_addr[ETH_ALEN];
struct ifmcaddr6 *pmc6;
int ret = 0;
if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
return 0;
rcu_read_lock();
in6_dev = __in6_dev_get(dev);
if (!in6_dev) {
rcu_read_unlock();
return 0;
}
read_lock_bh(&in6_dev->lock);
for (pmc6 = in6_dev->mc_list; pmc6; pmc6 = pmc6->next) {
if (IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) <
IPV6_ADDR_SCOPE_LINKLOCAL)
continue;
if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
ipv6_addr_is_ll_all_nodes(&pmc6->mca_addr))
continue;
if (!(flags->tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
IPV6_ADDR_MC_SCOPE(&pmc6->mca_addr) >
IPV6_ADDR_SCOPE_LINKLOCAL)
continue;
ipv6_eth_mc_map(&pmc6->mca_addr, mcast_addr);
if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
continue;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
if (!new) {
ret = -ENOMEM;
break;
}
ether_addr_copy(new->addr, mcast_addr);
hlist_add_head(&new->list, mcast_list);
ret++;
}
read_unlock_bh(&in6_dev->lock);
rcu_read_unlock();
return ret; return ret;
} }
#else
static inline int
batadv_mcast_mla_softif_get_ipv6(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
return 0;
}
#endif
/** /**
* batadv_mcast_mla_is_duplicate() - check whether an address is in a list * batadv_mcast_mla_softif_get() - get softif multicast listeners
* @mcast_addr: the multicast address to check * @dev: the device to collect multicast addresses from
* @mcast_list: the list with multicast addresses to search in * @mcast_list: a list to put found addresses into
* @flags: flags indicating the new multicast state
* *
* Return: true if the given address is already in the given list. * Collects multicast addresses of multicast listeners residing
* Otherwise returns false. * on this kernel on the given soft interface, dev, in
* the given mcast_list. In general, multicast listeners provided by
* your multicast receiving applications run directly on this node.
*
* If there is a bridge interface on top of dev, collects from that one
* instead. Just like with IP addresses and routes, multicast listeners
* will(/should) register to the bridge interface instead of an
* enslaved bat0.
*
* Return: -ENOMEM on memory allocation error or the number of
* items added to the mcast_list otherwise.
*/ */
static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr, static int
struct hlist_head *mcast_list) batadv_mcast_mla_softif_get(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{ {
struct batadv_hw_addr *mcast_entry; struct net_device *bridge = batadv_mcast_get_bridge(dev);
int ret4, ret6 = 0;
hlist_for_each_entry(mcast_entry, mcast_list, list) if (bridge)
if (batadv_compare_eth(mcast_entry->addr, mcast_addr)) dev = bridge;
return true;
return false; ret4 = batadv_mcast_mla_softif_get_ipv4(dev, mcast_list, flags);
if (ret4 < 0)
goto out;
ret6 = batadv_mcast_mla_softif_get_ipv6(dev, mcast_list, flags);
if (ret6 < 0) {
ret4 = 0;
goto out;
}
out:
if (bridge)
dev_put(bridge);
return ret4 + ret6;
} }
/** /**
...@@ -227,9 +572,9 @@ static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src) ...@@ -227,9 +572,9 @@ static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
/** /**
* batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners * batadv_mcast_mla_bridge_get() - get bridged-in multicast listeners
* @bat_priv: the bat priv with all the soft interface information
* @dev: a bridge slave whose bridge to collect multicast addresses from * @dev: a bridge slave whose bridge to collect multicast addresses from
* @mcast_list: a list to put found addresses into * @mcast_list: a list to put found addresses into
* @flags: flags indicating the new multicast state
* *
* Collects multicast addresses of multicast listeners residing * Collects multicast addresses of multicast listeners residing
* on foreign, non-mesh devices which we gave access to our mesh via * on foreign, non-mesh devices which we gave access to our mesh via
...@@ -239,14 +584,13 @@ static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src) ...@@ -239,14 +584,13 @@ static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
* Return: -ENOMEM on memory allocation error or the number of * Return: -ENOMEM on memory allocation error or the number of
* items added to the mcast_list otherwise. * items added to the mcast_list otherwise.
*/ */
static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv, static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct net_device *dev, struct hlist_head *mcast_list,
struct hlist_head *mcast_list) struct batadv_mcast_mla_flags *flags)
{ {
struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list); struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
bool all_ipv4 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV4;
bool all_ipv6 = bat_priv->mcast.flags & BATADV_MCAST_WANT_ALL_IPV6;
struct br_ip_list *br_ip_entry, *tmp; struct br_ip_list *br_ip_entry, *tmp;
u8 tvlv_flags = flags->tvlv_flags;
struct batadv_hw_addr *new; struct batadv_hw_addr *new;
u8 mcast_addr[ETH_ALEN]; u8 mcast_addr[ETH_ALEN];
int ret; int ret;
...@@ -259,11 +603,34 @@ static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv, ...@@ -259,11 +603,34 @@ static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv,
goto out; goto out;
list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) { list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
if (all_ipv4 && br_ip_entry->addr.proto == htons(ETH_P_IP)) if (br_ip_entry->addr.proto == htons(ETH_P_IP)) {
continue; if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
continue;
if (all_ipv6 && br_ip_entry->addr.proto == htons(ETH_P_IPV6)) if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
continue; ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
continue;
if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR4) &&
!ipv4_is_local_multicast(br_ip_entry->addr.u.ip4))
continue;
}
#if IS_ENABLED(CONFIG_IPV6)
if (br_ip_entry->addr.proto == htons(ETH_P_IPV6)) {
if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV6)
continue;
if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
ipv6_addr_is_ll_all_nodes(&br_ip_entry->addr.u.ip6))
continue;
if (!(tvlv_flags & BATADV_MCAST_WANT_NO_RTR6) &&
IPV6_ADDR_MC_SCOPE(&br_ip_entry->addr.u.ip6) >
IPV6_ADDR_SCOPE_LINKLOCAL)
continue;
}
#endif
batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr); batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->addr);
if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list)) if (batadv_mcast_mla_is_duplicate(mcast_addr, mcast_list))
...@@ -369,27 +736,6 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, ...@@ -369,27 +736,6 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,
} }
} }
/**
* batadv_mcast_has_bridge() - check whether the soft-iface is bridged
* @bat_priv: the bat priv with all the soft interface information
*
* Checks whether there is a bridge on top of our soft interface.
*
* Return: true if there is a bridge, false otherwise.
*/
static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
{
struct net_device *upper = bat_priv->soft_iface;
rcu_read_lock();
do {
upper = netdev_master_upper_dev_get_rcu(upper);
} while (upper && !(upper->priv_flags & IFF_EBRIDGE));
rcu_read_unlock();
return upper;
}
/** /**
* batadv_mcast_querier_log() - debug output regarding the querier status on * batadv_mcast_querier_log() - debug output regarding the querier status on
* link * link
...@@ -424,7 +770,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto, ...@@ -424,7 +770,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
batadv_info(bat_priv->soft_iface, batadv_info(bat_priv->soft_iface,
"%s Querier disappeared - multicast optimizations disabled\n", "%s Querier disappeared - multicast optimizations disabled\n",
str_proto); str_proto);
else if (!bat_priv->mcast.bridged && !new_state->exists) else if (!bat_priv->mcast.mla_flags.bridged && !new_state->exists)
batadv_info(bat_priv->soft_iface, batadv_info(bat_priv->soft_iface,
"No %s Querier present - multicast optimizations disabled\n", "No %s Querier present - multicast optimizations disabled\n",
str_proto); str_proto);
...@@ -446,9 +792,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto, ...@@ -446,9 +792,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
* batadv_mcast_bridge_log() - debug output for topology changes in bridged * batadv_mcast_bridge_log() - debug output for topology changes in bridged
* setups * setups
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @bridged: a flag about whether the soft interface is currently bridged or not * @new_flags: flags indicating the new multicast state
* @querier_ipv4: (maybe) new status of a potential, selected IGMP querier
* @querier_ipv6: (maybe) new status of a potential, selected MLD querier
* *
* If no bridges are ever used on this node, then this function does nothing. * If no bridges are ever used on this node, then this function does nothing.
* *
...@@ -461,126 +805,86 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto, ...@@ -461,126 +805,86 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
* multicast flags this node is going to set. * multicast flags this node is going to set.
*/ */
static void static void
batadv_mcast_bridge_log(struct batadv_priv *bat_priv, bool bridged, batadv_mcast_bridge_log(struct batadv_priv *bat_priv,
struct batadv_mcast_querier_state *querier_ipv4, struct batadv_mcast_mla_flags *new_flags)
struct batadv_mcast_querier_state *querier_ipv6)
{ {
if (!bat_priv->mcast.bridged && bridged) struct batadv_mcast_mla_flags *old_flags = &bat_priv->mcast.mla_flags;
if (!old_flags->bridged && new_flags->bridged)
batadv_dbg(BATADV_DBG_MCAST, bat_priv, batadv_dbg(BATADV_DBG_MCAST, bat_priv,
"Bridge added: Setting Unsnoopables(U)-flag\n"); "Bridge added: Setting Unsnoopables(U)-flag\n");
else if (bat_priv->mcast.bridged && !bridged) else if (old_flags->bridged && !new_flags->bridged)
batadv_dbg(BATADV_DBG_MCAST, bat_priv, batadv_dbg(BATADV_DBG_MCAST, bat_priv,
"Bridge removed: Unsetting Unsnoopables(U)-flag\n"); "Bridge removed: Unsetting Unsnoopables(U)-flag\n");
if (bridged) { if (new_flags->bridged) {
batadv_mcast_querier_log(bat_priv, "IGMP", batadv_mcast_querier_log(bat_priv, "IGMP",
&bat_priv->mcast.querier_ipv4, &old_flags->querier_ipv4,
querier_ipv4); &new_flags->querier_ipv4);
batadv_mcast_querier_log(bat_priv, "MLD", batadv_mcast_querier_log(bat_priv, "MLD",
&bat_priv->mcast.querier_ipv6, &old_flags->querier_ipv6,
querier_ipv6); &new_flags->querier_ipv6);
} }
} }
/** /**
* batadv_mcast_flags_logs() - output debug information about mcast flag changes * batadv_mcast_flags_logs() - output debug information about mcast flag changes
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @flags: flags indicating the new multicast state * @flags: TVLV flags indicating the new multicast state
* *
* Whenever the multicast flags this nodes announces changes (@mcast_flags vs. * Whenever the multicast TVLV flags this nodes announces change this notifies
* bat_priv->mcast.flags), this notifies userspace via the 'mcast' log level. * userspace via the 'mcast' log level.
*/ */
static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags) static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
{ {
u8 old_flags = bat_priv->mcast.flags; bool old_enabled = bat_priv->mcast.mla_flags.enabled;
char str_old_flags[] = "[...]"; u8 old_flags = bat_priv->mcast.mla_flags.tvlv_flags;
char str_old_flags[] = "[.... . ]";
sprintf(str_old_flags, "[%c%c%c]", sprintf(str_old_flags, "[%c%c%c%s%s]",
(old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', (old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
(old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', (old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
(old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.'); (old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
!(old_flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
!(old_flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
batadv_dbg(BATADV_DBG_MCAST, bat_priv, batadv_dbg(BATADV_DBG_MCAST, bat_priv,
"Changing multicast flags from '%s' to '[%c%c%c]'\n", "Changing multicast flags from '%s' to '[%c%c%c%s%s]'\n",
bat_priv->mcast.enabled ? str_old_flags : "<undefined>", old_enabled ? str_old_flags : "<undefined>",
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.'); (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
!(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
!(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
} }
/** /**
* batadv_mcast_mla_tvlv_update() - update multicast tvlv * batadv_mcast_mla_flags_update() - update multicast flags
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @flags: flags indicating the new multicast state
* *
* Updates the own multicast tvlv with our current multicast related settings, * Updates the own multicast tvlv with our current multicast related settings,
* capabilities and inabilities. * capabilities and inabilities.
*
* Return: false if we want all IPv4 && IPv6 multicast traffic and true
* otherwise.
*/ */
static bool batadv_mcast_mla_tvlv_update(struct batadv_priv *bat_priv) static void
batadv_mcast_mla_flags_update(struct batadv_priv *bat_priv,
struct batadv_mcast_mla_flags *flags)
{ {
struct batadv_tvlv_mcast_data mcast_data; struct batadv_tvlv_mcast_data mcast_data;
struct batadv_mcast_querier_state querier4 = {false, false};
struct batadv_mcast_querier_state querier6 = {false, false};
struct net_device *dev = bat_priv->soft_iface;
bool bridged;
mcast_data.flags = BATADV_NO_FLAGS; if (!memcmp(flags, &bat_priv->mcast.mla_flags, sizeof(*flags)))
memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved)); return;
bridged = batadv_mcast_has_bridge(bat_priv);
if (!bridged)
goto update;
if (!IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING))
pr_warn_once("No bridge IGMP snooping compiled - multicast optimizations disabled\n");
querier4.exists = br_multicast_has_querier_anywhere(dev, ETH_P_IP);
querier4.shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IP);
querier6.exists = br_multicast_has_querier_anywhere(dev, ETH_P_IPV6);
querier6.shadowing = br_multicast_has_querier_adjacent(dev, ETH_P_IPV6);
mcast_data.flags |= BATADV_MCAST_WANT_ALL_UNSNOOPABLES;
/* 1) If no querier exists at all, then multicast listeners on
* our local TT clients behind the bridge will keep silent.
* 2) If the selected querier is on one of our local TT clients,
* behind the bridge, then this querier might shadow multicast
* listeners on our local TT clients, behind this bridge.
*
* In both cases, we will signalize other batman nodes that
* we need all multicast traffic of the according protocol.
*/
if (!querier4.exists || querier4.shadowing)
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV4;
if (!querier6.exists || querier6.shadowing)
mcast_data.flags |= BATADV_MCAST_WANT_ALL_IPV6;
update:
batadv_mcast_bridge_log(bat_priv, bridged, &querier4, &querier6);
bat_priv->mcast.querier_ipv4.exists = querier4.exists;
bat_priv->mcast.querier_ipv4.shadowing = querier4.shadowing;
bat_priv->mcast.querier_ipv6.exists = querier6.exists; batadv_mcast_bridge_log(bat_priv, flags);
bat_priv->mcast.querier_ipv6.shadowing = querier6.shadowing; batadv_mcast_flags_log(bat_priv, flags->tvlv_flags);
bat_priv->mcast.bridged = bridged; mcast_data.flags = flags->tvlv_flags;
memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
if (!bat_priv->mcast.enabled || batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
mcast_data.flags != bat_priv->mcast.flags) { &mcast_data, sizeof(mcast_data));
batadv_mcast_flags_log(bat_priv, mcast_data.flags);
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
&mcast_data, sizeof(mcast_data));
bat_priv->mcast.flags = mcast_data.flags;
bat_priv->mcast.enabled = true;
}
return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 && bat_priv->mcast.mla_flags = *flags;
mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6);
} }
/** /**
...@@ -599,22 +903,24 @@ static void __batadv_mcast_mla_update(struct batadv_priv *bat_priv) ...@@ -599,22 +903,24 @@ static void __batadv_mcast_mla_update(struct batadv_priv *bat_priv)
{ {
struct net_device *soft_iface = bat_priv->soft_iface; struct net_device *soft_iface = bat_priv->soft_iface;
struct hlist_head mcast_list = HLIST_HEAD_INIT; struct hlist_head mcast_list = HLIST_HEAD_INIT;
struct batadv_mcast_mla_flags flags;
int ret; int ret;
if (!batadv_mcast_mla_tvlv_update(bat_priv)) flags = batadv_mcast_mla_flags_get(bat_priv);
goto update;
ret = batadv_mcast_mla_softif_get(bat_priv, soft_iface, &mcast_list); ret = batadv_mcast_mla_softif_get(soft_iface, &mcast_list, &flags);
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = batadv_mcast_mla_bridge_get(bat_priv, soft_iface, &mcast_list); ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list, &flags);
if (ret < 0) if (ret < 0)
goto out; goto out;
update: spin_lock(&bat_priv->mcast.mla_lock);
batadv_mcast_mla_tt_retract(bat_priv, &mcast_list); batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
batadv_mcast_mla_tt_add(bat_priv, &mcast_list); batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
batadv_mcast_mla_flags_update(bat_priv, &flags);
spin_unlock(&bat_priv->mcast.mla_lock);
out: out:
batadv_mcast_mla_list_free(&mcast_list); batadv_mcast_mla_list_free(&mcast_list);
...@@ -639,10 +945,7 @@ static void batadv_mcast_mla_update(struct work_struct *work) ...@@ -639,10 +945,7 @@ static void batadv_mcast_mla_update(struct work_struct *work)
priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work); priv_mcast = container_of(delayed_work, struct batadv_priv_mcast, work);
bat_priv = container_of(priv_mcast, struct batadv_priv, mcast); bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
spin_lock(&bat_priv->mcast.mla_lock);
__batadv_mcast_mla_update(bat_priv); __batadv_mcast_mla_update(bat_priv);
spin_unlock(&bat_priv->mcast.mla_lock);
batadv_mcast_start_timer(bat_priv); batadv_mcast_start_timer(bat_priv);
} }
...@@ -677,6 +980,7 @@ static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb) ...@@ -677,6 +980,7 @@ static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @skb: the IPv4 packet to check * @skb: the IPv4 packet to check
* @is_unsnoopable: stores whether the destination is snoopable * @is_unsnoopable: stores whether the destination is snoopable
* @is_routable: stores whether the destination is routable
* *
* Checks whether the given IPv4 packet has the potential to be forwarded with a * Checks whether the given IPv4 packet has the potential to be forwarded with a
* mode more optimal than classic flooding. * mode more optimal than classic flooding.
...@@ -686,7 +990,8 @@ static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb) ...@@ -686,7 +990,8 @@ static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
*/ */
static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct sk_buff *skb,
bool *is_unsnoopable) bool *is_unsnoopable,
int *is_routable)
{ {
struct iphdr *iphdr; struct iphdr *iphdr;
...@@ -699,16 +1004,13 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv, ...@@ -699,16 +1004,13 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
iphdr = ip_hdr(skb); iphdr = ip_hdr(skb);
/* TODO: Implement Multicast Router Discovery (RFC4286),
* then allow scope > link local, too
*/
if (!ipv4_is_local_multicast(iphdr->daddr))
return -EINVAL;
/* link-local multicast listeners behind a bridge are /* link-local multicast listeners behind a bridge are
* not snoopable (see RFC4541, section 2.1.2.2) * not snoopable (see RFC4541, section 2.1.2.2)
*/ */
*is_unsnoopable = true; if (ipv4_is_local_multicast(iphdr->daddr))
*is_unsnoopable = true;
else
*is_routable = ETH_P_IP;
return 0; return 0;
} }
...@@ -743,6 +1045,7 @@ static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb) ...@@ -743,6 +1045,7 @@ static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @skb: the IPv6 packet to check * @skb: the IPv6 packet to check
* @is_unsnoopable: stores whether the destination is snoopable * @is_unsnoopable: stores whether the destination is snoopable
* @is_routable: stores whether the destination is routable
* *
* Checks whether the given IPv6 packet has the potential to be forwarded with a * Checks whether the given IPv6 packet has the potential to be forwarded with a
* mode more optimal than classic flooding. * mode more optimal than classic flooding.
...@@ -751,7 +1054,8 @@ static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb) ...@@ -751,7 +1054,8 @@ static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
*/ */
static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct sk_buff *skb,
bool *is_unsnoopable) bool *is_unsnoopable,
int *is_routable)
{ {
struct ipv6hdr *ip6hdr; struct ipv6hdr *ip6hdr;
...@@ -764,10 +1068,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, ...@@ -764,10 +1068,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
ip6hdr = ipv6_hdr(skb); ip6hdr = ipv6_hdr(skb);
/* TODO: Implement Multicast Router Discovery (RFC4286), if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) < IPV6_ADDR_SCOPE_LINKLOCAL)
* then allow scope > link local, too
*/
if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL)
return -EINVAL; return -EINVAL;
/* link-local-all-nodes multicast listeners behind a bridge are /* link-local-all-nodes multicast listeners behind a bridge are
...@@ -775,6 +1076,8 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, ...@@ -775,6 +1076,8 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
*/ */
if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr)) if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
*is_unsnoopable = true; *is_unsnoopable = true;
else if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) > IPV6_ADDR_SCOPE_LINKLOCAL)
*is_routable = ETH_P_IPV6;
return 0; return 0;
} }
...@@ -784,6 +1087,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, ...@@ -784,6 +1087,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @skb: the multicast frame to check * @skb: the multicast frame to check
* @is_unsnoopable: stores whether the destination is snoopable * @is_unsnoopable: stores whether the destination is snoopable
* @is_routable: stores whether the destination is routable
* *
* Checks whether the given multicast ethernet frame has the potential to be * Checks whether the given multicast ethernet frame has the potential to be
* forwarded with a mode more optimal than classic flooding. * forwarded with a mode more optimal than classic flooding.
...@@ -792,7 +1096,8 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv, ...@@ -792,7 +1096,8 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
*/ */
static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct sk_buff *skb,
bool *is_unsnoopable) bool *is_unsnoopable,
int *is_routable)
{ {
struct ethhdr *ethhdr = eth_hdr(skb); struct ethhdr *ethhdr = eth_hdr(skb);
...@@ -802,13 +1107,15 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, ...@@ -802,13 +1107,15 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
switch (ntohs(ethhdr->h_proto)) { switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP: case ETH_P_IP:
return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb, return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
is_unsnoopable); is_unsnoopable,
is_routable);
case ETH_P_IPV6: case ETH_P_IPV6:
if (!IS_ENABLED(CONFIG_IPV6)) if (!IS_ENABLED(CONFIG_IPV6))
return -EINVAL; return -EINVAL;
return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb, return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
is_unsnoopable); is_unsnoopable,
is_routable);
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -824,16 +1131,39 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, ...@@ -824,16 +1131,39 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
* given ethhdr is from an IPv4 packet or the number of nodes which want all * given ethhdr is from an IPv4 packet or the number of nodes which want all
* IPv6 traffic if it matches an IPv6 packet. * IPv6 traffic if it matches an IPv6 packet.
*/ */
static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv, static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr) struct ethhdr *ethhdr)
{
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
case ETH_P_IPV6:
return atomic_read(&bat_priv->mcast.num_want_all_ipv6);
default:
/* we shouldn't be here... */
return 0;
}
}
/**
* batadv_mcast_forw_rtr_count() - count nodes with a multicast router
* @bat_priv: the bat priv with all the soft interface information
* @protocol: the ethernet protocol type to count multicast routers for
*
* Return: the number of nodes which want all routable IPv4 multicast traffic
* if the protocol is ETH_P_IP or the number of nodes which want all routable
* IPv6 traffic if the protocol is ETH_P_IPV6. Otherwise returns 0.
*/
static int batadv_mcast_forw_rtr_count(struct batadv_priv *bat_priv,
int protocol)
{ {
switch (ntohs(ethhdr->h_proto)) { switch (protocol) {
case ETH_P_IP: case ETH_P_IP:
return atomic_read(&bat_priv->mcast.num_want_all_ipv4); return atomic_read(&bat_priv->mcast.num_want_all_rtr4);
case ETH_P_IPV6: case ETH_P_IPV6:
return atomic_read(&bat_priv->mcast.num_want_all_ipv6); return atomic_read(&bat_priv->mcast.num_want_all_rtr6);
default: default:
/* we shouldn't be here... */
return 0; return 0;
} }
} }
...@@ -959,6 +1289,84 @@ batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv) ...@@ -959,6 +1289,84 @@ batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv)
return orig_node; return orig_node;
} }
/**
* batadv_mcast_forw_rtr4_node_get() - get a node with an ipv4 mcast router flag
* @bat_priv: the bat priv with all the soft interface information
*
* Return: an orig_node which has the BATADV_MCAST_WANT_NO_RTR4 flag unset and
* increases its refcount.
*/
static struct batadv_orig_node *
batadv_mcast_forw_rtr4_node_get(struct batadv_priv *bat_priv)
{
struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
rcu_read_lock();
hlist_for_each_entry_rcu(tmp_orig_node,
&bat_priv->mcast.want_all_rtr4_list,
mcast_want_all_rtr4_node) {
if (!kref_get_unless_zero(&tmp_orig_node->refcount))
continue;
orig_node = tmp_orig_node;
break;
}
rcu_read_unlock();
return orig_node;
}
/**
* batadv_mcast_forw_rtr6_node_get() - get a node with an ipv6 mcast router flag
* @bat_priv: the bat priv with all the soft interface information
*
* Return: an orig_node which has the BATADV_MCAST_WANT_NO_RTR6 flag unset
* and increases its refcount.
*/
static struct batadv_orig_node *
batadv_mcast_forw_rtr6_node_get(struct batadv_priv *bat_priv)
{
struct batadv_orig_node *tmp_orig_node, *orig_node = NULL;
rcu_read_lock();
hlist_for_each_entry_rcu(tmp_orig_node,
&bat_priv->mcast.want_all_rtr6_list,
mcast_want_all_rtr6_node) {
if (!kref_get_unless_zero(&tmp_orig_node->refcount))
continue;
orig_node = tmp_orig_node;
break;
}
rcu_read_unlock();
return orig_node;
}
/**
* batadv_mcast_forw_rtr_node_get() - get a node with an ipv4/ipv6 router flag
* @bat_priv: the bat priv with all the soft interface information
* @ethhdr: an ethernet header to determine the protocol family from
*
* Return: an orig_node which has no BATADV_MCAST_WANT_NO_RTR4 or
* BATADV_MCAST_WANT_NO_RTR6 flag, depending on the provided ethhdr, set and
* increases its refcount.
*/
static struct batadv_orig_node *
batadv_mcast_forw_rtr_node_get(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr)
{
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
return batadv_mcast_forw_rtr4_node_get(bat_priv);
case ETH_P_IPV6:
return batadv_mcast_forw_rtr6_node_get(bat_priv);
default:
/* we shouldn't be here... */
return NULL;
}
}
/** /**
* batadv_mcast_forw_mode() - check on how to forward a multicast packet * batadv_mcast_forw_mode() - check on how to forward a multicast packet
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
...@@ -977,8 +1385,11 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -977,8 +1385,11 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
bool is_unsnoopable = false; bool is_unsnoopable = false;
unsigned int mcast_fanout; unsigned int mcast_fanout;
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
int is_routable = 0;
int rtr_count = 0;
ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable); ret = batadv_mcast_forw_mode_check(bat_priv, skb, &is_unsnoopable,
&is_routable);
if (ret == -ENOMEM) if (ret == -ENOMEM)
return BATADV_FORW_NONE; return BATADV_FORW_NONE;
else if (ret < 0) else if (ret < 0)
...@@ -991,8 +1402,9 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -991,8 +1402,9 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr); ip_count = batadv_mcast_forw_want_all_ip_count(bat_priv, ethhdr);
unsnoop_count = !is_unsnoopable ? 0 : unsnoop_count = !is_unsnoopable ? 0 :
atomic_read(&bat_priv->mcast.num_want_all_unsnoopables); atomic_read(&bat_priv->mcast.num_want_all_unsnoopables);
rtr_count = batadv_mcast_forw_rtr_count(bat_priv, is_routable);
total_count = tt_count + ip_count + unsnoop_count; total_count = tt_count + ip_count + unsnoop_count + rtr_count;
switch (total_count) { switch (total_count) {
case 1: case 1:
...@@ -1002,6 +1414,9 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1002,6 +1414,9 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
*orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr); *orig = batadv_mcast_forw_ip_node_get(bat_priv, ethhdr);
else if (unsnoop_count) else if (unsnoop_count)
*orig = batadv_mcast_forw_unsnoop_node_get(bat_priv); *orig = batadv_mcast_forw_unsnoop_node_get(bat_priv);
else if (rtr_count)
*orig = batadv_mcast_forw_rtr_node_get(bat_priv,
ethhdr);
if (*orig) if (*orig)
return BATADV_FORW_SINGLE; return BATADV_FORW_SINGLE;
...@@ -1172,6 +1587,111 @@ batadv_mcast_forw_want_all(struct batadv_priv *bat_priv, ...@@ -1172,6 +1587,111 @@ batadv_mcast_forw_want_all(struct batadv_priv *bat_priv,
} }
} }
/**
* batadv_mcast_forw_want_all_rtr4() - forward to nodes with want-all-rtr4
* @bat_priv: the bat priv with all the soft interface information
* @skb: the multicast packet to transmit
* @vid: the vlan identifier
*
* Sends copies of a frame with multicast destination to any node with a
* BATADV_MCAST_WANT_NO_RTR4 flag unset. A transmission is performed via a
* batman-adv unicast packet for each such destination node.
*
* Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
* otherwise.
*/
static int
batadv_mcast_forw_want_all_rtr4(struct batadv_priv *bat_priv,
struct sk_buff *skb, unsigned short vid)
{
struct batadv_orig_node *orig_node;
int ret = NET_XMIT_SUCCESS;
struct sk_buff *newskb;
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node,
&bat_priv->mcast.want_all_rtr4_list,
mcast_want_all_rtr4_node) {
newskb = skb_copy(skb, GFP_ATOMIC);
if (!newskb) {
ret = NET_XMIT_DROP;
break;
}
batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
orig_node, vid);
}
rcu_read_unlock();
return ret;
}
/**
* batadv_mcast_forw_want_all_rtr6() - forward to nodes with want-all-rtr6
* @bat_priv: the bat priv with all the soft interface information
* @skb: The multicast packet to transmit
* @vid: the vlan identifier
*
* Sends copies of a frame with multicast destination to any node with a
* BATADV_MCAST_WANT_NO_RTR6 flag unset. A transmission is performed via a
* batman-adv unicast packet for each such destination node.
*
* Return: NET_XMIT_DROP on memory allocation failure, NET_XMIT_SUCCESS
* otherwise.
*/
static int
batadv_mcast_forw_want_all_rtr6(struct batadv_priv *bat_priv,
struct sk_buff *skb, unsigned short vid)
{
struct batadv_orig_node *orig_node;
int ret = NET_XMIT_SUCCESS;
struct sk_buff *newskb;
rcu_read_lock();
hlist_for_each_entry_rcu(orig_node,
&bat_priv->mcast.want_all_rtr6_list,
mcast_want_all_rtr6_node) {
newskb = skb_copy(skb, GFP_ATOMIC);
if (!newskb) {
ret = NET_XMIT_DROP;
break;
}
batadv_send_skb_unicast(bat_priv, newskb, BATADV_UNICAST, 0,
orig_node, vid);
}
rcu_read_unlock();
return ret;
}
/**
* batadv_mcast_forw_want_rtr() - forward packet to nodes in a want-all-rtr list
* @bat_priv: the bat priv with all the soft interface information
* @skb: the multicast packet to transmit
* @vid: the vlan identifier
*
* Sends copies of a frame with multicast destination to any node with a
* BATADV_MCAST_WANT_NO_RTR4 or BATADV_MCAST_WANT_NO_RTR6 flag unset. A
* transmission is performed via a batman-adv unicast packet for each such
* destination node.
*
* Return: NET_XMIT_DROP on memory allocation failure or if the protocol family
* is neither IPv4 nor IPv6. NET_XMIT_SUCCESS otherwise.
*/
static int
batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,
struct sk_buff *skb, unsigned short vid)
{
switch (ntohs(eth_hdr(skb)->h_proto)) {
case ETH_P_IP:
return batadv_mcast_forw_want_all_rtr4(bat_priv, skb, vid);
case ETH_P_IPV6:
return batadv_mcast_forw_want_all_rtr6(bat_priv, skb, vid);
default:
/* we shouldn't be here... */
return NET_XMIT_DROP;
}
}
/** /**
* batadv_mcast_forw_send() - send packet to any detected multicast recpient * batadv_mcast_forw_send() - send packet to any detected multicast recpient
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
...@@ -1205,6 +1725,12 @@ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -1205,6 +1725,12 @@ int batadv_mcast_forw_send(struct batadv_priv *bat_priv, struct sk_buff *skb,
return ret; return ret;
} }
ret = batadv_mcast_forw_want_rtr(bat_priv, skb, vid);
if (ret != NET_XMIT_SUCCESS) {
kfree_skb(skb);
return ret;
}
consume_skb(skb); consume_skb(skb);
return ret; return ret;
} }
...@@ -1344,6 +1870,127 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, ...@@ -1344,6 +1870,127 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
} }
} }
/**
* batadv_mcast_want_rtr4_update() - update want-all-rtr4 counter and list
* @bat_priv: the bat priv with all the soft interface information
* @orig: the orig_node which multicast state might have changed of
* @mcast_flags: flags indicating the new multicast state
*
* If the BATADV_MCAST_WANT_NO_RTR4 flag of this originator, orig, has
* toggled then this method updates counter and list accordingly.
*
* Caller needs to hold orig->mcast_handler_lock.
*/
static void batadv_mcast_want_rtr4_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig,
u8 mcast_flags)
{
struct hlist_node *node = &orig->mcast_want_all_rtr4_node;
struct hlist_head *head = &bat_priv->mcast.want_all_rtr4_list;
lockdep_assert_held(&orig->mcast_handler_lock);
/* switched from flag set to unset */
if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR4) &&
orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4) {
atomic_inc(&bat_priv->mcast.num_want_all_rtr4);
spin_lock_bh(&bat_priv->mcast.want_lists_lock);
/* flag checks above + mcast_handler_lock prevents this */
WARN_ON(!hlist_unhashed(node));
hlist_add_head_rcu(node, head);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
/* switched from flag unset to set */
} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR4 &&
!(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR4)) {
atomic_dec(&bat_priv->mcast.num_want_all_rtr4);
spin_lock_bh(&bat_priv->mcast.want_lists_lock);
/* flag checks above + mcast_handler_lock prevents this */
WARN_ON(hlist_unhashed(node));
hlist_del_init_rcu(node);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
}
}
/**
* batadv_mcast_want_rtr6_update() - update want-all-rtr6 counter and list
* @bat_priv: the bat priv with all the soft interface information
* @orig: the orig_node which multicast state might have changed of
* @mcast_flags: flags indicating the new multicast state
*
* If the BATADV_MCAST_WANT_NO_RTR6 flag of this originator, orig, has
* toggled then this method updates counter and list accordingly.
*
* Caller needs to hold orig->mcast_handler_lock.
*/
static void batadv_mcast_want_rtr6_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig,
u8 mcast_flags)
{
struct hlist_node *node = &orig->mcast_want_all_rtr6_node;
struct hlist_head *head = &bat_priv->mcast.want_all_rtr6_list;
lockdep_assert_held(&orig->mcast_handler_lock);
/* switched from flag set to unset */
if (!(mcast_flags & BATADV_MCAST_WANT_NO_RTR6) &&
orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6) {
atomic_inc(&bat_priv->mcast.num_want_all_rtr6);
spin_lock_bh(&bat_priv->mcast.want_lists_lock);
/* flag checks above + mcast_handler_lock prevents this */
WARN_ON(!hlist_unhashed(node));
hlist_add_head_rcu(node, head);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
/* switched from flag unset to set */
} else if (mcast_flags & BATADV_MCAST_WANT_NO_RTR6 &&
!(orig->mcast_flags & BATADV_MCAST_WANT_NO_RTR6)) {
atomic_dec(&bat_priv->mcast.num_want_all_rtr6);
spin_lock_bh(&bat_priv->mcast.want_lists_lock);
/* flag checks above + mcast_handler_lock prevents this */
WARN_ON(hlist_unhashed(node));
hlist_del_init_rcu(node);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
}
}
/**
* batadv_mcast_tvlv_flags_get() - get multicast flags from an OGM TVLV
* @enabled: whether the originator has multicast TVLV support enabled
* @tvlv_value: tvlv buffer containing the multicast flags
* @tvlv_value_len: tvlv buffer length
*
* Return: multicast flags for the given tvlv buffer
*/
static u8
batadv_mcast_tvlv_flags_get(bool enabled, void *tvlv_value, u16 tvlv_value_len)
{
u8 mcast_flags = BATADV_NO_FLAGS;
if (enabled && tvlv_value && tvlv_value_len >= sizeof(mcast_flags))
mcast_flags = *(u8 *)tvlv_value;
if (!enabled) {
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV4;
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV6;
}
/* remove redundant flags to avoid sending duplicate packets later */
if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)
mcast_flags |= BATADV_MCAST_WANT_NO_RTR4;
if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)
mcast_flags |= BATADV_MCAST_WANT_NO_RTR6;
return mcast_flags;
}
/** /**
* batadv_mcast_tvlv_ogm_handler() - process incoming multicast tvlv container * batadv_mcast_tvlv_ogm_handler() - process incoming multicast tvlv container
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
...@@ -1359,16 +2006,10 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, ...@@ -1359,16 +2006,10 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
u16 tvlv_value_len) u16 tvlv_value_len)
{ {
bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
u8 mcast_flags = BATADV_NO_FLAGS; u8 mcast_flags;
if (orig_mcast_enabled && tvlv_value &&
tvlv_value_len >= sizeof(mcast_flags))
mcast_flags = *(u8 *)tvlv_value;
if (!orig_mcast_enabled) { mcast_flags = batadv_mcast_tvlv_flags_get(orig_mcast_enabled,
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV4; tvlv_value, tvlv_value_len);
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV6;
}
spin_lock_bh(&orig->mcast_handler_lock); spin_lock_bh(&orig->mcast_handler_lock);
...@@ -1385,6 +2026,8 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv, ...@@ -1385,6 +2026,8 @@ static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags); batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags); batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags); batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_rtr4_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_rtr6_update(bat_priv, orig, mcast_flags);
orig->mcast_flags = mcast_flags; orig->mcast_flags = mcast_flags;
spin_unlock_bh(&orig->mcast_handler_lock); spin_unlock_bh(&orig->mcast_handler_lock);
...@@ -1417,15 +2060,16 @@ void batadv_mcast_init(struct batadv_priv *bat_priv) ...@@ -1417,15 +2060,16 @@ void batadv_mcast_init(struct batadv_priv *bat_priv)
static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv, static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv,
struct seq_file *seq) struct seq_file *seq)
{ {
u8 flags = bat_priv->mcast.flags; struct batadv_mcast_mla_flags *mla_flags = &bat_priv->mcast.mla_flags;
char querier4, querier6, shadowing4, shadowing6; char querier4, querier6, shadowing4, shadowing6;
bool bridged = bat_priv->mcast.bridged; bool bridged = mla_flags->bridged;
u8 flags = mla_flags->tvlv_flags;
if (bridged) { if (bridged) {
querier4 = bat_priv->mcast.querier_ipv4.exists ? '.' : '4'; querier4 = mla_flags->querier_ipv4.exists ? '.' : '4';
querier6 = bat_priv->mcast.querier_ipv6.exists ? '.' : '6'; querier6 = mla_flags->querier_ipv6.exists ? '.' : '6';
shadowing4 = bat_priv->mcast.querier_ipv4.shadowing ? '4' : '.'; shadowing4 = mla_flags->querier_ipv4.shadowing ? '4' : '.';
shadowing6 = bat_priv->mcast.querier_ipv6.shadowing ? '6' : '.'; shadowing6 = mla_flags->querier_ipv6.shadowing ? '6' : '.';
} else { } else {
querier4 = '?'; querier4 = '?';
querier6 = '?'; querier6 = '?';
...@@ -1433,10 +2077,12 @@ static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv, ...@@ -1433,10 +2077,12 @@ static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv,
shadowing6 = '?'; shadowing6 = '?';
} }
seq_printf(seq, "Multicast flags (own flags: [%c%c%c])\n", seq_printf(seq, "Multicast flags (own flags: [%c%c%c%s%s])\n",
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.', (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.', (flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.'); (flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.',
!(flags & BATADV_MCAST_WANT_NO_RTR4) ? "R4" : ". ",
!(flags & BATADV_MCAST_WANT_NO_RTR6) ? "R6" : ". ");
seq_printf(seq, "* Bridged [U]\t\t\t\t%c\n", bridged ? 'U' : '.'); seq_printf(seq, "* Bridged [U]\t\t\t\t%c\n", bridged ? 'U' : '.');
seq_printf(seq, "* No IGMP/MLD Querier [4/6]:\t\t%c/%c\n", seq_printf(seq, "* No IGMP/MLD Querier [4/6]:\t\t%c/%c\n",
querier4, querier6); querier4, querier6);
...@@ -1490,13 +2136,17 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset) ...@@ -1490,13 +2136,17 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
flags = orig_node->mcast_flags; flags = orig_node->mcast_flags;
seq_printf(seq, "%pM [%c%c%c]\n", orig_node->orig, seq_printf(seq, "%pM [%c%c%c%s%s]\n", orig_node->orig,
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) (flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)
? 'U' : '.', ? 'U' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV4) (flags & BATADV_MCAST_WANT_ALL_IPV4)
? '4' : '.', ? '4' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV6) (flags & BATADV_MCAST_WANT_ALL_IPV6)
? '6' : '.'); ? '6' : '.',
!(flags & BATADV_MCAST_WANT_NO_RTR4)
? "R4" : ". ",
!(flags & BATADV_MCAST_WANT_NO_RTR6)
? "R6" : ". ");
} }
rcu_read_unlock(); rcu_read_unlock();
} }
...@@ -1517,19 +2167,19 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset) ...@@ -1517,19 +2167,19 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
int batadv_mcast_mesh_info_put(struct sk_buff *msg, int batadv_mcast_mesh_info_put(struct sk_buff *msg,
struct batadv_priv *bat_priv) struct batadv_priv *bat_priv)
{ {
u32 flags = bat_priv->mcast.flags; u32 flags = bat_priv->mcast.mla_flags.tvlv_flags;
u32 flags_priv = BATADV_NO_FLAGS; u32 flags_priv = BATADV_NO_FLAGS;
if (bat_priv->mcast.bridged) { if (bat_priv->mcast.mla_flags.bridged) {
flags_priv |= BATADV_MCAST_FLAGS_BRIDGED; flags_priv |= BATADV_MCAST_FLAGS_BRIDGED;
if (bat_priv->mcast.querier_ipv4.exists) if (bat_priv->mcast.mla_flags.querier_ipv4.exists)
flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS; flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS;
if (bat_priv->mcast.querier_ipv6.exists) if (bat_priv->mcast.mla_flags.querier_ipv6.exists)
flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS; flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS;
if (bat_priv->mcast.querier_ipv4.shadowing) if (bat_priv->mcast.mla_flags.querier_ipv4.shadowing)
flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING; flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING;
if (bat_priv->mcast.querier_ipv6.shadowing) if (bat_priv->mcast.mla_flags.querier_ipv6.shadowing)
flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING; flags_priv |= BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING;
} }
...@@ -1770,6 +2420,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig) ...@@ -1770,6 +2420,8 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_rtr4_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_rtr6_update(bat_priv, orig, BATADV_NO_FLAGS);
spin_unlock_bh(&orig->mcast_handler_lock); spin_unlock_bh(&orig->mcast_handler_lock);
} }
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
#include "main.h" #include "main.h"
struct netlink_callback; #include <linux/netlink.h>
struct seq_file; #include <linux/seq_file.h>
struct sk_buff; #include <linux/skbuff.h>
/** /**
* enum batadv_forw_mode - the way a packet should be forwarded as * enum batadv_forw_mode - the way a packet should be forwarded as
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netlink.h> #include <linux/netlink.h>
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/genetlink.h> #include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h> #include <net/netlink.h>
#include <net/sock.h> #include <net/sock.h>
#include <uapi/linux/batadv_packet.h> #include <uapi/linux/batadv_packet.h>
...@@ -49,8 +51,6 @@ ...@@ -49,8 +51,6 @@
#include "tp_meter.h" #include "tp_meter.h"
#include "translation-table.h" #include "translation-table.h"
struct net;
struct genl_family batadv_netlink_family; struct genl_family batadv_netlink_family;
/* multicast groups */ /* multicast groups */
......
...@@ -9,11 +9,10 @@ ...@@ -9,11 +9,10 @@
#include "main.h" #include "main.h"
#include <linux/netlink.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/genetlink.h> #include <net/genetlink.h>
struct nlmsghdr;
void batadv_netlink_register(void); void batadv_netlink_register(void);
void batadv_netlink_unregister(void); void batadv_netlink_unregister(void);
int batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype); int batadv_netlink_get_ifindex(const struct nlmsghdr *nlh, int attrtype);
......
...@@ -1951,34 +1951,19 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset) ...@@ -1951,34 +1951,19 @@ int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
/** /**
* batadv_nc_init_debugfs() - create nc folder and related files in debugfs * batadv_nc_init_debugfs() - create nc folder and related files in debugfs
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
*
* Return: 0 on success or negative error number in case of failure
*/ */
int batadv_nc_init_debugfs(struct batadv_priv *bat_priv) void batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
{ {
struct dentry *nc_dir, *file; struct dentry *nc_dir;
nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir); nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir);
if (!nc_dir)
goto out;
file = debugfs_create_u8("min_tq", 0644, nc_dir, &bat_priv->nc.min_tq); debugfs_create_u8("min_tq", 0644, nc_dir, &bat_priv->nc.min_tq);
if (!file)
goto out;
file = debugfs_create_u32("max_fwd_delay", 0644, nc_dir, debugfs_create_u32("max_fwd_delay", 0644, nc_dir,
&bat_priv->nc.max_fwd_delay); &bat_priv->nc.max_fwd_delay);
if (!file)
goto out;
file = debugfs_create_u32("max_buffer_time", 0644, nc_dir, debugfs_create_u32("max_buffer_time", 0644, nc_dir,
&bat_priv->nc.max_buffer_time); &bat_priv->nc.max_buffer_time);
if (!file)
goto out;
return 0;
out:
return -ENOMEM;
} }
#endif #endif
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
#include "main.h" #include "main.h"
#include <linux/netdevice.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
struct batadv_ogm_packet;
struct net_device;
struct seq_file;
struct sk_buff;
#ifdef CONFIG_BATMAN_ADV_NC #ifdef CONFIG_BATMAN_ADV_NC
...@@ -40,7 +39,7 @@ void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv, ...@@ -40,7 +39,7 @@ void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv, void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
struct sk_buff *skb); struct sk_buff *skb);
int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset); int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset);
int batadv_nc_init_debugfs(struct batadv_priv *bat_priv); void batadv_nc_init_debugfs(struct batadv_priv *bat_priv);
#else /* ifdef CONFIG_BATMAN_ADV_NC */ #else /* ifdef CONFIG_BATMAN_ADV_NC */
...@@ -111,9 +110,8 @@ static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq, ...@@ -111,9 +110,8 @@ static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
return 0; return 0;
} }
static inline int batadv_nc_init_debugfs(struct batadv_priv *bat_priv) static inline void batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
{ {
return 0;
} }
#endif /* ifdef CONFIG_BATMAN_ADV_NC */ #endif /* ifdef CONFIG_BATMAN_ADV_NC */
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <net/sock.h> #include <net/sock.h>
#include <uapi/linux/batadv_packet.h>
#include <uapi/linux/batman_adv.h> #include <uapi/linux/batman_adv.h>
#include "bat_algo.h" #include "bat_algo.h"
...@@ -1043,7 +1044,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, ...@@ -1043,7 +1044,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
orig_node->bcast_seqno_reset = reset_time; orig_node->bcast_seqno_reset = reset_time;
#ifdef CONFIG_BATMAN_ADV_MCAST #ifdef CONFIG_BATMAN_ADV_MCAST
orig_node->mcast_flags = BATADV_NO_FLAGS; orig_node->mcast_flags = BATADV_MCAST_WANT_NO_RTR4;
orig_node->mcast_flags |= BATADV_MCAST_WANT_NO_RTR6;
INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node); INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node);
INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node); INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node);
INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node); INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node);
......
...@@ -12,12 +12,11 @@ ...@@ -12,12 +12,11 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/jhash.h> #include <linux/jhash.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct netlink_callback;
struct seq_file;
struct sk_buff;
bool batadv_compare_orig(const struct hlist_node *node, const void *data2); bool batadv_compare_orig(const struct hlist_node *node, const void *data2);
int batadv_originator_init(struct batadv_priv *bat_priv); int batadv_originator_init(struct batadv_priv *bat_priv);
void batadv_originator_free(struct batadv_priv *bat_priv); void batadv_originator_free(struct batadv_priv *bat_priv);
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
#include "main.h" #include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct sk_buff;
bool batadv_check_management_packet(struct sk_buff *skb, bool batadv_check_management_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface, struct batadv_hard_iface *hard_iface,
int header_len); int header_len);
......
...@@ -10,12 +10,11 @@ ...@@ -10,12 +10,11 @@
#include "main.h" #include "main.h"
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h> #include <uapi/linux/batadv_packet.h>
struct sk_buff;
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet, void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
bool dropped); bool dropped);
struct batadv_forw_packet * struct batadv_forw_packet *
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/random.h> #include <linux/random.h>
...@@ -803,11 +804,6 @@ static int batadv_softif_init_late(struct net_device *dev) ...@@ -803,11 +804,6 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->distributed_arp_table, 1); atomic_set(&bat_priv->distributed_arp_table, 1);
#endif #endif
#ifdef CONFIG_BATMAN_ADV_MCAST #ifdef CONFIG_BATMAN_ADV_MCAST
bat_priv->mcast.querier_ipv4.exists = false;
bat_priv->mcast.querier_ipv4.shadowing = false;
bat_priv->mcast.querier_ipv6.exists = false;
bat_priv->mcast.querier_ipv6.shadowing = false;
bat_priv->mcast.flags = BATADV_NO_FLAGS;
atomic_set(&bat_priv->multicast_mode, 1); atomic_set(&bat_priv->multicast_mode, 1);
atomic_set(&bat_priv->multicast_fanout, 16); atomic_set(&bat_priv->multicast_fanout, 16);
atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
......
...@@ -9,13 +9,12 @@ ...@@ -9,13 +9,12 @@
#include "main.h" #include "main.h"
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
#include <net/net_namespace.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
struct net_device;
struct net;
struct sk_buff;
int batadv_skb_head_push(struct sk_buff *skb, unsigned int len); int batadv_skb_head_push(struct sk_buff *skb, unsigned int len);
void batadv_interface_rx(struct net_device *soft_iface, void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, int hdr_size, struct sk_buff *skb, int hdr_size,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/limits.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/printk.h> #include <linux/printk.h>
#include <linux/rculist.h> #include <linux/rculist.h>
......
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
#include "main.h" #include "main.h"
#include <linux/kobject.h>
#include <linux/netdevice.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/types.h> #include <linux/types.h>
struct kobject;
struct net_device;
#define BATADV_SYSFS_IF_MESH_SUBDIR "mesh" #define BATADV_SYSFS_IF_MESH_SUBDIR "mesh"
#define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv" #define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv"
/** /**
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/limits.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/param.h> #include <linux/param.h>
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
#include "main.h" #include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct sk_buff;
void batadv_tp_meter_init(void); void batadv_tp_meter_init(void);
void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie); u32 test_length, u32 *cookie);
......
...@@ -9,13 +9,12 @@ ...@@ -9,13 +9,12 @@
#include "main.h" #include "main.h"
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h> #include <linux/types.h>
struct netlink_callback;
struct net_device;
struct seq_file;
struct sk_buff;
int batadv_tt_init(struct batadv_priv *bat_priv); int batadv_tt_init(struct batadv_priv *bat_priv);
bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
unsigned short vid, int ifindex, u32 mark); unsigned short vid, int ifindex, u32 mark);
......
...@@ -10,8 +10,7 @@ ...@@ -10,8 +10,7 @@
#include "main.h" #include "main.h"
#include <linux/types.h> #include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
struct batadv_ogm_packet;
void batadv_tvlv_container_register(struct batadv_priv *bat_priv, void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
u8 type, u8 version, u8 type, u8 version,
......
...@@ -14,20 +14,22 @@ ...@@ -14,20 +14,22 @@
#include <linux/average.h> #include <linux/average.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/if.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/kref.h> #include <linux/kref.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/sched.h> /* for linux/wait.h */ #include <linux/sched.h> /* for linux/wait.h */
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <uapi/linux/batadv_packet.h> #include <uapi/linux/batadv_packet.h>
#include <uapi/linux/batman_adv.h> #include <uapi/linux/batman_adv.h>
struct seq_file;
#ifdef CONFIG_BATMAN_ADV_DAT #ifdef CONFIG_BATMAN_ADV_DAT
/** /**
...@@ -402,6 +404,17 @@ struct batadv_orig_node { ...@@ -402,6 +404,17 @@ struct batadv_orig_node {
* list * list
*/ */
struct hlist_node mcast_want_all_ipv6_node; struct hlist_node mcast_want_all_ipv6_node;
/**
* @mcast_want_all_rtr4_node: a list node for the mcast.want_all_rtr4
* list
*/
struct hlist_node mcast_want_all_rtr4_node;
/**
* @mcast_want_all_rtr6_node: a list node for the mcast.want_all_rtr6
* list
*/
struct hlist_node mcast_want_all_rtr6_node;
#endif #endif
/** @capabilities: announced capabilities of this originator */ /** @capabilities: announced capabilities of this originator */
...@@ -1168,6 +1181,26 @@ struct batadv_mcast_querier_state { ...@@ -1168,6 +1181,26 @@ struct batadv_mcast_querier_state {
unsigned char shadowing:1; unsigned char shadowing:1;
}; };
/**
* struct batadv_mcast_mla_flags - flags for the querier, bridge and tvlv state
*/
struct batadv_mcast_mla_flags {
/** @querier_ipv4: the current state of an IGMP querier in the mesh */
struct batadv_mcast_querier_state querier_ipv4;
/** @querier_ipv6: the current state of an MLD querier in the mesh */
struct batadv_mcast_querier_state querier_ipv6;
/** @enabled: whether the multicast tvlv is currently enabled */
unsigned char enabled:1;
/** @bridged: whether the soft interface has a bridge on top */
unsigned char bridged:1;
/** @tvlv_flags: the flags we have last sent in our mcast tvlv */
u8 tvlv_flags;
};
/** /**
* struct batadv_priv_mcast - per mesh interface mcast data * struct batadv_priv_mcast - per mesh interface mcast data
*/ */
...@@ -1196,20 +1229,22 @@ struct batadv_priv_mcast { ...@@ -1196,20 +1229,22 @@ struct batadv_priv_mcast {
*/ */
struct hlist_head want_all_ipv6_list; struct hlist_head want_all_ipv6_list;
/** @querier_ipv4: the current state of an IGMP querier in the mesh */ /**
struct batadv_mcast_querier_state querier_ipv4; * @want_all_rtr4_list: a list of orig_nodes wanting all routable IPv4
* multicast traffic
/** @querier_ipv6: the current state of an MLD querier in the mesh */ */
struct batadv_mcast_querier_state querier_ipv6; struct hlist_head want_all_rtr4_list;
/** @flags: the flags we have last sent in our mcast tvlv */
u8 flags;
/** @enabled: whether the multicast tvlv is currently enabled */ /**
unsigned char enabled:1; * @want_all_rtr6_list: a list of orig_nodes wanting all routable IPv6
* multicast traffic
*/
struct hlist_head want_all_rtr6_list;
/** @bridged: whether the soft interface has a bridge on top */ /**
unsigned char bridged:1; * @mla_flags: flags for the querier, bridge and tvlv state
*/
struct batadv_mcast_mla_flags mla_flags;
/** /**
* @mla_lock: a lock protecting mla_list and mla_flags * @mla_lock: a lock protecting mla_list and mla_flags
...@@ -1228,6 +1263,12 @@ struct batadv_priv_mcast { ...@@ -1228,6 +1263,12 @@ struct batadv_priv_mcast {
/** @num_want_all_ipv6: counter for items in want_all_ipv6_list */ /** @num_want_all_ipv6: counter for items in want_all_ipv6_list */
atomic_t num_want_all_ipv6; atomic_t num_want_all_ipv6;
/** @num_want_all_rtr4: counter for items in want_all_rtr4_list */
atomic_t num_want_all_rtr4;
/** @num_want_all_rtr6: counter for items in want_all_rtr6_list */
atomic_t num_want_all_rtr6;
/** /**
* @want_lists_lock: lock for protecting modifications to mcasts * @want_lists_lock: lock for protecting modifications to mcasts
* want_all_{unsnoopables,ipv4,ipv6}_list (traversals are rcu-locked) * want_all_{unsnoopables,ipv4,ipv6}_list (traversals are rcu-locked)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment