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

Commit 3f9aed7c authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'batman-adv/next' of git://git.open-mesh.org/linux-merge

parents 31817df0 a7f9becb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -223,6 +223,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, const uint8_t *addr)
	orig_node->bat_priv = bat_priv;
	memcpy(orig_node->orig, addr, ETH_ALEN);
	orig_node->router = NULL;
	orig_node->tt_crc = 0;
	atomic_set(&orig_node->last_ttvn, 0);
	orig_node->tt_buff = NULL;
	orig_node->tt_buff_len = 0;
	atomic_set(&orig_node->tt_size, 0);
+3 −1
Original line number Diff line number Diff line
@@ -84,7 +84,9 @@ enum tt_query_flags {
enum tt_client_flags {
	TT_CLIENT_DEL     = 1 << 0,
	TT_CLIENT_ROAM    = 1 << 1,
	TT_CLIENT_NOPURGE = 1 << 8
	TT_CLIENT_NOPURGE = 1 << 8,
	TT_CLIENT_NEW     = 1 << 9,
	TT_CLIENT_PENDING = 1 << 10
};

struct batman_packet {
+12 −0
Original line number Diff line number Diff line
@@ -91,6 +91,18 @@ static void update_transtable(struct bat_priv *bat_priv,
		 * to recompute it to spot any possible inconsistency
		 * in the global table */
		orig_node->tt_crc = tt_global_crc(bat_priv, orig_node);

		/* The ttvn alone is not enough to guarantee consistency
		 * because a single value could repesent different states
		 * (due to the wrap around). Thus a node has to check whether
		 * the resulting table (after applying the changes) is still
		 * consistent or not. E.g. a node could disconnect while its
		 * ttvn is X and reconnect on ttvn = X + TTVN_MAX: in this case
		 * checking the CRC value is mandatory to detect the
		 * inconsistency */
		if (orig_node->tt_crc != tt_crc)
			goto request_table;

		/* Roaming phase is over: tables are in sync again. I can
		 * unset the flag */
		orig_node->tt_poss_change = false;
+1 −3
Original line number Diff line number Diff line
@@ -309,10 +309,8 @@ void schedule_own_packet(struct hard_iface *hard_iface)
	if (hard_iface == primary_if) {
		/* if at least one change happened */
		if (atomic_read(&bat_priv->tt_local_changes) > 0) {
			tt_commit_changes(bat_priv);
			prepare_packet_buffer(bat_priv, hard_iface);
			/* Increment the TTVN only once per OGM interval */
			atomic_inc(&bat_priv->ttvn);
			bat_priv->tt_poss_change = false;
		}

		/* if the changes have been sent enough times */
+128 −28
Original line number Diff line number Diff line
@@ -215,11 +215,14 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)

	tt_local_event(bat_priv, addr, tt_local_entry->flags);

	/* The local entry has to be marked as NEW to avoid to send it in
	 * a full table response going out before the next ttvn increment
	 * (consistency check) */
	tt_local_entry->flags |= TT_CLIENT_NEW;

	hash_add(bat_priv->tt_local_hash, compare_ltt, choose_orig,
		 tt_local_entry, &tt_local_entry->hash_entry);

	atomic_inc(&bat_priv->num_local_tt);

	/* remove address from global hash if present */
	tt_global_entry = tt_global_hash_find(bat_priv, addr);

@@ -227,8 +230,9 @@ void tt_local_add(struct net_device *soft_iface, const uint8_t *addr)
	if (tt_global_entry) {
		/* This node is probably going to update its tt table */
		tt_global_entry->orig_node->tt_poss_change = true;
		_tt_global_del(bat_priv, tt_global_entry,
			       "local tt received");
		/* The global entry has to be marked as PENDING and has to be
		 * kept for consistency purpose */
		tt_global_entry->flags |= TT_CLIENT_PENDING;
		send_roam_adv(bat_priv, tt_global_entry->addr,
			      tt_global_entry->orig_node);
	}
@@ -358,19 +362,17 @@ int tt_local_seq_print_text(struct seq_file *seq, void *offset)
	return ret;
}

static void tt_local_del(struct bat_priv *bat_priv,
static void tt_local_set_pending(struct bat_priv *bat_priv,
				 struct tt_local_entry *tt_local_entry,
			 const char *message)
				 uint16_t flags)
{
	bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry (%pM): %s\n",
		tt_local_entry->addr, message);

	atomic_dec(&bat_priv->num_local_tt);

	hash_remove(bat_priv->tt_local_hash, compare_ltt, choose_orig,
		    tt_local_entry->addr);
	tt_local_event(bat_priv, tt_local_entry->addr,
		       tt_local_entry->flags | flags);

	tt_local_entry_free_ref(tt_local_entry);
	/* The local client has to be merked as "pending to be removed" but has
	 * to be kept in the table in order to send it in an full tables
	 * response issued before the net ttvn increment (consistency check) */
	tt_local_entry->flags |= TT_CLIENT_PENDING;
}

void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
@@ -379,14 +381,14 @@ void tt_local_remove(struct bat_priv *bat_priv, const uint8_t *addr,
	struct tt_local_entry *tt_local_entry = NULL;

	tt_local_entry = tt_local_hash_find(bat_priv, addr);

	if (!tt_local_entry)
		goto out;

	tt_local_event(bat_priv, tt_local_entry->addr,
		       tt_local_entry->flags | TT_CLIENT_DEL |
	tt_local_set_pending(bat_priv, tt_local_entry, TT_CLIENT_DEL |
			     (roaming ? TT_CLIENT_ROAM : NO_FLAGS));
	tt_local_del(bat_priv, tt_local_entry, message);

	bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) pending to be removed: "
		"%s\n", tt_local_entry->addr, message);
out:
	if (tt_local_entry)
		tt_local_entry_free_ref(tt_local_entry);
@@ -411,18 +413,19 @@ static void tt_local_purge(struct bat_priv *bat_priv)
			if (tt_local_entry->flags & TT_CLIENT_NOPURGE)
				continue;

			/* entry already marked for deletion */
			if (tt_local_entry->flags & TT_CLIENT_PENDING)
				continue;

			if (!is_out_of_time(tt_local_entry->last_seen,
					    TT_LOCAL_TIMEOUT * 1000))
				continue;

			tt_local_event(bat_priv, tt_local_entry->addr,
				       tt_local_entry->flags | TT_CLIENT_DEL);
			atomic_dec(&bat_priv->num_local_tt);
			bat_dbg(DBG_TT, bat_priv, "Deleting local "
				"tt entry (%pM): timed out\n",
			tt_local_set_pending(bat_priv, tt_local_entry,
					     TT_CLIENT_DEL);
			bat_dbg(DBG_TT, bat_priv, "Local tt entry (%pM) "
				"pending to be removed: timed out\n",
				tt_local_entry->addr);
			hlist_del_rcu(node);
			tt_local_entry_free_ref(tt_local_entry);
		}
		spin_unlock_bh(list_lock);
	}
