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 <logging/log.h>
13 LOG_MODULE_REGISTER(net_route, CONFIG_NET_ROUTE_LOG_LEVEL);
14 
15 #include <kernel.h>
16 #include <limits.h>
17 #include <zephyr/types.h>
18 #include <sys/slist.h>
19 
20 #include <net/net_pkt.h>
21 #include <net/net_core.h>
22 #include <net/net_stats.h>
23 #include <net/net_mgmt.h>
24 #include <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 #if !defined(NET_ROUTE_EXTRA_DATA_SIZE)
33 #define NET_ROUTE_EXTRA_DATA_SIZE 0
34 #endif
35 
36 /* We keep track of the routes in a separate list so that we can remove
37  * the oldest routes (at tail) if needed.
38  */
39 static sys_slist_t routes;
40 
net_route_nexthop_remove(struct net_nbr * nbr)41 static void net_route_nexthop_remove(struct net_nbr *nbr)
42 {
43 	NET_DBG("Nexthop %p removed", nbr);
44 }
45 
46 /*
47  * This pool contains information next hop neighbors.
48  */
49 NET_NBR_POOL_INIT(net_route_nexthop_pool,
50 		  CONFIG_NET_MAX_NEXTHOPS,
51 		  sizeof(struct net_route_nexthop),
52 		  net_route_nexthop_remove,
53 		  0);
54 
net_nexthop_data(struct net_nbr * nbr)55 static inline struct net_route_nexthop *net_nexthop_data(struct net_nbr *nbr)
56 {
57 	return (struct net_route_nexthop *)nbr->data;
58 }
59 
get_nexthop_nbr(struct net_nbr * start,int idx)60 static inline struct net_nbr *get_nexthop_nbr(struct net_nbr *start, int idx)
61 {
62 	NET_ASSERT(idx < CONFIG_NET_MAX_NEXTHOPS, "idx %d >= max %d",
63 		   idx, CONFIG_NET_MAX_NEXTHOPS);
64 
65 	return (struct net_nbr *)((uint8_t *)start +
66 			((sizeof(struct net_nbr) + start->size) * idx));
67 }
68 
release_nexthop_route(struct net_route_nexthop * route_nexthop)69 static void release_nexthop_route(struct net_route_nexthop *route_nexthop)
70 {
71 	struct net_nbr *nbr = CONTAINER_OF(route_nexthop, struct net_nbr, __nbr);
72 
73 	net_nbr_unref(nbr);
74 }
75 
get_nexthop_route(void)76 static struct net_nbr *get_nexthop_route(void)
77 {
78 	int i;
79 
80 	for (i = 0; i < CONFIG_NET_MAX_NEXTHOPS; i++) {
81 		struct net_nbr *nbr = get_nexthop_nbr(
82 			(struct net_nbr *)net_route_nexthop_pool, i);
83 
84 		if (!nbr->ref) {
85 			nbr->data = nbr->__nbr;
86 
87 			nbr->idx = NET_NBR_LLADDR_UNKNOWN;
88 
89 			return net_nbr_ref(nbr);
90 		}
91 	}
92 
93 	return NULL;
94 }
95 
net_route_entry_remove(struct net_nbr * nbr)96 static void net_route_entry_remove(struct net_nbr *nbr)
97 {
98 	NET_DBG("Route %p removed", nbr);
99 }
100 
net_route_entries_table_clear(struct net_nbr_table * table)101 static void net_route_entries_table_clear(struct net_nbr_table *table)
102 {
103 	NET_DBG("Route table %p cleared", table);
104 }
105 
106 /*
107  * This pool contains routing table entries.
108  */
109 NET_NBR_POOL_INIT(net_route_entries_pool,
110 		  CONFIG_NET_MAX_ROUTES,
111 		  sizeof(struct net_route_entry),
112 		  net_route_entry_remove,
113 		  NET_ROUTE_EXTRA_DATA_SIZE);
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 	int i;
131 
132 	NET_ASSERT(route);
133 
134 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
135 		struct net_nbr *nbr = get_nbr(i);
136 
137 		if (!nbr->ref) {
138 			continue;
139 		}
140 
141 		if (nbr->data == (uint8_t *)route) {
142 			if (!nbr->ref) {
143 				return NULL;
144 			}
145 
146 			return nbr;
147 		}
148 	}
149 
150 	return NULL;
151 }
152 
net_routes_print(void)153 void net_routes_print(void)
154 {
155 	int i;
156 
157 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
158 		struct net_nbr *nbr = get_nbr(i);
159 
160 		if (!nbr->ref) {
161 			continue;
162 		}
163 
164 		NET_DBG("[%d] %p %d addr %s/%d",
165 			i, nbr, nbr->ref,
166 			log_strdup(net_sprint_ipv6_addr(
167 					   &net_route_data(nbr)->addr)),
168 			net_route_data(nbr)->prefix_len);
169 		NET_DBG("    iface %p idx %d ll %s",
170 			nbr->iface, nbr->idx,
171 			nbr->idx == NET_NBR_LLADDR_UNKNOWN ? "?" :
172 			log_strdup(net_sprint_ll_addr(
173 				net_nbr_get_lladdr(nbr->idx)->addr,
174 				net_nbr_get_lladdr(nbr->idx)->len)));
175 	}
176 }
177 
nbr_free(struct net_nbr * nbr)178 static inline void nbr_free(struct net_nbr *nbr)
179 {
180 	NET_DBG("nbr %p", nbr);
181 
182 	net_nbr_unref(nbr);
183 }
184 
nbr_new(struct net_if * iface,struct in6_addr * addr,uint8_t prefix_len)185 static struct net_nbr *nbr_new(struct net_if *iface,
186 			       struct in6_addr *addr,
187 			       uint8_t prefix_len)
188 {
189 	struct net_nbr *nbr = net_nbr_get(&net_nbr_routes.table);
190 
191 	if (!nbr) {
192 		return NULL;
193 	}
194 
195 	nbr->iface = iface;
196 
197 	net_ipaddr_copy(&net_route_data(nbr)->addr, addr);
198 	net_route_data(nbr)->prefix_len = prefix_len;
199 
200 	NET_DBG("[%d] nbr %p iface %p IPv6 %s/%d",
201 		nbr->idx, nbr, iface,
202 		log_strdup(net_sprint_ipv6_addr(&net_route_data(nbr)->addr)),
203 		prefix_len);
204 
205 	return nbr;
206 }
207 
nbr_nexthop_get(struct net_if * iface,struct in6_addr * addr)208 static struct net_nbr *nbr_nexthop_get(struct net_if *iface,
209 				       struct in6_addr *addr)
210 {
211 	/* Note that the nexthop host must be already in the neighbor
212 	 * cache. We just increase the ref count of an existing entry.
213 	 */
214 	struct net_nbr *nbr;
215 
216 	nbr = net_ipv6_nbr_lookup(iface, addr);
217 	if (nbr == NULL) {
218 		NET_DBG("Next hop neighbor not found!");
219 		return NULL;
220 	}
221 
222 	NET_ASSERT(nbr->idx != NET_NBR_LLADDR_UNKNOWN,
223 		   "Nexthop %s not in neighbor cache!",
224 		   net_sprint_ipv6_addr(addr));
225 
226 	net_nbr_ref(nbr);
227 
228 	NET_DBG("[%d] nbr %p iface %p IPv6 %s",
229 		nbr->idx, nbr, iface,
230 		log_strdup(net_sprint_ipv6_addr(addr)));
231 
232 	return nbr;
233 }
234 
nbr_nexthop_put(struct net_nbr * nbr)235 static int nbr_nexthop_put(struct net_nbr *nbr)
236 {
237 	NET_ASSERT(nbr);
238 
239 	NET_DBG("[%d] nbr %p iface %p", nbr->idx, nbr, nbr->iface);
240 
241 	net_nbr_unref(nbr);
242 
243 	return 0;
244 }
245 
246 
247 #define net_route_info(str, route, dst)					\
248 	do {								\
249 	if (CONFIG_NET_ROUTE_LOG_LEVEL >= LOG_LEVEL_DBG) {		\
250 		struct in6_addr *naddr = net_route_get_nexthop(route);	\
251 									\
252 		NET_ASSERT(naddr, "Unknown nexthop address");	\
253 									\
254 		NET_DBG("%s route to %s via %s (iface %p)", str,	\
255 			log_strdup(net_sprint_ipv6_addr(dst)),		\
256 			log_strdup(net_sprint_ipv6_addr(naddr)),	\
257 			route->iface);					\
258 	} } while (0)
259 
260 /* Route was accessed, so place it in front of the routes list */
update_route_access(struct net_route_entry * route)261 static inline void update_route_access(struct net_route_entry *route)
262 {
263 	sys_slist_find_and_remove(&routes, &route->node);
264 	sys_slist_prepend(&routes, &route->node);
265 }
266 
net_route_lookup(struct net_if * iface,struct in6_addr * dst)267 struct net_route_entry *net_route_lookup(struct net_if *iface,
268 					 struct in6_addr *dst)
269 {
270 	struct net_route_entry *route, *found = NULL;
271 	uint8_t longest_match = 0U;
272 	int i;
273 
274 	for (i = 0; i < CONFIG_NET_MAX_ROUTES && longest_match < 128; i++) {
275 		struct net_nbr *nbr = get_nbr(i);
276 
277 		if (!nbr->ref) {
278 			continue;
279 		}
280 
281 		if (iface && nbr->iface != iface) {
282 			continue;
283 		}
284 
285 		route = net_route_data(nbr);
286 
287 		if (route->prefix_len >= longest_match &&
288 		    net_ipv6_is_prefix(dst->s6_addr,
289 				       route->addr.s6_addr,
290 				       route->prefix_len)) {
291 			found = route;
292 			longest_match = route->prefix_len;
293 		}
294 	}
295 
296 	if (found) {
297 		net_route_info("Found", found, dst);
298 
299 		update_route_access(found);
300 	}
301 
302 	return found;
303 }
304 
net_route_add(struct net_if * iface,struct in6_addr * addr,uint8_t prefix_len,struct in6_addr * nexthop)305 struct net_route_entry *net_route_add(struct net_if *iface,
306 				      struct in6_addr *addr,
307 				      uint8_t prefix_len,
308 				      struct in6_addr *nexthop)
309 {
310 	struct net_linkaddr_storage *nexthop_lladdr;
311 	struct net_nbr *nbr, *nbr_nexthop, *tmp;
312 	struct net_route_nexthop *nexthop_route;
313 	struct net_route_entry *route;
314 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
315        struct net_event_ipv6_route info;
316 #endif
317 
318 	NET_ASSERT(addr);
319 	NET_ASSERT(iface);
320 	NET_ASSERT(nexthop);
321 
322 	if (net_ipv6_addr_cmp(addr, net_ipv6_unspecified_address())) {
323 		NET_DBG("Route cannot be towards unspecified address");
324 		return NULL;
325 	}
326 
327 	nbr_nexthop = net_ipv6_nbr_lookup(iface, nexthop);
328 	if (!nbr_nexthop) {
329 		NET_DBG("No such neighbor %s found",
330 			log_strdup(net_sprint_ipv6_addr(nexthop)));
331 		return NULL;
332 	}
333 
334 	nexthop_lladdr = net_nbr_get_lladdr(nbr_nexthop->idx);
335 
336 	NET_ASSERT(nexthop_lladdr);
337 
338 	NET_DBG("Nexthop %s lladdr is %s",
339 		log_strdup(net_sprint_ipv6_addr(nexthop)),
340 		log_strdup(net_sprint_ll_addr(nexthop_lladdr->addr,
341 					      nexthop_lladdr->len)));
342 
343 	route = net_route_lookup(iface, addr);
344 	if (route) {
345 		/* Update nexthop if not the same */
346 		struct in6_addr *nexthop_addr;
347 
348 		nexthop_addr = net_route_get_nexthop(route);
349 		if (nexthop_addr && net_ipv6_addr_cmp(nexthop, nexthop_addr)) {
350 			NET_DBG("No changes, return old route %p", route);
351 			return route;
352 		}
353 
354 		NET_DBG("Old route to %s found",
355 			log_strdup(net_sprint_ipv6_addr(nexthop_addr)));
356 
357 		net_route_del(route);
358 	}
359 
360 	nbr = nbr_new(iface, addr, prefix_len);
361 	if (!nbr) {
362 		/* Remove the oldest route and try again */
363 		sys_snode_t *last = sys_slist_peek_tail(&routes);
364 
365 		sys_slist_find_and_remove(&routes, last);
366 
367 		route = CONTAINER_OF(last,
368 				     struct net_route_entry,
369 				     node);
370 
371 		if (CONFIG_NET_ROUTE_LOG_LEVEL >= LOG_LEVEL_DBG) {
372 			struct in6_addr *tmp;
373 			struct net_linkaddr_storage *llstorage;
374 
375 			tmp = net_route_get_nexthop(route);
376 			nbr = net_ipv6_nbr_lookup(iface, tmp);
377 			if (nbr) {
378 				llstorage = net_nbr_get_lladdr(nbr->idx);
379 
380 				NET_DBG("Removing the oldest route %s "
381 					"via %s [%s]",
382 					log_strdup(net_sprint_ipv6_addr(
383 							   &route->addr)),
384 					log_strdup(net_sprint_ipv6_addr(tmp)),
385 					log_strdup(net_sprint_ll_addr(
386 							   llstorage->addr,
387 							   llstorage->len)));
388 			}
389 		}
390 
391 		net_route_del(route);
392 
393 		nbr = nbr_new(iface, addr, prefix_len);
394 		if (!nbr) {
395 			NET_ERR("Neighbor route alloc failed!");
396 			return NULL;
397 		}
398 	}
399 
400 	tmp = get_nexthop_route();
401 	if (!tmp) {
402 		NET_ERR("No nexthop route available!");
403 		return NULL;
404 	}
405 
406 	nexthop_route = net_nexthop_data(tmp);
407 
408 	route = net_route_data(nbr);
409 	route->iface = iface;
410 
411 	sys_slist_prepend(&routes, &route->node);
412 
413 	tmp = nbr_nexthop_get(iface, nexthop);
414 
415 	NET_ASSERT(tmp == nbr_nexthop);
416 
417 	nexthop_route->nbr = tmp;
418 
419 	sys_slist_init(&route->nexthop);
420 	sys_slist_prepend(&route->nexthop, &nexthop_route->node);
421 
422 	net_route_info("Added", route, addr);
423 
424 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
425 	net_ipaddr_copy(&info.addr, addr);
426 	net_ipaddr_copy(&info.nexthop, nexthop);
427 	info.prefix_len = prefix_len;
428 
429 	net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ROUTE_ADD,
430 					iface, (void *) &info,
431 					sizeof(struct net_event_ipv6_route));
432 #else
433 	net_mgmt_event_notify(NET_EVENT_IPV6_ROUTE_ADD, iface);
434 #endif
435 
436 	return route;
437 }
438 
net_route_del(struct net_route_entry * route)439 int net_route_del(struct net_route_entry *route)
440 {
441 	struct net_nbr *nbr;
442 	struct net_route_nexthop *nexthop_route;
443 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
444        struct net_event_ipv6_route info;
445 #endif
446 
447 	if (!route) {
448 		return -EINVAL;
449 	}
450 
451 #if defined(CONFIG_NET_MGMT_EVENT_INFO)
452 	net_ipaddr_copy(&info.addr, &route->addr);
453 	info.prefix_len = route->prefix_len;
454 	net_ipaddr_copy(&info.nexthop,
455 			net_route_get_nexthop(route));
456 
457 	net_mgmt_event_notify_with_info(NET_EVENT_IPV6_ROUTE_DEL,
458 					route->iface, (void *) &info,
459 					sizeof(struct net_event_ipv6_route));
460 #else
461 	net_mgmt_event_notify(NET_EVENT_IPV6_ROUTE_DEL, route->iface);
462 #endif
463 
464 	sys_slist_find_and_remove(&routes, &route->node);
465 
466 	nbr = net_route_get_nbr(route);
467 	if (!nbr) {
468 		return -ENOENT;
469 	}
470 
471 	net_route_info("Deleted", route, &route->addr);
472 
473 	SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) {
474 		if (!nexthop_route->nbr) {
475 			continue;
476 		}
477 
478 		nbr_nexthop_put(nexthop_route->nbr);
479 		release_nexthop_route(nexthop_route);
480 	}
481 
482 	nbr_free(nbr);
483 
484 	return 0;
485 }
486 
net_route_del_by_nexthop(struct net_if * iface,struct in6_addr * nexthop)487 int net_route_del_by_nexthop(struct net_if *iface, struct in6_addr *nexthop)
488 {
489 	int count = 0, status = 0;
490 	struct net_nbr *nbr_nexthop;
491 	struct net_route_nexthop *nexthop_route;
492 	int i, ret;
493 
494 	NET_ASSERT(iface);
495 	NET_ASSERT(nexthop);
496 
497 	nbr_nexthop = net_ipv6_nbr_lookup(iface, nexthop);
498 
499 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
500 		struct net_nbr *nbr = get_nbr(i);
501 		struct net_route_entry *route = net_route_data(nbr);
502 
503 		if (!route) {
504 			continue;
505 		}
506 
507 		SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route,
508 					     node) {
509 			if (nexthop_route->nbr == nbr_nexthop) {
510 				/* This route contains this nexthop */
511 				ret = net_route_del(route);
512 				if (!ret) {
513 					count++;
514 				} else {
515 					status = ret;
516 				}
517 				break;
518 			}
519 		}
520 	}
521 
522 	if (count) {
523 		return count;
524 	} else if (status < 0) {
525 		return status;
526 	}
527 
528 	return 0;
529 }
530 
net_route_del_by_nexthop_data(struct net_if * iface,struct in6_addr * nexthop,void * data)531 int net_route_del_by_nexthop_data(struct net_if *iface,
532 				  struct in6_addr *nexthop,
533 				  void *data)
534 {
535 	int count = 0, status = 0;
536 	struct net_nbr *nbr_nexthop;
537 	struct net_route_nexthop *nexthop_route;
538 	int i, ret;
539 
540 	NET_ASSERT(iface);
541 	NET_ASSERT(nexthop);
542 
543 	nbr_nexthop = net_ipv6_nbr_lookup(iface, nexthop);
544 	if (!nbr_nexthop) {
545 		return -EINVAL;
546 	}
547 
548 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
549 		struct net_nbr *nbr = get_nbr(i);
550 		struct net_route_entry *route = net_route_data(nbr);
551 
552 		SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route,
553 					     node) {
554 			void *extra_data;
555 
556 			if (nexthop_route->nbr != nbr_nexthop) {
557 				continue;
558 			}
559 
560 			if (nbr->extra_data_size == 0U) {
561 				continue;
562 			}
563 
564 			/* Routing engine specific extra data needs
565 			 * to match too.
566 			 */
567 			extra_data = net_nbr_extra_data(nbr_nexthop);
568 			if (extra_data != data) {
569 				continue;
570 			}
571 
572 			ret = net_route_del(route);
573 			if (!ret) {
574 				count++;
575 			} else {
576 				status = ret;
577 			}
578 
579 			break;
580 		}
581 	}
582 
583 	if (count) {
584 		return count;
585 	}
586 
587 	return status;
588 }
589 
net_route_get_nexthop(struct net_route_entry * route)590 struct in6_addr *net_route_get_nexthop(struct net_route_entry *route)
591 {
592 	struct net_route_nexthop *nexthop_route;
593 	struct net_ipv6_nbr_data *ipv6_nbr_data;
594 
595 	if (!route) {
596 		return NULL;
597 	}
598 
599 	SYS_SLIST_FOR_EACH_CONTAINER(&route->nexthop, nexthop_route, node) {
600 		struct in6_addr *addr;
601 
602 		NET_ASSERT(nexthop_route->nbr->idx != NET_NBR_LLADDR_UNKNOWN);
603 
604 		if (nexthop_route->nbr->idx == NET_NBR_LLADDR_UNKNOWN) {
605 			continue;
606 		}
607 
608 		ipv6_nbr_data = net_ipv6_nbr_data(nexthop_route->nbr);
609 		if (ipv6_nbr_data) {
610 			addr = &ipv6_nbr_data->addr;
611 			NET_ASSERT(addr);
612 
613 			return addr;
614 		} else {
615 			NET_ERR("could not get neighbor data from next hop");
616 		}
617 	}
618 
619 	return NULL;
620 }
621 
net_route_foreach(net_route_cb_t cb,void * user_data)622 int net_route_foreach(net_route_cb_t cb, void *user_data)
623 {
624 	int i, ret = 0;
625 
626 	for (i = 0; i < CONFIG_NET_MAX_ROUTES; i++) {
627 		struct net_route_entry *route;
628 		struct net_nbr *nbr;
629 
630 		nbr = get_nbr(i);
631 		if (!nbr) {
632 			continue;
633 		}
634 
635 		if (!nbr->ref) {
636 			continue;
637 		}
638 
639 		route = net_route_data(nbr);
640 		if (!route) {
641 			continue;
642 		}
643 
644 		cb(route, user_data);
645 
646 		ret++;
647 	}
648 
649 	return ret;
650 }
651 
652 #if defined(CONFIG_NET_ROUTE_MCAST)
653 /*
654  * This array contains multicast routing entries.
655  */
656 static
657 struct net_route_entry_mcast route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES];
658 
net_route_mcast_forward_packet(struct net_pkt * pkt,const struct net_ipv6_hdr * hdr)659 int net_route_mcast_forward_packet(struct net_pkt *pkt,
660 				   const struct net_ipv6_hdr *hdr)
661 {
662 	int i, ret = 0, err = 0;
663 
664 	for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; ++i) {
665 		struct net_route_entry_mcast *route = &route_mcast_entries[i];
666 		struct net_pkt *pkt_cpy = NULL;
667 
668 		if (!route->is_used) {
669 			continue;
670 		}
671 
672 		if (!net_if_flag_is_set(route->iface,
673 					NET_IF_FORWARD_MULTICASTS) ||
674 		    !net_ipv6_is_prefix(hdr->dst.s6_addr,
675 					route->group.s6_addr,
676 					route->prefix_len)         ||
677 		    (pkt->iface == route->iface)) {
678 			continue;
679 		}
680 
681 		pkt_cpy = net_pkt_shallow_clone(pkt, K_NO_WAIT);
682 
683 		if (pkt_cpy == NULL) {
684 			err--;
685 			continue;
686 		}
687 
688 		net_pkt_set_forwarding(pkt_cpy, true);
689 		net_pkt_set_iface(pkt_cpy, route->iface);
690 
691 		if (net_send_data(pkt_cpy) >= 0) {
692 			++ret;
693 		} else {
694 			net_pkt_unref(pkt_cpy);
695 			--err;
696 		}
697 	}
698 
699 	return (err == 0) ? ret : err;
700 }
701 
net_route_mcast_foreach(net_route_mcast_cb_t cb,struct in6_addr * skip,void * user_data)702 int net_route_mcast_foreach(net_route_mcast_cb_t cb,
703 			    struct in6_addr *skip,
704 			    void *user_data)
705 {
706 	int i, ret = 0;
707 
708 	for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) {
709 		struct net_route_entry_mcast *route = &route_mcast_entries[i];
710 
711 		if (route->is_used) {
712 			if (skip && net_ipv6_is_prefix(skip->s6_addr,
713 						       route->group.s6_addr,
714 						       route->prefix_len)) {
715 				continue;
716 			}
717 
718 			cb(route, user_data);
719 
720 			ret++;
721 		}
722 	}
723 
724 	return ret;
725 }
726 
net_route_mcast_add(struct net_if * iface,struct in6_addr * group,uint8_t prefix_len)727 struct net_route_entry_mcast *net_route_mcast_add(struct net_if *iface,
728 						  struct in6_addr *group,
729 						  uint8_t prefix_len)
730 {
731 	int i;
732 
733 	if ((!net_if_flag_is_set(iface, NET_IF_FORWARD_MULTICASTS)) ||
734 			(!net_ipv6_is_addr_mcast(group)) ||
735 			(net_ipv6_is_addr_mcast_iface(group)) ||
736 			(net_ipv6_is_addr_mcast_link(group))) {
737 		return NULL;
738 	}
739 
740 	for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) {
741 		struct net_route_entry_mcast *route = &route_mcast_entries[i];
742 
743 		if (!route->is_used) {
744 			net_ipaddr_copy(&route->group, group);
745 
746 			route->prefix_len = prefix_len;
747 			route->iface = iface;
748 			route->is_used = true;
749 
750 			return route;
751 		}
752 	}
753 
754 	return NULL;
755 }
756 
net_route_mcast_del(struct net_route_entry_mcast * route)757 bool net_route_mcast_del(struct net_route_entry_mcast *route)
758 {
759 	if (route > &route_mcast_entries[CONFIG_NET_MAX_MCAST_ROUTES - 1] ||
760 	    route < &route_mcast_entries[0]) {
761 		return false;
762 	}
763 
764 	NET_ASSERT(route->is_used,
765 		   "Multicast route %p to %s was already removed", route,
766 		   log_strdup(net_sprint_ipv6_addr(&route->group)));
767 
768 	route->is_used = false;
769 
770 	return true;
771 }
772 
773 struct net_route_entry_mcast *
net_route_mcast_lookup(struct in6_addr * group)774 net_route_mcast_lookup(struct in6_addr *group)
775 {
776 	int i;
777 
778 	for (i = 0; i < CONFIG_NET_MAX_MCAST_ROUTES; i++) {
779 		struct net_route_entry_mcast *route = &route_mcast_entries[i];
780 
781 		if (!route->is_used) {
782 			continue;
783 		}
784 
785 		if (net_ipv6_is_prefix(group->s6_addr,
786 					route->group.s6_addr,
787 					route->prefix_len)) {
788 			return route;
789 		}
790 	}
791 
792 	return NULL;
793 }
794 #endif /* CONFIG_NET_ROUTE_MCAST */
795 
net_route_get_info(struct net_if * iface,struct in6_addr * dst,struct net_route_entry ** route,struct in6_addr ** nexthop)796 bool net_route_get_info(struct net_if *iface,
797 			struct in6_addr *dst,
798 			struct net_route_entry **route,
799 			struct in6_addr **nexthop)
800 {
801 	struct net_if_router *router;
802 
803 	/* Search in neighbor table first, if not search in routing table. */
804 	if (net_ipv6_nbr_lookup(iface, dst)) {
805 		/* Found nexthop, no need to look into routing table. */
806 		*route = NULL;
807 		*nexthop = dst;
808 
809 		return true;
810 	}
811 
812 	*route = net_route_lookup(iface, dst);
813 	if (*route) {
814 		*nexthop = net_route_get_nexthop(*route);
815 		if (!*nexthop) {
816 			return false;
817 		}
818 
819 		return true;
820 	} else {
821 		/* No specific route to this host, use the default
822 		 * route instead.
823 		 */
824 		router = net_if_ipv6_router_find_default(NULL, dst);
825 		if (!router) {
826 			return false;
827 		}
828 
829 		*nexthop = &router->address.in6_addr;
830 
831 		return true;
832 	}
833 
834 	return false;
835 }
836 
net_route_packet(struct net_pkt * pkt,struct in6_addr * nexthop)837 int net_route_packet(struct net_pkt *pkt, struct in6_addr *nexthop)
838 {
839 	struct net_linkaddr_storage *lladdr;
840 	struct net_nbr *nbr;
841 
842 	nbr = net_ipv6_nbr_lookup(NULL, nexthop);
843 	if (!nbr) {
844 		NET_DBG("Cannot find %s neighbor",
845 			log_strdup(net_sprint_ipv6_addr(nexthop)));
846 		return -ENOENT;
847 	}
848 
849 	lladdr = net_nbr_get_lladdr(nbr->idx);
850 	if (!lladdr) {
851 		NET_DBG("Cannot find %s neighbor link layer address.",
852 			log_strdup(net_sprint_ipv6_addr(nexthop)));
853 		return -ESRCH;
854 	}
855 
856 #if defined(CONFIG_NET_L2_DUMMY)
857 	/* No need to do this check for dummy L2 as it does not have any
858 	 * link layer. This is done at runtime because we can have multiple
859 	 * network technologies enabled.
860 	 */
861 	if (net_if_l2(net_pkt_iface(pkt)) != &NET_L2_GET_NAME(DUMMY)) {
862 #endif
863 #if defined(CONFIG_NET_L2_PPP)
864 		/* PPP does not populate the lladdr fields */
865 		if (net_if_l2(net_pkt_iface(pkt)) != &NET_L2_GET_NAME(PPP)) {
866 #endif
867 			if (!net_pkt_lladdr_src(pkt)->addr) {
868 				NET_DBG("Link layer source address not set");
869 				return -EINVAL;
870 			}
871 
872 			/* Sanitycheck: If src and dst ll addresses are going
873 			 * to be same, then something went wrong in route
874 			 * lookup.
875 			 */
876 			if (!memcmp(net_pkt_lladdr_src(pkt)->addr, lladdr->addr,
877 				    lladdr->len)) {
878 				NET_ERR("Src ll and Dst ll are same");
879 				return -EINVAL;
880 			}
881 #if defined(CONFIG_NET_L2_PPP)
882 		}
883 #endif
884 #if defined(CONFIG_NET_L2_DUMMY)
885 	}
886 #endif
887 
888 	net_pkt_set_forwarding(pkt, true);
889 
890 	/* Set the destination and source ll address in the packet.
891 	 * We set the destination address to be the nexthop recipient.
892 	 */
893 	net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr;
894 	net_pkt_lladdr_src(pkt)->type = net_pkt_lladdr_if(pkt)->type;
895 	net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len;
896 
897 	net_pkt_lladdr_dst(pkt)->addr = lladdr->addr;
898 	net_pkt_lladdr_dst(pkt)->type = lladdr->type;
899 	net_pkt_lladdr_dst(pkt)->len = lladdr->len;
900 
901 	net_pkt_set_iface(pkt, nbr->iface);
902 
903 	return net_send_data(pkt);
904 }
905 
net_route_packet_if(struct net_pkt * pkt,struct net_if * iface)906 int net_route_packet_if(struct net_pkt *pkt, struct net_if *iface)
907 {
908 	/* The destination is reachable via iface. But since no valid nexthop
909 	 * is known, net_pkt_lladdr_dst(pkt) cannot be set here.
910 	 */
911 
912 	net_pkt_set_orig_iface(pkt, net_pkt_iface(pkt));
913 	net_pkt_set_iface(pkt, iface);
914 
915 	net_pkt_set_forwarding(pkt, true);
916 
917 	net_pkt_lladdr_src(pkt)->addr = net_pkt_lladdr_if(pkt)->addr;
918 	net_pkt_lladdr_src(pkt)->type = net_pkt_lladdr_if(pkt)->type;
919 	net_pkt_lladdr_src(pkt)->len = net_pkt_lladdr_if(pkt)->len;
920 
921 	return net_send_data(pkt);
922 }
923 
net_route_init(void)924 void net_route_init(void)
925 {
926 	NET_DBG("Allocated %d routing entries (%zu bytes)",
927 		CONFIG_NET_MAX_ROUTES, sizeof(net_route_entries_pool));
928 
929 	NET_DBG("Allocated %d nexthop entries (%zu bytes)",
930 		CONFIG_NET_MAX_NEXTHOPS, sizeof(net_route_nexthop_pool));
931 }
932