version 1.13, 2000/03/01 12:49:45 |
version 1.14, 2000/04/19 06:30:56 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
/* $KAME: in6_gif.c,v 1.34 2000/04/19 04:51:58 itojun Exp $ */ |
|
|
/* |
/* |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
* are met: |
* are met: |
|
|
* 3. Neither the name of the project nor the names of its contributors |
* 3. Neither the name of the project nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* without specific prior written permission. |
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
|
* in6_gif.c |
* in6_gif.c |
*/ |
*/ |
|
|
|
#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__) |
#include "opt_inet.h" |
#include "opt_inet.h" |
|
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
|
|
#include <sys/sockio.h> |
#include <sys/sockio.h> |
#include <sys/mbuf.h> |
#include <sys/mbuf.h> |
#include <sys/errno.h> |
#include <sys/errno.h> |
|
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) |
#include <sys/ioctl.h> |
#include <sys/ioctl.h> |
#include <sys/protosw.h> |
#endif |
|
|
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 3 |
|
#include <sys/malloc.h> |
|
#endif |
|
|
#include <net/if.h> |
#include <net/if.h> |
#include <net/route.h> |
#include <net/route.h> |
|
|
#ifdef INET |
#ifdef INET |
#include <netinet/ip.h> |
#include <netinet/ip.h> |
#endif |
#endif |
|
#include <netinet/ip_encap.h> |
#ifdef INET6 |
#ifdef INET6 |
#include <netinet/ip6.h> |
#include <netinet/ip6.h> |
#include <netinet6/ip6_var.h> |
#include <netinet6/ip6_var.h> |
#include <netinet6/in6_gif.h> |
#include <netinet6/in6_gif.h> |
|
#include <netinet6/in6_var.h> |
#endif |
#endif |
#include <netinet/ip_ecn.h> |
#include <netinet/ip_ecn.h> |
|
|
Line 194 in6_gif_output(ifp, family, m, rt) |
|
Line 204 in6_gif_output(ifp, family, m, rt) |
|
m_freem(m); |
m_freem(m); |
return ENETUNREACH; |
return ENETUNREACH; |
} |
} |
|
|
|
/* if it constitutes infinite encapsulation, punt. */ |
|
if (sc->gif_ro.ro_rt->rt_ifp == ifp) { |
|
m_freem(m); |
|
return ENETUNREACH; /*XXX*/ |
|
} |
#if 0 |
#if 0 |
ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu |
ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu |
- sizeof(struct ip6_hdr); |
- sizeof(struct ip6_hdr); |
#endif |
#endif |
} |
} |
|
|
|
#ifdef IPV6_MINMTU |
|
/* |
|
* force fragmentation to minimum MTU, to avoid path MTU discovery. |
|
* it is too painful to ask for resend of inner packet, to achieve |
|
* path MTU discovery for encapsulated packets. |
|
*/ |
|
return(ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL)); |
|
#else |
return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); |
return(ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL)); |
|
#endif |
} |
} |
|
|
int in6_gif_input(mp, offp, proto) |
int in6_gif_input(mp, offp, proto) |
Line 208 int in6_gif_input(mp, offp, proto) |
|
Line 233 int in6_gif_input(mp, offp, proto) |
|
int *offp, proto; |
int *offp, proto; |
{ |
{ |
struct mbuf *m = *mp; |
struct mbuf *m = *mp; |
struct gif_softc *sc; |
|
struct ifnet *gifp = NULL; |
struct ifnet *gifp = NULL; |
struct ip6_hdr *ip6; |
struct ip6_hdr *ip6; |
int i; |
|
int af = 0; |
int af = 0; |
u_int32_t otos; |
u_int32_t otos; |
|
|
ip6 = mtod(m, struct ip6_hdr *); |
ip6 = mtod(m, struct ip6_hdr *); |
|
|
#define satoin6(sa) (((struct sockaddr_in6 *)(sa))->sin6_addr) |
gifp = (struct ifnet *)encap_getarg(m); |
for (i = 0, sc = gif; i < ngif; i++, sc++) { |
|
if (sc->gif_psrc == NULL || |
|
sc->gif_pdst == NULL || |
|
sc->gif_psrc->sa_family != AF_INET6 || |
|
sc->gif_pdst->sa_family != AF_INET6) { |
|
continue; |
|
} |
|
if ((sc->gif_if.if_flags & IFF_UP) == 0) |
|
continue; |
|
if ((sc->gif_if.if_flags & IFF_LINK0) && |
|
IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && |
|
IN6_IS_ADDR_UNSPECIFIED(&satoin6(sc->gif_pdst))) { |
|
gifp = &sc->gif_if; |
|
continue; |
|
} |
|
if (IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_psrc), &ip6->ip6_dst) && |
|
IN6_ARE_ADDR_EQUAL(&satoin6(sc->gif_pdst), &ip6->ip6_src)) { |
|
gifp = &sc->gif_if; |
|
break; |
|
} |
|
} |
|
|
|
if (gifp == NULL) { |
if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) { |
m_freem(m); |
m_freem(m); |
ip6stat.ip6s_nogif++; |
ip6stat.ip6s_nogif++; |
return IPPROTO_DONE; |
return IPPROTO_DONE; |
} |
} |
|
|
otos = ip6->ip6_flow; |
otos = ip6->ip6_flow; |
m_adj(m, *offp); |
m_adj(m, *offp); |
|
|
Line 293 int in6_gif_input(mp, offp, proto) |
|
Line 295 int in6_gif_input(mp, offp, proto) |
|
gif_input(m, af, gifp); |
gif_input(m, af, gifp); |
return IPPROTO_DONE; |
return IPPROTO_DONE; |
} |
} |
|
|
|
/* |
|
* we know that we are in IFF_UP, outer address available, and outer family |
|
* matched the physical addr family. see gif_encapcheck(). |
|
*/ |
|
int |
|
gif_encapcheck6(m, off, proto, arg) |
|
const struct mbuf *m; |
|
int off; |
|
int proto; |
|
void *arg; |
|
{ |
|
struct ip6_hdr ip6; |
|
struct gif_softc *sc; |
|
struct sockaddr_in6 *src, *dst; |
|
int addrmatch; |
|
|
|
/* sanity check done in caller */ |
|
sc = (struct gif_softc *)arg; |
|
src = (struct sockaddr_in6 *)sc->gif_psrc; |
|
dst = (struct sockaddr_in6 *)sc->gif_pdst; |
|
|
|
/* LINTED const cast */ |
|
m_copydata((struct mbuf *)m, 0, sizeof(ip6), (caddr_t)&ip6); |
|
|
|
/* check for address match */ |
|
addrmatch = 0; |
|
if (IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6.ip6_dst)) |
|
addrmatch |= 1; |
|
if (IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6.ip6_src)) |
|
addrmatch |= 2; |
|
else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 && |
|
IN6_IS_ADDR_UNSPECIFIED(&dst->sin6_addr)) { |
|
addrmatch |= 2; /* we accept any source */ |
|
} |
|
if (addrmatch != 3) |
|
return 0; |
|
|
|
/* martian filters on outer source - done in ip6_input */ |
|
|
|
/* ingress filters on outer source */ |
|
if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { |
|
struct sockaddr_in6 sin6; |
|
struct rtentry *rt; |
|
|
|
bzero(&sin6, sizeof(sin6)); |
|
sin6.sin6_family = AF_INET6; |
|
sin6.sin6_len = sizeof(struct sockaddr_in6); |
|
sin6.sin6_addr = ip6.ip6_src; |
|
/* XXX scopeid */ |
|
#ifdef __FreeBSD__ |
|
rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL); |
|
#else |
|
rt = rtalloc1((struct sockaddr *)&sin6, 0); |
|
#endif |
|
if (!rt) |
|
return 0; |
|
if (rt->rt_ifp != m->m_pkthdr.rcvif) { |
|
rtfree(rt); |
|
return 0; |
|
} |
|
rtfree(rt); |
|
} |
|
|
|
/* prioritize: IFF_LINK0 mode is less preferred */ |
|
return (sc->gif_if.if_flags & IFF_LINK0) ? 128 : 128 * 2; |
|
} |