From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:33
Dear net maintainers,
here is another cleanup pull request of batman-adv to go into net-next.
Please pull or let me know of any problem!
Thank you,
Simon
The following changes since commit 799152bcf6cbe4393eb03690925a382cefae303c:
batman-adv: tt: decrement count for committed client on local_remove (2026-08-30 20:05:57 +0200)
are available in the Git repository at:
https://git.open-mesh.org/batadv.git tags/batadv-next-pullrequest-20260907
for you to fetch changes up to 6d7f71ae4cdcbb22f541638057299fe26c451e65:
batman-adv: correct batadv_hash_remove kdoc return type (2026-09-06 20:05:31 +0200)
----------------------------------------------------------------
This cleanup patchset includes the following patches, all by Sven Eckelmann:
- translation table cleanups (12 patches)
- kerneldoc fixes noted by sashiko (3 patches)
----------------------------------------------------------------
Sven Eckelmann (15):
batman-adv: tt: look up wifi state of incoming interface in helper
batman-adv: tt: extract allocation of new local entries
batman-adv: tt: replace forward gotos in batadv_tt_local_add()
batman-adv: tt: extract refresh of existing local entries
batman-adv: tt: extract update of dynamic client flags
batman-adv: tt: extract allocation of new global entries
batman-adv: tt: extract merging of flags into existing global entries
batman-adv: tt: replace add_orig_entry goto in batadv_tt_global_add()
batman-adv: tt: extract removal of the superseded local entry
batman-adv: tt: extract marking of a removed local entry
batman-adv: tt: extract immediate purge of a local entry
batman-adv: tt: drop the cleanup label from batadv_tt_local_remove()
batman-adv: tt: clarify kernel doc for batadv_tt_local_set_pending_event()
batman-adv: bat_iv: fix ogm_neigh_is_sob parameters references
batman-adv: correct batadv_hash_remove kdoc return type
net/batman-adv/bat_iv_ogm.c | 4 +-
net/batman-adv/hash.h | 2 +-
net/batman-adv/translation-table.c | 655 +++++++++++++++++++++++--------------
3 files changed, 420 insertions(+), 241 deletions(-)
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:34
From: Sven Eckelmann <sven@narfation.org>
batadv_tt_local_add() only needs to know whether the client was seen on a
wifi interface. But it kept the net_device reference of the incoming
interface alive until its own cleanup section, together with a "net" and an
"in_dev" variable which are of no interest to the rest of the function.
Move the lookup to a small helper which acquires and releases the
net_device reference itself.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 41 +++++++++++++++++++++---------
1 file changed, 29 insertions(+), 12 deletions(-)
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:35
From: Sven Eckelmann <sven@narfation.org>
batadv_tt_local_add() used two labels in the middle of the function to
express which parts of the common tail have to be executed: "add_event" to
announce a (re-)added client and "check_roaming" to skip that announcement.
Jumping forward into the middle of a function makes it hard to see which
path ends up sending an ADD event. Especially since the PENDING branch
reached "add_event" while the branch right below it reached "check_roaming"
instead.
Express the same in an "added" variable and turn the two client cases into
a plain if/else. The PENDING check returned early before the ROAM check
could run, so it becomes an "else if".
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 43 ++++++++++++++----------------
1 file changed, 20 insertions(+), 23 deletions(-)
@@ -846,12 +847,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,*flagcanberesetlikeitwasneverenqueued*/tt_local->common.flags&=~BATADV_TT_CLIENT_PENDING;-spin_unlock_bh(&tt_local->common.flags_lock);--gotoadd_event;-}--if(tt_local->common.flags&BATADV_TT_CLIENT_ROAM){+added=true;+}elseif(tt_local->common.flags&BATADV_TT_CLIENT_ROAM){batadv_dbg(BATADV_DBG_TT,bat_priv,"Roaming client %pM (vid: %d) came back to its original location\n",addr,batadv_print_vid(vid));
@@ -864,29 +861,29 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,roamed_back=true;}spin_unlock_bh(&tt_local->common.flags_lock);+}else{+tt_local=batadv_tt_local_create(mesh_iface,addr,vid,iif_is_wifi);+if(!tt_local)+gotoout;-gotocheck_roaming;-}--tt_local=batadv_tt_local_create(mesh_iface,addr,vid,iif_is_wifi);-if(!tt_local)-gotoout;+kref_get(&tt_local->common.refcount);+hash_added=batadv_hash_add(bat_priv->tt.local_hash,batadv_compare_tt,+batadv_choose_tt,&tt_local->common,+&tt_local->common.hash_entry);-kref_get(&tt_local->common.refcount);-hash_added=batadv_hash_add(bat_priv->tt.local_hash,batadv_compare_tt,-batadv_choose_tt,&tt_local->common,-&tt_local->common.hash_entry);+if(unlikely(hash_added!=0)){+/* remove the reference for the hash */+batadv_tt_local_entry_put(tt_local);+gotoout;+}-if(unlikely(hash_added!=0)){-/* remove the reference for the hash */-batadv_tt_local_entry_put(tt_local);-gotoout;+added=true;}-add_event:-batadv_tt_local_event(bat_priv,tt_local,BATADV_NO_FLAGS);+/* announce the (re-)added client to the mesh */+if(added)+batadv_tt_local_event(bat_priv,tt_local,BATADV_NO_FLAGS);-check_roaming:batadv_tt_local_add_roam(bat_priv,tt_global,roamed_back);spin_lock_bh(&tt_local->common.flags_lock);
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:35
From: Sven Eckelmann <sven@narfation.org>
The code which allocates and initializes a brand new local TT entry makes
up more than a third of batadv_tt_local_add(). It only shares the addr, vid
and iif_is_wifi parameters with the rest of the function.
Move it to batadv_tt_local_create(), which returns the fully initialized
entry. The error paths become plain returns.
The insertion into bat_priv->tt.local_hash intentionally stays in
batadv_tt_local_add(), keeping the extra reference for the hash next to the
error handling which has to drop it again.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 135 +++++++++++++++++------------
1 file changed, 79 insertions(+), 56 deletions(-)
@@ -720,6 +720,84 @@ static bool batadv_tt_iif_is_wifi(struct net *net, int ifindex)returnbatadv_is_wifi(wifi_flags);}+/**+*batadv_tt_local_create()-allocateandinitializealocalTTentry+*@mesh_iface:netdevstructofthemeshinterface+*@addr:themacaddressoftheclienttoadd+*@vid:VLANidentifier+*@iif_is_wifi:whethertheclientisconnectedviaawifiinterface+*+*Thereturnedentryisnotyetpartofbat_priv->tt.local_hash.Itismarked+*asBATADV_TT_CLIENT_NEWtoavoidsendingitinafulltableresponsegoing+*outbeforethenextttvnincrement(consistencycheck).+*+*Return:thenewentrywithaninitializedreferencecounteronsuccess,NULL+*otherwise.+*/+staticstructbatadv_tt_local_entry*+batadv_tt_local_create(structnet_device*mesh_iface,constu8*addr,+unsignedshortvid,booliif_is_wifi)+{+structbatadv_priv*bat_priv=netdev_priv(mesh_iface);+structbatadv_tt_local_entry*tt_local;+structbatadv_meshif_vlan*vlan;+intpacket_size_max;+inttable_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);+returnNULL;+}++tt_local=kmem_cache_alloc(batadv_tl_cache,GFP_ATOMIC);+if(!tt_local)+returnNULL;++/* increase the refcounter of the related vlan */+vlan=batadv_meshif_vlan_get(bat_priv,vid);+if(!vlan){+net_ratelimited_function(batadv_info,mesh_iface,+"adding TT local entry %pM to non-existent VLAN %d\n",+addr,batadv_print_vid(vid));+kmem_cache_free(batadv_tl_cache,tt_local);+returnNULL;+}++batadv_dbg(BATADV_DBG_TT,bat_priv,+"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",+addr,batadv_print_vid(vid),+(u8)atomic_read(&bat_priv->tt.vn));++ether_addr_copy(tt_local->common.addr,addr);+tt_local->common.vid=vid;+kref_init(&tt_local->common.refcount);+tt_local->last_seen=jiffies;+tt_local->common.added_at=tt_local->last_seen;+tt_local->vlan=vlan;+spin_lock_init(&tt_local->common.flags_lock);++scoped_guard(spinlock_bh,&tt_local->common.flags_lock){+tt_local->common.flags=BATADV_TT_CLIENT_NEW;+if(iif_is_wifi)+tt_local->common.flags|=BATADV_TT_CLIENT_WIFI;++/* the batman interface mac and multicast addresses should never+*bepurged+*/+if(batadv_compare_eth(addr,mesh_iface->dev_addr)||+is_multicast_ether_addr(addr))+tt_local->common.flags|=BATADV_TT_CLIENT_NOPURGE;+}++returntt_local;+}+/***batadv_tt_local_add()-addanewclienttothelocaltableorupdatean*existingclient
@@ -793,62 +868,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,gotocheck_roaming;}-/* 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);-gotoout;-}--tt_local=kmem_cache_alloc(batadv_tl_cache,GFP_ATOMIC);+tt_local=batadv_tt_local_create(mesh_iface,addr,vid,iif_is_wifi);if(!tt_local)gotoout;-/* increase the refcounter of the related vlan */-vlan=batadv_meshif_vlan_get(bat_priv,vid);-if(!vlan){-net_ratelimited_function(batadv_info,mesh_iface,-"adding TT local entry %pM to non-existent VLAN %d\n",-addr,batadv_print_vid(vid));-kmem_cache_free(batadv_tl_cache,tt_local);-tt_local=NULL;-gotoout;-}--batadv_dbg(BATADV_DBG_TT,bat_priv,-"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",-addr,batadv_print_vid(vid),-(u8)atomic_read(&bat_priv->tt.vn));--ether_addr_copy(tt_local->common.addr,addr);-tt_local->common.vid=vid;-kref_init(&tt_local->common.refcount);-tt_local->last_seen=jiffies;-tt_local->common.added_at=tt_local->last_seen;-tt_local->vlan=vlan;-spin_lock_init(&tt_local->common.flags_lock);--spin_lock_bh(&tt_local->common.flags_lock);-/* The local entry has to be marked as NEW to avoid to send it in-*afulltableresponsegoingoutbeforethenextttvnincrement-*(consistencycheck)-*/-tt_local->common.flags=BATADV_TT_CLIENT_NEW;-if(iif_is_wifi)-tt_local->common.flags|=BATADV_TT_CLIENT_WIFI;--/* the batman interface mac and multicast addresses should never be-*purged-*/-if(batadv_compare_eth(addr,mesh_iface->dev_addr)||-is_multicast_ether_addr(addr))-tt_local->common.flags|=BATADV_TT_CLIENT_NOPURGE;-spin_unlock_bh(&tt_local->common.flags_lock);-kref_get(&tt_local->common.refcount);hash_added=batadv_hash_add(bat_priv->tt.local_hash,batadv_compare_tt,batadv_choose_tt,&tt_local->common,
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:36
From: Sven Eckelmann <sven@narfation.org>
The handling of a client which is already part of the local translation
table is independent from the rest of batadv_tt_local_add(): it only
refreshes last_seen and evaluates the PENDING and ROAM flags of the entry
which was just looked up.
Move it to batadv_tt_local_add_existing(). It reports via its return value
whether the client has to be announced to the mesh again and whether the
client roamed back to its original location.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 78 +++++++++++++++++++-----------
1 file changed, 51 insertions(+), 27 deletions(-)
@@ -720,6 +720,55 @@ static bool batadv_tt_iif_is_wifi(struct net *net, int ifindex)returnbatadv_is_wifi(wifi_flags);}+/**+*batadv_tt_local_add_existing()-refreshanalreadyknownlocalTTentry+*@bat_priv:thebatprivwithallthemeshinterfaceinformation+*@tt_local:thelocalTTentrywhichwasfoundinthelocaltable+*@roamed_back:settotruewhentheclientreturnedtoitsoriginallocation+*+*Return:truewhentheclienthastobeannouncedtothemeshagain,false+*otherwise.+*/+staticboolbatadv_tt_local_add_existing(structbatadv_priv*bat_priv,+structbatadv_tt_local_entry*tt_local,+bool*roamed_back)+{+structbatadv_tt_common_entry*common=&tt_local->common;++tt_local->last_seen=jiffies;++scoped_guard(spinlock_bh,&common->flags_lock){+if(common->flags&BATADV_TT_CLIENT_PENDING){+batadv_dbg(BATADV_DBG_TT,bat_priv,+"Re-adding pending client %pM (vid: %d)\n",+common->addr,batadv_print_vid(common->vid));+/* whatever the reason why the PENDING flag was set,+*thisisaclientwhichwasenqueuedtoberemovedin+*thisorig_interval.Sinceitpoppedupagain,the+*flagcanberesetlikeitwasneverenqueued+*/+common->flags&=~BATADV_TT_CLIENT_PENDING;++returntrue;+}++if(common->flags&BATADV_TT_CLIENT_ROAM){+batadv_dbg(BATADV_DBG_TT,bat_priv,+"Roaming client %pM (vid: %d) came back to its original location\n",+common->addr,batadv_print_vid(common->vid));+/* the ROAM flag is set because this client roamed away+*andthenodegotaroaming_advertisementmessage.Now+*thattheclientpoppedupagainatitsoriginal+*locationsuchflagcanbeunset+*/+common->flags&=~BATADV_TT_CLIENT_ROAM;+*roamed_back=true;+}+}++returnfalse;+}+/***batadv_tt_local_create()-allocateandinitializealocalTTentry*@mesh_iface:netdevstructofthemeshinterface
@@ -834,33 +883,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,tt_global=batadv_tt_global_hash_find(bat_priv,addr,vid);if(tt_local){-tt_local->last_seen=jiffies;--spin_lock_bh(&tt_local->common.flags_lock);-if(tt_local->common.flags&BATADV_TT_CLIENT_PENDING){-batadv_dbg(BATADV_DBG_TT,bat_priv,-"Re-adding pending client %pM (vid: %d)\n",-addr,batadv_print_vid(vid));-/* whatever the reason why the PENDING flag was set,-*thisisaclientwhichwasenqueuedtoberemovedin-*thisorig_interval.Sinceitpoppedupagain,the-*flagcanberesetlikeitwasneverenqueued-*/-tt_local->common.flags&=~BATADV_TT_CLIENT_PENDING;-added=true;-}elseif(tt_local->common.flags&BATADV_TT_CLIENT_ROAM){-batadv_dbg(BATADV_DBG_TT,bat_priv,-"Roaming client %pM (vid: %d) came back to its original location\n",-addr,batadv_print_vid(vid));-/* the ROAM flag is set because this client roamed away-*andthenodegotaroaming_advertisementmessage.Now-*thattheclientpoppedupagainatitsoriginal-*locationsuchflagcanbeunset-*/-tt_local->common.flags&=~BATADV_TT_CLIENT_ROAM;-roamed_back=true;-}-spin_unlock_bh(&tt_local->common.flags_lock);+added=batadv_tt_local_add_existing(bat_priv,tt_local,+&roamed_back);}else{tt_local=batadv_tt_local_create(mesh_iface,addr,vid,iif_is_wifi);if(!tt_local)
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:38
From: Sven Eckelmann <sven@narfation.org>
The code which allocates and initializes a brand new global TT entry makes
up a third of batadv_tt_global_add() and only needs the tt_addr, vid and
flags arguments. It is also the only part of the "new entry" branch which
does not deal with the global hash.
Move it to batadv_tt_global_create() and let it return the initialized
entry.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 76 ++++++++++++++++++++----------
1 file changed, 51 insertions(+), 25 deletions(-)
@@ -1832,6 +1832,56 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,spin_unlock_bh(&tt_global->list_lock);}+/**+*batadv_tt_global_create()-allocateandinitializeaglobalTTentry+*@tt_addr:themacaddressofthenon-meshclient+*@vid:VLANidentifier+*@flags:TTflagsthathavetobesetforthisnon-meshclient+*+*Thereturnedentryisnotyetpartofbat_priv->tt.global_hashandhasan+*emptyoriginatorlist.+*+*Return:thenewentrywithaninitializedreferencecounteronsuccess,NULL+*otherwise.+*/+staticstructbatadv_tt_global_entry*+batadv_tt_global_create(constunsignedchar*tt_addr,unsignedshortvid,+u16flags)+{+structbatadv_tt_global_entry*tt_global_entry;+structbatadv_tt_common_entry*common;++tt_global_entry=kmem_cache_zalloc(batadv_tg_cache,GFP_ATOMIC);+if(!tt_global_entry)+returnNULL;++common=&tt_global_entry->common;+ether_addr_copy(common->addr,tt_addr);+common->vid=vid;+spin_lock_init(&common->flags_lock);++if(!is_multicast_ether_addr(common->addr)){+scoped_guard(spinlock_bh,&common->flags_lock)+common->flags=flags&(~BATADV_TT_SYNC_MASK);+}++tt_global_entry->roam_at=0;+/* node must store current time in case of roaming. This is+*neededtopurgethisentryoutontimeout(ifnobodyclaims+*it)+*/+if(flags&BATADV_TT_CLIENT_ROAM)+tt_global_entry->roam_at=jiffies;+kref_init(&common->refcount);+common->added_at=jiffies;++INIT_HLIST_HEAD(&tt_global_entry->orig_list);+atomic_set(&tt_global_entry->orig_list_count,0);+spin_lock_init(&tt_global_entry->list_lock);++returntt_global_entry;+}+/***batadv_tt_global_add()-addanewTTglobalentryorupdateanexistingone*@bat_priv:thebatprivwithallthemeshinterfaceinformation
@@ -1883,35 +1933,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,}if(!tt_global_entry){-tt_global_entry=kmem_cache_zalloc(batadv_tg_cache,-GFP_ATOMIC);+tt_global_entry=batadv_tt_global_create(tt_addr,vid,flags);if(!tt_global_entry)gotoout;common=&tt_global_entry->common;-ether_addr_copy(common->addr,tt_addr);-common->vid=vid;-spin_lock_init(&common->flags_lock);--if(!is_multicast_ether_addr(common->addr)){-spin_lock_bh(&common->flags_lock);-common->flags=flags&(~BATADV_TT_SYNC_MASK);-spin_unlock_bh(&common->flags_lock);-}--tt_global_entry->roam_at=0;-/* node must store current time in case of roaming. This is-*neededtopurgethisentryoutontimeout(ifnobodyclaims-*it)-*/-if(flags&BATADV_TT_CLIENT_ROAM)-tt_global_entry->roam_at=jiffies;-kref_init(&common->refcount);-common->added_at=jiffies;--INIT_HLIST_HEAD(&tt_global_entry->orig_list);-atomic_set(&tt_global_entry->orig_list_count,0);-spin_lock_init(&tt_global_entry->list_lock);kref_get(&common->refcount);hash_added=batadv_hash_add(bat_priv->tt.global_hash,
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:38
From: Sven Eckelmann <sven@narfation.org>
The WIFI and ISOLA flags are re-evaluated on every batadv_tt_local_add()
call, no matter whether a new entry was created or an existing one was
refreshed. It is mostly isolated from the rest of the
batadv_tt_local_add().
Move it to batadv_tt_local_update_flags(). To allow the caller to trigger
the queuing of ADD events, it returns whether one of the flags announced to
the other nodes actually changed.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 79 +++++++++++++++++++-----------
1 file changed, 50 insertions(+), 29 deletions(-)
@@ -847,6 +847,55 @@ batadv_tt_local_create(struct net_device *mesh_iface, const u8 *addr,returntt_local;}+/**+*batadv_tt_local_update_flags()-updatethedynamicflagsofalocalentry+*@bat_priv:thebatprivwithallthemeshinterfaceinformation+*@tt_local:thelocalTTentrytoupdate+*@iif_is_wifi:whethertheclientisconnectedviaawifiinterface+*@mark:thevaluecontainedintheskb->markfieldofthereceivedpacket(if+*any)+*+*Return:trueifaflagannouncedtotheothernodeswasmodified,false+*otherwise.+*/+staticbool+batadv_tt_local_update_flags(structbatadv_priv*bat_priv,+structbatadv_tt_local_entry*tt_local,+booliif_is_wifi,u32mark)+{+structbatadv_tt_common_entry*common=&tt_local->common;+u8remote_flags;+u32match_mark;+boolmodified;++scoped_guard(spinlock_bh,&common->flags_lock){+/* store the current remote flags before altering them. This+*helpsunderstandingisflagsarechangingornot+*/+remote_flags=common->flags&BATADV_TT_REMOTE_MASK;++if(iif_is_wifi)+common->flags|=BATADV_TT_CLIENT_WIFI;+else+common->flags&=~BATADV_TT_CLIENT_WIFI;++/* check the mark in the skb: if it's equal to the configured+*isolation_mark,itmeansthepacketiscomingfroman+*isolatednon-meshclient+*/+match_mark=(mark&bat_priv->isolation_mark_mask);+if(bat_priv->isolation_mark_mask&&+match_mark==bat_priv->isolation_mark)+common->flags|=BATADV_TT_CLIENT_ISOLA;+else+common->flags&=~BATADV_TT_CLIENT_ISOLA;++modified=remote_flags^(common->flags&BATADV_TT_REMOTE_MASK);+}++returnmodified;+}+/***batadv_tt_local_add()-addanewclienttothelocaltableorupdatean*existingclient
@@ -910,35 +956,10 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,batadv_tt_local_add_roam(bat_priv,tt_global,roamed_back);-spin_lock_bh(&tt_local->common.flags_lock);-/* store the current remote flags before altering them. This helps-*understandingisflagsarechangingornot-*/-remote_flags=tt_local->common.flags&BATADV_TT_REMOTE_MASK;--if(iif_is_wifi)-tt_local->common.flags|=BATADV_TT_CLIENT_WIFI;-else-tt_local->common.flags&=~BATADV_TT_CLIENT_WIFI;--/* check the mark in the skb: if it's equal to the configured-*isolation_mark,itmeansthepacketiscomingfromanisolated-*non-meshclient-*/-match_mark=(mark&bat_priv->isolation_mark_mask);-if(bat_priv->isolation_mark_mask&&-match_mark==bat_priv->isolation_mark)-tt_local->common.flags|=BATADV_TT_CLIENT_ISOLA;-else-tt_local->common.flags&=~BATADV_TT_CLIENT_ISOLA;--modified=remote_flags^(tt_local->common.flags&BATADV_TT_REMOTE_MASK);-spin_unlock_bh(&tt_local->common.flags_lock);-/* if any "dynamic" flag has been modified, resend an ADD event for this*entrysothatallthenodescangetthenewflags*/-if(modified)+if(batadv_tt_local_update_flags(bat_priv,tt_local,iif_is_wifi,mark))batadv_tt_local_event(bat_priv,tt_local,BATADV_NO_FLAGS);ret=true;
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:38
From: Sven Eckelmann <sven@narfation.org>
When an already known global TT entry is announced again, its flags have to
be merged with the announced ones. Two of the merge steps also decide
whether the originator list has to be purged before the announced
originator is added.
Move this to batadv_tt_global_merge_flags() and let it report via its
return value whether the originator list has to be purged.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 87 ++++++++++++++++++------------
1 file changed, 52 insertions(+), 35 deletions(-)
@@ -1832,6 +1832,57 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,spin_unlock_bh(&tt_global->list_lock);}+/**+*batadv_tt_global_merge_flags()-mergeannouncedflagsintoaglobalTTentry+*@tt_global_entry:theglobalTTentrytoupdate+*@flags:TTflagsannouncedforthisnon-meshclient+*+*Return:trueiftheoriginatorlistof@tt_global_entryhastobepurged+*beforetheannouncedoriginatorisadded,falseotherwise.+*/+staticbool+batadv_tt_global_merge_flags(structbatadv_tt_global_entry*tt_global_entry,+u16flags)+{+structbatadv_tt_common_entry*common=&tt_global_entry->common;+booldelete=false;++scoped_guard(spinlock_bh,&common->flags_lock){+/* if the client was temporary added before receiving the first+*OGMannouncingit,wehavetocleartheTEMPflag.Also,+*removetheprevioustemporaryorignodeandre-addit+*ifrequired.Iftheorigentrychanged,thenewonewhich+*isanon-temporaryentryispreferred.+*/+if(common->flags&BATADV_TT_CLIENT_TEMP){+delete=true;+common->flags&=~BATADV_TT_CLIENT_TEMP;+}++/* the change can carry possible "attribute" flags like the+*TT_CLIENT_TEMP,thereforetheyhavetobecopiedinthe+*cliententry+*/+if(!is_multicast_ether_addr(common->addr))+common->flags|=flags&(~BATADV_TT_SYNC_MASK);++/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only+*oneoriginatorleftinthelistandwepreviouslyreceiveda+*delete+roamingchangeforthisoriginator.+*+*Weshouldfirstdeletetheoldoriginatorbeforeaddingthe+*newone.+*/+if(common->flags&BATADV_TT_CLIENT_ROAM){+delete=true;+tt_global_entry->roam_at=0;+common->flags&=~BATADV_TT_CLIENT_ROAM;+}+}++returndelete;+}+/***batadv_tt_global_create()-allocateandinitializeaglobalTTentry*@tt_addr:themacaddressofthenon-meshclient
@@ -1974,41 +2025,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,gotoadd_orig_entry;}-delete=false;--spin_lock_bh(&common->flags_lock);-/* if the client was temporary added before receiving the first-*OGMannouncingit,wehavetocleartheTEMPflag.Also,-*removetheprevioustemporaryorignodeandre-addit-*ifrequired.Iftheorigentrychanged,thenewonewhich-*isanon-temporaryentryispreferred.-*/-if(common->flags&BATADV_TT_CLIENT_TEMP){-delete=true;-common->flags&=~BATADV_TT_CLIENT_TEMP;-}--/* the change can carry possible "attribute" flags like the-*TT_CLIENT_TEMP,thereforetheyhavetobecopiedinthe-*cliententry-*/-if(!is_multicast_ether_addr(common->addr))-common->flags|=flags&(~BATADV_TT_SYNC_MASK);--/* If there is the BATADV_TT_CLIENT_ROAM flag set, there is only-*oneoriginatorleftinthelistandwepreviouslyreceiveda-*delete+roamingchangeforthisoriginator.-*-*Weshouldfirstdeletetheoldoriginatorbeforeaddingthe-*newone.-*/-if(common->flags&BATADV_TT_CLIENT_ROAM){-delete=true;-tt_global_entry->roam_at=0;-common->flags&=~BATADV_TT_CLIENT_ROAM;-}-spin_unlock_bh(&common->flags_lock);-+delete=batadv_tt_global_merge_flags(tt_global_entry,flags);if(delete)batadv_tt_global_del_orig_list(tt_global_entry);}
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:38
From: Sven Eckelmann <sven@narfation.org>
The "add_orig_entry" label was only used to skip the flag merging of the
non-temporary path. Which means that the code jumping to it and the code
below it are the two halves of an if/else.
Both halves now only decide whether the originator list has to be purged,
so turn them into an if/else and purge the list at a single place.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
@@ -2021,15 +2021,16 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,if(batadv_tt_global_entry_has_orig(tt_global_entry,orig_node,NULL))gotoout_remove;-batadv_tt_global_del_orig_list(tt_global_entry);-gotoadd_orig_entry;++delete=true;+}else{+delete=batadv_tt_global_merge_flags(tt_global_entry,flags);}-delete=batadv_tt_global_merge_flags(tt_global_entry,flags);if(delete)batadv_tt_global_del_orig_list(tt_global_entry);}-add_orig_entry:+/* add the new orig_entry (if needed) or update it */batadv_tt_global_orig_entry_add(tt_global_entry,orig_node,ttvn,flags&BATADV_TT_SYNC_MASK);
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:39
From: Sven Eckelmann <sven@narfation.org>
The first locked section of batadv_tt_local_remove() does three things at
once
* it snapshots the flags for the return value
* it marks the client as ROAMed
* it decides whether the entry has to survive until the next ttvn increment
But this complex locked section is in the middle of the function and cannot
be written as scoped_guard() due to goto's in this routine.
Move it to batadv_tt_local_mark_removed() and report the decision via its
return value. But leave the batadv_tt_local_set_pending_event() flag
assembly outside the function because it has no locking requirements.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 48 ++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 13 deletions(-)
@@ -1443,6 +1443,38 @@ batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,batadv_print_vid(tt_local_entry->common.vid),message);}+/**+*batadv_tt_local_mark_removed()-markalocalentryasremoved+*@tt_local_entry:localTTentrytomark+*@roaming:trueifthedeletionisduetoaroamingevent+*@curr_flags:pointertostoretheflagsoftheentrybeforeitwasmarked+*+*Return:trueiftheentryhastobekeptinthelocaltableuntilthenext+*ttvnincrement,falseifitcanbepurgedimmediately.+*/+staticbool+batadv_tt_local_mark_removed(structbatadv_tt_local_entry*tt_local_entry,+boolroaming,u16*curr_flags)+{+structbatadv_tt_common_entry*common=&tt_local_entry->common;+boolpending=false;++scoped_guard(spinlock_bh,&common->flags_lock){+*curr_flags=common->flags;++/* mark the local client as ROAMed */+if(roaming)+common->flags|=BATADV_TT_CLIENT_ROAM;++if(!(common->flags&BATADV_TT_CLIENT_NEW)){+common->flags|=BATADV_TT_CLIENT_PENDING;+pending=true;+}+}++returnpending;+}+/***batadv_tt_local_remove()-logicallyremoveanentryfromthelocaltable*@bat_priv:thebatprivwithallthemeshinterfaceinformation
@@ -1467,26 +1499,16 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,if(!tt_local_entry)gotoout;-spin_lock_bh(&tt_local_entry->common.flags_lock);-curr_flags=tt_local_entry->common.flags;-flags=BATADV_TT_CLIENT_DEL;/* if this global entry addition is due to a roaming, the node has to*markthelocalentryas"roamed"inordertocorrectlyreroute*packetslater*/-if(roaming){+if(roaming)flags|=BATADV_TT_CLIENT_ROAM;-/* mark the local client as ROAMed */-tt_local_entry->common.flags|=BATADV_TT_CLIENT_ROAM;-}--if(!(tt_local_entry->common.flags&BATADV_TT_CLIENT_NEW)){-tt_local_entry->common.flags|=BATADV_TT_CLIENT_PENDING;-pending=true;-}-spin_unlock_bh(&tt_local_entry->common.flags_lock);+pending=batadv_tt_local_mark_removed(tt_local_entry,roaming,+&curr_flags);if(pending){batadv_tt_local_set_pending_event(bat_priv,tt_local_entry,flags,message);
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:39
From: Sven Eckelmann <sven@narfation.org>
A client which was announced by another originator is no longer a local
client. The code which drops it from the local table and takes over its
WIFI flag is the second cleanup stage of batadv_tt_global_add() and needed
its own goto to skip over the multicast case.
Move it to batadv_tt_global_purge_local().
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 61 ++++++++++++++++++++----------
1 file changed, 41 insertions(+), 20 deletions(-)
@@ -1832,6 +1832,46 @@ batadv_tt_global_orig_entry_add(struct batadv_tt_global_entry *tt_global,spin_unlock_bh(&tt_global->list_lock);}+/**+*batadv_tt_global_purge_local()-dropthelocalentryofanannouncedclient+*@bat_priv:thebatprivwithallthemeshinterfaceinformation+*@tt_global_entry:theglobalTTentryoftheannouncedclient+*@flags:TTflagsannouncedforthisnon-meshclient+*+*Aclientwhichisannouncedbyanotheroriginatorisnolongeralocal+*client.RemoveitfromthelocaltableandtakeovertheWIFIflagitwas+*trackedwith.+*/+staticvoid+batadv_tt_global_purge_local(structbatadv_priv*bat_priv,+structbatadv_tt_global_entry*tt_global_entry,+u16flags)+{+structbatadv_tt_common_entry*common=&tt_global_entry->common;+u16local_flags;++/* Do not remove multicast addresses from the local hash on+*globaladditions+*/+if(is_multicast_ether_addr(common->addr))+return;++/* remove address from local hash if present */+local_flags=batadv_tt_local_remove(bat_priv,common->addr,common->vid,+"global tt received",+flags&BATADV_TT_CLIENT_ROAM);++scoped_guard(spinlock_bh,&common->flags_lock){+common->flags|=local_flags&BATADV_TT_CLIENT_WIFI;++if(!(flags&BATADV_TT_CLIENT_ROAM))+/* this is a normal global add. Therefore the client is+*notinaroamingstateanymore.+*/+common->flags&=~BATADV_TT_CLIENT_ROAM;+}+}+/***batadv_tt_global_merge_flags()-mergeannouncedflagsintoaglobalTTentry*@tt_global_entry:theglobalTTentrytoupdate
@@ -2042,26 +2082,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,ret=true;out_remove:-/* Do not remove multicast addresses from the local hash on-*globaladditions-*/-if(is_multicast_ether_addr(tt_addr))-gotoout;--/* remove address from local hash if present */-local_flags=batadv_tt_local_remove(bat_priv,tt_addr,vid,-"global tt received",-flags&BATADV_TT_CLIENT_ROAM);--spin_lock_bh(&tt_global_entry->common.flags_lock);-tt_global_entry->common.flags|=local_flags&BATADV_TT_CLIENT_WIFI;--if(!(flags&BATADV_TT_CLIENT_ROAM))-/* this is a normal global add. Therefore the client is not in a-*roamingstateanymore.-*/-tt_global_entry->common.flags&=~BATADV_TT_CLIENT_ROAM;-spin_unlock_bh(&tt_global_entry->common.flags_lock);+batadv_tt_global_purge_local(bat_priv,tt_global_entry,flags);out:batadv_tt_global_entry_put(tt_global_entry);
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:40
From: Sven Eckelmann <sven@narfation.org>
With both locked sections moved to their own helpers, the only thing left
in the cleanup section is the reference of the looked up entry. The "out"
label is therefore only reached with a valid entry, except for the lookup
failure at the very beginning.
Return BATADV_NO_FLAGS directly when there is no entry and let the two
remaining cases be an if/else.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)
@@ -1526,13 +1526,12 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,boolroaming){structbatadv_tt_local_entry*tt_local_entry;-u16curr_flags=BATADV_NO_FLAGS;-boolpending=false;+u16curr_flags;u16flags;tt_local_entry=batadv_tt_local_hash_find(bat_priv,addr,vid);if(!tt_local_entry)-gotoout;+returnBATADV_NO_FLAGS;flags=BATADV_TT_CLIENT_DEL;/* if this global entry addition is due to a roaming, the node has to
@@ -1542,20 +1541,15 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,if(roaming)flags|=BATADV_TT_CLIENT_ROAM;-pending=batadv_tt_local_mark_removed(tt_local_entry,roaming,-&curr_flags);-if(pending){-batadv_tt_local_set_pending_event(bat_priv,tt_local_entry,flags,-message);-gotoout;-}--/* if this client has been added right now, it is possible to-*immediatelypurgeit-*/-batadv_tt_local_remove_now(bat_priv,tt_local_entry);+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+*immediatelypurgeit+*/+batadv_tt_local_remove_now(bat_priv,tt_local_entry);-out:batadv_tt_local_entry_put(tt_local_entry);returncurr_flags;
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:40
From: Sven Eckelmann <sven@narfation.org>
A client which was added after the last ttvn increment was never announced
and can be dropped from the local table right away. The code doing so is
the second half of batadv_tt_local_remove() and needed a goto to skip the
accounting when the entry was already gone from the hash.
Move it to batadv_tt_local_remove_now().
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 57 +++++++++++++++++++-----------
1 file changed, 37 insertions(+), 20 deletions(-)
@@ -1475,6 +1475,42 @@ batadv_tt_local_mark_removed(struct batadv_tt_local_entry *tt_local_entry,returnpending;}+/**+*batadv_tt_local_remove_now()-purgealocalentrywhichwasneverannounced+*@bat_priv:thebatprivwithallthemeshinterfaceinformation+*@tt_local_entry:localTTentrytopurge+*+*Aclientwhichwasaddedrightafterthelastttvnincrementwasneversent+*totheothernodes.Itcanthereforebedroppedfromthelocaltablewithout+*waitingforthenextttvnincrement.+*/+staticvoid+batadv_tt_local_remove_now(structbatadv_priv*bat_priv,+structbatadv_tt_local_entry*tt_local_entry)+{+structbatadv_tt_common_entry*common=&tt_local_entry->common;+structhlist_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,+batadv_choose_tt,common);+if(!tt_removed_node)+return;++/* batadv_tt_local_transition_new() may have committed the entry and+*thuscounteditinthelocaltablesizesincethe+*BATADV_TT_CLIENT_NEWcheckinbatadv_tt_local_mark_removed().+*/+if(!(batadv_tt_flags_get(common)&BATADV_TT_CLIENT_NEW))+batadv_tt_local_size_dec(bat_priv,common->vid);++/* drop reference of remove hash entry */+batadv_tt_local_entry_put(tt_local_entry);+}+/***batadv_tt_local_remove()-logicallyremoveanentryfromthelocaltable*@bat_priv:thebatprivwithallthemeshinterfaceinformation
@@ -1518,25 +1553,7 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,/* if this client has been added right now, it is possible to*immediatelypurgeit*/-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,-batadv_choose_tt,-&tt_local_entry->common);-if(!tt_removed_node)-gotoout;--/* batadv_tt_local_transition_new() may have committed the entry and-*thuscounteditinthelocaltablesizesincetheBATADV_TT_CLIENT_NEW-*checkabove.-*/-if(!(batadv_tt_flags_get(&tt_local_entry->common)&BATADV_TT_CLIENT_NEW))-batadv_tt_local_size_dec(bat_priv,tt_local_entry->common.vid);--/* drop reference of remove hash entry */-batadv_tt_local_entry_put(tt_local_entry);+batadv_tt_local_remove_now(bat_priv,tt_local_entry);out:batadv_tt_local_entry_put(tt_local_entry);
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:41
From: Sven Eckelmann <sven@narfation.org>
The batadv_iv_ogm_neigh_is_sob() kernel-doc summary line is still
referencing the old parameter names "neigh1" and "neigh2". But these are
now called "candidate" and "reference".
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831135117.574836-1-sw%40simonwunderlich.de?part=5
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/bat_iv_ogm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:41
From: Sven Eckelmann <sven@narfation.org>
Not the data is returned after a batadv_hash_remove() but the pointer to
the hlist_node which was used to look up the entry in the hash.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831135117.574836-1-sw%40simonwunderlich.de?part=8
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/hash.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Simon Wunderlich <sw@simonwunderlich.de> Date: 2026-09-07 08:18:41
From: Sven Eckelmann <sven@narfation.org>
The function batadv_tt_local_set_pending_event() is no longer setting the
BATADV_TT_CLIENT_PENDING because it must be done with the flags_lock held.
The kernel-doc must therefore correctly state that the flag must already be
set.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831135117.574836-1-sw%40simonwunderlich.de?part=12
Signed-off-by: Sven Eckelmann <sven@narfation.org>
Signed-off-by: Simon Wunderlich <sw@simonwunderlich.de>
---
net/batman-adv/translation-table.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
+/**+ * batadv_tt_global_purge_local() - drop the local entry of an announced client+ * @bat_priv: the bat priv with all the mesh interface information+ * @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.+ */
Discovered by: opus-5 · Missed by: sonnet-5, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
This isn't a bug, but should the new kernel-doc for
batadv_tt_global_purge_local() mention the two things the body actually
does beyond the summary?
The doc says removal from the local table happens, but multicast addresses
take an early return and nothing is removed:
if (is_multicast_ether_addr(common->addr))
return;
The doc also does not mention that the global entry's own flags are
modified, not just the inherited WIFI flag:
if (!(flags & BATADV_TT_CLIENT_ROAM))
common->flags &= ~BATADV_TT_CLIENT_ROAM;
Since flags_lock is documented in struct batadv_tt_common_entry as
protecting both @flags and @batadv_tt_global_entry.roam_at, a reader of the
new standalone helper might not expect the name purge_local() to also reset
the global roaming state.
Both behaviours are unchanged from the previous inline code under the
out_remove label in batadv_tt_global_add(), so this is only about the
description of the new helper.
Discovered by: opus-5, old-prompts · Missed by: gpt-5-6-sol, sashiko-gemini
Two comments in batadv_tt_local_remove() look like they no longer match the
code after the move.
First, the untouched comment further down in batadv_tt_local_remove() still
refers to a check "above":
net/batman-adv/translation-table.c:batadv_tt_local_remove() {
...
/* 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 above.
*/
if (!(batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_NEW))
batadv_tt_local_size_dec(bat_priv, tt_local_entry->common.vid);
...
}
After this patch there is no BATADV_TT_CLIENT_NEW test left anywhere above
that point in this function; the only one is now inside the new helper:
net/batman-adv/translation-table.c:batadv_tt_local_mark_removed() {
...
if (!(common->flags & BATADV_TT_CLIENT_NEW)) {
common->flags |= BATADV_TT_CLIENT_PENDING;
pending = true;
}
...
}
Should the wording be updated in this patch to name the helper, so the
size-accounting race stays traceable from the function it is documented in?
See patch 11 "batman-adv: tt: extract immediate purge of a local entry"
Second, the retained comment above the "if (roaming)" line still says the
node "has to mark the local entry as roamed", but the code it now precedes
only assembles the announcement flag word; the actual
common->flags |= BATADV_TT_CLIENT_ROAM happens in the
batadv_tt_local_mark_removed() call two lines below. Would it read better
moved or reworded so it describes the flag assembly?
No functional change is apparent here: flags is fully computed before the
call, *curr_flags is written unconditionally inside the guard so curr_flags
is always initialized for the caller, and the helper is only reached after
the !tt_local_entry early goto.
Discovered by: opus-5 · Missed by: opus-4-7, gpt-5-6-sol, sashiko-gemini · Confirmed by: gpt-5-6-sol
Is the "was never announced" wording in this new kernel doc a bit too
strong? The body of the same function documents the opposite case a few
lines later:
net/batman-adv/translation-table.c:batadv_tt_local_remove_now() {
/* 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().
*/
if (!(batadv_tt_flags_get(common) & BATADV_TT_CLIENT_NEW))
batadv_tt_local_size_dec(bat_priv, common->vid);
}
batadv_tt_local_mark_removed() drops common->flags_lock before returning
and batadv_tt_local_remove() holds no other lock, while
batadv_tt_local_transition_new() only holds the local list_lock and
flags_lock:
batadv_tt_local_commit_changes_nolock()
batadv_tt_local_transition_new() /* clears BATADV_TT_CLIENT_NEW,
batadv_tt_local_size_inc() */
batadv_tt_local_update_crc()
atomic_inc(&bat_priv->tt.vn)
So in that window the entry can be committed, counted and announced under
the current ttvn, and batadv_tt_local_remove_now() still unlinks it from
bat_priv->tt.local_hash instead of leaving it BATADV_TT_CLIENT_PENDING
until the next ttvn increment, as described by
batadv_tt_local_set_pending_event():
* Schedule the TT change announcement for 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.
Would it make sense either to soften the new kernel doc (and the matching
sentence in the commit message, "A client which was added after the last
ttvn increment was never announced and can be dropped from the local table
right away") to mention that the entry may already have been committed, or
to fall back to the pending path when the NEW flag turns out to be cleared?
Hello:
This series was applied to netdev/net-next.git (main)
by Sven Eckelmann [off-list ref]:
On Mon, 7 Sep 2026 10:18:10 +0200 you wrote:
From: Sven Eckelmann <sven@narfation.org>
batadv_tt_local_add() only needs to know whether the client was seen on a
wifi interface. But it kept the net_device reference of the incoming
interface alive until its own cleanup section, together with a "net" and an
"in_dev" variable which are of no interest to the rest of the function.
[...]