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