mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-10-26 10:57:38 +08:00
Merge tag 'batadv-next-pullrequest-20260930' of https://git.open-mesh.org/batadv
Simon Wunderlich says: ==================== This feature/cleanup patchset includes the following patches: - bla: avoid double free after failed backbone_hash alloc, by Sven Eckelmann - tt: update kerneldoc, by Sven Eckelmann (3 patches) - tt: fix local DEL handling, by Sven Eckelmann (3 patches) - tt: reject VLAN/TT entries before reaching size limit, by Sven Eckelmann - use assign_bit() where applicable, by Peng Fan * tag 'batadv-next-pullrequest-20260930' of https://git.open-mesh.org/batadv: batman-adv: use assign_bit() where applicable batman-adv: tt: reject VLAN/TT entries before reaching size limit batman-adv: tt: queue local DEL event before marking entry as pending batman-adv: tt: queue local DEL event under bucket lock batman-adv: tt: only queue local del event after successful unlink batman-adv: tt: soften kernel-doc for batadv_tt_local_remove_now() batman-adv: tt: clarify responsibility for roam flag during removal batman-adv: tt: clarify kernel-doc for batadv_tt_global_purge_local batman-adv: bla: avoid double free after failed backbone_hash alloc ==================== Link: https://patch.msgid.link/20260930094558.3723766-1-sw@simonwunderlich.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7770df9c56
7 files changed
+299
-98
No files matched your search
@@ -1625,6 +1625,7 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
|
||||
bat_priv->bla.backbone_hash = batadv_hash_new(32);
|
||||
if (!bat_priv->bla.backbone_hash) {
|
||||
batadv_hash_destroy(bat_priv->bla.claim_hash);
|
||||
bat_priv->bla.claim_hash = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -863,10 +863,8 @@ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
|
||||
u8 flags,
|
||||
void *tvlv_value, u16 tvlv_value_len)
|
||||
{
|
||||
if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
|
||||
clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
|
||||
else
|
||||
set_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities);
|
||||
assign_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities,
|
||||
!(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -198,6 +198,7 @@ int batadv_mesh_init(struct net_device *mesh_iface)
|
||||
spin_lock_init(&bat_priv->tt.roam_list_lock);
|
||||
spin_lock_init(&bat_priv->tt.last_changeset_lock);
|
||||
spin_lock_init(&bat_priv->tt.commit_lock);
|
||||
spin_lock_init(&bat_priv->tt.reserve_lock);
|
||||
spin_lock_init(&bat_priv->gw.list_lock);
|
||||
#ifdef CONFIG_BATMAN_ADV_MCAST
|
||||
spin_lock_init(&bat_priv->mcast.mla_lock);
|
||||
|
||||
@@ -561,6 +561,8 @@ void batadv_meshif_vlan_release(struct kref *ref)
|
||||
hlist_del_rcu(&vlan->list);
|
||||
spin_unlock_bh(&vlan->bat_priv->meshif_vlan_list_lock);
|
||||
|
||||
batadv_tt_local_unreserve_vlan(vlan->bat_priv);
|
||||
|
||||
kfree_rcu(vlan, rcu);
|
||||
}
|
||||
|
||||
@@ -614,9 +616,15 @@ int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid)
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
if (!batadv_tt_local_reserve_vlan(bat_priv, vid)) {
|
||||
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
vlan = kzalloc_obj(*vlan, GFP_ATOMIC);
|
||||
if (!vlan) {
|
||||
spin_unlock_bh(&bat_priv->meshif_vlan_list_lock);
|
||||
batadv_tt_local_unreserve_vlan(bat_priv);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
@@ -234,6 +234,162 @@ batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,
|
||||
return tt_global_entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_len() - compute length in bytes of given number of tt changes
|
||||
* @changes_num: number of tt changes
|
||||
*
|
||||
* Return: computed length in bytes.
|
||||
*/
|
||||
static int batadv_tt_len(int changes_num)
|
||||
{
|
||||
return changes_num * sizeof(struct batadv_tvlv_tt_change);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_transmit_size() - calculate the size of a full table response
|
||||
* for a given number of VLANs and local TT entries
|
||||
* @num_vlan: number of announced VLANs
|
||||
* @num_entries: number of announced local TT entries
|
||||
*
|
||||
* Return: local translation table size in bytes.
|
||||
*/
|
||||
static int batadv_tt_local_transmit_size(u16 num_vlan, u16 num_entries)
|
||||
{
|
||||
int hdr_size;
|
||||
|
||||
/* header size of tvlv encapsulated tt response payload */
|
||||
hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
|
||||
hdr_size += sizeof(struct batadv_tvlv_hdr);
|
||||
hdr_size += sizeof(struct batadv_tvlv_tt_data);
|
||||
hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
|
||||
|
||||
return hdr_size + batadv_tt_len(num_entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_reserve() - reserve room in the transmittable local table
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @num_vlan: number of VLANs to reserve
|
||||
* @num_entries: number of local TT entries to reserve
|
||||
* @table_size: stores the resulting worst case table size in bytes
|
||||
*
|
||||
* Add the requested number of VLANs and local TT entries to the reservation
|
||||
* counters and check whether the local translation table would then still fit
|
||||
* in a single full table response. The reservation is dropped again when it
|
||||
* would not.
|
||||
*
|
||||
* The reservation has to happen before the related object is allocated. This
|
||||
* way two parallel allocations cannot both observe enough room for themselves
|
||||
* and end up with a local table which can no longer be transmitted.
|
||||
*
|
||||
* A granted reservation must be returned via batadv_tt_local_unreserve() when
|
||||
* the related object is released or was never created.
|
||||
*
|
||||
* Return: true when the reservation was granted, false otherwise.
|
||||
*/
|
||||
static bool batadv_tt_local_reserve(struct batadv_priv *bat_priv, u16 num_vlan,
|
||||
u16 num_entries, int *table_size)
|
||||
{
|
||||
int packet_size_max = READ_ONCE(bat_priv->packet_size_max);
|
||||
|
||||
scoped_guard(spinlock_bh, &bat_priv->tt.reserve_lock) {
|
||||
bat_priv->tt.reserved_vlans += num_vlan;
|
||||
bat_priv->tt.reserved_entries += num_entries;
|
||||
|
||||
*table_size = batadv_tt_local_transmit_size(bat_priv->tt.reserved_vlans,
|
||||
bat_priv->tt.reserved_entries);
|
||||
if (*table_size <= packet_size_max)
|
||||
return true;
|
||||
|
||||
bat_priv->tt.reserved_vlans -= num_vlan;
|
||||
bat_priv->tt.reserved_entries -= num_entries;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_unreserve() - return room in the transmittable local table
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @num_vlan: number of VLANs to return
|
||||
* @num_entries: number of local TT entries to return
|
||||
*/
|
||||
static void batadv_tt_local_unreserve(struct batadv_priv *bat_priv,
|
||||
u16 num_vlan, u16 num_entries)
|
||||
{
|
||||
scoped_guard(spinlock_bh, &bat_priv->tt.reserve_lock) {
|
||||
bat_priv->tt.reserved_vlans -= num_vlan;
|
||||
bat_priv->tt.reserved_entries -= num_entries;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_reserve_entry() - reserve room for a new local TT entry
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @addr: the mac address of the client to add
|
||||
*
|
||||
* Return: true when the reservation was granted, false otherwise.
|
||||
*/
|
||||
static bool batadv_tt_local_reserve_entry(struct batadv_priv *bat_priv,
|
||||
const u8 *addr)
|
||||
{
|
||||
int table_size;
|
||||
|
||||
if (batadv_tt_local_reserve(bat_priv, 0, 1, &table_size))
|
||||
return true;
|
||||
|
||||
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
|
||||
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
|
||||
table_size,
|
||||
READ_ONCE(bat_priv->packet_size_max), addr);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_unreserve_entry() - return the room of a local TT entry
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
*/
|
||||
static void batadv_tt_local_unreserve_entry(struct batadv_priv *bat_priv)
|
||||
{
|
||||
batadv_tt_local_unreserve(bat_priv, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_reserve_vlan() - reserve room for a new VLAN
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @vid: the VLAN identifier
|
||||
*
|
||||
* Each VLAN adds a per VLAN header to the full table response and therefore
|
||||
* has to be reserved before batadv_meshif_create_vlan() allocates it.
|
||||
*
|
||||
* Return: true when the reservation was granted, false otherwise.
|
||||
*/
|
||||
bool batadv_tt_local_reserve_vlan(struct batadv_priv *bat_priv,
|
||||
unsigned short vid)
|
||||
{
|
||||
int table_size;
|
||||
|
||||
if (batadv_tt_local_reserve(bat_priv, 1, 0, &table_size))
|
||||
return true;
|
||||
|
||||
net_ratelimited_function(batadv_info, bat_priv->mesh_iface,
|
||||
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new VLAN: %d\n",
|
||||
table_size, READ_ONCE(bat_priv->packet_size_max),
|
||||
batadv_print_vid(vid));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_unreserve_vlan() - return the room of a VLAN
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
*/
|
||||
void batadv_tt_local_unreserve_vlan(struct batadv_priv *bat_priv)
|
||||
{
|
||||
batadv_tt_local_unreserve(bat_priv, 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_entry_release() - release tt_local_entry from lists and queue
|
||||
* for free after rcu grace period
|
||||
@@ -246,6 +402,7 @@ static void batadv_tt_local_entry_release(struct kref *ref)
|
||||
tt_local_entry = container_of(ref, struct batadv_tt_local_entry,
|
||||
common.refcount);
|
||||
|
||||
batadv_tt_local_unreserve_entry(tt_local_entry->vlan->bat_priv);
|
||||
batadv_meshif_vlan_put(tt_local_entry->vlan);
|
||||
|
||||
kfree_rcu(tt_local_entry, common.rcu);
|
||||
@@ -461,23 +618,21 @@ static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_event() - store a local TT event (ADD/DEL)
|
||||
* __batadv_tt_local_event() - store a local TT event (ADD/DEL) with given flags
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @tt_local_entry: the TT entry involved in the event
|
||||
* @event_flags: flags to store in the event structure
|
||||
* @common: the TT entry involved in the event
|
||||
* @flags: flags of the TT entry combined with the event flags
|
||||
*/
|
||||
static void batadv_tt_local_event(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
u8 event_flags)
|
||||
static void __batadv_tt_local_event(struct batadv_priv *bat_priv,
|
||||
const struct batadv_tt_common_entry *common,
|
||||
u8 flags)
|
||||
{
|
||||
struct batadv_tt_common_entry *common = &tt_local_entry->common;
|
||||
struct batadv_tt_change_node *tt_change_node;
|
||||
struct batadv_tt_change_node *entry;
|
||||
struct batadv_tt_change_node *safe;
|
||||
bool del_op_requested;
|
||||
bool del_op_entry;
|
||||
size_t changes;
|
||||
u8 flags;
|
||||
|
||||
tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);
|
||||
if (!tt_change_node)
|
||||
@@ -488,8 +643,6 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
|
||||
ether_addr_copy(tt_change_node->change.addr, common->addr);
|
||||
tt_change_node->change.vid = htons(common->vid);
|
||||
|
||||
flags = batadv_tt_flags_get(common) | event_flags;
|
||||
|
||||
tt_change_node->change.flags = flags;
|
||||
del_op_requested = flags & BATADV_TT_CLIENT_DEL;
|
||||
|
||||
@@ -538,14 +691,20 @@ update_changes:
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_len() - compute length in bytes of given number of tt changes
|
||||
* @changes_num: number of tt changes
|
||||
*
|
||||
* Return: computed length in bytes.
|
||||
* batadv_tt_local_event() - store a local TT event (ADD/DEL)
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @tt_local_entry: the TT entry involved in the event
|
||||
* @event_flags: flags to store in the event structure
|
||||
*/
|
||||
static int batadv_tt_len(int changes_num)
|
||||
static void batadv_tt_local_event(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
u8 event_flags)
|
||||
{
|
||||
return changes_num * sizeof(struct batadv_tvlv_tt_change);
|
||||
struct batadv_tt_common_entry *common = &tt_local_entry->common;
|
||||
u8 flags;
|
||||
|
||||
flags = batadv_tt_flags_get(common) | event_flags;
|
||||
__batadv_tt_local_event(bat_priv, common, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -571,7 +730,6 @@ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
|
||||
struct batadv_meshif_vlan *vlan;
|
||||
u16 tt_local_entries = 0;
|
||||
u16 num_vlan = 0;
|
||||
int hdr_size;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(vlan, &bat_priv->meshif_vlan_list, list) {
|
||||
@@ -580,13 +738,7 @@ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv)
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/* header size of tvlv encapsulated tt response payload */
|
||||
hdr_size = sizeof(struct batadv_unicast_tvlv_packet);
|
||||
hdr_size += sizeof(struct batadv_tvlv_hdr);
|
||||
hdr_size += sizeof(struct batadv_tvlv_tt_data);
|
||||
hdr_size += num_vlan * sizeof(struct batadv_tvlv_tt_vlan_data);
|
||||
|
||||
return hdr_size + batadv_tt_len(tt_local_entries);
|
||||
return batadv_tt_local_transmit_size(num_vlan, tt_local_entries);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -790,23 +942,15 @@ batadv_tt_local_create(struct net_device *mesh_iface, const u8 *addr,
|
||||
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
|
||||
struct batadv_tt_local_entry *tt_local;
|
||||
struct batadv_meshif_vlan *vlan;
|
||||
int packet_size_max;
|
||||
int table_size;
|
||||
|
||||
/* Ignore the client if we cannot send it in a full table response. */
|
||||
table_size = batadv_tt_local_table_transmit_size(bat_priv);
|
||||
table_size += batadv_tt_len(1);
|
||||
packet_size_max = READ_ONCE(bat_priv->packet_size_max);
|
||||
if (table_size > packet_size_max) {
|
||||
net_ratelimited_function(batadv_info, mesh_iface,
|
||||
"Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n",
|
||||
table_size, packet_size_max, addr);
|
||||
if (!batadv_tt_local_reserve_entry(bat_priv, addr))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);
|
||||
if (!tt_local)
|
||||
if (!tt_local) {
|
||||
batadv_tt_local_unreserve_entry(bat_priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* increase the refcounter of the related vlan */
|
||||
vlan = batadv_meshif_vlan_get(bat_priv, vid);
|
||||
@@ -815,6 +959,7 @@ batadv_tt_local_create(struct net_device *mesh_iface, const u8 *addr,
|
||||
"adding TT local entry %pM to non-existent VLAN %d\n",
|
||||
addr, batadv_print_vid(vid));
|
||||
kmem_cache_free(batadv_tl_cache, tt_local);
|
||||
batadv_tt_local_unreserve_entry(bat_priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1420,21 +1565,37 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_set_pending_event() - trigger events for TT pending removal
|
||||
* batadv_tt_local_set_pending() - mark local TT entry as pending removal
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @tt_local_entry: local TT entry which was marked as BATADV_TT_CLIENT_PENDING
|
||||
* @tt_local_entry: local TT entry to mark as BATADV_TT_CLIENT_PENDING
|
||||
* @flags: TT change flags to announce together with the pending removal
|
||||
* @message: debug message describing the reason for the change
|
||||
*
|
||||
* Schedule the TT change announcement for the entry. The caller must already
|
||||
* have added BATADV_TT_CLIENT_PENDING to the @tt_local_entry
|
||||
* Schedule the TT change announcement and set BATADV_TT_CLIENT_PENDING on the
|
||||
* entry. The entry is kept in the local table until the next TTVN increment
|
||||
* so that a consistency-check response can still be answered.
|
||||
*
|
||||
* Next to the flags_lock of the entry, the caller must hold the hash bucket
|
||||
* list_lock of @tt_local_entry. Otherwise
|
||||
* batadv_tt_local_purge_pending_clients() could remove the entry before its
|
||||
* change was queued.
|
||||
*/
|
||||
static void
|
||||
batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
u16 flags, const char *message)
|
||||
batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
u16 flags, const char *message)
|
||||
__must_hold(&tt_local_entry->common.flags_lock)
|
||||
{
|
||||
batadv_tt_local_event(bat_priv, tt_local_entry, flags);
|
||||
struct batadv_tt_common_entry *common = &tt_local_entry->common;
|
||||
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
|
||||
u32 i;
|
||||
|
||||
i = batadv_choose_tt(common, hash->size);
|
||||
lockdep_assert_held(&hash->list_locks[i]);
|
||||
lockdep_assert_held(&common->flags_lock);
|
||||
|
||||
__batadv_tt_local_event(bat_priv, common, common->flags | flags);
|
||||
common->flags |= BATADV_TT_CLIENT_PENDING;
|
||||
|
||||
batadv_dbg(BATADV_DBG_TT, bat_priv,
|
||||
"Local tt entry (%pM, vid: %d) pending to be removed: %s\n",
|
||||
@@ -1443,45 +1604,77 @@ batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_mark_removed() - mark a local entry as removed
|
||||
* batadv_tt_local_mark_removed() - mark a local entry as removed and queue DEL
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @tt_local_entry: local TT entry to mark
|
||||
* @message: message to append to the log on deletion
|
||||
* @roaming: true if the deletion is due to a roaming event
|
||||
* @curr_flags: pointer to store the flags of the entry before it was marked
|
||||
*
|
||||
* An already announced entry is marked as BATADV_TT_CLIENT_PENDING and the
|
||||
* (roamed) DEL change is queued. Both happen under the hash bucket list_lock
|
||||
* of the entry to prevent concurrent batadv_tt_local_purge_pending_clients()
|
||||
* from removing the entry and batadv_tt_local_transition_new() from clearing
|
||||
* BATADV_TT_CLIENT_NEW after it was checked.
|
||||
*
|
||||
* Return: true if the entry has to be kept in the local table until the next
|
||||
* ttvn increment, false if it can be purged immediately.
|
||||
*/
|
||||
static bool
|
||||
batadv_tt_local_mark_removed(struct batadv_tt_local_entry *tt_local_entry,
|
||||
bool roaming, u16 *curr_flags)
|
||||
batadv_tt_local_mark_removed(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_local_entry *tt_local_entry,
|
||||
const char *message, bool roaming, u16 *curr_flags)
|
||||
{
|
||||
spinlock_t *list_lock; /* protects write access to the hash lists */
|
||||
struct batadv_tt_common_entry *common = &tt_local_entry->common;
|
||||
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
|
||||
bool pending = false;
|
||||
u16 flags;
|
||||
u32 i;
|
||||
|
||||
i = batadv_choose_tt(common, hash->size);
|
||||
list_lock = &hash->list_locks[i];
|
||||
|
||||
spin_lock_bh(list_lock);
|
||||
|
||||
scoped_guard(spinlock_bh, &common->flags_lock) {
|
||||
*curr_flags = common->flags;
|
||||
|
||||
/* mark the local client as ROAMed */
|
||||
/* if this global entry addition is due to a roaming, the node
|
||||
* has to mark the local entry as "roamed" in order to
|
||||
* correctly reroute packets later
|
||||
*/
|
||||
if (roaming)
|
||||
common->flags |= BATADV_TT_CLIENT_ROAM;
|
||||
|
||||
if (!(common->flags & BATADV_TT_CLIENT_NEW)) {
|
||||
common->flags |= BATADV_TT_CLIENT_PENDING;
|
||||
pending = true;
|
||||
}
|
||||
if (common->flags & BATADV_TT_CLIENT_NEW)
|
||||
break;
|
||||
|
||||
flags = BATADV_TT_CLIENT_DEL;
|
||||
if (roaming)
|
||||
flags |= BATADV_TT_CLIENT_ROAM;
|
||||
|
||||
batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
|
||||
message);
|
||||
pending = true;
|
||||
}
|
||||
|
||||
spin_unlock_bh(list_lock);
|
||||
|
||||
return pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* batadv_tt_local_remove_now() - purge a local entry which was never announced
|
||||
* batadv_tt_local_remove_now() - purge a local entry which was not (yet) announced
|
||||
* @bat_priv: the bat priv with all the mesh interface information
|
||||
* @tt_local_entry: local TT entry to purge
|
||||
*
|
||||
* A client which was added right after the last ttvn increment was never sent
|
||||
* to the other nodes. It can therefore be dropped from the local table without
|
||||
* waiting for the next ttvn increment.
|
||||
* A client which was added right after the last ttvn increment was not (yet)
|
||||
* sent to the other nodes. It can therefore be dropped from the local table
|
||||
* without waiting for the next ttvn increment.
|
||||
*
|
||||
* If it was still announced by a parallel context before it was removed from
|
||||
* the hash, then the local TT size adjustment will be handled automatically.
|
||||
*/
|
||||
static void
|
||||
batadv_tt_local_remove_now(struct batadv_priv *bat_priv,
|
||||
@@ -1490,8 +1683,6 @@ batadv_tt_local_remove_now(struct batadv_priv *bat_priv,
|
||||
struct batadv_tt_common_entry *common = &tt_local_entry->common;
|
||||
struct hlist_node *tt_removed_node;
|
||||
|
||||
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
|
||||
|
||||
/* remove exactly this object when still present in hash */
|
||||
tt_removed_node = batadv_hash_remove(bat_priv->tt.local_hash,
|
||||
batadv_compare_tt_entry,
|
||||
@@ -1499,6 +1690,8 @@ batadv_tt_local_remove_now(struct batadv_priv *bat_priv,
|
||||
if (!tt_removed_node)
|
||||
return;
|
||||
|
||||
batadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);
|
||||
|
||||
/* batadv_tt_local_transition_new() may have committed the entry and
|
||||
* thus counted it in the local table size since the
|
||||
* BATADV_TT_CLIENT_NEW check in batadv_tt_local_mark_removed().
|
||||
@@ -1526,27 +1719,16 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
|
||||
{
|
||||
struct batadv_tt_local_entry *tt_local_entry;
|
||||
u16 curr_flags;
|
||||
u16 flags;
|
||||
|
||||
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
|
||||
if (!tt_local_entry)
|
||||
return BATADV_NO_FLAGS;
|
||||
|
||||
flags = BATADV_TT_CLIENT_DEL;
|
||||
/* if this global entry addition is due to a roaming, the node has to
|
||||
* mark the local entry as "roamed" in order to correctly reroute
|
||||
* packets later
|
||||
/* if this client has been added right now, it is possible to
|
||||
* immediately purge it
|
||||
*/
|
||||
if (roaming)
|
||||
flags |= BATADV_TT_CLIENT_ROAM;
|
||||
|
||||
if (batadv_tt_local_mark_removed(tt_local_entry, roaming, &curr_flags))
|
||||
batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
|
||||
flags, message);
|
||||
else
|
||||
/* if this client has been added right now, it is possible to
|
||||
* immediately purge it
|
||||
*/
|
||||
if (!batadv_tt_local_mark_removed(bat_priv, tt_local_entry, message,
|
||||
roaming, &curr_flags))
|
||||
batadv_tt_local_remove_now(bat_priv, tt_local_entry);
|
||||
|
||||
batadv_tt_local_entry_put(tt_local_entry);
|
||||
@@ -1571,37 +1753,25 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,
|
||||
|
||||
hlist_for_each_entry_safe(tt_common_entry, node_tmp, head,
|
||||
hash_entry) {
|
||||
bool cont = false;
|
||||
|
||||
tt_local_entry = container_of(tt_common_entry,
|
||||
struct batadv_tt_local_entry,
|
||||
common);
|
||||
|
||||
scoped_guard(spinlock_bh, &tt_local_entry->common.flags_lock) {
|
||||
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) {
|
||||
cont = true;
|
||||
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
|
||||
break;
|
||||
}
|
||||
|
||||
/* entry already marked for deletion */
|
||||
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) {
|
||||
cont = true;
|
||||
if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) {
|
||||
cont = true;
|
||||
if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
|
||||
break;
|
||||
}
|
||||
|
||||
tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
|
||||
batadv_tt_local_set_pending(bat_priv, tt_local_entry,
|
||||
BATADV_TT_CLIENT_DEL,
|
||||
"timed out");
|
||||
}
|
||||
|
||||
if (cont)
|
||||
continue;
|
||||
|
||||
batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
|
||||
BATADV_TT_CLIENT_DEL, "timed out");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1870,9 +2040,10 @@ out:
|
||||
* @tt_global_entry: the global TT entry of the announced client
|
||||
* @flags: TT flags announced for this non-mesh client
|
||||
*
|
||||
* A client which is announced by another originator is no longer a local
|
||||
* client. Remove it from the local table and take over the WIFI flag it was
|
||||
* tracked with.
|
||||
* A non-multicast client which is announced by another originator is no longer
|
||||
* a local client. Remove it from the local table and (for the global entry)
|
||||
* take over the WIFI flag it was tracked with. Reset the roaming flag in case
|
||||
* the announcement didn't contain the roaming flag.
|
||||
*/
|
||||
static void
|
||||
batadv_tt_global_purge_local(struct batadv_priv *bat_priv,
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
int batadv_tt_init(struct batadv_priv *bat_priv);
|
||||
bool batadv_tt_local_reserve_vlan(struct batadv_priv *bat_priv,
|
||||
unsigned short vid);
|
||||
void batadv_tt_local_unreserve_vlan(struct batadv_priv *bat_priv);
|
||||
bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
|
||||
unsigned short vid, int ifindex, u32 mark);
|
||||
u16 batadv_tt_local_remove(struct batadv_priv *bat_priv,
|
||||
|
||||
@@ -1055,6 +1055,25 @@ struct batadv_priv_tt {
|
||||
*/
|
||||
spinlock_t commit_lock;
|
||||
|
||||
/**
|
||||
* @reserved_entries: number of local TT entries which are currently
|
||||
* allocated or about to be allocated. Together with @reserved_vlans it
|
||||
* describes the worst case size of a full table response.
|
||||
*/
|
||||
u16 reserved_entries;
|
||||
|
||||
/**
|
||||
* @reserved_vlans: number of mesh interface VLANs which are currently
|
||||
* allocated or about to be allocated. Together with @reserved_entries
|
||||
* it describes the worst case size of a full table response.
|
||||
*/
|
||||
u16 reserved_vlans;
|
||||
|
||||
/**
|
||||
* @reserve_lock: lock protecting @reserved_entries & @reserved_vlans
|
||||
*/
|
||||
spinlock_t reserve_lock;
|
||||
|
||||
/** @work: work queue callback item for translation table purging */
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user