From 6f864eb5cfd8315b8f9a29167263282fe4593f3a Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 15 May 2026 08:41:19 +0200 Subject: [PATCH 01/15] batman-adv: drop batman-adv specific version Bumping the version number on the first pull request after each merge window was deemed inappropriate for an in-tree component. The version number carries little meaningful information in the context of the Linux kernel release model, where stable and distribution might all carry slightly different patches (without any change to the batman-adv version). Instead, expose a UTS_RELEASE-based string to consumers of the netlink and ethtool interfaces. To avoid recompilation for each (re)generate of generated/utsrelease.h, init_utsname()->release is used in code which can dynamically retrieve the version string. The MODULE_VERSION is moved to a separate file because it doesn't support dynamic retrieval of the version string (but constant "at compile time" string) and it is required for the /sys/module/batman_adv/version. The latter is unfortunately still required by userspace tools. Link: https://lore.kernel.org/r/20210203163302.13e8a2a7@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com Link: https://lore.kernel.org/r/YnfjtpuAaH+Zkf9S@unreal Link: https://lore.kernel.org/r/Y9faTA0rNSXg%2FsLD@nanopsycho Signed-off-by: Sven Eckelmann --- net/batman-adv/Makefile | 1 + net/batman-adv/main.c | 4 ++-- net/batman-adv/main.h | 4 ---- net/batman-adv/mesh-interface.c | 3 ++- net/batman-adv/netlink.c | 3 ++- net/batman-adv/version.c | 12 ++++++++++++ 6 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 net/batman-adv/version.c diff --git a/net/batman-adv/Makefile b/net/batman-adv/Makefile index d3c4d4143c14..5d7456f1240d 100644 --- a/net/batman-adv/Makefile +++ b/net/batman-adv/Makefile @@ -30,5 +30,6 @@ batman-adv-$(CONFIG_BATMAN_ADV_TRACING) += trace.o batman-adv-y += tp_meter.o batman-adv-y += translation-table.o batman-adv-y += tvlv.o +batman-adv-y += version.o CFLAGS_trace.o := -I$(src) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index a4d33ee0fda5..82bba3489378 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -112,7 +113,7 @@ static int __init batadv_init(void) batadv_netlink_register(); pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n", - BATADV_SOURCE_VERSION, BATADV_COMPAT_VERSION); + init_utsname()->release, BATADV_COMPAT_VERSION); return 0; @@ -684,6 +685,5 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR(BATADV_DRIVER_AUTHOR); MODULE_DESCRIPTION(BATADV_DRIVER_DESC); -MODULE_VERSION(BATADV_SOURCE_VERSION); MODULE_ALIAS_RTNL_LINK("batadv"); MODULE_ALIAS_GENL_FAMILY(BATADV_NL_NAME); diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index af230b017bc1..f68fc8b7239c 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -12,10 +12,6 @@ #define BATADV_DRIVER_DESC "B.A.T.M.A.N. advanced" #define BATADV_DRIVER_DEVICE "batman-adv" -#ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2025.5" -#endif - /* B.A.T.M.A.N. parameters */ #define BATADV_TQ_MAX_VALUE 255 diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index e7aa45bc6b7a..f25b86102957 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -892,7 +893,7 @@ static void batadv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { strscpy(info->driver, "B.A.T.M.A.N. advanced", sizeof(info->driver)); - strscpy(info->version, BATADV_SOURCE_VERSION, sizeof(info->version)); + strscpy(info->version, init_utsname()->release, sizeof(info->version)); strscpy(info->fw_version, "N/A", sizeof(info->fw_version)); strscpy(info->bus_info, "batman", sizeof(info->bus_info)); } diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 78c651f634cd..b30f018740fc 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -233,7 +234,7 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, if (!hdr) return -ENOBUFS; - if (nla_put_string(msg, BATADV_ATTR_VERSION, BATADV_SOURCE_VERSION) || + if (nla_put_string(msg, BATADV_ATTR_VERSION, init_utsname()->release) || nla_put_string(msg, BATADV_ATTR_ALGO_NAME, bat_priv->algo_ops->name) || nla_put_u32(msg, BATADV_ATTR_MESH_IFINDEX, mesh_iface->ifindex) || diff --git a/net/batman-adv/version.c b/net/batman-adv/version.c new file mode 100644 index 000000000000..2b8006fe85b5 --- /dev/null +++ b/net/batman-adv/version.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +/* WARNING userspace tools like batctl were relying on + * /sys/module/batman_adv/version to check if the module was loaded. If it + * isn't present, they usually error out before finishing setup of the batadv + * interface. It should be kept until it is unlikely that there are active + * installations of these "broken" versions of these tools with recent kernels. + */ +MODULE_VERSION(UTS_RELEASE); From 1e323d0e7d2292057701fba40414166488bfb9fb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 5 May 2026 10:23:06 +0200 Subject: [PATCH 02/15] MAINTAINERS: Rename batman-adv T(ree) Replace the batman-adv tree name "linux-merge" with "batadv" to match the patch prefix convention used in subject lines (e.g. "[PATCH batadv 1/10]"). The previous name "linux-merge" was ambiguous and was not suitable as a easy-to-recognize prefix. Routing of patches to net-next vs. net remains at maintainer discretion. Signed-off-by: Sven Eckelmann --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index f1d2a924d53d..741fb4166aa2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4440,7 +4440,7 @@ W: https://www.open-mesh.org/ Q: https://patchwork.open-mesh.org/project/batman/list/ B: https://www.open-mesh.org/projects/batman-adv/issues C: ircs://irc.hackint.org/batadv -T: git https://git.open-mesh.org/linux-merge.git +T: git https://git.open-mesh.org/batadv.git F: Documentation/networking/batman-adv.rst F: include/uapi/linux/batadv_packet.h F: include/uapi/linux/batman_adv.h From 6dbf9f76a6929889129d1d975be82cb09466c1c4 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 6 May 2026 08:44:32 +0200 Subject: [PATCH 03/15] MAINTAINERS: Don't send batman-adv patches to netdev Do not send batman-adv patches directly to the networking maintainers or the netdev mailing list for initial review. Keeping these patch iterations off netdev reduces review load, especially for patchsets that require multiple revisions before reaching consensus. After the review was finished on the BATMAN ADVANCED mailing list, the patches will be queued up and then submitted to netdev as PR, including the full patchset in the same thread (for the last review). Signed-off-by: Sven Eckelmann --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 741fb4166aa2..75ff01377fc6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18635,6 +18635,7 @@ F: net/ F: samples/pktgen/ F: tools/net/ F: tools/testing/selftests/net/ +X: Documentation/networking/batman-adv.rst X: Documentation/networking/mac80211-injection.rst X: Documentation/networking/mac80211_hwsim/ X: Documentation/networking/regulatory.rst @@ -18645,6 +18646,7 @@ X: include/net/iw_handler.h X: include/net/mac80211.h X: include/net/wext.h X: net/9p/ +X: net/batman-adv/ X: net/bluetooth/ X: net/can/ X: net/ceph/ From b8fbbfe81d3e9678290923f374d700aa03fa8d4e Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 3 May 2026 22:46:14 +0200 Subject: [PATCH 04/15] batman-adv: add missing includes Some of the recent fixes required features from new header files. There is currently no build problem because transitive includes take care of it. But the batman-adv source code tries to avoid the dependency to transitive/implicite includes because it has no control over them and they might get removed at some point. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_v_ogm.c | 1 + net/batman-adv/bridge_loop_avoidance.c | 1 + net/batman-adv/distributed-arp-table.c | 1 + net/batman-adv/fragmentation.c | 1 + net/batman-adv/gateway_client.c | 1 + net/batman-adv/hard-interface.c | 1 + net/batman-adv/mesh-interface.c | 1 + net/batman-adv/translation-table.c | 1 + net/batman-adv/tvlv.c | 1 + 9 files changed, 9 insertions(+) diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index d66ca77b1aaa..6436e9bc079b 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index ffe854018bd3..f6ca69252ff7 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index 0a8bd95e2f99..c6084ae6760c 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index e9553db42349..14ccf7811bf6 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index a9d0346e8332..ec743ce39be4 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index d6732c34aeaf..4b3804ef70b6 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index f25b86102957..d6f40ae3c815 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -8,6 +8,7 @@ #include "main.h" #include +#include #include #include #include diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9f6e67771ffa..28869f65ada0 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index cc6ac580c620..8e8b54e2172e 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -6,6 +6,7 @@ #include "main.h" +#include #include #include #include From 9550dd11e360ec0c460b13096ceda283601fa5cb Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 22:03:53 +0200 Subject: [PATCH 05/15] batman-adv: use atomic_xchg() for gw.reselect check batadv_gw_election() only needs to test whether gw.reselect was set and clear it afterwards. Replace the batadv_atomic_dec_not_zero() [atomic_add_unless(..., -1, 0)] call with atomic_xchg(..., 0) to simplify the logic and make the intent more explicit. Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index ec743ce39be4..026627c8ba45 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -211,7 +211,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) curr_gw = batadv_gw_get_selected_gw_node(bat_priv); - if (!batadv_atomic_dec_not_zero(&bat_priv->gw.reselect) && curr_gw) + if (atomic_xchg(&bat_priv->gw.reselect, 0) == 0 && curr_gw) goto out; /* if gw.reselect is set to 1 it means that a previous call to From c0559465842cd0160bb018d16c902c68f4b21648 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 13 May 2026 21:37:46 +0200 Subject: [PATCH 06/15] batman-adv: extract netdev wifi detection information object Previously, wifi_flags were stored directly in batadv_hard_iface, which is created for every network interface on the system (including those never attached to a mesh interface). This wastes memory and complicates the long-term goal of lazily allocating batadv_hard_iface only for interfaces that actually join a mesh. The problem is that several batman-adv features need wifi detection for net_devices (and their underlying devices) regardless of whether a batadv_hard_iface exists for them: * B.A.T.M.A.N. IV TQ hop penalty calculation * B.A.T.M.A.N. V ELP probing / throughput estimation * AP isolation To decouple wifi detection from batadv_hard_iface lifetime, introduce a global rhashtable (batadv_wifi_net_devices) mapping net_device pointers to batadv_wifi_net_device_state objects. Only net_devices that are actually detected as (indirect) wifi interfaces occupy an entry, keeping the common (non-wifi) case allocation-free. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_v_elp.c | 6 +- net/batman-adv/hard-interface.c | 191 +++++++++++++++++++++++++++++--- net/batman-adv/hard-interface.h | 34 +++++- net/batman-adv/main.c | 16 ++- net/batman-adv/types.h | 30 ++++- 5 files changed, 252 insertions(+), 25 deletions(-) diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index fdc2abe96d77..e207093de79f 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -85,6 +85,7 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, struct ethtool_link_ksettings link_settings; struct net_device *real_netdev; struct station_info sinfo; + u32 wifi_flags; u32 throughput; int ret; @@ -106,8 +107,9 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, /* if this is a wireless device, then ask its throughput through * cfg80211 API */ - if (batadv_is_wifi_hardif(hard_iface)) { - if (!batadv_is_cfg80211_hardif(hard_iface)) + wifi_flags = batadv_hardif_get_wifi_flags(hard_iface); + if (batadv_is_wifi(wifi_flags)) { + if (!batadv_is_cfg80211(wifi_flags)) /* unsupported WiFi driver version */ goto default_throughput; diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 4b3804ef70b6..647fda1898e5 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include #include @@ -43,6 +45,15 @@ #include "send.h" #include "translation-table.h" +static const struct rhashtable_params batadv_wifi_net_devices_params = { + .key_len = sizeof(struct net_device *), + .key_offset = offsetof(struct batadv_wifi_net_device_state, netdev), + .head_offset = offsetof(struct batadv_wifi_net_device_state, l), + .automatic_shrinking = true, +}; + +static struct rhashtable batadv_wifi_net_devices; + /** * batadv_hardif_release() - release hard interface from lists and queue for * free after rcu grace period @@ -356,21 +367,28 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device) } /** - * batadv_is_cfg80211_hardif() - check if the given hardif is a cfg80211 wifi - * interface + * batadv_hardif_get_wifi_flags() - retrieve wifi flags for hard_iface * @hard_iface: the device to check * - * Return: true if the net device is a cfg80211 wireless device, false - * otherwise. + * Return: batadv_hard_iface_wifi_flags flags of the device */ -bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface) +u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface) { - u32 allowed_flags = 0; + struct batadv_wifi_net_device_state *device_state; + u32 wifi_flags = 0; - allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; - allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; + if (!hard_iface) + return 0; - return !!(hard_iface->wifi_flags & allowed_flags); + rcu_read_lock(); + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &hard_iface->net_dev, + batadv_wifi_net_devices_params); + if (device_state) + wifi_flags = READ_ONCE(device_state->wifi_flags); + rcu_read_unlock(); + + return wifi_flags; } /** @@ -381,10 +399,9 @@ bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface) */ bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface) { - if (!hard_iface) - return false; + u32 wifi_flags = batadv_hardif_get_wifi_flags(hard_iface); - return hard_iface->wifi_flags != 0; + return batadv_is_wifi(wifi_flags); } /** @@ -890,7 +907,6 @@ batadv_hardif_add_interface(struct net_device *net_dev) kref_init(&hard_iface->refcount); hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT; - hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; @@ -942,6 +958,131 @@ static int batadv_hard_if_event_meshif(unsigned long event, return NOTIFY_DONE; } +/** + * batadv_wifi_net_device_insert() - save information about wifi net_device + * @net_dev: net_device to add to batadv_wifi_net_devices + * @wifi_flags: net_device which generated an event + * + * Return: 0 on result, negative value on error + */ +static int +batadv_wifi_net_device_insert(struct net_device *net_dev, u32 wifi_flags) +{ + struct batadv_wifi_net_device_state *device_state; + int ret; + + ASSERT_RTNL(); + + device_state = kzalloc_obj(*device_state, GFP_ATOMIC); + if (!device_state) + return -ENOMEM; + + device_state->wifi_flags = wifi_flags; + netdev_hold(net_dev, &device_state->dev_tracker, GFP_ATOMIC); + device_state->netdev = net_dev; + WRITE_ONCE(device_state->wifi_flags, wifi_flags); + + ret = rhashtable_insert_fast(&batadv_wifi_net_devices, &device_state->l, + batadv_wifi_net_devices_params); + if (ret < 0) + goto err_free; + + return 0; + +err_free: + netdev_put(device_state->netdev, &device_state->dev_tracker); + kfree(device_state); + return ret; +} + +/** + * batadv_wifi_net_device_remove() - remove information about wifi net_device + * @device_state: wifi net_device state to remove from batadv_wifi_net_device_state + */ +static void +batadv_wifi_net_device_remove(struct batadv_wifi_net_device_state *device_state) +{ + ASSERT_RTNL(); + + rhashtable_remove_fast(&batadv_wifi_net_devices, &device_state->l, + batadv_wifi_net_devices_params); + netdev_put(device_state->netdev, &device_state->dev_tracker); + kfree_rcu(device_state, rcu); +} + +/** + * batadv_wifi_net_device_update() - update wifi state of net_device + * @net_dev: net_device to update in batadv_wifi_net_devices + * + * The device will only be stored in batadv_wifi_net_devices when + * it could be identified as wifi device. If the net_device is no + * longer a wifi device, it is automatically removed from + * batadv_wifi_net_devices. + */ +static void +batadv_wifi_net_device_update(struct net_device *net_dev) +{ + struct batadv_wifi_net_device_state *device_state; + u32 wifi_flags; + + ASSERT_RTNL(); + + wifi_flags = batadv_wifi_flags_evaluate(net_dev); + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &net_dev, + batadv_wifi_net_devices_params); + + if (device_state) { + if (batadv_is_wifi(wifi_flags)) + WRITE_ONCE(device_state->wifi_flags, wifi_flags); + else + batadv_wifi_net_device_remove(device_state); + } else if (batadv_is_wifi(wifi_flags)) { + batadv_wifi_net_device_insert(net_dev, wifi_flags); + } +} + +/** + * batadv_wifi_net_device_unregister() - remove wifi state of net_device + * @net_dev: net_device to remove from batadv_wifi_net_devices + */ +static void +batadv_wifi_net_device_unregister(struct net_device *net_dev) +{ + struct batadv_wifi_net_device_state *device_state; + + ASSERT_RTNL(); + + device_state = rhashtable_lookup_fast(&batadv_wifi_net_devices, + &net_dev, + batadv_wifi_net_devices_params); + if (!device_state) + return; + + batadv_wifi_net_device_remove(device_state); +} + +/** + * batadv_wifi_net_device_event() - handle network events for batadv_wifi_net_devices + * @event: enum netdev_cmd event to handle + * @net_dev: net_device to update in batadv_wifi_net_devices + */ +static void batadv_wifi_net_device_event(unsigned long event, + struct net_device *net_dev) +{ + switch (event) { + case NETDEV_REGISTER: + case NETDEV_POST_TYPE_CHANGE: + case NETDEV_CHANGEUPPER: + batadv_wifi_net_device_update(net_dev); + break; + case NETDEV_UNREGISTER: + case NETDEV_PRE_TYPE_CHANGE: + batadv_wifi_net_device_unregister(net_dev); + break; + } +} + static int batadv_hard_if_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -953,6 +1094,8 @@ static int batadv_hard_if_event(struct notifier_block *this, if (batadv_meshif_is_valid(net_dev)) return batadv_hard_if_event_meshif(event, net_dev); + batadv_wifi_net_device_event(event, net_dev); + hard_iface = batadv_hardif_get_by_netdev(net_dev); if (!hard_iface && (event == NETDEV_REGISTER || event == NETDEV_POST_TYPE_CHANGE)) @@ -996,8 +1139,9 @@ static int batadv_hard_if_event(struct notifier_block *this, if (hard_iface == primary_if) batadv_primary_if_update_addr(bat_priv, NULL); break; + case NETDEV_REGISTER: + case NETDEV_POST_TYPE_CHANGE: case NETDEV_CHANGEUPPER: - hard_iface->wifi_flags = batadv_wifi_flags_evaluate(net_dev); if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; break; @@ -1015,3 +1159,22 @@ static int batadv_hard_if_event(struct notifier_block *this, struct notifier_block batadv_hard_if_notifier = { .notifier_call = batadv_hard_if_event, }; + +/** + * batadv_wifi_net_devices_init() - Initialize wifi devices cache + * + * Return: 0 on success, negative error code on failure + */ +int __init batadv_wifi_net_devices_init(void) +{ + return rhashtable_init(&batadv_wifi_net_devices, + &batadv_wifi_net_devices_params); +} + +/** + * batadv_wifi_net_devices_deinit() - Deinitialize wifi devices cache + */ +void batadv_wifi_net_devices_deinit(void) +{ + rhashtable_destroy(&batadv_wifi_net_devices); +} diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h index 9ba8fb2bdceb..089e65c8a481 100644 --- a/net/batman-adv/hard-interface.h +++ b/net/batman-adv/hard-interface.h @@ -10,6 +10,7 @@ #include "main.h" #include +#include #include #include #include @@ -69,7 +70,7 @@ extern struct notifier_block batadv_hard_if_notifier; struct net_device *__batadv_get_real_netdev(struct net_device *net_device); struct net_device *batadv_get_real_netdev(struct net_device *net_device); -bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface); +u32 batadv_hardif_get_wifi_flags(struct batadv_hard_iface *hard_iface); bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface); struct batadv_hard_iface* batadv_hardif_get_by_netdev(const struct net_device *net_dev); @@ -81,6 +82,8 @@ void batadv_update_min_mtu(struct net_device *mesh_iface); void batadv_hardif_release(struct kref *ref); int batadv_hardif_no_broadcast(struct batadv_hard_iface *if_outgoing, u8 *orig_addr, u8 *orig_neigh); +int __init batadv_wifi_net_devices_init(void); +void batadv_wifi_net_devices_deinit(void); /** * batadv_hardif_put() - decrement the hard interface refcounter and possibly @@ -119,4 +122,33 @@ batadv_primary_if_get_selected(struct batadv_priv *bat_priv) return hard_iface; } +/** + * batadv_is_cfg80211() - check if the given hardif is a cfg80211 + * wifi interface + * @wifi_flags: extracted batadv_hard_iface_wifi_flagss of an net_device + * + * Return: true if the net device is a cfg80211 wireless device, false + * otherwise. + */ +static inline bool batadv_is_cfg80211(u32 wifi_flags) +{ + u32 allowed_flags = 0; + + allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT; + allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT; + + return !!(wifi_flags & allowed_flags); +} + +/** + * batadv_is_wifi() - check if flags belong to wifi interface + * @wifi_flags: extracted batadv_hard_iface_wifi_flagss of an net_device + * + * Return: true if the net device is a 802.11 wireless device, false otherwise. + */ +static inline bool batadv_is_wifi(u32 wifi_flags) +{ + return wifi_flags != 0; +} + #endif /* _NET_BATMAN_ADV_HARD_INTERFACE_H_ */ diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 82bba3489378..d529014857c9 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -105,8 +105,14 @@ static int __init batadv_init(void) batadv_tp_meter_init(); batadv_event_workqueue = create_singlethread_workqueue("bat_events"); - if (!batadv_event_workqueue) + if (!batadv_event_workqueue) { + ret = -ENOMEM; goto err_create_wq; + } + + ret = batadv_wifi_net_devices_init(); + if (ret < 0) + goto err_init_wifi; register_netdevice_notifier(&batadv_hard_if_notifier); rtnl_link_register(&batadv_link_ops); @@ -117,10 +123,15 @@ static int __init batadv_init(void) return 0; +err_init_wifi: + destroy_workqueue(batadv_event_workqueue); + batadv_event_workqueue = NULL; + rcu_barrier(); + err_create_wq: batadv_tt_cache_destroy(); - return -ENOMEM; + return ret; } static void __exit batadv_exit(void) @@ -134,6 +145,7 @@ static void __exit batadv_exit(void) rcu_barrier(); + batadv_wifi_net_devices_deinit(); batadv_tt_cache_destroy(); } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index a01ee46d97f3..16fe84357742 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -21,6 +21,7 @@ #include #include #include +#include #include /* for linux/wait.h */ #include #include @@ -166,6 +167,29 @@ enum batadv_hard_iface_wifi_flags { BATADV_HARDIF_WIFI_CFG80211_INDIRECT = BIT(3), }; +/** + * struct batadv_wifi_net_device_state - cache of wifi information of net_devices + */ +struct batadv_wifi_net_device_state { + /** @l: anchor in rhashtable */ + struct rhash_head l; + + /** @netdev: pointer to the net_device */ + struct net_device *netdev; + + /** @dev_tracker: device tracker for @netdev */ + netdevice_tracker dev_tracker; + + /** + * @wifi_flags: flags whether this is (directly or indirectly) a wifi + * interface + */ + u32 wifi_flags; + + /** @rcu: struct used for freeing in an RCU-safe manner */ + struct rcu_head rcu; +}; + /** * struct batadv_hard_iface - network device known to batman-adv */ @@ -181,12 +205,6 @@ struct batadv_hard_iface { */ u8 num_bcasts; - /** - * @wifi_flags: flags whether this is (directly or indirectly) a wifi - * interface - */ - u32 wifi_flags; - /** @net_dev: pointer to the net_device */ struct net_device *net_dev; From 6a4f30e6e34cd15f44ffdb0a4991ff3a5a5b8f82 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 07/15] batman-adv: replace non-atomic meshif config fields with (READ|WRITE)_ONCE The meshif configuration values are only accessed as plain loads/stores and do not require full atomic_t semantics. Convert these fields to native integer types and replace their users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_iv_ogm.c | 26 +++++---- net/batman-adv/bat_v.c | 5 +- net/batman-adv/bat_v_ogm.c | 7 ++- net/batman-adv/bridge_loop_avoidance.c | 14 ++--- net/batman-adv/distributed-arp-table.c | 16 +++--- net/batman-adv/gateway_client.c | 6 +- net/batman-adv/gateway_common.c | 14 ++--- net/batman-adv/hard-interface.c | 10 ++-- net/batman-adv/log.h | 2 +- net/batman-adv/mesh-interface.c | 28 ++++----- net/batman-adv/multicast.c | 4 +- net/batman-adv/netlink.c | 57 +++++++++--------- net/batman-adv/originator.c | 1 - net/batman-adv/routing.c | 2 +- net/batman-adv/send.c | 2 +- net/batman-adv/types.h | 80 +++++++++++++------------- 16 files changed, 140 insertions(+), 134 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b8b1b997960a..5628017bee51 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -274,7 +275,7 @@ batadv_iv_ogm_emit_send_time(const struct batadv_priv *bat_priv) { unsigned int msecs; - msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; + msecs = READ_ONCE(bat_priv->orig_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); return jiffies + msecs_to_jiffies(msecs); @@ -289,7 +290,7 @@ static unsigned long batadv_iv_ogm_fwd_send_time(void) /* apply hop penalty for a normal link */ static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv) { - int hop_penalty = atomic_read(&bat_priv->hop_penalty); + int hop_penalty = READ_ONCE(bat_priv->hop_penalty); int new_tq; new_tq = tq * (BATADV_TQ_MAX_VALUE - hop_penalty); @@ -555,7 +556,7 @@ static bool batadv_iv_ogm_aggregate_new(const unsigned char *packet_buff, unsigned int skb_size; atomic_t *queue_left = own_packet ? NULL : &bat_priv->batman_queue_left; - if (atomic_read(&bat_priv->aggregated_ogms)) + if (READ_ONCE(bat_priv->aggregated_ogms)) skb_size = max_t(unsigned int, BATADV_MAX_AGGREGATION_BYTES, packet_len); else @@ -641,6 +642,7 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet; bool direct_link; unsigned long max_aggregation_jiffies; + bool aggregated_ogms; batadv_ogm_packet = (struct batadv_ogm_packet *)packet_buff; direct_link = !!(batadv_ogm_packet->flags & BATADV_DIRECTLINK); @@ -648,8 +650,10 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, /* find position for the packet in the forward queue */ spin_lock_bh(&bat_priv->forw_bat_list_lock); + aggregated_ogms = READ_ONCE(bat_priv->aggregated_ogms); + /* own packets are not to be aggregated */ - if (atomic_read(&bat_priv->aggregated_ogms) && !own_packet) { + if (aggregated_ogms && !own_packet) { hlist_for_each_entry(forw_packet_pos, &bat_priv->forw_bat_list, list) { if (batadv_iv_ogm_can_aggregate(batadv_ogm_packet, @@ -675,7 +679,7 @@ static bool batadv_iv_ogm_queue_add(struct batadv_priv *bat_priv, * we hold it back for a while, so that it might be aggregated * later on */ - if (!own_packet && atomic_read(&bat_priv->aggregated_ogms)) + if (!own_packet && aggregated_ogms) send_time += max_aggregation_jiffies; return batadv_iv_ogm_aggregate_new(packet_buff, packet_len, @@ -888,7 +892,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) */ queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_iv.reschedule_work, - msecs_to_jiffies(atomic_read(&bat_priv->orig_interval))); + msecs_to_jiffies(READ_ONCE(bat_priv->orig_interval))); } batadv_hardif_put(primary_if); @@ -2321,7 +2325,7 @@ static void batadv_iv_iface_enabled(struct batadv_hard_iface *hard_iface) static void batadv_iv_init_sel_class(struct batadv_priv *bat_priv) { /* set default TQ difference threshold to 20 */ - atomic_set(&bat_priv->gw.sel_class, 20); + WRITE_ONCE(bat_priv->gw.sel_class, 20); } static struct batadv_gw_node * @@ -2353,7 +2357,7 @@ batadv_iv_gw_get_best_gw_node(struct batadv_priv *bat_priv) tq_avg = router_ifinfo->bat_iv.tq_avg; - switch (atomic_read(&bat_priv->gw.sel_class)) { + switch (READ_ONCE(bat_priv->gw.sel_class)) { case 1: /* fast connection */ tmp_gw_factor = tq_avg * tq_avg; tmp_gw_factor *= gw_node->bandwidth_down; @@ -2407,13 +2411,14 @@ static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, { struct batadv_neigh_ifinfo *router_orig_ifinfo = NULL; struct batadv_neigh_ifinfo *router_gw_ifinfo = NULL; + u32 sel_class = READ_ONCE(bat_priv->gw.sel_class); struct batadv_neigh_node *router_gw = NULL; struct batadv_neigh_node *router_orig = NULL; u8 gw_tq_avg, orig_tq_avg; bool ret = false; /* dynamic re-election is performed only on fast or late switch */ - if (atomic_read(&bat_priv->gw.sel_class) <= 2) + if (sel_class <= 2) return false; router_gw = batadv_orig_router_get(curr_gw_orig, BATADV_IF_DEFAULT); @@ -2448,8 +2453,7 @@ static bool batadv_iv_gw_is_eligible(struct batadv_priv *bat_priv, /* if the routing class is greater than 3 the value tells us how much * greater the TQ value of the new gateway must be */ - if ((atomic_read(&bat_priv->gw.sel_class) > 3) && - (orig_tq_avg - gw_tq_avg < atomic_read(&bat_priv->gw.sel_class))) + if (sel_class > 3 && orig_tq_avg - gw_tq_avg < sel_class) goto out; batadv_dbg(BATADV_DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index de9444714264..492058a87682 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -505,7 +506,7 @@ static bool batadv_v_neigh_is_sob(struct batadv_neigh_node *neigh1, static void batadv_v_init_sel_class(struct batadv_priv *bat_priv) { /* set default throughput difference threshold to 5Mbps */ - atomic_set(&bat_priv->gw.sel_class, 50); + WRITE_ONCE(bat_priv->gw.sel_class, 50); } /** @@ -602,7 +603,7 @@ static bool batadv_v_gw_is_eligible(struct batadv_priv *bat_priv, u32 gw_throughput, orig_throughput, threshold; bool ret = false; - threshold = atomic_read(&bat_priv->gw.sel_class); + threshold = READ_ONCE(bat_priv->gw.sel_class); curr_gw = batadv_gw_node_get(bat_priv, curr_gw_orig); if (!curr_gw) { diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index 6436e9bc079b..28f28b61ad6b 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,7 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv) if (delayed_work_pending(&bat_priv->bat_v.ogm_wq)) return; - msecs = atomic_read(&bat_priv->orig_interval) - BATADV_JITTER; + msecs = READ_ONCE(bat_priv->orig_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); queue_delayed_work(batadv_event_workqueue, &bat_priv->bat_v.ogm_wq, msecs_to_jiffies(msecs)); @@ -247,7 +248,7 @@ static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, return; } - if (!atomic_read(&bat_priv->aggregated_ogms)) { + if (!READ_ONCE(bat_priv->aggregated_ogms)) { batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface); return; } @@ -486,7 +487,7 @@ static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, u32 throughput) { int if_hop_penalty = atomic_read(&if_incoming->hop_penalty); - int hop_penalty = atomic_read(&bat_priv->hop_penalty); + int hop_penalty = READ_ONCE(bat_priv->hop_penalty); int hop_penalty_max = BATADV_TQ_MAX_VALUE; /* Apply per hardif hop penalty */ diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index f6ca69252ff7..87d6b11161e4 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -1380,7 +1380,7 @@ void batadv_bla_update_orig_address(struct batadv_priv *bat_priv, bat_priv->bla.claim_dest.group = group; /* purge everything when bridge loop avoidance is turned off */ - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) oldif = NULL; if (!oldif) { @@ -1484,7 +1484,7 @@ static void batadv_bla_periodic_work(struct work_struct *work) batadv_bla_purge_claims(bat_priv, primary_if, 0); batadv_bla_purge_backbone_gw(bat_priv, 0); - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto out; if (atomic_dec_and_test(&bat_priv->bla.loopdetect_next)) { @@ -1783,7 +1783,7 @@ bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, struct batadv_bla_backbone_gw *backbone_gw; int i; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) return false; if (!hash) @@ -1821,7 +1821,7 @@ bool batadv_bla_is_backbone_gw(struct sk_buff *skb, struct batadv_bla_backbone_gw *backbone_gw; unsigned short vid; - if (!atomic_read(&orig_node->bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(orig_node->bat_priv->bridge_loop_avoidance)) return false; /* first, find out the vid. */ @@ -1953,7 +1953,7 @@ bool batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, if (!primary_if) goto handled; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto allow; if (batadv_bla_loopdetect_check(bat_priv, skb, primary_if, vid)) @@ -2085,7 +2085,7 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, if (!primary_if) goto out; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) goto allow; if (batadv_bla_process_claim(bat_priv, primary_if, skb)) @@ -2505,7 +2505,7 @@ bool batadv_bla_check_claim(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if = NULL; bool ret = true; - if (!atomic_read(&bat_priv->bridge_loop_avoidance)) + if (!READ_ONCE(bat_priv->bridge_loop_avoidance)) return ret; primary_if = batadv_primary_if_get_selected(bat_priv); diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index c6084ae6760c..0b02018c5b85 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -743,7 +743,7 @@ static void batadv_dat_tvlv_container_update(struct batadv_priv *bat_priv) { char dat_mode; - dat_mode = atomic_read(&bat_priv->distributed_arp_table); + dat_mode = READ_ONCE(bat_priv->distributed_arp_table); switch (dat_mode) { case 0: @@ -1139,7 +1139,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, int hdr_size = 0; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1234,7 +1234,7 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, unsigned short vid; int err; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1296,7 +1296,7 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, int hdr_size = 0; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1344,7 +1344,7 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, bool dropped = false; unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; vid = batadv_dat_get_vid(skb, &hdr_size); @@ -1714,7 +1714,7 @@ void batadv_dat_snoop_outgoing_dhcp_ack(struct batadv_priv *bat_priv, u8 chaddr[BATADV_DHCP_CHADDR_LEN]; __be32 ip_src, yiaddr; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr)) @@ -1744,7 +1744,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, __be16 proto; u8 *hw_src; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) return; if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN))) @@ -1789,7 +1789,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, int hdr_size = sizeof(struct batadv_bcast_packet); unsigned short vid; - if (!atomic_read(&bat_priv->distributed_arp_table)) + if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; /* If this packet is an ARP_REQUEST and the node already has the diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 026627c8ba45..305488a74a25 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -171,7 +171,7 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) { struct batadv_gw_node *curr_gw; - if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) + if (READ_ONCE(bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) return; curr_gw = batadv_gw_get_selected_gw_node(bat_priv); @@ -203,7 +203,7 @@ void batadv_gw_election(struct batadv_priv *bat_priv) struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' }; - if (atomic_read(&bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) + if (READ_ONCE(bat_priv->gw.mode) != BATADV_GW_MODE_CLIENT) goto out; if (!bat_priv->algo_ops->gw.get_best_gw_node) @@ -703,7 +703,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, if (!gw_node) goto out; - switch (atomic_read(&bat_priv->gw.mode)) { + switch (READ_ONCE(bat_priv->gw.mode)) { case BATADV_GW_MODE_SERVER: /* If we are a GW then we are our best GW. We can artificially * set the tq towards ourself as the maximum value diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 315fa90f0c94..675ebf098d4e 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -7,8 +7,8 @@ #include "gateway_common.h" #include "main.h" -#include #include +#include #include #include #include @@ -25,10 +25,10 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) { struct batadv_tvlv_gateway_data gw; + enum batadv_gw_modes gw_mode; u32 down, up; - char gw_mode; - gw_mode = atomic_read(&bat_priv->gw.mode); + gw_mode = READ_ONCE(bat_priv->gw.mode); switch (gw_mode) { case BATADV_GW_MODE_OFF: @@ -36,8 +36,8 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_GW, 1); break; case BATADV_GW_MODE_SERVER: - down = atomic_read(&bat_priv->gw.bandwidth_down); - up = atomic_read(&bat_priv->gw.bandwidth_up); + down = READ_ONCE(bat_priv->gw.bandwidth_down); + up = READ_ONCE(bat_priv->gw.bandwidth_up); gw.bandwidth_down = htonl(down); gw.bandwidth_up = htonl(up); batadv_tvlv_container_register(bat_priv, BATADV_TVLV_GW, 1, @@ -83,7 +83,7 @@ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, /* restart gateway selection */ if (gateway.bandwidth_down != 0 && - atomic_read(&bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) + READ_ONCE(bat_priv->gw.mode) == BATADV_GW_MODE_CLIENT) batadv_gw_check_election(bat_priv, orig); } @@ -96,7 +96,7 @@ void batadv_gw_init(struct batadv_priv *bat_priv) if (bat_priv->algo_ops->gw.init_sel_class) bat_priv->algo_ops->gw.init_sel_class(bat_priv); else - atomic_set(&bat_priv->gw.sel_class, 1); + WRITE_ONCE(bat_priv->gw.sel_class, 1); batadv_tvlv_handler_register(bat_priv, batadv_gw_tvlv_ogm_handler_v1, NULL, NULL, BATADV_TVLV_GW, 1, diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 647fda1898e5..e89aa4b61a7c 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -612,7 +612,7 @@ int batadv_hardif_min_mtu(struct net_device *mesh_iface) } rcu_read_unlock(); - if (atomic_read(&bat_priv->fragmentation) == 0) + if (READ_ONCE(bat_priv->fragmentation) == 0) goto out; /* with fragmentation enabled the maximum size of internally generated @@ -727,6 +727,7 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, int max_header_len = batadv_max_header_len(); unsigned int required_mtu; unsigned int hardif_mtu; + bool fragmentation; int ret; hardif_mtu = READ_ONCE(hard_iface->net_dev->mtu); @@ -764,15 +765,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, batadv_info(hard_iface->mesh_iface, "Adding interface: %s\n", hard_iface->net_dev->name); - if (atomic_read(&bat_priv->fragmentation) && - hardif_mtu < required_mtu) + fragmentation = READ_ONCE(bat_priv->fragmentation); + if (fragmentation && hardif_mtu < required_mtu) batadv_info(hard_iface->mesh_iface, "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 which could impact the performance. Setting the MTU to %i would solve the problem.\n", hard_iface->net_dev->name, hardif_mtu, required_mtu); - if (!atomic_read(&bat_priv->fragmentation) && - hardif_mtu < required_mtu) + if (!fragmentation && hardif_mtu < required_mtu) batadv_info(hard_iface->mesh_iface, "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 the MTU to %i.\n", hard_iface->net_dev->name, hardif_mtu, diff --git a/net/batman-adv/log.h b/net/batman-adv/log.h index 225b747a2048..a0d2b0d64b2b 100644 --- a/net/batman-adv/log.h +++ b/net/batman-adv/log.h @@ -76,7 +76,7 @@ __printf(2, 3); #define _batadv_dbg(type, bat_priv, ratelimited, fmt, arg...) \ do { \ struct batadv_priv *__batpriv = (bat_priv); \ - if (atomic_read(&__batpriv->log_level) & (type) && \ + if (READ_ONCE(__batpriv->log_level) & (type) && \ (!(ratelimited) || net_ratelimit())) \ batadv_debug_log(__batpriv, fmt, ## arg); \ } \ diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index d6f40ae3c815..071cbf1c1d31 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -257,7 +257,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, if (batadv_compare_eth(ethhdr->h_dest, ectp_addr)) goto dropped; - gw_mode = atomic_read(&bat_priv->gw.mode); + gw_mode = READ_ONCE(bat_priv->gw.mode); if (is_multicast_ether_addr(ethhdr->h_dest)) { /* if gw mode is off, broadcast every packet */ if (gw_mode == BATADV_GW_MODE_OFF) { @@ -754,31 +754,31 @@ static int batadv_meshif_init_late(struct net_device *dev) if (!bat_priv->bat_counters) return -ENOMEM; - atomic_set(&bat_priv->aggregated_ogms, 1); - atomic_set(&bat_priv->bonding, 0); + WRITE_ONCE(bat_priv->aggregated_ogms, 1); + WRITE_ONCE(bat_priv->bonding, 0); #ifdef CONFIG_BATMAN_ADV_BLA - atomic_set(&bat_priv->bridge_loop_avoidance, 1); + WRITE_ONCE(bat_priv->bridge_loop_avoidance, 1); #endif #ifdef CONFIG_BATMAN_ADV_DAT - atomic_set(&bat_priv->distributed_arp_table, 1); + WRITE_ONCE(bat_priv->distributed_arp_table, 1); #endif #ifdef CONFIG_BATMAN_ADV_MCAST - atomic_set(&bat_priv->multicast_mode, 1); - atomic_set(&bat_priv->multicast_fanout, 16); + WRITE_ONCE(bat_priv->multicast_mode, 1); + WRITE_ONCE(bat_priv->multicast_fanout, 16); atomic_set(&bat_priv->mcast.num_want_all_unsnoopables, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv4, 0); atomic_set(&bat_priv->mcast.num_want_all_ipv6, 0); atomic_set(&bat_priv->mcast.num_no_mc_ptype_capa, 0); #endif - atomic_set(&bat_priv->gw.mode, BATADV_GW_MODE_OFF); - atomic_set(&bat_priv->gw.bandwidth_down, 100); - atomic_set(&bat_priv->gw.bandwidth_up, 20); - atomic_set(&bat_priv->orig_interval, 1000); - atomic_set(&bat_priv->hop_penalty, 30); + WRITE_ONCE(bat_priv->gw.mode, BATADV_GW_MODE_OFF); + WRITE_ONCE(bat_priv->gw.bandwidth_down, 100); + WRITE_ONCE(bat_priv->gw.bandwidth_up, 20); + WRITE_ONCE(bat_priv->orig_interval, 1000); + WRITE_ONCE(bat_priv->hop_penalty, 30); #ifdef CONFIG_BATMAN_ADV_DEBUG - atomic_set(&bat_priv->log_level, 0); + WRITE_ONCE(bat_priv->log_level, 0); #endif - atomic_set(&bat_priv->fragmentation, 1); + WRITE_ONCE(bat_priv->fragmentation, 1); atomic_set(&bat_priv->packet_size_max, BATADV_MAX_MTU); atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN); diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index a3d3efe22d30..3274e2ac4f4a 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -1099,7 +1099,7 @@ static int batadv_mcast_forw_mode_check(struct batadv_priv *bat_priv, { struct ethhdr *ethhdr = eth_hdr(skb); - if (!atomic_read(&bat_priv->multicast_mode)) + if (!READ_ONCE(bat_priv->multicast_mode)) return -EINVAL; switch (ntohs(ethhdr->h_proto)) { @@ -1204,7 +1204,7 @@ batadv_mcast_forw_mode_by_count(struct batadv_priv *bat_priv, batadv_mcast_forw_push(bat_priv, skb, vid, is_routable, count)) return BATADV_FORW_MCAST; - if (count <= atomic_read(&bat_priv->multicast_fanout)) + if (count <= READ_ONCE(bat_priv->multicast_fanout)) return BATADV_FORW_UCASTS; return BATADV_FORW_BCAST; diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index b30f018740fc..027e9fe1042a 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -268,7 +269,7 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, } if (nla_put_u8(msg, BATADV_ATTR_AGGREGATED_OGMS_ENABLED, - !!atomic_read(&bat_priv->aggregated_ogms))) + !!READ_ONCE(bat_priv->aggregated_ogms))) goto nla_put_failure; if (batadv_netlink_mesh_fill_ap_isolation(msg, bat_priv)) @@ -283,35 +284,35 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_BONDING_ENABLED, - !!atomic_read(&bat_priv->bonding))) + !!READ_ONCE(bat_priv->bonding))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_BLA if (nla_put_u8(msg, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED, - !!atomic_read(&bat_priv->bridge_loop_avoidance))) + !!READ_ONCE(bat_priv->bridge_loop_avoidance))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BLA */ #ifdef CONFIG_BATMAN_ADV_DAT if (nla_put_u8(msg, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED, - !!atomic_read(&bat_priv->distributed_arp_table))) + !!READ_ONCE(bat_priv->distributed_arp_table))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DAT */ if (nla_put_u8(msg, BATADV_ATTR_FRAGMENTATION_ENABLED, - !!atomic_read(&bat_priv->fragmentation))) + !!READ_ONCE(bat_priv->fragmentation))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_DOWN, - atomic_read(&bat_priv->gw.bandwidth_down))) + READ_ONCE(bat_priv->gw.bandwidth_down))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_GW_BANDWIDTH_UP, - atomic_read(&bat_priv->gw.bandwidth_up))) + READ_ONCE(bat_priv->gw.bandwidth_up))) goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_GW_MODE, - atomic_read(&bat_priv->gw.mode))) + READ_ONCE(bat_priv->gw.mode))) goto nla_put_failure; if (bat_priv->algo_ops->gw.get_best_gw_node && @@ -320,32 +321,32 @@ static int batadv_netlink_mesh_fill(struct sk_buff *msg, * in use does not implement the GW API */ if (nla_put_u32(msg, BATADV_ATTR_GW_SEL_CLASS, - atomic_read(&bat_priv->gw.sel_class))) + READ_ONCE(bat_priv->gw.sel_class))) goto nla_put_failure; } if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, - atomic_read(&bat_priv->hop_penalty))) + READ_ONCE(bat_priv->hop_penalty))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_DEBUG if (nla_put_u32(msg, BATADV_ATTR_LOG_LEVEL, - atomic_read(&bat_priv->log_level))) + READ_ONCE(bat_priv->log_level))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_DEBUG */ #ifdef CONFIG_BATMAN_ADV_MCAST if (nla_put_u8(msg, BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED, - !atomic_read(&bat_priv->multicast_mode))) + !READ_ONCE(bat_priv->multicast_mode))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_MULTICAST_FANOUT, - atomic_read(&bat_priv->multicast_fanout))) + READ_ONCE(bat_priv->multicast_fanout))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_MCAST */ if (nla_put_u32(msg, BATADV_ATTR_ORIG_INTERVAL, - atomic_read(&bat_priv->orig_interval))) + READ_ONCE(bat_priv->orig_interval))) goto nla_put_failure; batadv_hardif_put(primary_if); @@ -433,7 +434,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]) { attr = info->attrs[BATADV_ATTR_AGGREGATED_OGMS_ENABLED]; - atomic_set(&bat_priv->aggregated_ogms, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->aggregated_ogms, !!nla_get_u8(attr)); } if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { @@ -457,14 +458,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_BONDING_ENABLED]) { attr = info->attrs[BATADV_ATTR_BONDING_ENABLED]; - atomic_set(&bat_priv->bonding, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->bonding, !!nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_BLA if (info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]) { attr = info->attrs[BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED]; - atomic_set(&bat_priv->bridge_loop_avoidance, + WRITE_ONCE(bat_priv->bridge_loop_avoidance, !!nla_get_u8(attr)); batadv_bla_status_update(bat_priv->mesh_iface); } @@ -474,7 +475,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]) { attr = info->attrs[BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED]; - atomic_set(&bat_priv->distributed_arp_table, + WRITE_ONCE(bat_priv->distributed_arp_table, !!nla_get_u8(attr)); batadv_dat_status_update(bat_priv->mesh_iface); } @@ -483,7 +484,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]) { attr = info->attrs[BATADV_ATTR_FRAGMENTATION_ENABLED]; - atomic_set(&bat_priv->fragmentation, !!nla_get_u8(attr)); + WRITE_ONCE(bat_priv->fragmentation, !!nla_get_u8(attr)); rtnl_lock(); batadv_update_min_mtu(bat_priv->mesh_iface); @@ -493,14 +494,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]) { attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_DOWN]; - atomic_set(&bat_priv->gw.bandwidth_down, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->gw.bandwidth_down, nla_get_u32(attr)); batadv_gw_tvlv_container_update(bat_priv); } if (info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]) { attr = info->attrs[BATADV_ATTR_GW_BANDWIDTH_UP]; - atomic_set(&bat_priv->gw.bandwidth_up, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->gw.bandwidth_up, nla_get_u32(attr)); batadv_gw_tvlv_container_update(bat_priv); } @@ -528,7 +529,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) * changing the gateway state */ batadv_gw_check_client_stop(bat_priv); - atomic_set(&bat_priv->gw.mode, gw_mode); + WRITE_ONCE(bat_priv->gw.mode, gw_mode); batadv_gw_tvlv_container_update(bat_priv); } } @@ -547,7 +548,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) sel_class = nla_get_u32(attr); if (sel_class >= 1 && sel_class <= sel_class_max) { - atomic_set(&bat_priv->gw.sel_class, sel_class); + WRITE_ONCE(bat_priv->gw.sel_class, sel_class); batadv_gw_reselect(bat_priv); } } @@ -555,14 +556,14 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; - atomic_set(&bat_priv->hop_penalty, nla_get_u8(attr)); + WRITE_ONCE(bat_priv->hop_penalty, nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_DEBUG if (info->attrs[BATADV_ATTR_LOG_LEVEL]) { attr = info->attrs[BATADV_ATTR_LOG_LEVEL]; - atomic_set(&bat_priv->log_level, + WRITE_ONCE(bat_priv->log_level, nla_get_u32(attr) & BATADV_DBG_ALL); } #endif /* CONFIG_BATMAN_ADV_DEBUG */ @@ -571,13 +572,13 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]) { attr = info->attrs[BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED]; - atomic_set(&bat_priv->multicast_mode, !nla_get_u8(attr)); + WRITE_ONCE(bat_priv->multicast_mode, !nla_get_u8(attr)); } if (info->attrs[BATADV_ATTR_MULTICAST_FANOUT]) { attr = info->attrs[BATADV_ATTR_MULTICAST_FANOUT]; - atomic_set(&bat_priv->multicast_fanout, nla_get_u32(attr)); + WRITE_ONCE(bat_priv->multicast_fanout, nla_get_u32(attr)); } #endif /* CONFIG_BATMAN_ADV_MCAST */ @@ -590,7 +591,7 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info) orig_interval = min_t(u32, orig_interval, INT_MAX); orig_interval = max_t(u32, orig_interval, 2 * BATADV_JITTER); - atomic_set(&bat_priv->orig_interval, orig_interval); + WRITE_ONCE(bat_priv->orig_interval, orig_interval); } batadv_netlink_notify_mesh(bat_priv); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index ad4921b659d9..0ce07bfdade5 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -7,7 +7,6 @@ #include "originator.h" #include "main.h" -#include #include #include #include diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 12c16f81cc51..1dd295d934f4 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -543,7 +543,7 @@ batadv_find_router(struct batadv_priv *bat_priv, /* only consider bonding for recv_if == BATADV_IF_DEFAULT (first hop) * and if activated. */ - if (!(recv_if == BATADV_IF_DEFAULT && atomic_read(&bat_priv->bonding))) + if (!(recv_if == BATADV_IF_DEFAULT && READ_ONCE(bat_priv->bonding))) return router; /* bonding: loop through the list of possible routers found diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 60cd67ec9cea..62ae98eef81e 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -185,7 +185,7 @@ int batadv_send_skb_to_orig(struct sk_buff *skb, /* Check if the skb is too large to send in one piece and fragment * it if needed. */ - if (atomic_read(&bat_priv->fragmentation) && + if (READ_ONCE(bat_priv->fragmentation) && skb->len > neigh_node->if_incoming->net_dev->mtu) { /* Fragment and send packet. */ ret = batadv_frag_send_packet(skb, orig_node, neigh_node); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 16fe84357742..c4845b5e43be 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1119,21 +1119,21 @@ struct batadv_priv_gw { /** * @mode: gateway operation: off, client or server (see batadv_gw_modes) */ - atomic_t mode; + enum batadv_gw_modes mode; /** @sel_class: gateway selection class (applies if gw_mode client) */ - atomic_t sel_class; + u32 sel_class; /** * @bandwidth_down: advertised uplink download bandwidth (if gw_mode * server) */ - atomic_t bandwidth_down; + u32 bandwidth_down; /** * @bandwidth_up: advertised uplink upload bandwidth (if gw_mode server) */ - atomic_t bandwidth_up; + u32 bandwidth_up; /** @reselect: bool indicating a gateway re-selection is in progress */ atomic_t reselect; @@ -1524,16 +1524,46 @@ struct batadv_priv { /** * @aggregated_ogms: bool indicating whether OGM aggregation is enabled */ - atomic_t aggregated_ogms; + u8 aggregated_ogms; /** @bonding: bool indicating whether traffic bonding is enabled */ - atomic_t bonding; + u8 bonding; /** * @fragmentation: bool indicating whether traffic fragmentation is * enabled */ - atomic_t fragmentation; + u8 fragmentation; + +#ifdef CONFIG_BATMAN_ADV_BLA + /** + * @bridge_loop_avoidance: bool indicating whether bridge loop + * avoidance is enabled + */ + u8 bridge_loop_avoidance; +#endif + +#ifdef CONFIG_BATMAN_ADV_DAT + /** + * @distributed_arp_table: bool indicating whether distributed ARP table + * is enabled + */ + u8 distributed_arp_table; +#endif + +#ifdef CONFIG_BATMAN_ADV_MCAST + /** + * @multicast_mode: Enable or disable multicast optimizations on this + * node's sender/originating side + */ + u8 multicast_mode; + + /** + * @multicast_fanout: Maximum number of packet copies to generate for a + * multicast-to-unicast conversion + */ + u32 multicast_fanout; +#endif /** * @packet_size_max: max packet size that can be transmitted via @@ -1548,48 +1578,18 @@ struct batadv_priv { */ atomic_t frag_seqno; -#ifdef CONFIG_BATMAN_ADV_BLA - /** - * @bridge_loop_avoidance: bool indicating whether bridge loop - * avoidance is enabled - */ - atomic_t bridge_loop_avoidance; -#endif - -#ifdef CONFIG_BATMAN_ADV_DAT - /** - * @distributed_arp_table: bool indicating whether distributed ARP table - * is enabled - */ - atomic_t distributed_arp_table; -#endif - -#ifdef CONFIG_BATMAN_ADV_MCAST - /** - * @multicast_mode: Enable or disable multicast optimizations on this - * node's sender/originating side - */ - atomic_t multicast_mode; - - /** - * @multicast_fanout: Maximum number of packet copies to generate for a - * multicast-to-unicast conversion - */ - atomic_t multicast_fanout; -#endif - /** @orig_interval: OGM broadcast interval in milliseconds */ - atomic_t orig_interval; + u32 orig_interval; /** * @hop_penalty: penalty which will be applied to an OGM's tq-field on * every hop */ - atomic_t hop_penalty; + u8 hop_penalty; #ifdef CONFIG_BATMAN_ADV_DEBUG /** @log_level: configured log level (see batadv_dbg_level) */ - atomic_t log_level; + u32 log_level; #endif /** From dbb48d9089bd607cbe7d73e795ede0090032eafc Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 08/15] batman-adv: replace non-atomic hardif config fields with (READ|WRITE)_ONCE The hardif configuration values are only accessed as plain loads/stores and do not require full atomic_t semantics. Convert these fields to native integer types and replace their users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_iv_ogm.c | 2 +- net/batman-adv/bat_v.c | 5 ++--- net/batman-adv/bat_v_elp.c | 7 ++++--- net/batman-adv/bat_v_ogm.c | 6 +++--- net/batman-adv/hard-interface.c | 2 +- net/batman-adv/netlink.c | 12 ++++++------ net/batman-adv/types.h | 6 +++--- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 5628017bee51..df8e64588e1e 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1218,7 +1218,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, inv_asym_penalty = BATADV_TQ_MAX_VALUE * neigh_rq_inv_cube; inv_asym_penalty /= neigh_rq_max_cube; tq_asym_penalty = BATADV_TQ_MAX_VALUE - inv_asym_penalty; - tq_iface_hop_penalty -= atomic_read(&if_incoming->hop_penalty); + tq_iface_hop_penalty -= READ_ONCE(if_incoming->hop_penalty); /* penalize if the OGM is forwarded on the same interface. WiFi * interfaces and other half duplex devices suffer from throughput diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c index 492058a87682..ac2932da5472 100644 --- a/net/batman-adv/bat_v.c +++ b/net/batman-adv/bat_v.c @@ -7,7 +7,6 @@ #include "bat_v.h" #include "main.h" -#include #include #include #include @@ -813,8 +812,8 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) /* enable link throughput auto-detection by setting the throughput * override to zero */ - atomic_set(&hard_iface->bat_v.throughput_override, 0); - atomic_set(&hard_iface->bat_v.elp_interval, 500); + WRITE_ONCE(hard_iface->bat_v.throughput_override, 0); + WRITE_ONCE(hard_iface->bat_v.elp_interval, 500); hard_iface->bat_v.aggr_len = 0; skb_queue_head_init(&hard_iface->bat_v.aggr_list); diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index e207093de79f..0190fafcbed2 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -62,7 +63,7 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface) { unsigned int msecs; - msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER; + msecs = READ_ONCE(hard_iface->bat_v.elp_interval) - BATADV_JITTER; msecs += get_random_u32_below(2 * BATADV_JITTER); queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq, @@ -98,7 +99,7 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh, /* if the user specified a customised value for this interface, then * return it directly */ - throughput = atomic_read(&hard_iface->bat_v.throughput_override); + throughput = READ_ONCE(hard_iface->bat_v.throughput_override); if (throughput != 0) { *pthroughput = throughput; return true; @@ -324,7 +325,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) elp_packet = (struct batadv_elp_packet *)skb->data; elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno)); - elp_interval = atomic_read(&hard_iface->bat_v.elp_interval); + elp_interval = READ_ONCE(hard_iface->bat_v.elp_interval); elp_packet->elp_interval = htonl(elp_interval); batadv_dbg(BATADV_DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index 28f28b61ad6b..f4cd8cad97e0 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -486,9 +486,9 @@ static u32 batadv_v_forward_penalty(struct batadv_priv *bat_priv, struct batadv_hard_iface *if_outgoing, u32 throughput) { - int if_hop_penalty = atomic_read(&if_incoming->hop_penalty); - int hop_penalty = READ_ONCE(bat_priv->hop_penalty); - int hop_penalty_max = BATADV_TQ_MAX_VALUE; + u32 if_hop_penalty = READ_ONCE(if_incoming->hop_penalty); + u32 hop_penalty = READ_ONCE(bat_priv->hop_penalty); + u32 hop_penalty_max = BATADV_TQ_MAX_VALUE; /* Apply per hardif hop penalty */ throughput = throughput * (hop_penalty_max - if_hop_penalty) / diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index e89aa4b61a7c..86e7d10864e2 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -910,7 +910,7 @@ batadv_hardif_add_interface(struct net_device *net_dev) if (batadv_is_wifi_hardif(hard_iface)) hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS; - atomic_set(&hard_iface->hop_penalty, 0); + WRITE_ONCE(hard_iface->hop_penalty, 0); batadv_v_hardif_init(hard_iface); diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 027e9fe1042a..368072f0513c 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -811,16 +811,16 @@ static int batadv_netlink_hardif_fill(struct sk_buff *msg, } if (nla_put_u8(msg, BATADV_ATTR_HOP_PENALTY, - atomic_read(&hard_iface->hop_penalty))) + READ_ONCE(hard_iface->hop_penalty))) goto nla_put_failure; #ifdef CONFIG_BATMAN_ADV_BATMAN_V if (nla_put_u32(msg, BATADV_ATTR_ELP_INTERVAL, - atomic_read(&hard_iface->bat_v.elp_interval))) + READ_ONCE(hard_iface->bat_v.elp_interval))) goto nla_put_failure; if (nla_put_u32(msg, BATADV_ATTR_THROUGHPUT_OVERRIDE, - atomic_read(&hard_iface->bat_v.throughput_override))) + READ_ONCE(hard_iface->bat_v.throughput_override))) goto nla_put_failure; #endif /* CONFIG_BATMAN_ADV_BATMAN_V */ @@ -913,7 +913,7 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, if (info->attrs[BATADV_ATTR_HOP_PENALTY]) { attr = info->attrs[BATADV_ATTR_HOP_PENALTY]; - atomic_set(&hard_iface->hop_penalty, nla_get_u8(attr)); + WRITE_ONCE(hard_iface->hop_penalty, nla_get_u8(attr)); } #ifdef CONFIG_BATMAN_ADV_BATMAN_V @@ -921,13 +921,13 @@ static int batadv_netlink_set_hardif(struct sk_buff *skb, if (info->attrs[BATADV_ATTR_ELP_INTERVAL]) { attr = info->attrs[BATADV_ATTR_ELP_INTERVAL]; - atomic_set(&hard_iface->bat_v.elp_interval, nla_get_u32(attr)); + WRITE_ONCE(hard_iface->bat_v.elp_interval, nla_get_u32(attr)); } if (info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]) { attr = info->attrs[BATADV_ATTR_THROUGHPUT_OVERRIDE]; - atomic_set(&hard_iface->bat_v.throughput_override, + WRITE_ONCE(hard_iface->bat_v.throughput_override, nla_get_u32(attr)); } #endif /* CONFIG_BATMAN_ADV_BATMAN_V */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c4845b5e43be..dd63cd28914d 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -114,7 +114,7 @@ enum batadv_v_hard_iface_flags { */ struct batadv_hard_iface_bat_v { /** @elp_interval: time interval between two ELP transmissions */ - atomic_t elp_interval; + u32 elp_interval; /** @elp_seqno: current ELP sequence number */ atomic_t elp_seqno; @@ -138,7 +138,7 @@ struct batadv_hard_iface_bat_v { * @throughput_override: throughput override to disable link * auto-detection */ - atomic_t throughput_override; + u32 throughput_override; /** @flags: interface specific flags */ u8 flags; @@ -236,7 +236,7 @@ struct batadv_hard_iface { * @hop_penalty: penalty which will be applied to the tq-field * of an OGM received via this interface */ - atomic_t hop_penalty; + u8 hop_penalty; /** @bat_iv: per hard-interface B.A.T.M.A.N. IV data */ struct batadv_hard_iface_bat_iv bat_iv; From 26f8f9f9379bb059fce6325ce87fe881f834fab3 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 09/15] batman-adv: replace non-atomic vlan config fields with (READ|WRITE)_ONCE The vlan configuration values are only accessed as plain loads/stores and do not require full atomic_t semantics. Convert these fields to native integer types and replace their users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/main.c | 2 +- net/batman-adv/mesh-interface.c | 2 +- net/batman-adv/netlink.c | 8 ++++---- net/batman-adv/translation-table.c | 2 +- net/batman-adv/types.h | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index d529014857c9..a5398c5df263 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -627,7 +627,7 @@ bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid) */ vlan = batadv_meshif_vlan_get(bat_priv, vid); if (vlan) { - ap_isolation_enabled = atomic_read(&vlan->ap_isolation); + ap_isolation_enabled = READ_ONCE(vlan->ap_isolation); batadv_meshif_vlan_put(vlan); } diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 071cbf1c1d31..58cbb4f8a5ab 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -567,7 +567,7 @@ int batadv_meshif_create_vlan(struct batadv_priv *bat_priv, unsigned short vid) vlan->vid = vid; kref_init(&vlan->refcount); - atomic_set(&vlan->ap_isolation, 0); + WRITE_ONCE(vlan->ap_isolation, 0); kref_get(&vlan->refcount); hlist_add_head_rcu(&vlan->list, &bat_priv->meshif_vlan_list); diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c index 368072f0513c..e5463003a3bd 100644 --- a/net/batman-adv/netlink.c +++ b/net/batman-adv/netlink.c @@ -181,7 +181,7 @@ static int batadv_netlink_mesh_fill_ap_isolation(struct sk_buff *msg, if (!vlan) return 0; - ap_isolation = atomic_read(&vlan->ap_isolation); + ap_isolation = READ_ONCE(vlan->ap_isolation); batadv_meshif_vlan_put(vlan); return nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, @@ -204,7 +204,7 @@ static int batadv_netlink_set_mesh_ap_isolation(struct nlattr *attr, if (!vlan) return -ENOENT; - atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + WRITE_ONCE(vlan->ap_isolation, !!nla_get_u8(attr)); batadv_meshif_vlan_put(vlan); return 0; @@ -1022,7 +1022,7 @@ static int batadv_netlink_vlan_fill(struct sk_buff *msg, goto nla_put_failure; if (nla_put_u8(msg, BATADV_ATTR_AP_ISOLATION_ENABLED, - !!atomic_read(&vlan->ap_isolation))) + !!READ_ONCE(vlan->ap_isolation))) goto nla_put_failure; genlmsg_end(msg, hdr); @@ -1110,7 +1110,7 @@ static int batadv_netlink_set_vlan(struct sk_buff *skb, struct genl_info *info) if (info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]) { attr = info->attrs[BATADV_ATTR_AP_ISOLATION_ENABLED]; - atomic_set(&vlan->ap_isolation, !!nla_get_u8(attr)); + WRITE_ONCE(vlan->ap_isolation, !!nla_get_u8(attr)); } batadv_netlink_notify_vlan(bat_priv, vlan); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 28869f65ada0..515f26ff8c26 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -3730,7 +3730,7 @@ bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, if (!vlan) return false; - if (!atomic_read(&vlan->ap_isolation)) + if (!READ_ONCE(vlan->ap_isolation)) goto vlan_put; tt_local_entry = batadv_tt_local_hash_find(bat_priv, dst, vid); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index dd63cd28914d..cf01a670d825 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1459,7 +1459,7 @@ struct batadv_meshif_vlan { unsigned short vid; /** @ap_isolation: AP isolation state */ - atomic_t ap_isolation; /* boolean */ + u8 ap_isolation; /* boolean */ /** @tt: TT private attributes (VLAN specific) */ struct batadv_vlan_tt tt; From 2b2450e3266ad01feb5ad0adb6ec3cd5b830c511 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 10/15] batman-adv: replace non-atomic mesh state with (READ|WRITE)_ONCE The mesh state is only accessed as plain loads/stores and does not require full atomic_t semantics. Convert to an enum and replace its users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_iv_ogm.c | 2 +- net/batman-adv/bat_v_elp.c | 2 +- net/batman-adv/bat_v_ogm.c | 2 +- net/batman-adv/main.c | 20 ++++++++++---------- net/batman-adv/mesh-interface.c | 6 +++--- net/batman-adv/send.c | 2 +- net/batman-adv/tp_meter.c | 6 +++--- net/batman-adv/types.h | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index df8e64588e1e..c436b77674a5 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1777,7 +1777,7 @@ static void batadv_iv_send_outstanding_bat_ogm_packet(struct work_struct *work) delayed_work); bat_priv = netdev_priv(forw_packet->if_incoming->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { dropped = true; goto out; } diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c index 0190fafcbed2..d53485d17220 100644 --- a/net/batman-adv/bat_v_elp.c +++ b/net/batman-adv/bat_v_elp.c @@ -307,7 +307,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work) hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v); bat_priv = netdev_priv(hard_iface->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out; /* we are in the process of shutting this interface down */ diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index f4cd8cad97e0..b337bd8e58e7 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -279,7 +279,7 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv) lockdep_assert_held(&bat_priv->bat_v.ogm_buff_mutex); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) goto out; ogm_buff = &bat_priv->bat_v.ogm_buff; diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index a5398c5df263..60d4f60066c8 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -200,31 +200,31 @@ int batadv_mesh_init(struct net_device *mesh_iface) ret = batadv_originator_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_orig; } ret = batadv_tt_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_tt; } ret = batadv_v_mesh_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_v; } ret = batadv_bla_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_bla; } ret = batadv_dat_init(bat_priv); if (ret < 0) { - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); goto err_dat; } @@ -232,7 +232,7 @@ int batadv_mesh_init(struct net_device *mesh_iface) batadv_mcast_init(bat_priv); atomic_set(&bat_priv->gw.reselect, 0); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_ACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_ACTIVE); return 0; @@ -246,7 +246,7 @@ int batadv_mesh_init(struct net_device *mesh_iface) batadv_originator_free(bat_priv); err_orig: batadv_purge_outstanding_packets(bat_priv, NULL); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); return ret; } @@ -259,7 +259,7 @@ void batadv_mesh_free(struct net_device *mesh_iface) { struct batadv_priv *bat_priv = netdev_priv(mesh_iface); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_DEACTIVATING); batadv_purge_outstanding_packets(bat_priv, NULL); batadv_tp_stop_all(bat_priv); @@ -290,7 +290,7 @@ void batadv_mesh_free(struct net_device *mesh_iface) free_percpu(bat_priv->bat_counters); bat_priv->bat_counters = NULL; - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); } /** @@ -454,7 +454,7 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, bat_priv = netdev_priv(hard_iface->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto err_free; /* discard frames on not active interfaces */ diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 58cbb4f8a5ab..7497f307c10d 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -125,7 +125,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) eth_hw_addr_set(dev, addr->sa_data); /* only modify transtable if it has been initialized before */ - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) return 0; rcu_read_lock(); @@ -192,7 +192,7 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb, int network_offset = ETH_HLEN; __be16 proto; - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto dropped; /* reset control block to avoid left overs from previous users */ @@ -783,7 +783,7 @@ static int batadv_meshif_init_late(struct net_device *dev) atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN); - atomic_set(&bat_priv->mesh_state, BATADV_MESH_INACTIVE); + WRITE_ONCE(bat_priv->mesh_state, BATADV_MESH_INACTIVE); atomic_set(&bat_priv->bcast_seqno, 1); atomic_set(&bat_priv->tt.vn, 0); atomic_set(&bat_priv->tt.ogm_append_cnt, 0); diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 62ae98eef81e..c7e86c83242a 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -1047,7 +1047,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work) delayed_work); bat_priv = netdev_priv(forw_packet->if_incoming->mesh_iface); - if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { + if (READ_ONCE(bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING) { dropped = true; goto out; } diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c index 0fc4ca78e84e..aefe757277b2 100644 --- a/net/batman-adv/tp_meter.c +++ b/net/batman-adv/tp_meter.c @@ -999,7 +999,7 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst, /* look for an already existing test towards this node */ spin_lock_bh(&bat_priv->tp_list_lock); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) { + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) { spin_unlock_bh(&bat_priv->tp_list_lock); batadv_tp_batctl_error_notify(BATADV_TP_REASON_DST_UNREACHABLE, dst, bat_priv, session_cookie); @@ -1387,7 +1387,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, struct batadv_tp_vars *tp_vars = NULL; spin_lock_bh(&bat_priv->tp_list_lock); - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto out_unlock; tp_vars = batadv_tp_list_find_session(bat_priv, icmp->orig, @@ -1518,7 +1518,7 @@ void batadv_tp_meter_recv(struct batadv_priv *bat_priv, struct sk_buff *skb) { struct batadv_icmp_tp_packet *icmp; - if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE) + if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE) goto out; icmp = (struct batadv_icmp_tp_packet *)skb->data; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index cf01a670d825..58375c0a643b 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1504,7 +1504,7 @@ struct batadv_priv { * @mesh_state: current status of the mesh * (inactive/active/deactivating) */ - atomic_t mesh_state; + enum batadv_mesh_state mesh_state; /** @mesh_iface: net device which holds this struct as private data */ struct net_device *mesh_iface; From 58020571b54f41ddd786eb96cb0deb66668453db Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 11/15] batman-adv: replace non-atomic packet_size_max with (READ|WRITE)_ONCE The maximum packet size of an meshif is only accessed as plain loads/stores and does not require full atomic_t semantics. Convert to a native integer and replace its users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/hard-interface.c | 3 +-- net/batman-adv/mesh-interface.c | 2 +- net/batman-adv/translation-table.c | 6 +++--- net/batman-adv/types.h | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 86e7d10864e2..bb3c31b5f259 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -7,7 +7,6 @@ #include "hard-interface.h" #include "main.h" -#include #include #include #include @@ -629,7 +628,7 @@ int batadv_hardif_min_mtu(struct net_device *mesh_iface) * overhead). For example, this value is used by TT to compute the * maximum local table size */ - atomic_set(&bat_priv->packet_size_max, min_mtu); + WRITE_ONCE(bat_priv->packet_size_max, min_mtu); /* the real mesh-interface MTU is computed by removing the payload * overhead from the maximum amount of bytes that was just computed. diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 7497f307c10d..b6797654b18a 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -779,7 +779,7 @@ static int batadv_meshif_init_late(struct net_device *dev) WRITE_ONCE(bat_priv->log_level, 0); #endif WRITE_ONCE(bat_priv->fragmentation, 1); - atomic_set(&bat_priv->packet_size_max, BATADV_MAX_MTU); + WRITE_ONCE(bat_priv->packet_size_max, BATADV_MAX_MTU); atomic_set(&bat_priv->bcast_queue_left, BATADV_BCAST_QUEUE_LEN); atomic_set(&bat_priv->batman_queue_left, BATADV_BATMAN_QUEUE_LEN); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 515f26ff8c26..e319b0796f7c 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -649,7 +649,7 @@ bool batadv_tt_local_add(struct net_device *mesh_iface, const u8 *addr, /* Ignore the client if we cannot send it in a full table response. */ table_size = batadv_tt_local_table_transmit_size(bat_priv); table_size += batadv_tt_len(1); - packet_size_max = atomic_read(&bat_priv->packet_size_max); + packet_size_max = READ_ONCE(bat_priv->packet_size_max); if (table_size > packet_size_max) { net_ratelimited_function(batadv_info, mesh_iface, "Local translation table size (%i) exceeds maximum packet size (%i); Ignoring new local tt entry: %pM\n", @@ -3069,7 +3069,7 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, /* Don't send the response, if larger than fragmented packet. */ tt_len = sizeof(struct batadv_unicast_tvlv_packet) + tvlv_len; - if (tt_len > atomic_read(&bat_priv->packet_size_max)) { + if (tt_len > READ_ONCE(bat_priv->packet_size_max)) { net_ratelimited_function(batadv_info, bat_priv->mesh_iface, "Ignoring TT_REQUEST from %pM; Response size exceeds max packet size.\n", res_dst_orig_node->orig); @@ -3932,7 +3932,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, void batadv_tt_local_resize_to_mtu(struct net_device *mesh_iface) { struct batadv_priv *bat_priv = netdev_priv(mesh_iface); - int packet_size_max = atomic_read(&bat_priv->packet_size_max); + int packet_size_max = READ_ONCE(bat_priv->packet_size_max); int table_size, timeout = BATADV_TT_LOCAL_TIMEOUT / 2; bool reduced = false; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 58375c0a643b..7533d71b7372 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -1570,7 +1570,7 @@ struct batadv_priv { * multiple fragmented skbs or a single frame if fragmentation is * disabled */ - atomic_t packet_size_max; + int packet_size_max; /** * @frag_seqno: incremental counter to identify chains of egress From 4dd2055046c4295c30ed552b4c2fd280b8d36317 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 12 May 2026 19:37:05 +0200 Subject: [PATCH 12/15] batman-adv: replace non-atomic last_ttvn with (READ|WRITE)_ONCE The last TT version number of an meshif is only accessed as plain loads/stores and does not require full atomic_t semantics. Convert to an native integer and replace its users with READ_ONCE()/WRITE_ONCE() to avoid load/store tearing. Signed-off-by: Sven Eckelmann --- net/batman-adv/originator.c | 2 +- net/batman-adv/routing.c | 4 ++-- net/batman-adv/send.c | 2 +- net/batman-adv/translation-table.c | 16 ++++++++-------- net/batman-adv/types.h | 2 +- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 0ce07bfdade5..d05c8240426b 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -965,7 +965,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, orig_node->bat_priv = bat_priv; ether_addr_copy(orig_node->orig, addr); batadv_dat_init_orig_node_addr(orig_node); - atomic_set(&orig_node->last_ttvn, 0); + WRITE_ONCE(orig_node->last_ttvn, 0); orig_node->tt_buff = NULL; orig_node->tt_buff_len = 0; orig_node->last_seen = jiffies; diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 1dd295d934f4..cd4368b846ad 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -765,7 +765,7 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, goto out; orig_addr = orig_node->orig; - orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + orig_ttvn = READ_ONCE(orig_node->last_ttvn); } /* update the packet header */ @@ -845,7 +845,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (!orig_node) return false; - curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + curr_ttvn = READ_ONCE(orig_node->last_ttvn); batadv_orig_node_put(orig_node); } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index c7e86c83242a..5f9da3606a8f 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -222,7 +222,7 @@ batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size, struct batadv_orig_node *orig_node) { struct batadv_unicast_packet *unicast_packet; - u8 ttvn = (u8)atomic_read(&orig_node->last_ttvn); + u8 ttvn = READ_ONCE(orig_node->last_ttvn); if (batadv_skb_head_push(skb, hdr_size) < 0) return false; diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index e319b0796f7c..8903b2f84f51 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -841,7 +841,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, } (*tt_data)->flags = BATADV_NO_FLAGS; - (*tt_data)->ttvn = atomic_read(&orig_node->last_ttvn); + (*tt_data)->ttvn = READ_ONCE(orig_node->last_ttvn); (*tt_data)->num_vlan = htons(num_vlan); tt_vlan = (*tt_data)->vlan_data; @@ -1822,7 +1822,7 @@ batadv_tt_global_dump_subentry(struct sk_buff *msg, u32 portid, u32 seq, if (!hdr) return -ENOBUFS; - last_ttvn = atomic_read(&orig->orig_node->last_ttvn); + last_ttvn = READ_ONCE(orig->orig_node->last_ttvn); if (nla_put(msg, BATADV_ATTR_TT_ADDRESS, ETH_ALEN, common->addr) || nla_put(msg, BATADV_ATTR_ORIG_ADDRESS, ETH_ALEN, @@ -3013,7 +3013,7 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, if (!res_dst_orig_node) goto out; - orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); + orig_ttvn = READ_ONCE(req_dst_orig_node->last_ttvn); req_ttvn = tt_data->ttvn; /* this node doesn't have the requested data */ @@ -3300,7 +3300,7 @@ static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, orig_node->tt_buff = NULL; spin_unlock_bh(&orig_node->tt_buff_lock); - atomic_set(&orig_node->last_ttvn, ttvn); + WRITE_ONCE(orig_node->last_ttvn, ttvn); out: batadv_orig_node_put(orig_node); @@ -3316,7 +3316,7 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, batadv_tt_save_orig_buffer(bat_priv, orig_node, tt_change, batadv_tt_len(tt_num_changes)); - atomic_set(&orig_node->last_ttvn, ttvn); + WRITE_ONCE(orig_node->last_ttvn, ttvn); } /** @@ -3769,7 +3769,7 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_change *tt_change, u16 tt_num_changes, u8 ttvn) { - u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); + u8 orig_ttvn = READ_ONCE(orig_node->last_ttvn); struct batadv_tvlv_tt_vlan_data *tt_vlan; bool full_table = true; bool has_tt_init; @@ -3911,7 +3911,7 @@ bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, if (!batadv_tt_global_add(bat_priv, orig_node, addr, vid, BATADV_TT_CLIENT_TEMP, - atomic_read(&orig_node->last_ttvn))) + READ_ONCE(orig_node->last_ttvn))) return false; batadv_dbg(BATADV_DBG_TT, bat_priv, @@ -4125,7 +4125,7 @@ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, batadv_tt_global_add(bat_priv, orig_node, roaming_adv->client, ntohs(roaming_adv->vid), BATADV_TT_CLIENT_ROAM, - atomic_read(&orig_node->last_ttvn) + 1); + READ_ONCE(orig_node->last_ttvn) + 1); out: batadv_orig_node_put(orig_node); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 7533d71b7372..c188ec1cfb74 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -464,7 +464,7 @@ struct batadv_orig_node { unsigned long capa_initialized; /** @last_ttvn: last seen translation table version number */ - atomic_t last_ttvn; + u8 last_ttvn; /** @tt_buff: last tt changeset this node received from the orig node */ unsigned char *tt_buff; From 5ffd4dd8742586d1e7b80fe04340f56762960d9c Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 3 May 2026 22:46:15 +0200 Subject: [PATCH 13/15] batman-adv: tt: replace open-coded overflow check with helper The commit 6043a632dd06 ("batman-adv: reject oversized global TT response buffers") introduced an open-coded check to ensure that the allocated buffer size can be stored in a u16. The check_add_overflow() helper can perform the addition and overflow check in one step, so use that instead. Acked-by: Antonio Quartulli Signed-off-by: Sven Eckelmann --- net/batman-adv/translation-table.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 8903b2f84f51..5e134d08a80f 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -799,10 +799,10 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, { u16 num_vlan = 0; u16 tvlv_len = 0; - unsigned int change_offset; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; u16 total_entries = 0; + size_t change_offset; u8 *tt_change_ptr; int vlan_entries; u16 sum_entries; @@ -826,14 +826,11 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, if (*tt_len < 0) *tt_len = batadv_tt_len(total_entries); - if (change_offset > U16_MAX || *tt_len > U16_MAX - change_offset) { + if (check_add_overflow(*tt_len, change_offset, &tvlv_len)) { *tt_len = 0; goto out; } - tvlv_len = *tt_len; - tvlv_len += change_offset; - *tt_data = kmalloc(tvlv_len, GFP_ATOMIC); if (!*tt_data) { *tt_len = 0; From 735522e7ca3fb852c498ec17b3841750f0a84607 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 15 May 2026 16:58:16 +0200 Subject: [PATCH 14/15] batman-adv: tvlv: avoid unnecessary OGM buffer reallocations Both OGMv1 (on the primary interface) and OGM2 unconditionally reallocated their packet buffer on every transmission cycle, regardless of whether the required size had changed. This meant a kfree/kmalloc pair even when the TVLV payload size was identical to the previous send. Introduce struct batadv_ogm_buf to encapsulate the OGM packet buffer together with its current length, allocated capacity, and fixed header length. This consolidates the separate buf/len arguments that were previously threaded through each call site. In batadv_tvlv_realloc_packet_buff(), the capacity is rounded up to the next power of two so that small growth or shrinkage in TVLV data does not trigger a reallocation. When kmalloc fails but the existing buffer is large enough to hold the new data, the oversized buffer is reused rather than returning an error. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_iv_ogm.c | 35 +++++++++++----------- net/batman-adv/bat_v_ogm.c | 30 +++++++++---------- net/batman-adv/tvlv.c | 58 ++++++++++++++++++++++--------------- net/batman-adv/tvlv.h | 3 +- net/batman-adv/types.h | 31 +++++++++++++------- 5 files changed, 89 insertions(+), 68 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index c436b77674a5..6f5a468c4084 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -195,14 +195,17 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) get_random_bytes(&random_seqno, sizeof(random_seqno)); atomic_set(&hard_iface->bat_iv.ogm_seqno, random_seqno); - hard_iface->bat_iv.ogm_buff_len = BATADV_OGM_HLEN; - ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff_len, GFP_ATOMIC); + hard_iface->bat_iv.ogm_buff.len = BATADV_OGM_HLEN; + hard_iface->bat_iv.ogm_buff.capacity = BATADV_OGM_HLEN; + hard_iface->bat_iv.ogm_buff.header_length = BATADV_OGM_HLEN; + + ogm_buff = kmalloc(hard_iface->bat_iv.ogm_buff.capacity, GFP_ATOMIC); if (!ogm_buff) { mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); return -ENOMEM; } - hard_iface->bat_iv.ogm_buff = ogm_buff; + hard_iface->bat_iv.ogm_buff.buf = ogm_buff; batadv_ogm_packet = (struct batadv_ogm_packet *)ogm_buff; batadv_ogm_packet->packet_type = BATADV_IV_OGM; @@ -221,8 +224,9 @@ static void batadv_iv_ogm_iface_disable(struct batadv_hard_iface *hard_iface) { mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - kfree(hard_iface->bat_iv.ogm_buff); - hard_iface->bat_iv.ogm_buff = NULL; + kfree(hard_iface->bat_iv.ogm_buff.buf); + memset(&hard_iface->bat_iv.ogm_buff, 0, + sizeof(hard_iface->bat_iv.ogm_buff)); mutex_unlock(&hard_iface->bat_iv.ogm_buff_mutex); @@ -236,7 +240,7 @@ static void batadv_iv_ogm_iface_update_mac(struct batadv_hard_iface *hard_iface) mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - ogm_buff = hard_iface->bat_iv.ogm_buff; + ogm_buff = hard_iface->bat_iv.ogm_buff.buf; if (!ogm_buff) goto unlock; @@ -258,7 +262,7 @@ batadv_iv_ogm_primary_iface_set(struct batadv_hard_iface *hard_iface) mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex); - ogm_buff = hard_iface->bat_iv.ogm_buff; + ogm_buff = hard_iface->bat_iv.ogm_buff.buf; if (!ogm_buff) goto unlock; @@ -796,10 +800,9 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); - unsigned char **ogm_buff = &hard_iface->bat_iv.ogm_buff; + struct batadv_ogm_buf *ogm_buff = &hard_iface->bat_iv.ogm_buff; struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *primary_if, *tmp_hard_iface; - int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; struct list_head *iter; u32 seqno; u16 tvlv_len = 0; @@ -811,7 +814,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) lockdep_assert_held(&hard_iface->bat_iv.ogm_buff_mutex); /* interface already disabled by batadv_iv_ogm_iface_disable */ - if (!*ogm_buff) + if (!ogm_buff->buf) return; /* the interface gets activated here to avoid race conditions between @@ -830,9 +833,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) * appended as it may alter the tt tvlv container */ batadv_tt_local_commit_changes(bat_priv); - ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, - ogm_buff_len, - BATADV_OGM_HLEN); + ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff); if (ret < 0) { reschedule = true; goto out; @@ -841,7 +842,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) tvlv_len = ret; } - batadv_ogm_packet = (struct batadv_ogm_packet *)(*ogm_buff); + batadv_ogm_packet = ogm_buff->buf; batadv_ogm_packet->tvlv_len = htons(tvlv_len); /* change sequence number to network order */ @@ -857,7 +858,7 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) /* OGMs from secondary interfaces are only scheduled on their * respective interfaces. */ - scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, + scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, ogm_buff->len, hard_iface, hard_iface, 1, send_time); if (!scheduled) reschedule = true; @@ -873,8 +874,8 @@ static void batadv_iv_ogm_schedule_buff(struct batadv_hard_iface *hard_iface) if (!kref_get_unless_zero(&tmp_hard_iface->refcount)) continue; - scheduled = batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, - *ogm_buff_len, hard_iface, + scheduled = batadv_iv_ogm_queue_add(bat_priv, ogm_buff->buf, + ogm_buff->len, hard_iface, tmp_hard_iface, 1, send_time); batadv_hardif_put(tmp_hard_iface); diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index b337bd8e58e7..2c4dca639709 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -270,10 +270,9 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv) { struct batadv_hard_iface *hard_iface; struct batadv_ogm2_packet *ogm_packet; + struct batadv_ogm_buf *ogm_buff; struct sk_buff *skb, *skb_tmp; - unsigned char **ogm_buff; struct list_head *iter; - int *ogm_buff_len; u16 tvlv_len; int ret; @@ -283,26 +282,23 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv) goto out; ogm_buff = &bat_priv->bat_v.ogm_buff; - ogm_buff_len = &bat_priv->bat_v.ogm_buff_len; /* tt changes have to be committed before the tvlv data is * appended as it may alter the tt tvlv container */ batadv_tt_local_commit_changes(bat_priv); - ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff, - ogm_buff_len, - BATADV_OGM2_HLEN); + ret = batadv_tvlv_container_ogm_append(bat_priv, ogm_buff); if (ret < 0) goto reschedule; tvlv_len = ret; - skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + *ogm_buff_len); + skb = netdev_alloc_skb_ip_align(NULL, ETH_HLEN + ogm_buff->len); if (!skb) goto reschedule; skb_reserve(skb, ETH_HLEN); - skb_put_data(skb, *ogm_buff, *ogm_buff_len); + skb_put_data(skb, ogm_buff->buf, ogm_buff->len); ogm_packet = (struct batadv_ogm2_packet *)skb->data; ogm_packet->seqno = htonl(atomic_read(&bat_priv->bat_v.ogm_seqno)); @@ -448,10 +444,10 @@ void batadv_v_ogm_primary_iface_set(struct batadv_hard_iface *primary_iface) struct batadv_ogm2_packet *ogm_packet; mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); - if (!bat_priv->bat_v.ogm_buff) + if (!bat_priv->bat_v.ogm_buff.buf) goto unlock; - ogm_packet = (struct batadv_ogm2_packet *)bat_priv->bat_v.ogm_buff; + ogm_packet = bat_priv->bat_v.ogm_buff.buf; ether_addr_copy(ogm_packet->orig, primary_iface->net_dev->dev_addr); unlock: @@ -1052,12 +1048,15 @@ int batadv_v_ogm_init(struct batadv_priv *bat_priv) unsigned char *ogm_buff; u32 random_seqno; - bat_priv->bat_v.ogm_buff_len = BATADV_OGM2_HLEN; - ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff_len, GFP_ATOMIC); + bat_priv->bat_v.ogm_buff.len = BATADV_OGM2_HLEN; + bat_priv->bat_v.ogm_buff.capacity = BATADV_OGM2_HLEN; + bat_priv->bat_v.ogm_buff.header_length = BATADV_OGM2_HLEN; + + ogm_buff = kzalloc(bat_priv->bat_v.ogm_buff.capacity, GFP_ATOMIC); if (!ogm_buff) return -ENOMEM; - bat_priv->bat_v.ogm_buff = ogm_buff; + bat_priv->bat_v.ogm_buff.buf = ogm_buff; ogm_packet = (struct batadv_ogm2_packet *)ogm_buff; ogm_packet->packet_type = BATADV_OGM2; ogm_packet->version = BATADV_COMPAT_VERSION; @@ -1085,9 +1084,8 @@ void batadv_v_ogm_free(struct batadv_priv *bat_priv) mutex_lock(&bat_priv->bat_v.ogm_buff_mutex); - kfree(bat_priv->bat_v.ogm_buff); - bat_priv->bat_v.ogm_buff = NULL; - bat_priv->bat_v.ogm_buff_len = 0; + kfree(bat_priv->bat_v.ogm_buff.buf); + memset(&bat_priv->bat_v.ogm_buff, 0, sizeof(bat_priv->bat_v.ogm_buff)); mutex_unlock(&bat_priv->bat_v.ogm_buff_mutex); } diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c index 8e8b54e2172e..cd75daea478c 100644 --- a/net/batman-adv/tvlv.c +++ b/net/batman-adv/tvlv.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -267,32 +268,48 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, /** * batadv_tvlv_realloc_packet_buff() - reallocate packet buffer to accommodate * requested packet size - * @packet_buff: packet buffer - * @packet_buff_len: packet buffer size - * @min_packet_len: requested packet minimum size + * @ogm_buff: ogm packet buffer * @additional_packet_len: requested additional packet size on top of minimum * size * * Return: true of the packet buffer could be changed to the requested size, * false otherwise. */ -static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, - int *packet_buff_len, - int min_packet_len, - int additional_packet_len) +static bool batadv_tvlv_realloc_packet_buff(struct batadv_ogm_buf *ogm_buff, + size_t additional_packet_len) { unsigned char *new_buff; + size_t newcapacity; + size_t newlen; - new_buff = kmalloc(min_packet_len + additional_packet_len, GFP_ATOMIC); + newlen = ogm_buff->header_length + additional_packet_len; + newcapacity = roundup_pow_of_two(newlen); + + /* nothing to reallocate */ + if (newcapacity == ogm_buff->capacity) { + ogm_buff->len = newlen; + return true; + } + + new_buff = kmalloc(newcapacity, GFP_ATOMIC); /* keep old buffer if kmalloc should fail */ - if (!new_buff) - return false; + if (!new_buff) { + /* continue to use oversize buffer if new data fits */ + if (newlen <= ogm_buff->capacity) { + ogm_buff->len = newlen; + return true; + } - memcpy(new_buff, *packet_buff, min_packet_len); - kfree(*packet_buff); - *packet_buff = new_buff; - *packet_buff_len = min_packet_len + additional_packet_len; + return false; + } + + memcpy(new_buff, ogm_buff->buf, ogm_buff->header_length); + kfree(ogm_buff->buf); + + ogm_buff->buf = new_buff; + ogm_buff->len = newlen; + ogm_buff->capacity = newcapacity; return true; } @@ -301,10 +318,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, * batadv_tvlv_container_ogm_append() - append tvlv container content to given * OGM packet buffer * @bat_priv: the bat priv with all the mesh interface information - * @packet_buff: ogm packet buffer - * @packet_buff_len: ogm packet buffer size including ogm header and tvlv - * content - * @packet_min_len: ogm header size to be preserved for the OGM itself + * @ogm_buff: ogm packet buffer * * The ogm packet might be enlarged or shrunk depending on the current size * and the size of the to-be-appended tvlv containers. @@ -313,8 +327,7 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, * if operation failed */ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, int packet_min_len) + struct batadv_ogm_buf *ogm_buff) { struct batadv_tvlv_container *tvlv; struct batadv_tvlv_hdr *tvlv_hdr; @@ -330,8 +343,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, goto end; } - ret = batadv_tvlv_realloc_packet_buff(packet_buff, packet_buff_len, - packet_min_len, tvlv_value_len); + ret = batadv_tvlv_realloc_packet_buff(ogm_buff, tvlv_value_len); if (!ret) { tvlv_len_ret = -ENOMEM; goto end; @@ -342,7 +354,7 @@ int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, if (!tvlv_value_len) goto end; - tvlv_value = (*packet_buff) + packet_min_len; + tvlv_value = (u8 *)ogm_buff->buf + ogm_buff->header_length; hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_hdr = tvlv_value; diff --git a/net/batman-adv/tvlv.h b/net/batman-adv/tvlv.h index f96f6b3f44a0..fc9783850443 100644 --- a/net/batman-adv/tvlv.h +++ b/net/batman-adv/tvlv.h @@ -17,8 +17,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, u8 type, u8 version, void *tvlv_value, u16 tvlv_value_len); int batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, int packet_min_len); + struct batadv_ogm_buf *ogm_buff); void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_orig_node *orig_node); diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index c188ec1cfb74..4e25057359b0 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -71,15 +71,29 @@ enum batadv_dhcp_recipient { */ #define BATADV_TT_SYNC_MASK 0x00F0 +/** + * struct batadv_ogm_buf - Buffer to construct an OGM with TVLV + */ +struct batadv_ogm_buf { + /** @buf: buffer holding the OGM packet */ + void *buf; + + /** @len: length of the OGM packet buffer data */ + size_t len; + + /** @capacity: size of allocated buf */ + size_t capacity; + + /** @header_length: fixed size header length (must be <= len) */ + size_t header_length; +}; + /** * struct batadv_hard_iface_bat_iv - per hard-interface B.A.T.M.A.N. IV data */ struct batadv_hard_iface_bat_iv { /** @ogm_buff: buffer holding the OGM packet */ - unsigned char *ogm_buff; - - /** @ogm_buff_len: length of the OGM packet buffer */ - int ogm_buff_len; + struct batadv_ogm_buf ogm_buff; /** @ogm_seqno: OGM sequence number - used to identify each OGM */ atomic_t ogm_seqno; @@ -87,7 +101,7 @@ struct batadv_hard_iface_bat_iv { /** @reschedule_work: recover OGM schedule after schedule error */ struct delayed_work reschedule_work; - /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ + /** @ogm_buff_mutex: lock protecting ogm_buff */ struct mutex ogm_buff_mutex; }; @@ -1481,15 +1495,12 @@ struct batadv_meshif_vlan { */ struct batadv_priv_bat_v { /** @ogm_buff: buffer holding the OGM packet */ - unsigned char *ogm_buff; - - /** @ogm_buff_len: length of the OGM packet buffer */ - int ogm_buff_len; + struct batadv_ogm_buf ogm_buff; /** @ogm_seqno: OGM sequence number - used to identify each OGM */ atomic_t ogm_seqno; - /** @ogm_buff_mutex: lock protecting ogm_buff and ogm_buff_len */ + /** @ogm_buff_mutex: lock protecting ogm_buff */ struct mutex ogm_buff_mutex; /** @ogm_wq: workqueue used to schedule OGM transmissions */ From 3bd64ca11d9a1672d67d3130a7264c2cf7f93cdf Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Mon, 4 May 2026 21:32:24 +0200 Subject: [PATCH 15/15] batman-adv: use neigh_node's orig_node only as id The orig_node member of struct batadv_neigh_node is no longer used in B.A.T.M.A.N. IV. But batadv_neigh_node_create() is still storing it. Only batadv_v_ogm_route_update() uses it to check if we route toward it - not needing the data stored in the batadv_orig_node object itself, but merely a pointer to identify the originator. The field cannot hold a proper reference because that would create a reference cycle, so it must never be dereferenced. Rename it to orig_node_id and mark it __private to make any future attempt to dereference it immediately noticeable. Signed-off-by: Sven Eckelmann --- net/batman-adv/bat_v_ogm.c | 2 +- net/batman-adv/originator.c | 5 ++++- net/batman-adv/types.h | 11 +++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c index 2c4dca639709..5936d0048be0 100644 --- a/net/batman-adv/bat_v_ogm.c +++ b/net/batman-adv/bat_v_ogm.c @@ -719,7 +719,7 @@ static bool batadv_v_ogm_route_update(struct batadv_priv *bat_priv, * don't route towards it */ router = batadv_orig_router_get(orig_node, if_outgoing); - if (router && router->orig_node != orig_node && !orig_neigh_router) { + if (router && ACCESS_PRIVATE(router, orig_node_id) != orig_node && !orig_neigh_router) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Drop packet: OGM via unknown neighbor!\n"); goto out; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index d05c8240426b..15d660ca7937 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -693,9 +693,12 @@ batadv_neigh_node_create(struct batadv_orig_node *orig_node, kref_get(&hard_iface->refcount); ether_addr_copy(neigh_node->addr, neigh_addr); neigh_node->if_incoming = hard_iface; - neigh_node->orig_node = orig_node; neigh_node->last_seen = jiffies; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + ACCESS_PRIVATE(neigh_node, orig_node_id) = orig_node; +#endif + /* increment unique neighbor refcount */ kref_get(&hardif_neigh->refcount); neigh_node->hardif_neigh = hardif_neigh; diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 4e25057359b0..19c7316889b6 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -663,8 +663,15 @@ struct batadv_neigh_node { /** @list: list node for &batadv_orig_node.neigh_list */ struct hlist_node list; - /** @orig_node: pointer to corresponding orig_node */ - struct batadv_orig_node *orig_node; +#ifdef CONFIG_BATMAN_ADV_BATMAN_V + /** + * @orig_node_id: pointer to corresponding orig_node. It must only be used + * to identify the node but must NEVER be dereferenced. The reference counter + * was not increased when this was assigned because it would otherwise create + * a reference cycle. + */ + struct batadv_orig_node *__private orig_node_id; +#endif /** @addr: the MAC address of the neighboring interface */ u8 addr[ETH_ALEN];