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