1 /*
2 * Copyright (c) 2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_virtual_ipip, CONFIG_NET_L2_IPIP_LOG_LEVEL);
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <errno.h>
13
14 #include <zephyr/net/net_core.h>
15 #include <zephyr/net/net_ip.h>
16 #include <zephyr/net/virtual.h>
17
18 #include "ipv4.h"
19 #include "ipv6.h"
20 #include "net_private.h"
21
22 #if defined(CONFIG_NET_L2_IPIP_TXRX_DEBUG)
23 #define DEBUG_TX 1
24 #define DEBUG_RX 1
25 #else
26 #define DEBUG_TX 0
27 #define DEBUG_RX 0
28 #endif
29
30 #define IPIPV4_MTU NET_IPV4_MTU
31 #define IPIPV6_MTU NET_IPV6_MTU
32
33 #define PKT_ALLOC_TIME K_MSEC(50)
34
35 static K_MUTEX_DEFINE(lock);
36
37 static void init_context_iface(void);
38
39 struct ipip_context {
40 struct net_if *iface;
41 struct net_if *attached_to;
42 union {
43 sa_family_t family;
44 struct net_addr peer;
45 };
46
47 union {
48 const struct in_addr *my4addr;
49 const struct in6_addr *my6addr;
50 };
51
52 bool is_used;
53 bool status;
54 bool init_done;
55 };
56
virt_dev_init(const struct device * dev)57 static int virt_dev_init(const struct device *dev)
58 {
59 ARG_UNUSED(dev);
60
61 init_context_iface();
62
63 return 0;
64 }
65
iface_init(struct net_if * iface)66 static void iface_init(struct net_if *iface)
67 {
68 struct ipip_context *ctx = net_if_get_device(iface)->data;
69
70 if (ctx->init_done) {
71 return;
72 }
73
74 ctx->iface = iface;
75 net_if_flag_set(iface, NET_IF_NO_AUTO_START);
76 net_if_flag_set(iface, NET_IF_POINTOPOINT);
77
78 (void)net_virtual_set_flags(iface, NET_L2_POINT_TO_POINT);
79
80 ctx->init_done = true;
81 }
82
get_capabilities(struct net_if * iface)83 static enum virtual_interface_caps get_capabilities(struct net_if *iface)
84 {
85 ARG_UNUSED(iface);
86
87 return VIRTUAL_INTERFACE_IPIP;
88 }
89
interface_start(const struct device * dev)90 static int interface_start(const struct device *dev)
91 {
92 struct ipip_context *ctx = dev->data;
93 int ret = 0;
94
95 if (ctx->status) {
96 return -EALREADY;
97 }
98
99 ctx->status = true;
100
101 NET_DBG("Starting iface %d", net_if_get_by_iface(ctx->iface));
102
103 return ret;
104 }
105
interface_stop(const struct device * dev)106 static int interface_stop(const struct device *dev)
107 {
108 struct ipip_context *ctx = dev->data;
109
110 if (!ctx->status) {
111 return -EALREADY;
112 }
113
114 ctx->status = false;
115
116 NET_DBG("Stopping iface %d", net_if_get_by_iface(ctx->iface));
117
118 return 0;
119 }
120
ipv4_get_tos(struct net_pkt * pkt)121 static uint8_t ipv4_get_tos(struct net_pkt *pkt)
122 {
123 NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(ipv4_access, struct net_ipv4_hdr);
124 struct net_ipv4_hdr *ipv4_hdr;
125
126 ipv4_hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &ipv4_access);
127 if (!ipv4_hdr) {
128 return 0;
129 }
130
131 return ipv4_hdr->tos;
132 }
133
interface_send(struct net_if * iface,struct net_pkt * pkt)134 static int interface_send(struct net_if *iface, struct net_pkt *pkt)
135 {
136 struct ipip_context *ctx = net_if_get_device(iface)->data;
137 struct net_pkt *tmp = NULL;
138 uint8_t nexthdr;
139 uint8_t tos = 0;
140 int ret;
141
142 if (ctx->attached_to == NULL) {
143 return -ENOENT;
144 }
145
146 if (net_pkt_family(pkt) == AF_INET) {
147 nexthdr = IPPROTO_IPIP;
148 tos = ipv4_get_tos(pkt);
149 } else if (net_pkt_family(pkt) == AF_INET6) {
150 nexthdr = IPPROTO_IPV6;
151 } else {
152 return -EINVAL;
153 }
154
155 /* Add new IP header */
156 if (IS_ENABLED(CONFIG_NET_IPV6) && ctx->family == AF_INET6) {
157 tmp = net_pkt_alloc_with_buffer(iface,
158 sizeof(struct net_ipv6_hdr),
159 AF_INET6, IPPROTO_IPV6,
160 PKT_ALLOC_TIME);
161 if (tmp == NULL) {
162 return -ENOMEM;
163 }
164
165 if (ctx->my6addr == NULL) {
166 ctx->my6addr = net_if_ipv6_select_src_addr(
167 ctx->attached_to,
168 &ctx->peer.in6_addr);
169 }
170
171 ret = net_ipv6_create(tmp, ctx->my6addr, &ctx->peer.in6_addr);
172 if (ret < 0) {
173 goto out;
174 }
175
176 net_buf_frag_add(tmp->buffer, pkt->buffer);
177 pkt->buffer = tmp->buffer;
178 tmp->buffer = NULL;
179
180 net_pkt_unref(tmp);
181 tmp = NULL;
182
183 net_pkt_cursor_init(pkt);
184
185 net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv6_hdr));
186 net_pkt_set_ipv6_ext_opt_len(pkt, 0);
187 net_pkt_set_iface(pkt, ctx->attached_to);
188
189 ret = net_ipv6_finalize(pkt, nexthdr);
190 if (ret < 0) {
191 goto out;
192 }
193
194 net_pkt_set_family(pkt, AF_INET6);
195
196 } else if (IS_ENABLED(CONFIG_NET_IPV4) && ctx->family == AF_INET) {
197 tmp = net_pkt_alloc_with_buffer(iface,
198 sizeof(struct net_ipv4_hdr),
199 AF_INET, IPPROTO_IP,
200 PKT_ALLOC_TIME);
201 if (tmp == NULL) {
202 return -ENOMEM;
203 }
204
205 if (ctx->my4addr == NULL) {
206 ctx->my4addr = net_if_ipv4_select_src_addr(
207 ctx->attached_to,
208 &ctx->peer.in_addr);
209 }
210
211 if (net_if_ipv4_get_ttl(ctx->attached_to) == 0) {
212 NET_WARN("Interface %d TTL set to 0",
213 net_if_get_by_iface(ctx->attached_to));
214 return -EINVAL;
215 }
216
217 net_pkt_set_ipv4_ttl(tmp,
218 net_if_ipv4_get_ttl(ctx->attached_to));
219
220 /* RFC2003 chapter 3.1 */
221 ret = net_ipv4_create_full(tmp, ctx->my4addr,
222 &ctx->peer.in_addr,
223 tos, 0U, NET_IPV4_DF,
224 0U);
225 if (ret < 0) {
226 goto out;
227 }
228
229 net_buf_frag_add(tmp->buffer, pkt->buffer);
230 pkt->buffer = tmp->buffer;
231 tmp->buffer = NULL;
232
233 net_pkt_unref(tmp);
234 tmp = NULL;
235
236 net_pkt_cursor_init(pkt);
237
238 net_pkt_set_ip_hdr_len(pkt, sizeof(struct net_ipv4_hdr));
239 net_pkt_set_ipv4_opts_len(pkt, 0);
240 net_pkt_set_iface(pkt, ctx->attached_to);
241
242 ret = net_ipv4_finalize(pkt, nexthdr);
243 if (ret < 0) {
244 goto out;
245 }
246
247 net_pkt_set_family(pkt, AF_INET);
248 }
249
250 if (DEBUG_TX) {
251 char str[sizeof("TX iface xx")];
252
253 snprintk(str, sizeof(str), "TX iface %d",
254 net_if_get_by_iface(net_pkt_iface(pkt)));
255
256 net_pkt_hexdump(pkt, str);
257 }
258
259 return net_send_data(pkt);
260
261 out:
262 if (tmp) {
263 net_pkt_unref(tmp);
264 }
265
266 return ret;
267 }
268
verify_remote_addr(struct ipip_context * ctx,struct sockaddr * remote_addr)269 static bool verify_remote_addr(struct ipip_context *ctx,
270 struct sockaddr *remote_addr)
271 {
272 if (ctx->family != remote_addr->sa_family) {
273 return false;
274 }
275
276 if (ctx->family == AF_INET) {
277 if (memcmp(&ctx->peer.in_addr, &net_sin(remote_addr)->sin_addr,
278 sizeof(struct in_addr)) == 0) {
279 return true;
280 }
281 } else {
282 if (memcmp(&ctx->peer.in6_addr, &net_sin6(remote_addr)->sin6_addr,
283 sizeof(struct in6_addr)) == 0) {
284 return true;
285 }
286 }
287
288 return false;
289 }
290
interface_recv(struct net_if * iface,struct net_pkt * pkt)291 static enum net_verdict interface_recv(struct net_if *iface,
292 struct net_pkt *pkt)
293 {
294 struct ipip_context *ctx = net_if_get_device(iface)->data;
295 struct net_pkt_cursor hdr_start;
296 uint8_t iptype;
297
298 net_pkt_cursor_backup(pkt, &hdr_start);
299
300 if (net_pkt_read_u8(pkt, &iptype)) {
301 return NET_DROP;
302 }
303
304 net_pkt_cursor_restore(pkt, &hdr_start);
305
306 switch (iptype & 0xf0) {
307 case 0x60:
308 net_pkt_set_family(pkt, AF_INET6);
309 break;
310 case 0x40:
311 net_pkt_set_family(pkt, AF_INET);
312 break;
313 default:
314 return NET_DROP;
315 }
316
317 /* Make sure we are receiving data from remote end of the
318 * tunnel. See RFC4213 chapter 4 for details.
319 */
320 if (!verify_remote_addr(ctx, net_pkt_remote_address(pkt))) {
321 NET_DBG("DROP: remote address %s unknown",
322 net_pkt_remote_address(pkt)->sa_family == AF_INET6 ?
323 net_sprint_ipv6_addr(&net_sin6(net_pkt_remote_address(pkt))->sin6_addr) :
324 net_sprint_ipv4_addr(&net_sin(net_pkt_remote_address(pkt))->sin_addr));
325 return NET_DROP;
326 }
327
328 if (DEBUG_RX) {
329 char str[sizeof("RX iface xx")];
330
331 snprintk(str, sizeof(str), "RX iface %d",
332 net_if_get_by_iface(iface));
333
334 net_pkt_hexdump(pkt, str);
335 }
336
337 /* net_pkt cursor must point to correct place so that we can fetch
338 * the network header.
339 */
340 if (IS_ENABLED(CONFIG_NET_IPV6) && net_pkt_family(pkt) == AF_INET6) {
341 NET_PKT_DATA_ACCESS_DEFINE(access, struct net_ipv6_hdr);
342 struct net_ipv6_hdr *hdr;
343 struct net_if *iface_test;
344
345 net_pkt_cursor_backup(pkt, &hdr_start);
346
347 hdr = (struct net_ipv6_hdr *)net_pkt_get_data(pkt, &access);
348 if (!hdr) {
349 return NET_DROP;
350 }
351
352 /* RFC4213 chapter 3.6 */
353 iface_test = net_if_ipv6_select_src_iface((struct in6_addr *)hdr->dst);
354 if (iface_test == NULL) {
355 NET_DBG("DROP: not for me (dst %s)",
356 net_sprint_ipv6_addr(&hdr->dst));
357 return NET_DROP;
358 }
359
360 if (iface != iface_test) {
361 NET_DBG("DROP: wrong interface %d (%p), expecting %d (%p)",
362 net_if_get_by_iface(iface_test), iface_test,
363 net_if_get_by_iface(iface), iface);
364 return NET_DROP;
365 }
366
367 /* Hop limit fields is decremented, RFC2473 chapter 3.1 and
368 * RFC4213 chapter 3.3
369 */
370 hdr->hop_limit--;
371 (void)net_pkt_set_data(pkt, &access);
372
373 net_pkt_set_iface(pkt, iface);
374
375 net_pkt_cursor_restore(pkt, &hdr_start);
376
377 return net_ipv6_input(pkt, false);
378 }
379
380 if (IS_ENABLED(CONFIG_NET_IPV4) && net_pkt_family(pkt) == AF_INET) {
381 NET_PKT_DATA_ACCESS_DEFINE(access, struct net_ipv4_hdr);
382 struct net_ipv4_hdr *hdr;
383 struct net_if *iface_test;
384 uint16_t sum;
385
386 net_pkt_cursor_backup(pkt, &hdr_start);
387
388 hdr = (struct net_ipv4_hdr *)net_pkt_get_data(pkt, &access);
389 if (!hdr) {
390 return NET_DROP;
391 }
392
393 iface_test = net_if_ipv4_select_src_iface((struct in_addr *)hdr->dst);
394 if (iface_test == NULL) {
395 NET_DBG("DROP: not for me (dst %s)",
396 net_sprint_ipv4_addr(&hdr->dst));
397 return NET_DROP;
398 }
399
400 if (iface != iface_test) {
401 NET_DBG("DROP: wrong interface %d (%p), expecting %d (%p)",
402 net_if_get_by_iface(iface_test), iface_test,
403 net_if_get_by_iface(iface), iface);
404 return NET_DROP;
405 }
406
407 /* TTL fields is decremented, RFC2003 chapter 3.1 */
408 hdr->ttl--;
409
410 /* Recalculate the checksum because TTL was changed */
411 hdr->chksum = 0U;
412
413 sum = calc_chksum(0, access.data, access.size);
414 sum = (sum == 0U) ? 0xffff : htons(sum);
415
416 hdr->chksum = ~sum;
417
418 (void)net_pkt_set_data(pkt, &access);
419
420 net_pkt_set_iface(pkt, iface);
421
422 net_pkt_cursor_restore(pkt, &hdr_start);
423
424 return net_ipv4_input(pkt, false);
425 }
426
427 return NET_CONTINUE;
428 }
429
interface_attach(struct net_if * iface,struct net_if * lower_iface)430 static int interface_attach(struct net_if *iface, struct net_if *lower_iface)
431 {
432 struct ipip_context *ctx;
433
434 if (net_if_get_by_iface(iface) < 0) {
435 return -ENOENT;
436 }
437
438 k_mutex_lock(&lock, K_FOREVER);
439
440 ctx = net_if_get_device(iface)->data;
441 ctx->attached_to = lower_iface;
442 ctx->iface = iface;
443
444 if (lower_iface == NULL) {
445 ctx->is_used = false;
446 } else {
447 ctx->is_used = true;
448
449 if (IS_ENABLED(CONFIG_NET_IPV6) && ctx->family == AF_INET6) {
450 struct net_if_addr *ifaddr;
451 struct in6_addr iid;
452 int ret;
453
454 /* RFC4213 chapter 3.7 */
455 ret = net_ipv6_addr_generate_iid(iface, NULL,
456 COND_CODE_1(CONFIG_NET_IPV6_IID_STABLE,
457 ((uint8_t *)&iface->config.ip.ipv6->network_counter),
458 (NULL)),
459 COND_CODE_1(CONFIG_NET_IPV6_IID_STABLE,
460 (sizeof(iface->config.ip.ipv6->network_counter)),
461 (0U)),
462 0,
463 &iid,
464 net_if_get_link_addr(iface));
465 if (ret < 0) {
466 NET_WARN("IPv6 IID generation issue (%d)", ret);
467 }
468
469 ifaddr = net_if_ipv6_addr_add(iface, &iid, NET_ADDR_AUTOCONF, 0);
470 if (!ifaddr) {
471 NET_ERR("Cannot add %s address to interface %p",
472 net_sprint_ipv6_addr(&iid),
473 iface);
474 }
475 }
476 }
477
478 k_mutex_unlock(&lock);
479
480 return 0;
481 }
482
interface_set_config(struct net_if * iface,enum virtual_interface_config_type type,const struct virtual_interface_config * config)483 static int interface_set_config(struct net_if *iface,
484 enum virtual_interface_config_type type,
485 const struct virtual_interface_config *config)
486 {
487 struct ipip_context *ctx = net_if_get_device(iface)->data;
488
489 switch (type) {
490 case VIRTUAL_INTERFACE_CONFIG_TYPE_PEER_ADDRESS:
491 if (IS_ENABLED(CONFIG_NET_IPV4) && config->family == AF_INET) {
492 char peer[INET_ADDRSTRLEN];
493 char *addr_str;
494
495 net_ipaddr_copy(&ctx->peer.in_addr, &config->peer4addr);
496
497 addr_str = net_addr_ntop(AF_INET, &ctx->peer.in_addr,
498 peer, sizeof(peer));
499
500 ctx->family = AF_INET;
501 net_virtual_set_name(iface, "IPv4 tunnel");
502
503 if (ctx->attached_to == NULL) {
504 (void)net_virtual_interface_attach(iface,
505 net_if_ipv4_select_src_iface(
506 &ctx->peer.in_addr));
507 }
508
509 if (ctx->attached_to) {
510 net_if_ipv4_set_ttl(iface,
511 net_if_ipv4_get_ttl(ctx->attached_to));
512 }
513
514 NET_DBG("Interface %d peer address %s attached to %d",
515 net_if_get_by_iface(iface),
516 addr_str,
517 net_if_get_by_iface(ctx->attached_to));
518
519 ctx->my4addr = NULL;
520
521 } else if (IS_ENABLED(CONFIG_NET_IPV6) &&
522 config->family == AF_INET6) {
523 char peer[INET6_ADDRSTRLEN];
524 char *addr_str;
525
526 net_ipaddr_copy(&ctx->peer.in6_addr,
527 &config->peer6addr);
528
529 addr_str = net_addr_ntop(AF_INET6, &ctx->peer.in6_addr,
530 peer, sizeof(peer));
531
532 ctx->family = AF_INET6;
533 net_virtual_set_name(iface, "IPv6 tunnel");
534
535 net_if_ipv6_set_hop_limit(iface, 64);
536
537 if (ctx->attached_to == NULL) {
538 (void)net_virtual_interface_attach(iface,
539 net_if_ipv6_select_src_iface(
540 &ctx->peer.in6_addr));
541 }
542
543 NET_DBG("Interface %d peer address %s attached to %d",
544 net_if_get_by_iface(iface),
545 addr_str,
546 net_if_get_by_iface(ctx->attached_to));
547
548 ctx->my6addr = NULL;
549 } else {
550 return -EINVAL;
551 }
552
553 return 0;
554
555 case VIRTUAL_INTERFACE_CONFIG_TYPE_MTU:
556 NET_DBG("Interface %d MTU set to %d",
557 net_if_get_by_iface(iface), config->mtu);
558 net_if_set_mtu(iface, config->mtu);
559 return 0;
560
561 default:
562 break;
563 }
564
565 return -ENOTSUP;
566 }
567
interface_get_config(struct net_if * iface,enum virtual_interface_config_type type,struct virtual_interface_config * config)568 static int interface_get_config(struct net_if *iface,
569 enum virtual_interface_config_type type,
570 struct virtual_interface_config *config)
571 {
572 struct ipip_context *ctx = net_if_get_device(iface)->data;
573
574 switch (type) {
575 case VIRTUAL_INTERFACE_CONFIG_TYPE_PEER_ADDRESS:
576 if (IS_ENABLED(CONFIG_NET_IPV6) &&
577 ctx->family == AF_INET6) {
578 net_ipaddr_copy(&config->peer6addr,
579 &ctx->peer.in6_addr);
580
581 } else if (IS_ENABLED(CONFIG_NET_IPV4) &&
582 ctx->family == AF_INET) {
583 net_ipaddr_copy(&config->peer4addr,
584 &ctx->peer.in_addr);
585
586 } else {
587 return -EINVAL;
588 }
589
590 config->family = ctx->family;
591 return 0;
592
593 case VIRTUAL_INTERFACE_CONFIG_TYPE_MTU:
594 config->mtu = net_if_get_mtu(iface);
595 return 0;
596
597 default:
598 break;
599 }
600
601 return -ENOTSUP;
602 }
603
604 static const struct virtual_interface_api ipip_iface_api = {
605 .iface_api.init = iface_init,
606
607 .get_capabilities = get_capabilities,
608 .start = interface_start,
609 .stop = interface_stop,
610 .send = interface_send,
611 .recv = interface_recv,
612 .attach = interface_attach,
613 .set_config = interface_set_config,
614 .get_config = interface_get_config,
615 };
616
617 #define NET_IPIP_INTERFACE_INIT(x, _) \
618 static struct ipip_context ipip_context_data_##x = { \
619 }; \
620 NET_VIRTUAL_INTERFACE_INIT_INSTANCE(ipip_##x, \
621 "IP_TUNNEL" #x, \
622 x, \
623 virt_dev_init, \
624 NULL, \
625 &ipip_context_data_##x, \
626 NULL, /* config */ \
627 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \
628 &ipip_iface_api, \
629 IPIPV4_MTU)
630
631 LISTIFY(CONFIG_NET_L2_IPIP_TUNNEL_COUNT, NET_IPIP_INTERFACE_INIT, (;), _);
632
633 #define INIT_IPIP_CONTEXT_PTR(x, _) \
634 [x] = &ipip_context_data_##x
635
636 static struct ipip_context *ipip_ctx[] = {
637 LISTIFY(CONFIG_NET_L2_IPIP_TUNNEL_COUNT, INIT_IPIP_CONTEXT_PTR, (,), _)
638 };
639
640 #define INIT_IPIP_CONTEXT_IFACE(x, _) \
641 ipip_context_data_##x.iface = NET_IF_GET(ipip_##x, x)
642
init_context_iface(void)643 static void init_context_iface(void)
644 {
645 static bool init_done;
646
647 if (init_done) {
648 return;
649 }
650
651 init_done = true;
652
653 LISTIFY(CONFIG_NET_L2_IPIP_TUNNEL_COUNT, INIT_IPIP_CONTEXT_IFACE, (;), _);
654 }
655
net_ipip_get_virtual_interface(struct net_if * input_iface)656 struct net_if *net_ipip_get_virtual_interface(struct net_if *input_iface)
657 {
658 struct net_if *iface = NULL;
659
660 k_mutex_lock(&lock, K_FOREVER);
661
662 ARRAY_FOR_EACH(ipip_ctx, i) {
663 if (ipip_ctx[i] == NULL || !ipip_ctx[i]->is_used) {
664 continue;
665 }
666
667 if (input_iface == ipip_ctx[i]->attached_to) {
668 iface = ipip_ctx[i]->iface;
669 goto out;
670 }
671 }
672
673 out:
674 k_mutex_unlock(&lock);
675
676 return iface;
677 }
678