Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b40d5aa authored by David S. Miller's avatar David S. Miller
Browse files

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



Antonio Quartulli says:

====================
In this small batch of patches you have:
- a fix for our Distributed ARP Table that makes sure that the input
  provided to the hash function during a query is the same as the one
  provided during an insert (so to prevent false negatives), by Antonio
  Quartulli
- a fix for our new protocol implementation B.A.T.M.A.N. V that ensures
  that a hard interface is properly re-activated when it is brought down
  and then up again, by Antonio Quartulli
- two fixes respectively to the reference counting of the tt_local_entry
  and neigh_node objects, by Sven Eckelmann. Such bug is rather severe
  as it would prevent the netdev objects references by batman-adv from
  being released after shutdown.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 33656a1f abe59c65
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -32,10 +32,21 @@

#include "bat_v_elp.h"
#include "bat_v_ogm.h"
#include "hard-interface.h"
#include "hash.h"
#include "originator.h"
#include "packet.h"

static void batadv_v_iface_activate(struct batadv_hard_iface *hard_iface)
{
	/* 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
	 */
	if (hard_iface->if_status == BATADV_IF_TO_BE_ACTIVATED)
		hard_iface->if_status = BATADV_IF_ACTIVE;
}

static int batadv_v_iface_enable(struct batadv_hard_iface *hard_iface)
{
	int ret;
@@ -274,6 +285,7 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,

static struct batadv_algo_ops batadv_batman_v __read_mostly = {
	.name = "BATMAN_V",
	.bat_iface_activate = batadv_v_iface_activate,
	.bat_iface_enable = batadv_v_iface_enable,
	.bat_iface_disable = batadv_v_iface_disable,
	.bat_iface_update_mac = batadv_v_iface_update_mac,
+10 −7
Original line number Diff line number Diff line
@@ -568,6 +568,7 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
 * be sent to
 * @bat_priv: the bat priv with all the soft interface information
 * @ip_dst: ipv4 to look up in the DHT
 * @vid: VLAN identifier
 *
 * An originator O is selected if and only if its DHT_ID value is one of three
 * closest values (from the LEFT, with wrap around if needed) then the hash
@@ -576,7 +577,8 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv,
 * Return: the candidate array of size BATADV_DAT_CANDIDATE_NUM.
 */
static struct batadv_dat_candidate *
batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst,
			     unsigned short vid)
{
	int select;
	batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
@@ -592,7 +594,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
		return NULL;

	dat.ip = ip_dst;
	dat.vid = 0;
	dat.vid = vid;
	ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,
						    BATADV_DAT_ADDR_MAX);

@@ -612,6 +614,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
 * @bat_priv: the bat priv with all the soft interface information
 * @skb: payload to send
 * @ip: the DHT key
 * @vid: VLAN identifier
 * @packet_subtype: unicast4addr packet subtype to use
 *
 * This function copies the skb with pskb_copy() and is sent as unicast packet
@@ -622,7 +625,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
 */
static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
				 struct sk_buff *skb, __be32 ip,
				 int packet_subtype)
				 unsigned short vid, int packet_subtype)
{
	int i;
	bool ret = false;
@@ -631,7 +634,7 @@ static bool batadv_dat_send_data(struct batadv_priv *bat_priv,
	struct sk_buff *tmp_skb;
	struct batadv_dat_candidate *cand;

	cand = batadv_dat_select_candidates(bat_priv, ip);
	cand = batadv_dat_select_candidates(bat_priv, ip, vid);
	if (!cand)
		goto out;

@@ -1022,7 +1025,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
		ret = true;
	} else {
		/* Send the request to the DHT */
		ret = batadv_dat_send_data(bat_priv, skb, ip_dst,
		ret = batadv_dat_send_data(bat_priv, skb, ip_dst, vid,
					   BATADV_P_DAT_DHT_GET);
	}
out:
@@ -1150,8 +1153,8 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv,
	/* Send the ARP reply to the candidates for both the IP addresses that
	 * the node obtained from the ARP reply
	 */
	batadv_dat_send_data(bat_priv, skb, ip_src, BATADV_P_DAT_DHT_PUT);
	batadv_dat_send_data(bat_priv, skb, ip_dst, BATADV_P_DAT_DHT_PUT);
	batadv_dat_send_data(bat_priv, skb, ip_src, vid, BATADV_P_DAT_DHT_PUT);
	batadv_dat_send_data(bat_priv, skb, ip_dst, vid, BATADV_P_DAT_DHT_PUT);
}

/**
+3 −0
Original line number Diff line number Diff line
@@ -407,6 +407,9 @@ batadv_hardif_activate_interface(struct batadv_hard_iface *hard_iface)

	batadv_update_min_mtu(hard_iface->soft_iface);

	if (bat_priv->bat_algo_ops->bat_iface_activate)
		bat_priv->bat_algo_ops->bat_iface_activate(hard_iface);

out:
	if (primary_if)
		batadv_hardif_put(primary_if);
+5 −11
Original line number Diff line number Diff line
@@ -250,7 +250,6 @@ static void batadv_neigh_node_release(struct kref *ref)
{
	struct hlist_node *node_tmp;
	struct batadv_neigh_node *neigh_node;
	struct batadv_hardif_neigh_node *hardif_neigh;
	struct batadv_neigh_ifinfo *neigh_ifinfo;
	struct batadv_algo_ops *bao;

@@ -262,13 +261,7 @@ static void batadv_neigh_node_release(struct kref *ref)
		batadv_neigh_ifinfo_put(neigh_ifinfo);
	}

	hardif_neigh = batadv_hardif_neigh_get(neigh_node->if_incoming,
					       neigh_node->addr);
	if (hardif_neigh) {
		/* batadv_hardif_neigh_get() increases refcount too */
		batadv_hardif_neigh_put(hardif_neigh);
		batadv_hardif_neigh_put(hardif_neigh);
	}
	batadv_hardif_neigh_put(neigh_node->hardif_neigh);

	if (bao->bat_neigh_free)
		bao->bat_neigh_free(neigh_node);
