diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c index 011ad7aedea..7c212b3cf18 100644 --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -927,8 +927,20 @@ gif_detach(struct gif_softc *sc) { sx_assert(&gif_ioctl_sx, SA_XLOCKED); - if (sc->gif_ecookie != NULL) - encap_detach(sc->gif_ecookie); + if (sc->gif_ecookie != NULL) { + switch (sc->gif_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; } diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c index a3e578e4cad..5de1a7c2883 100644 --- a/sys/net/if_gre.c +++ b/sys/net/if_gre.c @@ -555,8 +555,20 @@ gre_detach(struct gre_softc *sc) { sx_assert(&gre_ioctl_sx, SA_XLOCKED); - if (sc->gre_ecookie != NULL) - encap_detach(sc->gre_ecookie); + if (sc->gre_ecookie != NULL) { + switch (sc->gre_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; } diff --git a/sys/net/if_me.c b/sys/net/if_me.c index 4ab013bdcce..65fa596fdc6 100644 --- a/sys/net/if_me.c +++ b/sys/net/if_me.c @@ -37,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -140,19 +139,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) { @@ -376,8 +362,10 @@ 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(IPPROTO_MOBILE, + sizeof(struct ip) + sizeof(struct mobhdr) - + sizeof(in_addr_t), sizeof(in_addr_t) << 4, + me_encapcheck, me_input, 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 +380,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; diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c index b10202076d0..bfd70f2db2e 100644 --- a/sys/net/if_stf.c +++ b/sys/net/if_stf.c @@ -85,7 +85,6 @@ #include #include #include -#include #include #include #include @@ -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 char *stfnames[] = {"stf0", "stf", "6to4", NULL}; static int stfmodevent(module_t, int, void *); @@ -250,8 +237,9 @@ 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(IPPROTO_IPV6, sizeof(struct ip), + sizeof(in_addr_t) << 3, stf_encapcheck, in_stf_input, sc, + M_WAITOK); if (sc->encap_cookie == NULL) { if_printf(ifp, "attach failed\n"); free(sc, M_STF); @@ -274,7 +262,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); diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index c30709c878e..934e3e07021 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -47,7 +47,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -70,20 +69,6 @@ __FBSDID("$FreeBSD$"); #include -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) @@ -210,9 +195,8 @@ 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(-1, sizeof(struct ip), + sizeof(in_addr_t) << 4, gif_encapcheck, in_gif_input, sc, + M_WAITOK); return (0); } diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c index 82d46986e12..36650ba2980 100644 --- a/sys/netinet/ip_encap.c +++ b/sys/netinet/ip_encap.c @@ -3,6 +3,7 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * + * Copyright (c) 2018 Andrey V. Elsukov * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * @@ -56,417 +57,251 @@ * 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 __FBSDID("$FreeBSD$"); -#include "opt_mrouting.h" #include "opt_inet.h" #include "opt_inet6.h" #include #include +#include #include +#include #include -#include -#include #include #include -#include -#include +#include #include -#include +#include #include -#include -#include #include #include #ifdef INET6 -#include #include #endif -#include +static MALLOC_DEFINE(M_NETADDR, "encap_export_host", + "Export host address structure"); -#include -#include -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; + int (*match)(const struct mbuf *, int, int, void *); + int (*input)(struct mbuf **, int *, int); -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 *); + struct epoch_context epoch_ctx; +}; + +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); - -#ifdef INET -int -encap4_input(struct mbuf **mp, int *offp, int proto) +#define ENCAP_WLOCK() mtx_lock(&encapmtx) +#define ENCAP_WUNLOCK() mtx_unlock(&encapmtx) +#define ENCAP_RLOCK() NET_EPOCH_ENTER() +#define ENCAP_RUNLOCK() NET_EPOCH_EXIT() + +static struct encaptab * +encap_attach(struct encaptab_head *head, int proto, int min_length, + int exact_match, int (*match)(const struct mbuf *, int, int, void *), + int (*input)(struct mbuf **, int *, int), 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; - - 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); - } + struct encaptab *ep, *tmp; - /* - * 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 || input == NULL) + return (NULL); - 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); + ep = malloc(sizeof(*ep), M_NETADDR, mflags); + if (ep == NULL) + return (NULL); + + ep->proto = proto; + ep->min_length = min_length; + ep->exact_match = exact_match; + ep->arg = arg; + ep->match = match; + ep->input = input; + + ENCAP_WLOCK(); + CK_LIST_FOREACH(tmp, head, chain) { + if (tmp->exact_match <= exact_match) + break; } + if (tmp == NULL) + CK_LIST_INSERT_HEAD(head, ep, chain); + else + CK_LIST_INSERT_BEFORE(tmp, ep, chain); + ENCAP_WUNLOCK(); + return (ep); +} + +static void +encap_free(epoch_context_t ctx) +{ + struct encaptab *ep; - /* last resort: inject to raw socket */ - return (rip_input(mp, offp, proto)); + ep = __containerof(ctx, struct encaptab, epoch_ctx); + free(ep, M_NETADDR); } -#endif -#ifdef INET6 -int -encap6_input(struct mbuf **mp, int *offp, int proto) +static int +encap_detach(struct encaptab_head *head, const struct encaptab *cookie) { - 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); - } + struct encaptab *ep; - /* see encap4_input() for issues here */ - if (prio <= 0) - continue; - if (prio > matchprio) { - matchprio = prio; - match = ep; + ENCAP_WLOCK(); + CK_LIST_FOREACH(ep, head, chain) { + if (ep == cookie) { + CK_LIST_REMOVE(ep, chain); + ENCAP_WUNLOCK(); + epoch_call(net_epoch_preempt, &ep->epoch_ctx, + encap_free); + return (0); } } - if (match != NULL) { - psw = match->psw; - arg = match->arg; - } - mtx_unlock(&encapmtx); + ENCAP_WUNLOCK(); + return (EINVAL); +} - 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); +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); } } - - /* 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) +void * +encap_getarg(struct mbuf *m) { + void *p = NULL; + struct m_tag *tag; - mtx_assert(&encapmtx, MA_OWNED); - LIST_INSERT_HEAD(&encaptab, ep, chain); + tag = m_tag_find(m, PACKET_TAG_ENCAP, NULL); + if (tag) { + p = *(void**)(tag+1); + m_tag_delete(m, tag); + } + return (p); } -/* - * 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) +static int +encap_input(struct encaptab_head *head, struct mbuf **mp, int *offp, int proto) { - struct encaptab *ep; + struct encaptab *ep, *match; + int matchprio, ret; - /* 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) - return (NULL); + match = NULL; + matchprio = 0; - /* 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) + ENCAP_RLOCK(); + CK_LIST_FOREACH(ep, head, chain) { + if (ep->proto >= 0 && 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) + if (ep->min_length > (*mp)->m_pkthdr.len) 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) + ret = (*ep->match)(*mp, *offp, proto, ep->arg); + if (ret <= 0) continue; - - mtx_unlock(&encapmtx); - return (NULL); + if (ret > matchprio) { + match = ep; + /* + * No need to continue the search, we got the + * exact match. + */ + if (ret >= ep->exact_match) + break; + matchprio = ret; + } } - ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ - if (ep == NULL) { - mtx_unlock(&encapmtx); - return (NULL); + if (match != NULL) { + /* found a match, "match" has the best one */ + if (match->arg != NULL) + encap_fillarg(*mp, match->arg); + ret = (*match->input)(mp, offp, proto); + ENCAP_RUNLOCK(); + MPASS(ret == IPPROTO_DONE); + return (IPPROTO_DONE); } - 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); + ENCAP_RUNLOCK(); + return (0); } +#ifdef INET const struct encaptab * -encap_attach_func(int af, int proto, - int (*func)(const struct mbuf *, int, int, void *), - const struct protosw *psw, void *arg) +ip_encap_attach(int proto, int min_length, int exact_match, + int (*match)(const struct mbuf *, int, int, void *), + int (*input)(struct mbuf **, int *, int), void *arg, int mflags) { - struct encaptab *ep; - - /* sanity check on args */ - if (!func) - return (NULL); - ep = malloc(sizeof(*ep), M_NETADDR, M_NOWAIT); /*XXX*/ - if (ep == NULL) - return (NULL); - bzero(ep, sizeof(*ep)); + return (encap_attach(&ipv4_encaptab, proto, min_length, exact_match, + match, input, arg, mflags)); +} - ep->af = af; - ep->proto = proto; - ep->func = func; - ep->psw = psw; - ep->arg = arg; +int +ip_encap_detach(const struct encaptab *cookie) +{ - mtx_lock(&encapmtx); - encap_add(ep); - mtx_unlock(&encapmtx); - return (ep); + return (encap_detach(&ipv4_encaptab, cookie)); } int -encap_detach(const struct encaptab *cookie) +encap4_input(struct mbuf **mp, int *offp, int proto) { - 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; - } - } - mtx_unlock(&encapmtx); - return EINVAL; + if (encap_input(&ipv4_encaptab, mp, offp, proto) != IPPROTO_DONE) + return (rip_input(mp, offp, proto)); + return (IPPROTO_DONE); } +#endif -static int -mask_match(const struct encaptab *ep, const struct sockaddr *sp, - const struct sockaddr *dp) +#ifdef INET6 +const struct encaptab * +ip6_encap_attach(int proto, int min_length, int exact_match, + int (*match)(const struct mbuf *, int, int, void *), + int (*input)(struct mbuf **, int *, int), void *arg, int mflags) { - struct sockaddr_storage s; - struct sockaddr_storage d; - int i; - const u_int8_t *p, *q; - u_int8_t *r; - int matchlen; - - 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; + return (encap_attach(&ipv6_encaptab, proto, min_length, exact_match, + match, input, arg, mflags)); } -static void -encap_fillarg(struct mbuf *m, void *arg) +int +ip6_encap_detach(const struct encaptab *cookie) { - 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); - } - } + return (encap_detach(&ipv6_encaptab, cookie)); } -void * -encap_getarg(struct mbuf *m) +int +encap6_input(struct mbuf **mp, int *offp, int proto) { - void *p = NULL; - struct m_tag *tag; - tag = m_tag_find(m, PACKET_TAG_ENCAP, NULL); - if (tag) { - p = *(void**)(tag+1); - m_tag_delete(m, tag); - } - return p; + if (encap_input(&ipv6_encaptab, mp, offp, proto) != IPPROTO_DONE) + return (rip6_input(mp, offp, proto)); + return (IPPROTO_DONE); } +#endif + + diff --git a/sys/netinet/ip_encap.h b/sys/netinet/ip_encap.h index ef232189f39..7f70c0f869f 100644 --- a/sys/netinet/ip_encap.h +++ b/sys/netinet/ip_encap.h @@ -37,28 +37,21 @@ #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 */ -}; +struct encaptab; 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 *); + +const struct encaptab *ip_encap_attach(int proto, int min_length, + int exact_match, int (*match)(const struct mbuf *, int, int, void *), + int (*input)(struct mbuf **, int *, int), void *arg, int mflags); +int ip_encap_detach(const struct encaptab *); + +const struct encaptab *ip6_encap_attach(int proto, int min_length, + int exact_match, int (*match)(const struct mbuf *, int, int, void *), + int (*input)(struct mbuf **, int *, int), void *arg, int mflags); +int ip6_encap_detach(const struct encaptab *); + void *encap_getarg(struct mbuf *); #endif diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c index 5b865e07bc4..af84052c488 100644 --- a/sys/netinet/ip_gre.c +++ b/sys/netinet/ip_gre.c @@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include #include @@ -69,19 +68,6 @@ __FBSDID("$FreeBSD$"); #include -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) @@ -120,7 +106,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); @@ -161,9 +147,9 @@ 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(IPPROTO_GRE, + sizeof(struct greip) + sizeof(struct ip), + (2 * sizeof(in_addr_t) + 2 * sizeof(uint16_t)) << 3, + in_gre_encapcheck, gre_input, sc, M_WAITOK); return (0); } diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index fbf298fa54a..25d82a3ccd7 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -242,19 +242,7 @@ 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 *); /* @@ -2547,13 +2535,8 @@ static int pim_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { -#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 (64 + 8); /* claim the datagram. */ } /* @@ -2873,8 +2856,9 @@ 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(IPPROTO_PIM, + sizeof(struct ip) + PIM_MINLEN, (sizeof(in_addr_t) << 4) + 8, + pim_encapcheck, pim_input, NULL, M_WAITOK); if (pim_encap_cookie == NULL) { printf("ip_mroute: unable to attach pim encap\n"); VIF_LOCK_DESTROY(); @@ -2917,7 +2901,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; } diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c index e67d64eaf13..fc18efa3206 100644 --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -81,22 +80,8 @@ 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, ""); int in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn) @@ -224,9 +209,8 @@ 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(-1, sizeof(struct ip6_hdr), + sizeof(struct in6_addr) << 4, gif_encapcheck, in6_gif_input, sc, + M_WAITOK); return (0); } diff --git a/sys/netinet6/ip6_gre.c b/sys/netinet6/ip6_gre.c index 095a1deeb63..8ab3d233179 100644 --- a/sys/netinet6/ip6_gre.c +++ b/sys/netinet6/ip6_gre.c @@ -42,7 +42,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -61,18 +60,6 @@ __FBSDID("$FreeBSD$"); #include #include -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); @@ -138,9 +125,9 @@ 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(IPPROTO_GRE, + sizeof(struct greip6) + sizeof(struct ip), + (2 * sizeof(struct in6_addr) + 2 * sizeof(uint16_t)) << 3, + in6_gre_encapcheck, gre_input, sc, M_WAITOK); return (0); } diff --git a/sys/netinet6/ip6_mroute.c b/sys/netinet6/ip6_mroute.c index 524d35a27d9..92ec04375d0 100644 --- a/sys/netinet6/ip6_mroute.c +++ b/sys/netinet6/ip6_mroute.c @@ -109,7 +109,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include @@ -139,16 +138,6 @@ 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 VNET_DEFINE(int, ip6_mrouter_ver) = 0; @@ -1698,13 +1687,8 @@ static int pim6_encapcheck(const struct mbuf *m, int off, int proto, void *arg) { -#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 (128 + 8); /* claim the datagram. */ } /* @@ -1918,9 +1902,10 @@ 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(IPPROTO_PIM, + sizeof(struct ip6_hdr) + PIM_MINLEN, + (sizeof(struct in6_addr) << 4) + 8, + pim6_encapcheck, pim6_input, NULL, M_WAITOK); if (pim6_encap_cookie == NULL) { printf("ip6_mroute: unable to attach pim6 encap\n"); MIF6_LOCK_DESTROY(); @@ -1941,7 +1926,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(); diff --git a/sys/netipsec/xform_ipcomp.c b/sys/netipsec/xform_ipcomp.c index 7226e31dc19..2e54e149952 100644 --- a/sys/netipsec/xform_ipcomp.c +++ b/sys/netipsec/xform_ipcomp.c @@ -663,17 +663,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, @@ -698,17 +687,6 @@ ipcomp4_nonexp_encapcheck(const struct mbuf *m, int off, int proto, #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, @@ -758,12 +736,14 @@ ipcomp_attach(void) { #ifdef INET - ipe4_cookie = encap_attach_func(AF_INET, -1, - ipcomp4_nonexp_encapcheck, &ipcomp4_protosw, NULL); + ipe4_cookie = ip_encap_attach(-1, sizeof(struct ip), + sizeof(in_addr_t) << 4, ipcomp4_nonexp_encapcheck, + ipcomp_nonexp_input, 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(-1, sizeof(struct ip6_hdr), + sizeof(struct in6_addr) << 4, ipcomp6_nonexp_encapcheck, + ipcomp_nonexp_input, NULL, M_WAITOK); #endif xform_attach(&ipcomp_xformsw); } @@ -773,10 +753,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); }