1 /* 2 * $NetBSD: ip_gre.c,v 1.21 2002/08/14 00:23:30 itojun Exp $ 3 * 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Heiko W.Rupp <hwr@pilhuhn.de> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * deencapsulate tunneled packets and send them on 41 * output half is in net/if_gre.[ch] 42 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 43 */ 44 45 #include "opt_inet.h" 46 #include "opt_atalk.h" 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/mbuf.h> 51 #include <sys/socket.h> 52 #include <sys/socketvar.h> 53 #include <sys/protosw.h> 54 #include <sys/errno.h> 55 #include <sys/time.h> 56 #include <sys/kernel.h> 57 #include <sys/syslog.h> 58 #include <sys/in_cksum.h> 59 #include <net/bpf.h> 60 #include <net/ethernet.h> 61 #include <net/if.h> 62 #include <net/netisr.h> 63 #include <net/route.h> 64 #include <net/raw_cb.h> 65 66 #ifdef INET 67 #include <netinet/in.h> 68 #include <netinet/in_var.h> 69 #include <netinet/in_systm.h> 70 #include <netinet/ip.h> 71 #include <netinet/ip_var.h> 72 #include <netinet/ip_gre.h> 73 #else 74 #error ip_gre input without IP? 75 #endif 76 77 #ifdef NETATALK 78 #include <netproto/atalk/at.h> 79 #include <netproto/atalk/at_var.h> 80 #include <netproto/atalk/at_extern.h> 81 #endif 82 83 /* Needs IP headers. */ 84 #include <net/gre/if_gre.h> 85 86 #include <machine/stdarg.h> 87 88 #if 1 89 void gre_inet_ntoa(struct in_addr in); /* XXX */ 90 #endif 91 92 static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 93 94 static int gre_input2(struct mbuf *, int, u_char); 95 96 /* 97 * De-encapsulate a packet and feed it back through ip input (this 98 * routine is called whenever IP gets a packet with proto type 99 * IPPROTO_GRE and a local destination address). 100 * This really is simple 101 */ 102 int 103 gre_input(struct mbuf **mp, int *offp, int proto) 104 { 105 struct mbuf *m; 106 int ret, off; 107 108 off = *offp; 109 m = *mp; 110 *mp = NULL; 111 112 proto = (mtod(m, struct ip *))->ip_p; 113 114 ret = gre_input2(m, off, proto); 115 /* 116 * ret == 0 : packet not processed, meaning that 117 * no matching tunnel that is up is found. 118 * we inject it to raw ip socket to see if anyone picks it up. 119 */ 120 if (ret == 0) { 121 *mp = m; 122 rip_input(mp, offp, proto); 123 } 124 return(IPPROTO_DONE); 125 } 126 127 /* 128 * decapsulate. 129 * Does the real work and is called from gre_input() (above) 130 * returns 0 if packet is not yet processed 131 * and 1 if it needs no further processing 132 * proto is the protocol number of the "calling" foo_input() 133 * routine. 134 */ 135 136 static int 137 gre_input2(struct mbuf *m ,int hlen, u_char proto) 138 { 139 static const uint32_t af = AF_INET; 140 struct greip *gip = mtod(m, struct greip *); 141 int isr; 142 struct gre_softc *sc; 143 u_short flags; 144 145 if ((sc = gre_lookup(m, proto)) == NULL) { 146 /* No matching tunnel or tunnel is down. */ 147 return (0); 148 } 149 150 sc->sc_if.if_ipackets++; 151 sc->sc_if.if_ibytes += m->m_pkthdr.len; 152 153 switch (proto) { 154 case IPPROTO_GRE: 155 hlen += sizeof (struct gre_h); 156 157 /* process GRE flags as packet can be of variable len */ 158 flags = ntohs(gip->gi_flags); 159 160 /* Checksum & Offset are present */ 161 if ((flags & GRE_CP) | (flags & GRE_RP)) 162 hlen += 4; 163 /* We don't support routing fields (variable length) */ 164 if (flags & GRE_RP) 165 return(0); 166 if (flags & GRE_KP) 167 hlen += 4; 168 if (flags & GRE_SP) 169 hlen +=4; 170 171 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 172 case ETHERTYPE_IP: 173 case WCCP_PROTOCOL_TYPE: 174 isr = NETISR_IP; 175 break; 176 #ifdef NETATALK 177 case ETHERTYPE_ATALK: 178 isr = NETISR_ATALK1; 179 break; 180 #endif 181 case ETHERTYPE_IPV6: 182 /* FALLTHROUGH */ 183 default: /* others not yet supported */ 184 return(0); 185 } 186 break; 187 default: 188 /* others not yet supported */ 189 return(0); 190 } 191 192 m->m_data += hlen; 193 m->m_len -= hlen; 194 m->m_pkthdr.len -= hlen; 195 196 if (sc->sc_if.if_bpf) 197 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); 198 199 m->m_pkthdr.rcvif = &sc->sc_if; 200 netisr_queue(isr, m); 201 return(1); /* packet is done, no further processing needed */ 202 } 203 204 /* 205 * input routine for IPPRPOTO_MOBILE 206 * This is a little bit diffrent from the other modes, as the 207 * encapsulating header was not prepended, but instead inserted 208 * between IP header and payload 209 */ 210 211 int 212 gre_mobile_input(struct mbuf **mp, int *offp, int proto) 213 { 214 static const uint32_t af = AF_INET; 215 struct mbuf *m = *mp; 216 struct ip *ip = mtod(m, struct ip *); 217 struct mobip_h *mip = mtod(m, struct mobip_h *); 218 struct gre_softc *sc; 219 u_char osrc = 0; 220 int msiz, hlen; 221 222 hlen = *offp; 223 224 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 225 /* No matching tunnel or tunnel is down. */ 226 m_freem(m); 227 return(IPPROTO_DONE); 228 } 229 230 sc->sc_if.if_ipackets++; 231 sc->sc_if.if_ibytes += m->m_pkthdr.len; 232 233 if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 234 osrc = 1; 235 msiz = MOB_H_SIZ_L; 236 mip->mi.ip_src.s_addr = mip->mh.osrc; 237 } else { 238 msiz = MOB_H_SIZ_S; 239 } 240 mip->mi.ip_dst.s_addr = mip->mh.odst; 241 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 242 243 if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { 244 m_freem(m); 245 return(IPPROTO_DONE); 246 } 247 248 bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 249 (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 250 m->m_len -= msiz; 251 m->m_pkthdr.len -= msiz; 252 253 /* 254 * On FreeBSD, rip_input() supplies us with ip->ip_len 255 * already converted into host byteorder and also decreases 256 * it by the lengh of IP header, however, ip_input() expects 257 * that this field is in the original format (network byteorder 258 * and full size of IP packet), so that adjust accordingly. 259 */ 260 ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 261 262 ip->ip_sum = 0; 263 ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 264 265 if (sc->sc_if.if_bpf) 266 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); 267 268 m->m_pkthdr.rcvif = &sc->sc_if; 269 270 netisr_queue(NETISR_IP, m); 271 return(IPPROTO_DONE); 272 } 273 274 /* 275 * Find the gre interface associated with our src/dst/proto set. 276 */ 277 static struct gre_softc * 278 gre_lookup(struct mbuf *m, u_int8_t proto) 279 { 280 struct ip *ip = mtod(m, struct ip *); 281 struct gre_softc *sc; 282 283 for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 284 sc = LIST_NEXT(sc, sc_list)) { 285 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 286 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 287 (sc->g_proto == proto) && 288 ((sc->sc_if.if_flags & IFF_UP) != 0)) 289 return (sc); 290 } 291 292 return (NULL); 293 } 294