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