During the Wireless Battle Mesh v9 in Porto (PT) at the beginning of
May, we managed to uncover and fix some important bugs in our new B.A.T.M.A.N. V algorithm. These are the fixes we came up with together with others that I collected in the past weeks: - avoid potential crash due to NULL pointer dereference in B.A.T.M.A.N. V routine when a neigh_ifinfo object is not found, by Sven Eckelmann - avoid use-after-free of skb when counting outgoing bytes, by Florian Westphal - fix neigh_ifinfo object reference counting imbalance when using B.A.T.M.A.N. V, by Sven Eckelmann. Such imbalance may lead to the impossibility of releasing the related netdev object on shutdown - avoid invalid memory access in case of error while allocating bcast_own_sum when a new hard-interface is added, by Sven Eckelmann - ensure originator address is updated in OMG/ELP packet content upon primary interface address change, by Antonio Quartulli - fix integer overflow when computing TQ metric (B.A.T.M.A.N. IV), by Sven Eckelmann - avoid race condition while adding new neigh_node which would result in having two objects mapping to the same physical neighbour, by Linus Lüssing - ensure originator address is initialized in ELP packet content on secondary interfaces, by Marek Lindner -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJXO+ZsAAoJEJ4aZjxxc6bK7UEQALxcPqv2YtQhQCexHAPlmTxg 73uXuXpo0eWPxJh2FElcsHTHSt/l0/m/G8MEWCOfqI8MTeg+UTY5lXCY4iThtiY6 n08nl/CLkPNLuDGzAd7CpCM2jJ1iAzgJEVpUGQ6qoO5ekFvO09U/J/o6E8gDTX4I yc1kR3hcJeLbF6EUXEfTX/2THdFhkYSgHgZoGyM3eu43Zhv/6v454iEpqNxA/Ubr UngJTGSfqf20FidUt+xjbfptltTzj25Cp+VQ2DQ/LOuit0ChECjXwMfk0UkDHlKX bYPm1tcUJ0dzbR7cILMlzzzCSzH00leUk5GYYo59rAxBQiJ2j+92c2K0dcnv8cJJ q+GsZapyQFBIgPWS/TLtG1II3u8YWYvl+nEQXBDtPeRAjGoO4VwSbuatsf+enM8K i0c622iEc0b3cVe5H8reUh7SZMfMT/cQkEgpX5/psf8FWvEzeDv4HI3aUfVuSpck mEZAy59HeLWrF+KTScougv14vyoMmKfUcr5E1Oe4X1Ke9dpVvHGiI9wlqb/J0lfl rIc/5WI3ae/QAXkcPybanPEO8O0pBMP+Y4oCYpWmDu1qYfwZzDaSMqqEALQVVW2I 8Ta1gbzamgZDslf7YDSWOR0iyFAFcnMhT0qU6gv2+RGbcfwD+AGRLu5ufY/th0N3 L6AuFhvT/bxW6jN+iuAS =IACg -----END PGP SIGNATURE----- Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux-merge Antonio Quartulli says: ==================== During the Wireless Battle Mesh v9 in Porto (PT) at the beginning of May, we managed to uncover and fix some important bugs in our new B.A.T.M.A.N. V algorithm. These are the fixes we came up with together with others that I collected in the past weeks: - avoid potential crash due to NULL pointer dereference in B.A.T.M.A.N. V routine when a neigh_ifinfo object is not found, by Sven Eckelmann - avoid use-after-free of skb when counting outgoing bytes, by Florian Westphal - fix neigh_ifinfo object reference counting imbalance when using B.A.T.M.A.N. V, by Sven Eckelmann. Such imbalance may lead to the impossibility of releasing the related netdev object on shutdown - avoid invalid memory access in case of error while allocating bcast_own_sum when a new hard-interface is added, by Sven Eckelmann - ensure originator address is updated in OMG/ELP packet content upon primary interface address change, by Antonio Quartulli - fix integer overflow when computing TQ metric (B.A.T.M.A.N. IV), by Sven Eckelmann - avoid race condition while adding new neigh_node which would result in having two objects mapping to the same physical neighbour, by Linus Lüssing - ensure originator address is initialized in ELP packet content on secondary interfaces, by Marek Lindner ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e22cb5e787
|
@ -157,10 +157,8 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
|
|||
orig_node->bat_iv.bcast_own = data_ptr;
|
||||
|
||||
data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC);
|
||||
if (!data_ptr) {
|
||||
kfree(orig_node->bat_iv.bcast_own);
|
||||
if (!data_ptr)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum,
|
||||
(max_if_num - 1) * sizeof(u8));
|
||||
|
@ -1182,9 +1180,10 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
|
|||
u8 total_count;
|
||||
u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
|
||||
unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
|
||||
int tq_asym_penalty, inv_asym_penalty, if_num;
|
||||
int if_num;
|
||||
unsigned int tq_asym_penalty, inv_asym_penalty;
|
||||
unsigned int combined_tq;
|
||||
int tq_iface_penalty;
|
||||
unsigned int tq_iface_penalty;
|
||||
bool ret = false;
|
||||
|
||||
/* find corresponding one hop neighbor */
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/rculist.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
|
@ -39,6 +40,16 @@
|
|||
|
||||
static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
struct batadv_hard_iface *primary_if;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
|
||||
if (primary_if) {
|
||||
batadv_v_elp_iface_activate(primary_if, hard_iface);
|
||||
batadv_hardif_put(primary_if);
|
||||
}
|
||||
|
||||
/* B.A.T.M.A.N. V does not use any queuing mechanism, therefore it can
|
||||
* set the interface as ACTIVE right away, without any risk of race
|
||||
* condition
|
||||
|
@ -72,16 +83,34 @@ static void batadv_v_iface_disable(struct batadv_hard_iface *hard_iface)
|
|||
batadv_v_elp_iface_disable(hard_iface);
|
||||
}
|
||||
|
||||
static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
}
|
||||
|
||||
static void batadv_v_primary_iface_set(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
batadv_v_elp_primary_iface_set(hard_iface);
|
||||
batadv_v_ogm_primary_iface_set(hard_iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_iface_update_mac - react to hard-interface MAC address change
|
||||
* @hard_iface: the modified interface
|
||||
*
|
||||
* If the modified interface is the primary one, update the originator
|
||||
* address in the ELP and OGM messages to reflect the new MAC address.
|
||||
*/
|
||||
static void batadv_v_iface_update_mac(struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
|
||||
struct batadv_hard_iface *primary_if;
|
||||
|
||||
primary_if = batadv_primary_if_get_selected(bat_priv);
|
||||
if (primary_if != hard_iface)
|
||||
goto out;
|
||||
|
||||
batadv_v_primary_iface_set(hard_iface);
|
||||
out:
|
||||
if (primary_if)
|
||||
batadv_hardif_put(primary_if);
|
||||
}
|
||||
|
||||
static void
|
||||
batadv_v_hardif_neigh_init(struct batadv_hardif_neigh_node *hardif_neigh)
|
||||
{
|
||||
|
@ -255,14 +284,23 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
|
|||
struct batadv_hard_iface *if_outgoing2)
|
||||
{
|
||||
struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
|
||||
int ret = 0;
|
||||
|
||||
ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
|
||||
if (WARN_ON(!ifinfo1))
|
||||
goto err_ifinfo1;
|
||||
|
||||
ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
|
||||
if (WARN_ON(!ifinfo2))
|
||||
goto err_ifinfo2;
|
||||
|
||||
if (WARN_ON(!ifinfo1 || !ifinfo2))
|
||||
return 0;
|
||||
ret = ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
|
||||
|
||||
return ifinfo1->bat_v.throughput - ifinfo2->bat_v.throughput;
|
||||
batadv_neigh_ifinfo_put(ifinfo2);
|
||||
err_ifinfo2:
|
||||
batadv_neigh_ifinfo_put(ifinfo1);
|
||||
err_ifinfo1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
|
||||
|
@ -272,14 +310,26 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
|
|||
{
|
||||
struct batadv_neigh_ifinfo *ifinfo1, *ifinfo2;
|
||||
u32 threshold;
|
||||
bool ret = false;
|
||||
|
||||
ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
|
||||
if (WARN_ON(!ifinfo1))
|
||||
goto err_ifinfo1;
|
||||
|
||||
ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
|
||||
if (WARN_ON(!ifinfo2))
|
||||
goto err_ifinfo2;
|
||||
|
||||
threshold = ifinfo1->bat_v.throughput / 4;
|
||||
threshold = ifinfo1->bat_v.throughput - threshold;
|
||||
|
||||
return ifinfo2->bat_v.throughput > threshold;
|
||||
ret = ifinfo2->bat_v.throughput > threshold;
|
||||
|
||||
batadv_neigh_ifinfo_put(ifinfo2);
|
||||
err_ifinfo2:
|
||||
batadv_neigh_ifinfo_put(ifinfo1);
|
||||
err_ifinfo1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct batadv_algo_ops batadv_batman_v __read_mostly = {
|
||||
|
|
|
@ -376,6 +376,27 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
|
|||
hard_iface->bat_v.elp_skb = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_elp_iface_activate - update the ELP buffer belonging to the given
|
||||
* hard-interface
|
||||
* @primary_iface: the new primary interface
|
||||
* @hard_iface: interface holding the to-be-updated buffer
|
||||
*/
|
||||
void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface,
|
||||
struct batadv_hard_iface *hard_iface)
|
||||
{
|
||||
struct batadv_elp_packet *elp_packet;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!hard_iface->bat_v.elp_skb)
|
||||
return;
|
||||
|
||||
skb = hard_iface->bat_v.elp_skb;
|
||||
elp_packet = (struct batadv_elp_packet *)skb->data;
|
||||
ether_addr_copy(elp_packet->orig,
|
||||
primary_iface->net_dev->dev_addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_v_elp_primary_iface_set - change internal data to reflect the new
|
||||
* primary interface
|
||||
|
@ -384,8 +405,6 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
|
|||
void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
|
||||
{
|
||||
struct batadv_hard_iface *hard_iface;
|
||||
struct batadv_elp_packet *elp_packet;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* update orig field of every elp iface belonging to this mesh */
|
||||
rcu_read_lock();
|
||||
|
@ -393,13 +412,7 @@ void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
|
|||
if (primary_iface->soft_iface != hard_iface->soft_iface)
|
||||
continue;
|
||||
|
||||
if (!hard_iface->bat_v.elp_skb)
|
||||
continue;
|
||||
|
||||
skb = hard_iface->bat_v.elp_skb;
|
||||
elp_packet = (struct batadv_elp_packet *)skb->data;
|
||||
ether_addr_copy(elp_packet->orig,
|
||||
primary_iface->net_dev->dev_addr);
|
||||
batadv_v_elp_iface_activate(primary_iface, hard_iface);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ struct work_struct;
|
|||
|
||||
int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface);
|
||||
void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface);
|
||||
void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface,
|
||||
struct batadv_hard_iface *hard_iface);
|
||||
void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface);
|
||||
int batadv_v_elp_packet_recv(struct sk_buff *skb,
|
||||
struct batadv_hard_iface *if_incoming);
|
||||
|
|
|
@ -619,6 +619,8 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
|
|||
struct batadv_neigh_node *neigh_node;
|
||||
struct batadv_hardif_neigh_node *hardif_neigh = NULL;
|
||||
|
||||
spin_lock_bh(&orig_node->neigh_list_lock);
|
||||
|
||||
neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
|
||||
if (neigh_node)
|
||||
goto out;
|
||||
|
@ -650,15 +652,15 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
|
|||
kref_init(&neigh_node->refcount);
|
||||
kref_get(&neigh_node->refcount);
|
||||
|
||||
spin_lock_bh(&orig_node->neigh_list_lock);
|
||||
hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
|
||||
spin_unlock_bh(&orig_node->neigh_list_lock);
|
||||
|
||||
batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
|
||||
"Creating new neighbor %pM for orig_node %pM on interface %s\n",
|
||||
neigh_addr, orig_node->orig, hard_iface->net_dev->name);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&orig_node->neigh_list_lock);
|
||||
|
||||
if (hardif_neigh)
|
||||
batadv_hardif_neigh_put(hardif_neigh);
|
||||
return neigh_node;
|
||||
|
|
|
@ -601,6 +601,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
|
|||
struct batadv_unicast_packet *unicast_packet;
|
||||
struct ethhdr *ethhdr = eth_hdr(skb);
|
||||
int res, hdr_len, ret = NET_RX_DROP;
|
||||
unsigned int len;
|
||||
|
||||
unicast_packet = (struct batadv_unicast_packet *)skb->data;
|
||||
|
||||
|
@ -641,6 +642,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
|
|||
if (hdr_len > 0)
|
||||
batadv_skb_set_priority(skb, hdr_len);
|
||||
|
||||
len = skb->len;
|
||||
res = batadv_send_skb_to_orig(skb, orig_node, recv_if);
|
||||
|
||||
/* translate transmit result into receive result */
|
||||
|
@ -648,7 +650,7 @@ static int batadv_route_unicast_packet(struct sk_buff *skb,
|
|||
/* skb was transmitted and consumed */
|
||||
batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
|
||||
batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
|
||||
skb->len + ETH_HLEN);
|
||||
len + ETH_HLEN);
|
||||
|
||||
ret = NET_RX_SUCCESS;
|
||||
} else if (res == NET_XMIT_POLICED) {
|
||||
|
|
Loading…
Reference in New Issue