1 /** @file
2  * @brief Route handling.
3  *
4  */
5 
6 /*
7  * Copyright (c) 2016 Intel Corporation
8  *
9  * SPDX-License-Identifier: Apache-2.0
10  */
11 
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_route, CONFIG_NET_ROUTE_LOG_LEVEL);
14 
15 #include <zephyr/kernel.h>
16 #include <limits.h>
17 #include <zephyr/types.h>
18 #include <zephyr/sys/slist.h>
19 
20 #include <zephyr/net/net_pkt.h>
21 #include <zephyr/net/net_core.h>
22 #include <zephyr/net/net_stats.h>
23 #include <zephyr/net/net_mgmt.h>
24 #include <zephyr/net/net_ip.h>
25 
26 #include "net_private.h"
27 #include "ipv6.h"
28 #include "icmpv6.h"
29 #include "nbr.h"
30 #include "route.h"
31 
32 /* We keep track of the routes in a separate list so that we can remove
33  * the oldest routes (at tail) if needed.
34  */
35 static sys_slist_t routes;
36 
37 /* Track currently active route lifetime timers */
38 static sys_slist_t active_route_lifetime_timers;
39 
40 /* Timer that manages expired route entries. */
41 static struct k_work_delayable route_lifetime_timer;
42 
net_route_nexthop_remove(struct net_nbr * nbr)43 static void net_route_nexthop_remove(struct net_nbr *nbr)
44 {
45 	NET_DBG("Nexthop %p removed", nbr);
46 }
47 
48 /*
49  * This pool contains information next hop neighbors.
50  */
51 NET_NBR_POOL_INIT(net_route_nexthop_pool,
52 		  CONFIG_NET_MAX_NEXTHOPS,
53 		  sizeof(struct net_route_nexthop),
54 		  net_route_nexthop_remove);
55 
net_nexthop_data(struct net_nbr * nbr)56 static inline struct net_route_nexthop *net_nexthop_data(struct net_nbr *nbr)
57 {
58 	return (struct net_route_nexthop *)nbr->data;
59 }
60 
get_nexthop_nbr(struct net_nbr * start,int idx)61 static inline struct net_nbr *get_nexthop_nbr(struct net_nbr *start, int idx)
62 {
63 	NET_ASSERT(idx < CONFIG_NET_MAX_NEXTHOPS, "idx %d >= max %d",
64 		   idx, CONFIG_NET_MAX_NEXTHOPS);
65 
66 	return (struct net_nbr *)((uint8_t *)start +
67 			((sizeof(struct net_nbr) + start->size) * idx));
68 }
69 
release_nexthop_route(struct net_route_nexthop * route_nexthop)70 static void release_nexthop_route(struct net_route_nexthop *route_nexthop)
71 {
72 	struct net_nbr *nbr = CONTAINER_OF((uint8_t *)route_nexthop, struct net_nbr, __nbr[0]);
73 
74 	net_nbr_unref(nbr);
75 }
76 
get_nexthop_route(void)77 static struct net_nbr *get_nexthop_route(void)
78 {
79 	int i;
80 
81 	for (i = 0; i < CONFIG_NET_MAX_NEXTHOPS; i++) {
82 		struct net_nbr *nbr = get_nexthop_nbr(
83 			(struct net_nbr *)net_route_nexthop_pool, i);
84 
85 		if (!nbr->ref) {
86 			nbr->data = nbr->__nbr;
87 
88 			nbr->idx = NET_NBR_LLADDR_UNKNOWN;
89 
90 			return net_nbr_ref(nbr);
91 		}
92 	}
93 
94 	return NULL;
95 }
96 
net_route_entry_remove(struct net_nbr * nbr)97 static void net_route_entry_remove(struct net_nbr *nbr)
98 {
99 	NET_DBG("Route %p removed", nbr);
100 }
101 
net_route_entries_table_clear(struct net_nbr_table * table)102 static void net_route_entries_table_clear(struct net_nbr_table *table)
103 {
104 	NET_DBG("Route table %p cleared", table);
105 }
106 
107 /*
108  * This pool contains routing table entries.
109  */
110 NET_NBR_POOL_INIT(net_route_entries_pool,
111 		  CONFIG_NET_MAX_ROUTES,
112 		  sizeof(struct net_route_entry),
113 		  net_route_entry_remove);
114 
115 NET_NBR_TABLE_INIT(NET_NBR_LOCAL, nbr_routes, net_route_entries_pool,
116 		   net_route_entries_table_clear);
117 
get_nbr(int idx)118 static inline struct net_nbr *get_nbr(int idx)
119 {
120 	return &net_route_entries_pool[idx].nbr;
121 }
122 
net_route_data(struct net_nbr * nbr)123 static inline struct net_route_entry *net_route_data(struct net_nbr *nbr)
124 {
125 	return (struct net_route_entry *)nbr->data;
126 }
127 
net_route_get_nbr(struct net_route_entry * route)128 struct net_nbr *net_route_get_nbr(struct net_route_entry *route)
129 {
130 	struct net_nbr *ret = NULL;
131 	int i;
132 
133 	NET_ASSERT(route);
134 
135 	net_ipv6_nbr_lock();
136 
137 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
138 		struct net_nbr *nbr = get_nbr(i);
139 
140 		if (!nbr->ref) {
141 			continue;
142 		}
143 
144 		if (nbr->data == (uint8_t *)route) {
145 			if (!nbr->ref) {
146 				break;
147 			}
148 
149 			ret = nbr;
150 			break;
151 		}
152 	}
153 
154 	net_ipv6_nbr_unlock();
155 	return ret;
156 }
157 
net_routes_print(void)158 void net_routes_print(void)
159 {
160 	int i;
161 
162 	net_ipv6_nbr_lock();
163 
164 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
165 		struct net_nbr *nbr = get_nbr(i);
166 
167 		if (!nbr->ref) {
168 			continue;
169 		}
170 
171 		NET_DBG("[%d] %p %d addr %s/%d",
172 			i, nbr, nbr->ref,
173 			net_sprint_ipv6_addr(&net_route_data(nbr)->addr),
174 			net_route_data(nbr)->prefix_len);
175 		NET_DBG("    iface %p idx %d ll %s",
176 			nbr->iface, nbr->idx,
177 			nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
178 			net_sprint_ll_addr(
179 				net_nbr_get_lladdr(nbr->idx)->addr,
180 				net_nbr_get_lladdr(nbr->idx)->len));
181 	}
182 
183 	net_ipv6_nbr_unlock();
184 }
185 
nbr_free(struct net_nbr * nbr)186 static inline void nbr_free(struct net_nbr *nbr)
187 {
188 	NET_DBG("nbr %p", nbr);
189 
190 	net_nbr_unref(nbr);
191 }
192 
nbr_new(struct net_if * iface,struct in6_addr * addr,uint8_t prefix_len)193 static struct net_nbr *nbr_new(struct net_if *iface,
194 			       struct in6_addr *addr,
195 			       uint8_t prefix_len)
196 {
197 	struct net_nbr *nbr = net_nbr_get(&net_nbr_routes.table);
198 
199 	if (!nbr) {
200 		return NULL;
201 	}
202 
203 	nbr->iface = iface;
204 
205 	net_ipaddr_copy(&net_route_data(nbr)->addr, addr);
206 	net_route_data(nbr)->prefix_len = prefix_len;
207 
208 	NET_DBG("[%d] nbr %p iface %p IPv6 %s/%d",
209 		nbr->idx, nbr, iface,
210 		net_sprint_ipv6_addr(&net_route_data(nbr)->addr),
211 		prefix_len);
212 
213 	return nbr;
214 }
215 
nbr_nexthop_get(struct net_if * iface,struct in6_addr * addr)216 static struct net_nbr *nbr_nexthop_get(struct net_if *iface,
217 				       struct in6_addr *addr)
218 {
219 	/* Note that the nexthop host must be already in the neighbor
220 	 * cache. We just increase the ref count of an existing entry.
221 	 */
222 	struct net_nbr *nbr;
223 
224 	nbr = net_ipv6_nbr_lookup(iface, addr);
225 	if (nbr == NULL) {
226 		NET_DBG("Next hop neighbor not found!");
227 		return NULL;
228 	}
229 
230 	net_nbr_ref(nbr);
231 
232 	NET_DBG("[%d] nbr %p iface %p IPv6 %s",
233 		nbr->idx, nbr, iface,
234 		net_sprint_ipv6_addr(addr));
235 
236 	return nbr;
237 }
238 
nbr_nexthop_put(struct net_nbr * nbr)239 static int nbr_nexthop_put(struct net_nbr *nbr)
240 {
241 	NET_ASSERT(nbr);
242 
243 	NET_DBG("[%d] nbr %p iface %p", nbr->idx, nbr, nbr->iface);
244 
245 	net_nbr_unref(nbr);
246 
247 	return 0;
248 }
249 
250 #define net_route_info(str, route, dst)					\
251 	do {								\
252 	if (CONFIG_NET_ROUTE_LOG_LEVEL >= LOG_LEVEL_DBG) {		\
253 		struct in6_addr *naddr = net_route_get_nexthop(route);	\
254 									\
255 		NET_ASSERT(naddr, "Unknown nexthop address");	\
256 									\
257 		NET_DBG("%s route to %s via %s (iface %p)", str,	\
258 			net_sprint_ipv6_addr(dst),		\
259 			net_sprint_ipv6_addr(naddr),	\
260 			route->iface);					\
261 	} } while (false)
262 
263 /* Route was accessed, so place it in front of the routes list */
update_route_access(struct net_route_entry * route)264 static inline void update_route_access(struct net_route_entry *route)
265 {
266 	sys_slist_find_and_remove(&routes, &route->node);
267 	sys_slist_prepend(&routes, &route->node);
268 }
269 
net_route_lookup(struct net_if * iface,struct in6_addr * dst)270 struct net_route_entry *net_route_lookup(struct net_if *iface,
271 					 struct in6_addr *dst)
272 {
273 	struct net_route_entry *route, *found = NULL;
274 	uint8_t longest_match = 0U;
275 	int i;
276 
277 	net_ipv6_nbr_lock();
278 
279 	for (i = 0; i < CONFIG_NET_MAX_ROUTES && longest_match < 128; i++) {
280 		struct net_nbr *nbr = get_nbr(i);
281 
282 		if (!nbr->ref) {
283 			continue;
284 		}
285 
286 		if (iface && nbr->iface != iface) {
287 			continue;
288 		}
289 
290 		route = net_route_data(nbr);
291 
292 		if (route->prefix_len >= longest_match &&
293 		    net_ipv6_is_prefix(dst->s6_addr,
294 				       route->addr.s6_addr,
295 				       route->prefix_len)) {
296 			found = route;
297 			longest_match = route->prefix_len;
298 		}
299 	}
300 
301 	if (found) {
302 		net_route_info("Found", found, dst);
303 
304 		update_route_access(found);
305 	}
306 
307 	net_ipv6_nbr_unlock();
308 	return found;
309 }
310 
route_preference_is_lower(uint8_t old,uint8_t new)311 static inline bool route_preference_is_lower(uint8_t old, uint8_t new)
312 {
313 	if (new == NET_ROUTE_PREFERENCE_RESERVED || (new & 0xfc) != 0) {
314 		return true;
315 	}
316 
317 	/* Transform valid preference values into comparable integers */
318 	old = (old + 1) & 0x3;
319 	new = (new + 1) & 0x3;
320 
321 	return new < old;
322 }
323 
net_route_add(struct net_if * iface,struct in6_addr * addr,uint8_t prefix_len,struct in6_addr * nexthop,uint32_t lifetime,uint8_t preference)324 struct net_route_entry *net_route_add(struct net_if *iface,
325 				      struct in6_addr *addr,
326 				      uint8_t prefix_len,
327 				      struct in6_addr *nexthop,
328 				      uint32_t lifetime,
329 				      uint8_t preference)
330 {
331 	struct net_linkaddr_storage *nexthop_lladdr;
332 	struct net_nbr *nbr, *nbr_nexthop, *tmp;
333 	struct net_route_nexthop *nexthop_route;
334 	struct net_route_entry *route = NULL;
335 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
336        struct net_event_ipv6_route info;
337 #endif
338 
339 	NET_ASSERT(addr);
340 	NET_ASSERT(iface);
341 	NET_ASSERT(nexthop);
342 
343 	if (net_ipv6_addr_cmp(addr, net_ipv6_unspecified_address())) {
344 		NET_DBG("Route cannot be towards unspecified address");
345 		return NULL;
346 	}
347 
348 	net_ipv6_nbr_lock();
349 
350 	nbr_nexthop = net_ipv6_nbr_lookup(iface, nexthop);
351 	if (!nbr_nexthop) {
352 		NET_DBG("No such neighbor %s found",
353 			net_sprint_ipv6_addr(nexthop));
354 		goto exit;
355 	}
356 
357 	if (nbr_nexthop && nbr_nexthop->idx != NET_NBR_LLADDR_UNKNOWN) {
358 		nexthop_lladdr = net_nbr_get_lladdr(nbr_nexthop->idx);
359 		NET_ASSERT(nexthop_lladdr);
360 		NET_DBG("Nexthop %s lladdr is %s", net_sprint_ipv6_addr(nexthop),
361 			net_sprint_ll_addr(nexthop_lladdr->addr, nexthop_lladdr->len));
362 	}
363 
364 	route = net_route_lookup(iface, addr);
365 	if (route) {
366 		/* Update nexthop if not the same */
367 		struct in6_addr *nexthop_addr;
368 
369 		nexthop_addr = net_route_get_nexthop(route);
370 		if (nexthop_addr && net_ipv6_addr_cmp(nexthop, nexthop_addr)) {
371 			NET_DBG("No changes, return old route %p", route);
372 
373 			/* Reset lifetime timer. */
374 			net_route_update_lifetime(route, lifetime);
375 
376 			route->preference = preference;
377 
378 			goto exit;
379 		}
380 
381 		if (route_preference_is_lower(route->preference, preference)) {
382 			NET_DBG("No changes, ignoring route with lower preference");
383 			route = NULL;
384 			goto exit;
385 		}
386 
387 		NET_DBG("Old route to %s found",
388 			net_sprint_ipv6_addr(nexthop_addr));
389 
390 		net_route_del(route);
391 	}
392 
393 	nbr = nbr_new(iface, addr, prefix_len);
394 	if (!nbr) {
395 		/* Remove the oldest route and try again */
396 		sys_snode_t *last = sys_slist_peek_tail(&routes);
397 
398 		sys_slist_find_and_remove(&routes, last);
399 
400 		route = CONTAINER_OF(last,
401 				     struct net_route_entry,
402 				     node);
403 
404 		if (CONFIG_NET_ROUTE_LOG_LEVEL >= LOG_LEVEL_DBG) {
405 			struct in6_addr *in6_addr_tmp;
406 			struct net_linkaddr_storage *llstorage;
407 
408 			in6_addr_tmp = net_route_get_nexthop(route);
409 			nbr = net_ipv6_nbr_lookup(iface, in6_addr_tmp);
410 			if (nbr) {
411 				llstorage = net_nbr_get_lladdr(nbr->idx);
412 
413 				NET_DBG("Removing the oldest route %s "
414 					"via %s [%s]",
415 					net_sprint_ipv6_addr(&route->addr),
416 					net_sprint_ipv6_addr(in6_addr_tmp),
417 					net_sprint_ll_addr(llstorage->addr,
418 							   llstorage->len));
419 			}
420 		}
421 
422 		net_route_del(route);
423 
424 		nbr = nbr_new(iface, addr, prefix_len);
425 		if (!nbr) {
426 			NET_ERR("Neighbor route alloc failed!");
427 			route = NULL;
428 			goto exit;
429 		}
430 	}
431 
432 	tmp = get_nexthop_route();
433 	if (!tmp) {
434 		NET_ERR("No nexthop route available!");
435 		route = NULL;
436 		goto exit;
437 	}
438 
439 	nexthop_route = net_nexthop_data(tmp);
440 
441 	route = net_route_data(nbr);
442 	route->iface = iface;
443 	route->preference = preference;
444 
445 	net_route_update_lifetime(route, lifetime);
446 
447 	sys_slist_prepend(&routes, &route->node);
448 
449 	tmp = nbr_nexthop_get(iface, nexthop);
450 
451 	NET_ASSERT(tmp == nbr_nexthop);
452 
453 	nexthop_route->nbr = tmp;
454 
455 	sys_slist_init(&route->nexthop);
456 	sys_slist_prepend(&route->nexthop, &nexthop_route->node);
457 
458 	net_route_info("Added", route, addr);
459 
460 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
461 	net_ipaddr_copy(&info.addr, addr);
462 	net_ipaddr_copy(&info.nexthop, nexthop);
463 	info.prefix_len = prefix_len;
464 
465 	net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ROUTE_ADD,
466 					iface, (void *) &info,
467 					sizeof(struct net_event_ipv6_route));
468 #else
469 	net_mgmt_event_notify(NET_EVENT_IPV6_ROUTE_ADD, iface);
470 #endif
471 
472 exit:
473 	net_ipv6_nbr_unlock();
474 	return route;
475 }
476 
route_expired(struct net_route_entry * route)477 static void route_expired(struct net_route_entry *route)
478 {
479 	NET_DBG("Route to %s expired",
480 		net_sprint_ipv6_addr(&route->addr));
481 
482 	sys_slist_find_and_remove(&active_route_lifetime_timers,
483 				  &route->lifetime.node);
484 
485 	net_route_del(route);
486 }
487 
route_lifetime_timeout(struct k_work * work)488 static void route_lifetime_timeout(struct k_work *work)
489 {
490 	uint32_t next_update = UINT32_MAX;
491 	uint32_t current_time = k_uptime_get_32();
492 	struct net_route_entry *current, *next;
493 
494 	ARG_UNUSED(work);
495 
496 	net_ipv6_nbr_lock();
497 
498 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&active_route_lifetime_timers,
499 					  current, next, lifetime.node) {
500 		struct net_timeout *timeout = &current->lifetime;
501 		uint32_t this_update = net_timeout_evaluate(timeout,
502 							    current_time);
503 
504 		if (this_update == 0U) {
505 			route_expired(current);
506 			continue;
507 		}
508 
509 		if (this_update < next_update) {
510 			next_update = this_update;
511 		}
512 	}
513 
514 	if (next_update != UINT32_MAX) {
515 		k_work_reschedule(&route_lifetime_timer, K_MSEC(next_update));
516 	}
517 
518 	net_ipv6_nbr_unlock();
519 }
520 
net_route_update_lifetime(struct net_route_entry * route,uint32_t lifetime)521 void net_route_update_lifetime(struct net_route_entry *route, uint32_t lifetime)
522 {
523 	NET_DBG("Updating route lifetime of %s to %u secs",
524 		net_sprint_ipv6_addr(&route->addr),
525 		lifetime);
526 
527 	if (!route) {
528 		return;
529 	}
530 
531 	net_ipv6_nbr_lock();
532 
533 	if (lifetime == NET_IPV6_ND_INFINITE_LIFETIME) {
534 		route->is_infinite = true;
535 
536 		(void)sys_slist_find_and_remove(&active_route_lifetime_timers,
537 						&route->lifetime.node);
538 	} else {
539 		route->is_infinite = false;
540 
541 		net_timeout_set(&route->lifetime, lifetime, k_uptime_get_32());
542 
543 		(void)sys_slist_find_and_remove(&active_route_lifetime_timers,
544 						&route->lifetime.node);
545 		sys_slist_append(&active_route_lifetime_timers,
546 				 &route->lifetime.node);
547 		k_work_reschedule(&route_lifetime_timer, K_NO_WAIT);
548 	}
549 
550 	net_ipv6_nbr_unlock();
551 }
552 
net_route_del(struct net_route_entry * route)553 int net_route_del(struct net_route_entry *route)
554 {
555 	struct net_nbr *nbr;
556 	struct net_route_nexthop *nexthop_route;
557 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
558        struct net_event_ipv6_route info;
559 #endif
560 
561 	if (!route) {
562 		return -EINVAL;
563 	}
564 
565 	net_ipv6_nbr_lock();
566 
567 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
568 	net_ipaddr_copy(&info.addr, &route->addr);
569 	info.prefix_len = route->prefix_len;
570 	net_ipaddr_copy(&info.nexthop,
571 			net_route_get_nexthop(route));
572 
573 	net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ROUTE_DEL,
574 					route->iface, (void *) &info,
575 					sizeof(struct net_event_ipv6_route));
576 #else
577 	net_mgmt_event_notify(NET_EVENT_IPV6_ROUTE_DEL, route->iface);
578 #endif
579 
580 	if (!route->is_infinite) {
581 		sys_slist_find_and_remove(&active_route_lifetime_timers,
582 					  &route->lifetime.node);
583 
584 		if (sys_slist_is_empty(&active_route_lifetime_timers)) {
585 			k_work_cancel_delayable(&route_lifetime_timer);
586 		}
587 	}
588 
589 	sys_slist_find_and_remove(&routes, &route->node);
590 
591 	nbr = net_route_get_nbr(route);
592 	if (!nbr) {
593 		net_ipv6_nbr_unlock();
594 		return -ENOENT;
595 	}
596 
597 	net_route_info("Deleted", route, &route->addr);
598 
599 	SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) {
600 		if (!nexthop_route->nbr) {
601 			continue;
602 		}
603 
604 		nbr_nexthop_put(nexthop_route->nbr);
605 		release_nexthop_route(nexthop_route);
606 	}
607 
608 	nbr_free(nbr);
609 
610 	net_ipv6_nbr_unlock();
611 	return 0;
612 }
613 
net_route_del_by_nexthop(struct net_if * iface,struct in6_addr * nexthop)614 int net_route_del_by_nexthop(struct net_if *iface, struct in6_addr *nexthop)
615 {
616 	int count = 0, status = 0;
617 	struct net_nbr *nbr_nexthop;
618 	struct net_route_nexthop *nexthop_route;
619 	int i, ret;
620 
621 	NET_ASSERT(iface);
622 	NET_ASSERT(nexthop);
623 
624 	net_ipv6_nbr_lock();
625 
626 	nbr_nexthop = net_ipv6_nbr_lookup(iface, nexthop);
627 
628 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
629 		struct net_nbr *nbr = get_nbr(i);
630 		struct net_route_entry *route = net_route_data(nbr);
631 
632 		if (!route) {
633 			continue;
634 		}
635 
636 		SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route,
637 					     node) {
638 			if (nexthop_route->nbr == nbr_nexthop) {
639 				/* This route contains this nexthop */
640 				ret = net_route_del(route);
641 				if (!ret) {
642 					count++;
643 				} else {
644 					status = ret;
645 				}
646 				break;
647 			}
648 		}
649 	}
650 
651 	net_ipv6_nbr_unlock();
652 
653 	if (count) {
654 		return count;
655 	} else if (status < 0) {
656 		return status;
657 	}
658 
659 	return 0;
660 }
661 
net_route_get_nexthop(struct net_route_entry * route)662 struct in6_addr *net_route_get_nexthop(struct net_route_entry *route)
663 {
664 	struct net_route_nexthop *nexthop_route;
665 	struct net_ipv6_nbr_data *ipv6_nbr_data;
666 
667 	if (!route) {
668 		return NULL;
669 	}
670 
671 	net_ipv6_nbr_lock();
672 
673 	SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) {
674 		struct in6_addr *addr;
675 
676 		ipv6_nbr_data = net_ipv6_nbr_data(nexthop_route->nbr);
677 		if (ipv6_nbr_data) {
678 			addr = &ipv6_nbr_data->addr;
679 			NET_ASSERT(addr);
680 
681 			net_ipv6_nbr_unlock();
682 			return addr;
683 		} else {
684 			NET_ERR("could not get neighbor data from next hop");
685 		}
686 	}
687 
688 	net_ipv6_nbr_unlock();
689 	return NULL;
690 }
691 
net_route_foreach(net_route_cb_t cb,void * user_data)692 int net_route_foreach(net_route_cb_t cb, void *user_data)
693 {
694 	int i, ret = 0;
695 
696 	net_ipv6_nbr_lock();
697 
698 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
699 		struct net_route_entry *route;
700 		struct net_nbr *nbr;
701 
702 		nbr = get_nbr(i);
703 		if (!nbr) {
704 			continue;
705 		}
706 
707 		if (!nbr->ref) {
708 			continue;
709 		}
710 
711 		route = net_route_data(nbr);
712 		if (!route) {
713 			continue;
714 		}
715 
716 		cb(route, user_data);
717 
718 		ret++;
719 	}
720 
721 	net_ipv6_nbr_unlock();
722 	return ret;
723 }
724 
725 #if defined(CONFIG_NET_ROUTE_MCAST)
726 /*
727  * This array contains multicast routing entries.
728  */
729 static
730 struct net_route_entry_mcast route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES];
731 
mcast_route_iface_lookup(struct net_route_entry_mcast * entry,struct net_if * iface)732 static int mcast_route_iface_lookup(struct net_route_entry_mcast *entry, struct net_if *iface)
733 {
734 	ARRAY_FOR_EACH(entry->ifaces, i) {
735 		if (entry->ifaces[i] == iface) {
736 			return i;
737 		}
738 	}
739 
740 	return -1;
741 }
742 
net_route_mcast_iface_add(struct net_route_entry_mcast * entry,struct net_if * iface)743 bool net_route_mcast_iface_add(struct net_route_entry_mcast *entry, struct net_if *iface)
744 {
745 	if (!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) {
746 		return false;
747 	}
748 
749 	if (mcast_route_iface_lookup(entry, iface) >= 0) {
750 		/* Interface is already added */
751 		return true;
752 	}
753 
754 	ARRAY_FOR_EACH(entry->ifaces, i) {
755 		if (entry->ifaces[i] == NULL) {
756 			entry->ifaces[i] = iface;
757 
758 			return true;
759 		}
760 	}
761 
762 	/* There are no empty slots */
763 	return false;
764 }
765 
net_route_mcast_iface_del(struct net_route_entry_mcast * entry,struct net_if * iface)766 bool net_route_mcast_iface_del(struct net_route_entry_mcast *entry,
767 			      struct net_if *iface)
768 {
769 	int pos = mcast_route_iface_lookup(entry, iface);
770 
771 	if (pos < 0) {
772 		return false;
773 	}
774 
775 	entry->ifaces[pos] = NULL;
776 
777 	return true;
778 }
779 
780 #if defined(CONFIG_NET_MCAST_ROUTE_MLD_REPORTS)
781 struct mcast_route_mld_event {
782 	struct in6_addr *addr;
783 	uint8_t mode;
784 };
785 
send_mld_event(struct net_if * iface,void * user_data)786 static void send_mld_event(struct net_if *iface, void *user_data)
787 {
788 	struct mcast_route_mld_event *event = (struct mcast_route_mld_event *)user_data;
789 
790 	/* Do not send events for ifaces without IPv6, without MLD, already or still in
791 	 * a given group
792 	 */
793 	if (!iface->config.ip.ipv6 || net_if_flag_is_set(iface, NET_IF_IPV6_NO_MLD) ||
794 	    net_if_ipv6_maddr_lookup(event->addr, &iface)) {
795 		return;
796 	}
797 
798 	net_ipv6_mld_send_single(iface, event->addr, event->mode);
799 }
800 
propagate_mld_event(struct net_route_entry_mcast * route,bool route_added)801 static void propagate_mld_event(struct net_route_entry_mcast *route, bool route_added)
802 {
803 	struct mcast_route_mld_event mld_event;
804 
805 	/* Apply only for complete addresses */
806 	if (route->prefix_len == 128) {
807 		mld_event.addr = &route->group;
808 		mld_event.mode = route_added ? NET_IPV6_MLDv2_CHANGE_TO_EXCLUDE_MODE :
809 					       NET_IPV6_MLDv2_CHANGE_TO_INCLUDE_MODE;
810 
811 		net_if_foreach(send_mld_event, &mld_event);
812 	}
813 }
814 #else
815 #define propagate_mld_event(...)
816 #endif /* CONFIG_NET_MCAST_ROUTE_MLD_REPORTS */
817 
net_route_mcast_forward_packet(struct net_pkt * pkt,struct net_ipv6_hdr * hdr)818 int net_route_mcast_forward_packet(struct net_pkt *pkt, struct net_ipv6_hdr *hdr)
819 {
820 	int ret = 0, err = 0;
821 
822 	/* At this point, the original pkt has already stored the hop limit in its metadata.
823 	 * Change its value in a common buffer so the forwardee has a proper count. As we have
824 	 * a direct access to the buffer there is no need to perform read/write operations.
825 	 */
826 	hdr->hop_limit--;
827 
828 	ARRAY_FOR_EACH_PTR(route_mcast_entries, route) {
829 		struct net_pkt *pkt_cpy = NULL;
830 
831 		if (!route->is_used ||
832 			!net_ipv6_is_prefix(hdr->dst, route->group.s6_addr, route->prefix_len)) {
833 			continue;
834 		}
835 
836 		ARRAY_FOR_EACH(route->ifaces, i) {
837 			if (!route->ifaces[i] || pkt->iface == route->ifaces[i] ||
838 			    !net_if_flag_is_set(route->ifaces[i], NET_IF_FORWARD_MULTICASTS)) {
839 				continue;
840 			}
841 
842 			pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT);
843 
844 			if (pkt_cpy == NULL) {
845 				err--;
846 				continue;
847 			}
848 
849 			net_pkt_set_forwarding(pkt_cpy, true);
850 			net_pkt_set_orig_iface(pkt_cpy, pkt->iface);
851 			net_pkt_set_iface(pkt_cpy, route->ifaces[i]);
852 
853 			if (net_send_data(pkt_cpy) >= 0) {
854 				++ret;
855 			} else {
856 				net_pkt_unref(pkt_cpy);
857 				--err;
858 			}
859 		}
860 	}
861 
862 	return (err == 0) ? ret : err;
863 }
864 
net_route_mcast_foreach(net_route_mcast_cb_t cb,struct in6_addr * skip,void * user_data)865 int net_route_mcast_foreach(net_route_mcast_cb_t cb,
866 			    struct in6_addr *skip,
867 			    void *user_data)
868 {
869 	int ret = 0;
870 
871 	ARRAY_FOR_EACH_PTR(route_mcast_entries, route) {
872 		if (route->is_used) {
873 			if (skip && net_ipv6_is_prefix(skip->s6_addr,
874 						       route->group.s6_addr,
875 						       route->prefix_len)) {
876 				continue;
877 			}
878 
879 			cb(route, user_data);
880 
881 			ret++;
882 		}
883 	}
884 
885 	return ret;
886 }
887 
net_route_mcast_add(struct net_if * iface,struct in6_addr * group,uint8_t prefix_len)888 struct net_route_entry_mcast *net_route_mcast_add(struct net_if *iface,
889 						  struct in6_addr *group,
890 						  uint8_t prefix_len)
891 {
892 	net_ipv6_nbr_lock();
893 
894 	if ((!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) ||
895 			(!net_ipv6_is_addr_mcast(group)) ||
896 			(net_ipv6_is_addr_mcast_iface(group)) ||
897 			(net_ipv6_is_addr_mcast_link(group))) {
898 		net_ipv6_nbr_unlock();
899 		return NULL;
900 	}
901 
902 	ARRAY_FOR_EACH_PTR(route_mcast_entries, route) {
903 		if (!route->is_used) {
904 			net_ipaddr_copy(&route->group, group);
905 
906 			ARRAY_FOR_EACH(route->ifaces, i) {
907 				route->ifaces[i] = NULL;
908 			}
909 
910 			route->prefix_len = prefix_len;
911 			route->ifaces[0] = iface;
912 			route->is_used = true;
913 
914 			propagate_mld_event(route, true);
915 
916 			net_ipv6_nbr_unlock();
917 			return route;
918 		}
919 	}
920 
921 	net_ipv6_nbr_unlock();
922 	return NULL;
923 }
924 
net_route_mcast_del(struct net_route_entry_mcast * route)925 bool net_route_mcast_del(struct net_route_entry_mcast *route)
926 {
927 	if (route > &route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES - 1] ||
928 	    route < &route_mcast_entries[0]) {
929 		return false;
930 	}
931 
932 	NET_ASSERT(route->is_used,
933 		   "Multicast route %p to %s was already removed", route,
934 		   net_sprint_ipv6_addr(&route->group));
935 
936 	propagate_mld_event(route, false);
937 
938 	route->is_used = false;
939 
940 	return true;
941 }
942 
943 struct net_route_entry_mcast *
net_route_mcast_lookup(struct in6_addr * group)944 net_route_mcast_lookup(struct in6_addr *group)
945 {
946 	ARRAY_FOR_EACH_PTR(route_mcast_entries, route) {
947 		if (!route->is_used) {
948 			continue;
949 		}
950 
951 		if (net_ipv6_is_prefix(group->s6_addr,
952 					route->group.s6_addr,
953 					route->prefix_len)) {
954 			return route;
955 		}
956 	}
957 
958 	return NULL;
959 }
960 #endif /* CONFIG_NET_ROUTE_MCAST */
961 
net_route_get_info(struct net_if * iface,struct in6_addr * dst,struct net_route_entry ** route,struct in6_addr ** nexthop)962 bool net_route_get_info(struct net_if *iface,
963 			struct in6_addr *dst,
964 			struct net_route_entry **route,
965 			struct in6_addr **nexthop)
966 {
967 	struct net_if_router *router;
968 	bool ret = false;
969 
970 	net_ipv6_nbr_lock();
971 
972 	/* Search in neighbor table first, if not search in routing table. */
973 	if (net_ipv6_nbr_lookup(iface, dst)) {
974 		/* Found nexthop, no need to look into routing table. */
975 		*route = NULL;
976 		*nexthop = dst;
977 
978 		ret = true;
979 		goto exit;
980 	}
981 
982 	*route = net_route_lookup(iface, dst);
983 	if (*route) {
984 		*nexthop = net_route_get_nexthop(*route);
985 		if (!*nexthop) {
986 			goto exit;
987 		}
988 
989 		ret = true;
990 		goto exit;
991 	} else {
992 		/* No specific route to this host, use the default
993 		 * route instead.
994 		 */
995 		router = net_if_ipv6_router_find_default(NULL, dst);
996 		if (!router) {
997 			goto exit;
998 		}
999 
1000 		*nexthop = &router->address.in6_addr;
1001 
1002 		ret = true;
1003 		goto exit;
1004 	}
1005 
1006 exit:
1007 	net_ipv6_nbr_unlock();
1008 	return ret;
1009 }
1010 
is_ll_addr_supported(struct net_if * iface)1011 static bool is_ll_addr_supported(struct net_if *iface)
1012 {
1013 #if defined(CONFIG_NET_L2_DUMMY)
1014 	if (net_if_l2(iface) == &NET_L2_GET_NAME(DUMMY)) {
1015 		return false;
1016 	}
1017 #endif
1018 #if defined(CONFIG_NET_L2_PPP)
1019 	if (net_if_l2(iface) == &NET_L2_GET_NAME(PPP)) {
1020 		return false;
1021 	}
1022 #endif
1023 #if defined(CONFIG_NET_L2_OPENTHREAD)
1024 	if (net_if_l2(iface) == &NET_L2_GET_NAME(OPENTHREAD)) {
1025 		return false;
1026 	}
1027 #endif
1028 
1029 	return true;
1030 }
1031 
net_route_packet(struct net_pkt * pkt,struct in6_addr * nexthop)1032 int net_route_packet(struct net_pkt *pkt, struct in6_addr *nexthop)
1033 {
1034 	struct net_linkaddr_storage *lladdr = NULL;
1035 	struct net_nbr *nbr;
1036 	int err;
1037 
1038 	net_ipv6_nbr_lock();
1039 
1040 	nbr = net_ipv6_nbr_lookup(NULL, nexthop);
1041 	if (!nbr) {
1042 		NET_DBG("Cannot find %s neighbor",
1043 			net_sprint_ipv6_addr(nexthop));
1044 		err = -ENOENT;
1045 		goto error;
1046 	}
1047 
1048 	if (is_ll_addr_supported(nbr->iface) && is_ll_addr_supported(net_pkt_iface(pkt)) &&
1049 	    is_ll_addr_supported(net_pkt_orig_iface(pkt))) {
1050 		lladdr = net_nbr_get_lladdr(nbr->idx);
1051 		if (!lladdr) {
1052 			NET_DBG("Cannot find %s neighbor link layer address.",
1053 				net_sprint_ipv6_addr(nexthop));
1054 			err = -ESRCH;
1055 			goto error;
1056 		}
1057 
1058 		if (!net_pkt_lladdr_src(pkt)->addr) {
1059 			NET_DBG("Link layer source address not set");
1060 			err = -EINVAL;
1061 			goto error;
1062 		}
1063 
1064 		/* Sanitycheck: If src and dst ll addresses are going
1065 		 * to be same, then something went wrong in route
1066 		 * lookup.
1067 		 */
1068 		if (!memcmp(net_pkt_lladdr_src(pkt)->addr, lladdr->addr,
1069 				lladdr->len)) {
1070 			NET_ERR("Src ll and Dst ll are same");
1071 			err = -EINVAL;
1072 			goto error;
1073 		}
1074 	}
1075 
1076 	net_pkt_set_forwarding(pkt, true);
1077 
1078 	/* Set the source ll address of the iface (if relevant) and the
1079 	 * destination address to be the nexthop recipient.
1080 	 */
1081 	if (is_ll_addr_supported(net_pkt_iface(pkt))) {
1082 		net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr;
1083 		net_pkt_lladdr_src(pkt)->type = net_pkt_lladdr_if(pkt)->type;
1084 		net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len;
1085 	}
1086 
1087 	if (lladdr) {
1088 		net_pkt_lladdr_dst(pkt)->addr = lladdr->addr;
1089 		net_pkt_lladdr_dst(pkt)->type = lladdr->type;
1090 		net_pkt_lladdr_dst(pkt)->len = lladdr->len;
1091 	}
1092 
1093 	net_pkt_set_iface(pkt, nbr->iface);
1094 
1095 	net_ipv6_nbr_unlock();
1096 
1097 	return net_send_data(pkt);
1098 
1099 error:
1100 	net_ipv6_nbr_unlock();
1101 	return err;
1102 }
1103 
net_route_packet_if(struct net_pkt * pkt,struct net_if * iface)1104 int net_route_packet_if(struct net_pkt *pkt, struct net_if *iface)
1105 {
1106 	/* The destination is reachable via iface. But since no valid nexthop
1107 	 * is known, net_pkt_lladdr_dst(pkt) cannot be set here.
1108 	 */
1109 	net_pkt_set_orig_iface(pkt, net_pkt_iface(pkt));
1110 	net_pkt_set_iface(pkt, iface);
1111 
1112 	net_pkt_set_forwarding(pkt, true);
1113 
1114 	/* Set source LL address if only if relevant */
1115 	if (is_ll_addr_supported(iface)) {
1116 		net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr;
1117 		net_pkt_lladdr_src(pkt)->type = net_pkt_lladdr_if(pkt)->type;
1118 		net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len;
1119 	}
1120 
1121 	return net_send_data(pkt);
1122 }
1123 
net_route_init(void)1124 void net_route_init(void)
1125 {
1126 	NET_DBG("Allocated %d routing entries (%zu bytes)",
1127 		CONFIG_NET_MAX_ROUTES, sizeof(net_route_entries_pool));
1128 
1129 	NET_DBG("Allocated %d nexthop entries (%zu bytes)",
1130 		CONFIG_NET_MAX_NEXTHOPS, sizeof(net_route_nexthop_pool));
1131 
1132 #if defined(CONFIG_NET_ROUTE_MCAST)
1133 	memset(route_mcast_entries, 0, sizeof(route_mcast_entries));
1134 #endif
1135 	k_work_init_delayable(&route_lifetime_timer, route_lifetime_timeout);
1136 }
1137