if (tt_global_entry) {
/* This node is probably going to update its tt table */
tt_global_entry->orig_node->tt_poss_change = true;
- /* The global entry has to be marked as PENDING and has to be
+ /* The global entry has to be marked as ROAMING and has to be
* kept for consistency purpose */
- tt_global_entry->flags |= TT_CLIENT_PENDING;
+ tt_global_entry->flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+
send_roam_adv(bat_priv, tt_global_entry->addr,
tt_global_entry->orig_node);
}
const char *message, bool roaming)
{
struct tt_global_entry *tt_global_entry = NULL;
+ struct tt_local_entry *tt_local_entry = NULL;
tt_global_entry = tt_global_hash_find(bat_priv, addr);
if (!tt_global_entry)
if (tt_global_entry->orig_node == orig_node) {
if (roaming) {
- tt_global_entry->flags |= TT_CLIENT_ROAM;
- tt_global_entry->roam_at = jiffies;
- goto out;
+ /* if we are deleting a global entry due to a roam
+ * event, there are two possibilities:
+ * 1) the client roamed from node A to node B => we mark
+ * it with TT_CLIENT_ROAM, we start a timer and we
+ * wait for node B to claim it. In case of timeout
+ * the entry is purged.
+ * 2) the client roamed to us => we can directly delete
+ * the global entry, since it is useless now. */
+ tt_local_entry = tt_local_hash_find(bat_priv,
+ tt_global_entry->addr);
+ if (!tt_local_entry) {
+ tt_global_entry->flags |= TT_CLIENT_ROAM;
+ tt_global_entry->roam_at = jiffies;
+ goto out;
+ }
}
_tt_global_del(bat_priv, tt_global_entry, message);
}
out:
if (tt_global_entry)
tt_global_entry_free_ref(tt_global_entry);
+ if (tt_local_entry)
+ tt_local_entry_free_ref(tt_local_entry);
}
void tt_global_del_orig(struct bat_priv *bat_priv,
return total;
}
+/**
+ * batadv_tt_req_node_release - free tt_req node entry
+ * @ref: kref pointer of the tt req_node entry
+ */
+static void batadv_tt_req_node_release(struct kref *ref)
+{
+ struct tt_req_node *tt_req_node;
+
+ tt_req_node = container_of(ref, struct tt_req_node, refcount);
+
+ kfree(tt_req_node);
+}
+
+/**
+ * batadv_tt_req_node_put - decrement the tt_req_node refcounter and
+ * possibly release it
+ * @tt_req_node: tt_req_node to be free'd
+ */
+static void batadv_tt_req_node_put(struct tt_req_node *tt_req_node)
+{
+ kref_put(&tt_req_node->refcount, batadv_tt_req_node_release);
+}
+
static void tt_req_list_free(struct bat_priv *bat_priv)
{
struct tt_req_node *node, *safe;
list_for_each_entry_safe(node, safe, &bat_priv->tt_req_list, list) {
list_del(&node->list);
- kfree(node);
+ batadv_tt_req_node_put(node);
}
spin_unlock_bh(&bat_priv->tt_req_list_lock);
if (is_out_of_time(node->issued_at,
TT_REQUEST_TIMEOUT * 1000)) {
list_del(&node->list);
- kfree(node);
+ batadv_tt_req_node_put(node);
}
}
spin_unlock_bh(&bat_priv->tt_req_list_lock);
if (!tt_req_node)
goto unlock;
+ kref_init(&tt_req_node->refcount);
memcpy(tt_req_node->addr, orig_node->orig, ETH_ALEN);
tt_req_node->issued_at = jiffies;
+ kref_get(&tt_req_node->refcount);
list_add(&tt_req_node->list, &bat_priv->tt_req_list);
unlock:
spin_unlock_bh(&bat_priv->tt_req_list_lock);
hardif_free_ref(primary_if);
if (ret)
kfree_skb(skb);
+
if (ret && tt_req_node) {
spin_lock_bh(&bat_priv->tt_req_list_lock);
- list_del(&tt_req_node->list);
+ if (!list_empty(&tt_req_node->list)) {
+ list_del(&tt_req_node->list);
+ batadv_tt_req_node_put(tt_req_node);
+ }
spin_unlock_bh(&bat_priv->tt_req_list_lock);
- kfree(tt_req_node);
}
+
+ if (tt_req_node)
+ batadv_tt_req_node_put(tt_req_node);
+
return ret;
}
if (!compare_eth(node->addr, tt_response->src))
continue;
list_del(&node->list);
- kfree(node);
+ batadv_tt_req_node_put(node);
}
spin_unlock_bh(&bat_priv->tt_req_list_lock);
{
struct tt_local_entry *tt_local_entry = NULL;
struct tt_global_entry *tt_global_entry = NULL;
- bool ret = true;
+ bool ret = false;
if (!atomic_read(&bat_priv->ap_isolation))
- return false;
+ goto out;
tt_local_entry = tt_local_hash_find(bat_priv, dst);
if (!tt_local_entry)
if (!tt_global_entry)
goto out;
- if (_is_ap_isolated(tt_local_entry, tt_global_entry))
+ if (!_is_ap_isolated(tt_local_entry, tt_global_entry))
goto out;
- ret = false;
+ ret = true;
out:
if (tt_global_entry)