ip_gre.c revision 125226
1123992Ssobomax/* $NetBSD: ip_gre.c,v 1.29 2003/09/05 23:02:43 itojun Exp $ */ 2103026Ssobomax/* $FreeBSD: head/sys/netinet/ip_gre.c 125226 2004-01-30 09:03:01Z sobomax $ */ 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) 108123992Ssobomax struct mbuf *m; 109123992Ssobomax 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 /* 122125020Ssobomax * 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 */ 138103032Ssobomaxstatic int 139103026Ssobomaxgre_input2(struct mbuf *m ,int hlen, u_char proto) 140103026Ssobomax{ 141123992Ssobomax struct greip *gip; 142111888Sjlemon int isr; 143103026Ssobomax struct gre_softc *sc; 144123992Ssobomax u_int16_t flags; 145103026Ssobomax 146103026Ssobomax if ((sc = gre_lookup(m, proto)) == NULL) { 147103026Ssobomax /* No matching tunnel or tunnel is down. */ 148103026Ssobomax return (0); 149103026Ssobomax } 150103026Ssobomax 151123992Ssobomax if (m->m_len < sizeof(*gip)) { 152123992Ssobomax m = m_pullup(m, sizeof(*gip)); 153123992Ssobomax if (m == NULL) 154123992Ssobomax return (ENOBUFS); 155123992Ssobomax } 156123992Ssobomax gip = mtod(m, struct greip *); 157123992Ssobomax 158103026Ssobomax sc->sc_if.if_ipackets++; 159103026Ssobomax sc->sc_if.if_ibytes += m->m_pkthdr.len; 160103026Ssobomax 161103026Ssobomax switch (proto) { 162103026Ssobomax case IPPROTO_GRE: 163123992Ssobomax hlen += sizeof(struct gre_h); 164103026Ssobomax 165103026Ssobomax /* process GRE flags as packet can be of variable len */ 166103026Ssobomax flags = ntohs(gip->gi_flags); 167103026Ssobomax 168103026Ssobomax /* Checksum & Offset are present */ 169103026Ssobomax if ((flags & GRE_CP) | (flags & GRE_RP)) 170103026Ssobomax hlen += 4; 171103026Ssobomax /* We don't support routing fields (variable length) */ 172103026Ssobomax if (flags & GRE_RP) 173123992Ssobomax return (0); 174103026Ssobomax if (flags & GRE_KP) 175103026Ssobomax hlen += 4; 176103026Ssobomax if (flags & GRE_SP) 177123992Ssobomax hlen += 4; 178103026Ssobomax 179103026Ssobomax switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 180125024Ssobomax case WCCP_PROTOCOL_TYPE: 181125024Ssobomax if (sc->wccp_ver == WCCP_V2) 182125024Ssobomax hlen += 4; 183125024Ssobomax /* FALLTHROUGH */ 184125024Ssobomax case ETHERTYPE_IP: /* shouldn't need a schednetisr(), */ 185125024Ssobomax isr = NETISR_IP;/* as we are in ip_input */ 186103026Ssobomax break; 187103026Ssobomax#ifdef NETATALK 188103026Ssobomax case ETHERTYPE_ATALK: 189111888Sjlemon isr = NETISR_ATALK1; 190103026Ssobomax break; 191103026Ssobomax#endif 192103026Ssobomax case ETHERTYPE_IPV6: 193103026Ssobomax /* FALLTHROUGH */ 194103026Ssobomax default: /* others not yet supported */ 195123992Ssobomax return (0); 196103026Ssobomax } 197103026Ssobomax break; 198103026Ssobomax default: 199103026Ssobomax /* others not yet supported */ 200123992Ssobomax return (0); 201103026Ssobomax } 202103026Ssobomax 203123992Ssobomax if (hlen > m->m_pkthdr.len) { 204123992Ssobomax m_freem(m); 205123992Ssobomax return (EINVAL); 206123992Ssobomax } 207125226Ssobomax /* Unlike NetBSD, in FreeBSD m_adj() adjusts m->m_pkthdr.len as well */ 208123992Ssobomax m_adj(m, hlen); 209103026Ssobomax 210103026Ssobomax if (sc->sc_if.if_bpf) { 211103026Ssobomax u_int32_t af = AF_INET; 212123922Ssam bpf_mtap2(sc->sc_if.if_bpf, &af, sizeof(af), m); 213104366Ssobomax } 214103026Ssobomax 215103026Ssobomax m->m_pkthdr.rcvif = &sc->sc_if; 216103026Ssobomax 217111888Sjlemon netisr_dispatch(isr, m); 218103026Ssobomax 219123992Ssobomax return (1); /* packet is done, no further processing needed */ 220103026Ssobomax} 221103026Ssobomax 222103026Ssobomax/* 223103026Ssobomax * input routine for IPPRPOTO_MOBILE 224103026Ssobomax * This is a little bit diffrent from the other modes, as the 225103026Ssobomax * encapsulating header was not prepended, but instead inserted 226103026Ssobomax * between IP header and payload 227103026Ssobomax */ 228103026Ssobomax 229103026Ssobomaxvoid 230103026Ssobomax#if __STDC__ 231103026Ssobomaxgre_mobile_input(struct mbuf *m, ...) 232103026Ssobomax#else 233103026Ssobomaxgre_mobile_input(m, va_alist) 234103026Ssobomax struct mbuf *m; 235103026Ssobomax va_dcl 236103026Ssobomax#endif 237103026Ssobomax{ 238123992Ssobomax struct ip *ip; 239123992Ssobomax struct mobip_h *mip; 240103026Ssobomax struct gre_softc *sc; 241111888Sjlemon int hlen; 242103026Ssobomax va_list ap; 243103026Ssobomax int msiz; 244103026Ssobomax 245123992Ssobomax va_start(ap, m); 246103026Ssobomax hlen = va_arg(ap, int); 247103026Ssobomax va_end(ap); 248103026Ssobomax 249103026Ssobomax if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 250103026Ssobomax /* No matching tunnel or tunnel is down. */ 251103026Ssobomax m_freem(m); 252103026Ssobomax return; 253103026Ssobomax } 254103026Ssobomax 255123992Ssobomax if (m->m_len < sizeof(*mip)) { 256123992Ssobomax m = m_pullup(m, sizeof(*mip)); 257123992Ssobomax if (m == NULL) 258123992Ssobomax return; 259123992Ssobomax } 260123992Ssobomax ip = mtod(m, struct ip *); 261123992Ssobomax mip = mtod(m, struct mobip_h *); 262123992Ssobomax 263103026Ssobomax sc->sc_if.if_ipackets++; 264103026Ssobomax sc->sc_if.if_ibytes += m->m_pkthdr.len; 265103026Ssobomax 266123992Ssobomax if (ntohs(mip->mh.proto) & MOB_H_SBIT) { 267103026Ssobomax msiz = MOB_H_SIZ_L; 268103026Ssobomax mip->mi.ip_src.s_addr = mip->mh.osrc; 269123992Ssobomax } else 270103026Ssobomax msiz = MOB_H_SIZ_S; 271123992Ssobomax 272123992Ssobomax if (m->m_len < (ip->ip_hl << 2) + msiz) { 273123992Ssobomax m = m_pullup(m, (ip->ip_hl << 2) + msiz); 274123992Ssobomax if (m == NULL) 275123992Ssobomax return; 276123992Ssobomax ip = mtod(m, struct ip *); 277123992Ssobomax mip = mtod(m, struct mobip_h *); 278103026Ssobomax } 279123992Ssobomax 280103026Ssobomax mip->mi.ip_dst.s_addr = mip->mh.odst; 281103026Ssobomax mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 282103026Ssobomax 283123992Ssobomax if (gre_in_cksum((u_int16_t *)&mip->mh, msiz) != 0) { 284103026Ssobomax m_freem(m); 285103026Ssobomax return; 286103026Ssobomax } 287103026Ssobomax 288103026Ssobomax bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 289103026Ssobomax (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 290103026Ssobomax m->m_len -= msiz; 291103026Ssobomax m->m_pkthdr.len -= msiz; 292103026Ssobomax 293103026Ssobomax /* 294103026Ssobomax * On FreeBSD, rip_input() supplies us with ip->ip_len 295103026Ssobomax * already converted into host byteorder and also decreases 296103026Ssobomax * it by the lengh of IP header, however, ip_input() expects 297103026Ssobomax * that this field is in the original format (network byteorder 298103026Ssobomax * and full size of IP packet), so that adjust accordingly. 299103026Ssobomax */ 300103026Ssobomax ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 301125020Ssobomax 302103026Ssobomax ip->ip_sum = 0; 303103026Ssobomax ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 304103026Ssobomax 305103026Ssobomax if (sc->sc_if.if_bpf) { 306123922Ssam u_int32_t af = AF_INET; 307123922Ssam bpf_mtap2(sc->sc_if.if_bpf, &af, sizeof(af), m); 308104366Ssobomax } 309103026Ssobomax 310103026Ssobomax m->m_pkthdr.rcvif = &sc->sc_if; 311103026Ssobomax 312111888Sjlemon netisr_dispatch(NETISR_IP, m); 313103026Ssobomax} 314103026Ssobomax 315103026Ssobomax/* 316103026Ssobomax * Find the gre interface associated with our src/dst/proto set. 317103026Ssobomax */ 318103032Ssobomaxstatic struct gre_softc * 319103026Ssobomaxgre_lookup(m, proto) 320103026Ssobomax struct mbuf *m; 321103026Ssobomax u_int8_t proto; 322103026Ssobomax{ 323103026Ssobomax struct ip *ip = mtod(m, struct ip *); 324103026Ssobomax struct gre_softc *sc; 325103026Ssobomax 326103026Ssobomax for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 327103026Ssobomax sc = LIST_NEXT(sc, sc_list)) { 328103026Ssobomax if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 329103026Ssobomax (sc->g_src.s_addr == ip->ip_dst.s_addr) && 330103026Ssobomax (sc->g_proto == proto) && 331103026Ssobomax ((sc->sc_if.if_flags & IFF_UP) != 0)) 332103026Ssobomax return (sc); 333103026Ssobomax } 334103026Ssobomax 335103026Ssobomax return (NULL); 336103026Ssobomax} 337