@@ -665,6 +658,10 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
	neigh_node->orig_node = orig_node;
	neigh_node->last_seen = jiffies;

	/* increment unique neighbor refcount */
	kref_get(&hardif_neigh->refcount);
	neigh_node->hardif_neigh = hardif_neigh;

	/* extra reference for return */
	kref_init(&neigh_node->refcount);
	kref_get(&neigh_node->refcount);
@@ -673,9 +670,6 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
	hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
	spin_unlock_bh(&orig_node->neigh_list_lock);

	/* increment unique neighbor refcount */
	kref_get(&hardif_neigh->refcount);

	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);
+4 −38
Original line number Diff line number Diff line
@@ -215,6 +215,8 @@ static void batadv_tt_local_entry_release(struct kref *ref)
	tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
				      common.refcount);

	batadv_softif_vlan_put(tt_local_entry->vlan);

	kfree_rcu(tt_local_entry, common.rcu);
}

@@ -673,6 +675,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr,
	kref_get(&tt_local->common.refcount);
	tt_local->last_seen = jiffies;
	tt_local->common.added_at = tt_local->last_seen;
	tt_local->vlan = vlan;

	/* the batman interface mac and multicast addresses should never be
	 * purged
@@ -991,7 +994,6 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
	struct batadv_tt_common_entry *tt_common_entry;
	struct batadv_tt_local_entry *tt_local;
	struct batadv_hard_iface *primary_if;
	struct batadv_softif_vlan *vlan;
	struct hlist_head *head;
	unsigned short vid;
	u32 i;
@@ -1027,14 +1029,6 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
			last_seen_msecs = last_seen_msecs % 1000;

			no_purge = tt_common_entry->flags & np_flag;

			vlan = batadv_softif_vlan_get(bat_priv, vid);
			if (!vlan) {
				seq_printf(seq, "Cannot retrieve VLAN %d\n",
					   BATADV_PRINT_VID(vid));
				continue;
			}

			seq_printf(seq,
				   " * %pM %4i [%c%c%c%c%c%c] %3u.%03u   (%#.8x)\n",
				   tt_common_entry->addr,
@@ -1052,9 +1046,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset)
				     BATADV_TT_CLIENT_ISOLA) ? 'I' : '.'),
				   no_purge ? 0 : last_seen_secs,
				   no_purge ? 0 : last_seen_msecs,
				   vlan->tt.crc);

			batadv_softif_vlan_put(vlan);
				   tt_local->vlan->tt.crc);
		}
		rcu_read_unlock();
	}
@@ -1099,7 +1091,6 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
{
	struct batadv_tt_local_entry *tt_local_entry;
	u16 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);
@@ -1139,14 +1130,6 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
	/* extra call to free the local tt entry */
	batadv_tt_local_entry_put(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_put(vlan);
	batadv_softif_vlan_put(vlan);

out:
	if (tt_local_entry)
		batadv_tt_local_entry_put(tt_local_entry);
@@ -1219,7 +1202,6 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
	spinlock_t *list_lock; /* protects write access to the hash lists */
	struct batadv_tt_common_entry *tt_common_entry;
	struct batadv_tt_local_entry *tt_local;
	struct batadv_softif_vlan *vlan;
	struct hlist_node *node_tmp;
	struct hlist_head *head;
	u32 i;
@@ -1241,14 +1223,6 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
						struct batadv_tt_local_entry,
						common);

			/* decrease the reference held for this vlan */
			vlan = batadv_softif_vlan_get(bat_priv,
						      tt_common_entry->vid);
			if (vlan) {
				batadv_softif_vlan_put(vlan);
				batadv_softif_vlan_put(vlan);
			}

			batadv_tt_local_entry_put(tt_local);
		}
		spin_unlock_bh(list_lock);
@@ -3309,7 +3283,6 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
	struct batadv_hashtable *hash = bat_priv->tt.local_hash;
	struct batadv_tt_common_entry *tt_common;
	struct batadv_tt_local_entry *tt_local;
	struct batadv_softif_vlan *vlan;
	struct hlist_node *node_tmp;
	struct hlist_head *head;
	spinlock_t *list_lock; /* protects write access to the hash lists */
@@ -3339,13 +3312,6 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
						struct batadv_tt_local_entry,
						common);

			/* decrease the reference held for this vlan */
			vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
			if (vlan) {
				batadv_softif_vlan_put(vlan);
				batadv_softif_vlan_put(vlan);
			}

			batadv_tt_local_entry_put(tt_local);
		}
		spin_unlock_bh(list_lock);
Loading