17db7d9f3SSven Eckelmann // SPDX-License-Identifier: GPL-2.0
2cfa55c6dSSven Eckelmann /* Copyright (C) B.A.T.M.A.N. contributors:
3d353d8d4SMartin Hundebøll *
4d353d8d4SMartin Hundebøll * Martin Hundebøll, Jeppe Ledet-Pedersen
5d353d8d4SMartin Hundebøll */
6d353d8d4SMartin Hundebøll
7d353d8d4SMartin Hundebøll #include "network-coding.h"
81e2c2a4fSSven Eckelmann #include "main.h"
91e2c2a4fSSven Eckelmann
101e2c2a4fSSven Eckelmann #include <linux/atomic.h>
114635469fSLinus Lüssing #include <linux/bitops.h>
121e2c2a4fSSven Eckelmann #include <linux/byteorder/generic.h>
131e2c2a4fSSven Eckelmann #include <linux/compiler.h>
14eb7da4f1SSven Eckelmann #include <linux/container_of.h>
151e2c2a4fSSven Eckelmann #include <linux/errno.h>
161e2c2a4fSSven Eckelmann #include <linux/etherdevice.h>
17b92b94acSSven Eckelmann #include <linux/gfp.h>
181e2c2a4fSSven Eckelmann #include <linux/if_ether.h>
191e2c2a4fSSven Eckelmann #include <linux/if_packet.h>
201e2c2a4fSSven Eckelmann #include <linux/init.h>
211e2c2a4fSSven Eckelmann #include <linux/jhash.h>
221e2c2a4fSSven Eckelmann #include <linux/jiffies.h>
23daf99b48SSven Eckelmann #include <linux/kref.h>
241e2c2a4fSSven Eckelmann #include <linux/list.h>
251e2c2a4fSSven Eckelmann #include <linux/lockdep.h>
263a64469eSSven Eckelmann #include <linux/net.h>
271e2c2a4fSSven Eckelmann #include <linux/netdevice.h>
281e2c2a4fSSven Eckelmann #include <linux/printk.h>
29c4b40f80SSven Eckelmann #include <linux/random.h>
301e2c2a4fSSven Eckelmann #include <linux/rculist.h>
311e2c2a4fSSven Eckelmann #include <linux/rcupdate.h>
321e2c2a4fSSven Eckelmann #include <linux/skbuff.h>
331e2c2a4fSSven Eckelmann #include <linux/slab.h>
341e2c2a4fSSven Eckelmann #include <linux/spinlock.h>
351e2c2a4fSSven Eckelmann #include <linux/stddef.h>
361e2c2a4fSSven Eckelmann #include <linux/string.h>
371e2c2a4fSSven Eckelmann #include <linux/workqueue.h>
38fec149f5SSven Eckelmann #include <uapi/linux/batadv_packet.h>
391e2c2a4fSSven Eckelmann
401e2c2a4fSSven Eckelmann #include "hash.h"
41ba412080SSven Eckelmann #include "log.h"
421e2c2a4fSSven Eckelmann #include "originator.h"
432df5278bSMartin Hundebøll #include "routing.h"
441e2c2a4fSSven Eckelmann #include "send.h"
451f8dce49SMarkus Pargmann #include "tvlv.h"
46d353d8d4SMartin Hundebøll
4795332477SMartin Hundebøll static struct lock_class_key batadv_nc_coding_hash_lock_class_key;
48612d2b4fSMartin Hundebøll static struct lock_class_key batadv_nc_decoding_hash_lock_class_key;
4995332477SMartin Hundebøll
50d353d8d4SMartin Hundebøll static void batadv_nc_worker(struct work_struct *work);
512df5278bSMartin Hundebøll static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
522df5278bSMartin Hundebøll struct batadv_hard_iface *recv_if);
53d353d8d4SMartin Hundebøll
54d353d8d4SMartin Hundebøll /**
557e9a8c2cSSven Eckelmann * batadv_nc_init() - one-time initialization for network coding
56672e7978SSven Eckelmann *
57672e7978SSven Eckelmann * Return: 0 on success or negative error number in case of failure
586c519badSMatthias Schiffer */
batadv_nc_init(void)596c519badSMatthias Schiffer int __init batadv_nc_init(void)
606c519badSMatthias Schiffer {
616c519badSMatthias Schiffer /* Register our packet type */
62cde3fac5SMinghao Chi return batadv_recv_handler_register(BATADV_CODED,
636c519badSMatthias Schiffer batadv_nc_recv_coded_packet);
646c519badSMatthias Schiffer }
656c519badSMatthias Schiffer
666c519badSMatthias Schiffer /**
677e9a8c2cSSven Eckelmann * batadv_nc_start_timer() - initialise the nc periodic worker
68d353d8d4SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
69d353d8d4SMartin Hundebøll */
batadv_nc_start_timer(struct batadv_priv * bat_priv)70d353d8d4SMartin Hundebøll static void batadv_nc_start_timer(struct batadv_priv *bat_priv)
71d353d8d4SMartin Hundebøll {
72d353d8d4SMartin Hundebøll queue_delayed_work(batadv_event_workqueue, &bat_priv->nc.work,
73d353d8d4SMartin Hundebøll msecs_to_jiffies(10));
74d353d8d4SMartin Hundebøll }
75d353d8d4SMartin Hundebøll
76d353d8d4SMartin Hundebøll /**
777e9a8c2cSSven Eckelmann * batadv_nc_tvlv_container_update() - update the network coding tvlv container
783f4841ffSMarek Lindner * after network coding setting change
793f4841ffSMarek Lindner * @bat_priv: the bat priv with all the soft interface information
803f4841ffSMarek Lindner */
batadv_nc_tvlv_container_update(struct batadv_priv * bat_priv)813f4841ffSMarek Lindner static void batadv_nc_tvlv_container_update(struct batadv_priv *bat_priv)
823f4841ffSMarek Lindner {
833f4841ffSMarek Lindner char nc_mode;
843f4841ffSMarek Lindner
853f4841ffSMarek Lindner nc_mode = atomic_read(&bat_priv->network_coding);
863f4841ffSMarek Lindner
873f4841ffSMarek Lindner switch (nc_mode) {
883f4841ffSMarek Lindner case 0:
893f4841ffSMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1);
903f4841ffSMarek Lindner break;
913f4841ffSMarek Lindner case 1:
923f4841ffSMarek Lindner batadv_tvlv_container_register(bat_priv, BATADV_TVLV_NC, 1,
933f4841ffSMarek Lindner NULL, 0);
943f4841ffSMarek Lindner break;
953f4841ffSMarek Lindner }
963f4841ffSMarek Lindner }
973f4841ffSMarek Lindner
983f4841ffSMarek Lindner /**
997e9a8c2cSSven Eckelmann * batadv_nc_status_update() - update the network coding tvlv container after
1003f4841ffSMarek Lindner * network coding setting change
1013f4841ffSMarek Lindner * @net_dev: the soft interface net device
1023f4841ffSMarek Lindner */
batadv_nc_status_update(struct net_device * net_dev)1033f4841ffSMarek Lindner void batadv_nc_status_update(struct net_device *net_dev)
1043f4841ffSMarek Lindner {
1053f4841ffSMarek Lindner struct batadv_priv *bat_priv = netdev_priv(net_dev);
106f138694bSAntonio Quartulli
1073f4841ffSMarek Lindner batadv_nc_tvlv_container_update(bat_priv);
1083f4841ffSMarek Lindner }
1093f4841ffSMarek Lindner
1103f4841ffSMarek Lindner /**
1117e9a8c2cSSven Eckelmann * batadv_nc_tvlv_ogm_handler_v1() - process incoming nc tvlv container
1123f4841ffSMarek Lindner * @bat_priv: the bat priv with all the soft interface information
1133f4841ffSMarek Lindner * @orig: the orig_node of the ogm
1143f4841ffSMarek Lindner * @flags: flags indicating the tvlv state (see batadv_tvlv_handler_flags)
1153f4841ffSMarek Lindner * @tvlv_value: tvlv buffer containing the gateway data
1163f4841ffSMarek Lindner * @tvlv_value_len: tvlv buffer length
1173f4841ffSMarek Lindner */
batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv * bat_priv,struct batadv_orig_node * orig,u8 flags,void * tvlv_value,u16 tvlv_value_len)1183f4841ffSMarek Lindner static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv,
1193f4841ffSMarek Lindner struct batadv_orig_node *orig,
1206b5e971aSSven Eckelmann u8 flags,
1216b5e971aSSven Eckelmann void *tvlv_value, u16 tvlv_value_len)
1223f4841ffSMarek Lindner {
1233f4841ffSMarek Lindner if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)
1244635469fSLinus Lüssing clear_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
1253f4841ffSMarek Lindner else
1264635469fSLinus Lüssing set_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities);
1273f4841ffSMarek Lindner }
1283f4841ffSMarek Lindner
1293f4841ffSMarek Lindner /**
1307e9a8c2cSSven Eckelmann * batadv_nc_mesh_init() - initialise coding hash table and start housekeeping
131d353d8d4SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
132672e7978SSven Eckelmann *
133672e7978SSven Eckelmann * Return: 0 on success or negative error number in case of failure
134d353d8d4SMartin Hundebøll */
batadv_nc_mesh_init(struct batadv_priv * bat_priv)1356c519badSMatthias Schiffer int batadv_nc_mesh_init(struct batadv_priv *bat_priv)
136d353d8d4SMartin Hundebøll {
13795332477SMartin Hundebøll bat_priv->nc.timestamp_fwd_flush = jiffies;
138612d2b4fSMartin Hundebøll bat_priv->nc.timestamp_sniffed_purge = jiffies;
13995332477SMartin Hundebøll
140612d2b4fSMartin Hundebøll if (bat_priv->nc.coding_hash || bat_priv->nc.decoding_hash)
14195332477SMartin Hundebøll return 0;
14295332477SMartin Hundebøll
14395332477SMartin Hundebøll bat_priv->nc.coding_hash = batadv_hash_new(128);
14495332477SMartin Hundebøll if (!bat_priv->nc.coding_hash)
14595332477SMartin Hundebøll goto err;
14695332477SMartin Hundebøll
14795332477SMartin Hundebøll batadv_hash_set_lock_class(bat_priv->nc.coding_hash,
14895332477SMartin Hundebøll &batadv_nc_coding_hash_lock_class_key);
14995332477SMartin Hundebøll
150612d2b4fSMartin Hundebøll bat_priv->nc.decoding_hash = batadv_hash_new(128);
1516f68cd63SPavel Skripkin if (!bat_priv->nc.decoding_hash) {
1526f68cd63SPavel Skripkin batadv_hash_destroy(bat_priv->nc.coding_hash);
153612d2b4fSMartin Hundebøll goto err;
1546f68cd63SPavel Skripkin }
155612d2b4fSMartin Hundebøll
156f44d5407SMartin Hundebøll batadv_hash_set_lock_class(bat_priv->nc.decoding_hash,
157612d2b4fSMartin Hundebøll &batadv_nc_decoding_hash_lock_class_key);
158612d2b4fSMartin Hundebøll
159d353d8d4SMartin Hundebøll INIT_DELAYED_WORK(&bat_priv->nc.work, batadv_nc_worker);
160d353d8d4SMartin Hundebøll batadv_nc_start_timer(bat_priv);
161d353d8d4SMartin Hundebøll
1623f4841ffSMarek Lindner batadv_tvlv_handler_register(bat_priv, batadv_nc_tvlv_ogm_handler_v1,
163*0c4061c0SLinus Lüssing NULL, NULL, BATADV_TVLV_NC, 1,
1643f4841ffSMarek Lindner BATADV_TVLV_HANDLER_OGM_CIFNOTFND);
1653f4841ffSMarek Lindner batadv_nc_tvlv_container_update(bat_priv);
166d353d8d4SMartin Hundebøll return 0;
16795332477SMartin Hundebøll
16895332477SMartin Hundebøll err:
16995332477SMartin Hundebøll return -ENOMEM;
170d353d8d4SMartin Hundebøll }
171d353d8d4SMartin Hundebøll
172d353d8d4SMartin Hundebøll /**
1737e9a8c2cSSven Eckelmann * batadv_nc_init_bat_priv() - initialise the nc specific bat_priv variables
174d353d8d4SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
175d353d8d4SMartin Hundebøll */
batadv_nc_init_bat_priv(struct batadv_priv * bat_priv)176d353d8d4SMartin Hundebøll void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
177d353d8d4SMartin Hundebøll {
178dab7b621SSven Eckelmann atomic_set(&bat_priv->network_coding, 0);
179d56b1705SMartin Hundebøll bat_priv->nc.min_tq = 200;
18095332477SMartin Hundebøll bat_priv->nc.max_fwd_delay = 10;
181612d2b4fSMartin Hundebøll bat_priv->nc.max_buffer_time = 200;
182d56b1705SMartin Hundebøll }
183d56b1705SMartin Hundebøll
184d56b1705SMartin Hundebøll /**
1857e9a8c2cSSven Eckelmann * batadv_nc_init_orig() - initialise the nc fields of an orig_node
186d56b1705SMartin Hundebøll * @orig_node: the orig_node which is going to be initialised
187d56b1705SMartin Hundebøll */
batadv_nc_init_orig(struct batadv_orig_node * orig_node)188d56b1705SMartin Hundebøll void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
189d56b1705SMartin Hundebøll {
190d56b1705SMartin Hundebøll INIT_LIST_HEAD(&orig_node->in_coding_list);
191d56b1705SMartin Hundebøll INIT_LIST_HEAD(&orig_node->out_coding_list);
192d56b1705SMartin Hundebøll spin_lock_init(&orig_node->in_coding_list_lock);
193d56b1705SMartin Hundebøll spin_lock_init(&orig_node->out_coding_list_lock);
194d56b1705SMartin Hundebøll }
195d56b1705SMartin Hundebøll
196d56b1705SMartin Hundebøll /**
1977e9a8c2cSSven Eckelmann * batadv_nc_node_release() - release nc_node from lists and queue for free
1987e9a8c2cSSven Eckelmann * after rcu grace period
199daf99b48SSven Eckelmann * @ref: kref pointer of the nc_node
200d56b1705SMartin Hundebøll */
batadv_nc_node_release(struct kref * ref)201daf99b48SSven Eckelmann static void batadv_nc_node_release(struct kref *ref)
202d56b1705SMartin Hundebøll {
203daf99b48SSven Eckelmann struct batadv_nc_node *nc_node;
204daf99b48SSven Eckelmann
205daf99b48SSven Eckelmann nc_node = container_of(ref, struct batadv_nc_node, refcount);
206daf99b48SSven Eckelmann
2075d967310SSven Eckelmann batadv_orig_node_put(nc_node->orig_node);
20844e8e7e9SSven Eckelmann kfree_rcu(nc_node, rcu);
209d56b1705SMartin Hundebøll }
210d56b1705SMartin Hundebøll
211d56b1705SMartin Hundebøll /**
2127e9a8c2cSSven Eckelmann * batadv_nc_node_put() - decrement the nc_node refcounter and possibly
21344e8e7e9SSven Eckelmann * release it
214daf99b48SSven Eckelmann * @nc_node: nc_node to be free'd
215d56b1705SMartin Hundebøll */
batadv_nc_node_put(struct batadv_nc_node * nc_node)21627ad7545SSven Eckelmann static void batadv_nc_node_put(struct batadv_nc_node *nc_node)
217d56b1705SMartin Hundebøll {
2186340dcbdSSven Eckelmann if (!nc_node)
2196340dcbdSSven Eckelmann return;
2206340dcbdSSven Eckelmann
221daf99b48SSven Eckelmann kref_put(&nc_node->refcount, batadv_nc_node_release);
222d56b1705SMartin Hundebøll }
223d56b1705SMartin Hundebøll
224d56b1705SMartin Hundebøll /**
2257e9a8c2cSSven Eckelmann * batadv_nc_path_release() - release nc_path from lists and queue for free
2267e9a8c2cSSven Eckelmann * after rcu grace period
227727e0cd5SSven Eckelmann * @ref: kref pointer of the nc_path
228727e0cd5SSven Eckelmann */
batadv_nc_path_release(struct kref * ref)229727e0cd5SSven Eckelmann static void batadv_nc_path_release(struct kref *ref)
230727e0cd5SSven Eckelmann {
231727e0cd5SSven Eckelmann struct batadv_nc_path *nc_path;
232727e0cd5SSven Eckelmann
233727e0cd5SSven Eckelmann nc_path = container_of(ref, struct batadv_nc_path, refcount);
234727e0cd5SSven Eckelmann
235727e0cd5SSven Eckelmann kfree_rcu(nc_path, rcu);
236727e0cd5SSven Eckelmann }
237727e0cd5SSven Eckelmann
238727e0cd5SSven Eckelmann /**
2397e9a8c2cSSven Eckelmann * batadv_nc_path_put() - decrement the nc_path refcounter and possibly
240727e0cd5SSven Eckelmann * release it
241727e0cd5SSven Eckelmann * @nc_path: nc_path to be free'd
24295332477SMartin Hundebøll */
batadv_nc_path_put(struct batadv_nc_path * nc_path)2435fff2825SSven Eckelmann static void batadv_nc_path_put(struct batadv_nc_path *nc_path)
24495332477SMartin Hundebøll {
2456340dcbdSSven Eckelmann if (!nc_path)
2466340dcbdSSven Eckelmann return;
2476340dcbdSSven Eckelmann
248727e0cd5SSven Eckelmann kref_put(&nc_path->refcount, batadv_nc_path_release);
24995332477SMartin Hundebøll }
25095332477SMartin Hundebøll
25195332477SMartin Hundebøll /**
2527e9a8c2cSSven Eckelmann * batadv_nc_packet_free() - frees nc packet
25395332477SMartin Hundebøll * @nc_packet: the nc packet to free
25421ba5ab2SSven Eckelmann * @dropped: whether the packet is freed because is dropped
25595332477SMartin Hundebøll */
batadv_nc_packet_free(struct batadv_nc_packet * nc_packet,bool dropped)256bd687fe4SSven Eckelmann static void batadv_nc_packet_free(struct batadv_nc_packet *nc_packet,
257bd687fe4SSven Eckelmann bool dropped)
25895332477SMartin Hundebøll {
259bd687fe4SSven Eckelmann if (dropped)
26095332477SMartin Hundebøll kfree_skb(nc_packet->skb);
261bd687fe4SSven Eckelmann else
262bd687fe4SSven Eckelmann consume_skb(nc_packet->skb);
263bd687fe4SSven Eckelmann
2645fff2825SSven Eckelmann batadv_nc_path_put(nc_packet->nc_path);
26595332477SMartin Hundebøll kfree(nc_packet);
26695332477SMartin Hundebøll }
26795332477SMartin Hundebøll
26895332477SMartin Hundebøll /**
2697e9a8c2cSSven Eckelmann * batadv_nc_to_purge_nc_node() - checks whether an nc node has to be purged
270d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
271d56b1705SMartin Hundebøll * @nc_node: the nc node to check
272d56b1705SMartin Hundebøll *
27362fe710fSSven Eckelmann * Return: true if the entry has to be purged now, false otherwise
274d56b1705SMartin Hundebøll */
batadv_nc_to_purge_nc_node(struct batadv_priv * bat_priv,struct batadv_nc_node * nc_node)275d56b1705SMartin Hundebøll static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv,
276d56b1705SMartin Hundebøll struct batadv_nc_node *nc_node)
277d56b1705SMartin Hundebøll {
278d56b1705SMartin Hundebøll if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
279d56b1705SMartin Hundebøll return true;
280d56b1705SMartin Hundebøll
281d56b1705SMartin Hundebøll return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT);
282d56b1705SMartin Hundebøll }
283d56b1705SMartin Hundebøll
284d56b1705SMartin Hundebøll /**
2857e9a8c2cSSven Eckelmann * batadv_nc_to_purge_nc_path_coding() - checks whether an nc path has timed out
28695332477SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
28795332477SMartin Hundebøll * @nc_path: the nc path to check
28895332477SMartin Hundebøll *
28962fe710fSSven Eckelmann * Return: true if the entry has to be purged now, false otherwise
29095332477SMartin Hundebøll */
batadv_nc_to_purge_nc_path_coding(struct batadv_priv * bat_priv,struct batadv_nc_path * nc_path)29195332477SMartin Hundebøll static bool batadv_nc_to_purge_nc_path_coding(struct batadv_priv *bat_priv,
29295332477SMartin Hundebøll struct batadv_nc_path *nc_path)
29395332477SMartin Hundebøll {
29495332477SMartin Hundebøll if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
29595332477SMartin Hundebøll return true;
29695332477SMartin Hundebøll
29795332477SMartin Hundebøll /* purge the path when no packets has been added for 10 times the
29895332477SMartin Hundebøll * max_fwd_delay time
29995332477SMartin Hundebøll */
30095332477SMartin Hundebøll return batadv_has_timed_out(nc_path->last_valid,
30195332477SMartin Hundebøll bat_priv->nc.max_fwd_delay * 10);
30295332477SMartin Hundebøll }
30395332477SMartin Hundebøll
30495332477SMartin Hundebøll /**
3057e9a8c2cSSven Eckelmann * batadv_nc_to_purge_nc_path_decoding() - checks whether an nc path has timed
3067e9a8c2cSSven Eckelmann * out
307612d2b4fSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
308612d2b4fSMartin Hundebøll * @nc_path: the nc path to check
309612d2b4fSMartin Hundebøll *
31062fe710fSSven Eckelmann * Return: true if the entry has to be purged now, false otherwise
311612d2b4fSMartin Hundebøll */
batadv_nc_to_purge_nc_path_decoding(struct batadv_priv * bat_priv,struct batadv_nc_path * nc_path)312612d2b4fSMartin Hundebøll static bool batadv_nc_to_purge_nc_path_decoding(struct batadv_priv *bat_priv,
313612d2b4fSMartin Hundebøll struct batadv_nc_path *nc_path)
314612d2b4fSMartin Hundebøll {
315612d2b4fSMartin Hundebøll if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
316612d2b4fSMartin Hundebøll return true;
317612d2b4fSMartin Hundebøll
318612d2b4fSMartin Hundebøll /* purge the path when no packets has been added for 10 times the
319612d2b4fSMartin Hundebøll * max_buffer time
320612d2b4fSMartin Hundebøll */
321612d2b4fSMartin Hundebøll return batadv_has_timed_out(nc_path->last_valid,
322612d2b4fSMartin Hundebøll bat_priv->nc.max_buffer_time * 10);
323612d2b4fSMartin Hundebøll }
324612d2b4fSMartin Hundebøll
325612d2b4fSMartin Hundebøll /**
3267e9a8c2cSSven Eckelmann * batadv_nc_purge_orig_nc_nodes() - go through list of nc nodes and purge stale
327d56b1705SMartin Hundebøll * entries
328d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
329d56b1705SMartin Hundebøll * @list: list of nc nodes
330d56b1705SMartin Hundebøll * @lock: nc node list lock
331d56b1705SMartin Hundebøll * @to_purge: function in charge to decide whether an entry has to be purged or
332d56b1705SMartin Hundebøll * not. This function takes the nc node as argument and has to return
333d56b1705SMartin Hundebøll * a boolean value: true if the entry has to be deleted, false
334d56b1705SMartin Hundebøll * otherwise
335d56b1705SMartin Hundebøll */
336d56b1705SMartin Hundebøll static void
batadv_nc_purge_orig_nc_nodes(struct batadv_priv * bat_priv,struct list_head * list,spinlock_t * lock,bool (* to_purge)(struct batadv_priv *,struct batadv_nc_node *))337d56b1705SMartin Hundebøll batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
338d56b1705SMartin Hundebøll struct list_head *list,
339d56b1705SMartin Hundebøll spinlock_t *lock,
340d56b1705SMartin Hundebøll bool (*to_purge)(struct batadv_priv *,
341d56b1705SMartin Hundebøll struct batadv_nc_node *))
342d56b1705SMartin Hundebøll {
343d56b1705SMartin Hundebøll struct batadv_nc_node *nc_node, *nc_node_tmp;
344d56b1705SMartin Hundebøll
345d56b1705SMartin Hundebøll /* For each nc_node in list */
346d56b1705SMartin Hundebøll spin_lock_bh(lock);
347d56b1705SMartin Hundebøll list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) {
348d56b1705SMartin Hundebøll /* if an helper function has been passed as parameter,
349d56b1705SMartin Hundebøll * ask it if the entry has to be purged or not
350d56b1705SMartin Hundebøll */
351d56b1705SMartin Hundebøll if (to_purge && !to_purge(bat_priv, nc_node))
352d56b1705SMartin Hundebøll continue;
353d56b1705SMartin Hundebøll
354d56b1705SMartin Hundebøll batadv_dbg(BATADV_DBG_NC, bat_priv,
355d56b1705SMartin Hundebøll "Removing nc_node %pM -> %pM\n",
356d56b1705SMartin Hundebøll nc_node->addr, nc_node->orig_node->orig);
357d56b1705SMartin Hundebøll list_del_rcu(&nc_node->list);
35827ad7545SSven Eckelmann batadv_nc_node_put(nc_node);
359d56b1705SMartin Hundebøll }
360d56b1705SMartin Hundebøll spin_unlock_bh(lock);
361d56b1705SMartin Hundebøll }
362d56b1705SMartin Hundebøll
363d56b1705SMartin Hundebøll /**
3647e9a8c2cSSven Eckelmann * batadv_nc_purge_orig() - purges all nc node data attached of the given
365d56b1705SMartin Hundebøll * originator
366d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
367d56b1705SMartin Hundebøll * @orig_node: orig_node with the nc node entries to be purged
368d56b1705SMartin Hundebøll * @to_purge: function in charge to decide whether an entry has to be purged or
369d56b1705SMartin Hundebøll * not. This function takes the nc node as argument and has to return
370d56b1705SMartin Hundebøll * a boolean value: true is the entry has to be deleted, false
371d56b1705SMartin Hundebøll * otherwise
372d56b1705SMartin Hundebøll */
batadv_nc_purge_orig(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,bool (* to_purge)(struct batadv_priv *,struct batadv_nc_node *))373d56b1705SMartin Hundebøll void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
374d56b1705SMartin Hundebøll struct batadv_orig_node *orig_node,
375d56b1705SMartin Hundebøll bool (*to_purge)(struct batadv_priv *,
376d56b1705SMartin Hundebøll struct batadv_nc_node *))
377d56b1705SMartin Hundebøll {
378d56b1705SMartin Hundebøll /* Check ingoing nc_node's of this orig_node */
379d56b1705SMartin Hundebøll batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list,
380d56b1705SMartin Hundebøll &orig_node->in_coding_list_lock,
381d56b1705SMartin Hundebøll to_purge);
382d56b1705SMartin Hundebøll
383d56b1705SMartin Hundebøll /* Check outgoing nc_node's of this orig_node */
384d56b1705SMartin Hundebøll batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list,
385d56b1705SMartin Hundebøll &orig_node->out_coding_list_lock,
386d56b1705SMartin Hundebøll to_purge);
387d56b1705SMartin Hundebøll }
388d56b1705SMartin Hundebøll
389d56b1705SMartin Hundebøll /**
3907e9a8c2cSSven Eckelmann * batadv_nc_purge_orig_hash() - traverse entire originator hash to check if
3917e9a8c2cSSven Eckelmann * they have timed out nc nodes
392d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
393d56b1705SMartin Hundebøll */
batadv_nc_purge_orig_hash(struct batadv_priv * bat_priv)394d56b1705SMartin Hundebøll static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv)
395d56b1705SMartin Hundebøll {
396d56b1705SMartin Hundebøll struct batadv_hashtable *hash = bat_priv->orig_hash;
397d56b1705SMartin Hundebøll struct hlist_head *head;
398d56b1705SMartin Hundebøll struct batadv_orig_node *orig_node;
3996b5e971aSSven Eckelmann u32 i;
400d56b1705SMartin Hundebøll
401d56b1705SMartin Hundebøll if (!hash)
402d56b1705SMartin Hundebøll return;
403d56b1705SMartin Hundebøll
404d56b1705SMartin Hundebøll /* For each orig_node */
405d56b1705SMartin Hundebøll for (i = 0; i < hash->size; i++) {
406d56b1705SMartin Hundebøll head = &hash->table[i];
407d56b1705SMartin Hundebøll
408d56b1705SMartin Hundebøll rcu_read_lock();
409d56b1705SMartin Hundebøll hlist_for_each_entry_rcu(orig_node, head, hash_entry)
410d56b1705SMartin Hundebøll batadv_nc_purge_orig(bat_priv, orig_node,
411d56b1705SMartin Hundebøll batadv_nc_to_purge_nc_node);
412d56b1705SMartin Hundebøll rcu_read_unlock();
413d56b1705SMartin Hundebøll }
414d353d8d4SMartin Hundebøll }
415d353d8d4SMartin Hundebøll
416d353d8d4SMartin Hundebøll /**
4177e9a8c2cSSven Eckelmann * batadv_nc_purge_paths() - traverse all nc paths part of the hash and remove
41895332477SMartin Hundebøll * unused ones
41995332477SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
42095332477SMartin Hundebøll * @hash: hash table containing the nc paths to check
42195332477SMartin Hundebøll * @to_purge: function in charge to decide whether an entry has to be purged or
42295332477SMartin Hundebøll * not. This function takes the nc node as argument and has to return
42395332477SMartin Hundebøll * a boolean value: true is the entry has to be deleted, false
42495332477SMartin Hundebøll * otherwise
42595332477SMartin Hundebøll */
batadv_nc_purge_paths(struct batadv_priv * bat_priv,struct batadv_hashtable * hash,bool (* to_purge)(struct batadv_priv *,struct batadv_nc_path *))42695332477SMartin Hundebøll static void batadv_nc_purge_paths(struct batadv_priv *bat_priv,
42795332477SMartin Hundebøll struct batadv_hashtable *hash,
42895332477SMartin Hundebøll bool (*to_purge)(struct batadv_priv *,
42995332477SMartin Hundebøll struct batadv_nc_path *))
43095332477SMartin Hundebøll {
43195332477SMartin Hundebøll struct hlist_head *head;
43295332477SMartin Hundebøll struct hlist_node *node_tmp;
43395332477SMartin Hundebøll struct batadv_nc_path *nc_path;
43495332477SMartin Hundebøll spinlock_t *lock; /* Protects lists in hash */
4356b5e971aSSven Eckelmann u32 i;
43695332477SMartin Hundebøll
43795332477SMartin Hundebøll for (i = 0; i < hash->size; i++) {
43895332477SMartin Hundebøll head = &hash->table[i];
43995332477SMartin Hundebøll lock = &hash->list_locks[i];
44095332477SMartin Hundebøll
44195332477SMartin Hundebøll /* For each nc_path in this bin */
44295332477SMartin Hundebøll spin_lock_bh(lock);
44395332477SMartin Hundebøll hlist_for_each_entry_safe(nc_path, node_tmp, head, hash_entry) {
44495332477SMartin Hundebøll /* if an helper function has been passed as parameter,
44595332477SMartin Hundebøll * ask it if the entry has to be purged or not
44695332477SMartin Hundebøll */
44795332477SMartin Hundebøll if (to_purge && !to_purge(bat_priv, nc_path))
44895332477SMartin Hundebøll continue;
44995332477SMartin Hundebøll
45095332477SMartin Hundebøll /* purging an non-empty nc_path should never happen, but
45195332477SMartin Hundebøll * is observed under high CPU load. Delay the purging
45295332477SMartin Hundebøll * until next iteration to allow the packet_list to be
45395332477SMartin Hundebøll * emptied first.
45495332477SMartin Hundebøll */
45595332477SMartin Hundebøll if (!unlikely(list_empty(&nc_path->packet_list))) {
45695332477SMartin Hundebøll net_ratelimited_function(printk,
45795332477SMartin Hundebøll KERN_WARNING
45895332477SMartin Hundebøll "Skipping free of non-empty nc_path (%pM -> %pM)!\n",
45995332477SMartin Hundebøll nc_path->prev_hop,
46095332477SMartin Hundebøll nc_path->next_hop);
46195332477SMartin Hundebøll continue;
46295332477SMartin Hundebøll }
46395332477SMartin Hundebøll
46495332477SMartin Hundebøll /* nc_path is unused, so remove it */
46595332477SMartin Hundebøll batadv_dbg(BATADV_DBG_NC, bat_priv,
46695332477SMartin Hundebøll "Remove nc_path %pM -> %pM\n",
46795332477SMartin Hundebøll nc_path->prev_hop, nc_path->next_hop);
46895332477SMartin Hundebøll hlist_del_rcu(&nc_path->hash_entry);
4695fff2825SSven Eckelmann batadv_nc_path_put(nc_path);
47095332477SMartin Hundebøll }
47195332477SMartin Hundebøll spin_unlock_bh(lock);
47295332477SMartin Hundebøll }
47395332477SMartin Hundebøll }
47495332477SMartin Hundebøll
47595332477SMartin Hundebøll /**
4767e9a8c2cSSven Eckelmann * batadv_nc_hash_key_gen() - computes the nc_path hash key
47795332477SMartin Hundebøll * @key: buffer to hold the final hash key
47895332477SMartin Hundebøll * @src: source ethernet mac address going into the hash key
47995332477SMartin Hundebøll * @dst: destination ethernet mac address going into the hash key
48095332477SMartin Hundebøll */
batadv_nc_hash_key_gen(struct batadv_nc_path * key,const char * src,const char * dst)48195332477SMartin Hundebøll static void batadv_nc_hash_key_gen(struct batadv_nc_path *key, const char *src,
48295332477SMartin Hundebøll const char *dst)
48395332477SMartin Hundebøll {
48495332477SMartin Hundebøll memcpy(key->prev_hop, src, sizeof(key->prev_hop));
48595332477SMartin Hundebøll memcpy(key->next_hop, dst, sizeof(key->next_hop));
48695332477SMartin Hundebøll }
48795332477SMartin Hundebøll
48895332477SMartin Hundebøll /**
4897e9a8c2cSSven Eckelmann * batadv_nc_hash_choose() - compute the hash value for an nc path
49095332477SMartin Hundebøll * @data: data to hash
49195332477SMartin Hundebøll * @size: size of the hash table
49295332477SMartin Hundebøll *
49362fe710fSSven Eckelmann * Return: the selected index in the hash table for the given data.
49495332477SMartin Hundebøll */
batadv_nc_hash_choose(const void * data,u32 size)4956b5e971aSSven Eckelmann static u32 batadv_nc_hash_choose(const void *data, u32 size)
49695332477SMartin Hundebøll {
49795332477SMartin Hundebøll const struct batadv_nc_path *nc_path = data;
4986b5e971aSSven Eckelmann u32 hash = 0;
49995332477SMartin Hundebøll
50036fd61cbSSven Eckelmann hash = jhash(&nc_path->prev_hop, sizeof(nc_path->prev_hop), hash);
50136fd61cbSSven Eckelmann hash = jhash(&nc_path->next_hop, sizeof(nc_path->next_hop), hash);
50295332477SMartin Hundebøll
50395332477SMartin Hundebøll return hash % size;
50495332477SMartin Hundebøll }
50595332477SMartin Hundebøll
50695332477SMartin Hundebøll /**
5077e9a8c2cSSven Eckelmann * batadv_nc_hash_compare() - comparing function used in the network coding hash
50895332477SMartin Hundebøll * tables
50995332477SMartin Hundebøll * @node: node in the local table
51095332477SMartin Hundebøll * @data2: second object to compare the node to
51195332477SMartin Hundebøll *
5124b426b10SSven Eckelmann * Return: true if the two entry are the same, false otherwise
51395332477SMartin Hundebøll */
batadv_nc_hash_compare(const struct hlist_node * node,const void * data2)5144b426b10SSven Eckelmann static bool batadv_nc_hash_compare(const struct hlist_node *node,
51595332477SMartin Hundebøll const void *data2)
51695332477SMartin Hundebøll {
51795332477SMartin Hundebøll const struct batadv_nc_path *nc_path1, *nc_path2;
51895332477SMartin Hundebøll
51995332477SMartin Hundebøll nc_path1 = container_of(node, struct batadv_nc_path, hash_entry);
52095332477SMartin Hundebøll nc_path2 = data2;
52195332477SMartin Hundebøll
52295332477SMartin Hundebøll /* Return 1 if the two keys are identical */
523676970e5SAntonio Quartulli if (!batadv_compare_eth(nc_path1->prev_hop, nc_path2->prev_hop))
5244b426b10SSven Eckelmann return false;
52595332477SMartin Hundebøll
526676970e5SAntonio Quartulli if (!batadv_compare_eth(nc_path1->next_hop, nc_path2->next_hop))
5274b426b10SSven Eckelmann return false;
52895332477SMartin Hundebøll
5294b426b10SSven Eckelmann return true;
53095332477SMartin Hundebøll }
53195332477SMartin Hundebøll
53295332477SMartin Hundebøll /**
5337e9a8c2cSSven Eckelmann * batadv_nc_hash_find() - search for an existing nc path and return it
53495332477SMartin Hundebøll * @hash: hash table containing the nc path
53595332477SMartin Hundebøll * @data: search key
53695332477SMartin Hundebøll *
53762fe710fSSven Eckelmann * Return: the nc_path if found, NULL otherwise.
53895332477SMartin Hundebøll */
53995332477SMartin Hundebøll static struct batadv_nc_path *
batadv_nc_hash_find(struct batadv_hashtable * hash,void * data)54095332477SMartin Hundebøll batadv_nc_hash_find(struct batadv_hashtable *hash,
54195332477SMartin Hundebøll void *data)
54295332477SMartin Hundebøll {
54395332477SMartin Hundebøll struct hlist_head *head;
54495332477SMartin Hundebøll struct batadv_nc_path *nc_path, *nc_path_tmp = NULL;
54595332477SMartin Hundebøll int index;
54695332477SMartin Hundebøll
54795332477SMartin Hundebøll if (!hash)
54895332477SMartin Hundebøll return NULL;
54995332477SMartin Hundebøll
55095332477SMartin Hundebøll index = batadv_nc_hash_choose(data, hash->size);
55195332477SMartin Hundebøll head = &hash->table[index];
55295332477SMartin Hundebøll
55395332477SMartin Hundebøll rcu_read_lock();
55495332477SMartin Hundebøll hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
55595332477SMartin Hundebøll if (!batadv_nc_hash_compare(&nc_path->hash_entry, data))
55695332477SMartin Hundebøll continue;
55795332477SMartin Hundebøll
558727e0cd5SSven Eckelmann if (!kref_get_unless_zero(&nc_path->refcount))
55995332477SMartin Hundebøll continue;
56095332477SMartin Hundebøll
56195332477SMartin Hundebøll nc_path_tmp = nc_path;
56295332477SMartin Hundebøll break;
56395332477SMartin Hundebøll }
56495332477SMartin Hundebøll rcu_read_unlock();
56595332477SMartin Hundebøll
56695332477SMartin Hundebøll return nc_path_tmp;
56795332477SMartin Hundebøll }
56895332477SMartin Hundebøll
56995332477SMartin Hundebøll /**
5707e9a8c2cSSven Eckelmann * batadv_nc_send_packet() - send non-coded packet and free nc_packet struct
57195332477SMartin Hundebøll * @nc_packet: the nc packet to send
57295332477SMartin Hundebøll */
batadv_nc_send_packet(struct batadv_nc_packet * nc_packet)57395332477SMartin Hundebøll static void batadv_nc_send_packet(struct batadv_nc_packet *nc_packet)
57495332477SMartin Hundebøll {
57595d39278SAntonio Quartulli batadv_send_unicast_skb(nc_packet->skb, nc_packet->neigh_node);
57695332477SMartin Hundebøll nc_packet->skb = NULL;
577bd687fe4SSven Eckelmann batadv_nc_packet_free(nc_packet, false);
57895332477SMartin Hundebøll }
57995332477SMartin Hundebøll
58095332477SMartin Hundebøll /**
5817e9a8c2cSSven Eckelmann * batadv_nc_sniffed_purge() - Checks timestamp of given sniffed nc_packet.
582612d2b4fSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
583612d2b4fSMartin Hundebøll * @nc_path: the nc path the packet belongs to
584612d2b4fSMartin Hundebøll * @nc_packet: the nc packet to be checked
585612d2b4fSMartin Hundebøll *
586612d2b4fSMartin Hundebøll * Checks whether the given sniffed (overheard) nc_packet has hit its buffering
587612d2b4fSMartin Hundebøll * timeout. If so, the packet is no longer kept and the entry deleted from the
588612d2b4fSMartin Hundebøll * queue. Has to be called with the appropriate locks.
589612d2b4fSMartin Hundebøll *
59062fe710fSSven Eckelmann * Return: false as soon as the entry in the fifo queue has not been timed out
591612d2b4fSMartin Hundebøll * yet and true otherwise.
592612d2b4fSMartin Hundebøll */
batadv_nc_sniffed_purge(struct batadv_priv * bat_priv,struct batadv_nc_path * nc_path,struct batadv_nc_packet * nc_packet)593612d2b4fSMartin Hundebøll static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv,
594612d2b4fSMartin Hundebøll struct batadv_nc_path *nc_path,
595612d2b4fSMartin Hundebøll struct batadv_nc_packet *nc_packet)
596612d2b4fSMartin Hundebøll {
597612d2b4fSMartin Hundebøll unsigned long timeout = bat_priv->nc.max_buffer_time;
598612d2b4fSMartin Hundebøll bool res = false;
599612d2b4fSMartin Hundebøll
6002c72d655SSven Eckelmann lockdep_assert_held(&nc_path->packet_list_lock);
6012c72d655SSven Eckelmann
602612d2b4fSMartin Hundebøll /* Packets are added to tail, so the remaining packets did not time
603612d2b4fSMartin Hundebøll * out and we can stop processing the current queue
604612d2b4fSMartin Hundebøll */
605612d2b4fSMartin Hundebøll if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
606612d2b4fSMartin Hundebøll !batadv_has_timed_out(nc_packet->timestamp, timeout))
607612d2b4fSMartin Hundebøll goto out;
608612d2b4fSMartin Hundebøll
609612d2b4fSMartin Hundebøll /* purge nc packet */
610612d2b4fSMartin Hundebøll list_del(&nc_packet->list);
611bd687fe4SSven Eckelmann batadv_nc_packet_free(nc_packet, true);
612612d2b4fSMartin Hundebøll
613612d2b4fSMartin Hundebøll res = true;
614612d2b4fSMartin Hundebøll
615612d2b4fSMartin Hundebøll out:
616612d2b4fSMartin Hundebøll return res;
617612d2b4fSMartin Hundebøll }
618612d2b4fSMartin Hundebøll
619612d2b4fSMartin Hundebøll /**
6207e9a8c2cSSven Eckelmann * batadv_nc_fwd_flush() - Checks the timestamp of the given nc packet.
62195332477SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
62295332477SMartin Hundebøll * @nc_path: the nc path the packet belongs to
62395332477SMartin Hundebøll * @nc_packet: the nc packet to be checked
62495332477SMartin Hundebøll *
62595332477SMartin Hundebøll * Checks whether the given nc packet has hit its forward timeout. If so, the
62695332477SMartin Hundebøll * packet is no longer delayed, immediately sent and the entry deleted from the
62795332477SMartin Hundebøll * queue. Has to be called with the appropriate locks.
62895332477SMartin Hundebøll *
62962fe710fSSven Eckelmann * Return: false as soon as the entry in the fifo queue has not been timed out
63095332477SMartin Hundebøll * yet and true otherwise.
63195332477SMartin Hundebøll */
batadv_nc_fwd_flush(struct batadv_priv * bat_priv,struct batadv_nc_path * nc_path,struct batadv_nc_packet * nc_packet)63295332477SMartin Hundebøll static bool batadv_nc_fwd_flush(struct batadv_priv *bat_priv,
63395332477SMartin Hundebøll struct batadv_nc_path *nc_path,
63495332477SMartin Hundebøll struct batadv_nc_packet *nc_packet)
63595332477SMartin Hundebøll {
63695332477SMartin Hundebøll unsigned long timeout = bat_priv->nc.max_fwd_delay;
63795332477SMartin Hundebøll
6382c72d655SSven Eckelmann lockdep_assert_held(&nc_path->packet_list_lock);
6392c72d655SSven Eckelmann
64095332477SMartin Hundebøll /* Packets are added to tail, so the remaining packets did not time
64195332477SMartin Hundebøll * out and we can stop processing the current queue
64295332477SMartin Hundebøll */
64395332477SMartin Hundebøll if (atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE &&
64495332477SMartin Hundebøll !batadv_has_timed_out(nc_packet->timestamp, timeout))
64595332477SMartin Hundebøll return false;
64695332477SMartin Hundebøll
64795332477SMartin Hundebøll /* Send packet */
64895332477SMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_FORWARD);
64995332477SMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_FORWARD_BYTES,
65095332477SMartin Hundebøll nc_packet->skb->len + ETH_HLEN);
65195332477SMartin Hundebøll list_del(&nc_packet->list);
65295332477SMartin Hundebøll batadv_nc_send_packet(nc_packet);
65395332477SMartin Hundebøll
65495332477SMartin Hundebøll return true;
65595332477SMartin Hundebøll }
65695332477SMartin Hundebøll
65795332477SMartin Hundebøll /**
6587e9a8c2cSSven Eckelmann * batadv_nc_process_nc_paths() - traverse given nc packet pool and free timed
6597e9a8c2cSSven Eckelmann * out nc packets
66095332477SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
66195332477SMartin Hundebøll * @hash: to be processed hash table
66295332477SMartin Hundebøll * @process_fn: Function called to process given nc packet. Should return true
66395332477SMartin Hundebøll * to encourage this function to proceed with the next packet.
66495332477SMartin Hundebøll * Otherwise the rest of the current queue is skipped.
66595332477SMartin Hundebøll */
66695332477SMartin Hundebøll static void
batadv_nc_process_nc_paths(struct batadv_priv * bat_priv,struct batadv_hashtable * hash,bool (* process_fn)(struct batadv_priv *,struct batadv_nc_path *,struct batadv_nc_packet *))66795332477SMartin Hundebøll batadv_nc_process_nc_paths(struct batadv_priv *bat_priv,
66895332477SMartin Hundebøll struct batadv_hashtable *hash,
66995332477SMartin Hundebøll bool (*process_fn)(struct batadv_priv *,
67095332477SMartin Hundebøll struct batadv_nc_path *,
67195332477SMartin Hundebøll struct batadv_nc_packet *))
67295332477SMartin Hundebøll {
67395332477SMartin Hundebøll struct hlist_head *head;
67495332477SMartin Hundebøll struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
67595332477SMartin Hundebøll struct batadv_nc_path *nc_path;
67695332477SMartin Hundebøll bool ret;
67795332477SMartin Hundebøll int i;
67895332477SMartin Hundebøll
67995332477SMartin Hundebøll if (!hash)
68095332477SMartin Hundebøll return;
68195332477SMartin Hundebøll
68295332477SMartin Hundebøll /* Loop hash table bins */
68395332477SMartin Hundebøll for (i = 0; i < hash->size; i++) {
68495332477SMartin Hundebøll head = &hash->table[i];
68595332477SMartin Hundebøll
68695332477SMartin Hundebøll /* Loop coding paths */
68795332477SMartin Hundebøll rcu_read_lock();
68895332477SMartin Hundebøll hlist_for_each_entry_rcu(nc_path, head, hash_entry) {
68995332477SMartin Hundebøll /* Loop packets */
69095332477SMartin Hundebøll spin_lock_bh(&nc_path->packet_list_lock);
69195332477SMartin Hundebøll list_for_each_entry_safe(nc_packet, nc_packet_tmp,
69295332477SMartin Hundebøll &nc_path->packet_list, list) {
69395332477SMartin Hundebøll ret = process_fn(bat_priv, nc_path, nc_packet);
69495332477SMartin Hundebøll if (!ret)
69595332477SMartin Hundebøll break;
69695332477SMartin Hundebøll }
69795332477SMartin Hundebøll spin_unlock_bh(&nc_path->packet_list_lock);
69895332477SMartin Hundebøll }
69995332477SMartin Hundebøll rcu_read_unlock();
70095332477SMartin Hundebøll }
70195332477SMartin Hundebøll }
70295332477SMartin Hundebøll
70395332477SMartin Hundebøll /**
7047e9a8c2cSSven Eckelmann * batadv_nc_worker() - periodic task for housekeeping related to network
7057e9a8c2cSSven Eckelmann * coding
706d353d8d4SMartin Hundebøll * @work: kernel work struct
707d353d8d4SMartin Hundebøll */
batadv_nc_worker(struct work_struct * work)708d353d8d4SMartin Hundebøll static void batadv_nc_worker(struct work_struct *work)
709d353d8d4SMartin Hundebøll {
710d353d8d4SMartin Hundebøll struct delayed_work *delayed_work;
711d353d8d4SMartin Hundebøll struct batadv_priv_nc *priv_nc;
712d353d8d4SMartin Hundebøll struct batadv_priv *bat_priv;
71395332477SMartin Hundebøll unsigned long timeout;
714d353d8d4SMartin Hundebøll
7154ba4bc0fSGeliang Tang delayed_work = to_delayed_work(work);
716d353d8d4SMartin Hundebøll priv_nc = container_of(delayed_work, struct batadv_priv_nc, work);
717d353d8d4SMartin Hundebøll bat_priv = container_of(priv_nc, struct batadv_priv, nc);
718d353d8d4SMartin Hundebøll
719d56b1705SMartin Hundebøll batadv_nc_purge_orig_hash(bat_priv);
72095332477SMartin Hundebøll batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash,
72195332477SMartin Hundebøll batadv_nc_to_purge_nc_path_coding);
722612d2b4fSMartin Hundebøll batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash,
723612d2b4fSMartin Hundebøll batadv_nc_to_purge_nc_path_decoding);
72495332477SMartin Hundebøll
72595332477SMartin Hundebøll timeout = bat_priv->nc.max_fwd_delay;
72695332477SMartin Hundebøll
72795332477SMartin Hundebøll if (batadv_has_timed_out(bat_priv->nc.timestamp_fwd_flush, timeout)) {
72895332477SMartin Hundebøll batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.coding_hash,
72995332477SMartin Hundebøll batadv_nc_fwd_flush);
73095332477SMartin Hundebøll bat_priv->nc.timestamp_fwd_flush = jiffies;
73195332477SMartin Hundebøll }
732d56b1705SMartin Hundebøll
733612d2b4fSMartin Hundebøll if (batadv_has_timed_out(bat_priv->nc.timestamp_sniffed_purge,
734612d2b4fSMartin Hundebøll bat_priv->nc.max_buffer_time)) {
735612d2b4fSMartin Hundebøll batadv_nc_process_nc_paths(bat_priv, bat_priv->nc.decoding_hash,
736612d2b4fSMartin Hundebøll batadv_nc_sniffed_purge);
737612d2b4fSMartin Hundebøll bat_priv->nc.timestamp_sniffed_purge = jiffies;
738612d2b4fSMartin Hundebøll }
739612d2b4fSMartin Hundebøll
740d353d8d4SMartin Hundebøll /* Schedule a new check */
741d353d8d4SMartin Hundebøll batadv_nc_start_timer(bat_priv);
742d353d8d4SMartin Hundebøll }
743d353d8d4SMartin Hundebøll
744d353d8d4SMartin Hundebøll /**
7457e9a8c2cSSven Eckelmann * batadv_can_nc_with_orig() - checks whether the given orig node is suitable
7467e9a8c2cSSven Eckelmann * for coding or not
747d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
748d56b1705SMartin Hundebøll * @orig_node: neighboring orig node which may be used as nc candidate
749d56b1705SMartin Hundebøll * @ogm_packet: incoming ogm packet also used for the checks
750d56b1705SMartin Hundebøll *
75162fe710fSSven Eckelmann * Return: true if:
752d56b1705SMartin Hundebøll * 1) The OGM must have the most recent sequence number.
753d56b1705SMartin Hundebøll * 2) The TTL must be decremented by one and only one.
754d56b1705SMartin Hundebøll * 3) The OGM must be received from the first hop from orig_node.
755d56b1705SMartin Hundebøll * 4) The TQ value of the OGM must be above bat_priv->nc.min_tq.
756d56b1705SMartin Hundebøll */
batadv_can_nc_with_orig(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,struct batadv_ogm_packet * ogm_packet)757d56b1705SMartin Hundebøll static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
758d56b1705SMartin Hundebøll struct batadv_orig_node *orig_node,
759d56b1705SMartin Hundebøll struct batadv_ogm_packet *ogm_packet)
760d56b1705SMartin Hundebøll {
7617351a482SSimon Wunderlich struct batadv_orig_ifinfo *orig_ifinfo;
7626b5e971aSSven Eckelmann u32 last_real_seqno;
7636b5e971aSSven Eckelmann u8 last_ttl;
7647351a482SSimon Wunderlich
7657351a482SSimon Wunderlich orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT);
7667351a482SSimon Wunderlich if (!orig_ifinfo)
767d56b1705SMartin Hundebøll return false;
7687351a482SSimon Wunderlich
7697351a482SSimon Wunderlich last_ttl = orig_ifinfo->last_ttl;
7707351a482SSimon Wunderlich last_real_seqno = orig_ifinfo->last_real_seqno;
77135f94779SSven Eckelmann batadv_orig_ifinfo_put(orig_ifinfo);
7727351a482SSimon Wunderlich
7737351a482SSimon Wunderlich if (last_real_seqno != ntohl(ogm_packet->seqno))
7747351a482SSimon Wunderlich return false;
7757351a482SSimon Wunderlich if (last_ttl != ogm_packet->ttl + 1)
776d56b1705SMartin Hundebøll return false;
777d56b1705SMartin Hundebøll if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
778d56b1705SMartin Hundebøll return false;
779d56b1705SMartin Hundebøll if (ogm_packet->tq < bat_priv->nc.min_tq)
780d56b1705SMartin Hundebøll return false;
781d56b1705SMartin Hundebøll
782d56b1705SMartin Hundebøll return true;
783d56b1705SMartin Hundebøll }
784d56b1705SMartin Hundebøll
785d56b1705SMartin Hundebøll /**
7867e9a8c2cSSven Eckelmann * batadv_nc_find_nc_node() - search for an existing nc node and return it
787d56b1705SMartin Hundebøll * @orig_node: orig node originating the ogm packet
788d56b1705SMartin Hundebøll * @orig_neigh_node: neighboring orig node from which we received the ogm packet
789d56b1705SMartin Hundebøll * (can be equal to orig_node)
790d56b1705SMartin Hundebøll * @in_coding: traverse incoming or outgoing network coding list
791d56b1705SMartin Hundebøll *
79262fe710fSSven Eckelmann * Return: the nc_node if found, NULL otherwise.
793d56b1705SMartin Hundebøll */
7946fc77a54SSven Eckelmann static struct batadv_nc_node *
batadv_nc_find_nc_node(struct batadv_orig_node * orig_node,struct batadv_orig_node * orig_neigh_node,bool in_coding)7956fc77a54SSven Eckelmann batadv_nc_find_nc_node(struct batadv_orig_node *orig_node,
796d56b1705SMartin Hundebøll struct batadv_orig_node *orig_neigh_node,
797d56b1705SMartin Hundebøll bool in_coding)
798d56b1705SMartin Hundebøll {
799d56b1705SMartin Hundebøll struct batadv_nc_node *nc_node, *nc_node_out = NULL;
800d56b1705SMartin Hundebøll struct list_head *list;
801d56b1705SMartin Hundebøll
802d56b1705SMartin Hundebøll if (in_coding)
803d56b1705SMartin Hundebøll list = &orig_neigh_node->in_coding_list;
804d56b1705SMartin Hundebøll else
805d56b1705SMartin Hundebøll list = &orig_neigh_node->out_coding_list;
806d56b1705SMartin Hundebøll
807d56b1705SMartin Hundebøll /* Traverse list of nc_nodes to orig_node */
808d56b1705SMartin Hundebøll rcu_read_lock();
809d56b1705SMartin Hundebøll list_for_each_entry_rcu(nc_node, list, list) {
810d56b1705SMartin Hundebøll if (!batadv_compare_eth(nc_node->addr, orig_node->orig))
811d56b1705SMartin Hundebøll continue;
812d56b1705SMartin Hundebøll
813daf99b48SSven Eckelmann if (!kref_get_unless_zero(&nc_node->refcount))
814d56b1705SMartin Hundebøll continue;
815d56b1705SMartin Hundebøll
816d56b1705SMartin Hundebøll /* Found a match */
817d56b1705SMartin Hundebøll nc_node_out = nc_node;
818d56b1705SMartin Hundebøll break;
819d56b1705SMartin Hundebøll }
820d56b1705SMartin Hundebøll rcu_read_unlock();
821d56b1705SMartin Hundebøll
822d56b1705SMartin Hundebøll return nc_node_out;
823d56b1705SMartin Hundebøll }
824d56b1705SMartin Hundebøll
825d56b1705SMartin Hundebøll /**
8267e9a8c2cSSven Eckelmann * batadv_nc_get_nc_node() - retrieves an nc node or creates the entry if it was
827d56b1705SMartin Hundebøll * not found
828d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
829d56b1705SMartin Hundebøll * @orig_node: orig node originating the ogm packet
830d56b1705SMartin Hundebøll * @orig_neigh_node: neighboring orig node from which we received the ogm packet
831d56b1705SMartin Hundebøll * (can be equal to orig_node)
832d56b1705SMartin Hundebøll * @in_coding: traverse incoming or outgoing network coding list
833d56b1705SMartin Hundebøll *
83462fe710fSSven Eckelmann * Return: the nc_node if found or created, NULL in case of an error.
835d56b1705SMartin Hundebøll */
8366fc77a54SSven Eckelmann static struct batadv_nc_node *
batadv_nc_get_nc_node(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,struct batadv_orig_node * orig_neigh_node,bool in_coding)8376fc77a54SSven Eckelmann batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
838d56b1705SMartin Hundebøll struct batadv_orig_node *orig_node,
839d56b1705SMartin Hundebøll struct batadv_orig_node *orig_neigh_node,
840d56b1705SMartin Hundebøll bool in_coding)
841d56b1705SMartin Hundebøll {
842d56b1705SMartin Hundebøll struct batadv_nc_node *nc_node;
843d56b1705SMartin Hundebøll spinlock_t *lock; /* Used to lock list selected by "int in_coding" */
844d56b1705SMartin Hundebøll struct list_head *list;
845d56b1705SMartin Hundebøll
846d56b1705SMartin Hundebøll /* Select ingoing or outgoing coding node */
847d56b1705SMartin Hundebøll if (in_coding) {
848d56b1705SMartin Hundebøll lock = &orig_neigh_node->in_coding_list_lock;
849d56b1705SMartin Hundebøll list = &orig_neigh_node->in_coding_list;
850d56b1705SMartin Hundebøll } else {
851d56b1705SMartin Hundebøll lock = &orig_neigh_node->out_coding_list_lock;
852d56b1705SMartin Hundebøll list = &orig_neigh_node->out_coding_list;
853d56b1705SMartin Hundebøll }
854d56b1705SMartin Hundebøll
855fa122fecSSven Eckelmann spin_lock_bh(lock);
856fa122fecSSven Eckelmann
857fa122fecSSven Eckelmann /* Check if nc_node is already added */
858fa122fecSSven Eckelmann nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding);
859fa122fecSSven Eckelmann
860fa122fecSSven Eckelmann /* Node found */
861fa122fecSSven Eckelmann if (nc_node)
862fa122fecSSven Eckelmann goto unlock;
863fa122fecSSven Eckelmann
864fa122fecSSven Eckelmann nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC);
865fa122fecSSven Eckelmann if (!nc_node)
866fa122fecSSven Eckelmann goto unlock;
867fa122fecSSven Eckelmann
868fa122fecSSven Eckelmann /* Initialize nc_node */
869fa122fecSSven Eckelmann INIT_LIST_HEAD(&nc_node->list);
870fa122fecSSven Eckelmann kref_init(&nc_node->refcount);
871fa122fecSSven Eckelmann ether_addr_copy(nc_node->addr, orig_node->orig);
872fa122fecSSven Eckelmann kref_get(&orig_neigh_node->refcount);
873fa122fecSSven Eckelmann nc_node->orig_node = orig_neigh_node;
874fa122fecSSven Eckelmann
875d56b1705SMartin Hundebøll batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n",
876d56b1705SMartin Hundebøll nc_node->addr, nc_node->orig_node->orig);
877d56b1705SMartin Hundebøll
878d56b1705SMartin Hundebøll /* Add nc_node to orig_node */
879da7a26afSSven Eckelmann kref_get(&nc_node->refcount);
880d56b1705SMartin Hundebøll list_add_tail_rcu(&nc_node->list, list);
881fa122fecSSven Eckelmann
882fa122fecSSven Eckelmann unlock:
883d56b1705SMartin Hundebøll spin_unlock_bh(lock);
884d56b1705SMartin Hundebøll
885d56b1705SMartin Hundebøll return nc_node;
886d56b1705SMartin Hundebøll }
887d56b1705SMartin Hundebøll
888d56b1705SMartin Hundebøll /**
8897e9a8c2cSSven Eckelmann * batadv_nc_update_nc_node() - updates stored incoming and outgoing nc node
89034473822SSven Eckelmann * structs (best called on incoming OGMs)
891d56b1705SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
892d56b1705SMartin Hundebøll * @orig_node: orig node originating the ogm packet
893d56b1705SMartin Hundebøll * @orig_neigh_node: neighboring orig node from which we received the ogm packet
894d56b1705SMartin Hundebøll * (can be equal to orig_node)
895d56b1705SMartin Hundebøll * @ogm_packet: incoming ogm packet
896d56b1705SMartin Hundebøll * @is_single_hop_neigh: orig_node is a single hop neighbor
897d56b1705SMartin Hundebøll */
batadv_nc_update_nc_node(struct batadv_priv * bat_priv,struct batadv_orig_node * orig_node,struct batadv_orig_node * orig_neigh_node,struct batadv_ogm_packet * ogm_packet,int is_single_hop_neigh)898d56b1705SMartin Hundebøll void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
899d56b1705SMartin Hundebøll struct batadv_orig_node *orig_node,
900d56b1705SMartin Hundebøll struct batadv_orig_node *orig_neigh_node,
901d56b1705SMartin Hundebøll struct batadv_ogm_packet *ogm_packet,
902d56b1705SMartin Hundebøll int is_single_hop_neigh)
903d56b1705SMartin Hundebøll {
9044f248cffSSven Eckelmann struct batadv_nc_node *in_nc_node = NULL;
9054f248cffSSven Eckelmann struct batadv_nc_node *out_nc_node = NULL;
906d56b1705SMartin Hundebøll
907d56b1705SMartin Hundebøll /* Check if network coding is enabled */
908d56b1705SMartin Hundebøll if (!atomic_read(&bat_priv->network_coding))
909d56b1705SMartin Hundebøll goto out;
910d56b1705SMartin Hundebøll
9113f4841ffSMarek Lindner /* check if orig node is network coding enabled */
9124635469fSLinus Lüssing if (!test_bit(BATADV_ORIG_CAPA_HAS_NC, &orig_node->capabilities))
9133f4841ffSMarek Lindner goto out;
9143f4841ffSMarek Lindner
915d56b1705SMartin Hundebøll /* accept ogms from 'good' neighbors and single hop neighbors */
916d56b1705SMartin Hundebøll if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) &&
917d56b1705SMartin Hundebøll !is_single_hop_neigh)
918d56b1705SMartin Hundebøll goto out;
919d56b1705SMartin Hundebøll
920d56b1705SMartin Hundebøll /* Add orig_node as in_nc_node on hop */
921d56b1705SMartin Hundebøll in_nc_node = batadv_nc_get_nc_node(bat_priv, orig_node,
922d56b1705SMartin Hundebøll orig_neigh_node, true);
923d56b1705SMartin Hundebøll if (!in_nc_node)
924d56b1705SMartin Hundebøll goto out;
925d56b1705SMartin Hundebøll
926d56b1705SMartin Hundebøll in_nc_node->last_seen = jiffies;
927d56b1705SMartin Hundebøll
928d56b1705SMartin Hundebøll /* Add hop as out_nc_node on orig_node */
929d56b1705SMartin Hundebøll out_nc_node = batadv_nc_get_nc_node(bat_priv, orig_neigh_node,
930d56b1705SMartin Hundebøll orig_node, false);
931d56b1705SMartin Hundebøll if (!out_nc_node)
932d56b1705SMartin Hundebøll goto out;
933d56b1705SMartin Hundebøll
934d56b1705SMartin Hundebøll out_nc_node->last_seen = jiffies;
935d56b1705SMartin Hundebøll
936d56b1705SMartin Hundebøll out:
93727ad7545SSven Eckelmann batadv_nc_node_put(in_nc_node);
93827ad7545SSven Eckelmann batadv_nc_node_put(out_nc_node);
939d56b1705SMartin Hundebøll }
940d56b1705SMartin Hundebøll
941d56b1705SMartin Hundebøll /**
9427e9a8c2cSSven Eckelmann * batadv_nc_get_path() - get existing nc_path or allocate a new one
94395332477SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
94495332477SMartin Hundebøll * @hash: hash table containing the nc path
94595332477SMartin Hundebøll * @src: ethernet source address - first half of the nc path search key
94695332477SMartin Hundebøll * @dst: ethernet destination address - second half of the nc path search key
94795332477SMartin Hundebøll *
94862fe710fSSven Eckelmann * Return: pointer to nc_path if the path was found or created, returns NULL
94995332477SMartin Hundebøll * on error.
95095332477SMartin Hundebøll */
batadv_nc_get_path(struct batadv_priv * bat_priv,struct batadv_hashtable * hash,u8 * src,u8 * dst)95195332477SMartin Hundebøll static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv,
95295332477SMartin Hundebøll struct batadv_hashtable *hash,
9536b5e971aSSven Eckelmann u8 *src,
9546b5e971aSSven Eckelmann u8 *dst)
95595332477SMartin Hundebøll {
95695332477SMartin Hundebøll int hash_added;
95795332477SMartin Hundebøll struct batadv_nc_path *nc_path, nc_path_key;
95895332477SMartin Hundebøll
95995332477SMartin Hundebøll batadv_nc_hash_key_gen(&nc_path_key, src, dst);
96095332477SMartin Hundebøll
96195332477SMartin Hundebøll /* Search for existing nc_path */
96295332477SMartin Hundebøll nc_path = batadv_nc_hash_find(hash, (void *)&nc_path_key);
96395332477SMartin Hundebøll
96495332477SMartin Hundebøll if (nc_path) {
96595332477SMartin Hundebøll /* Set timestamp to delay removal of nc_path */
96695332477SMartin Hundebøll nc_path->last_valid = jiffies;
96795332477SMartin Hundebøll return nc_path;
96895332477SMartin Hundebøll }
96995332477SMartin Hundebøll
97095332477SMartin Hundebøll /* No existing nc_path was found; create a new */
97195332477SMartin Hundebøll nc_path = kzalloc(sizeof(*nc_path), GFP_ATOMIC);
97295332477SMartin Hundebøll
97395332477SMartin Hundebøll if (!nc_path)
97495332477SMartin Hundebøll return NULL;
97595332477SMartin Hundebøll
97695332477SMartin Hundebøll /* Initialize nc_path */
97795332477SMartin Hundebøll INIT_LIST_HEAD(&nc_path->packet_list);
97895332477SMartin Hundebøll spin_lock_init(&nc_path->packet_list_lock);
979727e0cd5SSven Eckelmann kref_init(&nc_path->refcount);
98095332477SMartin Hundebøll nc_path->last_valid = jiffies;
9818fdd0153SAntonio Quartulli ether_addr_copy(nc_path->next_hop, dst);
9828fdd0153SAntonio Quartulli ether_addr_copy(nc_path->prev_hop, src);
98395332477SMartin Hundebøll
98495332477SMartin Hundebøll batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_path %pM -> %pM\n",
98595332477SMartin Hundebøll nc_path->prev_hop,
98695332477SMartin Hundebøll nc_path->next_hop);
98795332477SMartin Hundebøll
98895332477SMartin Hundebøll /* Add nc_path to hash table */
989f489eab5SSven Eckelmann kref_get(&nc_path->refcount);
99095332477SMartin Hundebøll hash_added = batadv_hash_add(hash, batadv_nc_hash_compare,
99195332477SMartin Hundebøll batadv_nc_hash_choose, &nc_path_key,
99295332477SMartin Hundebøll &nc_path->hash_entry);
99395332477SMartin Hundebøll
99495332477SMartin Hundebøll if (hash_added < 0) {
99595332477SMartin Hundebøll kfree(nc_path);
99695332477SMartin Hundebøll return NULL;
99795332477SMartin Hundebøll }
99895332477SMartin Hundebøll
99995332477SMartin Hundebøll return nc_path;
100095332477SMartin Hundebøll }
100195332477SMartin Hundebøll
100295332477SMartin Hundebøll /**
10037e9a8c2cSSven Eckelmann * batadv_nc_random_weight_tq() - scale the receivers TQ-value to avoid unfair
10043c12de9aSMartin Hundebøll * selection of a receiver with slightly lower TQ than the other
10053c12de9aSMartin Hundebøll * @tq: to be weighted tq value
1006672e7978SSven Eckelmann *
1007672e7978SSven Eckelmann * Return: scaled tq value
10083c12de9aSMartin Hundebøll */
batadv_nc_random_weight_tq(u8 tq)10096b5e971aSSven Eckelmann static u8 batadv_nc_random_weight_tq(u8 tq)
10103c12de9aSMartin Hundebøll {
10113c12de9aSMartin Hundebøll /* randomize the estimated packet loss (max TQ - estimated TQ) */
10128032bf12SJason A. Donenfeld u8 rand_tq = get_random_u32_below(BATADV_TQ_MAX_VALUE + 1 - tq);
10133c12de9aSMartin Hundebøll
10143c12de9aSMartin Hundebøll /* convert to (randomized) estimated tq again */
10153c12de9aSMartin Hundebøll return BATADV_TQ_MAX_VALUE - rand_tq;
10163c12de9aSMartin Hundebøll }
10173c12de9aSMartin Hundebøll
10183c12de9aSMartin Hundebøll /**
10197e9a8c2cSSven Eckelmann * batadv_nc_memxor() - XOR destination with source
10203c12de9aSMartin Hundebøll * @dst: byte array to XOR into
10213c12de9aSMartin Hundebøll * @src: byte array to XOR from
10223c12de9aSMartin Hundebøll * @len: length of destination array
10233c12de9aSMartin Hundebøll */
batadv_nc_memxor(char * dst,const char * src,unsigned int len)10243c12de9aSMartin Hundebøll static void batadv_nc_memxor(char *dst, const char *src, unsigned int len)
10253c12de9aSMartin Hundebøll {
10263c12de9aSMartin Hundebøll unsigned int i;
10273c12de9aSMartin Hundebøll
10283c12de9aSMartin Hundebøll for (i = 0; i < len; ++i)
10293c12de9aSMartin Hundebøll dst[i] ^= src[i];
10303c12de9aSMartin Hundebøll }
10313c12de9aSMartin Hundebøll
10323c12de9aSMartin Hundebøll /**
10337e9a8c2cSSven Eckelmann * batadv_nc_code_packets() - code a received unicast_packet with an nc packet
10343c12de9aSMartin Hundebøll * into a coded_packet and send it
10353c12de9aSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
10363c12de9aSMartin Hundebøll * @skb: data skb to forward
10373c12de9aSMartin Hundebøll * @ethhdr: pointer to the ethernet header inside the skb
10383c12de9aSMartin Hundebøll * @nc_packet: structure containing the packet to the skb can be coded with
10393c12de9aSMartin Hundebøll * @neigh_node: next hop to forward packet to
10403c12de9aSMartin Hundebøll *
104162fe710fSSven Eckelmann * Return: true if both packets are consumed, false otherwise.
10423c12de9aSMartin Hundebøll */
batadv_nc_code_packets(struct batadv_priv * bat_priv,struct sk_buff * skb,struct ethhdr * ethhdr,struct batadv_nc_packet * nc_packet,struct batadv_neigh_node * neigh_node)10433c12de9aSMartin Hundebøll static bool batadv_nc_code_packets(struct batadv_priv *bat_priv,
10443c12de9aSMartin Hundebøll struct sk_buff *skb,
10453c12de9aSMartin Hundebøll struct ethhdr *ethhdr,
10463c12de9aSMartin Hundebøll struct batadv_nc_packet *nc_packet,
10473c12de9aSMartin Hundebøll struct batadv_neigh_node *neigh_node)
10483c12de9aSMartin Hundebøll {
10496b5e971aSSven Eckelmann u8 tq_weighted_neigh, tq_weighted_coding, tq_tmp;
10503c12de9aSMartin Hundebøll struct sk_buff *skb_dest, *skb_src;
10513c12de9aSMartin Hundebøll struct batadv_unicast_packet *packet1;
10523c12de9aSMartin Hundebøll struct batadv_unicast_packet *packet2;
10533c12de9aSMartin Hundebøll struct batadv_coded_packet *coded_packet;
105495d39278SAntonio Quartulli struct batadv_neigh_node *neigh_tmp, *router_neigh, *first_dest;
105595d39278SAntonio Quartulli struct batadv_neigh_node *router_coding = NULL, *second_dest;
105689652331SSimon Wunderlich struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL;
105789652331SSimon Wunderlich struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL;
105895d39278SAntonio Quartulli u8 *first_source, *second_source;
10593c12de9aSMartin Hundebøll __be32 packet_id1, packet_id2;
10603c12de9aSMartin Hundebøll size_t count;
10613c12de9aSMartin Hundebøll bool res = false;
10623c12de9aSMartin Hundebøll int coding_len;
10633c12de9aSMartin Hundebøll int unicast_size = sizeof(*packet1);
10643c12de9aSMartin Hundebøll int coded_size = sizeof(*coded_packet);
10653c12de9aSMartin Hundebøll int header_add = coded_size - unicast_size;
10663c12de9aSMartin Hundebøll
10677351a482SSimon Wunderlich /* TODO: do we need to consider the outgoing interface for
10687351a482SSimon Wunderlich * coded packets?
10697351a482SSimon Wunderlich */
10707351a482SSimon Wunderlich router_neigh = batadv_orig_router_get(neigh_node->orig_node,
10717351a482SSimon Wunderlich BATADV_IF_DEFAULT);
10723c12de9aSMartin Hundebøll if (!router_neigh)
10733c12de9aSMartin Hundebøll goto out;
10743c12de9aSMartin Hundebøll
107589652331SSimon Wunderlich router_neigh_ifinfo = batadv_neigh_ifinfo_get(router_neigh,
107689652331SSimon Wunderlich BATADV_IF_DEFAULT);
107789652331SSimon Wunderlich if (!router_neigh_ifinfo)
107889652331SSimon Wunderlich goto out;
107989652331SSimon Wunderlich
10803c12de9aSMartin Hundebøll neigh_tmp = nc_packet->neigh_node;
10817351a482SSimon Wunderlich router_coding = batadv_orig_router_get(neigh_tmp->orig_node,
10827351a482SSimon Wunderlich BATADV_IF_DEFAULT);
10833c12de9aSMartin Hundebøll if (!router_coding)
10843c12de9aSMartin Hundebøll goto out;
10853c12de9aSMartin Hundebøll
108689652331SSimon Wunderlich router_coding_ifinfo = batadv_neigh_ifinfo_get(router_coding,
108789652331SSimon Wunderlich BATADV_IF_DEFAULT);
108889652331SSimon Wunderlich if (!router_coding_ifinfo)
108989652331SSimon Wunderlich goto out;
109089652331SSimon Wunderlich
109189652331SSimon Wunderlich tq_tmp = router_neigh_ifinfo->bat_iv.tq_avg;
109289652331SSimon Wunderlich tq_weighted_neigh = batadv_nc_random_weight_tq(tq_tmp);
109389652331SSimon Wunderlich tq_tmp = router_coding_ifinfo->bat_iv.tq_avg;
109489652331SSimon Wunderlich tq_weighted_coding = batadv_nc_random_weight_tq(tq_tmp);
10953c12de9aSMartin Hundebøll
10963c12de9aSMartin Hundebøll /* Select one destination for the MAC-header dst-field based on
10973c12de9aSMartin Hundebøll * weighted TQ-values.
10983c12de9aSMartin Hundebøll */
10993c12de9aSMartin Hundebøll if (tq_weighted_neigh >= tq_weighted_coding) {
11003c12de9aSMartin Hundebøll /* Destination from nc_packet is selected for MAC-header */
110195d39278SAntonio Quartulli first_dest = nc_packet->neigh_node;
11023c12de9aSMartin Hundebøll first_source = nc_packet->nc_path->prev_hop;
110395d39278SAntonio Quartulli second_dest = neigh_node;
11043c12de9aSMartin Hundebøll second_source = ethhdr->h_source;
11053c12de9aSMartin Hundebøll packet1 = (struct batadv_unicast_packet *)nc_packet->skb->data;
11063c12de9aSMartin Hundebøll packet2 = (struct batadv_unicast_packet *)skb->data;
11073c12de9aSMartin Hundebøll packet_id1 = nc_packet->packet_id;
11083c12de9aSMartin Hundebøll packet_id2 = batadv_skb_crc32(skb,
11093c12de9aSMartin Hundebøll skb->data + sizeof(*packet2));
11103c12de9aSMartin Hundebøll } else {
11113c12de9aSMartin Hundebøll /* Destination for skb is selected for MAC-header */
111295d39278SAntonio Quartulli first_dest = neigh_node;
11133c12de9aSMartin Hundebøll first_source = ethhdr->h_source;
111495d39278SAntonio Quartulli second_dest = nc_packet->neigh_node;
11153c12de9aSMartin Hundebøll second_source = nc_packet->nc_path->prev_hop;
11163c12de9aSMartin Hundebøll packet1 = (struct batadv_unicast_packet *)skb->data;
11173c12de9aSMartin Hundebøll packet2 = (struct batadv_unicast_packet *)nc_packet->skb->data;
11183c12de9aSMartin Hundebøll packet_id1 = batadv_skb_crc32(skb,
11193c12de9aSMartin Hundebøll skb->data + sizeof(*packet1));
11203c12de9aSMartin Hundebøll packet_id2 = nc_packet->packet_id;
11213c12de9aSMartin Hundebøll }
11223c12de9aSMartin Hundebøll
11233c12de9aSMartin Hundebøll /* Instead of zero padding the smallest data buffer, we
11243c12de9aSMartin Hundebøll * code into the largest.
11253c12de9aSMartin Hundebøll */
11263c12de9aSMartin Hundebøll if (skb->len <= nc_packet->skb->len) {
11273c12de9aSMartin Hundebøll skb_dest = nc_packet->skb;
11283c12de9aSMartin Hundebøll skb_src = skb;
11293c12de9aSMartin Hundebøll } else {
11303c12de9aSMartin Hundebøll skb_dest = skb;
11313c12de9aSMartin Hundebøll skb_src = nc_packet->skb;
11323c12de9aSMartin Hundebøll }
11333c12de9aSMartin Hundebøll
11343c12de9aSMartin Hundebøll /* coding_len is used when decoding the packet shorter packet */
11353c12de9aSMartin Hundebøll coding_len = skb_src->len - unicast_size;
11363c12de9aSMartin Hundebøll
11373c12de9aSMartin Hundebøll if (skb_linearize(skb_dest) < 0 || skb_linearize(skb_src) < 0)
11383c12de9aSMartin Hundebøll goto out;
11393c12de9aSMartin Hundebøll
11403c12de9aSMartin Hundebøll skb_push(skb_dest, header_add);
11413c12de9aSMartin Hundebøll
11423c12de9aSMartin Hundebøll coded_packet = (struct batadv_coded_packet *)skb_dest->data;
11433c12de9aSMartin Hundebøll skb_reset_mac_header(skb_dest);
11443c12de9aSMartin Hundebøll
1145a40d9b07SSimon Wunderlich coded_packet->packet_type = BATADV_CODED;
1146a40d9b07SSimon Wunderlich coded_packet->version = BATADV_COMPAT_VERSION;
1147a40d9b07SSimon Wunderlich coded_packet->ttl = packet1->ttl;
11483c12de9aSMartin Hundebøll
11493c12de9aSMartin Hundebøll /* Info about first unicast packet */
11508fdd0153SAntonio Quartulli ether_addr_copy(coded_packet->first_source, first_source);
11518fdd0153SAntonio Quartulli ether_addr_copy(coded_packet->first_orig_dest, packet1->dest);
11523c12de9aSMartin Hundebøll coded_packet->first_crc = packet_id1;
11533c12de9aSMartin Hundebøll coded_packet->first_ttvn = packet1->ttvn;
11543c12de9aSMartin Hundebøll
11553c12de9aSMartin Hundebøll /* Info about second unicast packet */
115695d39278SAntonio Quartulli ether_addr_copy(coded_packet->second_dest, second_dest->addr);
11578fdd0153SAntonio Quartulli ether_addr_copy(coded_packet->second_source, second_source);
11588fdd0153SAntonio Quartulli ether_addr_copy(coded_packet->second_orig_dest, packet2->dest);
11593c12de9aSMartin Hundebøll coded_packet->second_crc = packet_id2;
1160a40d9b07SSimon Wunderlich coded_packet->second_ttl = packet2->ttl;
11613c12de9aSMartin Hundebøll coded_packet->second_ttvn = packet2->ttvn;
11623c12de9aSMartin Hundebøll coded_packet->coded_len = htons(coding_len);
11633c12de9aSMartin Hundebøll
11643c12de9aSMartin Hundebøll /* This is where the magic happens: Code skb_src into skb_dest */
11653c12de9aSMartin Hundebøll batadv_nc_memxor(skb_dest->data + coded_size,
11663c12de9aSMartin Hundebøll skb_src->data + unicast_size, coding_len);
11673c12de9aSMartin Hundebøll
11683c12de9aSMartin Hundebøll /* Update counters accordingly */
11693c12de9aSMartin Hundebøll if (BATADV_SKB_CB(skb_src)->decoded &&
11703c12de9aSMartin Hundebøll BATADV_SKB_CB(skb_dest)->decoded) {
11713c12de9aSMartin Hundebøll /* Both packets are recoded */
11723c12de9aSMartin Hundebøll count = skb_src->len + ETH_HLEN;
11733c12de9aSMartin Hundebøll count += skb_dest->len + ETH_HLEN;
11743c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE, 2);
11753c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES, count);
11763c12de9aSMartin Hundebøll } else if (!BATADV_SKB_CB(skb_src)->decoded &&
11773c12de9aSMartin Hundebøll !BATADV_SKB_CB(skb_dest)->decoded) {
11783c12de9aSMartin Hundebøll /* Both packets are newly coded */
11793c12de9aSMartin Hundebøll count = skb_src->len + ETH_HLEN;
11803c12de9aSMartin Hundebøll count += skb_dest->len + ETH_HLEN;
11813c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE, 2);
11823c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES, count);
11833c12de9aSMartin Hundebøll } else if (BATADV_SKB_CB(skb_src)->decoded &&
11843c12de9aSMartin Hundebøll !BATADV_SKB_CB(skb_dest)->decoded) {
11853c12de9aSMartin Hundebøll /* skb_src recoded and skb_dest is newly coded */
11863c12de9aSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
11873c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
11883c12de9aSMartin Hundebøll skb_src->len + ETH_HLEN);
11893c12de9aSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
11903c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
11913c12de9aSMartin Hundebøll skb_dest->len + ETH_HLEN);
11923c12de9aSMartin Hundebøll } else if (!BATADV_SKB_CB(skb_src)->decoded &&
11933c12de9aSMartin Hundebøll BATADV_SKB_CB(skb_dest)->decoded) {
11943c12de9aSMartin Hundebøll /* skb_src is newly coded and skb_dest is recoded */
11953c12de9aSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_CODE);
11963c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_CODE_BYTES,
11973c12de9aSMartin Hundebøll skb_src->len + ETH_HLEN);
11983c12de9aSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_RECODE);
11993c12de9aSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_RECODE_BYTES,
12003c12de9aSMartin Hundebøll skb_dest->len + ETH_HLEN);
12013c12de9aSMartin Hundebøll }
12023c12de9aSMartin Hundebøll
12033c12de9aSMartin Hundebøll /* skb_src is now coded into skb_dest, so free it */
1204bd687fe4SSven Eckelmann consume_skb(skb_src);
12053c12de9aSMartin Hundebøll
12063c12de9aSMartin Hundebøll /* avoid duplicate free of skb from nc_packet */
12073c12de9aSMartin Hundebøll nc_packet->skb = NULL;
1208bd687fe4SSven Eckelmann batadv_nc_packet_free(nc_packet, false);
12093c12de9aSMartin Hundebøll
12103c12de9aSMartin Hundebøll /* Send the coded packet and return true */
121195d39278SAntonio Quartulli batadv_send_unicast_skb(skb_dest, first_dest);
12123c12de9aSMartin Hundebøll res = true;
12133c12de9aSMartin Hundebøll out:
121425bb2509SSven Eckelmann batadv_neigh_node_put(router_neigh);
121525bb2509SSven Eckelmann batadv_neigh_node_put(router_coding);
1216044fa3aeSSven Eckelmann batadv_neigh_ifinfo_put(router_neigh_ifinfo);
1217044fa3aeSSven Eckelmann batadv_neigh_ifinfo_put(router_coding_ifinfo);
12183c12de9aSMartin Hundebøll return res;
12193c12de9aSMartin Hundebøll }
12203c12de9aSMartin Hundebøll
12213c12de9aSMartin Hundebøll /**
12227e9a8c2cSSven Eckelmann * batadv_nc_skb_coding_possible() - true if a decoded skb is available at dst.
12233c12de9aSMartin Hundebøll * @skb: data skb to forward
12243c12de9aSMartin Hundebøll * @dst: destination mac address of the other skb to code with
12253c12de9aSMartin Hundebøll * @src: source mac address of skb
12263c12de9aSMartin Hundebøll *
12273c12de9aSMartin Hundebøll * Whenever we network code a packet we have to check whether we received it in
12283c12de9aSMartin Hundebøll * a network coded form. If so, we may not be able to use it for coding because
12293c12de9aSMartin Hundebøll * some neighbors may also have received (overheard) the packet in the network
12303c12de9aSMartin Hundebøll * coded form without being able to decode it. It is hard to know which of the
12313c12de9aSMartin Hundebøll * neighboring nodes was able to decode the packet, therefore we can only
12323c12de9aSMartin Hundebøll * re-code the packet if the source of the previous encoded packet is involved.
12333c12de9aSMartin Hundebøll * Since the source encoded the packet we can be certain it has all necessary
12343c12de9aSMartin Hundebøll * decode information.
12353c12de9aSMartin Hundebøll *
123662fe710fSSven Eckelmann * Return: true if coding of a decoded packet is allowed.
12373c12de9aSMartin Hundebøll */
batadv_nc_skb_coding_possible(struct sk_buff * skb,u8 * dst,u8 * src)12386b5e971aSSven Eckelmann static bool batadv_nc_skb_coding_possible(struct sk_buff *skb, u8 *dst, u8 *src)
12393c12de9aSMartin Hundebøll {
12403c12de9aSMartin Hundebøll if (BATADV_SKB_CB(skb)->decoded && !batadv_compare_eth(dst, src))
12413c12de9aSMartin Hundebøll return false;
12423c12de9aSMartin Hundebøll return true;
12433c12de9aSMartin Hundebøll }
12443c12de9aSMartin Hundebøll
12453c12de9aSMartin Hundebøll /**
12467e9a8c2cSSven Eckelmann * batadv_nc_path_search() - Find the coding path matching in_nc_node and
12473c12de9aSMartin Hundebøll * out_nc_node to retrieve a buffered packet that can be used for coding.
12483c12de9aSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
12493c12de9aSMartin Hundebøll * @in_nc_node: pointer to skb next hop's neighbor nc node
12503c12de9aSMartin Hundebøll * @out_nc_node: pointer to skb source's neighbor nc node
12513c12de9aSMartin Hundebøll * @skb: data skb to forward
12523c12de9aSMartin Hundebøll * @eth_dst: next hop mac address of skb
12533c12de9aSMartin Hundebøll *
125462fe710fSSven Eckelmann * Return: true if coding of a decoded skb is allowed.
12553c12de9aSMartin Hundebøll */
12563c12de9aSMartin Hundebøll static struct batadv_nc_packet *
batadv_nc_path_search(struct batadv_priv * bat_priv,struct batadv_nc_node * in_nc_node,struct batadv_nc_node * out_nc_node,struct sk_buff * skb,u8 * eth_dst)12573c12de9aSMartin Hundebøll batadv_nc_path_search(struct batadv_priv *bat_priv,
12583c12de9aSMartin Hundebøll struct batadv_nc_node *in_nc_node,
12593c12de9aSMartin Hundebøll struct batadv_nc_node *out_nc_node,
12603c12de9aSMartin Hundebøll struct sk_buff *skb,
12616b5e971aSSven Eckelmann u8 *eth_dst)
12623c12de9aSMartin Hundebøll {
12633c12de9aSMartin Hundebøll struct batadv_nc_path *nc_path, nc_path_key;
12643c12de9aSMartin Hundebøll struct batadv_nc_packet *nc_packet_out = NULL;
12653c12de9aSMartin Hundebøll struct batadv_nc_packet *nc_packet, *nc_packet_tmp;
12663c12de9aSMartin Hundebøll struct batadv_hashtable *hash = bat_priv->nc.coding_hash;
12673c12de9aSMartin Hundebøll int idx;
12683c12de9aSMartin Hundebøll
12693c12de9aSMartin Hundebøll if (!hash)
12703c12de9aSMartin Hundebøll return NULL;
12713c12de9aSMartin Hundebøll
12723c12de9aSMartin Hundebøll /* Create almost path key */
12733c12de9aSMartin Hundebøll batadv_nc_hash_key_gen(&nc_path_key, in_nc_node->addr,
12743c12de9aSMartin Hundebøll out_nc_node->addr);
12753c12de9aSMartin Hundebøll idx = batadv_nc_hash_choose(&nc_path_key, hash->size);
12763c12de9aSMartin Hundebøll
12773c12de9aSMartin Hundebøll /* Check for coding opportunities in this nc_path */
12783c12de9aSMartin Hundebøll rcu_read_lock();
12793c12de9aSMartin Hundebøll hlist_for_each_entry_rcu(nc_path, &hash->table[idx], hash_entry) {
12803c12de9aSMartin Hundebøll if (!batadv_compare_eth(nc_path->prev_hop, in_nc_node->addr))
12813c12de9aSMartin Hundebøll continue;
12823c12de9aSMartin Hundebøll
12833c12de9aSMartin Hundebøll if (!batadv_compare_eth(nc_path->next_hop, out_nc_node->addr))
12843c12de9aSMartin Hundebøll continue;
12853c12de9aSMartin Hundebøll
12863c12de9aSMartin Hundebøll spin_lock_bh(&nc_path->packet_list_lock);
12873c12de9aSMartin Hundebøll if (list_empty(&nc_path->packet_list)) {
12883c12de9aSMartin Hundebøll spin_unlock_bh(&nc_path->packet_list_lock);
12893c12de9aSMartin Hundebøll continue;
12903c12de9aSMartin Hundebøll }
12913c12de9aSMartin Hundebøll
12923c12de9aSMartin Hundebøll list_for_each_entry_safe(nc_packet, nc_packet_tmp,
12933c12de9aSMartin Hundebøll &nc_path->packet_list, list) {
12943c12de9aSMartin Hundebøll if (!batadv_nc_skb_coding_possible(nc_packet->skb,
12953c12de9aSMartin Hundebøll eth_dst,
12963c12de9aSMartin Hundebøll in_nc_node->addr))
12973c12de9aSMartin Hundebøll continue;
12983c12de9aSMartin Hundebøll
12993c12de9aSMartin Hundebøll /* Coding opportunity is found! */
13003c12de9aSMartin Hundebøll list_del(&nc_packet->list);
13013c12de9aSMartin Hundebøll nc_packet_out = nc_packet;
13023c12de9aSMartin Hundebøll break;
13033c12de9aSMartin Hundebøll }
13043c12de9aSMartin Hundebøll
13053c12de9aSMartin Hundebøll spin_unlock_bh(&nc_path->packet_list_lock);
13063c12de9aSMartin Hundebøll break;
13073c12de9aSMartin Hundebøll }
13083c12de9aSMartin Hundebøll rcu_read_unlock();
13093c12de9aSMartin Hundebøll
13103c12de9aSMartin Hundebøll return nc_packet_out;
13113c12de9aSMartin Hundebøll }
13123c12de9aSMartin Hundebøll
13133c12de9aSMartin Hundebøll /**
1314bccb48c8SSven Eckelmann * batadv_nc_skb_src_search() - Loops through the list of neighboring nodes of
13157e9a8c2cSSven Eckelmann * the skb's sender (may be equal to the originator).
13163c12de9aSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
13173c12de9aSMartin Hundebøll * @skb: data skb to forward
13183c12de9aSMartin Hundebøll * @eth_dst: next hop mac address of skb
13193c12de9aSMartin Hundebøll * @eth_src: source mac address of skb
13203c12de9aSMartin Hundebøll * @in_nc_node: pointer to skb next hop's neighbor nc node
13213c12de9aSMartin Hundebøll *
132262fe710fSSven Eckelmann * Return: an nc packet if a suitable coding packet was found, NULL otherwise.
13233c12de9aSMartin Hundebøll */
13243c12de9aSMartin Hundebøll static struct batadv_nc_packet *
batadv_nc_skb_src_search(struct batadv_priv * bat_priv,struct sk_buff * skb,u8 * eth_dst,u8 * eth_src,struct batadv_nc_node * in_nc_node)13253c12de9aSMartin Hundebøll batadv_nc_skb_src_search(struct batadv_priv *bat_priv,
13263c12de9aSMartin Hundebøll struct sk_buff *skb,
13276b5e971aSSven Eckelmann u8 *eth_dst,
13286b5e971aSSven Eckelmann u8 *eth_src,
13293c12de9aSMartin Hundebøll struct batadv_nc_node *in_nc_node)
13303c12de9aSMartin Hundebøll {
13313c12de9aSMartin Hundebøll struct batadv_orig_node *orig_node;
13323c12de9aSMartin Hundebøll struct batadv_nc_node *out_nc_node;
13333c12de9aSMartin Hundebøll struct batadv_nc_packet *nc_packet = NULL;
13343c12de9aSMartin Hundebøll
13353c12de9aSMartin Hundebøll orig_node = batadv_orig_hash_find(bat_priv, eth_src);
13363c12de9aSMartin Hundebøll if (!orig_node)
13373c12de9aSMartin Hundebøll return NULL;
13383c12de9aSMartin Hundebøll
13393c12de9aSMartin Hundebøll rcu_read_lock();
13403c12de9aSMartin Hundebøll list_for_each_entry_rcu(out_nc_node,
13413c12de9aSMartin Hundebøll &orig_node->out_coding_list, list) {
13423c12de9aSMartin Hundebøll /* Check if the skb is decoded and if recoding is possible */
13433c12de9aSMartin Hundebøll if (!batadv_nc_skb_coding_possible(skb,
13443c12de9aSMartin Hundebøll out_nc_node->addr, eth_src))
13453c12de9aSMartin Hundebøll continue;
13463c12de9aSMartin Hundebøll
13473c12de9aSMartin Hundebøll /* Search for an opportunity in this nc_path */
13483c12de9aSMartin Hundebøll nc_packet = batadv_nc_path_search(bat_priv, in_nc_node,
13493c12de9aSMartin Hundebøll out_nc_node, skb, eth_dst);
13503c12de9aSMartin Hundebøll if (nc_packet)
13513c12de9aSMartin Hundebøll break;
13523c12de9aSMartin Hundebøll }
13533c12de9aSMartin Hundebøll rcu_read_unlock();
13543c12de9aSMartin Hundebøll
13555d967310SSven Eckelmann batadv_orig_node_put(orig_node);
13563c12de9aSMartin Hundebøll return nc_packet;
13573c12de9aSMartin Hundebøll }
13583c12de9aSMartin Hundebøll
13593c12de9aSMartin Hundebøll /**
13607e9a8c2cSSven Eckelmann * batadv_nc_skb_store_before_coding() - set the ethernet src and dst of the
1361612d2b4fSMartin Hundebøll * unicast skb before it is stored for use in later decoding
1362612d2b4fSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
1363612d2b4fSMartin Hundebøll * @skb: data skb to store
1364612d2b4fSMartin Hundebøll * @eth_dst_new: new destination mac address of skb
1365612d2b4fSMartin Hundebøll */
batadv_nc_skb_store_before_coding(struct batadv_priv * bat_priv,struct sk_buff * skb,u8 * eth_dst_new)1366612d2b4fSMartin Hundebøll static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv,
1367612d2b4fSMartin Hundebøll struct sk_buff *skb,
13686b5e971aSSven Eckelmann u8 *eth_dst_new)
1369612d2b4fSMartin Hundebøll {
1370612d2b4fSMartin Hundebøll struct ethhdr *ethhdr;
1371612d2b4fSMartin Hundebøll
1372612d2b4fSMartin Hundebøll /* Copy skb header to change the mac header */
1373bad93e9dSOctavian Purdila skb = pskb_copy_for_clone(skb, GFP_ATOMIC);
1374612d2b4fSMartin Hundebøll if (!skb)
1375612d2b4fSMartin Hundebøll return;
1376612d2b4fSMartin Hundebøll
1377612d2b4fSMartin Hundebøll /* Set the mac header as if we actually sent the packet uncoded */
13787ed4be95SAntonio Quartulli ethhdr = eth_hdr(skb);
13798fdd0153SAntonio Quartulli ether_addr_copy(ethhdr->h_source, ethhdr->h_dest);
13808fdd0153SAntonio Quartulli ether_addr_copy(ethhdr->h_dest, eth_dst_new);
1381612d2b4fSMartin Hundebøll
1382612d2b4fSMartin Hundebøll /* Set data pointer to MAC header to mimic packets from our tx path */
1383612d2b4fSMartin Hundebøll skb_push(skb, ETH_HLEN);
1384612d2b4fSMartin Hundebøll
1385612d2b4fSMartin Hundebøll /* Add the packet to the decoding packet pool */
1386612d2b4fSMartin Hundebøll batadv_nc_skb_store_for_decoding(bat_priv, skb);
1387612d2b4fSMartin Hundebøll
1388612d2b4fSMartin Hundebøll /* batadv_nc_skb_store_for_decoding() clones the skb, so we must free
1389612d2b4fSMartin Hundebøll * our ref
1390612d2b4fSMartin Hundebøll */
1391bd687fe4SSven Eckelmann consume_skb(skb);
1392612d2b4fSMartin Hundebøll }
1393612d2b4fSMartin Hundebøll
1394612d2b4fSMartin Hundebøll /**
13957e9a8c2cSSven Eckelmann * batadv_nc_skb_dst_search() - Loops through list of neighboring nodes to dst.
13963c12de9aSMartin Hundebøll * @skb: data skb to forward
13973c12de9aSMartin Hundebøll * @neigh_node: next hop to forward packet to
13983c12de9aSMartin Hundebøll * @ethhdr: pointer to the ethernet header inside the skb
13993c12de9aSMartin Hundebøll *
1400bccb48c8SSven Eckelmann * Loops through the list of neighboring nodes the next hop has a good
1401bccb48c8SSven Eckelmann * connection to (receives OGMs with a sufficient quality). We need to find a
1402bccb48c8SSven Eckelmann * neighbor of our next hop that potentially sent a packet which our next hop
1403bccb48c8SSven Eckelmann * also received (overheard) and has stored for later decoding.
14043c12de9aSMartin Hundebøll *
140562fe710fSSven Eckelmann * Return: true if the skb was consumed (encoded packet sent) or false otherwise
14063c12de9aSMartin Hundebøll */
batadv_nc_skb_dst_search(struct sk_buff * skb,struct batadv_neigh_node * neigh_node,struct ethhdr * ethhdr)14073c12de9aSMartin Hundebøll static bool batadv_nc_skb_dst_search(struct sk_buff *skb,
14083c12de9aSMartin Hundebøll struct batadv_neigh_node *neigh_node,
14093c12de9aSMartin Hundebøll struct ethhdr *ethhdr)
14103c12de9aSMartin Hundebøll {
14113c12de9aSMartin Hundebøll struct net_device *netdev = neigh_node->if_incoming->soft_iface;
14123c12de9aSMartin Hundebøll struct batadv_priv *bat_priv = netdev_priv(netdev);
14133c12de9aSMartin Hundebøll struct batadv_orig_node *orig_node = neigh_node->orig_node;
14143c12de9aSMartin Hundebøll struct batadv_nc_node *nc_node;
14153c12de9aSMartin Hundebøll struct batadv_nc_packet *nc_packet = NULL;
14163c12de9aSMartin Hundebøll
14173c12de9aSMartin Hundebøll rcu_read_lock();
14183c12de9aSMartin Hundebøll list_for_each_entry_rcu(nc_node, &orig_node->in_coding_list, list) {
14193c12de9aSMartin Hundebøll /* Search for coding opportunity with this in_nc_node */
14203c12de9aSMartin Hundebøll nc_packet = batadv_nc_skb_src_search(bat_priv, skb,
14213c12de9aSMartin Hundebøll neigh_node->addr,
14223c12de9aSMartin Hundebøll ethhdr->h_source, nc_node);
14233c12de9aSMartin Hundebøll
14243c12de9aSMartin Hundebøll /* Opportunity was found, so stop searching */
14253c12de9aSMartin Hundebøll if (nc_packet)
14263c12de9aSMartin Hundebøll break;
14273c12de9aSMartin Hundebøll }
14283c12de9aSMartin Hundebøll rcu_read_unlock();
14293c12de9aSMartin Hundebøll
14303c12de9aSMartin Hundebøll if (!nc_packet)
14313c12de9aSMartin Hundebøll return false;
14323c12de9aSMartin Hundebøll
1433612d2b4fSMartin Hundebøll /* Save packets for later decoding */
1434612d2b4fSMartin Hundebøll batadv_nc_skb_store_before_coding(bat_priv, skb,
1435612d2b4fSMartin Hundebøll neigh_node->addr);
1436612d2b4fSMartin Hundebøll batadv_nc_skb_store_before_coding(bat_priv, nc_packet->skb,
1437612d2b4fSMartin Hundebøll nc_packet->neigh_node->addr);
1438612d2b4fSMartin Hundebøll
14393c12de9aSMartin Hundebøll /* Code and send packets */
14403c12de9aSMartin Hundebøll if (batadv_nc_code_packets(bat_priv, skb, ethhdr, nc_packet,
14413c12de9aSMartin Hundebøll neigh_node))
14423c12de9aSMartin Hundebøll return true;
14433c12de9aSMartin Hundebøll
14443c12de9aSMartin Hundebøll /* out of mem ? Coding failed - we have to free the buffered packet
14453c12de9aSMartin Hundebøll * to avoid memleaks. The skb passed as argument will be dealt with
14463c12de9aSMartin Hundebøll * by the calling function.
14473c12de9aSMartin Hundebøll */
14483c12de9aSMartin Hundebøll batadv_nc_send_packet(nc_packet);
14493c12de9aSMartin Hundebøll return false;
14503c12de9aSMartin Hundebøll }
14513c12de9aSMartin Hundebøll
14523c12de9aSMartin Hundebøll /**
14537e9a8c2cSSven Eckelmann * batadv_nc_skb_add_to_path() - buffer skb for later encoding / decoding
145495332477SMartin Hundebøll * @skb: skb to add to path
145595332477SMartin Hundebøll * @nc_path: path to add skb to
145695332477SMartin Hundebøll * @neigh_node: next hop to forward packet to
145795332477SMartin Hundebøll * @packet_id: checksum to identify packet
145895332477SMartin Hundebøll *
145962fe710fSSven Eckelmann * Return: true if the packet was buffered or false in case of an error.
146095332477SMartin Hundebøll */
batadv_nc_skb_add_to_path(struct sk_buff * skb,struct batadv_nc_path * nc_path,struct batadv_neigh_node * neigh_node,__be32 packet_id)146195332477SMartin Hundebøll static bool batadv_nc_skb_add_to_path(struct sk_buff *skb,
146295332477SMartin Hundebøll struct batadv_nc_path *nc_path,
146395332477SMartin Hundebøll struct batadv_neigh_node *neigh_node,
146495332477SMartin Hundebøll __be32 packet_id)
146595332477SMartin Hundebøll {
146695332477SMartin Hundebøll struct batadv_nc_packet *nc_packet;
146795332477SMartin Hundebøll
146895332477SMartin Hundebøll nc_packet = kzalloc(sizeof(*nc_packet), GFP_ATOMIC);
146995332477SMartin Hundebøll if (!nc_packet)
147095332477SMartin Hundebøll return false;
147195332477SMartin Hundebøll
147295332477SMartin Hundebøll /* Initialize nc_packet */
147395332477SMartin Hundebøll nc_packet->timestamp = jiffies;
147495332477SMartin Hundebøll nc_packet->packet_id = packet_id;
147595332477SMartin Hundebøll nc_packet->skb = skb;
147695332477SMartin Hundebøll nc_packet->neigh_node = neigh_node;
147795332477SMartin Hundebøll nc_packet->nc_path = nc_path;
147895332477SMartin Hundebøll
147995332477SMartin Hundebøll /* Add coding packet to list */
148095332477SMartin Hundebøll spin_lock_bh(&nc_path->packet_list_lock);
148195332477SMartin Hundebøll list_add_tail(&nc_packet->list, &nc_path->packet_list);
148295332477SMartin Hundebøll spin_unlock_bh(&nc_path->packet_list_lock);
148395332477SMartin Hundebøll
148495332477SMartin Hundebøll return true;
148595332477SMartin Hundebøll }
148695332477SMartin Hundebøll
148795332477SMartin Hundebøll /**
14887e9a8c2cSSven Eckelmann * batadv_nc_skb_forward() - try to code a packet or add it to the coding packet
148995332477SMartin Hundebøll * buffer
149095332477SMartin Hundebøll * @skb: data skb to forward
149195332477SMartin Hundebøll * @neigh_node: next hop to forward packet to
149295332477SMartin Hundebøll *
149362fe710fSSven Eckelmann * Return: true if the skb was consumed (encoded packet sent) or false otherwise
149495332477SMartin Hundebøll */
batadv_nc_skb_forward(struct sk_buff * skb,struct batadv_neigh_node * neigh_node)149595332477SMartin Hundebøll bool batadv_nc_skb_forward(struct sk_buff *skb,
1496e91ecfc6SMartin Hundebøll struct batadv_neigh_node *neigh_node)
149795332477SMartin Hundebøll {
149895332477SMartin Hundebøll const struct net_device *netdev = neigh_node->if_incoming->soft_iface;
149995332477SMartin Hundebøll struct batadv_priv *bat_priv = netdev_priv(netdev);
150095332477SMartin Hundebøll struct batadv_unicast_packet *packet;
150195332477SMartin Hundebøll struct batadv_nc_path *nc_path;
1502e91ecfc6SMartin Hundebøll struct ethhdr *ethhdr = eth_hdr(skb);
150395332477SMartin Hundebøll __be32 packet_id;
150495332477SMartin Hundebøll u8 *payload;
150595332477SMartin Hundebøll
150695332477SMartin Hundebøll /* Check if network coding is enabled */
150795332477SMartin Hundebøll if (!atomic_read(&bat_priv->network_coding))
150895332477SMartin Hundebøll goto out;
150995332477SMartin Hundebøll
151095332477SMartin Hundebøll /* We only handle unicast packets */
151195332477SMartin Hundebøll payload = skb_network_header(skb);
151295332477SMartin Hundebøll packet = (struct batadv_unicast_packet *)payload;
1513a40d9b07SSimon Wunderlich if (packet->packet_type != BATADV_UNICAST)
151495332477SMartin Hundebøll goto out;
151595332477SMartin Hundebøll
15163c12de9aSMartin Hundebøll /* Try to find a coding opportunity and send the skb if one is found */
15173c12de9aSMartin Hundebøll if (batadv_nc_skb_dst_search(skb, neigh_node, ethhdr))
15183c12de9aSMartin Hundebøll return true;
15193c12de9aSMartin Hundebøll
152095332477SMartin Hundebøll /* Find or create a nc_path for this src-dst pair */
152195332477SMartin Hundebøll nc_path = batadv_nc_get_path(bat_priv,
152295332477SMartin Hundebøll bat_priv->nc.coding_hash,
152395332477SMartin Hundebøll ethhdr->h_source,
152495332477SMartin Hundebøll neigh_node->addr);
152595332477SMartin Hundebøll
152695332477SMartin Hundebøll if (!nc_path)
152795332477SMartin Hundebøll goto out;
152895332477SMartin Hundebøll
152995332477SMartin Hundebøll /* Add skb to nc_path */
153095332477SMartin Hundebøll packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet));
153195332477SMartin Hundebøll if (!batadv_nc_skb_add_to_path(skb, nc_path, neigh_node, packet_id))
153295332477SMartin Hundebøll goto free_nc_path;
153395332477SMartin Hundebøll
153495332477SMartin Hundebøll /* Packet is consumed */
153595332477SMartin Hundebøll return true;
153695332477SMartin Hundebøll
153795332477SMartin Hundebøll free_nc_path:
15385fff2825SSven Eckelmann batadv_nc_path_put(nc_path);
153995332477SMartin Hundebøll out:
154095332477SMartin Hundebøll /* Packet is not consumed */
154195332477SMartin Hundebøll return false;
154295332477SMartin Hundebøll }
154395332477SMartin Hundebøll
154495332477SMartin Hundebøll /**
15457e9a8c2cSSven Eckelmann * batadv_nc_skb_store_for_decoding() - save a clone of the skb which can be
15467e9a8c2cSSven Eckelmann * used when decoding coded packets
1547612d2b4fSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
1548612d2b4fSMartin Hundebøll * @skb: data skb to store
1549612d2b4fSMartin Hundebøll */
batadv_nc_skb_store_for_decoding(struct batadv_priv * bat_priv,struct sk_buff * skb)1550612d2b4fSMartin Hundebøll void batadv_nc_skb_store_for_decoding(struct batadv_priv *bat_priv,
1551612d2b4fSMartin Hundebøll struct sk_buff *skb)
1552612d2b4fSMartin Hundebøll {
1553612d2b4fSMartin Hundebøll struct batadv_unicast_packet *packet;
1554612d2b4fSMartin Hundebøll struct batadv_nc_path *nc_path;
15557ed4be95SAntonio Quartulli struct ethhdr *ethhdr = eth_hdr(skb);
1556612d2b4fSMartin Hundebøll __be32 packet_id;
1557612d2b4fSMartin Hundebøll u8 *payload;
1558612d2b4fSMartin Hundebøll
1559612d2b4fSMartin Hundebøll /* Check if network coding is enabled */
1560612d2b4fSMartin Hundebøll if (!atomic_read(&bat_priv->network_coding))
1561612d2b4fSMartin Hundebøll goto out;
1562612d2b4fSMartin Hundebøll
1563612d2b4fSMartin Hundebøll /* Check for supported packet type */
1564612d2b4fSMartin Hundebøll payload = skb_network_header(skb);
1565612d2b4fSMartin Hundebøll packet = (struct batadv_unicast_packet *)payload;
1566a40d9b07SSimon Wunderlich if (packet->packet_type != BATADV_UNICAST)
1567612d2b4fSMartin Hundebøll goto out;
1568612d2b4fSMartin Hundebøll
1569612d2b4fSMartin Hundebøll /* Find existing nc_path or create a new */
1570612d2b4fSMartin Hundebøll nc_path = batadv_nc_get_path(bat_priv,
1571612d2b4fSMartin Hundebøll bat_priv->nc.decoding_hash,
1572612d2b4fSMartin Hundebøll ethhdr->h_source,
1573612d2b4fSMartin Hundebøll ethhdr->h_dest);
1574612d2b4fSMartin Hundebøll
1575612d2b4fSMartin Hundebøll if (!nc_path)
1576612d2b4fSMartin Hundebøll goto out;
1577612d2b4fSMartin Hundebøll
1578612d2b4fSMartin Hundebøll /* Clone skb and adjust skb->data to point at batman header */
1579612d2b4fSMartin Hundebøll skb = skb_clone(skb, GFP_ATOMIC);
1580612d2b4fSMartin Hundebøll if (unlikely(!skb))
1581612d2b4fSMartin Hundebøll goto free_nc_path;
1582612d2b4fSMartin Hundebøll
1583612d2b4fSMartin Hundebøll if (unlikely(!pskb_may_pull(skb, ETH_HLEN)))
1584612d2b4fSMartin Hundebøll goto free_skb;
1585612d2b4fSMartin Hundebøll
1586612d2b4fSMartin Hundebøll if (unlikely(!skb_pull_rcsum(skb, ETH_HLEN)))
1587612d2b4fSMartin Hundebøll goto free_skb;
1588612d2b4fSMartin Hundebøll
1589612d2b4fSMartin Hundebøll /* Add skb to nc_path */
1590612d2b4fSMartin Hundebøll packet_id = batadv_skb_crc32(skb, payload + sizeof(*packet));
1591612d2b4fSMartin Hundebøll if (!batadv_nc_skb_add_to_path(skb, nc_path, NULL, packet_id))
1592612d2b4fSMartin Hundebøll goto free_skb;
1593612d2b4fSMartin Hundebøll
1594612d2b4fSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_BUFFER);
1595612d2b4fSMartin Hundebøll return;
1596612d2b4fSMartin Hundebøll
1597612d2b4fSMartin Hundebøll free_skb:
1598612d2b4fSMartin Hundebøll kfree_skb(skb);
1599612d2b4fSMartin Hundebøll free_nc_path:
16005fff2825SSven Eckelmann batadv_nc_path_put(nc_path);
1601612d2b4fSMartin Hundebøll out:
1602612d2b4fSMartin Hundebøll return;
1603612d2b4fSMartin Hundebøll }
1604612d2b4fSMartin Hundebøll
1605612d2b4fSMartin Hundebøll /**
16067e9a8c2cSSven Eckelmann * batadv_nc_skb_store_sniffed_unicast() - check if a received unicast packet
1607612d2b4fSMartin Hundebøll * should be saved in the decoding buffer and, if so, store it there
1608612d2b4fSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
1609612d2b4fSMartin Hundebøll * @skb: unicast skb to store
1610612d2b4fSMartin Hundebøll */
batadv_nc_skb_store_sniffed_unicast(struct batadv_priv * bat_priv,struct sk_buff * skb)1611612d2b4fSMartin Hundebøll void batadv_nc_skb_store_sniffed_unicast(struct batadv_priv *bat_priv,
1612612d2b4fSMartin Hundebøll struct sk_buff *skb)
1613612d2b4fSMartin Hundebøll {
16147ed4be95SAntonio Quartulli struct ethhdr *ethhdr = eth_hdr(skb);
1615612d2b4fSMartin Hundebøll
16166e0895c2SDavid S. Miller if (batadv_is_my_mac(bat_priv, ethhdr->h_dest))
1617612d2b4fSMartin Hundebøll return;
1618612d2b4fSMartin Hundebøll
1619612d2b4fSMartin Hundebøll /* Set data pointer to MAC header to mimic packets from our tx path */
1620612d2b4fSMartin Hundebøll skb_push(skb, ETH_HLEN);
1621612d2b4fSMartin Hundebøll
1622612d2b4fSMartin Hundebøll batadv_nc_skb_store_for_decoding(bat_priv, skb);
1623612d2b4fSMartin Hundebøll }
1624612d2b4fSMartin Hundebøll
1625612d2b4fSMartin Hundebøll /**
16267e9a8c2cSSven Eckelmann * batadv_nc_skb_decode_packet() - decode given skb using the decode data stored
16272df5278bSMartin Hundebøll * in nc_packet
16286e0895c2SDavid S. Miller * @bat_priv: the bat priv with all the soft interface information
16292df5278bSMartin Hundebøll * @skb: unicast skb to decode
16302df5278bSMartin Hundebøll * @nc_packet: decode data needed to decode the skb
16312df5278bSMartin Hundebøll *
163262fe710fSSven Eckelmann * Return: pointer to decoded unicast packet if the packet was decoded or NULL
16332df5278bSMartin Hundebøll * in case of an error.
16342df5278bSMartin Hundebøll */
16352df5278bSMartin Hundebøll static struct batadv_unicast_packet *
batadv_nc_skb_decode_packet(struct batadv_priv * bat_priv,struct sk_buff * skb,struct batadv_nc_packet * nc_packet)16366e0895c2SDavid S. Miller batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
16372df5278bSMartin Hundebøll struct batadv_nc_packet *nc_packet)
16382df5278bSMartin Hundebøll {
16392df5278bSMartin Hundebøll const int h_size = sizeof(struct batadv_unicast_packet);
16402df5278bSMartin Hundebøll const int h_diff = sizeof(struct batadv_coded_packet) - h_size;
16412df5278bSMartin Hundebøll struct batadv_unicast_packet *unicast_packet;
16422df5278bSMartin Hundebøll struct batadv_coded_packet coded_packet_tmp;
16432df5278bSMartin Hundebøll struct ethhdr *ethhdr, ethhdr_tmp;
16446b5e971aSSven Eckelmann u8 *orig_dest, ttl, ttvn;
16452df5278bSMartin Hundebøll unsigned int coding_len;
16467da19971SMarek Lindner int err;
16472df5278bSMartin Hundebøll
16482df5278bSMartin Hundebøll /* Save headers temporarily */
16492df5278bSMartin Hundebøll memcpy(&coded_packet_tmp, skb->data, sizeof(coded_packet_tmp));
16502df5278bSMartin Hundebøll memcpy(ðhdr_tmp, skb_mac_header(skb), sizeof(ethhdr_tmp));
16512df5278bSMartin Hundebøll
16522df5278bSMartin Hundebøll if (skb_cow(skb, 0) < 0)
16532df5278bSMartin Hundebøll return NULL;
16542df5278bSMartin Hundebøll
16552df5278bSMartin Hundebøll if (unlikely(!skb_pull_rcsum(skb, h_diff)))
16562df5278bSMartin Hundebøll return NULL;
16572df5278bSMartin Hundebøll
16582df5278bSMartin Hundebøll /* Data points to batman header, so set mac header 14 bytes before
16592df5278bSMartin Hundebøll * and network to data
16602df5278bSMartin Hundebøll */
16612df5278bSMartin Hundebøll skb_set_mac_header(skb, -ETH_HLEN);
16622df5278bSMartin Hundebøll skb_reset_network_header(skb);
16632df5278bSMartin Hundebøll
16642df5278bSMartin Hundebøll /* Reconstruct original mac header */
16657ed4be95SAntonio Quartulli ethhdr = eth_hdr(skb);
1666abae9479SFengguang Wu *ethhdr = ethhdr_tmp;
16672df5278bSMartin Hundebøll
16682df5278bSMartin Hundebøll /* Select the correct unicast header information based on the location
16692df5278bSMartin Hundebøll * of our mac address in the coded_packet header
16702df5278bSMartin Hundebøll */
16716e0895c2SDavid S. Miller if (batadv_is_my_mac(bat_priv, coded_packet_tmp.second_dest)) {
16722df5278bSMartin Hundebøll /* If we are the second destination the packet was overheard,
16732df5278bSMartin Hundebøll * so the Ethernet address must be copied to h_dest and
16742df5278bSMartin Hundebøll * pkt_type changed from PACKET_OTHERHOST to PACKET_HOST
16752df5278bSMartin Hundebøll */
16768fdd0153SAntonio Quartulli ether_addr_copy(ethhdr->h_dest, coded_packet_tmp.second_dest);
16772df5278bSMartin Hundebøll skb->pkt_type = PACKET_HOST;
16782df5278bSMartin Hundebøll
16792df5278bSMartin Hundebøll orig_dest = coded_packet_tmp.second_orig_dest;
16802df5278bSMartin Hundebøll ttl = coded_packet_tmp.second_ttl;
16812df5278bSMartin Hundebøll ttvn = coded_packet_tmp.second_ttvn;
16822df5278bSMartin Hundebøll } else {
16832df5278bSMartin Hundebøll orig_dest = coded_packet_tmp.first_orig_dest;
1684a40d9b07SSimon Wunderlich ttl = coded_packet_tmp.ttl;
16852df5278bSMartin Hundebøll ttvn = coded_packet_tmp.first_ttvn;
16862df5278bSMartin Hundebøll }
16872df5278bSMartin Hundebøll
16882df5278bSMartin Hundebøll coding_len = ntohs(coded_packet_tmp.coded_len);
16892df5278bSMartin Hundebøll
16902df5278bSMartin Hundebøll if (coding_len > skb->len)
16912df5278bSMartin Hundebøll return NULL;
16922df5278bSMartin Hundebøll
16932df5278bSMartin Hundebøll /* Here the magic is reversed:
16942df5278bSMartin Hundebøll * extract the missing packet from the received coded packet
16952df5278bSMartin Hundebøll */
16962df5278bSMartin Hundebøll batadv_nc_memxor(skb->data + h_size,
16972df5278bSMartin Hundebøll nc_packet->skb->data + h_size,
16982df5278bSMartin Hundebøll coding_len);
16992df5278bSMartin Hundebøll
17002df5278bSMartin Hundebøll /* Resize decoded skb if decoded with larger packet */
17017da19971SMarek Lindner if (nc_packet->skb->len > coding_len + h_size) {
17027da19971SMarek Lindner err = pskb_trim_rcsum(skb, coding_len + h_size);
17037da19971SMarek Lindner if (err)
17047da19971SMarek Lindner return NULL;
17057da19971SMarek Lindner }
17062df5278bSMartin Hundebøll
17072df5278bSMartin Hundebøll /* Create decoded unicast packet */
17082df5278bSMartin Hundebøll unicast_packet = (struct batadv_unicast_packet *)skb->data;
1709a40d9b07SSimon Wunderlich unicast_packet->packet_type = BATADV_UNICAST;
1710a40d9b07SSimon Wunderlich unicast_packet->version = BATADV_COMPAT_VERSION;
1711a40d9b07SSimon Wunderlich unicast_packet->ttl = ttl;
17128fdd0153SAntonio Quartulli ether_addr_copy(unicast_packet->dest, orig_dest);
17132df5278bSMartin Hundebøll unicast_packet->ttvn = ttvn;
17142df5278bSMartin Hundebøll
1715bd687fe4SSven Eckelmann batadv_nc_packet_free(nc_packet, false);
17162df5278bSMartin Hundebøll return unicast_packet;
17172df5278bSMartin Hundebøll }
17182df5278bSMartin Hundebøll
17192df5278bSMartin Hundebøll /**
17207e9a8c2cSSven Eckelmann * batadv_nc_find_decoding_packet() - search through buffered decoding data to
17212df5278bSMartin Hundebøll * find the data needed to decode the coded packet
17222df5278bSMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
17232df5278bSMartin Hundebøll * @ethhdr: pointer to the ethernet header inside the coded packet
17242df5278bSMartin Hundebøll * @coded: coded packet we try to find decode data for
17252df5278bSMartin Hundebøll *
172662fe710fSSven Eckelmann * Return: pointer to nc packet if the needed data was found or NULL otherwise.
17272df5278bSMartin Hundebøll */
17282df5278bSMartin Hundebøll static struct batadv_nc_packet *
batadv_nc_find_decoding_packet(struct batadv_priv * bat_priv,struct ethhdr * ethhdr,struct batadv_coded_packet * coded)17292df5278bSMartin Hundebøll batadv_nc_find_decoding_packet(struct batadv_priv *bat_priv,
17302df5278bSMartin Hundebøll struct ethhdr *ethhdr,
17312df5278bSMartin Hundebøll struct batadv_coded_packet *coded)
17322df5278bSMartin Hundebøll {
17332df5278bSMartin Hundebøll struct batadv_hashtable *hash = bat_priv->nc.decoding_hash;
17342df5278bSMartin Hundebøll struct batadv_nc_packet *tmp_nc_packet, *nc_packet = NULL;
17352df5278bSMartin Hundebøll struct batadv_nc_path *nc_path, nc_path_key;
17366b5e971aSSven Eckelmann u8 *dest, *source;
17372df5278bSMartin Hundebøll __be32 packet_id;
17382df5278bSMartin Hundebøll int index;
17392df5278bSMartin Hundebøll
17402df5278bSMartin Hundebøll if (!hash)
17412df5278bSMartin Hundebøll return NULL;
17422df5278bSMartin Hundebøll
17432df5278bSMartin Hundebøll /* Select the correct packet id based on the location of our mac-addr */
17442df5278bSMartin Hundebøll dest = ethhdr->h_source;
17456e0895c2SDavid S. Miller if (!batadv_is_my_mac(bat_priv, coded->second_dest)) {
17462df5278bSMartin Hundebøll source = coded->second_source;
17472df5278bSMartin Hundebøll packet_id = coded->second_crc;
17482df5278bSMartin Hundebøll } else {
17492df5278bSMartin Hundebøll source = coded->first_source;
17502df5278bSMartin Hundebøll packet_id = coded->first_crc;
17512df5278bSMartin Hundebøll }
17522df5278bSMartin Hundebøll
17532df5278bSMartin Hundebøll batadv_nc_hash_key_gen(&nc_path_key, source, dest);
17542df5278bSMartin Hundebøll index = batadv_nc_hash_choose(&nc_path_key, hash->size);
17552df5278bSMartin Hundebøll
17562df5278bSMartin Hundebøll /* Search for matching coding path */
17572df5278bSMartin Hundebøll rcu_read_lock();
17582df5278bSMartin Hundebøll hlist_for_each_entry_rcu(nc_path, &hash->table[index], hash_entry) {
17592df5278bSMartin Hundebøll /* Find matching nc_packet */
17602df5278bSMartin Hundebøll spin_lock_bh(&nc_path->packet_list_lock);
17612df5278bSMartin Hundebøll list_for_each_entry(tmp_nc_packet,
17622df5278bSMartin Hundebøll &nc_path->packet_list, list) {
17632df5278bSMartin Hundebøll if (packet_id == tmp_nc_packet->packet_id) {
17642df5278bSMartin Hundebøll list_del(&tmp_nc_packet->list);
17652df5278bSMartin Hundebøll
17662df5278bSMartin Hundebøll nc_packet = tmp_nc_packet;
17672df5278bSMartin Hundebøll break;
17682df5278bSMartin Hundebøll }
17692df5278bSMartin Hundebøll }
17702df5278bSMartin Hundebøll spin_unlock_bh(&nc_path->packet_list_lock);
17712df5278bSMartin Hundebøll
17722df5278bSMartin Hundebøll if (nc_packet)
17732df5278bSMartin Hundebøll break;
17742df5278bSMartin Hundebøll }
17752df5278bSMartin Hundebøll rcu_read_unlock();
17762df5278bSMartin Hundebøll
17772df5278bSMartin Hundebøll if (!nc_packet)
17782df5278bSMartin Hundebøll batadv_dbg(BATADV_DBG_NC, bat_priv,
17792df5278bSMartin Hundebøll "No decoding packet found for %u\n", packet_id);
17802df5278bSMartin Hundebøll
17812df5278bSMartin Hundebøll return nc_packet;
17822df5278bSMartin Hundebøll }
17832df5278bSMartin Hundebøll
17842df5278bSMartin Hundebøll /**
17857e9a8c2cSSven Eckelmann * batadv_nc_recv_coded_packet() - try to decode coded packet and enqueue the
17862df5278bSMartin Hundebøll * resulting unicast packet
17872df5278bSMartin Hundebøll * @skb: incoming coded packet
17882df5278bSMartin Hundebøll * @recv_if: pointer to interface this packet was received on
1789672e7978SSven Eckelmann *
1790672e7978SSven Eckelmann * Return: NET_RX_SUCCESS if the packet has been consumed or NET_RX_DROP
1791672e7978SSven Eckelmann * otherwise.
17922df5278bSMartin Hundebøll */
batadv_nc_recv_coded_packet(struct sk_buff * skb,struct batadv_hard_iface * recv_if)17932df5278bSMartin Hundebøll static int batadv_nc_recv_coded_packet(struct sk_buff *skb,
17942df5278bSMartin Hundebøll struct batadv_hard_iface *recv_if)
17952df5278bSMartin Hundebøll {
17962df5278bSMartin Hundebøll struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface);
17972df5278bSMartin Hundebøll struct batadv_unicast_packet *unicast_packet;
17982df5278bSMartin Hundebøll struct batadv_coded_packet *coded_packet;
17992df5278bSMartin Hundebøll struct batadv_nc_packet *nc_packet;
18002df5278bSMartin Hundebøll struct ethhdr *ethhdr;
18012df5278bSMartin Hundebøll int hdr_size = sizeof(*coded_packet);
18022df5278bSMartin Hundebøll
18032df5278bSMartin Hundebøll /* Check if network coding is enabled */
18042df5278bSMartin Hundebøll if (!atomic_read(&bat_priv->network_coding))
1805b91a2543SSven Eckelmann goto free_skb;
18062df5278bSMartin Hundebøll
18072df5278bSMartin Hundebøll /* Make sure we can access (and remove) header */
18082df5278bSMartin Hundebøll if (unlikely(!pskb_may_pull(skb, hdr_size)))
1809b91a2543SSven Eckelmann goto free_skb;
18102df5278bSMartin Hundebøll
18112df5278bSMartin Hundebøll coded_packet = (struct batadv_coded_packet *)skb->data;
18127ed4be95SAntonio Quartulli ethhdr = eth_hdr(skb);
18132df5278bSMartin Hundebøll
18142df5278bSMartin Hundebøll /* Verify frame is destined for us */
18156e0895c2SDavid S. Miller if (!batadv_is_my_mac(bat_priv, ethhdr->h_dest) &&
18166e0895c2SDavid S. Miller !batadv_is_my_mac(bat_priv, coded_packet->second_dest))
1817b91a2543SSven Eckelmann goto free_skb;
18182df5278bSMartin Hundebøll
18192df5278bSMartin Hundebøll /* Update stat counter */
18206e0895c2SDavid S. Miller if (batadv_is_my_mac(bat_priv, coded_packet->second_dest))
18212df5278bSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_SNIFFED);
18222df5278bSMartin Hundebøll
18232df5278bSMartin Hundebøll nc_packet = batadv_nc_find_decoding_packet(bat_priv, ethhdr,
18242df5278bSMartin Hundebøll coded_packet);
18252df5278bSMartin Hundebøll if (!nc_packet) {
18262df5278bSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
1827b91a2543SSven Eckelmann goto free_skb;
18282df5278bSMartin Hundebøll }
18292df5278bSMartin Hundebøll
18302df5278bSMartin Hundebøll /* Make skb's linear, because decoding accesses the entire buffer */
18312df5278bSMartin Hundebøll if (skb_linearize(skb) < 0)
18322df5278bSMartin Hundebøll goto free_nc_packet;
18332df5278bSMartin Hundebøll
18342df5278bSMartin Hundebøll if (skb_linearize(nc_packet->skb) < 0)
18352df5278bSMartin Hundebøll goto free_nc_packet;
18362df5278bSMartin Hundebøll
18372df5278bSMartin Hundebøll /* Decode the packet */
18386e0895c2SDavid S. Miller unicast_packet = batadv_nc_skb_decode_packet(bat_priv, skb, nc_packet);
18392df5278bSMartin Hundebøll if (!unicast_packet) {
18402df5278bSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE_FAILED);
18412df5278bSMartin Hundebøll goto free_nc_packet;
18422df5278bSMartin Hundebøll }
18432df5278bSMartin Hundebøll
18442df5278bSMartin Hundebøll /* Mark packet as decoded to do correct recoding when forwarding */
18452df5278bSMartin Hundebøll BATADV_SKB_CB(skb)->decoded = true;
18462df5278bSMartin Hundebøll batadv_inc_counter(bat_priv, BATADV_CNT_NC_DECODE);
18472df5278bSMartin Hundebøll batadv_add_counter(bat_priv, BATADV_CNT_NC_DECODE_BYTES,
18482df5278bSMartin Hundebøll skb->len + ETH_HLEN);
18492df5278bSMartin Hundebøll return batadv_recv_unicast_packet(skb, recv_if);
18502df5278bSMartin Hundebøll
18512df5278bSMartin Hundebøll free_nc_packet:
1852bd687fe4SSven Eckelmann batadv_nc_packet_free(nc_packet, true);
1853b91a2543SSven Eckelmann free_skb:
1854b91a2543SSven Eckelmann kfree_skb(skb);
1855b91a2543SSven Eckelmann
18562df5278bSMartin Hundebøll return NET_RX_DROP;
18572df5278bSMartin Hundebøll }
18582df5278bSMartin Hundebøll
18592df5278bSMartin Hundebøll /**
18607e9a8c2cSSven Eckelmann * batadv_nc_mesh_free() - clean up network coding memory
1861d353d8d4SMartin Hundebøll * @bat_priv: the bat priv with all the soft interface information
1862d353d8d4SMartin Hundebøll */
batadv_nc_mesh_free(struct batadv_priv * bat_priv)18636c519badSMatthias Schiffer void batadv_nc_mesh_free(struct batadv_priv *bat_priv)
1864d353d8d4SMartin Hundebøll {
18653f4841ffSMarek Lindner batadv_tvlv_container_unregister(bat_priv, BATADV_TVLV_NC, 1);
18663f4841ffSMarek Lindner batadv_tvlv_handler_unregister(bat_priv, BATADV_TVLV_NC, 1);
1867d353d8d4SMartin Hundebøll cancel_delayed_work_sync(&bat_priv->nc.work);
1868612d2b4fSMartin Hundebøll
186995332477SMartin Hundebøll batadv_nc_purge_paths(bat_priv, bat_priv->nc.coding_hash, NULL);
187095332477SMartin Hundebøll batadv_hash_destroy(bat_priv->nc.coding_hash);
1871612d2b4fSMartin Hundebøll batadv_nc_purge_paths(bat_priv, bat_priv->nc.decoding_hash, NULL);
1872612d2b4fSMartin Hundebøll batadv_hash_destroy(bat_priv->nc.decoding_hash);
1873d353d8d4SMartin Hundebøll }
1874