| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/08/31 20:31 | flow | patch-triage |
4mArgs:null Results: {
"EnableConfigs": [
"BATMAN_ADV",
"BATMAN_ADV_BATMAN_V",
"BATMAN_ADV_BLA",
"BATMAN_ADV_DAT",
"BATMAN_ADV_MCAST"
],
"FocusSymbols": [
"batadv_tt_local_add",
"batadv_tt_local_remove",
"batadv_transtable_search",
"batadv_is_my_client",
"batadv_tt_global_is_isolated",
"batadv_tt_global_client_is_roaming",
"batadv_tt_local_client_is_roaming"
],
"KMSANReasoning": "The patch series consists of several cleanups and bugfixes in batman-adv:\n1. Alignment annotations: Adds `__aligned(2)` to various MAC address byte arrays (`u8 addr[ETH_ALEN]`, `u8 orig[ETH_ALEN]`, etc.) to ensure 2-byte alignment for operations like `ether_addr_copy()`.\n2. Concurrency and locking improvements: Introduces `flags_lock` spinlock to `struct batadv_tt_common_entry` to protect concurrent read/write access to translation table entry flags (`common-\u003eflags`) and roaming timestamps (`roam_at`).\n3. Logic \u0026 naming fixes: Fixes neighbor comparison logic in `batadv_v_neigh_is_sob()` and renames parameters for clarity in `batadv_iv_ogm_neigh_is_sob()`.\n4. Debug output fix: Corrects field access in debug printing for encapsulated DAT packets.\n5. Hash table lookup accuracy: Introduces `batadv_compare_tt_entry()` to match exact pointer identities during `batadv_hash_remove()`.\n\nNone of the changes introduce uninitialized memory allocations, uninitialized variable usage, or leak uninitialized kernel memory to user space. Netlink dump handlers (`batadv_dat_cache_dump_entry`, `batadv_tt_local_dump_entry`, `batadv_tt_global_dump_subentry`) only serialize fully initialized scalars and MAC addresses. Concurrency, lifetime, and boundary checks are already covered by standard KASAN and LOCKDEP. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false,
"Reasoning": "The patch series introduces significant functional changes and bug fixes in the B.A.T.M.A.N. Advanced mesh protocol subsystem (net/batman-adv/). Key changes include adding spinlock protection (flags_lock) to avoid race conditions when reading and mutating translation table entry flags, fixing exact object removal from hash buckets (batadv_compare_tt_entry), correcting the B.A.T.M.A.N. V neighbor comparison calculation logic in batadv_v_neigh_is_sob(), and adding 2-byte alignment attributes to MAC address buffers. These changes alter core execution flows and state handling that are fully reachable and testable in virtual environments.",
"WorthFuzzing": true
} |
| 1/1 | 2026/08/31 20:31 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit f47ea3f9a76918a99237ce731d7cf6e85775d007\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Mon Aug 31 20:31:52 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c\nindex 53fbdbbe8f4f7..3fe09b4c30463 100644\n--- a/net/batman-adv/bat_iv_ogm.c\n+++ b/net/batman-adv/bat_iv_ogm.c\n@@ -2424,25 +2424,26 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,\n /**\n * batadv_iv_ogm_neigh_is_sob() - check if neigh1 is similarly good or better\n * than neigh2 from the metric prospective\n- * @neigh1: the first neighbor object of the comparison\n- * @if_outgoing1: outgoing interface for the first neighbor\n- * @neigh2: the second neighbor object of the comparison\n- * @if_outgoing2: outgoing interface for the second neighbor\n+ * @candidate: the first neighbor object of the comparison\n+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor\n+ * @reference: the second neighbor object of the comparison\n+ * @if_outgoing_ref: outgoing interface for the @reference neighbor\n *\n- * Return: true if the metric via neigh1 is equally good or better than\n- * the metric via neigh2, false otherwise.\n+ * Return: true if the metric via @candidate is equally good or better than\n+ * the metric via @reference, false otherwise.\n */\n static bool\n-batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,\n-\t\t\t struct batadv_hard_iface *if_outgoing1,\n-\t\t\t struct batadv_neigh_node *neigh2,\n-\t\t\t struct batadv_hard_iface *if_outgoing2)\n+batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *candidate,\n+\t\t\t struct batadv_hard_iface *if_outgoing_cand,\n+\t\t\t struct batadv_neigh_node *reference,\n+\t\t\t struct batadv_hard_iface *if_outgoing_ref)\n {\n \tbool ret;\n \tint diff;\n \n-\tret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,\n-\t\t\t\t if_outgoing2, \u0026diff);\n+\tret = batadv_iv_ogm_neigh_diff(candidate, if_outgoing_cand,\n+\t\t\t\t reference, if_outgoing_ref,\n+\t\t\t\t \u0026diff);\n \tif (!ret)\n \t\treturn false;\n \ndiff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c\nindex 0c27447cf6889..596889b3522d0 100644\n--- a/net/batman-adv/bat_v.c\n+++ b/net/batman-adv/bat_v.c\n@@ -514,40 +514,40 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,\n /**\n * batadv_v_neigh_is_sob() - check whether two B.A.T.M.A.N. V neighbours have\n * a similar or better throughput\n- * @neigh1: first neighbour to compare\n- * @if_outgoing1: outgoing interface to use for @neigh1\n- * @neigh2: second neighbour to compare\n- * @if_outgoing2: outgoing interface to use for @neigh2\n+ * @candidate: the first neighbor object of the comparison\n+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor\n+ * @reference: the second neighbor object of the comparison\n+ * @if_outgoing_ref: outgoing interface for the @reference neighbor\n *\n- * Return: true if the throughput of @neigh2 is at least 3/4 of the\n- * @neigh1 throughput\n+ * Return: true if the throughput of @candidate is more than 3/4 of the\n+ * @reference throughput\n */\n-static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,\n-\t\t\t\t struct batadv_hard_iface *if_outgoing1,\n-\t\t\t\t struct batadv_neigh_node *neigh2,\n-\t\t\t\t struct batadv_hard_iface *if_outgoing2)\n+static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *candidate,\n+\t\t\t\t struct batadv_hard_iface *if_outgoing_cand,\n+\t\t\t\t struct batadv_neigh_node *reference,\n+\t\t\t\t struct batadv_hard_iface *if_outgoing_ref)\n {\n-\tstruct batadv_neigh_ifinfo *ifinfo1;\n-\tstruct batadv_neigh_ifinfo *ifinfo2;\n+\tstruct batadv_neigh_ifinfo *ifinfo_cand;\n+\tstruct batadv_neigh_ifinfo *ifinfo_ref;\n \tbool ret = false;\n \tu32 threshold;\n \n-\tifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);\n-\tif (!ifinfo1)\n+\tifinfo_cand = batadv_neigh_ifinfo_get(candidate, if_outgoing_cand);\n+\tif (!ifinfo_cand)\n \t\tgoto err_ifinfo1;\n \n-\tifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);\n-\tif (!ifinfo2)\n+\tifinfo_ref = batadv_neigh_ifinfo_get(reference, if_outgoing_ref);\n+\tif (!ifinfo_ref)\n \t\tgoto err_ifinfo2;\n \n-\tthreshold = ifinfo1-\u003ebat_v.throughput / 4;\n-\tthreshold = ifinfo1-\u003ebat_v.throughput - threshold;\n+\tthreshold = ifinfo_ref-\u003ebat_v.throughput / 4;\n+\tthreshold = ifinfo_ref-\u003ebat_v.throughput - threshold;\n \n-\tret = ifinfo2-\u003ebat_v.throughput \u003e threshold;\n+\tret = ifinfo_cand-\u003ebat_v.throughput \u003e threshold;\n \n-\tbatadv_neigh_ifinfo_put(ifinfo2);\n+\tbatadv_neigh_ifinfo_put(ifinfo_ref);\n err_ifinfo2:\n-\tbatadv_neigh_ifinfo_put(ifinfo1);\n+\tbatadv_neigh_ifinfo_put(ifinfo_cand);\n err_ifinfo1:\n \treturn ret;\n }\ndiff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c\nindex f635da4b8ca65..ad6ab4a50658f 100644\n--- a/net/batman-adv/bridge_loop_avoidance.c\n+++ b/net/batman-adv/bridge_loop_avoidance.c\n@@ -663,7 +663,7 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)\n static void batadv_bla_send_announce(struct batadv_priv *bat_priv,\n \t\t\t\t struct batadv_bla_backbone_gw *backbone_gw)\n {\n-\tu8 mac[ETH_ALEN];\n+\tu8 mac[ETH_ALEN] __aligned(2);\n \t__be16 crc;\n \n \tmemcpy(mac, batadv_announce_mac, 4);\n@@ -1582,7 +1582,9 @@ static struct lock_class_key batadv_backbone_hash_lock_class_key;\n */\n int batadv_bla_init(struct batadv_priv *bat_priv)\n {\n-\tu8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};\n+\tstatic const u8 claim_dest[ETH_ALEN] __aligned(2) = {\n+\t\t0xff, 0x43, 0x05, 0x00, 0x00, 0x00\n+\t};\n \tstruct batadv_hard_iface *primary_if;\n \tunsigned long entrytime;\n \tu16 crc;\ndiff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c\nindex 011cfdc47fab4..a4be5b2a87d7a 100644\n--- a/net/batman-adv/distributed-arp-table.c\n+++ b/net/batman-adv/distributed-arp-table.c\n@@ -548,7 +548,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,\n \t\t\tbreak;\n \t\tdefault:\n \t\t\tbatadv_dbg(BATADV_DBG_DAT, bat_priv, \"* type: Unknown (%u)!\\n\",\n-\t\t\t\t unicast_4addr_packet-\u003eu.packet_type);\n+\t\t\t\t unicast_4addr_packet-\u003esubtype);\n \t\t}\n \t\tbreak;\n \tcase BATADV_BCAST:\n@@ -940,7 +940,7 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,\n \t\t\t struct netlink_callback *cb,\n \t\t\t struct batadv_dat_entry *dat_entry)\n {\n-\tu8 mac[ETH_ALEN];\n+\tu8 mac[ETH_ALEN] __aligned(2);\n \tu64 u64_mac;\n \tint msecs;\n \tvoid *hdr;\n@@ -1236,10 +1236,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,\n {\n \tstruct net_device *mesh_iface = bat_priv-\u003emesh_iface;\n \tstruct batadv_dat_entry *dat_entry = NULL;\n+\tu8 mac[ETH_ALEN] __aligned(2);\n \tstruct sk_buff *skb_new;\n \tunsigned short vid;\n \tbool ret = false;\n-\tu8 mac[ETH_ALEN];\n \tint hdr_size = 0;\n \t__be32 ip_dst;\n \t__be32 ip_src;\n@@ -1344,10 +1344,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,\n \t\t\t\t\t struct sk_buff *skb, int hdr_size)\n {\n \tstruct batadv_dat_entry *dat_entry = NULL;\n+\tu8 mac[ETH_ALEN] __aligned(2);\n \tstruct sk_buff *skb_new;\n \tunsigned short vid;\n \tbool ret = false;\n-\tu8 mac[ETH_ALEN];\n \t__be32 ip_src;\n \t__be32 ip_dst;\n \tu64 u64_mac;\n@@ -1474,9 +1474,9 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,\n \t\t\t\t\t struct sk_buff *skb, int hdr_size)\n {\n \tstruct batadv_dat_entry *dat_entry = NULL;\n+\tu8 mac[ETH_ALEN] __aligned(2);\n \tbool dropped = false;\n \tunsigned short vid;\n-\tu8 mac[ETH_ALEN];\n \t__be32 ip_src;\n \t__be32 ip_dst;\n \tu64 u64_mac;\ndiff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c\nindex e202088cf1fd4..63af21954cf90 100644\n--- a/net/batman-adv/mesh-interface.c\n+++ b/net/batman-adv/mesh-interface.c\n@@ -141,9 +141,9 @@ static struct net_device_stats *batadv_interface_stats(struct net_device *dev)\n static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)\n {\n \tstruct batadv_priv *bat_priv = netdev_priv(dev);\n+\tu8 old_addr[ETH_ALEN] __aligned(2);\n \tstruct batadv_meshif_vlan *vlan;\n \tstruct sockaddr *addr = p;\n-\tu8 old_addr[ETH_ALEN];\n \n \tif (!is_valid_ether_addr(addr-\u003esa_data))\n \t\treturn -EADDRNOTAVAIL;\n@@ -213,13 +213,18 @@ static void batadv_interface_set_rx_mode(struct net_device *dev)\n static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,\n \t\t\t\t struct net_device *mesh_iface)\n {\n-\tstatic const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 0x00, 0x00};\n-\tstatic const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};\n \tstruct batadv_priv *bat_priv = netdev_priv(mesh_iface);\n \tenum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;\n \tenum batadv_forw_mode forw_mode = BATADV_FORW_BCAST;\n+\tstatic const u8 ectp_addr[ETH_ALEN] __aligned(2) = {\n+\t\t0xCF, 0x00, 0x00, 0x00, 0x00, 0x00\n+\t};\n+\tstatic const u8 stp_addr[ETH_ALEN] __aligned(2) = {\n+\t\t0x01, 0x80, 0xC2, 0x00, 0x00, 0x00\n+\t};\n \tstruct batadv_hard_iface *primary_if = NULL;\n \tstruct batadv_bcast_packet *bcast_packet;\n+\tu8 chaddr[ETH_ALEN] __aligned(2);\n \tint network_offset = ETH_HLEN;\n \tunsigned int header_len = 0;\n \tunsigned long brd_delay = 0;\n@@ -229,7 +234,6 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,\n \tstruct ethhdr *ethhdr;\n \tbool do_bcast = false;\n \tu8 *dst_hint = NULL;\n-\tu8 chaddr[ETH_ALEN];\n \tunsigned short vid;\n \tbool client_added;\n \t__be16 proto;\ndiff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c\nindex 82fd527b61c02..22dd28d5e1abc 100644\n--- a/net/batman-adv/multicast.c\n+++ b/net/batman-adv/multicast.c\n@@ -368,9 +368,9 @@ batadv_mcast_mla_meshif_get_ipv4(struct net_device *dev,\n \t\t\t\t struct hlist_head *mcast_list,\n \t\t\t\t struct batadv_mcast_mla_flags *flags)\n {\n+\tu8 mcast_addr[ETH_ALEN] __aligned(2);\n \tstruct batadv_hw_addr *new;\n \tstruct in_device *in_dev;\n-\tu8 mcast_addr[ETH_ALEN];\n \tstruct ip_mc_list *pmc;\n \tint ret = 0;\n \n@@ -435,9 +435,9 @@ batadv_mcast_mla_meshif_get_ipv6(struct net_device *dev,\n \t\t\t\t struct hlist_head *mcast_list,\n \t\t\t\t struct batadv_mcast_mla_flags *flags)\n {\n+\tu8 mcast_addr[ETH_ALEN] __aligned(2);\n \tstruct batadv_hw_addr *new;\n \tstruct inet6_dev *in6_dev;\n-\tu8 mcast_addr[ETH_ALEN];\n \tstruct ifmcaddr6 *pmc6;\n \tint ret = 0;\n \n@@ -587,10 +587,10 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev,\n \t\t\t\t struct batadv_mcast_mla_flags *flags)\n {\n \tstruct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);\n+\tu8 mcast_addr[ETH_ALEN] __aligned(2);\n \tu8 tvlv_flags = flags-\u003etvlv_flags;\n \tstruct br_ip_list *br_ip_entry;\n \tstruct batadv_hw_addr *new;\n-\tu8 mcast_addr[ETH_ALEN];\n \tstruct br_ip_list *tmp;\n \tint ret;\n \ndiff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c\nindex 68f79853032ed..44a8cf89382c6 100644\n--- a/net/batman-adv/translation-table.c\n+++ b/net/batman-adv/translation-table.c\n@@ -13,6 +13,7 @@\n #include \u003clinux/build_bug.h\u003e\n #include \u003clinux/byteorder/generic.h\u003e\n #include \u003clinux/cache.h\u003e\n+#include \u003clinux/cleanup.h\u003e\n #include \u003clinux/compiler.h\u003e\n #include \u003clinux/container_of.h\u003e\n #include \u003clinux/crc32.h\u003e\n@@ -95,6 +96,26 @@ static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)\n \treturn (tt1-\u003evid == tt2-\u003evid) \u0026\u0026 batadv_compare_eth(data1, data2);\n }\n \n+/**\n+ * batadv_compare_tt_entry() - check if a hash node is a specific TT entry\n+ * @node: the list element pointer of the TT entry stored in the bucket\n+ * @data2: pointer to the tt_common_entry which is looked for\n+ *\n+ * Unlike batadv_compare_tt(), this only matches the very object which is\n+ * passed as @data2 and not just any entry for the same TT client. It is meant\n+ * for batadv_hash_remove() callers which must not unlink an entry they did not\n+ * look up themselves.\n+ *\n+ * Return: true if @node belongs to @data2, false otherwise\n+ */\n+static bool batadv_compare_tt_entry(const struct hlist_node *node,\n+\t\t\t\t const void *data2)\n+{\n+\tconst struct batadv_tt_common_entry *tt = data2;\n+\n+\treturn node == \u0026tt-\u003ehash_entry;\n+}\n+\n /**\n * batadv_choose_tt() - return the index of the tt entry in the hash table\n * @data: pointer to the tt_common_entry object to map\n@@ -312,6 +333,10 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,\n * given vid\n * @bat_priv: the bat priv with all the mesh interface information\n * @vid: the VLAN identifier\n+ *\n+ * It must only be called when removing the NEW flag of a\n+ * batadv_tt_local_entry while it is still part of the bat_priv-\u003ett.local_hash.\n+ * It must therefore be checked under the specific list_locks[i].\n */\n static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,\n \t\t\t\t unsigned short vid)\n@@ -324,6 +349,11 @@ static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,\n * given vid\n * @bat_priv: the bat priv with all the mesh interface information\n * @vid: the VLAN identifier\n+ *\n+ * It must only be called after a batadv_tt_local_entry without NEW flag\n+ * was removed from bat_priv-\u003ett.local_hash (under the specific\n+ * list_locks[i]) or when it is ensured that it is not accessible\n+ * in this list.\n */\n static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,\n \t\t\t\t unsigned short vid)\n@@ -413,6 +443,22 @@ batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)\n \tkref_put(\u0026orig_entry-\u003erefcount, batadv_tt_orig_list_entry_release);\n }\n \n+/**\n+ * batadv_tt_flags_get() - get a snapshot of the flags of a TT entry\n+ * @common: tt local \u0026 tt global common data\n+ *\n+ * Return: the flags of the TT entry as observed under its flags_lock.\n+ */\n+static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)\n+{\n+\tu16 flags;\n+\n+\tscoped_guard(spinlock_bh, \u0026common-\u003eflags_lock)\n+\t\tflags = common-\u003eflags;\n+\n+\treturn flags;\n+}\n+\n /**\n * batadv_tt_local_event() - store a local TT event (ADD/DEL)\n * @bat_priv: the bat priv with all the mesh interface information\n@@ -425,23 +471,25 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,\n {\n \tstruct batadv_tt_common_entry *common = \u0026tt_local_entry-\u003ecommon;\n \tstruct batadv_tt_change_node *tt_change_node;\n-\tu8 flags = common-\u003eflags | event_flags;\n \tstruct batadv_tt_change_node *entry;\n \tstruct batadv_tt_change_node *safe;\n \tbool del_op_requested;\n \tbool del_op_entry;\n \tsize_t changes;\n+\tu8 flags;\n \n \ttt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC);\n \tif (!tt_change_node)\n \t\treturn;\n \n-\ttt_change_node-\u003echange.flags = flags;\n \tmemset(tt_change_node-\u003echange.reserved, 0,\n \t sizeof(tt_change_node-\u003echange.reserved));\n \tether_addr_copy(tt_change_node-\u003echange.addr, common-\u003eaddr);\n \ttt_change_node-\u003echange.vid = htons(common-\u003evid);\n \n+\tflags = batadv_tt_flags_get(common) | event_flags;\n+\n+\ttt_change_node-\u003echange.flags = flags;\n \tdel_op_requested = flags \u0026 BATADV_TT_CLIENT_DEL;\n \n \t/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */\n@@ -575,7 +623,6 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,\n \t\t\t\t struct batadv_tt_global_entry *tt_global,\n \t\t\t\t const char *message)\n {\n-\tstruct batadv_tt_global_entry *tt_removed_entry;\n \tstruct hlist_node *tt_removed_node;\n \n \tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n@@ -583,18 +630,67 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,\n \t\t tt_global-\u003ecommon.addr,\n \t\t batadv_print_vid(tt_global-\u003ecommon.vid), message);\n \n+\t/* remove exactly this object when still present in hash */\n \ttt_removed_node = batadv_hash_remove(bat_priv-\u003ett.global_hash,\n-\t\t\t\t\t batadv_compare_tt,\n+\t\t\t\t\t batadv_compare_tt_entry,\n \t\t\t\t\t batadv_choose_tt,\n \t\t\t\t\t \u0026tt_global-\u003ecommon);\n \tif (!tt_removed_node)\n \t\treturn;\n \n \t/* drop reference of remove hash entry */\n-\ttt_removed_entry = hlist_entry(tt_removed_node,\n-\t\t\t\t struct batadv_tt_global_entry,\n-\t\t\t\t common.hash_entry);\n-\tbatadv_tt_global_entry_put(tt_removed_entry);\n+\tbatadv_tt_global_entry_put(tt_global);\n+}\n+\n+/**\n+ * batadv_tt_local_add_roam() - handle roamed clients during batadv_tt_local_add()\n+ * @bat_priv: the bat priv with all the mesh interface information\n+ * @tt_global: the global TT entry\n+ * @roamed_back: whether @tt_global roamed back\n+ */\n+static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,\n+\t\t\t\t struct batadv_tt_global_entry *tt_global,\n+\t\t\t\t bool roamed_back)\n+{\n+\tstruct batadv_tt_orig_list_entry *orig_entry;\n+\tstruct hlist_head *head;\n+\n+\tif (!tt_global)\n+\t\treturn;\n+\n+\t/* Check whether it is a roaming, but don't do anything if the roaming\n+\t * process has already been handled\n+\t */\n+\tscoped_guard(spinlock_bh, \u0026tt_global-\u003ecommon.flags_lock) {\n+\t\tif (tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM)\n+\t\t\treturn;\n+\n+\t\tif (!roamed_back) {\n+\t\t\t/* The global entry has to be marked as ROAMING and has to be\n+\t\t\t * kept for consistency purpose.\n+\t\t\t *\n+\t\t\t * batadv_tt_global_to_purge() evaluates roam_at as soon as it\n+\t\t\t * observes BATADV_TT_CLIENT_ROAM, so the timeout has to be\n+\t\t\t * stamped before the flag is published. Otherwise the entry can\n+\t\t\t * be deleted right away as \"Roaming timeout\".\n+\t\t\t */\n+\t\t\ttt_global-\u003eroam_at = jiffies;\n+\t\t\ttt_global-\u003ecommon.flags |= BATADV_TT_CLIENT_ROAM;\n+\t\t}\n+\t}\n+\n+\t/* These node are probably going to update their tt table */\n+\thead = \u0026tt_global-\u003eorig_list;\n+\trcu_read_lock();\n+\thlist_for_each_entry_rcu(orig_entry, head, list) {\n+\t\tbatadv_send_roam_adv(bat_priv, tt_global-\u003ecommon.addr,\n+\t\t\t\t tt_global-\u003ecommon.vid,\n+\t\t\t\t orig_entry-\u003eorig_node);\n+\t}\n+\trcu_read_unlock();\n+\n+\tif (roamed_back)\n+\t\tbatadv_tt_global_free(bat_priv, tt_global, \"Roaming canceled\");\n }\n \n /**\n@@ -615,20 +711,19 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n {\n \tstruct batadv_priv *bat_priv = netdev_priv(mesh_iface);\n \tstruct batadv_tt_global_entry *tt_global = NULL;\n-\tstruct batadv_tt_orig_list_entry *orig_entry;\n \tstruct batadv_tt_local_entry *tt_local;\n \tstruct net *net = dev_net(mesh_iface);\n \tstruct net_device *in_dev = NULL;\n \tstruct batadv_meshif_vlan *vlan;\n \tbool roamed_back = false;\n \tbool iif_is_wifi = false;\n-\tstruct hlist_head *head;\n \tint packet_size_max;\n \tbool ret = false;\n \tu8 remote_flags;\n \tint hash_added;\n \tint table_size;\n \tu32 match_mark;\n+\tbool modified;\n \n \tif (ifindex != BATADV_NULL_IFINDEX)\n \t\tin_dev = dev_get_by_index(net, ifindex);\n@@ -646,6 +741,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \n \tif (tt_local) {\n \t\ttt_local-\u003elast_seen = jiffies;\n+\n+\t\tspin_lock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n \t\tif (tt_local-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_PENDING) {\n \t\t\tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n \t\t\t\t \"Re-adding pending client %pM (vid: %d)\\n\",\n@@ -656,6 +753,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \t\t\t * flag can be reset like it was never enqueued\n \t\t\t */\n \t\t\ttt_local-\u003ecommon.flags \u0026= ~BATADV_TT_CLIENT_PENDING;\n+\t\t\tspin_unlock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n+\n \t\t\tgoto add_event;\n \t\t}\n \n@@ -671,6 +770,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \t\t\ttt_local-\u003ecommon.flags \u0026= ~BATADV_TT_CLIENT_ROAM;\n \t\t\troamed_back = true;\n \t\t}\n+\t\tspin_unlock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n+\n \t\tgoto check_roaming;\n \t}\n \n@@ -706,18 +807,21 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \t\t (u8)atomic_read(\u0026bat_priv-\u003ett.vn));\n \n \tether_addr_copy(tt_local-\u003ecommon.addr, addr);\n+\ttt_local-\u003ecommon.vid = vid;\n+\tkref_init(\u0026tt_local-\u003ecommon.refcount);\n+\ttt_local-\u003elast_seen = jiffies;\n+\ttt_local-\u003ecommon.added_at = tt_local-\u003elast_seen;\n+\ttt_local-\u003evlan = vlan;\n+\tspin_lock_init(\u0026tt_local-\u003ecommon.flags_lock);\n+\n+\tspin_lock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n \t/* The local entry has to be marked as NEW to avoid to send it in\n \t * a full table response going out before the next ttvn increment\n \t * (consistency check)\n \t */\n \ttt_local-\u003ecommon.flags = BATADV_TT_CLIENT_NEW;\n-\ttt_local-\u003ecommon.vid = vid;\n \tif (iif_is_wifi)\n \t\ttt_local-\u003ecommon.flags |= BATADV_TT_CLIENT_WIFI;\n-\tkref_init(\u0026tt_local-\u003ecommon.refcount);\n-\ttt_local-\u003elast_seen = jiffies;\n-\ttt_local-\u003ecommon.added_at = tt_local-\u003elast_seen;\n-\ttt_local-\u003evlan = vlan;\n \n \t/* the batman interface mac and multicast addresses should never be\n \t * purged\n@@ -725,6 +829,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \tif (batadv_compare_eth(addr, mesh_iface-\u003edev_addr) ||\n \t is_multicast_ether_addr(addr))\n \t\ttt_local-\u003ecommon.flags |= BATADV_TT_CLIENT_NOPURGE;\n+\tspin_unlock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n \n \tkref_get(\u0026tt_local-\u003ecommon.refcount);\n \thash_added = batadv_hash_add(bat_priv-\u003ett.local_hash, batadv_compare_tt,\n@@ -741,31 +846,9 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \tbatadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);\n \n check_roaming:\n-\t/* Check whether it is a roaming, but don't do anything if the roaming\n-\t * process has already been handled\n-\t */\n-\tif (tt_global \u0026\u0026 !(tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM)) {\n-\t\t/* These node are probably going to update their tt table */\n-\t\thead = \u0026tt_global-\u003eorig_list;\n-\t\trcu_read_lock();\n-\t\thlist_for_each_entry_rcu(orig_entry, head, list) {\n-\t\t\tbatadv_send_roam_adv(bat_priv, tt_global-\u003ecommon.addr,\n-\t\t\t\t\t tt_global-\u003ecommon.vid,\n-\t\t\t\t\t orig_entry-\u003eorig_node);\n-\t\t}\n-\t\trcu_read_unlock();\n-\t\tif (roamed_back) {\n-\t\t\tbatadv_tt_global_free(bat_priv, tt_global,\n-\t\t\t\t\t \"Roaming canceled\");\n-\t\t} else {\n-\t\t\t/* The global entry has to be marked as ROAMING and\n-\t\t\t * has to be kept for consistency purpose\n-\t\t\t */\n-\t\t\ttt_global-\u003ecommon.flags |= BATADV_TT_CLIENT_ROAM;\n-\t\t\ttt_global-\u003eroam_at = jiffies;\n-\t\t}\n-\t}\n+\tbatadv_tt_local_add_roam(bat_priv, tt_global, roamed_back);\n \n+\tspin_lock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n \t/* store the current remote flags before altering them. This helps\n \t * understanding is flags are changing or not\n \t */\n@@ -787,10 +870,13 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n \telse\n \t\ttt_local-\u003ecommon.flags \u0026= ~BATADV_TT_CLIENT_ISOLA;\n \n+\tmodified = remote_flags ^ (tt_local-\u003ecommon.flags \u0026 BATADV_TT_REMOTE_MASK);\n+\tspin_unlock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n+\n \t/* if any \"dynamic\" flag has been modified, resend an ADD event for this\n \t * entry so that all the nodes can get the new flags\n \t */\n-\tif (remote_flags ^ (tt_local-\u003ecommon.flags \u0026 BATADV_TT_REMOTE_MASK))\n+\tif (modified)\n \t\tbatadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);\n \n \tret = true;\n@@ -1115,6 +1201,7 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,\n \tstruct batadv_meshif_vlan *vlan;\n \tunsigned int last_seen_msecs;\n \tvoid *hdr;\n+\tu16 flags;\n \tu32 crc;\n \n \tlocal = container_of(common, struct batadv_tt_local_entry, common);\n@@ -1136,13 +1223,15 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,\n \n \tgenl_dump_check_consistent(cb, hdr);\n \n+\tflags = batadv_tt_flags_get(common);\n+\n \tif (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common-\u003eaddr) ||\n \t nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||\n \t nla_put_u16(msg, BATADV_ATTR_TT_VID, common-\u003evid) ||\n-\t nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common-\u003eflags))\n+\t nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))\n \t\tgoto nla_put_failure;\n \n-\tif (!(common-\u003eflags \u0026 BATADV_TT_CLIENT_NOPURGE) \u0026\u0026\n+\tif (!(flags \u0026 BATADV_TT_CLIENT_NOPURGE) \u0026\u0026\n \t nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))\n \t\tgoto nla_put_failure;\n \n@@ -1249,29 +1338,23 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)\n }\n \n /**\n- * batadv_tt_local_set_pending() - mark a local TT entry as pending removal\n+ * batadv_tt_local_set_pending_event() - trigger events for TT pending removal\n * @bat_priv: the bat priv with all the mesh interface information\n * @tt_local_entry: local TT entry to mark\n * @flags: TT change flags to announce together with the pending removal\n * @message: debug message describing the reason for the change\n *\n- * Schedule the TT change announcement and set BATADV_TT_CLIENT_PENDING on the\n- * entry. The entry is kept in the local table until the next TTVN increment\n- * so that a consistency-check response can still be answered.\n+ * Schedule the TT change announcement for the entry. The entry is kept in the\n+ * local table until the next TTVN increment so that a consistency-check\n+ * response can still be answered.\n */\n static void\n-batadv_tt_local_set_pending(struct batadv_priv *bat_priv,\n-\t\t\t struct batadv_tt_local_entry *tt_local_entry,\n-\t\t\t u16 flags, const char *message)\n+batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,\n+\t\t\t\t struct batadv_tt_local_entry *tt_local_entry,\n+\t\t\t\t u16 flags, const char *message)\n {\n \tbatadv_tt_local_event(bat_priv, tt_local_entry, flags);\n \n-\t/* The local client has to be marked as \"pending to be removed\" but has\n-\t * to be kept in the table in order to send it in a full table\n-\t * response issued before the net ttvn increment (consistency check)\n-\t */\n-\ttt_local_entry-\u003ecommon.flags |= BATADV_TT_CLIENT_PENDING;\n-\n \tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n \t\t \"Local tt entry (%pM, vid: %d) pending to be removed: %s\\n\",\n \t\t tt_local_entry-\u003ecommon.addr,\n@@ -1292,16 +1375,17 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,\n \t\t\t unsigned short vid, const char *message,\n \t\t\t bool roaming)\n {\n-\tstruct batadv_tt_local_entry *tt_removed_entry;\n \tstruct batadv_tt_local_entry *tt_local_entry;\n \tstruct hlist_node *tt_removed_node;\n \tu16 curr_flags = BATADV_NO_FLAGS;\n+\tbool pending = false;\n \tu16 flags;\n \n \ttt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);\n \tif (!tt_local_entry)\n \t\tgoto out;\n \n+\tspin_lock_bh(\u0026tt_local_entry-\u003ecommon.flags_lock);\n \tcurr_flags = tt_local_entry-\u003ecommon.flags;\n \n \tflags = BATADV_TT_CLIENT_DEL;\n@@ -1316,27 +1400,39 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,\n \t}\n \n \tif (!(tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_NEW)) {\n-\t\tbatadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,\n-\t\t\t\t\t message);\n+\t\ttt_local_entry-\u003ecommon.flags |= BATADV_TT_CLIENT_PENDING;\n+\t\tpending = true;\n+\t}\n+\tspin_unlock_bh(\u0026tt_local_entry-\u003ecommon.flags_lock);\n+\n+\tif (pending) {\n+\t\tbatadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,\n+\t\t\t\t\t\t message);\n \t\tgoto out;\n \t}\n+\n \t/* if this client has been added right now, it is possible to\n \t * immediately purge it\n \t */\n \tbatadv_tt_local_event(bat_priv, tt_local_entry, BATADV_TT_CLIENT_DEL);\n \n+\t/* remove exactly this object when still present in hash */\n \ttt_removed_node = batadv_hash_remove(bat_priv-\u003ett.local_hash,\n-\t\t\t\t\t batadv_compare_tt,\n+\t\t\t\t\t batadv_compare_tt_entry,\n \t\t\t\t\t batadv_choose_tt,\n \t\t\t\t\t \u0026tt_local_entry-\u003ecommon);\n \tif (!tt_removed_node)\n \t\tgoto out;\n \n+\t/* batadv_tt_local_transition_new() may have committed the entry and\n+\t * thus counted it in the local table size since the BATADV_TT_CLIENT_NEW\n+\t * check above.\n+\t */\n+\tif (!(batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon) \u0026 BATADV_TT_CLIENT_NEW))\n+\t\tbatadv_tt_local_size_dec(bat_priv, tt_local_entry-\u003ecommon.vid);\n+\n \t/* drop reference of remove hash entry */\n-\ttt_removed_entry = hlist_entry(tt_removed_node,\n-\t\t\t\t struct batadv_tt_local_entry,\n-\t\t\t\t common.hash_entry);\n-\tbatadv_tt_local_entry_put(tt_removed_entry);\n+\tbatadv_tt_local_entry_put(tt_local_entry);\n \n out:\n \tbatadv_tt_local_entry_put(tt_local_entry);\n@@ -1361,21 +1457,37 @@ static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,\n \n \thlist_for_each_entry_safe(tt_common_entry, node_tmp, head,\n \t\t\t\t hash_entry) {\n+\t\tbool cont = false;\n+\n \t\ttt_local_entry = container_of(tt_common_entry,\n \t\t\t\t\t struct batadv_tt_local_entry,\n \t\t\t\t\t common);\n-\t\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_NOPURGE)\n-\t\t\tcontinue;\n \n-\t\t/* entry already marked for deletion */\n-\t\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_PENDING)\n-\t\t\tcontinue;\n+\t\tscoped_guard(spinlock_bh, \u0026tt_local_entry-\u003ecommon.flags_lock) {\n+\t\t\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_NOPURGE) {\n+\t\t\t\tcont = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\t/* entry already marked for deletion */\n+\t\t\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_PENDING) {\n+\t\t\t\tcont = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\tif (!batadv_has_timed_out(tt_local_entry-\u003elast_seen, timeout)) {\n+\t\t\t\tcont = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\n+\t\t\ttt_local_entry-\u003ecommon.flags |= BATADV_TT_CLIENT_PENDING;\n+\t\t}\n \n-\t\tif (!batadv_has_timed_out(tt_local_entry-\u003elast_seen, timeout))\n+\t\tif (cont)\n \t\t\tcontinue;\n \n-\t\tbatadv_tt_local_set_pending(bat_priv, tt_local_entry,\n-\t\t\t\t\t BATADV_TT_CLIENT_DEL, \"timed out\");\n+\t\tbatadv_tt_local_set_pending_event(bat_priv, tt_local_entry,\n+\t\t\t\t\t\t BATADV_TT_CLIENT_DEL, \"timed out\");\n \t}\n }\n \n@@ -1581,8 +1693,10 @@ batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)\n \t\tflags |= orig_entry-\u003eflags;\n \trcu_read_unlock();\n \n-\tflags |= tt_global-\u003ecommon.flags \u0026 (~BATADV_TT_SYNC_MASK);\n-\ttt_global-\u003ecommon.flags = flags;\n+\tscoped_guard(spinlock_bh, \u0026tt_global-\u003ecommon.flags_lock) {\n+\t\tflags |= tt_global-\u003ecommon.flags \u0026 (~BATADV_TT_SYNC_MASK);\n+\t\ttt_global-\u003ecommon.flags = flags;\n+\t}\n }\n \n /**\n@@ -1664,8 +1778,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \tstruct batadv_tt_local_entry *tt_local_entry;\n \tstruct batadv_tt_common_entry *common;\n \tbool ret = false;\n+\tu16 global_flags;\n \tu16 local_flags;\n \tint hash_added;\n+\tbool delete;\n \n \t/* ignore global entries from backbone nodes */\n \tif (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node-\u003eorig, vid))\n@@ -1678,9 +1794,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t * for a roaming advertisement instead of manually messing up the global\n \t * table\n \t */\n-\tif ((flags \u0026 BATADV_TT_CLIENT_TEMP) \u0026\u0026 tt_local_entry \u0026\u0026\n-\t !(tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_NEW))\n-\t\tgoto out;\n+\tif ((flags \u0026 BATADV_TT_CLIENT_TEMP) \u0026\u0026 tt_local_entry) {\n+\t\tlocal_flags = batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon);\n+\t\tif (!(local_flags \u0026 BATADV_TT_CLIENT_NEW))\n+\t\t\tgoto out;\n+\t}\n \n \tif (!tt_global_entry) {\n \t\ttt_global_entry = kmem_cache_zalloc(batadv_tg_cache,\n@@ -1691,9 +1809,13 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\tcommon = \u0026tt_global_entry-\u003ecommon;\n \t\tether_addr_copy(common-\u003eaddr, tt_addr);\n \t\tcommon-\u003evid = vid;\n+\t\tspin_lock_init(\u0026common-\u003eflags_lock);\n \n-\t\tif (!is_multicast_ether_addr(common-\u003eaddr))\n+\t\tif (!is_multicast_ether_addr(common-\u003eaddr)) {\n+\t\t\tspin_lock_bh(\u0026common-\u003eflags_lock);\n \t\t\tcommon-\u003eflags = flags \u0026 (~BATADV_TT_SYNC_MASK);\n+\t\t\tspin_unlock_bh(\u0026common-\u003eflags_lock);\n+\t\t}\n \n \t\ttt_global_entry-\u003eroam_at = 0;\n \t\t/* node must store current time in case of roaming. This is\n@@ -1733,8 +1855,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\t * originator list and add the new one orig_entry\n \t\t */\n \t\tif (flags \u0026 BATADV_TT_CLIENT_TEMP) {\n-\t\t\tif (!(common-\u003eflags \u0026 BATADV_TT_CLIENT_TEMP))\n+\t\t\tglobal_flags = batadv_tt_flags_get(common);\n+\t\t\tif (!(global_flags \u0026 BATADV_TT_CLIENT_TEMP))\n \t\t\t\tgoto out;\n+\n \t\t\tif (batadv_tt_global_entry_has_orig(tt_global_entry,\n \t\t\t\t\t\t\t orig_node, NULL))\n \t\t\t\tgoto out_remove;\n@@ -1742,6 +1866,9 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\t\tgoto add_orig_entry;\n \t\t}\n \n+\t\tdelete = false;\n+\n+\t\tspin_lock_bh(\u0026common-\u003eflags_lock);\n \t\t/* if the client was temporary added before receiving the first\n \t\t * OGM announcing it, we have to clear the TEMP flag. Also,\n \t\t * remove the previous temporary orig node and re-add it\n@@ -1749,7 +1876,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\t * is a non-temporary entry is preferred.\n \t\t */\n \t\tif (common-\u003eflags \u0026 BATADV_TT_CLIENT_TEMP) {\n-\t\t\tbatadv_tt_global_del_orig_list(tt_global_entry);\n+\t\t\tdelete = true;\n \t\t\tcommon-\u003eflags \u0026= ~BATADV_TT_CLIENT_TEMP;\n \t\t}\n \n@@ -1768,10 +1895,14 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\t * new one.\n \t\t */\n \t\tif (common-\u003eflags \u0026 BATADV_TT_CLIENT_ROAM) {\n-\t\t\tbatadv_tt_global_del_orig_list(tt_global_entry);\n-\t\t\tcommon-\u003eflags \u0026= ~BATADV_TT_CLIENT_ROAM;\n+\t\t\tdelete = true;\n \t\t\ttt_global_entry-\u003eroam_at = 0;\n+\t\t\tcommon-\u003eflags \u0026= ~BATADV_TT_CLIENT_ROAM;\n \t\t}\n+\t\tspin_unlock_bh(\u0026common-\u003eflags_lock);\n+\n+\t\tif (delete)\n+\t\t\tbatadv_tt_global_del_orig_list(tt_global_entry);\n \t}\n add_orig_entry:\n \t/* add the new orig_entry (if needed) or update it */\n@@ -1795,6 +1926,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \tlocal_flags = batadv_tt_local_remove(bat_priv, tt_addr, vid,\n \t\t\t\t\t \"global tt received\",\n \t\t\t\t\t flags \u0026 BATADV_TT_CLIENT_ROAM);\n+\n+\tspin_lock_bh(\u0026tt_global_entry-\u003ecommon.flags_lock);\n \ttt_global_entry-\u003ecommon.flags |= local_flags \u0026 BATADV_TT_CLIENT_WIFI;\n \n \tif (!(flags \u0026 BATADV_TT_CLIENT_ROAM))\n@@ -1802,6 +1935,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n \t\t * roaming state anymore.\n \t\t */\n \t\ttt_global_entry-\u003ecommon.flags \u0026= ~BATADV_TT_CLIENT_ROAM;\n+\tspin_unlock_bh(\u0026tt_global_entry-\u003ecommon.flags_lock);\n \n out:\n \tbatadv_tt_global_entry_put(tt_global_entry);\n@@ -1871,9 +2005,9 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,\n \t\t\t struct batadv_tt_orig_list_entry *orig,\n \t\t\t bool best)\n {\n-\tu16 flags = (common-\u003eflags \u0026 (~BATADV_TT_SYNC_MASK)) | orig-\u003eflags;\n \tstruct batadv_orig_node_vlan *vlan;\n \tu8 last_ttvn;\n+\tu16 flags;\n \tvoid *hdr;\n \tu32 crc;\n \n@@ -1892,6 +2026,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,\n \tif (!hdr)\n \t\treturn -ENOBUFS;\n \n+\tflags = (batadv_tt_flags_get(common) \u0026 (~BATADV_TT_SYNC_MASK)) | orig-\u003eflags;\n \tlast_ttvn = READ_ONCE(orig-\u003eorig_node-\u003elast_ttvn);\n \n \tif (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common-\u003eaddr) ||\n@@ -2179,9 +2314,12 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,\n \trcu_read_unlock();\n \n \tif (last_entry) {\n-\t\t/* its the last one, mark for roaming. */\n-\t\ttt_global_entry-\u003ecommon.flags |= BATADV_TT_CLIENT_ROAM;\n-\t\ttt_global_entry-\u003eroam_at = jiffies;\n+\t\tscoped_guard(spinlock_bh, \u0026tt_global_entry-\u003ecommon.flags_lock) {\n+\t\t\t/* its the last one, mark for roaming. */\n+\t\t\ttt_global_entry-\u003eroam_at = jiffies;\n+\n+\t\t\ttt_global_entry-\u003ecommon.flags |= BATADV_TT_CLIENT_ROAM;\n+\t\t}\n \t} else {\n \t\t/* there is another entry, we can simply delete this\n \t\t * one and can still use the other one.\n@@ -2330,16 +2468,18 @@ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,\n \tunsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;\n \tbool purge = false;\n \n-\tif ((tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM) \u0026\u0026\n-\t batadv_has_timed_out(tt_global-\u003eroam_at, roam_timeout)) {\n-\t\tpurge = true;\n-\t\t*msg = \"Roaming timeout\\n\";\n-\t}\n+\tscoped_guard(spinlock_bh, \u0026tt_global-\u003ecommon.flags_lock) {\n+\t\tif ((tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM) \u0026\u0026\n+\t\t batadv_has_timed_out(tt_global-\u003eroam_at, roam_timeout)) {\n+\t\t\tpurge = true;\n+\t\t\t*msg = \"Roaming timeout\\n\";\n+\t\t}\n \n-\tif ((tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_TEMP) \u0026\u0026\n-\t batadv_has_timed_out(tt_global-\u003ecommon.added_at, temp_timeout)) {\n-\t\tpurge = true;\n-\t\t*msg = \"Temporary client timeout\\n\";\n+\t\tif ((tt_global-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_TEMP) \u0026\u0026\n+\t\t batadv_has_timed_out(tt_global-\u003ecommon.added_at, temp_timeout)) {\n+\t\t\tpurge = true;\n+\t\t\t*msg = \"Temporary client timeout\\n\";\n+\t\t}\n \t}\n \n \treturn purge;\n@@ -2437,8 +2577,8 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)\n /**\n * _batadv_is_ap_isolated() - check whether two clients are AP-isolated from\n * each other\n- * @tt_local_entry: local TT entry of the sending client\n- * @tt_global_entry: global TT entry of the destination client\n+ * @tt_local_entry: local TT entry of one local client\n+ * @tt_global_entry: global TT entry of the remote client\n *\n * Return: true if traffic between the two clients should be dropped because\n * either both are WiFi clients or both carry the ISOLATION flag; false\n@@ -2448,13 +2588,19 @@ static bool\n _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,\n \t\t struct batadv_tt_global_entry *tt_global_entry)\n {\n-\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_WIFI \u0026\u0026\n-\t tt_global_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_WIFI)\n+\tu16 global_flags;\n+\tu16 local_flags;\n+\n+\tglobal_flags = batadv_tt_flags_get(\u0026tt_global_entry-\u003ecommon);\n+\tlocal_flags = batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon);\n+\n+\tif (local_flags \u0026 BATADV_TT_CLIENT_WIFI \u0026\u0026\n+\t global_flags \u0026 BATADV_TT_CLIENT_WIFI)\n \t\treturn true;\n \n \t/* check if the two clients are marked as isolated */\n-\tif (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ISOLA \u0026\u0026\n-\t tt_global_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ISOLA)\n+\tif (local_flags \u0026 BATADV_TT_CLIENT_ISOLA \u0026\u0026\n+\t global_flags \u0026 BATADV_TT_CLIENT_ISOLA)\n \t\treturn true;\n \n \treturn false;\n@@ -2483,11 +2629,15 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,\n \tstruct batadv_tt_local_entry *tt_local_entry = NULL;\n \tstruct batadv_tt_orig_list_entry *best_entry;\n \tstruct batadv_orig_node *orig_node = NULL;\n+\tu16 flags;\n \n \tif (src \u0026\u0026 batadv_vlan_ap_isola_get(bat_priv, vid)) {\n \t\ttt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);\n-\t\tif (!tt_local_entry ||\n-\t\t (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_PENDING))\n+\t\tif (!tt_local_entry)\n+\t\t\tgoto out;\n+\n+\t\tflags = batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon);\n+\t\tif (flags \u0026 BATADV_TT_CLIENT_PENDING)\n \t\t\tgoto out;\n \t}\n \n@@ -2562,6 +2712,8 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,\n \n \t\trcu_read_lock();\n \t\thlist_for_each_entry_rcu(tt_common, head, hash_entry) {\n+\t\t\tu16 tt_flags;\n+\n \t\t\ttt_global = container_of(tt_common,\n \t\t\t\t\t\t struct batadv_tt_global_entry,\n \t\t\t\t\t\t common);\n@@ -2571,18 +2723,21 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,\n \t\t\tif (tt_common-\u003evid != vid)\n \t\t\t\tcontinue;\n \n+\t\t\ttt_flags = batadv_tt_flags_get(tt_common);\n+\n \t\t\t/* Roaming clients are in the global table for\n \t\t\t * consistency only. They don't have to be\n \t\t\t * taken into account while computing the\n \t\t\t * global crc\n \t\t\t */\n-\t\t\tif (tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_ROAM)\n+\t\t\tif (tt_flags \u0026 BATADV_TT_CLIENT_ROAM)\n \t\t\t\tcontinue;\n+\n \t\t\t/* Temporary clients have not been announced yet, so\n \t\t\t * they have to be skipped while computing the global\n \t\t\t * crc\n \t\t\t */\n-\t\t\tif (tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_TEMP)\n+\t\t\tif (tt_flags \u0026 BATADV_TT_CLIENT_TEMP)\n \t\t\t\tcontinue;\n \n \t\t\t/* find out if this global entry is announced by this\n@@ -2642,18 +2797,24 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,\n \n \t\trcu_read_lock();\n \t\thlist_for_each_entry_rcu(tt_common, head, hash_entry) {\n+\t\t\tu16 tt_flags;\n+\n \t\t\t/* compute the CRC only for entries belonging to the\n \t\t\t * VLAN identified by vid\n \t\t\t */\n \t\t\tif (tt_common-\u003evid != vid)\n \t\t\t\tcontinue;\n \n+\t\t\ttt_flags = batadv_tt_flags_get(tt_common);\n+\n \t\t\t/* not yet committed clients have not to be taken into\n \t\t\t * account while computing the CRC\n \t\t\t */\n-\t\t\tif (tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_NEW)\n+\t\t\tif (tt_flags \u0026 BATADV_TT_CLIENT_NEW)\n \t\t\t\tcontinue;\n \n+\t\t\tflags = tt_flags \u0026 BATADV_TT_SYNC_MASK;\n+\n \t\t\t/* use network order to read the VID: this ensures that\n \t\t\t * every node reads the bytes in the same order.\n \t\t\t */\n@@ -2663,7 +2824,6 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,\n \t\t\t/* compute the CRC on flags that have to be kept in sync\n \t\t\t * among nodes\n \t\t\t */\n-\t\t\tflags = tt_common-\u003eflags \u0026 BATADV_TT_SYNC_MASK;\n \t\t\tcrc_tmp = crc32c(crc_tmp, \u0026flags, sizeof(flags));\n \n \t\t\tcrc ^= crc32c(crc_tmp, tt_common-\u003eaddr, ETH_ALEN);\n@@ -2821,17 +2981,19 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,\n *\n * Return: true if the entry is a valid, false otherwise.\n */\n-static bool batadv_tt_local_valid(const void *entry_ptr,\n+static bool batadv_tt_local_valid(void *entry_ptr,\n \t\t\t\t const void *data_ptr,\n \t\t\t\t u8 *flags)\n {\n-\tconst struct batadv_tt_common_entry *tt_common_entry = entry_ptr;\n+\tstruct batadv_tt_common_entry *tt_common_entry = entry_ptr;\n+\tu16 tt_flags;\n \n-\tif (tt_common_entry-\u003eflags \u0026 BATADV_TT_CLIENT_NEW)\n+\ttt_flags = batadv_tt_flags_get(tt_common_entry);\n+\tif (tt_flags \u0026 BATADV_TT_CLIENT_NEW)\n \t\treturn false;\n \n \tif (flags)\n-\t\t*flags = tt_common_entry-\u003eflags;\n+\t\t*flags = tt_flags;\n \n \treturn true;\n }\n@@ -2848,16 +3010,18 @@ static bool batadv_tt_local_valid(const void *entry_ptr,\n *\n * Return: true if the entry is a valid, false otherwise.\n */\n-static bool batadv_tt_global_valid(const void *entry_ptr,\n+static bool batadv_tt_global_valid(void *entry_ptr,\n \t\t\t\t const void *data_ptr,\n \t\t\t\t u8 *flags)\n {\n-\tconst struct batadv_tt_common_entry *tt_common_entry = entry_ptr;\n-\tconst struct batadv_tt_global_entry *tt_global_entry;\n+\tstruct batadv_tt_common_entry *tt_common_entry = entry_ptr;\n \tconst struct batadv_orig_node *orig_node = data_ptr;\n+\tstruct batadv_tt_global_entry *tt_global_entry;\n+\tu16 tt_flags;\n \n-\tif (tt_common_entry-\u003eflags \u0026 BATADV_TT_CLIENT_ROAM ||\n-\t tt_common_entry-\u003eflags \u0026 BATADV_TT_CLIENT_TEMP)\n+\ttt_flags = batadv_tt_flags_get(tt_common_entry);\n+\tif (tt_flags \u0026 BATADV_TT_CLIENT_ROAM ||\n+\t tt_flags \u0026 BATADV_TT_CLIENT_TEMP)\n \t\treturn false;\n \n \ttt_global_entry = container_of(tt_common_entry,\n@@ -2886,7 +3050,7 @@ static bool batadv_tt_global_valid(const void *entry_ptr,\n static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,\n \t\t\t\t struct batadv_hashtable *hash,\n \t\t\t\t void *tvlv_buff, u16 tt_len,\n-\t\t\t\t bool (*valid_cb)(const void *,\n+\t\t\t\t bool (*valid_cb)(void *,\n \t\t\t\t\t\t const void *,\n \t\t\t\t\t\t u8 *flags),\n \t\t\t\t void *cb_data)\n@@ -3511,19 +3675,21 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,\n \t\t\t unsigned short vid)\n {\n \tstruct batadv_tt_local_entry *tt_local_entry;\n-\tbool ret = false;\n+\tu16 tt_flags;\n+\tbool ret;\n \n \ttt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);\n \tif (!tt_local_entry)\n-\t\tgoto out;\n+\t\treturn false;\n+\n+\ttt_flags = batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon);\n+\n \t/* Check if the client has been logically deleted (but is kept for\n \t * consistency purpose)\n \t */\n-\tif ((tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_PENDING) ||\n-\t (tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM))\n-\t\tgoto out;\n-\tret = true;\n-out:\n+\tret = !((tt_flags \u0026 BATADV_TT_CLIENT_PENDING) ||\n+\t\t(tt_flags \u0026 BATADV_TT_CLIENT_ROAM));\n+\n \tbatadv_tt_local_entry_put(tt_local_entry);\n \treturn ret;\n }\n@@ -3782,16 +3948,13 @@ void batadv_tt_free(struct batadv_priv *bat_priv)\n }\n \n /**\n- * batadv_tt_local_set_flags() - set or unset the specified flags on the local\n- * table and possibly count them in the TT size\n+ * batadv_tt_local_transition_new() - unset the NEW flag on the local\n+ * table and count them in the TT size\n * @bat_priv: the bat priv with all the mesh interface information\n- * @flags: the flag to switch\n- * @enable: whether to set or unset the flag\n- * @count: whether to increase the TT size by the number of changed entries\n */\n-static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,\n-\t\t\t\t bool enable, bool count)\n+static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)\n {\n+\tspinlock_t *list_lock; /* protects write access to the hash lists */\n \tstruct batadv_hashtable *hash = bat_priv-\u003ett.local_hash;\n \tstruct batadv_tt_common_entry *tt_common_entry;\n \tstruct hlist_head *head;\n@@ -3802,27 +3965,28 @@ static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,\n \n \tfor (i = 0; i \u003c hash-\u003esize; i++) {\n \t\thead = \u0026hash-\u003etable[i];\n+\t\tlist_lock = \u0026hash-\u003elist_locks[i];\n \n-\t\trcu_read_lock();\n-\t\thlist_for_each_entry_rcu(tt_common_entry,\n-\t\t\t\t\t head, hash_entry) {\n-\t\t\tif (enable) {\n-\t\t\t\tif ((tt_common_entry-\u003eflags \u0026 flags) == flags)\n-\t\t\t\t\tcontinue;\n-\t\t\t\ttt_common_entry-\u003eflags |= flags;\n-\t\t\t} else {\n-\t\t\t\tif (!(tt_common_entry-\u003eflags \u0026 flags))\n-\t\t\t\t\tcontinue;\n-\t\t\t\ttt_common_entry-\u003eflags \u0026= ~flags;\n+\t\tspin_lock_bh(list_lock);\n+\t\thlist_for_each_entry(tt_common_entry, head, hash_entry) {\n+\t\t\tbool cont = false;\n+\n+\t\t\tscoped_guard(spinlock_bh, \u0026tt_common_entry-\u003eflags_lock) {\n+\t\t\t\tif (!(tt_common_entry-\u003eflags \u0026 BATADV_TT_CLIENT_NEW)) {\n+\t\t\t\t\tcont = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\t\t\ttt_common_entry-\u003eflags \u0026= ~BATADV_TT_CLIENT_NEW;\n \t\t\t}\n \n-\t\t\tif (!count)\n+\t\t\tif (cont)\n \t\t\t\tcontinue;\n \n \t\t\tbatadv_tt_local_size_inc(bat_priv,\n \t\t\t\t\t\t tt_common_entry-\u003evid);\n \t\t}\n-\t\trcu_read_unlock();\n+\t\tspin_unlock_bh(list_lock);\n \t}\n }\n \n@@ -3854,16 +4018,31 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)\n \t\tspin_lock_bh(list_lock);\n \t\thlist_for_each_entry_safe(tt_common, node_tmp, head,\n \t\t\t\t\t hash_entry) {\n-\t\t\tif (!(tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_PENDING))\n-\t\t\t\tcontinue;\n+\t\t\tbool cont = false;\n \n-\t\t\tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n-\t\t\t\t \"Deleting local tt entry (%pM, vid: %d): pending\\n\",\n-\t\t\t\t tt_common-\u003eaddr,\n-\t\t\t\t batadv_print_vid(tt_common-\u003evid));\n+\t\t\tscoped_guard(spinlock_bh, \u0026tt_common-\u003eflags_lock) {\n+\t\t\t\tif (!(tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_PENDING)) {\n+\t\t\t\t\tcont = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\t\t\tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n+\t\t\t\t\t \"Deleting local tt entry (%pM, vid: %d): pending\\n\",\n+\t\t\t\t\t tt_common-\u003eaddr,\n+\t\t\t\t\t batadv_print_vid(tt_common-\u003evid));\n+\n+\t\t\t\thlist_del_rcu(\u0026tt_common-\u003ehash_entry);\n+\n+\t\t\t\t/* An entry which still carries BATADV_TT_CLIENT_NEW was\n+\t\t\t\t * never counted and must not be uncounted here.\n+\t\t\t\t */\n+\t\t\t\tif (!(tt_common-\u003eflags \u0026 BATADV_TT_CLIENT_NEW))\n+\t\t\t\t\tbatadv_tt_local_size_dec(bat_priv, tt_common-\u003evid);\n+\t\t\t}\n+\n+\t\t\tif (cont)\n+\t\t\t\tcontinue;\n \n-\t\t\tbatadv_tt_local_size_dec(bat_priv, tt_common-\u003evid);\n-\t\t\thlist_del_rcu(\u0026tt_common-\u003ehash_entry);\n \t\t\ttt_local = container_of(tt_common,\n \t\t\t\t\t\tstruct batadv_tt_local_entry,\n \t\t\t\t\t\tcommon);\n@@ -3891,7 +4070,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)\n \t\treturn;\n \t}\n \n-\tbatadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);\n+\tbatadv_tt_local_transition_new(bat_priv);\n \n \tbatadv_tt_local_purge_pending_clients(bat_priv);\n \tbatadv_tt_local_update_crc(bat_priv);\n@@ -4061,15 +4240,16 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,\n \t\t\t\t\tu8 *addr, unsigned short vid)\n {\n \tstruct batadv_tt_global_entry *tt_global_entry;\n-\tbool ret = false;\n+\tbool ret;\n \n \ttt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);\n \tif (!tt_global_entry)\n-\t\tgoto out;\n+\t\treturn false;\n+\n+\tret = batadv_tt_flags_get(\u0026tt_global_entry-\u003ecommon) \u0026 BATADV_TT_CLIENT_ROAM;\n \n-\tret = tt_global_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM;\n \tbatadv_tt_global_entry_put(tt_global_entry);\n-out:\n+\n \treturn ret;\n }\n \n@@ -4087,15 +4267,16 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,\n \t\t\t\t u8 *addr, unsigned short vid)\n {\n \tstruct batadv_tt_local_entry *tt_local_entry;\n-\tbool ret = false;\n+\tbool ret;\n \n \ttt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);\n \tif (!tt_local_entry)\n-\t\tgoto out;\n+\t\treturn false;\n+\n+\tret = batadv_tt_flags_get(\u0026tt_local_entry-\u003ecommon) \u0026 BATADV_TT_CLIENT_ROAM;\n \n-\tret = tt_local_entry-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ROAM;\n \tbatadv_tt_local_entry_put(tt_local_entry);\n-out:\n+\n \treturn ret;\n }\n \n@@ -4404,7 +4585,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,\n \tif (!tt)\n \t\treturn false;\n \n-\tret = tt-\u003ecommon.flags \u0026 BATADV_TT_CLIENT_ISOLA;\n+\tret = batadv_tt_flags_get(\u0026tt-\u003ecommon) \u0026 BATADV_TT_CLIENT_ISOLA;\n \n \tbatadv_tt_global_entry_put(tt);\n \ndiff --git a/net/batman-adv/types.h b/net/batman-adv/types.h\nindex 9bdc5a3e799e2..67872927cfb50 100644\n--- a/net/batman-adv/types.h\n+++ b/net/batman-adv/types.h\n@@ -410,7 +410,7 @@ struct batadv_orig_bat_iv {\n */\n struct batadv_orig_node {\n \t/** @orig: originator ethernet address */\n-\tu8 orig[ETH_ALEN];\n+\tu8 orig[ETH_ALEN] __aligned(2);\n \n \t/** @ifinfo_list: list for routers per outgoing interface */\n \tstruct hlist_head ifinfo_list;\n@@ -634,12 +634,12 @@ struct batadv_hardif_neigh_node {\n \tstruct hlist_node list;\n \n \t/** @addr: the MAC address of the neighboring interface */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/**\n \t * @orig: the address of the originator this neighbor node belongs to\n \t */\n-\tu8 orig[ETH_ALEN];\n+\tu8 orig[ETH_ALEN] __aligned(2);\n \n \t/** @if_incoming: pointer to incoming hard-interface */\n \tstruct batadv_hard_iface *if_incoming;\n@@ -677,7 +677,7 @@ struct batadv_neigh_node {\n #endif\n \n \t/** @addr: the MAC address of the neighboring interface */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/** @ifinfo_list: list for routing metrics per outgoing interface */\n \tstruct hlist_head ifinfo_list;\n@@ -777,7 +777,7 @@ struct batadv_neigh_ifinfo {\n */\n struct batadv_bcast_duplist_entry {\n \t/** @orig: mac address of orig node originating the broadcast */\n-\tu8 orig[ETH_ALEN];\n+\tu8 orig[ETH_ALEN] __aligned(2);\n \n \t/** @crc: crc32 checksum of broadcast payload */\n \tu32 crc;\n@@ -1085,7 +1085,7 @@ struct batadv_priv_bla {\n \tstruct batadv_hashtable *backbone_hash;\n \n \t/** @loopdetect_addr: MAC address used for own loopdetection frames */\n-\tu8 loopdetect_addr[ETH_ALEN];\n+\tu8 loopdetect_addr[ETH_ALEN] __aligned(2);\n \n \t/**\n \t * @loopdetect_lasttime: time when the loopdetection frames were sent\n@@ -1352,7 +1352,7 @@ struct batadv_tp_vars_common {\n \tstruct batadv_priv *bat_priv;\n \n \t/** @other_end: mac address of remote */\n-\tu8 other_end[ETH_ALEN];\n+\tu8 other_end[ETH_ALEN] __aligned(2);\n \n \t/** @session: TP session identifier */\n \tu8 session[2];\n@@ -1765,7 +1765,7 @@ struct batadv_bla_backbone_gw {\n \t * @orig: originator address of backbone node (mac address of primary\n \t * iface)\n \t */\n-\tu8 orig[ETH_ALEN];\n+\tu8 orig[ETH_ALEN] __aligned(2);\n \n \t/** @vid: vlan id this gateway was detected on */\n \tunsigned short vid;\n@@ -1810,7 +1810,7 @@ struct batadv_bla_backbone_gw {\n */\n struct batadv_bla_claim {\n \t/** @addr: mac address of claimed non-mesh client */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/** @vid: vlan id this client was detected on */\n \tunsigned short vid;\n@@ -1840,7 +1840,7 @@ struct batadv_bla_claim {\n */\n struct batadv_tt_common_entry {\n \t/** @addr: mac address of non-mesh client */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/** @vid: VLAN identifier */\n \tunsigned short vid;\n@@ -1851,12 +1851,21 @@ struct batadv_tt_common_entry {\n \t */\n \tstruct hlist_node hash_entry;\n \n-\t/** @flags: various state handling flags (see batadv_tt_client_flags) */\n+\t/**\n+\t * @flags: various state handling flags (see batadv_tt_client_flags),\n+\t * protected by @flags_lock\n+\t */\n \tu16 flags;\n \n \t/** @added_at: timestamp used for purging stale tt common entries */\n \tunsigned long added_at;\n \n+\t/**\n+\t * @flags_lock: protect modifications of @flags and\n+\t * @batadv_tt_global_entry.roam_at\n+\t */\n+\tspinlock_t flags_lock;\n+\n \t/** @refcount: number of contexts the object is used */\n \tstruct kref refcount;\n \n@@ -1942,7 +1951,7 @@ struct batadv_tt_req_node {\n \t/**\n \t * @addr: mac address of the originator this request was sent to\n \t */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/** @issued_at: timestamp used for purging stale tt requests */\n \tunsigned long issued_at;\n@@ -1959,7 +1968,7 @@ struct batadv_tt_req_node {\n */\n struct batadv_tt_roam_node {\n \t/** @addr: mac address of the client in the roaming phase */\n-\tu8 addr[ETH_ALEN];\n+\tu8 addr[ETH_ALEN] __aligned(2);\n \n \t/** @vid: VLAN identifier */\n \tu16 vid;\n@@ -2087,14 +2096,14 @@ struct batadv_algo_neigh_ops {\n \t\t struct batadv_hard_iface *if_outgoing2);\n \n \t/**\n-\t * @is_similar_or_better: check if neigh1 is equally similar or better\n-\t * than neigh2 for their respective outgoing interface from the metric\n+\t * @is_similar_or_better: check if @candidate is equally similar or better\n+\t * than @reference for their respective outgoing interface from the metric\n \t * prospective\n \t */\n-\tbool (*is_similar_or_better)(struct batadv_neigh_node *neigh1,\n-\t\t\t\t struct batadv_hard_iface *if_outgoing1,\n-\t\t\t\t struct batadv_neigh_node *neigh2,\n-\t\t\t\t struct batadv_hard_iface *if_outgoing2);\n+\tbool (*is_similar_or_better)(struct batadv_neigh_node *candidate,\n+\t\t\t\t struct batadv_hard_iface *if_outgoing_cand,\n+\t\t\t\t struct batadv_neigh_node *reference,\n+\t\t\t\t struct batadv_hard_iface *if_outgoing_ref);\n \n \t/** @dump: dump neighbors to a netlink socket (optional) */\n \tvoid (*dump)(struct sk_buff *msg, struct netlink_callback *cb,\n@@ -2204,7 +2213,7 @@ struct batadv_hw_addr {\n \tstruct hlist_node list;\n \n \t/** @addr: the MAC address of this list entry */\n-\tunsigned char addr[ETH_ALEN];\n+\tunsigned char addr[ETH_ALEN] __aligned(2);\n };\n \n /**\n"
} |
| 2/1 | 2026/08/31 20:31 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": [
"BATMAN_ADV",
"BATMAN_ADV_BATMAN_V",
"BATMAN_ADV_BLA",
"BATMAN_ADV_DAT",
"BATMAN_ADV_MCAST"
],
"FocusSymbols": [
"batadv_tt_local_add",
"batadv_tt_local_remove",
"batadv_transtable_search",
"batadv_is_my_client",
"batadv_tt_global_is_isolated",
"batadv_tt_global_client_is_roaming",
"batadv_tt_local_client_is_roaming"
],
"Reasoning": "The patch series introduces significant functional changes and bug fixes in the B.A.T.M.A.N. Advanced mesh protocol subsystem (net/batman-adv/). Key changes include adding spinlock protection (flags_lock) to avoid race conditions when reading and mutating translation table entry flags, fixing exact object removal from hash buckets (batadv_compare_tt_entry), correcting the B.A.T.M.A.N. V neighbor comparison calculation logic in batadv_v_neigh_is_sob(), and adding 2-byte alignment attributes to MAC address buffers. These changes alter core execution flows and state handling that are fully reachable and testable in virtual environments.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). - Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed, ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU. - Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove) that are executed only during PCI hot-unplug or sysfs driver unbind operations. If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. Prefer non-static, non-inlined API entrypoint functions over internal static helper functions (which are inlined by the compiler and do not have distinct symbol addresses). 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit f47ea3f9a76918a99237ce731d7cf6e85775d007
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 31 20:31:52 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 53fbdbbe8f4f7..3fe09b4c30463 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -2424,25 +2424,26 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
/**
* batadv_iv_ogm_neigh_is_sob() - check if neigh1 is similarly good or better
* than neigh2 from the metric prospective
- * @neigh1: the first neighbor object of the comparison
- * @if_outgoing1: outgoing interface for the first neighbor
- * @neigh2: the second neighbor object of the comparison
- * @if_outgoing2: outgoing interface for the second neighbor
+ * @candidate: the first neighbor object of the comparison
+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor
+ * @reference: the second neighbor object of the comparison
+ * @if_outgoing_ref: outgoing interface for the @reference neighbor
*
- * Return: true if the metric via neigh1 is equally good or better than
- * the metric via neigh2, false otherwise.
+ * Return: true if the metric via @candidate is equally good or better than
+ * the metric via @reference, false otherwise.
*/
static bool
-batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2)
+batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref)
{
bool ret;
int diff;
- ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
- if_outgoing2, &diff);
+ ret = batadv_iv_ogm_neigh_diff(candidate, if_outgoing_cand,
+ reference, if_outgoing_ref,
+ &diff);
if (!ret)
return false;
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index 0c27447cf6889..596889b3522d0 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -514,40 +514,40 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
/**
* batadv_v_neigh_is_sob() - check whether two B.A.T.M.A.N. V neighbours have
* a similar or better throughput
- * @neigh1: first neighbour to compare
- * @if_outgoing1: outgoing interface to use for @neigh1
- * @neigh2: second neighbour to compare
- * @if_outgoing2: outgoing interface to use for @neigh2
+ * @candidate: the first neighbor object of the comparison
+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor
+ * @reference: the second neighbor object of the comparison
+ * @if_outgoing_ref: outgoing interface for the @reference neighbor
*
- * Return: true if the throughput of @neigh2 is at least 3/4 of the
- * @neigh1 throughput
+ * Return: true if the throughput of @candidate is more than 3/4 of the
+ * @reference throughput
*/
-static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2)
+static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref)
{
- struct batadv_neigh_ifinfo *ifinfo1;
- struct batadv_neigh_ifinfo *ifinfo2;
+ struct batadv_neigh_ifinfo *ifinfo_cand;
+ struct batadv_neigh_ifinfo *ifinfo_ref;
bool ret = false;
u32 threshold;
- ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- if (!ifinfo1)
+ ifinfo_cand = batadv_neigh_ifinfo_get(candidate, if_outgoing_cand);
+ if (!ifinfo_cand)
goto err_ifinfo1;
- ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- if (!ifinfo2)
+ ifinfo_ref = batadv_neigh_ifinfo_get(reference, if_outgoing_ref);
+ if (!ifinfo_ref)
goto err_ifinfo2;
- threshold = ifinfo1->bat_v.throughput / 4;
- threshold = ifinfo1->bat_v.throughput - threshold;
+ threshold = ifinfo_ref->bat_v.throughput / 4;
+ threshold = ifinfo_ref->bat_v.throughput - threshold;
- ret = ifinfo2->bat_v.throughput > threshold;
+ ret = ifinfo_cand->bat_v.throughput > threshold;
- batadv_neigh_ifinfo_put(ifinfo2);
+ batadv_neigh_ifinfo_put(ifinfo_ref);
err_ifinfo2:
- batadv_neigh_ifinfo_put(ifinfo1);
+ batadv_neigh_ifinfo_put(ifinfo_cand);
err_ifinfo1:
return ret;
}
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index f635da4b8ca65..ad6ab4a50658f 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -663,7 +663,7 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
struct batadv_bla_backbone_gw *backbone_gw)
{
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] __aligned(2);
__be16 crc;
memcpy(mac, batadv_announce_mac, 4);
@@ -1582,7 +1582,9 @@ static struct lock_class_key batadv_backbone_hash_lock_class_key;
*/
int batadv_bla_init(struct batadv_priv *bat_priv)
{
- u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
+ static const u8 claim_dest[ETH_ALEN] __aligned(2) = {
+ 0xff, 0x43, 0x05, 0x00, 0x00, 0x00
+ };
struct batadv_hard_iface *primary_if;
unsigned long entrytime;
u16 crc;
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 011cfdc47fab4..a4be5b2a87d7a 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -548,7 +548,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,
break;
default:
batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: Unknown (%u)!\n",
- unicast_4addr_packet->u.packet_type);
+ unicast_4addr_packet->subtype);
}
break;
case BATADV_BCAST:
@@ -940,7 +940,7 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
struct netlink_callback *cb,
struct batadv_dat_entry *dat_entry)
{
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] __aligned(2);
u64 u64_mac;
int msecs;
void *hdr;
@@ -1236,10 +1236,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
{
struct net_device *mesh_iface = bat_priv->mesh_iface;
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
- u8 mac[ETH_ALEN];
int hdr_size = 0;
__be32 ip_dst;
__be32 ip_src;
@@ -1344,10 +1344,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
{
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
- u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
u64 u64_mac;
@@ -1474,9 +1474,9 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
{
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
bool dropped = false;
unsigned short vid;
- u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
u64 u64_mac;
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index e202088cf1fd4..63af21954cf90 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -141,9 +141,9 @@ static struct net_device_stats *batadv_interface_stats(struct net_device *dev)
static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
+ u8 old_addr[ETH_ALEN] __aligned(2);
struct batadv_meshif_vlan *vlan;
struct sockaddr *addr = p;
- u8 old_addr[ETH_ALEN];
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
@@ -213,13 +213,18 @@ static void batadv_interface_set_rx_mode(struct net_device *dev)
static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
struct net_device *mesh_iface)
{
- static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 0x00, 0x00};
- static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
enum batadv_forw_mode forw_mode = BATADV_FORW_BCAST;
+ static const u8 ectp_addr[ETH_ALEN] __aligned(2) = {
+ 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 stp_addr[ETH_ALEN] __aligned(2) = {
+ 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00
+ };
struct batadv_hard_iface *primary_if = NULL;
struct batadv_bcast_packet *bcast_packet;
+ u8 chaddr[ETH_ALEN] __aligned(2);
int network_offset = ETH_HLEN;
unsigned int header_len = 0;
unsigned long brd_delay = 0;
@@ -229,7 +234,6 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
struct ethhdr *ethhdr;
bool do_bcast = false;
u8 *dst_hint = NULL;
- u8 chaddr[ETH_ALEN];
unsigned short vid;
bool client_added;
__be16 proto;
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 82fd527b61c02..22dd28d5e1abc 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -368,9 +368,9 @@ batadv_mcast_mla_meshif_get_ipv4(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
struct batadv_hw_addr *new;
struct in_device *in_dev;
- u8 mcast_addr[ETH_ALEN];
struct ip_mc_list *pmc;
int ret = 0;
@@ -435,9 +435,9 @@ batadv_mcast_mla_meshif_get_ipv6(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
struct batadv_hw_addr *new;
struct inet6_dev *in6_dev;
- u8 mcast_addr[ETH_ALEN];
struct ifmcaddr6 *pmc6;
int ret = 0;
@@ -587,10 +587,10 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct batadv_mcast_mla_flags *flags)
{
struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
u8 tvlv_flags = flags->tvlv_flags;
struct br_ip_list *br_ip_entry;
struct batadv_hw_addr *new;
- u8 mcast_addr[ETH_ALEN];
struct br_ip_list *tmp;
int ret;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 68f79853032ed..44a8cf89382c6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -13,6 +13,7 @@
#include <linux/build_bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
+#include <linux/cleanup.h>
#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/crc32.h>
@@ -95,6 +96,26 @@ static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
}
+/**
+ * batadv_compare_tt_entry() - check if a hash node is a specific TT entry
+ * @node: the list element pointer of the TT entry stored in the bucket
+ * @data2: pointer to the tt_common_entry which is looked for
+ *
+ * Unlike batadv_compare_tt(), this only matches the very object which is
+ * passed as @data2 and not just any entry for the same TT client. It is meant
+ * for batadv_hash_remove() callers which must not unlink an entry they did not
+ * look up themselves.
+ *
+ * Return: true if @node belongs to @data2, false otherwise
+ */
+static bool batadv_compare_tt_entry(const struct hlist_node *node,
+ const void *data2)
+{
+ const struct batadv_tt_common_entry *tt = data2;
+
+ return node == &tt->hash_entry;
+}
+
/**
* batadv_choose_tt() - return the index of the tt entry in the hash table
* @data: pointer to the tt_common_entry object to map
@@ -312,6 +333,10 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called when removing the NEW flag of a
+ * batadv_tt_local_entry while it is still part of the bat_priv->tt.local_hash.
+ * It must therefore be checked under the specific list_locks[i].
*/
static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -324,6 +349,11 @@ static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called after a batadv_tt_local_entry without NEW flag
+ * was removed from bat_priv->tt.local_hash (under the specific
+ * list_locks[i]) or when it is ensured that it is not accessible
+ * in this list.
*/
static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -413,6 +443,22 @@ batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
}
+/**
+ * batadv_tt_flags_get() - get a snapshot of the flags of a TT entry
+ * @common: tt local & tt global common data
+ *
+ * Return: the flags of the TT entry as observed under its flags_lock.
+ */
+static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
+{
+ u16 flags;
+
+ scoped_guard(spinlock_bh, &common->flags_lock)
+ flags = common->flags;
+
+ return flags;
+}
+
/**
* batadv_tt_local_event() - store a local TT event (ADD/DEL)
* @bat_priv: the bat priv with all the mesh interface information
@@ -425,23 +471,25 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
{
struct batadv_tt_common_entry *common = &tt_local_entry->common;
struct batadv_tt_change_node *tt_change_node;
- u8 flags = common->flags | event_flags;
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)
return;
- tt_change_node->change.flags = flags;
memset(tt_change_node->change.reserved, 0,
sizeof(tt_change_node->change.reserved));
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;
/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */
@@ -575,7 +623,6 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
struct batadv_tt_global_entry *tt_global,
const char *message)
{
- struct batadv_tt_global_entry *tt_removed_entry;
struct hlist_node *tt_removed_node;
batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -583,18 +630,67 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
tt_global->common.addr,
batadv_print_vid(tt_global->common.vid), message);
+ /* remove exactly this object when still present in hash */
tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
- batadv_compare_tt,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_global->common);
if (!tt_removed_node)
return;
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_global_entry,
- common.hash_entry);
- batadv_tt_global_entry_put(tt_removed_entry);
+ batadv_tt_global_entry_put(tt_global);
+}
+
+/**
+ * batadv_tt_local_add_roam() - handle roamed clients during batadv_tt_local_add()
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_global: the global TT entry
+ * @roamed_back: whether @tt_global roamed back
+ */
+static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
+ struct batadv_tt_global_entry *tt_global,
+ bool roamed_back)
+{
+ struct batadv_tt_orig_list_entry *orig_entry;
+ struct hlist_head *head;
+
+ if (!tt_global)
+ return;
+
+ /* Check whether it is a roaming, but don't do anything if the roaming
+ * process has already been handled
+ */
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
+ return;
+
+ if (!roamed_back) {
+ /* The global entry has to be marked as ROAMING and has to be
+ * kept for consistency purpose.
+ *
+ * batadv_tt_global_to_purge() evaluates roam_at as soon as it
+ * observes BATADV_TT_CLIENT_ROAM, so the timeout has to be
+ * stamped before the flag is published. Otherwise the entry can
+ * be deleted right away as "Roaming timeout".
+ */
+ tt_global->roam_at = jiffies;
+ tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
+ }
+ }
+
+ /* These node are probably going to update their tt table */
+ head = &tt_global->orig_list;
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_entry, head, list) {
+ batadv_send_roam_adv(bat_priv, tt_global->common.addr,
+ tt_global->common.vid,
+ orig_entry->orig_node);
+ }
+ rcu_read_unlock();
+
+ if (roamed_back)
+ batadv_tt_global_free(bat_priv, tt_global, "Roaming canceled");
}
/**
@@ -615,20 +711,19 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_global_entry *tt_global = NULL;
- struct batadv_tt_orig_list_entry *orig_entry;
struct batadv_tt_local_entry *tt_local;
struct net *net = dev_net(mesh_iface);
struct net_device *in_dev = NULL;
struct batadv_meshif_vlan *vlan;
bool roamed_back = false;
bool iif_is_wifi = false;
- struct hlist_head *head;
int packet_size_max;
bool ret = false;
u8 remote_flags;
int hash_added;
int table_size;
u32 match_mark;
+ bool modified;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
@@ -646,6 +741,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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",
@@ -656,6 +753,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
* flag can be reset like it was never enqueued
*/
tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto add_event;
}
@@ -671,6 +770,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
roamed_back = true;
}
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto check_roaming;
}
@@ -706,18 +807,21 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
(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
* a full table response going out before the next ttvn increment
* (consistency check)
*/
tt_local->common.flags = BATADV_TT_CLIENT_NEW;
- tt_local->common.vid = vid;
if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
- kref_init(&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
@@ -725,6 +829,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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,
@@ -741,31 +846,9 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
check_roaming:
- /* Check whether it is a roaming, but don't do anything if the roaming
- * process has already been handled
- */
- if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
- /* These node are probably going to update their tt table */
- head = &tt_global->orig_list;
- rcu_read_lock();
- hlist_for_each_entry_rcu(orig_entry, head, list) {
- batadv_send_roam_adv(bat_priv, tt_global->common.addr,
- tt_global->common.vid,
- orig_entry->orig_node);
- }
- rcu_read_unlock();
- if (roamed_back) {
- batadv_tt_global_free(bat_priv, tt_global,
- "Roaming canceled");
- } else {
- /* The global entry has to be marked as ROAMING and
- * has to be kept for consistency purpose
- */
- tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global->roam_at = jiffies;
- }
- }
+ 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
* understanding is flags are changing or not
*/
@@ -787,10 +870,13 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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
* entry so that all the nodes can get the new flags
*/
- if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
+ if (modified)
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
ret = true;
@@ -1115,6 +1201,7 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
struct batadv_meshif_vlan *vlan;
unsigned int last_seen_msecs;
void *hdr;
+ u16 flags;
u32 crc;
local = container_of(common, struct batadv_tt_local_entry, common);
@@ -1136,13 +1223,15 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
+ flags = batadv_tt_flags_get(common);
+
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
- nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
+ nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
goto nla_put_failure;
- if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
+ if (!(flags & BATADV_TT_CLIENT_NOPURGE) &&
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
goto nla_put_failure;
@@ -1249,29 +1338,23 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
}
/**
- * batadv_tt_local_set_pending() - mark a local TT entry as pending removal
+ * batadv_tt_local_set_pending_event() - trigger events for TT pending removal
* @bat_priv: the bat priv with all the mesh interface information
* @tt_local_entry: local TT entry to mark
* @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 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.
+ * 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.
*/
static void
-batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
- struct batadv_tt_local_entry *tt_local_entry,
- u16 flags, const char *message)
+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_event(bat_priv, tt_local_entry, flags);
- /* The local client has to be marked as "pending to be removed" but has
- * to be kept in the table in order to send it in a full table
- * response issued before the net ttvn increment (consistency check)
- */
- tt_local_entry->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",
tt_local_entry->common.addr,
@@ -1292,16 +1375,17 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid, const char *message,
bool roaming)
{
- struct batadv_tt_local_entry *tt_removed_entry;
struct batadv_tt_local_entry *tt_local_entry;
struct hlist_node *tt_removed_node;
u16 curr_flags = BATADV_NO_FLAGS;
+ bool pending = false;
u16 flags;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
goto out;
+ spin_lock_bh(&tt_local_entry->common.flags_lock);
curr_flags = tt_local_entry->common.flags;
flags = BATADV_TT_CLIENT_DEL;
@@ -1316,27 +1400,39 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
}
if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
- batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
- message);
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ pending = true;
+ }
+ spin_unlock_bh(&tt_local_entry->common.flags_lock);
+
+ if (pending) {
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,
+ message);
goto out;
}
+
/* if this client has been added right now, it is possible to
* immediately purge it
*/
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,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_local_entry->common);
if (!tt_removed_node)
goto out;
+ /* 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);
+
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_local_entry,
- common.hash_entry);
- batadv_tt_local_entry_put(tt_removed_entry);
+ batadv_tt_local_entry_put(tt_local_entry);
out:
batadv_tt_local_entry_put(tt_local_entry);
@@ -1361,21 +1457,37 @@ 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);
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
- continue;
- /* entry already marked for deletion */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
- continue;
+ scoped_guard(spinlock_bh, &tt_local_entry->common.flags_lock) {
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) {
+ cont = true;
+ break;
+ }
+
+ /* entry already marked for deletion */
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) {
+ cont = true;
+ break;
+ }
+
+ if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) {
+ cont = true;
+ break;
+ }
+
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ }
- if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
+ if (cont)
continue;
- batadv_tt_local_set_pending(bat_priv, tt_local_entry,
- BATADV_TT_CLIENT_DEL, "timed out");
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
+ BATADV_TT_CLIENT_DEL, "timed out");
}
}
@@ -1581,8 +1693,10 @@ batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
flags |= orig_entry->flags;
rcu_read_unlock();
- flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
- tt_global->common.flags = flags;
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
+ tt_global->common.flags = flags;
+ }
}
/**
@@ -1664,8 +1778,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry;
struct batadv_tt_common_entry *common;
bool ret = false;
+ u16 global_flags;
u16 local_flags;
int hash_added;
+ bool delete;
/* ignore global entries from backbone nodes */
if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
@@ -1678,9 +1794,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* for a roaming advertisement instead of manually messing up the global
* table
*/
- if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
- !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
- goto out;
+ if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry) {
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (!(local_flags & BATADV_TT_CLIENT_NEW))
+ goto out;
+ }
if (!tt_global_entry) {
tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
@@ -1691,9 +1809,13 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
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))
+ 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
@@ -1733,8 +1855,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* originator list and add the new one orig_entry
*/
if (flags & BATADV_TT_CLIENT_TEMP) {
- if (!(common->flags & BATADV_TT_CLIENT_TEMP))
+ global_flags = batadv_tt_flags_get(common);
+ if (!(global_flags & BATADV_TT_CLIENT_TEMP))
goto out;
+
if (batadv_tt_global_entry_has_orig(tt_global_entry,
orig_node, NULL))
goto out_remove;
@@ -1742,6 +1866,9 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
goto add_orig_entry;
}
+ delete = false;
+
+ spin_lock_bh(&common->flags_lock);
/* if the client was temporary added before receiving the first
* OGM announcing it, we have to clear the TEMP flag. Also,
* remove the previous temporary orig node and re-add it
@@ -1749,7 +1876,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* is a non-temporary entry is preferred.
*/
if (common->flags & BATADV_TT_CLIENT_TEMP) {
- batadv_tt_global_del_orig_list(tt_global_entry);
+ delete = true;
common->flags &= ~BATADV_TT_CLIENT_TEMP;
}
@@ -1768,10 +1895,14 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* new one.
*/
if (common->flags & BATADV_TT_CLIENT_ROAM) {
- batadv_tt_global_del_orig_list(tt_global_entry);
- 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);
+
+ if (delete)
+ batadv_tt_global_del_orig_list(tt_global_entry);
}
add_orig_entry:
/* add the new orig_entry (if needed) or update it */
@@ -1795,6 +1926,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
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))
@@ -1802,6 +1935,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* roaming state anymore.
*/
tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
+ spin_unlock_bh(&tt_global_entry->common.flags_lock);
out:
batadv_tt_global_entry_put(tt_global_entry);
@@ -1871,9 +2005,9 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
struct batadv_tt_orig_list_entry *orig,
bool best)
{
- u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
struct batadv_orig_node_vlan *vlan;
u8 last_ttvn;
+ u16 flags;
void *hdr;
u32 crc;
@@ -1892,6 +2026,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
if (!hdr)
return -ENOBUFS;
+ flags = (batadv_tt_flags_get(common) & (~BATADV_TT_SYNC_MASK)) | orig->flags;
last_ttvn = READ_ONCE(orig->orig_node->last_ttvn);
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
@@ -2179,9 +2314,12 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
rcu_read_unlock();
if (last_entry) {
- /* its the last one, mark for roaming. */
- tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global_entry->roam_at = jiffies;
+ scoped_guard(spinlock_bh, &tt_global_entry->common.flags_lock) {
+ /* its the last one, mark for roaming. */
+ tt_global_entry->roam_at = jiffies;
+
+ tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
+ }
} else {
/* there is another entry, we can simply delete this
* one and can still use the other one.
@@ -2330,16 +2468,18 @@ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
bool purge = false;
- if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
- batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
- purge = true;
- *msg = "Roaming timeout\n";
- }
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
+ batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
+ purge = true;
+ *msg = "Roaming timeout\n";
+ }
- if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
- batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
- purge = true;
- *msg = "Temporary client timeout\n";
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
+ batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
+ purge = true;
+ *msg = "Temporary client timeout\n";
+ }
}
return purge;
@@ -2437,8 +2577,8 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
/**
* _batadv_is_ap_isolated() - check whether two clients are AP-isolated from
* each other
- * @tt_local_entry: local TT entry of the sending client
- * @tt_global_entry: global TT entry of the destination client
+ * @tt_local_entry: local TT entry of one local client
+ * @tt_global_entry: global TT entry of the remote client
*
* Return: true if traffic between the two clients should be dropped because
* either both are WiFi clients or both carry the ISOLATION flag; false
@@ -2448,13 +2588,19 @@ static bool
_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
struct batadv_tt_global_entry *tt_global_entry)
{
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
+ u16 global_flags;
+ u16 local_flags;
+
+ global_flags = batadv_tt_flags_get(&tt_global_entry->common);
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
+ if (local_flags & BATADV_TT_CLIENT_WIFI &&
+ global_flags & BATADV_TT_CLIENT_WIFI)
return true;
/* check if the two clients are marked as isolated */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
+ if (local_flags & BATADV_TT_CLIENT_ISOLA &&
+ global_flags & BATADV_TT_CLIENT_ISOLA)
return true;
return false;
@@ -2483,11 +2629,15 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry = NULL;
struct batadv_tt_orig_list_entry *best_entry;
struct batadv_orig_node *orig_node = NULL;
+ u16 flags;
if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
- if (!tt_local_entry ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
+ if (!tt_local_entry)
+ goto out;
+
+ flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (flags & BATADV_TT_CLIENT_PENDING)
goto out;
}
@@ -2562,6 +2712,8 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
tt_global = container_of(tt_common,
struct batadv_tt_global_entry,
common);
@@ -2571,18 +2723,21 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* Roaming clients are in the global table for
* consistency only. They don't have to be
* taken into account while computing the
* global crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
+ if (tt_flags & BATADV_TT_CLIENT_ROAM)
continue;
+
/* Temporary clients have not been announced yet, so
* they have to be skipped while computing the global
* crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
+ if (tt_flags & BATADV_TT_CLIENT_TEMP)
continue;
/* find out if this global entry is announced by this
@@ -2642,18 +2797,24 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
/* compute the CRC only for entries belonging to the
* VLAN identified by vid
*/
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* not yet committed clients have not to be taken into
* account while computing the CRC
*/
- if (tt_common->flags & BATADV_TT_CLIENT_NEW)
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
continue;
+ flags = tt_flags & BATADV_TT_SYNC_MASK;
+
/* use network order to read the VID: this ensures that
* every node reads the bytes in the same order.
*/
@@ -2663,7 +2824,6 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
/* compute the CRC on flags that have to be kept in sync
* among nodes
*/
- flags = tt_common->flags & BATADV_TT_SYNC_MASK;
crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
@@ -2821,17 +2981,19 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_local_valid(const void *entry_ptr,
+static bool batadv_tt_local_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
return false;
if (flags)
- *flags = tt_common_entry->flags;
+ *flags = tt_flags;
return true;
}
@@ -2848,16 +3010,18 @@ static bool batadv_tt_local_valid(const void *entry_ptr,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_global_valid(const void *entry_ptr,
+static bool batadv_tt_global_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
- const struct batadv_tt_global_entry *tt_global_entry;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
const struct batadv_orig_node *orig_node = data_ptr;
+ struct batadv_tt_global_entry *tt_global_entry;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
- tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_ROAM ||
+ tt_flags & BATADV_TT_CLIENT_TEMP)
return false;
tt_global_entry = container_of(tt_common_entry,
@@ -2886,7 +3050,7 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash,
void *tvlv_buff, u16 tt_len,
- bool (*valid_cb)(const void *,
+ bool (*valid_cb)(void *,
const void *,
u8 *flags),
void *cb_data)
@@ -3511,19 +3675,21 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ u16 tt_flags;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
+
+ tt_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
/* Check if the client has been logically deleted (but is kept for
* consistency purpose)
*/
- if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
- goto out;
- ret = true;
-out:
+ ret = !((tt_flags & BATADV_TT_CLIENT_PENDING) ||
+ (tt_flags & BATADV_TT_CLIENT_ROAM));
+
batadv_tt_local_entry_put(tt_local_entry);
return ret;
}
@@ -3782,16 +3948,13 @@ void batadv_tt_free(struct batadv_priv *bat_priv)
}
/**
- * batadv_tt_local_set_flags() - set or unset the specified flags on the local
- * table and possibly count them in the TT size
+ * batadv_tt_local_transition_new() - unset the NEW flag on the local
+ * table and count them in the TT size
* @bat_priv: the bat priv with all the mesh interface information
- * @flags: the flag to switch
- * @enable: whether to set or unset the flag
- * @count: whether to increase the TT size by the number of changed entries
*/
-static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
- bool enable, bool count)
+static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
{
+ spinlock_t *list_lock; /* protects write access to the hash lists */
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct batadv_tt_common_entry *tt_common_entry;
struct hlist_head *head;
@@ -3802,27 +3965,28 @@ static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- rcu_read_lock();
- hlist_for_each_entry_rcu(tt_common_entry,
- head, hash_entry) {
- if (enable) {
- if ((tt_common_entry->flags & flags) == flags)
- continue;
- tt_common_entry->flags |= flags;
- } else {
- if (!(tt_common_entry->flags & flags))
- continue;
- tt_common_entry->flags &= ~flags;
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry(tt_common_entry, head, hash_entry) {
+ bool cont = false;
+
+ scoped_guard(spinlock_bh, &tt_common_entry->flags_lock) {
+ if (!(tt_common_entry->flags & BATADV_TT_CLIENT_NEW)) {
+ cont = true;
+ break;
+ }
+
+ tt_common_entry->flags &= ~BATADV_TT_CLIENT_NEW;
}
- if (!count)
+ if (cont)
continue;
batadv_tt_local_size_inc(bat_priv,
tt_common_entry->vid);
}
- rcu_read_unlock();
+ spin_unlock_bh(list_lock);
}
}
@@ -3854,16 +4018,31 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_common, node_tmp, head,
hash_entry) {
- if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
- continue;
+ bool cont = false;
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Deleting local tt entry (%pM, vid: %d): pending\n",
- tt_common->addr,
- batadv_print_vid(tt_common->vid));
+ scoped_guard(spinlock_bh, &tt_common->flags_lock) {
+ if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) {
+ cont = true;
+ break;
+ }
+
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Deleting local tt entry (%pM, vid: %d): pending\n",
+ tt_common->addr,
+ batadv_print_vid(tt_common->vid));
+
+ hlist_del_rcu(&tt_common->hash_entry);
+
+ /* An entry which still carries BATADV_TT_CLIENT_NEW was
+ * never counted and must not be uncounted here.
+ */
+ if (!(tt_common->flags & BATADV_TT_CLIENT_NEW))
+ batadv_tt_local_size_dec(bat_priv, tt_common->vid);
+ }
+
+ if (cont)
+ continue;
- batadv_tt_local_size_dec(bat_priv, tt_common->vid);
- hlist_del_rcu(&tt_common->hash_entry);
tt_local = container_of(tt_common,
struct batadv_tt_local_entry,
common);
@@ -3891,7 +4070,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
return;
}
- batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
+ batadv_tt_local_transition_new(bat_priv);
batadv_tt_local_purge_pending_clients(bat_priv);
batadv_tt_local_update_crc(bat_priv);
@@ -4061,15 +4240,16 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_global_entry *tt_global_entry;
- bool ret = false;
+ bool ret;
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (!tt_global_entry)
- goto out;
+ return false;
+
+ ret = batadv_tt_flags_get(&tt_global_entry->common) & BATADV_TT_CLIENT_ROAM;
- ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_global_entry_put(tt_global_entry);
-out:
+
return ret;
}
@@ -4087,15 +4267,16 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
+
+ ret = batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_ROAM;
- ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_local_entry_put(tt_local_entry);
-out:
+
return ret;
}
@@ -4404,7 +4585,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
if (!tt)
return false;
- ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
+ ret = batadv_tt_flags_get(&tt->common) & BATADV_TT_CLIENT_ISOLA;
batadv_tt_global_entry_put(tt);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 9bdc5a3e799e2..67872927cfb50 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -410,7 +410,7 @@ struct batadv_orig_bat_iv {
*/
struct batadv_orig_node {
/** @orig: originator ethernet address */
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @ifinfo_list: list for routers per outgoing interface */
struct hlist_head ifinfo_list;
@@ -634,12 +634,12 @@ struct batadv_hardif_neigh_node {
struct hlist_node list;
/** @addr: the MAC address of the neighboring interface */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/**
* @orig: the address of the originator this neighbor node belongs to
*/
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @if_incoming: pointer to incoming hard-interface */
struct batadv_hard_iface *if_incoming;
@@ -677,7 +677,7 @@ struct batadv_neigh_node {
#endif
/** @addr: the MAC address of the neighboring interface */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @ifinfo_list: list for routing metrics per outgoing interface */
struct hlist_head ifinfo_list;
@@ -777,7 +777,7 @@ struct batadv_neigh_ifinfo {
*/
struct batadv_bcast_duplist_entry {
/** @orig: mac address of orig node originating the broadcast */
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @crc: crc32 checksum of broadcast payload */
u32 crc;
@@ -1085,7 +1085,7 @@ struct batadv_priv_bla {
struct batadv_hashtable *backbone_hash;
/** @loopdetect_addr: MAC address used for own loopdetection frames */
- u8 loopdetect_addr[ETH_ALEN];
+ u8 loopdetect_addr[ETH_ALEN] __aligned(2);
/**
* @loopdetect_lasttime: time when the loopdetection frames were sent
@@ -1352,7 +1352,7 @@ struct batadv_tp_vars_common {
struct batadv_priv *bat_priv;
/** @other_end: mac address of remote */
- u8 other_end[ETH_ALEN];
+ u8 other_end[ETH_ALEN] __aligned(2);
/** @session: TP session identifier */
u8 session[2];
@@ -1765,7 +1765,7 @@ struct batadv_bla_backbone_gw {
* @orig: originator address of backbone node (mac address of primary
* iface)
*/
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @vid: vlan id this gateway was detected on */
unsigned short vid;
@@ -1810,7 +1810,7 @@ struct batadv_bla_backbone_gw {
*/
struct batadv_bla_claim {
/** @addr: mac address of claimed non-mesh client */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: vlan id this client was detected on */
unsigned short vid;
@@ -1840,7 +1840,7 @@ struct batadv_bla_claim {
*/
struct batadv_tt_common_entry {
/** @addr: mac address of non-mesh client */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: VLAN identifier */
unsigned short vid;
@@ -1851,12 +1851,21 @@ struct batadv_tt_common_entry {
*/
struct hlist_node hash_entry;
- /** @flags: various state handling flags (see batadv_tt_client_flags) */
+ /**
+ * @flags: various state handling flags (see batadv_tt_client_flags),
+ * protected by @flags_lock
+ */
u16 flags;
/** @added_at: timestamp used for purging stale tt common entries */
unsigned long added_at;
+ /**
+ * @flags_lock: protect modifications of @flags and
+ * @batadv_tt_global_entry.roam_at
+ */
+ spinlock_t flags_lock;
+
/** @refcount: number of contexts the object is used */
struct kref refcount;
@@ -1942,7 +1951,7 @@ struct batadv_tt_req_node {
/**
* @addr: mac address of the originator this request was sent to
*/
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @issued_at: timestamp used for purging stale tt requests */
unsigned long issued_at;
@@ -1959,7 +1968,7 @@ struct batadv_tt_req_node {
*/
struct batadv_tt_roam_node {
/** @addr: mac address of the client in the roaming phase */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: VLAN identifier */
u16 vid;
@@ -2087,14 +2096,14 @@ struct batadv_algo_neigh_ops {
struct batadv_hard_iface *if_outgoing2);
/**
- * @is_similar_or_better: check if neigh1 is equally similar or better
- * than neigh2 for their respective outgoing interface from the metric
+ * @is_similar_or_better: check if @candidate is equally similar or better
+ * than @reference for their respective outgoing interface from the metric
* prospective
*/
- bool (*is_similar_or_better)(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2);
+ bool (*is_similar_or_better)(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref);
/** @dump: dump neighbors to a netlink socket (optional) */
void (*dump)(struct sk_buff *msg, struct netlink_callback *cb,
@@ -2204,7 +2213,7 @@ struct batadv_hw_addr {
struct hlist_node list;
/** @addr: the MAC address of this list entry */
- unsigned char addr[ETH_ALEN];
+ unsigned char addr[ETH_ALEN] __aligned(2);
};
/**
|
| 3/2 | 2026/08/31 20:31 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 22623 output: 30 thoughts: 798 Thoughts: **Analyzing the Linux Kernel Patch for Fuzzing Potential** Okay, let's dive into this patch series for the Linux kernel and determine if it introduces functional changes that warrant fuzzing. First, I need to understand what's actually been modified. Let's start by looking at the changed files. * `net/batman-adv/bat_iv_ogm.c`: Looks like a straightforward parameter rename within the `batadv_iv_ogm_neigh_is_sob` function. Minor, unlikely to be fruitful for fuzzing on its own. * `net/batman-adv/bat_v.c`: Ah, a bug fix! The `batadv_v_neigh_is_sob` calculation had a logic inversion issue – the threshold was computed using one neighbor's throughput but compared against another. Fixing this is important, of course, but it's a specific correction. Still, worth noting as a potential area to examine with focused fuzzing if we know the throughput calculation. * `net/batman-adv/bridge_loop_avoidance.c`, `net/batman-adv/distributed-arp-table.c`, `net/batman-adv/mesh-interface.c`, `net/batman-adv/multicast.c`, and `net/batman-adv/types.h`: These all involve `__aligned(2)` annotations on MAC addresses or additions in a struct. These are likely related to memory alignment for performance or hardware compatibility. Probably not interesting for fuzzing in isolation, but keep it in mind if they are part of a larger change. * `net/batman-adv/translation-table.c`: Now *this* is interesting. Major locking and race condition fixes! A new `flags_lock` spinlock has been added to `struct batadv_tt_common_entry`, and a bunch of new functions are being introduced (`batadv_compare_tt_entry`, `batadv_tt_flags_get`, etc.) along with updates to numerous existing functions. This is a *significant* refactor potentially touching many areas where concurrent access and state changes are occurring. This screams potential for concurrency-related bugs and race conditions, a prime candidate for fuzzing. This is a very interesting section. Next, I need to check the Kconfig configuration options for BATMAN_ADV and any related settings. I need to figure out what functionality is enabled by these components. The easiest thing to do will be to use grepper or simply read Kconfig. I want to see how these patched components are controlled and whether there are any dependencies on other subsystems or features that could expand the attack surface. This will help determine the scope and relevance of these changes. |
| 4/2 | 2026/08/31 20:32 | tool | grepper |
0mArgs:{
"Expression": "BATMAN_ADV",
"PathPrefix": "net/batman-adv"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 679 lines.\nUse more precise expression if possible.\n\nnet/batman-adv/Kconfig-9-\nnet/batman-adv/Kconfig:10:config BATMAN_ADV\nnet/batman-adv/Kconfig-11-\ttristate \"B.A.T.M.A.N. Advanced Meshing Protocol\"\n--\nnet/batman-adv/Kconfig-19-\nnet/batman-adv/Kconfig:20:config BATMAN_ADV_BATMAN_V\nnet/batman-adv/Kconfig-21-\tbool \"B.A.T.M.A.N. V protocol\"\nnet/batman-adv/Kconfig:22:\tdepends on BATMAN_ADV \u0026\u0026 !(CFG80211=m \u0026\u0026 BATMAN_ADV=y)\nnet/batman-adv/Kconfig-23-\tdefault y\n--\nnet/batman-adv/Kconfig-33-\nnet/batman-adv/Kconfig:34:config BATMAN_ADV_BLA\nnet/batman-adv/Kconfig-35-\tbool \"Bridge Loop Avoidance\"\nnet/batman-adv/Kconfig:36:\tdepends on BATMAN_ADV \u0026\u0026 INET\nnet/batman-adv/Kconfig-37-\tselect CRC16\n--\nnet/batman-adv/Kconfig-46-\nnet/batman-adv/Kconfig:47:config BATMAN_ADV_DAT\nnet/batman-adv/Kconfig-48-\tbool \"Distributed ARP Table\"\nnet/batman-adv/Kconfig:49:\tdepends on BATMAN_ADV \u0026\u0026 INET\nnet/batman-adv/Kconfig-50-\tdefault y\n--\nnet/batman-adv/Kconfig-56-\nnet/batman-adv/Kconfig:57:config BATMAN_ADV_MCAST\nnet/batman-adv/Kconfig-58-\tbool \"Multicast optimisation\"\nnet/batman-adv/Kconfig:59:\tdepends on BATMAN_ADV \u0026\u0026 INET \u0026\u0026 !(BRIDGE=m \u0026\u0026 BATMAN_ADV=y)\nnet/batman-adv/Kconfig-60-\tdefault y\n--\nnet/batman-adv/Kconfig-65-\nnet/batman-adv/Kconfig:66:config BATMAN_ADV_DEBUG\nnet/batman-adv/Kconfig-67-\tbool \"B.A.T.M.A.N. debugging\"\nnet/batman-adv/Kconfig:68:\tdepends on BATMAN_ADV\nnet/batman-adv/Kconfig-69-\thelp\n--\nnet/batman-adv/Kconfig-74-\nnet/batman-adv/Kconfig:75:config BATMAN_ADV_TRACING\nnet/batman-adv/Kconfig-76-\tbool \"B.A.T.M.A.N. tracing support\"\nnet/batman-adv/Kconfig:77:\tdepends on BATMAN_ADV\nnet/batman-adv/Kconfig-78-\tdepends on EVENT_TRACING\n--\nnet/batman-adv/Kconfig-82-\t messages using the generic tracing infrastructure of the kernel.\nnet/batman-adv/Kconfig:83:\t BATMAN_ADV_DEBUG must also be selected to get trace events for\nnet/batman-adv/Kconfig-84-\t batadv_dbg.\n--\nnet/batman-adv/Makefile-5-\nnet/batman-adv/Makefile:6:obj-$(CONFIG_BATMAN_ADV) += batman-adv.o\nnet/batman-adv/Makefile-7-batman-adv-y += bat_algo.o\nnet/batman-adv/Makefile=8=batman-adv-y += bat_iv_ogm.o\nnet/batman-adv/Makefile:9:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o\nnet/batman-adv/Makefile:10:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o\nnet/batman-adv/Makefile:11:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_ogm.o\nnet/batman-adv/Makefile-12-batman-adv-y += bitarray.o\nnet/batman-adv/Makefile:13:batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o\nnet/batman-adv/Makefile:14:batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o\nnet/batman-adv/Makefile-15-batman-adv-y += fragmentation.o\n--\nnet/batman-adv/Makefile=19=batman-adv-y += hash.o\nnet/batman-adv/Makefile:20:batman-adv-$(CONFIG_BATMAN_ADV_DEBUG) += log.o\nnet/batman-adv/Makefile-21-batman-adv-y += main.o\nnet/batman-adv/Makefile=22=batman-adv-y += mesh-interface.o\nnet/batman-adv/Makefile:23:batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o\nnet/batman-adv/Makefile:24:batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast_forw.o\nnet/batman-adv/Makefile-25-batman-adv-y += netlink.o\n--\nnet/batman-adv/Makefile=28=batman-adv-y += send.o\nnet/batman-adv/Makefile:29:batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o\nnet/batman-adv/Makefile-30-batman-adv-y += tp_meter.o\n--\nnet/batman-adv/bat_algo.h-6-\nnet/batman-adv/bat_algo.h:7:#ifndef _NET_BATMAN_ADV_BAT_ALGO_H_\nnet/batman-adv/bat_algo.h:8:#define _NET_BATMAN_ADV_BAT_ALGO_H_\nnet/batman-adv/bat_algo.h-9-\n--\nnet/batman-adv/bat_algo.h=21=int batadv_algo_dump(struct sk_buff *msg, struct netlink_callback *cb);\nnet/batman-adv/bat_algo.h-22-\nnet/batman-adv/bat_algo.h:23:#endif /* _NET_BATMAN_ADV_BAT_ALGO_H_ */\n--\nnet/batman-adv/bat_iv_ogm.h-6-\nnet/batman-adv/bat_iv_ogm.h:7:#ifndef _NET_BATMAN_ADV_BAT_IV_OGM_H_\nnet/batman-adv/bat_iv_ogm.h:8:#define _NET_BATMAN_ADV_BAT_IV_OGM_H_\nnet/batman-adv/bat_iv_ogm.h-9-\n--\nnet/batman-adv/bat_iv_ogm.h=13=void batadv_iv_deinit(void);\nnet/batman-adv/bat_iv_ogm.h-14-\nnet/batman-adv/bat_iv_ogm.h:15:#endif /* _NET_BATMAN_ADV_BAT_IV_OGM_H_ */\n--\nnet/batman-adv/bat_v.h-6-\nnet/batman-adv/bat_v.h:7:#ifndef _NET_BATMAN_ADV_BAT_V_H_\nnet/batman-adv/bat_v.h:8:#define _NET_BATMAN_ADV_BAT_V_H_\nnet/batman-adv/bat_v.h-9-\n--\nnet/batman-adv/bat_v.h-11-\nnet/batman-adv/bat_v.h:12:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/bat_v.h-13-\n--\nnet/batman-adv/bat_v.h=40=static inline void batadv_v_mesh_free(struct batadv_priv *bat_priv)\n--\nnet/batman-adv/bat_v.h-43-\nnet/batman-adv/bat_v.h:44:#endif /* CONFIG_BATMAN_ADV_BATMAN_V */\nnet/batman-adv/bat_v.h-45-\nnet/batman-adv/bat_v.h:46:#endif /* _NET_BATMAN_ADV_BAT_V_H_ */\n--\nnet/batman-adv/bat_v_elp.h-6-\nnet/batman-adv/bat_v_elp.h:7:#ifndef _NET_BATMAN_ADV_BAT_V_ELP_H_\nnet/batman-adv/bat_v_elp.h:8:#define _NET_BATMAN_ADV_BAT_V_ELP_H_\nnet/batman-adv/bat_v_elp.h-9-\n--\nnet/batman-adv/bat_v_elp.h=19=int batadv_v_elp_packet_recv(struct sk_buff *skb,\n--\nnet/batman-adv/bat_v_elp.h-21-\nnet/batman-adv/bat_v_elp.h:22:#endif /* _NET_BATMAN_ADV_BAT_V_ELP_H_ */\n--\nnet/batman-adv/bat_v_ogm.h-6-\nnet/batman-adv/bat_v_ogm.h:7:#ifndef _NET_BATMAN_ADV_BAT_V_OGM_H_\nnet/batman-adv/bat_v_ogm.h:8:#define _NET_BATMAN_ADV_BAT_V_OGM_H_\nnet/batman-adv/bat_v_ogm.h-9-\n--\nnet/batman-adv/bat_v_ogm.h=24=int batadv_v_ogm_packet_recv(struct sk_buff *skb,\n--\nnet/batman-adv/bat_v_ogm.h-26-\nnet/batman-adv/bat_v_ogm.h:27:#endif /* _NET_BATMAN_ADV_BAT_V_OGM_H_ */\n--\nnet/batman-adv/bitarray.h-6-\nnet/batman-adv/bitarray.h:7:#ifndef _NET_BATMAN_ADV_BITARRAY_H_\nnet/batman-adv/bitarray.h:8:#define _NET_BATMAN_ADV_BITARRAY_H_\nnet/batman-adv/bitarray.h-9-\n--\nnet/batman-adv/bitarray.h=53=bool batadv_bit_get_packet(void *priv, unsigned long *seq_bits,\n--\nnet/batman-adv/bitarray.h-55-\nnet/batman-adv/bitarray.h:56:#endif /* _NET_BATMAN_ADV_BITARRAY_H_ */\n--\nnet/batman-adv/bridge_loop_avoidance.c=2464=int batadv_bla_backbone_dump(struct sk_buff *msg, struct netlink_callback *cb)\n--\nnet/batman-adv/bridge_loop_avoidance.c-2507-\nnet/batman-adv/bridge_loop_avoidance.c:2508:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/bridge_loop_avoidance.c-2509-/**\n--\nnet/batman-adv/bridge_loop_avoidance.h-6-\nnet/batman-adv/bridge_loop_avoidance.h:7:#ifndef _NET_BATMAN_ADV_BLA_H_\nnet/batman-adv/bridge_loop_avoidance.h:8:#define _NET_BATMAN_ADV_BLA_H_\nnet/batman-adv/bridge_loop_avoidance.h-9-\n--\nnet/batman-adv/bridge_loop_avoidance.h=27=static inline bool batadv_bla_is_loopdetect_mac(const uint8_t *mac)\n--\nnet/batman-adv/bridge_loop_avoidance.h-34-\nnet/batman-adv/bridge_loop_avoidance.h:35:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/bridge_loop_avoidance.h-36-bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/bridge_loop_avoidance.h=54=void batadv_bla_free(struct batadv_priv *bat_priv);\nnet/batman-adv/bridge_loop_avoidance.h:55:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/bridge_loop_avoidance.h-56-bool batadv_bla_check_claim(struct batadv_priv *bat_priv, u8 *addr,\n--\nnet/batman-adv/bridge_loop_avoidance.h-59-#define BATADV_BLA_CRC_INIT\t0\nnet/batman-adv/bridge_loop_avoidance.h:60:#else /* ifdef CONFIG_BATMAN_ADV_BLA */\nnet/batman-adv/bridge_loop_avoidance.h-61-\n--\nnet/batman-adv/bridge_loop_avoidance.h=124=bool batadv_bla_check_claim(struct batadv_priv *bat_priv, u8 *addr,\n--\nnet/batman-adv/bridge_loop_avoidance.h-129-\nnet/batman-adv/bridge_loop_avoidance.h:130:#endif /* ifdef CONFIG_BATMAN_ADV_BLA */\nnet/batman-adv/bridge_loop_avoidance.h-131-\nnet/batman-adv/bridge_loop_avoidance.h:132:#endif /* ifndef _NET_BATMAN_ADV_BLA_H_ */\n--\nnet/batman-adv/distributed-arp-table.c=444=static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,\n--\nnet/batman-adv/distributed-arp-table.c-491-\nnet/batman-adv/distributed-arp-table.c:492:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/distributed-arp-table.c-493-\n--\nnet/batman-adv/distributed-arp-table.c=570=static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/distributed-arp-table.c-574-\nnet/batman-adv/distributed-arp-table.c:575:#endif /* CONFIG_BATMAN_ADV_DEBUG */\nnet/batman-adv/distributed-arp-table.c-576-\n--\nnet/batman-adv/distributed-arp-table.h-6-\nnet/batman-adv/distributed-arp-table.h:7:#ifndef _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_\nnet/batman-adv/distributed-arp-table.h:8:#define _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_\nnet/batman-adv/distributed-arp-table.h-9-\n--\nnet/batman-adv/distributed-arp-table.h-20-\nnet/batman-adv/distributed-arp-table.h:21:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/distributed-arp-table.h-22-\n--\nnet/batman-adv/distributed-arp-table.h=179=static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.h-183-\nnet/batman-adv/distributed-arp-table.h:184:#endif /* CONFIG_BATMAN_ADV_DAT */\nnet/batman-adv/distributed-arp-table.h-185-\nnet/batman-adv/distributed-arp-table.h:186:#endif /* _NET_BATMAN_ADV_DISTRIBUTED_ARP_TABLE_H_ */\n--\nnet/batman-adv/fragmentation.h-6-\nnet/batman-adv/fragmentation.h:7:#ifndef _NET_BATMAN_ADV_FRAGMENTATION_H_\nnet/batman-adv/fragmentation.h:8:#define _NET_BATMAN_ADV_FRAGMENTATION_H_\nnet/batman-adv/fragmentation.h-9-\n--\nnet/batman-adv/fragmentation.h=37=batadv_frag_check_entry(struct batadv_frag_table_entry *frags_entry)\n--\nnet/batman-adv/fragmentation.h-44-\nnet/batman-adv/fragmentation.h:45:#endif /* _NET_BATMAN_ADV_FRAGMENTATION_H_ */\n--\nnet/batman-adv/gateway_client.h-6-\nnet/batman-adv/gateway_client.h:7:#ifndef _NET_BATMAN_ADV_GATEWAY_CLIENT_H_\nnet/batman-adv/gateway_client.h:8:#define _NET_BATMAN_ADV_GATEWAY_CLIENT_H_\nnet/batman-adv/gateway_client.h-9-\n--\nnet/batman-adv/gateway_client.h=47=static inline void batadv_gw_node_put(struct batadv_gw_node *gw_node)\n--\nnet/batman-adv/gateway_client.h-54-\nnet/batman-adv/gateway_client.h:55:#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */\n--\nnet/batman-adv/gateway_common.h-6-\nnet/batman-adv/gateway_common.h:7:#ifndef _NET_BATMAN_ADV_GATEWAY_COMMON_H_\nnet/batman-adv/gateway_common.h:8:#define _NET_BATMAN_ADV_GATEWAY_COMMON_H_\nnet/batman-adv/gateway_common.h-9-\n--\nnet/batman-adv/gateway_common.h=29=void batadv_gw_free(struct batadv_priv *bat_priv);\nnet/batman-adv/gateway_common.h-30-\nnet/batman-adv/gateway_common.h:31:#endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */\n--\nnet/batman-adv/hard-interface.h-6-\nnet/batman-adv/hard-interface.h:7:#ifndef _NET_BATMAN_ADV_HARD_INTERFACE_H_\nnet/batman-adv/hard-interface.h:8:#define _NET_BATMAN_ADV_HARD_INTERFACE_H_\nnet/batman-adv/hard-interface.h-9-\n--\nnet/batman-adv/hard-interface.h=144=static inline bool batadv_is_wifi(u32 wifi_flags)\n--\nnet/batman-adv/hard-interface.h-148-\nnet/batman-adv/hard-interface.h:149:#endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */\n--\nnet/batman-adv/hash.h-6-\nnet/batman-adv/hash.h:7:#ifndef _NET_BATMAN_ADV_HASH_H_\nnet/batman-adv/hash.h:8:#define _NET_BATMAN_ADV_HASH_H_\nnet/batman-adv/hash.h-9-\n--\nnet/batman-adv/hash.h=143=static inline void *batadv_hash_remove(struct batadv_hashtable *hash,\n--\nnet/batman-adv/hash.h-170-\nnet/batman-adv/hash.h:171:#endif /* _NET_BATMAN_ADV_HASH_H_ */\n--\nnet/batman-adv/log.h-6-\nnet/batman-adv/log.h:7:#ifndef _NET_BATMAN_ADV_LOG_H_\nnet/batman-adv/log.h:8:#define _NET_BATMAN_ADV_LOG_H_\nnet/batman-adv/log.h-9-\n--\nnet/batman-adv/log.h-16-\nnet/batman-adv/log.h:17:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/log.h-18-\n--\nnet/batman-adv/log.h=38=enum batadv_dbg_level {\n--\nnet/batman-adv/log.h-63-\nnet/batman-adv/log.h:64:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/log.h-65-int batadv_debug_log(struct batadv_priv *bat_priv, const char *fmt, ...)\nnet/batman-adv/log.h=66=__printf(2, 3);\n--\nnet/batman-adv/log.h-83-\twhile (0)\nnet/batman-adv/log.h:84:#else /* !CONFIG_BATMAN_ADV_DEBUG */\nnet/batman-adv/log.h-85-__printf(4, 5)\nnet/batman-adv/log.h=86=static inline void _batadv_dbg(int type __always_unused,\n--\nnet/batman-adv/log.h-147-\nnet/batman-adv/log.h:148:#endif /* _NET_BATMAN_ADV_LOG_H_ */\n--\nnet/batman-adv/main.c=189=int batadv_mesh_init(struct net_device *mesh_iface)\n--\nnet/batman-adv/main.c-201-\tspin_lock_init(\u0026bat_priv-\u003egw.list_lock);\nnet/batman-adv/main.c:202:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/main.c-203-\tspin_lock_init(\u0026bat_priv-\u003emcast.mla_lock);\n--\nnet/batman-adv/main.c-213-\tINIT_HLIST_HEAD(\u0026bat_priv-\u003egw.gateway_list);\nnet/batman-adv/main.c:214:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/main.c-215-\tINIT_HLIST_HEAD(\u0026bat_priv-\u003emcast.want_all_unsnoopables_list);\n--\nnet/batman-adv/main.c-221-\tINIT_LIST_HEAD(\u0026bat_priv-\u003ett.roam_list);\nnet/batman-adv/main.c:222:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/main.c-223-\tINIT_HLIST_HEAD(\u0026bat_priv-\u003emcast.mla_list);\n--\nnet/batman-adv/main.h-6-\nnet/batman-adv/main.h:7:#ifndef _NET_BATMAN_ADV_MAIN_H_\nnet/batman-adv/main.h:8:#define _NET_BATMAN_ADV_MAIN_H_\nnet/batman-adv/main.h-9-\n--\nnet/batman-adv/main.h=370=int batadv_throw_uevent(struct batadv_priv *bat_priv, enum batadv_uev_type type,\n--\nnet/batman-adv/main.h-372-\nnet/batman-adv/main.h:373:#endif /* _NET_BATMAN_ADV_MAIN_H_ */\n--\nnet/batman-adv/mesh-interface.c=795=static int batadv_meshif_init_late(struct net_device *dev)\n--\nnet/batman-adv/mesh-interface.c-815-\tWRITE_ONCE(bat_priv-\u003ebonding, 0);\nnet/batman-adv/mesh-interface.c:816:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/mesh-interface.c-817-\tWRITE_ONCE(bat_priv-\u003ebridge_loop_avoidance, 1);\nnet/batman-adv/mesh-interface.c-818-#endif\nnet/batman-adv/mesh-interface.c:819:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/mesh-interface.c-820-\tWRITE_ONCE(bat_priv-\u003edistributed_arp_table, 1);\nnet/batman-adv/mesh-interface.c-821-#endif\nnet/batman-adv/mesh-interface.c:822:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/mesh-interface.c-823-\tWRITE_ONCE(bat_priv-\u003emulticast_mode, 1);\n--\nnet/batman-adv/mesh-interface.c-834-\tWRITE_ONCE(bat_priv-\u003ehop_penalty, 30);\nnet/batman-adv/mesh-interface.c:835:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/mesh-interface.c-836-\tWRITE_ONCE(bat_priv-\u003elog_level, 0);\n--\nnet/batman-adv/mesh-interface.c-846-\tatomic_set(\u0026bat_priv-\u003ett.ogm_append_cnt, 0);\nnet/batman-adv/mesh-interface.c:847:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/mesh-interface.c-848-\tatomic_set(\u0026bat_priv-\u003ebla.num_requests, 0);\n--\nnet/batman-adv/mesh-interface.c=957=static const struct {\n--\nnet/batman-adv/mesh-interface.c-982-\t{ \"tt_roam_adv_rx\" },\nnet/batman-adv/mesh-interface.c:983:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/mesh-interface.c-984-\t{ \"mcast_tx\" },\n--\nnet/batman-adv/mesh-interface.c-994-#endif\nnet/batman-adv/mesh-interface.c:995:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/mesh-interface.c-996-\t{ \"dat_get_tx\" },\n--\nnet/batman-adv/mesh-interface.h-6-\nnet/batman-adv/mesh-interface.h:7:#ifndef _NET_BATMAN_ADV_MESH_INTERFACE_H_\nnet/batman-adv/mesh-interface.h:8:#define _NET_BATMAN_ADV_MESH_INTERFACE_H_\nnet/batman-adv/mesh-interface.h-9-\n--\nnet/batman-adv/mesh-interface.h=35=static inline void batadv_meshif_vlan_put(struct batadv_meshif_vlan *vlan)\n--\nnet/batman-adv/mesh-interface.h-42-\nnet/batman-adv/mesh-interface.h:43:#endif /* _NET_BATMAN_ADV_MESH_INTERFACE_H_ */\n--\nnet/batman-adv/multicast.h-6-\nnet/batman-adv/multicast.h:7:#ifndef _NET_BATMAN_ADV_MULTICAST_H_\nnet/batman-adv/multicast.h:8:#define _NET_BATMAN_ADV_MULTICAST_H_\nnet/batman-adv/multicast.h-9-\n--\nnet/batman-adv/multicast.h=19=enum batadv_forw_mode {\n--\nnet/batman-adv/multicast.h-41-\nnet/batman-adv/multicast.h:42:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/multicast.h-43-\n--\nnet/batman-adv/multicast.h=116=static inline int batadv_mcast_forw_mcsend(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.h-122-\nnet/batman-adv/multicast.h:123:#endif /* CONFIG_BATMAN_ADV_MCAST */\nnet/batman-adv/multicast.h-124-\nnet/batman-adv/multicast.h:125:#endif /* _NET_BATMAN_ADV_MULTICAST_H_ */\n--\nnet/batman-adv/netlink.c=230=static int batadv_netlink_mesh_fill(struct sk_buff *msg,\n--\nnet/batman-adv/netlink.c-254-\nnet/batman-adv/netlink.c:255:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/netlink.c-256-\tif (nla_put_u16(msg, BATADV_ATTR_BLA_CRC,\n--\nnet/batman-adv/netlink.c-295-\nnet/batman-adv/netlink.c:296:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/netlink.c-297-\tif (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED,\n--\nnet/batman-adv/netlink.c-299-\t\tgoto nla_put_failure;\nnet/batman-adv/netlink.c:300:#endif /* CONFIG_BATMAN_ADV_BLA */\nnet/batman-adv/netlink.c-301-\nnet/batman-adv/netlink.c:302:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/netlink.c-303-\tif (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED,\n--\nnet/batman-adv/netlink.c-305-\t\tgoto nla_put_failure;\nnet/batman-adv/netlink.c:306:#endif /* CONFIG_BATMAN_ADV_DAT */\nnet/batman-adv/netlink.c-307-\n--\nnet/batman-adv/netlink.c-337-\nnet/batman-adv/netlink.c:338:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/netlink.c-339-\tif (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL,\n--\nnet/batman-adv/netlink.c-341-\t\tgoto nla_put_failure;\nnet/batman-adv/netlink.c:342:#endif /* CONFIG_BATMAN_ADV_DEBUG */\nnet/batman-adv/netlink.c-343-\nnet/batman-adv/netlink.c:344:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/netlink.c-345-\tif (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED,\n--\nnet/batman-adv/netlink.c-351-\t\tgoto nla_put_failure;\nnet/batman-adv/netlink.c:352:#endif /* CONFIG_BATMAN_ADV_MCAST */\nnet/batman-adv/netlink.c-353-\n--\nnet/batman-adv/netlink.c=435=static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)\n--\nnet/batman-adv/netlink.c-469-\nnet/batman-adv/netlink.c:470:#ifdef CONFIG_BATMAN_ADV_BLA\nnet/batman-adv/netlink.c-471-\tif (info-\u003eattrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]) {\n--\nnet/batman-adv/netlink.c-477-\t}\nnet/batman-adv/netlink.c:478:#endif /* CONFIG_BATMAN_ADV_BLA */\nnet/batman-adv/netlink.c-479-\nnet/batman-adv/netlink.c:480:#ifdef CONFIG_BATMAN_ADV_DAT\nnet/batman-adv/netlink.c-481-\tif (info-\u003eattrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]) {\n--\nnet/batman-adv/netlink.c-487-\t}\nnet/batman-adv/netlink.c:488:#endif /* CONFIG_BATMAN_ADV_DAT */\nnet/batman-adv/netlink.c-489-\n--\nnet/batman-adv/netlink.c-567-\nnet/batman-adv/netlink.c:568:#ifdef CONFIG_BATMAN_ADV_DEBUG\nnet/batman-adv/netlink.c-569-\tif (info-\u003eattrs[BATADV_ATTR_LOG_LEVEL]) {\n--\nnet/batman-adv/netlink.c-574-\t}\nnet/batman-adv/netlink.c:575:#endif /* CONFIG_BATMAN_ADV_DEBUG */\nnet/batman-adv/netlink.c-576-\nnet/batman-adv/netlink.c:577:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/netlink.c-578-\tif (info-\u003eattrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]) {\n--\nnet/batman-adv/netlink.c-588-\t}\nnet/batman-adv/netlink.c:589:#endif /* CONFIG_BATMAN_ADV_MCAST */\nnet/batman-adv/netlink.c-590-\n--\nnet/batman-adv/netlink.c=781=static int batadv_netlink_hardif_fill(struct sk_buff *msg,\n--\nnet/batman-adv/netlink.c-822-\nnet/batman-adv/netlink.c:823:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/netlink.c-824-\tif (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL,\n--\nnet/batman-adv/netlink.c-830-\t\tgoto nla_put_failure;\nnet/batman-adv/netlink.c:831:#endif /* CONFIG_BATMAN_ADV_BATMAN_V */\nnet/batman-adv/netlink.c-832-\n--\nnet/batman-adv/netlink.c=912=static int batadv_netlink_set_hardif(struct sk_buff *skb,\n--\nnet/batman-adv/netlink.c-924-\nnet/batman-adv/netlink.c:925:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/netlink.c-926-\n--\nnet/batman-adv/netlink.c-944-\t}\nnet/batman-adv/netlink.c:945:#endif /* CONFIG_BATMAN_ADV_BATMAN_V */\nnet/batman-adv/netlink.c-946-\n--\nnet/batman-adv/netlink.h-6-\nnet/batman-adv/netlink.h:7:#ifndef _NET_BATMAN_ADV_NETLINK_H_\nnet/batman-adv/netlink.h:8:#define _NET_BATMAN_ADV_NETLINK_H_\nnet/batman-adv/netlink.h-9-\n--\nnet/batman-adv/netlink.h=26=extern struct genl_family batadv_netlink_family;\nnet/batman-adv/netlink.h-27-\nnet/batman-adv/netlink.h:28:#endif /* _NET_BATMAN_ADV_NETLINK_H_ */\n--\nnet/batman-adv/originator.c=672=batadv_neigh_node_create(struct batadv_orig_node *orig_node,\n--\nnet/batman-adv/originator.c-702-\nnet/batman-adv/originator.c:703:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/originator.c-704-\tACCESS_PRIVATE(neigh_node, orig_node_id) = orig_node;\n--\nnet/batman-adv/originator.c=947=struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/originator.c-983-\nnet/batman-adv/originator.c:984:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/originator.c-985-\torig_node-\u003emcast_flags = BATADV_MCAST_WANT_NO_RTR4;\n--\nnet/batman-adv/originator.h-6-\nnet/batman-adv/originator.h:7:#ifndef _NET_BATMAN_ADV_ORIGINATOR_H_\nnet/batman-adv/originator.h:8:#define _NET_BATMAN_ADV_ORIGINATOR_H_\nnet/batman-adv/originator.h-9-\n--\nnet/batman-adv/originator.h=162=static inline void batadv_orig_node_put(struct batadv_orig_node *orig_node)\n--\nnet/batman-adv/originator.h-169-\nnet/batman-adv/originator.h:170:#endif /* _NET_BATMAN_ADV_ORIGINATOR_H_ */\n--\nnet/batman-adv/routing.c=1263=int batadv_recv_bcast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-1377-\nnet/batman-adv/routing.c:1378:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/routing.c-1379-/**\n--\nnet/batman-adv/routing.c=1392=int batadv_recv_mcast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-1453-}\nnet/batman-adv/routing.c:1454:#endif /* CONFIG_BATMAN_ADV_MCAST */\n--\nnet/batman-adv/routing.h-6-\nnet/batman-adv/routing.h:7:#ifndef _NET_BATMAN_ADV_ROUTING_H_\nnet/batman-adv/routing.h:8:#define _NET_BATMAN_ADV_ROUTING_H_\nnet/batman-adv/routing.h-9-\n--\nnet/batman-adv/routing.h=28=int batadv_recv_bcast_packet(struct sk_buff *skb,\nnet/batman-adv/routing.h-29-\t\t\t struct batadv_hard_iface *recv_if);\nnet/batman-adv/routing.h:30:#ifdef CONFIG_BATMAN_ADV_MCAST\nnet/batman-adv/routing.h-31-int batadv_recv_mcast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.h=49=bool batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff,\n--\nnet/batman-adv/routing.h-52-\nnet/batman-adv/routing.h:53:#endif /* _NET_BATMAN_ADV_ROUTING_H_ */\n--\nnet/batman-adv/send.c=133=int batadv_send_unicast_skb(struct sk_buff *skb,\n--\nnet/batman-adv/send.c-135-{\nnet/batman-adv/send.c:136:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/send.c-137-\tstruct batadv_hardif_neigh_node *hardif_neigh;\n--\nnet/batman-adv/send.c-142-\nnet/batman-adv/send.c:143:#ifdef CONFIG_BATMAN_ADV_BATMAN_V\nnet/batman-adv/send.c-144-\thardif_neigh = batadv_hardif_neigh_get(neigh-\u003eif_incoming, neigh-\u003eaddr);\n--\nnet/batman-adv/send.h-6-\nnet/batman-adv/send.h:7:#ifndef _NET_BATMAN_ADV_SEND_H_\n\n"
} |
| 5/2 | 2026/08/31 20:32 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 34283 output: 35 thoughts: 646 Thoughts: **Analyzing the Latest B.A.T.M.A.N. Advanced Patch** Okay, let's break this down. First, the core of the work seems to be in `net/batman-adv/translation-table.c`. It's a significant fix-up around concurrency issues and potential race conditions within the B.A.T.M.A.N. translation table. Specifically, a `flags_lock` was introduced within `batadv_tt_common_entry` to guard access to the `flags` field and `roam_at`. This is crucial because `flags` controls things like `BATADV_TT_CLIENT_NEW`, `BATADV_TT_CLIENT_PENDING`, and so on. Concurrent access to these flags is a classic source of problems, so this lock is a smart move. There's also a bug fix in how the local hash table entries are removed; it was matching based on address and VID instead of the correct pointer comparison. The code in `batadv_tt_local_remove`, `batadv_tt_local_purge_pending_clients`, and others has also been cleaned up. Then, moving on to `net/batman-adv/bat_v.c`, there's a correction to the `batadv_v_neigh_is_sob` calculation. It appears the logic for determining if a neighbor is suitable (having better throughput) was inverted or flawed in some way. Finally, in `net/batman-adv/distributed-arp-table.c`, there's a minor correction in `batadv_dbg_arp` with the subtype of the packet. I also see several instances of `__aligned(2)` annotations on MAC addresses. That's a good practice to avoid unaligned memory access issues during casting or copying Ethernet addresses. The question then becomes, is this code even reachable in a testing environment like QEMU or using fuzzing? The answer is yes. B.A.T.M.A.N. Advanced is a module in the Linux kernel that operates over virtual interfaces or raw netlink, and it is frequently fuzzed, thus reachable. Now, should we consider it worthy of intense fuzzing? Definitely. This patch alters execution flow, including core routing and translation table logic. We've got the introduction of concurrency locking, potentially inverting of logic in `batadv_v_neigh_is_sob` and a hash removal bug fix, as well as several fixes to local table size counting and transition logic. So, the next step is to nail down the entry points and the relevant configurations. Time to check `net/batman-adv/Kconfig`. |
| 6/2 | 2026/08/31 20:32 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/Kconfig",
"FirstLine": 1,
"LineCount": 85
}Results: {
"Contents": " 1:\t# SPDX-License-Identifier: GPL-2.0\n 2:\t# Copyright (C) B.A.T.M.A.N. contributors:\n 3:\t#\n 4:\t# Marek Lindner, Simon Wunderlich\n 5:\t\n 6:\t#\n 7:\t# B.A.T.M.A.N meshing protocol\n 8:\t#\n 9:\t\n 10:\tconfig BATMAN_ADV\n 11:\t\ttristate \"B.A.T.M.A.N. Advanced Meshing Protocol\"\n 12:\t\tselect CRC32\n 13:\t\thelp\n 14:\t\t B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is\n 15:\t\t a routing protocol for multi-hop ad-hoc mesh networks. The\n 16:\t\t networks may be wired or wireless. See\n 17:\t\t https://www.open-mesh.org/ for more information and user space\n 18:\t\t tools.\n 19:\t\n 20:\tconfig BATMAN_ADV_BATMAN_V\n 21:\t\tbool \"B.A.T.M.A.N. V protocol\"\n 22:\t\tdepends on BATMAN_ADV \u0026\u0026 !(CFG80211=m \u0026\u0026 BATMAN_ADV=y)\n 23:\t\tdefault y\n 24:\t\thelp\n 25:\t\t This option enables the B.A.T.M.A.N. V protocol, the successor\n 26:\t\t of the currently used B.A.T.M.A.N. IV protocol. The main\n 27:\t\t changes include splitting of the OGM protocol into a neighbor\n 28:\t\t discovery protocol (Echo Location Protocol, ELP) and a new OGM\n 29:\t\t Protocol OGMv2 for flooding protocol information through the\n 30:\t\t network, as well as a throughput based metric.\n 31:\t\t B.A.T.M.A.N. V is currently considered experimental and not\n 32:\t\t compatible to B.A.T.M.A.N. IV networks.\n 33:\t\n 34:\tconfig BATMAN_ADV_BLA\n 35:\t\tbool \"Bridge Loop Avoidance\"\n 36:\t\tdepends on BATMAN_ADV \u0026\u0026 INET\n 37:\t\tselect CRC16\n 38:\t\tselect NET_CRC32C\n 39:\t\tdefault y\n 40:\t\thelp\n 41:\t\t This option enables BLA (Bridge Loop Avoidance), a mechanism\n 42:\t\t to avoid Ethernet frames looping when mesh nodes are connected\n 43:\t\t to both the same LAN and the same mesh. If you will never use\n 44:\t\t more than one mesh node in the same LAN, you can safely remove\n 45:\t\t this feature and save some space.\n 46:\t\n 47:\tconfig BATMAN_ADV_DAT\n 48:\t\tbool \"Distributed ARP Table\"\n 49:\t\tdepends on BATMAN_ADV \u0026\u0026 INET\n 50:\t\tdefault y\n 51:\t\thelp\n 52:\t\t This option enables DAT (Distributed ARP Table), a DHT based\n 53:\t\t mechanism that increases ARP reliability on sparse wireless\n 54:\t\t mesh networks. If you think that your network does not need\n 55:\t\t this option you can safely remove it and save some space.\n 56:\t\n 57:\tconfig BATMAN_ADV_MCAST\n 58:\t\tbool \"Multicast optimisation\"\n 59:\t\tdepends on BATMAN_ADV \u0026\u0026 INET \u0026\u0026 !(BRIDGE=m \u0026\u0026 BATMAN_ADV=y)\n 60:\t\tdefault y\n 61:\t\thelp\n 62:\t\t This option enables the multicast optimisation which aims to\n 63:\t\t reduce the air overhead while improving the reliability of\n 64:\t\t multicast messages.\n 65:\t\n 66:\tconfig BATMAN_ADV_DEBUG\n 67:\t\tbool \"B.A.T.M.A.N. debugging\"\n 68:\t\tdepends on BATMAN_ADV\n 69:\t\thelp\n 70:\t\t This is an option for use by developers; most people should\n 71:\t\t say N here. This enables compilation of support for\n 72:\t\t outputting debugging information to the tracing buffer. The output is\n 73:\t\t controlled via the batadv netdev specific log_level setting.\n 74:\t\n 75:\tconfig BATMAN_ADV_TRACING\n 76:\t\tbool \"B.A.T.M.A.N. tracing support\"\n 77:\t\tdepends on BATMAN_ADV\n 78:\t\tdepends on EVENT_TRACING\n 79:\t\thelp\n 80:\t\t This is an option for use by developers; most people should\n 81:\t\t say N here. Select this option to gather traces like the debug\n 82:\t\t messages using the generic tracing infrastructure of the kernel.\n 83:\t\t BATMAN_ADV_DEBUG must also be selected to get trace events for\n 84:\t\t batadv_dbg.\n"
} |
| 7/2 | 2026/08/31 20:32 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 36805 output: 28 thoughts: 22 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Kconfig Dependency Deep Dive** Okay, so I need to figure out the inclusion and dependencies of `BATMAN_ADV`. Time to go straight to the source – the parent `Kconfig` file. I'm thinking I'll trace the path to see the exact context in which `BATMAN_ADV` is brought into the build configuration. What are the gating options? Are there any specific hardware or kernel feature dependencies I need to be aware of? Are there any conflicting configurations that might prevent it from being enabled in certain scenarios? Understanding the full picture of its dependencies will be crucial for debugging or customizing its behavior later on. This is where the fun begins. Let's see what the `Kconfig` files reveal. |
| 8/2 | 2026/08/31 20:32 | tool | grepper |
0mError:no matches Args: {
"Expression": "BATMAN_ADV",
"PathPrefix": "net/Kconfig"
}Results: {
"error": "no matches"
} |
| 9/2 | 2026/08/31 20:32 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 37036 output: 25 thoughts: 25 Thoughts: Here's my take on the thought process, as if it were my own: **Navigating the Configuration Landscape** Okay, so I need to figure out where a specific network configuration option resides. My first instinct, given my experience with the Linux kernel's networking subsystem, is to start with the foundational `net/Kconfig` file. That's usually the jumping-off point for anything network-related. If it's not immediately obvious there, or if I suspect this option might be part of an add-on or a more specialized part of networking I'll need to go deeper. So, I need to check either `net/Kconfig` or, since it's a possibility, that I am dealing with something in batman-adv, I'll go for the specific `source "net/batman-adv/Kconfig"` file and investigate it thoroughly. I am pretty confident I'll find my answer in one of those two locations. |
| 10/2 | 2026/08/31 20:32 | tool | grepper |
0mArgs:{
"Expression": "batman-adv",
"PathPrefix": "net"
}Results: {
"Output": "\nFull output is too long, showing 500 out of 571 lines.\nUse more precise expression if possible.\n\nnet/Kconfig=272=source \"net/dns_resolver/Kconfig\"\nnet/Kconfig:273:source \"net/batman-adv/Kconfig\"\nnet/Kconfig-274-source \"net/openvswitch/Kconfig\"\n--\nnet/Makefile=59=obj-$(CONFIG_CEPH_LIB)\t\t+= ceph/\nnet/Makefile:60:obj-$(CONFIG_BATMAN_ADV)\t+= batman-adv/\nnet/Makefile-61-obj-$(CONFIG_NFC)\t\t+= nfc/\n--\nnet/batman-adv/Makefile-5-\nnet/batman-adv/Makefile:6:obj-$(CONFIG_BATMAN_ADV) += batman-adv.o\nnet/batman-adv/Makefile:7:batman-adv-y += bat_algo.o\nnet/batman-adv/Makefile:8:batman-adv-y += bat_iv_ogm.o\nnet/batman-adv/Makefile:9:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v.o\nnet/batman-adv/Makefile:10:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_elp.o\nnet/batman-adv/Makefile:11:batman-adv-$(CONFIG_BATMAN_ADV_BATMAN_V) += bat_v_ogm.o\nnet/batman-adv/Makefile:12:batman-adv-y += bitarray.o\nnet/batman-adv/Makefile:13:batman-adv-$(CONFIG_BATMAN_ADV_BLA) += bridge_loop_avoidance.o\nnet/batman-adv/Makefile:14:batman-adv-$(CONFIG_BATMAN_ADV_DAT) += distributed-arp-table.o\nnet/batman-adv/Makefile:15:batman-adv-y += fragmentation.o\nnet/batman-adv/Makefile:16:batman-adv-y += gateway_client.o\nnet/batman-adv/Makefile:17:batman-adv-y += gateway_common.o\nnet/batman-adv/Makefile:18:batman-adv-y += hard-interface.o\nnet/batman-adv/Makefile:19:batman-adv-y += hash.o\nnet/batman-adv/Makefile:20:batman-adv-$(CONFIG_BATMAN_ADV_DEBUG) += log.o\nnet/batman-adv/Makefile:21:batman-adv-y += main.o\nnet/batman-adv/Makefile:22:batman-adv-y += mesh-interface.o\nnet/batman-adv/Makefile:23:batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast.o\nnet/batman-adv/Makefile:24:batman-adv-$(CONFIG_BATMAN_ADV_MCAST) += multicast_forw.o\nnet/batman-adv/Makefile:25:batman-adv-y += netlink.o\nnet/batman-adv/Makefile:26:batman-adv-y += originator.o\nnet/batman-adv/Makefile:27:batman-adv-y += routing.o\nnet/batman-adv/Makefile:28:batman-adv-y += send.o\nnet/batman-adv/Makefile:29:batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o\nnet/batman-adv/Makefile:30:batman-adv-y += tp_meter.o\nnet/batman-adv/Makefile:31:batman-adv-y += translation-table.o\nnet/batman-adv/Makefile:32:batman-adv-y += tvlv.o\nnet/batman-adv/Makefile:33:batman-adv-y += version.o\nnet/batman-adv/Makefile-34-\n--\nnet/batman-adv/bat_algo.c=26=static struct hlist_head batadv_algo_list;\n--\nnet/batman-adv/bat_algo.c-28-/**\nnet/batman-adv/bat_algo.c:29: * batadv_algo_init() - Initialize batman-adv algorithm management data\nnet/batman-adv/bat_algo.c-30- * structures\n--\nnet/batman-adv/bat_algo.c=107=int batadv_algo_select(struct batadv_priv *bat_priv, const char *name)\n--\nnet/batman-adv/bat_algo.c-124- *\nnet/batman-adv/bat_algo.c:125: * Check that the requested algorithm is known to batman-adv and then store\nnet/batman-adv/bat_algo.c-126- * the name as the new default routing algorithm.\n--\nnet/batman-adv/bat_v_elp.c=230=batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)\n--\nnet/batman-adv/bat_v_elp.c-248-\t * algorithm sampling interval (minstrel). In this way, if not\nnet/batman-adv/bat_v_elp.c:249:\t * enough traffic has been sent to the neighbor, batman-adv can\nnet/batman-adv/bat_v_elp.c-250-\t * generate 2 probe packets and push the RC algorithm to perform\n--\nnet/batman-adv/bat_v_elp.c=290=static void batadv_v_elp_periodic_work(struct work_struct *work)\n--\nnet/batman-adv/bat_v_elp.c-338-\t/* The throughput metric is updated on each sent packet. This way, if a\nnet/batman-adv/bat_v_elp.c:339:\t * node is dead and no longer sends packets, batman-adv is still able to\nnet/batman-adv/bat_v_elp.c-340-\t * react timely to its death.\n--\nnet/batman-adv/distributed-arp-table.c=64=enum batadv_boothtype {\n--\nnet/batman-adv/distributed-arp-table.c-69-/**\nnet/batman-adv/distributed-arp-table.c:70: * enum batadv_dhcpoptioncode - DHCP option codes relevant for batman-adv DAT\nnet/batman-adv/distributed-arp-table.c-71- */\nnet/batman-adv/distributed-arp-table.c=72=enum batadv_dhcpoptioncode {\n--\nnet/batman-adv/distributed-arp-table.c-83-/**\nnet/batman-adv/distributed-arp-table.c:84: * enum batadv_dhcptype - DHCP message types relevant for batman-adv DAT\nnet/batman-adv/distributed-arp-table.c-85- */\n--\nnet/batman-adv/distributed-arp-table.c=1082=static u16 batadv_arp_get_type(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.c-1152- * @skb: the buffer containing the packet to extract the VID from\nnet/batman-adv/distributed-arp-table.c:1153: * @hdr_size: the size of the batman-adv header encapsulating the packet\nnet/batman-adv/distributed-arp-table.c-1154- *\n--\nnet/batman-adv/distributed-arp-table.c=1857=void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.c-1879- * @skb: the packet to snoop\nnet/batman-adv/distributed-arp-table.c:1880: * @hdr_size: header size, up to the tail of the batman-adv header\nnet/batman-adv/distributed-arp-table.c-1881- *\n--\nnet/batman-adv/fragmentation.c=505=int batadv_frag_send_packet(struct sk_buff *skb,\n--\nnet/batman-adv/fragmentation.c-551-\t * linearized to avoid incorrect length information after all\nnet/batman-adv/fragmentation.c:552:\t * batman-adv fragments were created and submitted to the\nnet/batman-adv/fragmentation.c-553-\t * hard-interface\n--\nnet/batman-adv/gateway_client.c=178=void batadv_gw_check_client_stop(struct batadv_priv *bat_priv)\n--\nnet/batman-adv/gateway_client.c-193-\nnet/batman-adv/gateway_client.c:194:\t/* if batman-adv is switching the gw client mode off and a gateway was\nnet/batman-adv/gateway_client.c-195-\t * already selected, send a DEL uevent\n--\nnet/batman-adv/gateway_client.c=516=int batadv_gw_dump(struct sk_buff *msg, struct netlink_callback *cb)\n--\nnet/batman-adv/gateway_client.c-553- * @skb: the packet to check\nnet/batman-adv/gateway_client.c:554: * @header_len: a pointer to the batman-adv header size\nnet/batman-adv/gateway_client.c-555- * @chaddr: buffer where the client address will be stored. Valid\n--\nnet/batman-adv/hard-interface.c=127=static bool batadv_mutual_parents(const struct net_device *dev1,\n--\nnet/batman-adv/hard-interface.c-152- *\nnet/batman-adv/hard-interface.c:153: * If the user creates any virtual device on top of a batman-adv interface, it\nnet/batman-adv/hard-interface.c-154- * is important to prevent this new interface from being used to create a new\n--\nnet/batman-adv/hard-interface.c-156- * configuration). This function recursively checks all the fathers of the\nnet/batman-adv/hard-interface.c:157: * device passed as argument looking for a batman-adv mesh interface.\nnet/batman-adv/hard-interface.c-158- *\nnet/batman-adv/hard-interface.c:159: * Return: true if the device is descendant of a batman-adv mesh interface (or\nnet/batman-adv/hard-interface.c:160: * if it is a batman-adv interface itself), false otherwise\nnet/batman-adv/hard-interface.c-161- */\nnet/batman-adv/hard-interface.c=162=static bool batadv_is_on_batman_iface(const struct net_device *net_dev)\n--\nnet/batman-adv/hard-interface.c-169-\nnet/batman-adv/hard-interface.c:170:\t/* check if this is a batman-adv mesh interface */\nnet/batman-adv/hard-interface.c-171-\tif (batadv_meshif_is_valid(net_dev))\n--\nnet/batman-adv/hard-interface.c-205- * Refuse loopback devices, non-Ethernet devices, devices with a non-Ethernet\nnet/batman-adv/hard-interface.c:206: * address length and any device that is already part of a batman-adv mesh\nnet/batman-adv/hard-interface.c-207- * interface stack.\n--\nnet/batman-adv/hard-interface.c=653=int batadv_hardif_min_mtu(struct net_device *mesh_iface)\n--\nnet/batman-adv/hard-interface.c-682-\t/* report to the other components the maximum amount of bytes that\nnet/batman-adv/hard-interface.c:683:\t * batman-adv can send over the wire (without considering the payload\nnet/batman-adv/hard-interface.c-684-\t * overhead). For example, this value is used by TT to compute the\n--\nnet/batman-adv/hard-interface.c=794=int batadv_hardif_enable_interface(struct net_device *net_dev,\n--\nnet/batman-adv/hard-interface.c-864-\t\tbatadv_info(hard_iface-\u003emesh_iface,\nnet/batman-adv/hard-interface.c:865:\t\t\t \"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 whic...\nnet/batman-adv/hard-interface.c-866-\t\t\t hard_iface-\u003enet_dev-\u003ename, hardif_mtu,\n--\nnet/batman-adv/hard-interface.c-870-\t\tbatadv_info(hard_iface-\u003emesh_iface,\nnet/batman-adv/hard-interface.c:871:\t\t\t \"The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing t...\nnet/batman-adv/hard-interface.c-872-\t\t\t hard_iface-\u003enet_dev-\u003ename, hardif_mtu,\n--\nnet/batman-adv/main.c=80=static char *batadv_uev_type_str[] = {\n--\nnet/batman-adv/main.c-85-/**\nnet/batman-adv/main.c:86: * batadv_init() - batman-adv module init function\nnet/batman-adv/main.c-87- *\n--\nnet/batman-adv/main.c=93=static int __init batadv_init(void)\n--\nnet/batman-adv/main.c-162-/**\nnet/batman-adv/main.c:163: * batadv_exit() - batman-adv module exit function\nnet/batman-adv/main.c-164- *\n--\nnet/batman-adv/main.c=554=static void batadv_recv_handler_init(void)\n--\nnet/batman-adv/main.c-603-/**\nnet/batman-adv/main.c:604: * batadv_recv_handler_register() - Register handler for batman-adv packet type\nnet/batman-adv/main.c-605- * @packet_type: batadv_packettype which should be handled\n--\nnet/batman-adv/main.c=687=bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid)\n--\nnet/batman-adv/main.c-704-/**\nnet/batman-adv/main.c:705: * batadv_throw_uevent() - Send an uevent with batman-adv specific env data\nnet/batman-adv/main.c-706- * @bat_priv: the bat priv with all the mesh interface information\n--\nnet/batman-adv/main.h-12-#define BATADV_DRIVER_DESC \"B.A.T.M.A.N. advanced\"\nnet/batman-adv/main.h:13:#define BATADV_DRIVER_DEVICE \"batman-adv\"\nnet/batman-adv/main.h-14-\n--\nnet/batman-adv/main.h=170=enum batadv_uev_type {\n--\nnet/batman-adv/main.h-195-#endif\nnet/batman-adv/main.h:196:/* Append 'batman-adv: ' before kernel messages */\nnet/batman-adv/main.h-197-#define pr_fmt(fmt) KBUILD_MODNAME \": \" fmt\n--\nnet/batman-adv/mesh-interface.c=213=static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,\n--\nnet/batman-adv/mesh-interface.c-442-/**\nnet/batman-adv/mesh-interface.c:443: * batadv_interface_rx() - receive ethernet frame on local batman-adv interface\nnet/batman-adv/mesh-interface.c-444- * @mesh_iface: local interface which will receive the ethernet frame\nnet/batman-adv/mesh-interface.c-445- * @skb: ethernet frame for @mesh_iface\nnet/batman-adv/mesh-interface.c:446: * @hdr_size: size of already parsed batman-adv header\nnet/batman-adv/mesh-interface.c:447: * @orig_node: originator from which the batman-adv packet was sent\nnet/batman-adv/mesh-interface.c-448- *\nnet/batman-adv/mesh-interface.c-449- * Sends an ethernet frame to the receive path of the local @mesh_iface.\nnet/batman-adv/mesh-interface.c:450: * skb-\u003edata must still point to the batman-adv header with the size @hdr_size.\nnet/batman-adv/mesh-interface.c-451- * The caller has to have parsed this header already and made sure that at least\n--\nnet/batman-adv/mesh-interface.c-454- * The packet may still get dropped. This can happen when the encapsulated\nnet/batman-adv/mesh-interface.c:455: * ethernet frame is invalid or contains again a batman-adv packet. Also\nnet/batman-adv/mesh-interface.c-456- * unicast packets will be dropped directly when they were sent between two\n--\nnet/batman-adv/mesh-interface.c=459=void batadv_interface_rx(struct net_device *mesh_iface,\n--\nnet/batman-adv/mesh-interface.c-475-\nnet/batman-adv/mesh-interface.c:476:\t/* clean the netfilter state now that the batman-adv header has been\nnet/batman-adv/mesh-interface.c-477-\t * removed\n--\nnet/batman-adv/mesh-interface.c=674=static int batadv_interface_add_vid(struct net_device *dev, __be16 proto,\n--\nnet/batman-adv/mesh-interface.c-680-\t/* only 802.1Q vlans are supported.\nnet/batman-adv/mesh-interface.c:681:\t * batman-adv does not know how to handle other types\nnet/batman-adv/mesh-interface.c-682-\t */\n--\nnet/batman-adv/mesh-interface.c=729=static int batadv_interface_kill_vid(struct net_device *dev, __be16 proto,\n--\nnet/batman-adv/mesh-interface.c-734-\nnet/batman-adv/mesh-interface.c:735:\t/* only 802.1Q vlans are supported. batman-adv does not know how to\nnet/batman-adv/mesh-interface.c-736-\t * handle other types\n--\nnet/batman-adv/mesh-interface.c-758-\nnet/batman-adv/mesh-interface.c:759:/* batman-adv network devices have devices nesting below it and are a special\nnet/batman-adv/mesh-interface.c-760- * \"super class\" of normal network devices; split their locks off into a\n--\nnet/batman-adv/mesh-interface.c=1133=static int batadv_meshif_newlink(struct net_device *dev,\n--\nnet/batman-adv/mesh-interface.c-1154- * netlink\nnet/batman-adv/mesh-interface.c:1155: * @mesh_iface: the to-be-removed batman-adv interface\nnet/batman-adv/mesh-interface.c-1156- * @head: list pointer\n--\nnet/batman-adv/mesh-interface.c=1158=static void batadv_meshif_destroy_netlink(struct net_device *mesh_iface,\n--\nnet/batman-adv/mesh-interface.c-1174- *\nnet/batman-adv/mesh-interface.c:1175: * Return: true when net_dev is a batman-adv interface, false otherwise\nnet/batman-adv/mesh-interface.c-1176- */\n--\nnet/batman-adv/multicast.c=714=static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-752- * behind our local bridge segment: Snooping switches will directly\nnet/batman-adv/multicast.c:753: * forward listener reports to the querier, therefore batman-adv and\nnet/batman-adv/multicast.c-754- * the bridge will potentially not see these listeners - the querier is\n--\nnet/batman-adv/multicast.c=1165=static int batadv_mcast_forw_rtr_count(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1187- * mode to use. For BATADV_FORW_MCAST it also encapsulates the packet with a\nnet/batman-adv/multicast.c:1188: * complete batman-adv multicast header.\nnet/batman-adv/multicast.c-1189- *\n--\nnet/batman-adv/multicast.c-1193- *\tand the encapsulated multicast packet with all destination addresses\nnet/batman-adv/multicast.c:1194: *\twould still fit into an 1280 bytes batman-adv multicast packet\nnet/batman-adv/multicast.c-1195- *\t(excluding the outer ethernet frame) and we could successfully push\nnet/batman-adv/multicast.c:1196: *\tthe full batman-adv multicast packet header.\nnet/batman-adv/multicast.c:1197: *\tBATADV_FORW_UCASTS: If the packet cannot be sent in a batman-adv\nnet/batman-adv/multicast.c:1198: *\tmulticast packet and the amount of batman-adv unicast packets needed\nnet/batman-adv/multicast.c-1199- *\tis smaller or equal to the configured multicast fanout.\n--\nnet/batman-adv/multicast.c=1280=static int batadv_mcast_forw_send_orig(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1307- * listener registered in the translation table. A transmission is performed\nnet/batman-adv/multicast.c:1308: * via a batman-adv unicast packet for each such destination node.\nnet/batman-adv/multicast.c-1309- *\n--\nnet/batman-adv/multicast.c=1314=batadv_mcast_forw_tt(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/multicast.c-1353- * BATADV_MCAST_WANT_ALL_IPV4 flag set. A transmission is performed via a\nnet/batman-adv/multicast.c:1354: * batman-adv unicast packet for each such destination node.\nnet/batman-adv/multicast.c-1355- *\n--\nnet/batman-adv/multicast.c=1360=batadv_mcast_forw_want_all_ipv4(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1390- * BATADV_MCAST_WANT_ALL_IPV6 flag set. A transmission is performed via a\nnet/batman-adv/multicast.c:1391: * batman-adv unicast packet for each such destination node.\nnet/batman-adv/multicast.c-1392- *\n--\nnet/batman-adv/multicast.c=1397=batadv_mcast_forw_want_all_ipv6(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1427- * BATADV_MCAST_WANT_ALL_IPV4 or BATADV_MCAST_WANT_ALL_IPV6 flag set. A\nnet/batman-adv/multicast.c:1428: * transmission is performed via a batman-adv unicast packet for each such\nnet/batman-adv/multicast.c-1429- * destination node.\n--\nnet/batman-adv/multicast.c=1435=batadv_mcast_forw_want_all(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1456- * BATADV_MCAST_WANT_NO_RTR4 flag unset. A transmission is performed via a\nnet/batman-adv/multicast.c:1457: * batman-adv unicast packet for each such destination node.\nnet/batman-adv/multicast.c-1458- *\n--\nnet/batman-adv/multicast.c=1463=batadv_mcast_forw_want_all_rtr4(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1493- * BATADV_MCAST_WANT_NO_RTR6 flag unset. A transmission is performed via a\nnet/batman-adv/multicast.c:1494: * batman-adv unicast packet for each such destination node.\nnet/batman-adv/multicast.c-1495- *\n--\nnet/batman-adv/multicast.c=1500=batadv_mcast_forw_want_all_rtr6(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1530- * BATADV_MCAST_WANT_NO_RTR4 or BATADV_MCAST_WANT_NO_RTR6 flag unset. A\nnet/batman-adv/multicast.c:1531: * transmission is performed via a batman-adv unicast packet for each such\nnet/batman-adv/multicast.c-1532- * destination node.\n--\nnet/batman-adv/multicast.c=1538=batadv_mcast_forw_want_rtr(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast.c-1560- * interest in it, that is either via the translation table or the according\nnet/batman-adv/multicast.c:1561: * want-all flags. A transmission is performed via a batman-adv unicast packet\nnet/batman-adv/multicast.c-1562- * for each such destination node.\n--\nnet/batman-adv/multicast.h=19=enum batadv_forw_mode {\nnet/batman-adv/multicast.h-20-\t/**\nnet/batman-adv/multicast.h:21:\t * @BATADV_FORW_BCAST: forward the packet to all nodes via a batman-adv\nnet/batman-adv/multicast.h-22-\t * broadcast packet\n--\nnet/batman-adv/multicast.h-27-\t * @BATADV_FORW_UCASTS: forward the packet to some nodes via one\nnet/batman-adv/multicast.h:28:\t * or more batman-adv unicast packets\nnet/batman-adv/multicast.h-29-\t */\n--\nnet/batman-adv/multicast.h-33-\t * @BATADV_FORW_MCAST: forward the packet to some nodes via a\nnet/batman-adv/multicast.h:34:\t * batman-adv multicast packet\nnet/batman-adv/multicast.h-35-\t */\n--\nnet/batman-adv/multicast_forw.c=583=batadv_mcast_forw_push_tvlvs(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/multicast_forw.c-605- *\nnet/batman-adv/multicast_forw.c:606: * Pushes a batman-adv multicast packet header onto the given skb and sets\nnet/batman-adv/multicast_forw.c-607- * the provided total TVLV length value in it.\n--\nnet/batman-adv/multicast_forw.c=615=batadv_mcast_forw_push_hdr(struct sk_buff *skb, unsigned short tvlv_len)\n--\nnet/batman-adv/multicast_forw.c-641- *\nnet/batman-adv/multicast_forw.c:642: * This sorts destination entries into either the original batman-adv\nnet/batman-adv/multicast_forw.c-643- * multicast packet or the skb (copy) that is going to be sent to comp_neigh\n--\nnet/batman-adv/multicast_forw.c-645- *\nnet/batman-adv/multicast_forw.c:646: * In preparation for the next, to be (unicast) transmitted batman-adv multicast\nnet/batman-adv/multicast_forw.c-647- * packet skb to be sent to the given neighbor node, tries to collect all\n--\nnet/batman-adv/multicast_forw.c=710=static bool batadv_mcast_forw_shrink_fill(u8 *slot, u16 num_dests_slot)\n--\nnet/batman-adv/multicast_forw.c-736- * batadv_mcast_forw_shrink_pack_dests() - pack destinations of a tracker TVLV\nnet/batman-adv/multicast_forw.c:737: * @skb: the batman-adv multicast packet to compact destinations in\nnet/batman-adv/multicast_forw.c-738- *\n--\nnet/batman-adv/multicast_forw.c=792=batadv_mcast_forw_shrink_align_offset(unsigned int num_dests_old,\n--\nnet/batman-adv/multicast_forw.c-808- * batadv_mcast_forw_shrink_update_headers() - update shrunk mc packet headers\nnet/batman-adv/multicast_forw.c:809: * @skb: the batman-adv multicast packet to update headers of\nnet/batman-adv/multicast_forw.c-810- * @num_dests_reduce: the number of destinations that were removed\nnet/batman-adv/multicast_forw.c-811- *\nnet/batman-adv/multicast_forw.c:812: * This updates any fields of a batman-adv multicast packet that are affected\nnet/batman-adv/multicast_forw.c-813- * by the reduced number of destinations in the multicast tracket TVLV. In\n--\nnet/batman-adv/multicast_forw.c-817- * The TVLV length field of the according generic TVLV header.\nnet/batman-adv/multicast_forw.c:818: * The batman-adv multicast packet's total TVLV length field.\nnet/batman-adv/multicast_forw.c-819- *\nnet/batman-adv/multicast_forw.c:820: * Return: The offset in skb's tail direction at which the new batman-adv\nnet/batman-adv/multicast_forw.c-821- * multicast packet header needs to start.\n--\nnet/batman-adv/multicast_forw.c=824=batadv_mcast_forw_shrink_update_headers(struct sk_buff *skb,\n--\nnet/batman-adv/multicast_forw.c-860- * batadv_mcast_forw_shrink_move_headers() - move multicast headers by offset\nnet/batman-adv/multicast_forw.c:861: * @skb: the batman-adv multicast packet to move headers for\nnet/batman-adv/multicast_forw.c-862- * @offset: a non-negative offset to move headers by, towards the skb tail\nnet/batman-adv/multicast_forw.c-863- *\nnet/batman-adv/multicast_forw.c:864: * Moves the batman-adv multicast packet header, its multicast tracker TVLV and\nnet/batman-adv/multicast_forw.c-865- * any TVLVs in between by the given offset in direction towards the tail.\n--\nnet/batman-adv/multicast_forw.c=868=batadv_mcast_forw_shrink_move_headers(struct sk_buff *skb, unsigned int offset)\n--\nnet/batman-adv/multicast_forw.c-885- * batadv_mcast_forw_shrink_tracker() - remove zero addresses in a tracker tvlv\nnet/batman-adv/multicast_forw.c:886: * @skb: the batman-adv multicast packet to (potentially) shrink\nnet/batman-adv/multicast_forw.c-887- *\nnet/batman-adv/multicast_forw.c-888- * Removes all destinations with a zero MAC addresses (00:00:00:00:00:00) from\nnet/batman-adv/multicast_forw.c:889: * the given batman-adv multicast packet's tracker TVLV and updates headers\nnet/batman-adv/multicast_forw.c:890: * accordingly to maintain a valid batman-adv multicast packet.\nnet/batman-adv/multicast_forw.c-891- */\nnet/batman-adv/multicast_forw.c=892=static void batadv_mcast_forw_shrink_tracker(struct sk_buff *skb)\n--\nnet/batman-adv/multicast_forw.c-905-/**\nnet/batman-adv/multicast_forw.c:906: * batadv_mcast_forw_packet() - forward a batman-adv multicast packet\nnet/batman-adv/multicast_forw.c-907- * @bat_priv: the bat priv with all the mesh interface information\nnet/batman-adv/multicast_forw.c:908: * @skb: the received or locally generated batman-adv multicast packet\nnet/batman-adv/multicast_forw.c-909- * @local_xmit: indicates that the packet was locally generated and not received\nnet/batman-adv/multicast_forw.c-910- *\nnet/batman-adv/multicast_forw.c:911: * Parses the tracker TVLV of a batman-adv multicast packet and forwards the\nnet/batman-adv/multicast_forw.c-912- * packet as indicated in this TVLV.\n--\nnet/batman-adv/multicast_forw.c=924=static int batadv_mcast_forw_packet(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast_forw.c-1030- * @bat_priv: the bat priv with all the mesh interface information\nnet/batman-adv/multicast_forw.c:1031: * @skb: the received batman-adv multicast packet\nnet/batman-adv/multicast_forw.c-1032- *\nnet/batman-adv/multicast_forw.c:1033: * Parses the tracker TVLV of an incoming batman-adv multicast packet and\nnet/batman-adv/multicast_forw.c-1034- * forwards the packet as indicated in this TVLV.\n--\nnet/batman-adv/multicast_forw.c=1046=int batadv_mcast_forw_tracker_tvlv_handler(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast_forw.c-1055- *\nnet/batman-adv/multicast_forw.c:1056: * Calculates the total batman-adv multicast packet header length for a given\nnet/batman-adv/multicast_forw.c-1057- * number of destination nodes (excluding the outer ethernet frame).\nnet/batman-adv/multicast_forw.c-1058- *\nnet/batman-adv/multicast_forw.c:1059: * Return: The calculated total batman-adv multicast packet header length.\nnet/batman-adv/multicast_forw.c-1060- */\n--\nnet/batman-adv/multicast_forw.c=1091=static int batadv_mcast_forw_expand_head(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/multicast_forw.c-1118-/**\nnet/batman-adv/multicast_forw.c:1119: * batadv_mcast_forw_push() - encapsulate skb in a batman-adv multicast packet\nnet/batman-adv/multicast_forw.c-1120- * @bat_priv: the bat priv with all the mesh interface information\n--\nnet/batman-adv/multicast_forw.c-1125- *\nnet/batman-adv/multicast_forw.c:1126: * Encapsulates the given multicast packet in a batman-adv multicast packet.\nnet/batman-adv/multicast_forw.c-1127- * A multicast tracker TVLV with destination originator addresses for any node\n--\nnet/batman-adv/multicast_forw.c=1138=bool batadv_mcast_forw_push(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/multicast_forw.c-1167-/**\nnet/batman-adv/multicast_forw.c:1168: * batadv_mcast_forw_mcsend() - send a self prepared batman-adv multicast packet\nnet/batman-adv/multicast_forw.c-1169- * @bat_priv: the bat priv with all the mesh interface information\n--\nnet/batman-adv/multicast_forw.c-1171- *\nnet/batman-adv/multicast_forw.c:1172: * Transmits a batman-adv multicast packet that was locally prepared and\nnet/batman-adv/multicast_forw.c-1173- * consumes/frees it.\n--\nnet/batman-adv/netlink.c=53=struct genl_family batadv_netlink_family;\n--\nnet/batman-adv/netlink.c-55-/**\nnet/batman-adv/netlink.c:56: * enum batadv_netlink_multicast_groups - batman-adv generic netlink multicast\nnet/batman-adv/netlink.c-57- * groups\n--\nnet/batman-adv/netlink.c=1297=batadv_get_vlan_from_info(struct batadv_priv *bat_priv, struct net *net,\n--\nnet/batman-adv/netlink.c-1315-/**\nnet/batman-adv/netlink.c:1316: * batadv_pre_doit() - Prepare batman-adv genl doit request\nnet/batman-adv/netlink.c-1317- * @ops: requested netlink operation\n--\nnet/batman-adv/netlink.c=1323=static int batadv_pre_doit(const struct genl_split_ops *ops,\n--\nnet/batman-adv/netlink.c-1384-/**\nnet/batman-adv/netlink.c:1385: * batadv_post_doit() - End batman-adv genl doit request\nnet/batman-adv/netlink.c-1386- * @ops: requested netlink operation\n--\nnet/batman-adv/originator.c=109=batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node,\n--\nnet/batman-adv/originator.c-132-/**\nnet/batman-adv/originator.c:133: * batadv_vlan_id_valid() - check if vlan id is in valid batman-adv encoding\nnet/batman-adv/originator.c-134- * @vid: the VLAN identifier\n--\nnet/batman-adv/routing.c=182=bool batadv_check_management_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-213-/**\nnet/batman-adv/routing.c:214: * batadv_skb_decrement_ttl() - decrement ttl in a batman-adv header, csum-safe\nnet/batman-adv/routing.c:215: * @skb: the received packet with @skb-\u003edata pointing to the batman-adv header\nnet/batman-adv/routing.c-216- *\n--\nnet/batman-adv/routing.c=1263=int batadv_recv_bcast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-1379-/**\nnet/batman-adv/routing.c:1380: * batadv_recv_mcast_packet() - process received batman-adv multicast packet\nnet/batman-adv/routing.c:1381: * @skb: the received batman-adv multicast packet\nnet/batman-adv/routing.c-1382- * @recv_if: interface that the skb is received on\nnet/batman-adv/routing.c-1383- *\nnet/batman-adv/routing.c:1384: * Parses the given, received batman-adv multicast packet. Depending on the\nnet/batman-adv/routing.c-1385- * contents of its TVLV forwards it and/or decapsulates it to hand it to the\n--\nnet/batman-adv/send.c=269=bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/send.c-311- *\nnet/batman-adv/send.c:312: * Wrap the given skb into a batman-adv unicast or unicast-4addr header\nnet/batman-adv/send.c-313- * depending on whether BATADV_UNICAST or BATADV_UNICAST_4ADDR was supplied\n--\nnet/batman-adv/send.c=318=int batadv_send_skb_unicast(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/send.c-386- * Look up the recipient node for the destination address in the ethernet\nnet/batman-adv/send.c:387: * header via the translation table. Wrap the given skb into a batman-adv\nnet/batman-adv/send.c-388- * unicast or unicast-4addr header depending on whether BATADV_UNICAST or\n--\nnet/batman-adv/send.c=394=int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/send.c-428- *\nnet/batman-adv/send.c:429: * Look up the currently selected gateway. Wrap the given skb into a batman-adv\nnet/batman-adv/send.c-430- * unicast header and send this frame to this gateway node.\n--\nnet/batman-adv/send.h=66=int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/send.h-76- * Look up the recipient node for the destination address in the ethernet\nnet/batman-adv/send.h:77: * header via the translation table. Wrap the given skb into a batman-adv\nnet/batman-adv/send.h-78- * unicast header. Then send this frame to the according destination node.\n--\nnet/batman-adv/send.h=82=static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/send.h-98- * Look up the recipient node for the destination address in the ethernet\nnet/batman-adv/send.h:99: * header via the translation table. Wrap the given skb into a batman-adv\nnet/batman-adv/send.h-100- * unicast-4addr header. Then send this frame to the according destination\n--\nnet/batman-adv/tp_meter.c=1046=void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,\n--\nnet/batman-adv/tp_meter.c-1111-\t/* initialise the CWND to 3*MSS (Section 3.1 in RFC5681).\nnet/batman-adv/tp_meter.c:1112:\t * For batman-adv the MSS is the size of the payload received by the\nnet/batman-adv/tp_meter.c-1113-\t * mesh_interface, hence its MTU\n--\nnet/batman-adv/types.h=193=struct batadv_wifi_net_device_state {\n--\nnet/batman-adv/types.h-213-/**\nnet/batman-adv/types.h:214: * struct batadv_hard_iface - network device known to batman-adv\nnet/batman-adv/types.h-215- */\nnet/batman-adv/types.h=216=struct batadv_hard_iface {\nnet/batman-adv/types.h:217:\t/** @if_status: status of the interface for batman-adv */\nnet/batman-adv/types.h-218-\tchar if_status;\n--\nnet/batman-adv/types.h-235-\t * @batman_adv_ptype: packet type describing packets that should be\nnet/batman-adv/types.h:236:\t * processed by batman-adv for this interface\nnet/batman-adv/types.h-237-\t */\n\n"
} |
| 11/2 | 2026/08/31 20:32 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 49036 output: 38 thoughts: 560 Thoughts: **Analyzing Modified Functions in batman-adv for Non-Static Entries** Okay, let's get down to brass tacks. I need to pinpoint the non-static functions that were touched in `net/batman-adv/translation-table.c` and associated files. This is likely part of a deeper dive into the Batman-adv code, probably related to some recent modifications or a specific task I'm working on. Let's see what's been changed, function by function. Right, so after reviewing the diff, here's what stands out: * **`net/batman-adv/bat_iv_ogm.c` and `net/batman-adv/bat_v.c`:** These files have `batadv_iv_ogm_neigh_is_sob` and `batadv_v_neigh_is_sob`, respectively, but they are static function declarations, which is less interesting for my current objective. Likely some tweaks to the algorithm operations. * **`net/batman-adv/bridge_loop_avoidance.c`:** `batadv_bla_init` is a non-static function which is worth further examination. * **`net/batman-adv/distributed-arp-table.c`:** Several non-static functions are here: `batadv_dat_cache_dump_entry`, `batadv_dat_snoop_outgoing_arp_request`, `batadv_dat_snoop_incoming_arp_request`, and `batadv_dat_snoop_incoming_arp_reply`. I need to understand how these functions are being used and their impact on the dat path. * **`net/batman-adv/mesh-interface.c`:** This has some static netdev operations, `batadv_interface_set_mac_addr`, and `batadv_interface_tx`. They likely won't be relevant for my current non-static function investigation. * **`net/batman-adv/multicast.c`:** Here are a few functions to check, including `batadv_mcast_mla_meshif_get_ipv4`, `batadv_mcast_mla_meshif_get_ipv6`, and `batadv_mcast_mla_bridge_get`. * **`net/batman-adv/translation-table.c`:** And here's the core. Several non-static functions have been modified here: `batadv_tt_local_add`, `batadv_tt_local_dump`, `batadv_tt_local_remove`, `batadv_transtable_search`, `batadv_is_my_client`, `batadv_tt_global_client_is_roaming`, `batadv_tt_local_client_is_roaming`, and `batadv_tt_global_is_isolated`. There's also `batadv_tt_local_dump_entry` in the mix, but that is a static function. These functions, especially the TT-related ones, are the primary focus of my attention. Now, let's also take a look at the declarations in the `net/batman-adv/translation-table.h` file to get the full picture. I need to see the context and arguments of those functions to understand the scope of the modifications. |
| 12/2 | 2026/08/31 20:32 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/translation-table.h",
"FirstLine": 1,
"LineCount": 55
}Results: {
"Contents": " 1:\t/* SPDX-License-Identifier: GPL-2.0 */\n 2:\t/* Copyright (C) B.A.T.M.A.N. contributors:\n 3:\t *\n 4:\t * Marek Lindner, Simon Wunderlich, Antonio Quartulli\n 5:\t */\n 6:\t\n 7:\t#ifndef _NET_BATMAN_ADV_TRANSLATION_TABLE_H_\n 8:\t#define _NET_BATMAN_ADV_TRANSLATION_TABLE_H_\n 9:\t\n 10:\t#include \"main.h\"\n 11:\t\n 12:\t#include \u003clinux/kref.h\u003e\n 13:\t#include \u003clinux/netdevice.h\u003e\n 14:\t#include \u003clinux/netlink.h\u003e\n 15:\t#include \u003clinux/skbuff.h\u003e\n 16:\t#include \u003clinux/types.h\u003e\n 17:\t\n 18:\tint batadv_tt_init(struct batadv_priv *bat_priv);\n 19:\tbool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n 20:\t\t\t\t unsigned short vid, int ifindex, u32 mark);\n 21:\tu16 batadv_tt_local_remove(struct batadv_priv *bat_priv,\n 22:\t\t\t\t const u8 *addr, unsigned short vid,\n 23:\t\t\t\t const char *message, bool roaming);\n 24:\tint batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb);\n 25:\tint batadv_tt_global_dump(struct sk_buff *msg, struct netlink_callback *cb);\n 26:\tvoid batadv_tt_global_del_orig(struct batadv_priv *bat_priv,\n 27:\t\t\t\t struct batadv_orig_node *orig_node,\n 28:\t\t\t\t s32 match_vid, const char *message);\n 29:\tstruct batadv_tt_global_entry *\n 30:\tbatadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr,\n 31:\t\t\t\t unsigned short vid);\n 32:\tvoid batadv_tt_global_entry_release(struct kref *ref);\n 33:\tint batadv_tt_global_hash_count(struct batadv_priv *bat_priv,\n 34:\t\t\t\t\tconst u8 *addr, unsigned short vid);\n 35:\tstruct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,\n 36:\t\t\t\t\t\t\t const u8 *src, const u8 *addr,\n 37:\t\t\t\t\t\t\t unsigned short vid);\n 38:\tvoid batadv_tt_free(struct batadv_priv *bat_priv);\n 39:\tbool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,\n 40:\t\t\t\t unsigned short vid);\n 41:\tbool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,\n 42:\t\t\t\t unsigned short vid);\n 43:\tvoid batadv_tt_local_commit_changes(struct batadv_priv *bat_priv);\n 44:\tbool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,\n 45:\t\t\t\t\t\tu8 *addr, unsigned short vid);\n 46:\tbool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,\n 47:\t\t\t\t\t u8 *addr, unsigned short vid);\n 48:\tvoid batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface);\n 49:\tbool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv,\n 50:\t\t\t\t\t\t struct batadv_orig_node *orig_node,\n 51:\t\t\t\t\t\t const unsigned char *addr,\n 52:\t\t\t\t\t\t unsigned short vid);\n 53:\tbool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,\n 54:\t\t\t\t\t const u8 *addr, unsigned short vid);\n 55:\t\n"
} |
| 13/2 | 2026/08/31 20:32 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 51448 output: 307 thoughts: 721 Thoughts: **Analyzing B.A.T.M.A.N. Advanced Configuration and Focus Symbols for Testing** Okay, let's break this down systematically. First, I need to verify the dependencies for the B.A.T.M.A.N. Advanced configuration options. Looking at `net/batman-adv/Kconfig`, I can see the core dependency, `BATMAN_ADV`, relies on the `NET` subsystem, as expected. From there, `BATMAN_ADV_BATMAN_V` has a more nuanced dependency, requiring `BATMAN_ADV` but excluding the combination of `CFG80211` as a module and `BATMAN_ADV` enabled. `BATMAN_ADV_BLA`, `BATMAN_ADV_DAT`, and `BATMAN_ADV_MCAST` all depend on both `BATMAN_ADV` and `INET`. `BATMAN_ADV_MCAST` also excludes the scenario where `BRIDGE` is a module and `BATMAN_ADV` is enabled. Finally, `BATMAN_ADV_DEBUG` depends solely on `BATMAN_ADV`. I'll double-check that there aren't any other crucial configs in the `net/batman-adv/` directory that I need to account for, then I'll move on to confirming that the required configs are indeed those I've just reviewed: `BATMAN_ADV`, `BATMAN_ADV_BATMAN_V`, `BATMAN_ADV_BLA`, `BATMAN_ADV_DAT`, and `BATMAN_ADV_MCAST`. Next, I need to identify the key focus symbols – the API entrypoints directly modified or affected by this patch. I need to be precise here, focusing on those that are not static or inlined. The relevant functions appear to be: `batadv_tt_local_add`, `batadv_tt_local_remove`, `batadv_transtable_search`, `batadv_is_my_client`, `batadv_tt_global_client_is_roaming`, `batadv_tt_local_client_is_roaming`, and `batadv_tt_global_is_isolated`. These are likely where the core functionality changes are happening. Now, let's confirm everything for the test run. The `WorthFuzzing` flag is set to true. The `EnableConfigs` list aligns perfectly with the required configurations I identified earlier: `BATMAN_ADV`, `BATMAN_ADV_BATMAN_V`, `BATMAN_ADV_BLA`, `BATMAN_ADV_DAT`, and `BATMAN_ADV_MCAST`. The `FocusSymbols` list matches what I isolated as the critical API entrypoints. The reasoning is pretty clear: This patch series is touching the B.A.T.M.A.N. Advanced routing and translation table subsystem, specifically introducing spinlock synchronization to address concurrency races on entry flags, fixing hash table entry removal comparisons, correcting the neighbor metric throughput comparison logic, and ensuring 2-byte alignment for MAC address manipulation. This sounds like important work to improve stability and performance. Everything seems to be in order. I'm ready to call the `set-results` tool now. |
| 14/2 | 2026/08/31 20:32 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"BATMAN_ADV",
"BATMAN_ADV_BATMAN_V",
"BATMAN_ADV_BLA",
"BATMAN_ADV_DAT",
"BATMAN_ADV_MCAST"
],
"FocusSymbols": [
"batadv_tt_local_add",
"batadv_tt_local_remove",
"batadv_transtable_search",
"batadv_is_my_client",
"batadv_tt_global_is_isolated",
"batadv_tt_global_client_is_roaming",
"batadv_tt_local_client_is_roaming"
],
"Reasoning": "The patch series introduces significant functional changes and bug fixes in the B.A.T.M.A.N. Advanced mesh protocol subsystem (net/batman-adv/). Key changes include adding spinlock protection (flags_lock) to avoid race conditions when reading and mutating translation table entry flags, fixing exact object removal from hash buckets (batadv_compare_tt_entry), correcting the B.A.T.M.A.N. V neighbor comparison calculation logic in batadv_v_neigh_is_sob(), and adding 2-byte alignment attributes to MAC address buffers. These changes alter core execution flows and state handling that are fully reachable and testable in virtual environments.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"BATMAN_ADV",
"BATMAN_ADV_BATMAN_V",
"BATMAN_ADV_BLA",
"BATMAN_ADV_DAT",
"BATMAN_ADV_MCAST"
],
"FocusSymbols": [
"batadv_tt_local_add",
"batadv_tt_local_remove",
"batadv_transtable_search",
"batadv_is_my_client",
"batadv_tt_global_is_isolated",
"batadv_tt_global_client_is_roaming",
"batadv_tt_local_client_is_roaming"
],
"Reasoning": "The patch series introduces significant functional changes and bug fixes in the B.A.T.M.A.N. Advanced mesh protocol subsystem (net/batman-adv/). Key changes include adding spinlock protection (flags_lock) to avoid race conditions when reading and mutating translation table entry flags, fixing exact object removal from hash buckets (batadv_compare_tt_entry), correcting the B.A.T.M.A.N. V neighbor comparison calculation logic in batadv_v_neigh_is_sob(), and adding 2-byte alignment attributes to MAC address buffers. These changes alter core execution flows and state handling that are fully reachable and testable in virtual environments.",
"WorthFuzzing": true
} |
| 15/1 | 2026/08/31 20:32 | action | If |
3mArgs:{
"WorthFuzzing": true
}Results: null |
| 16/2 | 2026/08/31 20:32 | agent | kmsan-evaluator |
3mModel:core Args: null Results: {
"KMSANReasoning": "The patch series consists of several cleanups and bugfixes in batman-adv:\n1. Alignment annotations: Adds `__aligned(2)` to various MAC address byte arrays (`u8 addr[ETH_ALEN]`, `u8 orig[ETH_ALEN]`, etc.) to ensure 2-byte alignment for operations like `ether_addr_copy()`.\n2. Concurrency and locking improvements: Introduces `flags_lock` spinlock to `struct batadv_tt_common_entry` to protect concurrent read/write access to translation table entry flags (`common-\u003eflags`) and roaming timestamps (`roam_at`).\n3. Logic \u0026 naming fixes: Fixes neighbor comparison logic in `batadv_v_neigh_is_sob()` and renames parameters for clarity in `batadv_iv_ogm_neigh_is_sob()`.\n4. Debug output fix: Corrects field access in debug printing for encapsulated DAT packets.\n5. Hash table lookup accuracy: Introduces `batadv_compare_tt_entry()` to match exact pointer identities during `batadv_hash_remove()`.\n\nNone of the changes introduce uninitialized memory allocations, uninitialized variable usage, or leak uninitialized kernel memory to user space. Netlink dump handlers (`batadv_dat_cache_dump_entry`, `batadv_tt_local_dump_entry`, `batadv_tt_global_dump_subentry`) only serialize fully initialized scalars and MAC addresses. Concurrency, lifetime, and boundary checks are already covered by standard KASAN and LOCKDEP. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Instruction: You are an expert Linux kernel security engineer specializing in kernel memory
error detectors (KASAN and KMSAN). Your job is to review the provided patch series and
determine if the code changes justify spawning a dedicated KMSAN (KernelMemorySanitizer)
fuzzing session in addition to standard KASAN fuzzing.
CRITICAL DISTINCTION BETWEEN KASAN AND KMSAN:
- Standard KASAN kernel builds (upstream-apparmor-kasan.config) already enable
a comprehensive suite of debugging tools and sanitizers, including KASAN
(out-of-bounds accesses, use-after-free, double free, invalid free), LOCKDEP
(locking bugs and deadlocks), UB-sanitizers, and memory corruption checks.
- KMSAN (KernelMemorySanitizer) detects reads of UNINITIALIZED memory (stack, heap,
or page allocations) and kernel-to-user memory info-leaks.
Rule: THERE IS NO SENSE IN RUNNING A KMSAN SESSION IF A BUG CAN BE CAUGHT BY KASAN,
LOCKDEP, OR OTHER STANDARD BUG DETECTORS.
A dedicated KMSAN fuzzing session incurs significant resource costs. You must ONLY
set NeedsKMSAN=true if the code changes introduce or expose UNINITIALIZED MEMORY risks
that are detected ONLY by KMSAN.
Look holistically at the patch series and surrounding code. Even if no direct
uninitialized field accesses or new buffer allocations are added in the diff itself,
a patch may alter control flow, bounds checking, or data length calculations in ways
that change how the rest of the code operates on existing buffers (e.g. allowing
uninitialized stack/heap memory to be read, copied to user space, or used in control
flow). Do not hesitate to use your code access tools to inspect the surrounding code,
called functions, and callers.
Set NeedsKMSAN=true ONLY IF the patch introduces or modifies:
1. Kernel structures sent to user space (via copy_to_user, put_user, netlink skb
attributes, ioctl output arguments, socket options, or BPF buffers) where fields
or structure padding might not be fully initialized/zeroed.
2. Conditional logic or branching that depends on potentially uninitialized variables
or struct fields.
3. Allocation or initialization of complex data structures where uninitialized fields
could be read later in reachable code paths.
4. Bounds checks, lengths, or logic in a way that allows surrounding code to access
uninitialized bytes of existing buffers.
Set NeedsKMSAN=false IF:
- The code changes primarily risk out-of-bounds access, array overflows, NULL pointer
dereferences, locking deadlocks, or use-after-free bugs (these are already caught
by KASAN, LOCKDEP, or standard bug detectors).
- All stack/heap structures touched or introduced by the patch are fully zeroed
or initialized (e.g. using = {0}, memset, kzalloc) before being read or copied.
- The patch does not introduce any risk of uninitialized memory usage or info-leaks.
Use your code access tools to inspect the surrounding code if necessary, then provide
detailed KMSANReasoning contrasting KASAN vs KMSAN applicability for this patch.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: For your convenience, here is the diff of the changes:
commit f47ea3f9a76918a99237ce731d7cf6e85775d007
Author: syz-cluster <triage@syzkaller.com>
Date: Mon Aug 31 20:31:52 2026 +0000
syz-cluster: applied patch under review
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 53fbdbbe8f4f7..3fe09b4c30463 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -2424,25 +2424,26 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1,
/**
* batadv_iv_ogm_neigh_is_sob() - check if neigh1 is similarly good or better
* than neigh2 from the metric prospective
- * @neigh1: the first neighbor object of the comparison
- * @if_outgoing1: outgoing interface for the first neighbor
- * @neigh2: the second neighbor object of the comparison
- * @if_outgoing2: outgoing interface for the second neighbor
+ * @candidate: the first neighbor object of the comparison
+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor
+ * @reference: the second neighbor object of the comparison
+ * @if_outgoing_ref: outgoing interface for the @reference neighbor
*
- * Return: true if the metric via neigh1 is equally good or better than
- * the metric via neigh2, false otherwise.
+ * Return: true if the metric via @candidate is equally good or better than
+ * the metric via @reference, false otherwise.
*/
static bool
-batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2)
+batadv_iv_ogm_neigh_is_sob(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref)
{
bool ret;
int diff;
- ret = batadv_iv_ogm_neigh_diff(neigh1, if_outgoing1, neigh2,
- if_outgoing2, &diff);
+ ret = batadv_iv_ogm_neigh_diff(candidate, if_outgoing_cand,
+ reference, if_outgoing_ref,
+ &diff);
if (!ret)
return false;
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index 0c27447cf6889..596889b3522d0 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -514,40 +514,40 @@ static int batadv_v_neigh_cmp(struct batadv_neigh_node *neigh1,
/**
* batadv_v_neigh_is_sob() - check whether two B.A.T.M.A.N. V neighbours have
* a similar or better throughput
- * @neigh1: first neighbour to compare
- * @if_outgoing1: outgoing interface to use for @neigh1
- * @neigh2: second neighbour to compare
- * @if_outgoing2: outgoing interface to use for @neigh2
+ * @candidate: the first neighbor object of the comparison
+ * @if_outgoing_cand: outgoing interface for the @candidate neighbor
+ * @reference: the second neighbor object of the comparison
+ * @if_outgoing_ref: outgoing interface for the @reference neighbor
*
- * Return: true if the throughput of @neigh2 is at least 3/4 of the
- * @neigh1 throughput
+ * Return: true if the throughput of @candidate is more than 3/4 of the
+ * @reference throughput
*/
-static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2)
+static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref)
{
- struct batadv_neigh_ifinfo *ifinfo1;
- struct batadv_neigh_ifinfo *ifinfo2;
+ struct batadv_neigh_ifinfo *ifinfo_cand;
+ struct batadv_neigh_ifinfo *ifinfo_ref;
bool ret = false;
u32 threshold;
- ifinfo1 = batadv_neigh_ifinfo_get(neigh1, if_outgoing1);
- if (!ifinfo1)
+ ifinfo_cand = batadv_neigh_ifinfo_get(candidate, if_outgoing_cand);
+ if (!ifinfo_cand)
goto err_ifinfo1;
- ifinfo2 = batadv_neigh_ifinfo_get(neigh2, if_outgoing2);
- if (!ifinfo2)
+ ifinfo_ref = batadv_neigh_ifinfo_get(reference, if_outgoing_ref);
+ if (!ifinfo_ref)
goto err_ifinfo2;
- threshold = ifinfo1->bat_v.throughput / 4;
- threshold = ifinfo1->bat_v.throughput - threshold;
+ threshold = ifinfo_ref->bat_v.throughput / 4;
+ threshold = ifinfo_ref->bat_v.throughput - threshold;
- ret = ifinfo2->bat_v.throughput > threshold;
+ ret = ifinfo_cand->bat_v.throughput > threshold;
- batadv_neigh_ifinfo_put(ifinfo2);
+ batadv_neigh_ifinfo_put(ifinfo_ref);
err_ifinfo2:
- batadv_neigh_ifinfo_put(ifinfo1);
+ batadv_neigh_ifinfo_put(ifinfo_cand);
err_ifinfo1:
return ret;
}
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index f635da4b8ca65..ad6ab4a50658f 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -663,7 +663,7 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw)
static void batadv_bla_send_announce(struct batadv_priv *bat_priv,
struct batadv_bla_backbone_gw *backbone_gw)
{
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] __aligned(2);
__be16 crc;
memcpy(mac, batadv_announce_mac, 4);
@@ -1582,7 +1582,9 @@ static struct lock_class_key batadv_backbone_hash_lock_class_key;
*/
int batadv_bla_init(struct batadv_priv *bat_priv)
{
- u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00};
+ static const u8 claim_dest[ETH_ALEN] __aligned(2) = {
+ 0xff, 0x43, 0x05, 0x00, 0x00, 0x00
+ };
struct batadv_hard_iface *primary_if;
unsigned long entrytime;
u16 crc;
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 011cfdc47fab4..a4be5b2a87d7a 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -548,7 +548,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,
break;
default:
batadv_dbg(BATADV_DBG_DAT, bat_priv, "* type: Unknown (%u)!\n",
- unicast_4addr_packet->u.packet_type);
+ unicast_4addr_packet->subtype);
}
break;
case BATADV_BCAST:
@@ -940,7 +940,7 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
struct netlink_callback *cb,
struct batadv_dat_entry *dat_entry)
{
- u8 mac[ETH_ALEN];
+ u8 mac[ETH_ALEN] __aligned(2);
u64 u64_mac;
int msecs;
void *hdr;
@@ -1236,10 +1236,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
{
struct net_device *mesh_iface = bat_priv->mesh_iface;
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
- u8 mac[ETH_ALEN];
int hdr_size = 0;
__be32 ip_dst;
__be32 ip_src;
@@ -1344,10 +1344,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
{
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
- u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
u64 u64_mac;
@@ -1474,9 +1474,9 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct sk_buff *skb, int hdr_size)
{
struct batadv_dat_entry *dat_entry = NULL;
+ u8 mac[ETH_ALEN] __aligned(2);
bool dropped = false;
unsigned short vid;
- u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
u64 u64_mac;
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index e202088cf1fd4..63af21954cf90 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -141,9 +141,9 @@ static struct net_device_stats *batadv_interface_stats(struct net_device *dev)
static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
{
struct batadv_priv *bat_priv = netdev_priv(dev);
+ u8 old_addr[ETH_ALEN] __aligned(2);
struct batadv_meshif_vlan *vlan;
struct sockaddr *addr = p;
- u8 old_addr[ETH_ALEN];
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
@@ -213,13 +213,18 @@ static void batadv_interface_set_rx_mode(struct net_device *dev)
static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
struct net_device *mesh_iface)
{
- static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, 0x00, 0x00};
- static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x00};
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO;
enum batadv_forw_mode forw_mode = BATADV_FORW_BCAST;
+ static const u8 ectp_addr[ETH_ALEN] __aligned(2) = {
+ 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const u8 stp_addr[ETH_ALEN] __aligned(2) = {
+ 0x01, 0x80, 0xC2, 0x00, 0x00, 0x00
+ };
struct batadv_hard_iface *primary_if = NULL;
struct batadv_bcast_packet *bcast_packet;
+ u8 chaddr[ETH_ALEN] __aligned(2);
int network_offset = ETH_HLEN;
unsigned int header_len = 0;
unsigned long brd_delay = 0;
@@ -229,7 +234,6 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
struct ethhdr *ethhdr;
bool do_bcast = false;
u8 *dst_hint = NULL;
- u8 chaddr[ETH_ALEN];
unsigned short vid;
bool client_added;
__be16 proto;
diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c
index 82fd527b61c02..22dd28d5e1abc 100644
--- a/net/batman-adv/multicast.c
+++ b/net/batman-adv/multicast.c
@@ -368,9 +368,9 @@ batadv_mcast_mla_meshif_get_ipv4(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
struct batadv_hw_addr *new;
struct in_device *in_dev;
- u8 mcast_addr[ETH_ALEN];
struct ip_mc_list *pmc;
int ret = 0;
@@ -435,9 +435,9 @@ batadv_mcast_mla_meshif_get_ipv6(struct net_device *dev,
struct hlist_head *mcast_list,
struct batadv_mcast_mla_flags *flags)
{
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
struct batadv_hw_addr *new;
struct inet6_dev *in6_dev;
- u8 mcast_addr[ETH_ALEN];
struct ifmcaddr6 *pmc6;
int ret = 0;
@@ -587,10 +587,10 @@ static int batadv_mcast_mla_bridge_get(struct net_device *dev,
struct batadv_mcast_mla_flags *flags)
{
struct list_head bridge_mcast_list = LIST_HEAD_INIT(bridge_mcast_list);
+ u8 mcast_addr[ETH_ALEN] __aligned(2);
u8 tvlv_flags = flags->tvlv_flags;
struct br_ip_list *br_ip_entry;
struct batadv_hw_addr *new;
- u8 mcast_addr[ETH_ALEN];
struct br_ip_list *tmp;
int ret;
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 68f79853032ed..44a8cf89382c6 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -13,6 +13,7 @@
#include <linux/build_bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
+#include <linux/cleanup.h>
#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/crc32.h>
@@ -95,6 +96,26 @@ static bool batadv_compare_tt(const struct hlist_node *node, const void *data2)
return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
}
+/**
+ * batadv_compare_tt_entry() - check if a hash node is a specific TT entry
+ * @node: the list element pointer of the TT entry stored in the bucket
+ * @data2: pointer to the tt_common_entry which is looked for
+ *
+ * Unlike batadv_compare_tt(), this only matches the very object which is
+ * passed as @data2 and not just any entry for the same TT client. It is meant
+ * for batadv_hash_remove() callers which must not unlink an entry they did not
+ * look up themselves.
+ *
+ * Return: true if @node belongs to @data2, false otherwise
+ */
+static bool batadv_compare_tt_entry(const struct hlist_node *node,
+ const void *data2)
+{
+ const struct batadv_tt_common_entry *tt = data2;
+
+ return node == &tt->hash_entry;
+}
+
/**
* batadv_choose_tt() - return the index of the tt entry in the hash table
* @data: pointer to the tt_common_entry object to map
@@ -312,6 +333,10 @@ static void batadv_tt_local_size_mod(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called when removing the NEW flag of a
+ * batadv_tt_local_entry while it is still part of the bat_priv->tt.local_hash.
+ * It must therefore be checked under the specific list_locks[i].
*/
static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -324,6 +349,11 @@ static void batadv_tt_local_size_inc(struct batadv_priv *bat_priv,
* given vid
* @bat_priv: the bat priv with all the mesh interface information
* @vid: the VLAN identifier
+ *
+ * It must only be called after a batadv_tt_local_entry without NEW flag
+ * was removed from bat_priv->tt.local_hash (under the specific
+ * list_locks[i]) or when it is ensured that it is not accessible
+ * in this list.
*/
static void batadv_tt_local_size_dec(struct batadv_priv *bat_priv,
unsigned short vid)
@@ -413,6 +443,22 @@ batadv_tt_orig_list_entry_put(struct batadv_tt_orig_list_entry *orig_entry)
kref_put(&orig_entry->refcount, batadv_tt_orig_list_entry_release);
}
+/**
+ * batadv_tt_flags_get() - get a snapshot of the flags of a TT entry
+ * @common: tt local & tt global common data
+ *
+ * Return: the flags of the TT entry as observed under its flags_lock.
+ */
+static u16 batadv_tt_flags_get(struct batadv_tt_common_entry *common)
+{
+ u16 flags;
+
+ scoped_guard(spinlock_bh, &common->flags_lock)
+ flags = common->flags;
+
+ return flags;
+}
+
/**
* batadv_tt_local_event() - store a local TT event (ADD/DEL)
* @bat_priv: the bat priv with all the mesh interface information
@@ -425,23 +471,25 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
{
struct batadv_tt_common_entry *common = &tt_local_entry->common;
struct batadv_tt_change_node *tt_change_node;
- u8 flags = common->flags | event_flags;
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)
return;
- tt_change_node->change.flags = flags;
memset(tt_change_node->change.reserved, 0,
sizeof(tt_change_node->change.reserved));
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;
/* check for ADD+DEL, DEL+ADD, ADD+ADD or DEL+DEL events */
@@ -575,7 +623,6 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
struct batadv_tt_global_entry *tt_global,
const char *message)
{
- struct batadv_tt_global_entry *tt_removed_entry;
struct hlist_node *tt_removed_node;
batadv_dbg(BATADV_DBG_TT, bat_priv,
@@ -583,18 +630,67 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv,
tt_global->common.addr,
batadv_print_vid(tt_global->common.vid), message);
+ /* remove exactly this object when still present in hash */
tt_removed_node = batadv_hash_remove(bat_priv->tt.global_hash,
- batadv_compare_tt,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_global->common);
if (!tt_removed_node)
return;
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_global_entry,
- common.hash_entry);
- batadv_tt_global_entry_put(tt_removed_entry);
+ batadv_tt_global_entry_put(tt_global);
+}
+
+/**
+ * batadv_tt_local_add_roam() - handle roamed clients during batadv_tt_local_add()
+ * @bat_priv: the bat priv with all the mesh interface information
+ * @tt_global: the global TT entry
+ * @roamed_back: whether @tt_global roamed back
+ */
+static void batadv_tt_local_add_roam(struct batadv_priv *bat_priv,
+ struct batadv_tt_global_entry *tt_global,
+ bool roamed_back)
+{
+ struct batadv_tt_orig_list_entry *orig_entry;
+ struct hlist_head *head;
+
+ if (!tt_global)
+ return;
+
+ /* Check whether it is a roaming, but don't do anything if the roaming
+ * process has already been handled
+ */
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if (tt_global->common.flags & BATADV_TT_CLIENT_ROAM)
+ return;
+
+ if (!roamed_back) {
+ /* The global entry has to be marked as ROAMING and has to be
+ * kept for consistency purpose.
+ *
+ * batadv_tt_global_to_purge() evaluates roam_at as soon as it
+ * observes BATADV_TT_CLIENT_ROAM, so the timeout has to be
+ * stamped before the flag is published. Otherwise the entry can
+ * be deleted right away as "Roaming timeout".
+ */
+ tt_global->roam_at = jiffies;
+ tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
+ }
+ }
+
+ /* These node are probably going to update their tt table */
+ head = &tt_global->orig_list;
+ rcu_read_lock();
+ hlist_for_each_entry_rcu(orig_entry, head, list) {
+ batadv_send_roam_adv(bat_priv, tt_global->common.addr,
+ tt_global->common.vid,
+ orig_entry->orig_node);
+ }
+ rcu_read_unlock();
+
+ if (roamed_back)
+ batadv_tt_global_free(bat_priv, tt_global, "Roaming canceled");
}
/**
@@ -615,20 +711,19 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
{
struct batadv_priv *bat_priv = netdev_priv(mesh_iface);
struct batadv_tt_global_entry *tt_global = NULL;
- struct batadv_tt_orig_list_entry *orig_entry;
struct batadv_tt_local_entry *tt_local;
struct net *net = dev_net(mesh_iface);
struct net_device *in_dev = NULL;
struct batadv_meshif_vlan *vlan;
bool roamed_back = false;
bool iif_is_wifi = false;
- struct hlist_head *head;
int packet_size_max;
bool ret = false;
u8 remote_flags;
int hash_added;
int table_size;
u32 match_mark;
+ bool modified;
if (ifindex != BATADV_NULL_IFINDEX)
in_dev = dev_get_by_index(net, ifindex);
@@ -646,6 +741,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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",
@@ -656,6 +753,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
* flag can be reset like it was never enqueued
*/
tt_local->common.flags &= ~BATADV_TT_CLIENT_PENDING;
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto add_event;
}
@@ -671,6 +770,8 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
tt_local->common.flags &= ~BATADV_TT_CLIENT_ROAM;
roamed_back = true;
}
+ spin_unlock_bh(&tt_local->common.flags_lock);
+
goto check_roaming;
}
@@ -706,18 +807,21 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
(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
* a full table response going out before the next ttvn increment
* (consistency check)
*/
tt_local->common.flags = BATADV_TT_CLIENT_NEW;
- tt_local->common.vid = vid;
if (iif_is_wifi)
tt_local->common.flags |= BATADV_TT_CLIENT_WIFI;
- kref_init(&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
@@ -725,6 +829,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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,
@@ -741,31 +846,9 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
check_roaming:
- /* Check whether it is a roaming, but don't do anything if the roaming
- * process has already been handled
- */
- if (tt_global && !(tt_global->common.flags & BATADV_TT_CLIENT_ROAM)) {
- /* These node are probably going to update their tt table */
- head = &tt_global->orig_list;
- rcu_read_lock();
- hlist_for_each_entry_rcu(orig_entry, head, list) {
- batadv_send_roam_adv(bat_priv, tt_global->common.addr,
- tt_global->common.vid,
- orig_entry->orig_node);
- }
- rcu_read_unlock();
- if (roamed_back) {
- batadv_tt_global_free(bat_priv, tt_global,
- "Roaming canceled");
- } else {
- /* The global entry has to be marked as ROAMING and
- * has to be kept for consistency purpose
- */
- tt_global->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global->roam_at = jiffies;
- }
- }
+ 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
* understanding is flags are changing or not
*/
@@ -787,10 +870,13 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,
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
* entry so that all the nodes can get the new flags
*/
- if (remote_flags ^ (tt_local->common.flags & BATADV_TT_REMOTE_MASK))
+ if (modified)
batadv_tt_local_event(bat_priv, tt_local, BATADV_NO_FLAGS);
ret = true;
@@ -1115,6 +1201,7 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
struct batadv_meshif_vlan *vlan;
unsigned int last_seen_msecs;
void *hdr;
+ u16 flags;
u32 crc;
local = container_of(common, struct batadv_tt_local_entry, common);
@@ -1136,13 +1223,15 @@ batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
+ flags = batadv_tt_flags_get(common);
+
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
nla_put_u32(msg, BATADV_ATTR_TT_CRC32, crc) ||
nla_put_u16(msg, BATADV_ATTR_TT_VID, common->vid) ||
- nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, common->flags))
+ nla_put_u32(msg, BATADV_ATTR_TT_FLAGS, flags))
goto nla_put_failure;
- if (!(common->flags & BATADV_TT_CLIENT_NOPURGE) &&
+ if (!(flags & BATADV_TT_CLIENT_NOPURGE) &&
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, last_seen_msecs))
goto nla_put_failure;
@@ -1249,29 +1338,23 @@ int batadv_tt_local_dump(struct sk_buff *msg, struct netlink_callback *cb)
}
/**
- * batadv_tt_local_set_pending() - mark a local TT entry as pending removal
+ * batadv_tt_local_set_pending_event() - trigger events for TT pending removal
* @bat_priv: the bat priv with all the mesh interface information
* @tt_local_entry: local TT entry to mark
* @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 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.
+ * 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.
*/
static void
-batadv_tt_local_set_pending(struct batadv_priv *bat_priv,
- struct batadv_tt_local_entry *tt_local_entry,
- u16 flags, const char *message)
+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_event(bat_priv, tt_local_entry, flags);
- /* The local client has to be marked as "pending to be removed" but has
- * to be kept in the table in order to send it in a full table
- * response issued before the net ttvn increment (consistency check)
- */
- tt_local_entry->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",
tt_local_entry->common.addr,
@@ -1292,16 +1375,17 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid, const char *message,
bool roaming)
{
- struct batadv_tt_local_entry *tt_removed_entry;
struct batadv_tt_local_entry *tt_local_entry;
struct hlist_node *tt_removed_node;
u16 curr_flags = BATADV_NO_FLAGS;
+ bool pending = false;
u16 flags;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
goto out;
+ spin_lock_bh(&tt_local_entry->common.flags_lock);
curr_flags = tt_local_entry->common.flags;
flags = BATADV_TT_CLIENT_DEL;
@@ -1316,27 +1400,39 @@ u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,
}
if (!(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW)) {
- batadv_tt_local_set_pending(bat_priv, tt_local_entry, flags,
- message);
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ pending = true;
+ }
+ spin_unlock_bh(&tt_local_entry->common.flags_lock);
+
+ if (pending) {
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry, flags,
+ message);
goto out;
}
+
/* if this client has been added right now, it is possible to
* immediately purge it
*/
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,
+ batadv_compare_tt_entry,
batadv_choose_tt,
&tt_local_entry->common);
if (!tt_removed_node)
goto out;
+ /* 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);
+
/* drop reference of remove hash entry */
- tt_removed_entry = hlist_entry(tt_removed_node,
- struct batadv_tt_local_entry,
- common.hash_entry);
- batadv_tt_local_entry_put(tt_removed_entry);
+ batadv_tt_local_entry_put(tt_local_entry);
out:
batadv_tt_local_entry_put(tt_local_entry);
@@ -1361,21 +1457,37 @@ 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);
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE)
- continue;
- /* entry already marked for deletion */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING)
- continue;
+ scoped_guard(spinlock_bh, &tt_local_entry->common.flags_lock) {
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_NOPURGE) {
+ cont = true;
+ break;
+ }
+
+ /* entry already marked for deletion */
+ if (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) {
+ cont = true;
+ break;
+ }
+
+ if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout)) {
+ cont = true;
+ break;
+ }
+
+ tt_local_entry->common.flags |= BATADV_TT_CLIENT_PENDING;
+ }
- if (!batadv_has_timed_out(tt_local_entry->last_seen, timeout))
+ if (cont)
continue;
- batadv_tt_local_set_pending(bat_priv, tt_local_entry,
- BATADV_TT_CLIENT_DEL, "timed out");
+ batadv_tt_local_set_pending_event(bat_priv, tt_local_entry,
+ BATADV_TT_CLIENT_DEL, "timed out");
}
}
@@ -1581,8 +1693,10 @@ batadv_tt_global_sync_flags(struct batadv_tt_global_entry *tt_global)
flags |= orig_entry->flags;
rcu_read_unlock();
- flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
- tt_global->common.flags = flags;
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ flags |= tt_global->common.flags & (~BATADV_TT_SYNC_MASK);
+ tt_global->common.flags = flags;
+ }
}
/**
@@ -1664,8 +1778,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry;
struct batadv_tt_common_entry *common;
bool ret = false;
+ u16 global_flags;
u16 local_flags;
int hash_added;
+ bool delete;
/* ignore global entries from backbone nodes */
if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid))
@@ -1678,9 +1794,11 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* for a roaming advertisement instead of manually messing up the global
* table
*/
- if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry &&
- !(tt_local_entry->common.flags & BATADV_TT_CLIENT_NEW))
- goto out;
+ if ((flags & BATADV_TT_CLIENT_TEMP) && tt_local_entry) {
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (!(local_flags & BATADV_TT_CLIENT_NEW))
+ goto out;
+ }
if (!tt_global_entry) {
tt_global_entry = kmem_cache_zalloc(batadv_tg_cache,
@@ -1691,9 +1809,13 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
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))
+ 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
@@ -1733,8 +1855,10 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* originator list and add the new one orig_entry
*/
if (flags & BATADV_TT_CLIENT_TEMP) {
- if (!(common->flags & BATADV_TT_CLIENT_TEMP))
+ global_flags = batadv_tt_flags_get(common);
+ if (!(global_flags & BATADV_TT_CLIENT_TEMP))
goto out;
+
if (batadv_tt_global_entry_has_orig(tt_global_entry,
orig_node, NULL))
goto out_remove;
@@ -1742,6 +1866,9 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
goto add_orig_entry;
}
+ delete = false;
+
+ spin_lock_bh(&common->flags_lock);
/* if the client was temporary added before receiving the first
* OGM announcing it, we have to clear the TEMP flag. Also,
* remove the previous temporary orig node and re-add it
@@ -1749,7 +1876,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* is a non-temporary entry is preferred.
*/
if (common->flags & BATADV_TT_CLIENT_TEMP) {
- batadv_tt_global_del_orig_list(tt_global_entry);
+ delete = true;
common->flags &= ~BATADV_TT_CLIENT_TEMP;
}
@@ -1768,10 +1895,14 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* new one.
*/
if (common->flags & BATADV_TT_CLIENT_ROAM) {
- batadv_tt_global_del_orig_list(tt_global_entry);
- 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);
+
+ if (delete)
+ batadv_tt_global_del_orig_list(tt_global_entry);
}
add_orig_entry:
/* add the new orig_entry (if needed) or update it */
@@ -1795,6 +1926,8 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
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))
@@ -1802,6 +1935,7 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
* roaming state anymore.
*/
tt_global_entry->common.flags &= ~BATADV_TT_CLIENT_ROAM;
+ spin_unlock_bh(&tt_global_entry->common.flags_lock);
out:
batadv_tt_global_entry_put(tt_global_entry);
@@ -1871,9 +2005,9 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
struct batadv_tt_orig_list_entry *orig,
bool best)
{
- u16 flags = (common->flags & (~BATADV_TT_SYNC_MASK)) | orig->flags;
struct batadv_orig_node_vlan *vlan;
u8 last_ttvn;
+ u16 flags;
void *hdr;
u32 crc;
@@ -1892,6 +2026,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq,
if (!hdr)
return -ENOBUFS;
+ flags = (batadv_tt_flags_get(common) & (~BATADV_TT_SYNC_MASK)) | orig->flags;
last_ttvn = READ_ONCE(orig->orig_node->last_ttvn);
if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) ||
@@ -2179,9 +2314,12 @@ batadv_tt_global_del_roaming(struct batadv_priv *bat_priv,
rcu_read_unlock();
if (last_entry) {
- /* its the last one, mark for roaming. */
- tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
- tt_global_entry->roam_at = jiffies;
+ scoped_guard(spinlock_bh, &tt_global_entry->common.flags_lock) {
+ /* its the last one, mark for roaming. */
+ tt_global_entry->roam_at = jiffies;
+
+ tt_global_entry->common.flags |= BATADV_TT_CLIENT_ROAM;
+ }
} else {
/* there is another entry, we can simply delete this
* one and can still use the other one.
@@ -2330,16 +2468,18 @@ static bool batadv_tt_global_to_purge(struct batadv_tt_global_entry *tt_global,
unsigned long temp_timeout = BATADV_TT_CLIENT_TEMP_TIMEOUT;
bool purge = false;
- if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
- batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
- purge = true;
- *msg = "Roaming timeout\n";
- }
+ scoped_guard(spinlock_bh, &tt_global->common.flags_lock) {
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_ROAM) &&
+ batadv_has_timed_out(tt_global->roam_at, roam_timeout)) {
+ purge = true;
+ *msg = "Roaming timeout\n";
+ }
- if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
- batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
- purge = true;
- *msg = "Temporary client timeout\n";
+ if ((tt_global->common.flags & BATADV_TT_CLIENT_TEMP) &&
+ batadv_has_timed_out(tt_global->common.added_at, temp_timeout)) {
+ purge = true;
+ *msg = "Temporary client timeout\n";
+ }
}
return purge;
@@ -2437,8 +2577,8 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv)
/**
* _batadv_is_ap_isolated() - check whether two clients are AP-isolated from
* each other
- * @tt_local_entry: local TT entry of the sending client
- * @tt_global_entry: global TT entry of the destination client
+ * @tt_local_entry: local TT entry of one local client
+ * @tt_global_entry: global TT entry of the remote client
*
* Return: true if traffic between the two clients should be dropped because
* either both are WiFi clients or both carry the ISOLATION flag; false
@@ -2448,13 +2588,19 @@ static bool
_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,
struct batadv_tt_global_entry *tt_global_entry)
{
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_WIFI &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_WIFI)
+ u16 global_flags;
+ u16 local_flags;
+
+ global_flags = batadv_tt_flags_get(&tt_global_entry->common);
+ local_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
+ if (local_flags & BATADV_TT_CLIENT_WIFI &&
+ global_flags & BATADV_TT_CLIENT_WIFI)
return true;
/* check if the two clients are marked as isolated */
- if (tt_local_entry->common.flags & BATADV_TT_CLIENT_ISOLA &&
- tt_global_entry->common.flags & BATADV_TT_CLIENT_ISOLA)
+ if (local_flags & BATADV_TT_CLIENT_ISOLA &&
+ global_flags & BATADV_TT_CLIENT_ISOLA)
return true;
return false;
@@ -2483,11 +2629,15 @@ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,
struct batadv_tt_local_entry *tt_local_entry = NULL;
struct batadv_tt_orig_list_entry *best_entry;
struct batadv_orig_node *orig_node = NULL;
+ u16 flags;
if (src && batadv_vlan_ap_isola_get(bat_priv, vid)) {
tt_local_entry = batadv_tt_local_hash_find(bat_priv, src, vid);
- if (!tt_local_entry ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING))
+ if (!tt_local_entry)
+ goto out;
+
+ flags = batadv_tt_flags_get(&tt_local_entry->common);
+ if (flags & BATADV_TT_CLIENT_PENDING)
goto out;
}
@@ -2562,6 +2712,8 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
tt_global = container_of(tt_common,
struct batadv_tt_global_entry,
common);
@@ -2571,18 +2723,21 @@ static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv,
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* Roaming clients are in the global table for
* consistency only. They don't have to be
* taken into account while computing the
* global crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_ROAM)
+ if (tt_flags & BATADV_TT_CLIENT_ROAM)
continue;
+
/* Temporary clients have not been announced yet, so
* they have to be skipped while computing the global
* crc
*/
- if (tt_common->flags & BATADV_TT_CLIENT_TEMP)
+ if (tt_flags & BATADV_TT_CLIENT_TEMP)
continue;
/* find out if this global entry is announced by this
@@ -2642,18 +2797,24 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
rcu_read_lock();
hlist_for_each_entry_rcu(tt_common, head, hash_entry) {
+ u16 tt_flags;
+
/* compute the CRC only for entries belonging to the
* VLAN identified by vid
*/
if (tt_common->vid != vid)
continue;
+ tt_flags = batadv_tt_flags_get(tt_common);
+
/* not yet committed clients have not to be taken into
* account while computing the CRC
*/
- if (tt_common->flags & BATADV_TT_CLIENT_NEW)
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
continue;
+ flags = tt_flags & BATADV_TT_SYNC_MASK;
+
/* use network order to read the VID: this ensures that
* every node reads the bytes in the same order.
*/
@@ -2663,7 +2824,6 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv,
/* compute the CRC on flags that have to be kept in sync
* among nodes
*/
- flags = tt_common->flags & BATADV_TT_SYNC_MASK;
crc_tmp = crc32c(crc_tmp, &flags, sizeof(flags));
crc ^= crc32c(crc_tmp, tt_common->addr, ETH_ALEN);
@@ -2821,17 +2981,19 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_local_valid(const void *entry_ptr,
+static bool batadv_tt_local_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_NEW)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_NEW)
return false;
if (flags)
- *flags = tt_common_entry->flags;
+ *flags = tt_flags;
return true;
}
@@ -2848,16 +3010,18 @@ static bool batadv_tt_local_valid(const void *entry_ptr,
*
* Return: true if the entry is a valid, false otherwise.
*/
-static bool batadv_tt_global_valid(const void *entry_ptr,
+static bool batadv_tt_global_valid(void *entry_ptr,
const void *data_ptr,
u8 *flags)
{
- const struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
- const struct batadv_tt_global_entry *tt_global_entry;
+ struct batadv_tt_common_entry *tt_common_entry = entry_ptr;
const struct batadv_orig_node *orig_node = data_ptr;
+ struct batadv_tt_global_entry *tt_global_entry;
+ u16 tt_flags;
- if (tt_common_entry->flags & BATADV_TT_CLIENT_ROAM ||
- tt_common_entry->flags & BATADV_TT_CLIENT_TEMP)
+ tt_flags = batadv_tt_flags_get(tt_common_entry);
+ if (tt_flags & BATADV_TT_CLIENT_ROAM ||
+ tt_flags & BATADV_TT_CLIENT_TEMP)
return false;
tt_global_entry = container_of(tt_common_entry,
@@ -2886,7 +3050,7 @@ static bool batadv_tt_global_valid(const void *entry_ptr,
static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,
struct batadv_hashtable *hash,
void *tvlv_buff, u16 tt_len,
- bool (*valid_cb)(const void *,
+ bool (*valid_cb)(void *,
const void *,
u8 *flags),
void *cb_data)
@@ -3511,19 +3675,21 @@ bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,
unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ u16 tt_flags;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
+
+ tt_flags = batadv_tt_flags_get(&tt_local_entry->common);
+
/* Check if the client has been logically deleted (but is kept for
* consistency purpose)
*/
- if ((tt_local_entry->common.flags & BATADV_TT_CLIENT_PENDING) ||
- (tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM))
- goto out;
- ret = true;
-out:
+ ret = !((tt_flags & BATADV_TT_CLIENT_PENDING) ||
+ (tt_flags & BATADV_TT_CLIENT_ROAM));
+
batadv_tt_local_entry_put(tt_local_entry);
return ret;
}
@@ -3782,16 +3948,13 @@ void batadv_tt_free(struct batadv_priv *bat_priv)
}
/**
- * batadv_tt_local_set_flags() - set or unset the specified flags on the local
- * table and possibly count them in the TT size
+ * batadv_tt_local_transition_new() - unset the NEW flag on the local
+ * table and count them in the TT size
* @bat_priv: the bat priv with all the mesh interface information
- * @flags: the flag to switch
- * @enable: whether to set or unset the flag
- * @count: whether to increase the TT size by the number of changed entries
*/
-static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
- bool enable, bool count)
+static void batadv_tt_local_transition_new(struct batadv_priv *bat_priv)
{
+ spinlock_t *list_lock; /* protects write access to the hash lists */
struct batadv_hashtable *hash = bat_priv->tt.local_hash;
struct batadv_tt_common_entry *tt_common_entry;
struct hlist_head *head;
@@ -3802,27 +3965,28 @@ static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags,
for (i = 0; i < hash->size; i++) {
head = &hash->table[i];
+ list_lock = &hash->list_locks[i];
- rcu_read_lock();
- hlist_for_each_entry_rcu(tt_common_entry,
- head, hash_entry) {
- if (enable) {
- if ((tt_common_entry->flags & flags) == flags)
- continue;
- tt_common_entry->flags |= flags;
- } else {
- if (!(tt_common_entry->flags & flags))
- continue;
- tt_common_entry->flags &= ~flags;
+ spin_lock_bh(list_lock);
+ hlist_for_each_entry(tt_common_entry, head, hash_entry) {
+ bool cont = false;
+
+ scoped_guard(spinlock_bh, &tt_common_entry->flags_lock) {
+ if (!(tt_common_entry->flags & BATADV_TT_CLIENT_NEW)) {
+ cont = true;
+ break;
+ }
+
+ tt_common_entry->flags &= ~BATADV_TT_CLIENT_NEW;
}
- if (!count)
+ if (cont)
continue;
batadv_tt_local_size_inc(bat_priv,
tt_common_entry->vid);
}
- rcu_read_unlock();
+ spin_unlock_bh(list_lock);
}
}
@@ -3854,16 +4018,31 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
spin_lock_bh(list_lock);
hlist_for_each_entry_safe(tt_common, node_tmp, head,
hash_entry) {
- if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING))
- continue;
+ bool cont = false;
- batadv_dbg(BATADV_DBG_TT, bat_priv,
- "Deleting local tt entry (%pM, vid: %d): pending\n",
- tt_common->addr,
- batadv_print_vid(tt_common->vid));
+ scoped_guard(spinlock_bh, &tt_common->flags_lock) {
+ if (!(tt_common->flags & BATADV_TT_CLIENT_PENDING)) {
+ cont = true;
+ break;
+ }
+
+ batadv_dbg(BATADV_DBG_TT, bat_priv,
+ "Deleting local tt entry (%pM, vid: %d): pending\n",
+ tt_common->addr,
+ batadv_print_vid(tt_common->vid));
+
+ hlist_del_rcu(&tt_common->hash_entry);
+
+ /* An entry which still carries BATADV_TT_CLIENT_NEW was
+ * never counted and must not be uncounted here.
+ */
+ if (!(tt_common->flags & BATADV_TT_CLIENT_NEW))
+ batadv_tt_local_size_dec(bat_priv, tt_common->vid);
+ }
+
+ if (cont)
+ continue;
- batadv_tt_local_size_dec(bat_priv, tt_common->vid);
- hlist_del_rcu(&tt_common->hash_entry);
tt_local = container_of(tt_common,
struct batadv_tt_local_entry,
common);
@@ -3891,7 +4070,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv)
return;
}
- batadv_tt_local_set_flags(bat_priv, BATADV_TT_CLIENT_NEW, false, true);
+ batadv_tt_local_transition_new(bat_priv);
batadv_tt_local_purge_pending_clients(bat_priv);
batadv_tt_local_update_crc(bat_priv);
@@ -4061,15 +4240,16 @@ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_global_entry *tt_global_entry;
- bool ret = false;
+ bool ret;
tt_global_entry = batadv_tt_global_hash_find(bat_priv, addr, vid);
if (!tt_global_entry)
- goto out;
+ return false;
+
+ ret = batadv_tt_flags_get(&tt_global_entry->common) & BATADV_TT_CLIENT_ROAM;
- ret = tt_global_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_global_entry_put(tt_global_entry);
-out:
+
return ret;
}
@@ -4087,15 +4267,16 @@ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,
u8 *addr, unsigned short vid)
{
struct batadv_tt_local_entry *tt_local_entry;
- bool ret = false;
+ bool ret;
tt_local_entry = batadv_tt_local_hash_find(bat_priv, addr, vid);
if (!tt_local_entry)
- goto out;
+ return false;
+
+ ret = batadv_tt_flags_get(&tt_local_entry->common) & BATADV_TT_CLIENT_ROAM;
- ret = tt_local_entry->common.flags & BATADV_TT_CLIENT_ROAM;
batadv_tt_local_entry_put(tt_local_entry);
-out:
+
return ret;
}
@@ -4404,7 +4585,7 @@ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv,
if (!tt)
return false;
- ret = tt->common.flags & BATADV_TT_CLIENT_ISOLA;
+ ret = batadv_tt_flags_get(&tt->common) & BATADV_TT_CLIENT_ISOLA;
batadv_tt_global_entry_put(tt);
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 9bdc5a3e799e2..67872927cfb50 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -410,7 +410,7 @@ struct batadv_orig_bat_iv {
*/
struct batadv_orig_node {
/** @orig: originator ethernet address */
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @ifinfo_list: list for routers per outgoing interface */
struct hlist_head ifinfo_list;
@@ -634,12 +634,12 @@ struct batadv_hardif_neigh_node {
struct hlist_node list;
/** @addr: the MAC address of the neighboring interface */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/**
* @orig: the address of the originator this neighbor node belongs to
*/
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @if_incoming: pointer to incoming hard-interface */
struct batadv_hard_iface *if_incoming;
@@ -677,7 +677,7 @@ struct batadv_neigh_node {
#endif
/** @addr: the MAC address of the neighboring interface */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @ifinfo_list: list for routing metrics per outgoing interface */
struct hlist_head ifinfo_list;
@@ -777,7 +777,7 @@ struct batadv_neigh_ifinfo {
*/
struct batadv_bcast_duplist_entry {
/** @orig: mac address of orig node originating the broadcast */
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @crc: crc32 checksum of broadcast payload */
u32 crc;
@@ -1085,7 +1085,7 @@ struct batadv_priv_bla {
struct batadv_hashtable *backbone_hash;
/** @loopdetect_addr: MAC address used for own loopdetection frames */
- u8 loopdetect_addr[ETH_ALEN];
+ u8 loopdetect_addr[ETH_ALEN] __aligned(2);
/**
* @loopdetect_lasttime: time when the loopdetection frames were sent
@@ -1352,7 +1352,7 @@ struct batadv_tp_vars_common {
struct batadv_priv *bat_priv;
/** @other_end: mac address of remote */
- u8 other_end[ETH_ALEN];
+ u8 other_end[ETH_ALEN] __aligned(2);
/** @session: TP session identifier */
u8 session[2];
@@ -1765,7 +1765,7 @@ struct batadv_bla_backbone_gw {
* @orig: originator address of backbone node (mac address of primary
* iface)
*/
- u8 orig[ETH_ALEN];
+ u8 orig[ETH_ALEN] __aligned(2);
/** @vid: vlan id this gateway was detected on */
unsigned short vid;
@@ -1810,7 +1810,7 @@ struct batadv_bla_backbone_gw {
*/
struct batadv_bla_claim {
/** @addr: mac address of claimed non-mesh client */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: vlan id this client was detected on */
unsigned short vid;
@@ -1840,7 +1840,7 @@ struct batadv_bla_claim {
*/
struct batadv_tt_common_entry {
/** @addr: mac address of non-mesh client */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: VLAN identifier */
unsigned short vid;
@@ -1851,12 +1851,21 @@ struct batadv_tt_common_entry {
*/
struct hlist_node hash_entry;
- /** @flags: various state handling flags (see batadv_tt_client_flags) */
+ /**
+ * @flags: various state handling flags (see batadv_tt_client_flags),
+ * protected by @flags_lock
+ */
u16 flags;
/** @added_at: timestamp used for purging stale tt common entries */
unsigned long added_at;
+ /**
+ * @flags_lock: protect modifications of @flags and
+ * @batadv_tt_global_entry.roam_at
+ */
+ spinlock_t flags_lock;
+
/** @refcount: number of contexts the object is used */
struct kref refcount;
@@ -1942,7 +1951,7 @@ struct batadv_tt_req_node {
/**
* @addr: mac address of the originator this request was sent to
*/
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @issued_at: timestamp used for purging stale tt requests */
unsigned long issued_at;
@@ -1959,7 +1968,7 @@ struct batadv_tt_req_node {
*/
struct batadv_tt_roam_node {
/** @addr: mac address of the client in the roaming phase */
- u8 addr[ETH_ALEN];
+ u8 addr[ETH_ALEN] __aligned(2);
/** @vid: VLAN identifier */
u16 vid;
@@ -2087,14 +2096,14 @@ struct batadv_algo_neigh_ops {
struct batadv_hard_iface *if_outgoing2);
/**
- * @is_similar_or_better: check if neigh1 is equally similar or better
- * than neigh2 for their respective outgoing interface from the metric
+ * @is_similar_or_better: check if @candidate is equally similar or better
+ * than @reference for their respective outgoing interface from the metric
* prospective
*/
- bool (*is_similar_or_better)(struct batadv_neigh_node *neigh1,
- struct batadv_hard_iface *if_outgoing1,
- struct batadv_neigh_node *neigh2,
- struct batadv_hard_iface *if_outgoing2);
+ bool (*is_similar_or_better)(struct batadv_neigh_node *candidate,
+ struct batadv_hard_iface *if_outgoing_cand,
+ struct batadv_neigh_node *reference,
+ struct batadv_hard_iface *if_outgoing_ref);
/** @dump: dump neighbors to a netlink socket (optional) */
void (*dump)(struct sk_buff *msg, struct netlink_callback *cb,
@@ -2204,7 +2213,7 @@ struct batadv_hw_addr {
struct hlist_node list;
/** @addr: the MAC address of this list entry */
- unsigned char addr[ETH_ALEN];
+ unsigned char addr[ETH_ALEN] __aligned(2);
};
/**
|
| 17/3 | 2026/08/31 20:32 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 22620 output: 29 thoughts: 1308 Thoughts: **KMSAN Fuzzing Session Assessment** Okay, so the question is whether this patch series warrants a dedicated KMSAN fuzzing session. I need to figure out if there are any potential uninitialized memory issues either introduced or exposed by the changes. Let's break this down. First, I see several source files impacted, and it looks like a combination of parameter renames, minor logic fixes, and some data structure modifications. The alignment changes using `__aligned(2)` immediately catch my eye, especially in relation to Ethernet addresses. I know those alignment pragmas are important to consider. Specifically, the alignment changes are added to several structures in `types.h` and some local arrays. I need to carefully analyze these alignment changes within the context of the affected structures. I need to make sure this doesn't introduce padding issues or unexpected struct layout changes that could lead to read-before-write issues. For example: * I see a bunch of `u8 addr[ETH_ALEN] __aligned(2)` in `types.h`. `ETH_ALEN` is 6 bytes. 6 bytes aligned to 2 bytes is perfectly valid, so that's not automatically a problem. But I need to look at *how* these fields are used, where they are allocated, and if the alignment changes could interact with the compiler's structure layout decisions. * I see a new spinlock, `flags_lock`, being added to `struct batadv_tt_common_entry`. That's interesting, and I need to check where it's initialized and how it's used. Are there race conditions being addressed here, and if so, how? Let's check where the spinlock is initialized. I see `spin_lock_init()` calls in `batadv_tt_local_add()` and `batadv_tt_global_add()`. That looks standard. Are there other places where `batadv_tt_common_entry` is initialized or allocated? I'll need to search the codebase for `batadv_tg_cache` and `batadv_tl_cache` or `tt_common`. This is the most likely location for a problem. The translation table changes with the spinlocks is the most interesting part of this patch series from a KMSAN perspective. Race conditions in the roaming and purging logic are likely targets for this type of check. The `batadv_compare_tt_entry` and the refactoring of dumping functions to snapshot the flags with `batadv_tt_flags_get(common)` might be helpful. But I need to be sure the lock is being held for the duration of the accesses. This is where I'll need to focus my attention. It looks like it addresses race conditions so it might be worthwhile. My initial assessment is that the alignment changes are unlikely to be a *direct* source of uninitialized memory problems, but they could indirectly expose existing issues. The most significant area of concern is the spinlock introduction and the refactoring around the translation table, and I will focus on that area. I might need a dedicated session to confirm. |
| 18/3 | 2026/08/31 20:32 | tool | grepper |
0mArgs:{
"Expression": "kmem_cache_alloc.*batadv_t[gl]_cache"
}Results: {
"Output": "net/batman-adv/translation-table.c=709=bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-788-\nnet/batman-adv/translation-table.c:789:\ttt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);\nnet/batman-adv/translation-table.c-790-\tif (!tt_local)\n"
} |
| 19/3 | 2026/08/31 20:33 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 24756 output: 20 thoughts: 15 Thoughts: Here's my take on those thoughts, tailored for an expert audience: **Diving Deeper into the Cache** Okay, so we're looking at optimizing this particular aspect. We've got our usual suspects, but I'm feeling that nagging sense that we might be missing a critical piece of the puzzle. We can't just stop at the obvious entry points. To truly get a comprehensive understanding and potential performance bottlenecks, I really need to check `batadv_tg_cache` as well. It's too important to skip, and it could hold the key to a major breakthrough in optimizing this area. It's a key piece and I'd be remiss if I didn't verify it. |
| 20/3 | 2026/08/31 20:33 | tool | grepper |
0mArgs:{
"Expression": "batadv_tg_cache"
}Results: {
"Output": "net/batman-adv/translation-table.c=57=static struct kmem_cache *batadv_tl_cache __read_mostly;\nnet/batman-adv/translation-table.c:58:static struct kmem_cache *batadv_tg_cache __read_mostly;\nnet/batman-adv/translation-table.c-59-static struct kmem_cache *batadv_tt_orig_cache __read_mostly;\n--\nnet/batman-adv/translation-table.c=1772=static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-1803-\tif (!tt_global_entry) {\nnet/batman-adv/translation-table.c:1804:\t\ttt_global_entry = kmem_cache_zalloc(batadv_tg_cache,\nnet/batman-adv/translation-table.c-1805-\t\t\t\t\t\t GFP_ATOMIC);\n--\nnet/batman-adv/translation-table.c=4600=int __init batadv_tt_cache_init(void)\n--\nnet/batman-adv/translation-table.c-4613-\nnet/batman-adv/translation-table.c:4614:\tbatadv_tg_cache = kmem_cache_create(\"batadv_tg_cache\", tg_size, 0,\nnet/batman-adv/translation-table.c-4615-\t\t\t\t\t SLAB_HWCACHE_ALIGN, NULL);\nnet/batman-adv/translation-table.c:4616:\tif (!batadv_tg_cache)\nnet/batman-adv/translation-table.c-4617-\t\tgoto err_tt_tl_destroy;\n--\nnet/batman-adv/translation-table.c-4654-err_tt_tg_destroy:\nnet/batman-adv/translation-table.c:4655:\tkmem_cache_destroy(batadv_tg_cache);\nnet/batman-adv/translation-table.c:4656:\tbatadv_tg_cache = NULL;\nnet/batman-adv/translation-table.c-4657-err_tt_tl_destroy:\n--\nnet/batman-adv/translation-table.c=4667=void batadv_tt_cache_destroy(void)\n--\nnet/batman-adv/translation-table.c-4669-\tkmem_cache_destroy(batadv_tl_cache);\nnet/batman-adv/translation-table.c:4670:\tkmem_cache_destroy(batadv_tg_cache);\nnet/batman-adv/translation-table.c-4671-\tkmem_cache_destroy(batadv_tt_orig_cache);\n"
} |
| 21/3 | 2026/08/31 20:33 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 25652 output: 40 thoughts: 28 Thoughts: Here's my summary, as if I were the one thinking these thoughts, targeting an expert audience: **Diving into `batadv_tt_local_add()`** Okay, time to dig into this. I need to refresh my memory on how BATMAN Advanced handles local translation table entries. Let's start with `batadv_tt_local_add()` around line 789 in `translation-table.c`. I expect to find the core logic for adding new local entries there, probably involving hash table lookups or insertions, maybe some aging considerations. Hopefully, there's a quick and dirty way to identify the exact data structures and locking primitives used. Let's see what we've got! I'm curious if they used an RCU to optimise this. |
| 22/3 | 2026/08/31 20:33 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/translation-table.c",
"FirstLine": 785,
"LineCount": 60
}Results: {
"Contents": " 785:\t\t\t\t\t\t table_size, packet_size_max, addr);\n 786:\t\t\tgoto out;\n 787:\t\t}\n 788:\t\n 789:\t\ttt_local = kmem_cache_alloc(batadv_tl_cache, GFP_ATOMIC);\n 790:\t\tif (!tt_local)\n 791:\t\t\tgoto out;\n 792:\t\n 793:\t\t/* increase the refcounter of the related vlan */\n 794:\t\tvlan = batadv_meshif_vlan_get(bat_priv, vid);\n 795:\t\tif (!vlan) {\n 796:\t\t\tnet_ratelimited_function(batadv_info, mesh_iface,\n 797:\t\t\t\t\t\t \"adding TT local entry %pM to non-existent VLAN %d\\n\",\n 798:\t\t\t\t\t\t addr, batadv_print_vid(vid));\n 799:\t\t\tkmem_cache_free(batadv_tl_cache, tt_local);\n 800:\t\t\ttt_local = NULL;\n 801:\t\t\tgoto out;\n 802:\t\t}\n 803:\t\n 804:\t\tbatadv_dbg(BATADV_DBG_TT, bat_priv,\n 805:\t\t\t \"Creating new local tt entry: %pM (vid: %d, ttvn: %d)\\n\",\n 806:\t\t\t addr, batadv_print_vid(vid),\n 807:\t\t\t (u8)atomic_read(\u0026bat_priv-\u003ett.vn));\n 808:\t\n 809:\t\tether_addr_copy(tt_local-\u003ecommon.addr, addr);\n 810:\t\ttt_local-\u003ecommon.vid = vid;\n 811:\t\tkref_init(\u0026tt_local-\u003ecommon.refcount);\n 812:\t\ttt_local-\u003elast_seen = jiffies;\n 813:\t\ttt_local-\u003ecommon.added_at = tt_local-\u003elast_seen;\n 814:\t\ttt_local-\u003evlan = vlan;\n 815:\t\tspin_lock_init(\u0026tt_local-\u003ecommon.flags_lock);\n 816:\t\n 817:\t\tspin_lock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n 818:\t\t/* The local entry has to be marked as NEW to avoid to send it in\n 819:\t\t * a full table response going out before the next ttvn increment\n 820:\t\t * (consistency check)\n 821:\t\t */\n 822:\t\ttt_local-\u003ecommon.flags = BATADV_TT_CLIENT_NEW;\n 823:\t\tif (iif_is_wifi)\n 824:\t\t\ttt_local-\u003ecommon.flags |= BATADV_TT_CLIENT_WIFI;\n 825:\t\n 826:\t\t/* the batman interface mac and multicast addresses should never be\n 827:\t\t * purged\n 828:\t\t */\n 829:\t\tif (batadv_compare_eth(addr, mesh_iface-\u003edev_addr) ||\n 830:\t\t is_multicast_ether_addr(addr))\n 831:\t\t\ttt_local-\u003ecommon.flags |= BATADV_TT_CLIENT_NOPURGE;\n 832:\t\tspin_unlock_bh(\u0026tt_local-\u003ecommon.flags_lock);\n 833:\t\n 834:\t\tkref_get(\u0026tt_local-\u003ecommon.refcount);\n 835:\t\thash_added = batadv_hash_add(bat_priv-\u003ett.local_hash, batadv_compare_tt,\n 836:\t\t\t\t\t batadv_choose_tt, \u0026tt_local-\u003ecommon,\n 837:\t\t\t\t\t \u0026tt_local-\u003ecommon.hash_entry);\n 838:\t\n 839:\t\tif (unlikely(hash_added != 0)) {\n 840:\t\t\t/* remove the reference for the hash */\n 841:\t\t\tbatadv_tt_local_entry_put(tt_local);\n 842:\t\t\tgoto out;\n 843:\t\t}\n 844:\t\n"
} |
| 23/3 | 2026/08/31 20:33 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 26933 output: 23 thoughts: 128 Thoughts: **Analyzing the Batadv TT Local Entry Structure** Okay, let's dive into the `batadv_tt_local_entry` and `batadv_tt_common_entry` structures. I need to make sure I've got a complete picture of initialization in the local table. So, running down the fields, I see `addr`, `vid`, `refcount`, `last_seen`, `added_at`, `vlan`, `flags_lock`, and `flags` are all handled during initialization. The `hash_entry` is clearly taken care of either by `batadv_hash_add` or the standard hlist functionality, which makes sense. I think that covers the main initialization points, but I want to be absolutely certain. Time to double-check against the definitive source. I'll open up `types.h` and give `struct batadv_tt_local_entry` another, closer look. Just want to rule out anything I might be missing. |
| 24/3 | 2026/08/31 20:33 | tool | grepper |
0mArgs:{
"Expression": "struct batadv_tt_local_entry"
}Results: {
"Output": "net/batman-adv/translation-table.c=149=batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-194- */\nnet/batman-adv/translation-table.c:195:static struct batadv_tt_local_entry *\nnet/batman-adv/translation-table.c-196-batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-198-{\nnet/batman-adv/translation-table.c:199:\tstruct batadv_tt_local_entry *tt_local_entry = NULL;\nnet/batman-adv/translation-table.c-200-\tstruct batadv_tt_common_entry *tt_common_entry;\n--\nnet/batman-adv/translation-table.c-205-\t\ttt_local_entry = container_of(tt_common_entry,\nnet/batman-adv/translation-table.c:206:\t\t\t\t\t struct batadv_tt_local_entry,\nnet/batman-adv/translation-table.c-207-\t\t\t\t\t common);\n--\nnet/batman-adv/translation-table.c=241=static void batadv_tt_local_entry_release(struct kref *ref)\nnet/batman-adv/translation-table.c-242-{\nnet/batman-adv/translation-table.c:243:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-244-\nnet/batman-adv/translation-table.c:245:\ttt_local_entry = container_of(ref, struct batadv_tt_local_entry,\nnet/batman-adv/translation-table.c-246-\t\t\t\t common.refcount);\n--\nnet/batman-adv/translation-table.c=258=static void\nnet/batman-adv/translation-table.c:259:batadv_tt_local_entry_put(struct batadv_tt_local_entry *tt_local_entry)\nnet/batman-adv/translation-table.c-260-{\n--\nnet/batman-adv/translation-table.c=468=static void batadv_tt_local_event(struct batadv_priv *bat_priv,\nnet/batman-adv/translation-table.c:469:\t\t\t\t struct batadv_tt_local_entry *tt_local_entry,\nnet/batman-adv/translation-table.c-470-\t\t\t\t u8 event_flags)\n--\nnet/batman-adv/translation-table.c=709=bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-713-\tstruct batadv_tt_global_entry *tt_global = NULL;\nnet/batman-adv/translation-table.c:714:\tstruct batadv_tt_local_entry *tt_local;\nnet/batman-adv/translation-table.c-715-\tstruct net *net = dev_net(mesh_iface);\n--\nnet/batman-adv/translation-table.c=1195=batadv_tt_local_dump_entry(struct sk_buff *msg, u32 portid,\n--\nnet/batman-adv/translation-table.c-1199-{\nnet/batman-adv/translation-table.c:1200:\tstruct batadv_tt_local_entry *local;\nnet/batman-adv/translation-table.c-1201-\tstruct batadv_meshif_vlan *vlan;\n--\nnet/batman-adv/translation-table.c-1206-\nnet/batman-adv/translation-table.c:1207:\tlocal = container_of(common, struct batadv_tt_local_entry, common);\nnet/batman-adv/translation-table.c-1208-\tlast_seen_msecs = jiffies_to_msecs(jiffies - local-\u003elast_seen);\n--\nnet/batman-adv/translation-table.c=1352=batadv_tt_local_set_pending_event(struct batadv_priv *bat_priv,\nnet/batman-adv/translation-table.c:1353:\t\t\t\t struct batadv_tt_local_entry *tt_local_entry,\nnet/batman-adv/translation-table.c-1354-\t\t\t\t u16 flags, const char *message)\n--\nnet/batman-adv/translation-table.c=1374=u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-1377-{\nnet/batman-adv/translation-table.c:1378:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-1379-\tstruct hlist_node *tt_removed_node;\n--\nnet/batman-adv/translation-table.c=1450=static void batadv_tt_local_purge_list(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-1454-\tstruct batadv_tt_common_entry *tt_common_entry;\nnet/batman-adv/translation-table.c:1455:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-1456-\tstruct hlist_node *node_tmp;\n--\nnet/batman-adv/translation-table.c-1462-\t\ttt_local_entry = container_of(tt_common_entry,\nnet/batman-adv/translation-table.c:1463:\t\t\t\t\t struct batadv_tt_local_entry,\nnet/batman-adv/translation-table.c-1464-\t\t\t\t\t common);\n--\nnet/batman-adv/translation-table.c=1525=static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)\n--\nnet/batman-adv/translation-table.c-1528-\tstruct batadv_tt_common_entry *tt_common_entry;\nnet/batman-adv/translation-table.c:1529:\tstruct batadv_tt_local_entry *tt_local;\nnet/batman-adv/translation-table.c-1530-\tstruct batadv_hashtable *hash;\n--\nnet/batman-adv/translation-table.c-1548-\t\t\ttt_local = container_of(tt_common_entry,\nnet/batman-adv/translation-table.c:1549:\t\t\t\t\t\tstruct batadv_tt_local_entry,\nnet/batman-adv/translation-table.c-1550-\t\t\t\t\t\tcommon);\n--\nnet/batman-adv/translation-table.c=1772=static bool batadv_tt_global_add(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-1777-\tstruct batadv_tt_global_entry *tt_global_entry;\nnet/batman-adv/translation-table.c:1778:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-1779-\tstruct batadv_tt_common_entry *common;\n--\nnet/batman-adv/translation-table.c=2342=static void batadv_tt_global_del(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-2346-{\nnet/batman-adv/translation-table.c:2347:\tstruct batadv_tt_local_entry *local_entry = NULL;\nnet/batman-adv/translation-table.c-2348-\tstruct batadv_tt_global_entry *tt_global_entry;\n--\nnet/batman-adv/translation-table.c=2587=static bool\nnet/batman-adv/translation-table.c:2588:_batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry,\nnet/batman-adv/translation-table.c-2589-\t\t struct batadv_tt_global_entry *tt_global_entry)\n--\nnet/batman-adv/translation-table.c=2623=struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-2628-\tstruct batadv_tt_global_entry *tt_global_entry = NULL;\nnet/batman-adv/translation-table.c:2629:\tstruct batadv_tt_local_entry *tt_local_entry = NULL;\nnet/batman-adv/translation-table.c-2630-\tstruct batadv_tt_orig_list_entry *best_entry;\n--\nnet/batman-adv/translation-table.c=3674=bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr,\n--\nnet/batman-adv/translation-table.c-3676-{\nnet/batman-adv/translation-table.c:3677:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-3678-\tu16 tt_flags;\n--\nnet/batman-adv/translation-table.c=4001=static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)\n--\nnet/batman-adv/translation-table.c-4005-\tstruct batadv_tt_common_entry *tt_common;\nnet/batman-adv/translation-table.c:4006:\tstruct batadv_tt_local_entry *tt_local;\nnet/batman-adv/translation-table.c-4007-\tstruct hlist_node *node_tmp;\n--\nnet/batman-adv/translation-table.c-4046-\t\t\ttt_local = container_of(tt_common,\nnet/batman-adv/translation-table.c:4047:\t\t\t\t\t\tstruct batadv_tt_local_entry,\nnet/batman-adv/translation-table.c-4048-\t\t\t\t\t\tcommon);\n--\nnet/batman-adv/translation-table.c=4110=bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst,\n--\nnet/batman-adv/translation-table.c-4113-\tstruct batadv_tt_global_entry *tt_global_entry;\nnet/batman-adv/translation-table.c:4114:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-4115-\tstruct batadv_meshif_vlan *vlan;\n--\nnet/batman-adv/translation-table.c=4266=bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-4268-{\nnet/batman-adv/translation-table.c:4269:\tstruct batadv_tt_local_entry *tt_local_entry;\nnet/batman-adv/translation-table.c-4270-\tbool ret;\n--\nnet/batman-adv/translation-table.c=4600=int __init batadv_tt_cache_init(void)\n--\nnet/batman-adv/translation-table.c-4606-\tsize_t tt_req_size = sizeof(struct batadv_tt_req_node);\nnet/batman-adv/translation-table.c:4607:\tsize_t tl_size = sizeof(struct batadv_tt_local_entry);\nnet/batman-adv/translation-table.c-4608-\n--\nnet/batman-adv/types.h=1841=struct batadv_tt_common_entry {\n--\nnet/batman-adv/types.h-1876-/**\nnet/batman-adv/types.h:1877: * struct batadv_tt_local_entry - translation table local entry data\nnet/batman-adv/types.h-1878- */\nnet/batman-adv/types.h:1879:struct batadv_tt_local_entry {\nnet/batman-adv/types.h-1880-\t/** @common: general translation table data */\n"
} |
| 25/3 | 2026/08/31 20:33 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 30583 output: 39 thoughts: 21 Thoughts: Here's my take on the thought process, as if it were my own: **Diving into the Batadv Codebase** Okay, time to get my hands dirty. I'm going to start by taking a look at `struct batadv_tt_local_entry`. I know it's defined in `types.h`, so that's where I'll begin. This struct is critical for understanding how the batadv (B.A.T.M.A.N. advanced) protocol manages its local topology tables, so getting a solid grasp on its structure is going to be key to whatever I'm troubleshooting or enhancing. Let's see what the developers have defined in there, what fields they chose and their reasoning. Let's start with a low-level look, and then I can connect the data to the overall process. Time to dig in! |
| 26/3 | 2026/08/31 20:33 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/types.h",
"FirstLine": 1875,
"LineCount": 30
}Results: {
"Contents": "1875:\t\n1876:\t/**\n1877:\t * struct batadv_tt_local_entry - translation table local entry data\n1878:\t */\n1879:\tstruct batadv_tt_local_entry {\n1880:\t\t/** @common: general translation table data */\n1881:\t\tstruct batadv_tt_common_entry common;\n1882:\t\n1883:\t\t/** @last_seen: timestamp used for purging stale tt local entries */\n1884:\t\tunsigned long last_seen;\n1885:\t\n1886:\t\t/** @vlan: mesh-interface vlan of the entry */\n1887:\t\tstruct batadv_meshif_vlan *vlan;\n1888:\t};\n1889:\t\n1890:\t/**\n1891:\t * struct batadv_tt_global_entry - translation table global entry data\n1892:\t */\n1893:\tstruct batadv_tt_global_entry {\n1894:\t\t/** @common: general translation table data */\n1895:\t\tstruct batadv_tt_common_entry common;\n1896:\t\n1897:\t\t/** @orig_list: list of orig nodes announcing this non-mesh client */\n1898:\t\tstruct hlist_head orig_list;\n1899:\t\n1900:\t\t/** @orig_list_count: number of items in the orig_list */\n1901:\t\tatomic_t orig_list_count;\n1902:\t\n1903:\t\t/** @list_lock: lock protecting orig_list */\n1904:\t\tspinlock_t list_lock;\n"
} |
| 27/3 | 2026/08/31 20:33 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 31267 output: 43 thoughts: 264 Thoughts: **Analyzing the Patch: A Deep Dive**
Okay, let's dissect these changes methodically. First, `batadv_iv_ogm_neigh_is_sob`: seems like it's just a simple parameter rename, nothing to raise an eyebrow about there. Moving on, `batadv_v_neigh_is_sob` is a bit more involved. Ah, a parameter rename *and* some logic correction, specifically around throughput comparison. Interesting. Let me break this down... it looks like they're calculating a threshold as one-fourth of the reference interface's throughput and then subtracting it from the total. The final comparison, `candidate > 3/4 * reference`, should make sense. And, importantly, no memory allocation or uninitialized reads, which is always good to see. The code is fairly concise and efficient in its approach.
Now, let's shift gears to the `bridge_loop_avoidance.c` modifications. I see a `u8 mac[ETH_ALEN] __aligned(2);` declaration in `batadv_bla_send_announce` and a `static const u8 claim_dest[ETH_ALEN] __aligned(2) = { ... };` in `batadv_bla_init`. Looks like a potential change to MAC address handling, so let's start by scrutinizing the `batadv_bla_send_announce` function, specifically around line 663. That's where the heart of the bridge loop avoidance logic will be.
|
| 28/3 | 2026/08/31 20:34 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/bridge_loop_avoidance.c",
"FirstLine": 660,
"LineCount": 25
}Results: {
"Contents": " 660:\t * @bat_priv: the bat priv with all the mesh interface information\n 661:\t * @backbone_gw: our backbone gateway which should be announced\n 662:\t */\n 663:\tstatic void batadv_bla_send_announce(struct batadv_priv *bat_priv,\n 664:\t\t\t\t\t struct batadv_bla_backbone_gw *backbone_gw)\n 665:\t{\n 666:\t\tu8 mac[ETH_ALEN] __aligned(2);\n 667:\t\t__be16 crc;\n 668:\t\n 669:\t\tmemcpy(mac, batadv_announce_mac, 4);\n 670:\t\tspin_lock_bh(\u0026backbone_gw-\u003ecrc_lock);\n 671:\t\tcrc = htons(backbone_gw-\u003ecrc);\n 672:\t\tspin_unlock_bh(\u0026backbone_gw-\u003ecrc_lock);\n 673:\t\tmemcpy(\u0026mac[4], \u0026crc, 2);\n 674:\t\n 675:\t\tbatadv_bla_send_claim(bat_priv, mac, backbone_gw-\u003evid,\n 676:\t\t\t\t BATADV_CLAIM_TYPE_ANNOUNCE);\n 677:\t}\n 678:\t\n 679:\t/**\n 680:\t * batadv_bla_add_claim() - Adds a claim in the claim hash\n 681:\t * @bat_priv: the bat priv with all the mesh interface information\n 682:\t * @mac: the mac address of the claim\n 683:\t * @vid: the VLAN ID of the frame\n 684:\t * @backbone_gw: the backbone gateway which claims it\n"
} |
| 29/3 | 2026/08/31 20:34 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 32341 output: 34 thoughts: 84 Thoughts: **Analyzing the MAC Address and Potential Bug** Okay, so I'm focusing on this `mac` variable. It looks like the full 6 bytes are being written, which is good. We're getting the complete MAC address, four bytes plus two bytes. Now, I'm moving on to this `distributed-arp-table.c` file. Specifically, I'm checking out `batadv_dbg_arp`. Ah, here's a potential area to investigate: it seems like we're using `unicast_4addr_packet->subtype` instead of `unicast_4addr_packet->u.packet_type`. That seems odd, so I need to verify what the correct field is. I'll need to go and analyze the `batadv_unicast_4addr_packet` structure to understand what each field represents and make sure this is the right field to be using. This might be a bug waiting to happen. I need to make sure the right data is being accessed. |
| 30/3 | 2026/08/31 20:34 | tool | grepper |
0mArgs:{
"Expression": "unicast_4addr_packet",
"PathPrefix": "net/batman-adv/"
}Results: {
"Output": "net/batman-adv/distributed-arp-table.c=502=static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,\n--\nnet/batman-adv/distributed-arp-table.c-504-{\nnet/batman-adv/distributed-arp-table.c:505:\tstruct batadv_unicast_4addr_packet *unicast_4addr_packet;\nnet/batman-adv/distributed-arp-table.c-506-\tstruct batadv_bcast_packet *bcast_pkt;\n--\nnet/batman-adv/distributed-arp-table.c-523-\nnet/batman-adv/distributed-arp-table.c:524:\tunicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb-\u003edata;\nnet/batman-adv/distributed-arp-table.c-525-\nnet/batman-adv/distributed-arp-table.c:526:\tswitch (unicast_4addr_packet-\u003eu.packet_type) {\nnet/batman-adv/distributed-arp-table.c-527-\tcase BATADV_UNICAST:\n--\nnet/batman-adv/distributed-arp-table.c-533-\t\t\t \"* encapsulated within a UNICAST_4ADDR packet (src: %pM)\\n\",\nnet/batman-adv/distributed-arp-table.c:534:\t\t\t unicast_4addr_packet-\u003esrc);\nnet/batman-adv/distributed-arp-table.c:535:\t\tswitch (unicast_4addr_packet-\u003esubtype) {\nnet/batman-adv/distributed-arp-table.c-536-\t\tcase BATADV_P_DAT_DHT_PUT:\n--\nnet/batman-adv/distributed-arp-table.c-550-\t\t\tbatadv_dbg(BATADV_DBG_DAT, bat_priv, \"* type: Unknown (%u)!\\n\",\nnet/batman-adv/distributed-arp-table.c:551:\t\t\t\t unicast_4addr_packet-\u003esubtype);\nnet/batman-adv/distributed-arp-table.c-552-\t\t}\n--\nnet/batman-adv/distributed-arp-table.c-554-\tcase BATADV_BCAST:\nnet/batman-adv/distributed-arp-table.c:555:\t\tbcast_pkt = (struct batadv_bcast_packet *)unicast_4addr_packet;\nnet/batman-adv/distributed-arp-table.c-556-\t\torig_addr = bcast_pkt-\u003eorig;\n--\nnet/batman-adv/distributed-arp-table.c-563-\t\t\t \"* encapsulated within an unknown packet type (0x%x)\\n\",\nnet/batman-adv/distributed-arp-table.c:564:\t\t\t unicast_4addr_packet-\u003eu.packet_type);\nnet/batman-adv/distributed-arp-table.c-565-\t}\n--\nnet/batman-adv/main.c=370=int batadv_max_header_len(void)\n--\nnet/batman-adv/main.c-376-\theader_len = max_t(int, header_len,\nnet/batman-adv/main.c:377:\t\t\t sizeof(struct batadv_unicast_4addr_packet));\nnet/batman-adv/main.c-378-\theader_len = max_t(int, header_len,\n--\nnet/batman-adv/main.c=554=static void batadv_recv_handler_init(void)\n--\nnet/batman-adv/main.c-570-\tBUILD_BUG_ON(sizeof(struct batadv_unicast_packet) != 10);\nnet/batman-adv/main.c:571:\tBUILD_BUG_ON(sizeof(struct batadv_unicast_4addr_packet) != 18);\nnet/batman-adv/main.c-572-\tBUILD_BUG_ON(sizeof(struct batadv_frag_packet) != 20);\n--\nnet/batman-adv/routing.c=740=static int batadv_route_unicast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-776-\tcase BATADV_UNICAST_4ADDR:\nnet/batman-adv/routing.c:777:\t\thdr_len = sizeof(struct batadv_unicast_4addr_packet);\nnet/batman-adv/routing.c-778-\t\tbreak;\n--\nnet/batman-adv/routing.c=1039=int batadv_recv_unicast_packet(struct sk_buff *skb,\n--\nnet/batman-adv/routing.c-1042-\tstruct batadv_priv *bat_priv = netdev_priv(recv_if-\u003emesh_iface);\nnet/batman-adv/routing.c:1043:\tstruct batadv_unicast_4addr_packet *unicast_4addr_packet;\nnet/batman-adv/routing.c-1044-\tstruct batadv_unicast_packet *unicast_packet;\n--\nnet/batman-adv/routing.c-1059-\tif (is4addr)\nnet/batman-adv/routing.c:1060:\t\thdr_size = sizeof(*unicast_4addr_packet);\nnet/batman-adv/routing.c-1061-\n--\nnet/batman-adv/routing.c-1092-\t\tif (is4addr) {\nnet/batman-adv/routing.c:1093:\t\t\tunicast_4addr_packet =\nnet/batman-adv/routing.c:1094:\t\t\t\t(struct batadv_unicast_4addr_packet *)skb-\u003edata;\nnet/batman-adv/routing.c:1095:\t\t\tsubtype = unicast_4addr_packet-\u003esubtype;\nnet/batman-adv/routing.c-1096-\t\t\tbatadv_dat_inc_counter(bat_priv, subtype);\n--\nnet/batman-adv/routing.c-1104-\t\t\tif (subtype == BATADV_P_DATA) {\nnet/batman-adv/routing.c:1105:\t\t\t\torig_addr = unicast_4addr_packet-\u003esrc;\nnet/batman-adv/routing.c-1106-\t\t\t\torig_node = batadv_orig_hash_find(bat_priv,\n--\nnet/batman-adv/send.c=269=bool batadv_send_skb_prepare_unicast_4addr(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/send.c-273-{\nnet/batman-adv/send.c:274:\tstruct batadv_unicast_4addr_packet *uc_4addr_packet;\nnet/batman-adv/send.c-275-\tstruct batadv_hard_iface *primary_if;\n--\nnet/batman-adv/send.c-289-\nnet/batman-adv/send.c:290:\tuc_4addr_packet = (struct batadv_unicast_4addr_packet *)skb-\u003edata;\nnet/batman-adv/send.c-291-\tuc_4addr_packet-\u003eu.packet_type = BATADV_UNICAST_4ADDR;\n"
} |
| 31/3 | 2026/08/31 20:34 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 34538 output: 42 thoughts: 60 Thoughts: **Diving into the Batadv DAT Cache Dump** Alright, let's get into this. I need to take a look at `batadv_dat_cache_dump_entry` in the `distributed-arp-table.c` file. Specifically, I see a declaration for `u8 mac[ETH_ALEN] __aligned(2);`. That's interesting, but the real task here is to dig into what `batadv_dat_cache_dump_entry` is actually *doing*. Let's go through this function definition with a fine tooth comb. I want to see how it's implemented and how it is behaving. |
| 32/3 | 2026/08/31 20:34 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/distributed-arp-table.c",
"FirstLine": 938,
"LineCount": 40
}Results: {
"Contents": " 938:\tstatic int\n 939:\tbatadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,\n 940:\t\t\t\t struct netlink_callback *cb,\n 941:\t\t\t\t struct batadv_dat_entry *dat_entry)\n 942:\t{\n 943:\t\tu8 mac[ETH_ALEN] __aligned(2);\n 944:\t\tu64 u64_mac;\n 945:\t\tint msecs;\n 946:\t\tvoid *hdr;\n 947:\t\n 948:\t\thdr = genlmsg_put(msg, portid, cb-\u003enlh-\u003enlmsg_seq,\n 949:\t\t\t\t \u0026batadv_netlink_family, NLM_F_MULTI,\n 950:\t\t\t\t BATADV_CMD_GET_DAT_CACHE);\n 951:\t\tif (!hdr)\n 952:\t\t\treturn -ENOBUFS;\n 953:\t\n 954:\t\tgenl_dump_check_consistent(cb, hdr);\n 955:\t\n 956:\t\tmsecs = jiffies_to_msecs(jiffies - dat_entry-\u003elast_update);\n 957:\t\tu64_mac = atomic64_read(\u0026dat_entry-\u003emac_addr);\n 958:\t\tu64_to_ether_addr(u64_mac, mac);\n 959:\t\n 960:\t\tif (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,\n 961:\t\t\t\t dat_entry-\u003eip) ||\n 962:\t\t nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN, mac) ||\n 963:\t\t nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry-\u003evid) ||\n 964:\t\t nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {\n 965:\t\t\tgenlmsg_cancel(msg, hdr);\n 966:\t\t\treturn -EMSGSIZE;\n 967:\t\t}\n 968:\t\n 969:\t\tgenlmsg_end(msg, hdr);\n 970:\t\treturn 0;\n 971:\t}\n 972:\t\n 973:\t/**\n 974:\t * batadv_dat_cache_dump_bucket() - dump one bucket of the DAT cache table to\n 975:\t * a netlink socket\n 976:\t * @msg: buffer for the message\n 977:\t * @portid: netlink port\n"
} |
| 33/3 | 2026/08/31 20:34 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 35486 output: 23 thoughts: 69 Thoughts: **Analyzing the Memory Alignment in `u64_to_ether_addr`** Okay, so I'm looking at this `u64_to_ether_addr` function and it seems to be copying 6 bytes to `mac` using something like `put_unaligned`. The immediate flag here is that these types of operations can often depend on memory alignment, and specifically, the use of `put_unaligned` (or equivalent) raises a red flag in my mind. The code's using an operation that anticipates 2-byte alignment. So, the next logical step is to dive into the kernel headers and get a clearer picture of `u64_to_ether_addr` itself. I need to understand why this `__aligned(2)` attribute was added across these files. I suspect it's directly related to the memory alignment requirements of the `put_unaligned` function or whatever equivalent function is being used to write the MAC address. I'm going to determine whether it is essential or a precaution. |
| 34/3 | 2026/08/31 20:35 | tool | grepper |
0mArgs:{
"Expression": "u64_to_ether_addr"
}Results: {
"Output": "drivers/infiniband/hw/erdma/erdma_main.c=537=static int erdma_ib_device_add(struct pci_dev *pdev)\n--\ndrivers/infiniband/hw/erdma/erdma_main.c-588-\ndrivers/infiniband/hw/erdma/erdma_main.c:589:\tu64_to_ether_addr(mac, dev-\u003eattrs.peer_addr);\ndrivers/infiniband/hw/erdma/erdma_main.c-590-\n--\ndrivers/net/dsa/b53/b53_priv.h=332=static inline void b53_arl_to_entry(struct b53_arl_entry *ent,\n--\ndrivers/net/dsa/b53/b53_priv.h-339-\tent-\u003eis_static = !!(fwd_entry \u0026 ARLTBL_STATIC);\ndrivers/net/dsa/b53/b53_priv.h:340:\tu64_to_ether_addr(mac_vid, ent-\u003emac);\ndrivers/net/dsa/b53/b53_priv.h-341-\tent-\u003evid = mac_vid \u003e\u003e ARLTBL_VID_S;\n--\ndrivers/net/dsa/b53/b53_priv.h=344=static inline void b53_arl_to_entry_25(struct b53_arl_entry *ent,\n--\ndrivers/net/dsa/b53/b53_priv.h-350-\tent-\u003eis_static = !!(mac_vid \u0026 ARLTBL_STATIC_25);\ndrivers/net/dsa/b53/b53_priv.h:351:\tu64_to_ether_addr(mac_vid, ent-\u003emac);\ndrivers/net/dsa/b53/b53_priv.h-352-\tent-\u003eport = (mac_vid \u0026 ARLTBL_DATA_PORT_ID_MASK_25) \u003e\u003e\n--\ndrivers/net/dsa/b53/b53_priv.h=359=static inline void b53_arl_to_entry_89(struct b53_arl_entry *ent,\n--\ndrivers/net/dsa/b53/b53_priv.h-366-\tent-\u003eis_static = !!(fwd_entry \u0026 ARLTBL_STATIC_89);\ndrivers/net/dsa/b53/b53_priv.h:367:\tu64_to_ether_addr(mac_vid, ent-\u003emac);\ndrivers/net/dsa/b53/b53_priv.h-368-\tent-\u003evid = mac_vid \u003e\u003e ARLTBL_VID_S;\n--\ndrivers/net/dsa/b53/b53_priv.h=417=static inline void b53_arl_search_to_entry_25(struct b53_arl_entry *ent,\n--\ndrivers/net/dsa/b53/b53_priv.h-423-\tent-\u003eis_static = !!(mac_vid \u0026 ARLTBL_STATIC_25);\ndrivers/net/dsa/b53/b53_priv.h:424:\tu64_to_ether_addr(mac_vid, ent-\u003emac);\ndrivers/net/dsa/b53/b53_priv.h-425-\tent-\u003evid = (mac_vid \u0026 ARL_SRCH_RSLT_VID_MASK_25) \u003e\u003e\n--\ndrivers/net/dsa/b53/b53_priv.h=435=static inline void b53_arl_search_to_entry_63xx(struct b53_arl_entry *ent,\n--\ndrivers/net/dsa/b53/b53_priv.h-438-\tmemset(ent, 0, sizeof(*ent));\ndrivers/net/dsa/b53/b53_priv.h:439:\tu64_to_ether_addr(mac_vid, ent-\u003emac);\ndrivers/net/dsa/b53/b53_priv.h-440-\tent-\u003evid = mac_vid \u003e\u003e ARLTBL_VID_S;\n--\ndrivers/net/dsa/sja1105/sja1105_main.c=1837=static int sja1105_fdb_dump(struct dsa_switch *ds, int port,\n--\ndrivers/net/dsa/sja1105/sja1105_main.c-1867-\ndrivers/net/dsa/sja1105/sja1105_main.c:1868:\t\tu64_to_ether_addr(l2_lookup.macaddr, macaddr);\ndrivers/net/dsa/sja1105/sja1105_main.c-1869-\n--\ndrivers/net/dsa/sja1105/sja1105_main.c=1886=static void sja1105_fast_age(struct dsa_switch *ds, int port)\n--\ndrivers/net/dsa/sja1105/sja1105_main.c-1923-\ndrivers/net/dsa/sja1105/sja1105_main.c:1924:\t\tu64_to_ether_addr(l2_lookup.macaddr, macaddr);\ndrivers/net/dsa/sja1105/sja1105_main.c-1925-\n--\ndrivers/net/ethernet/fungible/funeth/funeth_main.c=953=static int fun_get_port_attributes(struct net_device *netdev)\n--\ndrivers/net/ethernet/fungible/funeth/funeth_main.c-974-\t\tcase FUN_ADMIN_PORT_KEY_MACADDR:\ndrivers/net/ethernet/fungible/funeth/funeth_main.c:975:\t\t\tu64_to_ether_addr(data[i], mac);\ndrivers/net/ethernet/fungible/funeth/funeth_main.c-976-\t\t\tif (is_zero_ether_addr(mac)) {\n--\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c=62=static int hbg_hw_dev_specs_init(struct hbg_priv *priv)\n--\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c-82-\tmac_addr = hbg_reg_read64(priv, HBG_REG_MAC_ADDR_ADDR);\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c:83:\tu64_to_ether_addr(mac_addr, (u8 *)specs-\u003emac_addr.sa_data);\ndrivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c-84-\n--\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c=434=int cgx_lmac_addr_del(u8 cgx_id, u8 lmac_id, u8 index)\n--\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c-463-\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c:464:\tu64_to_ether_addr(cfg, mac);\ndrivers/net/ethernet/marvell/octeontx2/af/cgx.c-465-\tif (is_multicast_ether_addr(mac))\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c=790=static void rvu_setup_pfvf_macaddress(struct rvu *rvu)\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c-808-\t\t\tif (*mac)\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c:809:\t\t\t\tu64_to_ether_addr(*mac, pfvf-\u003emac_addr);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c-810-\t\t\telse\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c-824-\t\t\t\tif (*mac)\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c:825:\t\t\t\t\tu64_to_ether_addr(*mac, pfvf-\u003emac_addr);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu.c-826-\t\t\t\telse\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c=875=static int rvu_dbg_rvu_fwdata_display(struct seq_file *s, void *unused)\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-910-\tfor (i = 0; i \u003c PF_MACNUM_MAX; i++) {\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c:911:\t\tu64_to_ether_addr(fwdata-\u003epf_macs[i], mac);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-912-\t\tif (!is_zero_ether_addr(mac)) {\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-924-\tfor (i = 0; i \u003c VF_MACNUM_MAX; i++) {\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c:925:\t\tu64_to_ether_addr(fwdata-\u003evf_macs[i], mac);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-926-\t\tif (!is_zero_ether_addr(mac)) {\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c=2961=static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id)\n--\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-3000-\t\t\tmac = FIELD_GET(CGX_RX_DMAC_ADR_MASK, cfg);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c:3001:\t\t\tu64_to_ether_addr(mac, dmac);\ndrivers/net/ethernet/marvell/octeontx2/af/rvu_debugfs.c-3002-\t\t\tseq_printf(s, \"%7d %pM\\n\", index, dmac);\n--\ndrivers/net/ethernet/mellanox/mlx4/cmd.c=3161=int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting)\n--\ndrivers/net/ethernet/mellanox/mlx4/cmd.c-3178-\ndrivers/net/ethernet/mellanox/mlx4/cmd.c:3179:\tu64_to_ether_addr(s_info-\u003emac, mac);\ndrivers/net/ethernet/mellanox/mlx4/cmd.c-3180-\tif (setting \u0026\u0026 !is_valid_ether_addr(mac)) {\n--\ndrivers/net/ethernet/mellanox/mlx4/en_netdev.c=533=static void mlx4_en_u64_to_mac(struct net_device *dev, u64 src_mac)\n--\ndrivers/net/ethernet/mellanox/mlx4/en_netdev.c-536-\ndrivers/net/ethernet/mellanox/mlx4/en_netdev.c:537:\tu64_to_ether_addr(src_mac, addr);\ndrivers/net/ethernet/mellanox/mlx4/en_netdev.c-538-\teth_hw_addr_set(dev, addr);\n--\ndrivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c=66=static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv)\n--\ndrivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c-73-\t\t\t\t \u0026local_mac);\ndrivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c:74:\tu64_to_ether_addr(local_mac, mac);\ndrivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c-75-\n--\ndrivers/net/ethernet/tehuti/tn40.c=1532=static void tn40_mac_init(struct tn40_priv *priv)\n--\ndrivers/net/ethernet/tehuti/tn40.c-1540-\ndrivers/net/ethernet/tehuti/tn40.c:1541:\tu64_to_ether_addr(val, addr);\ndrivers/net/ethernet/tehuti/tn40.c-1542-\teth_hw_addr_set(priv-\u003endev, addr);\n--\ndrivers/net/wireless/marvell/mwifiex/main.c=948=int mwifiex_set_mac_address(struct mwifiex_private *priv,\n--\ndrivers/net/wireless/marvell/mwifiex/main.c-975-\ndrivers/net/wireless/marvell/mwifiex/main.c:976:\tu64_to_ether_addr(mac_addr, priv-\u003ecurr_addr);\ndrivers/net/wireless/marvell/mwifiex/main.c-977-\n--\ndrivers/net/wireless/marvell/mwifiex/main.c-982-\tif (ret) {\ndrivers/net/wireless/marvell/mwifiex/main.c:983:\t\tu64_to_ether_addr(old_mac_addr, priv-\u003ecurr_addr);\ndrivers/net/wireless/marvell/mwifiex/main.c-984-\t\tmwifiex_dbg(priv-\u003eadapter, ERROR,\n--\ndrivers/net/wireless/nxp/nxpwifi/main.c=923=int nxpwifi_set_mac_address(struct nxpwifi_private *priv,\n--\ndrivers/net/wireless/nxp/nxpwifi/main.c-947-\ndrivers/net/wireless/nxp/nxpwifi/main.c:948:\tu64_to_ether_addr(mac_addr, priv-\u003ecurr_addr);\ndrivers/net/wireless/nxp/nxpwifi/main.c-949-\n--\ndrivers/net/wireless/nxp/nxpwifi/main.c-954-\tif (ret) {\ndrivers/net/wireless/nxp/nxpwifi/main.c:955:\t\tu64_to_ether_addr(old_mac_addr, priv-\u003ecurr_addr);\ndrivers/net/wireless/nxp/nxpwifi/main.c-956-\t\tnxpwifi_dbg(priv-\u003eadapter, ERROR,\n--\ninclude/linux/etherdevice.h=464=static inline u64 ether_addr_to_u64(const u8 *addr)\n--\ninclude/linux/etherdevice.h-475-/**\ninclude/linux/etherdevice.h:476: * u64_to_ether_addr - Convert a u64 to an Ethernet address.\ninclude/linux/etherdevice.h-477- * @u: u64 to convert to an Ethernet MAC address\n--\ninclude/linux/etherdevice.h-479- */\ninclude/linux/etherdevice.h:480:static inline void u64_to_ether_addr(u64 u, u8 *addr)\ninclude/linux/etherdevice.h-481-{\n--\ninclude/linux/etherdevice.h=495=static inline void eth_addr_dec(u8 *addr)\n--\ninclude/linux/etherdevice.h-499-\tu--;\ninclude/linux/etherdevice.h:500:\tu64_to_ether_addr(u, addr);\ninclude/linux/etherdevice.h-501-}\n--\ninclude/linux/etherdevice.h=507=static inline void eth_addr_inc(u8 *addr)\n--\ninclude/linux/etherdevice.h-511-\tu++;\ninclude/linux/etherdevice.h:512:\tu64_to_ether_addr(u, addr);\ninclude/linux/etherdevice.h-513-}\n--\ninclude/linux/etherdevice.h=521=static inline void eth_addr_add(u8 *addr, long offset)\n--\ninclude/linux/etherdevice.h-525-\tu += offset;\ninclude/linux/etherdevice.h:526:\tu64_to_ether_addr(u, addr);\ninclude/linux/etherdevice.h-527-}\n--\ninclude/linux/etherdevice.h=604=static inline void eth_hw_addr_gen(struct net_device *dev, const u8 *base_addr,\n--\ninclude/linux/etherdevice.h-610-\tu += id;\ninclude/linux/etherdevice.h:611:\tu64_to_ether_addr(u, addr);\ninclude/linux/etherdevice.h-612-\teth_hw_addr_set(dev, addr);\n--\ninclude/net/cfg80211.h=8291=static inline void cfg80211_gen_new_bssid(const u8 *bssid, u8 max_bssid,\n--\ninclude/net/cfg80211.h-8301-\ninclude/net/cfg80211.h:8302:\tu64_to_ether_addr(new_bssid_u64, new_bssid);\ninclude/net/cfg80211.h-8303-}\n--\nnet/batman-adv/distributed-arp-table.c=939=batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,\n--\nnet/batman-adv/distributed-arp-table.c-957-\tu64_mac = atomic64_read(\u0026dat_entry-\u003emac_addr);\nnet/batman-adv/distributed-arp-table.c:958:\tu64_to_ether_addr(u64_mac, mac);\nnet/batman-adv/distributed-arp-table.c-959-\n--\nnet/batman-adv/distributed-arp-table.c=1234=bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.c-1276-\t\tu64_mac = atomic64_read(\u0026dat_entry-\u003emac_addr);\nnet/batman-adv/distributed-arp-table.c:1277:\t\tu64_to_ether_addr(u64_mac, mac);\nnet/batman-adv/distributed-arp-table.c-1278-\n--\nnet/batman-adv/distributed-arp-table.c=1343=bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.c-1383-\tu64_mac = atomic64_read(\u0026dat_entry-\u003emac_addr);\nnet/batman-adv/distributed-arp-table.c:1384:\tu64_to_ether_addr(u64_mac, mac);\nnet/batman-adv/distributed-arp-table.c-1385-\n--\nnet/batman-adv/distributed-arp-table.c=1473=bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/distributed-arp-table.c-1515-\t\tu64_mac = atomic64_read(\u0026dat_entry-\u003emac_addr);\nnet/batman-adv/distributed-arp-table.c:1516:\t\tu64_to_ether_addr(u64_mac, mac);\nnet/batman-adv/distributed-arp-table.c-1517-\n--\ntools/testing/selftests/net/forwarding/lib.sh=1092=ether_addr_to_u64()\n--\ntools/testing/selftests/net/forwarding/lib.sh-1109-\ntools/testing/selftests/net/forwarding/lib.sh:1110:u64_to_ether_addr()\ntools/testing/selftests/net/forwarding/lib.sh-1111-{\n--\ntools/testing/selftests/net/forwarding/lib.sh=2296=has_unicast_flt()\n--\ntools/testing/selftests/net/forwarding/lib.sh-2304-\tip link add link $dev name macvlan-tmp type macvlan mode private\ntools/testing/selftests/net/forwarding/lib.sh:2305:\tip link set macvlan-tmp address $(u64_to_ether_addr $((tmp + 1)))\ntools/testing/selftests/net/forwarding/lib.sh-2306-\tip link set macvlan-tmp up\n"
} |
| 35/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 41360 output: 36 thoughts: 28 Thoughts: Here's my attempt at summarizing my thought process, as if I were a networking kernel expert: **Diving into the `u64_to_ether_addr` Function** Okay, so I'm trying to figure out what's happening with `u64_to_ether_addr` in `include/linux/etherdevice.h`. I'm guessing this function is responsible for converting a 64-bit unsigned integer into an Ethernet MAC address format, likely represented as a `struct ether_addr` or a `u8[6]`. Given that it's in a header file, it's probably an inline function or a macro. I need to understand how it handles the conversion – whether it's simply a bitwise operation, a shift, or something more complex to deal with endianness or potential validation. My main concern is how efficient and safe this is. Are there any edge cases? Does it perform any error checking on the input `u64`? I'd expect it to handle the byte order correctly when constructing the MAC address since these values are always represented in network byte order which is big-endian, whereas the kernel could be running on either a big or little endian architecture. I want to check for any potential overflow situations that could lead to security vulnerabilities. Let's see how it's actually implemented. |
| 36/3 | 2026/08/31 20:35 | tool | read-file |
0mArgs:{
"File": "include/linux/etherdevice.h",
"FirstLine": 475,
"LineCount": 20
}Results: {
"Contents": " 475:\t/**\n 476:\t * u64_to_ether_addr - Convert a u64 to an Ethernet address.\n 477:\t * @u: u64 to convert to an Ethernet MAC address\n 478:\t * @addr: Pointer to a six-byte array to contain the Ethernet address\n 479:\t */\n 480:\tstatic inline void u64_to_ether_addr(u64 u, u8 *addr)\n 481:\t{\n 482:\t\tint i;\n 483:\t\n 484:\t\tfor (i = ETH_ALEN - 1; i \u003e= 0; i--) {\n 485:\t\t\taddr[i] = u \u0026 0xff;\n 486:\t\t\tu = u \u003e\u003e 8;\n 487:\t\t}\n 488:\t}\n 489:\t\n 490:\t/**\n 491:\t * eth_addr_dec - Decrement the given MAC address\n 492:\t *\n 493:\t * @addr: Pointer to a six-byte array containing Ethernet address to decrement\n 494:\t */\n"
} |
| 37/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 42014 output: 36 thoughts: 97 Thoughts: **Analyzing the Ether Address Copy Function** Okay, let's dive into this `ether_addr_copy` function. I need to understand its constraints. According to the header file, specifically `include/linux/etherdevice.h`, the function expects the source pointer (`src`) and the destination pointer (`dst`) to be aligned to `u16`. It uses that alignment to access `u16` units. Got it. So, alignment is key here to avoid potential unaligned memory access issues. I should probably double-check the surrounding code in `include/linux/etherdevice.h` around `ether_addr_copy` to make sure I haven't missed anything, or perhaps to see if there is anything I can leverage for my use case. |
| 38/3 | 2026/08/31 20:35 | tool | grepper |
0mArgs:{
"Expression": "static inline void ether_addr_copy",
"PathPrefix": "include/linux/etherdevice.h"
}Results: {
"Output": "include/linux/etherdevice.h=290=static inline u32 eth_hw_addr_crc(struct netdev_hw_addr *ha)\n--\ninclude/linux/etherdevice.h-301- */\ninclude/linux/etherdevice.h:302:static inline void ether_addr_copy(u8 *dst, const u8 *src)\ninclude/linux/etherdevice.h-303-{\n"
} |
| 39/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 42422 output: 36 thoughts: 11 Thoughts: Okay, here's my interpretation of that thought process, tailored for an expert audience, and written in the first person: **Analyzing the `ether_addr_copy` Function** Alright, let's dive in and take a look at the `ether_addr_copy` function. I want to quickly refresh my memory on the implementation details and understand the specific context where it is being used. I know this is a pretty basic function, probably just copying the MAC address, but I want to ensure that I remember all details to verify that it's doing precisely what it needs to do, without any overhead. I'll need to check for any obvious gotchas like potential alignment issues, overlap, or whether it's optimized in the common implementation of the underlying compiler or architecture. I will evaluate the function's assumptions about the size of the MAC address to ensure it matches any network interface controller requirements I might be designing/debugging. Is it a straight memory copy, or are there any bit-level manipulations involved? Any non-obvious optimizations that are used? It's always worth revisiting the fundamentals, especially with something this low-level. I'll also be watching out for any potential race conditions if the function isn't thread-safe, or if the source and destination buffers are not guaranteed to be correctly aligned. I will then verify that the copy is correctly handled and any associated error conditions are correctly handled. |
| 40/3 | 2026/08/31 20:35 | tool | read-file |
0mArgs:{
"File": "include/linux/etherdevice.h",
"FirstLine": 295,
"LineCount": 20
}Results: {
"Contents": " 295:\t/**\n 296:\t * ether_addr_copy - Copy an Ethernet address\n 297:\t * @dst: Pointer to a six-byte array Ethernet address destination\n 298:\t * @src: Pointer to a six-byte array Ethernet address source\n 299:\t *\n 300:\t * Please note: dst \u0026 src must both be aligned to u16.\n 301:\t */\n 302:\tstatic inline void ether_addr_copy(u8 *dst, const u8 *src)\n 303:\t{\n 304:\t#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)\n 305:\t\t*(u32 *)dst = *(const u32 *)src;\n 306:\t\t*(u16 *)(dst + 4) = *(const u16 *)(src + 4);\n 307:\t#else\n 308:\t\tu16 *a = (u16 *)dst;\n 309:\t\tconst u16 *b = (const u16 *)src;\n 310:\t\n 311:\t\ta[0] = b[0];\n 312:\t\ta[1] = b[1];\n 313:\t\ta[2] = b[2];\n 314:\t#endif\n"
} |
| 41/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 43110 output: 36 thoughts: 372 Thoughts: **My Analysis of Alignment Issues in batman-adv** Okay, so the `ether_addr_copy` function has this requirement that both the destination (`dst`) and source (`src`) memory addresses need to be aligned to a `u16` boundary. This whole slew of changes in `batman-adv` are addressing potentially unaligned memory accesses, especially on architectures where unaligned access isn't handled efficiently. The introduction of `__aligned(2)` to `u8 mac[ETH_ALEN]` arrays is the tell. I know KASAN and UBSAN will catch unaligned access or boundary violations, but alignment itself doesn't mean the memory is uninitialized. We need to be careful. Let's dive deeper into the code, starting with `translation-table.c`. I'll focus on the changes in the `batadv_tt_local_event` function. ```c tt_change_node = kmem_cache_alloc(batadv_tt_change_cache, GFP_ATOMIC); if (!tt_change_node) return; memset(tt_change_node->change.reserved, 0, sizeof(tt_change_node->change.reserved)); 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; ``` Looking at this, within the context of `tt_change_node->change`, I see a few key initializations. The `flags` field is assigned a value. The `reserved` field is specifically zeroed out with `memset`. The `addr` field is copied using `ether_addr_copy`, which is good because we expect that to handle the alignment correctly. The `vid` field is initialized with `htons`. Just to be absolutely sure, I'll double-check the definition of the `struct batadv_tt_change_node` itself to make certain that all members within the embedded `change` struct are, in fact, getting appropriately initialized. Always good to be thorough! |
| 42/3 | 2026/08/31 20:35 | tool | grepper |
0mArgs:{
"Expression": "struct batadv_tt_change_node",
"PathPrefix": "net/batman-adv/"
}Results: {
"Output": "net/batman-adv/translation-table.c=468=static void batadv_tt_local_event(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-472-\tstruct batadv_tt_common_entry *common = \u0026tt_local_entry-\u003ecommon;\nnet/batman-adv/translation-table.c:473:\tstruct batadv_tt_change_node *tt_change_node;\nnet/batman-adv/translation-table.c:474:\tstruct batadv_tt_change_node *entry;\nnet/batman-adv/translation-table.c:475:\tstruct batadv_tt_change_node *safe;\nnet/batman-adv/translation-table.c-476-\tbool del_op_requested;\n--\nnet/batman-adv/translation-table.c=1096=static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)\n--\nnet/batman-adv/translation-table.c-1098-\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c:1099:\tstruct batadv_tt_change_node *entry;\nnet/batman-adv/translation-table.c-1100-\tstruct batadv_tvlv_tt_data *tt_data;\nnet/batman-adv/translation-table.c:1101:\tstruct batadv_tt_change_node *safe;\nnet/batman-adv/translation-table.c-1102-\tint tt_diff_entries_count = 0;\n--\nnet/batman-adv/translation-table.c=1591=static void batadv_tt_changes_list_free(struct batadv_priv *bat_priv)\nnet/batman-adv/translation-table.c-1592-{\nnet/batman-adv/translation-table.c:1593:\tstruct batadv_tt_change_node *entry;\nnet/batman-adv/translation-table.c:1594:\tstruct batadv_tt_change_node *safe;\nnet/batman-adv/translation-table.c-1595-\n--\nnet/batman-adv/translation-table.c=4600=int __init batadv_tt_cache_init(void)\n--\nnet/batman-adv/translation-table.c-4602-\tsize_t tt_orig_size = sizeof(struct batadv_tt_orig_list_entry);\nnet/batman-adv/translation-table.c:4603:\tsize_t tt_change_size = sizeof(struct batadv_tt_change_node);\nnet/batman-adv/translation-table.c-4604-\tsize_t tt_roam_size = sizeof(struct batadv_tt_roam_node);\n--\nnet/batman-adv/types.h=1913=struct batadv_tt_orig_list_entry {\n--\nnet/batman-adv/types.h-1936-/**\nnet/batman-adv/types.h:1937: * struct batadv_tt_change_node - structure for tt changes occurred\nnet/batman-adv/types.h-1938- */\nnet/batman-adv/types.h:1939:struct batadv_tt_change_node {\nnet/batman-adv/types.h-1940-\t/** @list: list node for \u0026batadv_priv_tt.changes_list */\n"
} |
| 43/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 44931 output: 39 thoughts: 21 Thoughts: Here's my take on the thought process, as requested: **Diving into `types.h`** Okay, so I need to zero in on something specific, and my first instinct is to check `types.h`. I'm thinking, likely the issue I'm chasing is within the definitions or declarations related to the data structures involved. Specifically, I'm going to look at lines 1935 through 1950. That range usually covers a particular grouping or related definitions, and is likely where I'll find what I'm looking for. This should provide some solid leads. Let's see what's there... |
| 44/3 | 2026/08/31 20:35 | tool | read-file |
0mArgs:{
"File": "net/batman-adv/types.h",
"FirstLine": 1935,
"LineCount": 20
}Results: {
"Contents": "1935:\t\n1936:\t/**\n1937:\t * struct batadv_tt_change_node - structure for tt changes occurred\n1938:\t */\n1939:\tstruct batadv_tt_change_node {\n1940:\t\t/** @list: list node for \u0026batadv_priv_tt.changes_list */\n1941:\t\tstruct list_head list;\n1942:\t\n1943:\t\t/** @change: holds the actual translation table diff data */\n1944:\t\tstruct batadv_tvlv_tt_change change;\n1945:\t};\n1946:\t\n1947:\t/**\n1948:\t * struct batadv_tt_req_node - data to keep track of the tt requests in flight\n1949:\t */\n1950:\tstruct batadv_tt_req_node {\n1951:\t\t/**\n1952:\t\t * @addr: mac address of the originator this request was sent to\n1953:\t\t */\n1954:\t\tu8 addr[ETH_ALEN] __aligned(2);\n"
} |
| 45/3 | 2026/08/31 20:35 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 45424 output: 24 thoughts: 16 Thoughts: Here's a summary of my immediate thought process, focusing on `struct batadv_tvlv_tt_change`: **Diving into the `batadv_tvlv_tt_change` Structure** Okay, so I'm looking at `struct batadv_tvlv_tt_change`. Immediately, I'm thinking about its role within the batadv framework. It's almost certainly related to managing and signaling changes within the Tunneling VLAN-aware Link State Table Vector (TVLV) mechanism, given the naming convention. My immediate questions are: * What specific parameters does it encompass? * What triggers the creation or modification of an instance of this struct? Is it a change in network topology, an update in VLAN configuration, or perhaps a timer-based check? * How is this structure used in relation to other batadv data structures, such as the TVLV table itself, and which functions leverage it? * Is this structure specific to a certain batadv version or is it more generic? * Does it relate to security aspects of the batadv framework? I expect to see members that describe the nature of the change (e.g., add, delete, modify), information about the relevant TVLV entry or entries, timestamps, and likely some sort of context that allows the framework to handle the update gracefully, possibly including flags to handle races/concurrency. It's likely that a linked list or similar mechanism is involved for queuing or processing these change events. The details here are going to be key to understanding the latency and robustness of batadv's handling of TVLV updates. My focus is going to be on the structure's data members and their relationship to various batadv functions, particularly those associated with the batadv TVLV sub-module. |
| 46/3 | 2026/08/31 20:36 | tool | grepper |
0mArgs:{
"Expression": "struct batadv_tvlv_tt_change"
}Results: {
"Output": "include/uapi/linux/batadv_packet.h=623=struct batadv_tvlv_tt_data {\n--\ninclude/uapi/linux/batadv_packet.h-630-/**\ninclude/uapi/linux/batadv_packet.h:631: * struct batadv_tvlv_tt_change - translation table diff data\ninclude/uapi/linux/batadv_packet.h-632- * @flags: status indicators concerning the non-mesh client (see\n--\ninclude/uapi/linux/batadv_packet.h-637- */\ninclude/uapi/linux/batadv_packet.h:638:struct batadv_tvlv_tt_change {\ninclude/uapi/linux/batadv_packet.h-639-\t__u8 flags;\n--\nnet/batman-adv/main.c=554=static void batadv_recv_handler_init(void)\n--\nnet/batman-adv/main.c-578-\tBUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_vlan_data) != 8);\nnet/batman-adv/main.c:579:\tBUILD_BUG_ON(sizeof(struct batadv_tvlv_tt_change) != 12);\nnet/batman-adv/main.c-580-\tBUILD_BUG_ON(sizeof(struct batadv_tvlv_roam_adv) != 8);\n--\nnet/batman-adv/translation-table.c=545=static int batadv_tt_len(int changes_num)\nnet/batman-adv/translation-table.c-546-{\nnet/batman-adv/translation-table.c:547:\treturn changes_num * sizeof(struct batadv_tvlv_tt_change);\nnet/batman-adv/translation-table.c-548-}\n--\nnet/batman-adv/translation-table.c=908=batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node,\nnet/batman-adv/translation-table.c-909-\t\t\t\t struct batadv_tvlv_tt_data **tt_data,\nnet/batman-adv/translation-table.c:910:\t\t\t\t struct batadv_tvlv_tt_change **tt_change,\nnet/batman-adv/translation-table.c-911-\t\t\t\t s32 *tt_len)\n--\nnet/batman-adv/translation-table.c-981-\ttt_change_ptr = (u8 *)*tt_data + change_offset;\nnet/batman-adv/translation-table.c:982:\t*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;\nnet/batman-adv/translation-table.c-983-\n--\nnet/batman-adv/translation-table.c=1009=batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv,\nnet/batman-adv/translation-table.c-1010-\t\t\t\t struct batadv_tvlv_tt_data **tt_data,\nnet/batman-adv/translation-table.c:1011:\t\t\t\t struct batadv_tvlv_tt_change **tt_change,\nnet/batman-adv/translation-table.c-1012-\t\t\t\t s32 *tt_len)\n--\nnet/batman-adv/translation-table.c-1082-\ttt_change_ptr = (u8 *)*tt_data + change_offset;\nnet/batman-adv/translation-table.c:1083:\t*tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr;\nnet/batman-adv/translation-table.c-1084-\n--\nnet/batman-adv/translation-table.c=1096=static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv)\nnet/batman-adv/translation-table.c-1097-{\nnet/batman-adv/translation-table.c:1098:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-1099-\tstruct batadv_tt_change_node *entry;\n--\nnet/batman-adv/translation-table.c-1143-\t\t\t \u0026entry-\u003echange,\nnet/batman-adv/translation-table.c:1144:\t\t\t sizeof(struct batadv_tvlv_tt_change));\nnet/batman-adv/translation-table.c-1145-\t\t\ttt_diff_entries_count++;\n--\nnet/batman-adv/translation-table.c=3050=static u16 batadv_tt_tvlv_generate(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-3058-\tstruct batadv_tt_common_entry *tt_common_entry;\nnet/batman-adv/translation-table.c:3059:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-3060-\tstruct hlist_head *head;\n--\nnet/batman-adv/translation-table.c=3297=static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-3303-\tstruct batadv_orig_node *req_dst_orig_node;\nnet/batman-adv/translation-table.c:3304:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-3305-\tbool ret = false;\n--\nnet/batman-adv/translation-table.c=3428=static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-3433-\tstruct batadv_hard_iface *primary_if = NULL;\nnet/batman-adv/translation-table.c:3434:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-3435-\tstruct batadv_orig_node *orig_node;\n--\nnet/batman-adv/translation-table.c=3569=static void _batadv_tt_update_changes(struct batadv_priv *bat_priv,\nnet/batman-adv/translation-table.c-3570-\t\t\t\t struct batadv_orig_node *orig_node,\nnet/batman-adv/translation-table.c:3571:\t\t\t\t struct batadv_tvlv_tt_change *tt_change,\nnet/batman-adv/translation-table.c-3572-\t\t\t\t u16 tt_num_changes, u8 ttvn)\n--\nnet/batman-adv/translation-table.c=3614=static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv,\nnet/batman-adv/translation-table.c:3615:\t\t\t\t struct batadv_tvlv_tt_change *tt_change,\nnet/batman-adv/translation-table.c-3616-\t\t\t\t u8 ttvn, u8 *resp_src,\n--\nnet/batman-adv/translation-table.c=3653=static void batadv_tt_update_changes(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-3655-\t\t\t\t u16 tt_num_changes, u8 ttvn,\nnet/batman-adv/translation-table.c:3656:\t\t\t\t struct batadv_tvlv_tt_change *tt_change)\nnet/batman-adv/translation-table.c-3657-{\n--\nnet/batman-adv/translation-table.c=3704=static void batadv_handle_tt_response(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-3708-\tstruct batadv_orig_node *orig_node = NULL;\nnet/batman-adv/translation-table.c:3709:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-3710-\tstruct batadv_tt_req_node *node;\n--\nnet/batman-adv/translation-table.c-3726-\nnet/batman-adv/translation-table.c:3727:\ttt_change = (struct batadv_tvlv_tt_change *)tvlv_ptr;\nnet/batman-adv/translation-table.c-3728-\tif (tt_data-\u003eflags \u0026 BATADV_TT_FULL_TABLE) {\n--\nnet/batman-adv/translation-table.c=4155=static void batadv_tt_update_orig(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-4157-\t\t\t\t const void *tt_buff, u16 tt_num_vlan,\nnet/batman-adv/translation-table.c:4158:\t\t\t\t struct batadv_tvlv_tt_change *tt_change,\nnet/batman-adv/translation-table.c-4159-\t\t\t\t u16 tt_num_changes, u8 ttvn)\n--\nnet/batman-adv/translation-table.c=4367=static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,\n--\nnet/batman-adv/translation-table.c-4371-{\nnet/batman-adv/translation-table.c:4372:\tstruct batadv_tvlv_tt_change *tt_change;\nnet/batman-adv/translation-table.c-4373-\tstruct batadv_tvlv_tt_data *tt_data;\n--\nnet/batman-adv/translation-table.c-4387-\nnet/batman-adv/translation-table.c:4388:\ttt_change = (struct batadv_tvlv_tt_change *)((void *)tt_data\nnet/batman-adv/translation-table.c-4389-\t\t\t\t\t\t + tt_data_sz);\n--\nnet/batman-adv/types.h=1939=struct batadv_tt_change_node {\n--\nnet/batman-adv/types.h-1943-\t/** @change: holds the actual translation table diff data */\nnet/batman-adv/types.h:1944:\tstruct batadv_tvlv_tt_change change;\nnet/batman-adv/types.h-1945-};\n"
} |
| 47/3 | 2026/08/31 20:36 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 48599 output: 41 thoughts: 18 Thoughts: Here's a summary of my thought process, as requested: **Diving into the `batadv_tvlv_tt_change` Structure** Okay, first things first, let's get a handle on the `struct batadv_tvlv_tt_change`. I need to refresh my memory on what this specific structure encapsulates within the Batmand codebase. It's been a while since I last looked deeply into the inner workings of the TT (Topology Table) management, so this is a good starting point. I need to understand this structure to analyze some related change events, so I'll dig into its definition, see the specific fields, and what those fields signify. It's the foundation for understanding the mechanics. |
| 48/3 | 2026/08/31 20:36 | tool | read-file |
0mArgs:{
"File": "include/uapi/linux/batadv_packet.h",
"FirstLine": 630,
"LineCount": 20
}Results: {
"Contents": " 630:\t/**\n 631:\t * struct batadv_tvlv_tt_change - translation table diff data\n 632:\t * @flags: status indicators concerning the non-mesh client (see\n 633:\t * batadv_tt_client_flags)\n 634:\t * @reserved: reserved field - useful for alignment purposes only\n 635:\t * @addr: mac address of non-mesh client that triggered this tt change\n 636:\t * @vid: VLAN identifier\n 637:\t */\n 638:\tstruct batadv_tvlv_tt_change {\n 639:\t\t__u8 flags;\n 640:\t\t__u8 reserved[3];\n 641:\t\t__u8 addr[ETH_ALEN];\n 642:\t\t__be16 vid;\n 643:\t};\n 644:\t\n 645:\t/**\n 646:\t * struct batadv_tvlv_roam_adv - roaming advertisement\n 647:\t * @client: mac address of roaming client\n 648:\t * @vid: VLAN identifier\n 649:\t */\n"
} |
| 49/3 | 2026/08/31 20:36 | llm | kmsan-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 49116 output: 371 thoughts: 1172 Thoughts: **KMSAN Assessment: A Thorough Review** Okay, let's break this down systematically. First, I confirmed that all 12 bytes of the `batadv_tvlv_tt_change` struct are accounted for, with all fields initialized or copied appropriately – flags, reserved bytes (memset to 0), the MAC address (using `ether_addr_copy`), and the `vid` (using `htons`). I then checked the netlink dump functions in `translation-table.c`. Both `batadv_tt_local_dump_entry` and `batadv_tt_global_dump_subentry` explicitly initialize all netlink attributes with scalar values or initialized MAC address bytes. Next, I looked at `batadv_compare_tt_entry` and `batadv_hash_remove`. `batadv_hash_remove` uses `batadv_compare_tt_entry` to ensure the correct entry is removed based on pointer identity, effectively addressing a locking and lifetime concern. Now, let's compare all this against the KMSAN criteria. My assessment is that the patch primarily modifies or introduces: 1. Adding `__aligned(2)` attributes to MAC address arrays and struct fields for proper alignment. 2. Adding and using per-entry spinlock to protect `common->flags` and `roam_at`. 3. Correcting function parameter names and logical comparisons. 4. Correcting a debug print statement. 5. Improving hash removal matching. None of these changes touch on the KMSAN concerns. There are no uninitialized variables being sent to userspace, no conditional logic depending on uninitialized values, no new complex data structures with potentially uninitialized fields, and no bounds checks or logic that could lead to reading uninitialized bytes. I carefully verified that the netlink dumps are safe, serializing only fully initialized values and MAC addresses. The relevant structures and local variables are properly initialized. Standard sanitizers like KASAN and LOCKDEP are already in place to handle concurrency, memory safety, and lifetime issues. Therefore, `NeedsKMSAN` should definitely be set to `false`. I am now preparing the final response and will call `set-results`. |
| 50/3 | 2026/08/31 20:36 | tool | set-results |
0mArgs:{
"KMSANReasoning": "The patch series consists of several cleanups and bugfixes in batman-adv:\n1. Alignment annotations: Adds `__aligned(2)` to various MAC address byte arrays (`u8 addr[ETH_ALEN]`, `u8 orig[ETH_ALEN]`, etc.) to ensure 2-byte alignment for operations like `ether_addr_copy()`.\n2. Concurrency and locking improvements: Introduces `flags_lock` spinlock to `struct batadv_tt_common_entry` to protect concurrent read/write access to translation table entry flags (`common-\u003eflags`) and roaming timestamps (`roam_at`).\n3. Logic \u0026 naming fixes: Fixes neighbor comparison logic in `batadv_v_neigh_is_sob()` and renames parameters for clarity in `batadv_iv_ogm_neigh_is_sob()`.\n4. Debug output fix: Corrects field access in debug printing for encapsulated DAT packets.\n5. Hash table lookup accuracy: Introduces `batadv_compare_tt_entry()` to match exact pointer identities during `batadv_hash_remove()`.\n\nNone of the changes introduce uninitialized memory allocations, uninitialized variable usage, or leak uninitialized kernel memory to user space. Netlink dump handlers (`batadv_dat_cache_dump_entry`, `batadv_tt_local_dump_entry`, `batadv_tt_global_dump_subentry`) only serialize fully initialized scalars and MAC addresses. Concurrency, lifetime, and boundary checks are already covered by standard KASAN and LOCKDEP. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
}Results: {
"KMSANReasoning": "The patch series consists of several cleanups and bugfixes in batman-adv:\n1. Alignment annotations: Adds `__aligned(2)` to various MAC address byte arrays (`u8 addr[ETH_ALEN]`, `u8 orig[ETH_ALEN]`, etc.) to ensure 2-byte alignment for operations like `ether_addr_copy()`.\n2. Concurrency and locking improvements: Introduces `flags_lock` spinlock to `struct batadv_tt_common_entry` to protect concurrent read/write access to translation table entry flags (`common-\u003eflags`) and roaming timestamps (`roam_at`).\n3. Logic \u0026 naming fixes: Fixes neighbor comparison logic in `batadv_v_neigh_is_sob()` and renames parameters for clarity in `batadv_iv_ogm_neigh_is_sob()`.\n4. Debug output fix: Corrects field access in debug printing for encapsulated DAT packets.\n5. Hash table lookup accuracy: Introduces `batadv_compare_tt_entry()` to match exact pointer identities during `batadv_hash_remove()`.\n\nNone of the changes introduce uninitialized memory allocations, uninitialized variable usage, or leak uninitialized kernel memory to user space. Netlink dump handlers (`batadv_dat_cache_dump_entry`, `batadv_tt_local_dump_entry`, `batadv_tt_global_dump_subentry`) only serialize fully initialized scalars and MAC addresses. Concurrency, lifetime, and boundary checks are already covered by standard KASAN and LOCKDEP. Thus, a dedicated KMSAN fuzzing session is not warranted.",
"NeedsKMSAN": false
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|