This feature patchset includes the following changes:
- two patches with minimal clean up work by Antonio Quartulli and Simon Wunderlich - eight patches of B.A.T.M.A.N. V, API and documentation clean up work, by Antonio Quartulli and Marek Lindner - Andrew Lunn fixed the skb priority adoption when forwarding fragmented packets (two patches) - Multicast optimization support is now enabled for bridges which comes with some protocol updates, by Linus Luessing -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCgAGBQJXdmhpAAoJEKEr45hCkp6h/R0P/1K0mZjs1lk15j1oc0EeE/lJ a47nwLQiAj9O790SUhQuonUYtbw5jhxZq5P1zYvg44ngRdUhsH9yiwr+Yado40CW 5ek+EdfGfkwNThGG++knVrbhLPrGxSC9Q2qJCApergt4wViWvvovSJOZsKVcanei Qv9uGn6TIhZW3FFhvYk6/xgseZhjRISgxPkO1N20tMcC3f0w4YgM5QcCPGG2KB3N CYq1qryyl4Jf6NeNap/lXiTo6JA5qOHYe68ziotJTtlsrsYQ3WitJvuKO+bWuQIv zOU/jQ7qUwuabLT5TnzZKxQJvhrqfA5V20OM3yD4lnhdgvqVsHgHoIRy6RpN4U8M rFlgROZvm+k0ATnL8AcUtIY7EA/EA0ifHN2fdTAfQ0XNc0VxTXEWB4qTTBJu3+se N0+QyIjpXzgHqKxjIpr8Sm3tBO/ANCui/gWl5SToGXis3xDsRivvTMWNSNYjgDcP WdyLtx9h7RLNOh64Idwsq4yDHt+/P86z7xJQdlkmrshkjqL/HNgS93U5CeAC3mN0 S6N5PgZG07EYnGxzxDid+6x1UP1VA7dyqHJpxpYY7qbw+/aDVlq5XH/vI/9Lbq5i vu/54L8cVG5nBe54SZBeUib5W7Wkgf3POWzt+rrRwbHY+gAE1zUPQNNzgDtLHH0N K/XJwdcoGQzA5LEynGE7 =js/J -----END PGP SIGNATURE----- Merge tag 'batadv-next-for-davem-20160701' of git://git.open-mesh.org/linux-merge Simon Wunderlich says: ==================== This feature patchset includes the following changes: - two patches with minimal clean up work by Antonio Quartulli and Simon Wunderlich - eight patches of B.A.T.M.A.N. V, API and documentation clean up work, by Antonio Quartulli and Marek Lindner - Andrew Lunn fixed the skb priority adoption when forwarding fragmented packets (two patches) - Multicast optimization support is now enabled for bridges which comes with some protocol updates, by Linus Luessing ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3ea00443f1
|
@ -1,19 +1,10 @@
|
|||
|
||||
What: /sys/class/net/<iface>/batman-adv/throughput_override
|
||||
Date: Feb 2014
|
||||
Contact: Antonio Quartulli <antonio@meshcoding.com>
|
||||
description:
|
||||
Defines the throughput value to be used by B.A.T.M.A.N. V
|
||||
when estimating the link throughput using this interface.
|
||||
If the value is set to 0 then batman-adv will try to
|
||||
estimate the throughput by itself.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/elp_interval
|
||||
Date: Feb 2014
|
||||
Contact: Linus Lüssing <linus.luessing@web.de>
|
||||
Description:
|
||||
Defines the interval in milliseconds in which batman
|
||||
sends its probing packets for link quality measurements.
|
||||
emits probing packets for neighbor sensing (ELP).
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/iface_status
|
||||
Date: May 2010
|
||||
|
@ -28,3 +19,12 @@ Description:
|
|||
The /sys/class/net/<iface>/batman-adv/mesh_iface file
|
||||
displays the batman mesh interface this <iface>
|
||||
currently is associated with.
|
||||
|
||||
What: /sys/class/net/<iface>/batman-adv/throughput_override
|
||||
Date: Feb 2014
|
||||
Contact: Antonio Quartulli <a@unstable.cc>
|
||||
description:
|
||||
Defines the throughput value to be used by B.A.T.M.A.N. V
|
||||
when estimating the link throughput using this interface.
|
||||
If the value is set to 0 then batman-adv will try to
|
||||
estimate the throughput by itself.
|
||||
|
|
|
@ -66,7 +66,7 @@ config BATMAN_ADV_NC
|
|||
|
||||
config BATMAN_ADV_MCAST
|
||||
bool "Multicast optimisation"
|
||||
depends on BATMAN_ADV
|
||||
depends on BATMAN_ADV && INET && !(BRIDGE=m && BATMAN_ADV=y)
|
||||
default n
|
||||
help
|
||||
This option enables the multicast optimisation which aims to
|
||||
|
|
|
@ -18,13 +18,14 @@
|
|||
#ifndef _NET_BATMAN_ADV_BAT_ALGO_H_
|
||||
#define _NET_BATMAN_ADV_BAT_ALGO_H_
|
||||
|
||||
struct batadv_priv;
|
||||
#include "main.h"
|
||||
|
||||
int batadv_iv_init(void);
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
|
||||
|
||||
int batadv_v_init(void);
|
||||
void batadv_v_hardif_init(struct batadv_hard_iface *hardif);
|
||||
int batadv_v_mesh_init(struct batadv_priv *bat_priv);
|
||||
void batadv_v_mesh_free(struct batadv_priv *bat_priv);
|
||||
|
||||
|
@ -35,6 +36,10 @@ static inline int batadv_v_init(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void batadv_v_hardif_init(struct batadv_hard_iface *hardif)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int batadv_v_mesh_init(struct batadv_priv *bat_priv)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/if_ether.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/lockdep.h>
|
||||
|
@ -58,6 +59,8 @@
|
|||
#include "send.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work);
|
||||
|
||||
/**
|
||||
* enum batadv_dup_status - duplicate status
|
||||
* @BATADV_NO_DUP: the packet is no duplicate
|
||||
|
@ -336,7 +339,8 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
|
|||
{
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
|
||||
neigh_node = batadv_neigh_node_new(orig_node, hard_iface, neigh_addr);
|
||||
neigh_node = batadv_neigh_node_get_or_create(orig_node,
|
||||
hard_iface, neigh_addr);
|
||||
if (!neigh_node)
|
||||
goto out;
|
||||
|
||||
|
@ -730,7 +734,7 @@ static void batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff,
|
|||
|
||||
/* start timer for this packet */
|
||||
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
|
||||
batadv_send_outstanding_bat_ogm_packet);
|
||||
batadv_iv_send_outstanding_bat_ogm_packet);
|
||||
queue_delayed_work(batadv_event_workqueue,
|
||||
&forw_packet_aggr->delayed_work,
|
||||
send_time - jiffies);
|
||||
|
@ -937,6 +941,19 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
|||
u16 tvlv_len = 0;
|
||||
unsigned long send_time;
|
||||
|
||||
if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
|
||||
(hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
|
||||
return;
|
||||
|
||||
/* the interface gets activated here to avoid race conditions between
|
||||
* the moment of activating the interface in
|
||||
* hardif_activate_interface() where the originator mac is set and
|
||||
* outdated packets (especially uninitialized mac addresses) in the
|
||||
* packet queue
|
||||
*/
|
||||
if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
|
||||
hard_iface->if_status = BATADV_IF_ACTIVE;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
|
||||
if (hard_iface == primary_if) {
|
||||
|
@ -1778,6 +1795,45 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
|
|||
batadv_orig_node_put(orig_node);
|
||||
}
|
||||
|
||||
static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work;
|
||||
struct batadv_forw_packet *forw_packet;
|
||||
struct batadv_priv *bat_priv;
|
||||
|
||||
delayed_work = to_delayed_work(work);
|
||||
forw_packet = container_of(delayed_work, struct batadv_forw_packet,
|
||||
delayed_work);
|
||||
bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
|
||||
spin_lock_bh(&bat_priv->forw_bat_list_lock);
|
||||
hlist_del(&forw_packet->list);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
||||
goto out;
|
||||
|
||||
batadv_iv_ogm_emit(forw_packet);
|
||||
|
||||
/* we have to have at least one packet in the queue to determine the
|
||||
* queues wake up time unless we are shutting down.
|
||||
*
|
||||
* only re-schedule if this is the "original" copy, e.g. the OGM of the
|
||||
* primary interface should only be rescheduled once per period, but
|
||||
* this function will be called for the forw_packet instances of the
|
||||
* other secondary interfaces as well.
|
||||
*/
|
||||
if (forw_packet->own &&
|
||||
forw_packet->if_incoming == forw_packet->if_outgoing)
|
||||
batadv_iv_ogm_schedule(forw_packet->if_incoming);
|
||||
|
||||
out:
|
||||
/* don't count own packet */
|
||||
if (!forw_packet->own)
|
||||
atomic_inc(&bat_priv->batman_queue_left);
|
||||
|
||||
batadv_forw_packet_free(forw_packet);
|
||||
}
|
||||
|
||||
static int batadv_iv_ogm_receive(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *if_incoming)
|
||||
{
|
||||
|
@ -1794,7 +1850,8 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb,
|
|||
/* did we receive a B.A.T.M.A.N. IV OGM packet on an interface
|
||||
* that does not have B.A.T.M.A.N. IV enabled ?
|
||||
*/
|
||||
if (bat_priv->bat_algo_ops->bat_ogm_emit != batadv_iv_ogm_emit)
|
||||
if (bat_priv->bat_algo_ops->bat_iface_enable !=
|
||||
batadv_iv_ogm_iface_enable)
|
||||
return NET_RX_DROP;
|
||||
|
||||
batadv_inc_counter(bat_priv, BATADV_CNT_MGMT_RX);
|
||||
|
@ -2052,14 +2109,19 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void batadv_iv_iface_activate(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
/* begin scheduling originator messages on that interface */
|
||||
batadv_iv_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
||||
static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
|
||||
.name = "BATMAN_IV",
|
||||
.bat_iface_activate = batadv_iv_iface_activate,
|
||||
.bat_iface_enable = batadv_iv_ogm_iface_enable,
|
||||
.bat_iface_disable = batadv_iv_ogm_iface_disable,
|
||||
.bat_iface_update_mac = batadv_iv_ogm_iface_update_mac,
|
||||
.bat_primary_iface_set = batadv_iv_ogm_primary_iface_set,
|
||||
.bat_ogm_schedule = batadv_iv_ogm_schedule,
|
||||
.bat_ogm_emit = batadv_iv_ogm_emit,
|
||||
.bat_neigh_cmp = batadv_iv_ogm_neigh_cmp,
|
||||
.bat_neigh_is_similar_or_better = batadv_iv_ogm_neigh_is_sob,
|
||||
.bat_neigh_print = batadv_iv_neigh_print,
|
||||
|
|
|
@ -70,11 +70,6 @@ static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
|
|||
if (ret < 0)
|
||||
batadv_v_elp_iface_disable(hard_iface);
|
||||
|
||||
/* enable link throughput auto-detection by setting the throughput
|
||||
* override to zero
|
||||
*/
|
||||
atomic_set(&hard_iface->bat_v.throughput_override, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -119,14 +114,6 @@ batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
|
|||
batadv_v_elp_throughput_metric_update);
|
||||
}
|
||||
|
||||
static void batadv_v_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
}
|
||||
|
||||
static void batadv_v_ogm_emit(struct batadv_forw_packet *forw_packet)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_orig_print_neigh - print neighbors for the originator table
|
||||
* @orig_node: the orig_node for which the neighbors are printed
|
||||
|
@ -340,14 +327,26 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
|
|||
.bat_iface_update_mac = batadv_v_iface_update_mac,
|
||||
.bat_primary_iface_set = batadv_v_primary_iface_set,
|
||||
.bat_hardif_neigh_init = batadv_v_hardif_neigh_init,
|
||||
.bat_ogm_emit = batadv_v_ogm_emit,
|
||||
.bat_ogm_schedule = batadv_v_ogm_schedule,
|
||||
.bat_orig_print = batadv_v_orig_print,
|
||||
.bat_neigh_cmp = batadv_v_neigh_cmp,
|
||||
.bat_neigh_is_similar_or_better = batadv_v_neigh_is_sob,
|
||||
.bat_neigh_print = batadv_v_neigh_print,
|
||||
};
|
||||
|
||||
/**
|
||||
* batadv_v_hardif_init - initialize the algorithm specific fields in the
|
||||
* hard-interface object
|
||||
* @hard_iface: the hard-interface to initialize
|
||||
*/
|
||||
void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
/* enable link throughput auto-detection by setting the throughput
|
||||
* override to zero
|
||||
*/
|
||||
atomic_set(&hard_iface->bat_v.throughput_override, 0);
|
||||
atomic_set(&hard_iface->bat_v.elp_interval, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_mesh_init - initialize the B.A.T.M.A.N. V private resources for a
|
||||
* mesh
|
||||
|
|
|
@ -344,7 +344,6 @@ int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
|
|||
/* randomize initial seqno to avoid collision */
|
||||
get_random_bytes(&random_seqno, sizeof(random_seqno));
|
||||
atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
|
||||
atomic_set(&hard_iface->bat_v.elp_interval, 500);
|
||||
|
||||
/* assume full-duplex by default */
|
||||
hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
|
||||
|
@ -443,7 +442,8 @@ static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
|
|||
if (!orig_neigh)
|
||||
return;
|
||||
|
||||
neigh = batadv_neigh_node_new(orig_neigh, if_incoming, neigh_addr);
|
||||
neigh = batadv_neigh_node_get_or_create(orig_neigh,
|
||||
if_incoming, neigh_addr);
|
||||
if (!neigh)
|
||||
goto orig_free;
|
||||
|
||||
|
|
|
@ -683,8 +683,8 @@ static void batadv_v_ogm_process(const struct sk_buff *skb, int ogm_offset,
|
|||
if (!orig_node)
|
||||
return;
|
||||
|
||||
neigh_node = batadv_neigh_node_new(orig_node, if_incoming,
|
||||
ethhdr->h_source);
|
||||
neigh_node = batadv_neigh_node_get_or_create(orig_node, if_incoming,
|
||||
ethhdr->h_source);
|
||||
if (!neigh_node)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "distributed-arp-table.h"
|
||||
#include "gateway_client.h"
|
||||
#include "icmp_socket.h"
|
||||
#include "multicast.h"
|
||||
#include "network-coding.h"
|
||||
#include "originator.h"
|
||||
#include "translation-table.h"
|
||||
|
@ -363,6 +364,22 @@ static int batadv_nc_nodes_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
/**
|
||||
* batadv_mcast_flags_open - prepare file handler for reads from mcast_flags
|
||||
* @inode: inode which was opened
|
||||
* @file: file handle to be initialized
|
||||
*
|
||||
* Return: 0 on success or negative error number in case of failure
|
||||
*/
|
||||
static int batadv_mcast_flags_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)inode->i_private;
|
||||
|
||||
return single_open(file, batadv_mcast_flags_seq_print_text, net_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BATADV_DEBUGINFO(_name, _mode, _open) \
|
||||
struct batadv_debuginfo batadv_debuginfo_##_name = { \
|
||||
.attr = { \
|
||||
|
@ -407,6 +424,9 @@ static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
|
|||
#ifdef CONFIG_BATMAN_ADV_NC
|
||||
static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
|
||||
#endif
|
||||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
static BATADV_DEBUGINFO(mcast_flags, S_IRUGO, batadv_mcast_flags_open);
|
||||
#endif
|
||||
|
||||
static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
|
||||
&batadv_debuginfo_neighbors,
|
||||
|
@ -423,6 +443,9 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
|
|||
&batadv_debuginfo_transtable_local,
|
||||
#ifdef CONFIG_BATMAN_ADV_NC
|
||||
&batadv_debuginfo_nc_nodes,
|
||||
#endif
|
||||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
&batadv_debuginfo_mcast_flags,
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/pkt_sched.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -414,7 +413,7 @@ static struct sk_buff *batadv_frag_create(struct sk_buff *skb,
|
|||
if (!skb_fragment)
|
||||
goto err;
|
||||
|
||||
skb->priority = TC_PRIO_CONTROL;
|
||||
skb_fragment->priority = skb->priority;
|
||||
|
||||
/* Eat the last mtu-bytes of the skb */
|
||||
skb_reserve(skb_fragment, header_size + ETH_HLEN);
|
||||
|
@ -473,6 +472,15 @@ bool batadv_frag_send_packet(struct sk_buff *skb,
|
|||
frag_header.reserved = 0;
|
||||
frag_header.no = 0;
|
||||
frag_header.total_size = htons(skb->len);
|
||||
|
||||
/* skb->priority values from 256->263 are magic values to
|
||||
* directly indicate a specific 802.1d priority. This is used
|
||||
* to allow 802.1d priority to be passed directly in from VLAN
|
||||
* tags, etc.
|
||||
*/
|
||||
if (skb->priority >= 256 && skb->priority <= 263)
|
||||
frag_header.priority = skb->priority - 256;
|
||||
|
||||
ether_addr_copy(frag_header.orig, primary_if->net_dev->dev_addr);
|
||||
ether_addr_copy(frag_header.dest, orig_node->orig);
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
|
|||
|
||||
tq_avg = router_ifinfo->bat_iv.tq_avg;
|
||||
|
||||
switch (atomic_read(&bat_priv->gw_sel_class)) {
|
||||
switch (atomic_read(&bat_priv->gw.sel_class)) {
|
||||
case 1: /* fast connection */
|
||||
tmp_gw_factor = tq_avg * tq_avg;
|
||||
tmp_gw_factor *= gw_node->bandwidth_down;
|
||||
|
@ -255,7 +255,7 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)
|
|||
{
|
||||
struct batadv_gw_node *curr_gw;
|
||||
|
||||
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
|
||||
if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
|
||||
return;
|
||||
|
||||
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
||||
|
@ -283,7 +283,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
|
|||
struct batadv_neigh_ifinfo *router_ifinfo = NULL;
|
||||
char gw_addr[18] = { '\0' };
|
||||
|
||||
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
|
||||
if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT)
|
||||
goto out;
|
||||
|
||||
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
||||
|
@ -402,8 +402,8 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv,
|
|||
/* if the routing class is greater than 3 the value tells us how much
|
||||
* greater the TQ value of the new gateway must be
|
||||
*/
|
||||
if ((atomic_read(&bat_priv->gw_sel_class) > 3) &&
|
||||
(orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw_sel_class)))
|
||||
if ((atomic_read(&bat_priv->gw.sel_class) > 3) &&
|
||||
(orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class)))
|
||||
goto out;
|
||||
|
||||
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
|
||||
|
@ -638,8 +638,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
|
|||
goto out;
|
||||
|
||||
seq_printf(seq,
|
||||
" %-12s (%s/%i) %17s [%10s]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
|
||||
"Gateway", "#", BATADV_TQ_MAX_VALUE, "Nexthop", "outgoingIF",
|
||||
" Gateway (#/255) Nexthop [outgoingIF]: advertised uplink bandwidth ... [B.A.T.M.A.N. adv %s, MainIF/MAC: %s/%pM (%s)]\n",
|
||||
BATADV_SOURCE_VERSION, primary_if->net_dev->name,
|
||||
primary_if->net_dev->dev_addr, net_dev->name);
|
||||
|
||||
|
@ -821,7 +820,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
|
|||
if (!gw_node)
|
||||
goto out;
|
||||
|
||||
switch (atomic_read(&bat_priv->gw_mode)) {
|
||||
switch (atomic_read(&bat_priv->gw.mode)) {
|
||||
case BATADV_GW_MODE_SERVER:
|
||||
/* If we are a GW then we are our best GW. We can artificially
|
||||
* set the tq towards ourself as the maximum value
|
||||
|
|
|
@ -144,7 +144,7 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv)
|
|||
u32 down, up;
|
||||
char gw_mode;
|
||||
|
||||
gw_mode = atomic_read(&bat_priv->gw_mode);
|
||||
gw_mode = atomic_read(&bat_priv->gw.mode);
|
||||
|
||||
switch (gw_mode) {
|
||||
case BATADV_GW_MODE_OFF:
|
||||
|
@ -241,8 +241,8 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
|
|||
|
||||
/* restart gateway selection if fast or late switching was enabled */
|
||||
if ((gateway.bandwidth_down != 0) &&
|
||||
(atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_CLIENT) &&
|
||||
(atomic_read(&bat_priv->gw_sel_class) > 2))
|
||||
(atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) &&
|
||||
(atomic_read(&bat_priv->gw.sel_class) > 2))
|
||||
batadv_gw_check_election(bat_priv, orig);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "bat_algo.h"
|
||||
#include "bridge_loop_avoidance.h"
|
||||
#include "debugfs.h"
|
||||
#include "distributed-arp-table.h"
|
||||
|
@ -553,9 +554,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
|
|||
|
||||
batadv_hardif_recalc_extra_skbroom(soft_iface);
|
||||
|
||||
/* begin scheduling originator messages on that interface */
|
||||
batadv_schedule_bat_ogm(hard_iface);
|
||||
|
||||
out:
|
||||
return 0;
|
||||
|
||||
|
@ -686,6 +684,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
|
|||
if (batadv_is_wifi_netdev(net_dev))
|
||||
hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
|
||||
|
||||
batadv_v_hardif_init(hard_iface);
|
||||
|
||||
/* extra reference for return */
|
||||
kref_init(&hard_iface->refcount);
|
||||
kref_get(&hard_iface->refcount);
|
||||
|
|
|
@ -569,8 +569,6 @@ int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops)
|
|||
!bat_algo_ops->bat_iface_disable ||
|
||||
!bat_algo_ops->bat_iface_update_mac ||
|
||||
!bat_algo_ops->bat_primary_iface_set ||
|
||||
!bat_algo_ops->bat_ogm_schedule ||
|
||||
!bat_algo_ops->bat_ogm_emit ||
|
||||
!bat_algo_ops->bat_neigh_cmp ||
|
||||
!bat_algo_ops->bat_neigh_is_similar_or_better) {
|
||||
pr_info("Routing algo '%s' does not implement required ops\n",
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#define BATADV_DRIVER_DEVICE "batman-adv"
|
||||
|
||||
#ifndef BATADV_SOURCE_VERSION
|
||||
#define BATADV_SOURCE_VERSION "2016.2"
|
||||
#define BATADV_SOURCE_VERSION "2016.3"
|
||||
#endif
|
||||
|
||||
/* B.A.T.M.A.N. parameters */
|
||||
|
@ -231,6 +231,7 @@ __be32 batadv_skb_crc32(struct sk_buff *skb, u8 *payload_ptr);
|
|||
* @BATADV_DBG_BLA: bridge loop avoidance messages
|
||||
* @BATADV_DBG_DAT: ARP snooping and DAT related messages
|
||||
* @BATADV_DBG_NC: network coding related messages
|
||||
* @BATADV_DBG_MCAST: multicast related messages
|
||||
* @BATADV_DBG_ALL: the union of all the above log levels
|
||||
*/
|
||||
enum batadv_dbg_level {
|
||||
|
@ -240,7 +241,8 @@ enum batadv_dbg_level {
|
|||
BATADV_DBG_BLA = BIT(3),
|
||||
BATADV_DBG_DAT = BIT(4),
|
||||
BATADV_DBG_NC = BIT(5),
|
||||
BATADV_DBG_ALL = 63,
|
||||
BATADV_DBG_MCAST = BIT(6),
|
||||
BATADV_DBG_ALL = 127,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_DEBUG
|
||||
|
|
|
@ -25,17 +25,23 @@
|
|||
#include <linux/errno.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/if_bridge.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/igmp.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
@ -43,18 +49,55 @@
|
|||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/if_inet6.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
#include "hard-interface.h"
|
||||
#include "hash.h"
|
||||
#include "packet.h"
|
||||
#include "translation-table.h"
|
||||
|
||||
/**
|
||||
* batadv_mcast_get_bridge - get the bridge on top of the softif if it exists
|
||||
* @soft_iface: netdev struct of the mesh interface
|
||||
*
|
||||
* If the given soft interface has a bridge on top then the refcount
|
||||
* of the according net device is increased.
|
||||
*
|
||||
* Return: NULL if no such bridge exists. Otherwise the net device of the
|
||||
* bridge.
|
||||
*/
|
||||
static struct net_device *batadv_mcast_get_bridge(struct net_device *soft_iface)
|
||||
{
|
||||
struct net_device *upper = soft_iface;
|
||||
|
||||
rcu_read_lock();
|
||||
do {
|
||||
upper = netdev_master_upper_dev_get_rcu(upper);
|
||||
} while (upper && !(upper->priv_flags & IFF_EBRIDGE));
|
||||
|
||||
if (upper)
|
||||
dev_hold(upper);
|
||||
rcu_read_unlock();
|
||||
|
||||
return upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* Collect multicast addresses of the local multicast listeners
|
||||
* on the given soft interface, dev, in the given mcast_list.
|
||||
* 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.
|
||||
|
@ -62,12 +105,13 @@
|
|||
static int batadv_mcast_mla_softif_get(struct net_device *dev,
|
||||
struct hlist_head *mcast_list)
|
||||
{
|
||||
struct net_device *bridge = batadv_mcast_get_bridge(dev);
|
||||
struct netdev_hw_addr *mc_list_entry;
|
||||
struct batadv_hw_addr *new;
|
||||
int ret = 0;
|
||||
|
||||
netif_addr_lock_bh(dev);
|
||||
netdev_for_each_mc_addr(mc_list_entry, dev) {
|
||||
netif_addr_lock_bh(bridge ? bridge : dev);
|
||||
netdev_for_each_mc_addr(mc_list_entry, bridge ? bridge : dev) {
|
||||
new = kmalloc(sizeof(*new), GFP_ATOMIC);
|
||||
if (!new) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -78,7 +122,10 @@ static int batadv_mcast_mla_softif_get(struct net_device *dev,
|
|||
hlist_add_head(&new->list, mcast_list);
|
||||
ret++;
|
||||
}
|
||||
netif_addr_unlock_bh(dev);
|
||||
netif_addr_unlock_bh(bridge ? bridge : dev);
|
||||
|
||||
if (bridge)
|
||||
dev_put(bridge);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -103,6 +150,83 @@ static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr,
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_mla_br_addr_cpy - copy a bridge multicast address
|
||||
* @dst: destination to write to - a multicast MAC address
|
||||
* @src: source to read from - a multicast IP address
|
||||
*
|
||||
* Converts a given multicast IPv4/IPv6 address from a bridge
|
||||
* to its matching multicast MAC address and copies it into the given
|
||||
* destination buffer.
|
||||
*
|
||||
* Caller needs to make sure the destination buffer can hold
|
||||
* at least ETH_ALEN bytes.
|
||||
*/
|
||||
static void batadv_mcast_mla_br_addr_cpy(char *dst, const struct br_ip *src)
|
||||
{
|
||||
if (src->proto == htons(ETH_P_IP))
|
||||
ip_eth_mc_map(src->u.ip4, dst);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
else if (src->proto == htons(ETH_P_IPV6))
|
||||
ipv6_eth_mc_map(&src->u.ip6, dst);
|
||||
#endif
|
||||
else
|
||||
eth_zero_addr(dst);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_mla_bridge_get - get bridged-in multicast listeners
|
||||
* @dev: a bridge slave whose bridge to collect multicast addresses from
|
||||
* @mcast_list: a list to put found addresses into
|
||||
*
|
||||
* Collects multicast addresses of multicast listeners residing
|
||||
* on foreign, non-mesh devices which we gave access to our mesh via
|
||||
* a bridge on top of the given soft interface, dev, in the given
|
||||
* mcast_list.
|
||||
*
|
||||
* 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 net_device *dev,
|
||||
struct hlist_head *mcast_list)
|
||||
{
|
||||
struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
|
||||
struct br_ip_list *br_ip_entry, *tmp;
|
||||
struct batadv_hw_addr *new;
|
||||
u8 mcast_addr[ETH_ALEN];
|
||||
int ret;
|
||||
|
||||
/* we don't need to detect these devices/listeners, the IGMP/MLD
|
||||
* snooping code of the Linux bridge already does that for us
|
||||
*/
|
||||
ret = br_multicast_list_adjacent(dev, &bridge_mcast_list);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
list_for_each_entry(br_ip_entry, &bridge_mcast_list, list) {
|
||||
batadv_mcast_mla_br_addr_cpy(mcast_addr, &br_ip_entry->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);
|
||||
}
|
||||
|
||||
out:
|
||||
list_for_each_entry_safe(br_ip_entry, tmp, &bridge_mcast_list, list) {
|
||||
list_del(&br_ip_entry->list);
|
||||
kfree(br_ip_entry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_mla_list_free - free a list of multicast addresses
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -213,6 +337,122 @@ static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
|
|||
return upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_querier_log - debug output regarding the querier status on link
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
* @str_proto: a string for the querier protocol (e.g. "IGMP" or "MLD")
|
||||
* @old_state: the previous querier state on our link
|
||||
* @new_state: the new querier state on our link
|
||||
*
|
||||
* Outputs debug messages to the logging facility with log level 'mcast'
|
||||
* regarding changes to the querier status on the link which are relevant
|
||||
* to our multicast optimizations.
|
||||
*
|
||||
* Usually this is about whether a querier appeared or vanished in
|
||||
* our mesh or whether the querier is in the suboptimal position of being
|
||||
* behind our local bridge segment: Snooping switches will directly
|
||||
* forward listener reports to the querier, therefore batman-adv and
|
||||
* the bridge will potentially not see these listeners - the querier is
|
||||
* potentially shadowing listeners from us then.
|
||||
*
|
||||
* This is only interesting for nodes with a bridge on top of their
|
||||
* soft interface.
|
||||
*/
|
||||
static void
|
||||
batadv_mcast_querier_log(struct batadv_priv *bat_priv, char *str_proto,
|
||||
struct batadv_mcast_querier_state *old_state,
|
||||
struct batadv_mcast_querier_state *new_state)
|
||||
{
|
||||
if (!old_state->exists && new_state->exists)
|
||||
batadv_info(bat_priv->soft_iface, "%s Querier appeared\n",
|
||||
str_proto);
|
||||
else if (old_state->exists && !new_state->exists)
|
||||
batadv_info(bat_priv->soft_iface,
|
||||
"%s Querier disappeared - multicast optimizations disabled\n",
|
||||
str_proto);
|
||||
else if (!bat_priv->mcast.bridged && !new_state->exists)
|
||||
batadv_info(bat_priv->soft_iface,
|
||||
"No %s Querier present - multicast optimizations disabled\n",
|
||||
str_proto);
|
||||
|
||||
if (new_state->exists) {
|
||||
if ((!old_state->shadowing && new_state->shadowing) ||
|
||||
(!old_state->exists && new_state->shadowing))
|
||||
batadv_dbg(BATADV_DBG_MCAST, bat_priv,
|
||||
"%s Querier is behind our bridged segment: Might shadow listeners\n",
|
||||
str_proto);
|
||||
else if (old_state->shadowing && !new_state->shadowing)
|
||||
batadv_dbg(BATADV_DBG_MCAST, bat_priv,
|
||||
"%s Querier is not behind our bridged segment\n",
|
||||
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
|
||||
*
|
||||
* If no bridges are ever used on this node, then this function does nothing.
|
||||
*
|
||||
* Otherwise this function outputs debug information to the 'mcast' log level
|
||||
* which might be relevant to our multicast optimizations.
|
||||
*
|
||||
* More precisely, it outputs information when a bridge interface is added or
|
||||
* removed from a soft interface. And when a bridge is present, it further
|
||||
* outputs information about the querier state which is relevant for the
|
||||
* 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)
|
||||
{
|
||||
if (!bat_priv->mcast.bridged && bridged)
|
||||
batadv_dbg(BATADV_DBG_MCAST, bat_priv,
|
||||
"Bridge added: Setting Unsnoopables(U)-flag\n");
|
||||
else if (bat_priv->mcast.bridged && !bridged)
|
||||
batadv_dbg(BATADV_DBG_MCAST, bat_priv,
|
||||
"Bridge removed: Unsetting Unsnoopables(U)-flag\n");
|
||||
|
||||
if (bridged) {
|
||||
batadv_mcast_querier_log(bat_priv, "IGMP",
|
||||
&bat_priv->mcast.querier_ipv4,
|
||||
querier_ipv4);
|
||||
batadv_mcast_querier_log(bat_priv, "MLD",
|
||||
&bat_priv->mcast.querier_ipv6,
|
||||
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
|
||||
*
|
||||
* Whenever the multicast flags this nodes announces changes (@mcast_flags vs.
|
||||
* bat_priv->mcast.flags), 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[] = "[...]";
|
||||
|
||||
sprintf(str_old_flags, "[%c%c%c]",
|
||||
(old_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
|
||||
(old_flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
|
||||
(old_flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.');
|
||||
|
||||
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>",
|
||||
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
|
||||
(flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
|
||||
(flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.');
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_mla_tvlv_update - update multicast tvlv
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -220,38 +460,73 @@ static bool batadv_mcast_has_bridge(struct batadv_priv *bat_priv)
|
|||
* Updates the own multicast tvlv with our current multicast related settings,
|
||||
* capabilities and inabilities.
|
||||
*
|
||||
* Return: true if the tvlv container is registered afterwards. Otherwise
|
||||
* returns false.
|
||||
* 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)
|
||||
{
|
||||
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));
|
||||
|
||||
/* Avoid attaching MLAs, if there is a bridge on top of our soft
|
||||
* interface, we don't support that yet (TODO)
|
||||
*/
|
||||
if (batadv_mcast_has_bridge(bat_priv)) {
|
||||
if (bat_priv->mcast.enabled) {
|
||||
batadv_tvlv_container_unregister(bat_priv,
|
||||
BATADV_TVLV_MCAST, 1);
|
||||
bat_priv->mcast.enabled = false;
|
||||
}
|
||||
bridged = batadv_mcast_has_bridge(bat_priv);
|
||||
if (!bridged)
|
||||
goto update;
|
||||
|
||||
return false;
|
||||
}
|
||||
#if !IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING)
|
||||
pr_warn_once("No bridge IGMP snooping compiled - multicast optimizations disabled\n");
|
||||
#endif
|
||||
|
||||
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;
|
||||
bat_priv->mcast.querier_ipv6.shadowing = querier6.shadowing;
|
||||
|
||||
bat_priv->mcast.bridged = bridged;
|
||||
|
||||
if (!bat_priv->mcast.enabled ||
|
||||
mcast_data.flags != bat_priv->mcast.flags) {
|
||||
batadv_tvlv_container_register(bat_priv, BATADV_TVLV_MCAST, 1,
|
||||
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 true;
|
||||
return !(mcast_data.flags &
|
||||
(BATADV_MCAST_WANT_ALL_IPV4 + BATADV_MCAST_WANT_ALL_IPV6));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -274,6 +549,10 @@ void batadv_mcast_mla_update(struct batadv_priv *bat_priv)
|
|||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = batadv_mcast_mla_bridge_get(soft_iface, &mcast_list);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
update:
|
||||
batadv_mcast_mla_tt_retract(bat_priv, &mcast_list);
|
||||
batadv_mcast_mla_tt_add(bat_priv, &mcast_list);
|
||||
|
@ -282,6 +561,31 @@ out:
|
|||
batadv_mcast_mla_list_free(bat_priv, &mcast_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_is_report_ipv4 - check for IGMP reports
|
||||
* @skb: the ethernet frame destined for the mesh
|
||||
*
|
||||
* This call might reallocate skb data.
|
||||
*
|
||||
* Checks whether the given frame is a valid IGMP report.
|
||||
*
|
||||
* Return: If so then true, otherwise false.
|
||||
*/
|
||||
static bool batadv_mcast_is_report_ipv4(struct sk_buff *skb)
|
||||
{
|
||||
if (ip_mc_check_igmp(skb, NULL) < 0)
|
||||
return false;
|
||||
|
||||
switch (igmp_hdr(skb)->type) {
|
||||
case IGMP_HOST_MEMBERSHIP_REPORT:
|
||||
case IGMPV2_HOST_MEMBERSHIP_REPORT:
|
||||
case IGMPV3_HOST_MEMBERSHIP_REPORT:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_forw_mode_check_ipv4 - check for optimized forwarding potential
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -304,6 +608,9 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
|
|||
if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*iphdr)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (batadv_mcast_is_report_ipv4(skb))
|
||||
return -EINVAL;
|
||||
|
||||
iphdr = ip_hdr(skb);
|
||||
|
||||
/* TODO: Implement Multicast Router Discovery (RFC4286),
|
||||
|
@ -320,6 +627,31 @@ static int batadv_mcast_forw_mode_check_ipv4(struct batadv_priv *bat_priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* batadv_mcast_is_report_ipv6 - check for MLD reports
|
||||
* @skb: the ethernet frame destined for the mesh
|
||||
*
|
||||
* This call might reallocate skb data.
|
||||
*
|
||||
* Checks whether the given frame is a valid MLD report.
|
||||
*
|
||||
* Return: If so then true, otherwise false.
|
||||
*/
|
||||
static bool batadv_mcast_is_report_ipv6(struct sk_buff *skb)
|
||||
{
|
||||
if (ipv6_mc_check_mld(skb, NULL) < 0)
|
||||
return false;
|
||||
|
||||
switch (icmp6_hdr(skb)->icmp6_type) {
|
||||
case ICMPV6_MGM_REPORT:
|
||||
case ICMPV6_MLD2_REPORT:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_forw_mode_check_ipv6 - check for optimized forwarding potential
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
|
@ -341,6 +673,9 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
|
|||
if (!pskb_may_pull(skb, sizeof(struct ethhdr) + sizeof(*ip6hdr)))
|
||||
return -ENOMEM;
|
||||
|
||||
if (batadv_mcast_is_report_ipv6(skb))
|
||||
return -EINVAL;
|
||||
|
||||
ip6hdr = ipv6_hdr(skb);
|
||||
|
||||
/* TODO: Implement Multicast Router Discovery (RFC4286),
|
||||
|
@ -357,6 +692,7 @@ static int batadv_mcast_forw_mode_check_ipv6(struct batadv_priv *bat_priv,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* batadv_mcast_forw_mode_check - check for optimized forwarding potential
|
||||
|
@ -385,9 +721,11 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv,
|
|||
case ETH_P_IP:
|
||||
return batadv_mcast_forw_mode_check_ipv4(bat_priv, skb,
|
||||
is_unsnoopable);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case ETH_P_IPV6:
|
||||
return batadv_mcast_forw_mode_check_ipv6(bat_priv, skb,
|
||||
is_unsnoopable);
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -728,18 +1066,18 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
|
|||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_tvlv_ogm_handler_v1 - 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
|
||||
* @orig: the orig_node of the ogm
|
||||
* @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
|
||||
* @tvlv_value: tvlv buffer containing the multicast data
|
||||
* @tvlv_value_len: tvlv buffer length
|
||||
*/
|
||||
static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
|
||||
struct batadv_orig_node *orig,
|
||||
u8 flags,
|
||||
void *tvlv_value,
|
||||
u16 tvlv_value_len)
|
||||
static void batadv_mcast_tvlv_ogm_handler(struct batadv_priv *bat_priv,
|
||||
struct batadv_orig_node *orig,
|
||||
u8 flags,
|
||||
void *tvlv_value,
|
||||
u16 tvlv_value_len)
|
||||
{
|
||||
bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
|
||||
u8 mcast_flags = BATADV_NO_FLAGS;
|
||||
|
@ -789,19 +1127,120 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
|
|||
*/
|
||||
void batadv_mcast_init(struct batadv_priv *bat_priv)
|
||||
{
|
||||
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler_v1,
|
||||
NULL, BATADV_TVLV_MCAST, 1,
|
||||
batadv_tvlv_handler_register(bat_priv, batadv_mcast_tvlv_ogm_handler,
|
||||
NULL, BATADV_TVLV_MCAST, 2,
|
||||
BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_flags_print_header - print own mcast flags to debugfs table
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
* @seq: debugfs table seq_file struct
|
||||
*
|
||||
* Prints our own multicast flags including a more specific reason why
|
||||
* they are set, that is prints the bridge and querier state too, to
|
||||
* the debugfs table specified via @seq.
|
||||
*/
|
||||
static void batadv_mcast_flags_print_header(struct batadv_priv *bat_priv,
|
||||
struct seq_file *seq)
|
||||
{
|
||||
u8 flags = bat_priv->mcast.flags;
|
||||
char querier4, querier6, shadowing4, shadowing6;
|
||||
bool bridged = bat_priv->mcast.bridged;
|
||||
|
||||
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' : '.';
|
||||
} else {
|
||||
querier4 = '?';
|
||||
querier6 = '?';
|
||||
shadowing4 = '?';
|
||||
shadowing6 = '?';
|
||||
}
|
||||
|
||||
seq_printf(seq, "Multicast flags (own flags: [%c%c%c])\n",
|
||||
(flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) ? 'U' : '.',
|
||||
(flags & BATADV_MCAST_WANT_ALL_IPV4) ? '4' : '.',
|
||||
(flags & BATADV_MCAST_WANT_ALL_IPV6) ? '6' : '.');
|
||||
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);
|
||||
seq_printf(seq, "* Shadowing IGMP/MLD Querier [4/6]:\t%c/%c\n",
|
||||
shadowing4, shadowing6);
|
||||
seq_puts(seq, "-------------------------------------------\n");
|
||||
seq_printf(seq, " %-10s %s\n", "Originator", "Flags");
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_flags_seq_print_text - print the mcast flags of other nodes
|
||||
* @seq: seq file to print on
|
||||
* @offset: not used
|
||||
*
|
||||
* This prints a table of (primary) originators and their according
|
||||
* multicast flags, including (in the header) our own.
|
||||
*
|
||||
* Return: always 0
|
||||
*/
|
||||
int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset)
|
||||
{
|
||||
struct net_device *net_dev = (struct net_device *)seq->private;
|
||||
struct batadv_priv *bat_priv = netdev_priv(net_dev);
|
||||
struct batadv_hard_iface *primary_if;
|
||||
struct batadv_hashtable *hash = bat_priv->orig_hash;
|
||||
struct batadv_orig_node *orig_node;
|
||||
struct hlist_head *head;
|
||||
u8 flags;
|
||||
u32 i;
|
||||
|
||||
primary_if = batadv_seq_print_text_primary_if_get(seq);
|
||||
if (!primary_if)
|
||||
return 0;
|
||||
|
||||
batadv_mcast_flags_print_header(bat_priv, seq);
|
||||
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
head = &hash->table[i];
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
||||
if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
|
||||
&orig_node->capa_initialized))
|
||||
continue;
|
||||
|
||||
if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
|
||||
&orig_node->capabilities)) {
|
||||
seq_printf(seq, "%pM -\n", orig_node->orig);
|
||||
continue;
|
||||
}
|
||||
|
||||
flags = orig_node->mcast_flags;
|
||||
|
||||
seq_printf(seq, "%pM [%c%c%c]\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' : '.');
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
batadv_hardif_put(primary_if);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_mcast_free - free the multicast optimizations structures
|
||||
* @bat_priv: the bat priv with all the soft interface information
|
||||
*/
|
||||
void batadv_mcast_free(struct batadv_priv *bat_priv)
|
||||
{
|
||||
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
|
||||
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 1);
|
||||
batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
|
||||
batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_MCAST, 2);
|
||||
|
||||
spin_lock_bh(&bat_priv->tt.commit_lock);
|
||||
batadv_mcast_mla_tt_retract(bat_priv, NULL);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "main.h"
|
||||
|
||||
struct seq_file;
|
||||
struct sk_buff;
|
||||
|
||||
/**
|
||||
|
@ -46,6 +47,8 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
|||
|
||||
void batadv_mcast_init(struct batadv_priv *bat_priv);
|
||||
|
||||
int batadv_mcast_flags_seq_print_text(struct seq_file *seq, void *offset);
|
||||
|
||||
void batadv_mcast_free(struct batadv_priv *bat_priv);
|
||||
|
||||
void batadv_mcast_purge_orig(struct batadv_orig_node *orig_node);
|
||||
|
|
|
@ -251,10 +251,8 @@ static void batadv_neigh_node_release(struct kref *ref)
|
|||
struct hlist_node *node_tmp;
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
struct batadv_neigh_ifinfo *neigh_ifinfo;
|
||||
struct batadv_algo_ops *bao;
|
||||
|
||||
neigh_node = container_of(ref, struct batadv_neigh_node, refcount);
|
||||
bao = neigh_node->orig_node->bat_priv->bat_algo_ops;
|
||||
|
||||
hlist_for_each_entry_safe(neigh_ifinfo, node_tmp,
|
||||
&neigh_node->ifinfo_list, list) {
|
||||
|
@ -263,9 +261,6 @@ static void batadv_neigh_node_release(struct kref *ref)
|
|||
|
||||
batadv_hardif_neigh_put(neigh_node->hardif_neigh);
|
||||
|
||||
if (bao->bat_neigh_free)
|
||||
bao->bat_neigh_free(neigh_node);
|
||||
|
||||
batadv_hardif_put(neigh_node->if_incoming);
|
||||
|
||||
kfree_rcu(neigh_node, rcu);
|
||||
|
@ -602,19 +597,19 @@ batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
|
|||
}
|
||||
|
||||
/**
|
||||
* batadv_neigh_node_new - create and init a new neigh_node object
|
||||
* batadv_neigh_node_create - create a neigh node object
|
||||
* @orig_node: originator object representing the neighbour
|
||||
* @hard_iface: the interface where the neighbour is connected to
|
||||
* @neigh_addr: the mac address of the neighbour interface
|
||||
*
|
||||
* Allocates a new neigh_node object and initialises all the generic fields.
|
||||
*
|
||||
* Return: neighbor when found. Othwerwise NULL
|
||||
* Return: the neighbour node if found or created or NULL otherwise.
|
||||
*/
|
||||
struct batadv_neigh_node *
|
||||
batadv_neigh_node_new(struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
const u8 *neigh_addr)
|
||||
static struct batadv_neigh_node *
|
||||
batadv_neigh_node_create(struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
const u8 *neigh_addr)
|
||||
{
|
||||
struct batadv_neigh_node *neigh_node;
|
||||
struct batadv_hardif_neigh_node *hardif_neigh = NULL;
|
||||
|
@ -666,6 +661,29 @@ out:
|
|||
return neigh_node;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_neigh_node_get_or_create - retrieve or create a neigh node object
|
||||
* @orig_node: originator object representing the neighbour
|
||||
* @hard_iface: the interface where the neighbour is connected to
|
||||
* @neigh_addr: the mac address of the neighbour interface
|
||||
*
|
||||
* Return: the neighbour node if found or created or NULL otherwise.
|
||||
*/
|
||||
struct batadv_neigh_node *
|
||||
batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
const u8 *neigh_addr)
|
||||
{
|
||||
struct batadv_neigh_node *neigh_node = NULL;
|
||||
|
||||
/* first check without locking to avoid the overhead */
|
||||
neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
|
||||
if (neigh_node)
|
||||
return neigh_node;
|
||||
|
||||
return batadv_neigh_node_create(orig_node, hard_iface, neigh_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_hardif_neigh_seq_print_text - print the single hop neighbour list
|
||||
* @seq: neighbour table seq_file struct
|
||||
|
|
|
@ -46,9 +46,9 @@ batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
|
|||
void
|
||||
batadv_hardif_neigh_put(struct batadv_hardif_neigh_node *hardif_neigh);
|
||||
struct batadv_neigh_node *
|
||||
batadv_neigh_node_new(struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
const u8 *neigh_addr);
|
||||
batadv_neigh_node_get_or_create(struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *hard_iface,
|
||||
const u8 *neigh_addr);
|
||||
void batadv_neigh_node_put(struct batadv_neigh_node *neigh_node);
|
||||
struct batadv_neigh_node *
|
||||
batadv_orig_router_get(struct batadv_orig_node *orig_node,
|
||||
|
|
|
@ -420,6 +420,7 @@ struct batadv_unicast_4addr_packet {
|
|||
* @dest: final destination used when routing fragments
|
||||
* @orig: originator of the fragment used when merging the packet
|
||||
* @no: fragment number within this sequence
|
||||
* @priority: priority of frame, from ToS IP precedence or 802.1p
|
||||
* @reserved: reserved byte for alignment
|
||||
* @seqno: sequence identification
|
||||
* @total_size: size of the merged packet
|
||||
|
@ -430,9 +431,11 @@ struct batadv_frag_packet {
|
|||
u8 ttl;
|
||||
#if defined(__BIG_ENDIAN_BITFIELD)
|
||||
u8 no:4;
|
||||
u8 reserved:4;
|
||||
u8 priority:3;
|
||||
u8 reserved:1;
|
||||
#elif defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
u8 reserved:4;
|
||||
u8 reserved:1;
|
||||
u8 priority:3;
|
||||
u8 no:4;
|
||||
#else
|
||||
#error "unknown bitfield endianness"
|
||||
|
|
|
@ -1007,6 +1007,8 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
|
|||
if (!orig_node_src)
|
||||
goto out;
|
||||
|
||||
skb->priority = frag_packet->priority + 256;
|
||||
|
||||
/* Route the fragment if it is not for us and too big to be merged. */
|
||||
if (!batadv_is_my_mac(bat_priv, frag_packet->dest) &&
|
||||
batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) {
|
||||
|
|
|
@ -428,27 +428,7 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,
|
|||
orig_node, vid);
|
||||
}
|
||||
|
||||
void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
|
||||
if ((hard_iface->if_status == BATADV_IF_NOT_IN_USE) ||
|
||||
(hard_iface->if_status == BATADV_IF_TO_BE_REMOVED))
|
||||
return;
|
||||
|
||||
/* the interface gets activated here to avoid race conditions between
|
||||
* the moment of activating the interface in
|
||||
* hardif_activate_interface() where the originator mac is set and
|
||||
* outdated packets (especially uninitialized mac addresses) in the
|
||||
* packet queue
|
||||
*/
|
||||
if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
|
||||
hard_iface->if_status = BATADV_IF_ACTIVE;
|
||||
|
||||
bat_priv->bat_algo_ops->bat_ogm_schedule(hard_iface);
|
||||
}
|
||||
|
||||
static void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
|
||||
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet)
|
||||
{
|
||||
kfree_skb(forw_packet->skb);
|
||||
if (forw_packet->if_incoming)
|
||||
|
@ -604,45 +584,6 @@ out:
|
|||
atomic_inc(&bat_priv->bcast_queue_left);
|
||||
}
|
||||
|
||||
void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *delayed_work;
|
||||
struct batadv_forw_packet *forw_packet;
|
||||
struct batadv_priv *bat_priv;
|
||||
|
||||
delayed_work = to_delayed_work(work);
|
||||
forw_packet = container_of(delayed_work, struct batadv_forw_packet,
|
||||
delayed_work);
|
||||
bat_priv = netdev_priv(forw_packet->if_incoming->soft_iface);
|
||||
spin_lock_bh(&bat_priv->forw_bat_list_lock);
|
||||
hlist_del(&forw_packet->list);
|
||||
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
|
||||
|
||||
if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
|
||||
goto out;
|
||||
|
||||
bat_priv->bat_algo_ops->bat_ogm_emit(forw_packet);
|
||||
|
||||
/* we have to have at least one packet in the queue to determine the
|
||||
* queues wake up time unless we are shutting down.
|
||||
*
|
||||
* only re-schedule if this is the "original" copy, e.g. the OGM of the
|
||||
* primary interface should only be rescheduled once per period, but
|
||||
* this function will be called for the forw_packet instances of the
|
||||
* other secondary interfaces as well.
|
||||
*/
|
||||
if (forw_packet->own &&
|
||||
forw_packet->if_incoming == forw_packet->if_outgoing)
|
||||
batadv_schedule_bat_ogm(forw_packet->if_incoming);
|
||||
|
||||
out:
|
||||
/* don't count own packet */
|
||||
if (!forw_packet->own)
|
||||
atomic_inc(&bat_priv->batman_queue_left);
|
||||
|
||||
batadv_forw_packet_free(forw_packet);
|
||||
}
|
||||
|
||||
void
|
||||
batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
|
||||
const struct batadv_hard_iface *hard_iface)
|
||||
|
|
|
@ -26,8 +26,8 @@
|
|||
#include "packet.h"
|
||||
|
||||
struct sk_buff;
|
||||
struct work_struct;
|
||||
|
||||
void batadv_forw_packet_free(struct batadv_forw_packet *forw_packet);
|
||||
int batadv_send_skb_to_orig(struct sk_buff *skb,
|
||||
struct batadv_orig_node *orig_node,
|
||||
struct batadv_hard_iface *recv_if);
|
||||
|
@ -38,11 +38,9 @@ int batadv_send_broadcast_skb(struct sk_buff *skb,
|
|||
struct batadv_hard_iface *hard_iface);
|
||||
int batadv_send_unicast_skb(struct sk_buff *skb,
|
||||
struct batadv_neigh_node *neigh_node);
|
||||
void batadv_schedule_bat_ogm(struct batadv_hard_iface *hard_iface);
|
||||
int batadv_add_bcast_packet_to_list(struct batadv_priv *bat_priv,
|
||||
const struct sk_buff *skb,
|
||||
unsigned long delay);
|
||||
void batadv_send_outstanding_bat_ogm_packet(struct work_struct *work);
|
||||
void
|
||||
batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
|
||||
const struct batadv_hard_iface *hard_iface);
|
||||
|
|
|
@ -255,7 +255,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
|
|||
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
|
||||
goto dropped;
|
||||
|
||||
gw_mode = atomic_read(&bat_priv->gw_mode);
|
||||
gw_mode = atomic_read(&bat_priv->gw.mode);
|
||||
if (is_multicast_ether_addr(ethhdr->h_dest)) {
|
||||
/* if gw mode is off, broadcast every packet */
|
||||
if (gw_mode == BATADV_GW_MODE_OFF) {
|
||||
|
@ -808,6 +808,10 @@ 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->mcast.num_disabled, 0);
|
||||
|
@ -815,8 +819,8 @@ static int batadv_softif_init_late(struct net_device *dev)
|
|||
atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0);
|
||||
atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0);
|
||||
#endif
|
||||
atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
|
||||
atomic_set(&bat_priv->gw_sel_class, 20);
|
||||
atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF);
|
||||
atomic_set(&bat_priv->gw.sel_class, 20);
|
||||
atomic_set(&bat_priv->gw.bandwidth_down, 100);
|
||||
atomic_set(&bat_priv->gw.bandwidth_up, 20);
|
||||
atomic_set(&bat_priv->orig_interval, 1000);
|
||||
|
|
|
@ -389,12 +389,12 @@ static int batadv_store_uint_attr(const char *buff, size_t count,
|
|||
return count;
|
||||
}
|
||||
|
||||
static inline ssize_t
|
||||
__batadv_store_uint_attr(const char *buff, size_t count,
|
||||
int min, int max,
|
||||
void (*post_func)(struct net_device *),
|
||||
const struct attribute *attr,
|
||||
atomic_t *attr_store, struct net_device *net_dev)
|
||||
static ssize_t __batadv_store_uint_attr(const char *buff, size_t count,
|
||||
int min, int max,
|
||||
void (*post_func)(struct net_device *),
|
||||
const struct attribute *attr,
|
||||
atomic_t *attr_store,
|
||||
struct net_device *net_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -427,7 +427,7 @@ static ssize_t batadv_show_gw_mode(struct kobject *kobj, struct attribute *attr,
|
|||
struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
|
||||
int bytes_written;
|
||||
|
||||
switch (atomic_read(&bat_priv->gw_mode)) {
|
||||
switch (atomic_read(&bat_priv->gw.mode)) {
|
||||
case BATADV_GW_MODE_CLIENT:
|
||||
bytes_written = sprintf(buff, "%s\n",
|
||||
BATADV_GW_MODE_CLIENT_NAME);
|
||||
|
@ -476,10 +476,10 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (atomic_read(&bat_priv->gw_mode) == gw_mode_tmp)
|
||||
if (atomic_read(&bat_priv->gw.mode) == gw_mode_tmp)
|
||||
return count;
|
||||
|
||||
switch (atomic_read(&bat_priv->gw_mode)) {
|
||||
switch (atomic_read(&bat_priv->gw.mode)) {
|
||||
case BATADV_GW_MODE_CLIENT:
|
||||
curr_gw_mode_str = BATADV_GW_MODE_CLIENT_NAME;
|
||||
break;
|
||||
|
@ -508,7 +508,7 @@ static ssize_t batadv_store_gw_mode(struct kobject *kobj,
|
|||
* state
|
||||
*/
|
||||
batadv_gw_check_client_stop(bat_priv);
|
||||
atomic_set(&bat_priv->gw_mode, (unsigned int)gw_mode_tmp);
|
||||
atomic_set(&bat_priv->gw.mode, (unsigned int)gw_mode_tmp);
|
||||
batadv_gw_tvlv_container_update(bat_priv);
|
||||
return count;
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ BATADV_ATTR_SIF_UINT(orig_interval, orig_interval, S_IRUGO | S_IWUSR,
|
|||
2 * BATADV_JITTER, INT_MAX, NULL);
|
||||
BATADV_ATTR_SIF_UINT(hop_penalty, hop_penalty, S_IRUGO | S_IWUSR, 0,
|
||||
BATADV_TQ_MAX_VALUE, NULL);
|
||||
BATADV_ATTR_SIF_UINT(gw_sel_class, gw_sel_class, S_IRUGO | S_IWUSR, 1,
|
||||
BATADV_ATTR_SIF_UINT(gw_sel_class, gw.sel_class, S_IRUGO | S_IWUSR, 1,
|
||||
BATADV_TQ_MAX_VALUE, batadv_post_gw_reselect);
|
||||
static BATADV_ATTR(gw_bandwidth, S_IRUGO | S_IWUSR, batadv_show_gw_bwidth,
|
||||
batadv_store_gw_bwidth);
|
||||
|
|
|
@ -996,7 +996,6 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
|
|||
struct batadv_tt_local_entry *tt_local;
|
||||
struct batadv_hard_iface *primary_if;
|
||||
struct hlist_head *head;
|
||||
unsigned short vid;
|
||||
u32 i;
|
||||
int last_seen_secs;
|
||||
int last_seen_msecs;
|
||||
|
@ -1023,7 +1022,6 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
|
|||
tt_local = container_of(tt_common_entry,
|
||||
struct batadv_tt_local_entry,
|
||||
common);
|
||||
vid = tt_common_entry->vid;
|
||||
last_seen_jiffies = jiffies - tt_local->last_seen;
|
||||
last_seen_msecs = jiffies_to_msecs(last_seen_jiffies);
|
||||
last_seen_secs = last_seen_msecs / 1000;
|
||||
|
|
|
@ -707,6 +707,8 @@ struct batadv_priv_debug_log {
|
|||
* @list: list of available gateway nodes
|
||||
* @list_lock: lock protecting gw_list & curr_gw
|
||||
* @curr_gw: pointer to currently selected gateway node
|
||||
* @mode: gateway operation: off, client or server (see batadv_gw_modes)
|
||||
* @sel_class: gateway selection class (applies if gw_mode client)
|
||||
* @bandwidth_down: advertised uplink download bandwidth (if gw_mode server)
|
||||
* @bandwidth_up: advertised uplink upload bandwidth (if gw_mode server)
|
||||
* @reselect: bool indicating a gateway re-selection is in progress
|
||||
|
@ -715,6 +717,8 @@ struct batadv_priv_gw {
|
|||
struct hlist_head list;
|
||||
spinlock_t list_lock; /* protects gw_list & curr_gw */
|
||||
struct batadv_gw_node __rcu *curr_gw; /* rcu protected pointer */
|
||||
atomic_t mode;
|
||||
atomic_t sel_class;
|
||||
atomic_t bandwidth_down;
|
||||
atomic_t bandwidth_up;
|
||||
atomic_t reselect;
|
||||
|
@ -750,6 +754,17 @@ struct batadv_priv_dat {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
/**
|
||||
* struct batadv_mcast_querier_state - IGMP/MLD querier state when bridged
|
||||
* @exists: whether a querier exists in the mesh
|
||||
* @shadowing: if a querier exists, whether it is potentially shadowing
|
||||
* multicast listeners (i.e. querier is behind our own bridge segment)
|
||||
*/
|
||||
struct batadv_mcast_querier_state {
|
||||
bool exists;
|
||||
bool shadowing;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct batadv_priv_mcast - per mesh interface mcast data
|
||||
* @mla_list: list of multicast addresses we are currently announcing via TT
|
||||
|
@ -757,8 +772,11 @@ struct batadv_priv_dat {
|
|||
* multicast traffic
|
||||
* @want_all_ipv4_list: a list of orig_nodes wanting all IPv4 multicast traffic
|
||||
* @want_all_ipv6_list: a list of orig_nodes wanting all IPv6 multicast traffic
|
||||
* @querier_ipv4: the current state of an IGMP querier in the mesh
|
||||
* @querier_ipv6: the current state of an MLD querier in the mesh
|
||||
* @flags: the flags we have last sent in our mcast tvlv
|
||||
* @enabled: whether the multicast tvlv is currently enabled
|
||||
* @bridged: whether the soft interface has a bridge on top
|
||||
* @num_disabled: number of nodes that have no mcast tvlv
|
||||
* @num_want_all_unsnoopables: number of nodes wanting unsnoopable IP traffic
|
||||
* @num_want_all_ipv4: counter for items in want_all_ipv4_list
|
||||
|
@ -771,8 +789,11 @@ struct batadv_priv_mcast {
|
|||
struct hlist_head want_all_unsnoopables_list;
|
||||
struct hlist_head want_all_ipv4_list;
|
||||
struct hlist_head want_all_ipv6_list;
|
||||
struct batadv_mcast_querier_state querier_ipv4;
|
||||
struct batadv_mcast_querier_state querier_ipv6;
|
||||
u8 flags;
|
||||
bool enabled;
|
||||
bool bridged;
|
||||
atomic_t num_disabled;
|
||||
atomic_t num_want_all_unsnoopables;
|
||||
atomic_t num_want_all_ipv4;
|
||||
|
@ -865,8 +886,6 @@ struct batadv_priv_bat_v {
|
|||
* enabled
|
||||
* @multicast_mode: Enable or disable multicast optimizations on this node's
|
||||
* sender/originating side
|
||||
* @gw_mode: gateway operation: off, client or server (see batadv_gw_modes)
|
||||
* @gw_sel_class: gateway selection class (applies if gw_mode client)
|
||||
* @orig_interval: OGM broadcast interval in milliseconds
|
||||
* @hop_penalty: penalty which will be applied to an OGM's tq-field on every hop
|
||||
* @log_level: configured log level (see batadv_dbg_level)
|
||||
|
@ -922,8 +941,6 @@ struct batadv_priv {
|
|||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
atomic_t multicast_mode;
|
||||
#endif
|
||||
atomic_t gw_mode;
|
||||
atomic_t gw_sel_class;
|
||||
atomic_t orig_interval;
|
||||
atomic_t hop_penalty;
|
||||
#ifdef CONFIG_BATMAN_ADV_DEBUG
|
||||
|
@ -1271,8 +1288,6 @@ struct batadv_forw_packet {
|
|||
* @bat_iface_update_mac: (re-)init mac addresses of the protocol information
|
||||
* belonging to this hard-interface
|
||||
* @bat_primary_iface_set: called when primary interface is selected / changed
|
||||
* @bat_ogm_schedule: prepare a new outgoing OGM for the send queue
|
||||
* @bat_ogm_emit: send scheduled OGM
|
||||
* @bat_hardif_neigh_init: called on creation of single hop entry
|
||||
* @bat_neigh_cmp: compare the metrics of two neighbors for their respective
|
||||
* outgoing interfaces
|
||||
|
@ -1280,8 +1295,6 @@ struct batadv_forw_packet {
|
|||
* better than neigh2 for their respective outgoing interface from the metric
|
||||
* prospective
|
||||
* @bat_neigh_print: print the single hop neighbor list (optional)
|
||||
* @bat_neigh_free: free the resources allocated by the routing algorithm for a
|
||||
* neigh_node object
|
||||
* @bat_orig_print: print the originator table (optional)
|
||||
* @bat_orig_free: free the resources allocated by the routing algorithm for an
|
||||
* orig_node object
|
||||
|
@ -1298,8 +1311,6 @@ struct batadv_algo_ops {
|
|||
void (*bat_iface_disable)(struct batadv_hard_iface *hard_iface);
|
||||
void (*bat_iface_update_mac)(struct batadv_hard_iface *hard_iface);
|
||||
void (*bat_primary_iface_set)(struct batadv_hard_iface *hard_iface);
|
||||
void (*bat_ogm_schedule)(struct batadv_hard_iface *hard_iface);
|
||||
void (*bat_ogm_emit)(struct batadv_forw_packet *forw_packet);
|
||||
/* neigh_node handling API */
|
||||
void (*bat_hardif_neigh_init)(struct batadv_hardif_neigh_node *neigh);
|
||||
int (*bat_neigh_cmp)(struct batadv_neigh_node *neigh1,
|
||||
|
@ -1312,7 +1323,6 @@ struct batadv_algo_ops {
|
|||
struct batadv_neigh_node *neigh2,
|
||||
struct batadv_hard_iface *if_outgoing2);
|
||||
void (*bat_neigh_print)(struct batadv_priv *priv, struct seq_file *seq);
|
||||
void (*bat_neigh_free)(struct batadv_neigh_node *neigh);
|
||||
/* orig_node handling API */
|
||||
void (*bat_orig_print)(struct batadv_priv *priv, struct seq_file *seq,
|
||||
struct batadv_hard_iface *hard_iface);
|
||||
|
|
Loading…
Reference in New Issue