1 /* $NetBSD: if_gre.c,v 1.7 1999/03/12 22:42:31 perry Exp $ */ 2 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 * Encapsulate L3 protocols into IP 41 * See RFC 1701 and 1702 for more details. 42 * If_gre is compatible with Cisco GRE tunnels, so you can 43 * have a NetBSD box as the other end of a tunnel interface of a Cisco 44 * router. See gre(4) for more details. 45 * Also supported: IP in IP encaps (proto 55) as of RFC 2004 46 */ 47 48 #include "gre.h" 49 #if NGRE > 0 50 51 #include "opt_inet.h" 52 #include "bpfilter.h" 53 54 #include <sys/param.h> 55 #include <sys/proc.h> 56 #include <sys/malloc.h> 57 #include <sys/mbuf.h> 58 #include <sys/buf.h> 59 #include <sys/dkstat.h> 60 #include <sys/protosw.h> 61 #include <sys/socket.h> 62 #include <sys/ioctl.h> 63 #include <sys/sockio.h> 64 #include <sys/file.h> 65 #include <sys/tty.h> 66 #include <sys/kernel.h> 67 #include <sys/conf.h> 68 #if __NetBSD__ 69 #include <sys/systm.h> 70 #endif 71 72 #include <machine/cpu.h> 73 74 #include <net/ethertypes.h> 75 #include <net/if.h> 76 #include <net/if_types.h> 77 #include <net/netisr.h> 78 #include <net/route.h> 79 80 #ifdef INET 81 #include <netinet/in.h> 82 #include <netinet/in_systm.h> 83 #include <netinet/in_var.h> 84 #include <netinet/ip.h> 85 #include <netinet/ip_var.h> 86 #else 87 #error "Huh? if_gre without inet?" 88 #endif 89 90 #ifdef NS 91 #include <netns/ns.h> 92 #include <netns/ns_if.h> 93 #endif 94 95 #ifdef NETATALK 96 #include <netatalk/at.h> 97 #include <netatalk/at_var.h> 98 #include <netatalk/at_extern.h> 99 #endif 100 101 #if NBPFILTER > 0 102 #include <sys/time.h> 103 #include <net/bpf.h> 104 #endif 105 106 #include <net/if_gre.h> 107 108 #define GREMTU 1450 /* XXX this is below the standard MTU of 109 1500 Bytes, allowing for headers, 110 but we should possibly do path mtu discovery 111 before changing if state to up to find the 112 correct value */ 113 #define LINK_MASK (IFF_LINK0|IFF_LINK1|IFF_LINK2) 114 115 struct gre_softc gre_softc[NGRE]; 116 117 118 void gre_compute_route(struct gre_softc *sc); 119 #ifdef DIAGNOSTIC 120 void gre_inet_ntoa(struct in_addr in); 121 #endif 122 123 void greattach(void) 124 { 125 126 register struct gre_softc *sc; 127 register int i; 128 129 i = 0 ; 130 for (sc=gre_softc ; i < NGRE; sc++ ) { 131 sprintf(sc->sc_if.if_xname, "gre%d", i++); 132 sc->sc_if.if_softc = sc; 133 sc->sc_if.if_type = IFT_OTHER; 134 sc->sc_if.if_addrlen = 4; 135 sc->sc_if.if_hdrlen = 24; /* IP + GRE */ 136 sc->sc_if.if_mtu = GREMTU; 137 sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST; 138 sc->sc_if.if_output = gre_output; 139 sc->sc_if.if_ioctl = gre_ioctl; 140 sc->sc_if.if_collisions=0; 141 sc->sc_if.if_ierrors=0; 142 sc->sc_if.if_oerrors=0; 143 sc->sc_if.if_ipackets=0; 144 sc->sc_if.if_opackets=0; 145 sc->g_dst.s_addr=sc->g_src.s_addr=INADDR_ANY; 146 sc->g_proto=IPPROTO_GRE; 147 if_attach(&sc->sc_if); 148 #if 0 149 #if NBPFILTER > 0 150 bpfattach(&sc->gre_bpf, &sc->sc_if, DLT_RAW, sizeof(u_int32_t) ); 151 #endif 152 #endif 153 154 } 155 } 156 157 158 /* 159 * The output routine. Takes a packet and encapsulates it in the protocol 160 * given by sc->g_proto. See also RFC 1701 and RFC 2004 161 */ 162 163 struct ip ip_h; 164 struct mobile_h mob_h; 165 166 int 167 gre_output(ifp, m, dst, rt) 168 struct ifnet *ifp; 169 register struct mbuf *m; 170 struct sockaddr *dst; 171 register struct rtentry *rt; 172 { 173 int error=0; 174 struct gre_softc *sc=(struct gre_softc *)(ifp->if_softc); 175 struct greip *gh; 176 struct ip *inp; 177 u_char ttl,osrc; 178 u_short etype=0; 179 180 181 gh=NULL; 182 inp=NULL; 183 osrc=0; 184 185 #if 0 186 #if NBPFILTER >0 187 188 if (sc->gre_bpf) { 189 /* see comment of other if_foo.c files */ 190 struct mbuf m0; 191 u_int af = dst->sa_family; 192 193 m0.m_next =m; 194 m0.m_len =4; 195 m0.m_data = (char *)⁡ 196 197 bpf_mtap(ifp->if_bpf, &m0); 198 } 199 #endif 200 #endif 201 202 ttl=255; 203 204 if (sc->g_proto == IPPROTO_MOBILE) { 205 if (dst->sa_family == AF_INET) { 206 struct mbuf *m0; 207 int msiz; 208 209 inp=mtod(m,struct ip *); 210 211 memset(&mob_h,0,MOB_H_SIZ_L); 212 mob_h.proto=(inp->ip_p)<<8; 213 mob_h.odst=inp->ip_dst.s_addr; 214 inp->ip_dst.s_addr=sc->g_dst.s_addr; 215 216 /* 217 * If the packet comes from our host, we only change the 218 * destination address in the IP header. Else we also need 219 * to save and change the source 220 */ 221 222 if (in_hosteq(inp->ip_src, sc->g_src)) { 223 msiz=MOB_H_SIZ_S; 224 } else { 225 mob_h.proto |= MOB_H_SBIT; 226 mob_h.osrc=inp->ip_src.s_addr; 227 inp->ip_src.s_addr=sc->g_src.s_addr; 228 msiz=MOB_H_SIZ_L; 229 } 230 HTONS(mob_h.proto); 231 mob_h.hcrc=gre_in_cksum((u_short *)&mob_h,msiz); 232 233 if ((m->m_data - msiz) < m->m_pktdat) { 234 /* need new mbuf */ 235 MGETHDR(m0, M_DONTWAIT, MT_HEADER); 236 if (m0==NULL) { 237 IF_DROP(&ifp->if_snd); 238 m_freem(m); 239 return(ENOBUFS); 240 } 241 m0->m_next=m; 242 m->m_data += sizeof(struct ip); 243 m->m_len -= sizeof(struct ip); 244 m0->m_pkthdr.len=m->m_pkthdr.len+msiz; 245 m0->m_len = msiz + sizeof(struct ip); 246 m0->m_data += max_linkhdr; 247 memcpy(mtod(m0, caddr_t), (caddr_t) inp, sizeof(struct ip)); 248 m=m0; 249 } else { /* we have some spave left in the old one */ 250 m->m_data-=msiz; 251 m->m_len+=msiz; 252 m->m_pkthdr.len+=msiz; 253 memmove(mtod(m, caddr_t), inp, sizeof(struct ip)); 254 } 255 inp=mtod(m,struct ip *); 256 memcpy((caddr_t) (inp+1), &mob_h, (unsigned) msiz); 257 NTOHS(inp->ip_len); 258 inp->ip_len+=msiz; 259 } else { /* AF_INET */ 260 IF_DROP(&ifp->if_snd); 261 m_freem(m); 262 return(EINVAL); 263 } 264 } else if (sc->g_proto == IPPROTO_GRE) { 265 switch(dst->sa_family) { 266 case AF_INET: 267 inp=mtod(m,struct ip *); 268 ttl=inp->ip_ttl; 269 etype=ETHERTYPE_IP; 270 break; 271 #ifdef NETATALK 272 case AF_APPLETALK: 273 etype=ETHERTYPE_ATALK; 274 break; 275 #endif 276 #ifdef NS 277 case AF_NS: 278 etype=ETHERTYPE_NS; 279 break; 280 #endif 281 default: 282 IF_DROP(&ifp->if_snd); 283 m_freem(m); 284 return(EAFNOSUPPORT); 285 } 286 M_PREPEND(m,sizeof(struct greip),M_DONTWAIT); 287 } else { 288 error= EINVAL; 289 IF_DROP(&ifp->if_snd); 290 m_freem(m); 291 return(error); 292 } 293 294 295 if (m == NULL) { 296 IF_DROP(&ifp->if_snd); 297 return(ENOBUFS); 298 } 299 300 gh=mtod(m,struct greip *); 301 if (sc->g_proto == IPPROTO_GRE){ 302 /* we don't have any GRE flags for now */ 303 304 memset((void*)&gh->gi_g,0, sizeof(struct gre_h)); 305 gh->gi_ptype=htons(etype); 306 } 307 308 gh->gi_pr = sc->g_proto; 309 if (sc->g_proto != IPPROTO_MOBILE) { 310 gh->gi_src = sc->g_src; 311 gh->gi_dst = sc->g_dst; 312 ((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2; 313 ((struct ip*)gh)->ip_ttl=ttl; 314 ((struct ip*)gh)->ip_tos=inp->ip_tos; 315 gh->gi_len = m->m_pkthdr.len; 316 } 317 318 ifp->if_opackets++; 319 ifp->if_obytes+=m->m_pkthdr.len; 320 /* send it off */ 321 error=ip_output(m,NULL,&sc->route,0,NULL); 322 if (error) { 323 ifp->if_oerrors++; 324 } 325 return(error); 326 327 } 328 329 int 330 gre_ioctl(ifp, cmd, data) 331 struct ifnet *ifp; 332 u_long cmd; 333 caddr_t data; 334 { 335 336 register struct ifaddr *ifa = (struct ifaddr *)data; 337 register struct ifreq *ifr = (struct ifreq *)data; 338 register struct in_ifaddr *ia = (struct in_ifaddr *)data; 339 register struct gre_softc *sc = ifp->if_softc; 340 int s; 341 struct sockaddr_in si; 342 struct sockaddr *sa =NULL; 343 int error; 344 345 error= 0; 346 347 s = splimp(); 348 switch(cmd) { 349 case SIOCSIFADDR: 350 case SIOCSIFDSTADDR: 351 /* 352 * set tunnel endpoints in case that we "only" 353 * have ip over ip encapsulation. This allows to 354 * set tunnel endpoints with ifconfig. 355 */ 356 if (ifa->ifa_addr->sa_family == AF_INET) { 357 sa = ifa->ifa_addr; 358 sc->g_src = (satosin(sa))->sin_addr; 359 sc->g_dst = ia->ia_dstaddr.sin_addr; 360 if ((sc->g_src.s_addr != INADDR_ANY) && 361 (sc->g_dst.s_addr != INADDR_ANY)) { 362 if (sc->route.ro_rt != 0) /* free old route */ 363 RTFREE(sc->route.ro_rt); 364 gre_compute_route(sc); 365 ifp->if_flags |= IFF_UP; 366 } 367 } 368 break; 369 case SIOCSIFFLAGS: 370 if ((sc->g_dst.s_addr== INADDR_ANY) || 371 (sc->g_src.s_addr== INADDR_ANY)) 372 ifp->if_flags &= ~IFF_UP; 373 374 switch(ifr->ifr_flags & LINK_MASK) { 375 case IFF_LINK0: 376 sc->g_proto = IPPROTO_GRE; 377 ifp->if_flags |= IFF_LINK0; 378 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 379 break; 380 case IFF_LINK2: 381 sc->g_proto = IPPROTO_MOBILE; 382 ifp->if_flags |= IFF_LINK2; 383 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1); 384 break; 385 } 386 break; 387 case SIOCSIFMTU: 388 if (ifr->ifr_mtu > GREMTU || ifr->ifr_mtu < 576) { 389 error = EINVAL; 390 break; 391 } 392 ifp->if_mtu = ifr->ifr_mtu; 393 break; 394 case SIOCGIFMTU: 395 ifr->ifr_mtu = sc->sc_if.if_mtu; 396 break; 397 case SIOCADDMULTI: 398 case SIOCDELMULTI: 399 if (ifr == 0 ) { 400 error = EAFNOSUPPORT; 401 break; 402 } 403 switch(ifr->ifr_addr.sa_family) { 404 #ifdef INET 405 case AF_INET: 406 break; 407 #endif 408 default: 409 error = EAFNOSUPPORT; 410 break; 411 } 412 break; 413 case GRESPROTO: 414 sc->g_proto = ifr->ifr_flags; 415 switch (sc->g_proto) { 416 case IPPROTO_GRE : 417 ifp->if_flags |= IFF_LINK0; 418 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 419 break; 420 case IPPROTO_MOBILE : 421 ifp->if_flags |= IFF_LINK2; 422 ifp->if_flags &= ~(IFF_LINK1|IFF_LINK2); 423 break; 424 default: 425 ifp->if_flags &= ~(IFF_LINK0|IFF_LINK1|IFF_LINK2); 426 } 427 break; 428 case GREGPROTO: 429 ifr->ifr_flags = sc->g_proto; 430 break; 431 case GRESADDRS: 432 case GRESADDRD: 433 /* 434 * set tunnel endpoints, compute a less specific route 435 * to the remote end and mark if as up 436 */ 437 sa = &ifr->ifr_addr; 438 if (cmd == GRESADDRS ) 439 sc->g_src = (satosin(sa))->sin_addr; 440 if (cmd == GRESADDRD ) 441 sc->g_dst = (satosin(sa))->sin_addr; 442 if ((sc->g_src.s_addr != INADDR_ANY) && 443 (sc->g_dst.s_addr != INADDR_ANY)) { 444 if (sc->route.ro_rt != 0) /* free old route */ 445 RTFREE(sc->route.ro_rt); 446 gre_compute_route(sc); 447 ifp->if_flags |= IFF_UP; 448 } 449 break; 450 case GREGADDRS: 451 si.sin_addr.s_addr = sc->g_src.s_addr; 452 sa=sintosa(&si); 453 ifr->ifr_addr = *sa; 454 break; 455 case GREGADDRD: 456 si.sin_addr.s_addr = sc->g_dst.s_addr; 457 sa=sintosa(&si); 458 ifr->ifr_addr = *sa; 459 break; 460 default: 461 error = EINVAL; 462 } 463 464 splx(s); 465 return(error); 466 } 467 468 /* 469 * computes a route to our destination that is not the one 470 * which would be taken by ip_output(), as this one will loop back to 471 * us. If the interface is p2p as a--->b, then a routing entry exists 472 * If we now send a packet to b (e.g. ping b), this will come down here 473 * gets src=a, dst=b tacked on and would from ip_ouput() sent back to 474 * if_gre. 475 * Goal here is to compute a route to b that is less specific than 476 * a-->b. We know that this one exists as in normal operation we have 477 * at least a default route which matches. 478 */ 479 480 void gre_compute_route(struct gre_softc *sc) 481 { 482 struct route *ro; 483 u_int32_t a,b,c; 484 485 ro=&sc->route; 486 487 memset(ro,0,sizeof(struct route)); 488 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst; 489 ro->ro_dst.sa_family=AF_INET; 490 ro->ro_dst.sa_len=sizeof(ro->ro_dst); 491 /* 492 * toggle last bit, so our interface is not found, but a less 493 * specific route. I'd rather like to specify a shorter mask, 494 * but this is not possible. Should work though. XXX 495 * there is a simpler way ... 496 */ 497 a= ntohl(sc->g_dst.s_addr); 498 b= a & 0x01; 499 c= a & 0xfffffffe; 500 b = b ^ 0x01; 501 a = b | c; 502 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr=htonl(a); 503 504 #ifdef DIAGNOSTIC 505 printf("%s: searching a route to ",sc->sc_if.if_xname); 506 gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr); 507 #endif 508 509 rtalloc(ro); 510 511 /* 512 * now change it back - else ip_output will just drop 513 * the route and search one to this interface ... 514 */ 515 ((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst; 516 517 #ifdef DIAGNOSTIC 518 printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname); 519 gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr); 520 printf("\n"); 521 #endif 522 } 523 524 /* 525 * do a checksum of a buffer - much like in_cksum, which operates on 526 * mbufs. 527 */ 528 529 u_short 530 gre_in_cksum(p, len) 531 u_short *p; 532 u_int len; 533 { 534 u_int sum = 0; 535 int nwords = len >> 1; 536 537 while (nwords-- != 0) 538 sum += *p++; 539 540 if (len & 1) { 541 union { 542 u_short w; 543 u_char c[2]; 544 } u; 545 u.c[0] = *(u_char *)p; 546 u.c[1] = 0; 547 sum += u.w; 548 } 549 550 /* end-around-carry */ 551 sum = (sum >> 16) + (sum & 0xffff); 552 sum += (sum >> 16); 553 return (~sum); 554 } 555 556 557 /* while testing ... */ 558 #ifdef DIAGNOSTIC 559 void 560 gre_inet_ntoa(in) 561 struct in_addr in; 562 { 563 register char *p; 564 565 p = (char *)∈ 566 #define UC(b) (((int)b)&0xff) 567 printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); 568 } 569 570 #endif 571 #endif 572 573