mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-04 12:52:15 +00:00
Rework IP encapsulation handling code.
Currently it has several disadvantages: - it uses single mutex to protect internal structures. It is used by data- and control- path, thus there are no parallelism at all. - it uses single list to keep encap handlers for both INET and INET6 families. - struct encaptab keeps unneeded information (src, dst, masks, protosw), that isn't used by code in the source tree. - matches are prioritized and when many tunneling interfaces are registered, encapcheck handler of each interface is invoked for each packet. The search takes O(n) for n interfaces. All this work is done with exclusive lock held. What this patch includes: - the datapath is converted to be lockless using epoch(9) KPI. - struct encaptab now linked using CK_LIST. - all unused fields removed from struct encaptab. Several new fields addedr: min_length is the minimum packet length, that encapsulation handler expects to see; exact_match is maximum number of bits, that can return an encapsulation handler, when it wants to consume a packet. - IPv6 and IPv4 handlers are stored in separate lists; - added new "encap_lookup_t" method, that will be used later. It is targeted to speedup lookup of needed interface, when gif(4)/gre(4) have many interfaces. - the need to use protosw structure is eliminated. The only pr_input method was used from this structure, so I don't see the need to keep using it. - encap_input_t method changed to avoid using mbuf tags to store softc pointer. Now it is passed directly trough encap_input_t method. encap_getarg() funtions is removed. - all sockaddr structures and code that uses them removed. We don't have any code in the tree that uses them. All consumers use encap_attach_func() method, that relies on invoking of encapcheck() to determine the needed handler. - introduced struct encap_config, it contains parameters of encap handler that is going to be registered by encap_attach() function. - encap handlers are stored in lists ordered by exact_match value, thus handlers that need more bits to match will be checked first, and if encapcheck method returns exact_match value, the search will be stopped. - all current consumers changed to use new KPI. Reviewed by: mmacy Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D15617
This commit is contained in:
parent
56009ba0ed
commit
6d8fdfa9d5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=334671
@ -923,12 +923,24 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
}
|
||||
|
||||
static void
|
||||
gif_detach(struct gif_softc *sc)
|
||||
gif_detach(struct gif_softc *sc, int family)
|
||||
{
|
||||
|
||||
sx_assert(&gif_ioctl_sx, SA_XLOCKED);
|
||||
if (sc->gif_ecookie != NULL)
|
||||
encap_detach(sc->gif_ecookie);
|
||||
if (sc->gif_ecookie != NULL) {
|
||||
switch (family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
ip_encap_detach(sc->gif_ecookie);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ip6_encap_detach(sc->gif_ecookie);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sc->gif_ecookie = NULL;
|
||||
}
|
||||
|
||||
@ -1020,7 +1032,7 @@ gif_set_tunnel(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst)
|
||||
}
|
||||
|
||||
if (sc->gif_family != src->sa_family)
|
||||
gif_detach(sc);
|
||||
gif_detach(sc, sc->gif_family);
|
||||
if (sc->gif_family == 0 ||
|
||||
sc->gif_family != src->sa_family)
|
||||
error = gif_attach(sc, src->sa_family);
|
||||
@ -1058,7 +1070,7 @@ gif_delete_tunnel(struct ifnet *ifp)
|
||||
sc->gif_family = 0;
|
||||
GIF_WUNLOCK(sc);
|
||||
if (family != 0) {
|
||||
gif_detach(sc);
|
||||
gif_detach(sc, family);
|
||||
free(sc->gif_hdr, M_GIF);
|
||||
}
|
||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
||||
|
@ -551,12 +551,24 @@ gre_updatehdr(struct gre_softc *sc)
|
||||
}
|
||||
|
||||
static void
|
||||
gre_detach(struct gre_softc *sc)
|
||||
gre_detach(struct gre_softc *sc, int family)
|
||||
{
|
||||
|
||||
sx_assert(&gre_ioctl_sx, SA_XLOCKED);
|
||||
if (sc->gre_ecookie != NULL)
|
||||
encap_detach(sc->gre_ecookie);
|
||||
if (sc->gre_ecookie != NULL) {
|
||||
switch (family) {
|
||||
#ifdef INET
|
||||
case AF_INET:
|
||||
ip_encap_detach(sc->gre_ecookie);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case AF_INET6:
|
||||
ip6_encap_detach(sc->gre_ecookie);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
sc->gre_ecookie = NULL;
|
||||
}
|
||||
|
||||
@ -624,7 +636,7 @@ gre_set_tunnel(struct ifnet *ifp, struct sockaddr *src,
|
||||
return (EAFNOSUPPORT);
|
||||
}
|
||||
if (sc->gre_family != 0)
|
||||
gre_detach(sc);
|
||||
gre_detach(sc, sc->gre_family);
|
||||
GRE_WLOCK(sc);
|
||||
if (sc->gre_family != 0)
|
||||
free(sc->gre_hdr, M_GRE);
|
||||
@ -666,7 +678,7 @@ gre_delete_tunnel(struct ifnet *ifp)
|
||||
sc->gre_family = 0;
|
||||
GRE_WUNLOCK(sc);
|
||||
if (family != 0) {
|
||||
gre_detach(sc);
|
||||
gre_detach(sc, family);
|
||||
free(sc->gre_hdr, M_GRE);
|
||||
}
|
||||
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
|
||||
@ -674,12 +686,11 @@ gre_delete_tunnel(struct ifnet *ifp)
|
||||
}
|
||||
|
||||
int
|
||||
gre_input(struct mbuf **mp, int *offp, int proto)
|
||||
gre_input(struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
struct gre_softc *sc;
|
||||
struct gre_softc *sc = arg;
|
||||
struct grehdr *gh;
|
||||
struct ifnet *ifp;
|
||||
struct mbuf *m;
|
||||
uint32_t *opts;
|
||||
#ifdef notyet
|
||||
uint32_t key;
|
||||
@ -687,12 +698,8 @@ gre_input(struct mbuf **mp, int *offp, int proto)
|
||||
uint16_t flags;
|
||||
int hlen, isr, af;
|
||||
|
||||
m = *mp;
|
||||
sc = encap_getarg(m);
|
||||
KASSERT(sc != NULL, ("encap_getarg returned NULL"));
|
||||
|
||||
ifp = GRE2IFP(sc);
|
||||
hlen = *offp + sizeof(struct grehdr) + 4 * sizeof(uint32_t);
|
||||
hlen = off + sizeof(struct grehdr) + 4 * sizeof(uint32_t);
|
||||
if (m->m_pkthdr.len < hlen)
|
||||
goto drop;
|
||||
if (m->m_len < hlen) {
|
||||
@ -700,7 +707,7 @@ gre_input(struct mbuf **mp, int *offp, int proto)
|
||||
if (m == NULL)
|
||||
goto drop;
|
||||
}
|
||||
gh = (struct grehdr *)mtodo(m, *offp);
|
||||
gh = (struct grehdr *)mtodo(m, off);
|
||||
flags = ntohs(gh->gre_flags);
|
||||
if (flags & ~GRE_FLAGS_MASK)
|
||||
goto drop;
|
||||
@ -710,7 +717,7 @@ gre_input(struct mbuf **mp, int *offp, int proto)
|
||||
/* reserved1 field must be zero */
|
||||
if (((uint16_t *)opts)[1] != 0)
|
||||
goto drop;
|
||||
if (in_cksum_skip(m, m->m_pkthdr.len, *offp) != 0)
|
||||
if (in_cksum_skip(m, m->m_pkthdr.len, off) != 0)
|
||||
goto drop;
|
||||
hlen += 2 * sizeof(uint16_t);
|
||||
opts++;
|
||||
@ -760,7 +767,7 @@ gre_input(struct mbuf **mp, int *offp, int proto)
|
||||
default:
|
||||
goto drop;
|
||||
}
|
||||
m_adj(m, *offp + hlen);
|
||||
m_adj(m, off + hlen);
|
||||
m_clrprotoflags(m);
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
M_SETFIB(m, ifp->if_fib);
|
||||
|
@ -101,7 +101,7 @@ struct gre_softc {
|
||||
#define gre_oip gre_gihdr->gi_ip
|
||||
#define gre_oip6 gre_gi6hdr->gi6_ip6
|
||||
|
||||
int gre_input(struct mbuf **, int *, int);
|
||||
int gre_input(struct mbuf *, int, int, void *);
|
||||
#ifdef INET
|
||||
int in_gre_attach(struct gre_softc *);
|
||||
int in_gre_output(struct mbuf *, int, int);
|
||||
|
@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/rmlock.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
@ -122,11 +121,22 @@ static int me_transmit(struct ifnet *, struct mbuf *);
|
||||
static int me_ioctl(struct ifnet *, u_long, caddr_t);
|
||||
static int me_output(struct ifnet *, struct mbuf *,
|
||||
const struct sockaddr *, struct route *);
|
||||
static int me_input(struct mbuf **, int *, int);
|
||||
static int me_input(struct mbuf *, int, int, void *);
|
||||
|
||||
static int me_set_tunnel(struct ifnet *, struct sockaddr_in *,
|
||||
struct sockaddr_in *);
|
||||
static void me_delete_tunnel(struct ifnet *);
|
||||
static int me_encapcheck(const struct mbuf *, int, int, void *);
|
||||
|
||||
#define ME_MINLEN (sizeof(struct ip) + sizeof(struct mobhdr) -\
|
||||
sizeof(in_addr_t))
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = IPPROTO_MOBILE,
|
||||
.min_length = ME_MINLEN,
|
||||
.exact_match = (sizeof(in_addr_t) << 4) + 8,
|
||||
.check = me_encapcheck,
|
||||
.input = me_input
|
||||
};
|
||||
|
||||
SYSCTL_DECL(_net_link);
|
||||
static SYSCTL_NODE(_net_link, IFT_TUNNEL, me, CTLFLAG_RW, 0,
|
||||
@ -140,19 +150,6 @@ static VNET_DEFINE(int, max_me_nesting) = MAX_ME_NEST;
|
||||
SYSCTL_INT(_net_link_me, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET,
|
||||
&VNET_NAME(max_me_nesting), 0, "Max nested tunnels");
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static const struct protosw in_mobile_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = IPPROTO_MOBILE,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = me_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctlinput = rip_ctlinput,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
|
||||
static void
|
||||
vnet_me_init(const void *unused __unused)
|
||||
{
|
||||
@ -334,17 +331,13 @@ me_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
|
||||
if (m->m_pkthdr.len < sizeof(struct ip) + sizeof(struct mobhdr) -
|
||||
sizeof(struct in_addr))
|
||||
return (0);
|
||||
|
||||
ret = 0;
|
||||
ME_RLOCK(sc);
|
||||
if (ME_READY(sc)) {
|
||||
ip = mtod(m, struct ip *);
|
||||
if (sc->me_src.s_addr == ip->ip_dst.s_addr &&
|
||||
sc->me_dst.s_addr == ip->ip_src.s_addr)
|
||||
ret = 32 * 2;
|
||||
ret = 32 * 2 + 8;
|
||||
}
|
||||
ME_RUNLOCK(sc);
|
||||
return (ret);
|
||||
@ -376,8 +369,8 @@ me_set_tunnel(struct ifnet *ifp, struct sockaddr_in *src,
|
||||
ME_WUNLOCK(sc);
|
||||
|
||||
if (sc->me_ecookie == NULL)
|
||||
sc->me_ecookie = encap_attach_func(AF_INET, IPPROTO_MOBILE,
|
||||
me_encapcheck, &in_mobile_protosw, sc);
|
||||
sc->me_ecookie = ip_encap_attach(&ipv4_encap_cfg,
|
||||
sc, M_WAITOK);
|
||||
if (sc->me_ecookie != NULL) {
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
@ -392,7 +385,7 @@ me_delete_tunnel(struct ifnet *ifp)
|
||||
|
||||
sx_assert(&me_ioctl_sx, SA_XLOCKED);
|
||||
if (sc->me_ecookie != NULL)
|
||||
encap_detach(sc->me_ecookie);
|
||||
ip_encap_detach(sc->me_ecookie);
|
||||
sc->me_ecookie = NULL;
|
||||
ME_WLOCK(sc);
|
||||
sc->me_src.s_addr = 0;
|
||||
@ -414,20 +407,15 @@ me_in_cksum(uint16_t *p, int nwords)
|
||||
return (~sum);
|
||||
}
|
||||
|
||||
int
|
||||
me_input(struct mbuf **mp, int *offp, int proto)
|
||||
static int
|
||||
me_input(struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
struct me_softc *sc;
|
||||
struct me_softc *sc = arg;
|
||||
struct mobhdr *mh;
|
||||
struct ifnet *ifp;
|
||||
struct mbuf *m;
|
||||
struct ip *ip;
|
||||
int hlen;
|
||||
|
||||
m = *mp;
|
||||
sc = encap_getarg(m);
|
||||
KASSERT(sc != NULL, ("encap_getarg returned NULL"));
|
||||
|
||||
ifp = ME2IFP(sc);
|
||||
/* checks for short packets */
|
||||
hlen = sizeof(struct mobhdr);
|
||||
|
@ -85,7 +85,6 @@
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/rmlock.h>
|
||||
@ -151,19 +150,7 @@ static const char stfname[] = "stf";
|
||||
static MALLOC_DEFINE(M_STF, stfname, "6to4 Tunnel Interface");
|
||||
static const int ip_stf_ttl = 40;
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static int in_stf_input(struct mbuf **, int *, int);
|
||||
static struct protosw in_stf_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = IPPROTO_IPV6,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = in_stf_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
|
||||
static int in_stf_input(struct mbuf *, int, int, void *);
|
||||
static char *stfnames[] = {"stf0", "stf", "6to4", NULL};
|
||||
|
||||
static int stfmodevent(module_t, int, void *);
|
||||
@ -183,6 +170,14 @@ static int stf_clone_create(struct if_clone *, char *, size_t, caddr_t);
|
||||
static int stf_clone_destroy(struct if_clone *, struct ifnet *);
|
||||
static struct if_clone *stf_cloner;
|
||||
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = IPPROTO_IPV6,
|
||||
.min_length = sizeof(struct ip),
|
||||
.exact_match = (sizeof(in_addr_t) << 3) + 8,
|
||||
.check = stf_encapcheck,
|
||||
.input = in_stf_input
|
||||
};
|
||||
|
||||
static int
|
||||
stf_clone_match(struct if_clone *ifc, const char *name)
|
||||
{
|
||||
@ -250,8 +245,7 @@ stf_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
|
||||
ifp->if_dname = stfname;
|
||||
ifp->if_dunit = IF_DUNIT_NONE;
|
||||
|
||||
sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6,
|
||||
stf_encapcheck, &in_stf_protosw, sc);
|
||||
sc->encap_cookie = ip_encap_attach(&ipv4_encap_cfg, sc, M_WAITOK);
|
||||
if (sc->encap_cookie == NULL) {
|
||||
if_printf(ifp, "attach failed\n");
|
||||
free(sc, M_STF);
|
||||
@ -274,7 +268,7 @@ stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
|
||||
struct stf_softc *sc = ifp->if_softc;
|
||||
int err __unused;
|
||||
|
||||
err = encap_detach(sc->encap_cookie);
|
||||
err = ip_encap_detach(sc->encap_cookie);
|
||||
KASSERT(err == 0, ("Unexpected error detaching encap_cookie"));
|
||||
bpfdetach(ifp);
|
||||
if_detach(ifp);
|
||||
@ -608,18 +602,13 @@ stf_checkaddr6(struct stf_softc *sc, struct in6_addr *in6, struct ifnet *inifp)
|
||||
}
|
||||
|
||||
static int
|
||||
in_stf_input(struct mbuf **mp, int *offp, int proto)
|
||||
in_stf_input(struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
struct stf_softc *sc;
|
||||
struct stf_softc *sc = arg;
|
||||
struct ip *ip;
|
||||
struct ip6_hdr *ip6;
|
||||
struct mbuf *m;
|
||||
u_int8_t otos, itos;
|
||||
struct ifnet *ifp;
|
||||
int off;
|
||||
|
||||
m = *mp;
|
||||
off = *offp;
|
||||
|
||||
if (proto != IPPROTO_IPV6) {
|
||||
m_freem(m);
|
||||
@ -627,9 +616,6 @@ in_stf_input(struct mbuf **mp, int *offp, int proto)
|
||||
}
|
||||
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
sc = (struct stf_softc *)encap_getarg(m);
|
||||
|
||||
if (sc == NULL || (STF2IFP(sc)->if_flags & IFF_UP) == 0) {
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
@ -680,7 +666,7 @@ in_stf_input(struct mbuf **mp, int *offp, int proto)
|
||||
ip6->ip6_flow |= htonl((u_int32_t)itos << 20);
|
||||
|
||||
m->m_pkthdr.rcvif = ifp;
|
||||
|
||||
|
||||
if (bpf_peers_present(ifp->if_bpf)) {
|
||||
/*
|
||||
* We need to prepend the address family as
|
||||
|
@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
@ -70,25 +69,11 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <net/if_gif.h>
|
||||
|
||||
static int in_gif_input(struct mbuf **, int *, int);
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static struct protosw in_gif_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = 0/* IPPROTO_IPV[46] */,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = in_gif_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
|
||||
#define GIF_TTL 30
|
||||
static VNET_DEFINE(int, ip_gif_ttl) = GIF_TTL;
|
||||
#define V_ip_gif_ttl VNET(ip_gif_ttl)
|
||||
SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW,
|
||||
&VNET_NAME(ip_gif_ttl), 0, "");
|
||||
&VNET_NAME(ip_gif_ttl), 0, "Default TTL value for encapsulated packets");
|
||||
|
||||
int
|
||||
in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
|
||||
@ -136,15 +121,13 @@ in_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
|
||||
}
|
||||
|
||||
static int
|
||||
in_gif_input(struct mbuf **mp, int *offp, int proto)
|
||||
in_gif_input(struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
struct gif_softc *sc;
|
||||
struct gif_softc *sc = arg;
|
||||
struct ifnet *gifp;
|
||||
struct ip *ip;
|
||||
uint8_t ecn;
|
||||
|
||||
sc = encap_getarg(m);
|
||||
if (sc == NULL) {
|
||||
m_freem(m);
|
||||
KMOD_IPSTAT_INC(ips_nogif);
|
||||
@ -154,7 +137,7 @@ in_gif_input(struct mbuf **mp, int *offp, int proto)
|
||||
if ((gifp->if_flags & IFF_UP) != 0) {
|
||||
ip = mtod(m, struct ip *);
|
||||
ecn = ip->ip_tos;
|
||||
m_adj(m, *offp);
|
||||
m_adj(m, off);
|
||||
gif_input(m, gifp, proto, ecn);
|
||||
} else {
|
||||
m_freem(m);
|
||||
@ -182,7 +165,7 @@ in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
ip = mtod(m, const struct ip *);
|
||||
if (sc->gif_iphdr->ip_src.s_addr != ip->ip_dst.s_addr)
|
||||
return (0);
|
||||
ret = 32;
|
||||
ret = 32 + 8; /* src + proto */
|
||||
if (sc->gif_iphdr->ip_dst.s_addr != ip->ip_src.s_addr) {
|
||||
if ((sc->gif_options & GIF_IGNORE_SOURCE) == 0)
|
||||
return (0);
|
||||
@ -205,14 +188,19 @@ in_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = -1,
|
||||
.min_length = sizeof(struct ip),
|
||||
.exact_match = (sizeof(in_addr_t) << 4) + 8,
|
||||
.check = gif_encapcheck,
|
||||
.input = in_gif_input
|
||||
};
|
||||
|
||||
int
|
||||
in_gif_attach(struct gif_softc *sc)
|
||||
{
|
||||
|
||||
KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL"));
|
||||
sc->gif_ecookie = encap_attach_func(AF_INET, -1, gif_encapcheck,
|
||||
&in_gif_protosw, sc);
|
||||
if (sc->gif_ecookie == NULL)
|
||||
return (EEXIST);
|
||||
sc->gif_ecookie = ip_encap_attach(&ipv4_encap_cfg, sc, M_WAITOK);
|
||||
return (0);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -56,417 +57,214 @@
|
||||
* So, clearly good old protosw does not work for protocol #4 and #41.
|
||||
* The code will let you match protocol via src/dst address pair.
|
||||
*/
|
||||
/* XXX is M_NETADDR correct? */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_mrouting.h"
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
#include <net/if_var.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_encap.h>
|
||||
|
||||
#ifdef INET6
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
#endif
|
||||
|
||||
#include <machine/stdarg.h>
|
||||
static MALLOC_DEFINE(M_NETADDR, "encap_export_host",
|
||||
"Export host address structure");
|
||||
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
static MALLOC_DEFINE(M_NETADDR, "encap_export_host", "Export host address structure");
|
||||
struct encaptab {
|
||||
CK_LIST_ENTRY(encaptab) chain;
|
||||
int proto;
|
||||
int min_length;
|
||||
int exact_match;
|
||||
void *arg;
|
||||
|
||||
static void encap_add(struct encaptab *);
|
||||
static int mask_match(const struct encaptab *, const struct sockaddr *,
|
||||
const struct sockaddr *);
|
||||
static void encap_fillarg(struct mbuf *, void *);
|
||||
encap_lookup_t lookup;
|
||||
encap_check_t check;
|
||||
encap_input_t input;
|
||||
};
|
||||
|
||||
CK_LIST_HEAD(encaptab_head, encaptab);
|
||||
#ifdef INET
|
||||
static struct encaptab_head ipv4_encaptab = CK_LIST_HEAD_INITIALIZER();
|
||||
#endif
|
||||
#ifdef INET6
|
||||
static struct encaptab_head ipv6_encaptab = CK_LIST_HEAD_INITIALIZER();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* All global variables in ip_encap.c are locked using encapmtx.
|
||||
*/
|
||||
static struct mtx encapmtx;
|
||||
MTX_SYSINIT(encapmtx, &encapmtx, "encapmtx", MTX_DEF);
|
||||
static LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(encaptab);
|
||||
#define ENCAP_WLOCK() mtx_lock(&encapmtx)
|
||||
#define ENCAP_WUNLOCK() mtx_unlock(&encapmtx)
|
||||
#define ENCAP_RLOCK() epoch_enter_preempt(net_epoch_preempt)
|
||||
#define ENCAP_RUNLOCK() epoch_exit_preempt(net_epoch_preempt)
|
||||
#define ENCAP_WAIT() epoch_wait_preempt(net_epoch_preempt)
|
||||
|
||||
#ifdef INET
|
||||
int
|
||||
encap4_input(struct mbuf **mp, int *offp, int proto)
|
||||
static struct encaptab *
|
||||
encap_attach(struct encaptab_head *head, const struct encap_config *cfg,
|
||||
void *arg, int mflags)
|
||||
{
|
||||
struct ip *ip;
|
||||
struct mbuf *m;
|
||||
struct sockaddr_in s, d;
|
||||
const struct protosw *psw;
|
||||
struct encaptab *ep, *match;
|
||||
void *arg;
|
||||
int matchprio, off, prio;
|
||||
struct encaptab *ep, *tmp;
|
||||
|
||||
m = *mp;
|
||||
off = *offp;
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
bzero(&s, sizeof(s));
|
||||
s.sin_family = AF_INET;
|
||||
s.sin_len = sizeof(struct sockaddr_in);
|
||||
s.sin_addr = ip->ip_src;
|
||||
bzero(&d, sizeof(d));
|
||||
d.sin_family = AF_INET;
|
||||
d.sin_len = sizeof(struct sockaddr_in);
|
||||
d.sin_addr = ip->ip_dst;
|
||||
|
||||
arg = NULL;
|
||||
psw = NULL;
|
||||
match = NULL;
|
||||
matchprio = 0;
|
||||
mtx_lock(&encapmtx);
|
||||
LIST_FOREACH(ep, &encaptab, chain) {
|
||||
if (ep->af != AF_INET)
|
||||
continue;
|
||||
if (ep->proto >= 0 && ep->proto != proto)
|
||||
continue;
|
||||
if (ep->func)
|
||||
prio = (*ep->func)(m, off, proto, ep->arg);
|
||||
else {
|
||||
/*
|
||||
* it's inbound traffic, we need to match in reverse
|
||||
* order
|
||||
*/
|
||||
prio = mask_match(ep, (struct sockaddr *)&d,
|
||||
(struct sockaddr *)&s);
|
||||
}
|
||||
|
||||
/*
|
||||
* We prioritize the matches by using bit length of the
|
||||
* matches. mask_match() and user-supplied matching function
|
||||
* should return the bit length of the matches (for example,
|
||||
* if both src/dst are matched for IPv4, 64 should be returned).
|
||||
* 0 or negative return value means "it did not match".
|
||||
*
|
||||
* The question is, since we have two "mask" portion, we
|
||||
* cannot really define total order between entries.
|
||||
* For example, which of these should be preferred?
|
||||
* mask_match() returns 48 (32 + 16) for both of them.
|
||||
* src=3ffe::/16, dst=3ffe:501::/32
|
||||
* src=3ffe:501::/32, dst=3ffe::/16
|
||||
*
|
||||
* We need to loop through all the possible candidates
|
||||
* to get the best match - the search takes O(n) for
|
||||
* n attachments (i.e. interfaces).
|
||||
*/
|
||||
if (prio <= 0)
|
||||
continue;
|
||||
if (prio > matchprio) {
|
||||
matchprio = prio;
|
||||
match = ep;
|
||||
}
|
||||
}
|
||||
if (match != NULL) {
|
||||
psw = match->psw;
|
||||
arg = match->arg;
|
||||
}
|
||||
mtx_unlock(&encapmtx);
|
||||
|
||||
if (match != NULL) {
|
||||
/* found a match, "match" has the best one */
|
||||
if (psw != NULL && psw->pr_input != NULL) {
|
||||
encap_fillarg(m, arg);
|
||||
(*psw->pr_input)(mp, offp, proto);
|
||||
} else
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
|
||||
/* last resort: inject to raw socket */
|
||||
return (rip_input(mp, offp, proto));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INET6
|
||||
int
|
||||
encap6_input(struct mbuf **mp, int *offp, int proto)
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
struct ip6_hdr *ip6;
|
||||
struct sockaddr_in6 s, d;
|
||||
const struct protosw *psw;
|
||||
struct encaptab *ep, *match;
|
||||
void *arg;
|
||||
int prio, matchprio;
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
|
||||
bzero(&s, sizeof(s));
|
||||
s.sin6_family = AF_INET6;
|
||||
s.sin6_len = sizeof(struct sockaddr_in6);
|
||||
s.sin6_addr = ip6->ip6_src;
|
||||
bzero(&d, sizeof(d));
|
||||
d.sin6_family = AF_INET6;
|
||||
d.sin6_len = sizeof(struct sockaddr_in6);
|
||||
d.sin6_addr = ip6->ip6_dst;
|
||||
|
||||
arg = NULL;
|
||||
psw = NULL;
|
||||
match = NULL;
|
||||
matchprio = 0;
|
||||
mtx_lock(&encapmtx);
|
||||
LIST_FOREACH(ep, &encaptab, chain) {
|
||||
if (ep->af != AF_INET6)
|
||||
continue;
|
||||
if (ep->proto >= 0 && ep->proto != proto)
|
||||
continue;
|
||||
if (ep->func)
|
||||
prio = (*ep->func)(m, *offp, proto, ep->arg);
|
||||
else {
|
||||
/*
|
||||
* it's inbound traffic, we need to match in reverse
|
||||
* order
|
||||
*/
|
||||
prio = mask_match(ep, (struct sockaddr *)&d,
|
||||
(struct sockaddr *)&s);
|
||||
}
|
||||
|
||||
/* see encap4_input() for issues here */
|
||||
if (prio <= 0)
|
||||
continue;
|
||||
if (prio > matchprio) {
|
||||
matchprio = prio;
|
||||
match = ep;
|
||||
}
|
||||
}
|
||||
if (match != NULL) {
|
||||
psw = match->psw;
|
||||
arg = match->arg;
|
||||
}
|
||||
mtx_unlock(&encapmtx);
|
||||
|
||||
if (match != NULL) {
|
||||
/* found a match */
|
||||
if (psw != NULL && psw->pr_input != NULL) {
|
||||
encap_fillarg(m, arg);
|
||||
return (*psw->pr_input)(mp, offp, proto);
|
||||
} else {
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
/* last resort: inject to raw socket */
|
||||
return rip6_input(mp, offp, proto);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*lint -sem(encap_add, custodial(1)) */
|
||||
static void
|
||||
encap_add(struct encaptab *ep)
|
||||
{
|
||||
|
||||
mtx_assert(&encapmtx, MA_OWNED);
|
||||
LIST_INSERT_HEAD(&encaptab, ep, chain);
|
||||
}
|
||||
|
||||
/*
|
||||
* sp (src ptr) is always my side, and dp (dst ptr) is always remote side.
|
||||
* length of mask (sm and dm) is assumed to be same as sp/dp.
|
||||
* Return value will be necessary as input (cookie) for encap_detach().
|
||||
*/
|
||||
const struct encaptab *
|
||||
encap_attach(int af, int proto, const struct sockaddr *sp,
|
||||
const struct sockaddr *sm, const struct sockaddr *dp,
|
||||
const struct sockaddr *dm, const struct protosw *psw, void *arg)
|
||||
{
|
||||
struct encaptab *ep;
|
||||
|
||||
/* sanity check on args */
|
||||
if (sp->sa_len > sizeof(ep->src) || dp->sa_len > sizeof(ep->dst))
|
||||
return (NULL);
|
||||
if (sp->sa_len != dp->sa_len)
|
||||
return (NULL);
|
||||
if (af != sp->sa_family || af != dp->sa_family)
|
||||
if (cfg == NULL || cfg->input == NULL ||
|
||||
(cfg->check == NULL && cfg->lookup == NULL) ||
|
||||
(cfg->lookup != NULL && cfg->exact_match != ENCAP_DRV_LOOKUP) ||
|
||||
(cfg->exact_match == ENCAP_DRV_LOOKUP && cfg->lookup == NULL))
|
||||
return (NULL);
|
||||
|
||||
/* check if anyone have already attached with exactly same config */
|
||||
mtx_lock(&encapmtx);
|
||||
LIST_FOREACH(ep, &encaptab, chain) {
|
||||
if (ep->af != af)
|
||||
continue;
|
||||
if (ep->proto != proto)
|
||||
continue;
|
||||
if (ep->src.ss_len != sp->sa_len ||
|
||||
bcmp(&ep->src, sp, sp->sa_len) != 0 ||
|
||||
bcmp(&ep->srcmask, sm, sp->sa_len) != 0)
|
||||
continue;
|
||||
if (ep->dst.ss_len != dp->sa_len ||
|
||||
bcmp(&ep->dst, dp, dp->sa_len) != 0 ||
|
||||
bcmp(&ep->dstmask, dm, dp->sa_len) != 0)
|
||||
continue;
|
||||
|
||||
mtx_unlock(&encapmtx);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
|
||||
if (ep == NULL) {
|
||||
mtx_unlock(&encapmtx);
|
||||
return (NULL);
|
||||
}
|
||||
bzero(ep, sizeof(*ep));
|
||||
|
||||
ep->af = af;
|
||||
ep->proto = proto;
|
||||
bcopy(sp, &ep->src, sp->sa_len);
|
||||
bcopy(sm, &ep->srcmask, sp->sa_len);
|
||||
bcopy(dp, &ep->dst, dp->sa_len);
|
||||
bcopy(dm, &ep->dstmask, dp->sa_len);
|
||||
ep->psw = psw;
|
||||
ep->arg = arg;
|
||||
|
||||
encap_add(ep);
|
||||
mtx_unlock(&encapmtx);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
const struct encaptab *
|
||||
encap_attach_func(int af, int proto,
|
||||
int (*func)(const struct mbuf *, int, int, void *),
|
||||
const struct protosw *psw, void *arg)
|
||||
{
|
||||
struct encaptab *ep;
|
||||
|
||||
/* sanity check on args */
|
||||
if (!func)
|
||||
return (NULL);
|
||||
|
||||
ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/
|
||||
ep = malloc(sizeof(*ep), M_NETADDR, mflags);
|
||||
if (ep == NULL)
|
||||
return (NULL);
|
||||
bzero(ep, sizeof(*ep));
|
||||
|
||||
ep->af = af;
|
||||
ep->proto = proto;
|
||||
ep->func = func;
|
||||
ep->psw = psw;
|
||||
ep->proto = cfg->proto;
|
||||
ep->min_length = cfg->min_length;
|
||||
ep->exact_match = cfg->exact_match;
|
||||
ep->arg = arg;
|
||||
ep->lookup = cfg->exact_match == ENCAP_DRV_LOOKUP ? cfg->lookup: NULL;
|
||||
ep->check = cfg->exact_match != ENCAP_DRV_LOOKUP ? cfg->check: NULL;
|
||||
ep->input = cfg->input;
|
||||
|
||||
mtx_lock(&encapmtx);
|
||||
encap_add(ep);
|
||||
mtx_unlock(&encapmtx);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
int
|
||||
encap_detach(const struct encaptab *cookie)
|
||||
{
|
||||
const struct encaptab *ep = cookie;
|
||||
struct encaptab *p;
|
||||
|
||||
mtx_lock(&encapmtx);
|
||||
LIST_FOREACH(p, &encaptab, chain) {
|
||||
if (p == ep) {
|
||||
LIST_REMOVE(p, chain);
|
||||
mtx_unlock(&encapmtx);
|
||||
free(p, M_NETADDR); /*XXX*/
|
||||
return 0;
|
||||
}
|
||||
ENCAP_WLOCK();
|
||||
CK_LIST_FOREACH(tmp, head, chain) {
|
||||
if (tmp->exact_match <= ep->exact_match)
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&encapmtx);
|
||||
|
||||
return EINVAL;
|
||||
if (tmp == NULL)
|
||||
CK_LIST_INSERT_HEAD(head, ep, chain);
|
||||
else
|
||||
CK_LIST_INSERT_BEFORE(tmp, ep, chain);
|
||||
ENCAP_WUNLOCK();
|
||||
return (ep);
|
||||
}
|
||||
|
||||
static int
|
||||
mask_match(const struct encaptab *ep, const struct sockaddr *sp,
|
||||
const struct sockaddr *dp)
|
||||
encap_detach(struct encaptab_head *head, const struct encaptab *cookie)
|
||||
{
|
||||
struct sockaddr_storage s;
|
||||
struct sockaddr_storage d;
|
||||
int i;
|
||||
const u_int8_t *p, *q;
|
||||
u_int8_t *r;
|
||||
int matchlen;
|
||||
struct encaptab *ep;
|
||||
|
||||
if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d))
|
||||
return 0;
|
||||
if (sp->sa_family != ep->af || dp->sa_family != ep->af)
|
||||
return 0;
|
||||
if (sp->sa_len != ep->src.ss_len || dp->sa_len != ep->dst.ss_len)
|
||||
return 0;
|
||||
|
||||
matchlen = 0;
|
||||
|
||||
p = (const u_int8_t *)sp;
|
||||
q = (const u_int8_t *)&ep->srcmask;
|
||||
r = (u_int8_t *)&s;
|
||||
for (i = 0 ; i < sp->sa_len; i++) {
|
||||
r[i] = p[i] & q[i];
|
||||
/* XXX estimate */
|
||||
matchlen += (q[i] ? 8 : 0);
|
||||
}
|
||||
|
||||
p = (const u_int8_t *)dp;
|
||||
q = (const u_int8_t *)&ep->dstmask;
|
||||
r = (u_int8_t *)&d;
|
||||
for (i = 0 ; i < dp->sa_len; i++) {
|
||||
r[i] = p[i] & q[i];
|
||||
/* XXX rough estimate */
|
||||
matchlen += (q[i] ? 8 : 0);
|
||||
}
|
||||
|
||||
/* need to overwrite len/family portion as we don't compare them */
|
||||
s.ss_len = sp->sa_len;
|
||||
s.ss_family = sp->sa_family;
|
||||
d.ss_len = dp->sa_len;
|
||||
d.ss_family = dp->sa_family;
|
||||
|
||||
if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 &&
|
||||
bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) {
|
||||
return matchlen;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
encap_fillarg(struct mbuf *m, void *arg)
|
||||
{
|
||||
struct m_tag *tag;
|
||||
|
||||
if (arg != NULL) {
|
||||
tag = m_tag_get(PACKET_TAG_ENCAP, sizeof(void *), M_NOWAIT);
|
||||
if (tag != NULL) {
|
||||
*(void**)(tag+1) = arg;
|
||||
m_tag_prepend(m, tag);
|
||||
ENCAP_WLOCK();
|
||||
CK_LIST_FOREACH(ep, head, chain) {
|
||||
if (ep == cookie) {
|
||||
CK_LIST_REMOVE(ep, chain);
|
||||
ENCAP_WUNLOCK();
|
||||
ENCAP_WAIT();
|
||||
free(ep, M_NETADDR);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
ENCAP_WUNLOCK();
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
void *
|
||||
encap_getarg(struct mbuf *m)
|
||||
static int
|
||||
encap_input(struct encaptab_head *head, struct mbuf *m, int off, int proto)
|
||||
{
|
||||
void *p = NULL;
|
||||
struct m_tag *tag;
|
||||
struct encaptab *ep, *match;
|
||||
void *arg;
|
||||
int matchprio, ret;
|
||||
|
||||
tag = m_tag_find(m, PACKET_TAG_ENCAP, NULL);
|
||||
if (tag) {
|
||||
p = *(void**)(tag+1);
|
||||
m_tag_delete(m, tag);
|
||||
match = NULL;
|
||||
matchprio = 0;
|
||||
|
||||
ENCAP_RLOCK();
|
||||
CK_LIST_FOREACH(ep, head, chain) {
|
||||
if (ep->proto >= 0 && ep->proto != proto)
|
||||
continue;
|
||||
if (ep->min_length > m->m_pkthdr.len)
|
||||
continue;
|
||||
if (ep->exact_match == ENCAP_DRV_LOOKUP)
|
||||
ret = (*ep->lookup)(m, off, proto, &arg);
|
||||
else
|
||||
ret = (*ep->check)(m, off, proto, ep->arg);
|
||||
if (ret <= 0)
|
||||
continue;
|
||||
if (ret > matchprio) {
|
||||
match = ep;
|
||||
if (ep->exact_match != ENCAP_DRV_LOOKUP)
|
||||
arg = ep->arg;
|
||||
/*
|
||||
* No need to continue the search, we got the
|
||||
* exact match.
|
||||
*/
|
||||
if (ret >= ep->exact_match)
|
||||
break;
|
||||
matchprio = ret;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
|
||||
if (match != NULL) {
|
||||
/* found a match, "match" has the best one */
|
||||
ret = (*match->input)(m, off, proto, arg);
|
||||
ENCAP_RUNLOCK();
|
||||
MPASS(ret == IPPROTO_DONE);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
ENCAP_RUNLOCK();
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
const struct encaptab *
|
||||
ip_encap_attach(const struct encap_config *cfg, void *arg, int mflags)
|
||||
{
|
||||
|
||||
return (encap_attach(&ipv4_encaptab, cfg, arg, mflags));
|
||||
}
|
||||
|
||||
int
|
||||
ip_encap_detach(const struct encaptab *cookie)
|
||||
{
|
||||
|
||||
return (encap_detach(&ipv4_encaptab, cookie));
|
||||
}
|
||||
|
||||
int
|
||||
encap4_input(struct mbuf **mp, int *offp, int proto)
|
||||
{
|
||||
|
||||
if (encap_input(&ipv4_encaptab, *mp, *offp, proto) != IPPROTO_DONE)
|
||||
return (rip_input(mp, offp, proto));
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
#ifdef INET6
|
||||
const struct encaptab *
|
||||
ip6_encap_attach(const struct encap_config *cfg, void *arg, int mflags)
|
||||
{
|
||||
|
||||
return (encap_attach(&ipv6_encaptab, cfg, arg, mflags));
|
||||
}
|
||||
|
||||
int
|
||||
ip6_encap_detach(const struct encaptab *cookie)
|
||||
{
|
||||
|
||||
return (encap_detach(&ipv6_encaptab, cookie));
|
||||
}
|
||||
|
||||
int
|
||||
encap6_input(struct mbuf **mp, int *offp, int proto)
|
||||
{
|
||||
|
||||
if (encap_input(&ipv6_encaptab, *mp, *offp, proto) != IPPROTO_DONE)
|
||||
return (rip6_input(mp, offp, proto));
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
@ -5,6 +5,7 @@
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||
* Copyright (c) 2018 Andrey V. Elsukov <ae@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -37,29 +38,33 @@
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
struct encaptab {
|
||||
LIST_ENTRY(encaptab) chain;
|
||||
int af;
|
||||
int proto; /* -1: don't care, I'll check myself */
|
||||
struct sockaddr_storage src; /* my addr */
|
||||
struct sockaddr_storage srcmask;
|
||||
struct sockaddr_storage dst; /* remote addr */
|
||||
struct sockaddr_storage dstmask;
|
||||
int (*func)(const struct mbuf *, int, int, void *);
|
||||
const struct protosw *psw; /* only pr_input will be used */
|
||||
void *arg; /* passed via m->m_pkthdr.aux */
|
||||
};
|
||||
|
||||
int encap4_input(struct mbuf **, int *, int);
|
||||
int encap6_input(struct mbuf **, int *, int);
|
||||
const struct encaptab *encap_attach(int, int, const struct sockaddr *,
|
||||
const struct sockaddr *, const struct sockaddr *,
|
||||
const struct sockaddr *, const struct protosw *, void *);
|
||||
const struct encaptab *encap_attach_func(int, int,
|
||||
int (*)(const struct mbuf *, int, int, void *),
|
||||
const struct protosw *, void *);
|
||||
int encap_detach(const struct encaptab *);
|
||||
void *encap_getarg(struct mbuf *);
|
||||
|
||||
typedef int (*encap_lookup_t)(const struct mbuf *, int, int, void **);
|
||||
typedef int (*encap_check_t)(const struct mbuf *, int, int, void *);
|
||||
typedef int (*encap_input_t)(struct mbuf *, int , int, void *);
|
||||
|
||||
struct encap_config {
|
||||
int proto; /* protocol */
|
||||
int min_length; /* minimum packet length */
|
||||
int exact_match; /* a packet is exactly matched */
|
||||
#define ENCAP_DRV_LOOKUP 0x7fffffff
|
||||
|
||||
encap_lookup_t lookup;
|
||||
encap_check_t check;
|
||||
encap_input_t input;
|
||||
};
|
||||
|
||||
struct encaptab;
|
||||
|
||||
const struct encaptab *ip_encap_attach(const struct encap_config *,
|
||||
void *arg, int mflags);
|
||||
const struct encaptab *ip6_encap_attach(const struct encap_config *,
|
||||
void *arg, int mflags);
|
||||
|
||||
int ip_encap_detach(const struct encaptab *);
|
||||
int ip6_encap_detach(const struct encaptab *);
|
||||
#endif
|
||||
|
||||
#endif /*_NETINET_IP_ENCAP_H_*/
|
||||
|
@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -69,24 +68,11 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <net/if_gre.h>
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static const struct protosw in_gre_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = IPPROTO_GRE,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = gre_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctlinput = rip_ctlinput,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
|
||||
#define GRE_TTL 30
|
||||
VNET_DEFINE(int, ip_gre_ttl) = GRE_TTL;
|
||||
#define V_ip_gre_ttl VNET(ip_gre_ttl)
|
||||
SYSCTL_INT(_net_inet_ip, OID_AUTO, grettl, CTLFLAG_VNET | CTLFLAG_RW,
|
||||
&VNET_NAME(ip_gre_ttl), 0, "");
|
||||
&VNET_NAME(ip_gre_ttl), 0, "Default TTL value for encapsulated packets");
|
||||
|
||||
static int
|
||||
in_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
@ -100,12 +86,6 @@ in_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
return (0);
|
||||
|
||||
M_ASSERTPKTHDR(m);
|
||||
/*
|
||||
* We expect that payload contains at least IPv4
|
||||
* or IPv6 packet.
|
||||
*/
|
||||
if (m->m_pkthdr.len < sizeof(struct greip) + sizeof(struct ip))
|
||||
return (0);
|
||||
|
||||
GRE_RLOCK(sc);
|
||||
if (sc->gre_family == 0)
|
||||
@ -120,7 +100,7 @@ in_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
goto bad;
|
||||
|
||||
GRE_RUNLOCK(sc);
|
||||
return (32 * 2);
|
||||
return (32 * 3); /* src + dst + gre_hdr */
|
||||
bad:
|
||||
GRE_RUNLOCK(sc);
|
||||
return (0);
|
||||
@ -156,14 +136,19 @@ in_gre_output(struct mbuf *m, int af, int hlen)
|
||||
return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL));
|
||||
}
|
||||
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = IPPROTO_GRE,
|
||||
.min_length = sizeof(struct greip) + sizeof(struct ip),
|
||||
.exact_match = (sizeof(in_addr_t) << 4) + 32,
|
||||
.check = in_gre_encapcheck,
|
||||
.input = gre_input
|
||||
};
|
||||
|
||||
int
|
||||
in_gre_attach(struct gre_softc *sc)
|
||||
{
|
||||
|
||||
KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL"));
|
||||
sc->gre_ecookie = encap_attach_func(AF_INET, IPPROTO_GRE,
|
||||
in_gre_encapcheck, &in_gre_protosw, sc);
|
||||
if (sc->gre_ecookie == NULL)
|
||||
return (EEXIST);
|
||||
sc->gre_ecookie = ip_encap_attach(&ipv4_encap_cfg, sc, M_WAITOK);
|
||||
return (0);
|
||||
}
|
||||
|
@ -242,20 +242,17 @@ SYSCTL_ULONG(_net_inet_pim, OID_AUTO, squelch_wholepkt, CTLFLAG_RW,
|
||||
&pim_squelch_wholepkt, 0,
|
||||
"Disable IGMP_WHOLEPKT notifications if rendezvous point is unspecified");
|
||||
|
||||
extern struct domain inetdomain;
|
||||
static const struct protosw in_pim_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = IPPROTO_PIM,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
.pr_input = pim_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
static const struct encaptab *pim_encap_cookie;
|
||||
|
||||
static int pim_encapcheck(const struct mbuf *, int, int, void *);
|
||||
static int pim_input(struct mbuf *, int, int, void *);
|
||||
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = IPPROTO_PIM,
|
||||
.min_length = sizeof(struct ip) + PIM_MINLEN,
|
||||
.exact_match = 8,
|
||||
.check = pim_encapcheck,
|
||||
.input = pim_input
|
||||
};
|
||||
|
||||
/*
|
||||
* Note: the PIM Register encapsulation adds the following in front of a
|
||||
@ -2544,16 +2541,12 @@ pim_register_send_rp(struct ip *ip, struct vif *vifp, struct mbuf *mb_copy,
|
||||
* into the kernel.
|
||||
*/
|
||||
static int
|
||||
pim_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
pim_encapcheck(const struct mbuf *m __unused, int off __unused,
|
||||
int proto __unused, void *arg __unused)
|
||||
{
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
KASSERT(proto == IPPROTO_PIM, ("not for IPPROTO_PIM"));
|
||||
#endif
|
||||
if (proto != IPPROTO_PIM)
|
||||
return 0; /* not for us; reject the datagram. */
|
||||
|
||||
return 64; /* claim the datagram. */
|
||||
return (8); /* claim the datagram. */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2564,18 +2557,15 @@ pim_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
* (used by PIM-SM): the PIM header is stripped off, and the inner packet
|
||||
* is passed to if_simloop().
|
||||
*/
|
||||
int
|
||||
pim_input(struct mbuf **mp, int *offp, int proto)
|
||||
static int
|
||||
pim_input(struct mbuf *m, int off, int proto, void *arg __unused)
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
struct ip *ip = mtod(m, struct ip *);
|
||||
struct pim *pim;
|
||||
int iphlen = *offp;
|
||||
int iphlen = off;
|
||||
int minlen;
|
||||
int datalen = ntohs(ip->ip_len) - iphlen;
|
||||
int ip_tos;
|
||||
|
||||
*mp = NULL;
|
||||
|
||||
/* Keep statistics */
|
||||
PIMSTAT_INC(pims_rcv_total_msgs);
|
||||
@ -2779,10 +2769,7 @@ pim_input(struct mbuf **mp, int *offp, int proto)
|
||||
* XXX: the outer IP header pkt size of a Register is not adjust to
|
||||
* reflect the fact that the inner multicast data is truncated.
|
||||
*/
|
||||
*mp = m;
|
||||
rip_input(mp, offp, proto);
|
||||
|
||||
return (IPPROTO_DONE);
|
||||
return (rip_input(&m, &off, proto));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2873,8 +2860,7 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
TUNABLE_ULONG_FETCH("net.inet.pim.squelch_wholepkt",
|
||||
&pim_squelch_wholepkt);
|
||||
|
||||
pim_encap_cookie = encap_attach_func(AF_INET, IPPROTO_PIM,
|
||||
pim_encapcheck, &in_pim_protosw, NULL);
|
||||
pim_encap_cookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK);
|
||||
if (pim_encap_cookie == NULL) {
|
||||
printf("ip_mroute: unable to attach pim encap\n");
|
||||
VIF_LOCK_DESTROY();
|
||||
@ -2917,7 +2903,7 @@ ip_mroute_modevent(module_t mod, int type, void *unused)
|
||||
EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag);
|
||||
|
||||
if (pim_encap_cookie) {
|
||||
encap_detach(pim_encap_cookie);
|
||||
ip_encap_detach(pim_encap_cookie);
|
||||
pim_encap_cookie = NULL;
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,6 @@ struct pimstat {
|
||||
#define PIMCTL_STATS 1 /* statistics (read-only) */
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
int pim_input(struct mbuf **, int *, int);
|
||||
SYSCTL_DECL(_net_inet_pim);
|
||||
#endif
|
||||
|
||||
|
@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/queue.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
@ -81,22 +80,9 @@ static VNET_DEFINE(int, ip6_gif_hlim) = GIF_HLIM;
|
||||
#define V_ip6_gif_hlim VNET(ip6_gif_hlim)
|
||||
|
||||
SYSCTL_DECL(_net_inet6_ip6);
|
||||
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim, CTLFLAG_VNET | CTLFLAG_RW,
|
||||
&VNET_NAME(ip6_gif_hlim), 0, "");
|
||||
|
||||
static int in6_gif_input(struct mbuf **, int *, int);
|
||||
|
||||
extern struct domain inet6domain;
|
||||
static struct protosw 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
|
||||
};
|
||||
SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim,
|
||||
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(ip6_gif_hlim), 0,
|
||||
"Default hop limit for encapsulated packets");
|
||||
|
||||
int
|
||||
in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
|
||||
@ -147,15 +133,13 @@ in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
|
||||
}
|
||||
|
||||
static int
|
||||
in6_gif_input(struct mbuf **mp, int *offp, int proto)
|
||||
in6_gif_input(struct mbuf *m, int off, int proto, void *arg)
|
||||
{
|
||||
struct mbuf *m = *mp;
|
||||
struct gif_softc *sc = arg;
|
||||
struct ifnet *gifp;
|
||||
struct gif_softc *sc;
|
||||
struct ip6_hdr *ip6;
|
||||
uint8_t ecn;
|
||||
|
||||
sc = encap_getarg(m);
|
||||
if (sc == NULL) {
|
||||
m_freem(m);
|
||||
IP6STAT_INC(ip6s_nogif);
|
||||
@ -165,7 +149,7 @@ in6_gif_input(struct mbuf **mp, int *offp, int proto)
|
||||
if ((gifp->if_flags & IFF_UP) != 0) {
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
ecn = (ntohl(ip6->ip6_flow) >> 20) & 0xff;
|
||||
m_adj(m, *offp);
|
||||
m_adj(m, off);
|
||||
gif_input(m, gifp, proto, ecn);
|
||||
} else {
|
||||
m_freem(m);
|
||||
@ -219,14 +203,19 @@ in6_gif_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static const struct encap_config ipv6_encap_cfg = {
|
||||
.proto = -1,
|
||||
.min_length = sizeof(struct ip6_hdr),
|
||||
.exact_match = (sizeof(struct in6_addr) << 4) + 8,
|
||||
.check = gif_encapcheck,
|
||||
.input = in6_gif_input
|
||||
};
|
||||
|
||||
int
|
||||
in6_gif_attach(struct gif_softc *sc)
|
||||
{
|
||||
|
||||
KASSERT(sc->gif_ecookie == NULL, ("gif_ecookie isn't NULL"));
|
||||
sc->gif_ecookie = encap_attach_func(AF_INET6, -1, gif_encapcheck,
|
||||
(void *)&in6_gif_protosw, sc);
|
||||
if (sc->gif_ecookie == NULL)
|
||||
return (EEXIST);
|
||||
sc->gif_ecookie = ip6_encap_attach(&ipv6_encap_cfg, sc, M_WAITOK);
|
||||
return (0);
|
||||
}
|
||||
|
@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/queue.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <net/if.h>
|
||||
@ -61,18 +60,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet6/in6_var.h>
|
||||
#include <net/if_gre.h>
|
||||
|
||||
extern struct domain inet6domain;
|
||||
struct protosw in6_gre_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = IPPROTO_GRE,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR,
|
||||
.pr_input = gre_input,
|
||||
.pr_output = rip6_output,
|
||||
.pr_ctloutput = rip6_ctloutput,
|
||||
.pr_usrreqs = &rip6_usrreqs
|
||||
};
|
||||
|
||||
VNET_DEFINE(int, ip6_gre_hlim) = IPV6_DEFHLIM;
|
||||
#define V_ip6_gre_hlim VNET(ip6_gre_hlim)
|
||||
|
||||
@ -117,7 +104,7 @@ in6_gre_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
goto bad;
|
||||
|
||||
GRE_RUNLOCK(sc);
|
||||
return (128 * 2);
|
||||
return (128 * 2 + 32);
|
||||
bad:
|
||||
GRE_RUNLOCK(sc);
|
||||
return (0);
|
||||
@ -133,14 +120,19 @@ in6_gre_output(struct mbuf *m, int af, int hlen)
|
||||
return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
static const struct encap_config ipv6_encap_cfg = {
|
||||
.proto = IPPROTO_GRE,
|
||||
.min_length = sizeof(struct greip6) + sizeof(struct ip),
|
||||
.exact_match = (sizeof(struct in6_addr) << 4) + 32,
|
||||
.check = in6_gre_encapcheck,
|
||||
.input = gre_input
|
||||
};
|
||||
|
||||
int
|
||||
in6_gre_attach(struct gre_softc *sc)
|
||||
{
|
||||
|
||||
KASSERT(sc->gre_ecookie == NULL, ("gre_ecookie isn't NULL"));
|
||||
sc->gre_ecookie = encap_attach_func(AF_INET6, IPPROTO_GRE,
|
||||
in6_gre_encapcheck, &in6_gre_protosw, sc);
|
||||
if (sc->gre_ecookie == NULL)
|
||||
return (EEXIST);
|
||||
sc->gre_ecookie = ip6_encap_attach(&ipv6_encap_cfg, sc, M_WAITOK);
|
||||
return (0);
|
||||
}
|
||||
|
@ -109,7 +109,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/raw_cb.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
@ -139,17 +138,17 @@ extern int in6_mcast_loop;
|
||||
extern struct domain inet6domain;
|
||||
|
||||
static const struct encaptab *pim6_encap_cookie;
|
||||
static const struct protosw in6_pim_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = IPPROTO_PIM,
|
||||
.pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR,
|
||||
.pr_input = pim6_input,
|
||||
.pr_output = rip6_output,
|
||||
.pr_ctloutput = rip6_ctloutput,
|
||||
.pr_usrreqs = &rip6_usrreqs
|
||||
};
|
||||
static int pim6_encapcheck(const struct mbuf *, int, int, void *);
|
||||
static int pim6_input(struct mbuf *, int, int, void *);
|
||||
|
||||
static const struct encap_config ipv6_encap_cfg = {
|
||||
.proto = IPPROTO_PIM,
|
||||
.min_length = sizeof(struct ip6_hdr) + PIM_MINLEN,
|
||||
.exact_match = 8,
|
||||
.check = pim6_encapcheck,
|
||||
.input = pim6_input
|
||||
};
|
||||
|
||||
|
||||
static VNET_DEFINE(int, ip6_mrouter_ver) = 0;
|
||||
#define V_ip6_mrouter_ver VNET(ip6_mrouter_ver)
|
||||
@ -1695,16 +1694,12 @@ register_send(struct ip6_hdr *ip6, struct mif6 *mif, struct mbuf *m)
|
||||
* into the kernel.
|
||||
*/
|
||||
static int
|
||||
pim6_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
pim6_encapcheck(const struct mbuf *m __unused, int off __unused,
|
||||
int proto __unused, void *arg __unused)
|
||||
{
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
KASSERT(proto == IPPROTO_PIM, ("not for IPPROTO_PIM"));
|
||||
#endif
|
||||
if (proto != IPPROTO_PIM)
|
||||
return 0; /* not for us; reject the datagram. */
|
||||
|
||||
return 64; /* claim the datagram. */
|
||||
return (8); /* claim the datagram. */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1714,20 +1709,18 @@ pim6_encapcheck(const struct mbuf *m, int off, int proto, void *arg)
|
||||
* The only message processed is the REGISTER pim message; the pim header
|
||||
* is stripped off, and the inner packet is passed to register_mforward.
|
||||
*/
|
||||
int
|
||||
pim6_input(struct mbuf **mp, int *offp, int proto)
|
||||
static int
|
||||
pim6_input(struct mbuf *m, int off, int proto, void *arg __unused)
|
||||
{
|
||||
struct pim *pim; /* pointer to a pim struct */
|
||||
struct ip6_hdr *ip6;
|
||||
int pimlen;
|
||||
struct mbuf *m = *mp;
|
||||
int minlen;
|
||||
int off = *offp;
|
||||
|
||||
PIM6STAT_INC(pim6s_rcv_total);
|
||||
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
pimlen = m->m_pkthdr.len - *offp;
|
||||
pimlen = m->m_pkthdr.len - off;
|
||||
|
||||
/*
|
||||
* Validate lengths
|
||||
@ -1904,8 +1897,7 @@ pim6_input(struct mbuf **mp, int *offp, int proto)
|
||||
* encapsulated ip6 header.
|
||||
*/
|
||||
pim6_input_to_daemon:
|
||||
rip6_input(&m, offp, proto);
|
||||
return (IPPROTO_DONE);
|
||||
return (rip6_input(&m, &off, proto));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1918,9 +1910,8 @@ ip6_mroute_modevent(module_t mod, int type, void *unused)
|
||||
MFC6_LOCK_INIT();
|
||||
MIF6_LOCK_INIT();
|
||||
|
||||
pim6_encap_cookie = encap_attach_func(AF_INET6, IPPROTO_PIM,
|
||||
pim6_encapcheck,
|
||||
(const struct protosw *)&in6_pim_protosw, NULL);
|
||||
pim6_encap_cookie = ip6_encap_attach(&ipv6_encap_cfg,
|
||||
NULL, M_WAITOK);
|
||||
if (pim6_encap_cookie == NULL) {
|
||||
printf("ip6_mroute: unable to attach pim6 encap\n");
|
||||
MIF6_LOCK_DESTROY();
|
||||
@ -1941,7 +1932,7 @@ ip6_mroute_modevent(module_t mod, int type, void *unused)
|
||||
return EINVAL;
|
||||
|
||||
if (pim6_encap_cookie) {
|
||||
encap_detach(pim6_encap_cookie);
|
||||
ip6_encap_detach(pim6_encap_cookie);
|
||||
pim6_encap_cookie = NULL;
|
||||
}
|
||||
X_ip6_mrouter_done();
|
||||
|
@ -53,10 +53,6 @@ struct pim6stat {
|
||||
uint64_t pim6s_snd_registers; /* sent registers */
|
||||
};
|
||||
|
||||
#if (defined(KERNEL)) || (defined(_KERNEL))
|
||||
int pim6_input(struct mbuf **, int*, int);
|
||||
#endif /* KERNEL */
|
||||
|
||||
/*
|
||||
* Identifiers for PIM sysctl nodes
|
||||
*/
|
||||
|
@ -118,7 +118,7 @@ ipcomp_encapcheck(union sockaddr_union *src, union sockaddr_union *dst)
|
||||
}
|
||||
|
||||
static int
|
||||
ipcomp_nonexp_input(struct mbuf **mp, int *offp, int proto)
|
||||
ipcomp_nonexp_input(struct mbuf *m, int off, int proto, void *arg __unused)
|
||||
{
|
||||
int isr;
|
||||
|
||||
@ -135,13 +135,13 @@ ipcomp_nonexp_input(struct mbuf **mp, int *offp, int proto)
|
||||
#endif
|
||||
default:
|
||||
IPCOMPSTAT_INC(ipcomps_nopf);
|
||||
m_freem(*mp);
|
||||
m_freem(m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
m_adj(*mp, *offp);
|
||||
IPCOMPSTAT_ADD(ipcomps_ibytes, (*mp)->m_pkthdr.len);
|
||||
m_adj(m, off);
|
||||
IPCOMPSTAT_ADD(ipcomps_ibytes, m->m_pkthdr.len);
|
||||
IPCOMPSTAT_INC(ipcomps_input);
|
||||
netisr_dispatch(isr, *mp);
|
||||
netisr_dispatch(isr, m);
|
||||
return (IPPROTO_DONE);
|
||||
}
|
||||
|
||||
@ -662,19 +662,6 @@ ipcomp_output_cb(struct cryptop *crp)
|
||||
}
|
||||
|
||||
#ifdef INET
|
||||
static const struct encaptab *ipe4_cookie = NULL;
|
||||
extern struct domain inetdomain;
|
||||
static struct protosw ipcomp4_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inetdomain,
|
||||
.pr_protocol = 0 /* IPPROTO_IPV[46] */,
|
||||
.pr_flags = PR_ATOMIC | PR_ADDR | PR_LASTHDR,
|
||||
.pr_input = ipcomp_nonexp_input,
|
||||
.pr_output = rip_output,
|
||||
.pr_ctloutput = rip_ctloutput,
|
||||
.pr_usrreqs = &rip_usrreqs
|
||||
};
|
||||
|
||||
static int
|
||||
ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
|
||||
void *arg __unused)
|
||||
@ -695,21 +682,17 @@ ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
|
||||
dst.sin.sin_addr = ip->ip_dst;
|
||||
return (ipcomp_encapcheck(&src, &dst));
|
||||
}
|
||||
|
||||
static const struct encaptab *ipe4_cookie = NULL;
|
||||
static const struct encap_config ipv4_encap_cfg = {
|
||||
.proto = -1,
|
||||
.min_length = sizeof(struct ip),
|
||||
.exact_match = sizeof(in_addr_t) << 4,
|
||||
.check = ipcomp4_nonexp_encapcheck,
|
||||
.input = ipcomp_nonexp_input
|
||||
};
|
||||
#endif
|
||||
#ifdef INET6
|
||||
static const struct encaptab *ipe6_cookie = NULL;
|
||||
extern struct domain inet6domain;
|
||||
static struct protosw ipcomp6_protosw = {
|
||||
.pr_type = SOCK_RAW,
|
||||
.pr_domain = &inet6domain,
|
||||
.pr_protocol = 0 /* IPPROTO_IPV[46] */,
|
||||
.pr_flags = PR_ATOMIC | PR_ADDR | PR_LASTHDR,
|
||||
.pr_input = ipcomp_nonexp_input,
|
||||
.pr_output = rip6_output,
|
||||
.pr_ctloutput = rip6_ctloutput,
|
||||
.pr_usrreqs = &rip6_usrreqs
|
||||
};
|
||||
|
||||
static int
|
||||
ipcomp6_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
|
||||
void *arg __unused)
|
||||
@ -742,6 +725,15 @@ ipcomp6_nonexp_encapcheck(const struct mbuf *m, int off, int proto,
|
||||
}
|
||||
return (ipcomp_encapcheck(&src, &dst));
|
||||
}
|
||||
|
||||
static const struct encaptab *ipe6_cookie = NULL;
|
||||
static const struct encap_config ipv6_encap_cfg = {
|
||||
.proto = -1,
|
||||
.min_length = sizeof(struct ip6_hdr),
|
||||
.exact_match = sizeof(struct in6_addr) << 4,
|
||||
.check = ipcomp6_nonexp_encapcheck,
|
||||
.input = ipcomp_nonexp_input
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct xformsw ipcomp_xformsw = {
|
||||
@ -758,12 +750,10 @@ ipcomp_attach(void)
|
||||
{
|
||||
|
||||
#ifdef INET
|
||||
ipe4_cookie = encap_attach_func(AF_INET, -1,
|
||||
ipcomp4_nonexp_encapcheck, &ipcomp4_protosw, NULL);
|
||||
ipe4_cookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
ipe6_cookie = encap_attach_func(AF_INET6, -1,
|
||||
ipcomp6_nonexp_encapcheck, &ipcomp6_protosw, NULL);
|
||||
ipe6_cookie = ip6_encap_attach(&ipv6_encap_cfg, NULL, M_WAITOK);
|
||||
#endif
|
||||
xform_attach(&ipcomp_xformsw);
|
||||
}
|
||||
@ -773,10 +763,10 @@ ipcomp_detach(void)
|
||||
{
|
||||
|
||||
#ifdef INET
|
||||
encap_detach(ipe4_cookie);
|
||||
ip_encap_detach(ipe4_cookie);
|
||||
#endif
|
||||
#ifdef INET6
|
||||
encap_detach(ipe6_cookie);
|
||||
ip6_encap_detach(ipe6_cookie);
|
||||
#endif
|
||||
xform_detach(&ipcomp_xformsw);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user