xref: /freebsd/sys/netinet/ip_gre.c (revision 8e96e13e6a8e0eae60f74facc7ac6f4ada2ea7b1)
18e96e13eSMaxim Sobolev /*	$NetBSD: ip_gre.c,v 1.21 2002/08/14 00:23:30 itojun Exp $ */
28e96e13eSMaxim Sobolev /*	 $FreeBSD$ */
38e96e13eSMaxim Sobolev 
48e96e13eSMaxim Sobolev /*
58e96e13eSMaxim Sobolev  * Copyright (c) 1998 The NetBSD Foundation, Inc.
68e96e13eSMaxim Sobolev  * All rights reserved.
78e96e13eSMaxim Sobolev  *
88e96e13eSMaxim Sobolev  * This code is derived from software contributed to The NetBSD Foundation
98e96e13eSMaxim Sobolev  * by Heiko W.Rupp <hwr@pilhuhn.de>
108e96e13eSMaxim Sobolev  *
118e96e13eSMaxim Sobolev  * Redistribution and use in source and binary forms, with or without
128e96e13eSMaxim Sobolev  * modification, are permitted provided that the following conditions
138e96e13eSMaxim Sobolev  * are met:
148e96e13eSMaxim Sobolev  * 1. Redistributions of source code must retain the above copyright
158e96e13eSMaxim Sobolev  *    notice, this list of conditions and the following disclaimer.
168e96e13eSMaxim Sobolev  * 2. Redistributions in binary form must reproduce the above copyright
178e96e13eSMaxim Sobolev  *    notice, this list of conditions and the following disclaimer in the
188e96e13eSMaxim Sobolev  *    documentation and/or other materials provided with the distribution.
198e96e13eSMaxim Sobolev  * 3. All advertising materials mentioning features or use of this software
208e96e13eSMaxim Sobolev  *    must display the following acknowledgement:
218e96e13eSMaxim Sobolev  *        This product includes software developed by the NetBSD
228e96e13eSMaxim Sobolev  *        Foundation, Inc. and its contributors.
238e96e13eSMaxim Sobolev  * 4. Neither the name of The NetBSD Foundation nor the names of its
248e96e13eSMaxim Sobolev  *    contributors may be used to endorse or promote products derived
258e96e13eSMaxim Sobolev  *    from this software without specific prior written permission.
268e96e13eSMaxim Sobolev  *
278e96e13eSMaxim Sobolev  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
288e96e13eSMaxim Sobolev  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
298e96e13eSMaxim Sobolev  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
308e96e13eSMaxim Sobolev  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
318e96e13eSMaxim Sobolev  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
328e96e13eSMaxim Sobolev  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
338e96e13eSMaxim Sobolev  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
348e96e13eSMaxim Sobolev  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
358e96e13eSMaxim Sobolev  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
368e96e13eSMaxim Sobolev  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
378e96e13eSMaxim Sobolev  * POSSIBILITY OF SUCH DAMAGE.
388e96e13eSMaxim Sobolev  */
398e96e13eSMaxim Sobolev 
408e96e13eSMaxim Sobolev /*
418e96e13eSMaxim Sobolev  * deencapsulate tunneled packets and send them on
428e96e13eSMaxim Sobolev  * output half is in net/if_gre.[ch]
438e96e13eSMaxim Sobolev  * This currently handles IPPROTO_GRE, IPPROTO_MOBILE
448e96e13eSMaxim Sobolev  */
458e96e13eSMaxim Sobolev 
468e96e13eSMaxim Sobolev #include <sys/cdefs.h>
478e96e13eSMaxim Sobolev __RCSID("@(#) $FreeBSD$");
488e96e13eSMaxim Sobolev 
498e96e13eSMaxim Sobolev #include "opt_inet.h"
508e96e13eSMaxim Sobolev #include "opt_ns.h"
518e96e13eSMaxim Sobolev #include "opt_atalk.h"
528e96e13eSMaxim Sobolev #include "bpf.h"
538e96e13eSMaxim Sobolev 
548e96e13eSMaxim Sobolev #include <sys/param.h>
558e96e13eSMaxim Sobolev #include <sys/systm.h>
568e96e13eSMaxim Sobolev #include <sys/mbuf.h>
578e96e13eSMaxim Sobolev #include <sys/socket.h>
588e96e13eSMaxim Sobolev #include <sys/socketvar.h>
598e96e13eSMaxim Sobolev #include <sys/protosw.h>
608e96e13eSMaxim Sobolev #include <sys/errno.h>
618e96e13eSMaxim Sobolev #include <sys/time.h>
628e96e13eSMaxim Sobolev #include <sys/kernel.h>
638e96e13eSMaxim Sobolev #include <sys/syslog.h>
648e96e13eSMaxim Sobolev #include <net/bpf.h>
658e96e13eSMaxim Sobolev #include <net/ethernet.h>
668e96e13eSMaxim Sobolev #include <net/if.h>
678e96e13eSMaxim Sobolev #include <net/netisr.h>
688e96e13eSMaxim Sobolev #include <net/route.h>
698e96e13eSMaxim Sobolev #include <net/raw_cb.h>
708e96e13eSMaxim Sobolev 
718e96e13eSMaxim Sobolev #ifdef INET
728e96e13eSMaxim Sobolev #include <netinet/in.h>
738e96e13eSMaxim Sobolev #include <netinet/in_var.h>
748e96e13eSMaxim Sobolev #include <netinet/in_systm.h>
758e96e13eSMaxim Sobolev #include <netinet/ip.h>
768e96e13eSMaxim Sobolev #include <netinet/ip_var.h>
778e96e13eSMaxim Sobolev #include <netinet/ip_gre.h>
788e96e13eSMaxim Sobolev #include <machine/in_cksum.h>
798e96e13eSMaxim Sobolev #else
808e96e13eSMaxim Sobolev #error ip_gre input without IP?
818e96e13eSMaxim Sobolev #endif
828e96e13eSMaxim Sobolev 
838e96e13eSMaxim Sobolev #ifdef NS
848e96e13eSMaxim Sobolev #include <netns/ns.h>
858e96e13eSMaxim Sobolev #include <netns/ns_if.h>
868e96e13eSMaxim Sobolev #endif
878e96e13eSMaxim Sobolev 
888e96e13eSMaxim Sobolev #ifdef NETATALK
898e96e13eSMaxim Sobolev #include <netatalk/at.h>
908e96e13eSMaxim Sobolev #include <netatalk/at_var.h>
918e96e13eSMaxim Sobolev #include <netatalk/at_extern.h>
928e96e13eSMaxim Sobolev #endif
938e96e13eSMaxim Sobolev 
948e96e13eSMaxim Sobolev /* Needs IP headers. */
958e96e13eSMaxim Sobolev #include <net/if_gre.h>
968e96e13eSMaxim Sobolev 
978e96e13eSMaxim Sobolev #include <machine/stdarg.h>
988e96e13eSMaxim Sobolev 
998e96e13eSMaxim Sobolev #if 1
1008e96e13eSMaxim Sobolev void gre_inet_ntoa(struct in_addr in); 	/* XXX */
1018e96e13eSMaxim Sobolev #endif
1028e96e13eSMaxim Sobolev 
1038e96e13eSMaxim Sobolev struct gre_softc *gre_lookup __P((struct mbuf *, u_int8_t));
1048e96e13eSMaxim Sobolev 
1058e96e13eSMaxim Sobolev int	gre_input2 __P((struct mbuf *, int, u_char));
1068e96e13eSMaxim Sobolev 
1078e96e13eSMaxim Sobolev /*
1088e96e13eSMaxim Sobolev  * De-encapsulate a packet and feed it back through ip input (this
1098e96e13eSMaxim Sobolev  * routine is called whenever IP gets a packet with proto type
1108e96e13eSMaxim Sobolev  * IPPROTO_GRE and a local destination address).
1118e96e13eSMaxim Sobolev  * This really is simple
1128e96e13eSMaxim Sobolev  */
1138e96e13eSMaxim Sobolev void
1148e96e13eSMaxim Sobolev #if __STDC__
1158e96e13eSMaxim Sobolev gre_input(struct mbuf *m, ...)
1168e96e13eSMaxim Sobolev #else
1178e96e13eSMaxim Sobolev gre_input(m, va_alist)
1188e96e13eSMaxim Sobolev         struct mbuf *m;
1198e96e13eSMaxim Sobolev         va_dcl
1208e96e13eSMaxim Sobolev #endif
1218e96e13eSMaxim Sobolev {
1228e96e13eSMaxim Sobolev 	int off, ret, proto;
1238e96e13eSMaxim Sobolev 	va_list ap;
1248e96e13eSMaxim Sobolev 
1258e96e13eSMaxim Sobolev 	va_start(ap, m);
1268e96e13eSMaxim Sobolev 	off = va_arg(ap, int);
1278e96e13eSMaxim Sobolev 	va_end(ap);
1288e96e13eSMaxim Sobolev 	proto = (mtod(m, struct ip *))->ip_p;
1298e96e13eSMaxim Sobolev 
1308e96e13eSMaxim Sobolev 	ret = gre_input2(m, off, proto);
1318e96e13eSMaxim Sobolev 	/*
1328e96e13eSMaxim Sobolev 	 * ret == 0 : packet not processed, meaning that
1338e96e13eSMaxim Sobolev 	 * no matching tunnel that is up is found.
1348e96e13eSMaxim Sobolev 	 * we inject it to raw ip socket to see if anyone picks it up.
1358e96e13eSMaxim Sobolev 	 */
1368e96e13eSMaxim Sobolev 	if (ret == 0)
1378e96e13eSMaxim Sobolev 		rip_input(m, off);
1388e96e13eSMaxim Sobolev }
1398e96e13eSMaxim Sobolev 
1408e96e13eSMaxim Sobolev /*
1418e96e13eSMaxim Sobolev  * decapsulate.
1428e96e13eSMaxim Sobolev  * Does the real work and is called from gre_input() (above)
1438e96e13eSMaxim Sobolev  * returns 0 if packet is not yet processed
1448e96e13eSMaxim Sobolev  * and 1 if it needs no further processing
1458e96e13eSMaxim Sobolev  * proto is the protocol number of the "calling" foo_input()
1468e96e13eSMaxim Sobolev  * routine.
1478e96e13eSMaxim Sobolev  */
1488e96e13eSMaxim Sobolev 
1498e96e13eSMaxim Sobolev int
1508e96e13eSMaxim Sobolev gre_input2(struct mbuf *m ,int hlen, u_char proto)
1518e96e13eSMaxim Sobolev {
1528e96e13eSMaxim Sobolev 	struct greip *gip = mtod(m, struct greip *);
1538e96e13eSMaxim Sobolev 	int s;
1548e96e13eSMaxim Sobolev 	struct ifqueue *ifq;
1558e96e13eSMaxim Sobolev 	struct gre_softc *sc;
1568e96e13eSMaxim Sobolev 	u_short flags;
1578e96e13eSMaxim Sobolev 
1588e96e13eSMaxim Sobolev 	if ((sc = gre_lookup(m, proto)) == NULL) {
1598e96e13eSMaxim Sobolev 		/* No matching tunnel or tunnel is down. */
1608e96e13eSMaxim Sobolev 		return (0);
1618e96e13eSMaxim Sobolev 	}
1628e96e13eSMaxim Sobolev 
1638e96e13eSMaxim Sobolev 	sc->sc_if.if_ipackets++;
1648e96e13eSMaxim Sobolev 	sc->sc_if.if_ibytes += m->m_pkthdr.len;
1658e96e13eSMaxim Sobolev 
1668e96e13eSMaxim Sobolev 	switch (proto) {
1678e96e13eSMaxim Sobolev 	case IPPROTO_GRE:
1688e96e13eSMaxim Sobolev 		hlen += sizeof (struct gre_h);
1698e96e13eSMaxim Sobolev 
1708e96e13eSMaxim Sobolev 		/* process GRE flags as packet can be of variable len */
1718e96e13eSMaxim Sobolev 		flags = ntohs(gip->gi_flags);
1728e96e13eSMaxim Sobolev 
1738e96e13eSMaxim Sobolev 		/* Checksum & Offset are present */
1748e96e13eSMaxim Sobolev 		if ((flags & GRE_CP) | (flags & GRE_RP))
1758e96e13eSMaxim Sobolev 			hlen += 4;
1768e96e13eSMaxim Sobolev 		/* We don't support routing fields (variable length) */
1778e96e13eSMaxim Sobolev 		if (flags & GRE_RP)
1788e96e13eSMaxim Sobolev 			return(0);
1798e96e13eSMaxim Sobolev 		if (flags & GRE_KP)
1808e96e13eSMaxim Sobolev 			hlen += 4;
1818e96e13eSMaxim Sobolev 		if (flags & GRE_SP)
1828e96e13eSMaxim Sobolev 			hlen +=4;
1838e96e13eSMaxim Sobolev 
1848e96e13eSMaxim Sobolev 		switch (ntohs(gip->gi_ptype)) { /* ethertypes */
1858e96e13eSMaxim Sobolev 		case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */
1868e96e13eSMaxim Sobolev 			ifq = &ipintrq;          /* we are in ip_input */
1878e96e13eSMaxim Sobolev 			break;
1888e96e13eSMaxim Sobolev 		break;
1898e96e13eSMaxim Sobolev #ifdef NS
1908e96e13eSMaxim Sobolev 		case ETHERTYPE_NS:
1918e96e13eSMaxim Sobolev 			ifq = &nsintrq;
1928e96e13eSMaxim Sobolev 			schednetisr(NETISR_NS);
1938e96e13eSMaxim Sobolev 			break;
1948e96e13eSMaxim Sobolev #endif
1958e96e13eSMaxim Sobolev #ifdef NETATALK
1968e96e13eSMaxim Sobolev 		case ETHERTYPE_ATALK:
1978e96e13eSMaxim Sobolev 			ifq = &atintrq1;
1988e96e13eSMaxim Sobolev 			schednetisr(NETISR_ATALK);
1998e96e13eSMaxim Sobolev 			break;
2008e96e13eSMaxim Sobolev #endif
2018e96e13eSMaxim Sobolev 		case ETHERTYPE_IPV6:
2028e96e13eSMaxim Sobolev 			/* FALLTHROUGH */
2038e96e13eSMaxim Sobolev 		default:	   /* others not yet supported */
2048e96e13eSMaxim Sobolev 			return(0);
2058e96e13eSMaxim Sobolev 		}
2068e96e13eSMaxim Sobolev 		break;
2078e96e13eSMaxim Sobolev 	default:
2088e96e13eSMaxim Sobolev 		/* others not yet supported */
2098e96e13eSMaxim Sobolev 		return(0);
2108e96e13eSMaxim Sobolev 	}
2118e96e13eSMaxim Sobolev 
2128e96e13eSMaxim Sobolev 	m->m_data += hlen;
2138e96e13eSMaxim Sobolev 	m->m_len -= hlen;
2148e96e13eSMaxim Sobolev 	m->m_pkthdr.len -= hlen;
2158e96e13eSMaxim Sobolev 
2168e96e13eSMaxim Sobolev #if NBPF > 0
2178e96e13eSMaxim Sobolev 	if (sc->sc_if.if_bpf) {
2188e96e13eSMaxim Sobolev 		struct mbuf m0;
2198e96e13eSMaxim Sobolev 		u_int32_t af = AF_INET;
2208e96e13eSMaxim Sobolev 
2218e96e13eSMaxim Sobolev 		m0.m_next = m;
2228e96e13eSMaxim Sobolev 		m0.m_len = 4;
2238e96e13eSMaxim Sobolev 		m0.m_data = (char *)&af;
2248e96e13eSMaxim Sobolev 
2258e96e13eSMaxim Sobolev 		bpf_mtap(&(sc->sc_if), &m0);
2268e96e13eSMaxim Sobolev 		}
2278e96e13eSMaxim Sobolev #endif /*NBPF > 0*/
2288e96e13eSMaxim Sobolev 
2298e96e13eSMaxim Sobolev 	m->m_pkthdr.rcvif = &sc->sc_if;
2308e96e13eSMaxim Sobolev 
2318e96e13eSMaxim Sobolev 	s = splnet();		/* possible */
2328e96e13eSMaxim Sobolev 	if (_IF_QFULL(ifq)) {
2338e96e13eSMaxim Sobolev 		_IF_DROP(ifq);
2348e96e13eSMaxim Sobolev 		m_freem(m);
2358e96e13eSMaxim Sobolev 	} else {
2368e96e13eSMaxim Sobolev 		IF_ENQUEUE(ifq,m);
2378e96e13eSMaxim Sobolev 	}
2388e96e13eSMaxim Sobolev 	splx(s);
2398e96e13eSMaxim Sobolev 
2408e96e13eSMaxim Sobolev 	return(1);	/* packet is done, no further processing needed */
2418e96e13eSMaxim Sobolev }
2428e96e13eSMaxim Sobolev 
2438e96e13eSMaxim Sobolev /*
2448e96e13eSMaxim Sobolev  * input routine for IPPRPOTO_MOBILE
2458e96e13eSMaxim Sobolev  * This is a little bit diffrent from the other modes, as the
2468e96e13eSMaxim Sobolev  * encapsulating header was not prepended, but instead inserted
2478e96e13eSMaxim Sobolev  * between IP header and payload
2488e96e13eSMaxim Sobolev  */
2498e96e13eSMaxim Sobolev 
2508e96e13eSMaxim Sobolev void
2518e96e13eSMaxim Sobolev #if __STDC__
2528e96e13eSMaxim Sobolev gre_mobile_input(struct mbuf *m, ...)
2538e96e13eSMaxim Sobolev #else
2548e96e13eSMaxim Sobolev gre_mobile_input(m, va_alist)
2558e96e13eSMaxim Sobolev         struct mbuf *m;
2568e96e13eSMaxim Sobolev         va_dcl
2578e96e13eSMaxim Sobolev #endif
2588e96e13eSMaxim Sobolev {
2598e96e13eSMaxim Sobolev 	struct ip *ip = mtod(m, struct ip *);
2608e96e13eSMaxim Sobolev 	struct mobip_h *mip = mtod(m, struct mobip_h *);
2618e96e13eSMaxim Sobolev 	struct ifqueue *ifq;
2628e96e13eSMaxim Sobolev 	struct gre_softc *sc;
2638e96e13eSMaxim Sobolev 	int hlen,s;
2648e96e13eSMaxim Sobolev 	va_list ap;
2658e96e13eSMaxim Sobolev 	u_char osrc = 0;
2668e96e13eSMaxim Sobolev 	int msiz;
2678e96e13eSMaxim Sobolev 
2688e96e13eSMaxim Sobolev 	va_start(ap,m);
2698e96e13eSMaxim Sobolev 	hlen = va_arg(ap, int);
2708e96e13eSMaxim Sobolev 	va_end(ap);
2718e96e13eSMaxim Sobolev 
2728e96e13eSMaxim Sobolev 	if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) {
2738e96e13eSMaxim Sobolev 		/* No matching tunnel or tunnel is down. */
2748e96e13eSMaxim Sobolev 		m_freem(m);
2758e96e13eSMaxim Sobolev 		return;
2768e96e13eSMaxim Sobolev 	}
2778e96e13eSMaxim Sobolev 
2788e96e13eSMaxim Sobolev 	sc->sc_if.if_ipackets++;
2798e96e13eSMaxim Sobolev 	sc->sc_if.if_ibytes += m->m_pkthdr.len;
2808e96e13eSMaxim Sobolev 
2818e96e13eSMaxim Sobolev 	if(ntohs(mip->mh.proto) & MOB_H_SBIT) {
2828e96e13eSMaxim Sobolev 		osrc = 1;
2838e96e13eSMaxim Sobolev 		msiz = MOB_H_SIZ_L;
2848e96e13eSMaxim Sobolev 		mip->mi.ip_src.s_addr = mip->mh.osrc;
2858e96e13eSMaxim Sobolev 	} else {
2868e96e13eSMaxim Sobolev 		msiz = MOB_H_SIZ_S;
2878e96e13eSMaxim Sobolev 	}
2888e96e13eSMaxim Sobolev 	mip->mi.ip_dst.s_addr = mip->mh.odst;
2898e96e13eSMaxim Sobolev 	mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8);
2908e96e13eSMaxim Sobolev 
2918e96e13eSMaxim Sobolev 	if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) {
2928e96e13eSMaxim Sobolev 		m_freem(m);
2938e96e13eSMaxim Sobolev 		return;
2948e96e13eSMaxim Sobolev 	}
2958e96e13eSMaxim Sobolev 
2968e96e13eSMaxim Sobolev 	bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) +
2978e96e13eSMaxim Sobolev 	    (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2));
2988e96e13eSMaxim Sobolev 	m->m_len -= msiz;
2998e96e13eSMaxim Sobolev 	m->m_pkthdr.len -= msiz;
3008e96e13eSMaxim Sobolev 
3018e96e13eSMaxim Sobolev 	/*
3028e96e13eSMaxim Sobolev 	 * On FreeBSD, rip_input() supplies us with ip->ip_len
3038e96e13eSMaxim Sobolev 	 * already converted into host byteorder and also decreases
3048e96e13eSMaxim Sobolev 	 * it by the lengh of IP header, however, ip_input() expects
3058e96e13eSMaxim Sobolev 	 * that this field is in the original format (network byteorder
3068e96e13eSMaxim Sobolev 	 * and full size of IP packet), so that adjust accordingly.
3078e96e13eSMaxim Sobolev 	 */
3088e96e13eSMaxim Sobolev 	ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz);
3098e96e13eSMaxim Sobolev 
3108e96e13eSMaxim Sobolev 	ip->ip_sum = 0;
3118e96e13eSMaxim Sobolev 	ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
3128e96e13eSMaxim Sobolev 
3138e96e13eSMaxim Sobolev #if NBPF > 0
3148e96e13eSMaxim Sobolev 	if (sc->sc_if.if_bpf) {
3158e96e13eSMaxim Sobolev 		struct mbuf m0;
3168e96e13eSMaxim Sobolev 		u_int af = AF_INET;
3178e96e13eSMaxim Sobolev 
3188e96e13eSMaxim Sobolev 		m0.m_next = m;
3198e96e13eSMaxim Sobolev 		m0.m_len = 4;
3208e96e13eSMaxim Sobolev 		m0.m_data = (char *)&af;
3218e96e13eSMaxim Sobolev 
3228e96e13eSMaxim Sobolev 		bpf_mtap(&(sc->sc_if), &m0);
3238e96e13eSMaxim Sobolev 		}
3248e96e13eSMaxim Sobolev #endif /*NBPFILTER > 0*/
3258e96e13eSMaxim Sobolev 
3268e96e13eSMaxim Sobolev 	m->m_pkthdr.rcvif = &sc->sc_if;
3278e96e13eSMaxim Sobolev 
3288e96e13eSMaxim Sobolev 	ifq = &ipintrq;
3298e96e13eSMaxim Sobolev 	s = splnet();       /* possible */
3308e96e13eSMaxim Sobolev 	if (_IF_QFULL(ifq)) {
3318e96e13eSMaxim Sobolev 		_IF_DROP(ifq);
3328e96e13eSMaxim Sobolev 		m_freem(m);
3338e96e13eSMaxim Sobolev 	} else {
3348e96e13eSMaxim Sobolev 		IF_ENQUEUE(ifq,m);
3358e96e13eSMaxim Sobolev 	}
3368e96e13eSMaxim Sobolev 	splx(s);
3378e96e13eSMaxim Sobolev }
3388e96e13eSMaxim Sobolev 
3398e96e13eSMaxim Sobolev /*
3408e96e13eSMaxim Sobolev  * Find the gre interface associated with our src/dst/proto set.
3418e96e13eSMaxim Sobolev  */
3428e96e13eSMaxim Sobolev struct gre_softc *
3438e96e13eSMaxim Sobolev gre_lookup(m, proto)
3448e96e13eSMaxim Sobolev 	struct mbuf *m;
3458e96e13eSMaxim Sobolev 	u_int8_t proto;
3468e96e13eSMaxim Sobolev {
3478e96e13eSMaxim Sobolev 	struct ip *ip = mtod(m, struct ip *);
3488e96e13eSMaxim Sobolev 	struct gre_softc *sc;
3498e96e13eSMaxim Sobolev 
3508e96e13eSMaxim Sobolev 	for (sc = LIST_FIRST(&gre_softc_list); sc != NULL;
3518e96e13eSMaxim Sobolev 	     sc = LIST_NEXT(sc, sc_list)) {
3528e96e13eSMaxim Sobolev 		if ((sc->g_dst.s_addr == ip->ip_src.s_addr) &&
3538e96e13eSMaxim Sobolev 		    (sc->g_src.s_addr == ip->ip_dst.s_addr) &&
3548e96e13eSMaxim Sobolev 		    (sc->g_proto == proto) &&
3558e96e13eSMaxim Sobolev 		    ((sc->sc_if.if_flags & IFF_UP) != 0))
3568e96e13eSMaxim Sobolev 			return (sc);
3578e96e13eSMaxim Sobolev 	}
3588e96e13eSMaxim Sobolev 
3598e96e13eSMaxim Sobolev 	return (NULL);
3608e96e13eSMaxim Sobolev }
361