📄 in6_gif.c
字号:
//==========================================================================
//
// src/sys/netinet6/in6_gif.c
//
//==========================================================================
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD,
// FreeBSD or other sources, and are covered by the appropriate
// copyright disclaimers included herein.
//
// Portions created by Red Hat are
// Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
/* $KAME: in6_gif.c,v 1.88 2001/12/21 03:32:34 itojun Exp $ */
/*
* 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.
*/
/* define it if you want to use encap_attach_func (it helps *BSD merge) */
/*#define USE_ENCAPCHECK*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
#include <sys/ioctl.h>
#endif
#include <sys/queue.h>
#include <sys/protosw.h>
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
#include <sys/malloc.h>
#endif
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#ifdef INET
#include <netinet/ip.h>
#endif
#include <netinet/ip_encap.h>
#ifdef INET6
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/in6_gif.h>
#include <netinet6/in6_var.h>
#endif
#include <netinet6/ip6protosw.h>
#include <netinet/ip_ecn.h>
#ifdef __OpenBSD__
#include <netinet/ip_ipsp.h>
#endif
#include <net/if_gif.h>
#ifdef __OpenBSD__
#include "bridge.h"
#endif
static int gif_validate6 __P((const struct ip6_hdr *, struct gif_softc *,
struct ifnet *));
static int in6_gif_rtcachettl = 300; /* XXX see in_gif.c */
int ip6_gif_hlim = GIF_HLIM;
extern struct domain inet6domain;
struct ip6protosw in6_gif_protosw =
{ SOCK_RAW, &inet6domain, 0/* IPPROTO_IPV[46] */, PR_ATOMIC|PR_ADDR,
in6_gif_input, rip6_output, in6_gif_ctlinput, rip6_ctloutput,
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
0,
#else
rip6_usrreq,
#endif
0, 0, 0, 0,
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
&rip6_usrreqs
#endif
};
extern LIST_HEAD(, gif_softc) gif_softc_list;
#ifndef offsetof
#define offsetof(s, e) ((int)&((s *)0)->e)
#endif
int
in6_gif_output(ifp, family, m)
struct ifnet *ifp;
int family; /* family of the packet to be encapsulate. */
struct mbuf *m;
{
#ifdef __OpenBSD__
struct gif_softc *sc = (struct gif_softc*)ifp;
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 tdb tdb;
struct xformsw xfs;
int error;
int hlen, poff;
struct mbuf *mp;
long time_second;
if (sin6_src == NULL || sin6_dst == NULL ||
sin6_src->sin6_family != AF_INET6 ||
sin6_dst->sin6_family != AF_INET6) {
m_freem(m);
return EAFNOSUPPORT;
}
/* setup dummy tdb. it highly depends on ipip_output() code. */
bzero(&tdb, sizeof(tdb));
bzero(&xfs, sizeof(xfs));
tdb.tdb_src.sin6.sin6_family = AF_INET6;
tdb.tdb_src.sin6.sin6_len = sizeof(struct sockaddr_in6);
tdb.tdb_src.sin6.sin6_addr = sin6_src->sin6_addr;
tdb.tdb_dst.sin6.sin6_family = AF_INET6;
tdb.tdb_dst.sin6.sin6_len = sizeof(struct sockaddr_in6);
tdb.tdb_dst.sin6.sin6_addr = sin6_dst->sin6_addr;
tdb.tdb_xform = &xfs;
xfs.xf_type = -1; /* not XF_IP4 */
switch (family) {
#ifdef INET
case AF_INET:
{
if (m->m_len < sizeof(struct ip)) {
m = m_pullup(m, sizeof(struct ip));
if (!m)
return ENOBUFS;
}
hlen = (mtod(m, struct ip *)->ip_hl) << 2;
poff = offsetof(struct ip, ip_p);
break;
}
#endif
#ifdef INET6
case AF_INET6:
{
hlen = sizeof(struct ip6_hdr);
poff = offsetof(struct ip6_hdr, ip6_nxt);
break;
}
#endif
#if NBRIDGE > 0
case AF_LINK:
break;
#endif /* NBRIDGE */
default:
#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
family);
#endif
m_freem(m);
return EAFNOSUPPORT;
}
#if NBRIDGE > 0
if (family == AF_LINK) {
mp = NULL;
error = etherip_output(m, &tdb, &mp, 0, 0);
if (error)
return error;
else if (mp == NULL)
return EFAULT;
m = mp;
goto sendit;
}
#endif /* NBRIDGE */
/* encapsulate into IPv6 packet */
mp = NULL;
error = ipip_output(m, &tdb, &mp, hlen, poff);
if (error)
return error;
else if (mp == NULL)
return EFAULT;
m = mp;
#if NBRIDGE > 0
sendit:
#endif /* NBRIDGE */
/*
* compare address family just for safety. other validity checks
* are made in in6_selectsrc() called from ip6_output().
*/
if (sc->gif_ro6.ro_rt && (dst->sin6_family != sin6_dst->sin6_family ||
sc->rtcache_expire == 0 ||
time_second >= sc->rtcache_expire)) {
RTFREE(sc->gif_ro6.ro_rt);
sc->gif_ro6.ro_rt = NULL;
}
#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.
*/
error = ip6_output(m, 0, &sc->gif_ro6, IPV6_MINMTU, 0, NULL);
#else
error = ip6_output(m, 0, &sc->gif_ro6, 0, 0, NULL);
#endif
if (sc->gif_ro6.ro_rt && time_second >= sc->rtcache_expire)
sc->rtcache_expire = time_second + in6_gif_rtcachettl;
return(error);
#else /* !__OpenBSD__ */
struct gif_softc *sc = (struct gif_softc*)ifp;
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;
int proto, error;
u_int8_t itos, otos;
#if !(defined(__FreeBSD__) && __FreeBSD__ >= 3)
long time_second;
#endif
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 *);
itos = ip->ip_tos;
break;
}
#endif
#ifdef INET6
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 *);
itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
break;
}
#endif
#if defined(__NetBSD__) && defined(ISO)
case AF_ISO:
proto = IPPROTO_EON;
itos = 0;
break;
#endif
default:
#ifdef DEBUG
printf("in6_gif_output: warning: unknown family %d passed\n",
family);
#endif
m_freem(m);
return EAFNOSUPPORT;
}
/* prepend new IP header */
M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT);
if (m && m->m_len < sizeof(struct ip6_hdr))
m = m_pullup(m, sizeof(struct ip6_hdr));
if (m == NULL)
return ENOBUFS;
ip6 = mtod(m, struct ip6_hdr *);
ip6->ip6_flow = 0;
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
ip6->ip6_plen = htons((u_short)m->m_pkthdr.len);
ip6->ip6_nxt = proto;
ip6->ip6_hlim = ip6_gif_hlim;
ip6->ip6_src = sin6_src->sin6_addr;
/* bidirectional configured tunnel mode */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -