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 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/mbuf.h> 50 #include <sys/socket.h> 51 #include <sys/socketvar.h> 52 #include <sys/protosw.h> 53 #include <sys/errno.h> 54 #include <sys/time.h> 55 #include <sys/kernel.h> 56 #include <sys/syslog.h> 57 #include <sys/in_cksum.h> 58 #include <net/bpf.h> 59 #include <net/ethernet.h> 60 #include <net/if.h> 61 #include <net/netisr.h> 62 #include <net/route.h> 63 #include <net/raw_cb.h> 64 65 #ifdef INET 66 #include <netinet/in.h> 67 #include <netinet/in_var.h> 68 #include <netinet/in_systm.h> 69 #include <netinet/ip.h> 70 #include <netinet/ip_var.h> 71 #include <netinet/ip_gre.h> 72 #else 73 #error ip_gre input without IP? 74 #endif 75 76 /* Needs IP headers. */ 77 #include <net/gre/if_gre.h> 78 79 #include <machine/stdarg.h> 80 81 #if 1 82 void gre_inet_ntoa(struct in_addr in); /* XXX */ 83 #endif 84 85 static struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 86 87 static int gre_input2(struct mbuf *, int, u_char); 88 89 /* 90 * De-encapsulate a packet and feed it back through ip input (this 91 * routine is called whenever IP gets a packet with proto type 92 * IPPROTO_GRE and a local destination address). 93 * This really is simple 94 */ 95 int 96 gre_input(struct mbuf **mp, int *offp, int proto) 97 { 98 struct mbuf *m; 99 int ret, off; 100 101 off = *offp; 102 m = *mp; 103 *mp = NULL; 104 105 proto = (mtod(m, struct ip *))->ip_p; 106 107 ret = gre_input2(m, off, proto); 108 /* 109 * ret == 0 : packet not processed, meaning that 110 * no matching tunnel that is up is found. 111 * we inject it to raw ip socket to see if anyone picks it up. 112 */ 113 if (ret == 0) { 114 *mp = m; 115 rip_input(mp, offp, proto); 116 } 117 return(IPPROTO_DONE); 118 } 119 120 /* 121 * decapsulate. 122 * Does the real work and is called from gre_input() (above) 123 * returns 0 if packet is not yet processed 124 * and 1 if it needs no further processing 125 * proto is the protocol number of the "calling" foo_input() 126 * routine. 127 */ 128 129 static int 130 gre_input2(struct mbuf *m ,int hlen, u_char proto) 131 { 132 static const uint32_t af = AF_INET; 133 struct greip *gip = mtod(m, struct greip *); 134 int isr; 135 struct gre_softc *sc; 136 u_short flags; 137 138 if ((sc = gre_lookup(m, proto)) == NULL) { 139 /* No matching tunnel or tunnel is down. */ 140 return (0); 141 } 142 143 IFNET_STAT_INC(&sc->sc_if, ipackets, 1); 144 IFNET_STAT_INC(&sc->sc_if, ibytes, m->m_pkthdr.len); 145 146 switch (proto) { 147 case IPPROTO_GRE: 148 hlen += sizeof (struct gre_h); 149 150 /* process GRE flags as packet can be of variable len */ 151 flags = ntohs(gip->gi_flags); 152 153 /* Checksum & Offset are present */ 154 if ((flags & GRE_CP) | (flags & GRE_RP)) 155 hlen += 4; 156 /* We don't support routing fields (variable length) */ 157 if (flags & GRE_RP) 158 return(0); 159 if (flags & GRE_KP) 160 hlen += 4; 161 if (flags & GRE_SP) 162 hlen +=4; 163 164 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 165 case ETHERTYPE_IP: 166 case WCCP_PROTOCOL_TYPE: 167 isr = NETISR_IP; 168 break; 169 case ETHERTYPE_IPV6: 170 /* FALLTHROUGH */ 171 default: /* others not yet supported */ 172 return(0); 173 } 174 break; 175 default: 176 /* others not yet supported */ 177 return(0); 178 } 179 180 m->m_data += hlen; 181 m->m_len -= hlen; 182 m->m_pkthdr.len -= hlen; 183 184 if (sc->sc_if.if_bpf) { 185 bpf_gettoken(); 186 if (sc->sc_if.if_bpf) 187 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); 188 bpf_reltoken(); 189 } 190 191 m->m_pkthdr.rcvif = &sc->sc_if; 192 m->m_flags &= ~M_HASH; 193 netisr_queue(isr, m); 194 return(1); /* packet is done, no further processing needed */ 195 } 196 197 /* 198 * input routine for IPPRPOTO_MOBILE 199 * This is a little bit diffrent from the other modes, as the 200 * encapsulating header was not prepended, but instead inserted 201 * between IP header and payload 202 */ 203 204 int 205 gre_mobile_input(struct mbuf **mp, int *offp, int proto) 206 { 207 static const uint32_t af = AF_INET; 208 struct mbuf *m = *mp; 209 struct ip *ip = mtod(m, struct ip *); 210 struct mobip_h *mip = mtod(m, struct mobip_h *); 211 struct gre_softc *sc; 212 int msiz; 213 214 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 215 /* No matching tunnel or tunnel is down. */ 216 m_freem(m); 217 return(IPPROTO_DONE); 218 } 219 220 IFNET_STAT_INC(&sc->sc_if, ipackets, 1); 221 IFNET_STAT_INC(&sc->sc_if, ibytes, m->m_pkthdr.len); 222 223 if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 224 msiz = MOB_H_SIZ_L; 225 mip->mi.ip_src.s_addr = mip->mh.osrc; 226 } else { 227 msiz = MOB_H_SIZ_S; 228 } 229 mip->mi.ip_dst.s_addr = mip->mh.odst; 230 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 231 232 if (gre_in_cksum((u_short*)&mip->mh,msiz) != 0) { 233 m_freem(m); 234 return(IPPROTO_DONE); 235 } 236 237 bcopy((caddr_t)(ip) + (ip->ip_hl << 2) + msiz, (caddr_t)(ip) + 238 (ip->ip_hl << 2), m->m_len - msiz - (ip->ip_hl << 2)); 239 m->m_len -= msiz; 240 m->m_pkthdr.len -= msiz; 241 242 /* 243 * On FreeBSD, rip_input() supplies us with ip->ip_len 244 * already converted into host byteorder and also decreases 245 * it by the lengh of IP header, however, ip_input() expects 246 * that this field is in the original format (network byteorder 247 * and full size of IP packet), so that adjust accordingly. 248 */ 249 ip->ip_len = htons(ip->ip_len + sizeof(struct ip) - msiz); 250 251 ip->ip_sum = 0; 252 ip->ip_sum = in_cksum(m, (ip->ip_hl << 2)); 253 254 if (sc->sc_if.if_bpf) { 255 bpf_gettoken(); 256 if (sc->sc_if.if_bpf) 257 bpf_ptap(sc->sc_if.if_bpf, m, &af, sizeof(af)); 258 bpf_reltoken(); 259 } 260 261 m->m_pkthdr.rcvif = &sc->sc_if; 262 263 netisr_queue(NETISR_IP, m); 264 return(IPPROTO_DONE); 265 } 266 267 /* 268 * Find the gre interface associated with our src/dst/proto set. 269 */ 270 static struct gre_softc * 271 gre_lookup(struct mbuf *m, u_int8_t proto) 272 { 273 struct ip *ip = mtod(m, struct ip *); 274 struct gre_softc *sc; 275 276 for (sc = LIST_FIRST(&gre_softc_list); sc != NULL; 277 sc = LIST_NEXT(sc, sc_list)) { 278 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 279 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 280 (sc->g_proto == proto) && 281 ((sc->sc_if.if_flags & IFF_UP) != 0)) 282 return (sc); 283 } 284 285 return (NULL); 286 } 287