summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Eckelmann <sven@narfation.org>2026-08-05 10:24:15 +0200
committerSven Eckelmann <sven@narfation.org>2026-08-05 10:24:15 +0200
commite52983cdce2abb22f58a92883fd8f468655ee804 (patch)
treee38c6b0a8cd15741b3cb3430d7b142354d300112
parent02aee8ebea3a714d92b27da9a9d8791d8c8c9a4f (diff)
parent0c53bc18a61ba6056eb6ee5cd64923825c90a113 (diff)
downloadbatadv/merge.tar.gz
Merge branch 'batadv/net' into batadv/mergeHEADbatadv/merge
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c78
-rw-r--r--net/batman-adv/distributed-arp-table.c66
-rw-r--r--net/batman-adv/main.c4
-rw-r--r--net/batman-adv/mesh-interface.c7
-rw-r--r--net/batman-adv/multicast_forw.c7
-rw-r--r--net/batman-adv/types.h2
6 files changed, 100 insertions, 64 deletions
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 94e074235e15..f635da4b8ca6 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -325,11 +325,6 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw)
}
spin_unlock_bh(list_lock);
}
-
- /* all claims gone, initialize CRC */
- spin_lock_bh(&backbone_gw->crc_lock);
- backbone_gw->crc = BATADV_BLA_CRC_INIT;
- spin_unlock_bh(&backbone_gw->crc_lock);
}
/**
@@ -695,12 +690,14 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
struct batadv_bla_backbone_gw *old_backbone_gw;
struct batadv_bla_claim search_claim;
struct batadv_bla_claim *claim;
- bool remove_crc = false;
int hash_added;
+ u16 claim_crc;
+ bool changed;
ether_addr_copy(search_claim.addr, mac);
search_claim.vid = vid;
claim = batadv_claim_hash_find(bat_priv, &search_claim);
+ claim_crc = crc16(0, mac, ETH_ALEN);
/* create a new claim entry if it does not exist yet. */
if (!claim) {
@@ -732,43 +729,56 @@ static void batadv_bla_add_claim(struct batadv_priv *bat_priv,
kfree(claim);
return;
}
+
+ spin_lock_bh(&backbone_gw->crc_lock);
+ backbone_gw->crc ^= claim_crc;
+ spin_unlock_bh(&backbone_gw->crc_lock);
+
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
+
+ batadv_claim_put(claim);
+ return;
+ }
+
+ WRITE_ONCE(claim->lasttime, jiffies);
+
+ /* replace backbone_gw atomically and adjust reference counters */
+ spin_lock_bh(&claim->backbone_lock);
+ if (claim->backbone_gw != backbone_gw) {
+ changed = true;
+
+ old_backbone_gw = claim->backbone_gw;
+ kref_get(&backbone_gw->refcount);
+ claim->backbone_gw = backbone_gw;
} else {
- WRITE_ONCE(claim->lasttime, jiffies);
- if (claim->backbone_gw == backbone_gw)
- /* no need to register a new backbone */
- goto claim_free_ref;
+ old_backbone_gw = NULL;
+ changed = false;
+ }
+ spin_unlock_bh(&claim->backbone_lock);
+ if (changed) {
batadv_dbg(BATADV_DBG_BLA, bat_priv,
"%s(): changing ownership for %pM, vid %d to gw %pM\n",
__func__, mac, batadv_print_vid(vid),
backbone_gw->orig);
- remove_crc = true;
- }
+ /* add claim address to new backbone_gw */
+ spin_lock_bh(&backbone_gw->crc_lock);
+ backbone_gw->crc ^= claim_crc;
+ spin_unlock_bh(&backbone_gw->crc_lock);
- /* replace backbone_gw atomically and adjust reference counters */
- spin_lock_bh(&claim->backbone_lock);
- old_backbone_gw = claim->backbone_gw;
- kref_get(&backbone_gw->refcount);
- claim->backbone_gw = backbone_gw;
- spin_unlock_bh(&claim->backbone_lock);
+ WRITE_ONCE(backbone_gw->lasttime, jiffies);
+ }
- if (remove_crc) {
+ if (old_backbone_gw) {
/* remove claim address from old backbone_gw */
spin_lock_bh(&old_backbone_gw->crc_lock);
- old_backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
+ old_backbone_gw->crc ^= claim_crc;
spin_unlock_bh(&old_backbone_gw->crc_lock);
- }
- batadv_backbone_gw_put(old_backbone_gw);
-
- /* add claim address to new backbone_gw */
- spin_lock_bh(&backbone_gw->crc_lock);
- backbone_gw->crc ^= crc16(0, claim->addr, ETH_ALEN);
- spin_unlock_bh(&backbone_gw->crc_lock);
- WRITE_ONCE(backbone_gw->lasttime, jiffies);
+ batadv_backbone_gw_put(old_backbone_gw);
+ }
-claim_free_ref:
batadv_claim_put(claim);
}
@@ -940,26 +950,18 @@ static bool batadv_handle_unclaim(struct batadv_priv *bat_priv,
const u8 *backbone_addr, const u8 *claim_addr,
unsigned short vid)
{
- struct batadv_bla_backbone_gw *backbone_gw;
-
/* unclaim in any case if it is our own */
if (primary_if && batadv_compare_eth(backbone_addr,
primary_if->net_dev->dev_addr))
batadv_bla_send_claim(bat_priv, claim_addr, vid,
BATADV_CLAIM_TYPE_UNCLAIM);
- backbone_gw = batadv_backbone_hash_find(bat_priv, backbone_addr, vid);
-
- if (!backbone_gw)
- return true;
-
/* this must be an UNCLAIM frame */
batadv_dbg(BATADV_DBG_BLA, bat_priv,
"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n", __func__,
- claim_addr, batadv_print_vid(vid), backbone_gw->orig);
+ claim_addr, batadv_print_vid(vid), backbone_addr);
batadv_bla_del_claim(bat_priv, claim_addr, vid);
- batadv_backbone_gw_put(backbone_gw);
return true;
}
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 0d5a9cb0affe..011cfdc47fab 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -316,7 +316,10 @@ static u8 *batadv_arp_hw_src(struct sk_buff *skb, int hdr_size)
*/
static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size)
{
- return *(__force __be32 *)(batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN);
+ u8 *src = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN;
+ __be32 *ip = (__force __be32 *)src;
+
+ return get_unaligned(ip);
}
/**
@@ -341,8 +344,9 @@ static u8 *batadv_arp_hw_dst(struct sk_buff *skb, int hdr_size)
static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size)
{
u8 *dst = batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN * 2 + 4;
+ __be32 *ip = (__force __be32 *)dst;
- return *(__force __be32 *)dst;
+ return get_unaligned(ip);
}
/**
@@ -440,18 +444,19 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip,
static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
u8 *mac_addr, unsigned short vid)
{
+ u64 u64_mac = ether_addr_to_u64(mac_addr);
struct batadv_dat_entry *dat_entry;
int hash_added;
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip, vid);
/* if this entry is already known, just update it */
if (dat_entry) {
- if (!batadv_compare_eth(dat_entry->mac_addr, mac_addr))
- ether_addr_copy(dat_entry->mac_addr, mac_addr);
+ atomic64_set(&dat_entry->mac_addr, u64_mac);
+
dat_entry->last_update = jiffies;
batadv_dbg(BATADV_DBG_DAT, bat_priv,
"Entry updated: %pI4 %pM (vid: %d)\n",
- &dat_entry->ip, dat_entry->mac_addr,
+ &dat_entry->ip, mac_addr,
batadv_print_vid(vid));
goto out;
}
@@ -462,7 +467,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
dat_entry->ip = ip;
dat_entry->vid = vid;
- ether_addr_copy(dat_entry->mac_addr, mac_addr);
+ atomic64_set(&dat_entry->mac_addr, u64_mac);
dat_entry->last_update = jiffies;
kref_init(&dat_entry->refcount);
@@ -478,7 +483,7 @@ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip,
}
batadv_dbg(BATADV_DBG_DAT, bat_priv, "New entry added: %pI4 %pM (vid: %d)\n",
- &dat_entry->ip, dat_entry->mac_addr, batadv_print_vid(vid));
+ &dat_entry->ip, mac_addr, batadv_print_vid(vid));
out:
batadv_dat_entry_put(dat_entry);
@@ -935,6 +940,8 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
struct netlink_callback *cb,
struct batadv_dat_entry *dat_entry)
{
+ u8 mac[ETH_ALEN];
+ u64 u64_mac;
int msecs;
void *hdr;
@@ -947,11 +954,12 @@ batadv_dat_cache_dump_entry(struct sk_buff *msg, u32 portid,
genl_dump_check_consistent(cb, hdr);
msecs = jiffies_to_msecs(jiffies - dat_entry->last_update);
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
+ u64_to_ether_addr(u64_mac, mac);
if (nla_put_in_addr(msg, BATADV_ATTR_DAT_CACHE_IP4ADDRESS,
dat_entry->ip) ||
- nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN,
- dat_entry->mac_addr) ||
+ nla_put(msg, BATADV_ATTR_DAT_CACHE_HWADDRESS, ETH_ALEN, mac) ||
nla_put_u16(msg, BATADV_ATTR_DAT_CACHE_VID, dat_entry->vid) ||
nla_put_u32(msg, BATADV_ATTR_LAST_SEEN_MSECS, msecs)) {
genlmsg_cancel(msg, hdr);
@@ -1231,10 +1239,12 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
+ u8 mac[ETH_ALEN];
int hdr_size = 0;
__be32 ip_dst;
__be32 ip_src;
u16 type = 0;
+ u64 u64_mac;
u8 *hw_src;
if (!READ_ONCE(bat_priv->distributed_arp_table))
@@ -1263,6 +1273,9 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_dst, vid);
if (dat_entry) {
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
+ u64_to_ether_addr(u64_mac, mac);
+
/* If the ARP request is destined for a local client the local
* client will answer itself. DAT would only generate a
* duplicate packet.
@@ -1271,7 +1284,7 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
* additional DAT answer may trigger kernel warnings about
* a packet coming from the wrong port.
*/
- if (batadv_is_my_client(bat_priv, dat_entry->mac_addr, vid)) {
+ if (batadv_is_my_client(bat_priv, mac, vid)) {
ret = true;
goto out;
}
@@ -1281,18 +1294,16 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv,
* the backbone gws belonging to our backbone has claimed the
* destination.
*/
- if (!batadv_bla_check_claim(bat_priv,
- dat_entry->mac_addr, vid)) {
+ if (!batadv_bla_check_claim(bat_priv, mac, vid)) {
batadv_dbg(BATADV_DBG_DAT, bat_priv,
"Device %pM claimed by another backbone gw. Don't send ARP reply!",
- dat_entry->mac_addr);
+ mac);
ret = true;
goto out;
}
skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
- dat_entry->mac_addr,
- hw_src, vid);
+ mac, hw_src, vid);
if (!skb_new)
goto out;
@@ -1336,8 +1347,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
struct sk_buff *skb_new;
unsigned short vid;
bool ret = false;
+ u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
+ u64 u64_mac;
u8 *hw_src;
u16 type;
int err;
@@ -1367,8 +1380,11 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv,
if (!dat_entry)
goto out;
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
+ u64_to_ether_addr(u64_mac, mac);
+
skb_new = batadv_dat_arp_create_reply(bat_priv, ip_dst, ip_src,
- dat_entry->mac_addr, hw_src, vid);
+ mac, hw_src, vid);
if (!skb_new)
goto out;
@@ -1460,8 +1476,10 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
struct batadv_dat_entry *dat_entry = NULL;
bool dropped = false;
unsigned short vid;
+ u8 mac[ETH_ALEN];
__be32 ip_src;
__be32 ip_dst;
+ u64 u64_mac;
u8 *hw_src;
u8 *hw_dst;
u16 type;
@@ -1493,11 +1511,17 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv,
* this frame would lead to doubled receive of an ARP reply.
*/
dat_entry = batadv_dat_entry_hash_find(bat_priv, ip_src, vid);
- if (dat_entry && batadv_compare_eth(hw_src, dat_entry->mac_addr)) {
- batadv_dbg(BATADV_DBG_DAT, bat_priv, "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",
- hw_src, &ip_src, hw_dst, &ip_dst,
- dat_entry->mac_addr, &dat_entry->ip);
- dropped = true;
+ if (dat_entry) {
+ u64_mac = atomic64_read(&dat_entry->mac_addr);
+ u64_to_ether_addr(u64_mac, mac);
+
+ if (batadv_compare_eth(hw_src, mac)) {
+ batadv_dbg(BATADV_DBG_DAT, bat_priv,
+ "Doubled ARP reply removed: ARP MSG = [src: %pM-%pI4 dst: %pM-%pI4]; dat_entry: %pM-%pI4\n",
+ hw_src, &ip_src, hw_dst, &ip_dst,
+ mac, &dat_entry->ip);
+ dropped = true;
+ }
}
/* Update our internal cache with both the IP addresses the node got
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 77597171d637..d89d44706269 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -492,6 +492,10 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (!skb)
goto err_put;
+ /* Merged fragments re-enter here with reused skb metadata. */
+ skb->dev = dev;
+ skb->skb_iif = dev->ifindex;
+
/* packet should hold at least type and version */
if (unlikely(!pskb_may_pull(skb, 2)))
goto err_free;
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 8e55b61dd2a6..e202088cf1fd 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -305,6 +305,8 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
if (batadv_compare_eth(ethhdr->h_dest, ectp_addr))
goto dropped;
+ batadv_skb_set_priority(skb, 0);
+
gw_mode = READ_ONCE(bat_priv->gw.mode);
if (is_multicast_ether_addr(ethhdr->h_dest)) {
/* if gw mode is off, broadcast every packet */
@@ -338,6 +340,9 @@ static netdev_tx_t batadv_interface_tx(struct sk_buff *skb,
send:
if (do_bcast && !is_broadcast_ether_addr(ethhdr->h_dest)) {
+ /* WARNING batadv_mcast_forw_mode might add more headers
+ * in front of the skb. and might even reallocate the skb
+ */
forw_mode = batadv_mcast_forw_mode(bat_priv, skb, vid,
&mcast_is_routable);
switch (forw_mode) {
@@ -355,8 +360,6 @@ send:
}
}
- batadv_skb_set_priority(skb, 0);
-
/* ethernet packet should be broadcasted */
if (do_bcast) {
primary_if = batadv_primary_if_get_selected(bat_priv);
diff --git a/net/batman-adv/multicast_forw.c b/net/batman-adv/multicast_forw.c
index bae2a8110976..ac97cd8b81dc 100644
--- a/net/batman-adv/multicast_forw.c
+++ b/net/batman-adv/multicast_forw.c
@@ -1105,8 +1105,11 @@ static int batadv_mcast_forw_expand_head(struct batadv_priv *bat_priv,
return -EINVAL;
}
- if (skb_headroom(skb) < hdr_size &&
- pskb_expand_head(skb, hdr_size, 0, GFP_ATOMIC) < 0)
+ if (skb_cow(skb, hdr_size) < 0)
+ return -ENOMEM;
+
+ /* batadv_mcast_forw_scrape() + batadv_mcast_forw_packet() require linearized skb */
+ if (skb_linearize(skb) < 0)
return -ENOMEM;
return 0;
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 42b631573512..9bdc5a3e799e 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -2176,7 +2176,7 @@ struct batadv_dat_entry {
__be32 ip;
/** @mac_addr: the MAC address associated to the stored IPv4 */
- u8 mac_addr[ETH_ALEN];
+ atomic64_t mac_addr;
/** @vid: the vlan ID associated to this entry */
unsigned short vid;