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

Merge branch 'batman-adv-fixes'

Sven Eckelmann says:

====================
batman-adv: Fixes for Linux 4.7

Antonio currently seems to be occupied. This is currently rather unfortunate
because there are patches waiting in the batman-adv development repository
maint(enance) branch [1] since up to 6 weeks. I am now getting asked when
these patches will hit the distribution kernels and therefore decided to
submit these patches directly to netdev.

The patch from Simon works around the problem that warnings could be triggered
in the translation table code via packets using a VLAN not configured on the
target host. This warning was replaced with a rate limited info message.

Ben Hutchings found an superfluous batadv_softif_vlan_put in the error
handling code of the translation table while he backported the "batman-adv:
Fix reference counting of vlan object for tt_local_entry" patch to the stable
kernels. He noticed correctly that this batadv_softif_vlan_put should also
have been removed by the said patch.

The most requested fix at the moment is related to a double free in the
translation table code. It is a race condition which mostly happens on systems
with multiple cores and multiple network interface attached to batman-adv. Two
Freifunk communities which were haunted by weird crashes (with backtraces
reporting problems in other parts of the kernel) were kind enough to test this
patch. They reported that there systems are now running stable after applying
this patch.

An invalid memory access was detected in the batadv_icmp_packet_rr handling
code when receiving a skbuff with fragments. The last patch is fixing a memory
leak when the interface is removed via .dellink. The code to fix it was copied
from the code handling the legacy sysfs interface to remove netdevices from a
batman-adv netdevice.

