xref: /linux/net/batman-adv/originator.c (revision 74ef115359f5beb565baddfb250f264d9177c108)
1 /*
2  * Copyright (C) 2009-2010 B.A.T.M.A.N. contributors:
3  *
4  * Marek Lindner, Simon Wunderlich
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301, USA
19  *
20  */
21 
22 /* increase the reference counter for this originator */
23 
24 #include "main.h"
25 #include "originator.h"
26 #include "hash.h"
27 #include "translation-table.h"
28 #include "routing.h"
29 #include "gateway_client.h"
30 #include "hard-interface.h"
31 #include "unicast.h"
32 #include "soft-interface.h"
33 
34 static void purge_orig(struct work_struct *work);
35 
36 static void start_purge_timer(struct bat_priv *bat_priv)
37 {
38 	INIT_DELAYED_WORK(&bat_priv->orig_work, purge_orig);
39 	queue_delayed_work(bat_event_workqueue, &bat_priv->orig_work, 1 * HZ);
40 }
41 
42 int originator_init(struct bat_priv *bat_priv)
43 {
44 	if (bat_priv->orig_hash)
45 		return 1;
46 
47 	spin_lock_bh(&bat_priv->orig_hash_lock);
48 	bat_priv->orig_hash = hash_new(1024);
49 
50 	if (!bat_priv->orig_hash)
51 		goto err;
52 
53 	spin_unlock_bh(&bat_priv->orig_hash_lock);
54 	start_purge_timer(bat_priv);
55 	return 1;
56 
57 err:
58 	spin_unlock_bh(&bat_priv->orig_hash_lock);
59 	return 0;
60 }
61 
62 struct neigh_node *
63 create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node,
64 		uint8_t *neigh, struct batman_if *if_incoming)
65 {
66 	struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
67 	struct neigh_node *neigh_node;
68 
69 	bat_dbg(DBG_BATMAN, bat_priv,
70 		"Creating new last-hop neighbor of originator\n");
71 
72 	neigh_node = kzalloc(sizeof(struct neigh_node), GFP_ATOMIC);
73 	if (!neigh_node)
74 		return NULL;
75 
76 	INIT_LIST_HEAD(&neigh_node->list);
77 
78 	memcpy(neigh_node->addr, neigh, ETH_ALEN);
79 	neigh_node->orig_node = orig_neigh_node;
80 	neigh_node->if_incoming = if_incoming;
81 
82 	list_add_tail(&neigh_node->list, &orig_node->neigh_list);
83 	return neigh_node;
84 }
85 
86 static void free_orig_node(void *data, void *arg)
87 {
88 	struct list_head *list_pos, *list_pos_tmp;
89 	struct neigh_node *neigh_node;
90 	struct orig_node *orig_node = (struct orig_node *)data;
91 	struct bat_priv *bat_priv = (struct bat_priv *)arg;
92 
93 	/* for all neighbors towards this originator ... */
94 	list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
95 		neigh_node = list_entry(list_pos, struct neigh_node, list);
96 
97 		list_del(list_pos);
98 		kfree(neigh_node);
99 	}
100 
101 	frag_list_free(&orig_node->frag_list);
102 	hna_global_del_orig(bat_priv, orig_node, "originator timed out");
103 
104 	kfree(orig_node->bcast_own);
105 	kfree(orig_node->bcast_own_sum);
106 	kfree(orig_node);
107 }
108 
109 void originator_free(struct bat_priv *bat_priv)
110 {
111 	if (!bat_priv->orig_hash)
112 		return;
113 
114 	cancel_delayed_work_sync(&bat_priv->orig_work);
115 
116 	spin_lock_bh(&bat_priv->orig_hash_lock);
117 	hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
118 	bat_priv->orig_hash = NULL;
119 	spin_unlock_bh(&bat_priv->orig_hash_lock);
120 }
121 
122 /* this function finds or creates an originator entry for the given
123  * address if it does not exits */
124 struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
125 {
126 	struct orig_node *orig_node;
127 	int size;
128 	int hash_added;
129 
130 	orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
131 						   compare_orig, choose_orig,
132 						   addr));
133 
134 	if (orig_node)
135 		return orig_node;
136 
137 	bat_dbg(DBG_BATMAN, bat_priv,
138 		"Creating new originator: %pM\n", addr);
139 
140 	orig_node = kzalloc(sizeof(struct orig_node), GFP_ATOMIC);
141 	if (!orig_node)
142 		return NULL;
143 
144 	INIT_LIST_HEAD(&orig_node->neigh_list);
145 
146 	memcpy(orig_node->orig, addr, ETH_ALEN);
147 	orig_node->router = NULL;
148 	orig_node->hna_buff = NULL;
149 	orig_node->bcast_seqno_reset = jiffies - 1
150 					- msecs_to_jiffies(RESET_PROTECTION_MS);
151 	orig_node->batman_seqno_reset = jiffies - 1
152 					- msecs_to_jiffies(RESET_PROTECTION_MS);
153 
154 	size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS;
155 
156 	orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
157 	if (!orig_node->bcast_own)
158 		goto free_orig_node;
159 
160 	size = bat_priv->num_ifaces * sizeof(uint8_t);
161 	orig_node->bcast_own_sum = kzalloc(size, GFP_ATOMIC);
162 
163 	INIT_LIST_HEAD(&orig_node->frag_list);
164 	orig_node->last_frag_packet = 0;
165 
166 	if (!orig_node->bcast_own_sum)
167 		goto free_bcast_own;
168 
169 	hash_added = hash_add(bat_priv->orig_hash, compare_orig, choose_orig,
170 			      orig_node);
171 	if (hash_added < 0)
172 		goto free_bcast_own_sum;
173 
174 	return orig_node;
175 free_bcast_own_sum:
176 	kfree(orig_node->bcast_own_sum);
177 free_bcast_own:
178 	kfree(orig_node->bcast_own);
179 free_orig_node:
180 	kfree(orig_node);
181 	return NULL;
182 }
183 
184 static bool purge_orig_neighbors(struct bat_priv *bat_priv,
185 				 struct orig_node *orig_node,
186 				 struct neigh_node **best_neigh_node)
187 {
188 	struct list_head *list_pos, *list_pos_tmp;
189 	struct neigh_node *neigh_node;
190 	bool neigh_purged = false;
191 
192 	*best_neigh_node = NULL;
193 
194 	/* for all neighbors towards this originator ... */
195 	list_for_each_safe(list_pos, list_pos_tmp, &orig_node->neigh_list) {
196 		neigh_node = list_entry(list_pos, struct neigh_node, list);
197 
198 		if ((time_after(jiffies,
199 			neigh_node->last_valid + PURGE_TIMEOUT * HZ)) ||
200 		    (neigh_node->if_incoming->if_status == IF_INACTIVE) ||
201 		    (neigh_node->if_incoming->if_status == IF_TO_BE_REMOVED)) {
202 
203 			if (neigh_node->if_incoming->if_status ==
204 							IF_TO_BE_REMOVED)
205 				bat_dbg(DBG_BATMAN, bat_priv,
206 					"neighbor purge: originator %pM, "
207 					"neighbor: %pM, iface: %s\n",
208 					orig_node->orig, neigh_node->addr,
209 					neigh_node->if_incoming->net_dev->name);
210 			else
211 				bat_dbg(DBG_BATMAN, bat_priv,
212 					"neighbor timeout: originator %pM, "
213 					"neighbor: %pM, last_valid: %lu\n",
214 					orig_node->orig, neigh_node->addr,
215 					(neigh_node->last_valid / HZ));
216 
217 			neigh_purged = true;
218 			list_del(list_pos);
219 			kfree(neigh_node);
220 		} else {
221 			if ((!*best_neigh_node) ||
222 			    (neigh_node->tq_avg > (*best_neigh_node)->tq_avg))
223 				*best_neigh_node = neigh_node;
224 		}
225 	}
226 	return neigh_purged;
227 }
228 
229 static bool purge_orig_node(struct bat_priv *bat_priv,
230 			    struct orig_node *orig_node)
231 {
232 	struct neigh_node *best_neigh_node;
233 
234 	if (time_after(jiffies,
235 		orig_node->last_valid + 2 * PURGE_TIMEOUT * HZ)) {
236 
237 		bat_dbg(DBG_BATMAN, bat_priv,
238 			"Originator timeout: originator %pM, last_valid %lu\n",
239 			orig_node->orig, (orig_node->last_valid / HZ));
240 		return true;
241 	} else {
242 		if (purge_orig_neighbors(bat_priv, orig_node,
243 							&best_neigh_node)) {
244 			update_routes(bat_priv, orig_node,
245 				      best_neigh_node,
246 				      orig_node->hna_buff,
247 				      orig_node->hna_buff_len);
248 			/* update bonding candidates, we could have lost
249 			 * some candidates. */
250 			update_bonding_candidates(orig_node);
251 		}
252 	}
253 
254 	return false;
255 }
256 
257 static void _purge_orig(struct bat_priv *bat_priv)
258 {
259 	struct hashtable_t *hash = bat_priv->orig_hash;
260 	struct hlist_node *walk, *safe;
261 	struct hlist_head *head;
262 	struct element_t *bucket;
263 	struct orig_node *orig_node;
264 	int i;
265 
266 	if (!hash)
267 		return;
268 
269 	spin_lock_bh(&bat_priv->orig_hash_lock);
270 
271 	/* for all origins... */
272 	for (i = 0; i < hash->size; i++) {
273 		head = &hash->table[i];
274 
275 		hlist_for_each_entry_safe(bucket, walk, safe, head, hlist) {
276 			orig_node = bucket->data;
277 
278 			if (purge_orig_node(bat_priv, orig_node)) {
279 				if (orig_node->gw_flags)
280 					gw_node_delete(bat_priv, orig_node);
281 				hlist_del(walk);
282 				kfree(bucket);
283 				free_orig_node(orig_node, bat_priv);
284 			}
285 
286 			if (time_after(jiffies, orig_node->last_frag_packet +
287 						msecs_to_jiffies(FRAG_TIMEOUT)))
288 				frag_list_free(&orig_node->frag_list);
289 		}
290 	}
291 
292 	spin_unlock_bh(&bat_priv->orig_hash_lock);
293 
294 	gw_node_purge(bat_priv);
295 	gw_election(bat_priv);
296 
297 	softif_neigh_purge(bat_priv);
298 }
299 
300 static void purge_orig(struct work_struct *work)
301 {
302 	struct delayed_work *delayed_work =
303 		container_of(work, struct delayed_work, work);
304 	struct bat_priv *bat_priv =
305 		container_of(delayed_work, struct bat_priv, orig_work);
306 
307 	_purge_orig(bat_priv);
308 	start_purge_timer(bat_priv);
309 }
310 
311 void purge_orig_ref(struct bat_priv *bat_priv)
312 {
313 	_purge_orig(bat_priv);
314 }
315 
316 int orig_seq_print_text(struct seq_file *seq, void *offset)
317 {
318 	struct net_device *net_dev = (struct net_device *)seq->private;
319 	struct bat_priv *bat_priv = netdev_priv(net_dev);
320 	struct hashtable_t *hash = bat_priv->orig_hash;
321 	struct hlist_node *walk;
322 	struct hlist_head *head;
323 	struct element_t *bucket;
324 	struct orig_node *orig_node;
325 	struct neigh_node *neigh_node;
326 	int batman_count = 0;
327 	int last_seen_secs;
328 	int last_seen_msecs;
329 	int i;
330 
331 	if ((!bat_priv->primary_if) ||
332 	    (bat_priv->primary_if->if_status != IF_ACTIVE)) {
333 		if (!bat_priv->primary_if)
334 			return seq_printf(seq, "BATMAN mesh %s disabled - "
335 				     "please specify interfaces to enable it\n",
336 				     net_dev->name);
337 
338 		return seq_printf(seq, "BATMAN mesh %s "
339 				  "disabled - primary interface not active\n",
340 				  net_dev->name);
341 	}
342 
343 	seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n",
344 		   SOURCE_VERSION, REVISION_VERSION_STR,
345 		   bat_priv->primary_if->net_dev->name,
346 		   bat_priv->primary_if->net_dev->dev_addr, net_dev->name);
347 	seq_printf(seq, "  %-15s %s (%s/%i) %17s [%10s]: %20s ...\n",
348 		   "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
349 		   "outgoingIF", "Potential nexthops");
350 
351 	spin_lock_bh(&bat_priv->orig_hash_lock);
352 
353 	for (i = 0; i < hash->size; i++) {
354 		head = &hash->table[i];
355 
356 		hlist_for_each_entry(bucket, walk, head, hlist) {
357 			orig_node = bucket->data;
358 
359 			if (!orig_node->router)
360 				continue;
361 
362 			if (orig_node->router->tq_avg == 0)
363 				continue;
364 
365 			last_seen_secs = jiffies_to_msecs(jiffies -
366 						orig_node->last_valid) / 1000;
367 			last_seen_msecs = jiffies_to_msecs(jiffies -
368 						orig_node->last_valid) % 1000;
369 
370 			neigh_node = orig_node->router;
371 			seq_printf(seq, "%pM %4i.%03is   (%3i) %pM [%10s]:",
372 				   orig_node->orig, last_seen_secs,
373 				   last_seen_msecs, neigh_node->tq_avg,
374 				   neigh_node->addr,
375 				   neigh_node->if_incoming->net_dev->name);
376 
377 			list_for_each_entry(neigh_node, &orig_node->neigh_list,
378 					    list) {
379 				seq_printf(seq, " %pM (%3i)", neigh_node->addr,
380 						neigh_node->tq_avg);
381 			}
382 
383 			seq_printf(seq, "\n");
384 			batman_count++;
385 		}
386 	}
387 
388 	spin_unlock_bh(&bat_priv->orig_hash_lock);
389 
390 	if ((batman_count == 0))
391 		seq_printf(seq, "No batman nodes in range ...\n");
392 
393 	return 0;
394 }
395 
396 static int orig_node_add_if(struct orig_node *orig_node, int max_if_num)
397 {
398 	void *data_ptr;
399 
400 	data_ptr = kmalloc(max_if_num * sizeof(unsigned long) * NUM_WORDS,
401 			   GFP_ATOMIC);
402 	if (!data_ptr) {
403 		pr_err("Can't resize orig: out of memory\n");
404 		return -1;
405 	}
406 
407 	memcpy(data_ptr, orig_node->bcast_own,
408 	       (max_if_num - 1) * sizeof(unsigned long) * NUM_WORDS);
409 	kfree(orig_node->bcast_own);
410 	orig_node->bcast_own = data_ptr;
411 
412 	data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
413 	if (!data_ptr) {
414 		pr_err("Can't resize orig: out of memory\n");
415 		return -1;
416 	}
417 
418 	memcpy(data_ptr, orig_node->bcast_own_sum,
419 	       (max_if_num - 1) * sizeof(uint8_t));
420 	kfree(orig_node->bcast_own_sum);
421 	orig_node->bcast_own_sum = data_ptr;
422 
423 	return 0;
424 }
425 
426 int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
427 {
428 	struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
429 	struct hashtable_t *hash = bat_priv->orig_hash;
430 	struct hlist_node *walk;
431 	struct hlist_head *head;
432 	struct element_t *bucket;
433 	struct orig_node *orig_node;
434 	int i;
435 
436 	/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
437 	 * if_num */
438 	spin_lock_bh(&bat_priv->orig_hash_lock);
439 
440 	for (i = 0; i < hash->size; i++) {
441 		head = &hash->table[i];
442 
443 		hlist_for_each_entry(bucket, walk, head, hlist) {
444 			orig_node = bucket->data;
445 
446 			if (orig_node_add_if(orig_node, max_if_num) == -1)
447 				goto err;
448 		}
449 	}
450 
451 	spin_unlock_bh(&bat_priv->orig_hash_lock);
452 	return 0;
453 
454 err:
455 	spin_unlock_bh(&bat_priv->orig_hash_lock);
456 	return -ENOMEM;
457 }
458 
459 static int orig_node_del_if(struct orig_node *orig_node,
460 		     int max_if_num, int del_if_num)
461 {
462 	void *data_ptr = NULL;
463 	int chunk_size;
464 
465 	/* last interface was removed */
466 	if (max_if_num == 0)
467 		goto free_bcast_own;
468 
469 	chunk_size = sizeof(unsigned long) * NUM_WORDS;
470 	data_ptr = kmalloc(max_if_num * chunk_size, GFP_ATOMIC);
471 	if (!data_ptr) {
472 		pr_err("Can't resize orig: out of memory\n");
473 		return -1;
474 	}
475 
476 	/* copy first part */
477 	memcpy(data_ptr, orig_node->bcast_own, del_if_num * chunk_size);
478 
479 	/* copy second part */
480 	memcpy(data_ptr + del_if_num * chunk_size,
481 	       orig_node->bcast_own + ((del_if_num + 1) * chunk_size),
482 	       (max_if_num - del_if_num) * chunk_size);
483 
484 free_bcast_own:
485 	kfree(orig_node->bcast_own);
486 	orig_node->bcast_own = data_ptr;
487 
488 	if (max_if_num == 0)
489 		goto free_own_sum;
490 
491 	data_ptr = kmalloc(max_if_num * sizeof(uint8_t), GFP_ATOMIC);
492 	if (!data_ptr) {
493 		pr_err("Can't resize orig: out of memory\n");
494 		return -1;
495 	}
496 
497 	memcpy(data_ptr, orig_node->bcast_own_sum,
498 	       del_if_num * sizeof(uint8_t));
499 
500 	memcpy(data_ptr + del_if_num * sizeof(uint8_t),
501 	       orig_node->bcast_own_sum + ((del_if_num + 1) * sizeof(uint8_t)),
502 	       (max_if_num - del_if_num) * sizeof(uint8_t));
503 
504 free_own_sum:
505 	kfree(orig_node->bcast_own_sum);
506 	orig_node->bcast_own_sum = data_ptr;
507 
508 	return 0;
509 }
510 
511 int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
512 {
513 	struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
514 	struct hashtable_t *hash = bat_priv->orig_hash;
515 	struct hlist_node *walk;
516 	struct hlist_head *head;
517 	struct element_t *bucket;
518 	struct batman_if *batman_if_tmp;
519 	struct orig_node *orig_node;
520 	int i, ret;
521 
522 	/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
523 	 * if_num */
524 	spin_lock_bh(&bat_priv->orig_hash_lock);
525 
526 	for (i = 0; i < hash->size; i++) {
527 		head = &hash->table[i];
528 
529 		hlist_for_each_entry(bucket, walk, head, hlist) {
530 			orig_node = bucket->data;
531 
532 			ret = orig_node_del_if(orig_node, max_if_num,
533 					batman_if->if_num);
534 
535 			if (ret == -1)
536 				goto err;
537 		}
538 	}
539 
540 	/* renumber remaining batman interfaces _inside_ of orig_hash_lock */
541 	rcu_read_lock();
542 	list_for_each_entry_rcu(batman_if_tmp, &if_list, list) {
543 		if (batman_if_tmp->if_status == IF_NOT_IN_USE)
544 			continue;
545 
546 		if (batman_if == batman_if_tmp)
547 			continue;
548 
549 		if (batman_if->soft_iface != batman_if_tmp->soft_iface)
550 			continue;
551 
552 		if (batman_if_tmp->if_num > batman_if->if_num)
553 			batman_if_tmp->if_num--;
554 	}
555 	rcu_read_unlock();
556 
557 	batman_if->if_num = -1;
558 	spin_unlock_bh(&bat_priv->orig_hash_lock);
559 	return 0;
560 
561 err:
562 	spin_unlock_bh(&bat_priv->orig_hash_lock);
563 	return -ENOMEM;
564 }
565