Commit 0537a149 authored by Sven Eckelmann's avatar Sven Eckelmann Committed by Zicheng Qu
Browse files

batman-adv: Ignore neighbor throughput metrics in error case

mainline inclusion
from mainline-v6.14-rc3
commit e7e34ffc976aaae4f465b7898303241b81ceefc3
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBPLJA
CVE: CVE-2025-21823

Reference: https://web.git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e7e34ffc976aaae4f465b7898303241b81ceefc3



--------------------------------

If a temporary error happened in the evaluation of the neighbor throughput
information, then the invalid throughput result should not be stored in the
throughtput EWMA.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
Signed-off-by: default avatarSimon Wunderlich <sw@simonwunderlich.de>
Signed-off-by: default avatarZicheng Qu <quzicheng@huawei.com>
parent 100c7a8e
Loading
Loading
Loading
Loading
+34 −16
Original line number Diff line number Diff line
@@ -60,11 +60,13 @@ static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
/**
 * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
 * @neigh: the neighbour for which the throughput has to be obtained
 * @pthroughput: calculated throughput towards the given neighbour in multiples
 *  of 100kpbs (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
 *
 * Return: The throughput towards the given neighbour in multiples of 100kpbs
 *         (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
 * Return: true when value behind @pthroughput was set
 */
static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
					u32 *pthroughput)
{
	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
	struct net_device *soft_iface = hard_iface->soft_iface;
@@ -78,14 +80,16 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
	 * batman-adv interface
	 */
	if (!soft_iface)
		return BATADV_THROUGHPUT_DEFAULT_VALUE;
		return false;

	/* if the user specified a customised value for this interface, then
	 * return it directly
	 */
	throughput =  atomic_read(&hard_iface->bat_v.throughput_override);
	if (throughput != 0)
		return throughput;
	if (throughput != 0) {
		*pthroughput = throughput;
		return true;
	}

	/* if this is a wireless device, then ask its throughput through
	 * cfg80211 API
@@ -112,19 +116,24 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
			 * possible to delete this neighbor. For now set
			 * the throughput metric to 0.
			 */
			return 0;
			*pthroughput = 0;
			return true;
		}
		if (ret)
			goto default_throughput;

		if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT))
			return sinfo.expected_throughput / 100;
		if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) {
			*pthroughput = sinfo.expected_throughput / 100;
			return true;
		}

		/* try to estimate the expected throughput based on reported tx
		 * rates
		 */
		if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE))
			return cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
		if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
			*pthroughput = cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
			return true;
		}

		goto default_throughput;
	}
@@ -143,8 +152,10 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
			hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;

		throughput = link_settings.base.speed;
		if (throughput && throughput != SPEED_UNKNOWN)
			return throughput * 10;
		if (throughput && throughput != SPEED_UNKNOWN) {
			*pthroughput = throughput * 10;
			return true;
		}
	}

default_throughput:
@@ -158,7 +169,8 @@ static u32 batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh)
	}

	/* if none of the above cases apply, return the base_throughput */
	return BATADV_THROUGHPUT_DEFAULT_VALUE;
	*pthroughput = BATADV_THROUGHPUT_DEFAULT_VALUE;
	return true;
}

/**
@@ -170,15 +182,21 @@ void batadv_v_elp_throughput_metric_update(struct work_struct *work)
{
	struct batadv_hardif_neigh_node_bat_v *neigh_bat_v;
	struct batadv_hardif_neigh_node *neigh;
	u32 throughput;
	bool valid;

	neigh_bat_v = container_of(work, struct batadv_hardif_neigh_node_bat_v,
				   metric_work);
	neigh = container_of(neigh_bat_v, struct batadv_hardif_neigh_node,
			     bat_v);

	ewma_throughput_add(&neigh->bat_v.throughput,
			    batadv_v_elp_get_throughput(neigh));
	valid = batadv_v_elp_get_throughput(neigh, &throughput);
	if (!valid)
		goto put_neigh;

	ewma_throughput_add(&neigh->bat_v.throughput, throughput);

put_neigh:
	/* decrement refcounter to balance increment performed before scheduling
	 * this task
	 */