@@ -785,6 +788,11 @@ struct orig_node *transtable_search(struct bat_priv *bat_priv,
	if (!atomic_inc_not_zero(&tt_global_entry->orig_node->refcount))
		goto free_tt;

	/* A global client marked as PENDING has already moved from that
	 * originator */
	if (tt_global_entry->flags & TT_CLIENT_PENDING)
		goto free_tt;

	orig_node = tt_global_entry->orig_node;

free_tt:
@@ -846,6 +854,10 @@ uint16_t tt_local_crc(struct bat_priv *bat_priv)
		rcu_read_lock();
		hlist_for_each_entry_rcu(tt_local_entry, node,
					 head, hash_entry) {
			/* not yet committed clients have not to be taken into
			 * account while computing the CRC */
			if (tt_local_entry->flags & TT_CLIENT_NEW)
				continue;
			total_one = 0;
			for (j = 0; j < ETH_ALEN; j++)
				total_one = crc16_byte(total_one,
@@ -935,6 +947,16 @@ static struct tt_req_node *new_tt_req_node(struct bat_priv *bat_priv,
	return tt_req_node;
}

/* data_ptr is useless here, but has to be kept to respect the prototype */
static int tt_local_valid_entry(const void *entry_ptr, const void *data_ptr)
{
	const struct tt_local_entry *tt_local_entry = entry_ptr;

	if (tt_local_entry->flags & TT_CLIENT_NEW)
		return 0;
	return 1;
}

static int tt_global_valid_entry(const void *entry_ptr, const void *data_ptr)
{
	const struct tt_global_entry *tt_global_entry = entry_ptr;
@@ -1275,7 +1297,8 @@ static bool send_my_tt_response(struct bat_priv *bat_priv,

		skb = tt_response_fill_table(tt_len, ttvn,
					     bat_priv->tt_local_hash,
					     primary_if, NULL, NULL);
					     primary_if, tt_local_valid_entry,
					     NULL);
		if (!skb)
			goto out;

@@ -1400,6 +1423,10 @@ bool is_my_client(struct bat_priv *bat_priv, const uint8_t *addr)
	tt_local_entry = tt_local_hash_find(bat_priv, addr);
	if (!tt_local_entry)
		goto out;
	/* Check if the client has been logically deleted (but is kept for
	 * consistency purpose) */
	if (tt_local_entry->flags & TT_CLIENT_PENDING)
		goto out;
	ret = true;
out:
	if (tt_local_entry)
@@ -1620,3 +1647,76 @@ void tt_free(struct bat_priv *bat_priv)

	kfree(bat_priv->tt_buff);
}

/* This function will reset the specified flags from all the entries in
 * the given hash table and will increment num_local_tt for each involved
 * entry */
static void tt_local_reset_flags(struct bat_priv *bat_priv, uint16_t flags)
{
	int i;
	struct hashtable_t *hash = bat_priv->tt_local_hash;
	struct hlist_head *head;
	struct hlist_node *node;
	struct tt_local_entry *tt_local_entry;

	if (!hash)
		return;

	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];

		rcu_read_lock();
		hlist_for_each_entry_rcu(tt_local_entry, node,
					 head, hash_entry) {
			tt_local_entry->flags &= ~flags;
			atomic_inc(&bat_priv->num_local_tt);
		}
		rcu_read_unlock();
	}

}

/* Purge out all the tt local entries marked with TT_CLIENT_PENDING */
static void tt_local_purge_pending_clients(struct bat_priv *bat_priv)
{
	struct hashtable_t *hash = bat_priv->tt_local_hash;
	struct tt_local_entry *tt_local_entry;
	struct hlist_node *node, *node_tmp;
	struct hlist_head *head;
	spinlock_t *list_lock; /* protects write access to the hash lists */
	int i;

	if (!hash)
		return;

	for (i = 0; i < hash->size; i++) {
		head = &hash->table[i];
		list_lock = &hash->list_locks[i];

		spin_lock_bh(list_lock);
		hlist_for_each_entry_safe(tt_local_entry, node, node_tmp,
					  head, hash_entry) {
			if (!(tt_local_entry->flags & TT_CLIENT_PENDING))
				continue;

			bat_dbg(DBG_TT, bat_priv, "Deleting local tt entry "
				"(%pM): pending\n", tt_local_entry->addr);

			atomic_dec(&bat_priv->num_local_tt);
			hlist_del_rcu(node);
			tt_local_entry_free_ref(tt_local_entry);
		}
		spin_unlock_bh(list_lock);
	}

}

void tt_commit_changes(struct bat_priv *bat_priv)
{
	tt_local_reset_flags(bat_priv, TT_CLIENT_NEW);
	tt_local_purge_pending_clients(bat_priv);

	/* Increment the TTVN only once per OGM interval */
	atomic_inc(&bat_priv->ttvn);
	bat_priv->tt_poss_change = false;
}
Loading