There are still 28 patches in the development tree for v4.8 but I will leave
them to Antonio because these are cleanups and features and therefore for net-
next.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 69fc58a5 420cb1b7
...@@ -374,6 +374,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb, ...@@ -374,6 +374,7 @@ int batadv_recv_icmp_packet(struct sk_buff *skb,
if (skb_cow(skb, ETH_HLEN) < 0) if (skb_cow(skb, ETH_HLEN) < 0)
goto out; goto out;
ethhdr = eth_hdr(skb);
icmph = (struct batadv_icmp_header *)skb->data; icmph = (struct batadv_icmp_header *)skb->data;
icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph; icmp_packet_rr = (struct batadv_icmp_packet_rr *)icmph;
if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN) if (icmp_packet_rr->rr_cur >= BATADV_RR_LEN)
......
...@@ -1033,7 +1033,9 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface) ...@@ -1033,7 +1033,9 @@ void batadv_softif_destroy_sysfs(struct net_device *soft_iface)
static void batadv_softif_destroy_netlink(struct net_device *soft_iface, static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
struct list_head *head) struct list_head *head)
{ {
struct batadv_priv *bat_priv = netdev_priv(soft_iface);
struct batadv_hard_iface *hard_iface; struct batadv_hard_iface *hard_iface;
struct batadv_softif_vlan *vlan;
list_for_each_entry(hard_iface, &batadv_hardif_list, list) { list_for_each_entry(hard_iface, &batadv_hardif_list, list) {
if (hard_iface->soft_iface == soft_iface) if (hard_iface->soft_iface == soft_iface)
...@@ -1041,6 +1043,13 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface, ...@@ -1041,6 +1043,13 @@ static void batadv_softif_destroy_netlink(struct net_device *soft_iface,
BATADV_IF_CLEANUP_KEEP); BATADV_IF_CLEANUP_KEEP);
} }
/* destroy the "untagged" VLAN */
vlan = batadv_softif_vlan_get(bat_priv, BATADV_NO_FLAGS);
if (vlan) {
batadv_softif_destroy_vlan(bat_priv, vlan);
batadv_softif_vlan_put(vlan);
}
batadv_sysfs_del_meshif(soft_iface); batadv_sysfs_del_meshif(soft_iface);
unregister_netdevice_queue(soft_iface, head); unregister_netdevice_queue(soft_iface, head);
} }
......
...@@ -650,8 +650,10 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, ...@@ -650,8 +650,10 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
/* increase the refcounter of the related vlan */ /* increase the refcounter of the related vlan */
vlan = batadv_softif_vlan_get(bat_priv, vid); vlan = batadv_softif_vlan_get(bat_priv, vid);
if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d", if (!vlan) {
addr, BATADV_PRINT_VID(vid))) { net_ratelimited_function(batadv_info, soft_iface,
"adding TT local entry %pM to non-existent VLAN %d\n",
addr, BATADV_PRINT_VID(vid));
kfree(tt_local); kfree(tt_local);
tt_local = NULL; tt_local = NULL;
goto out; goto out;
...@@ -691,7 +693,6 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, ...@@ -691,7 +693,6 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
if (unlikely(hash_added != 0)) { if (unlikely(hash_added != 0)) {
/* remove the reference for the hash */ /* remove the reference for the hash */
batadv_tt_local_entry_put(tt_local); batadv_tt_local_entry_put(tt_local);
batadv_softif_vlan_put(vlan);
goto out; goto out;
} }
...@@ -2269,6 +2270,29 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, ...@@ -2269,6 +2270,29 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
return crc; return crc;
} }
/**
* batadv_tt_req_node_release - free tt_req node entry
* @ref: kref pointer of the tt req_node entry
*/
static void batadv_tt_req_node_release(struct kref *ref)
{
struct batadv_tt_req_node *tt_req_node;
tt_req_node = container_of(ref, struct batadv_tt_req_node, refcount);
kfree(tt_req_node);
}
/**
* batadv_tt_req_node_put - decrement the tt_req_node refcounter and
* possibly release it
* @tt_req_node: tt_req_node to be free'd
*/
static void batadv_tt_req_node_put(struct batadv_tt_req_node *tt_req_node)
{
kref_put(&tt_req_node->refcount, batadv_tt_req_node_release);
}
static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
{ {
struct batadv_tt_req_node *node; struct batadv_tt_req_node *node;
...@@ -2278,7 +2302,7 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) ...@@ -2278,7 +2302,7 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv)
hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) {
hlist_del_init(&node->list); hlist_del_init(&node->list);
kfree(node); batadv_tt_req_node_put(node);
} }
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
...@@ -2315,7 +2339,7 @@ static void batadv_tt_req_purge(struct batadv_priv *bat_priv) ...@@ -2315,7 +2339,7 @@ static void batadv_tt_req_purge(struct batadv_priv *bat_priv)
if (batadv_has_timed_out(node->issued_at, if (batadv_has_timed_out(node->issued_at,
BATADV_TT_REQUEST_TIMEOUT)) { BATADV_TT_REQUEST_TIMEOUT)) {
hlist_del_init(&node->list); hlist_del_init(&node->list);
kfree(node); batadv_tt_req_node_put(node);
} }
} }
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
...@@ -2347,9 +2371,11 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, ...@@ -2347,9 +2371,11 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
if (!tt_req_node) if (!tt_req_node)
goto unlock; goto unlock;
kref_init(&tt_req_node->refcount);
ether_addr_copy(tt_req_node->addr, orig_node->orig); ether_addr_copy(tt_req_node->addr, orig_node->orig);
tt_req_node->issued_at = jiffies; tt_req_node->issued_at = jiffies;
kref_get(&tt_req_node->refcount);
hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list);
unlock: unlock:
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
...@@ -2613,13 +2639,19 @@ static bool batadv_send_tt_request(struct batadv_priv *bat_priv, ...@@ -2613,13 +2639,19 @@ static bool batadv_send_tt_request(struct batadv_priv *bat_priv,
out: out:
if (primary_if) if (primary_if)
batadv_hardif_put(primary_if); batadv_hardif_put(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);
/* hlist_del_init() verifies tt_req_node still is in the list */ if (!hlist_unhashed(&tt_req_node->list)) {
hlist_del_init(&tt_req_node->list); hlist_del_init(&tt_req_node->list);
batadv_tt_req_node_put(tt_req_node);
}
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
kfree(tt_req_node);
} }
if (tt_req_node)
batadv_tt_req_node_put(tt_req_node);
kfree(tvlv_tt_data); kfree(tvlv_tt_data);
return ret; return ret;
} }
...@@ -3055,7 +3087,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, ...@@ -3055,7 +3087,7 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv,
if (!batadv_compare_eth(node->addr, resp_src)) if (!batadv_compare_eth(node->addr, resp_src))
continue; continue;
hlist_del_init(&node->list); hlist_del_init(&node->list);
kfree(node); batadv_tt_req_node_put(node);
} }
spin_unlock_bh(&bat_priv->tt.req_list_lock); spin_unlock_bh(&bat_priv->tt.req_list_lock);
......
...@@ -1137,11 +1137,13 @@ struct batadv_tt_change_node { ...@@ -1137,11 +1137,13 @@ struct batadv_tt_change_node {
* struct batadv_tt_req_node - data to keep track of the tt requests in flight * struct batadv_tt_req_node - data to keep track of the tt requests in flight
* @addr: mac address address of the originator this request was sent to * @addr: mac address address of the originator this request was sent to
* @issued_at: timestamp used for purging stale tt requests * @issued_at: timestamp used for purging stale tt requests
* @refcount: number of contexts the object is used by
* @list: list node for batadv_priv_tt::req_list * @list: list node for batadv_priv_tt::req_list
*/ */
struct batadv_tt_req_node { struct batadv_tt_req_node {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
unsigned long issued_at; unsigned long issued_at;
struct kref refcount;
struct hlist_node list; struct hlist_node list;
}; };
......
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