summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorPaolo Abeni <pabeni@redhat.com>2026-07-02 10:30:26 +0200
committerPaolo Abeni <pabeni@redhat.com>2026-07-02 10:30:27 +0200
commitf07f1e3dedb20077a401193c9b65fe37e7d38046 (patch)
tree968b1d6d16becfb26a69180ec6ac3c839bc12423 /net
parent07d3aaa046ceffb2ed72010d88cb6071717c4906 (diff)
parent247691642fd4de7a029de253e47dba936542ce9f (diff)
downloadlinux-next-f07f1e3dedb20077a401193c9b65fe37e7d38046.tar.gz
linux-next-f07f1e3dedb20077a401193c9b65fe37e7d38046.zip
Merge tag 'batadv-next-pullrequest-20260630' of https://git.open-mesh.org/batadv
Simon Wunderlich says: ==================== This cleanup patchset includes the following patches: - drop hardif global list, by Nora Schiffer (2 patches) - make hard_iface->mesh_iface immutable, by Sven Eckelmann - further post-hardif global list cleanups, by Nora Schiffer (3 patches) - cleanups and simplifications depending on the hardif->mesh_iface immutability guarantee, by Sven Eckelmann (3 patches) - tvlv: extract tvlv header iterator, by Sven Eckelmann - tp_meter: improve unacked list handling, by Sven Eckelmann (5 patches) * tag 'batadv-next-pullrequest-20260630' of https://git.open-mesh.org/batadv: batman-adv: tp_meter: delay allocation of unacked entry batman-adv: tp_meter: adjust name of receiver lock batman-adv: tp_meter: keep unacked list for receivers batman-adv: tp_meter: combine adjacent/overlapping unacked entries batman-adv: tp_meter: simplify unordered ack calculation batman-adv: tvlv: extract tvlv header iterator batman-adv: iv: drop migration check for batadv_hard_iface Revert "batman-adv: v: stop OGMv2 on disabled interface" batman-adv: drop NULL check for immutable hardif->mesh_iface batman-adv: drop unneeded goto and initialization from batadv_hardif_disable_interface() batman-adv: move hardif generation counter into batadv_priv batman-adv: remove BATADV_IF_NOT_IN_USE hardif state batman-adv: make hard_iface->mesh_iface immutable batman-adv: remove global hardif list batman-adv: create hardif only for netdevs that are part of a mesh ==================== Link: https://patch.msgid.link/ Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Diffstat (limited to 'net')
-rw-r--r--net/batman-adv/bat_iv_ogm.c12
-rw-r--r--net/batman-adv/bat_v_elp.c9
-rw-r--r--net/batman-adv/bat_v_ogm.c33
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c9
-rw-r--r--net/batman-adv/hard-interface.c165
-rw-r--r--net/batman-adv/hard-interface.h10
-rw-r--r--net/batman-adv/main.c9
-rw-r--r--net/batman-adv/main.h3
-rw-r--r--net/batman-adv/mesh-interface.c13
-rw-r--r--net/batman-adv/netlink.c4
-rw-r--r--net/batman-adv/originator.c4
-rw-r--r--net/batman-adv/tp_meter.c217
-rw-r--r--net/batman-adv/tvlv.c86
-rw-r--r--net/batman-adv/types.h28
14 files changed, 273 insertions, 329 deletions
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index bb2f012b454e..22622283f59b 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -404,23 +404,14 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet,
/* send a batman ogm packet */
static void batadv_iv_ogm_emit(struct batadv_forw_packet *forw_packet)
{
- struct net_device *mesh_iface;
-
if (!forw_packet->if_incoming) {
pr_err("Error - can't forward packet: incoming iface not specified\n");
return;
}
- mesh_iface = forw_packet->if_incoming->mesh_iface;
-
if (WARN_ON(!forw_packet->if_outgoing))
return;
- if (forw_packet->if_outgoing->mesh_iface != mesh_iface) {
- pr_warn("%s: mesh interface switch for queued OGM\n", __func__);
- return;
- }
-
if (forw_packet->if_incoming->if_status != BATADV_IF_ACTIVE)
return;
@@ -910,8 +901,7 @@ out:
static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface)
{
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
- hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+ if (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
return;
mutex_lock(&hard_iface->bat_iv.ogm_buff_mutex);
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index 4841f0f1a9b1..262e40040007 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -90,12 +90,6 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
u32 throughput;
int ret;
- /* don't query throughput when no longer associated with any
- * batman-adv interface
- */
- if (!mesh_iface)
- return false;
-
/* if the user specified a customised value for this interface, then
* return it directly
*/
@@ -311,8 +305,7 @@ static void batadv_v_elp_periodic_work(struct work_struct *work)
goto out;
/* we are in the process of shutting this interface down */
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
- hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
+ if (hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
goto out;
/* the interface was enabled but may not be ready yet */
diff --git a/net/batman-adv/bat_v_ogm.c b/net/batman-adv/bat_v_ogm.c
index 037921aad35d..e921d49f7ece 100644
--- a/net/batman-adv/bat_v_ogm.c
+++ b/net/batman-adv/bat_v_ogm.c
@@ -115,14 +115,14 @@ static void batadv_v_ogm_start_timer(struct batadv_priv *bat_priv)
/**
* batadv_v_ogm_send_to_if() - send a batman ogm using a given interface
- * @bat_priv: the bat priv with all the mesh interface information
* @skb: the OGM to send
* @hard_iface: the interface to use to send the OGM
*/
-static void batadv_v_ogm_send_to_if(struct batadv_priv *bat_priv,
- struct sk_buff *skb,
+static void batadv_v_ogm_send_to_if(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface)
{
+ struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
+
if (hard_iface->if_status != BATADV_IF_ACTIVE) {
kfree_skb(skb);
return;
@@ -189,7 +189,6 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
/**
* batadv_v_ogm_aggr_send() - flush & send aggregation queue
- * @bat_priv: the bat priv with all the mesh interface information
* @hard_iface: the interface with the aggregation queue to flush
*
* Aggregates all OGMv2 packets currently in the aggregation queue into a
@@ -199,8 +198,7 @@ static void batadv_v_ogm_aggr_list_free(struct batadv_hard_iface *hard_iface)
*
* Caller needs to hold the hard_iface->bat_v.aggr_list.lock.
*/
-static void batadv_v_ogm_aggr_send(struct batadv_priv *bat_priv,
- struct batadv_hard_iface *hard_iface)
+static void batadv_v_ogm_aggr_send(struct batadv_hard_iface *hard_iface)
{
unsigned int aggr_len = hard_iface->bat_v.aggr_len;
struct sk_buff *skb_aggr;
@@ -230,26 +228,21 @@ static void batadv_v_ogm_aggr_send(struct batadv_priv *bat_priv,
consume_skb(skb);
}
- batadv_v_ogm_send_to_if(bat_priv, skb_aggr, hard_iface);
+ batadv_v_ogm_send_to_if(skb_aggr, hard_iface);
}
/**
* batadv_v_ogm_queue_on_if() - queue a batman ogm on a given interface
- * @bat_priv: the bat priv with all the mesh interface information
* @skb: the OGM to queue
* @hard_iface: the interface to queue the OGM on
*/
-static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv,
- struct sk_buff *skb,
+static void batadv_v_ogm_queue_on_if(struct sk_buff *skb,
struct batadv_hard_iface *hard_iface)
{
- if (hard_iface->mesh_iface != bat_priv->mesh_iface) {
- kfree_skb(skb);
- return;
- }
+ struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
if (!READ_ONCE(bat_priv->aggregated_ogms)) {
- batadv_v_ogm_send_to_if(bat_priv, skb, hard_iface);
+ batadv_v_ogm_send_to_if(skb, hard_iface);
return;
}
@@ -260,7 +253,7 @@ static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv,
}
if (!batadv_v_ogm_queue_left(skb, hard_iface))
- batadv_v_ogm_aggr_send(bat_priv, hard_iface);
+ batadv_v_ogm_aggr_send(hard_iface);
hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb);
__skb_queue_tail(&hard_iface->bat_v.aggr_list, skb);
@@ -357,7 +350,7 @@ static void batadv_v_ogm_send_meshif(struct batadv_priv *bat_priv)
break;
}
- batadv_v_ogm_queue_on_if(bat_priv, skb_tmp, hard_iface);
+ batadv_v_ogm_queue_on_if(skb_tmp, hard_iface);
batadv_hardif_put(hard_iface);
}
rcu_read_unlock();
@@ -397,14 +390,12 @@ void batadv_v_ogm_aggr_work(struct work_struct *work)
{
struct batadv_hard_iface_bat_v *batv;
struct batadv_hard_iface *hard_iface;
- struct batadv_priv *bat_priv;
batv = container_of(work, struct batadv_hard_iface_bat_v, aggr_wq.work);
hard_iface = container_of(batv, struct batadv_hard_iface, bat_v);
- bat_priv = netdev_priv(hard_iface->mesh_iface);
spin_lock_bh(&hard_iface->bat_v.aggr_list.lock);
- batadv_v_ogm_aggr_send(bat_priv, hard_iface);
+ batadv_v_ogm_aggr_send(hard_iface);
spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock);
batadv_v_ogm_start_queue_timer(hard_iface);
@@ -601,7 +592,7 @@ static void batadv_v_ogm_forward(struct batadv_priv *bat_priv,
if_outgoing->net_dev->name, ntohl(ogm_forward->throughput),
ogm_forward->ttl, if_incoming->net_dev->name);
- batadv_v_ogm_queue_on_if(bat_priv, skb, if_outgoing);
+ batadv_v_ogm_queue_on_if(skb, if_outgoing);
out:
batadv_orig_ifinfo_put(orig_ifinfo);
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 5c73f6ba16cf..f9a1fadf8de9 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -344,7 +344,6 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,
struct sk_buff *skb;
struct ethhdr *ethhdr;
struct batadv_hard_iface *primary_if;
- struct net_device *mesh_iface;
u8 *hw_src;
struct batadv_bla_claim_dst local_claim_dest;
__be32 zeroip = 0;
@@ -357,14 +356,10 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,
sizeof(local_claim_dest));
local_claim_dest.type = claimtype;
- mesh_iface = READ_ONCE(primary_if->mesh_iface);
- if (!mesh_iface)
- goto out;
-
skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
/* IP DST: 0.0.0.0 */
zeroip,
- mesh_iface,
+ primary_if->mesh_iface,
/* IP SRC: 0.0.0.0 */
zeroip,
/* Ethernet DST: Broadcast */
@@ -442,7 +437,7 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, const u8 *mac,
}
skb_reset_mac_header(skb);
- skb->protocol = eth_type_trans(skb, mesh_iface);
+ skb->protocol = eth_type_trans(skb, primary_if->mesh_iface);
batadv_inc_counter(bat_priv, BATADV_CNT_RX);
batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
skb->len + ETH_HLEN);
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 03d01c20a954..b6867576bbaf 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -63,6 +63,7 @@ void batadv_hardif_release(struct kref *ref)
struct batadv_hard_iface *hard_iface;
hard_iface = container_of(ref, struct batadv_hard_iface, refcount);
+ netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
netdev_put(hard_iface->net_dev, &hard_iface->dev_tracker);
kfree_rcu(hard_iface, rcu);
@@ -75,21 +76,21 @@ void batadv_hardif_release(struct kref *ref)
* Return: batadv_hard_iface of net_dev (with increased refcnt), NULL on errors
*/
struct batadv_hard_iface *
-batadv_hardif_get_by_netdev(const struct net_device *net_dev)
+batadv_hardif_get_by_netdev(struct net_device *net_dev)
{
struct batadv_hard_iface *hard_iface;
+ struct net_device *mesh_iface;
- rcu_read_lock();
- list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
- if (hard_iface->net_dev == net_dev &&
- kref_get_unless_zero(&hard_iface->refcount))
- goto out;
- }
+ ASSERT_RTNL();
- hard_iface = NULL;
+ mesh_iface = netdev_master_upper_dev_get(net_dev);
+ if (!mesh_iface || !batadv_meshif_is_valid(mesh_iface))
+ return NULL;
+
+ hard_iface = netdev_lower_dev_get_private(mesh_iface, net_dev);
+ if (!kref_get_unless_zero(&hard_iface->refcount))
+ return NULL;
-out:
- rcu_read_unlock();
return hard_iface;
}
@@ -245,7 +246,7 @@ struct net_device *__batadv_get_real_netdev(struct net_device *netdev)
}
hard_iface = batadv_hardif_get_by_netdev(netdev);
- if (!hard_iface || !hard_iface->mesh_iface)
+ if (!hard_iface)
goto out;
net = dev_net(hard_iface->mesh_iface);
@@ -539,16 +540,10 @@ static void batadv_check_known_mac_addr(const struct batadv_hard_iface *hard_ifa
const struct batadv_hard_iface *tmp_hard_iface;
struct list_head *iter;
- if (!mesh_iface)
- return;
-
netdev_for_each_lower_private(mesh_iface, tmp_hard_iface, iter) {
if (tmp_hard_iface == hard_iface)
continue;
- if (tmp_hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- continue;
-
if (!batadv_compare_eth(tmp_hard_iface->net_dev->dev_addr,
hard_iface->net_dev->dev_addr))
continue;
@@ -574,9 +569,6 @@ static void batadv_hardif_recalc_extra_skbroom(struct net_device *mesh_iface)
rcu_read_lock();
netdev_for_each_lower_private_rcu(mesh_iface, hard_iface, iter) {
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- continue;
-
lower_header_len = max_t(unsigned short, lower_header_len,
hard_iface->net_dev->hard_header_len);
@@ -723,38 +715,63 @@ batadv_hardif_deactivate_interface(struct batadv_hard_iface *hard_iface)
}
/**
- * batadv_hardif_enable_interface() - Enslave hard interface to mesh interface
- * @hard_iface: hard interface to add to mesh interface
+ * batadv_hardif_enable_interface() - Enslave interface to mesh interface
+ * @net_dev: netdev struct of the interface to add to mesh interface
* @mesh_iface: netdev struct of the mesh interface
*
* Return: 0 on success or negative error number in case of failure
*/
-int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
+int batadv_hardif_enable_interface(struct net_device *net_dev,
struct net_device *mesh_iface)
{
struct batadv_priv *bat_priv;
__be16 ethertype = htons(ETH_P_BATMAN);
int max_header_len = batadv_max_header_len();
+ struct batadv_hard_iface *hard_iface;
unsigned int required_mtu;
unsigned int hardif_mtu;
bool fragmentation;
int ret;
- hardif_mtu = READ_ONCE(hard_iface->net_dev->mtu);
+ ASSERT_RTNL();
+
+ if (!batadv_is_valid_iface(net_dev))
+ return -EINVAL;
+
+ hardif_mtu = READ_ONCE(net_dev->mtu);
required_mtu = READ_ONCE(mesh_iface->mtu) + max_header_len;
if (hardif_mtu < ETH_MIN_MTU + max_header_len)
return -EINVAL;
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- goto out;
+ hard_iface = kzalloc_obj(*hard_iface, GFP_ATOMIC);
+ if (!hard_iface)
+ return -ENOMEM;
- kref_get(&hard_iface->refcount);
+ netdev_hold(net_dev, &hard_iface->dev_tracker, GFP_ATOMIC);
+ hard_iface->net_dev = net_dev;
+
+ hard_iface->if_status = BATADV_IF_INACTIVE;
+
+ INIT_HLIST_HEAD(&hard_iface->neigh_list);
+
+ mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
+ spin_lock_init(&hard_iface->neigh_list_lock);
+ kref_init(&hard_iface->refcount);
+
+ hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
+ if (batadv_is_wifi_hardif(hard_iface))
+ hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
+
+ WRITE_ONCE(hard_iface->hop_penalty, 0);
+
+ batadv_v_hardif_init(hard_iface);
netdev_hold(mesh_iface, &hard_iface->meshif_dev_tracker, GFP_ATOMIC);
hard_iface->mesh_iface = mesh_iface;
bat_priv = netdev_priv(hard_iface->mesh_iface);
+ bat_priv->hardif_generation++;
ret = netdev_master_upper_dev_link(hard_iface->net_dev,
mesh_iface, hard_iface, NULL, NULL);
if (ret)
@@ -764,9 +781,6 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (ret < 0)
goto err_upper;
- hard_iface->if_status = BATADV_IF_INACTIVE;
-
- kref_get(&hard_iface->refcount);
hard_iface->batman_adv_ptype.type = ethertype;
hard_iface->batman_adv_ptype.func = batadv_batman_skb_recv;
hard_iface->batman_adv_ptype.dev = hard_iface->net_dev;
@@ -802,14 +816,11 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
if (bat_priv->algo_ops->iface.enabled)
bat_priv->algo_ops->iface.enabled(hard_iface);
-out:
return 0;
err_upper:
netdev_upper_dev_unlink(hard_iface->net_dev, mesh_iface);
err_dev:
- hard_iface->mesh_iface = NULL;
- netdev_put(mesh_iface, &hard_iface->meshif_dev_tracker);
batadv_hardif_put(hard_iface);
return ret;
}
@@ -821,17 +832,18 @@ err_dev:
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
{
struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface);
- struct batadv_hard_iface *primary_if = NULL;
+ struct batadv_hard_iface *primary_if;
+
+ ASSERT_RTNL();
batadv_hardif_deactivate_interface(hard_iface);
if (hard_iface->if_status != BATADV_IF_INACTIVE)
- goto out;
+ return;
batadv_info(hard_iface->mesh_iface, "Removing interface: %s\n",
hard_iface->net_dev->name);
dev_remove_pack(&hard_iface->batman_adv_ptype);
- batadv_hardif_put(hard_iface);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (hard_iface == primary_if) {
@@ -842,15 +854,16 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
batadv_hardif_put(new_if);
}
+ batadv_hardif_put(primary_if);
bat_priv->algo_ops->iface.disable(hard_iface);
- hard_iface->if_status = BATADV_IF_NOT_IN_USE;
+ hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
/* delete all references to this hard_iface */
batadv_purge_orig_ref(bat_priv);
batadv_purge_outstanding_packets(bat_priv, hard_iface);
- netdev_put(hard_iface->mesh_iface, &hard_iface->meshif_dev_tracker);
+ bat_priv->hardif_generation++;
netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface);
batadv_hardif_recalc_extra_skbroom(hard_iface->mesh_iface);
@@ -858,67 +871,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface)
if (list_empty(&hard_iface->mesh_iface->adj_list.lower))
batadv_gw_check_client_stop(bat_priv);
- hard_iface->mesh_iface = NULL;
- batadv_hardif_put(hard_iface);
-
-out:
- batadv_hardif_put(primary_if);
-}
-
-static struct batadv_hard_iface *
-batadv_hardif_add_interface(struct net_device *net_dev)
-{
- struct batadv_hard_iface *hard_iface;
-
- ASSERT_RTNL();
-
- if (!batadv_is_valid_iface(net_dev))
- return NULL;
-
- hard_iface = kzalloc_obj(*hard_iface, GFP_ATOMIC);
- if (!hard_iface)
- return NULL;
-
- netdev_hold(net_dev, &hard_iface->dev_tracker, GFP_ATOMIC);
- hard_iface->net_dev = net_dev;
-
- hard_iface->mesh_iface = NULL;
- hard_iface->if_status = BATADV_IF_NOT_IN_USE;
-
- INIT_LIST_HEAD(&hard_iface->list);
- INIT_HLIST_HEAD(&hard_iface->neigh_list);
-
- mutex_init(&hard_iface->bat_iv.ogm_buff_mutex);
- spin_lock_init(&hard_iface->neigh_list_lock);
- kref_init(&hard_iface->refcount);
-
- hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
- if (batadv_is_wifi_hardif(hard_iface))
- hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;
-
- WRITE_ONCE(hard_iface->hop_penalty, 0);
-
- batadv_v_hardif_init(hard_iface);
-
- kref_get(&hard_iface->refcount);
- list_add_tail_rcu(&hard_iface->list, &batadv_hardif_list);
- batadv_hardif_generation++;
-
- return hard_iface;
-}
-
-static void batadv_hardif_remove_interface(struct batadv_hard_iface *hard_iface)
-{
- ASSERT_RTNL();
-
- /* first deactivate interface */
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- batadv_hardif_disable_interface(hard_iface);
-
- if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
- return;
-
- hard_iface->if_status = BATADV_IF_TO_BE_REMOVED;
batadv_hardif_put(hard_iface);
}
@@ -1082,10 +1034,6 @@ static int batadv_hard_if_event(struct notifier_block *this,
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))
- hard_iface = batadv_hardif_add_interface(net_dev);
-
if (!hard_iface)
goto out;
@@ -1099,19 +1047,12 @@ static int batadv_hard_if_event(struct notifier_block *this,
break;
case NETDEV_UNREGISTER:
case NETDEV_PRE_TYPE_CHANGE:
- list_del_rcu(&hard_iface->list);
- batadv_hardif_generation++;
-
- batadv_hardif_remove_interface(hard_iface);
+ batadv_hardif_disable_interface(hard_iface);
break;
case NETDEV_CHANGEMTU:
- if (hard_iface->mesh_iface)
- batadv_update_min_mtu(hard_iface->mesh_iface);
+ batadv_update_min_mtu(hard_iface->mesh_iface);
break;
case NETDEV_CHANGEADDR:
- if (hard_iface->if_status == BATADV_IF_NOT_IN_USE)
- goto hardif_put;
-
batadv_check_known_mac_addr(hard_iface);
bat_priv = netdev_priv(hard_iface->mesh_iface);
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index af31696c3978..935f47ca9a48 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -22,12 +22,6 @@
*/
enum batadv_hard_if_state {
/**
- * @BATADV_IF_NOT_IN_USE: interface is not used as slave interface of a
- * batman-adv mesh interface
- */
- BATADV_IF_NOT_IN_USE,
-
- /**
* @BATADV_IF_TO_BE_REMOVED: interface will be removed from mesh
* interface
*/
@@ -74,8 +68,8 @@ u32 batadv_netdev_get_wifi_flags(struct net_device *net_dev);
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);
-int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
+batadv_hardif_get_by_netdev(struct net_device *net_dev);
+int batadv_hardif_enable_interface(struct net_device *net_dev,
struct net_device *mesh_iface);
void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface);
int batadv_hardif_min_mtu(struct net_device *mesh_iface);
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 3c4572284b53..04bb030ef299 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -59,11 +59,6 @@
#include "tp_meter.h"
#include "translation-table.h"
-/* List manipulations on hardif_list have to be rtnl_lock()'ed,
- * list traversals just rcu-locked
- */
-struct list_head batadv_hardif_list;
-unsigned int batadv_hardif_generation;
static int (*batadv_rx_handler[256])(struct sk_buff *skb,
struct batadv_hard_iface *recv_if);
@@ -95,7 +90,6 @@ static int __init batadv_init(void)
if (ret < 0)
return ret;
- INIT_LIST_HEAD(&batadv_hardif_list);
batadv_algo_init();
batadv_recv_handler_init();
@@ -450,9 +444,6 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev,
if (unlikely(skb->mac_len != ETH_HLEN || !skb_mac_header(skb)))
goto err_free;
- if (!hard_iface->mesh_iface)
- goto err_free;
-
bat_priv = netdev_priv(hard_iface->mesh_iface);
if (READ_ONCE(bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index f68fc8b7239c..e738758ee4a7 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -226,9 +226,6 @@ static inline int batadv_print_vid(unsigned short vid)
return -1;
}
-extern struct list_head batadv_hardif_list;
-extern unsigned int batadv_hardif_generation;
-
extern struct workqueue_struct *batadv_event_workqueue;
int batadv_mesh_init(struct net_device *mesh_iface);
diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c
index 44026810b99c..a37368c1f5b5 100644
--- a/net/batman-adv/mesh-interface.c
+++ b/net/batman-adv/mesh-interface.c
@@ -836,18 +836,7 @@ static int batadv_meshif_slave_add(struct net_device *dev,
struct net_device *slave_dev,
struct netlink_ext_ack *extack)
{
- struct batadv_hard_iface *hard_iface;
- int ret = -EINVAL;
-
- hard_iface = batadv_hardif_get_by_netdev(slave_dev);
- if (!hard_iface || hard_iface->mesh_iface)
- goto out;
-
- ret = batadv_hardif_enable_interface(hard_iface, dev);
-
-out:
- batadv_hardif_put(hard_iface);
- return ret;
+ return batadv_hardif_enable_interface(slave_dev, dev);
}
/**
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index 4cf9e3c54ad3..d2bc48c70714 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -968,7 +968,7 @@ batadv_netlink_dump_hardif(struct sk_buff *msg, struct netlink_callback *cb)
bat_priv = netdev_priv(mesh_iface);
rtnl_lock();
- cb->seq = batadv_hardif_generation << 1 | 1;
+ cb->seq = bat_priv->hardif_generation << 1 | 1;
netdev_for_each_lower_private(mesh_iface, hard_iface, iter) {
if (i++ < skip)
@@ -1211,7 +1211,9 @@ batadv_netlink_get_hardif_from_ifindex(struct batadv_priv *bat_priv,
if (!hard_dev)
return ERR_PTR(-ENODEV);
+ rtnl_lock();
hard_iface = batadv_hardif_get_by_netdev(hard_dev);
+ rtnl_unlock();
if (!hard_iface)
goto err_put_harddev;
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 9b38bd9e8da7..48f837cf665a 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -1033,7 +1033,6 @@ batadv_purge_neigh_ifinfo(struct batadv_priv *bat_priv,
/* don't purge if the interface is not (going) down */
if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
- if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
continue;
@@ -1077,7 +1076,6 @@ batadv_purge_orig_ifinfo(struct batadv_priv *bat_priv,
/* don't purge if the interface is not (going) down */
if (if_outgoing->if_status != BATADV_IF_INACTIVE &&
- if_outgoing->if_status != BATADV_IF_NOT_IN_USE &&
if_outgoing->if_status != BATADV_IF_TO_BE_REMOVED)
continue;
@@ -1127,10 +1125,8 @@ batadv_purge_orig_neighbors(struct batadv_priv *bat_priv,
if (batadv_has_timed_out(last_seen, BATADV_PURGE_TIMEOUT) ||
if_incoming->if_status == BATADV_IF_INACTIVE ||
- if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
if_incoming->if_status == BATADV_IF_TO_BE_REMOVED) {
if (if_incoming->if_status == BATADV_IF_INACTIVE ||
- if_incoming->if_status == BATADV_IF_NOT_IN_USE ||
if_incoming->if_status == BATADV_IF_TO_BE_REMOVED)
batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
"neighbor purge: originator %pM, neighbor: %pM, iface: %s\n",
diff --git a/net/batman-adv/tp_meter.c b/net/batman-adv/tp_meter.c
index c2eea7dbc488..00467aa79de9 100644
--- a/net/batman-adv/tp_meter.c
+++ b/net/batman-adv/tp_meter.c
@@ -358,28 +358,16 @@ batadv_tp_list_find_sender_session(struct batadv_priv *bat_priv, const u8 *dst,
}
/**
- * batadv_tp_vars_common_release() - release batadv_tp_vars_common from lists
+ * batadv_tp_sender_release() - release batadv_tp_sender
* and queue for free after rcu grace period
- * @ref: kref pointer of the batadv_tp_vars_common
+ * @ref: kref pointer of the batadv_tp_sender
*/
-static void batadv_tp_vars_common_release(struct kref *ref)
+static void batadv_tp_sender_release(struct kref *ref)
{
- struct batadv_tp_vars_common *tp_vars;
- struct batadv_tp_unacked *un, *safe;
-
- tp_vars = container_of(ref, struct batadv_tp_vars_common, refcount);
-
- /* lock should not be needed because this object is now out of any
- * context!
- */
- spin_lock_bh(&tp_vars->unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
- list_del(&un->list);
- kfree(un);
- }
- spin_unlock_bh(&tp_vars->unacked_lock);
+ struct batadv_tp_sender *tp_vars;
- kfree_rcu(tp_vars, rcu);
+ tp_vars = container_of(ref, struct batadv_tp_sender, common.refcount);
+ kfree_rcu(tp_vars, common.rcu);
}
/**
@@ -392,7 +380,7 @@ static void batadv_tp_sender_put(struct batadv_tp_sender *tp_vars)
if (!tp_vars)
return;
- kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
+ kref_put(&tp_vars->common.refcount, batadv_tp_sender_release);
}
/**
@@ -1145,9 +1133,6 @@ void batadv_tp_start(struct batadv_priv *bat_priv, const u8 *dst,
init_waitqueue_head(&tp_vars->more_bytes);
init_completion(&tp_vars->finished);
- spin_lock_init(&tp_vars->common.unacked_lock);
- INIT_LIST_HEAD(&tp_vars->common.unacked_list);
-
spin_lock_init(&tp_vars->cc_lock);
tp_vars->prerandom_offset = 0;
@@ -1252,6 +1237,33 @@ batadv_tp_list_find_receiver_session(struct batadv_priv *bat_priv, const u8 *dst
}
/**
+ * batadv_tp_receiver_release() - release batadv_tp_receiver
+ * and queue for free after rcu grace period
+ * @ref: kref pointer of the batadv_tp_receiver
+ */
+static void batadv_tp_receiver_release(struct kref *ref)
+{
+ struct batadv_tp_receiver *tp_vars;
+ struct batadv_tp_unacked *safe;
+ struct batadv_tp_unacked *un;
+
+ tp_vars = container_of(ref, struct batadv_tp_receiver, common.refcount);
+
+ /* lock should not be needed because this object is now out of any
+ * context!
+ */
+ spin_lock_bh(&tp_vars->ack_seqno_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
+ list_del(&un->list);
+ kfree(un);
+ tp_vars->unacked_count--;
+ }
+ spin_unlock_bh(&tp_vars->ack_seqno_lock);
+
+ kfree_rcu(tp_vars, common.rcu);
+}
+
+/**
* batadv_tp_receiver_put() - decrement the batadv_tp_receiver
* refcounter and possibly release it
* @tp_vars: the private data of the current TP meter session to be free'd
@@ -1261,7 +1273,7 @@ static void batadv_tp_receiver_put(struct batadv_tp_receiver *tp_vars)
if (!tp_vars)
return;
- kref_put(&tp_vars->common.refcount, batadv_tp_vars_common_release);
+ kref_put(&tp_vars->common.refcount, batadv_tp_receiver_release);
}
/**
@@ -1304,13 +1316,13 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t)
if (batadv_tp_list_detach(&tp_vars->common))
batadv_tp_receiver_put(tp_vars);
- spin_lock_bh(&tp_vars->common.unacked_lock);
- list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
+ spin_lock_bh(&tp_vars->ack_seqno_lock);
+ list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
list_del(&un->list);
kfree(un);
- tp_vars->common.unacked_count--;
+ tp_vars->unacked_count--;
}
- spin_unlock_bh(&tp_vars->common.unacked_lock);
+ spin_unlock_bh(&tp_vars->ack_seqno_lock);
/* drop reference of timer */
if (WARN_ON(atomic_xchg(&tp_vars->receiving, 0) != 1))
@@ -1403,69 +1415,106 @@ out:
*/
static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
u32 seqno, u32 payload_len)
- __must_hold(&tp_vars->common.unacked_lock)
+ __must_hold(&tp_vars->ack_seqno_lock)
{
- struct batadv_tp_unacked *un, *new;
- bool added = false;
-
- new = kmalloc_obj(*new, GFP_ATOMIC);
- if (unlikely(!new))
- return false;
-
- new->seqno = seqno;
- new->len = payload_len;
-
- /* if the list is empty immediately attach this new object */
- if (list_empty(&tp_vars->common.unacked_list)) {
- list_add(&new->list, &tp_vars->common.unacked_list);
- tp_vars->common.unacked_count++;
- return true;
- }
-
- /* otherwise loop over the list and either drop the packet because this
- * is a duplicate or store it at the right position.
+ struct list_head *pos = &tp_vars->unacked_list;
+ struct batadv_tp_unacked *new = NULL;
+ u32 end_seqno = seqno + payload_len;
+ struct batadv_tp_unacked *safe;
+ struct batadv_tp_unacked *un;
+
+ /* loop over the list to find either an existing entry which the new
+ * seqno range can be merged with or the position at which a new entry
+ * has to be inserted.
*
* The iteration is done in the reverse way because it is likely that
* the last received packet (the one being processed now) has a bigger
* seqno than all the others already stored.
*/
- list_for_each_entry_reverse(un, &tp_vars->common.unacked_list, list) {
- /* check for duplicates */
- if (new->seqno == un->seqno) {
- if (new->len > un->len)
- un->len = new->len;
- kfree(new);
- added = true;
- break;
- }
-
- /* look for the right position */
- if (batadv_seq_before(new->seqno, un->seqno))
+ list_for_each_entry_reverse(un, &tp_vars->unacked_list, list) {
+ /* look for the right position - an un which is smaller */
+ if (batadv_seq_before(seqno, un->seqno))
continue;
- /* as soon as an entry having a bigger seqno is found, the new
- * one is attached _after_ it. In this way the list is kept in
- * ascending order
+ /* smaller/equal seqno was found but they might be directly
+ * after another or overlapping. keep only a single entry
+ *
+ * It is already known that:
+ *
+ * un->seqno <= seqno
+ *
+ * When establishing that:
+ *
+ * seqno <= un->seqno + un->len
+ *
+ * Then it is not necessary to add a new entry because the
+ * smaller/equal seqno of un might already contain the new
+ * received packet or we only add new data directly after
+ * the end of un. The latter can be identified using:
+ *
+ * un->seqno + un->len <= end_seqno
*/
- list_add(&new->list, &un->list);
- added = true;
- tp_vars->common.unacked_count++;
+ if (!batadv_seq_before(un->seqno + un->len, seqno)) {
+ /* new data directly after un? */
+ if (!batadv_seq_before(end_seqno, un->seqno + un->len))
+ un->len = end_seqno - un->seqno;
+
+ /* un now represents both old un + new range and has to
+ * be used to check if the gap to the next seqno range
+ * was closed
+ */
+ new = un;
+ } else {
+ /* as soon as an entry having a smaller seqno is found,
+ * the new one is attached _after_ it. In this way the
+ * list is kept in ascending order
+ */
+ pos = &un->list;
+ }
+
break;
}
- /* received packet with smallest seqno out of order; add it to front */
- if (!added) {
- list_add(&new->list, &tp_vars->common.unacked_list);
- tp_vars->common.unacked_count++;
+ /* no entry to merge with was found; insert a new one after the entry
+ * with the next smaller seqno (or at the front of the list when the
+ * new seqno is the smallest or the list is empty)
+ */
+ if (!new) {
+ new = kmalloc_obj(*new, GFP_ATOMIC);
+ if (unlikely(!new))
+ return false;
+
+ new->seqno = seqno;
+ new->len = payload_len;
+
+ list_add(&new->list, pos);
+ tp_vars->unacked_count++;
+ }
+
+ /* check if new filled the gap to the next list entries */
+ un = new;
+ list_for_each_entry_safe_continue(un, safe, &tp_vars->unacked_list, list) {
+ if (batadv_seq_before(end_seqno, un->seqno))
+ break;
+
+ /* next entry is overlapping or adjacent - combine both */
+ if (batadv_seq_before(end_seqno, un->seqno + un->len)) {
+ end_seqno = un->seqno + un->len;
+ new->len = end_seqno - new->seqno;
+ }
+
+ list_del(&un->list);
+ kfree(un);
+ tp_vars->unacked_count--;
}
/* remove the last (biggest) unacked seqno when list is too large */
- if (tp_vars->common.unacked_count > BATADV_TP_MAX_UNACKED) {
- un = list_last_entry(&tp_vars->common.unacked_list,
+ if (tp_vars->unacked_count > BATADV_TP_MAX_UNACKED) {
+ un = list_last_entry(&tp_vars->unacked_list,
struct batadv_tp_unacked, list);
list_del(&un->list);
kfree(un);
- tp_vars->common.unacked_count--;
+ tp_vars->unacked_count--;
}
return true;
@@ -1477,7 +1526,7 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars,
* @tp_vars: the private data of the current TP meter session
*/
static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
- __must_hold(&tp_vars->common.unacked_lock)
+ __must_hold(&tp_vars->ack_seqno_lock)
{
struct batadv_tp_unacked *un, *safe;
u32 to_ack;
@@ -1485,7 +1534,7 @@ static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
/* go through the unacked packet list and possibly ACK them as
* well
*/
- list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) {
+ list_for_each_entry_safe(un, safe, &tp_vars->unacked_list, list) {
/* the list is ordered, therefore it is possible to stop as soon
* there is a gap between the last acked seqno and the seqno of
* the packet under inspection
@@ -1493,14 +1542,14 @@ static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars)
if (batadv_seq_before(tp_vars->last_recv, un->seqno))
break;
- to_ack = un->seqno + un->len - tp_vars->last_recv;
+ to_ack = un->seqno + un->len;
- if (batadv_seq_before(tp_vars->last_recv, un->seqno + un->len))
- tp_vars->last_recv += to_ack;
+ if (batadv_seq_before(tp_vars->last_recv, to_ack))
+ tp_vars->last_recv = to_ack;
list_del(&un->list);
kfree(un);
- tp_vars->common.unacked_count--;
+ tp_vars->unacked_count--;
}
}
@@ -1547,9 +1596,9 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv,
tp_vars->common.bat_priv = bat_priv;
kref_init(&tp_vars->common.refcount);
- spin_lock_init(&tp_vars->common.unacked_lock);
- INIT_LIST_HEAD(&tp_vars->common.unacked_list);
- tp_vars->common.unacked_count = 0;
+ spin_lock_init(&tp_vars->ack_seqno_lock);
+ INIT_LIST_HEAD(&tp_vars->unacked_list);
+ tp_vars->unacked_count = 0;
kref_get(&tp_vars->common.refcount);
timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0);
@@ -1609,7 +1658,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
WRITE_ONCE(tp_vars->last_recv_time, jiffies);
}
- spin_lock_bh(&tp_vars->common.unacked_lock);
+ spin_lock_bh(&tp_vars->ack_seqno_lock);
/* if the packet is a duplicate, it may be the case that an ACK has been
* lost. Resend the ACK
@@ -1625,7 +1674,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
* not been enqueued correctly
*/
if (!batadv_tp_handle_out_of_order(tp_vars, seqno, payload_len)) {
- spin_unlock_bh(&tp_vars->common.unacked_lock);
+ spin_unlock_bh(&tp_vars->ack_seqno_lock);
goto out;
}
@@ -1641,7 +1690,7 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv,
send_ack:
to_ack = tp_vars->last_recv;
- spin_unlock_bh(&tp_vars->common.unacked_lock);
+ spin_unlock_bh(&tp_vars->ack_seqno_lock);
/* send the ACK. If the received packet was out of order, the ACK that
* is going to be sent is a duplicate (the sender will count them and
diff --git a/net/batman-adv/tvlv.c b/net/batman-adv/tvlv.c
index 1c9fb21985f6..49bf2ed9ecdc 100644
--- a/net/batman-adv/tvlv.c
+++ b/net/batman-adv/tvlv.c
@@ -443,6 +443,54 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv,
}
/**
+ * batadv_tvlv_hdr_next() - move a tvlv buffer cursor to the next container
+ * @tvlv_value: cursor into the tvlv buffer, advanced past the returned
+ * container's content on success
+ * @tvlv_value_len: remaining length of the tvlv buffer, reduced by the returned
+ * container's size on success
+ *
+ * Parses a single container header at the current cursor position and, if a
+ * complete container is available, advances the cursor and remaining length
+ * past it. The returned header stays valid; its content is located at
+ * (returned header + 1) and is ntohs(hdr->len) bytes long.
+ *
+ * Return: pointer to the next tvlv container header, or NULL if no further
+ * complete container is present in the buffer.
+ */
+static struct batadv_tvlv_hdr *batadv_tvlv_hdr_next(void **tvlv_value, u16 *tvlv_value_len)
+{
+ struct batadv_tvlv_hdr *tvlv_hdr;
+ u16 tvlv_value_cont_len;
+ void *tvlv_value_cont;
+ u16 tvlv_len;
+
+ tvlv_value_cont = *tvlv_value;
+ tvlv_len = *tvlv_value_len;
+
+ if (tvlv_len < sizeof(*tvlv_hdr))
+ return NULL;
+
+ tvlv_hdr = tvlv_value_cont;
+ tvlv_value_cont_len = ntohs(tvlv_hdr->len);
+ tvlv_value_cont = tvlv_hdr + 1;
+ tvlv_len -= sizeof(*tvlv_hdr);
+
+ if (tvlv_value_cont_len > tvlv_len)
+ return NULL;
+
+ /* the next tvlv header is accessed assuming (at least) 2-byte
+ * alignment, so it must start at an even offset.
+ */
+ if (tvlv_value_cont_len & 1)
+ return NULL;
+
+ *tvlv_value = (u8 *)tvlv_value_cont + tvlv_value_cont_len;
+ *tvlv_value_len = tvlv_len - tvlv_value_cont_len;
+
+ return tvlv_hdr;
+}
+
+/**
* batadv_tvlv_containers_contain() - check if a tvlv buffer holds a container
* @tvlv_value: tvlv content
* @tvlv_value_len: tvlv content length
@@ -457,28 +505,10 @@ static bool batadv_tvlv_containers_contain(void *tvlv_value,
u8 version)
{
struct batadv_tvlv_hdr *tvlv_hdr;
- u16 tvlv_value_cont_len;
-
- while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
- tvlv_hdr = tvlv_value;
- tvlv_value_cont_len = ntohs(tvlv_hdr->len);
- tvlv_value = tvlv_hdr + 1;
- tvlv_value_len -= sizeof(*tvlv_hdr);
-
- if (tvlv_value_cont_len > tvlv_value_len)
- break;
-
- /* the next tvlv header is accessed assuming (at least) 2-byte
- * alignment, so it must start at an even offset.
- */
- if (tvlv_value_cont_len & 1)
- break;
+ while ((tvlv_hdr = batadv_tvlv_hdr_next(&tvlv_value, &tvlv_value_len))) {
if (tvlv_hdr->type == type && tvlv_hdr->version == version)
return true;
-
- tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
- tvlv_value_len -= tvlv_value_cont_len;
}
return false;
@@ -511,20 +541,8 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND;
int ret = NET_RX_SUCCESS;
- while (tvlv_value_len >= sizeof(*tvlv_hdr)) {
- tvlv_hdr = tvlv_value;
+ while ((tvlv_hdr = batadv_tvlv_hdr_next(&tvlv_value, &tvlv_value_len))) {
tvlv_value_cont_len = ntohs(tvlv_hdr->len);
- tvlv_value = tvlv_hdr + 1;
- tvlv_value_len -= sizeof(*tvlv_hdr);
-
- if (tvlv_value_cont_len > tvlv_value_len)
- break;
-
- /* the next tvlv header is accessed assuming (at least) 2-byte
- * alignment, so it must start at an even offset.
- */
- if (tvlv_value_cont_len & 1)
- break;
tvlv_handler = batadv_tvlv_handler_get(bat_priv,
tvlv_hdr->type,
@@ -532,11 +550,9 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv,
ret |= batadv_tvlv_call_handler(bat_priv, tvlv_handler,
packet_type, orig_node, skb,
- tvlv_value,
+ tvlv_hdr + 1,
tvlv_value_cont_len);
batadv_tvlv_handler_put(tvlv_handler);
- tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len;
- tvlv_value_len -= tvlv_value_cont_len;
}
if (packet_type != BATADV_IV_OGM &&
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index b1f9f8964c3f..cd12755d21f3 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -214,9 +214,6 @@ struct batadv_wifi_net_device_state {
* struct batadv_hard_iface - network device known to batman-adv
*/
struct batadv_hard_iface {
- /** @list: list node for batadv_hardif_list */
- struct list_head list;
-
/** @if_status: status of the interface for batman-adv */
char if_status;
@@ -1335,9 +1332,9 @@ struct batadv_tp_unacked {
u32 seqno;
/** @len: length of the packet */
- u16 len;
+ u32 len;
- /** @list: list node for &batadv_tp_vars_common.unacked_list */
+ /** @list: list node for &batadv_tp_receiver.unacked_list */
struct list_head list;
};
@@ -1360,15 +1357,6 @@ struct batadv_tp_vars_common {
/** @session: TP session identifier */
u8 session[2];
- /** @unacked_list: list of unacked packets (meta-info only) */
- struct list_head unacked_list;
-
- /** @unacked_lock: protect unacked_list + &batadv_tp_receiver.last_recv */
- spinlock_t unacked_lock;
-
- /** @unacked_count: number of unacked entries */
- size_t unacked_count;
-
/** @refcount: number of context where the object is used */
struct kref refcount;
@@ -1482,6 +1470,15 @@ struct batadv_tp_receiver {
/** @last_recv_time: time (jiffies) a msg was received */
unsigned long last_recv_time;
+
+ /** @unacked_list: list of unacked packets (meta-info only) */
+ struct list_head unacked_list;
+
+ /** @ack_seqno_lock: protect unacked_list + &batadv_tp_receiver.last_recv */
+ spinlock_t ack_seqno_lock;
+
+ /** @unacked_count: number of unacked entries */
+ size_t unacked_count;
};
/**
@@ -1679,6 +1676,9 @@ struct batadv_priv {
/** @tp_num: number of currently active tp sessions */
atomic_t tp_num;
+ /** @hardif_generation: generation counter added to netlink hardif dumps */
+ unsigned int hardif_generation;
+
/** @orig_work: work queue callback item for orig node purging */
struct delayed_work orig_work;