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