1 /* $OpenBSD: ip_gre.c,v 1.11 2001/06/19 00:48:23 deraadt 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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 /* 41 * decapsulate tunneled packets and send them on 42 * output half is in net/if_gre.[ch] 43 * This currently handles IPPROTO_GRE, IPPROTO_MOBILE 44 */ 45 46 47 #include "gre.h" 48 #if NGRE > 0 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/mbuf.h> 53 #include <sys/socket.h> 54 #include <sys/sysctl.h> 55 #include <net/if.h> 56 #include <net/netisr.h> 57 #include <net/route.h> 58 #include <net/bpf.h> 59 60 #ifdef INET 61 #include <netinet/in.h> 62 #include <netinet/in_var.h> 63 #include <netinet/in_systm.h> 64 #include <netinet/ip.h> 65 #include <netinet/ip_gre.h> 66 #include <netinet/if_ether.h> 67 #else 68 #error "ip_gre used without inet" 69 #endif 70 71 #ifdef NS 72 #include <netns/ns.h> 73 #include <netns/ns_if.h> 74 #endif 75 76 #ifdef NETATALK 77 #include <netatalk/at.h> 78 #include <netatalk/at_var.h> 79 #include <netatalk/at_extern.h> 80 #endif 81 82 #include "bpfilter.h" 83 84 /* Needs IP headers. */ 85 #include <net/if_gre.h> 86 87 struct gre_softc *gre_lookup __P((struct mbuf *, u_int8_t)); 88 static int gre_input2 __P((struct mbuf *, int, u_char)); 89 90 /* 91 * Decapsulate. 92 * Does the real work and is called from gre_input() (above) 93 * returns 0 if packet is not yet processed 94 * and 1 if it needs no further processing 95 * proto is the protocol number of the "calling" foo_input() 96 * routine. 97 */ 98 99 static int 100 gre_input2(m , hlen, proto) 101 struct mbuf *m; 102 int hlen; 103 u_char proto; 104 { 105 register struct greip *gip = mtod(m, struct greip *); 106 register int s; 107 register struct ifqueue *ifq; 108 struct gre_softc *sc; 109 u_short flags; 110 u_int af; 111 112 if ((sc = gre_lookup(m, proto)) == NULL) { 113 /* No matching tunnel or tunnel is down. */ 114 return (0); 115 } 116 117 m->m_pkthdr.rcvif = &sc->sc_if; 118 119 sc->sc_if.if_ipackets++; 120 sc->sc_if.if_ibytes += m->m_pkthdr.len; 121 122 switch (proto) { 123 case IPPROTO_GRE: 124 hlen += sizeof (struct gre_h); 125 126 /* process GRE flags as packet can be of variable len */ 127 flags = ntohs(gip->gi_flags); 128 129 /* Checksum & Offset are present */ 130 if ((flags & GRE_CP) | (flags & GRE_RP)) 131 hlen += 4; 132 133 /* We don't support routing fields (variable length) */ 134 if (flags & GRE_RP) 135 return (0); 136 137 if (flags & GRE_KP) 138 hlen += 4; 139 140 if (flags & GRE_SP) 141 hlen += 4; 142 143 switch (ntohs(gip->gi_ptype)) { /* ethertypes */ 144 case ETHERTYPE_IP: /* shouldn't need a schednetisr(), as */ 145 ifq = &ipintrq; /* we are in ip_input */ 146 af = AF_INET; 147 break; 148 #ifdef NS 149 case ETHERTYPE_NS: 150 ifq = &nsintrq; 151 schednetisr(NETISR_NS); 152 af = AF_NS; 153 break; 154 #endif 155 #ifdef NETATALK 156 case ETHERTYPE_AT: 157 ifq = &atintrq1; 158 schednetisr(NETISR_ATALK); 159 af = AF_APPLETALK; 160 break; 161 #endif 162 #ifdef INET6 163 case ETHERTYPE_IPV6: 164 ifq = &ip6intrq; 165 schednetisr(NETISR_IPV6); 166 af = AF_INET6; 167 break; 168 #endif /* INET6 */ 169 default: /* others not yet supported */ 170 return (0); 171 } 172 break; 173 default: 174 /* others not yet supported */ 175 return(0); 176 } 177 178 m->m_data += hlen; 179 m->m_len -= hlen; 180 m->m_pkthdr.len -= hlen; 181 182 #if NBPFILTER > 0 183 if (sc->sc_if.if_bpf) { 184 /* 185 * We need to prepend the address family as 186 * a four byte field. Cons up a fake header 187 * to pacify bpf. This is safe because bpf 188 * will only read from the mbuf (i.e., it won't 189 * try to free it or keep a pointer a to it). 190 */ 191 struct mbuf m0; 192 193 m0.m_next = m; 194 m0.m_len = 4; 195 m0.m_data = (char *) ⁡ 196 197 bpf_mtap(sc->sc_if.if_bpf, &m0); 198 } 199 #endif 200 201 s = splimp(); /* possible */ 202 if (IF_QFULL(ifq)) { 203 IF_DROP(ifq); 204 m_freem(m); 205 } else { 206 IF_ENQUEUE(ifq, m); 207 } 208 splx(s); 209 210 return (1); /* packet is done, no further processing needed */ 211 } 212 213 /* 214 * Decapsulate a packet and feed it back through ip_input (this 215 * routine is called whenever IP gets a packet with proto type 216 * IPPROTO_GRE and a local destination address). 217 */ 218 void 219 #if __STDC__ 220 gre_input(struct mbuf *m, ...) 221 #else 222 gre_input(m, va_alist) 223 struct mbuf *m; 224 va_dcl 225 #endif 226 { 227 register int hlen,ret; 228 va_list ap; 229 230 va_start(ap, m); 231 hlen = va_arg(ap, int); 232 va_end(ap); 233 234 if (!gre_allow) { 235 m_freem(m); 236 return; 237 } 238 239 ret = gre_input2(m, hlen, IPPROTO_GRE); 240 /* 241 * ret == 0: packet not processed, but input from here 242 * means no matching tunnel that is up is found, 243 * so we can just free the mbuf and return 244 */ 245 if (!ret) 246 m_freem(m); 247 } 248 249 /* 250 * Input routine for IPPRPOTO_MOBILE. 251 * This is a little bit diffrent from the other modes, as the 252 * encapsulating header was not prepended, but instead inserted 253 * between IP header and payload. 254 */ 255 256 void 257 #if __STDC__ 258 gre_mobile_input(struct mbuf *m, ...) 259 #else 260 gre_mobile_input(m, va_alist) 261 struct mbuf *m; 262 va_dcl 263 #endif 264 { 265 register struct ip *ip = mtod(m, struct ip *); 266 register struct mobip_h *mip = mtod(m, struct mobip_h *); 267 register struct ifqueue *ifq; 268 struct gre_softc *sc; 269 register int hlen,s; 270 va_list ap; 271 u_char osrc = 0; 272 int msiz; 273 u_int af = AF_INET; 274 275 va_start(ap,m); 276 hlen = va_arg(ap, int); 277 va_end(ap); 278 279 if (!ip_mobile_allow) { 280 m_freem(m); 281 return; 282 } 283 284 if ((sc = gre_lookup(m, IPPROTO_MOBILE)) == NULL) { 285 /* No matching tunnel or tunnel is down. */ 286 m_freem(m); 287 return; 288 } 289 290 m->m_pkthdr.rcvif = &sc->sc_if; 291 292 sc->sc_if.if_ipackets++; 293 sc->sc_if.if_ibytes += m->m_pkthdr.len; 294 295 if(ntohs(mip->mh.proto) & MOB_H_SBIT) { 296 osrc = 1; 297 msiz = MOB_H_SIZ_L; 298 mip->mi.ip_src.s_addr = mip->mh.osrc; 299 } else { 300 msiz = MOB_H_SIZ_S; 301 } 302 mip->mi.ip_dst.s_addr = mip->mh.odst; 303 mip->mi.ip_p = (ntohs(mip->mh.proto) >> 8); 304 305 if (gre_in_cksum((u_short*) &mip->mh,msiz) != 0) { 306 m_freem(m); 307 return; 308 } 309 310 bcopy(ip + (ip->ip_hl << 2) + msiz, ip + (ip->ip_hl << 2), 311 m->m_len - msiz - (ip->ip_hl << 2)); 312 313 m->m_len -= msiz; 314 ip->ip_len -= msiz; 315 HTONS(ip->ip_len); 316 m->m_pkthdr.len -= msiz; 317 318 ip->ip_sum = 0; 319 ip->ip_sum = in_cksum(m,(ip->ip_hl << 2)); 320 321 ifq = &ipintrq; 322 323 #if NBPFILTER > 0 324 if (sc->sc_if.if_bpf) { 325 /* 326 * We need to prepend the address family as 327 * a four byte field. Cons up a fake header 328 * to pacify bpf. This is safe because bpf 329 * will only read from the mbuf (i.e., it won't 330 * try to free it or keep a pointer a to it). 331 */ 332 struct mbuf m0; 333 334 m0.m_next = m; 335 m0.m_len = 4; 336 m0.m_data = (char *) ⁡ 337 338 bpf_mtap(sc->sc_if.if_bpf, &m0); 339 } 340 #endif 341 342 s = splimp(); /* possible */ 343 if (IF_QFULL(ifq)) { 344 IF_DROP(ifq); 345 m_freem(m); 346 } else { 347 IF_ENQUEUE(ifq, m); 348 } 349 splx(s); 350 } 351 352 /* 353 * Find the gre interface associated with our src/dst/proto set. 354 */ 355 struct gre_softc * 356 gre_lookup(m, proto) 357 struct mbuf *m; 358 u_int8_t proto; 359 { 360 struct ip *ip = mtod(m, struct ip *); 361 struct gre_softc *sc; 362 int i; 363 364 for (i = 0, sc = gre; i < ngre; i++, sc++) { 365 if ((sc->g_dst.s_addr == ip->ip_src.s_addr) && 366 (sc->g_src.s_addr == ip->ip_dst.s_addr) && 367 (sc->g_proto == proto) && 368 ((sc->sc_if.if_flags & IFF_UP) != 0)) 369 return (sc); 370 } 371 372 return (NULL); 373 } 374 375 int 376 gre_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 377 int *name; 378 u_int namelen; 379 void *oldp; 380 size_t *oldlenp; 381 void *newp; 382 size_t newlen; 383 { 384 /* All sysctl names at this level are terminal. */ 385 if (namelen != 1) 386 return (ENOTDIR); 387 388 switch (name[0]) { 389 case GRECTL_ALLOW: 390 return (sysctl_int(oldp, oldlenp, newp, newlen, &gre_allow)); 391 default: 392 return (ENOPROTOOPT); 393 } 394 /* NOTREACHED */ 395 } 396 397 int 398 ipmobile_sysctl(name, namelen, oldp, oldlenp, newp, newlen) 399 int *name; 400 u_int namelen; 401 void *oldp; 402 size_t *oldlenp; 403 void *newp; 404 size_t newlen; 405 { 406 /* All sysctl names at this level are terminal. */ 407 if (namelen != 1) 408 return (ENOTDIR); 409 410 switch (name[0]) { 411 case MOBILEIPCTL_ALLOW: 412 return (sysctl_int(oldp, oldlenp, newp, newlen, 413 &ip_mobile_allow)); 414 default: 415 return (ENOPROTOOPT); 416 } 417 /* NOTREACHED */ 418 } 419 #endif /* if NGRE > 0 */ 420