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 {
* @BATADV_MCAST_WANT_ALL_UNSNOOPABLES: we want all packets destined for
* 224.0.0.0/24 or ff02::1
* @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
* (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 {
BATADV_MCAST_WANT_ALL_UNSNOOPABLES = 1UL << 0,
BATADV_MCAST_WANT_ALL_IPV4 = 1UL << 1,
BATADV_MCAST_WANT_ALL_IPV6 = 1UL << 2,
BATADV_MCAST_WANT_NO_RTR4 = 1UL << 3,
BATADV_MCAST_WANT_NO_RTR6 = 1UL << 4,
};
/* tt data subtypes */
......
......@@ -9,12 +9,11 @@
#include "main.h"
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h>
struct netlink_callback;
struct seq_file;
struct sk_buff;
extern char batadv_routing_algo[];
extern struct list_head batadv_hardif_list;
......
......@@ -21,6 +21,7 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/types.h>
......@@ -41,8 +42,6 @@
#include "netlink.h"
#include "originator.h"
struct sk_buff;
static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
......
......@@ -9,8 +9,8 @@
#include "main.h"
struct sk_buff;
struct work_struct;
#include <linux/skbuff.h>
#include <linux/workqueue.h>
int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
......
......@@ -9,10 +9,9 @@
#include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h>
struct sk_buff;
int batadv_v_ogm_init(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);
......
......@@ -10,14 +10,13 @@
#include "main.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/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
* detect frame sent by bridge loop avoidance
......
......@@ -10,7 +10,6 @@
#include <asm/current.h>
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/export.h>
#include <linux/fs.h>
......@@ -293,31 +292,13 @@ static struct batadv_debuginfo *batadv_hardif_debuginfos[] = {
void batadv_debugfs_init(void)
{
struct batadv_debuginfo **bat_debug;
struct dentry *file;
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;
err:
debugfs_remove_recursive(batadv_debugfs);
batadv_debugfs = NULL;
for (bat_debug = batadv_general_debuginfos; *bat_debug; ++bat_debug)
debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
batadv_debugfs, NULL, &(*bat_debug)->fops);
}
/**
......@@ -333,42 +314,23 @@ void batadv_debugfs_destroy(void)
* batadv_debugfs_add_hardif() - creates the base directory for a hard interface
* in debugfs.
* @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 batadv_debuginfo **bat_debug;
struct dentry *file;
if (!batadv_debugfs)
goto out;
if (net != &init_net)
return 0;
return;
hard_iface->debug_dir = debugfs_create_dir(hard_iface->net_dev->name,
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;
rem_attr:
debugfs_remove_recursive(hard_iface->debug_dir);
hard_iface->debug_dir = NULL;
out:
return -ENOMEM;
for (bat_debug = batadv_hardif_debuginfos; *bat_debug; ++bat_debug)
debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
hard_iface->debug_dir, hard_iface->net_dev,
&(*bat_debug)->fops);
}
/**
......@@ -379,15 +341,12 @@ void batadv_debugfs_rename_hardif(struct batadv_hard_iface *hard_iface)
{
const char *name = hard_iface->net_dev->name;
struct dentry *dir;
struct dentry *d;
dir = hard_iface->debug_dir;
if (!dir)
return;
d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
if (!d)
pr_err("Can't rename debugfs dir to %s\n", name);
debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
}
/**
......@@ -419,44 +378,29 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
struct batadv_priv *bat_priv = netdev_priv(dev);
struct batadv_debuginfo **bat_debug;
struct net *net = dev_net(dev);
struct dentry *file;
if (!batadv_debugfs)
goto out;
if (net != &init_net)
return 0;
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)
goto rem_attr;
batadv_socket_setup(bat_priv);
if (batadv_debug_log_setup(bat_priv) < 0)
goto rem_attr;
for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug) {
file = debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
bat_priv->debug_dir,
dev, &(*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;
}
}
for (bat_debug = batadv_mesh_debuginfos; *bat_debug; ++bat_debug)
debugfs_create_file(((*bat_debug)->attr).name,
S_IFREG | ((*bat_debug)->attr).mode,
bat_priv->debug_dir, dev,
&(*bat_debug)->fops);
if (batadv_nc_init_debugfs(bat_priv) < 0)
goto rem_attr;
batadv_nc_init_debugfs(bat_priv);
return 0;
rem_attr:
debugfs_remove_recursive(bat_priv->debug_dir);
bat_priv->debug_dir = NULL;
out:
return -ENOMEM;
}
......@@ -469,15 +413,12 @@ void batadv_debugfs_rename_meshif(struct net_device *dev)
struct batadv_priv *bat_priv = netdev_priv(dev);
const char *name = dev->name;
struct dentry *dir;
struct dentry *d;
dir = bat_priv->debug_dir;
if (!dir)
return;
d = debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
if (!d)
pr_err("Can't rename debugfs dir to %s\n", name);
debugfs_rename(dir->d_parent, dir, dir->d_parent, name);
}
/**
......
......@@ -9,8 +9,8 @@
#include "main.h"
struct file;
struct net_device;
#include <linux/fs.h>
#include <linux/netdevice.h>
#define BATADV_DEBUGFS_SUBDIR "batman_adv"
......@@ -22,7 +22,7 @@ void batadv_debugfs_destroy(void);
int batadv_debugfs_add_meshif(struct net_device *dev);
void batadv_debugfs_rename_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_del_hardif(struct batadv_hard_iface *hard_iface);
......@@ -54,9 +54,8 @@ static inline void batadv_debugfs_del_meshif(struct net_device *dev)
}
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
......
......@@ -11,15 +11,14 @@
#include <linux/compiler.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
#include "originator.h"
struct netlink_callback;
struct seq_file;
struct sk_buff;
#ifdef CONFIG_BATMAN_ADV_DAT
/* BATADV_DAT_ADDR_MAX - maximum address value in the DHT space */
......
......@@ -11,11 +11,10 @@
#include <linux/compiler.h>
#include <linux/list.h>
#include <linux/skbuff.h>
#include <linux/stddef.h>
#include <linux/types.h>
struct sk_buff;
void batadv_frag_purge_orig(struct batadv_orig_node *orig,
bool (*check_cb)(struct batadv_frag_table_entry *));
bool batadv_frag_skb_fwd(struct sk_buff *skb,
......
......@@ -9,12 +9,11 @@
#include "main.h"
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h>
struct batadv_tvlv_gateway_data;
struct netlink_callback;
struct seq_file;
struct sk_buff;
#include <uapi/linux/batadv_packet.h>
void batadv_gw_check_client_stop(struct batadv_priv *bat_priv);
void batadv_gw_reselect(struct batadv_priv *bat_priv);
......
......@@ -11,6 +11,7 @@
#include <linux/byteorder/generic.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/math64.h>
#include <linux/netdevice.h>
#include <linux/stddef.h>
......
......@@ -9,10 +9,9 @@
#include "main.h"
#include <linux/netdevice.h>
#include <linux/types.h>
struct net_device;
/**
* enum batadv_bandwidth_units - bandwidth unit types
*/
......
......@@ -16,6 +16,7 @@
#include <linux/if_ether.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
......@@ -920,9 +921,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
hard_iface->soft_iface = NULL;
hard_iface->if_status = BATADV_IF_NOT_IN_USE;
ret = batadv_debugfs_add_hardif(hard_iface);
if (ret)
goto free_sysfs;
batadv_debugfs_add_hardif(hard_iface);
INIT_LIST_HEAD(&hard_iface->list);
INIT_HLIST_HEAD(&hard_iface->neigh_list);
......@@ -944,8 +943,6 @@ batadv_hardif_add_interface(struct net_device *net_dev)
return hard_iface;
free_sysfs:
batadv_sysfs_del_hardif(&hard_iface->hardif_obj);
free_if:
kfree(hard_iface);
release_dev:
......
......@@ -11,13 +11,12 @@
#include <linux/compiler.h>
#include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/notifier.h>
#include <linux/rcupdate.h>
#include <linux/stddef.h>
#include <linux/types.h>
struct net_device;
struct net;
#include <net/net_namespace.h>
/**
* enum batadv_hard_if_state - State of a hard interface
......
......@@ -12,13 +12,12 @@
#include <linux/atomic.h>
#include <linux/compiler.h>
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/rculist.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/types.h>
struct lock_class_key;
/* callback to a compare function. should compare 2 element datas for their
* keys
*
......
......@@ -314,25 +314,11 @@ static const struct file_operations batadv_fops = {
/**
* batadv_socket_setup() - Create debugfs "socket" file
* @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;
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;
debugfs_create_file(BATADV_ICMP_SOCKET, 0600, bat_priv->debug_dir,
bat_priv, &batadv_fops);
}
/**
......
......@@ -10,12 +10,11 @@
#include "main.h"
#include <linux/types.h>
struct batadv_icmp_header;
#include <uapi/linux/batadv_packet.h>
#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
......
......@@ -190,27 +190,16 @@ static const struct file_operations batadv_log_fops = {
*/
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);
if (!bat_priv->debug_log)
goto err;
return -ENOMEM;
spin_lock_init(&bat_priv->debug_log->lock);
init_waitqueue_head(&bat_priv->debug_log->queue_wait);
d = debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
&batadv_log_fops);
if (!d)
goto err;
debugfs_create_file("log", 0400, bat_priv->debug_dir, bat_priv,
&batadv_log_fops);
return 0;
err:
return -ENOMEM;
}
/**
......
......@@ -9,6 +9,7 @@
#include "main.h"
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/printk.h>
......
......@@ -13,7 +13,7 @@
#define BATADV_DRIVER_DEVICE "batman-adv"
#ifndef BATADV_SOURCE_VERSION
#define BATADV_SOURCE_VERSION "2019.2"
#define BATADV_SOURCE_VERSION "2019.3"
#endif
/* B.A.T.M.A.N. parameters */
......@@ -205,20 +205,20 @@ enum batadv_uev_type {
/* Kernel headers */
#include <linux/atomic.h>
#include <linux/compiler.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <linux/jiffies.h>
#include <linux/netdevice.h>
#include <linux/percpu.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
#include "types.h"
struct net_device;
struct packet_type;
struct seq_file;
struct sk_buff;
#include "main.h"
/**
* batadv_print_vid() - return printable version of vid information
......
......@@ -20,6 +20,7 @@
#include <linux/igmp.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/inetdevice.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/jiffies.h>
......@@ -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
* @addr: the MAC address to check
* batadv_mcast_mla_rtr_flags_softif_get_ipv4() - get mcast router flags from
* node for IPv4
* @dev: the interface to check
*
* Return: True, if MAC address is one reserved for IPv4 multicast, false
* otherwise.
* Checks the presence of an IPv4 multicast router on this node.
*
* 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
* @addr: the MAC address to check
* batadv_mcast_mla_rtr_flags_softif_get_ipv6() - get mcast router flags from
* node for IPv6
* @dev: the interface to check
*
* Return: True, if MAC address is one reserved for IPv6 multicast, false
* otherwise.
* Checks the presence of an IPv6 multicast router on this node.
*
* 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
* @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
* @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
* 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 int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv,
struct net_device *dev,
struct hlist_head *mcast_list)
static int
batadv_mcast_mla_softif_get_ipv4(struct net_device *dev,
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 in_device *in_dev;
u8 mcast_addr[ETH_ALEN];
struct ip_mc_list *pmc;
int ret = 0;
netif_addr_lock_bh(bridge ? bridge : dev);
netdev_for_each_mc_addr(mc_list_entry, bridge ? bridge : dev) {
if (all_ipv4 && batadv_mcast_addr_is_ipv4(mc_list_entry->addr))
if (flags->tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
return 0;
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;
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;
new = kmalloc(sizeof(*new), GFP_ATOMIC);
......@@ -169,36 +408,142 @@ static int batadv_mcast_mla_softif_get(struct batadv_priv *bat_priv,
break;
}
ether_addr_copy(new->addr, mc_list_entry->addr);
ether_addr_copy(new->addr, mcast_addr);
hlist_add_head(&new->list, mcast_list);
ret++;
}
netif_addr_unlock_bh(bridge ? bridge : dev);
rcu_read_unlock();
if (bridge)
dev_put(bridge);
return ret;
}
/**
* 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;
}
#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
* @mcast_addr: the multicast address to check
* @mcast_list: the list with multicast addresses to search in
* batadv_mcast_mla_softif_get() - get softif 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
*
* Return: true if the given address is already in the given list.
* Otherwise returns false.
* Collects multicast addresses of 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.
*
* 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,
struct hlist_head *mcast_list)
static int
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 (batadv_compare_eth(mcast_entry->addr, mcast_addr))
return true;
if (bridge)
dev = bridge;
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)
/**
* 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
* @mcast_list: a list to put found addresses into
* @flags: flags indicating the new multicast state
*
* Collects multicast addresses of multicast listeners residing
* 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)
* Return: -ENOMEM on memory allocation error or the number of
* items added to the mcast_list otherwise.
*/
static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv,
struct net_device *dev,
struct hlist_head *mcast_list)
static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
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;
u8 tvlv_flags = flags->tvlv_flags;
struct batadv_hw_addr *new;
u8 mcast_addr[ETH_ALEN];
int ret;
......@@ -259,11 +603,34 @@ static int batadv_mcast_mla_bridge_get(struct batadv_priv *bat_priv,
goto out;
list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
if (all_ipv4 && br_ip_entry->addr.proto == htons(ETH_P_IP))
continue;
if (br_ip_entry->addr.proto == htons(ETH_P_IP)) {
if (tvlv_flags & BATADV_MCAST_WANT_ALL_IPV4)
continue;
if (all_ipv6 && br_ip_entry->addr.proto == htons(ETH_P_IPV6))
continue;
if (tvlv_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
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);
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,
}
}
/**
* 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
* link
......@@ -424,7 +770,7 @@ batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
batadv_info(bat_priv->soft_iface,
"%s Querier disappeared - multicast optimizations disabled\n",
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,
"No %s Querier present - multicast optimizations disabled\n",
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
* setups
* @bat_priv: the bat priv with all the soft interface information
* @bridged: a flag about whether the soft interface is currently bridged or not
* @querier_ipv4: (maybe) new status of a potential, selected IGMP querier
* @querier_ipv6: (maybe) new status of a potential, selected MLD querier
* @new_flags: flags indicating the new multicast state
*
* 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,
* multicast flags this node is going to set.
*/
static void
batadv_mcast_bridge_log(struct batadv_priv *bat_priv, bool bridged,
struct batadv_mcast_querier_state *querier_ipv4,
struct batadv_mcast_querier_state *querier_ipv6)
batadv_mcast_bridge_log(struct batadv_priv *bat_priv,
struct batadv_mcast_mla_flags *new_flags)
{
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,
"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,
"Bridge removed: Unsetting Unsnoopables(U)-flag\n");
if (bridged) {
if (new_flags->bridged) {
batadv_mcast_querier_log(bat_priv, "IGMP",
&bat_priv->mcast.querier_ipv4,
querier_ipv4);
&old_flags->querier_ipv4,
&new_flags->querier_ipv4);
batadv_mcast_querier_log(bat_priv, "MLD",
&bat_priv->mcast.querier_ipv6,
querier_ipv6);
&old_flags->querier_ipv6,
&new_flags->querier_ipv6);
}
}
/**
* batadv_mcast_flags_logs() - output debug information about mcast flag changes
* @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.
* bat_priv->mcast.flags), this notifies userspace via the 'mcast' log level.
* Whenever the multicast TVLV flags this nodes announces change this notifies
* userspace via the 'mcast' log level.
*/
static void batadv_mcast_flags_log(struct batadv_priv *bat_priv, u8 flags)
{
u8 old_flags = bat_priv->mcast.flags;
char str_old_flags[] = "[...]";
bool old_enabled = bat_priv->mcast.mla_flags.enabled;
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_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,
"Changing multicast flags from '%s' to '[%c%c%c]'\n",
bat_priv->mcast.enabled ? str_old_flags : "<undefined>",
"Changing multicast flags from '%s' to '[%c%c%c%s%s]'\n",
old_enabled ? str_old_flags : "<undefined>",
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
(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
* @flags: flags indicating the new multicast state
*
* Updates the own multicast tvlv with our current multicast related settings,
* 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_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;
memset(mcast_data.reserved, 0, sizeof(mcast_data.reserved));
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;
if (!memcmp(flags, &bat_priv->mcast.mla_flags, sizeof(*flags)))
return;
bat_priv->mcast.querier_ipv6.exists = querier6.exists;
bat_priv->mcast.querier_ipv6.shadowing = querier6.shadowing;
batadv_mcast_bridge_log(bat_priv, flags);
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 ||
mcast_data.flags != bat_priv->mcast.flags) {
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;
}
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 2,
&mcast_data, sizeof(mcast_data));
return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 &&
mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6);
bat_priv->mcast.mla_flags = *flags;
}
/**
......@@ -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 hlist_head mcast_list = HLIST_HEAD_INIT;
struct batadv_mcast_mla_flags flags;
int ret;
if (!batadv_mcast_mla_tvlv_update(bat_priv))
goto update;
flags = batadv_mcast_mla_flags_get(bat_priv);
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)
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)
goto out;
update:
spin_lock(&bat_priv->mcast.mla_lock);
batadv_mcast_mla_tt_retract(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:
batadv_mcast_mla_list_free(&mcast_list);
......@@ -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);
bat_priv = container_of(priv_mcast, struct batadv_priv, mcast);
spin_lock(&bat_priv->mcast.mla_lock);
__batadv_mcast_mla_update(bat_priv);
spin_unlock(&bat_priv->mcast.mla_lock);
batadv_mcast_start_timer(bat_priv);
}
......@@ -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
* @skb: the IPv4 packet to check
* @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
* mode more optimal than classic flooding.
......@@ -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,
struct sk_buff *skb,
bool *is_unsnoopable)
bool *is_unsnoopable,
int *is_routable)
{
struct iphdr *iphdr;
......@@ -699,16 +1004,13 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
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
* 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;
}
......@@ -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
* @skb: the IPv6 packet to check
* @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
* mode more optimal than classic flooding.
......@@ -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,
struct sk_buff *skb,
bool *is_unsnoopable)
bool *is_unsnoopable,
int *is_routable)
{
struct ipv6hdr *ip6hdr;
......@@ -764,10 +1068,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
ip6hdr = ipv6_hdr(skb);
/* TODO: Implement Multicast Router Discovery (RFC4286),
* then allow scope > link local, too
*/
if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) != IPV6_ADDR_SCOPE_LINKLOCAL)
if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) < IPV6_ADDR_SCOPE_LINKLOCAL)
return -EINVAL;
/* 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,
*/
if (ipv6_addr_is_ll_all_nodes(&ip6hdr->daddr))
*is_unsnoopable = true;
else if (IPV6_ADDR_MC_SCOPE(&ip6hdr->daddr) > IPV6_ADDR_SCOPE_LINKLOCAL)
*is_routable = ETH_P_IPV6;
return 0;
}
......@@ -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
* @skb: the multicast frame to check
* @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
* 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,
*/
static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
struct sk_buff *skb,
bool *is_unsnoopable)
bool *is_unsnoopable,
int *is_routable)
{
struct ethhdr *ethhdr = eth_hdr(skb);
......@@ -802,13 +1107,15 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
switch (ntohs(ethhdr->h_proto)) {
case ETH_P_IP:
return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
is_unsnoopable);
is_unsnoopable,
is_routable);
case ETH_P_IPV6:
if (!IS_ENABLED(CONFIG_IPV6))
return -EINVAL;
return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
is_unsnoopable);
is_unsnoopable,
is_routable);
default:
return -EINVAL;
}
......@@ -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
* IPv6 traffic if it matches an IPv6 packet.
*/
static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
struct ethhdr *ethhdr)
static int batadv_mcast_forw_want_all_ip_count(struct batadv_priv *bat_priv,
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:
return atomic_read(&bat_priv->mcast.num_want_all_ipv4);
return atomic_read(&bat_priv->mcast.num_want_all_rtr4);
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:
/* we shouldn't be here... */
return 0;
}
}
......@@ -959,6 +1289,84 @@ batadv_mcast_forw_unsnoop_node_get(struct batadv_priv *bat_priv)
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
* @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,
bool is_unsnoopable = false;
unsigned int mcast_fanout;
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)
return BATADV_FORW_NONE;
else if (ret < 0)
......@@ -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);
unsnoop_count = !is_unsnoopable ? 0 :
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) {
case 1:
......@@ -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);
else if (unsnoop_count)
*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)
return BATADV_FORW_SINGLE;
......@@ -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
* @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,
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);
return ret;
}
......@@ -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
* @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,
u16 tvlv_value_len)
{
bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
u8 mcast_flags = BATADV_NO_FLAGS;
if (orig_mcast_enabled && tvlv_value &&
tvlv_value_len >= sizeof(mcast_flags))
mcast_flags = *(u8 *)tvlv_value;
u8 mcast_flags;
if (!orig_mcast_enabled) {
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV4;
mcast_flags |= BATADV_MCAST_WANT_ALL_IPV6;
}
mcast_flags = batadv_mcast_tvlv_flags_get(orig_mcast_enabled,
tvlv_value, tvlv_value_len);
spin_lock_bh(&orig->mcast_handler_lock);
......@@ -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_ipv4_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;
spin_unlock_bh(&orig->mcast_handler_lock);
......@@ -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,
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;
bool bridged = bat_priv->mcast.bridged;
bool bridged = mla_flags->bridged;
u8 flags = mla_flags->tvlv_flags;
if (bridged) {
querier4 = bat_priv->mcast.querier_ipv4.exists ? '.' : '4';
querier6 = bat_priv->mcast.querier_ipv6.exists ? '.' : '6';
shadowing4 = bat_priv->mcast.querier_ipv4.shadowing ? '4' : '.';
shadowing6 = bat_priv->mcast.querier_ipv6.shadowing ? '6' : '.';
querier4 = mla_flags->querier_ipv4.exists ? '.' : '4';
querier6 = mla_flags->querier_ipv6.exists ? '.' : '6';
shadowing4 = mla_flags->querier_ipv4.shadowing ? '4' : '.';
shadowing6 = mla_flags->querier_ipv6.shadowing ? '6' : '.';
} else {
querier4 = '?';
querier6 = '?';
......@@ -1433,10 +2077,12 @@ static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv,
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_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, "* No IGMP/MLD Querier [4/6]:\t\t%c/%c\n",
querier4, querier6);
......@@ -1490,13 +2136,17 @@ int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
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)
? 'U' : '.',
(flags & BATADV_MCAST_WANT_ALL_IPV4)
? '4' : '.',
(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();
}
......@@ -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,
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;
if (bat_priv->mcast.bridged) {
if (bat_priv->mcast.mla_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;
if (bat_priv->mcast.querier_ipv6.exists)
if (bat_priv->mcast.mla_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;
if (bat_priv->mcast.querier_ipv6.shadowing)
if (bat_priv->mcast.mla_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)
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_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);
}
......@@ -9,9 +9,9 @@
#include "main.h"
struct netlink_callback;
struct seq_file;
struct sk_buff;
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
/**
* enum batadv_forw_mode - the way a packet should be forwarded as
......
......@@ -21,6 +21,7 @@
#include <linux/if_vlan.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
......@@ -30,6 +31,7 @@
#include <linux/stddef.h>
#include <linux/types.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
#include <net/sock.h>
#include <uapi/linux/batadv_packet.h>
......@@ -49,8 +51,6 @@
#include "tp_meter.h"
#include "translation-table.h"
struct net;
struct genl_family batadv_netlink_family;
/* multicast groups */
......
......@@ -9,11 +9,10 @@
#include "main.h"
#include <linux/netlink.h>
#include <linux/types.h>
#include <net/genetlink.h>
struct nlmsghdr;
void batadv_netlink_register(void);
void batadv_netlink_unregister(void);
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)
/**
* batadv_nc_init_debugfs() - create nc folder and related files in debugfs
* @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);
if (!nc_dir)
goto out;
file = debugfs_create_u8("min_tq", 0644, nc_dir, &bat_priv->nc.min_tq);
if (!file)
goto out;
debugfs_create_u8("min_tq", 0644, nc_dir, &bat_priv->nc.min_tq);
file = debugfs_create_u32("max_fwd_delay", 0644, nc_dir,
&bat_priv->nc.max_fwd_delay);
if (!file)
goto out;
debugfs_create_u32("max_fwd_delay", 0644, nc_dir,
&bat_priv->nc.max_fwd_delay);
file = debugfs_create_u32("max_buffer_time", 0644, nc_dir,
&bat_priv->nc.max_buffer_time);
if (!file)
goto out;
return 0;
out:
return -ENOMEM;
debugfs_create_u32("max_buffer_time", 0644, nc_dir,
&bat_priv->nc.max_buffer_time);
}
#endif
......@@ -9,12 +9,11 @@
#include "main.h"
#include <linux/netdevice.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/types.h>
struct batadv_ogm_packet;
struct net_device;
struct seq_file;
struct sk_buff;
#include <uapi/linux/batadv_packet.h>
#ifdef CONFIG_BATMAN_ADV_NC
......@@ -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,
struct sk_buff *skb);
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 */
......@@ -111,9 +110,8 @@ static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
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 */
......
......@@ -27,6 +27,7 @@
#include <linux/stddef.h>
#include <linux/workqueue.h>
#include <net/sock.h>
#include <uapi/linux/batadv_packet.h>
#include <uapi/linux/batman_adv.h>
#include "bat_algo.h"
......@@ -1043,7 +1044,8 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
orig_node->bcast_seqno_reset = reset_time;
#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_ipv4_node);
INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node);
......
......@@ -12,12 +12,11 @@
#include <linux/compiler.h>
#include <linux/if_ether.h>
#include <linux/jhash.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.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);
int batadv_originator_init(struct batadv_priv *bat_priv);
void batadv_originator_free(struct batadv_priv *bat_priv);
......
......@@ -9,10 +9,9 @@
#include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h>
struct sk_buff;
bool batadv_check_management_packet(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface,
int header_len);
......
......@@ -10,12 +10,11 @@
#include "main.h"
#include <linux/compiler.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
struct sk_buff;
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet,
bool dropped);
struct batadv_forw_packet *
......
......@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/lockdep.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/percpu.h>
#include <linux/printk.h>
#include <linux/random.h>
......@@ -803,11 +804,6 @@ static int batadv_softif_init_late(struct net_device *dev)
atomic_set(&bat_priv->distributed_arp_table, 1);
#endif
#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_fanout, 16);
atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0);
......
......@@ -9,13 +9,12 @@
#include "main.h"
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <net/net_namespace.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);
void batadv_interface_rx(struct net_device *soft_iface,
struct sk_buff *skb, int hdr_size,
......
......@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/kref.h>
#include <linux/limits.h>
#include <linux/netdevice.h>
#include <linux/printk.h>
#include <linux/rculist.h>
......
......@@ -9,12 +9,11 @@
#include "main.h"
#include <linux/kobject.h>
#include <linux/netdevice.h>
#include <linux/sysfs.h>
#include <linux/types.h>
struct kobject;
struct net_device;
#define BATADV_SYSFS_IF_MESH_SUBDIR "mesh"
#define BATADV_SYSFS_IF_BAT_SUBDIR "batman_adv"
/**
......
......@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/param.h>
......
......@@ -9,10 +9,9 @@
#include "main.h"
#include <linux/skbuff.h>
#include <linux/types.h>
struct sk_buff;
void batadv_tp_meter_init(void);
void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
u32 test_length, u32 *cookie);
......
......@@ -9,13 +9,12 @@
#include "main.h"
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/seq_file.h>
#include <linux/skbuff.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);
bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
unsigned short vid, int ifindex, u32 mark);
......
......@@ -10,8 +10,7 @@
#include "main.h"
#include <linux/types.h>
struct batadv_ogm_packet;
#include <uapi/linux/batadv_packet.h>
void batadv_tvlv_container_register(struct batadv_priv *bat_priv,
u8 type, u8 version,
......
......@@ -14,20 +14,22 @@
#include <linux/average.h>
#include <linux/bitops.h>
#include <linux/compiler.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/sched.h> /* for linux/wait.h */
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <uapi/linux/batadv_packet.h>
#include <uapi/linux/batman_adv.h>
struct seq_file;
#ifdef CONFIG_BATMAN_ADV_DAT
/**
......@@ -402,6 +404,17 @@ struct batadv_orig_node {
* list
*/
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
/** @capabilities: announced capabilities of this originator */
......@@ -1168,6 +1181,26 @@ struct batadv_mcast_querier_state {
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
*/
......@@ -1196,20 +1229,22 @@ struct batadv_priv_mcast {
*/
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;
/** @querier_ipv6: the current state of an MLD querier in the mesh */
struct batadv_mcast_querier_state querier_ipv6;
/** @flags: the flags we have last sent in our mcast tvlv */
u8 flags;
/**
* @want_all_rtr4_list: a list of orig_nodes wanting all routable IPv4
* multicast traffic
*/
struct hlist_head want_all_rtr4_list;
/** @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
......@@ -1228,6 +1263,12 @@ struct batadv_priv_mcast {
/** @num_want_all_ipv6: counter for items in want_all_ipv6_list */
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_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