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