xref: /openbsd-src/sys/net/if_gif.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: if_gif.c,v 1.86 2016/09/13 07:48:45 mpi 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 
40 #include <net/if.h>
41 #include <net/if_var.h>
42 #include <net/if_types.h>
43 #include <net/route.h>
44 
45 #include <netinet/in.h>
46 #include <netinet/in_var.h>
47 #include <netinet/ip.h>
48 #include <netinet/ip_ether.h>
49 #include <netinet/ip_var.h>
50 #include <netinet/ip_ipsp.h>
51 
52 #ifdef INET6
53 #include <netinet6/in6_var.h>
54 #include <netinet/ip6.h>
55 #include <netinet6/ip6_var.h>
56 #endif /* INET6 */
57 
58 #include <net/if_gif.h>
59 
60 #include "bpfilter.h"
61 #if NBPFILTER > 0
62 #include <net/bpf.h>
63 #endif
64 
65 #ifdef MPLS
66 #include <netinet/ip_ether.h>
67 #endif
68 
69 #include "pf.h"
70 #if NPF > 0
71 #include <net/pfvar.h>
72 #endif
73 
74 #define GIF_MTU		(1280)	/* Default MTU */
75 #define GIF_MTU_MIN	(1280)	/* Minimum MTU */
76 #define GIF_MTU_MAX	(8192)	/* Maximum MTU */
77 
78 void	gifattach(int);
79 int	gif_clone_create(struct if_clone *, int);
80 int	gif_clone_destroy(struct ifnet *);
81 int	gif_checkloop(struct ifnet *, struct mbuf *);
82 void	gif_start(struct ifnet *);
83 int	gif_ioctl(struct ifnet *, u_long, caddr_t);
84 int	gif_output(struct ifnet *, struct mbuf *, struct sockaddr *,
85 	    struct rtentry *);
86 
87 int	in_gif_output(struct ifnet *, int, struct mbuf **);
88 int	in6_gif_output(struct ifnet *, int, struct mbuf **);
89 
90 /*
91  * gif global variable definitions
92  */
93 struct gif_softc_head gif_softc_list;
94 struct if_clone gif_cloner =
95     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
96 
97 void
98 gifattach(int count)
99 {
100 	LIST_INIT(&gif_softc_list);
101 	if_clone_attach(&gif_cloner);
102 }
103 
104 int
105 gif_clone_create(struct if_clone *ifc, int unit)
106 {
107 	struct gif_softc *sc;
108 	int s;
109 
110 	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
111 	if (!sc)
112 		return (ENOMEM);
113 
114 	snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname,
115 	     "%s%d", ifc->ifc_name, unit);
116 	sc->gif_if.if_mtu    = GIF_MTU;
117 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
118 	sc->gif_if.if_ioctl  = gif_ioctl;
119 	sc->gif_if.if_start  = gif_start;
120 	sc->gif_if.if_output = gif_output;
121 	sc->gif_if.if_rtrequest = p2p_rtrequest;
122 	sc->gif_if.if_type   = IFT_GIF;
123 	IFQ_SET_MAXLEN(&sc->gif_if.if_snd, IFQ_MAXLEN);
124 	sc->gif_if.if_softc = sc;
125 	if_attach(&sc->gif_if);
126 	if_alloc_sadl(&sc->gif_if);
127 
128 #if NBPFILTER > 0
129 	bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_LOOP, sizeof(u_int32_t));
130 #endif
131 	s = splnet();
132 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
133 	splx(s);
134 
135 	return (0);
136 }
137 
138 int
139 gif_clone_destroy(struct ifnet *ifp)
140 {
141 	struct gif_softc *sc = ifp->if_softc;
142 	int s;
143 
144 	s = splnet();
145 	LIST_REMOVE(sc, gif_list);
146 	splx(s);
147 
148 	if_detach(ifp);
149 
150 	if (sc->gif_psrc)
151 		free((caddr_t)sc->gif_psrc, M_IFADDR, 0);
152 	sc->gif_psrc = NULL;
153 	if (sc->gif_pdst)
154 		free((caddr_t)sc->gif_pdst, M_IFADDR, 0);
155 	sc->gif_pdst = NULL;
156 	free(sc, M_DEVBUF, sizeof(*sc));
157 	return (0);
158 }
159 
160 void
161 gif_start(struct ifnet *ifp)
162 {
163 	struct gif_softc *sc = (struct gif_softc*)ifp;
164 	struct mbuf *m;
165 
166 	for (;;) {
167 		IFQ_DEQUEUE(&ifp->if_snd, m);
168 		if (m == NULL)
169 			break;
170 
171 		/* is interface up and usable? */
172 		if (!(ifp->if_flags & IFF_UP) ||
173 		    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
174 		    sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
175 			m_freem(m);
176 			continue;
177 		}
178 
179 #if NBPFILTER > 0
180 		if (ifp->if_bpf) {
181 			int offset;
182 			sa_family_t family;
183 			u_int8_t proto;
184 
185 			/* must decapsulate outer header for bpf */
186 			switch (sc->gif_psrc->sa_family) {
187 			case AF_INET:
188 				offset = sizeof(struct ip);
189 				proto = mtod(m, struct ip *)->ip_p;
190 				break;
191 #ifdef INET6
192 			case AF_INET6:
193 				offset = sizeof(struct ip6_hdr);
194 				proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
195 				break;
196 #endif
197 			default:
198 				proto = 0;
199 				break;
200 			}
201 			switch (proto) {
202 			case IPPROTO_IPV4:
203 				family = AF_INET;
204 				break;
205 			case IPPROTO_IPV6:
206 				family = AF_INET6;
207 				break;
208 			case IPPROTO_ETHERIP:
209 				family = AF_LINK;
210 				offset += sizeof(struct etherip_header);
211 				break;
212 			case IPPROTO_MPLS:
213 				family = AF_MPLS;
214 				break;
215 			default:
216 				offset = 0;
217 				family = sc->gif_psrc->sa_family;
218 				break;
219 			}
220 			m->m_data += offset;
221 			m->m_len -= offset;
222 			m->m_pkthdr.len -= offset;
223 			bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
224 			m->m_data -= offset;
225 			m->m_len += offset;
226 			m->m_pkthdr.len += offset;
227 		}
228 #endif
229 		ifp->if_opackets++;
230 
231 		/* XXX we should cache the outgoing route */
232 
233 		switch (sc->gif_psrc->sa_family) {
234 		case AF_INET:
235 			ip_output(m, NULL, NULL, 0, NULL, NULL, 0);
236 			break;
237 #ifdef INET6
238 		case AF_INET6:
239 			/*
240 			 * force fragmentation to minimum MTU, to avoid path
241 			 * MTU discovery. It is too painful to ask for resend
242 			 * of inner packet, to achieve path MTU discovery for
243 			 * encapsulated packets.
244 			 */
245 			ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL);
246 			break;
247 #endif
248 		default:
249 			m_freem(m);
250 			break;
251 		}
252 	}
253 }
254 
255 int
256 gif_encap(struct ifnet *ifp, struct mbuf **mp, sa_family_t af)
257 {
258 	struct gif_softc *sc = (struct gif_softc*)ifp;
259 	int error = 0;
260 	/*
261 	 * Remove multicast and broadcast flags or encapsulated packet
262 	 * ends up as multicast or broadcast packet.
263 	 */
264 	(*mp)->m_flags &= ~(M_BCAST|M_MCAST);
265 
266 	/*
267 	 * Encapsulate packet. Add IP or IP6 header depending on tunnel AF.
268 	 */
269 	switch (sc->gif_psrc->sa_family) {
270 	case AF_INET:
271 		error = in_gif_output(ifp, af, mp);
272 		break;
273 #ifdef INET6
274 	case AF_INET6:
275 		error = in6_gif_output(ifp, af, mp);
276 		break;
277 #endif
278 	default:
279 		m_freem(*mp);
280 		error = EAFNOSUPPORT;
281 		break;
282 	}
283 
284 	if (error)
285 		return (error);
286 
287 	error = gif_checkloop(ifp, *mp);
288 	return (error);
289 }
290 
291 int
292 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
293     struct rtentry *rt)
294 {
295 	struct gif_softc *sc = (struct gif_softc*)ifp;
296 	int error = 0;
297 
298 	if (!(ifp->if_flags & IFF_UP) ||
299 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
300 	    sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
301 		m_freem(m);
302 		error = ENETDOWN;
303 		goto end;
304 	}
305 
306 	error = gif_encap(ifp, &m, dst->sa_family);
307 	if (error)
308 		goto end;
309 
310 	error = if_enqueue(ifp, m);
311 
312 end:
313 	if (error)
314 		ifp->if_oerrors++;
315 	return (error);
316 }
317 
318 int
319 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
320 {
321 	struct gif_softc *sc  = (struct gif_softc*)ifp;
322 	struct ifreq     *ifr = (struct ifreq *)data;
323 	int error = 0, size;
324 	struct sockaddr *dst, *src;
325 	struct sockaddr *sa;
326 	int s;
327 	struct gif_softc *sc2;
328 
329 	switch (cmd) {
330 	case SIOCSIFADDR:
331 		break;
332 
333 	case SIOCSIFDSTADDR:
334 		break;
335 
336 	case SIOCADDMULTI:
337 	case SIOCDELMULTI:
338 		break;
339 
340 	case SIOCSIFPHYADDR:
341 #ifdef INET6
342 	case SIOCSIFPHYADDR_IN6:
343 #endif /* INET6 */
344 	case SIOCSLIFPHYADDR:
345 		switch (cmd) {
346 		case SIOCSIFPHYADDR:
347 			src = sintosa(
348 				&(((struct in_aliasreq *)data)->ifra_addr));
349 			dst = sintosa(
350 				&(((struct in_aliasreq *)data)->ifra_dstaddr));
351 			break;
352 #ifdef INET6
353 		case SIOCSIFPHYADDR_IN6:
354 			src = sin6tosa(
355 				&(((struct in6_aliasreq *)data)->ifra_addr));
356 			dst = sin6tosa(
357 				&(((struct in6_aliasreq *)data)->ifra_dstaddr));
358 			break;
359 #endif
360 		case SIOCSLIFPHYADDR:
361 			src = (struct sockaddr *)
362 				&(((struct if_laddrreq *)data)->addr);
363 			dst = (struct sockaddr *)
364 				&(((struct if_laddrreq *)data)->dstaddr);
365 			break;
366 		default:
367 			return (EINVAL);
368 		}
369 
370 		/* sa_family must be equal */
371 		if (src->sa_family != dst->sa_family)
372 			return (EINVAL);
373 
374 		/* validate sa_len */
375 		switch (src->sa_family) {
376 		case AF_INET:
377 			if (src->sa_len != sizeof(struct sockaddr_in))
378 				return (EINVAL);
379 			break;
380 #ifdef INET6
381 		case AF_INET6:
382 			if (src->sa_len != sizeof(struct sockaddr_in6))
383 				return (EINVAL);
384 			break;
385 #endif
386 		default:
387 			return (EAFNOSUPPORT);
388 		}
389 		switch (dst->sa_family) {
390 		case AF_INET:
391 			if (dst->sa_len != sizeof(struct sockaddr_in))
392 				return (EINVAL);
393 			break;
394 #ifdef INET6
395 		case AF_INET6:
396 			if (dst->sa_len != sizeof(struct sockaddr_in6))
397 				return (EINVAL);
398 			break;
399 #endif
400 		default:
401 			return (EAFNOSUPPORT);
402 		}
403 
404 		/* check sa_family looks sane for the cmd */
405 		switch (cmd) {
406 		case SIOCSIFPHYADDR:
407 			if (src->sa_family == AF_INET)
408 				break;
409 			return (EAFNOSUPPORT);
410 #ifdef INET6
411 		case SIOCSIFPHYADDR_IN6:
412 			if (src->sa_family == AF_INET6)
413 				break;
414 			return (EAFNOSUPPORT);
415 #endif /* INET6 */
416 		case SIOCSLIFPHYADDR:
417 			/* checks done in the above */
418 			break;
419 		}
420 
421 		LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
422 			if (sc2 == sc)
423 				continue;
424 			if (!sc2->gif_pdst || !sc2->gif_psrc)
425 				continue;
426 			if (sc2->gif_pdst->sa_family != dst->sa_family ||
427 			    sc2->gif_pdst->sa_len != dst->sa_len ||
428 			    sc2->gif_psrc->sa_family != src->sa_family ||
429 			    sc2->gif_psrc->sa_len != src->sa_len)
430 				continue;
431 			/* can't configure same pair of address onto two gifs */
432 			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
433 			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
434 				error = EADDRNOTAVAIL;
435 				goto bad;
436 			}
437 
438 			/* can't configure multiple multi-dest interfaces */
439 #define multidest(x) \
440 	(satosin(x)->sin_addr.s_addr == INADDR_ANY)
441 #ifdef INET6
442 #define multidest6(x) \
443 	(IN6_IS_ADDR_UNSPECIFIED(&satosin6(x)->sin6_addr))
444 #endif
445 			if (dst->sa_family == AF_INET &&
446 			    multidest(dst) && multidest(sc2->gif_pdst)) {
447 				error = EADDRNOTAVAIL;
448 				goto bad;
449 			}
450 #ifdef INET6
451 			if (dst->sa_family == AF_INET6 &&
452 			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
453 				error = EADDRNOTAVAIL;
454 				goto bad;
455 			}
456 #endif
457 		}
458 
459 		if (sc->gif_psrc)
460 			free((caddr_t)sc->gif_psrc, M_IFADDR, 0);
461 		sa = malloc(src->sa_len, M_IFADDR, M_WAITOK);
462 		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
463 		sc->gif_psrc = sa;
464 
465 		if (sc->gif_pdst)
466 			free((caddr_t)sc->gif_pdst, M_IFADDR, 0);
467 		sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK);
468 		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
469 		sc->gif_pdst = sa;
470 
471 		s = splnet();
472 		ifp->if_flags |= IFF_RUNNING;
473 		if_up(ifp);		/* send up RTM_IFINFO */
474 		splx(s);
475 
476 		error = 0;
477 		break;
478 
479 #ifdef SIOCDIFPHYADDR
480 	case SIOCDIFPHYADDR:
481 		if (sc->gif_psrc) {
482 			free((caddr_t)sc->gif_psrc, M_IFADDR, 0);
483 			sc->gif_psrc = NULL;
484 		}
485 		if (sc->gif_pdst) {
486 			free((caddr_t)sc->gif_pdst, M_IFADDR, 0);
487 			sc->gif_pdst = NULL;
488 		}
489 		/* change the IFF_{UP, RUNNING} flag as well? */
490 		break;
491 #endif
492 
493 	case SIOCGIFPSRCADDR:
494 #ifdef INET6
495 	case SIOCGIFPSRCADDR_IN6:
496 #endif /* INET6 */
497 		if (sc->gif_psrc == NULL) {
498 			error = EADDRNOTAVAIL;
499 			goto bad;
500 		}
501 		src = sc->gif_psrc;
502 		switch (cmd) {
503 		case SIOCGIFPSRCADDR:
504 			dst = &ifr->ifr_addr;
505 			size = sizeof(ifr->ifr_addr);
506 			break;
507 #ifdef INET6
508 		case SIOCGIFPSRCADDR_IN6:
509 			dst = sin6tosa(
510 				&(((struct in6_ifreq *)data)->ifr_addr));
511 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
512 			break;
513 #endif /* INET6 */
514 		default:
515 			error = EADDRNOTAVAIL;
516 			goto bad;
517 		}
518 		if (src->sa_len > size)
519 			return (EINVAL);
520 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
521 		break;
522 
523 	case SIOCGIFPDSTADDR:
524 #ifdef INET6
525 	case SIOCGIFPDSTADDR_IN6:
526 #endif /* INET6 */
527 		if (sc->gif_pdst == NULL) {
528 			error = EADDRNOTAVAIL;
529 			goto bad;
530 		}
531 		src = sc->gif_pdst;
532 		switch (cmd) {
533 		case SIOCGIFPDSTADDR:
534 			dst = &ifr->ifr_addr;
535 			size = sizeof(ifr->ifr_addr);
536 			break;
537 #ifdef INET6
538 		case SIOCGIFPDSTADDR_IN6:
539 			dst = sin6tosa(&(((struct in6_ifreq *)data)->ifr_addr));
540 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
541 			break;
542 #endif /* INET6 */
543 		default:
544 			error = EADDRNOTAVAIL;
545 			goto bad;
546 		}
547 		if (src->sa_len > size)
548 			return (EINVAL);
549 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
550 		break;
551 
552 	case SIOCGLIFPHYADDR:
553 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
554 			error = EADDRNOTAVAIL;
555 			goto bad;
556 		}
557 
558 		/* copy src */
559 		src = sc->gif_psrc;
560 		dst = (struct sockaddr *)
561 			&(((struct if_laddrreq *)data)->addr);
562 		size = sizeof(((struct if_laddrreq *)data)->addr);
563 		if (src->sa_len > size)
564 			return (EINVAL);
565 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
566 
567 		/* copy dst */
568 		src = sc->gif_pdst;
569 		dst = (struct sockaddr *)
570 			&(((struct if_laddrreq *)data)->dstaddr);
571 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
572 		if (src->sa_len > size)
573 			return (EINVAL);
574 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
575 		break;
576 
577 	case SIOCSIFFLAGS:
578 		/* if_ioctl() takes care of it */
579 		break;
580 
581 	case SIOCSIFMTU:
582 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
583 			error = EINVAL;
584 		else
585 			ifp->if_mtu = ifr->ifr_mtu;
586 		break;
587 
588 	case SIOCSLIFPHYRTABLE:
589 		if (ifr->ifr_rdomainid < 0 ||
590 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
591 		    !rtable_exists(ifr->ifr_rdomainid)) {
592 			error = EINVAL;
593 			break;
594 		}
595 		sc->gif_rtableid = ifr->ifr_rdomainid;
596 		break;
597 	case SIOCGLIFPHYRTABLE:
598 		ifr->ifr_rdomainid = sc->gif_rtableid;
599 		break;
600 	default:
601 		error = ENOTTY;
602 		break;
603 	}
604  bad:
605 	return (error);
606 }
607 
608 int
609 gif_checkloop(struct ifnet *ifp, struct mbuf *m)
610 {
611 	struct m_tag *mtag;
612 
613 	/*
614 	 * gif may cause infinite recursion calls when misconfigured.
615 	 * We'll prevent this by detecting loops.
616 	 */
617 	for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
618 	    mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
619 		if (*(struct ifnet **)(mtag + 1) == ifp) {
620 			log(LOG_NOTICE, "gif_output: "
621 			    "recursively called too many times\n");
622 			m_freem(m);
623 			return ENETUNREACH;
624 		}
625 	}
626 
627 	mtag = m_tag_get(PACKET_TAG_GIF, sizeof(struct ifnet *), M_NOWAIT);
628 	if (mtag == NULL) {
629 		m_freem(m);
630 		return ENOMEM;
631 	}
632 	*(struct ifnet **)(mtag + 1) = ifp;
633 	m_tag_prepend(m, mtag);
634 	return 0;
635 }
636 
637 int
638 in_gif_output(struct ifnet *ifp, int family, struct mbuf **m0)
639 {
640 	struct gif_softc *sc = (struct gif_softc*)ifp;
641 	struct sockaddr_in *sin_src = satosin(sc->gif_psrc);
642 	struct sockaddr_in *sin_dst = satosin(sc->gif_pdst);
643 	struct tdb tdb;
644 	struct xformsw xfs;
645 	int error;
646 	struct mbuf *m = *m0;
647 
648 	if (sin_src == NULL || sin_dst == NULL ||
649 	    sin_src->sin_family != AF_INET ||
650 	    sin_dst->sin_family != AF_INET) {
651 		m_freem(m);
652 		return EAFNOSUPPORT;
653 	}
654 
655 #ifdef DIAGNOSTIC
656 	if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
657 		printf("%s: trying to send packet on wrong domain. "
658 		    "if %d vs. mbuf %d, AF %d\n", ifp->if_xname,
659 		    ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid),
660 		    family);
661 	}
662 #endif
663 
664 	/* setup dummy tdb.  it highly depends on ipip_output() code. */
665 	bzero(&tdb, sizeof(tdb));
666 	bzero(&xfs, sizeof(xfs));
667 	tdb.tdb_src.sin.sin_family = AF_INET;
668 	tdb.tdb_src.sin.sin_len = sizeof(struct sockaddr_in);
669 	tdb.tdb_src.sin.sin_addr = sin_src->sin_addr;
670 	tdb.tdb_dst.sin.sin_family = AF_INET;
671 	tdb.tdb_dst.sin.sin_len = sizeof(struct sockaddr_in);
672 	tdb.tdb_dst.sin.sin_addr = sin_dst->sin_addr;
673 	tdb.tdb_xform = &xfs;
674 	xfs.xf_type = -1;	/* not XF_IP4 */
675 
676 	switch (family) {
677 	case AF_INET:
678 		break;
679 #ifdef INET6
680 	case AF_INET6:
681 		break;
682 #endif
683 #if MPLS
684 	case AF_MPLS:
685 		break;
686 #endif
687 	default:
688 #ifdef DEBUG
689 	        printf("%s: warning: unknown family %d passed\n", __func__,
690 			family);
691 #endif
692 		m_freem(m);
693 		return EAFNOSUPPORT;
694 	}
695 
696 	/* encapsulate into IPv4 packet */
697 	*m0 = NULL;
698 #ifdef MPLS
699 	if (family == AF_MPLS)
700 		error = etherip_output(m, &tdb, m0, IPPROTO_MPLS);
701 	else
702 #endif
703 	error = ipip_output(m, &tdb, m0, 0, 0);
704 	if (error)
705 		return error;
706 	else if (*m0 == NULL)
707 		return EFAULT;
708 
709 	m = *m0;
710 
711 	m->m_pkthdr.ph_rtableid = sc->gif_rtableid;
712 #if NPF > 0
713 	pf_pkt_addr_changed(m);
714 #endif
715 	return 0;
716 }
717 
718 void
719 in_gif_input(struct mbuf *m, ...)
720 {
721 	int off;
722 	struct gif_softc *sc;
723 	struct ifnet *gifp = NULL;
724 	struct ip *ip;
725 	va_list ap;
726 
727 	va_start(ap, m);
728 	off = va_arg(ap, int);
729 	va_end(ap);
730 
731 	/* IP-in-IP header is caused by tunnel mode, so skip gif lookup */
732 	if (m->m_flags & M_TUNNEL) {
733 		m->m_flags &= ~M_TUNNEL;
734 		goto inject;
735 	}
736 
737 	ip = mtod(m, struct ip *);
738 
739 	/* this code will be soon improved. */
740 	LIST_FOREACH(sc, &gif_softc_list, gif_list) {
741 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
742 		    sc->gif_psrc->sa_family != AF_INET ||
743 		    sc->gif_pdst->sa_family != AF_INET ||
744 		    rtable_l2(sc->gif_rtableid) !=
745 		    rtable_l2(m->m_pkthdr.ph_rtableid)) {
746 			continue;
747 		}
748 
749 		if ((sc->gif_if.if_flags & IFF_UP) == 0)
750 			continue;
751 
752 		if (in_hosteq(satosin(sc->gif_psrc)->sin_addr, ip->ip_dst) &&
753 		    in_hosteq(satosin(sc->gif_pdst)->sin_addr, ip->ip_src)) {
754 			gifp = &sc->gif_if;
755 			break;
756 		}
757 	}
758 
759 	if (gifp) {
760 		m->m_pkthdr.ph_ifidx = gifp->if_index;
761 		m->m_pkthdr.ph_rtableid = gifp->if_rdomain;
762 		gifp->if_ipackets++;
763 		gifp->if_ibytes += m->m_pkthdr.len;
764 		/* We have a configured GIF */
765 		ipip_input(m, off, gifp, ip->ip_p);
766 		return;
767 	}
768 
769 inject:
770 	ip4_input(m, off); /* No GIF interface was configured */
771 	return;
772 }
773 
774 #ifdef INET6
775 int
776 in6_gif_output(struct ifnet *ifp, int family, struct mbuf **m0)
777 {
778 	struct gif_softc *sc = (struct gif_softc*)ifp;
779 	struct sockaddr_in6 *sin6_src = satosin6(sc->gif_psrc);
780 	struct sockaddr_in6 *sin6_dst = satosin6(sc->gif_pdst);
781 	struct tdb tdb;
782 	struct xformsw xfs;
783 	int error;
784 	struct mbuf *m = *m0;
785 
786 	if (sin6_src == NULL || sin6_dst == NULL ||
787 	    sin6_src->sin6_family != AF_INET6 ||
788 	    sin6_dst->sin6_family != AF_INET6) {
789 		m_freem(m);
790 		return EAFNOSUPPORT;
791 	}
792 
793 	/* setup dummy tdb.  it highly depends on ipip_output() code. */
794 	bzero(&tdb, sizeof(tdb));
795 	bzero(&xfs, sizeof(xfs));
796 	tdb.tdb_src.sin6.sin6_family = AF_INET6;
797 	tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6);
798 	tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr;
799 	tdb.tdb_dst.sin6.sin6_family = AF_INET6;
800 	tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
801 	tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr;
802 	tdb.tdb_xform = &xfs;
803 	xfs.xf_type = -1;	/* not XF_IP4 */
804 
805 	switch (family) {
806 	case AF_INET:
807 		break;
808 #ifdef INET6
809 	case AF_INET6:
810 		break;
811 #endif
812 #ifdef MPLS
813 	case AF_MPLS:
814 		break;
815 #endif
816 	default:
817 #ifdef DEBUG
818 		printf("%s: warning: unknown family %d passed\n", __func__,
819 			family);
820 #endif
821 		m_freem(m);
822 		return EAFNOSUPPORT;
823 	}
824 
825 	/* encapsulate into IPv6 packet */
826 	*m0 = NULL;
827 #if MPLS
828 	if (family == AF_MPLS)
829 		error = etherip_output(m, &tdb, m0, IPPROTO_MPLS);
830 	else
831 #endif
832 	error = ipip_output(m, &tdb, m0, 0, 0);
833 	if (error)
834 	        return error;
835 	else if (*m0 == NULL)
836 	        return EFAULT;
837 
838 	m = *m0;
839 
840 #if NPF > 0
841 	pf_pkt_addr_changed(m);
842 #endif
843 	return 0;
844 }
845 
846 int in6_gif_input(struct mbuf **mp, int *offp, int proto)
847 {
848 	struct mbuf *m = *mp;
849 	struct gif_softc *sc;
850 	struct ifnet *gifp = NULL;
851 	struct ip6_hdr *ip6;
852 
853 	/* XXX What if we run transport-mode IPsec to protect gif tunnel ? */
854 	if (m->m_flags & (M_AUTH | M_CONF))
855 	        goto inject;
856 
857 	ip6 = mtod(m, struct ip6_hdr *);
858 
859 #define satoin6(sa)	(satosin6(sa)->sin6_addr)
860 	LIST_FOREACH(sc, &gif_softc_list, gif_list) {
861 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
862 		    sc->gif_psrc->sa_family != AF_INET6 ||
863 		    sc->gif_pdst->sa_family != AF_INET6) {
864 			continue;
865 		}
866 
867 		if ((sc->gif_if.if_flags & IFF_UP) == 0)
868 			continue;
869 
870 		if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) &&
871 		    IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) {
872 			gifp = &sc->gif_if;
873 			break;
874 		}
875 	}
876 
877 	if (gifp) {
878 	        m->m_pkthdr.ph_ifidx = gifp->if_index;
879 		gifp->if_ipackets++;
880 		gifp->if_ibytes += m->m_pkthdr.len;
881 		ipip_input(m, *offp, gifp, proto);
882 		return IPPROTO_DONE;
883 	}
884 
885 inject:
886 	/* No GIF tunnel configured */
887 	ip4_input6(&m, offp, proto);
888 	return IPPROTO_DONE;
889 }
890 #endif /* INET6 */
891