1 /* $OpenBSD: if_gif.c,v 1.138 2024/05/13 01:15:53 jsg Exp $ */
2 /* $KAME: if_gif.c,v 1.43 2001/02/20 08:51:07 itojun Exp $ */
3
4 /*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <sys/syslog.h>
39 #include <sys/queue.h>
40
41 #include <net/if.h>
42 #include <net/if_var.h>
43 #include <net/if_types.h>
44 #include <net/route.h>
45
46 #include <netinet/in.h>
47 #include <netinet/in_var.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_var.h>
50 #include <netinet/ip_ipip.h>
51 #include <netinet/ip_ecn.h>
52
53 #ifdef INET6
54 #include <netinet6/in6_var.h>
55 #include <netinet/ip6.h>
56 #include <netinet6/ip6_var.h>
57 #endif /* INET6 */
58
59 #include <net/if_gif.h>
60
61 #include "bpfilter.h"
62 #if NBPFILTER > 0
63 #include <net/bpf.h>
64 #endif
65
66 #ifdef MPLS
67 #include <netmpls/mpls.h>
68 #endif
69
70 #include "pf.h"
71 #if NPF > 0
72 #include <net/pfvar.h>
73 #endif
74
75 #define GIF_MTU (1280) /* Default MTU */
76 #define GIF_MTU_MIN (1280) /* Minimum MTU */
77 #define GIF_MTU_MAX (8192) /* Maximum MTU */
78
79 union gif_addr {
80 struct in6_addr in6;
81 struct in_addr in4;
82 };
83
84 struct gif_tunnel {
85 TAILQ_ENTRY(gif_tunnel) t_entry;
86
87 union gif_addr t_src;
88 #define t_src4 t_src.in4
89 #define t_src6 t_src.in6
90 union gif_addr t_dst;
91 #define t_dst4 t_dst.in4
92 #define t_dst6 t_dst.in6
93 u_int t_rtableid;
94
95 sa_family_t t_af;
96 };
97
98 TAILQ_HEAD(gif_list, gif_tunnel);
99
100 static inline int gif_cmp(const struct gif_tunnel *,
101 const struct gif_tunnel *);
102
103 struct gif_softc {
104 struct gif_tunnel sc_tunnel; /* must be first */
105 struct ifnet sc_if;
106 uint16_t sc_df;
107 int sc_ttl;
108 int sc_txhprio;
109 int sc_rxhprio;
110 int sc_ecn;
111 };
112
113 struct gif_list gif_list = TAILQ_HEAD_INITIALIZER(gif_list);
114
115 void gifattach(int);
116 int gif_clone_create(struct if_clone *, int);
117 int gif_clone_destroy(struct ifnet *);
118
119 void gif_start(struct ifnet *);
120 int gif_ioctl(struct ifnet *, u_long, caddr_t);
121 int gif_output(struct ifnet *, struct mbuf *, struct sockaddr *,
122 struct rtentry *);
123 int gif_send(struct gif_softc *, struct mbuf *, uint8_t, uint8_t, uint8_t);
124
125 int gif_up(struct gif_softc *);
126 int gif_down(struct gif_softc *);
127 int gif_set_tunnel(struct gif_softc *, struct if_laddrreq *);
128 int gif_get_tunnel(struct gif_softc *, struct if_laddrreq *);
129 int gif_del_tunnel(struct gif_softc *);
130 int gif_input(struct gif_tunnel *, struct mbuf **, int *, int, int,
131 uint8_t);
132
133 /*
134 * gif global variable definitions
135 */
136 struct if_clone gif_cloner =
137 IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
138
139 void
gifattach(int count)140 gifattach(int count)
141 {
142 if_clone_attach(&gif_cloner);
143 }
144
145 int
gif_clone_create(struct if_clone * ifc,int unit)146 gif_clone_create(struct if_clone *ifc, int unit)
147 {
148 struct gif_softc *sc;
149 struct ifnet *ifp;
150
151 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
152 ifp = &sc->sc_if;
153
154 sc->sc_df = htons(0);
155 sc->sc_ttl = ip_defttl;
156 sc->sc_txhprio = IF_HDRPRIO_PAYLOAD;
157 sc->sc_rxhprio = IF_HDRPRIO_PAYLOAD;
158 sc->sc_ecn = ECN_ALLOWED;
159
160 snprintf(ifp->if_xname, sizeof(ifp->if_xname),
161 "%s%d", ifc->ifc_name, unit);
162
163 ifp->if_mtu = GIF_MTU;
164 ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
165 ifp->if_xflags = IFXF_CLONED;
166 ifp->if_ioctl = gif_ioctl;
167 ifp->if_bpf_mtap = p2p_bpf_mtap;
168 ifp->if_input = p2p_input;
169 ifp->if_start = gif_start;
170 ifp->if_output = gif_output;
171 ifp->if_rtrequest = p2p_rtrequest;
172 ifp->if_type = IFT_GIF;
173 ifp->if_softc = sc;
174
175 if_counters_alloc(ifp);
176 if_attach(ifp);
177 if_alloc_sadl(ifp);
178
179 #if NBPFILTER > 0
180 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
181 #endif
182
183 NET_LOCK();
184 TAILQ_INSERT_TAIL(&gif_list, &sc->sc_tunnel, t_entry);
185 NET_UNLOCK();
186
187 return (0);
188 }
189
190 int
gif_clone_destroy(struct ifnet * ifp)191 gif_clone_destroy(struct ifnet *ifp)
192 {
193 struct gif_softc *sc = ifp->if_softc;
194
195 NET_LOCK();
196 if (ISSET(ifp->if_flags, IFF_RUNNING))
197 gif_down(sc);
198
199 TAILQ_REMOVE(&gif_list, &sc->sc_tunnel, t_entry);
200 NET_UNLOCK();
201
202 if_detach(ifp);
203
204 free(sc, M_DEVBUF, sizeof(*sc));
205
206 return (0);
207 }
208
209 void
gif_start(struct ifnet * ifp)210 gif_start(struct ifnet *ifp)
211 {
212 struct gif_softc *sc = ifp->if_softc;
213 struct mbuf *m;
214 #if NBPFILTER > 0
215 caddr_t if_bpf;
216 #endif
217 uint8_t proto, ttl, tos;
218 int ttloff, tttl;
219
220 tttl = sc->sc_ttl;
221
222 while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
223 #if NBPFILTER > 0
224 if_bpf = ifp->if_bpf;
225 if (if_bpf) {
226 bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family, m,
227 BPF_DIRECTION_OUT);
228 }
229 #endif
230
231 switch (m->m_pkthdr.ph_family) {
232 case AF_INET: {
233 struct ip *ip;
234
235 m = m_pullup(m, sizeof(*ip));
236 if (m == NULL)
237 continue;
238
239 ip = mtod(m, struct ip *);
240 tos = ip->ip_tos;
241
242 ttloff = offsetof(struct ip, ip_ttl);
243 proto = IPPROTO_IPV4;
244 break;
245 }
246 #ifdef INET6
247 case AF_INET6: {
248 struct ip6_hdr *ip6;
249
250 m = m_pullup(m, sizeof(*ip6));
251 if (m == NULL)
252 continue;
253
254 ip6 = mtod(m, struct ip6_hdr *);
255 tos = ntohl(ip6->ip6_flow >> 20);
256
257 ttloff = offsetof(struct ip6_hdr, ip6_hlim);
258 proto = IPPROTO_IPV6;
259 break;
260 }
261 #endif
262 #ifdef MPLS
263 case AF_MPLS: {
264 uint32_t shim;
265
266 m = m_pullup(m, sizeof(shim));
267 if (m == NULL)
268 continue;
269
270 shim = *mtod(m, uint32_t *) & MPLS_EXP_MASK;
271 tos = (ntohl(shim) >> MPLS_EXP_OFFSET) << 5;
272
273 ttloff = 3;
274
275 proto = IPPROTO_MPLS;
276 break;
277 }
278 #endif
279 default:
280 unhandled_af(m->m_pkthdr.ph_family);
281 }
282
283 if (tttl == -1) {
284 KASSERT(m->m_len > ttloff);
285
286 ttl = *(m->m_data + ttloff);
287 } else
288 ttl = tttl;
289
290 switch (sc->sc_txhprio) {
291 case IF_HDRPRIO_PAYLOAD:
292 /* tos is already set */
293 break;
294 case IF_HDRPRIO_PACKET:
295 tos = IFQ_PRIO2TOS(m->m_pkthdr.pf.prio);
296 break;
297 default:
298 tos = IFQ_PRIO2TOS(sc->sc_txhprio);
299 break;
300 }
301
302 gif_send(sc, m, proto, ttl, tos);
303 }
304 }
305
306 int
gif_send(struct gif_softc * sc,struct mbuf * m,uint8_t proto,uint8_t ttl,uint8_t itos)307 gif_send(struct gif_softc *sc, struct mbuf *m,
308 uint8_t proto, uint8_t ttl, uint8_t itos)
309 {
310 uint8_t otos;
311
312 m->m_flags &= ~(M_BCAST|M_MCAST);
313 m->m_pkthdr.ph_rtableid = sc->sc_tunnel.t_rtableid;
314
315 #if NPF > 0
316 pf_pkt_addr_changed(m);
317 #endif
318
319 ip_ecn_ingress(sc->sc_ecn, &otos, &itos);
320
321 switch (sc->sc_tunnel.t_af) {
322 case AF_INET: {
323 struct ip *ip;
324
325 if (in_nullhost(sc->sc_tunnel.t_dst4))
326 goto drop;
327
328 m = m_prepend(m, sizeof(*ip), M_DONTWAIT);
329 if (m == NULL)
330 return (-1);
331
332 ip = mtod(m, struct ip *);
333 ip->ip_off = sc->sc_df;
334 ip->ip_tos = otos;
335 ip->ip_len = htons(m->m_pkthdr.len);
336 ip->ip_ttl = ttl;
337 ip->ip_p = proto;
338 ip->ip_src = sc->sc_tunnel.t_src4;
339 ip->ip_dst = sc->sc_tunnel.t_dst4;
340
341 ip_send(m);
342 break;
343 }
344 #ifdef INET6
345 case AF_INET6: {
346 struct ip6_hdr *ip6;
347 int len = m->m_pkthdr.len;
348 uint32_t flow;
349
350 if (IN6_IS_ADDR_UNSPECIFIED(&sc->sc_tunnel.t_dst6))
351 goto drop;
352
353 m = m_prepend(m, sizeof(*ip6), M_DONTWAIT);
354 if (m == NULL)
355 return (-1);
356
357 flow = otos << 20;
358 if (ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
359 flow |= m->m_pkthdr.ph_flowid;
360
361 ip6 = mtod(m, struct ip6_hdr *);
362 ip6->ip6_flow = htonl(flow);
363 ip6->ip6_vfc |= IPV6_VERSION;
364 ip6->ip6_plen = htons(len);
365 ip6->ip6_nxt = proto;
366 ip6->ip6_hlim = ttl;
367 ip6->ip6_src = sc->sc_tunnel.t_src6;
368 ip6->ip6_dst = sc->sc_tunnel.t_dst6;
369
370 if (sc->sc_df)
371 SET(m->m_pkthdr.csum_flags, M_IPV6_DF_OUT);
372
373 ip6_send(m);
374 break;
375 }
376 #endif
377 default:
378 m_freem(m);
379 break;
380 }
381
382 return (0);
383
384 drop:
385 m_freem(m);
386 return (0);
387 }
388
389 int
gif_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)390 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
391 struct rtentry *rt)
392 {
393 struct m_tag *mtag;
394 int error = 0;
395
396 if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
397 error = ENETDOWN;
398 goto drop;
399 }
400
401 switch (dst->sa_family) {
402 case AF_INET:
403 #ifdef INET6
404 case AF_INET6:
405 #endif
406 #ifdef MPLS
407 case AF_MPLS:
408 #endif
409 break;
410 default:
411 error = EAFNOSUPPORT;
412 goto drop;
413 }
414
415 /* Try to limit infinite recursion through misconfiguration. */
416 for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag;
417 mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) {
418 if (memcmp((caddr_t)(mtag + 1), &ifp->if_index,
419 sizeof(ifp->if_index)) == 0) {
420 error = EIO;
421 goto drop;
422 }
423 }
424
425 mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
426 if (mtag == NULL) {
427 error = ENOBUFS;
428 goto drop;
429 }
430 memcpy((caddr_t)(mtag + 1), &ifp->if_index, sizeof(ifp->if_index));
431 m_tag_prepend(m, mtag);
432
433 m->m_pkthdr.ph_family = dst->sa_family;
434
435 error = if_enqueue(ifp, m);
436
437 if (error)
438 ifp->if_oerrors++;
439 return (error);
440
441 drop:
442 m_freem(m);
443 return (error);
444 }
445
446 int
gif_up(struct gif_softc * sc)447 gif_up(struct gif_softc *sc)
448 {
449 NET_ASSERT_LOCKED();
450
451 SET(sc->sc_if.if_flags, IFF_RUNNING);
452
453 return (0);
454 }
455
456 int
gif_down(struct gif_softc * sc)457 gif_down(struct gif_softc *sc)
458 {
459 NET_ASSERT_LOCKED();
460
461 CLR(sc->sc_if.if_flags, IFF_RUNNING);
462
463 /* barrier? */
464
465 return (0);
466 }
467
468 int
gif_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)469 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
470 {
471 struct gif_softc *sc = ifp->if_softc;
472 struct ifreq *ifr = (struct ifreq *)data;
473 int error = 0;
474
475 switch (cmd) {
476 case SIOCSIFADDR:
477 SET(ifp->if_flags, IFF_UP);
478 /* FALLTHROUGH */
479 case SIOCSIFFLAGS:
480 if (ISSET(ifp->if_flags, IFF_UP)) {
481 if (!ISSET(ifp->if_flags, IFF_RUNNING))
482 error = gif_up(sc);
483 else
484 error = 0;
485 } else {
486 if (ISSET(ifp->if_flags, IFF_RUNNING))
487 error = gif_down(sc);
488 }
489 break;
490
491 case SIOCADDMULTI:
492 case SIOCDELMULTI:
493 break;
494
495 case SIOCSLIFPHYADDR:
496 error = gif_set_tunnel(sc, (struct if_laddrreq *)data);
497 break;
498 case SIOCGLIFPHYADDR:
499 error = gif_get_tunnel(sc, (struct if_laddrreq *)data);
500 break;
501 case SIOCDIFPHYADDR:
502 error = gif_del_tunnel(sc);
503 break;
504
505 case SIOCSIFMTU:
506 if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX) {
507 error = EINVAL;
508 break;
509 }
510
511 ifp->if_mtu = ifr->ifr_mtu;
512 break;
513
514 case SIOCSLIFPHYRTABLE:
515 if (ifr->ifr_rdomainid < 0 ||
516 ifr->ifr_rdomainid > RT_TABLEID_MAX ||
517 !rtable_exists(ifr->ifr_rdomainid)) {
518 error = EINVAL;
519 break;
520 }
521 sc->sc_tunnel.t_rtableid = ifr->ifr_rdomainid;
522 break;
523 case SIOCGLIFPHYRTABLE:
524 ifr->ifr_rdomainid = sc->sc_tunnel.t_rtableid;
525 break;
526
527 case SIOCSLIFPHYTTL:
528 if (ifr->ifr_ttl != -1 &&
529 (ifr->ifr_ttl < 1 || ifr->ifr_ttl > 0xff)) {
530 error = EINVAL;
531 break;
532 }
533
534 /* commit */
535 sc->sc_ttl = ifr->ifr_ttl;
536 break;
537 case SIOCGLIFPHYTTL:
538 ifr->ifr_ttl = sc->sc_ttl;
539 break;
540
541 case SIOCSLIFPHYDF:
542 /* commit */
543 sc->sc_df = ifr->ifr_df ? htons(IP_DF) : htons(0);
544 break;
545 case SIOCGLIFPHYDF:
546 ifr->ifr_df = sc->sc_df ? 1 : 0;
547 break;
548
549 case SIOCSLIFPHYECN:
550 sc->sc_ecn = ifr->ifr_metric ? ECN_ALLOWED : ECN_FORBIDDEN;
551 break;
552 case SIOCGLIFPHYECN:
553 ifr->ifr_metric = (sc->sc_ecn == ECN_ALLOWED);
554 break;
555
556 case SIOCSTXHPRIO:
557 error = if_txhprio_l3_check(ifr->ifr_hdrprio);
558 if (error != 0)
559 break;
560
561 sc->sc_txhprio = ifr->ifr_hdrprio;
562 break;
563 case SIOCGTXHPRIO:
564 ifr->ifr_hdrprio = sc->sc_txhprio;
565 break;
566
567 case SIOCSRXHPRIO:
568 error = if_rxhprio_l3_check(ifr->ifr_hdrprio);
569 if (error != 0)
570 break;
571
572 sc->sc_rxhprio = ifr->ifr_hdrprio;
573 break;
574 case SIOCGRXHPRIO:
575 ifr->ifr_hdrprio = sc->sc_rxhprio;
576 break;
577
578 default:
579 error = ENOTTY;
580 break;
581 }
582
583 return (error);
584 }
585
586 int
gif_get_tunnel(struct gif_softc * sc,struct if_laddrreq * req)587 gif_get_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
588 {
589 struct gif_tunnel *tunnel = &sc->sc_tunnel;
590 struct sockaddr *src = (struct sockaddr *)&req->addr;
591 struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
592 struct sockaddr_in *sin;
593 #ifdef INET6 /* ifconfig already embeds the scopeid */
594 struct sockaddr_in6 *sin6;
595 #endif
596
597 switch (tunnel->t_af) {
598 case AF_UNSPEC:
599 return (EADDRNOTAVAIL);
600 case AF_INET:
601 sin = (struct sockaddr_in *)src;
602 memset(sin, 0, sizeof(*sin));
603 sin->sin_family = AF_INET;
604 sin->sin_len = sizeof(*sin);
605 sin->sin_addr = tunnel->t_src4;
606
607 sin = (struct sockaddr_in *)dst;
608 memset(sin, 0, sizeof(*sin));
609 sin->sin_family = AF_INET;
610 sin->sin_len = sizeof(*sin);
611 sin->sin_addr = tunnel->t_dst4;
612
613 break;
614
615 #ifdef INET6
616 case AF_INET6:
617 sin6 = (struct sockaddr_in6 *)src;
618 memset(sin6, 0, sizeof(*sin6));
619 sin6->sin6_family = AF_INET6;
620 sin6->sin6_len = sizeof(*sin6);
621 in6_recoverscope(sin6, &tunnel->t_src6);
622
623 sin6 = (struct sockaddr_in6 *)dst;
624 memset(sin6, 0, sizeof(*sin6));
625 sin6->sin6_family = AF_INET6;
626 sin6->sin6_len = sizeof(*sin6);
627 in6_recoverscope(sin6, &tunnel->t_dst6);
628
629 break;
630 #endif
631 default:
632 return (EAFNOSUPPORT);
633 }
634
635 return (0);
636 }
637
638 int
gif_set_tunnel(struct gif_softc * sc,struct if_laddrreq * req)639 gif_set_tunnel(struct gif_softc *sc, struct if_laddrreq *req)
640 {
641 struct gif_tunnel *tunnel = &sc->sc_tunnel;
642 struct sockaddr *src = (struct sockaddr *)&req->addr;
643 struct sockaddr *dst = (struct sockaddr *)&req->dstaddr;
644 struct sockaddr_in *src4, *dst4;
645 #ifdef INET6
646 struct sockaddr_in6 *src6, *dst6;
647 int error;
648 #endif
649
650 /* sa_family and sa_len must be equal */
651 if (src->sa_family != dst->sa_family || src->sa_len != dst->sa_len)
652 return (EINVAL);
653
654 /* validate */
655 switch (dst->sa_family) {
656 case AF_INET:
657 if (dst->sa_len != sizeof(*dst4))
658 return (EINVAL);
659
660 src4 = (struct sockaddr_in *)src;
661 if (in_nullhost(src4->sin_addr) ||
662 IN_MULTICAST(src4->sin_addr.s_addr))
663 return (EINVAL);
664
665 dst4 = (struct sockaddr_in *)dst;
666 /* dst4 can be 0.0.0.0 */
667 if (IN_MULTICAST(dst4->sin_addr.s_addr))
668 return (EINVAL);
669
670 tunnel->t_src4 = src4->sin_addr;
671 tunnel->t_dst4 = dst4->sin_addr;
672
673 break;
674 #ifdef INET6
675 case AF_INET6:
676 if (dst->sa_len != sizeof(*dst6))
677 return (EINVAL);
678
679 src6 = (struct sockaddr_in6 *)src;
680 if (IN6_IS_ADDR_UNSPECIFIED(&src6->sin6_addr) ||
681 IN6_IS_ADDR_MULTICAST(&src6->sin6_addr))
682 return (EINVAL);
683
684 dst6 = (struct sockaddr_in6 *)dst;
685 if (IN6_IS_ADDR_MULTICAST(&dst6->sin6_addr))
686 return (EINVAL);
687
688 error = in6_embedscope(&tunnel->t_src6, src6, NULL, NULL);
689 if (error != 0)
690 return (error);
691
692 error = in6_embedscope(&tunnel->t_dst6, dst6, NULL, NULL);
693 if (error != 0)
694 return (error);
695
696 break;
697 #endif
698 default:
699 return (EAFNOSUPPORT);
700 }
701
702 /* commit */
703 tunnel->t_af = dst->sa_family;
704
705 return (0);
706 }
707
708 int
gif_del_tunnel(struct gif_softc * sc)709 gif_del_tunnel(struct gif_softc *sc)
710 {
711 /* commit */
712 sc->sc_tunnel.t_af = AF_UNSPEC;
713
714 return (0);
715 }
716
717 int
in_gif_input(struct mbuf ** mp,int * offp,int proto,int af)718 in_gif_input(struct mbuf **mp, int *offp, int proto, int af)
719 {
720 struct mbuf *m = *mp;
721 struct gif_tunnel key;
722 struct ip *ip;
723 int rv;
724
725 ip = mtod(m, struct ip *);
726
727 key.t_af = AF_INET;
728 key.t_src4 = ip->ip_dst;
729 key.t_dst4 = ip->ip_src;
730
731 rv = gif_input(&key, mp, offp, proto, af, ip->ip_tos);
732 if (rv == -1)
733 rv = ipip_input(mp, offp, proto, af);
734
735 return (rv);
736 }
737
738 #ifdef INET6
739 int
in6_gif_input(struct mbuf ** mp,int * offp,int proto,int af)740 in6_gif_input(struct mbuf **mp, int *offp, int proto, int af)
741 {
742 struct mbuf *m = *mp;
743 struct gif_tunnel key;
744 struct ip6_hdr *ip6;
745 uint32_t flow;
746 int rv;
747
748 ip6 = mtod(m, struct ip6_hdr *);
749
750 key.t_af = AF_INET6;
751 key.t_src6 = ip6->ip6_dst;
752 key.t_dst6 = ip6->ip6_src;
753
754 flow = ntohl(ip6->ip6_flow);
755
756 rv = gif_input(&key, mp, offp, proto, af, flow >> 20);
757 if (rv == -1)
758 rv = ipip_input(mp, offp, proto, af);
759
760 return (rv);
761 }
762 #endif /* INET6 */
763
764 struct gif_softc *
gif_find(const struct gif_tunnel * key)765 gif_find(const struct gif_tunnel *key)
766 {
767 struct gif_tunnel *t;
768 struct gif_softc *sc;
769
770 TAILQ_FOREACH(t, &gif_list, t_entry) {
771 if (gif_cmp(key, t) != 0)
772 continue;
773
774 sc = (struct gif_softc *)t;
775 if (!ISSET(sc->sc_if.if_flags, IFF_RUNNING))
776 continue;
777
778 return (sc);
779 }
780
781 return (NULL);
782 }
783
784 int
gif_input(struct gif_tunnel * key,struct mbuf ** mp,int * offp,int proto,int af,uint8_t otos)785 gif_input(struct gif_tunnel *key, struct mbuf **mp, int *offp, int proto,
786 int af, uint8_t otos)
787 {
788 struct mbuf *m = *mp;
789 struct gif_softc *sc;
790 struct ifnet *ifp;
791 uint8_t itos;
792 int rxhprio;
793
794 /* IP-in-IP header is caused by tunnel mode, so skip gif lookup */
795 if (m->m_flags & M_TUNNEL) {
796 m->m_flags &= ~M_TUNNEL;
797 return (-1);
798 }
799
800 key->t_rtableid = m->m_pkthdr.ph_rtableid;
801
802 sc = gif_find(key);
803 if (sc == NULL) {
804 memset(&key->t_dst, 0, sizeof(key->t_dst));
805 sc = gif_find(key);
806 if (sc == NULL)
807 return (-1);
808 }
809
810 m_adj(m, *offp); /* this is ours now */
811
812 ifp = &sc->sc_if;
813 rxhprio = sc->sc_rxhprio;
814
815 switch (proto) {
816 case IPPROTO_IPV4: {
817 struct ip *ip;
818
819 m = *mp = m_pullup(m, sizeof(*ip));
820 if (m == NULL)
821 return (IPPROTO_DONE);
822
823 ip = mtod(m, struct ip *);
824
825 itos = ip->ip_tos;
826 if (ip_ecn_egress(sc->sc_ecn, &otos, &itos) == 0)
827 goto drop;
828
829 if (itos != ip->ip_tos)
830 ip_tos_patch(ip, itos);
831
832 m->m_pkthdr.ph_family = AF_INET;
833 break;
834 }
835 #ifdef INET6
836 case IPPROTO_IPV6: {
837 struct ip6_hdr *ip6;
838
839 m = *mp = m_pullup(m, sizeof(*ip6));
840 if (m == NULL)
841 return (IPPROTO_DONE);
842
843 ip6 = mtod(m, struct ip6_hdr *);
844
845 itos = ntohl(ip6->ip6_flow) >> 20;
846 if (!ip_ecn_egress(sc->sc_ecn, &otos, &itos))
847 goto drop;
848
849 CLR(ip6->ip6_flow, htonl(0xff << 20));
850 SET(ip6->ip6_flow, htonl(itos << 20));
851
852 m->m_pkthdr.ph_family = AF_INET6;
853 break;
854 }
855 #endif /* INET6 */
856 #ifdef MPLS
857 case IPPROTO_MPLS: {
858 uint32_t shim;
859 m = *mp = m_pullup(m, sizeof(shim));
860 if (m == NULL)
861 return (IPPROTO_DONE);
862
863 shim = *mtod(m, uint32_t *) & MPLS_EXP_MASK;
864 itos = (ntohl(shim) >> MPLS_EXP_OFFSET) << 5;
865
866 m->m_pkthdr.ph_family = AF_MPLS;
867 break;
868 }
869 #endif /* MPLS */
870 default:
871 return (-1);
872 }
873
874 m->m_flags &= ~(M_MCAST|M_BCAST);
875
876 switch (rxhprio) {
877 case IF_HDRPRIO_PACKET:
878 /* nop */
879 break;
880 case IF_HDRPRIO_PAYLOAD:
881 m->m_pkthdr.pf.prio = IFQ_TOS2PRIO(itos);
882 break;
883 case IF_HDRPRIO_OUTER:
884 m->m_pkthdr.pf.prio = IFQ_TOS2PRIO(otos);
885 break;
886 default:
887 m->m_pkthdr.pf.prio = rxhprio;
888 break;
889 }
890
891 *mp = NULL;
892 if_vinput(ifp, m);
893 return (IPPROTO_DONE);
894
895 drop:
896 m_freemp(mp);
897 return (IPPROTO_DONE);
898 }
899
900 static inline int
gif_ip_cmp(int af,const union gif_addr * a,const union gif_addr * b)901 gif_ip_cmp(int af, const union gif_addr *a, const union gif_addr *b)
902 {
903 switch (af) {
904 #ifdef INET6
905 case AF_INET6:
906 return (memcmp(&a->in6, &b->in6, sizeof(a->in6)));
907 #endif /* INET6 */
908 case AF_INET:
909 return (memcmp(&a->in4, &b->in4, sizeof(a->in4)));
910 default:
911 panic("%s: unsupported af %d", __func__, af);
912 }
913
914 return (0);
915 }
916
917
918 static inline int
gif_cmp(const struct gif_tunnel * a,const struct gif_tunnel * b)919 gif_cmp(const struct gif_tunnel *a, const struct gif_tunnel *b)
920 {
921 int rv;
922
923 /* sort by routing table */
924 if (a->t_rtableid > b->t_rtableid)
925 return (1);
926 if (a->t_rtableid < b->t_rtableid)
927 return (-1);
928
929 /* sort by address */
930 if (a->t_af > b->t_af)
931 return (1);
932 if (a->t_af < b->t_af)
933 return (-1);
934
935 rv = gif_ip_cmp(a->t_af, &a->t_dst, &b->t_dst);
936 if (rv != 0)
937 return (rv);
938
939 rv = gif_ip_cmp(a->t_af, &a->t_src, &b->t_src);
940 if (rv != 0)
941 return (rv);
942
943 return (0);
944 }
945