aboutsummaryrefslogtreecommitdiffstats
path: root/net/batman-adv
diff options
context:
space:
mode:
authorMartin Hundebøll <martin@hundeboll.net>2013-01-25 05:12:39 -0500
committerAntonio Quartulli <ordex@autistici.org>2013-03-13 17:53:49 -0400
commitd56b1705e28c196312607bc8bdde0e91879c20b6 (patch)
tree3f48f0c97be0db6927edc1dec0d414a28557e06b /net/batman-adv
parentd353d8d4d9f0184ac43a90c6e04b593c33bd28ea (diff)
batman-adv: network coding - detect coding nodes and remove these after timeout
To use network coding efficiently, a relay must know when neighbor nodes are likely to have enough information to be able to decode a network coded packet. This is detected by using OGMs from batman-adv to discover when one neighbor is in range of another neighbor. The relay check the TLL to detect when an OGM is forwarded from one neighbor by another neighbor, and thereby knows that the two neighbors are in range and thus overhear packets sent by each other. This information is saved in the orig_node struct to be used when searching for coding opportunities. Two lists are added to the orig_node struct: One for neighbors that can hear the orig_node (outgoing nc_nodes) and one for neighbors that the orig_node can hear (incoming nc_nodes). Information about nc_nodes is kept for 10 seconds and is available through debugfs in batman_adv/nc_nodes to use when debugging network coding. Signed-off-by: Martin Hundebøll <martin@hundeboll.net> Signed-off-by: Marek Lindner <lindner_marek@yahoo.de> Signed-off-by: Antonio Quartulli <ordex@autistici.org>
Diffstat (limited to 'net/batman-adv')
-rw-r--r--net/batman-adv/bat_iv_ogm.c5
-rw-r--r--net/batman-adv/debugfs.c18
-rw-r--r--net/batman-adv/main.h2
-rw-r--r--net/batman-adv/network-coding.c414
-rw-r--r--net/batman-adv/network-coding.h47
-rw-r--r--net/batman-adv/originator.c6
-rw-r--r--net/batman-adv/types.h32
7 files changed, 524 insertions, 0 deletions
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index a5bb0a769eb9..071f288b77a8 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -27,6 +27,7 @@
27#include "hard-interface.h" 27#include "hard-interface.h"
28#include "send.h" 28#include "send.h"
29#include "bat_algo.h" 29#include "bat_algo.h"
30#include "network-coding.h"
30 31
31static struct batadv_neigh_node * 32static struct batadv_neigh_node *
32batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, 33batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface,
@@ -1185,6 +1186,10 @@ static void batadv_iv_ogm_process(const struct ethhdr *ethhdr,
1185 if (!orig_neigh_node) 1186 if (!orig_neigh_node)
1186 goto out; 1187 goto out;
1187 1188
1189 /* Update nc_nodes of the originator */
1190 batadv_nc_update_nc_node(bat_priv, orig_node, orig_neigh_node,
1191 batadv_ogm_packet, is_single_hop_neigh);
1192
1188 orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node); 1193 orig_neigh_router = batadv_orig_node_get_router(orig_neigh_node);
1189 1194
1190 /* drop packet if sender is not a direct neighbor and if we 1195 /* drop packet if sender is not a direct neighbor and if we
diff --git a/net/batman-adv/debugfs.c b/net/batman-adv/debugfs.c
index 6ae86516db4d..f186a55b23c3 100644
--- a/net/batman-adv/debugfs.c
+++ b/net/batman-adv/debugfs.c
@@ -32,6 +32,7 @@
32#include "icmp_socket.h" 32#include "icmp_socket.h"
33#include "bridge_loop_avoidance.h" 33#include "bridge_loop_avoidance.h"
34#include "distributed-arp-table.h" 34#include "distributed-arp-table.h"
35#include "network-coding.h"
35 36
36static struct dentry *batadv_debugfs; 37static struct dentry *batadv_debugfs;
37 38
@@ -310,6 +311,14 @@ struct batadv_debuginfo {
310 const struct file_operations fops; 311 const struct file_operations fops;
311}; 312};
312 313
314#ifdef CONFIG_BATMAN_ADV_NC
315static int batadv_nc_nodes_open(struct inode *inode, struct file *file)
316{
317 struct net_device *net_dev = (struct net_device *)inode->i_private;
318 return single_open(file, batadv_nc_nodes_seq_print_text, net_dev);
319}
320#endif
321
313#define BATADV_DEBUGINFO(_name, _mode, _open) \ 322#define BATADV_DEBUGINFO(_name, _mode, _open) \
314struct batadv_debuginfo batadv_debuginfo_##_name = { \ 323struct batadv_debuginfo batadv_debuginfo_##_name = { \
315 .attr = { .name = __stringify(_name), \ 324 .attr = { .name = __stringify(_name), \
@@ -348,6 +357,9 @@ static BATADV_DEBUGINFO(dat_cache, S_IRUGO, batadv_dat_cache_open);
348static BATADV_DEBUGINFO(transtable_local, S_IRUGO, 357static BATADV_DEBUGINFO(transtable_local, S_IRUGO,
349 batadv_transtable_local_open); 358 batadv_transtable_local_open);
350static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open); 359static BATADV_DEBUGINFO(vis_data, S_IRUGO, batadv_vis_data_open);
360#ifdef CONFIG_BATMAN_ADV_NC
361static BATADV_DEBUGINFO(nc_nodes, S_IRUGO, batadv_nc_nodes_open);
362#endif
351 363
352static struct batadv_debuginfo *batadv_mesh_debuginfos[] = { 364static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
353 &batadv_debuginfo_originators, 365 &batadv_debuginfo_originators,
@@ -362,6 +374,9 @@ static struct batadv_debuginfo *batadv_mesh_debuginfos[] = {
362#endif 374#endif
363 &batadv_debuginfo_transtable_local, 375 &batadv_debuginfo_transtable_local,
364 &batadv_debuginfo_vis_data, 376 &batadv_debuginfo_vis_data,
377#ifdef CONFIG_BATMAN_ADV_NC
378 &batadv_debuginfo_nc_nodes,
379#endif
365 NULL, 380 NULL,
366}; 381};
367 382
@@ -431,6 +446,9 @@ int batadv_debugfs_add_meshif(struct net_device *dev)
431 } 446 }
432 } 447 }
433 448
449 if (batadv_nc_init_debugfs(bat_priv) < 0)
450 goto rem_attr;
451
434 return 0; 452 return 0;
435rem_attr: 453rem_attr:
436 debugfs_remove_recursive(bat_priv->debug_dir); 454 debugfs_remove_recursive(bat_priv->debug_dir);
diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h
index 59ba2ff8e252..8a10619ae916 100644
--- a/net/batman-adv/main.h
+++ b/net/batman-adv/main.h
@@ -105,6 +105,8 @@
105#define BATADV_RESET_PROTECTION_MS 30000 105#define BATADV_RESET_PROTECTION_MS 30000
106#define BATADV_EXPECTED_SEQNO_RANGE 65536 106#define BATADV_EXPECTED_SEQNO_RANGE 65536
107 107
108#define BATADV_NC_NODE_TIMEOUT 10000 /* Milliseconds */
109
108enum batadv_mesh_state { 110enum batadv_mesh_state {
109 BATADV_MESH_INACTIVE, 111 BATADV_MESH_INACTIVE,
110 BATADV_MESH_ACTIVE, 112 BATADV_MESH_ACTIVE,
diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c
index 9c2d54bdd2ce..ff4985d84726 100644
--- a/net/batman-adv/network-coding.c
+++ b/net/batman-adv/network-coding.c
@@ -17,8 +17,12 @@
17 * 02110-1301, USA 17 * 02110-1301, USA
18 */ 18 */
19 19
20#include <linux/debugfs.h>
21
20#include "main.h" 22#include "main.h"
21#include "network-coding.h" 23#include "network-coding.h"
24#include "originator.h"
25#include "hard-interface.h"
22 26
23static void batadv_nc_worker(struct work_struct *work); 27static void batadv_nc_worker(struct work_struct *work);
24 28
@@ -51,6 +55,151 @@ int batadv_nc_init(struct batadv_priv *bat_priv)
51void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) 55void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
52{ 56{
53 atomic_set(&bat_priv->network_coding, 1); 57 atomic_set(&bat_priv->network_coding, 1);
58 bat_priv->nc.min_tq = 200;
59}
60
61/**
62 * batadv_nc_init_orig - initialise the nc fields of an orig_node
63 * @orig_node: the orig_node which is going to be initialised
64 */
65void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
66{
67 INIT_LIST_HEAD(&orig_node->in_coding_list);
68 INIT_LIST_HEAD(&orig_node->out_coding_list);
69 spin_lock_init(&orig_node->in_coding_list_lock);
70 spin_lock_init(&orig_node->out_coding_list_lock);
71}
72
73/**
74 * batadv_nc_node_free_rcu - rcu callback to free an nc node and remove
75 * its refcount on the orig_node
76 * @rcu: rcu pointer of the nc node
77 */
78static void batadv_nc_node_free_rcu(struct rcu_head *rcu)
79{
80 struct batadv_nc_node *nc_node;
81
82 nc_node = container_of(rcu, struct batadv_nc_node, rcu);
83 batadv_orig_node_free_ref(nc_node->orig_node);
84 kfree(nc_node);
85}
86
87/**
88 * batadv_nc_node_free_ref - decrements the nc node refcounter and possibly
89 * frees it
90 * @nc_node: the nc node to free
91 */
92static void batadv_nc_node_free_ref(struct batadv_nc_node *nc_node)
93{
94 if (atomic_dec_and_test(&nc_node->refcount))
95 call_rcu(&nc_node->rcu, batadv_nc_node_free_rcu);
96}
97
98/**
99 * batadv_nc_to_purge_nc_node - checks whether an nc node has to be purged
100 * @bat_priv: the bat priv with all the soft interface information
101 * @nc_node: the nc node to check
102 *
103 * Returns true if the entry has to be purged now, false otherwise
104 */
105static bool batadv_nc_to_purge_nc_node(struct batadv_priv *bat_priv,
106 struct batadv_nc_node *nc_node)
107{
108 if (atomic_read(&bat_priv->mesh_state) != BATADV_MESH_ACTIVE)
109 return true;
110
111 return batadv_has_timed_out(nc_node->last_seen, BATADV_NC_NODE_TIMEOUT);
112}
113
114/**
115 * batadv_nc_purge_orig_nc_nodes - go through list of nc nodes and purge stale
116 * entries
117 * @bat_priv: the bat priv with all the soft interface information
118 * @list: list of nc nodes
119 * @lock: nc node list lock
120 * @to_purge: function in charge to decide whether an entry has to be purged or
121 * not. This function takes the nc node as argument and has to return
122 * a boolean value: true if the entry has to be deleted, false
123 * otherwise
124 */
125static void
126batadv_nc_purge_orig_nc_nodes(struct batadv_priv *bat_priv,
127 struct list_head *list,
128 spinlock_t *lock,
129 bool (*to_purge)(struct batadv_priv *,
130 struct batadv_nc_node *))
131{
132 struct batadv_nc_node *nc_node, *nc_node_tmp;
133
134 /* For each nc_node in list */
135 spin_lock_bh(lock);
136 list_for_each_entry_safe(nc_node, nc_node_tmp, list, list) {
137 /* if an helper function has been passed as parameter,
138 * ask it if the entry has to be purged or not
139 */
140 if (to_purge && !to_purge(bat_priv, nc_node))
141 continue;
142
143 batadv_dbg(BATADV_DBG_NC, bat_priv,
144 "Removing nc_node %pM -> %pM\n",
145 nc_node->addr, nc_node->orig_node->orig);
146 list_del_rcu(&nc_node->list);
147 batadv_nc_node_free_ref(nc_node);
148 }
149 spin_unlock_bh(lock);
150}
151
152/**
153 * batadv_nc_purge_orig - purges all nc node data attached of the given
154 * originator
155 * @bat_priv: the bat priv with all the soft interface information
156 * @orig_node: orig_node with the nc node entries to be purged
157 * @to_purge: function in charge to decide whether an entry has to be purged or
158 * not. This function takes the nc node as argument and has to return
159 * a boolean value: true is the entry has to be deleted, false
160 * otherwise
161 */
162void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
163 struct batadv_orig_node *orig_node,
164 bool (*to_purge)(struct batadv_priv *,
165 struct batadv_nc_node *))
166{
167 /* Check ingoing nc_node's of this orig_node */
168 batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->in_coding_list,
169 &orig_node->in_coding_list_lock,
170 to_purge);
171
172 /* Check outgoing nc_node's of this orig_node */
173 batadv_nc_purge_orig_nc_nodes(bat_priv, &orig_node->out_coding_list,
174 &orig_node->out_coding_list_lock,
175 to_purge);
176}
177
178/**
179 * batadv_nc_purge_orig_hash - traverse entire originator hash to check if they
180 * have timed out nc nodes
181 * @bat_priv: the bat priv with all the soft interface information
182 */
183static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv)
184{
185 struct batadv_hashtable *hash = bat_priv->orig_hash;
186 struct hlist_head *head;
187 struct batadv_orig_node *orig_node;
188 uint32_t i;
189
190 if (!hash)
191 return;
192
193 /* For each orig_node */
194 for (i = 0; i < hash->size; i++) {
195 head = &hash->table[i];
196
197 rcu_read_lock();
198 hlist_for_each_entry_rcu(orig_node, head, hash_entry)
199 batadv_nc_purge_orig(bat_priv, orig_node,
200 batadv_nc_to_purge_nc_node);
201 rcu_read_unlock();
202 }
54} 203}
55 204
56/** 205/**
@@ -67,11 +216,197 @@ static void batadv_nc_worker(struct work_struct *work)
67 priv_nc = container_of(delayed_work, struct batadv_priv_nc, work); 216 priv_nc = container_of(delayed_work, struct batadv_priv_nc, work);
68 bat_priv = container_of(priv_nc, struct batadv_priv, nc); 217 bat_priv = container_of(priv_nc, struct batadv_priv, nc);
69 218
219 batadv_nc_purge_orig_hash(bat_priv);
220
70 /* Schedule a new check */ 221 /* Schedule a new check */
71 batadv_nc_start_timer(bat_priv); 222 batadv_nc_start_timer(bat_priv);
72} 223}
73 224
74/** 225/**
226 * batadv_can_nc_with_orig - checks whether the given orig node is suitable for
227 * coding or not
228 * @bat_priv: the bat priv with all the soft interface information
229 * @orig_node: neighboring orig node which may be used as nc candidate
230 * @ogm_packet: incoming ogm packet also used for the checks
231 *
232 * Returns true if:
233 * 1) The OGM must have the most recent sequence number.
234 * 2) The TTL must be decremented by one and only one.
235 * 3) The OGM must be received from the first hop from orig_node.
236 * 4) The TQ value of the OGM must be above bat_priv->nc.min_tq.
237 */
238static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv,
239 struct batadv_orig_node *orig_node,
240 struct batadv_ogm_packet *ogm_packet)
241{
242 if (orig_node->last_real_seqno != ogm_packet->seqno)
243 return false;
244 if (orig_node->last_ttl != ogm_packet->header.ttl + 1)
245 return false;
246 if (!batadv_compare_eth(ogm_packet->orig, ogm_packet->prev_sender))
247 return false;
248 if (ogm_packet->tq < bat_priv->nc.min_tq)
249 return false;
250
251 return true;
252}
253
254/**
255 * batadv_nc_find_nc_node - search for an existing nc node and return it
256 * @orig_node: orig node originating the ogm packet
257 * @orig_neigh_node: neighboring orig node from which we received the ogm packet
258 * (can be equal to orig_node)
259 * @in_coding: traverse incoming or outgoing network coding list
260 *
261 * Returns the nc_node if found, NULL otherwise.
262 */
263static struct batadv_nc_node
264*batadv_nc_find_nc_node(struct batadv_orig_node *orig_node,
265 struct batadv_orig_node *orig_neigh_node,
266 bool in_coding)
267{
268 struct batadv_nc_node *nc_node, *nc_node_out = NULL;
269 struct list_head *list;
270
271 if (in_coding)
272 list = &orig_neigh_node->in_coding_list;
273 else
274 list = &orig_neigh_node->out_coding_list;
275
276 /* Traverse list of nc_nodes to orig_node */
277 rcu_read_lock();
278 list_for_each_entry_rcu(nc_node, list, list) {
279 if (!batadv_compare_eth(nc_node->addr, orig_node->orig))
280 continue;
281
282 if (!atomic_inc_not_zero(&nc_node->refcount))
283 continue;
284
285 /* Found a match */
286 nc_node_out = nc_node;
287 break;
288 }
289 rcu_read_unlock();
290
291 return nc_node_out;
292}
293
294/**
295 * batadv_nc_get_nc_node - retrieves an nc node or creates the entry if it was
296 * not found
297 * @bat_priv: the bat priv with all the soft interface information
298 * @orig_node: orig node originating the ogm packet
299 * @orig_neigh_node: neighboring orig node from which we received the ogm packet
300 * (can be equal to orig_node)
301 * @in_coding: traverse incoming or outgoing network coding list
302 *
303 * Returns the nc_node if found or created, NULL in case of an error.
304 */
305static struct batadv_nc_node
306*batadv_nc_get_nc_node(struct batadv_priv *bat_priv,
307 struct batadv_orig_node *orig_node,
308 struct batadv_orig_node *orig_neigh_node,
309 bool in_coding)
310{
311 struct batadv_nc_node *nc_node;
312 spinlock_t *lock; /* Used to lock list selected by "int in_coding" */
313 struct list_head *list;
314
315 /* Check if nc_node is already added */
316 nc_node = batadv_nc_find_nc_node(orig_node, orig_neigh_node, in_coding);
317
318 /* Node found */
319 if (nc_node)
320 return nc_node;
321
322 nc_node = kzalloc(sizeof(*nc_node), GFP_ATOMIC);
323 if (!nc_node)
324 return NULL;
325
326 if (!atomic_inc_not_zero(&orig_neigh_node->refcount))
327 goto free;
328
329 /* Initialize nc_node */
330 INIT_LIST_HEAD(&nc_node->list);
331 memcpy(nc_node->addr, orig_node->orig, ETH_ALEN);
332 nc_node->orig_node = orig_neigh_node;
333 atomic_set(&nc_node->refcount, 2);
334
335 /* Select ingoing or outgoing coding node */
336 if (in_coding) {
337 lock = &orig_neigh_node->in_coding_list_lock;
338 list = &orig_neigh_node->in_coding_list;
339 } else {
340 lock = &orig_neigh_node->out_coding_list_lock;
341 list = &orig_neigh_node->out_coding_list;
342 }
343
344 batadv_dbg(BATADV_DBG_NC, bat_priv, "Adding nc_node %pM -> %pM\n",
345 nc_node->addr, nc_node->orig_node->orig);
346
347 /* Add nc_node to orig_node */
348 spin_lock_bh(lock);
349 list_add_tail_rcu(&nc_node->list, list);
350 spin_unlock_bh(lock);
351
352 return nc_node;
353
354free:
355 kfree(nc_node);
356 return NULL;
357}
358
359/**
360 * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node structs
361 * (best called on incoming OGMs)
362 * @bat_priv: the bat priv with all the soft interface information
363 * @orig_node: orig node originating the ogm packet
364 * @orig_neigh_node: neighboring orig node from which we received the ogm packet
365 * (can be equal to orig_node)
366 * @ogm_packet: incoming ogm packet
367 * @is_single_hop_neigh: orig_node is a single hop neighbor
368 */
369void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
370 struct batadv_orig_node *orig_node,
371 struct batadv_orig_node *orig_neigh_node,
372 struct batadv_ogm_packet *ogm_packet,
373 int is_single_hop_neigh)
374{
375 struct batadv_nc_node *in_nc_node = NULL, *out_nc_node = NULL;
376
377 /* Check if network coding is enabled */
378 if (!atomic_read(&bat_priv->network_coding))
379 goto out;
380
381 /* accept ogms from 'good' neighbors and single hop neighbors */
382 if (!batadv_can_nc_with_orig(bat_priv, orig_node, ogm_packet) &&
383 !is_single_hop_neigh)
384 goto out;
385
386 /* Add orig_node as in_nc_node on hop */
387 in_nc_node = batadv_nc_get_nc_node(bat_priv, orig_node,
388 orig_neigh_node, true);
389 if (!in_nc_node)
390 goto out;
391
392 in_nc_node->last_seen = jiffies;
393
394 /* Add hop as out_nc_node on orig_node */
395 out_nc_node = batadv_nc_get_nc_node(bat_priv, orig_neigh_node,
396 orig_node, false);
397 if (!out_nc_node)
398 goto out;
399
400 out_nc_node->last_seen = jiffies;
401
402out:
403 if (in_nc_node)
404 batadv_nc_node_free_ref(in_nc_node);
405 if (out_nc_node)
406 batadv_nc_node_free_ref(out_nc_node);
407}
408
409/**
75 * batadv_nc_free - clean up network coding memory 410 * batadv_nc_free - clean up network coding memory
76 * @bat_priv: the bat priv with all the soft interface information 411 * @bat_priv: the bat priv with all the soft interface information
77 */ 412 */
@@ -79,3 +414,82 @@ void batadv_nc_free(struct batadv_priv *bat_priv)
79{ 414{
80 cancel_delayed_work_sync(&bat_priv->nc.work); 415 cancel_delayed_work_sync(&bat_priv->nc.work);
81} 416}
417
418/**
419 * batadv_nc_nodes_seq_print_text - print the nc node information
420 * @seq: seq file to print on
421 * @offset: not used
422 */
423int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset)
424{
425 struct net_device *net_dev = (struct net_device *)seq->private;
426 struct batadv_priv *bat_priv = netdev_priv(net_dev);
427 struct batadv_hashtable *hash = bat_priv->orig_hash;
428 struct batadv_hard_iface *primary_if;
429 struct hlist_head *head;
430 struct batadv_orig_node *orig_node;
431 struct batadv_nc_node *nc_node;
432 int i;
433
434 primary_if = batadv_seq_print_text_primary_if_get(seq);
435 if (!primary_if)
436 goto out;
437
438 /* Traverse list of originators */
439 for (i = 0; i < hash->size; i++) {
440 head = &hash->table[i];
441
442 /* For each orig_node in this bin */
443 rcu_read_lock();
444 hlist_for_each_entry_rcu(orig_node, head, hash_entry) {
445 seq_printf(seq, "Node: %pM\n", orig_node->orig);
446
447 seq_printf(seq, " Ingoing: ");
448 /* For each in_nc_node to this orig_node */
449 list_for_each_entry_rcu(nc_node,
450 &orig_node->in_coding_list,
451 list)
452 seq_printf(seq, "%pM ",
453 nc_node->addr);
454 seq_printf(seq, "\n");
455
456 seq_printf(seq, " Outgoing: ");
457 /* For out_nc_node to this orig_node */
458 list_for_each_entry_rcu(nc_node,
459 &orig_node->out_coding_list,
460 list)
461 seq_printf(seq, "%pM ",
462 nc_node->addr);
463 seq_printf(seq, "\n\n");
464 }
465 rcu_read_unlock();
466 }
467
468out:
469 if (primary_if)
470 batadv_hardif_free_ref(primary_if);
471 return 0;
472}
473
474/**
475 * batadv_nc_init_debugfs - create nc folder and related files in debugfs
476 * @bat_priv: the bat priv with all the soft interface information
477 */
478int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
479{
480 struct dentry *nc_dir, *file;
481
482 nc_dir = debugfs_create_dir("nc", bat_priv->debug_dir);
483 if (!nc_dir)
484 goto out;
485
486 file = debugfs_create_u8("min_tq", S_IRUGO | S_IWUSR, nc_dir,
487 &bat_priv->nc.min_tq);
488 if (!file)
489 goto out;
490
491 return 0;
492
493out:
494 return -ENOMEM;
495}
diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h
index 7483cba4b5d4..4c56cd98d9de 100644
--- a/net/batman-adv/network-coding.h
+++ b/net/batman-adv/network-coding.h
@@ -24,7 +24,19 @@
24 24
25int batadv_nc_init(struct batadv_priv *bat_priv); 25int batadv_nc_init(struct batadv_priv *bat_priv);
26void batadv_nc_free(struct batadv_priv *bat_priv); 26void batadv_nc_free(struct batadv_priv *bat_priv);
27void batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
28 struct batadv_orig_node *orig_node,
29 struct batadv_orig_node *orig_neigh_node,
30 struct batadv_ogm_packet *ogm_packet,
31 int is_single_hop_neigh);
32void batadv_nc_purge_orig(struct batadv_priv *bat_priv,
33 struct batadv_orig_node *orig_node,
34 bool (*to_purge)(struct batadv_priv *,
35 struct batadv_nc_node *));
27void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv); 36void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv);
37void batadv_nc_init_orig(struct batadv_orig_node *orig_node);
38int batadv_nc_nodes_seq_print_text(struct seq_file *seq, void *offset);
39int batadv_nc_init_debugfs(struct batadv_priv *bat_priv);
28 40
29#else /* ifdef CONFIG_BATMAN_ADV_NC */ 41#else /* ifdef CONFIG_BATMAN_ADV_NC */
30 42
@@ -38,11 +50,46 @@ static inline void batadv_nc_free(struct batadv_priv *bat_priv)
38 return; 50 return;
39} 51}
40 52
53static inline void
54batadv_nc_update_nc_node(struct batadv_priv *bat_priv,
55 struct batadv_orig_node *orig_node,
56 struct batadv_orig_node *orig_neigh_node,
57 struct batadv_ogm_packet *ogm_packet,
58 int is_single_hop_neigh)
59{
60 return;
61}
62
63static inline void
64batadv_nc_purge_orig(struct batadv_priv *bat_priv,
65 struct batadv_orig_node *orig_node,
66 bool (*to_purge)(struct batadv_priv *,
67 struct batadv_nc_node *))
68{
69 return;
70}
71
41static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv) 72static inline void batadv_nc_init_bat_priv(struct batadv_priv *bat_priv)
42{ 73{
43 return; 74 return;
44} 75}
45 76
77static inline void batadv_nc_init_orig(struct batadv_orig_node *orig_node)
78{
79 return;
80}
81
82static inline int batadv_nc_nodes_seq_print_text(struct seq_file *seq,
83 void *offset)
84{
85 return 0;
86}
87
88static inline int batadv_nc_init_debugfs(struct batadv_priv *bat_priv)
89{
90 return 0;
91}
92
46#endif /* ifdef CONFIG_BATMAN_ADV_NC */ 93#endif /* ifdef CONFIG_BATMAN_ADV_NC */
47 94
48#endif /* _NET_BATMAN_ADV_NETWORK_CODING_H_ */ 95#endif /* _NET_BATMAN_ADV_NETWORK_CODING_H_ */
diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c
index 96fb80b724dc..585e684a380b 100644
--- a/net/batman-adv/originator.c
+++ b/net/batman-adv/originator.c
@@ -28,6 +28,7 @@
28#include "unicast.h" 28#include "unicast.h"
29#include "soft-interface.h" 29#include "soft-interface.h"
30#include "bridge_loop_avoidance.h" 30#include "bridge_loop_avoidance.h"
31#include "network-coding.h"
31 32
32/* hash class keys */ 33/* hash class keys */
33static struct lock_class_key batadv_orig_hash_lock_class_key; 34static struct lock_class_key batadv_orig_hash_lock_class_key;
@@ -142,6 +143,9 @@ static void batadv_orig_node_free_rcu(struct rcu_head *rcu)
142 143
143 spin_unlock_bh(&orig_node->neigh_list_lock); 144 spin_unlock_bh(&orig_node->neigh_list_lock);
144 145
146 /* Free nc_nodes */
147 batadv_nc_purge_orig(orig_node->bat_priv, orig_node, NULL);
148
145 batadv_frag_list_free(&orig_node->frag_list); 149 batadv_frag_list_free(&orig_node->frag_list);
146 batadv_tt_global_del_orig(orig_node->bat_priv, orig_node, 150 batadv_tt_global_del_orig(orig_node->bat_priv, orig_node,
147 "originator timed out"); 151 "originator timed out");
@@ -219,6 +223,8 @@ struct batadv_orig_node *batadv_get_orig_node(struct batadv_priv *bat_priv,
219 spin_lock_init(&orig_node->neigh_list_lock); 223 spin_lock_init(&orig_node->neigh_list_lock);
220 spin_lock_init(&orig_node->tt_buff_lock); 224 spin_lock_init(&orig_node->tt_buff_lock);
221 225
226 batadv_nc_init_orig(orig_node);
227
222 /* extra reference for return */ 228 /* extra reference for return */
223 atomic_set(&orig_node->refcount, 2); 229 atomic_set(&orig_node->refcount, 2);
224 230
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 83bfe7c38f81..1544ab40bedd 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -128,6 +128,10 @@ struct batadv_hard_iface {
128 * @bond_list: list of bonding candidates 128 * @bond_list: list of bonding candidates
129 * @refcount: number of contexts the object is used 129 * @refcount: number of contexts the object is used
130 * @rcu: struct used for freeing in an RCU-safe manner 130 * @rcu: struct used for freeing in an RCU-safe manner
131 * @in_coding_list: list of nodes this orig can hear
132 * @out_coding_list: list of nodes that can hear this orig
133 * @in_coding_list_lock: protects in_coding_list
134 * @out_coding_list_lock: protects out_coding_list
131 */ 135 */
132struct batadv_orig_node { 136struct batadv_orig_node {
133 uint8_t orig[ETH_ALEN]; 137 uint8_t orig[ETH_ALEN];
@@ -171,6 +175,12 @@ struct batadv_orig_node {
171 struct list_head bond_list; 175 struct list_head bond_list;
172 atomic_t refcount; 176 atomic_t refcount;
173 struct rcu_head rcu; 177 struct rcu_head rcu;
178#ifdef CONFIG_BATMAN_ADV_NC
179 struct list_head in_coding_list;
180 struct list_head out_coding_list;
181 spinlock_t in_coding_list_lock; /* Protects in_coding_list */
182 spinlock_t out_coding_list_lock; /* Protects out_coding_list */
183#endif
174}; 184};
175 185
176/** 186/**
@@ -430,9 +440,13 @@ struct batadv_priv_dat {
430/** 440/**
431 * struct batadv_priv_nc - per mesh interface network coding private data 441 * struct batadv_priv_nc - per mesh interface network coding private data
432 * @work: work queue callback item for cleanup 442 * @work: work queue callback item for cleanup
443 * @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
444 * @min_tq: only consider neighbors for encoding if neigh_tq > min_tq
433 */ 445 */
434struct batadv_priv_nc { 446struct batadv_priv_nc {
435 struct delayed_work work; 447 struct delayed_work work;
448 struct dentry *debug_dir;
449 u8 min_tq;
436}; 450};
437 451
438/** 452/**
@@ -716,6 +730,24 @@ struct batadv_tt_roam_node {
716}; 730};
717 731
718/** 732/**
733 * struct batadv_nc_node - network coding node
734 * @list: next and prev pointer for the list handling
735 * @addr: the node's mac address
736 * @refcount: number of contexts the object is used by
737 * @rcu: struct used for freeing in an RCU-safe manner
738 * @orig_node: pointer to corresponding orig node struct
739 * @last_seen: timestamp of last ogm received from this node
740 */
741struct batadv_nc_node {
742 struct list_head list;
743 uint8_t addr[ETH_ALEN];
744 atomic_t refcount;
745 struct rcu_head rcu;
746 struct batadv_orig_node *orig_node;
747 unsigned long last_seen;
748};
749
750/**
719 * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded 751 * struct batadv_forw_packet - structure for bcast packets to be sent/forwarded
720 * @list: list node for batadv_socket_client::queue_list 752 * @list: list node for batadv_socket_client::queue_list
721 * @send_time: execution time for delayed_work (packet sending) 753 * @send_time: execution time for delayed_work (packet sending)