xref: /openbmc/linux/net/batman-adv/bat_v_elp.c (revision fd5e9fccbd504c5179ab57ff695c610bca8809d6)
17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3d6f94d91SLinus Luessing  *
4d6f94d91SLinus Luessing  * Linus Lüssing, Marek Lindner
5d6f94d91SLinus Luessing  */
6d6f94d91SLinus Luessing 
7d6f94d91SLinus Luessing #include "bat_v_elp.h"
8d6f94d91SLinus Luessing #include "main.h"
9d6f94d91SLinus Luessing 
10d6f94d91SLinus Luessing #include <linux/atomic.h>
11d6289088SSven Eckelmann #include <linux/bitops.h>
12d6f94d91SLinus Luessing #include <linux/byteorder/generic.h>
13eb7da4f1SSven Eckelmann #include <linux/container_of.h>
14d6f94d91SLinus Luessing #include <linux/errno.h>
15d6f94d91SLinus Luessing #include <linux/etherdevice.h>
16c833484eSAntonio Quartulli #include <linux/ethtool.h>
17b92b94acSSven Eckelmann #include <linux/gfp.h>
18d6f94d91SLinus Luessing #include <linux/if_ether.h>
19d6f94d91SLinus Luessing #include <linux/jiffies.h>
20c833484eSAntonio Quartulli #include <linux/kref.h>
21*a7aa2317SSven Eckelmann #include <linux/list.h>
22fcd193e1SSven Eckelmann #include <linux/minmax.h>
23d6f94d91SLinus Luessing #include <linux/netdevice.h>
24d6289088SSven Eckelmann #include <linux/nl80211.h>
25d6f94d91SLinus Luessing #include <linux/random.h>
26d6f94d91SLinus Luessing #include <linux/rculist.h>
27d6f94d91SLinus Luessing #include <linux/rcupdate.h>
28c833484eSAntonio Quartulli #include <linux/rtnetlink.h>
29d6f94d91SLinus Luessing #include <linux/skbuff.h>
30*a7aa2317SSven Eckelmann #include <linux/slab.h>
31d6f94d91SLinus Luessing #include <linux/stddef.h>
32d6f94d91SLinus Luessing #include <linux/string.h>
33d6f94d91SLinus Luessing #include <linux/types.h>
34d6f94d91SLinus Luessing #include <linux/workqueue.h>
35c833484eSAntonio Quartulli #include <net/cfg80211.h>
36fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
37d6f94d91SLinus Luessing 
38d6f94d91SLinus Luessing #include "bat_algo.h"
399323158eSAntonio Quartulli #include "bat_v_ogm.h"
40d6f94d91SLinus Luessing #include "hard-interface.h"
41ba412080SSven Eckelmann #include "log.h"
42162bd64cSLinus Luessing #include "originator.h"
43162bd64cSLinus Luessing #include "routing.h"
44d6f94d91SLinus Luessing #include "send.h"
45d6f94d91SLinus Luessing 
46d6f94d91SLinus Luessing /**
47*a7aa2317SSven Eckelmann  * struct batadv_v_metric_queue_entry - list of hardif neighbors which require
48*a7aa2317SSven Eckelmann  *  and metric update
49*a7aa2317SSven Eckelmann  */
50*a7aa2317SSven Eckelmann struct batadv_v_metric_queue_entry {
51*a7aa2317SSven Eckelmann 	/** @hardif_neigh: hardif neighbor scheduled for metric update */
52*a7aa2317SSven Eckelmann 	struct batadv_hardif_neigh_node *hardif_neigh;
53*a7aa2317SSven Eckelmann 
54*a7aa2317SSven Eckelmann 	/** @list: list node for metric_queue */
55*a7aa2317SSven Eckelmann 	struct list_head list;
56*a7aa2317SSven Eckelmann };
57*a7aa2317SSven Eckelmann 
58*a7aa2317SSven Eckelmann /**
597e9a8c2cSSven Eckelmann  * batadv_v_elp_start_timer() - restart timer for ELP periodic work
60d6f94d91SLinus Luessing  * @hard_iface: the interface for which the timer has to be reset
61d6f94d91SLinus Luessing  */
batadv_v_elp_start_timer(struct batadv_hard_iface * hard_iface)62d6f94d91SLinus Luessing static void batadv_v_elp_start_timer(struct batadv_hard_iface *hard_iface)
63d6f94d91SLinus Luessing {
64d6f94d91SLinus Luessing 	unsigned int msecs;
65d6f94d91SLinus Luessing 
66d6f94d91SLinus Luessing 	msecs = atomic_read(&hard_iface->bat_v.elp_interval) - BATADV_JITTER;
678032bf12SJason A. Donenfeld 	msecs += get_random_u32_below(2 * BATADV_JITTER);
68d6f94d91SLinus Luessing 
69d6f94d91SLinus Luessing 	queue_delayed_work(batadv_event_workqueue, &hard_iface->bat_v.elp_wq,
70d6f94d91SLinus Luessing 			   msecs_to_jiffies(msecs));
71d6f94d91SLinus Luessing }
72d6f94d91SLinus Luessing 
73d6f94d91SLinus Luessing /**
747e9a8c2cSSven Eckelmann  * batadv_v_elp_get_throughput() - get the throughput towards a neighbour
75c833484eSAntonio Quartulli  * @neigh: the neighbour for which the throughput has to be obtained
7696405e2cSSven Eckelmann  * @pthroughput: calculated throughput towards the given neighbour in multiples
7796405e2cSSven Eckelmann  *  of 100kpbs (a value of '1' equals 0.1Mbps, '10' equals 1Mbps, etc).
78c833484eSAntonio Quartulli  *
7996405e2cSSven Eckelmann  * Return: true when value behind @pthroughput was set
80c833484eSAntonio Quartulli  */
batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node * neigh,u32 * pthroughput)8196405e2cSSven Eckelmann static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
8296405e2cSSven Eckelmann 					u32 *pthroughput)
83c833484eSAntonio Quartulli {
84c833484eSAntonio Quartulli 	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
85072b2787SAndy Strohman 	struct net_device *soft_iface = hard_iface->soft_iface;
86c833484eSAntonio Quartulli 	struct ethtool_link_ksettings link_settings;
871942de1bSMarek Lindner 	struct net_device *real_netdev;
88c833484eSAntonio Quartulli 	struct station_info sinfo;
89c833484eSAntonio Quartulli 	u32 throughput;
90c833484eSAntonio Quartulli 	int ret;
91c833484eSAntonio Quartulli 
92072b2787SAndy Strohman 	/* don't query throughput when no longer associated with any
93072b2787SAndy Strohman 	 * batman-adv interface
94072b2787SAndy Strohman 	 */
95072b2787SAndy Strohman 	if (!soft_iface)
9696405e2cSSven Eckelmann 		return false;
97072b2787SAndy Strohman 
98c833484eSAntonio Quartulli 	/* if the user specified a customised value for this interface, then
99c833484eSAntonio Quartulli 	 * return it directly
100c833484eSAntonio Quartulli 	 */
101c833484eSAntonio Quartulli 	throughput =  atomic_read(&hard_iface->bat_v.throughput_override);
10296405e2cSSven Eckelmann 	if (throughput != 0) {
10396405e2cSSven Eckelmann 		*pthroughput = throughput;
10496405e2cSSven Eckelmann 		return true;
10596405e2cSSven Eckelmann 	}
106c833484eSAntonio Quartulli 
107c833484eSAntonio Quartulli 	/* if this is a wireless device, then ask its throughput through
108c833484eSAntonio Quartulli 	 * cfg80211 API
109c833484eSAntonio Quartulli 	 */
11010b1bbb4SSven Eckelmann 	if (batadv_is_wifi_hardif(hard_iface)) {
11110b1bbb4SSven Eckelmann 		if (!batadv_is_cfg80211_hardif(hard_iface))
112f44a3ae9SMarek Lindner 			/* unsupported WiFi driver version */
113f44a3ae9SMarek Lindner 			goto default_throughput;
114f44a3ae9SMarek Lindner 
1151942de1bSMarek Lindner 		real_netdev = batadv_get_real_netdev(hard_iface->net_dev);
1161942de1bSMarek Lindner 		if (!real_netdev)
1171942de1bSMarek Lindner 			goto default_throughput;
1181942de1bSMarek Lindner 
1191942de1bSMarek Lindner 		ret = cfg80211_get_station(real_netdev, neigh->addr, &sinfo);
1201942de1bSMarek Lindner 
121ca8c3b92SAnders Roxell 		if (!ret) {
1227d652669SFelix Fietkau 			/* free the TID stats immediately */
1237d652669SFelix Fietkau 			cfg80211_sinfo_release_content(&sinfo);
124ca8c3b92SAnders Roxell 		}
1257d652669SFelix Fietkau 
1261942de1bSMarek Lindner 		dev_put(real_netdev);
127c833484eSAntonio Quartulli 		if (ret == -ENOENT) {
128c833484eSAntonio Quartulli 			/* Node is not associated anymore! It would be
129c833484eSAntonio Quartulli 			 * possible to delete this neighbor. For now set
130c833484eSAntonio Quartulli 			 * the throughput metric to 0.
131c833484eSAntonio Quartulli 			 */
13296405e2cSSven Eckelmann 			*pthroughput = 0;
13396405e2cSSven Eckelmann 			return true;
134c833484eSAntonio Quartulli 		}
1353f3f8732SSven Eckelmann 		if (ret)
1363f3f8732SSven Eckelmann 			goto default_throughput;
1373f3f8732SSven Eckelmann 
13896405e2cSSven Eckelmann 		if (sinfo.filled & BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT)) {
13996405e2cSSven Eckelmann 			*pthroughput = sinfo.expected_throughput / 100;
14096405e2cSSven Eckelmann 			return true;
14196405e2cSSven Eckelmann 		}
1422b1aa5a4SRené Treffer 
1432b1aa5a4SRené Treffer 		/* try to estimate the expected throughput based on reported tx
1442b1aa5a4SRené Treffer 		 * rates
1452b1aa5a4SRené Treffer 		 */
14696405e2cSSven Eckelmann 		if (sinfo.filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
14796405e2cSSven Eckelmann 			*pthroughput = cfg80211_calculate_bitrate(&sinfo.txrate) / 3;
14896405e2cSSven Eckelmann 			return true;
14996405e2cSSven Eckelmann 		}
1502b1aa5a4SRené Treffer 
1512b1aa5a4SRené Treffer 		goto default_throughput;
152c833484eSAntonio Quartulli 	}
153c833484eSAntonio Quartulli 
154*a7aa2317SSven Eckelmann 	/* only use rtnl_trylock because the elp worker will be cancelled while
155*a7aa2317SSven Eckelmann 	 * the rntl_lock is held. the cancel_delayed_work_sync() would otherwise
156*a7aa2317SSven Eckelmann 	 * wait forever when the elp work_item was started and it is then also
157*a7aa2317SSven Eckelmann 	 * trying to rtnl_lock
158*a7aa2317SSven Eckelmann 	 */
159*a7aa2317SSven Eckelmann 	if (!rtnl_trylock())
160*a7aa2317SSven Eckelmann 		return false;
161*a7aa2317SSven Eckelmann 
162c833484eSAntonio Quartulli 	/* if not a wifi interface, check if this device provides data via
163c833484eSAntonio Quartulli 	 * ethtool (e.g. an Ethernet adapter)
164c833484eSAntonio Quartulli 	 */
165c833484eSAntonio Quartulli 	ret = __ethtool_get_link_ksettings(hard_iface->net_dev, &link_settings);
166c833484eSAntonio Quartulli 	rtnl_unlock();
1679ad346c9SSven Eckelmann 	if (ret == 0) {
168c833484eSAntonio Quartulli 		/* link characteristics might change over time */
169c833484eSAntonio Quartulli 		if (link_settings.base.duplex == DUPLEX_FULL)
170c833484eSAntonio Quartulli 			hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
171c833484eSAntonio Quartulli 		else
172c833484eSAntonio Quartulli 			hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
173c833484eSAntonio Quartulli 
174c833484eSAntonio Quartulli 		throughput = link_settings.base.speed;
17596405e2cSSven Eckelmann 		if (throughput && throughput != SPEED_UNKNOWN) {
17696405e2cSSven Eckelmann 			*pthroughput = throughput * 10;
17796405e2cSSven Eckelmann 			return true;
17896405e2cSSven Eckelmann 		}
179c833484eSAntonio Quartulli 	}
180c833484eSAntonio Quartulli 
181c833484eSAntonio Quartulli default_throughput:
182c833484eSAntonio Quartulli 	if (!(hard_iface->bat_v.flags & BATADV_WARNING_DEFAULT)) {
183072b2787SAndy Strohman 		batadv_info(soft_iface,
184c833484eSAntonio Quartulli 			    "WiFi driver or ethtool info does not provide information about link speeds on interface %s, therefore defaulting to hardcoded throughput values of %u.%1u Mbps. Consider overriding the throughput manually or checking your driver.\n",
185c833484eSAntonio Quartulli 			    hard_iface->net_dev->name,
186c833484eSAntonio Quartulli 			    BATADV_THROUGHPUT_DEFAULT_VALUE / 10,
187c833484eSAntonio Quartulli 			    BATADV_THROUGHPUT_DEFAULT_VALUE % 10);
188c833484eSAntonio Quartulli 		hard_iface->bat_v.flags |= BATADV_WARNING_DEFAULT;
189c833484eSAntonio Quartulli 	}
190c833484eSAntonio Quartulli 
191c833484eSAntonio Quartulli 	/* if none of the above cases apply, return the base_throughput */
19296405e2cSSven Eckelmann 	*pthroughput = BATADV_THROUGHPUT_DEFAULT_VALUE;
19396405e2cSSven Eckelmann 	return true;
194c833484eSAntonio Quartulli }
195c833484eSAntonio Quartulli 
196c833484eSAntonio Quartulli /**
1977e9a8c2cSSven Eckelmann  * batadv_v_elp_throughput_metric_update() - worker updating the throughput
1987e9a8c2cSSven Eckelmann  *  metric of a single hop neighbour
199*a7aa2317SSven Eckelmann  * @neigh: the neighbour to probe
200c833484eSAntonio Quartulli  */
201*a7aa2317SSven Eckelmann static void
batadv_v_elp_throughput_metric_update(struct batadv_hardif_neigh_node * neigh)202*a7aa2317SSven Eckelmann batadv_v_elp_throughput_metric_update(struct batadv_hardif_neigh_node *neigh)
203c833484eSAntonio Quartulli {
20496405e2cSSven Eckelmann 	u32 throughput;
20596405e2cSSven Eckelmann 	bool valid;
206c833484eSAntonio Quartulli 
20796405e2cSSven Eckelmann 	valid = batadv_v_elp_get_throughput(neigh, &throughput);
20896405e2cSSven Eckelmann 	if (!valid)
209*a7aa2317SSven Eckelmann 		return;
210c833484eSAntonio Quartulli 
21196405e2cSSven Eckelmann 	ewma_throughput_add(&neigh->bat_v.throughput, throughput);
212c833484eSAntonio Quartulli }
213c833484eSAntonio Quartulli 
214c833484eSAntonio Quartulli /**
2157e9a8c2cSSven Eckelmann  * batadv_v_elp_wifi_neigh_probe() - send link probing packets to a neighbour
2168d2d499eSAntonio Quartulli  * @neigh: the neighbour to probe
2178d2d499eSAntonio Quartulli  *
2188d2d499eSAntonio Quartulli  * Sends a predefined number of unicast wifi packets to a given neighbour in
2198d2d499eSAntonio Quartulli  * order to trigger the throughput estimation on this link by the RC algorithm.
220bccb48c8SSven Eckelmann  * Packets are sent only if there is not enough payload unicast traffic towards
221bccb48c8SSven Eckelmann  * this neighbour..
2228d2d499eSAntonio Quartulli  *
2238d2d499eSAntonio Quartulli  * Return: True on success and false in case of error during skb preparation.
2248d2d499eSAntonio Quartulli  */
2258d2d499eSAntonio Quartulli static bool
batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node * neigh)2268d2d499eSAntonio Quartulli batadv_v_elp_wifi_neigh_probe(struct batadv_hardif_neigh_node *neigh)
2278d2d499eSAntonio Quartulli {
2288d2d499eSAntonio Quartulli 	struct batadv_hard_iface *hard_iface = neigh->if_incoming;
2298d2d499eSAntonio Quartulli 	struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
2308d2d499eSAntonio Quartulli 	unsigned long last_tx_diff;
2318d2d499eSAntonio Quartulli 	struct sk_buff *skb;
2328d2d499eSAntonio Quartulli 	int probe_len, i;
2338d2d499eSAntonio Quartulli 	int elp_skb_len;
2348d2d499eSAntonio Quartulli 
2358d2d499eSAntonio Quartulli 	/* this probing routine is for Wifi neighbours only */
23610b1bbb4SSven Eckelmann 	if (!batadv_is_wifi_hardif(hard_iface))
2378d2d499eSAntonio Quartulli 		return true;
2388d2d499eSAntonio Quartulli 
2398d2d499eSAntonio Quartulli 	/* probe the neighbor only if no unicast packets have been sent
2408d2d499eSAntonio Quartulli 	 * to it in the last 100 milliseconds: this is the rate control
2418d2d499eSAntonio Quartulli 	 * algorithm sampling interval (minstrel). In this way, if not
2428d2d499eSAntonio Quartulli 	 * enough traffic has been sent to the neighbor, batman-adv can
2438d2d499eSAntonio Quartulli 	 * generate 2 probe packets and push the RC algorithm to perform
2448d2d499eSAntonio Quartulli 	 * the sampling
2458d2d499eSAntonio Quartulli 	 */
2468d2d499eSAntonio Quartulli 	last_tx_diff = jiffies_to_msecs(jiffies - neigh->bat_v.last_unicast_tx);
2478d2d499eSAntonio Quartulli 	if (last_tx_diff <= BATADV_ELP_PROBE_MAX_TX_DIFF)
2488d2d499eSAntonio Quartulli 		return true;
2498d2d499eSAntonio Quartulli 
2508d2d499eSAntonio Quartulli 	probe_len = max_t(int, sizeof(struct batadv_elp_packet),
2518d2d499eSAntonio Quartulli 			  BATADV_ELP_MIN_PROBE_SIZE);
2528d2d499eSAntonio Quartulli 
2538d2d499eSAntonio Quartulli 	for (i = 0; i < BATADV_ELP_PROBES_PER_NODE; i++) {
2548d2d499eSAntonio Quartulli 		elp_skb_len = hard_iface->bat_v.elp_skb->len;
2558d2d499eSAntonio Quartulli 		skb = skb_copy_expand(hard_iface->bat_v.elp_skb, 0,
2568d2d499eSAntonio Quartulli 				      probe_len - elp_skb_len,
2578d2d499eSAntonio Quartulli 				      GFP_ATOMIC);
2588d2d499eSAntonio Quartulli 		if (!skb)
2598d2d499eSAntonio Quartulli 			return false;
2608d2d499eSAntonio Quartulli 
2618d2d499eSAntonio Quartulli 		/* Tell the skb to get as big as the allocated space (we want
2628d2d499eSAntonio Quartulli 		 * the packet to be exactly of that size to make the link
2638d2d499eSAntonio Quartulli 		 * throughput estimation effective.
2648d2d499eSAntonio Quartulli 		 */
26588d0895dSSven Eckelmann 		skb_put_zero(skb, probe_len - hard_iface->bat_v.elp_skb->len);
2668d2d499eSAntonio Quartulli 
2678d2d499eSAntonio Quartulli 		batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
2688d2d499eSAntonio Quartulli 			   "Sending unicast (probe) ELP packet on interface %s to %pM\n",
2698d2d499eSAntonio Quartulli 			   hard_iface->net_dev->name, neigh->addr);
2708d2d499eSAntonio Quartulli 
2718d2d499eSAntonio Quartulli 		batadv_send_skb_packet(skb, hard_iface, neigh->addr);
2728d2d499eSAntonio Quartulli 	}
2738d2d499eSAntonio Quartulli 
2748d2d499eSAntonio Quartulli 	return true;
2758d2d499eSAntonio Quartulli }
2768d2d499eSAntonio Quartulli 
2778d2d499eSAntonio Quartulli /**
2787e9a8c2cSSven Eckelmann  * batadv_v_elp_periodic_work() - ELP periodic task per interface
279d6f94d91SLinus Luessing  * @work: work queue item
280d6f94d91SLinus Luessing  *
281bccb48c8SSven Eckelmann  * Emits broadcast ELP messages in regular intervals.
282d6f94d91SLinus Luessing  */
batadv_v_elp_periodic_work(struct work_struct * work)283d6f94d91SLinus Luessing static void batadv_v_elp_periodic_work(struct work_struct *work)
284d6f94d91SLinus Luessing {
285*a7aa2317SSven Eckelmann 	struct batadv_v_metric_queue_entry *metric_entry;
286*a7aa2317SSven Eckelmann 	struct batadv_v_metric_queue_entry *metric_safe;
287c833484eSAntonio Quartulli 	struct batadv_hardif_neigh_node *hardif_neigh;
288d6f94d91SLinus Luessing 	struct batadv_hard_iface *hard_iface;
289d6f94d91SLinus Luessing 	struct batadv_hard_iface_bat_v *bat_v;
290d6f94d91SLinus Luessing 	struct batadv_elp_packet *elp_packet;
291*a7aa2317SSven Eckelmann 	struct list_head metric_queue;
292d6f94d91SLinus Luessing 	struct batadv_priv *bat_priv;
293d6f94d91SLinus Luessing 	struct sk_buff *skb;
294d6f94d91SLinus Luessing 	u32 elp_interval;
295d6f94d91SLinus Luessing 
296d6f94d91SLinus Luessing 	bat_v = container_of(work, struct batadv_hard_iface_bat_v, elp_wq.work);
297d6f94d91SLinus Luessing 	hard_iface = container_of(bat_v, struct batadv_hard_iface, bat_v);
298d6f94d91SLinus Luessing 	bat_priv = netdev_priv(hard_iface->soft_iface);
299d6f94d91SLinus Luessing 
300d6f94d91SLinus Luessing 	if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_DEACTIVATING)
301d6f94d91SLinus Luessing 		goto out;
302d6f94d91SLinus Luessing 
303d6f94d91SLinus Luessing 	/* we are in the process of shutting this interface down */
304825ffe1fSSven Eckelmann 	if (hard_iface->if_status == BATADV_IF_NOT_IN_USE ||
305825ffe1fSSven Eckelmann 	    hard_iface->if_status == BATADV_IF_TO_BE_REMOVED)
306d6f94d91SLinus Luessing 		goto out;
307d6f94d91SLinus Luessing 
308d6f94d91SLinus Luessing 	/* the interface was enabled but may not be ready yet */
309d6f94d91SLinus Luessing 	if (hard_iface->if_status != BATADV_IF_ACTIVE)
310d6f94d91SLinus Luessing 		goto restart_timer;
311d6f94d91SLinus Luessing 
312d6f94d91SLinus Luessing 	skb = skb_copy(hard_iface->bat_v.elp_skb, GFP_ATOMIC);
313d6f94d91SLinus Luessing 	if (!skb)
314d6f94d91SLinus Luessing 		goto restart_timer;
315d6f94d91SLinus Luessing 
316d6f94d91SLinus Luessing 	elp_packet = (struct batadv_elp_packet *)skb->data;
317d6f94d91SLinus Luessing 	elp_packet->seqno = htonl(atomic_read(&hard_iface->bat_v.elp_seqno));
318d6f94d91SLinus Luessing 	elp_interval = atomic_read(&hard_iface->bat_v.elp_interval);
319d6f94d91SLinus Luessing 	elp_packet->elp_interval = htonl(elp_interval);
320d6f94d91SLinus Luessing 
321d6f94d91SLinus Luessing 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
322d6f94d91SLinus Luessing 		   "Sending broadcast ELP packet on interface %s, seqno %u\n",
323d6f94d91SLinus Luessing 		   hard_iface->net_dev->name,
324d6f94d91SLinus Luessing 		   atomic_read(&hard_iface->bat_v.elp_seqno));
325d6f94d91SLinus Luessing 
32695d39278SAntonio Quartulli 	batadv_send_broadcast_skb(skb, hard_iface);
327d6f94d91SLinus Luessing 
328d6f94d91SLinus Luessing 	atomic_inc(&hard_iface->bat_v.elp_seqno);
329d6f94d91SLinus Luessing 
330*a7aa2317SSven Eckelmann 	INIT_LIST_HEAD(&metric_queue);
331*a7aa2317SSven Eckelmann 
332c833484eSAntonio Quartulli 	/* The throughput metric is updated on each sent packet. This way, if a
333c833484eSAntonio Quartulli 	 * node is dead and no longer sends packets, batman-adv is still able to
334c833484eSAntonio Quartulli 	 * react timely to its death.
335c833484eSAntonio Quartulli 	 *
336c833484eSAntonio Quartulli 	 * The throughput metric is updated by following these steps:
337c833484eSAntonio Quartulli 	 * 1) if the hard_iface is wifi => send a number of unicast ELPs for
338c833484eSAntonio Quartulli 	 *    probing/sampling to each neighbor
339c833484eSAntonio Quartulli 	 * 2) update the throughput metric value of each neighbor (note that the
340c833484eSAntonio Quartulli 	 *    value retrieved in this step might be 100ms old because the
341c833484eSAntonio Quartulli 	 *    probing packets at point 1) could still be in the HW queue)
342c833484eSAntonio Quartulli 	 */
343c833484eSAntonio Quartulli 	rcu_read_lock();
344c833484eSAntonio Quartulli 	hlist_for_each_entry_rcu(hardif_neigh, &hard_iface->neigh_list, list) {
3458d2d499eSAntonio Quartulli 		if (!batadv_v_elp_wifi_neigh_probe(hardif_neigh))
3468d2d499eSAntonio Quartulli 			/* if something goes wrong while probing, better to stop
3478d2d499eSAntonio Quartulli 			 * sending packets immediately and reschedule the task
3488d2d499eSAntonio Quartulli 			 */
3498d2d499eSAntonio Quartulli 			break;
3508d2d499eSAntonio Quartulli 
351c833484eSAntonio Quartulli 		if (!kref_get_unless_zero(&hardif_neigh->refcount))
352c833484eSAntonio Quartulli 			continue;
353c833484eSAntonio Quartulli 
354c833484eSAntonio Quartulli 		/* Reading the estimated throughput from cfg80211 is a task that
355c833484eSAntonio Quartulli 		 * may sleep and that is not allowed in an rcu protected
356*a7aa2317SSven Eckelmann 		 * context. Therefore add it to metric_queue and process it
357*a7aa2317SSven Eckelmann 		 * outside rcu protected context.
358c833484eSAntonio Quartulli 		 */
359*a7aa2317SSven Eckelmann 		metric_entry = kzalloc(sizeof(*metric_entry), GFP_ATOMIC);
360*a7aa2317SSven Eckelmann 		if (!metric_entry) {
3614c4af690SMarek Lindner 			batadv_hardif_neigh_put(hardif_neigh);
362*a7aa2317SSven Eckelmann 			continue;
363*a7aa2317SSven Eckelmann 		}
364*a7aa2317SSven Eckelmann 
365*a7aa2317SSven Eckelmann 		metric_entry->hardif_neigh = hardif_neigh;
366*a7aa2317SSven Eckelmann 		list_add(&metric_entry->list, &metric_queue);
367c833484eSAntonio Quartulli 	}
368c833484eSAntonio Quartulli 	rcu_read_unlock();
369c833484eSAntonio Quartulli 
370*a7aa2317SSven Eckelmann 	list_for_each_entry_safe(metric_entry, metric_safe, &metric_queue, list) {
371*a7aa2317SSven Eckelmann 		batadv_v_elp_throughput_metric_update(metric_entry->hardif_neigh);
372*a7aa2317SSven Eckelmann 
373*a7aa2317SSven Eckelmann 		batadv_hardif_neigh_put(metric_entry->hardif_neigh);
374*a7aa2317SSven Eckelmann 		list_del(&metric_entry->list);
375*a7aa2317SSven Eckelmann 		kfree(metric_entry);
376*a7aa2317SSven Eckelmann 	}
377*a7aa2317SSven Eckelmann 
378d6f94d91SLinus Luessing restart_timer:
379d6f94d91SLinus Luessing 	batadv_v_elp_start_timer(hard_iface);
380d6f94d91SLinus Luessing out:
381d6f94d91SLinus Luessing 	return;
382d6f94d91SLinus Luessing }
383d6f94d91SLinus Luessing 
384d6f94d91SLinus Luessing /**
3857e9a8c2cSSven Eckelmann  * batadv_v_elp_iface_enable() - setup the ELP interface private resources
386d6f94d91SLinus Luessing  * @hard_iface: interface for which the data has to be prepared
387d6f94d91SLinus Luessing  *
388d6f94d91SLinus Luessing  * Return: 0 on success or a -ENOMEM in case of failure.
389d6f94d91SLinus Luessing  */
batadv_v_elp_iface_enable(struct batadv_hard_iface * hard_iface)390d6f94d91SLinus Luessing int batadv_v_elp_iface_enable(struct batadv_hard_iface *hard_iface)
391d6f94d91SLinus Luessing {
392f4156f96SSven Eckelmann 	static const size_t tvlv_padding = sizeof(__be32);
393d6f94d91SLinus Luessing 	struct batadv_elp_packet *elp_packet;
394d6f94d91SLinus Luessing 	unsigned char *elp_buff;
395d6f94d91SLinus Luessing 	u32 random_seqno;
396d6f94d91SLinus Luessing 	size_t size;
397d6f94d91SLinus Luessing 	int res = -ENOMEM;
398d6f94d91SLinus Luessing 
399f4156f96SSven Eckelmann 	size = ETH_HLEN + NET_IP_ALIGN + BATADV_ELP_HLEN + tvlv_padding;
400d6f94d91SLinus Luessing 	hard_iface->bat_v.elp_skb = dev_alloc_skb(size);
401d6f94d91SLinus Luessing 	if (!hard_iface->bat_v.elp_skb)
402d6f94d91SLinus Luessing 		goto out;
403d6f94d91SLinus Luessing 
404d6f94d91SLinus Luessing 	skb_reserve(hard_iface->bat_v.elp_skb, ETH_HLEN + NET_IP_ALIGN);
405f4156f96SSven Eckelmann 	elp_buff = skb_put_zero(hard_iface->bat_v.elp_skb,
406f4156f96SSven Eckelmann 				BATADV_ELP_HLEN + tvlv_padding);
407d6f94d91SLinus Luessing 	elp_packet = (struct batadv_elp_packet *)elp_buff;
408d6f94d91SLinus Luessing 
409d6f94d91SLinus Luessing 	elp_packet->packet_type = BATADV_ELP;
410d6f94d91SLinus Luessing 	elp_packet->version = BATADV_COMPAT_VERSION;
411d6f94d91SLinus Luessing 
412d6f94d91SLinus Luessing 	/* randomize initial seqno to avoid collision */
413d6f94d91SLinus Luessing 	get_random_bytes(&random_seqno, sizeof(random_seqno));
414d6f94d91SLinus Luessing 	atomic_set(&hard_iface->bat_v.elp_seqno, random_seqno);
415d6f94d91SLinus Luessing 
416c833484eSAntonio Quartulli 	/* assume full-duplex by default */
417c833484eSAntonio Quartulli 	hard_iface->bat_v.flags |= BATADV_FULL_DUPLEX;
418c833484eSAntonio Quartulli 
419c833484eSAntonio Quartulli 	/* warn the user (again) if there is no throughput data is available */
420c833484eSAntonio Quartulli 	hard_iface->bat_v.flags &= ~BATADV_WARNING_DEFAULT;
421c833484eSAntonio Quartulli 
42210b1bbb4SSven Eckelmann 	if (batadv_is_wifi_hardif(hard_iface))
423c833484eSAntonio Quartulli 		hard_iface->bat_v.flags &= ~BATADV_FULL_DUPLEX;
424c833484eSAntonio Quartulli 
425d6f94d91SLinus Luessing 	INIT_DELAYED_WORK(&hard_iface->bat_v.elp_wq,
426d6f94d91SLinus Luessing 			  batadv_v_elp_periodic_work);
427d6f94d91SLinus Luessing 	batadv_v_elp_start_timer(hard_iface);
428d6f94d91SLinus Luessing 	res = 0;
429d6f94d91SLinus Luessing 
430d6f94d91SLinus Luessing out:
431d6f94d91SLinus Luessing 	return res;
432d6f94d91SLinus Luessing }
433d6f94d91SLinus Luessing 
434d6f94d91SLinus Luessing /**
4357e9a8c2cSSven Eckelmann  * batadv_v_elp_iface_disable() - release ELP interface private resources
436d6f94d91SLinus Luessing  * @hard_iface: interface for which the resources have to be released
437d6f94d91SLinus Luessing  */
batadv_v_elp_iface_disable(struct batadv_hard_iface * hard_iface)438d6f94d91SLinus Luessing void batadv_v_elp_iface_disable(struct batadv_hard_iface *hard_iface)
439d6f94d91SLinus Luessing {
440d6f94d91SLinus Luessing 	cancel_delayed_work_sync(&hard_iface->bat_v.elp_wq);
441d6f94d91SLinus Luessing 
442d6f94d91SLinus Luessing 	dev_kfree_skb(hard_iface->bat_v.elp_skb);
443d6f94d91SLinus Luessing 	hard_iface->bat_v.elp_skb = NULL;
444d6f94d91SLinus Luessing }
445d6f94d91SLinus Luessing 
446d6f94d91SLinus Luessing /**
4477e9a8c2cSSven Eckelmann  * batadv_v_elp_iface_activate() - update the ELP buffer belonging to the given
448ebe24ceaSMarek Lindner  *  hard-interface
449ebe24ceaSMarek Lindner  * @primary_iface: the new primary interface
450ebe24ceaSMarek Lindner  * @hard_iface: interface holding the to-be-updated buffer
451ebe24ceaSMarek Lindner  */
batadv_v_elp_iface_activate(struct batadv_hard_iface * primary_iface,struct batadv_hard_iface * hard_iface)452ebe24ceaSMarek Lindner void batadv_v_elp_iface_activate(struct batadv_hard_iface *primary_iface,
453ebe24ceaSMarek Lindner 				 struct batadv_hard_iface *hard_iface)
454ebe24ceaSMarek Lindner {
455ebe24ceaSMarek Lindner 	struct batadv_elp_packet *elp_packet;
456ebe24ceaSMarek Lindner 	struct sk_buff *skb;
457ebe24ceaSMarek Lindner 
458ebe24ceaSMarek Lindner 	if (!hard_iface->bat_v.elp_skb)
459ebe24ceaSMarek Lindner 		return;
460ebe24ceaSMarek Lindner 
461ebe24ceaSMarek Lindner 	skb = hard_iface->bat_v.elp_skb;
462ebe24ceaSMarek Lindner 	elp_packet = (struct batadv_elp_packet *)skb->data;
463ebe24ceaSMarek Lindner 	ether_addr_copy(elp_packet->orig,
464ebe24ceaSMarek Lindner 			primary_iface->net_dev->dev_addr);
465ebe24ceaSMarek Lindner }
466ebe24ceaSMarek Lindner 
467ebe24ceaSMarek Lindner /**
4687e9a8c2cSSven Eckelmann  * batadv_v_elp_primary_iface_set() - change internal data to reflect the new
469d6f94d91SLinus Luessing  *  primary interface
470d6f94d91SLinus Luessing  * @primary_iface: the new primary interface
471d6f94d91SLinus Luessing  */
batadv_v_elp_primary_iface_set(struct batadv_hard_iface * primary_iface)472d6f94d91SLinus Luessing void batadv_v_elp_primary_iface_set(struct batadv_hard_iface *primary_iface)
473d6f94d91SLinus Luessing {
474d6f94d91SLinus Luessing 	struct batadv_hard_iface *hard_iface;
475d6f94d91SLinus Luessing 
476d6f94d91SLinus Luessing 	/* update orig field of every elp iface belonging to this mesh */
477d6f94d91SLinus Luessing 	rcu_read_lock();
478d6f94d91SLinus Luessing 	list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) {
479d6f94d91SLinus Luessing 		if (primary_iface->soft_iface != hard_iface->soft_iface)
480d6f94d91SLinus Luessing 			continue;
481d6f94d91SLinus Luessing 
482ebe24ceaSMarek Lindner 		batadv_v_elp_iface_activate(primary_iface, hard_iface);
483d6f94d91SLinus Luessing 	}
484d6f94d91SLinus Luessing 	rcu_read_unlock();
485d6f94d91SLinus Luessing }
486162bd64cSLinus Luessing 
487162bd64cSLinus Luessing /**
4887e9a8c2cSSven Eckelmann  * batadv_v_elp_neigh_update() - update an ELP neighbour node
489162bd64cSLinus Luessing  * @bat_priv: the bat priv with all the soft interface information
490162bd64cSLinus Luessing  * @neigh_addr: the neighbour interface address
491162bd64cSLinus Luessing  * @if_incoming: the interface the packet was received through
492162bd64cSLinus Luessing  * @elp_packet: the received ELP packet
493162bd64cSLinus Luessing  *
494162bd64cSLinus Luessing  * Updates the ELP neighbour node state with the data received within the new
495162bd64cSLinus Luessing  * ELP packet.
496162bd64cSLinus Luessing  */
batadv_v_elp_neigh_update(struct batadv_priv * bat_priv,u8 * neigh_addr,struct batadv_hard_iface * if_incoming,struct batadv_elp_packet * elp_packet)497162bd64cSLinus Luessing static void batadv_v_elp_neigh_update(struct batadv_priv *bat_priv,
498162bd64cSLinus Luessing 				      u8 *neigh_addr,
499162bd64cSLinus Luessing 				      struct batadv_hard_iface *if_incoming,
500162bd64cSLinus Luessing 				      struct batadv_elp_packet *elp_packet)
501162bd64cSLinus Luessing 
502162bd64cSLinus Luessing {
503162bd64cSLinus Luessing 	struct batadv_neigh_node *neigh;
504162bd64cSLinus Luessing 	struct batadv_orig_node *orig_neigh;
505162bd64cSLinus Luessing 	struct batadv_hardif_neigh_node *hardif_neigh;
506162bd64cSLinus Luessing 	s32 seqno_diff;
507162bd64cSLinus Luessing 	s32 elp_latest_seqno;
508162bd64cSLinus Luessing 
509162bd64cSLinus Luessing 	orig_neigh = batadv_v_ogm_orig_get(bat_priv, elp_packet->orig);
510162bd64cSLinus Luessing 	if (!orig_neigh)
511162bd64cSLinus Luessing 		return;
512162bd64cSLinus Luessing 
5136f0a6b5eSMarek Lindner 	neigh = batadv_neigh_node_get_or_create(orig_neigh,
5146f0a6b5eSMarek Lindner 						if_incoming, neigh_addr);
515162bd64cSLinus Luessing 	if (!neigh)
516162bd64cSLinus Luessing 		goto orig_free;
517162bd64cSLinus Luessing 
518162bd64cSLinus Luessing 	hardif_neigh = batadv_hardif_neigh_get(if_incoming, neigh_addr);
519162bd64cSLinus Luessing 	if (!hardif_neigh)
520162bd64cSLinus Luessing 		goto neigh_free;
521162bd64cSLinus Luessing 
522162bd64cSLinus Luessing 	elp_latest_seqno = hardif_neigh->bat_v.elp_latest_seqno;
523162bd64cSLinus Luessing 	seqno_diff = ntohl(elp_packet->seqno) - elp_latest_seqno;
524162bd64cSLinus Luessing 
525162bd64cSLinus Luessing 	/* known or older sequence numbers are ignored. However always adopt
526162bd64cSLinus Luessing 	 * if the router seems to have been restarted.
527162bd64cSLinus Luessing 	 */
528162bd64cSLinus Luessing 	if (seqno_diff < 1 && seqno_diff > -BATADV_ELP_MAX_AGE)
529162bd64cSLinus Luessing 		goto hardif_free;
530162bd64cSLinus Luessing 
531162bd64cSLinus Luessing 	neigh->last_seen = jiffies;
532162bd64cSLinus Luessing 	hardif_neigh->last_seen = jiffies;
533162bd64cSLinus Luessing 	hardif_neigh->bat_v.elp_latest_seqno = ntohl(elp_packet->seqno);
534162bd64cSLinus Luessing 	hardif_neigh->bat_v.elp_interval = ntohl(elp_packet->elp_interval);
535162bd64cSLinus Luessing 
536162bd64cSLinus Luessing hardif_free:
537162bd64cSLinus Luessing 	batadv_hardif_neigh_put(hardif_neigh);
538162bd64cSLinus Luessing neigh_free:
539162bd64cSLinus Luessing 	batadv_neigh_node_put(neigh);
540162bd64cSLinus Luessing orig_free:
541162bd64cSLinus Luessing 	batadv_orig_node_put(orig_neigh);
542162bd64cSLinus Luessing }
543162bd64cSLinus Luessing 
544162bd64cSLinus Luessing /**
5457e9a8c2cSSven Eckelmann  * batadv_v_elp_packet_recv() - main ELP packet handler
546162bd64cSLinus Luessing  * @skb: the received packet
547162bd64cSLinus Luessing  * @if_incoming: the interface this packet was received through
548162bd64cSLinus Luessing  *
549bccb48c8SSven Eckelmann  * Return: NET_RX_SUCCESS and consumes the skb if the packet was properly
550162bd64cSLinus Luessing  * processed or NET_RX_DROP in case of failure.
551162bd64cSLinus Luessing  */
batadv_v_elp_packet_recv(struct sk_buff * skb,struct batadv_hard_iface * if_incoming)552162bd64cSLinus Luessing int batadv_v_elp_packet_recv(struct sk_buff *skb,
553162bd64cSLinus Luessing 			     struct batadv_hard_iface *if_incoming)
554162bd64cSLinus Luessing {
555162bd64cSLinus Luessing 	struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
556162bd64cSLinus Luessing 	struct batadv_elp_packet *elp_packet;
557162bd64cSLinus Luessing 	struct batadv_hard_iface *primary_if;
558eac27a41SRemi Pommarel 	struct ethhdr *ethhdr;
559b91a2543SSven Eckelmann 	bool res;
560b91a2543SSven Eckelmann 	int ret = NET_RX_DROP;
561162bd64cSLinus Luessing 
562b91a2543SSven Eckelmann 	res = batadv_check_management_packet(skb, if_incoming, BATADV_ELP_HLEN);
563b91a2543SSven Eckelmann 	if (!res)
564b91a2543SSven Eckelmann 		goto free_skb;
565162bd64cSLinus Luessing 
566eac27a41SRemi Pommarel 	ethhdr = eth_hdr(skb);
567162bd64cSLinus Luessing 	if (batadv_is_my_mac(bat_priv, ethhdr->h_source))
568b91a2543SSven Eckelmann 		goto free_skb;
569162bd64cSLinus Luessing 
570162bd64cSLinus Luessing 	/* did we receive a B.A.T.M.A.N. V ELP packet on an interface
571162bd64cSLinus Luessing 	 * that does not have B.A.T.M.A.N. V ELP enabled ?
572162bd64cSLinus Luessing 	 */
57329824a55SAntonio Quartulli 	if (strcmp(bat_priv->algo_ops->name, "BATMAN_V") != 0)
574b91a2543SSven Eckelmann 		goto free_skb;
575162bd64cSLinus Luessing 
576162bd64cSLinus Luessing 	elp_packet = (struct batadv_elp_packet *)skb->data;
577162bd64cSLinus Luessing 
578162bd64cSLinus Luessing 	batadv_dbg(BATADV_DBG_BATMAN, bat_priv,
579162bd64cSLinus Luessing 		   "Received ELP packet from %pM seqno %u ORIG: %pM\n",
580162bd64cSLinus Luessing 		   ethhdr->h_source, ntohl(elp_packet->seqno),
581162bd64cSLinus Luessing 		   elp_packet->orig);
582162bd64cSLinus Luessing 
583162bd64cSLinus Luessing 	primary_if = batadv_primary_if_get_selected(bat_priv);
584162bd64cSLinus Luessing 	if (!primary_if)
585b91a2543SSven Eckelmann 		goto free_skb;
586162bd64cSLinus Luessing 
587162bd64cSLinus Luessing 	batadv_v_elp_neigh_update(bat_priv, ethhdr->h_source, if_incoming,
588162bd64cSLinus Luessing 				  elp_packet);
589162bd64cSLinus Luessing 
590b91a2543SSven Eckelmann 	ret = NET_RX_SUCCESS;
591162bd64cSLinus Luessing 	batadv_hardif_put(primary_if);
592b91a2543SSven Eckelmann 
593b91a2543SSven Eckelmann free_skb:
594b91a2543SSven Eckelmann 	if (ret == NET_RX_SUCCESS)
595162bd64cSLinus Luessing 		consume_skb(skb);
596b91a2543SSven Eckelmann 	else
597b91a2543SSven Eckelmann 		kfree_skb(skb);
598b91a2543SSven Eckelmann 
599b91a2543SSven Eckelmann 	return ret;
600162bd64cSLinus Luessing }
601