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 *)⁡ 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 *)⁡ 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