diff options
author | David S. Miller | 2016-05-19 11:51:14 -0700 |
---|---|---|
committer | David S. Miller | 2016-05-19 11:51:14 -0700 |
commit | e22cb5e787623a98e22a2660041b455a2c138b02 (patch) | |
tree | 13c732c132c9229244487ab68fa141fd37020bd0 /net | |
parent | 6104503cddbbaf341c091fa900d93488d6342ad6 (diff) | |
parent | ebe24cea95ab969f76f2922032f6c390fdc816f2 (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/batman-adv/bat_iv_ogm.c | 9 | ||||
-rw-r--r-- | net/batman-adv/bat_v.c | 66 | ||||
-rw-r--r-- | net/batman-adv/bat_v_elp.c | 31 | ||||
-rw-r--r-- | net/batman-adv/bat_v_elp.h | 2 | ||||
-rw-r--r-- | net/batman-adv/originator.c | 6 | ||||
-rw-r--r-- | net/batman-adv/routing.c | 4 |
6 files changed, 93 insertions, 25 deletions
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 7f98a9d39883..ce2f203048d3 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -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 */ diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 3ff8bd1b7bdc..0a12e5cdd65d 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -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 = { diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 3844e7efd0b0..df42eb1365a0 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -377,6 +377,27 @@ void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface) } /** + * 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 * @primary_iface: 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(); } diff --git a/net/batman-adv/bat_v_elp.h b/net/batman-adv/bat_v_elp.h index e95f1bca0785..cc130b2d05e5 100644 --- a/net/batman-adv/bat_v_elp.h +++ b/net/batman-adv/bat_v_elp.h @@ -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); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 1ff4ee473966..7f51bc2c06eb 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -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; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index ae850f2d11cb..e3857ed4057f 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -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) { |