summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Kicinski <kuba@kernel.org>2026-06-02 12:00:48 -0700
committerJakub Kicinski <kuba@kernel.org>2026-06-02 12:00:48 -0700
commitf8524d16e231a25ce55b6407a5ca25b551aec1ca (patch)
tree9b166710f2d091accd3c5d088ea03e92ca0bb81a
parented9ea881746b4b80a5e3279159c07855275990e0 (diff)
parent3bd64ca11d9a1672d67d3130a7264c2cf7f93cdf (diff)
downloadlinux-f8524d16e231a25ce55b6407a5ca25b551aec1ca.tar.gz
linux-f8524d16e231a25ce55b6407a5ca25b551aec1ca.zip
Merge tag 'batadv-next-pullrequest-20260601' of https://git.open-mesh.org/batadv
Simon Wunderlich says: ==================== This batman-adv cleanup patchset includes the following patches, all by Sven Eckelmann: - drop batman-adv specific version - MAINTAINERS housekeeping for batman-adv (two patches) - add missing includes - use atomic_xchg() for gw.reselect check - extract netdev wifi detection information object - replace inappropriate atomic access with (READ|WRITE)_ONCE (six patches) - tt: replace open-coded overflow check with helper - tvlv: avoid unnecessary OGM buffer reallocations - use neigh_node's orig_node only as id * tag 'batadv-next-pullrequest-20260601' of https://git.open-mesh.org/batadv: batman-adv: use neigh_node's orig_node only as id batman-adv: tvlv: avoid unnecessary OGM buffer reallocations batman-adv: tt: replace open-coded overflow check with helper batman-adv: replace non-atomic last_ttvn with (READ|WRITE)_ONCE batman-adv: replace non-atomic packet_size_max with (READ|WRITE)_ONCE batman-adv: replace non-atomic mesh state with (READ|WRITE)_ONCE batman-adv: replace non-atomic vlan config fields with (READ|WRITE)_ONCE batman-adv: replace non-atomic hardif config fields with (READ|WRITE)_ONCE batman-adv: replace non-atomic meshif config fields with (READ|WRITE)_ONCE batman-adv: extract netdev wifi detection information object batman-adv: use atomic_xchg() for gw.reselect check batman-adv: add missing includes MAINTAINERS: Don't send batman-adv patches to netdev MAINTAINERS: Rename batman-adv T(ree) batman-adv: drop batman-adv specific version ==================== Link: https://patch.msgid.link/20260601123629.707089-1-sw@simonwunderlich.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r--MAINTAINERS4
-rw-r--r--net/batman-adv/Makefile1
-rw-r--r--net/batman-adv/bat_iv_ogm.c65
-rw-r--r--net/batman-adv/bat_v.c10
-rw-r--r--net/batman-adv/bat_v_elp.c15
-rw-r--r--net/batman-adv/bat_v_ogm.c46
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c15
-rw-r--r--net/batman-adv/distributed-arp-table.c17
-rw-r--r--net/batman-adv/fragmentation.c1
-rw-r--r--net/batman-adv/gateway_client.c9
-rw-r--r--net/batman-adv/gateway_common.c14
-rw-r--r--net/batman-adv/hard-interface.c207
-rw-r--r--net/batman-adv/hard-interface.h34
-rw-r--r--net/batman-adv/log.h2
-rw-r--r--net/batman-adv/main.c42
-rw-r--r--net/batman-adv/main.h4
-rw-r--r--net/batman-adv/mesh-interface.c42
-rw-r--r--net/batman-adv/multicast.c4
-rw-r--r--net/batman-adv/netlink.c80
-rw-r--r--net/batman-adv/originator.c8
-rw-r--r--net/batman-adv/routing.c6
-rw-r--r--net/batman-adv/send.c6
-rw-r--r--net/batman-adv/tp_meter.c6
-rw-r--r--net/batman-adv/translation-table.c32
-rw-r--r--net/batman-adv/tvlv.c57
-rw-r--r--net/batman-adv/tvlv.h3
-rw-r--r--net/batman-adv/types.h138
-rw-r--r--net/batman-adv/version.c12
28 files changed, 581 insertions, 299 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 142a91386338..cf7e92d9e6db 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4449,7 +4449,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
@@ -18642,6 +18642,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
@@ -18652,6 +18653,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/
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/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index b8b1b997960a..6f5a468c4084 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -13,6 +13,7 @@
#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
+#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -194,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;
@@ -220,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);
@@ -235,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;
@@ -257,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;
@@ -274,7 +279,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 +294,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 +560,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 +646,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 +654,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 +683,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,
@@ -792,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;
@@ -807,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
@@ -826,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;
@@ -837,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 */
@@ -853,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;
@@ -869,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);
@@ -888,7 +893,7 @@ out:
*/
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);
@@ -1214,7 +1219,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
@@ -1773,7 +1778,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;
}
@@ -2321,7 +2326,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 +2358,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 +2412,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 +2454,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..ac2932da5472 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -7,8 +7,8 @@
#include "bat_v.h"
#include "main.h"
-#include <linux/atomic.h>
#include <linux/cache.h>
+#include <linux/compiler.h>
#include <linux/errno.h>
#include <linux/if_ether.h>
#include <linux/init.h>
@@ -505,7 +505,7 @@ err_ifinfo1:
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 +602,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) {
@@ -812,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 fdc2abe96d77..d53485d17220 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -10,6 +10,7 @@
#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/byteorder/generic.h>
+#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -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,
@@ -85,6 +86,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;
@@ -97,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;
@@ -106,8 +108,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;
@@ -304,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 */
@@ -322,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 d66ca77b1aaa..5936d0048be0 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -8,7 +8,9 @@
#include "main.h"
#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
+#include <linux/compiler.h>
#include <linux/container_of.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
@@ -105,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));
@@ -246,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;
}
@@ -268,39 +270,35 @@ 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;
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;
- 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));
@@ -446,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:
@@ -484,9 +482,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 = atomic_read(&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) /
@@ -721,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;
@@ -1050,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;
@@ -1083,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/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index ffe854018bd3..87d6b11161e4 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 <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/compiler.h>
#include <linux/container_of.h>
@@ -1379,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) {
@@ -1483,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)) {
@@ -1782,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)
@@ -1820,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. */
@@ -1952,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))
@@ -2084,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))
@@ -2504,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 0a8bd95e2f99..0b02018c5b85 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -9,6 +9,7 @@
#include <linux/atomic.h>
#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/container_of.h>
#include <linux/err.h>
@@ -742,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:
@@ -1138,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);
@@ -1233,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);
@@ -1295,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);
@@ -1343,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);
@@ -1713,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))
@@ -1743,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)))
@@ -1788,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/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 <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/errno.h>
#include <linux/etherdevice.h>
diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c
index a9d0346e8332..305488a74a25 100644
--- a/net/batman-adv/gateway_client.c
+++ b/net/batman-adv/gateway_client.c
@@ -8,6 +8,7 @@
#include "main.h"
#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/container_of.h>
#include <linux/err.h>
@@ -170,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);
@@ -202,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)
@@ -210,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
@@ -702,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 <linux/atomic.h>
#include <linux/byteorder/generic.h>
+#include <linux/compiler.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include <uapi/linux/batadv_packet.h>
@@ -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 d6732c34aeaf..bb3c31b5f259 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -7,7 +7,7 @@
#include "hard-interface.h"
#include "main.h"
-#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/compiler.h>
#include <linux/container_of.h>
@@ -25,6 +25,8 @@
#include <linux/notifier.h>
#include <linux/printk.h>
#include <linux/rculist.h>
+#include <linux/rhashtable-types.h>
+#include <linux/rhashtable.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -42,6 +44,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
@@ -355,21 +366,28 @@ out:
}
/**
- * 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;
+
+ if (!hard_iface)
+ return 0;
- allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;
- allowed_flags |= BATADV_HARDIF_WIFI_CFG80211_INDIRECT;
+ 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 !!(hard_iface->wifi_flags & allowed_flags);
+ return wifi_flags;
}
/**
@@ -380,10 +398,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);
}
/**
@@ -594,7 +611,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
@@ -611,7 +628,7 @@ out:
* 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.
@@ -709,6 +726,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);
@@ -746,15 +764,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,
@@ -889,11 +906,10 @@ 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;
- atomic_set(&hard_iface->hop_penalty, 0);
+ WRITE_ONCE(hard_iface->hop_penalty, 0);
batadv_v_hardif_init(hard_iface);
@@ -941,6 +957,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)
{
@@ -952,6 +1093,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))
@@ -995,8 +1138,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;
@@ -1014,3 +1158,22 @@ out:
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 <linux/compiler.h>
+#include <linux/init.h>
#include <linux/kref.h>
#include <linux/netdevice.h>
#include <linux/rcupdate.h>
@@ -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 @@ out:
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/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/main.c b/net/batman-adv/main.c
index a4d33ee0fda5..60d4f60066c8 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -33,6 +33,7 @@
#include <linux/sprintf.h>
#include <linux/stddef.h>
#include <linux/string.h>
+#include <linux/utsname.h>
#include <linux/workqueue.h>
#include <net/dsfield.h>
#include <net/genetlink.h>
@@ -104,22 +105,33 @@ 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);
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;
+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)
@@ -133,6 +145,7 @@ static void __exit batadv_exit(void)
rcu_barrier();
+ batadv_wifi_net_devices_deinit();
batadv_tt_cache_destroy();
}
@@ -187,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;
}
@@ -219,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;
@@ -233,7 +246,7 @@ err_tt:
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;
}
@@ -246,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);
@@ -277,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);
}
/**
@@ -441,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 */
@@ -614,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);
}
@@ -684,6 +697,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..b6797654b18a 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -8,6 +8,7 @@
#include "main.h"
#include <linux/atomic.h>
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
#include <linux/compiler.h>
@@ -36,6 +37,7 @@
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/utsname.h>
#include <net/netlink.h>
#include <net/rtnetlink.h>
#include <uapi/linux/batadv_packet.h>
@@ -123,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();
@@ -190,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 */
@@ -255,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) {
@@ -565,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);
@@ -752,36 +754,36 @@ 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);
- atomic_set(&bat_priv->packet_size_max, BATADV_MAX_MTU);
+ WRITE_ONCE(bat_priv->fragmentation, 1);
+ 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);
- 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);
@@ -892,7 +894,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/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 78c651f634cd..e5463003a3bd 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -13,6 +13,7 @@
#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
+#include <linux/compiler.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/gfp.h>
@@ -28,6 +29,7 @@
#include <linux/skbuff.h>
#include <linux/stddef.h>
#include <linux/types.h>
+#include <linux/utsname.h>
#include <net/genetlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
@@ -179,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,
@@ -202,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;
@@ -233,7 +235,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) ||
@@ -267,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))
@@ -282,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 &&
@@ -319,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);
@@ -432,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]) {
@@ -456,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);
}
@@ -473,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);
}
@@ -482,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);
@@ -492,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);
}
@@ -527,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);
}
}
@@ -546,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);
}
}
@@ -554,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 */
@@ -570,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 */
@@ -589,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);
@@ -809,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 */
@@ -911,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
@@ -919,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 */
@@ -1020,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);
@@ -1108,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/originator.c b/net/batman-adv/originator.c
index ad4921b659d9..15d660ca7937 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -7,7 +7,6 @@
#include "originator.h"
#include "main.h"
-#include <linux/atomic.h>
#include <linux/container_of.h>
#include <linux/err.h>
#include <linux/errno.h>
@@ -694,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;
@@ -966,7 +968,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 12c16f81cc51..cd4368b846ad 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
@@ -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 60cd67ec9cea..5f9da3606a8f 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);
@@ -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;
@@ -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/translation-table.c b/net/batman-adv/translation-table.c
index 9f6e67771ffa..5e134d08a80f 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -9,6 +9,7 @@
#include <linux/atomic.h>
#include <linux/bitops.h>
+#include <linux/bug.h>
#include <linux/build_bug.h>
#include <linux/byteorder/generic.h>
#include <linux/cache.h>
@@ -648,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",
@@ -798,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;
@@ -825,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;
@@ -840,7 +838,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;
@@ -1821,7 +1819,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,
@@ -3012,7 +3010,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 */
@@ -3068,7 +3066,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);
@@ -3299,7 +3297,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);
@@ -3315,7 +3313,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);
}
/**
@@ -3729,7 +3727,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);
@@ -3768,7 +3766,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;
@@ -3910,7 +3908,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,
@@ -3931,7 +3929,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;
@@ -4124,7 +4122,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/tvlv.c b/net/batman-adv/tvlv.c
index cc6ac580c620..cd75daea478c 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -6,6 +6,7 @@
#include "main.h"
+#include <linux/bug.h>
#include <linux/byteorder/generic.h>
#include <linux/container_of.h>
#include <linux/errno.h>
@@ -16,6 +17,7 @@
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/lockdep.h>
+#include <linux/log2.h>
#include <linux/netdevice.h>
#include <linux/pkt_sched.h>
#include <linux/rculist.h>
@@ -266,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)
+ if (!new_buff) {
+ /* continue to use oversize buffer if new data fits */
+ if (newlen <= ogm_buff->capacity) {
+ ogm_buff->len = newlen;
+ return true;
+ }
+
return false;
+ }
+
+ memcpy(new_buff, ogm_buff->buf, ogm_buff->header_length);
+ kfree(ogm_buff->buf);
- memcpy(new_buff, *packet_buff, min_packet_len);
- kfree(*packet_buff);
- *packet_buff = new_buff;
- *packet_buff_len = min_packet_len + additional_packet_len;
+ ogm_buff->buf = new_buff;
+ ogm_buff->len = newlen;
+ ogm_buff->capacity = newcapacity;
return true;
}
@@ -300,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.
@@ -312,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;
@@ -329,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;
@@ -341,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 a01ee46d97f3..19c7316889b6 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -21,6 +21,7 @@
#include <linux/mutex.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
+#include <linux/rhashtable-types.h>
#include <linux/sched.h> /* for linux/wait.h */
#include <linux/skbuff.h>
#include <linux/spinlock.h>
@@ -71,14 +72,28 @@ 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;
@@ -86,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;
};
@@ -113,7 +128,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;
@@ -137,7 +152,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;
@@ -167,6 +182,29 @@ enum batadv_hard_iface_wifi_flags {
};
/**
+ * 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
*/
struct batadv_hard_iface {
@@ -181,12 +219,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;
@@ -218,7 +250,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;
@@ -446,7 +478,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;
@@ -631,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];
@@ -1101,21 +1140,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;
@@ -1441,7 +1480,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;
@@ -1463,15 +1502,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 */
@@ -1486,7 +1522,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;
@@ -1506,36 +1542,23 @@ 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;
-
- /**
- * @packet_size_max: max packet size that can be transmitted via
- * multiple fragmented skbs or a single frame if fragmentation is
- * disabled
- */
- atomic_t packet_size_max;
-
- /**
- * @frag_seqno: incremental counter to identify chains of egress
- * fragments
- */
- atomic_t frag_seqno;
+ u8 fragmentation;
#ifdef CONFIG_BATMAN_ADV_BLA
/**
* @bridge_loop_avoidance: bool indicating whether bridge loop
* avoidance is enabled
*/
- atomic_t bridge_loop_avoidance;
+ u8 bridge_loop_avoidance;
#endif
#ifdef CONFIG_BATMAN_ADV_DAT
@@ -1543,7 +1566,7 @@ struct batadv_priv {
* @distributed_arp_table: bool indicating whether distributed ARP table
* is enabled
*/
- atomic_t distributed_arp_table;
+ u8 distributed_arp_table;
#endif
#ifdef CONFIG_BATMAN_ADV_MCAST
@@ -1551,27 +1574,40 @@ struct batadv_priv {
* @multicast_mode: Enable or disable multicast optimizations on this
* node's sender/originating side
*/
- atomic_t multicast_mode;
+ u8 multicast_mode;
/**
* @multicast_fanout: Maximum number of packet copies to generate for a
* multicast-to-unicast conversion
*/
- atomic_t multicast_fanout;
+ u32 multicast_fanout;
#endif
+ /**
+ * @packet_size_max: max packet size that can be transmitted via
+ * multiple fragmented skbs or a single frame if fragmentation is
+ * disabled
+ */
+ int packet_size_max;
+
+ /**
+ * @frag_seqno: incremental counter to identify chains of egress
+ * fragments
+ */
+ atomic_t frag_seqno;
+
/** @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
/**
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 <generated/utsrelease.h>
+#include <linux/module.h>
+
+/* 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);