2005-01-07 02:30:35 +00:00
|
|
|
/*-
|
1999-12-07 17:39:16 +00:00
|
|
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 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
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
2007-12-10 16:03:40 +00:00
|
|
|
*
|
|
|
|
* $KAME: in6_gif.c,v 1.49 2001/05/14 14:02:17 itojun Exp $
|
1999-12-07 17:39:16 +00:00
|
|
|
*/
|
|
|
|
|
2007-12-10 16:03:40 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
#include "opt_inet.h"
|
2000-07-04 16:35:15 +00:00
|
|
|
#include "opt_inet6.h"
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <sys/mbuf.h>
|
|
|
|
#include <sys/errno.h>
|
2010-04-29 11:52:42 +00:00
|
|
|
#include <sys/kernel.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <sys/queue.h>
|
|
|
|
#include <sys/syslog.h>
|
2010-04-29 11:52:42 +00:00
|
|
|
#include <sys/sysctl.h>
|
2002-10-16 19:49:37 +00:00
|
|
|
#include <sys/protosw.h>
|
2001-06-11 12:39:29 +00:00
|
|
|
#include <sys/malloc.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <net/route.h>
|
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#ifdef INET
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#endif
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet/ip_encap.h>
|
|
|
|
#ifdef INET6
|
|
|
|
#include <netinet/ip6.h>
|
1999-12-07 17:39:16 +00:00
|
|
|
#include <netinet6/ip6_var.h>
|
|
|
|
#include <netinet6/in6_gif.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#include <netinet6/in6_var.h>
|
|
|
|
#endif
|
2002-10-16 19:49:37 +00:00
|
|
|
#include <netinet6/ip6protosw.h>
|
1999-12-22 19:13:38 +00:00
|
|
|
#include <netinet/ip_ecn.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#ifdef INET6
|
1999-12-22 19:13:38 +00:00
|
|
|
#include <netinet6/ip6_ecn.h>
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
#include <net/if_gif.h>
|
|
|
|
|
2010-04-29 11:52:42 +00:00
|
|
|
VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM;
|
|
|
|
#define V_ip6_gif_hlim VNET(ip6_gif_hlim)
|
|
|
|
|
|
|
|
SYSCTL_DECL(_net_inet6_ip6);
|
|
|
|
SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_RW,
|
|
|
|
&VNET_NAME(ip6_gif_hlim), 0, "");
|
|
|
|
|
2002-10-16 19:49:37 +00:00
|
|
|
static int gif_validate6(const struct ip6_hdr *, struct gif_softc *,
|
|
|
|
struct ifnet *);
|
|
|
|
|
|
|
|
extern struct domain inet6domain;
|
2009-01-05 20:29:01 +00:00
|
|
|
struct ip6protosw in6_gif_protosw = {
|
|
|
|
.pr_type = SOCK_RAW,
|
|
|
|
.pr_domain = &inet6domain,
|
|
|
|
.pr_protocol = 0, /* IPPROTO_IPV[46] */
|
|
|
|
.pr_flags = PR_ATOMIC|PR_ADDR,
|
|
|
|
.pr_input = in6_gif_input,
|
|
|
|
.pr_output = rip6_output,
|
|
|
|
.pr_ctloutput = rip6_ctloutput,
|
|
|
|
.pr_usrreqs = &rip6_usrreqs
|
2002-10-16 19:49:37 +00:00
|
|
|
};
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_gif_output(struct ifnet *ifp,
|
|
|
|
int family, /* family of the packet to be encapsulate */
|
|
|
|
struct mbuf *m)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
2005-06-10 16:49:24 +00:00
|
|
|
struct gif_softc *sc = ifp->if_softc;
|
1999-12-07 17:39:16 +00:00
|
|
|
struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&sc->gif_ro6.ro_dst;
|
|
|
|
struct sockaddr_in6 *sin6_src = (struct sockaddr_in6 *)sc->gif_psrc;
|
|
|
|
struct sockaddr_in6 *sin6_dst = (struct sockaddr_in6 *)sc->gif_pdst;
|
|
|
|
struct ip6_hdr *ip6;
|
2005-12-21 21:29:45 +00:00
|
|
|
struct etherip_header eiphdr;
|
2009-03-07 19:08:58 +00:00
|
|
|
int error, len, proto;
|
1999-12-22 19:13:38 +00:00
|
|
|
u_int8_t itos, otos;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2006-01-30 08:39:09 +00:00
|
|
|
GIF_LOCK_ASSERT(sc);
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
if (sin6_src == NULL || sin6_dst == NULL ||
|
|
|
|
sin6_src->sin6_family != AF_INET6 ||
|
|
|
|
sin6_dst->sin6_family != AF_INET6) {
|
|
|
|
m_freem(m);
|
|
|
|
return EAFNOSUPPORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (family) {
|
|
|
|
#ifdef INET
|
|
|
|
case AF_INET:
|
|
|
|
{
|
|
|
|
struct ip *ip;
|
|
|
|
|
|
|
|
proto = IPPROTO_IPV4;
|
|
|
|
if (m->m_len < sizeof(*ip)) {
|
|
|
|
m = m_pullup(m, sizeof(*ip));
|
|
|
|
if (!m)
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
ip = mtod(m, struct ip *);
|
1999-12-22 19:13:38 +00:00
|
|
|
itos = ip->ip_tos;
|
1999-12-07 17:39:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
2000-07-04 16:35:15 +00:00
|
|
|
#ifdef INET6
|
1999-12-07 17:39:16 +00:00
|
|
|
case AF_INET6:
|
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
proto = IPPROTO_IPV6;
|
|
|
|
if (m->m_len < sizeof(*ip6)) {
|
|
|
|
m = m_pullup(m, sizeof(*ip6));
|
|
|
|
if (!m)
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
1999-12-22 19:13:38 +00:00
|
|
|
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
|
1999-12-07 17:39:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
2005-12-21 21:29:45 +00:00
|
|
|
case AF_LINK:
|
2007-07-05 16:29:40 +00:00
|
|
|
proto = IPPROTO_ETHERIP;
|
Fix and add a workaround on an issue of EtherIP packet with reversed
version field sent via gif(4)+if_bridge(4). The EtherIP
implementation found on FreeBSD 6.1, 6.2, 6.3, 7.0, 7.1, and 7.2 had
an interoperability issue because it sent the incorrect EtherIP
packets and discarded the correct ones.
This change introduces the following two flags to gif(4):
accept_rev_ethip_ver: accepts both correct EtherIP packets and ones
with reversed version field, if enabled. If disabled, the gif
accepts the correct packets only. This flag is enabled by
default.
send_rev_ethip_ver: sends EtherIP packets with reversed version field
intentionally, if enabled. If disabled, the gif sends the correct
packets only. This flag is disabled by default.
These flags are stored in struct gif_softc and can be set by
ifconfig(8) on per-interface basis.
Note that this is an incompatible change of EtherIP with the older
FreeBSD releases. If you need to interoperate older FreeBSD boxes and
new versions after this commit, setting "send_rev_ethip_ver" is
needed.
Reviewed by: thompsa and rwatson
Spotted by: Shunsuke SHINOMIYA
PR: kern/125003
MFC after: 2 weeks
2009-06-07 23:00:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* GIF_SEND_REVETHIP (disabled by default) intentionally
|
|
|
|
* sends an EtherIP packet with revered version field in
|
|
|
|
* the header. This is a knob for backward compatibility
|
|
|
|
* with FreeBSD 7.2R or prior.
|
|
|
|
*/
|
|
|
|
if ((sc->gif_options & GIF_SEND_REVETHIP)) {
|
|
|
|
eiphdr.eip_ver = 0;
|
|
|
|
eiphdr.eip_resvl = ETHERIP_VERSION;
|
|
|
|
eiphdr.eip_resvh = 0;
|
|
|
|
} else {
|
|
|
|
eiphdr.eip_ver = ETHERIP_VERSION;
|
|
|
|
eiphdr.eip_resvl = 0;
|
|
|
|
eiphdr.eip_resvh = 0;
|
|
|
|
}
|
2007-07-05 16:29:40 +00:00
|
|
|
/* prepend Ethernet-in-IP header */
|
2012-12-05 08:04:20 +00:00
|
|
|
M_PREPEND(m, sizeof(struct etherip_header), M_NOWAIT);
|
2007-07-05 16:29:40 +00:00
|
|
|
if (m && m->m_len < sizeof(struct etherip_header))
|
|
|
|
m = m_pullup(m, sizeof(struct etherip_header));
|
|
|
|
if (m == NULL)
|
|
|
|
return ENOBUFS;
|
|
|
|
bcopy(&eiphdr, mtod(m, struct etherip_header *),
|
2005-12-21 21:29:45 +00:00
|
|
|
sizeof(struct etherip_header));
|
|
|
|
break;
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
default:
|
2000-07-04 16:35:15 +00:00
|
|
|
#ifdef DEBUG
|
1999-12-07 17:39:16 +00:00
|
|
|
printf("in6_gif_output: warning: unknown family %d passed\n",
|
|
|
|
family);
|
|
|
|
#endif
|
|
|
|
m_freem(m);
|
|
|
|
return EAFNOSUPPORT;
|
|
|
|
}
|
2003-10-08 18:26:08 +00:00
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
/* prepend new IP header */
|
2009-03-07 19:08:58 +00:00
|
|
|
len = sizeof(struct ip6_hdr);
|
|
|
|
#ifndef __NO_STRICT_ALIGNMENT
|
|
|
|
if (family == AF_LINK)
|
|
|
|
len += ETHERIP_ALIGN;
|
|
|
|
#endif
|
2012-12-05 08:04:20 +00:00
|
|
|
M_PREPEND(m, len, M_NOWAIT);
|
2009-03-07 19:08:58 +00:00
|
|
|
if (m != NULL && m->m_len < len)
|
|
|
|
m = m_pullup(m, len);
|
1999-12-07 17:39:16 +00:00
|
|
|
if (m == NULL) {
|
|
|
|
printf("ENOBUFS in in6_gif_output %d\n", __LINE__);
|
|
|
|
return ENOBUFS;
|
|
|
|
}
|
2009-03-07 19:08:58 +00:00
|
|
|
#ifndef __NO_STRICT_ALIGNMENT
|
|
|
|
if (family == AF_LINK) {
|
|
|
|
len = mtod(m, vm_offset_t) & 3;
|
|
|
|
KASSERT(len == 0 || len == ETHERIP_ALIGN,
|
|
|
|
("in6_gif_output: unexpected misalignment"));
|
|
|
|
m->m_data += len;
|
|
|
|
m->m_len -= ETHERIP_ALIGN;
|
|
|
|
}
|
|
|
|
#endif
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
ip6->ip6_flow = 0;
|
2000-07-04 16:35:15 +00:00
|
|
|
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
|
|
|
|
ip6->ip6_vfc |= IPV6_VERSION;
|
1999-12-07 17:39:16 +00:00
|
|
|
ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
|
|
|
|
ip6->ip6_nxt = proto;
|
Commit step 1 of the vimage project, (network stack)
virtualization work done by Marko Zec (zec@).
This is the first in a series of commits over the course
of the next few weeks.
Mark all uses of global variables to be virtualized
with a V_ prefix.
Use macros to map them back to their global names for
now, so this is a NOP change only.
We hope to have caught at least 85-90% of what is needed
so we do not invalidate a lot of outstanding patches again.
Obtained from: //depot/projects/vimage-commit2/...
Reviewed by: brooks, des, ed, mav, julian,
jamie, kris, rwatson, zec, ...
(various people I forgot, different versions)
md5 (with a bit of help)
Sponsored by: NLnet Foundation, The FreeBSD Foundation
X-MFC after: never
V_Commit_Message_Reviewed_By: more people than the patch
2008-08-17 23:27:27 +00:00
|
|
|
ip6->ip6_hlim = V_ip6_gif_hlim;
|
1999-12-07 17:39:16 +00:00
|
|
|
ip6->ip6_src = sin6_src->sin6_addr;
|
2001-06-11 12:39:29 +00:00
|
|
|
/* bidirectional configured tunnel mode */
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&sin6_dst->sin6_addr))
|
|
|
|
ip6->ip6_dst = sin6_dst->sin6_addr;
|
|
|
|
else {
|
|
|
|
m_freem(m);
|
|
|
|
return ENETUNREACH;
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
2003-10-29 15:07:04 +00:00
|
|
|
ip_ecn_ingress((ifp->if_flags & IFF_LINK1) ? ECN_ALLOWED : ECN_NOCARE,
|
|
|
|
&otos, &itos);
|
|
|
|
ip6->ip6_flow &= ~htonl(0xff << 20);
|
2001-06-11 12:39:29 +00:00
|
|
|
ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2012-02-03 13:08:44 +00:00
|
|
|
M_SETFIB(m, sc->gif_fibnum);
|
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
if (dst->sin6_family != sin6_dst->sin6_family ||
|
|
|
|
!IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
|
|
|
|
/* cache route doesn't match */
|
|
|
|
bzero(dst, sizeof(*dst));
|
|
|
|
dst->sin6_family = sin6_dst->sin6_family;
|
|
|
|
dst->sin6_len = sizeof(struct sockaddr_in6);
|
|
|
|
dst->sin6_addr = sin6_dst->sin6_addr;
|
|
|
|
if (sc->gif_ro6.ro_rt) {
|
|
|
|
RTFREE(sc->gif_ro6.ro_rt);
|
|
|
|
sc->gif_ro6.ro_rt = NULL;
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
#if 0
|
2005-06-10 16:49:24 +00:00
|
|
|
GIF2IFP(sc)->if_mtu = GIF_MTU;
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sc->gif_ro6.ro_rt == NULL) {
|
2012-02-03 13:08:44 +00:00
|
|
|
in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum);
|
1999-12-07 17:39:16 +00:00
|
|
|
if (sc->gif_ro6.ro_rt == NULL) {
|
|
|
|
m_freem(m);
|
|
|
|
return ENETUNREACH;
|
|
|
|
}
|
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
/* if it constitutes infinite encapsulation, punt. */
|
|
|
|
if (sc->gif_ro.ro_rt->rt_ifp == ifp) {
|
|
|
|
m_freem(m);
|
|
|
|
return ENETUNREACH; /*XXX*/
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
ifp->if_mtu = sc->gif_ro6.ro_rt->rt_ifp->if_mtu
|
|
|
|
- sizeof(struct ip6_hdr);
|
|
|
|
#endif
|
|
|
|
}
|
2003-10-08 18:26:08 +00:00
|
|
|
|
2000-07-04 16:35:15 +00:00
|
|
|
#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.
|
|
|
|
*/
|
2004-12-09 09:52:58 +00:00
|
|
|
error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL, NULL);
|
2000-07-04 16:35:15 +00:00
|
|
|
#else
|
2004-12-09 09:52:58 +00:00
|
|
|
error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL, NULL);
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
2004-12-09 09:48:47 +00:00
|
|
|
|
2005-06-10 16:49:24 +00:00
|
|
|
if (!(GIF2IFP(sc)->if_flags & IFF_LINK0) &&
|
2004-12-10 07:51:14 +00:00
|
|
|
sc->gif_ro6.ro_rt != NULL) {
|
2004-12-09 09:48:47 +00:00
|
|
|
RTFREE(sc->gif_ro6.ro_rt);
|
|
|
|
sc->gif_ro6.ro_rt = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
1999-12-07 17:39:16 +00:00
|
|
|
}
|
|
|
|
|
2003-10-08 18:26:08 +00:00
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_gif_input(struct mbuf **mp, int *offp, int proto)
|
1999-12-07 17:39:16 +00:00
|
|
|
{
|
|
|
|
struct mbuf *m = *mp;
|
|
|
|
struct ifnet *gifp = NULL;
|
2005-06-20 20:17:00 +00:00
|
|
|
struct gif_softc *sc;
|
1999-12-07 17:39:16 +00:00
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
int af = 0;
|
1999-12-22 19:13:38 +00:00
|
|
|
u_int32_t otos;
|
1999-12-07 17:39:16 +00:00
|
|
|
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
|
|
|
|
2005-06-20 20:17:00 +00:00
|
|
|
sc = (struct gif_softc *)encap_getarg(m);
|
|
|
|
if (sc == NULL) {
|
|
|
|
m_freem(m);
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_nogif);
|
2005-06-20 20:17:00 +00:00
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
|
2005-06-20 20:17:00 +00:00
|
|
|
gifp = GIF2IFP(sc);
|
2000-07-04 16:35:15 +00:00
|
|
|
if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
|
1999-12-07 17:39:16 +00:00
|
|
|
m_freem(m);
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_nogif);
|
1999-12-07 17:39:16 +00:00
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
1999-12-22 19:13:38 +00:00
|
|
|
otos = ip6->ip6_flow;
|
1999-12-07 17:39:16 +00:00
|
|
|
m_adj(m, *offp);
|
|
|
|
|
|
|
|
switch (proto) {
|
|
|
|
#ifdef INET
|
|
|
|
case IPPROTO_IPV4:
|
|
|
|
{
|
|
|
|
struct ip *ip;
|
1999-12-22 19:13:38 +00:00
|
|
|
u_int8_t otos8;
|
1999-12-07 17:39:16 +00:00
|
|
|
af = AF_INET;
|
1999-12-22 19:13:38 +00:00
|
|
|
otos8 = (ntohl(otos) >> 20) & 0xff;
|
1999-12-07 17:39:16 +00:00
|
|
|
if (m->m_len < sizeof(*ip)) {
|
|
|
|
m = m_pullup(m, sizeof(*ip));
|
|
|
|
if (!m)
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
|
|
|
ip = mtod(m, struct ip *);
|
2003-10-29 15:07:04 +00:00
|
|
|
if (ip_ecn_egress((gifp->if_flags & IFF_LINK1) ?
|
|
|
|
ECN_ALLOWED : ECN_NOCARE,
|
|
|
|
&otos8, &ip->ip_tos) == 0) {
|
|
|
|
m_freem(m);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif /* INET */
|
2000-07-04 16:35:15 +00:00
|
|
|
#ifdef INET6
|
1999-12-07 17:39:16 +00:00
|
|
|
case IPPROTO_IPV6:
|
|
|
|
{
|
|
|
|
struct ip6_hdr *ip6;
|
|
|
|
af = AF_INET6;
|
|
|
|
if (m->m_len < sizeof(*ip6)) {
|
|
|
|
m = m_pullup(m, sizeof(*ip6));
|
|
|
|
if (!m)
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
|
|
|
ip6 = mtod(m, struct ip6_hdr *);
|
2003-10-29 15:07:04 +00:00
|
|
|
if (ip6_ecn_egress((gifp->if_flags & IFF_LINK1) ?
|
|
|
|
ECN_ALLOWED : ECN_NOCARE,
|
|
|
|
&otos, &ip6->ip6_flow) == 0) {
|
|
|
|
m_freem(m);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
1999-12-07 17:39:16 +00:00
|
|
|
break;
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
#endif
|
2007-07-05 16:29:40 +00:00
|
|
|
case IPPROTO_ETHERIP:
|
|
|
|
af = AF_LINK;
|
|
|
|
break;
|
2005-12-21 21:29:45 +00:00
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
default:
|
2013-04-09 07:11:22 +00:00
|
|
|
IP6STAT_INC(ip6s_nogif);
|
1999-12-07 17:39:16 +00:00
|
|
|
m_freem(m);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
2003-10-08 18:26:08 +00:00
|
|
|
|
1999-12-07 17:39:16 +00:00
|
|
|
gif_input(m, af, gifp);
|
|
|
|
return IPPROTO_DONE;
|
|
|
|
}
|
2000-07-04 16:35:15 +00:00
|
|
|
|
|
|
|
/*
|
2002-10-16 19:49:37 +00:00
|
|
|
* validate outer address.
|
2000-07-04 16:35:15 +00:00
|
|
|
*/
|
2002-10-16 19:49:37 +00:00
|
|
|
static int
|
2007-07-05 16:23:49 +00:00
|
|
|
gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
|
|
|
|
struct ifnet *ifp)
|
2002-10-16 19:49:37 +00:00
|
|
|
{
|
2000-07-04 16:35:15 +00:00
|
|
|
struct sockaddr_in6 *src, *dst;
|
|
|
|
|
|
|
|
src = (struct sockaddr_in6 *)sc->gif_psrc;
|
|
|
|
dst = (struct sockaddr_in6 *)sc->gif_pdst;
|
|
|
|
|
2002-10-16 19:49:37 +00:00
|
|
|
/*
|
|
|
|
* Check for address match. Note that the check is for an incoming
|
|
|
|
* packet. We should compare the *source* address in our configuration
|
|
|
|
* and the *destination* address of the packet, and vice versa.
|
|
|
|
*/
|
|
|
|
if (!IN6_ARE_ADDR_EQUAL(&src->sin6_addr, &ip6->ip6_dst) ||
|
|
|
|
!IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_src))
|
2000-07-04 16:35:15 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* martian filters on outer source - done in ip6_input */
|
|
|
|
|
|
|
|
/* ingress filters on outer source */
|
2005-06-10 16:49:24 +00:00
|
|
|
if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0 && ifp) {
|
2000-07-04 16:35:15 +00:00
|
|
|
struct sockaddr_in6 sin6;
|
|
|
|
struct rtentry *rt;
|
|
|
|
|
|
|
|
bzero(&sin6, sizeof(sin6));
|
|
|
|
sin6.sin6_family = AF_INET6;
|
|
|
|
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
2002-10-16 19:49:37 +00:00
|
|
|
sin6.sin6_addr = ip6->ip6_src;
|
|
|
|
sin6.sin6_scope_id = 0; /* XXX */
|
|
|
|
|
2012-02-03 13:08:44 +00:00
|
|
|
rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL,
|
|
|
|
sc->gif_fibnum);
|
2002-10-16 19:49:37 +00:00
|
|
|
if (!rt || rt->rt_ifp != ifp) {
|
2001-06-11 12:39:29 +00:00
|
|
|
#if 0
|
2006-12-12 12:17:58 +00:00
|
|
|
char ip6buf[INET6_ADDRSTRLEN];
|
2001-06-11 12:39:29 +00:00
|
|
|
log(LOG_WARNING, "%s: packet from %s dropped "
|
2005-06-10 16:49:24 +00:00
|
|
|
"due to ingress filter\n", if_name(GIF2IFP(sc)),
|
2006-12-12 12:17:58 +00:00
|
|
|
ip6_sprintf(ip6buf, &sin6.sin6_addr));
|
2001-06-11 12:39:29 +00:00
|
|
|
#endif
|
|
|
|
if (rt)
|
2009-01-31 10:48:02 +00:00
|
|
|
RTFREE_LOCKED(rt);
|
2000-07-04 16:35:15 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2009-01-31 10:48:02 +00:00
|
|
|
RTFREE_LOCKED(rt);
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
|
|
|
|
2001-06-11 12:39:29 +00:00
|
|
|
return 128 * 2;
|
2000-07-04 16:35:15 +00:00
|
|
|
}
|
2002-10-16 19:49:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* we know that we are in IFF_UP, outer address available, and outer family
|
|
|
|
* matched the physical addr family. see gif_encapcheck().
|
|
|
|
* sanity check for arg should have been done in the caller.
|
|
|
|
*/
|
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
gif_encapcheck6(const struct mbuf *m, int off, int proto, void *arg)
|
2002-10-16 19:49:37 +00:00
|
|
|
{
|
|
|
|
struct ip6_hdr ip6;
|
|
|
|
struct gif_softc *sc;
|
|
|
|
struct ifnet *ifp;
|
|
|
|
|
|
|
|
/* sanity check done in caller */
|
|
|
|
sc = (struct gif_softc *)arg;
|
|
|
|
|
|
|
|
/* LINTED const cast */
|
|
|
|
m_copydata(m, 0, sizeof(ip6), (caddr_t)&ip6);
|
|
|
|
ifp = ((m->m_flags & M_PKTHDR) != 0) ? m->m_pkthdr.rcvif : NULL;
|
|
|
|
|
|
|
|
return gif_validate6(&ip6, sc, ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_gif_attach(struct gif_softc *sc)
|
2002-10-16 19:49:37 +00:00
|
|
|
{
|
|
|
|
sc->encap_cookie6 = encap_attach_func(AF_INET6, -1, gif_encapcheck,
|
2006-02-05 09:52:40 +00:00
|
|
|
(void *)&in6_gif_protosw, sc);
|
2002-10-16 19:49:37 +00:00
|
|
|
if (sc->encap_cookie6 == NULL)
|
|
|
|
return EEXIST;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2007-07-05 16:23:49 +00:00
|
|
|
in6_gif_detach(struct gif_softc *sc)
|
2002-10-16 19:49:37 +00:00
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = encap_detach(sc->encap_cookie6);
|
|
|
|
if (error == 0)
|
|
|
|
sc->encap_cookie6 = NULL;
|
|
|
|
return error;
|
|
|
|
}
|