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