KNFify. Add LINK1 flag to turn off that address munging thing, for cases
where the tunnel endpoint is not the same as the remote GRE destination.
This commit is contained in:
parent
4ca6c63ecd
commit
12b25faeaf
243
sys/net/if_gre.c
243
sys/net/if_gre.c
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: if_gre.c,v 1.7 1999/03/12 22:42:31 perry Exp $ */
|
||||
/* $NetBSD: if_gre.c,v 1.8 1999/06/28 07:52:38 explorer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 The NetBSD Foundation, Inc.
|
||||
@ -120,14 +120,14 @@ void gre_compute_route(struct gre_softc *sc);
|
||||
void gre_inet_ntoa(struct in_addr in);
|
||||
#endif
|
||||
|
||||
void greattach(void)
|
||||
void
|
||||
greattach(void)
|
||||
{
|
||||
|
||||
register struct gre_softc *sc;
|
||||
register int i;
|
||||
struct gre_softc *sc;
|
||||
int i;
|
||||
|
||||
i = 0 ;
|
||||
for (sc=gre_softc ; i < NGRE; sc++ ) {
|
||||
for (sc = gre_softc ; i < NGRE ; sc++ ) {
|
||||
sprintf(sc->sc_if.if_xname, "gre%d", i++);
|
||||
sc->sc_if.if_softc = sc;
|
||||
sc->sc_if.if_type = IFT_OTHER;
|
||||
@ -137,13 +137,13 @@ void greattach(void)
|
||||
sc->sc_if.if_flags = IFF_POINTOPOINT|IFF_MULTICAST;
|
||||
sc->sc_if.if_output = gre_output;
|
||||
sc->sc_if.if_ioctl = gre_ioctl;
|
||||
sc->sc_if.if_collisions=0;
|
||||
sc->sc_if.if_ierrors=0;
|
||||
sc->sc_if.if_oerrors=0;
|
||||
sc->sc_if.if_ipackets=0;
|
||||
sc->sc_if.if_opackets=0;
|
||||
sc->g_dst.s_addr=sc->g_src.s_addr=INADDR_ANY;
|
||||
sc->g_proto=IPPROTO_GRE;
|
||||
sc->sc_if.if_collisions = 0;
|
||||
sc->sc_if.if_ierrors = 0;
|
||||
sc->sc_if.if_oerrors = 0;
|
||||
sc->sc_if.if_ipackets = 0;
|
||||
sc->sc_if.if_opackets = 0;
|
||||
sc->g_dst.s_addr = sc->g_src.s_addr=INADDR_ANY;
|
||||
sc->g_proto = IPPROTO_GRE;
|
||||
if_attach(&sc->sc_if);
|
||||
#if 0
|
||||
#if NBPFILTER > 0
|
||||
@ -160,27 +160,26 @@ void greattach(void)
|
||||
* given by sc->g_proto. See also RFC 1701 and RFC 2004
|
||||
*/
|
||||
|
||||
#if 0
|
||||
struct ip ip_h;
|
||||
#endif
|
||||
struct mobile_h mob_h;
|
||||
|
||||
int
|
||||
gre_output(ifp, m, dst, rt)
|
||||
struct ifnet *ifp;
|
||||
register struct mbuf *m;
|
||||
struct sockaddr *dst;
|
||||
register struct rtentry *rt;
|
||||
gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
|
||||
struct rtentry *rt)
|
||||
{
|
||||
int error=0;
|
||||
struct gre_softc *sc=(struct gre_softc *)(ifp->if_softc);
|
||||
int error = 0;
|
||||
struct gre_softc *sc = (struct gre_softc *)(ifp->if_softc);
|
||||
struct greip *gh;
|
||||
struct ip *inp;
|
||||
u_char ttl,osrc;
|
||||
u_short etype=0;
|
||||
u_char ttl, osrc;
|
||||
u_short etype = 0;
|
||||
|
||||
|
||||
gh=NULL;
|
||||
inp=NULL;
|
||||
osrc=0;
|
||||
gh = NULL;
|
||||
inp = NULL;
|
||||
osrc = 0;
|
||||
|
||||
#if 0
|
||||
#if NBPFILTER >0
|
||||
@ -190,8 +189,8 @@ gre_output(ifp, m, dst, rt)
|
||||
struct mbuf m0;
|
||||
u_int af = dst->sa_family;
|
||||
|
||||
m0.m_next =m;
|
||||
m0.m_len =4;
|
||||
m0.m_next = m;
|
||||
m0.m_len = 4;
|
||||
m0.m_data = (char *)⁡
|
||||
|
||||
bpf_mtap(ifp->if_bpf, &m0);
|
||||
@ -199,110 +198,111 @@ gre_output(ifp, m, dst, rt)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ttl=255;
|
||||
ttl = 255;
|
||||
|
||||
if (sc->g_proto == IPPROTO_MOBILE) {
|
||||
if (dst->sa_family == AF_INET) {
|
||||
struct mbuf *m0;
|
||||
int msiz;
|
||||
|
||||
inp=mtod(m,struct ip *);
|
||||
inp = mtod(m, struct ip *);
|
||||
|
||||
memset(&mob_h,0,MOB_H_SIZ_L);
|
||||
mob_h.proto=(inp->ip_p)<<8;
|
||||
mob_h.odst=inp->ip_dst.s_addr;
|
||||
inp->ip_dst.s_addr=sc->g_dst.s_addr;
|
||||
memset(&mob_h, 0, MOB_H_SIZ_L);
|
||||
mob_h.proto = (inp->ip_p) << 8;
|
||||
mob_h.odst = inp->ip_dst.s_addr;
|
||||
inp->ip_dst.s_addr = sc->g_dst.s_addr;
|
||||
|
||||
/*
|
||||
* If the packet comes from our host, we only change the
|
||||
* destination address in the IP header. Else we also need
|
||||
* to save and change the source
|
||||
* If the packet comes from our host, we only change
|
||||
* the destination address in the IP header.
|
||||
* Else we also need to save and change the source
|
||||
*/
|
||||
|
||||
if (in_hosteq(inp->ip_src, sc->g_src)) {
|
||||
msiz=MOB_H_SIZ_S;
|
||||
msiz = MOB_H_SIZ_S;
|
||||
} else {
|
||||
mob_h.proto |= MOB_H_SBIT;
|
||||
mob_h.osrc=inp->ip_src.s_addr;
|
||||
inp->ip_src.s_addr=sc->g_src.s_addr;
|
||||
msiz=MOB_H_SIZ_L;
|
||||
mob_h.osrc = inp->ip_src.s_addr;
|
||||
inp->ip_src.s_addr = sc->g_src.s_addr;
|
||||
msiz = MOB_H_SIZ_L;
|
||||
}
|
||||
HTONS(mob_h.proto);
|
||||
mob_h.hcrc=gre_in_cksum((u_short *)&mob_h,msiz);
|
||||
mob_h.hcrc = gre_in_cksum((u_short *)&mob_h, msiz);
|
||||
|
||||
if ((m->m_data - msiz) < m->m_pktdat) {
|
||||
/* need new mbuf */
|
||||
MGETHDR(m0, M_DONTWAIT, MT_HEADER);
|
||||
if (m0==NULL) {
|
||||
if (m0 == NULL) {
|
||||
IF_DROP(&ifp->if_snd);
|
||||
m_freem(m);
|
||||
return(ENOBUFS);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
m0->m_next=m;
|
||||
m0->m_next = m;
|
||||
m->m_data += sizeof(struct ip);
|
||||
m->m_len -= sizeof(struct ip);
|
||||
m0->m_pkthdr.len=m->m_pkthdr.len+msiz;
|
||||
m0->m_pkthdr.len = m->m_pkthdr.len + msiz;
|
||||
m0->m_len = msiz + sizeof(struct ip);
|
||||
m0->m_data += max_linkhdr;
|
||||
memcpy(mtod(m0, caddr_t), (caddr_t) inp, sizeof(struct ip));
|
||||
m=m0;
|
||||
} else { /* we have some spave left in the old one */
|
||||
m->m_data-=msiz;
|
||||
m->m_len+=msiz;
|
||||
m->m_pkthdr.len+=msiz;
|
||||
memmove(mtod(m, caddr_t), inp, sizeof(struct ip));
|
||||
memcpy(mtod(m0, caddr_t), (caddr_t)inp,
|
||||
sizeof(struct ip));
|
||||
m = m0;
|
||||
} else { /* we have some spave left in the old one */
|
||||
m->m_data -= msiz;
|
||||
m->m_len += msiz;
|
||||
m->m_pkthdr.len += msiz;
|
||||
memmove(mtod(m, caddr_t), inp,
|
||||
sizeof(struct ip));
|
||||
}
|
||||
inp=mtod(m,struct ip *);
|
||||
memcpy((caddr_t) (inp+1), &mob_h, (unsigned) msiz);
|
||||
inp=mtod(m, struct ip *);
|
||||
memcpy((caddr_t)(inp + 1), &mob_h, (unsigned)msiz);
|
||||
NTOHS(inp->ip_len);
|
||||
inp->ip_len+=msiz;
|
||||
inp->ip_len += msiz;
|
||||
} else { /* AF_INET */
|
||||
IF_DROP(&ifp->if_snd);
|
||||
m_freem(m);
|
||||
return(EINVAL);
|
||||
return (EINVAL);
|
||||
}
|
||||
} else if (sc->g_proto == IPPROTO_GRE) {
|
||||
switch(dst->sa_family) {
|
||||
case AF_INET:
|
||||
inp=mtod(m,struct ip *);
|
||||
ttl=inp->ip_ttl;
|
||||
etype=ETHERTYPE_IP;
|
||||
inp = mtod(m, struct ip *);
|
||||
ttl = inp->ip_ttl;
|
||||
etype = ETHERTYPE_IP;
|
||||
break;
|
||||
#ifdef NETATALK
|
||||
case AF_APPLETALK:
|
||||
etype=ETHERTYPE_ATALK;
|
||||
etype = ETHERTYPE_ATALK;
|
||||
break;
|
||||
#endif
|
||||
#ifdef NS
|
||||
case AF_NS:
|
||||
etype=ETHERTYPE_NS;
|
||||
etype = ETHERTYPE_NS;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
IF_DROP(&ifp->if_snd);
|
||||
m_freem(m);
|
||||
return(EAFNOSUPPORT);
|
||||
return (EAFNOSUPPORT);
|
||||
}
|
||||
M_PREPEND(m,sizeof(struct greip),M_DONTWAIT);
|
||||
M_PREPEND(m, sizeof(struct greip), M_DONTWAIT);
|
||||
} else {
|
||||
error= EINVAL;
|
||||
error = EINVAL;
|
||||
IF_DROP(&ifp->if_snd);
|
||||
m_freem(m);
|
||||
return(error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
if (m == NULL) {
|
||||
IF_DROP(&ifp->if_snd);
|
||||
return(ENOBUFS);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
|
||||
gh=mtod(m,struct greip *);
|
||||
if (sc->g_proto == IPPROTO_GRE){
|
||||
gh = mtod(m, struct greip *);
|
||||
if (sc->g_proto == IPPROTO_GRE) {
|
||||
/* we don't have any GRE flags for now */
|
||||
|
||||
memset((void*)&gh->gi_g,0, sizeof(struct gre_h));
|
||||
gh->gi_ptype=htons(etype);
|
||||
memset((void *)&gh->gi_g, 0, sizeof(struct gre_h));
|
||||
gh->gi_ptype = htons(etype);
|
||||
}
|
||||
|
||||
gh->gi_pr = sc->g_proto;
|
||||
@ -310,39 +310,35 @@ gre_output(ifp, m, dst, rt)
|
||||
gh->gi_src = sc->g_src;
|
||||
gh->gi_dst = sc->g_dst;
|
||||
((struct ip*)gh)->ip_hl = (sizeof(struct ip)) >> 2;
|
||||
((struct ip*)gh)->ip_ttl=ttl;
|
||||
((struct ip*)gh)->ip_tos=inp->ip_tos;
|
||||
((struct ip*)gh)->ip_ttl = ttl;
|
||||
((struct ip*)gh)->ip_tos = inp->ip_tos;
|
||||
gh->gi_len = m->m_pkthdr.len;
|
||||
}
|
||||
|
||||
ifp->if_opackets++;
|
||||
ifp->if_obytes+=m->m_pkthdr.len;
|
||||
ifp->if_obytes += m->m_pkthdr.len;
|
||||
/* send it off */
|
||||
error=ip_output(m,NULL,&sc->route,0,NULL);
|
||||
if (error) {
|
||||
error = ip_output(m, NULL, &sc->route, 0, NULL);
|
||||
if (error)
|
||||
ifp->if_oerrors++;
|
||||
}
|
||||
return(error);
|
||||
return (error);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
gre_ioctl(ifp, cmd, data)
|
||||
struct ifnet *ifp;
|
||||
u_long cmd;
|
||||
caddr_t data;
|
||||
gre_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
{
|
||||
|
||||
register struct ifaddr *ifa = (struct ifaddr *)data;
|
||||
register struct ifreq *ifr = (struct ifreq *)data;
|
||||
register struct in_ifaddr *ia = (struct in_ifaddr *)data;
|
||||
register struct gre_softc *sc = ifp->if_softc;
|
||||
struct ifaddr *ifa = (struct ifaddr *)data;
|
||||
struct ifreq *ifr = (struct ifreq *)data;
|
||||
struct in_ifaddr *ia = (struct in_ifaddr *)data;
|
||||
struct gre_softc *sc = ifp->if_softc;
|
||||
int s;
|
||||
struct sockaddr_in si;
|
||||
struct sockaddr *sa =NULL;
|
||||
struct sockaddr *sa = NULL;
|
||||
int error;
|
||||
|
||||
error= 0;
|
||||
error = 0;
|
||||
|
||||
s = splimp();
|
||||
switch(cmd) {
|
||||
@ -367,8 +363,8 @@ gre_ioctl(ifp, cmd, data)
|
||||
}
|
||||
break;
|
||||
case SIOCSIFFLAGS:
|
||||
if ((sc->g_dst.s_addr== INADDR_ANY) ||
|
||||
(sc->g_src.s_addr== INADDR_ANY))
|
||||
if ((sc->g_dst.s_addr == INADDR_ANY) ||
|
||||
(sc->g_src.s_addr == INADDR_ANY))
|
||||
ifp->if_flags &= ~IFF_UP;
|
||||
|
||||
switch(ifr->ifr_flags & LINK_MASK) {
|
||||
@ -396,11 +392,11 @@ gre_ioctl(ifp, cmd, data)
|
||||
break;
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
if (ifr == 0 ) {
|
||||
if (ifr == 0) {
|
||||
error = EAFNOSUPPORT;
|
||||
break;
|
||||
}
|
||||
switch(ifr->ifr_addr.sa_family) {
|
||||
switch (ifr->ifr_addr.sa_family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
break;
|
||||
@ -449,12 +445,12 @@ gre_ioctl(ifp, cmd, data)
|
||||
break;
|
||||
case GREGADDRS:
|
||||
si.sin_addr.s_addr = sc->g_src.s_addr;
|
||||
sa=sintosa(&si);
|
||||
sa = sintosa(&si);
|
||||
ifr->ifr_addr = *sa;
|
||||
break;
|
||||
case GREGADDRD:
|
||||
si.sin_addr.s_addr = sc->g_dst.s_addr;
|
||||
sa=sintosa(&si);
|
||||
sa = sintosa(&si);
|
||||
ifr->ifr_addr = *sa;
|
||||
break;
|
||||
default:
|
||||
@ -462,7 +458,7 @@ gre_ioctl(ifp, cmd, data)
|
||||
}
|
||||
|
||||
splx(s);
|
||||
return(error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -477,33 +473,38 @@ gre_ioctl(ifp, cmd, data)
|
||||
* at least a default route which matches.
|
||||
*/
|
||||
|
||||
void gre_compute_route(struct gre_softc *sc)
|
||||
void
|
||||
gre_compute_route(struct gre_softc *sc)
|
||||
{
|
||||
struct route *ro;
|
||||
u_int32_t a,b,c;
|
||||
u_int32_t a, b, c;
|
||||
|
||||
ro=&sc->route;
|
||||
ro = &sc->route;
|
||||
|
||||
memset(ro,0,sizeof(struct route));
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
|
||||
ro->ro_dst.sa_family=AF_INET;
|
||||
ro->ro_dst.sa_len=sizeof(ro->ro_dst);
|
||||
memset(ro, 0, sizeof(struct route));
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
|
||||
ro->ro_dst.sa_family = AF_INET;
|
||||
ro->ro_dst.sa_len = sizeof(ro->ro_dst);
|
||||
|
||||
/*
|
||||
* toggle last bit, so our interface is not found, but a less
|
||||
* specific route. I'd rather like to specify a shorter mask,
|
||||
* but this is not possible. Should work though. XXX
|
||||
* there is a simpler way ...
|
||||
*/
|
||||
a= ntohl(sc->g_dst.s_addr);
|
||||
b= a & 0x01;
|
||||
c= a & 0xfffffffe;
|
||||
b = b ^ 0x01;
|
||||
a = b | c;
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr=htonl(a);
|
||||
if ((sc->sc_if.if_flags & IFF_LINK1) == 0) {
|
||||
a = ntohl(sc->g_dst.s_addr);
|
||||
b = a & 0x01;
|
||||
c = a & 0xfffffffe;
|
||||
b = b ^ 0x01;
|
||||
a = b | c;
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr.s_addr
|
||||
= htonl(a);
|
||||
}
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
printf("%s: searching a route to ",sc->sc_if.if_xname);
|
||||
gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
|
||||
printf("%s: searching a route to ", sc->sc_if.if_xname);
|
||||
gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
|
||||
#endif
|
||||
|
||||
rtalloc(ro);
|
||||
@ -512,12 +513,13 @@ gre_inet_ntoa(((struct sockaddr_in *)&ro->ro_dst)->sin_addr);
|
||||
* now change it back - else ip_output will just drop
|
||||
* the route and search one to this interface ...
|
||||
*/
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr=sc->g_dst;
|
||||
if ((sc->sc_if.if_flags & IFF_LINK1) == 0)
|
||||
((struct sockaddr_in *)&ro->ro_dst)->sin_addr = sc->g_dst;
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
|
||||
gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
|
||||
printf("\n");
|
||||
printf(", choosing %s with gateway ",ro->ro_rt->rt_ifp->if_xname);
|
||||
gre_inet_ntoa(((struct sockaddr_in *)(ro->ro_rt->rt_gateway))->sin_addr);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -527,9 +529,7 @@ printf("\n");
|
||||
*/
|
||||
|
||||
u_short
|
||||
gre_in_cksum(p, len)
|
||||
u_short *p;
|
||||
u_int len;
|
||||
gre_in_cksum(u_short *p, u_int len)
|
||||
{
|
||||
u_int sum = 0;
|
||||
int nwords = len >> 1;
|
||||
@ -557,14 +557,13 @@ gre_in_cksum(p, len)
|
||||
/* while testing ... */
|
||||
#ifdef DIAGNOSTIC
|
||||
void
|
||||
gre_inet_ntoa(in)
|
||||
struct in_addr in;
|
||||
gre_inet_ntoa(struct in_addr in)
|
||||
{
|
||||
register char *p;
|
||||
char *p;
|
||||
|
||||
p = (char *)∈
|
||||
p = (char *)∈
|
||||
#define UC(b) (((int)b)&0xff)
|
||||
printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
|
||||
printf("%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user