1 /* $OpenBSD: ip_gre.c,v 1.32 2008/06/26 05:42:20 ray Exp $ */ 2 /* $NetBSD: ip_gre.c,v 1.9 1999/10/25 19:18:11 drochner Exp $ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Heiko W.Rupp <hwr@pilhuhn.de> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * decapsulate tunneled packets and send them on 35 * output half is in net/if_gre.[ch] 36 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 37 */ 38 39 40 #include "gre.h" 41 #if NGRE > 0 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/mbuf.h> 46 #include <sys/socket.h> 47 #include <sys/sysctl.h> 48 #include <net/if.h> 49 #include <net/netisr.h> 50 #include <net/route.h> 51 #include <net/bpf.h> 52 53 #ifdef INET 54 #include <netinet/in.h> 55 #include <netinet/in_var.h> 56 #include <netinet/in_systm.h> 57 #include <netinet/ip.h> 58 #include <netinet/ip_var.h> 59 #include <netinet/ip_gre.h> 60 #include <netinet/if_ether.h> 61 #else 62 #error "ip_gre used without inet" 63 #endif 64 65 #ifdef NETATALK 66 #include <netatalk/at.h> 67 #include <netatalk/at_var.h> 68 #include <netatalk/at_extern.h> 69 #endif 70 71 #include "bpfilter.h" 72 73 /* Needs IP headers. */ 74 #include <net/if_gre.h> 75 76 struct gre_softc *gre_lookup(struct mbuf *, u_int8_t); 77 int gre_input2(struct mbuf *, int, u_char); 78 79 /* 80 * Decapsulate. 81 * Does the real work and is called from gre_input() (above) 82 * returns 0 if packet is not yet processed 83 * and 1 if it needs no further processing 84 * proto is the protocol number of the "calling" foo_input() 85 * routine. 86 */ 87 88 int 89 gre_input2(m , hlen, proto) 90 struct mbuf *m; 91 int hlen; 92 u_char proto; 93 { 94 struct greip *gip; 95 int s; 96 struct ifqueue *ifq; 97 struct gre_softc *sc; 98 u_short flags; 99 u_int af; 100 101 if ((sc = gre_lookup(m, proto)) == NULL) { 102 /* No matching tunnel or tunnel is down. */ 103 return (0); 104 } 105 106 if (m->m_len < sizeof(*gip)) { 107 m = m_pullup(m, sizeof(*gip)); 108 if (m == NULL) 109 return (ENOBUFS); 110 } 111 gip = mtod(m, struct greip *); 112 113 m->m_pkthdr.rcvif = &sc->sc_if; 114 115 sc->sc_if.if_ipackets++; 116 sc->sc_if.if_ibytes += m->m_pkthdr.len; 117 118 switch (proto) { 119 case IPPROTO_GRE: 120 hlen += sizeof (struct gre_h); 121 122 /* process GRE flags as packet can be of variable len */ 123 flags = ntohs(gip->gi_flags); 124 125 /* Checksum & Offset are present */ 126 if ((flags & GRE_CP) | (flags & GRE_RP)) 127 hlen += 4; 128 129 /* We don't support routing fields (variable length) */ 130 if (flags & GRE_RP) 131 return (0); 132 133 if (flags & GRE_KP) 134 hlen += 4; 135 136 if (flags & GRE_SP) 137 hlen += 4; 138 139 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 140 case GREPROTO_WCCP: 141 /* WCCP/GRE: 142 * So far as I can see (and test) it seems that Cisco's WCCP 143 * GRE tunnel is precisely a IP-in-GRE tunnel that differs 144 * only in its protocol number. At least, it works for me. 145 * 146 * The Internet Draft can be found if you look for 147 * draft-forster-wrec-wccp-v1-00.txt 148 * 149 * So yes, we're doing a fall-through (unless, of course, 150 * net.inet.gre.wccp is 0). 151 */ 152 if (!gre_wccp) 153 return (0); 154 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 155 ifq = &ipintrq; /* we are in ip_input */ 156 af = AF_INET; 157 break; 158 #ifdef NETATALK 159 case ETHERTYPE_AT: 160 ifq = &atintrq1; 161 schednetisr(NETISR_ATALK); 162 af = AF_APPLETALK; 163 break; 164 #endif 165 #ifdef INET6 166 case ETHERTYPE_IPV6: 167 ifq = &ip6intrq; 168 schednetisr(NETISR_IPV6); 169 af = AF_INET6; 170 break; 171 #endif /* INET6 */ 172 default: /* others not yet supported */ 173 return (0); 174 } 175 break; 176 default: 177 /* others not yet supported */ 178 return (0); 179 } 180 181 if (hlen > m->m_pkthdr.len) { 182 m_freem(m); 183 return (EINVAL); 184 } 185 m_adj(m, hlen); 186 187 #if NBPFILTER > 0 188 if (sc->sc_if.if_bpf) 189 bpf_mtap_af(sc->sc_if.if_bpf, af, m, BPF_DIRECTION_IN); 190 #endif 191 192 s = splnet(); /* possible */ 193 IF_INPUT_ENQUEUE(ifq, m); 194 splx(s); 195 196 return (1); /* packet is done, no further processing needed */ 197 } 198 199 /* 200 * Decapsulate a packet and feed it back through ip_input (this 201 * routine is called whenever IP gets a packet with proto type 202 * IPPROTO_GRE and a local destination address). 203 */ 204 void 205 gre_input(struct mbuf *m, ...) 206 { 207 int hlen, ret; 208 va_list ap; 209 210 va_start(ap, m); 211 hlen = va_arg(ap, int); 212 va_end(ap); 213 214 if (!gre_allow) { 215 m_freem(m); 216 return; 217 } 218 219 ret = gre_input2(m, hlen, IPPROTO_GRE); 220 /* 221 * ret == 0: packet not processed, but input from here 222 * means no matching tunnel that is up is found. 223 * we inject it to raw ip socket to see if anyone picks it up. 224 * possible that we received a WCCPv1-style GRE packet 225 * but we're not set to accept them. 226 */ 227 if (!ret) 228 rip_input(m, hlen, IPPROTO_GRE); 229 } 230 231 /* 232 * Input routine for IPPRPOTO_MOBILE. 233 * This is a little bit diffrent from the other modes, as the 234 * encapsulating header was not prepended, but instead inserted 235 * between IP header and payload. 236 */ 237 238 void 239 gre_mobile_input(struct mbuf *m, ...) 240 { 241 struct ip *ip; 242 struct mobip_h *mip; 243 struct ifqueue *ifq; 244 struct gre_softc *sc; 245 int hlen, s; 246 va_list ap; 247 u_char osrc = 0; 248 int msiz; 249 250 va_start(ap, m); 251 hlen = va_arg(ap, int); 252 va_end(ap); 253 254 if (!ip_mobile_allow) { 255 m_freem(m); 256 return; 257 } 258 259 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 260 /* No matching tunnel or tunnel is down. */ 261 m_freem(m); 262 return; 263 } 264 265 if (m->m_len < sizeof(*mip)) { 266 m = m_pullup(m, sizeof(*mip)); 267 if (m == NULL) 268 return; 269 } 270 ip = mtod(m, struct ip *); 271 mip = mtod(m, struct mobip_h *); 272 273 m->m_pkthdr.rcvif = &sc->sc_if; 274 275 sc->sc_if.if_ipackets++; 276 sc->sc_if.if_ibytes += m->m_pkthdr.len; 277 278 if (ntohs(mip->mh.proto) & MOB_H_SBIT) { 279 osrc = 1; 280 msiz = MOB_H_SIZ_L; 281 mip->mi.ip_src.s_addr = mip->mh.osrc; 282 } else 283 msiz = MOB_H_SIZ_S; 284 285 if (m->m_len < (ip->ip_hl << 2) + msiz) { 286 m = m_pullup(m, (ip->ip_hl << 2) + msiz); 287 if (m == NULL) 288 return; 289 ip = mtod(m, struct ip *); 290 mip = mtod(m, struct mobip_h *); 291 } 292 293 mip->mi.ip_dst.s_addr = mip->mh.odst; 294 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 295 296 if (gre_in_cksum((u_short *) &mip->mh, msiz) != 0) { 297 m_freem(m); 298 return; 299 } 300 301 bcopy(ip + (ip->ip_hl << 2) + msiz, ip + (ip->ip_hl << 2), 302 m->m_len - msiz - (ip->ip_hl << 2)); 303 304 m->m_len -= msiz; 305 ip->ip_len = htons(ntohs(ip->ip_len) - msiz); 306 m->m_pkthdr.len -= msiz; 307 308 ip->ip_sum = 0; 309 ip->ip_sum = in_cksum(m,(ip->ip_hl << 2)); 310 311 ifq = &ipintrq; 312 313 #if NBPFILTER > 0 314 if (sc->sc_if.if_bpf) 315 bpf_mtap_af(sc->sc_if.if_bpf, AF_INET, m, BPF_DIRECTION_IN); 316 #endif 317 318 s = splnet(); /* possible */ 319 IF_INPUT_ENQUEUE(ifq, m); 320 splx(s); 321 } 322 323 /* 324 * Find the gre interface associated with our src/dst/proto set. 325 */ 326 struct gre_softc * 327 gre_lookup(m, proto) 328 struct mbuf *m; 329 u_int8_t proto; 330 { 331 struct ip *ip = mtod(m, struct ip *); 332 struct gre_softc *sc; 333 334 LIST_FOREACH(sc, &gre_softc_list, sc_list) { 335 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 336 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 337 (sc->g_proto == proto) && 338 ((sc->sc_if.if_flags & IFF_UP) != 0)) 339 return (sc); 340 } 341 342 return (NULL); 343 } 344 345 int 346 gre_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 347 int *name; 348 u_int namelen; 349 void *oldp; 350 size_t *oldlenp; 351 void *newp; 352 size_t newlen; 353 { 354 /* All sysctl names at this level are terminal. */ 355 if (namelen != 1) 356 return (ENOTDIR); 357 358 switch (name[0]) { 359 case GRECTL_ALLOW: 360 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_allow)); 361 case GRECTL_WCCP: 362 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_wccp)); 363 default: 364 return (ENOPROTOOPT); 365 } 366 /* NOTREACHED */ 367 } 368 369 int 370 ipmobile_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 371 int *name; 372 u_int namelen; 373 void *oldp; 374 size_t *oldlenp; 375 void *newp; 376 size_t newlen; 377 { 378 /* All sysctl names at this level are terminal. */ 379 if (namelen != 1) 380 return (ENOTDIR); 381 382 switch (name[0]) { 383 case MOBILEIPCTL_ALLOW: 384 return (sysctl_int(oldp, oldlenp, newp, newlen, 385 &ip_mobile_allow)); 386 default: 387 return (ENOPROTOOPT); 388 } 389 /* NOTREACHED */ 390 } 391 #endif /* if NGRE > 0 */ 392