xref: /openbsd/sys/net/if_gif.c (revision 8932bfb7)
1 /*	$OpenBSD: if_gif.c,v 1.55 2010/07/03 04:44:51 guenther 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_var.h>
53 #endif	/* INET */
54 
55 #ifdef INET6
56 #ifndef INET
57 #include <netinet/in.h>
58 #endif
59 #include <netinet/ip6.h>
60 #include <netinet6/ip6_var.h>
61 #include <netinet6/in6_gif.h>
62 #endif /* INET6 */
63 
64 #include <net/if_gif.h>
65 
66 #include "bpfilter.h"
67 #include "bridge.h"
68 
69 void	gifattach(int);
70 int	gif_clone_create(struct if_clone *, int);
71 int	gif_clone_destroy(struct ifnet *);
72 int	gif_checkloop(struct ifnet *, struct mbuf *);
73 
74 /*
75  * gif global variable definitions
76  */
77 struct gif_softc_head gif_softc_list;
78 struct if_clone gif_cloner =
79     IF_CLONE_INITIALIZER("gif", gif_clone_create, gif_clone_destroy);
80 
81 /* ARGSUSED */
82 void
83 gifattach(int count)
84 {
85 	LIST_INIT(&gif_softc_list);
86 	if_clone_attach(&gif_cloner);
87 }
88 
89 int
90 gif_clone_create(struct if_clone *ifc, int unit)
91 {
92 	struct gif_softc *sc;
93 	int s;
94 
95 	sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT|M_ZERO);
96 	if (!sc)
97 		return (ENOMEM);
98 
99 	snprintf(sc->gif_if.if_xname, sizeof sc->gif_if.if_xname,
100 	     "%s%d", ifc->ifc_name, unit);
101 	sc->gif_if.if_mtu    = GIF_MTU;
102 	sc->gif_if.if_flags  = IFF_POINTOPOINT | IFF_MULTICAST;
103 	sc->gif_if.if_ioctl  = gif_ioctl;
104 	sc->gif_if.if_start  = gif_start;
105 	sc->gif_if.if_output = gif_output;
106 	sc->gif_if.if_type   = IFT_GIF;
107 	IFQ_SET_MAXLEN(&sc->gif_if.if_snd, ifqmaxlen);
108 	IFQ_SET_READY(&sc->gif_if.if_snd);
109 	sc->gif_if.if_softc = sc;
110 	if_attach(&sc->gif_if);
111 	if_alloc_sadl(&sc->gif_if);
112 
113 #if NBPFILTER > 0
114 	bpfattach(&sc->gif_if.if_bpf, &sc->gif_if, DLT_NULL,
115 	    sizeof(u_int));
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 				break;
242 			case IPPROTO_MPLS:
243 				family = AF_MPLS;
244 				break;
245 			default:
246 				offset = 0;
247 				family = sc->gif_psrc->sa_family;
248 				break;
249 			}
250 			m->m_data += offset;
251 			m->m_len -= offset;
252 			m->m_pkthdr.len -= offset;
253 			bpf_mtap_af(ifp->if_bpf, family, m, BPF_DIRECTION_OUT);
254 			m->m_data -= offset;
255 			m->m_len += offset;
256 			m->m_pkthdr.len += offset;
257 		}
258 #endif
259 		ifp->if_opackets++;
260 
261 		/* XXX we should cache the outgoing route */
262 
263 		switch (sc->gif_psrc->sa_family) {
264 #ifdef INET
265 		case AF_INET:
266 			ip_output(m, (void *)NULL, (void *)NULL, 0,
267 			    (void *)NULL, (void *)NULL);
268 			break;
269 #endif
270 #ifdef INET6
271 		case AF_INET6:
272 			/*
273 			 * force fragmentation to minimum MTU, to avoid path
274 			 * MTU discovery. It is too painful to ask for resend
275 			 * of inner packet, to achieve path MTU discovery for
276 			 * encapsulated packets.
277 			 */
278 			ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL,
279 			     NULL);
280 			break;
281 #endif
282 		default:
283 			m_freem(m);
284 			break;
285 		}
286 	}
287 }
288 
289 int
290 gif_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
291     struct rtentry *rt)
292 {
293 	struct gif_softc *sc = (struct gif_softc*)ifp;
294 	int error = 0;
295 	int s;
296 	sa_family_t family = dst->sa_family;
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 	/*
307 	 * Remove multicast and broadcast flags or encapsulated packet
308 	 * ends up as multicast or broadcast packet.
309 	 */
310 	m->m_flags &= ~(M_BCAST|M_MCAST);
311 
312 	/*
313 	 * Encapsulate packet. Add IP or IP6 header depending on tunnel AF.
314 	 */
315 	switch (sc->gif_psrc->sa_family) {
316 #ifdef INET
317 	case AF_INET:
318 		error = in_gif_output(ifp, family, &m);
319 		break;
320 #endif
321 #ifdef INET6
322 	case AF_INET6:
323 		error = in6_gif_output(ifp, family, &m);
324 		break;
325 #endif
326 	default:
327 		m_freem(m);
328 		error = EAFNOSUPPORT;
329 		break;
330 	}
331 
332 	if (error)
333 		goto end;
334 
335 	if ((error = gif_checkloop(ifp, m)))
336 		goto end;
337 
338 	/*
339 	 * Queue message on interface, and start output.
340 	 */
341 	s = splnet();
342 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
343 	if (error) {
344 		/* mbuf is already freed */
345 		splx(s);
346 		goto end;
347 	}
348 	ifp->if_obytes += m->m_pkthdr.len;
349 	if_start(ifp);
350 	splx(s);
351 
352 end:
353 	if (error)
354 		ifp->if_oerrors++;
355 	return (error);
356 }
357 
358 int
359 gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
360 {
361 	struct gif_softc *sc  = (struct gif_softc*)ifp;
362 	struct ifreq     *ifr = (struct ifreq*)data;
363 	int error = 0, size;
364 	struct sockaddr *dst, *src;
365 	struct sockaddr *sa;
366 	int s;
367 	struct gif_softc *sc2;
368 
369 	switch (cmd) {
370 	case SIOCSIFADDR:
371 		break;
372 
373 	case SIOCSIFDSTADDR:
374 		break;
375 
376 	case SIOCADDMULTI:
377 	case SIOCDELMULTI:
378 		switch (ifr->ifr_addr.sa_family) {
379 #ifdef INET
380 		case AF_INET:	/* IP supports Multicast */
381 			break;
382 #endif /* INET */
383 #ifdef INET6
384 		case AF_INET6:	/* IP6 supports Multicast */
385 			break;
386 #endif /* INET6 */
387 		default:  /* Other protocols doesn't support Multicast */
388 			error = EAFNOSUPPORT;
389 			break;
390 		}
391 		break;
392 
393 	case SIOCSIFPHYADDR:
394 #ifdef INET6
395 	case SIOCSIFPHYADDR_IN6:
396 #endif /* INET6 */
397 	case SIOCSLIFPHYADDR:
398 		switch (cmd) {
399 #ifdef INET
400 		case SIOCSIFPHYADDR:
401 			src = (struct sockaddr *)
402 				&(((struct in_aliasreq *)data)->ifra_addr);
403 			dst = (struct sockaddr *)
404 				&(((struct in_aliasreq *)data)->ifra_dstaddr);
405 			break;
406 #endif
407 #ifdef INET6
408 		case SIOCSIFPHYADDR_IN6:
409 			src = (struct sockaddr *)
410 				&(((struct in6_aliasreq *)data)->ifra_addr);
411 			dst = (struct sockaddr *)
412 				&(((struct in6_aliasreq *)data)->ifra_dstaddr);
413 			break;
414 #endif
415 		case SIOCSLIFPHYADDR:
416 			src = (struct sockaddr *)
417 				&(((struct if_laddrreq *)data)->addr);
418 			dst = (struct sockaddr *)
419 				&(((struct if_laddrreq *)data)->dstaddr);
420 			break;
421 		default:
422 			return (EINVAL);
423 		}
424 
425 		/* sa_family must be equal */
426 		if (src->sa_family != dst->sa_family)
427 			return (EINVAL);
428 
429 		/* validate sa_len */
430 		switch (src->sa_family) {
431 #ifdef INET
432 		case AF_INET:
433 			if (src->sa_len != sizeof(struct sockaddr_in))
434 				return (EINVAL);
435 			break;
436 #endif
437 #ifdef INET6
438 		case AF_INET6:
439 			if (src->sa_len != sizeof(struct sockaddr_in6))
440 				return (EINVAL);
441 			break;
442 #endif
443 		default:
444 			return (EAFNOSUPPORT);
445 		}
446 		switch (dst->sa_family) {
447 #ifdef INET
448 		case AF_INET:
449 			if (dst->sa_len != sizeof(struct sockaddr_in))
450 				return (EINVAL);
451 			break;
452 #endif
453 #ifdef INET6
454 		case AF_INET6:
455 			if (dst->sa_len != sizeof(struct sockaddr_in6))
456 				return (EINVAL);
457 			break;
458 #endif
459 		default:
460 			return (EAFNOSUPPORT);
461 		}
462 
463 		/* check sa_family looks sane for the cmd */
464 		switch (cmd) {
465 		case SIOCSIFPHYADDR:
466 			if (src->sa_family == AF_INET)
467 				break;
468 			return (EAFNOSUPPORT);
469 #ifdef INET6
470 		case SIOCSIFPHYADDR_IN6:
471 			if (src->sa_family == AF_INET6)
472 				break;
473 			return (EAFNOSUPPORT);
474 #endif /* INET6 */
475 		case SIOCSLIFPHYADDR:
476 			/* checks done in the above */
477 			break;
478 		}
479 
480 		LIST_FOREACH(sc2, &gif_softc_list, gif_list) {
481 			if (sc2 == sc)
482 				continue;
483 			if (!sc2->gif_pdst || !sc2->gif_psrc)
484 				continue;
485 			if (sc2->gif_pdst->sa_family != dst->sa_family ||
486 			    sc2->gif_pdst->sa_len != dst->sa_len ||
487 			    sc2->gif_psrc->sa_family != src->sa_family ||
488 			    sc2->gif_psrc->sa_len != src->sa_len)
489 				continue;
490 			/* can't configure same pair of address onto two gifs */
491 			if (bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 &&
492 			    bcmp(sc2->gif_psrc, src, src->sa_len) == 0) {
493 				error = EADDRNOTAVAIL;
494 				goto bad;
495 			}
496 
497 			/* can't configure multiple multi-dest interfaces */
498 #define multidest(x) \
499 	(((struct sockaddr_in *)(x))->sin_addr.s_addr == INADDR_ANY)
500 #ifdef INET6
501 #define multidest6(x) \
502 	(IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(x))->sin6_addr))
503 #endif
504 			if (dst->sa_family == AF_INET &&
505 			    multidest(dst) && multidest(sc2->gif_pdst)) {
506 				error = EADDRNOTAVAIL;
507 				goto bad;
508 			}
509 #ifdef INET6
510 			if (dst->sa_family == AF_INET6 &&
511 			    multidest6(dst) && multidest6(sc2->gif_pdst)) {
512 				error = EADDRNOTAVAIL;
513 				goto bad;
514 			}
515 #endif
516 		}
517 
518 		if (sc->gif_psrc)
519 			free((caddr_t)sc->gif_psrc, M_IFADDR);
520 		sa = malloc(src->sa_len, M_IFADDR, M_WAITOK);
521 		bcopy((caddr_t)src, (caddr_t)sa, src->sa_len);
522 		sc->gif_psrc = sa;
523 
524 		if (sc->gif_pdst)
525 			free((caddr_t)sc->gif_pdst, M_IFADDR);
526 		sa = malloc(dst->sa_len, M_IFADDR, M_WAITOK);
527 		bcopy((caddr_t)dst, (caddr_t)sa, dst->sa_len);
528 		sc->gif_pdst = sa;
529 
530 		s = splnet();
531 		ifp->if_flags |= IFF_RUNNING;
532 		if_up(ifp);		/* send up RTM_IFINFO */
533 		splx(s);
534 
535 		error = 0;
536 		break;
537 
538 #ifdef SIOCDIFPHYADDR
539 	case SIOCDIFPHYADDR:
540 		if (sc->gif_psrc) {
541 			free((caddr_t)sc->gif_psrc, M_IFADDR);
542 			sc->gif_psrc = NULL;
543 		}
544 		if (sc->gif_pdst) {
545 			free((caddr_t)sc->gif_pdst, M_IFADDR);
546 			sc->gif_pdst = NULL;
547 		}
548 		/* change the IFF_{UP, RUNNING} flag as well? */
549 		break;
550 #endif
551 
552 	case SIOCGIFPSRCADDR:
553 #ifdef INET6
554 	case SIOCGIFPSRCADDR_IN6:
555 #endif /* INET6 */
556 		if (sc->gif_psrc == NULL) {
557 			error = EADDRNOTAVAIL;
558 			goto bad;
559 		}
560 		src = sc->gif_psrc;
561 		switch (cmd) {
562 #ifdef INET
563 		case SIOCGIFPSRCADDR:
564 			dst = &ifr->ifr_addr;
565 			size = sizeof(ifr->ifr_addr);
566 			break;
567 #endif /* INET */
568 #ifdef INET6
569 		case SIOCGIFPSRCADDR_IN6:
570 			dst = (struct sockaddr *)
571 				&(((struct in6_ifreq *)data)->ifr_addr);
572 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
573 			break;
574 #endif /* INET6 */
575 		default:
576 			error = EADDRNOTAVAIL;
577 			goto bad;
578 		}
579 		if (src->sa_len > size)
580 			return (EINVAL);
581 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
582 		break;
583 
584 	case SIOCGIFPDSTADDR:
585 #ifdef INET6
586 	case SIOCGIFPDSTADDR_IN6:
587 #endif /* INET6 */
588 		if (sc->gif_pdst == NULL) {
589 			error = EADDRNOTAVAIL;
590 			goto bad;
591 		}
592 		src = sc->gif_pdst;
593 		switch (cmd) {
594 #ifdef INET
595 		case SIOCGIFPDSTADDR:
596 			dst = &ifr->ifr_addr;
597 			size = sizeof(ifr->ifr_addr);
598 			break;
599 #endif /* INET */
600 #ifdef INET6
601 		case SIOCGIFPDSTADDR_IN6:
602 			dst = (struct sockaddr *)
603 				&(((struct in6_ifreq *)data)->ifr_addr);
604 			size = sizeof(((struct in6_ifreq *)data)->ifr_addr);
605 			break;
606 #endif /* INET6 */
607 		default:
608 			error = EADDRNOTAVAIL;
609 			goto bad;
610 		}
611 		if (src->sa_len > size)
612 			return (EINVAL);
613 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
614 		break;
615 
616 	case SIOCGLIFPHYADDR:
617 		if (sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
618 			error = EADDRNOTAVAIL;
619 			goto bad;
620 		}
621 
622 		/* copy src */
623 		src = sc->gif_psrc;
624 		dst = (struct sockaddr *)
625 			&(((struct if_laddrreq *)data)->addr);
626 		size = sizeof(((struct if_laddrreq *)data)->addr);
627 		if (src->sa_len > size)
628 			return (EINVAL);
629 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
630 
631 		/* copy dst */
632 		src = sc->gif_pdst;
633 		dst = (struct sockaddr *)
634 			&(((struct if_laddrreq *)data)->dstaddr);
635 		size = sizeof(((struct if_laddrreq *)data)->dstaddr);
636 		if (src->sa_len > size)
637 			return (EINVAL);
638 		bcopy((caddr_t)src, (caddr_t)dst, src->sa_len);
639 		break;
640 
641 	case SIOCSIFFLAGS:
642 		/* if_ioctl() takes care of it */
643 		break;
644 
645 	case SIOCSIFMTU:
646 		if (ifr->ifr_mtu < GIF_MTU_MIN || ifr->ifr_mtu > GIF_MTU_MAX)
647 			error = EINVAL;
648 		else
649 			ifp->if_mtu = ifr->ifr_mtu;
650 		break;
651 
652 	case SIOCSLIFPHYRTABLE:
653 		if (ifr->ifr_rdomainid < 0 ||
654 		    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
655 		    !rtable_exists(ifr->ifr_rdomainid)) {
656 			error = EINVAL;
657 			break;
658 		}
659 		sc->gif_rtableid = ifr->ifr_rdomainid;
660 		break;
661 	case SIOCGLIFPHYRTABLE:
662 		ifr->ifr_rdomainid = sc->gif_rtableid;
663 		break;
664 	default:
665 		error = ENOTTY;
666 		break;
667 	}
668  bad:
669 	return (error);
670 }
671 
672 int
673 gif_checkloop(struct ifnet *ifp, struct mbuf *m)
674 {
675 	struct m_tag *mtag;
676 
677 	/*
678 	 * gif may cause infinite recursion calls when misconfigured.
679 	 * We'll prevent this by detecting loops.
680 	 */
681 	for (mtag = m_tag_find(m, PACKET_TAG_GIF, NULL); mtag;
682 	    mtag = m_tag_find(m, PACKET_TAG_GIF, mtag)) {
683 		if (!bcmp((caddr_t)(mtag + 1), &ifp,
684 		    sizeof(struct ifnet *))) {
685 			log(LOG_NOTICE, "gif_output: "
686 			    "recursively called too many times\n");
687 			m_freem(m);
688 			return ENETUNREACH;
689 		}
690 	}
691 
692 	mtag = m_tag_get(PACKET_TAG_GIF, sizeof(caddr_t), M_NOWAIT);
693 	if (mtag == NULL) {
694 		m_freem(m);
695 		return ENOMEM;
696 	}
697 	bcopy(&ifp, mtag + 1, sizeof(caddr_t));
698 	m_tag_prepend(m, mtag);
699 	return 0;
700 }
701