1977 lines
59 KiB
Diff
1977 lines
59 KiB
Diff
diff --git Makefile.kbuild Makefile.kbuild
|
|
index 489bb36..8ddbfe6 100644
|
|
--- Makefile.kbuild
|
|
+++ Makefile.kbuild
|
|
@@ -38,4 +38,3 @@ batman-adv-y += soft-interface.o
|
|
batman-adv-y += sysfs.o
|
|
batman-adv-y += translation-table.o
|
|
batman-adv-y += unicast.o
|
|
-batman-adv-y += vis.o
|
|
diff --git bat_iv_ogm.c bat_iv_ogm.c
|
|
index 2031071..6407369 100644
|
|
--- bat_iv_ogm.c
|
|
+++ bat_iv_ogm.c
|
|
@@ -687,11 +687,10 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
|
struct batadv_ogm_packet *batadv_ogm_packet;
|
|
struct batadv_hard_iface *primary_if;
|
|
int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len;
|
|
- int vis_server, tt_num_changes = 0;
|
|
+ int tt_num_changes = 0;
|
|
uint32_t seqno;
|
|
uint8_t bandwidth;
|
|
|
|
- vis_server = atomic_read(&bat_priv->vis_mode);
|
|
primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
|
|
if (hard_iface == primary_if)
|
|
@@ -711,10 +710,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
|
|
if (tt_num_changes >= 0)
|
|
batadv_ogm_packet->tt_num_changes = tt_num_changes;
|
|
|
|
- if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC)
|
|
- batadv_ogm_packet->flags |= BATADV_VIS_SERVER;
|
|
- else
|
|
- batadv_ogm_packet->flags &= ~BATADV_VIS_SERVER;
|
|
+ batadv_ogm_packet->flags = 0;
|
|
|
|
if (hard_iface == primary_if &&
|
|
atomic_read(&bat_priv->gw_mode) == BATADV_GW_MODE_SERVER) {
|
|
diff --git compat.h compat.h
|
|
index 3e11f89..63feaa9 100644
|
|
--- compat.h
|
|
+++ compat.h
|
|
@@ -266,7 +266,9 @@ static int __batadv_interface_set_mac_addr(x, y)
|
|
dev->master;\
|
|
})
|
|
#define hlist_entry_safe(ptr, type, member) \
|
|
- (ptr) ? hlist_entry(ptr, type, member) : NULL
|
|
+ ({ typeof(ptr) ____ptr = (ptr); \
|
|
+ ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
|
|
+ })
|
|
|
|
#undef hlist_for_each_entry
|
|
#define hlist_for_each_entry(pos, head, member) \
|
|
@@ -318,4 +320,33 @@ static int __batadv_interface_set_mac_addr(x, y)
|
|
})
|
|
#endif /* < KERNEL_VERSION(3, 11, 0) */
|
|
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
|
|
+
|
|
+/* alloc_netdev() was defined differently before 2.6.38 */
|
|
+#undef alloc_netdev
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)
|
|
+#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
|
|
+ alloc_netdev_mq(sizeof_priv, name, setup, 1)
|
|
+#else
|
|
+#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \
|
|
+ alloc_netdev_mqs(sizeof_priv, name, setup, 1, 1)
|
|
+#endif /* nested < KERNEL_VERSION(2, 6, 38) */
|
|
+
|
|
+#endif /* < KERNEL_VERSION(3, 17, 0) */
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
|
|
+
|
|
+static inline bool seq_has_overflowed(struct seq_file *m)
|
|
+{
|
|
+ return m->count == m->size;
|
|
+}
|
|
+
|
|
+#endif /* < KERNEL_VERSION(3, 19, 0) */
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
|
|
+
|
|
+#define dev_get_iflink(_net_dev) ((_net_dev)->iflink)
|
|
+
|
|
+#endif /* < KERNEL_VERSION(4, 1, 0) */
|
|
+
|
|
#endif /* _NET_BATMAN_ADV_COMPAT_H_ */
|
|
diff --git debugfs.c debugfs.c
|
|
index f186a55..049a7a2 100644
|
|
--- debugfs.c
|
|
+++ debugfs.c
|
|
@@ -28,7 +28,6 @@
|
|
#include "gateway_common.h"
|
|
#include "gateway_client.h"
|
|
#include "soft-interface.h"
|
|
-#include "vis.h"
|
|
#include "icmp_socket.h"
|
|
#include "bridge_loop_avoidance.h"
|
|
#include "distributed-arp-table.h"
|
|
@@ -300,12 +299,6 @@ static int batadv_transtable_local_open(struct inode *inode, struct file *file)
|
|
return single_open(file, batadv_tt_local_seq_print_text, net_dev);
|
|
}
|
|
|
|
-static int batadv_vis_data_open(struct inode *inode, struct file *file)
|
|
-{
|
|
- struct net_device *net_dev = (struct net_device *)inode->i_private;
|
|
- return single_open(file, batadv_vis_seq_print_text, net_dev);
|
|
-}
|
|
-
|
|
struct batadv_debuginfo {
|
|
struct attribute attr;
|
|
const struct file_operations fops;
|
|
@@ -356,7 +349,6 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open);
|
|
#endif
|
|
static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
|
|
batadv_transtable_local_open);
|
|
-static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
|
|
#ifdef CONFIG_BATMAN_ADV_NC
|
|
static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
|
|
#endif
|
|
@@ -373,7 +365,6 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
|
|
&batadv_debuginfo_dat_cache,
|
|
#endif
|
|
&batadv_debuginfo_transtable_local,
|
|
- &batadv_debuginfo_vis_data,
|
|
#ifdef CONFIG_BATMAN_ADV_NC
|
|
&batadv_debuginfo_nc_nodes,
|
|
#endif
|
|
diff --git gateway_client.c gateway_client.c
|
|
index 7614af3..04fbfb2 100644
|
|
--- gateway_client.c
|
|
+++ gateway_client.c
|
|
@@ -115,16 +115,12 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
|
|
{
|
|
struct batadv_neigh_node *router;
|
|
struct batadv_gw_node *gw_node, *curr_gw = NULL;
|
|
- uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
|
|
- uint32_t gw_divisor;
|
|
+ uint64_t max_gw_factor = 0, tmp_gw_factor = 0;
|
|
uint8_t max_tq = 0;
|
|
int down, up;
|
|
uint8_t tq_avg;
|
|
struct batadv_orig_node *orig_node;
|
|
|
|
- gw_divisor = BATADV_TQ_LOCAL_WINDOW_SIZE * BATADV_TQ_LOCAL_WINDOW_SIZE;
|
|
- gw_divisor *= 64;
|
|
-
|
|
rcu_read_lock();
|
|
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
|
|
if (gw_node->deleted)
|
|
@@ -146,7 +142,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
|
|
&down, &up);
|
|
|
|
tmp_gw_factor = tq_avg * tq_avg * down * 100 * 100;
|
|
- tmp_gw_factor /= gw_divisor;
|
|
+ tmp_gw_factor >>= 18;
|
|
|
|
if ((tmp_gw_factor > max_gw_factor) ||
|
|
((tmp_gw_factor == max_gw_factor) &&
|
|
@@ -450,16 +446,17 @@ static int batadv_write_buffer_text(struct batadv_priv *bat_priv,
|
|
|
|
curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
|
|
|
|
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
|
|
- (curr_gw == gw_node ? "=>" : " "),
|
|
- gw_node->orig_node->orig,
|
|
- router->tq_avg, router->addr,
|
|
- router->if_incoming->net_dev->name,
|
|
- gw_node->orig_node->gw_flags,
|
|
- (down > 2048 ? down / 1024 : down),
|
|
- (down > 2048 ? "MBit" : "KBit"),
|
|
- (up > 2048 ? up / 1024 : up),
|
|
- (up > 2048 ? "MBit" : "KBit"));
|
|
+ seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n",
|
|
+ (curr_gw == gw_node ? "=>" : " "),
|
|
+ gw_node->orig_node->orig,
|
|
+ router->tq_avg, router->addr,
|
|
+ router->if_incoming->net_dev->name,
|
|
+ gw_node->orig_node->gw_flags,
|
|
+ (down > 2048 ? down / 1024 : down),
|
|
+ (down > 2048 ? "MBit" : "KBit"),
|
|
+ (up > 2048 ? up / 1024 : up),
|
|
+ (up > 2048 ? "MBit" : "KBit"));
|
|
+ ret = seq_has_overflowed(seq) ? -1 : 0;
|
|
|
|
batadv_neigh_node_free_ref(router);
|
|
if (curr_gw)
|
|
diff --git gateway_common.c gateway_common.c
|
|
index 84bb2b1..bb3f667 100644
|
|
--- gateway_common.c
|
|
+++ gateway_common.c
|
|
@@ -87,10 +87,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
|
|
if (strlen(buff) > 4) {
|
|
tmp_ptr = buff + strlen(buff) - 4;
|
|
|
|
- if (strnicmp(tmp_ptr, "mbit", 4) == 0)
|
|
+ if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
|
|
multi = 1024;
|
|
|
|
- if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
|
|
+ if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) ||
|
|
(multi > 1))
|
|
*tmp_ptr = '\0';
|
|
}
|
|
@@ -112,10 +112,10 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
|
|
if (strlen(slash_ptr + 1) > 4) {
|
|
tmp_ptr = slash_ptr + 1 - 4 + strlen(slash_ptr + 1);
|
|
|
|
- if (strnicmp(tmp_ptr, "mbit", 4) == 0)
|
|
+ if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
|
|
multi = 1024;
|
|
|
|
- if ((strnicmp(tmp_ptr, "kbit", 4) == 0) ||
|
|
+ if ((strncasecmp(tmp_ptr, "kbit", 4) == 0) ||
|
|
(multi > 1))
|
|
*tmp_ptr = '\0';
|
|
}
|
|
diff --git gen-compat-autoconf.sh gen-compat-autoconf.sh
|
|
index 78573e4..c5a3f5d 100755
|
|
--- gen-compat-autoconf.sh
|
|
+++ gen-compat-autoconf.sh
|
|
@@ -5,7 +5,8 @@ set -e
|
|
TARGET=${1:="compat-autoconf.h"}
|
|
TMP="${TARGET}.tmp"
|
|
|
|
-echo -n > "${TMP}"
|
|
+rm -f "${TMP}"
|
|
+touch "${TMP}"
|
|
|
|
gen_config() {
|
|
KEY="${1}"
|
|
diff --git hard-interface.c hard-interface.c
|
|
index c478e6b..01f0a80 100644
|
|
--- hard-interface.c
|
|
+++ hard-interface.c
|
|
@@ -83,19 +83,18 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
|
|
return true;
|
|
|
|
/* no more parents..stop recursion */
|
|
- if (net_dev->iflink == net_dev->ifindex)
|
|
+ if (dev_get_iflink(net_dev) == 0 ||
|
|
+ dev_get_iflink(net_dev) == net_dev->ifindex)
|
|
return false;
|
|
|
|
/* recurse over the parent device */
|
|
- parent_dev = dev_get_by_index(&init_net, net_dev->iflink);
|
|
+ parent_dev = __dev_get_by_index(&init_net, dev_get_iflink(net_dev));
|
|
/* if we got a NULL parent_dev there is something broken.. */
|
|
if (WARN(!parent_dev, "Cannot find parent device"))
|
|
return false;
|
|
|
|
ret = batadv_is_on_batman_iface(parent_dev);
|
|
|
|
- if (parent_dev)
|
|
- dev_put(parent_dev);
|
|
return ret;
|
|
}
|
|
|
|
@@ -194,9 +193,7 @@ out:
|
|
static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
|
|
struct batadv_hard_iface *oldif)
|
|
{
|
|
- struct batadv_vis_packet *vis_packet;
|
|
struct batadv_hard_iface *primary_if;
|
|
- struct sk_buff *skb;
|
|
|
|
primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
if (!primary_if)
|
|
@@ -204,12 +201,6 @@ static void batadv_primary_if_update_addr(struct batadv_priv *bat_priv,
|
|
|
|
batadv_dat_init_own_addr(bat_priv, primary_if);
|
|
|
|
- skb = bat_priv->vis.my_info->skb_packet;
|
|
- vis_packet = (struct batadv_vis_packet *)skb->data;
|
|
- memcpy(vis_packet->vis_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
|
|
- memcpy(vis_packet->sender_orig,
|
|
- primary_if->net_dev->dev_addr, ETH_ALEN);
|
|
-
|
|
batadv_bla_update_orig_address(bat_priv, primary_if, oldif);
|
|
out:
|
|
if (primary_if)
|
|
@@ -600,6 +591,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
|
|
/* extra reference for return */
|
|
atomic_set(&hard_iface->refcount, 2);
|
|
|
|
+ atomic_set(&hard_iface->no_rebroadcast, 0);
|
|
+
|
|
batadv_check_known_mac_addr(hard_iface->net_dev);
|
|
list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
|
|
|
|
diff --git main.c main.c
|
|
index c8e0671..a718d07 100644
|
|
--- main.c
|
|
+++ main.c
|
|
@@ -32,7 +32,6 @@
|
|
#include "gateway_client.h"
|
|
#include "bridge_loop_avoidance.h"
|
|
#include "distributed-arp-table.h"
|
|
-#include "vis.h"
|
|
#include "hash.h"
|
|
#include "bat_algo.h"
|
|
#include "network-coding.h"
|
|
@@ -106,8 +105,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
|
|
spin_lock_init(&bat_priv->tt.roam_list_lock);
|
|
spin_lock_init(&bat_priv->tt.last_changeset_lock);
|
|
spin_lock_init(&bat_priv->gw.list_lock);
|
|
- spin_lock_init(&bat_priv->vis.hash_lock);
|
|
- spin_lock_init(&bat_priv->vis.list_lock);
|
|
|
|
INIT_HLIST_HEAD(&bat_priv->forw_bat_list);
|
|
INIT_HLIST_HEAD(&bat_priv->forw_bcast_list);
|
|
@@ -127,10 +124,6 @@ int batadv_mesh_init(struct net_device *soft_iface)
|
|
batadv_tt_local_add(soft_iface, soft_iface->dev_addr,
|
|
BATADV_NULL_IFINDEX);
|
|
|
|
- ret = batadv_vis_init(bat_priv);
|
|
- if (ret < 0)
|
|
- goto err;
|
|
-
|
|
ret = batadv_bla_init(bat_priv);
|
|
if (ret < 0)
|
|
goto err;
|
|
@@ -161,8 +154,6 @@ void batadv_mesh_free(struct net_device *soft_iface)
|
|
|
|
batadv_purge_outstanding_packets(bat_priv, NULL);
|
|
|
|
- batadv_vis_quit(bat_priv);
|
|
-
|
|
batadv_gw_node_purge(bat_priv);
|
|
batadv_nc_mesh_free(bat_priv);
|
|
batadv_dat_free(bat_priv);
|
|
diff --git main.h main.h
|
|
index 2c0c14d..06e8971 100644
|
|
--- main.h
|
|
+++ main.h
|
|
@@ -86,8 +86,6 @@
|
|
/* numbers of originator to contact for any PUT/GET DHT operation */
|
|
#define BATADV_DAT_CANDIDATES_NUM 3
|
|
|
|
-#define BATADV_VIS_INTERVAL 5000 /* 5 seconds */
|
|
-
|
|
/* how much worse secondary interfaces may be to be considered as bonding
|
|
* candidates
|
|
*/
|
|
@@ -223,21 +221,29 @@ enum batadv_dbg_level {
|
|
int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)
|
|
__printf(2, 3);
|
|
|
|
-#define batadv_dbg(type, bat_priv, fmt, arg...) \
|
|
+/* possibly ratelimited debug output */
|
|
+#define _batadv_dbg(type, bat_priv, ratelimited, fmt, arg...) \
|
|
do { \
|
|
- if (atomic_read(&bat_priv->log_level) & type) \
|
|
+ if (atomic_read(&bat_priv->log_level) & type && \
|
|
+ (!ratelimited || net_ratelimit())) \
|
|
batadv_debug_log(bat_priv, fmt, ## arg);\
|
|
} \
|
|
while (0)
|
|
#else /* !CONFIG_BATMAN_ADV_DEBUG */
|
|
-__printf(3, 4)
|
|
-static inline void batadv_dbg(int type __always_unused,
|
|
+__printf(4, 5)
|
|
+static inline void _batadv_dbg(int type __always_unused,
|
|
struct batadv_priv *bat_priv __always_unused,
|
|
+ int ratelimited __always_unused,
|
|
const char *fmt __always_unused, ...)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
+#define batadv_dbg(type, bat_priv, arg...) \
|
|
+ _batadv_dbg(type, bat_priv, 0, ## arg)
|
|
+#define batadv_dbg_ratelimited(type, bat_priv, arg...) \
|
|
+ _batadv_dbg(type, bat_priv, 1, ## arg)
|
|
+
|
|
#define batadv_info(net_dev, fmt, arg...) \
|
|
do { \
|
|
struct net_device *_netdev = (net_dev); \
|
|
diff --git originator.c originator.c
|
|
index f50553a..af1b427 100644
|
|
--- originator.c
|
|
+++ originator.c
|
|
@@ -147,8 +147,6 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
|
|
batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
|
|
|
|
batadv_frag_list_free(&orig_node->frag_list);
|
|
- batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
|
|
- "originator timed out");
|
|
|
|
kfree(orig_node->tt_buff);
|
|
kfree(orig_node->bcast_own);
|
|
@@ -254,6 +252,7 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
|
|
orig_node->tt_buff = NULL;
|
|
orig_node->tt_buff_len = 0;
|
|
atomic_set(&orig_node->tt_size, 0);
|
|
+ orig_node->last_seen = jiffies;
|
|
reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
|
|
orig_node->bcast_seqno_reset = reset_time;
|
|
orig_node->batman_seqno_reset = reset_time;
|
|
@@ -392,6 +391,9 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv)
|
|
batadv_gw_node_delete(bat_priv,
|
|
orig_node);
|
|
hlist_del_rcu(&orig_node->hash_entry);
|
|
+ batadv_tt_global_del_orig(orig_node->bat_priv,
|
|
+ orig_node,
|
|
+ "originator timed out");
|
|
batadv_orig_node_free_ref(orig_node);
|
|
continue;
|
|
}
|
|
diff --git packet.h packet.h
|
|
index a51ccfc..d12da01 100644
|
|
--- packet.h
|
|
+++ packet.h
|
|
@@ -53,7 +53,6 @@ enum batadv_subtype {
|
|
enum batadv_iv_flags {
|
|
BATADV_NOT_BEST_NEXT_HOP = BIT(3),
|
|
BATADV_PRIMARIES_FIRST_HOP = BIT(4),
|
|
- BATADV_VIS_SERVER = BIT(5),
|
|
BATADV_DIRECTLINK = BIT(6),
|
|
};
|
|
|
|
@@ -66,12 +65,6 @@ enum batadv_icmp_packettype {
|
|
BATADV_PARAMETER_PROBLEM = 12,
|
|
};
|
|
|
|
-/* vis defines */
|
|
-enum batadv_vis_packettype {
|
|
- BATADV_VIS_TYPE_SERVER_SYNC = 0,
|
|
- BATADV_VIS_TYPE_CLIENT_UPDATE = 1,
|
|
-};
|
|
-
|
|
/* fragmentation defines */
|
|
enum batadv_unicast_frag_flags {
|
|
BATADV_UNI_FRAG_HEAD = BIT(0),
|
|
@@ -133,7 +126,7 @@ struct batadv_header {
|
|
|
|
struct batadv_ogm_packet {
|
|
struct batadv_header header;
|
|
- uint8_t flags; /* 0x40: DIRECTLINK flag, 0x20 VIS_SERVER flag... */
|
|
+ uint8_t flags; /* 0x40: DIRECTLINK flag... */
|
|
__be32 seqno;
|
|
uint8_t orig[ETH_ALEN];
|
|
uint8_t prev_sender[ETH_ALEN];
|
|
diff --git routing.c routing.c
|
|
index 2f0bd3f..5a11611 100644
|
|
--- routing.c
|
|
+++ routing.c
|
|
@@ -25,7 +25,6 @@
|
|
#include "icmp_socket.h"
|
|
#include "translation-table.h"
|
|
#include "originator.h"
|
|
-#include "vis.h"
|
|
#include "unicast.h"
|
|
#include "bridge_loop_avoidance.h"
|
|
#include "distributed-arp-table.h"
|
|
@@ -940,11 +939,11 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
|
|
if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest)) {
|
|
if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
|
|
ethhdr->h_dest))
|
|
- net_ratelimited_function(batadv_dbg, BATADV_DBG_TT,
|
|
- bat_priv,
|
|
- "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n",
|
|
- unicast_packet->dest,
|
|
- ethhdr->h_dest);
|
|
+ batadv_dbg_ratelimited(BATADV_DBG_TT,
|
|
+ bat_priv,
|
|
+ "Rerouting unicast packet to %pM (dst=%pM): Local Roaming\n",
|
|
+ unicast_packet->dest,
|
|
+ ethhdr->h_dest);
|
|
/* at this point the mesh destination should have been
|
|
* substituted with the originator address found in the global
|
|
* table. If not, let the packet go untouched anyway because
|
|
@@ -986,10 +985,10 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
|
|
*/
|
|
if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
|
|
ethhdr->h_dest)) {
|
|
- net_ratelimited_function(batadv_dbg, BATADV_DBG_TT, bat_priv,
|
|
- "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
|
|
- unicast_packet->dest, ethhdr->h_dest,
|
|
- old_ttvn, curr_ttvn);
|
|
+ batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv,
|
|
+ "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
|
|
+ unicast_packet->dest, ethhdr->h_dest,
|
|
+ old_ttvn, curr_ttvn);
|
|
return 1;
|
|
}
|
|
|
|
@@ -1229,46 +1228,76 @@ int batadv_recv_vis_packet(struct sk_buff *skb,
|
|
struct batadv_vis_packet *vis_packet;
|
|
struct ethhdr *ethhdr;
|
|
struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
|
|
+ struct batadv_orig_node *orig_node = NULL;
|
|
+ struct batadv_hard_iface *primary_if = NULL;
|
|
+ int res, ret = NET_RX_DROP;
|
|
int hdr_size = sizeof(*vis_packet);
|
|
|
|
+ primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
+ if (!primary_if)
|
|
+ goto out;
|
|
+
|
|
/* keep skb linear */
|
|
if (skb_linearize(skb) < 0)
|
|
- return NET_RX_DROP;
|
|
+ goto out;
|
|
|
|
if (unlikely(!pskb_may_pull(skb, hdr_size)))
|
|
- return NET_RX_DROP;
|
|
+ goto out;
|
|
|
|
vis_packet = (struct batadv_vis_packet *)skb->data;
|
|
ethhdr = eth_hdr(skb);
|
|
|
|
/* not for me */
|
|
if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest))
|
|
- return NET_RX_DROP;
|
|
+ goto out;
|
|
|
|
/* ignore own packets */
|
|
if (batadv_is_my_mac(bat_priv, vis_packet->vis_orig))
|
|
- return NET_RX_DROP;
|
|
+ goto out;
|
|
|
|
if (batadv_is_my_mac(bat_priv, vis_packet->sender_orig))
|
|
- return NET_RX_DROP;
|
|
-
|
|
- switch (vis_packet->vis_type) {
|
|
- case BATADV_VIS_TYPE_SERVER_SYNC:
|
|
- batadv_receive_server_sync_packet(bat_priv, vis_packet,
|
|
- skb_headlen(skb));
|
|
- break;
|
|
+ goto out;
|
|
|
|
- case BATADV_VIS_TYPE_CLIENT_UPDATE:
|
|
- batadv_receive_client_update_packet(bat_priv, vis_packet,
|
|
- skb_headlen(skb));
|
|
- break;
|
|
+ /* for me?? */
|
|
+ if (batadv_is_my_mac(bat_priv, vis_packet->target_orig))
|
|
+ goto out;
|
|
|
|
- default: /* ignore unknown packet */
|
|
- break;
|
|
+ /* TTL exceeded */
|
|
+ if (vis_packet->header.ttl < 2) {
|
|
+ pr_debug("Warning - can't forward vis packet from %pM to %pM: ttl exceeded\n",
|
|
+ ethhdr->h_source, vis_packet->target_orig);
|
|
+ goto out;
|
|
}
|
|
|
|
- /* We take a copy of the data in the packet, so we should
|
|
- * always free the skbuf.
|
|
- */
|
|
- return NET_RX_DROP;
|
|
+ /* get routing information */
|
|
+ orig_node = batadv_orig_hash_find(bat_priv, vis_packet->target_orig);
|
|
+
|
|
+ if (!orig_node)
|
|
+ goto out;
|
|
+
|
|
+ /* create a copy of the skb, if needed, to modify it. */
|
|
+ if (skb_cow(skb, ETH_HLEN) < 0)
|
|
+ goto out;
|
|
+
|
|
+ vis_packet = (struct batadv_vis_packet *)skb->data;
|
|
+
|
|
+ /* decrement ttl */
|
|
+ vis_packet->header.ttl--;
|
|
+
|
|
+ memcpy(vis_packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
|
|
+
|
|
+ res = batadv_send_skb_to_orig(skb, orig_node, recv_if);
|
|
+
|
|
+ /* translate transmit result into receive result */
|
|
+ if (res == NET_XMIT_SUCCESS)
|
|
+ ret = NET_RX_SUCCESS;
|
|
+
|
|
+out:
|
|
+ if (orig_node)
|
|
+ batadv_orig_node_free_ref(orig_node);
|
|
+
|
|
+ if (primary_if)
|
|
+ batadv_hardif_free_ref(primary_if);
|
|
+
|
|
+ return ret;
|
|
}
|
|
diff --git send.c send.c
|
|
index e9ff8d8..853fcb8 100644
|
|
--- send.c
|
|
+++ send.c
|
|
@@ -24,7 +24,6 @@
|
|
#include "translation-table.h"
|
|
#include "soft-interface.h"
|
|
#include "hard-interface.h"
|
|
-#include "vis.h"
|
|
#include "gateway_common.h"
|
|
#include "originator.h"
|
|
#include "network-coding.h"
|
|
@@ -272,6 +271,10 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work)
|
|
if (forw_packet->num_packets >= hard_iface->num_bcasts)
|
|
continue;
|
|
|
|
+ if (atomic_read(&hard_iface->no_rebroadcast) &&
|
|
+ forw_packet->skb->dev == hard_iface->net_dev)
|
|
+ continue;
|
|
+
|
|
/* send a copy of the saved skb */
|
|
skb1 = skb_clone(forw_packet->skb, GFP_ATOMIC);
|
|
if (skb1)
|
|
diff --git soft-interface.c soft-interface.c
|
|
index 33b6144..c5d4743 100644
|
|
--- soft-interface.c
|
|
+++ soft-interface.c
|
|
@@ -324,6 +324,11 @@ void batadv_interface_rx(struct net_device *soft_iface,
|
|
skb_pull_rcsum(skb, hdr_size);
|
|
skb_reset_mac_header(skb);
|
|
|
|
+ /* clean the netfilter state now that the batman-adv header has been
|
|
+ * removed
|
|
+ */
|
|
+ nf_reset(skb);
|
|
+
|
|
ethhdr = eth_hdr(skb);
|
|
|
|
switch (ntohs(ethhdr->h_proto)) {
|
|
@@ -467,7 +472,6 @@ static int batadv_softif_init_late(struct net_device *dev)
|
|
atomic_set(&bat_priv->distributed_arp_table, 1);
|
|
#endif
|
|
atomic_set(&bat_priv->ap_isolation, 0);
|
|
- atomic_set(&bat_priv->vis_mode, BATADV_VIS_TYPE_CLIENT_UPDATE);
|
|
atomic_set(&bat_priv->gw_mode, BATADV_GW_MODE_OFF);
|
|
atomic_set(&bat_priv->gw_sel_class, 20);
|
|
atomic_set(&bat_priv->gw_bandwidth, 41);
|
|
@@ -626,7 +630,7 @@ static void batadv_softif_init_early(struct net_device *dev)
|
|
/* generate random address */
|
|
eth_hw_addr_random(dev);
|
|
|
|
- SET_ETHTOOL_OPS(dev, &batadv_ethtool_ops);
|
|
+ dev->ethtool_ops = &batadv_ethtool_ops;
|
|
|
|
memset(priv, 0, sizeof(*priv));
|
|
}
|
|
@@ -637,7 +641,7 @@ struct net_device *batadv_softif_create(const char *name)
|
|
int ret;
|
|
|
|
soft_iface = alloc_netdev(sizeof(struct batadv_priv), name,
|
|
- batadv_softif_init_early);
|
|
+ NET_NAME_UNKNOWN, batadv_softif_init_early);
|
|
if (!soft_iface)
|
|
return NULL;
|
|
|
|
diff --git sysfs-class-net-batman-adv sysfs-class-net-batman-adv
|
|
index bdc0070..88f6f70 100644
|
|
--- sysfs-class-net-batman-adv
|
|
+++ sysfs-class-net-batman-adv
|
|
@@ -13,3 +13,13 @@ Description:
|
|
displays the batman mesh interface this <iface>
|
|
currently is associated with.
|
|
|
|
+What: /sys/class/net/<iface>/batman-adv/no_rebroadcast
|
|
+Date: Sep 2013
|
|
+Contact: Linus Lüssing <linus.luessing@web.de>
|
|
+Description:
|
|
+ With this option set incoming multicast payload frames on
|
|
+ <iface> are not being rebroadcasted on <iface> again. This
|
|
+ option should be set on links which are known to be transitive
|
|
+ and symmetric only, for instance point-to-point wifi longshots
|
|
+ or wired links. Using this option wrongly is going to
|
|
+ break your mesh network, use at your own risk!
|
|
diff --git sysfs.c sysfs.c
|
|
index 929e304..944209a 100644
|
|
--- sysfs.c
|
|
+++ sysfs.c
|
|
@@ -25,7 +25,6 @@
|
|
#include "hard-interface.h"
|
|
#include "gateway_common.h"
|
|
#include "gateway_client.h"
|
|
-#include "vis.h"
|
|
|
|
static struct net_device *batadv_kobj_to_netdev(struct kobject *obj)
|
|
{
|
|
@@ -53,6 +52,17 @@ static char *batadv_uev_type_str[] = {
|
|
"gw"
|
|
};
|
|
|
|
+/* Use this, if you have customized show and store functions
|
|
+ * for hard interface attrs
|
|
+ */
|
|
+#define BATADV_ATTR_HIF(_name, _mode, _show, _store) \
|
|
+struct batadv_attribute batadv_attr_hif_##_name = { \
|
|
+ .attr = {.name = __stringify(_name), \
|
|
+ .mode = _mode }, \
|
|
+ .show = _show, \
|
|
+ .store = _store, \
|
|
+};
|
|
+
|
|
/* Use this, if you have customized show and store functions */
|
|
#define BATADV_ATTR(_name, _mode, _show, _store) \
|
|
struct batadv_attribute batadv_attr_##_name = { \
|
|
@@ -123,6 +133,52 @@ ssize_t batadv_show_##_name(struct kobject *kobj, \
|
|
batadv_store_##_name)
|
|
|
|
|
|
+#define BATADV_ATTR_HIF_STORE_BOOL(_name, _post_func) \
|
|
+ssize_t batadv_store_hif_##_name(struct kobject *kobj, \
|
|
+ struct attribute *attr, char *buff, \
|
|
+ size_t count) \
|
|
+{ \
|
|
+ struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
|
|
+ struct batadv_hard_iface *hard_iface; \
|
|
+ size_t res; \
|
|
+ \
|
|
+ hard_iface = batadv_hardif_get_by_netdev(net_dev); \
|
|
+ if (!hard_iface) \
|
|
+ return 0; \
|
|
+ \
|
|
+ res = __batadv_store_bool_attr(buff, count, _post_func, \
|
|
+ attr, &hard_iface->_name, \
|
|
+ hard_iface->soft_iface); \
|
|
+ batadv_hardif_free_ref(hard_iface); \
|
|
+ return res; \
|
|
+}
|
|
+
|
|
+#define BATADV_ATTR_HIF_SHOW_BOOL(_name) \
|
|
+ssize_t batadv_show_hif_##_name(struct kobject *kobj, \
|
|
+ struct attribute *attr, char *buff) \
|
|
+{ \
|
|
+ struct net_device *net_dev = batadv_kobj_to_netdev(kobj); \
|
|
+ struct batadv_hard_iface *hard_iface; \
|
|
+ size_t res; \
|
|
+ \
|
|
+ hard_iface = batadv_hardif_get_by_netdev(net_dev); \
|
|
+ if (!hard_iface) \
|
|
+ return 0; \
|
|
+ \
|
|
+ res = sprintf(buff, "%s\n", \
|
|
+ atomic_read(&hard_iface->_name) == 0 ? \
|
|
+ "disabled" : "enabled"); \
|
|
+ batadv_hardif_free_ref(hard_iface); \
|
|
+ return res; \
|
|
+}
|
|
+
|
|
+/* Use this, if you are going to turn a [name] in the vlan struct on or off */
|
|
+#define BATADV_ATTR_HIF_BOOL(_name, _mode, _post_func) \
|
|
+ static BATADV_ATTR_HIF_STORE_BOOL(_name, _post_func) \
|
|
+ static BATADV_ATTR_HIF_SHOW_BOOL(_name) \
|
|
+ static BATADV_ATTR_HIF(_name, _mode, batadv_show_hif_##_name, \
|
|
+ batadv_store_hif_##_name)
|
|
+
|
|
static int batadv_store_bool_attr(char *buff, size_t count,
|
|
struct net_device *net_dev,
|
|
const char *attr_name, atomic_t *attr)
|
|
@@ -230,74 +286,6 @@ __batadv_store_uint_attr(const char *buff, size_t count,
|
|
return ret;
|
|
}
|
|
|
|
-static ssize_t batadv_show_vis_mode(struct kobject *kobj,
|
|
- struct attribute *attr, char *buff)
|
|
-{
|
|
- struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj);
|
|
- int vis_mode = atomic_read(&bat_priv->vis_mode);
|
|
- const char *mode;
|
|
-
|
|
- if (vis_mode == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
|
- mode = "client";
|
|
- else
|
|
- mode = "server";
|
|
-
|
|
- return sprintf(buff, "%s\n", mode);
|
|
-}
|
|
-
|
|
-static ssize_t batadv_store_vis_mode(struct kobject *kobj,
|
|
- struct attribute *attr, char *buff,
|
|
- size_t count)
|
|
-{
|
|
- struct net_device *net_dev = batadv_kobj_to_netdev(kobj);
|
|
- struct batadv_priv *bat_priv = netdev_priv(net_dev);
|
|
- unsigned long val;
|
|
- int ret, vis_mode_tmp = -1;
|
|
- const char *old_mode, *new_mode;
|
|
-
|
|
- ret = kstrtoul(buff, 10, &val);
|
|
-
|
|
- if (((count == 2) && (!ret) &&
|
|
- (val == BATADV_VIS_TYPE_CLIENT_UPDATE)) ||
|
|
- (strncmp(buff, "client", 6) == 0) ||
|
|
- (strncmp(buff, "off", 3) == 0))
|
|
- vis_mode_tmp = BATADV_VIS_TYPE_CLIENT_UPDATE;
|
|
-
|
|
- if (((count == 2) && (!ret) &&
|
|
- (val == BATADV_VIS_TYPE_SERVER_SYNC)) ||
|
|
- (strncmp(buff, "server", 6) == 0))
|
|
- vis_mode_tmp = BATADV_VIS_TYPE_SERVER_SYNC;
|
|
-
|
|
- if (vis_mode_tmp < 0) {
|
|
- if (buff[count - 1] == '\n')
|
|
- buff[count - 1] = '\0';
|
|
-
|
|
- batadv_info(net_dev,
|
|
- "Invalid parameter for 'vis mode' setting received: %s\n",
|
|
- buff);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- if (atomic_read(&bat_priv->vis_mode) == vis_mode_tmp)
|
|
- return count;
|
|
-
|
|
- if (atomic_read(&bat_priv->vis_mode) == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
|
- old_mode = "client";
|
|
- else
|
|
- old_mode = "server";
|
|
-
|
|
- if (vis_mode_tmp == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
|
- new_mode = "client";
|
|
- else
|
|
- new_mode = "server";
|
|
-
|
|
- batadv_info(net_dev, "Changing vis mode from: %s to: %s\n", old_mode,
|
|
- new_mode);
|
|
-
|
|
- atomic_set(&bat_priv->vis_mode, (unsigned int)vis_mode_tmp);
|
|
- return count;
|
|
-}
|
|
-
|
|
static ssize_t batadv_show_bat_algo(struct kobject *kobj,
|
|
struct attribute *attr, char *buff)
|
|
{
|
|
@@ -426,8 +414,6 @@ BATADV_ATTR_SIF_BOOL(distributed_arp_table, S_IRUGO | S_IWUSR, NULL);
|
|
#endif
|
|
BATADV_ATTR_SIF_BOOL(fragmentation, S_IRUGO | S_IWUSR, batadv_update_min_mtu);
|
|
BATADV_ATTR_SIF_BOOL(ap_isolation, S_IRUGO | S_IWUSR, NULL);
|
|
-static BATADV_ATTR(vis_mode, S_IRUGO | S_IWUSR, batadv_show_vis_mode,
|
|
- batadv_store_vis_mode);
|
|
static BATADV_ATTR(routing_algo, S_IRUGO, batadv_show_bat_algo, NULL);
|
|
static BATADV_ATTR(gw_mode, S_IRUGO | S_IWUSR, batadv_show_gw_mode,
|
|
batadv_store_gw_mode);
|
|
@@ -457,7 +443,6 @@ static struct batadv_attribute *batadv_mesh_attrs[] = {
|
|
#endif
|
|
&batadv_attr_fragmentation,
|
|
&batadv_attr_ap_isolation,
|
|
- &batadv_attr_vis_mode,
|
|
&batadv_attr_routing_algo,
|
|
&batadv_attr_gw_mode,
|
|
&batadv_attr_orig_interval,
|
|
@@ -642,10 +627,12 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
|
|
static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
|
|
batadv_store_mesh_iface);
|
|
static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
|
|
+BATADV_ATTR_HIF_BOOL(no_rebroadcast, S_IRUGO | S_IWUSR, NULL);
|
|
|
|
static struct batadv_attribute *batadv_batman_attrs[] = {
|
|
&batadv_attr_mesh_iface,
|
|
&batadv_attr_iface_status,
|
|
+ &batadv_attr_hif_no_rebroadcast,
|
|
NULL,
|
|
};
|
|
|
|
diff --git types.h types.h
|
|
index b2c94e1..2c5b80e 100644
|
|
--- types.h
|
|
+++ types.h
|
|
@@ -85,6 +85,7 @@ struct batadv_hard_iface {
|
|
struct rcu_head rcu;
|
|
struct batadv_hard_iface_bat_iv bat_iv;
|
|
struct work_struct cleanup_work;
|
|
+ atomic_t no_rebroadcast;
|
|
};
|
|
|
|
/**
|
|
@@ -430,24 +431,6 @@ struct batadv_priv_gw {
|
|
};
|
|
|
|
/**
|
|
- * struct batadv_priv_vis - per mesh interface vis data
|
|
- * @send_list: list of batadv_vis_info packets to sent
|
|
- * @hash: hash table containing vis data from other nodes in the network
|
|
- * @hash_lock: lock protecting the hash table
|
|
- * @list_lock: lock protecting my_info::recv_list
|
|
- * @work: work queue callback item for vis packet sending
|
|
- * @my_info: holds this node's vis data sent on a regular basis
|
|
- */
|
|
-struct batadv_priv_vis {
|
|
- struct list_head send_list;
|
|
- struct batadv_hashtable *hash;
|
|
- spinlock_t hash_lock; /* protects hash */
|
|
- spinlock_t list_lock; /* protects my_info::recv_list */
|
|
- struct delayed_work work;
|
|
- struct batadv_vis_info *my_info;
|
|
-};
|
|
-
|
|
-/**
|
|
* struct batadv_priv_dat - per mesh interface DAT private data
|
|
* @addr: node DAT address
|
|
* @hash: hashtable representing the local ARP cache
|
|
@@ -504,7 +487,6 @@ struct batadv_priv_nc {
|
|
* enabled
|
|
* @distributed_arp_table: bool indicating whether distributed ARP table is
|
|
* enabled
|
|
- * @vis_mode: vis operation: client or server (see batadv_vis_packettype)
|
|
* @gw_mode: gateway operation: off, client or server (see batadv_gw_modes)
|
|
* @gw_sel_class: gateway selection class (applies if gw_mode client)
|
|
* @gw_bandwidth: gateway announced bandwidth (applies if gw_mode server)
|
|
@@ -531,7 +513,6 @@ struct batadv_priv_nc {
|
|
* @debug_log: holding debug logging relevant data
|
|
* @gw: gateway data
|
|
* @tt: translation table data
|
|
- * @vis: vis data
|
|
* @dat: distributed arp table data
|
|
* @network_coding: bool indicating whether network coding is enabled
|
|
* @batadv_priv_nc: network coding data
|
|
@@ -551,7 +532,6 @@ struct batadv_priv {
|
|
#ifdef CONFIG_BATMAN_ADV_DAT
|
|
atomic_t distributed_arp_table;
|
|
#endif
|
|
- atomic_t vis_mode;
|
|
atomic_t gw_mode;
|
|
atomic_t gw_sel_class;
|
|
atomic_t gw_bandwidth;
|
|
@@ -583,7 +563,6 @@ struct batadv_priv {
|
|
#endif
|
|
struct batadv_priv_gw gw;
|
|
struct batadv_priv_tt tt;
|
|
- struct batadv_priv_vis vis;
|
|
#ifdef CONFIG_BATMAN_ADV_DAT
|
|
struct batadv_priv_dat dat;
|
|
#endif
|
|
@@ -878,66 +857,6 @@ struct batadv_frag_packet_list_entry {
|
|
};
|
|
|
|
/**
|
|
- * struct batadv_vis_info - local data for vis information
|
|
- * @first_seen: timestamp used for purging stale vis info entries
|
|
- * @recv_list: List of server-neighbors we have received this packet from. This
|
|
- * packet should not be re-forward to them again. List elements are struct
|
|
- * batadv_vis_recvlist_node
|
|
- * @send_list: list of packets to be forwarded
|
|
- * @refcount: number of contexts the object is used
|
|
- * @hash_entry: hlist node for batadv_priv_vis::hash
|
|
- * @bat_priv: pointer to soft_iface this orig node belongs to
|
|
- * @skb_packet: contains the vis packet
|
|
- */
|
|
-struct batadv_vis_info {
|
|
- unsigned long first_seen;
|
|
- struct list_head recv_list;
|
|
- struct list_head send_list;
|
|
- struct kref refcount;
|
|
- struct hlist_node hash_entry;
|
|
- struct batadv_priv *bat_priv;
|
|
- struct sk_buff *skb_packet;
|
|
-} __packed;
|
|
-
|
|
-/**
|
|
- * struct batadv_vis_info_entry - contains link information for vis
|
|
- * @src: source MAC of the link, all zero for local TT entry
|
|
- * @dst: destination MAC of the link, client mac address for local TT entry
|
|
- * @quality: transmission quality of the link, or 0 for local TT entry
|
|
- */
|
|
-struct batadv_vis_info_entry {
|
|
- uint8_t src[ETH_ALEN];
|
|
- uint8_t dest[ETH_ALEN];
|
|
- uint8_t quality;
|
|
-} __packed;
|
|
-
|
|
-/**
|
|
- * struct batadv_vis_recvlist_node - list entry for batadv_vis_info::recv_list
|
|
- * @list: list node for batadv_vis_info::recv_list
|
|
- * @mac: MAC address of the originator from where the vis_info was received
|
|
- */
|
|
-struct batadv_vis_recvlist_node {
|
|
- struct list_head list;
|
|
- uint8_t mac[ETH_ALEN];
|
|
-};
|
|
-
|
|
-/**
|
|
- * struct batadv_vis_if_list_entry - auxiliary data for vis data generation
|
|
- * @addr: MAC address of the interface
|
|
- * @primary: true if this interface is the primary interface
|
|
- * @list: list node the interface list
|
|
- *
|
|
- * While scanning for vis-entries of a particular vis-originator
|
|
- * this list collects its interfaces to create a subgraph/cluster
|
|
- * out of them later
|
|
- */
|
|
-struct batadv_vis_if_list_entry {
|
|
- uint8_t addr[ETH_ALEN];
|
|
- bool primary;
|
|
- struct hlist_node list;
|
|
-};
|
|
-
|
|
-/**
|
|
* struct batadv_algo_ops - mesh algorithm callbacks
|
|
* @list: list node for the batadv_algo_list
|
|
* @name: name of the algorithm
|
|
diff --git vis.c vis.c
|
|
deleted file mode 100644
|
|
index 4983340..0000000
|
|
--- vis.c
|
|
+++ /dev/null
|
|
@@ -1,936 +0,0 @@
|
|
-/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
|
|
- *
|
|
- * Simon Wunderlich
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or
|
|
- * modify it under the terms of version 2 of the GNU General Public
|
|
- * License as published by the Free Software Foundation.
|
|
- *
|
|
- * This program is distributed in the hope that it will be useful, but
|
|
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
- * General Public License for more details.
|
|
- *
|
|
- * You should have received a copy of the GNU General Public License
|
|
- * along with this program; if not, write to the Free Software
|
|
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
- * 02110-1301, USA
|
|
- */
|
|
-
|
|
-#include "main.h"
|
|
-#include "send.h"
|
|
-#include "translation-table.h"
|
|
-#include "vis.h"
|
|
-#include "soft-interface.h"
|
|
-#include "hard-interface.h"
|
|
-#include "hash.h"
|
|
-#include "originator.h"
|
|
-
|
|
-#define BATADV_MAX_VIS_PACKET_SIZE 1000
|
|
-
|
|
-/* hash class keys */
|
|
-static struct lock_class_key batadv_vis_hash_lock_class_key;
|
|
-
|
|
-/* free the info */
|
|
-static void batadv_free_info(struct kref *ref)
|
|
-{
|
|
- struct batadv_vis_info *info;
|
|
- struct batadv_priv *bat_priv;
|
|
- struct batadv_vis_recvlist_node *entry, *tmp;
|
|
-
|
|
- info = container_of(ref, struct batadv_vis_info, refcount);
|
|
- bat_priv = info->bat_priv;
|
|
-
|
|
- list_del_init(&info->send_list);
|
|
- spin_lock_bh(&bat_priv->vis.list_lock);
|
|
- list_for_each_entry_safe(entry, tmp, &info->recv_list, list) {
|
|
- list_del(&entry->list);
|
|
- kfree(entry);
|
|
- }
|
|
-
|
|
- spin_unlock_bh(&bat_priv->vis.list_lock);
|
|
- kfree_skb(info->skb_packet);
|
|
- kfree(info);
|
|
-}
|
|
-
|
|
-/* Compare two vis packets, used by the hashing algorithm */
|
|
-static int batadv_vis_info_cmp(const struct hlist_node *node, const void *data2)
|
|
-{
|
|
- const struct batadv_vis_info *d1, *d2;
|
|
- const struct batadv_vis_packet *p1, *p2;
|
|
-
|
|
- d1 = container_of(node, struct batadv_vis_info, hash_entry);
|
|
- d2 = data2;
|
|
- p1 = (struct batadv_vis_packet *)d1->skb_packet->data;
|
|
- p2 = (struct batadv_vis_packet *)d2->skb_packet->data;
|
|
- return batadv_compare_eth(p1->vis_orig, p2->vis_orig);
|
|
-}
|
|
-
|
|
-/* hash function to choose an entry in a hash table of given size
|
|
- * hash algorithm from http://en.wikipedia.org/wiki/Hash_table
|
|
- */
|
|
-static uint32_t batadv_vis_info_choose(const void *data, uint32_t size)
|
|
-{
|
|
- const struct batadv_vis_info *vis_info = data;
|
|
- const struct batadv_vis_packet *packet;
|
|
- const unsigned char *key;
|
|
- uint32_t hash = 0;
|
|
- size_t i;
|
|
-
|
|
- packet = (struct batadv_vis_packet *)vis_info->skb_packet->data;
|
|
- key = packet->vis_orig;
|
|
- for (i = 0; i < ETH_ALEN; i++) {
|
|
- hash += key[i];
|
|
- hash += (hash << 10);
|
|
- hash ^= (hash >> 6);
|
|
- }
|
|
-
|
|
- hash += (hash << 3);
|
|
- hash ^= (hash >> 11);
|
|
- hash += (hash << 15);
|
|
-
|
|
- return hash % size;
|
|
-}
|
|
-
|
|
-static struct batadv_vis_info *
|
|
-batadv_vis_hash_find(struct batadv_priv *bat_priv, const void *data)
|
|
-{
|
|
- struct batadv_hashtable *hash = bat_priv->vis.hash;
|
|
- struct hlist_head *head;
|
|
- struct batadv_vis_info *vis_info, *vis_info_tmp = NULL;
|
|
- uint32_t index;
|
|
-
|
|
- if (!hash)
|
|
- return NULL;
|
|
-
|
|
- index = batadv_vis_info_choose(data, hash->size);
|
|
- head = &hash->table[index];
|
|
-
|
|
- rcu_read_lock();
|
|
- hlist_for_each_entry_rcu(vis_info, head, hash_entry) {
|
|
- if (!batadv_vis_info_cmp(&vis_info->hash_entry, data))
|
|
- continue;
|
|
-
|
|
- vis_info_tmp = vis_info;
|
|
- break;
|
|
- }
|
|
- rcu_read_unlock();
|
|
-
|
|
- return vis_info_tmp;
|
|
-}
|
|
-
|
|
-/* insert interface to the list of interfaces of one originator, if it
|
|
- * does not already exist in the list
|
|
- */
|
|
-static void batadv_vis_data_insert_interface(const uint8_t *interface,
|
|
- struct hlist_head *if_list,
|
|
- bool primary)
|
|
-{
|
|
- struct batadv_vis_if_list_entry *entry;
|
|
-
|
|
- hlist_for_each_entry(entry, if_list, list) {
|
|
- if (batadv_compare_eth(entry->addr, interface))
|
|
- return;
|
|
- }
|
|
-
|
|
- /* it's a new address, add it to the list */
|
|
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
|
- if (!entry)
|
|
- return;
|
|
- memcpy(entry->addr, interface, ETH_ALEN);
|
|
- entry->primary = primary;
|
|
- hlist_add_head(&entry->list, if_list);
|
|
-}
|
|
-
|
|
-static void batadv_vis_data_read_prim_sec(struct seq_file *seq,
|
|
- const struct hlist_head *if_list)
|
|
-{
|
|
- struct batadv_vis_if_list_entry *entry;
|
|
-
|
|
- hlist_for_each_entry(entry, if_list, list) {
|
|
- if (entry->primary)
|
|
- seq_puts(seq, "PRIMARY, ");
|
|
- else
|
|
- seq_printf(seq, "SEC %pM, ", entry->addr);
|
|
- }
|
|
-}
|
|
-
|
|
-/* read an entry */
|
|
-static ssize_t
|
|
-batadv_vis_data_read_entry(struct seq_file *seq,
|
|
- const struct batadv_vis_info_entry *entry,
|
|
- const uint8_t *src, bool primary)
|
|
-{
|
|
- if (primary && entry->quality == 0)
|
|
- return seq_printf(seq, "TT %pM, ", entry->dest);
|
|
- else if (batadv_compare_eth(entry->src, src))
|
|
- return seq_printf(seq, "TQ %pM %d, ", entry->dest,
|
|
- entry->quality);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void
|
|
-batadv_vis_data_insert_interfaces(struct hlist_head *list,
|
|
- struct batadv_vis_packet *packet,
|
|
- struct batadv_vis_info_entry *entries)
|
|
-{
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < packet->entries; i++) {
|
|
- if (entries[i].quality == 0)
|
|
- continue;
|
|
-
|
|
- if (batadv_compare_eth(entries[i].src, packet->vis_orig))
|
|
- continue;
|
|
-
|
|
- batadv_vis_data_insert_interface(entries[i].src, list, false);
|
|
- }
|
|
-}
|
|
-
|
|
-static void batadv_vis_data_read_entries(struct seq_file *seq,
|
|
- struct hlist_head *list,
|
|
- struct batadv_vis_packet *packet,
|
|
- struct batadv_vis_info_entry *entries)
|
|
-{
|
|
- int i;
|
|
- struct batadv_vis_if_list_entry *entry;
|
|
-
|
|
- hlist_for_each_entry(entry, list, list) {
|
|
- seq_printf(seq, "%pM,", entry->addr);
|
|
-
|
|
- for (i = 0; i < packet->entries; i++)
|
|
- batadv_vis_data_read_entry(seq, &entries[i],
|
|
- entry->addr, entry->primary);
|
|
-
|
|
- /* add primary/secondary records */
|
|
- if (batadv_compare_eth(entry->addr, packet->vis_orig))
|
|
- batadv_vis_data_read_prim_sec(seq, list);
|
|
-
|
|
- seq_puts(seq, "\n");
|
|
- }
|
|
-}
|
|
-
|
|
-static void batadv_vis_seq_print_text_bucket(struct seq_file *seq,
|
|
- const struct hlist_head *head)
|
|
-{
|
|
- struct batadv_vis_info *info;
|
|
- struct batadv_vis_packet *packet;
|
|
- uint8_t *entries_pos;
|
|
- struct batadv_vis_info_entry *entries;
|
|
- struct batadv_vis_if_list_entry *entry;
|
|
- struct hlist_node *n;
|
|
-
|
|
- HLIST_HEAD(vis_if_list);
|
|
-
|
|
- hlist_for_each_entry_rcu(info, head, hash_entry) {
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
- entries_pos = (uint8_t *)packet + sizeof(*packet);
|
|
- entries = (struct batadv_vis_info_entry *)entries_pos;
|
|
-
|
|
- batadv_vis_data_insert_interface(packet->vis_orig, &vis_if_list,
|
|
- true);
|
|
- batadv_vis_data_insert_interfaces(&vis_if_list, packet,
|
|
- entries);
|
|
- batadv_vis_data_read_entries(seq, &vis_if_list, packet,
|
|
- entries);
|
|
-
|
|
- hlist_for_each_entry_safe(entry, n, &vis_if_list, list) {
|
|
- hlist_del(&entry->list);
|
|
- kfree(entry);
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-int batadv_vis_seq_print_text(struct seq_file *seq, void *offset)
|
|
-{
|
|
- struct batadv_hard_iface *primary_if;
|
|
- struct hlist_head *head;
|
|
- struct net_device *net_dev = (struct net_device *)seq->private;
|
|
- struct batadv_priv *bat_priv = netdev_priv(net_dev);
|
|
- struct batadv_hashtable *hash = bat_priv->vis.hash;
|
|
- uint32_t i;
|
|
- int ret = 0;
|
|
- int vis_server = atomic_read(&bat_priv->vis_mode);
|
|
-
|
|
- primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
- if (!primary_if)
|
|
- goto out;
|
|
-
|
|
- if (vis_server == BATADV_VIS_TYPE_CLIENT_UPDATE)
|
|
- goto out;
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- for (i = 0; i < hash->size; i++) {
|
|
- head = &hash->table[i];
|
|
- batadv_vis_seq_print_text_bucket(seq, head);
|
|
- }
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-
|
|
-out:
|
|
- if (primary_if)
|
|
- batadv_hardif_free_ref(primary_if);
|
|
- return ret;
|
|
-}
|
|
-
|
|
-/* add the info packet to the send list, if it was not
|
|
- * already linked in.
|
|
- */
|
|
-static void batadv_send_list_add(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_info *info)
|
|
-{
|
|
- if (list_empty(&info->send_list)) {
|
|
- kref_get(&info->refcount);
|
|
- list_add_tail(&info->send_list, &bat_priv->vis.send_list);
|
|
- }
|
|
-}
|
|
-
|
|
-/* delete the info packet from the send list, if it was
|
|
- * linked in.
|
|
- */
|
|
-static void batadv_send_list_del(struct batadv_vis_info *info)
|
|
-{
|
|
- if (!list_empty(&info->send_list)) {
|
|
- list_del_init(&info->send_list);
|
|
- kref_put(&info->refcount, batadv_free_info);
|
|
- }
|
|
-}
|
|
-
|
|
-/* tries to add one entry to the receive list. */
|
|
-static void batadv_recv_list_add(struct batadv_priv *bat_priv,
|
|
- struct list_head *recv_list, const char *mac)
|
|
-{
|
|
- struct batadv_vis_recvlist_node *entry;
|
|
-
|
|
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
|
|
- if (!entry)
|
|
- return;
|
|
-
|
|
- memcpy(entry->mac, mac, ETH_ALEN);
|
|
- spin_lock_bh(&bat_priv->vis.list_lock);
|
|
- list_add_tail(&entry->list, recv_list);
|
|
- spin_unlock_bh(&bat_priv->vis.list_lock);
|
|
-}
|
|
-
|
|
-/* returns 1 if this mac is in the recv_list */
|
|
-static int batadv_recv_list_is_in(struct batadv_priv *bat_priv,
|
|
- const struct list_head *recv_list,
|
|
- const char *mac)
|
|
-{
|
|
- const struct batadv_vis_recvlist_node *entry;
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.list_lock);
|
|
- list_for_each_entry(entry, recv_list, list) {
|
|
- if (batadv_compare_eth(entry->mac, mac)) {
|
|
- spin_unlock_bh(&bat_priv->vis.list_lock);
|
|
- return 1;
|
|
- }
|
|
- }
|
|
- spin_unlock_bh(&bat_priv->vis.list_lock);
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/* try to add the packet to the vis_hash. return NULL if invalid (e.g. too old,
|
|
- * broken.. ). vis hash must be locked outside. is_new is set when the packet
|
|
- * is newer than old entries in the hash.
|
|
- */
|
|
-static struct batadv_vis_info *
|
|
-batadv_add_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_packet *vis_packet, int vis_info_len,
|
|
- int *is_new, int make_broadcast)
|
|
-{
|
|
- struct batadv_vis_info *info, *old_info;
|
|
- struct batadv_vis_packet *search_packet, *old_packet;
|
|
- struct batadv_vis_info search_elem;
|
|
- struct batadv_vis_packet *packet;
|
|
- struct sk_buff *tmp_skb;
|
|
- int hash_added;
|
|
- size_t len;
|
|
- size_t max_entries;
|
|
-
|
|
- *is_new = 0;
|
|
- /* sanity check */
|
|
- if (!bat_priv->vis.hash)
|
|
- return NULL;
|
|
-
|
|
- /* see if the packet is already in vis_hash */
|
|
- search_elem.skb_packet = dev_alloc_skb(sizeof(*search_packet));
|
|
- if (!search_elem.skb_packet)
|
|
- return NULL;
|
|
- len = sizeof(*search_packet);
|
|
- tmp_skb = search_elem.skb_packet;
|
|
- search_packet = (struct batadv_vis_packet *)skb_put(tmp_skb, len);
|
|
-
|
|
- memcpy(search_packet->vis_orig, vis_packet->vis_orig, ETH_ALEN);
|
|
- old_info = batadv_vis_hash_find(bat_priv, &search_elem);
|
|
- kfree_skb(search_elem.skb_packet);
|
|
-
|
|
- if (old_info) {
|
|
- tmp_skb = old_info->skb_packet;
|
|
- old_packet = (struct batadv_vis_packet *)tmp_skb->data;
|
|
- if (!batadv_seq_after(ntohl(vis_packet->seqno),
|
|
- ntohl(old_packet->seqno))) {
|
|
- if (old_packet->seqno == vis_packet->seqno) {
|
|
- batadv_recv_list_add(bat_priv,
|
|
- &old_info->recv_list,
|
|
- vis_packet->sender_orig);
|
|
- return old_info;
|
|
- } else {
|
|
- /* newer packet is already in hash. */
|
|
- return NULL;
|
|
- }
|
|
- }
|
|
- /* remove old entry */
|
|
- batadv_hash_remove(bat_priv->vis.hash, batadv_vis_info_cmp,
|
|
- batadv_vis_info_choose, old_info);
|
|
- batadv_send_list_del(old_info);
|
|
- kref_put(&old_info->refcount, batadv_free_info);
|
|
- }
|
|
-
|
|
- info = kmalloc(sizeof(*info), GFP_ATOMIC);
|
|
- if (!info)
|
|
- return NULL;
|
|
-
|
|
- len = sizeof(*packet) + vis_info_len;
|
|
- info->skb_packet = netdev_alloc_skb_ip_align(NULL, len + ETH_HLEN);
|
|
- if (!info->skb_packet) {
|
|
- kfree(info);
|
|
- return NULL;
|
|
- }
|
|
- skb_reserve(info->skb_packet, ETH_HLEN);
|
|
- packet = (struct batadv_vis_packet *)skb_put(info->skb_packet, len);
|
|
-
|
|
- kref_init(&info->refcount);
|
|
- INIT_LIST_HEAD(&info->send_list);
|
|
- INIT_LIST_HEAD(&info->recv_list);
|
|
- info->first_seen = jiffies;
|
|
- info->bat_priv = bat_priv;
|
|
- memcpy(packet, vis_packet, len);
|
|
-
|
|
- /* initialize and add new packet. */
|
|
- *is_new = 1;
|
|
-
|
|
- /* Make it a broadcast packet, if required */
|
|
- if (make_broadcast)
|
|
- memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
|
|
-
|
|
- /* repair if entries is longer than packet. */
|
|
- max_entries = vis_info_len / sizeof(struct batadv_vis_info_entry);
|
|
- if (packet->entries > max_entries)
|
|
- packet->entries = max_entries;
|
|
-
|
|
- batadv_recv_list_add(bat_priv, &info->recv_list, packet->sender_orig);
|
|
-
|
|
- /* try to add it */
|
|
- hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp,
|
|
- batadv_vis_info_choose, info,
|
|
- &info->hash_entry);
|
|
- if (hash_added != 0) {
|
|
- /* did not work (for some reason) */
|
|
- kref_put(&info->refcount, batadv_free_info);
|
|
- info = NULL;
|
|
- }
|
|
-
|
|
- return info;
|
|
-}
|
|
-
|
|
-/* handle the server sync packet, forward if needed. */
|
|
-void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_packet *vis_packet,
|
|
- int vis_info_len)
|
|
-{
|
|
- struct batadv_vis_info *info;
|
|
- int is_new, make_broadcast;
|
|
- int vis_server = atomic_read(&bat_priv->vis_mode);
|
|
-
|
|
- make_broadcast = (vis_server == BATADV_VIS_TYPE_SERVER_SYNC);
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- info = batadv_add_packet(bat_priv, vis_packet, vis_info_len,
|
|
- &is_new, make_broadcast);
|
|
- if (!info)
|
|
- goto end;
|
|
-
|
|
- /* only if we are server ourselves and packet is newer than the one in
|
|
- * hash.
|
|
- */
|
|
- if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC && is_new)
|
|
- batadv_send_list_add(bat_priv, info);
|
|
-end:
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-}
|
|
-
|
|
-/* handle an incoming client update packet and schedule forward if needed. */
|
|
-void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_packet *vis_packet,
|
|
- int vis_info_len)
|
|
-{
|
|
- struct batadv_vis_info *info;
|
|
- struct batadv_vis_packet *packet;
|
|
- int is_new;
|
|
- int vis_server = atomic_read(&bat_priv->vis_mode);
|
|
- int are_target = 0;
|
|
-
|
|
- /* clients shall not broadcast. */
|
|
- if (is_broadcast_ether_addr(vis_packet->target_orig))
|
|
- return;
|
|
-
|
|
- /* Are we the target for this VIS packet? */
|
|
- if (vis_server == BATADV_VIS_TYPE_SERVER_SYNC &&
|
|
- batadv_is_my_mac(bat_priv, vis_packet->target_orig))
|
|
- are_target = 1;
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- info = batadv_add_packet(bat_priv, vis_packet, vis_info_len,
|
|
- &is_new, are_target);
|
|
-
|
|
- if (!info)
|
|
- goto end;
|
|
- /* note that outdated packets will be dropped at this point. */
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
-
|
|
- /* send only if we're the target server or ... */
|
|
- if (are_target && is_new) {
|
|
- packet->vis_type = BATADV_VIS_TYPE_SERVER_SYNC; /* upgrade! */
|
|
- batadv_send_list_add(bat_priv, info);
|
|
-
|
|
- /* ... we're not the recipient (and thus need to forward). */
|
|
- } else if (!batadv_is_my_mac(bat_priv, packet->target_orig)) {
|
|
- batadv_send_list_add(bat_priv, info);
|
|
- }
|
|
-
|
|
-end:
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-}
|
|
-
|
|
-/* Walk the originators and find the VIS server with the best tq. Set the packet
|
|
- * address to its address and return the best_tq.
|
|
- *
|
|
- * Must be called with the originator hash locked
|
|
- */
|
|
-static int batadv_find_best_vis_server(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_info *info)
|
|
-{
|
|
- struct batadv_hashtable *hash = bat_priv->orig_hash;
|
|
- struct batadv_neigh_node *router;
|
|
- struct hlist_head *head;
|
|
- struct batadv_orig_node *orig_node;
|
|
- struct batadv_vis_packet *packet;
|
|
- int best_tq = -1;
|
|
- uint32_t i;
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
-
|
|
- for (i = 0; i < hash->size; i++) {
|
|
- head = &hash->table[i];
|
|
-
|
|
- rcu_read_lock();
|
|
- hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
|
- router = batadv_orig_node_get_router(orig_node);
|
|
- if (!router)
|
|
- continue;
|
|
-
|
|
- if ((orig_node->flags & BATADV_VIS_SERVER) &&
|
|
- (router->tq_avg > best_tq)) {
|
|
- best_tq = router->tq_avg;
|
|
- memcpy(packet->target_orig, orig_node->orig,
|
|
- ETH_ALEN);
|
|
- }
|
|
- batadv_neigh_node_free_ref(router);
|
|
- }
|
|
- rcu_read_unlock();
|
|
- }
|
|
-
|
|
- return best_tq;
|
|
-}
|
|
-
|
|
-/* Return true if the vis packet is full. */
|
|
-static bool batadv_vis_packet_full(const struct batadv_vis_info *info)
|
|
-{
|
|
- const struct batadv_vis_packet *packet;
|
|
- size_t num;
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
- num = BATADV_MAX_VIS_PACKET_SIZE / sizeof(struct batadv_vis_info_entry);
|
|
-
|
|
- if (num < packet->entries + 1)
|
|
- return true;
|
|
- return false;
|
|
-}
|
|
-
|
|
-/* generates a packet of own vis data,
|
|
- * returns 0 on success, -1 if no packet could be generated
|
|
- */
|
|
-static int batadv_generate_vis_packet(struct batadv_priv *bat_priv)
|
|
-{
|
|
- struct batadv_hashtable *hash = bat_priv->orig_hash;
|
|
- struct hlist_head *head;
|
|
- struct batadv_orig_node *orig_node;
|
|
- struct batadv_neigh_node *router;
|
|
- struct batadv_vis_info *info = bat_priv->vis.my_info;
|
|
- struct batadv_vis_packet *packet;
|
|
- struct batadv_vis_info_entry *entry;
|
|
- struct batadv_tt_common_entry *tt_common_entry;
|
|
- uint8_t *packet_pos;
|
|
- int best_tq = -1;
|
|
- uint32_t i;
|
|
-
|
|
- info->first_seen = jiffies;
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
- packet->vis_type = atomic_read(&bat_priv->vis_mode);
|
|
-
|
|
- memcpy(packet->target_orig, batadv_broadcast_addr, ETH_ALEN);
|
|
- packet->header.ttl = BATADV_TTL;
|
|
- packet->seqno = htonl(ntohl(packet->seqno) + 1);
|
|
- packet->entries = 0;
|
|
- packet->reserved = 0;
|
|
- skb_trim(info->skb_packet, sizeof(*packet));
|
|
-
|
|
- if (packet->vis_type == BATADV_VIS_TYPE_CLIENT_UPDATE) {
|
|
- best_tq = batadv_find_best_vis_server(bat_priv, info);
|
|
-
|
|
- if (best_tq < 0)
|
|
- return best_tq;
|
|
- }
|
|
-
|
|
- for (i = 0; i < hash->size; i++) {
|
|
- head = &hash->table[i];
|
|
-
|
|
- rcu_read_lock();
|
|
- hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
|
|
- router = batadv_orig_node_get_router(orig_node);
|
|
- if (!router)
|
|
- continue;
|
|
-
|
|
- if (!batadv_compare_eth(router->addr, orig_node->orig))
|
|
- goto next;
|
|
-
|
|
- if (router->if_incoming->if_status != BATADV_IF_ACTIVE)
|
|
- goto next;
|
|
-
|
|
- if (router->tq_avg < 1)
|
|
- goto next;
|
|
-
|
|
- /* fill one entry into buffer. */
|
|
- packet_pos = skb_put(info->skb_packet, sizeof(*entry));
|
|
- entry = (struct batadv_vis_info_entry *)packet_pos;
|
|
- memcpy(entry->src,
|
|
- router->if_incoming->net_dev->dev_addr,
|
|
- ETH_ALEN);
|
|
- memcpy(entry->dest, orig_node->orig, ETH_ALEN);
|
|
- entry->quality = router->tq_avg;
|
|
- packet->entries++;
|
|
-
|
|
-next:
|
|
- batadv_neigh_node_free_ref(router);
|
|
-
|
|
- if (batadv_vis_packet_full(info))
|
|
- goto unlock;
|
|
- }
|
|
- rcu_read_unlock();
|
|
- }
|
|
-
|
|
- hash = bat_priv->tt.local_hash;
|
|
-
|
|
- for (i = 0; i < hash->size; i++) {
|
|
- head = &hash->table[i];
|
|
-
|
|
- rcu_read_lock();
|
|
- hlist_for_each_entry_rcu(tt_common_entry, head,
|
|
- hash_entry) {
|
|
- packet_pos = skb_put(info->skb_packet, sizeof(*entry));
|
|
- entry = (struct batadv_vis_info_entry *)packet_pos;
|
|
- memset(entry->src, 0, ETH_ALEN);
|
|
- memcpy(entry->dest, tt_common_entry->addr, ETH_ALEN);
|
|
- entry->quality = 0; /* 0 means TT */
|
|
- packet->entries++;
|
|
-
|
|
- if (batadv_vis_packet_full(info))
|
|
- goto unlock;
|
|
- }
|
|
- rcu_read_unlock();
|
|
- }
|
|
-
|
|
- return 0;
|
|
-
|
|
-unlock:
|
|
- rcu_read_unlock();
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/* free old vis packets. Must be called with this vis_hash_lock
|
|
- * held
|
|
- */
|
|
-static void batadv_purge_vis_packets(struct batadv_priv *bat_priv)
|
|
-{
|
|
- uint32_t i;
|
|
- struct batadv_hashtable *hash = bat_priv->vis.hash;
|
|
- struct hlist_node *node_tmp;
|
|
- struct hlist_head *head;
|
|
- struct batadv_vis_info *info;
|
|
-
|
|
- for (i = 0; i < hash->size; i++) {
|
|
- head = &hash->table[i];
|
|
-
|
|
- hlist_for_each_entry_safe(info, node_tmp,
|
|
- head, hash_entry) {
|
|
- /* never purge own data. */
|
|
- if (info == bat_priv->vis.my_info)
|
|
- continue;
|
|
-
|
|
- if (batadv_has_timed_out(info->first_seen,
|
|
- BATADV_VIS_TIMEOUT)) {
|
|
- hlist_del(&info->hash_entry);
|
|
- batadv_send_list_del(info);
|
|
- kref_put(&info->refcount, batadv_free_info);
|
|
- }
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-static void batadv_broadcast_vis_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_info *info)
|
|
-{
|
|
- struct batadv_hashtable *hash = bat_priv->orig_hash;
|
|
- struct hlist_head *head;
|
|
- struct batadv_orig_node *orig_node;
|
|
- struct batadv_vis_packet *packet;
|
|
- struct sk_buff *skb;
|
|
- uint32_t i, res;
|
|
-
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
-
|
|
- /* send to all routers in range. */
|
|
- 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 it's a vis server and reachable, send it. */
|
|
- if (!(orig_node->flags & BATADV_VIS_SERVER))
|
|
- continue;
|
|
-
|
|
- /* don't send it if we already received the packet from
|
|
- * this node.
|
|
- */
|
|
- if (batadv_recv_list_is_in(bat_priv, &info->recv_list,
|
|
- orig_node->orig))
|
|
- continue;
|
|
-
|
|
- memcpy(packet->target_orig, orig_node->orig, ETH_ALEN);
|
|
- skb = skb_clone(info->skb_packet, GFP_ATOMIC);
|
|
- if (!skb)
|
|
- continue;
|
|
-
|
|
- res = batadv_send_skb_to_orig(skb, orig_node, NULL);
|
|
- if (res == NET_XMIT_DROP)
|
|
- kfree_skb(skb);
|
|
- }
|
|
- rcu_read_unlock();
|
|
- }
|
|
-}
|
|
-
|
|
-static void batadv_unicast_vis_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_info *info)
|
|
-{
|
|
- struct batadv_orig_node *orig_node;
|
|
- struct sk_buff *skb;
|
|
- struct batadv_vis_packet *packet;
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
-
|
|
- orig_node = batadv_orig_hash_find(bat_priv, packet->target_orig);
|
|
- if (!orig_node)
|
|
- goto out;
|
|
-
|
|
- skb = skb_clone(info->skb_packet, GFP_ATOMIC);
|
|
- if (!skb)
|
|
- goto out;
|
|
-
|
|
- if (batadv_send_skb_to_orig(skb, orig_node, NULL) == NET_XMIT_DROP)
|
|
- kfree_skb(skb);
|
|
-
|
|
-out:
|
|
- if (orig_node)
|
|
- batadv_orig_node_free_ref(orig_node);
|
|
-}
|
|
-
|
|
-/* only send one vis packet. called from batadv_send_vis_packets() */
|
|
-static void batadv_send_vis_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_info *info)
|
|
-{
|
|
- struct batadv_hard_iface *primary_if;
|
|
- struct batadv_vis_packet *packet;
|
|
-
|
|
- primary_if = batadv_primary_if_get_selected(bat_priv);
|
|
- if (!primary_if)
|
|
- goto out;
|
|
-
|
|
- packet = (struct batadv_vis_packet *)info->skb_packet->data;
|
|
- if (packet->header.ttl < 2) {
|
|
- pr_debug("Error - can't send vis packet: ttl exceeded\n");
|
|
- goto out;
|
|
- }
|
|
-
|
|
- memcpy(packet->sender_orig, primary_if->net_dev->dev_addr, ETH_ALEN);
|
|
- packet->header.ttl--;
|
|
-
|
|
- if (is_broadcast_ether_addr(packet->target_orig))
|
|
- batadv_broadcast_vis_packet(bat_priv, info);
|
|
- else
|
|
- batadv_unicast_vis_packet(bat_priv, info);
|
|
- packet->header.ttl++; /* restore TTL */
|
|
-
|
|
-out:
|
|
- if (primary_if)
|
|
- batadv_hardif_free_ref(primary_if);
|
|
-}
|
|
-
|
|
-/* called from timer; send (and maybe generate) vis packet. */
|
|
-static void batadv_send_vis_packets(struct work_struct *work)
|
|
-{
|
|
- struct delayed_work *delayed_work;
|
|
- struct batadv_priv *bat_priv;
|
|
- struct batadv_priv_vis *priv_vis;
|
|
- struct batadv_vis_info *info;
|
|
-
|
|
- delayed_work = container_of(work, struct delayed_work, work);
|
|
- priv_vis = container_of(delayed_work, struct batadv_priv_vis, work);
|
|
- bat_priv = container_of(priv_vis, struct batadv_priv, vis);
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- batadv_purge_vis_packets(bat_priv);
|
|
-
|
|
- if (batadv_generate_vis_packet(bat_priv) == 0) {
|
|
- /* schedule if generation was successful */
|
|
- batadv_send_list_add(bat_priv, bat_priv->vis.my_info);
|
|
- }
|
|
-
|
|
- while (!list_empty(&bat_priv->vis.send_list)) {
|
|
- info = list_first_entry(&bat_priv->vis.send_list,
|
|
- typeof(*info), send_list);
|
|
-
|
|
- kref_get(&info->refcount);
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-
|
|
- batadv_send_vis_packet(bat_priv, info);
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- batadv_send_list_del(info);
|
|
- kref_put(&info->refcount, batadv_free_info);
|
|
- }
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-
|
|
- queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
|
|
- msecs_to_jiffies(BATADV_VIS_INTERVAL));
|
|
-}
|
|
-
|
|
-/* init the vis server. this may only be called when if_list is already
|
|
- * initialized (e.g. bat0 is initialized, interfaces have been added)
|
|
- */
|
|
-int batadv_vis_init(struct batadv_priv *bat_priv)
|
|
-{
|
|
- struct batadv_vis_packet *packet;
|
|
- int hash_added;
|
|
- unsigned int len;
|
|
- unsigned long first_seen;
|
|
- struct sk_buff *tmp_skb;
|
|
-
|
|
- if (bat_priv->vis.hash)
|
|
- return 0;
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
-
|
|
- bat_priv->vis.hash = batadv_hash_new(256);
|
|
- if (!bat_priv->vis.hash) {
|
|
- pr_err("Can't initialize vis_hash\n");
|
|
- goto err;
|
|
- }
|
|
-
|
|
- batadv_hash_set_lock_class(bat_priv->vis.hash,
|
|
- &batadv_vis_hash_lock_class_key);
|
|
-
|
|
- bat_priv->vis.my_info = kmalloc(BATADV_MAX_VIS_PACKET_SIZE, GFP_ATOMIC);
|
|
- if (!bat_priv->vis.my_info)
|
|
- goto err;
|
|
-
|
|
- len = sizeof(*packet) + BATADV_MAX_VIS_PACKET_SIZE + ETH_HLEN;
|
|
- bat_priv->vis.my_info->skb_packet = netdev_alloc_skb_ip_align(NULL,
|
|
- len);
|
|
- if (!bat_priv->vis.my_info->skb_packet)
|
|
- goto free_info;
|
|
-
|
|
- skb_reserve(bat_priv->vis.my_info->skb_packet, ETH_HLEN);
|
|
- tmp_skb = bat_priv->vis.my_info->skb_packet;
|
|
- packet = (struct batadv_vis_packet *)skb_put(tmp_skb, sizeof(*packet));
|
|
-
|
|
- /* prefill the vis info */
|
|
- first_seen = jiffies - msecs_to_jiffies(BATADV_VIS_INTERVAL);
|
|
- bat_priv->vis.my_info->first_seen = first_seen;
|
|
- INIT_LIST_HEAD(&bat_priv->vis.my_info->recv_list);
|
|
- INIT_LIST_HEAD(&bat_priv->vis.my_info->send_list);
|
|
- kref_init(&bat_priv->vis.my_info->refcount);
|
|
- bat_priv->vis.my_info->bat_priv = bat_priv;
|
|
- packet->header.version = BATADV_COMPAT_VERSION;
|
|
- packet->header.packet_type = BATADV_VIS;
|
|
- packet->header.ttl = BATADV_TTL;
|
|
- packet->seqno = 0;
|
|
- packet->reserved = 0;
|
|
- packet->entries = 0;
|
|
-
|
|
- INIT_LIST_HEAD(&bat_priv->vis.send_list);
|
|
-
|
|
- hash_added = batadv_hash_add(bat_priv->vis.hash, batadv_vis_info_cmp,
|
|
- batadv_vis_info_choose,
|
|
- bat_priv->vis.my_info,
|
|
- &bat_priv->vis.my_info->hash_entry);
|
|
- if (hash_added != 0) {
|
|
- pr_err("Can't add own vis packet into hash\n");
|
|
- /* not in hash, need to remove it manually. */
|
|
- kref_put(&bat_priv->vis.my_info->refcount, batadv_free_info);
|
|
- goto err;
|
|
- }
|
|
-
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-
|
|
- INIT_DELAYED_WORK(&bat_priv->vis.work, batadv_send_vis_packets);
|
|
- queue_delayed_work(batadv_event_workqueue, &bat_priv->vis.work,
|
|
- msecs_to_jiffies(BATADV_VIS_INTERVAL));
|
|
-
|
|
- return 0;
|
|
-
|
|
-free_info:
|
|
- kfree(bat_priv->vis.my_info);
|
|
- bat_priv->vis.my_info = NULL;
|
|
-err:
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
- batadv_vis_quit(bat_priv);
|
|
- return -ENOMEM;
|
|
-}
|
|
-
|
|
-/* Decrease the reference count on a hash item info */
|
|
-static void batadv_free_info_ref(struct hlist_node *node, void *arg)
|
|
-{
|
|
- struct batadv_vis_info *info;
|
|
-
|
|
- info = container_of(node, struct batadv_vis_info, hash_entry);
|
|
- batadv_send_list_del(info);
|
|
- kref_put(&info->refcount, batadv_free_info);
|
|
-}
|
|
-
|
|
-/* shutdown vis-server */
|
|
-void batadv_vis_quit(struct batadv_priv *bat_priv)
|
|
-{
|
|
- if (!bat_priv->vis.hash)
|
|
- return;
|
|
-
|
|
- cancel_delayed_work_sync(&bat_priv->vis.work);
|
|
-
|
|
- spin_lock_bh(&bat_priv->vis.hash_lock);
|
|
- /* properly remove, kill timers ... */
|
|
- batadv_hash_delete(bat_priv->vis.hash, batadv_free_info_ref, NULL);
|
|
- bat_priv->vis.hash = NULL;
|
|
- bat_priv->vis.my_info = NULL;
|
|
- spin_unlock_bh(&bat_priv->vis.hash_lock);
|
|
-}
|
|
diff --git vis.h vis.h
|
|
deleted file mode 100644
|
|
index ad92b0e..0000000
|
|
--- vis.h
|
|
+++ /dev/null
|
|
@@ -1,36 +0,0 @@
|
|
-/* Copyright (C) 2008-2013 B.A.T.M.A.N. contributors:
|
|
- *
|
|
- * Simon Wunderlich, Marek Lindner
|
|
- *
|
|
- * This program is free software; you can redistribute it and/or
|
|
- * modify it under the terms of version 2 of the GNU General Public
|
|
- * License as published by the Free Software Foundation.
|
|
- *
|
|
- * This program is distributed in the hope that it will be useful, but
|
|
- * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
- * General Public License for more details.
|
|
- *
|
|
- * You should have received a copy of the GNU General Public License
|
|
- * along with this program; if not, write to the Free Software
|
|
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
- * 02110-1301, USA
|
|
- */
|
|
-
|
|
-#ifndef _NET_BATMAN_ADV_VIS_H_
|
|
-#define _NET_BATMAN_ADV_VIS_H_
|
|
-
|
|
-/* timeout of vis packets in milliseconds */
|
|
-#define BATADV_VIS_TIMEOUT 200000
|
|
-
|
|
-int batadv_vis_seq_print_text(struct seq_file *seq, void *offset);
|
|
-void batadv_receive_server_sync_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_packet *vis_packet,
|
|
- int vis_info_len);
|
|
-void batadv_receive_client_update_packet(struct batadv_priv *bat_priv,
|
|
- struct batadv_vis_packet *vis_packet,
|
|
- int vis_info_len);
|
|
-int batadv_vis_init(struct batadv_priv *bat_priv);
|
|
-void batadv_vis_quit(struct batadv_priv *bat_priv);
|
|
-
|
|
-#endif /* _NET_BATMAN_ADV_VIS_H_ */
|