xref: /openbsd-src/sys/net/if_gif.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: if_gif.c,v 1.57 2012/05/12 12:58:16 mpf 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/kernel.h>
36 #include <sys/mbuf.h>
37 #include <sys/socket.h>
38 #include <sys/sockio.h>
39 #include <sys/syslog.h>
40 
41 #include <net/if.h>
42 #include <net/if_types.h>
43 #include <net/route.h>
44 #include <net/bpf.h>
45 
46 #ifdef	INET
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/in_var.h>
50 #include <netinet/in_gif.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_ether.h>
53 #include <netinet/ip_var.h>
54 #endif	/* INET */
55 
56 #ifdef INET6
57 #ifndef INET
58 #include <netinet/in.h>
59 #endif
60 #include <netinet/ip6.h>
61 #include <netinet6/ip6_var.h>
62 #include <netinet6/in6_gif.h>
63 #endif /* INET6 */
64 
65 #include <net/if_gif.h>
66 
67 #include "bpfilter.h"
68 #include "bridge.h"
69 
70 void	gifattach(int);
71 int	gif_clone_create(struct if_clone *, int);
72 int	gif_clone_destroy(struct ifnet *);
73 int	gif_checkloop(struct ifnet *, struct mbuf *);
74 
75 /*
76  * gif global variable definitions
77  */
78 struct gif_softc_head gif_softc_list;
79 struct if_clone gif_cloner =
80     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
81 
82 /* ARGSUSED */
83 void
84 gifattach(int count)
85 {
86 	LIST_INIT(&gif_softc_list);
87 	if_clone_attach(&gif_cloner);
88 }
89 
90 int
91 gif_clone_create(struct if_clone *ifc, int unit)
92 {
93 	struct gif_softc *sc;
94 	int s;
95 
96 	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
97 	if (!sc)
98 		return (ENOMEM);
99 
100 	snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname,
101 	     "%s%d", ifc->ifc_name, unit);
102 	sc->gif_if.if_mtu    = GIF_MTU;
103 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
104 	sc->gif_if.if_ioctl  = gif_ioctl;
105 	sc->gif_if.if_start  = gif_start;
106 	sc->gif_if.if_output = gif_output;
107 	sc->gif_if.if_type   = IFT_GIF;
108 	IFQ_SET_MAXLEN(&sc->gif_if.if_snd, ifqmaxlen);
109 	IFQ_SET_READY(&sc->gif_if.if_snd);
110 	sc->gif_if.if_softc = sc;
111 	if_attach(&sc->gif_if);
112 	if_alloc_sadl(&sc->gif_if);
113 
114 #if NBPFILTER > 0
115 	bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_LOOP, sizeof(u_int32_t));
116 #endif
117 	s = splnet();
118 	LIST_INSERT_HEAD(&gif_softc_list, sc, gif_list);
119 	splx(s);
120 
121 	return (0);
122 }
123 
124 int
125 gif_clone_destroy(struct ifnet *ifp)
126 {
127 	struct gif_softc *sc = ifp->if_softc;
128 	int s;
129 
130 	s = splnet();
131 	LIST_REMOVE(sc, gif_list);
132 	splx(s);
133 
134 	if_detach(ifp);
135 
136 	if (sc->gif_psrc)
137 		free((caddr_t)sc->gif_psrc, M_IFADDR);
138 	sc->gif_psrc = NULL;
139 	if (sc->gif_pdst)
140 		free((caddr_t)sc->gif_pdst, M_IFADDR);
141 	sc->gif_pdst = NULL;
142 	free(sc, M_DEVBUF);
143 	return (0);
144 }
145 
146 void
147 gif_start(struct ifnet *ifp)
148 {
149 	struct gif_softc *sc = (struct gif_softc*)ifp;
150 	struct mbuf *m;
151 	int s;
152 	sa_family_t family;
153 
154 	while (1) {
155 		s = splnet();
156 		IFQ_DEQUEUE(&ifp->if_snd, m);
157 		splx(s);
158 
159 		if (m == NULL)
160 			break;
161 
162 		/* is interface up and usable? */
163 		if ((ifp->if_flags & (IFF_OACTIVE | IFF_UP)) != IFF_UP ||
164 		    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
165 		    sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
166 			m_freem(m);
167 			continue;
168 		}
169 
170 		/* get tunnel address family */
171 		family = sc->gif_psrc->sa_family;
172 
173 		/*
174 		 * Check if the packet is comming via bridge and needs
175 		 * etherip encapsulation or not. bridge(4) directly calls
176 		 * the start function and bypasses the if_output function
177 		 * so we need to do the encap here.
178 		 */
179 		if (ifp->if_bridge && (m->m_flags & M_PROTO1)) {
180 			int error = 0;
181 			/*
182 			 * Remove multicast and broadcast flags or encapsulated
183 			 * packet ends up as multicast or broadcast packet.
184 			 */
185 			m->m_flags &= ~(M_BCAST|M_MCAST);
186 			switch (sc->gif_psrc->sa_family) {
187 #ifdef INET
188 			case AF_INET:
189 				error = in_gif_output(ifp, AF_LINK, &m);
190 				break;
191 #endif
192 #ifdef INET6
193 			case AF_INET6:
194 				error = in6_gif_output(ifp, AF_LINK, &m);
195 				break;
196 #endif
197 			default:
198 				error = EAFNOSUPPORT;
199 				m_freem(m);
200 				break;
201 			}
202 			if (error)
203 				continue;
204 			if (gif_checkloop(ifp, m))
205 				continue;
206 		}
207 
208 #if NBPFILTER > 0
209 		if (ifp->if_bpf) {
210 			int offset;
211 			sa_family_t family;
212 			u_int8_t proto;
213 
214 			/* must decapsulate outer header for bpf */
215 			switch (sc->gif_psrc->sa_family) {
216 #ifdef INET
217 			case AF_INET:
218 				offset = sizeof(struct ip);
219 				proto = mtod(m, struct ip *)->ip_p;
220 				break;
221 #endif
222 #ifdef INET6
223 			case AF_INET6:
224 				offset = sizeof(struct ip6_hdr);
225 				proto = mtod(m, struct ip6_hdr *)->ip6_nxt;
226 				break;
227 #endif
228 			default:
229 				proto = 0;
230 				break;
231 			}
232 			switch (proto) {
233 			case IPPROTO_IPV4:
234 				family = AF_INET;
235 				break;
236 			case IPPROTO_IPV6:
237 				family = AF_INET6;
238 				break;
239 			case IPPROTO_ETHERIP:
240 				family = AF_LINK;
241 				offset += sizeof(struct etherip_header);
242 				break;
243 			case IPPROTO_MPLS:
244 				family = AF_MPLS;
245 				break;
246 			default:
247 				offset = 0;
248 				family = sc->gif_psrc->sa_family;
249 				break;
250 			}
251 			m->m_data += offset;
252 			m->m_len -= offset;
253 			m->m_pkthdr.len -= offset;
254 			bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
255 			m->m_data -= offset;
256 			m->m_len += offset;
257 			m->m_pkthdr.len += offset;
258 		}
259 #endif
260 		ifp->if_opackets++;
261 
262 		/* XXX we should cache the outgoing route */
263 
264 		switch (sc->gif_psrc->sa_family) {
265 #ifdef INET
266 		case AF_INET:
267 			ip_output(m, (void *)NULL, (void *)NULL, 0,
268 			    (void *)NULL, (void *)NULL);
269 			break;
270 #endif
271 #ifdef INET6
272 		case AF_INET6:
273 			/*
274 			 * force fragmentation to minimum MTU, to avoid path
275 			 * MTU discovery. It is too painful to ask for resend
276 			 * of inner packet, to achieve path MTU discovery for
277 			 * encapsulated packets.
278 			 */
279 			ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL,
280 			     NULL);
281 			break;
282 #endif
283 		default:
284 			m_freem(m);
285 			break;
286 		}
287 	}
288 }
289 
290 int
291 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
292     struct rtentry *rt)
293 {
294 	struct gif_softc *sc = (struct gif_softc*)ifp;
295 	int error = 0;
296 	int s;
297 	sa_family_t family = dst->sa_family;
298 
299 	if (!(ifp->if_flags & IFF_UP) ||
300 	    sc->gif_psrc == NULL || sc->gif_pdst == NULL ||
301 	    sc->gif_psrc->sa_family != sc->gif_pdst->sa_family) {
302 		m_freem(m);
303 		error = ENETDOWN;
304 		goto end;
305 	}
306 
307 	/*
308 	 * Remove multicast and broadcast flags or encapsulated packet
309 	 * ends up as multicast or broadcast packet.
310 	 */
311 	m->m_flags &= ~(M_BCAST|M_MCAST);
312 
313 	/*
314 	 * Encapsulate packet. Add IP or IP6 header depending on tunnel AF.
315 	 */
316 	switch (sc->gif_psrc->sa_family) {
317 #ifdef INET
318 	case AF_INET:
319 		error = in_gif_output(ifp, family, &m);
320 		break;
321 #endif
322 #ifdef INET6
323 	case AF_INET6:
324 		error = in6_gif_output(ifp, family, &m);
325 		break;
326 #endif
327 	default:
328 		m_freem(m);
329 		error = EAFNOSUPPORT;
330 		break;
331 	}
332 
333 	if (error)
334 		goto end;
335 
336 	if ((error = gif_checkloop(ifp, m)))
337 		goto end;
338 
339 	/*
340 	 * Queue message on interface, and start output.
341 	 */
342 	s = splnet();
343 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
344 	if (error) {
345 		/* mbuf is already freed */
346 		splx(s);
347 		goto end;
348 	}
349 	ifp->if_obytes += m->m_pkthdr.len;
350 	if_start(ifp);
351 	splx(s);
352 
353 end:
354 	if (error)
355 		ifp->if_oerrors++;
356 	return (error);
357 }
358 
359 int
360 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
361 {
362 	struct gif_softc *sc  = (struct gif_softc*)ifp;
363 	struct ifreq     *ifr = (struct ifreq*)data;
364 	int error = 0, size;
365 	struct sockaddr *dst, *src;
366 	struct sockaddr *sa;
367 	int s;
368 	struct gif_softc *sc2;
369 
370 	switch (cmd) {
371 	case SIOCSIFADDR:
372 		break;
373 
374 	case SIOCSIFDSTADDR:
375 		break;
376 
377 	case SIOCADDMULTI:
378 	case SIOCDELMULTI:
379 		switch (ifr->ifr_addr.sa_family) {
380 #ifdef INET
381 		case AF_INET:	/* IP supports Multicast */
382 			break;
383 #endif /* INET */
384 #ifdef INET6
385 		case AF_INET6:	/* IP6 supports Multicast */
386 			break;
387 #endif /* INET6 */
388 		default:  /* Other protocols doesn't support Multicast */
389 			error = EAFNOSUPPORT;
390 			break;
391 		}
392 		break;
393 
394 	case SIOCSIFPHYADDR:
395 #ifdef INET6
396 	case SIOCSIFPHYADDR_IN6:
397 #endif /* INET6 */
398 	case SIOCSLIFPHYADDR:
399 		switch (cmd) {
400 #ifdef INET
401 		case SIOCSIFPHYADDR:
402 			src = (struct sockaddr *)
403 				&(((struct in_aliasreq *)data)->ifra_addr);
404 			dst = (struct sockaddr *)
405 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
406 			break;
407 #endif
408 #ifdef INET6
409 		case SIOCSIFPHYADDR_IN6:
410 			src = (struct sockaddr *)
411 				&(((struct in6_aliasreq *)data)->ifra_addr);
412 			dst = (struct sockaddr *)
413 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
414 			break;
415 #endif
416 		case SIOCSLIFPHYADDR:
417 			src = (struct sockaddr *)
418 				&(((struct if_laddrreq *)data)->addr);
419 			dst = (struct sockaddr *)
420 				&(((struct if_laddrreq *)data)->dstaddr);
421 			break;
422 		default:
423 			return (EINVAL);
424 		}
425 
426 		/* sa_family must be equal */
427 		if (src->sa_family != dst->sa_family)
428 			return (EINVAL);
429 
430 		/* validate sa_len */
431 		switch (src->sa_family) {
432 #ifdef INET
433 		case AF_INET:
434 			if (src->sa_len != sizeof(struct sockaddr_in))
435 				return (EINVAL);
436 			break;
437 #endif
438 #ifdef INET6
439 		case AF_INET6:
440 			if (src->sa_len != sizeof(struct sockaddr_in6))
441 				return (EINVAL);
442 			break;
443 #endif
444 		default:
445 			return (EAFNOSUPPORT);
446 		}
447 		switch (dst->sa_family) {
448 #ifdef INET
449 		case AF_INET:
450 			if (dst->sa_len != sizeof(struct sockaddr_in))
451 				return (EINVAL);
452 			break;
453 #endif
454 #ifdef INET6
455 		case AF_INET6:
456 			if (dst->sa_len != sizeof(struct sockaddr_in6))
457 				return (EINVAL);
458 			break;
459 #endif
460 		default:
461 			return (EAFNOSUPPORT);
462 		}
463 
464 		/* check sa_family looks sane for the cmd */
465 		switch (cmd) {
466 		case SIOCSIFPHYADDR:
467 			if (src->sa_family == AF_INET)
468 				break;
469 			return (EAFNOSUPPORT);
470 #ifdef INET6
471 		case SIOCSIFPHYADDR_IN6:
472 			if (src->sa_family == AF_INET6)
473 				break;
474 			return (EAFNOSUPPORT);
475 #endif /* INET6 */
476 		case SIOCSLIFPHYADDR:
477 			/* checks done in the above */
478 			break;
479 		}
480 
481 		LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
482 			if (sc2 == sc)
483 				continue;
484 			if (!sc2->gif_pdst || !sc2->gif_psrc)
485 				continue;
486 			if (sc2->gif_pdst->sa_family != dst->sa_family ||
487 			    sc2->gif_pdst->sa_len != dst->sa_len ||
488 			    sc2->gif_psrc->sa_family != src->sa_family ||
489 			    sc2->gif_psrc->sa_len != src->sa_len)
490 				continue;
491 			/* can't configure same pair of address onto two gifs */
492 			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
493 			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
494 				error = EADDRNOTAVAIL;
495 				goto bad;
496 			}
497 
498 			/* can't configure multiple multi-dest interfaces */
499 #define multidest(x) \
500 	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
501 #ifdef INET6
502 #define multidest6(x) \
503 	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
504 #endif
505 			if (dst->sa_family == AF_INET &&
506 			    multidest(dst) && multidest(sc2->gif_pdst)) {
507 				error = EADDRNOTAVAIL;
508 				goto bad;
509 			}
510 #ifdef INET6
511 			if (dst->sa_family == AF_INET6 &&
512 			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
513 				error = EADDRNOTAVAIL;
514 				goto bad;
515 			}
516 #endif
517 		}
518 
519 		if (sc->gif_psrc)
520 			free((caddr_t)sc->gif_psrc, M_IFADDR);
521 		sa = malloc(src->sa_len, M_IFADDR, M_WAITOK);
522 		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
523 		sc->gif_psrc = sa;
524 
525 		if (sc->gif_pdst)
526 			free((caddr_t)sc->gif_pdst, M_IFADDR);
527 		sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK);
528 		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
529 		sc->gif_pdst = sa;
530 
531 		s = splnet();
532 		ifp->if_flags |= IFF_RUNNING;
533 		if_up(ifp);		/* send up RTM_IFINFO */
534 		splx(s);
535 
536 		error = 0;
537 		break;
538 
539 #ifdef SIOCDIFPHYADDR
540 	case SIOCDIFPHYADDR:
541 		if (sc->gif_psrc) {
542 			free((caddr_t)sc->gif_psrc, M_IFADDR);
543 			sc->gif_psrc = NULL;
544 		}
545 		if (sc->gif_pdst) {
546 			free((caddr_t)sc->gif_pdst, M_IFADDR);
547 			sc->gif_pdst = NULL;
548 		}
549 		/* change the IFF_{UP, RUNNING} flag as well? */
550 		break;
551 #endif
552 
553 	case SIOCGIFPSRCADDR:
554 #ifdef INET6
555 	case SIOCGIFPSRCADDR_IN6:
556 #endif /* INET6 */
557 		if (sc->gif_psrc == NULL) {
558 			error = EADDRNOTAVAIL;
559 			goto bad;
560 		}
561 		src = sc->gif_psrc;
562 		switch (cmd) {
563 #ifdef INET
564 		case SIOCGIFPSRCADDR:
565 			dst = &ifr->ifr_addr;
566 			size = sizeof(ifr->ifr_addr);
567 			break;
568 #endif /* INET */
569 #ifdef INET6
570 		case SIOCGIFPSRCADDR_IN6:
571 			dst = (struct sockaddr *)
572 				&(((struct in6_ifreq *)data)->ifr_addr);
573 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
574 			break;
575 #endif /* INET6 */
576 		default:
577 			error = EADDRNOTAVAIL;
578 			goto bad;
579 		}
580 		if (src->sa_len > size)
581 			return (EINVAL);
582 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
583 		break;
584 
585 	case SIOCGIFPDSTADDR:
586 #ifdef INET6
587 	case SIOCGIFPDSTADDR_IN6:
588 #endif /* INET6 */
589 		if (sc->gif_pdst == NULL) {
590 			error = EADDRNOTAVAIL;
591 			goto bad;
592 		}
593 		src = sc->gif_pdst;
594 		switch (cmd) {
595 #ifdef INET
596 		case SIOCGIFPDSTADDR:
597 			dst = &ifr->ifr_addr;
598 			size = sizeof(ifr->ifr_addr);
599 			break;
600 #endif /* INET */
601 #ifdef INET6
602 		case SIOCGIFPDSTADDR_IN6:
603 			dst = (struct sockaddr *)
604 				&(((struct in6_ifreq *)data)->ifr_addr);
605 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
606 			break;
607 #endif /* INET6 */
608 		default:
609 			error = EADDRNOTAVAIL;
610 			goto bad;
611 		}
612 		if (src->sa_len > size)
613 			return (EINVAL);
614 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
615 		break;
616 
617 	case SIOCGLIFPHYADDR:
618 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
619 			error = EADDRNOTAVAIL;
620 			goto bad;
621 		}
622 
623 		/* copy src */
624 		src = sc->gif_psrc;
625 		dst = (struct sockaddr *)
626 			&(((struct if_laddrreq *)data)->addr);
627 		size = sizeof(((struct if_laddrreq *)data)->addr);
628 		if (src->sa_len > size)
629 			return (EINVAL);
630 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
631 
632 		/* copy dst */
633 		src = sc->gif_pdst;
634 		dst = (struct sockaddr *)
635 			&(((struct if_laddrreq *)data)->dstaddr);
636 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
637 		if (src->sa_len > size)
638 			return (EINVAL);
639 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
640 		break;
641 
642 	case SIOCSIFFLAGS:
643 		/* if_ioctl() takes care of it */
644 		break;
645 
646 	case SIOCSIFMTU:
647 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
648 			error = EINVAL;
649 		else
650 			ifp->if_mtu = ifr->ifr_mtu;
651 		break;
652 
653 	case SIOCSLIFPHYRTABLE:
654 		if (ifr->ifr_rdomainid < 0 ||
655 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
656 		    !rtable_exists(ifr->ifr_rdomainid)) {
657 			error = EINVAL;
658 			break;
659 		}
660 		sc->gif_rtableid = ifr->ifr_rdomainid;
661 		break;
662 	case SIOCGLIFPHYRTABLE:
663 		ifr->ifr_rdomainid = sc->gif_rtableid;
664 		break;
665 	default:
666 		error = ENOTTY;
667 		break;
668 	}
669  bad:
670 	return (error);
671 }
672 
673 int
674 gif_checkloop(struct ifnet *ifp, struct mbuf *m)
675 {
676 	struct m_tag *mtag;
677 
678 	/*
679 	 * gif may cause infinite recursion calls when misconfigured.
680 	 * We'll prevent this by detecting loops.
681 	 */
682 	for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
683 	    mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
684 		if (!bcmp((caddr_t)(mtag + 1), &ifp,
685 		    sizeof(struct ifnet *))) {
686 			log(LOG_NOTICE, "gif_output: "
687 			    "recursively called too many times\n");
688 			m_freem(m);
689 			return ENETUNREACH;
690 		}
691 	}
692 
693 	mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
694 	if (mtag == NULL) {
695 		m_freem(m);
696 		return ENOMEM;
697 	}
698 	bcopy(&ifp, mtag + 1, sizeof(caddr_t));
699 	m_tag_prepend(m, mtag);
700 	return 0;
701 }
702