The following commit has been merged in the merge/master branch: commit ac44ee35fb889d6348f5b51cc832d906810c2453 Merge: e01abefce143a2d3f99695e5e66d6155d9799ed3 9fb6f304db4c7d82c72f49f759ae58fc745750e8 Author: Antonio Quartulli antonio@meshcoding.com Date: Sat May 10 10:07:55 2014 +0200
Merge commit '9fb6f304db4c7d82c72f49f759ae58fc745750e8' into merge/master
diff --combined net/batman-adv/bat_iv_ogm.c index b3bd4ec,f04224c..f04224c --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@@ -1545,6 -1545,8 +1545,8 @@@ out_neigh if ((orig_neigh_node) && (!is_single_hop_neigh)) batadv_orig_node_free_ref(orig_neigh_node); out: + if (router_ifinfo) + batadv_neigh_ifinfo_free_ref(router_ifinfo); if (router) batadv_neigh_node_free_ref(router); if (router_router) diff --combined net/batman-adv/distributed-arp-table.c index b25fd64,aa5d494..aa5d494 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@@ -940,8 -940,7 +940,7 @@@ bool batadv_dat_snoop_outgoing_arp_requ * additional DAT answer may trigger kernel warnings about * a packet coming from the wrong port. */ - if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, - BATADV_NO_FLAGS)) { + if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, vid)) { ret = true; goto out; } diff --combined net/batman-adv/fragmentation.c index bcc4bea,f14e54a..f14e54a --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@@ -418,12 -418,13 +418,13 @@@ bool batadv_frag_send_packet(struct sk_ struct batadv_neigh_node *neigh_node) { struct batadv_priv *bat_priv; - struct batadv_hard_iface *primary_if; + struct batadv_hard_iface *primary_if = NULL; struct batadv_frag_packet frag_header; struct sk_buff *skb_fragment; unsigned mtu = neigh_node->if_incoming->net_dev->mtu; unsigned header_size = sizeof(frag_header); unsigned max_fragment_size, max_packet_size; + bool ret = false;
/* To avoid merge and refragmentation at next-hops we never send * fragments larger than BATADV_FRAG_MAX_FRAG_SIZE @@@ -483,7 -484,11 +484,11 @@@ skb->len + ETH_HLEN); batadv_send_skb_packet(skb, neigh_node->if_incoming, neigh_node->addr);
- return true; + ret = true; + out_err: - return false; + if (primary_if) + batadv_hardif_free_ref(primary_if); + + return ret; } diff --combined net/batman-adv/gateway_client.c index c835e13,90cff58..90cff58 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@@ -42,8 -42,10 +42,10 @@@
static void batadv_gw_node_free_ref(struct batadv_gw_node *gw_node) { - if (atomic_dec_and_test(&gw_node->refcount)) + if (atomic_dec_and_test(&gw_node->refcount)) { + batadv_orig_node_free_ref(gw_node->orig_node); kfree_rcu(gw_node, rcu); + } }
static struct batadv_gw_node * @@@ -406,9 -408,14 +408,14 @@@ static void batadv_gw_node_add(struct b if (gateway->bandwidth_down == 0) return;
+ if (!atomic_inc_not_zero(&orig_node->refcount)) + return; + gw_node = kzalloc(sizeof(*gw_node), GFP_ATOMIC); - if (!gw_node) + if (!gw_node) { + batadv_orig_node_free_ref(orig_node); return; + }
INIT_HLIST_NODE(&gw_node->list); gw_node->orig_node = orig_node; diff --combined net/batman-adv/multicast.c index 8c7ca81,96b66fd..96b66fd --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@@ -415,7 -415,7 +415,7 @@@ batadv_mcast_forw_ipv4_node_get(struct hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_ipv4_list, mcast_want_all_ipv4_node) { - if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; @@@ -442,7 -442,7 +442,7 @@@ batadv_mcast_forw_ipv6_node_get(struct hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_ipv6_list, mcast_want_all_ipv6_node) { - if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; @@@ -493,7 -493,7 +493,7 @@@ batadv_mcast_forw_unsnoop_node_get(stru hlist_for_each_entry_rcu(tmp_orig_node, &bat_priv->mcast.want_all_unsnoopables_list, mcast_want_all_unsnoopables_node) { - if (!atomic_inc_not_zero(&orig_node->refcount)) + if (!atomic_inc_not_zero(&tmp_orig_node->refcount)) continue;
orig_node = tmp_orig_node; diff --combined net/batman-adv/originator.c index ffd9dfb,bb1425f..bb1425f --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@@ -501,12 -501,17 +501,17 @@@ batadv_neigh_node_get(const struct bata static void batadv_orig_ifinfo_free_rcu(struct rcu_head *rcu) { struct batadv_orig_ifinfo *orig_ifinfo; + struct batadv_neigh_node *router;
orig_ifinfo = container_of(rcu, struct batadv_orig_ifinfo, rcu);
if (orig_ifinfo->if_outgoing != BATADV_IF_DEFAULT) batadv_hardif_free_ref_now(orig_ifinfo->if_outgoing);
+ /* this is the last reference to this object */ + router = rcu_dereference_protected(orig_ifinfo->router, true); + if (router) + batadv_neigh_node_free_ref_now(router); kfree(orig_ifinfo); }
@@@ -702,6 -707,47 +707,47 @@@ free_orig_node }
/** + * batadv_purge_neigh_ifinfo - purge obsolete ifinfo entries from neighbor + * @bat_priv: the bat priv with all the soft interface information + * @neigh_node: orig node which is to be checked + */ + static void + batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv, + struct batadv_neigh_node *neigh) + { + struct batadv_neigh_ifinfo *neigh_ifinfo; + struct batadv_hard_iface *if_outgoing; + struct hlist_node *node_tmp; + + spin_lock_bh(&neigh->ifinfo_lock); + + /* for all ifinfo objects for this neighinator */ + hlist_for_each_entry_safe(neigh_ifinfo, node_tmp, + &neigh->ifinfo_list, list) { + if_outgoing = neigh_ifinfo->if_outgoing; + + /* always keep the default interface */ + if (if_outgoing == BATADV_IF_DEFAULT) + continue; + + /* don't purge if the interface is not (going) down */ + if ((if_outgoing->if_status != BATADV_IF_INACTIVE) && + (if_outgoing->if_status != BATADV_IF_NOT_IN_USE) && + (if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)) + continue; + + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "neighbor/ifinfo purge: neighbor %pM, iface: %s\n", + neigh->addr, if_outgoing->net_dev->name); + + hlist_del_rcu(&neigh_ifinfo->list); + batadv_neigh_ifinfo_free_ref(neigh_ifinfo); + } + + spin_unlock_bh(&neigh->ifinfo_lock); + } + + /** * batadv_purge_orig_ifinfo - purge obsolete ifinfo entries from originator * @bat_priv: the bat priv with all the soft interface information * @orig_node: orig node which is to be checked @@@ -800,6 -846,11 +846,11 @@@ batadv_purge_orig_neighbors(struct bata
hlist_del_rcu(&neigh_node->list); batadv_neigh_node_free_ref(neigh_node); + } else { + /* only neccesary if not the whole neighbor is to be deleted, + * but some interface has been removed. + */ + batadv_purge_neigh_ifinfo(bat_priv, neigh_node); } }
@@@ -857,7 -908,7 +908,7 @@@ static bool batadv_purge_orig_node(stru { struct batadv_neigh_node *best_neigh_node; struct batadv_hard_iface *hard_iface; - bool changed; + bool changed_ifinfo, changed_neigh;
if (batadv_has_timed_out(orig_node->last_seen, 2 * BATADV_PURGE_TIMEOUT)) { @@@ -867,10 -918,10 +918,10 @@@ jiffies_to_msecs(orig_node->last_seen)); return true; } - changed = batadv_purge_orig_ifinfo(bat_priv, orig_node); - changed = changed || batadv_purge_orig_neighbors(bat_priv, orig_node); + changed_ifinfo = batadv_purge_orig_ifinfo(bat_priv, orig_node); + changed_neigh = batadv_purge_orig_neighbors(bat_priv, orig_node);
- if (!changed) + if (!changed_ifinfo && !changed_neigh) return false;
/* first for NULL ... */ @@@ -1028,7 -1079,8 +1079,8 @@@ int batadv_orig_hardif_seq_print_text(s bat_priv->bat_algo_ops->bat_orig_print(bat_priv, seq, hard_iface);
out: - batadv_hardif_free_ref(hard_iface); + if (hard_iface) + batadv_hardif_free_ref(hard_iface); return 0; }
diff --combined net/batman-adv/soft-interface.c index 744a59b,9f070de..9f070de --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -106,6 -106,7 +106,7 @@@ static struct net_device_stats *batadv_ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) { struct batadv_priv *bat_priv = netdev_priv(dev); + struct batadv_softif_vlan *vlan; struct sockaddr *addr = p; uint8_t old_addr[ETH_ALEN];
@@@ -116,12 -117,17 +117,17 @@@ ether_addr_copy(dev->dev_addr, addr->sa_data);
/* only modify transtable if it has been initialized before */ - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) { - batadv_tt_local_remove(bat_priv, old_addr, BATADV_NO_FLAGS, + if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + return 0; + + rcu_read_lock(); + hlist_for_each_entry_rcu(vlan, &bat_priv->softif_vlan_list, list) { + batadv_tt_local_remove(bat_priv, old_addr, vlan->vid, "mac address changed", false); - batadv_tt_local_add(dev, addr->sa_data, BATADV_NO_FLAGS, + batadv_tt_local_add(dev, addr->sa_data, vlan->vid, BATADV_NULL_IFINDEX, BATADV_NO_MARK); } + rcu_read_unlock();
return 0; }