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