Commit 95a428f3 authored by David S. Miller's avatar David S. Miller

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

Antonio Quartulli says:

====================
Included changes:
- prevent DAT from replying on behalf of local clients and confuse L2
  bridges
- fix crash on double list removal of TT objects (tt_local_entry)
- fix crash due to missing NULL checks
- initialize bw values for new GWs objects to prevent memory leak
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d1163e91 27a4d5ef
...@@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, ...@@ -1138,6 +1138,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
* @bat_priv: the bat priv with all the soft interface information * @bat_priv: the bat priv with all the soft interface information
* @skb: packet to check * @skb: packet to check
* @hdr_size: size of the encapsulation header * @hdr_size: size of the encapsulation header
*
* Returns true if the packet was snooped and consumed by DAT. False if the
* packet has to be delivered to the interface
*/ */
bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size) struct sk_buff *skb, int hdr_size)
...@@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, ...@@ -1145,7 +1148,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
uint16_t type; uint16_t type;
__be32 ip_src, ip_dst; __be32 ip_src, ip_dst;
uint8_t *hw_src, *hw_dst; uint8_t *hw_src, *hw_dst;
bool ret = false; bool dropped = false;
unsigned short vid; unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) if (!atomic_read(&bat_priv->distributed_arp_table))
...@@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, ...@@ -1174,12 +1177,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
/* if this REPLY is directed to a client of mine, let's deliver the /* if this REPLY is directed to a client of mine, let's deliver the
* packet to the interface * packet to the interface
*/ */
ret = !batadv_is_my_client(bat_priv, hw_dst, vid); dropped = !batadv_is_my_client(bat_priv, hw_dst, vid);
/* if this REPLY is sent on behalf of a client of mine, let's drop the
* packet because the client will reply by itself
*/
dropped |= batadv_is_my_client(bat_priv, hw_src, vid);
out: out:
if (ret) if (dropped)
kfree_skb(skb); kfree_skb(skb);
/* if ret == false -> packet has to be delivered to the interface */ /* if dropped == false -> deliver to the interface */
return ret; return dropped;
} }
/** /**
......
...@@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv, ...@@ -439,6 +439,8 @@ static void batadv_gw_node_add(struct batadv_priv *bat_priv,
INIT_HLIST_NODE(&gw_node->list); INIT_HLIST_NODE(&gw_node->list);
gw_node->orig_node = orig_node; gw_node->orig_node = orig_node;
gw_node->bandwidth_down = ntohl(gateway->bandwidth_down);
gw_node->bandwidth_up = ntohl(gateway->bandwidth_up);
atomic_set(&gw_node->refcount, 1); atomic_set(&gw_node->refcount, 1);
spin_lock_bh(&bat_priv->gw.list_lock); spin_lock_bh(&bat_priv->gw.list_lock);
......
...@@ -479,6 +479,9 @@ void batadv_interface_rx(struct net_device *soft_iface, ...@@ -479,6 +479,9 @@ void batadv_interface_rx(struct net_device *soft_iface,
*/ */
void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan) void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
{ {
if (!vlan)
return;
if (atomic_dec_and_test(&vlan->refcount)) { if (atomic_dec_and_test(&vlan->refcount)) {
spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
hlist_del_rcu(&vlan->list); hlist_del_rcu(&vlan->list);
......
...@@ -594,6 +594,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, ...@@ -594,6 +594,9 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *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",
addr, BATADV_PRINT_VID(vid)))
goto out;
batadv_dbg(BATADV_DBG_TT, bat_priv, batadv_dbg(BATADV_DBG_TT, bat_priv,
"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
...@@ -1034,6 +1037,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, ...@@ -1034,6 +1037,7 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry; struct batadv_tt_local_entry *tt_local_entry;
uint16_t flags, curr_flags = BATADV_NO_FLAGS; uint16_t flags, curr_flags = BATADV_NO_FLAGS;
struct batadv_softif_vlan *vlan; struct batadv_softif_vlan *vlan;
void *tt_entry_exists;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry) if (!tt_local_entry)
...@@ -1061,11 +1065,22 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, ...@@ -1061,11 +1065,22 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
* immediately purge it * immediately purge it
*/ */
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL); batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
hlist_del_rcu(&tt_local_entry->common.hash_entry);
tt_entry_exists = batadv_hash_remove(bat_priv->tt.local_hash,
batadv_compare_tt,
batadv_choose_tt,
&tt_local_entry->common);
if (!tt_entry_exists)
goto out;
/* extra call to free the local tt entry */
batadv_tt_local_entry_free_ref(tt_local_entry); batadv_tt_local_entry_free_ref(tt_local_entry);
/* decrease the reference held for this vlan */ /* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv, vid); vlan = batadv_softif_vlan_get(bat_priv, vid);
if (!vlan)
goto out;
batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan);
batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan);
...@@ -1166,8 +1181,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) ...@@ -1166,8 +1181,10 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
/* decrease the reference held for this vlan */ /* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv, vlan = batadv_softif_vlan_get(bat_priv,
tt_common_entry->vid); tt_common_entry->vid);
batadv_softif_vlan_free_ref(vlan); if (vlan) {
batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan);
batadv_softif_vlan_free_ref(vlan);
}
batadv_tt_local_entry_free_ref(tt_local); batadv_tt_local_entry_free_ref(tt_local);
} }
...@@ -3207,8 +3224,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) ...@@ -3207,8 +3224,10 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
/* decrease the reference held for this vlan */ /* decrease the reference held for this vlan */
vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
batadv_softif_vlan_free_ref(vlan); if (vlan) {
batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan);
batadv_softif_vlan_free_ref(vlan);
}
batadv_tt_local_entry_free_ref(tt_local); batadv_tt_local_entry_free_ref(tt_local);
} }
......
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