The following commit has been merged in the master branch: commit c1f066d4ee0bde4bb0ff4ac295218b631729e0de Merge: 2bd736fa0d8a1da90e6ccaa6a79e56a8d2ae60c4 53cf037bf846417fd92dc92ddf97267f69b110f4 Author: David S. Miller davem@davemloft.net Date: Mon Aug 17 14:31:42 2015 -0700
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: David S. Miller davem@davemloft.net
diff --combined net/batman-adv/distributed-arp-table.c index 6d0b471,1cfba20..cc7d87d --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@@ -19,6 -19,7 +19,7 @@@ #include "main.h"
#include <linux/atomic.h> + #include <linux/bitops.h> #include <linux/byteorder/generic.h> #include <linux/errno.h> #include <linux/etherdevice.h> @@@ -453,7 -454,7 +454,7 @@@ static bool batadv_is_orig_node_eligibl int j;
/* 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;
/* Check if this node has already been selected... */ @@@ -713,9 -714,9 +714,9 @@@ static void batadv_dat_tvlv_ogm_handler uint16_t tvlv_value_len) { if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) - orig->capabilities &= ~BATADV_ORIG_CAPA_HAS_DAT; + clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities); else - orig->capabilities |= BATADV_ORIG_CAPA_HAS_DAT; + set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities); }
/** @@@ -1138,9 -1139,6 +1139,9 @@@ void batadv_dat_snoop_outgoing_arp_repl * @bat_priv: the bat priv with all the soft interface information * @skb: packet to check * @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, struct sk_buff *skb, int hdr_size) @@@ -1148,7 -1146,7 +1149,7 @@@ uint16_t type; __be32 ip_src, ip_dst; uint8_t *hw_src, *hw_dst; - bool ret = false; + bool dropped = false; unsigned short vid;
if (!atomic_read(&bat_priv->distributed_arp_table)) @@@ -1177,17 -1175,12 +1178,17 @@@ /* if this REPLY is directed to a client of mine, let's deliver the * 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: - if (ret) + if (dropped) kfree_skb(skb); - /* if ret == false -> packet has to be delivered to the interface */ - return ret; + /* if dropped == false -> deliver to the interface */ + return dropped; }
/** diff --combined net/batman-adv/gateway_client.c index cffa92d,4ac24d8..6012e2b --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@@ -153,15 -153,11 +153,11 @@@ batadv_gw_get_best_gw_node(struct batad struct batadv_neigh_node *router; struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; - uint32_t max_gw_factor = 0, tmp_gw_factor = 0; - uint32_t gw_divisor; + uint64_t max_gw_factor = 0, tmp_gw_factor = 0; uint8_t max_tq = 0; uint8_t tq_avg; struct batadv_orig_node *orig_node;
- gw_divisor = BATADV_TQ_LOCAL_WINDOW_SIZE * BATADV_TQ_LOCAL_WINDOW_SIZE; - gw_divisor *= 64; - rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { if (gw_node->deleted) @@@ -187,7 -183,7 +183,7 @@@ tmp_gw_factor = tq_avg * tq_avg; tmp_gw_factor *= gw_node->bandwidth_down; tmp_gw_factor *= 100 * 100; - tmp_gw_factor /= gw_divisor; + tmp_gw_factor >>= 18;
if ((tmp_gw_factor > max_gw_factor) || ((tmp_gw_factor == max_gw_factor) && @@@ -439,8 -435,6 +435,8 @@@ static void batadv_gw_node_add(struct b
INIT_HLIST_NODE(&gw_node->list); 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);
spin_lock_bh(&bat_priv->gw.list_lock); diff --combined net/batman-adv/soft-interface.c index a2fc843,926292d..51cda3a --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -202,6 -202,7 +202,7 @@@ static int batadv_interface_tx(struct s int gw_mode; enum batadv_forw_mode forw_mode; struct batadv_orig_node *mcast_single_orig = NULL; + int network_offset = ETH_HLEN;
if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped; @@@ -214,14 -215,18 +215,18 @@@ case ETH_P_8021Q: vhdr = vlan_eth_hdr(skb);
- if (vhdr->h_vlan_encapsulated_proto != ethertype) + if (vhdr->h_vlan_encapsulated_proto != ethertype) { + network_offset += VLAN_HLEN; break; + }
/* fall through */ case ETH_P_BATMAN: goto dropped; }
+ skb_set_network_header(skb, network_offset); + if (batadv_bla_tx(bat_priv, skb, vid)) goto dropped;
@@@ -479,9 -484,6 +484,9 @@@ out */ void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan) { + if (!vlan) + return; + if (atomic_dec_and_test(&vlan->refcount)) { spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock); hlist_del_rcu(&vlan->list); diff --combined net/batman-adv/translation-table.c index 5e953297,cd35bb8..db06de2 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@@ -19,6 -19,7 +19,7 @@@ #include "main.h"
#include <linux/atomic.h> + #include <linux/bitops.h> #include <linux/bug.h> #include <linux/byteorder/generic.h> #include <linux/compiler.h> @@@ -594,9 -595,6 +595,9 @@@ bool batadv_tt_local_add(struct net_dev
/* increase the refcounter of the related vlan */ 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, "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", @@@ -1037,7 -1035,6 +1038,7 @@@ uint16_t batadv_tt_local_remove(struct struct batadv_tt_local_entry *tt_local_entry; uint16_t flags, curr_flags = BATADV_NO_FLAGS; struct batadv_softif_vlan *vlan; + void *tt_entry_exists;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid); if (!tt_local_entry) @@@ -1065,22 -1062,11 +1066,22 @@@ * immediately purge it */ 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);
/* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, vid); + if (!vlan) + goto out; + batadv_softif_vlan_free_ref(vlan); batadv_softif_vlan_free_ref(vlan);
@@@ -1181,10 -1167,8 +1182,10 @@@ static void batadv_tt_local_table_free( /* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, tt_common_entry->vid); - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + if (vlan) { + batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_free_ref(vlan); + }
batadv_tt_local_entry_free_ref(tt_local); } @@@ -1879,7 -1863,7 +1880,7 @@@ void batadv_tt_global_del_orig(struct b } 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, @@@ -2212,7 -2196,7 +2213,7 @@@ static void batadv_tt_req_list_free(str spin_lock_bh(&bat_priv->tt.req_list_lock);
list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { - list_del(&node->list); + list_del_init(&node->list); kfree(node); }
@@@ -2248,7 -2232,7 +2249,7 @@@ static void batadv_tt_req_purge(struct list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (batadv_has_timed_out(node->issued_at, BATADV_TT_REQUEST_TIMEOUT)) { - list_del(&node->list); + list_del_init(&node->list); kfree(node); } } @@@ -2530,7 -2514,8 +2531,8 @@@ out batadv_hardif_free_ref(primary_if); if (ret && tt_req_node) { 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); kfree(tt_req_node); } @@@ -2838,7 -2823,7 +2840,7 @@@ static void _batadv_tt_update_changes(s 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, @@@ -2967,7 -2952,7 +2969,7 @@@ static void batadv_handle_tt_response(s list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (!batadv_compare_eth(node->addr, resp_src)) continue; - list_del(&node->list); + list_del_init(&node->list); kfree(node); }
@@@ -3224,10 -3209,8 +3226,10 @@@ static void batadv_tt_local_purge_pendi
/* decrease the reference held for this vlan */ vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid); - batadv_softif_vlan_free_ref(vlan); - batadv_softif_vlan_free_ref(vlan); + if (vlan) { + batadv_softif_vlan_free_ref(vlan); + batadv_softif_vlan_free_ref(vlan); + }
batadv_tt_local_entry_free_ref(tt_local); } @@@ -3340,7 -3323,8 +3342,8 @@@ static void batadv_tt_update_orig(struc bool has_tt_init;
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 * increased by one -> we can apply the attached changes
linux-merge@lists.open-mesh.org