ip_gre.c revision 123922
1103026Ssobomax/* $NetBSD: ip_gre.c,v 1.21 2002/08/14 00:23:30 itojun Exp $ */ 2103026Ssobomax/* $FreeBSD: head/sys/netinet/ip_gre.c 123922 2003-12-28 03:56:00Z sam $ */ 3103026Ssobomax 4103026Ssobomax/* 5103026Ssobomax * Copyright (c) 1998 The NetBSD Foundation, Inc. 6103026Ssobomax * All rights reserved. 7103026Ssobomax * 8103026Ssobomax * This code is derived from software contributed to The NetBSD Foundation 9103026Ssobomax * by Heiko W.Rupp <hwr@pilhuhn.de> 10103026Ssobomax * 11103026Ssobomax * Redistribution and use in source and binary forms, with or without 12103026Ssobomax * modification, are permitted provided that the following conditions 13103026Ssobomax * are met: 14103026Ssobomax * 1. Redistributions of source code must retain the above copyright 15103026Ssobomax * notice, this list of conditions and the following disclaimer. 16103026Ssobomax * 2. Redistributions in binary form must reproduce the above copyright 17103026Ssobomax * notice, this list of conditions and the following disclaimer in the 18103026Ssobomax * documentation and/or other materials provided with the distribution. 19103026Ssobomax * 3. All advertising materials mentioning features or use of this software 20103026Ssobomax * must display the following acknowledgement: 21103026Ssobomax * This product includes software developed by the NetBSD 22103026Ssobomax * Foundation, Inc. and its contributors. 23103026Ssobomax * 4. Neither the name of The NetBSD Foundation nor the names of its 24103026Ssobomax * contributors may be used to endorse or promote products derived 25103026Ssobomax * from this software without specific prior written permission. 26103026Ssobomax * 27103026Ssobomax * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28103026Ssobomax * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29103026Ssobomax * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30103026Ssobomax * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31103026Ssobomax * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32103026Ssobomax * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33103026Ssobomax * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34103026Ssobomax * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35103026Ssobomax * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36103026Ssobomax * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37103026Ssobomax * POSSIBILITY OF SUCH DAMAGE. 38103026Ssobomax */ 39103026Ssobomax 40103026Ssobomax/* 41103026Ssobomax * deencapsulate tunneled packets and send them on 42103026Ssobomax * output half is in net/if_gre.[ch] 43103026Ssobomax * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 44103026Ssobomax */ 45103026Ssobomax 46103026Ssobomax#include "opt_inet.h" 47103026Ssobomax#include "opt_atalk.h" 48103026Ssobomax 49103026Ssobomax#include <sys/param.h> 50103026Ssobomax#include <sys/systm.h> 51103026Ssobomax#include <sys/mbuf.h> 52103026Ssobomax#include <sys/socket.h> 53103026Ssobomax#include <sys/socketvar.h> 54103026Ssobomax#include <sys/protosw.h> 55103026Ssobomax#include <sys/errno.h> 56103026Ssobomax#include <sys/time.h> 57103026Ssobomax#include <sys/kernel.h> 58103026Ssobomax#include <sys/syslog.h> 59103026Ssobomax#include <net/bpf.h> 60103026Ssobomax#include <net/ethernet.h> 61103026Ssobomax#include <net/if.h> 62103026Ssobomax#include <net/netisr.h> 63103026Ssobomax#include <net/route.h> 64103026Ssobomax#include <net/raw_cb.h> 65103026Ssobomax 66103026Ssobomax#ifdef INET 67103026Ssobomax#include <netinet/in.h> 68103026Ssobomax#include <netinet/in_var.h> 69103026Ssobomax#include <netinet/in_systm.h> 70103026Ssobomax#include <netinet/ip.h> 71103026Ssobomax#include <netinet/ip_var.h> 72103026Ssobomax#include <netinet/ip_gre.h> 73103026Ssobomax#include <machine/in_cksum.h> 74103026Ssobomax#else 75103026Ssobomax#error ip_gre input without IP? 76103026Ssobomax#endif 77103026Ssobomax 78103026Ssobomax#ifdef NETATALK 79103026Ssobomax#include <netatalk/at.h> 80103026Ssobomax#include <netatalk/at_var.h> 81103026Ssobomax#include <netatalk/at_extern.h> 82103026Ssobomax#endif 83103026Ssobomax 84103026Ssobomax/* Needs IP headers. */ 85103026Ssobomax#include <net/if_gre.h> 86103026Ssobomax 87103026Ssobomax#include <machine/stdarg.h> 88103026Ssobomax 89103026Ssobomax#if 1 90103026Ssobomaxvoid gre_inet_ntoa(struct in_addr in); /* XXX */ 91103026Ssobomax#endif 92103026Ssobomax 93105301Salfredstatic struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 94103026Ssobomax 95105301Salfredstatic int gre_input2(struct mbuf *, int, u_char); 96103026Ssobomax 97103026Ssobomax/* 98103026Ssobomax * De-encapsulate a packet and feed it back through ip input (this 99103026Ssobomax * routine is called whenever IP gets a packet with proto type 100103026Ssobomax * IPPROTO_GRE and a local destination address). 101103026Ssobomax * This really is simple 102103026Ssobomax */ 103103026Ssobomaxvoid 104103026Ssobomax#if __STDC__ 105103026Ssobomaxgre_input(struct mbuf *m, ...) 106103026Ssobomax#else 107103026Ssobomaxgre_input(m, va_alist) 108103026Ssobomax struct mbuf *m; 109103026Ssobomax va_dcl 110103026Ssobomax#endif 111103026Ssobomax{ 112103026Ssobomax int off, ret, proto; 113103026Ssobomax va_list ap; 114103026Ssobomax 115103026Ssobomax va_start(ap, m); 116103026Ssobomax off = va_arg(ap, int); 117103026Ssobomax va_end(ap); 118103026Ssobomax proto = (mtod(m, struct ip *))->ip_p; 119103026Ssobomax 120103026Ssobomax ret = gre_input2(m, off, proto); 121103026Ssobomax /* 122103026Ssobomax * ret == 0 : packet not processed, meaning that 123103026Ssobomax * no matching tunnel that is up is found. 124103026Ssobomax * we inject it to raw ip socket to see if anyone picks it up. 125103026Ssobomax */ 126103026Ssobomax if (ret == 0) 127103026Ssobomax rip_input(m, off); 128103026Ssobomax} 129103026Ssobomax 130103026Ssobomax/* 131103026Ssobomax * decapsulate. 132103026Ssobomax * Does the real work and is called from gre_input() (above) 133103026Ssobomax * returns 0 if packet is not yet processed 134103026Ssobomax * and 1 if it needs no further processing 135103026Ssobomax * proto is the protocol number of the "calling" foo_input() 136103026Ssobomax * routine. 137103026Ssobomax */ 138103026Ssobomax 139103032Ssobomaxstatic int 140103026Ssobomaxgre_input2(struct mbuf *m ,int hlen, u_char proto) 141103026Ssobomax{ 142103026Ssobomax struct greip *gip = mtod(m, struct greip *); 143111888Sjlemon int isr; 144103026Ssobomax struct gre_softc *sc; 145103026Ssobomax u_short flags; 146103026Ssobomax 147103026Ssobomax if ((sc = gre_lookup(m, proto)) == NULL) { 148103026Ssobomax /* No matching tunnel or tunnel is down. */ 149103026Ssobomax return (0); 150103026Ssobomax } 151103026Ssobomax 152103026Ssobomax sc->sc_if.if_ipackets++; 153103026Ssobomax sc->sc_if.if_ibytes += m->m_pkthdr.len; 154103026Ssobomax 155103026Ssobomax switch (proto) { 156103026Ssobomax case IPPROTO_GRE: 157103026Ssobomax hlen += sizeof (struct gre_h); 158103026Ssobomax 159103026Ssobomax /* process GRE flags as packet can be of variable len */ 160103026Ssobomax flags = ntohs(gip->gi_flags); 161103026Ssobomax 162103026Ssobomax /* Checksum & Offset are present */ 163103026Ssobomax if ((flags & GRE_CP) | (flags & GRE_RP)) 164103026Ssobomax hlen += 4; 165103026Ssobomax /* We don't support routing fields (variable length) */ 166103026Ssobomax if (flags & GRE_RP) 167103026Ssobomax return(0); 168103026Ssobomax if (flags & GRE_KP) 169103026Ssobomax hlen += 4; 170103026Ssobomax if (flags & GRE_SP) 171103026Ssobomax hlen +=4; 172103026Ssobomax 173103026Ssobomax switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 174103026Ssobomax case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 175107670Ssobomax case WCCP_PROTOCOL_TYPE: /* we are in ip_input */ 176111888Sjlemon isr = NETISR_IP; 177103026Ssobomax break; 178103026Ssobomax#ifdef NETATALK 179103026Ssobomax case ETHERTYPE_ATALK: 180111888Sjlemon isr = NETISR_ATALK1; 181103026Ssobomax break; 182103026Ssobomax#endif 183103026Ssobomax case ETHERTYPE_IPV6: 184103026Ssobomax /* FALLTHROUGH */ 185103026Ssobomax default: /* others not yet supported */ 186103026Ssobomax return(0); 187103026Ssobomax } 188103026Ssobomax break; 189103026Ssobomax default: 190103026Ssobomax /* others not yet supported */ 191103026Ssobomax return(0); 192103026Ssobomax } 193103026Ssobomax 194103026Ssobomax m->m_data += hlen; 195103026Ssobomax m->m_len -= hlen; 196103026Ssobomax m->m_pkthdr.len -= hlen; 197103026Ssobomax 198103026Ssobomax if (sc->sc_if.if_bpf) { 199103026Ssobomax u_int32_t af = AF_INET; 200123922Ssam bpf_mtap2(sc->sc_if.if_bpf, &af, sizeof(af), m); 201104366Ssobomax } 202103026Ssobomax 203103026Ssobomax m->m_pkthdr.rcvif = &sc->sc_if; 204103026Ssobomax 205111888Sjlemon netisr_dispatch(isr, m); 206103026Ssobomax 207103026Ssobomax return(1); /* packet is done, no further processing needed */ 208103026Ssobomax} 209103026Ssobomax 210103026Ssobomax/* 211103026Ssobomax * input routine for IPPRPOTO_MOBILE 212103026Ssobomax * This is a little bit diffrent from the other modes, as the 213103026Ssobomax * encapsulating header was not prepended, but instead inserted 214103026Ssobomax * between IP header and payload 215103026Ssobomax */ 216103026Ssobomax 217103026Ssobomaxvoid 218103026Ssobomax#if __STDC__ 219103026Ssobomaxgre_mobile_input(struct mbuf *m, ...) 220103026Ssobomax#else 221103026Ssobomaxgre_mobile_input(m, va_alist) 222103026Ssobomax struct mbuf *m; 223103026Ssobomax va_dcl 224103026Ssobomax#endif 225103026Ssobomax{ 226103026Ssobomax struct ip *ip = mtod(m, struct ip *); 227103026Ssobomax struct mobip_h *mip = mtod(m, struct mobip_h *); 228103026Ssobomax struct gre_softc *sc; 229111888Sjlemon int hlen; 230103026Ssobomax va_list ap; 231103026Ssobomax u_char osrc = 0; 232103026Ssobomax int msiz; 233103026Ssobomax 234103026Ssobomax va_start(ap,m); 235103026Ssobomax hlen = va_arg(ap, int); 236103026Ssobomax va_end(ap); 237103026Ssobomax 238103026Ssobomax if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 239103026Ssobomax /* No matching tunnel or tunnel is down. */ 240103026Ssobomax m_freem(m); 241103026Ssobomax return; 242103026Ssobomax } 243103026Ssobomax 244103026Ssobomax sc->sc_if.if_ipackets++; 245103026Ssobomax sc->sc_if.if_ibytes += m->m_pkthdr.len; 246103026Ssobomax 247103026Ssobomax if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 248103026Ssobomax osrc = 1; 249103026Ssobomax msiz = MOB_H_SIZ_L; 250103026Ssobomax mip->mi.ip_src.s_addr = mip->mh.osrc; 251103026Ssobomax } else { 252103026Ssobomax msiz = MOB_H_SIZ_S; 253103026Ssobomax } 254103026Ssobomax mip->mi.ip_dst.s_addr = mip->mh.odst; 255103026Ssobomax mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 256103026Ssobomax 257103026Ssobomax if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { 258103026Ssobomax m_freem(m); 259103026Ssobomax return; 260103026Ssobomax } 261103026Ssobomax 262103026Ssobomax bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 263103026Ssobomax (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 264103026Ssobomax m->m_len -= msiz; 265103026Ssobomax m->m_pkthdr.len -= msiz; 266103026Ssobomax 267103026Ssobomax /* 268103026Ssobomax * On FreeBSD, rip_input() supplies us with ip->ip_len 269103026Ssobomax * already converted into host byteorder and also decreases 270103026Ssobomax * it by the lengh of IP header, however, ip_input() expects 271103026Ssobomax * that this field is in the original format (network byteorder 272103026Ssobomax * and full size of IP packet), so that adjust accordingly. 273103026Ssobomax */ 274103026Ssobomax ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 275103026Ssobomax 276103026Ssobomax ip->ip_sum = 0; 277103026Ssobomax ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 278103026Ssobomax 279103026Ssobomax if (sc->sc_if.if_bpf) { 280123922Ssam u_int32_t af = AF_INET; 281123922Ssam bpf_mtap2(sc->sc_if.if_bpf, &af, sizeof(af), m); 282104366Ssobomax } 283103026Ssobomax 284103026Ssobomax m->m_pkthdr.rcvif = &sc->sc_if; 285103026Ssobomax 286111888Sjlemon netisr_dispatch(NETISR_IP, m); 287103026Ssobomax} 288103026Ssobomax 289103026Ssobomax/* 290103026Ssobomax * Find the gre interface associated with our src/dst/proto set. 291103026Ssobomax */ 292103032Ssobomaxstatic struct gre_softc * 293103026Ssobomaxgre_lookup(m, proto) 294103026Ssobomax struct mbuf *m; 295103026Ssobomax u_int8_t proto; 296103026Ssobomax{ 297103026Ssobomax struct ip *ip = mtod(m, struct ip *); 298103026Ssobomax struct gre_softc *sc; 299103026Ssobomax 300103026Ssobomax for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 301103026Ssobomax sc = LIST_NEXT(sc, sc_list)) { 302103026Ssobomax if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 303103026Ssobomax (sc->g_src.s_addr == ip->ip_dst.s_addr) && 304103026Ssobomax (sc->g_proto == proto) && 305103026Ssobomax ((sc->sc_if.if_flags & IFF_UP) != 0)) 306103026Ssobomax return (sc); 307103026Ssobomax } 308103026Ssobomax 309103026Ssobomax return (NULL); 310103026Ssobomax} 311