Commit c1f066d4 authored by David S. Miller's avatar David S. Miller

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

Antonio Quartulli says:

====================
Included changes:
- avoid integer overflow in GW selection routine
- prevent race condition by making capability bit changes atomic (use
  clear/set/test_bit)
- fix synchronization issue in mcast tvlv handler
- fix crash on double list removal of TT Request objects
- fix leak by puring packets enqueued for sending upon iface removal
- ensure network header pointer is set in skb
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2bd736fa 53cf037b
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "main.h" #include "main.h"
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -453,7 +454,7 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res, ...@@ -453,7 +454,7 @@ static bool batadv_is_orig_node_eligible(struct batadv_dat_candidate *res,
int j; int j;
/* check if orig node candidate is running DAT */ /* check if orig node candidate is running DAT */
if (!(candidate->capabilities & BATADV_ORIG_CAPA_HAS_DAT)) if (!test_bit(BATADV_ORIG_CAPA_HAS_DAT, &candidate->capabilities))
goto out; goto out;
/* Check if this node has already been selected... */ /* Check if this node has already been selected... */
...@@ -713,9 +714,9 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, ...@@ -713,9 +714,9 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
uint16_t tvlv_value_len) uint16_t tvlv_value_len)
{ {
if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_DAT; clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
else else
orig->capabilities |= BATADV_ORIG_CAPA_HAS_DAT; set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
} }
/** /**
......
...@@ -153,15 +153,11 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) ...@@ -153,15 +153,11 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
struct batadv_neigh_node *router; struct batadv_neigh_node *router;
struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_neigh_ifinfo *router_ifinfo;
struct batadv_gw_node *gw_node, *curr_gw = NULL; struct batadv_gw_node *gw_node, *curr_gw = NULL;
uint32_t max_gw_factor = 0, tmp_gw_factor = 0; uint64_t max_gw_factor = 0, tmp_gw_factor = 0;
uint32_t gw_divisor;
uint8_t max_tq = 0; uint8_t max_tq = 0;
uint8_t tq_avg; uint8_t tq_avg;
struct batadv_orig_node *orig_node; struct batadv_orig_node *orig_node;
gw_divisor = BATADV_TQ_LOCAL_WINDOW_SIZE * BATADV_TQ_LOCAL_WINDOW_SIZE;
gw_divisor *= 64;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) {
if (gw_node->deleted) if (gw_node->deleted)
...@@ -187,7 +183,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) ...@@ -187,7 +183,7 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv)
tmp_gw_factor = tq_avg * tq_avg; tmp_gw_factor = tq_avg * tq_avg;
tmp_gw_factor *= gw_node->bandwidth_down; tmp_gw_factor *= gw_node->bandwidth_down;
tmp_gw_factor *= 100 * 100; tmp_gw_factor *= 100 * 100;
tmp_gw_factor /= gw_divisor; tmp_gw_factor >>= 18;
if ((tmp_gw_factor > max_gw_factor) || if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) && ((tmp_gw_factor == max_gw_factor) &&
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "main.h" #include "main.h"
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -588,19 +590,26 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -588,19 +590,26 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb,
* *
* If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator, * If the BATADV_MCAST_WANT_ALL_UNSNOOPABLES flag of this originator,
* orig, has toggled then this method updates counter and list accordingly. * orig, has toggled then this method updates counter and list accordingly.
*
* Caller needs to hold orig->mcast_handler_lock.
*/ */
static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig, struct batadv_orig_node *orig,
uint8_t mcast_flags) uint8_t mcast_flags)
{ {
struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node;
struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list;
/* switched from flag unset to set */ /* switched from flag unset to set */
if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES && if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES &&
!(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) { !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) {
atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables); atomic_inc(&bat_priv->mcast.num_want_all_unsnoopables);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_add_head_rcu(&orig->mcast_want_all_unsnoopables_node, /* flag checks above + mcast_handler_lock prevents this */
&bat_priv->mcast.want_all_unsnoopables_list); WARN_ON(!hlist_unhashed(node));
hlist_add_head_rcu(node, head);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
/* switched from flag set to unset */ /* switched from flag set to unset */
} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) && } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES) &&
...@@ -608,7 +617,10 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, ...@@ -608,7 +617,10 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables); atomic_dec(&bat_priv->mcast.num_want_all_unsnoopables);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_del_rcu(&orig->mcast_want_all_unsnoopables_node); /* flag checks above + mcast_handler_lock prevents this */
WARN_ON(hlist_unhashed(node));
hlist_del_init_rcu(node);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
} }
} }
...@@ -621,19 +633,26 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, ...@@ -621,19 +633,26 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv,
* *
* If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has * If the BATADV_MCAST_WANT_ALL_IPV4 flag of this originator, orig, has
* toggled then this method updates counter and list accordingly. * toggled then this method updates counter and list accordingly.
*
* Caller needs to hold orig->mcast_handler_lock.
*/ */
static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig, struct batadv_orig_node *orig,
uint8_t mcast_flags) uint8_t mcast_flags)
{ {
struct hlist_node *node = &orig->mcast_want_all_ipv4_node;
struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list;
/* switched from flag unset to set */ /* switched from flag unset to set */
if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 && if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 &&
!(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) { !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) {
atomic_inc(&bat_priv->mcast.num_want_all_ipv4); atomic_inc(&bat_priv->mcast.num_want_all_ipv4);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_add_head_rcu(&orig->mcast_want_all_ipv4_node, /* flag checks above + mcast_handler_lock prevents this */
&bat_priv->mcast.want_all_ipv4_list); WARN_ON(!hlist_unhashed(node));
hlist_add_head_rcu(node, head);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
/* switched from flag set to unset */ /* switched from flag set to unset */
} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) && } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV4) &&
...@@ -641,7 +660,10 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, ...@@ -641,7 +660,10 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
atomic_dec(&bat_priv->mcast.num_want_all_ipv4); atomic_dec(&bat_priv->mcast.num_want_all_ipv4);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_del_rcu(&orig->mcast_want_all_ipv4_node); /* flag checks above + mcast_handler_lock prevents this */
WARN_ON(hlist_unhashed(node));
hlist_del_init_rcu(node);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
} }
} }
...@@ -654,19 +676,26 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, ...@@ -654,19 +676,26 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv,
* *
* If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has * If the BATADV_MCAST_WANT_ALL_IPV6 flag of this originator, orig, has
* toggled then this method updates counter and list accordingly. * toggled then this method updates counter and list accordingly.
*
* Caller needs to hold orig->mcast_handler_lock.
*/ */
static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
struct batadv_orig_node *orig, struct batadv_orig_node *orig,
uint8_t mcast_flags) uint8_t mcast_flags)
{ {
struct hlist_node *node = &orig->mcast_want_all_ipv6_node;
struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list;
/* switched from flag unset to set */ /* switched from flag unset to set */
if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 && if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 &&
!(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) { !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) {
atomic_inc(&bat_priv->mcast.num_want_all_ipv6); atomic_inc(&bat_priv->mcast.num_want_all_ipv6);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_add_head_rcu(&orig->mcast_want_all_ipv6_node, /* flag checks above + mcast_handler_lock prevents this */
&bat_priv->mcast.want_all_ipv6_list); WARN_ON(!hlist_unhashed(node));
hlist_add_head_rcu(node, head);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
/* switched from flag set to unset */ /* switched from flag set to unset */
} else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) && } else if (!(mcast_flags & BATADV_MCAST_WANT_ALL_IPV6) &&
...@@ -674,7 +703,10 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, ...@@ -674,7 +703,10 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv,
atomic_dec(&bat_priv->mcast.num_want_all_ipv6); atomic_dec(&bat_priv->mcast.num_want_all_ipv6);
spin_lock_bh(&bat_priv->mcast.want_lists_lock); spin_lock_bh(&bat_priv->mcast.want_lists_lock);
hlist_del_rcu(&orig->mcast_want_all_ipv6_node); /* flag checks above + mcast_handler_lock prevents this */
WARN_ON(hlist_unhashed(node));
hlist_del_init_rcu(node);
spin_unlock_bh(&bat_priv->mcast.want_lists_lock); spin_unlock_bh(&bat_priv->mcast.want_lists_lock);
} }
} }
...@@ -697,39 +729,42 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, ...@@ -697,39 +729,42 @@ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
uint8_t mcast_flags = BATADV_NO_FLAGS; uint8_t mcast_flags = BATADV_NO_FLAGS;
bool orig_initialized; bool orig_initialized;
orig_initialized = orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST; if (orig_mcast_enabled && tvlv_value &&
(tvlv_value_len >= sizeof(mcast_flags)))
mcast_flags = *(uint8_t *)tvlv_value;
spin_lock_bh(&orig->mcast_handler_lock);
orig_initialized = test_bit(BATADV_ORIG_CAPA_HAS_MCAST,
&orig->capa_initialized);
/* If mcast support is turned on decrease the disabled mcast node /* If mcast support is turned on decrease the disabled mcast node
* counter only if we had increased it for this node before. If this * counter only if we had increased it for this node before. If this
* is a completely new orig_node no need to decrease the counter. * is a completely new orig_node no need to decrease the counter.
*/ */
if (orig_mcast_enabled && if (orig_mcast_enabled &&
!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST)) { !test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities)) {
if (orig_initialized) if (orig_initialized)
atomic_dec(&bat_priv->mcast.num_disabled); atomic_dec(&bat_priv->mcast.num_disabled);
orig->capabilities |= BATADV_ORIG_CAPA_HAS_MCAST; set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
/* If mcast support is being switched off or if this is an initial /* If mcast support is being switched off or if this is an initial
* OGM without mcast support then increase the disabled mcast * OGM without mcast support then increase the disabled mcast
* node counter. * node counter.
*/ */
} else if (!orig_mcast_enabled && } else if (!orig_mcast_enabled &&
(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST || (test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities) ||
!orig_initialized)) { !orig_initialized)) {
atomic_inc(&bat_priv->mcast.num_disabled); atomic_inc(&bat_priv->mcast.num_disabled);
orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_MCAST; clear_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities);
} }
orig->capa_initialized |= BATADV_ORIG_CAPA_HAS_MCAST; set_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized);
if (orig_mcast_enabled && tvlv_value &&
(tvlv_value_len >= sizeof(mcast_flags)))
mcast_flags = *(uint8_t *)tvlv_value;
batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags); batadv_mcast_want_unsnoop_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags); batadv_mcast_want_ipv4_update(bat_priv, orig, mcast_flags);
batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags); batadv_mcast_want_ipv6_update(bat_priv, orig, mcast_flags);
orig->mcast_flags = mcast_flags; orig->mcast_flags = mcast_flags;
spin_unlock_bh(&orig->mcast_handler_lock);
} }
/** /**
...@@ -763,11 +798,15 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig) ...@@ -763,11 +798,15 @@ void batadv_mcast_purge_orig(struct batadv_orig_node *orig)
{ {
struct batadv_priv *bat_priv = orig->bat_priv; struct batadv_priv *bat_priv = orig->bat_priv;
if (!(orig->capabilities & BATADV_ORIG_CAPA_HAS_MCAST) && spin_lock_bh(&orig->mcast_handler_lock);
orig->capa_initialized & BATADV_ORIG_CAPA_HAS_MCAST)
if (!test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capabilities) &&
test_bit(BATADV_ORIG_CAPA_HAS_MCAST, &orig->capa_initialized))
atomic_dec(&bat_priv->mcast.num_disabled); atomic_dec(&bat_priv->mcast.num_disabled);
batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_unsnoop_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_ipv4_update(bat_priv, orig, BATADV_NO_FLAGS);
batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS); batadv_mcast_want_ipv6_update(bat_priv, orig, BATADV_NO_FLAGS);
spin_unlock_bh(&orig->mcast_handler_lock);
} }
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "main.h" #include "main.h"
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
...@@ -134,9 +135,9 @@ static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, ...@@ -134,9 +135,9 @@ static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
uint16_t tvlv_value_len) uint16_t tvlv_value_len)
{ {
if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_NC; clear_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
else else
orig->capabilities |= BATADV_ORIG_CAPA_HAS_NC; set_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
} }
/** /**
...@@ -894,7 +895,7 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, ...@@ -894,7 +895,7 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
goto out; goto out;
/* check if orig node is network coding enabled */ /* check if orig node is network coding enabled */
if (!(orig_node->capabilities & BATADV_ORIG_CAPA_HAS_NC)) if (!test_bit(BATADV_ORIG_CAPA_HAS_NC, &orig_node->capabilities))
goto out; goto out;
/* accept ogms from 'good' neighbors and single hop neighbors */ /* accept ogms from 'good' neighbors and single hop neighbors */
......
...@@ -696,8 +696,13 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, ...@@ -696,8 +696,13 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
orig_node->last_seen = jiffies; orig_node->last_seen = jiffies;
reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS); reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
orig_node->bcast_seqno_reset = reset_time; orig_node->bcast_seqno_reset = reset_time;
#ifdef CONFIG_BATMAN_ADV_MCAST #ifdef CONFIG_BATMAN_ADV_MCAST
orig_node->mcast_flags = BATADV_NO_FLAGS; orig_node->mcast_flags = BATADV_NO_FLAGS;
INIT_HLIST_NODE(&orig_node->mcast_want_all_unsnoopables_node);
INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv4_node);
INIT_HLIST_NODE(&orig_node->mcast_want_all_ipv6_node);
spin_lock_init(&orig_node->mcast_handler_lock);
#endif #endif
/* create a vlan object for the "untagged" LAN */ /* create a vlan object for the "untagged" LAN */
......
...@@ -616,7 +616,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv, ...@@ -616,7 +616,8 @@ batadv_purge_outstanding_packets(struct batadv_priv *bat_priv,
* we delete only packets belonging to the given interface * we delete only packets belonging to the given interface
*/ */
if ((hard_iface) && if ((hard_iface) &&
(forw_packet->if_incoming != hard_iface)) (forw_packet->if_incoming != hard_iface) &&
(forw_packet->if_outgoing != hard_iface))
continue; continue;
spin_unlock_bh(&bat_priv->forw_bcast_list_lock); spin_unlock_bh(&bat_priv->forw_bcast_list_lock);
......
...@@ -202,6 +202,7 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -202,6 +202,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
int gw_mode; int gw_mode;
enum batadv_forw_mode forw_mode; enum batadv_forw_mode forw_mode;
struct batadv_orig_node *mcast_single_orig = NULL; struct batadv_orig_node *mcast_single_orig = NULL;
int network_offset = ETH_HLEN;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
goto dropped; goto dropped;
...@@ -214,14 +215,18 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -214,14 +215,18 @@ static int batadv_interface_tx(struct sk_buff *skb,
case ETH_P_8021Q: case ETH_P_8021Q:
vhdr = vlan_eth_hdr(skb); vhdr = vlan_eth_hdr(skb);
if (vhdr->h_vlan_encapsulated_proto != ethertype) if (vhdr->h_vlan_encapsulated_proto != ethertype) {
network_offset += VLAN_HLEN;
break; break;
}
/* fall through */ /* fall through */
case ETH_P_BATMAN: case ETH_P_BATMAN:
goto dropped; goto dropped;
} }
skb_set_network_header(skb, network_offset);
if (batadv_bla_tx(bat_priv, skb, vid)) if (batadv_bla_tx(bat_priv, skb, vid))
goto dropped; goto dropped;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "main.h" #include "main.h"
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/byteorder/generic.h> #include <linux/byteorder/generic.h>
#include <linux/compiler.h> #include <linux/compiler.h>
...@@ -1879,7 +1880,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, ...@@ -1879,7 +1880,7 @@ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv,
} }
spin_unlock_bh(list_lock); spin_unlock_bh(list_lock);
} }
orig_node->capa_initialized &= ~BATADV_ORIG_CAPA_HAS_TT; clear_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
} }
static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global, static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
...@@ -2212,7 +2213,7 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) ...@@ -2212,7 +2213,7 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
spin_lock_bh(&bat_priv->tt.req_list_lock); spin_lock_bh(&bat_priv->tt.req_list_lock);
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
list_del(&node->list); list_del_init(&node->list);
kfree(node); kfree(node);
} }
...@@ -2248,7 +2249,7 @@ static void batadv_tt_req_purge(struct batadv_priv *bat_priv) ...@@ -2248,7 +2249,7 @@ static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
if (batadv_has_timed_out(node->issued_at, if (batadv_has_timed_out(node->issued_at,
BATADV_TT_REQUEST_TIMEOUT)) { BATADV_TT_REQUEST_TIMEOUT)) {
list_del(&node->list); list_del_init(&node->list);
kfree(node); kfree(node);
} }
} }
...@@ -2530,7 +2531,8 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, ...@@ -2530,7 +2531,8 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv,
batadv_hardif_free_ref(primary_if); batadv_hardif_free_ref(primary_if);
if (ret && tt_req_node) { if (ret && tt_req_node) {
spin_lock_bh(&bat_priv->tt.req_list_lock); spin_lock_bh(&bat_priv->tt.req_list_lock);
list_del(&tt_req_node->list); /* list_del_init() verifies tt_req_node still is in the list */
list_del_init(&tt_req_node->list);
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
kfree(tt_req_node); kfree(tt_req_node);
} }
...@@ -2838,7 +2840,7 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, ...@@ -2838,7 +2840,7 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,
return; return;
} }
} }
orig_node->capa_initialized |= BATADV_ORIG_CAPA_HAS_TT; set_bit(BATADV_ORIG_CAPA_HAS_TT, &orig_node->capa_initialized);
} }
static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,
...@@ -2967,7 +2969,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, ...@@ -2967,7 +2969,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
if (!batadv_compare_eth(node->addr, resp_src)) if (!batadv_compare_eth(node->addr, resp_src))
continue; continue;
list_del(&node->list); list_del_init(&node->list);
kfree(node); kfree(node);
} }
...@@ -3340,7 +3342,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, ...@@ -3340,7 +3342,8 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
bool has_tt_init; bool has_tt_init;
tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff; tt_vlan = (struct batadv_tvlv_tt_vlan_data *)tt_buff;
has_tt_init = orig_node->capa_initialized & BATADV_ORIG_CAPA_HAS_TT; has_tt_init = test_bit(BATADV_ORIG_CAPA_HAS_TT,
&orig_node->capa_initialized);
/* orig table not initialised AND first diff is in the OGM OR the ttvn /* orig table not initialised AND first diff is in the OGM OR the ttvn
* increased by one -> we can apply the attached changes * increased by one -> we can apply the attached changes
......
...@@ -221,6 +221,7 @@ struct batadv_orig_bat_iv { ...@@ -221,6 +221,7 @@ struct batadv_orig_bat_iv {
* @batadv_dat_addr_t: address of the orig node in the distributed hash * @batadv_dat_addr_t: address of the orig node in the distributed hash
* @last_seen: time when last packet from this node was received * @last_seen: time when last packet from this node was received
* @bcast_seqno_reset: time when the broadcast seqno window was reset * @bcast_seqno_reset: time when the broadcast seqno window was reset
* @mcast_handler_lock: synchronizes mcast-capability and -flag changes
* @mcast_flags: multicast flags announced by the orig node * @mcast_flags: multicast flags announced by the orig node
* @mcast_want_all_unsnoop_node: a list node for the * @mcast_want_all_unsnoop_node: a list node for the
* mcast.want_all_unsnoopables list * mcast.want_all_unsnoopables list
...@@ -268,13 +269,15 @@ struct batadv_orig_node { ...@@ -268,13 +269,15 @@ struct batadv_orig_node {
unsigned long last_seen; unsigned long last_seen;
unsigned long bcast_seqno_reset; unsigned long bcast_seqno_reset;
#ifdef CONFIG_BATMAN_ADV_MCAST #ifdef CONFIG_BATMAN_ADV_MCAST
/* synchronizes mcast tvlv specific orig changes */
spinlock_t mcast_handler_lock;
uint8_t mcast_flags; uint8_t mcast_flags;
struct hlist_node mcast_want_all_unsnoopables_node; struct hlist_node mcast_want_all_unsnoopables_node;
struct hlist_node mcast_want_all_ipv4_node; struct hlist_node mcast_want_all_ipv4_node;
struct hlist_node mcast_want_all_ipv6_node; struct hlist_node mcast_want_all_ipv6_node;
#endif #endif
uint8_t capabilities; unsigned long capabilities;
uint8_t capa_initialized; unsigned long capa_initialized;
atomic_t last_ttvn; atomic_t last_ttvn;
unsigned char *tt_buff; unsigned char *tt_buff;
int16_t tt_buff_len; int16_t tt_buff_len;
...@@ -313,10 +316,10 @@ struct batadv_orig_node { ...@@ -313,10 +316,10 @@ struct batadv_orig_node {
* (= orig node announces a tvlv of type BATADV_TVLV_MCAST) * (= orig node announces a tvlv of type BATADV_TVLV_MCAST)
*/ */
enum batadv_orig_capabilities { enum batadv_orig_capabilities {
BATADV_ORIG_CAPA_HAS_DAT = BIT(0), BATADV_ORIG_CAPA_HAS_DAT,
BATADV_ORIG_CAPA_HAS_NC = BIT(1), BATADV_ORIG_CAPA_HAS_NC,
BATADV_ORIG_CAPA_HAS_TT = BIT(2), BATADV_ORIG_CAPA_HAS_TT,
BATADV_ORIG_CAPA_HAS_MCAST = BIT(3), BATADV_ORIG_CAPA_HAS_MCAST,
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment