1*77d6f587Sknakahara /* $NetBSD: ip_encap.c,v 1.77 2022/12/07 08:33:02 knakahara Exp $ */
228922b99Sitojun /* $KAME: ip_encap.c,v 1.73 2001/10/02 08:30:58 itojun Exp $ */
339091335Sitojun
439091335Sitojun /*
539091335Sitojun * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
639091335Sitojun * All rights reserved.
739091335Sitojun *
839091335Sitojun * Redistribution and use in source and binary forms, with or without
939091335Sitojun * modification, are permitted provided that the following conditions
1039091335Sitojun * are met:
1139091335Sitojun * 1. Redistributions of source code must retain the above copyright
1239091335Sitojun * notice, this list of conditions and the following disclaimer.
1339091335Sitojun * 2. Redistributions in binary form must reproduce the above copyright
1439091335Sitojun * notice, this list of conditions and the following disclaimer in the
1539091335Sitojun * documentation and/or other materials provided with the distribution.
1639091335Sitojun * 3. Neither the name of the project nor the names of its contributors
1739091335Sitojun * may be used to endorse or promote products derived from this software
1839091335Sitojun * without specific prior written permission.
1939091335Sitojun *
2039091335Sitojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
2139091335Sitojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2239091335Sitojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2339091335Sitojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
2439091335Sitojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2539091335Sitojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2639091335Sitojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2739091335Sitojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2839091335Sitojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2939091335Sitojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3039091335Sitojun * SUCH DAMAGE.
3139091335Sitojun */
3239091335Sitojun /*
3339091335Sitojun * My grandfather said that there's a devil inside tunnelling technology...
3439091335Sitojun *
3539091335Sitojun * We have surprisingly many protocols that want packets with IP protocol
3639091335Sitojun * #4 or #41. Here's a list of protocols that want protocol #41:
3739091335Sitojun * RFC1933 configured tunnel
3839091335Sitojun * RFC1933 automatic tunnel
3939091335Sitojun * RFC2401 IPsec tunnel
4039091335Sitojun * RFC2473 IPv6 generic packet tunnelling
4139091335Sitojun * RFC2529 6over4 tunnel
4228922b99Sitojun * RFC3056 6to4 tunnel
4328922b99Sitojun * isatap tunnel
4439091335Sitojun * mobile-ip6 (uses RFC2473)
4539091335Sitojun * Here's a list of protocol that want protocol #4:
4639091335Sitojun * RFC1853 IPv4-in-IPv4 tunnelling
4739091335Sitojun * RFC2003 IPv4 encapsulation within IPv4
4839091335Sitojun * RFC2344 reverse tunnelling for mobile-ip4
4939091335Sitojun * RFC2401 IPsec tunnel
5039091335Sitojun * Well, what can I say. They impose different en/decapsulation mechanism
5139091335Sitojun * from each other, so they need separate protocol handler. The only one
5239091335Sitojun * we can easily determine by protocol # is IPsec, which always has
5339091335Sitojun * AH/ESP/IPComp header right after outer IP header.
5439091335Sitojun *
5539091335Sitojun * So, clearly good old protosw does not work for protocol #4 and #41.
5639091335Sitojun * The code will let you match protocol via src/dst address pair.
5739091335Sitojun */
5839091335Sitojun /* XXX is M_NETADDR correct? */
5939091335Sitojun
60ea1cd7ebSlukem #include <sys/cdefs.h>
61*77d6f587Sknakahara __KERNEL_RCSID(0, "$NetBSD: ip_encap.c,v 1.77 2022/12/07 08:33:02 knakahara Exp $");
62ea1cd7ebSlukem
631c4a50f1Spooka #ifdef _KERNEL_OPT
6439091335Sitojun #include "opt_mrouting.h"
6539091335Sitojun #include "opt_inet.h"
666284b358Sknakahara #include "opt_net_mpsafe.h"
671c4a50f1Spooka #endif
6839091335Sitojun
6939091335Sitojun #include <sys/param.h>
7039091335Sitojun #include <sys/systm.h>
7139091335Sitojun #include <sys/socket.h>
728b6ba330Sknakahara #include <sys/socketvar.h> /* for softnet_lock */
7339091335Sitojun #include <sys/sockio.h>
7439091335Sitojun #include <sys/mbuf.h>
7539091335Sitojun #include <sys/errno.h>
76dcfe05e7Sitojun #include <sys/queue.h>
770072297aSknakahara #include <sys/kmem.h>
787899e09eSknakahara #include <sys/mutex.h>
79c544c867Sknakahara #include <sys/condvar.h>
807899e09eSknakahara #include <sys/psref.h>
817899e09eSknakahara #include <sys/pslist.h>
8238a7d489Sknakahara #include <sys/thmap.h>
8339091335Sitojun
8439091335Sitojun #include <net/if.h>
8539091335Sitojun
8639091335Sitojun #include <netinet/in.h>
8739091335Sitojun #include <netinet/in_systm.h>
8839091335Sitojun #include <netinet/ip.h>
8939091335Sitojun #include <netinet/ip_var.h>
9039091335Sitojun #include <netinet/ip_encap.h>
9139091335Sitojun #ifdef MROUTING
9239091335Sitojun #include <netinet/ip_mroute.h>
9339091335Sitojun #endif /* MROUTING */
9439091335Sitojun
9539091335Sitojun #ifdef INET6
9639091335Sitojun #include <netinet/ip6.h>
9739091335Sitojun #include <netinet6/ip6_var.h>
98b546d527Sknakahara #include <netinet6/ip6protosw.h> /* for struct ip6ctlparam */
9928922b99Sitojun #include <netinet6/in6_var.h>
10028922b99Sitojun #include <netinet6/in6_pcb.h>
10128922b99Sitojun #include <netinet/icmp6.h>
10239091335Sitojun #endif
10339091335Sitojun
1046284b358Sknakahara #ifdef NET_MPSAFE
1056284b358Sknakahara #define ENCAP_MPSAFE 1
1066284b358Sknakahara #endif
1076284b358Sknakahara
10828922b99Sitojun enum direction { INBOUND, OUTBOUND };
10928922b99Sitojun
11028922b99Sitojun #ifdef INET
1117899e09eSknakahara static struct encaptab *encap4_lookup(struct mbuf *, int, int, enum direction,
1127899e09eSknakahara struct psref *);
11328922b99Sitojun #endif
11428922b99Sitojun #ifdef INET6
1157899e09eSknakahara static struct encaptab *encap6_lookup(struct mbuf *, int, int, enum direction,
1167899e09eSknakahara struct psref *);
11728922b99Sitojun #endif
11834944823Sperry static int encap_add(struct encaptab *);
11934944823Sperry static int encap_remove(struct encaptab *);
120a14187ecSriastradh static void encap_afcheck(int, const struct sockaddr *, const struct sockaddr *);
12138a7d489Sknakahara static void encap_key_init(struct encap_key *, const struct sockaddr *,
12238a7d489Sknakahara const struct sockaddr *);
12338a7d489Sknakahara static void encap_key_inc(struct encap_key *);
12439091335Sitojun
1257899e09eSknakahara /*
1267899e09eSknakahara * In encap[46]_lookup(), ep->func can sleep(e.g. rtalloc1) while walking
1277899e09eSknakahara * encap_table. So, it cannot use pserialize_read_enter()
1287899e09eSknakahara */
1297899e09eSknakahara static struct {
1307899e09eSknakahara struct pslist_head list;
1317899e09eSknakahara pserialize_t psz;
1327899e09eSknakahara struct psref_class *elem_class; /* for the element of et_list */
1337899e09eSknakahara } encaptab __cacheline_aligned = {
1347899e09eSknakahara .list = PSLIST_INITIALIZER,
1357899e09eSknakahara };
1367899e09eSknakahara #define encap_table encaptab.list
13739091335Sitojun
138c544c867Sknakahara static struct {
139c544c867Sknakahara kmutex_t lock;
140c544c867Sknakahara kcondvar_t cv;
141c544c867Sknakahara struct lwp *busy;
142c544c867Sknakahara } encap_whole __cacheline_aligned;
143c544c867Sknakahara
14438a7d489Sknakahara static thmap_t *encap_map[2]; /* 0 for AF_INET, 1 for AF_INET6 */
14538a7d489Sknakahara
1460d787d11Sozaki-r static bool encap_initialized = false;
147c544c867Sknakahara /*
148c544c867Sknakahara * must be done before other encap interfaces initialization.
149c544c867Sknakahara */
150c544c867Sknakahara void
encapinit(void)151c544c867Sknakahara encapinit(void)
152c544c867Sknakahara {
153c544c867Sknakahara
1540d787d11Sozaki-r if (encap_initialized)
1550d787d11Sozaki-r return;
1560d787d11Sozaki-r
157d0e44f18Sknakahara encaptab.psz = pserialize_create();
158d0e44f18Sknakahara encaptab.elem_class = psref_class_create("encapelem", IPL_SOFTNET);
159d0e44f18Sknakahara
160c544c867Sknakahara mutex_init(&encap_whole.lock, MUTEX_DEFAULT, IPL_NONE);
161c544c867Sknakahara cv_init(&encap_whole.cv, "ip_encap cv");
162c544c867Sknakahara encap_whole.busy = NULL;
1630d787d11Sozaki-r
1640d787d11Sozaki-r encap_initialized = true;
165c544c867Sknakahara }
166c544c867Sknakahara
16739091335Sitojun void
encap_init(void)16851ad03a9Sperry encap_init(void)
16939091335Sitojun {
17028922b99Sitojun static int initialized = 0;
17128922b99Sitojun
17228922b99Sitojun if (initialized)
17328922b99Sitojun return;
17428922b99Sitojun initialized++;
17539091335Sitojun #if 0
17639091335Sitojun /*
17739091335Sitojun * we cannot use LIST_INIT() here, since drivers may want to call
178dcfe05e7Sitojun * encap_attach(), on driver attach. encap_init() will be called
17939091335Sitojun * on AF_INET{,6} initialization, which happens after driver
18039091335Sitojun * initialization - using LIST_INIT() here can nuke encap_attach()
18139091335Sitojun * from drivers.
18239091335Sitojun */
1837899e09eSknakahara PSLIST_INIT(&encap_table);
18439091335Sitojun #endif
18528922b99Sitojun
18638a7d489Sknakahara encap_map[0] = thmap_create(0, NULL, THMAP_NOCOPY);
18738a7d489Sknakahara #ifdef INET6
18838a7d489Sknakahara encap_map[1] = thmap_create(0, NULL, THMAP_NOCOPY);
18938a7d489Sknakahara #endif
19039091335Sitojun }
19139091335Sitojun
192dcfe05e7Sitojun #ifdef INET
19328922b99Sitojun static struct encaptab *
encap4_lookup(struct mbuf * m,int off,int proto,enum direction dir,struct psref * match_psref)1947899e09eSknakahara encap4_lookup(struct mbuf *m, int off, int proto, enum direction dir,
1957899e09eSknakahara struct psref *match_psref)
19639091335Sitojun {
19739091335Sitojun struct ip *ip;
198c6e7028dSpooka struct ip_pack4 pack;
19939091335Sitojun struct encaptab *ep, *match;
20039091335Sitojun int prio, matchprio;
2017899e09eSknakahara int s;
20238a7d489Sknakahara thmap_t *emap = encap_map[0];
20338a7d489Sknakahara struct encap_key key;
20439091335Sitojun
20573c17c4aSozaki-r KASSERT(m->m_len >= sizeof(*ip));
20673c17c4aSozaki-r
20739091335Sitojun ip = mtod(m, struct ip *);
20839091335Sitojun
209c363a9cbScegger memset(&pack, 0, sizeof(pack));
21028922b99Sitojun pack.p.sp_len = sizeof(pack);
21128922b99Sitojun pack.mine.sin_family = pack.yours.sin_family = AF_INET;
21228922b99Sitojun pack.mine.sin_len = pack.yours.sin_len = sizeof(struct sockaddr_in);
21328922b99Sitojun if (dir == INBOUND) {
21428922b99Sitojun pack.mine.sin_addr = ip->ip_dst;
21528922b99Sitojun pack.yours.sin_addr = ip->ip_src;
21628922b99Sitojun } else {
21728922b99Sitojun pack.mine.sin_addr = ip->ip_src;
21828922b99Sitojun pack.yours.sin_addr = ip->ip_dst;
21928922b99Sitojun }
22039091335Sitojun
22139091335Sitojun match = NULL;
22239091335Sitojun matchprio = 0;
22328922b99Sitojun
2247899e09eSknakahara s = pserialize_read_enter();
22538a7d489Sknakahara
22638a7d489Sknakahara encap_key_init(&key, sintosa(&pack.mine), sintosa(&pack.yours));
22738a7d489Sknakahara while ((ep = thmap_get(emap, &key, sizeof(key))) != NULL) {
22838a7d489Sknakahara struct psref elem_psref;
22938a7d489Sknakahara
23038a7d489Sknakahara KASSERT(ep->af == AF_INET);
23138a7d489Sknakahara
23238a7d489Sknakahara if (ep->proto >= 0 && ep->proto != proto) {
23338a7d489Sknakahara encap_key_inc(&key);
23438a7d489Sknakahara continue;
23538a7d489Sknakahara }
23638a7d489Sknakahara
23738a7d489Sknakahara psref_acquire(&elem_psref, &ep->psref,
23838a7d489Sknakahara encaptab.elem_class);
23938a7d489Sknakahara if (ep->func) {
24038a7d489Sknakahara pserialize_read_exit(s);
24138a7d489Sknakahara prio = (*ep->func)(m, off, proto, ep->arg);
24238a7d489Sknakahara s = pserialize_read_enter();
24338a7d489Sknakahara } else {
24438a7d489Sknakahara prio = pack.mine.sin_len + pack.yours.sin_len;
24538a7d489Sknakahara }
24638a7d489Sknakahara
24738a7d489Sknakahara if (prio <= 0) {
24838a7d489Sknakahara psref_release(&elem_psref, &ep->psref,
24938a7d489Sknakahara encaptab.elem_class);
25038a7d489Sknakahara encap_key_inc(&key);
25138a7d489Sknakahara continue;
25238a7d489Sknakahara }
25338a7d489Sknakahara if (prio > matchprio) {
25438a7d489Sknakahara /* release last matched ep */
25538a7d489Sknakahara if (match != NULL)
25638a7d489Sknakahara psref_release(match_psref, &match->psref,
25738a7d489Sknakahara encaptab.elem_class);
25838a7d489Sknakahara
25938a7d489Sknakahara psref_copy(match_psref, &elem_psref,
26038a7d489Sknakahara encaptab.elem_class);
26138a7d489Sknakahara matchprio = prio;
26238a7d489Sknakahara match = ep;
26338a7d489Sknakahara }
26438a7d489Sknakahara
26538a7d489Sknakahara psref_release(&elem_psref, &ep->psref,
26638a7d489Sknakahara encaptab.elem_class);
26738a7d489Sknakahara encap_key_inc(&key);
26838a7d489Sknakahara }
26938a7d489Sknakahara
2707899e09eSknakahara PSLIST_READER_FOREACH(ep, &encap_table, struct encaptab, chain) {
2717899e09eSknakahara struct psref elem_psref;
27228922b99Sitojun
27339091335Sitojun if (ep->af != AF_INET)
27439091335Sitojun continue;
27539091335Sitojun if (ep->proto >= 0 && ep->proto != proto)
27639091335Sitojun continue;
2777899e09eSknakahara
2787899e09eSknakahara psref_acquire(&elem_psref, &ep->psref,
2797899e09eSknakahara encaptab.elem_class);
2807899e09eSknakahara pserialize_read_exit(s);
2817899e09eSknakahara /* ep->func is sleepable. e.g. rtalloc1 */
28239091335Sitojun prio = (*ep->func)(m, off, proto, ep->arg);
2837899e09eSknakahara s = pserialize_read_enter();
28439091335Sitojun
28539091335Sitojun /*
28639091335Sitojun * We prioritize the matches by using bit length of the
287*77d6f587Sknakahara * matches. user-supplied matching function
28839091335Sitojun * should return the bit length of the matches (for example,
28939091335Sitojun * if both src/dst are matched for IPv4, 64 should be returned).
29039091335Sitojun * 0 or negative return value means "it did not match".
29139091335Sitojun *
29239091335Sitojun * We need to loop through all the possible candidates
29339091335Sitojun * to get the best match - the search takes O(n) for
29439091335Sitojun * n attachments (i.e. interfaces).
29539091335Sitojun */
2967899e09eSknakahara if (prio <= 0) {
2977899e09eSknakahara psref_release(&elem_psref, &ep->psref,
2987899e09eSknakahara encaptab.elem_class);
29939091335Sitojun continue;
3007899e09eSknakahara }
30139091335Sitojun if (prio > matchprio) {
3027899e09eSknakahara /* release last matched ep */
3037899e09eSknakahara if (match != NULL)
3047899e09eSknakahara psref_release(match_psref, &match->psref,
3057899e09eSknakahara encaptab.elem_class);
3067899e09eSknakahara
3077899e09eSknakahara psref_copy(match_psref, &elem_psref,
3087899e09eSknakahara encaptab.elem_class);
30939091335Sitojun matchprio = prio;
31039091335Sitojun match = ep;
31139091335Sitojun }
3127899e09eSknakahara KASSERTMSG((match == NULL) || psref_held(&match->psref,
3137899e09eSknakahara encaptab.elem_class),
3147899e09eSknakahara "current match = %p, but not hold its psref", match);
3157899e09eSknakahara
3167899e09eSknakahara psref_release(&elem_psref, &ep->psref,
3177899e09eSknakahara encaptab.elem_class);
31839091335Sitojun }
3197899e09eSknakahara pserialize_read_exit(s);
32039091335Sitojun
32128922b99Sitojun return match;
32228922b99Sitojun }
32328922b99Sitojun
32428922b99Sitojun void
encap4_input(struct mbuf * m,int off,int proto)32515652348Smaxv encap4_input(struct mbuf *m, int off, int proto)
32628922b99Sitojun {
327b546d527Sknakahara const struct encapsw *esw;
32828922b99Sitojun struct encaptab *match;
3297899e09eSknakahara struct psref match_psref;
33028922b99Sitojun
3317899e09eSknakahara match = encap4_lookup(m, off, proto, INBOUND, &match_psref);
33239091335Sitojun if (match) {
33339091335Sitojun /* found a match, "match" has the best one */
334b546d527Sknakahara esw = match->esw;
335b546d527Sknakahara if (esw && esw->encapsw4.pr_input) {
336fb23bb2cSknakahara (*esw->encapsw4.pr_input)(m, off, proto, match->arg);
3377899e09eSknakahara psref_release(&match_psref, &match->psref,
3387899e09eSknakahara encaptab.elem_class);
339b71542e5Sknakahara } else {
3407899e09eSknakahara psref_release(&match_psref, &match->psref,
3417899e09eSknakahara encaptab.elem_class);
34239091335Sitojun m_freem(m);
343b71542e5Sknakahara }
34439091335Sitojun return;
34539091335Sitojun }
34639091335Sitojun
34739091335Sitojun /* last resort: inject to raw socket */
348a1b205bfSknakahara SOFTNET_LOCK_IF_NET_MPSAFE();
34939091335Sitojun rip_input(m, off, proto);
350a1b205bfSknakahara SOFTNET_UNLOCK_IF_NET_MPSAFE();
35139091335Sitojun }
35239091335Sitojun #endif
35339091335Sitojun
35439091335Sitojun #ifdef INET6
35528922b99Sitojun static struct encaptab *
encap6_lookup(struct mbuf * m,int off,int proto,enum direction dir,struct psref * match_psref)3567899e09eSknakahara encap6_lookup(struct mbuf *m, int off, int proto, enum direction dir,
3577899e09eSknakahara struct psref *match_psref)
35839091335Sitojun {
35939091335Sitojun struct ip6_hdr *ip6;
360c6e7028dSpooka struct ip_pack6 pack;
36139091335Sitojun int prio, matchprio;
3627899e09eSknakahara int s;
36328922b99Sitojun struct encaptab *ep, *match;
36438a7d489Sknakahara thmap_t *emap = encap_map[1];
36538a7d489Sknakahara struct encap_key key;
36639091335Sitojun
36773c17c4aSozaki-r KASSERT(m->m_len >= sizeof(*ip6));
36873c17c4aSozaki-r
36939091335Sitojun ip6 = mtod(m, struct ip6_hdr *);
37039091335Sitojun
371c363a9cbScegger memset(&pack, 0, sizeof(pack));
37228922b99Sitojun pack.p.sp_len = sizeof(pack);
37328922b99Sitojun pack.mine.sin6_family = pack.yours.sin6_family = AF_INET6;
37428922b99Sitojun pack.mine.sin6_len = pack.yours.sin6_len = sizeof(struct sockaddr_in6);
37528922b99Sitojun if (dir == INBOUND) {
37628922b99Sitojun pack.mine.sin6_addr = ip6->ip6_dst;
37728922b99Sitojun pack.yours.sin6_addr = ip6->ip6_src;
37828922b99Sitojun } else {
37928922b99Sitojun pack.mine.sin6_addr = ip6->ip6_src;
38028922b99Sitojun pack.yours.sin6_addr = ip6->ip6_dst;
38128922b99Sitojun }
38239091335Sitojun
38339091335Sitojun match = NULL;
38439091335Sitojun matchprio = 0;
38528922b99Sitojun
3867899e09eSknakahara s = pserialize_read_enter();
38738a7d489Sknakahara
38838a7d489Sknakahara encap_key_init(&key, sin6tosa(&pack.mine), sin6tosa(&pack.yours));
38938a7d489Sknakahara while ((ep = thmap_get(emap, &key, sizeof(key))) != NULL) {
39038a7d489Sknakahara struct psref elem_psref;
39138a7d489Sknakahara
39238a7d489Sknakahara KASSERT(ep->af == AF_INET6);
39338a7d489Sknakahara
39438a7d489Sknakahara if (ep->proto >= 0 && ep->proto != proto) {
39538a7d489Sknakahara encap_key_inc(&key);
39638a7d489Sknakahara continue;
39738a7d489Sknakahara }
39838a7d489Sknakahara
39938a7d489Sknakahara psref_acquire(&elem_psref, &ep->psref,
40038a7d489Sknakahara encaptab.elem_class);
40138a7d489Sknakahara if (ep->func) {
40238a7d489Sknakahara pserialize_read_exit(s);
40338a7d489Sknakahara prio = (*ep->func)(m, off, proto, ep->arg);
40438a7d489Sknakahara s = pserialize_read_enter();
40538a7d489Sknakahara } else {
40638a7d489Sknakahara prio = pack.mine.sin6_len + pack.yours.sin6_len;
40738a7d489Sknakahara }
40838a7d489Sknakahara
40938a7d489Sknakahara if (prio <= 0) {
41038a7d489Sknakahara psref_release(&elem_psref, &ep->psref,
41138a7d489Sknakahara encaptab.elem_class);
41238a7d489Sknakahara encap_key_inc(&key);
41338a7d489Sknakahara continue;
41438a7d489Sknakahara }
41538a7d489Sknakahara if (prio > matchprio) {
41638a7d489Sknakahara /* release last matched ep */
41738a7d489Sknakahara if (match != NULL)
41838a7d489Sknakahara psref_release(match_psref, &match->psref,
41938a7d489Sknakahara encaptab.elem_class);
42038a7d489Sknakahara
42138a7d489Sknakahara psref_copy(match_psref, &elem_psref,
42238a7d489Sknakahara encaptab.elem_class);
42338a7d489Sknakahara matchprio = prio;
42438a7d489Sknakahara match = ep;
42538a7d489Sknakahara }
42638a7d489Sknakahara psref_release(&elem_psref, &ep->psref,
42738a7d489Sknakahara encaptab.elem_class);
42838a7d489Sknakahara encap_key_inc(&key);
42938a7d489Sknakahara }
43038a7d489Sknakahara
4317899e09eSknakahara PSLIST_READER_FOREACH(ep, &encap_table, struct encaptab, chain) {
4327899e09eSknakahara struct psref elem_psref;
43328922b99Sitojun
43439091335Sitojun if (ep->af != AF_INET6)
43539091335Sitojun continue;
43639091335Sitojun if (ep->proto >= 0 && ep->proto != proto)
43739091335Sitojun continue;
4387899e09eSknakahara
4397899e09eSknakahara psref_acquire(&elem_psref, &ep->psref,
4407899e09eSknakahara encaptab.elem_class);
4417899e09eSknakahara
4427899e09eSknakahara pserialize_read_exit(s);
4437899e09eSknakahara /* ep->func is sleepable. e.g. rtalloc1 */
44428922b99Sitojun prio = (*ep->func)(m, off, proto, ep->arg);
4457899e09eSknakahara s = pserialize_read_enter();
44639091335Sitojun
44728922b99Sitojun /* see encap4_lookup() for issues here */
4487899e09eSknakahara if (prio <= 0) {
4497899e09eSknakahara psref_release(&elem_psref, &ep->psref,
4507899e09eSknakahara encaptab.elem_class);
45139091335Sitojun continue;
4527899e09eSknakahara }
45339091335Sitojun if (prio > matchprio) {
4547899e09eSknakahara /* release last matched ep */
4557899e09eSknakahara if (match != NULL)
4567899e09eSknakahara psref_release(match_psref, &match->psref,
4577899e09eSknakahara encaptab.elem_class);
4587899e09eSknakahara
4597899e09eSknakahara psref_copy(match_psref, &elem_psref,
4607899e09eSknakahara encaptab.elem_class);
46139091335Sitojun matchprio = prio;
46239091335Sitojun match = ep;
46339091335Sitojun }
4647899e09eSknakahara KASSERTMSG((match == NULL) || psref_held(&match->psref,
4657899e09eSknakahara encaptab.elem_class),
4667899e09eSknakahara "current match = %p, but not hold its psref", match);
4677899e09eSknakahara
4687899e09eSknakahara psref_release(&elem_psref, &ep->psref,
4697899e09eSknakahara encaptab.elem_class);
47039091335Sitojun }
4717899e09eSknakahara pserialize_read_exit(s);
47239091335Sitojun
47328922b99Sitojun return match;
47428922b99Sitojun }
47528922b99Sitojun
47628922b99Sitojun int
encap6_input(struct mbuf ** mp,int * offp,int proto)47751ad03a9Sperry encap6_input(struct mbuf **mp, int *offp, int proto)
47828922b99Sitojun {
47928922b99Sitojun struct mbuf *m = *mp;
480b546d527Sknakahara const struct encapsw *esw;
48128922b99Sitojun struct encaptab *match;
4827899e09eSknakahara struct psref match_psref;
483a1b205bfSknakahara int rv;
48428922b99Sitojun
4857899e09eSknakahara match = encap6_lookup(m, *offp, proto, INBOUND, &match_psref);
48628922b99Sitojun
48739091335Sitojun if (match) {
48839091335Sitojun /* found a match */
489b546d527Sknakahara esw = match->esw;
490b546d527Sknakahara if (esw && esw->encapsw6.pr_input) {
4917899e09eSknakahara int ret;
492fb23bb2cSknakahara ret = (*esw->encapsw6.pr_input)(mp, offp, proto,
493fb23bb2cSknakahara match->arg);
4947899e09eSknakahara psref_release(&match_psref, &match->psref,
4957899e09eSknakahara encaptab.elem_class);
4967899e09eSknakahara return ret;
49739091335Sitojun } else {
4987899e09eSknakahara psref_release(&match_psref, &match->psref,
4997899e09eSknakahara encaptab.elem_class);
50039091335Sitojun m_freem(m);
50139091335Sitojun return IPPROTO_DONE;
50239091335Sitojun }
50339091335Sitojun }
50439091335Sitojun
50539091335Sitojun /* last resort: inject to raw socket */
506a1b205bfSknakahara SOFTNET_LOCK_IF_NET_MPSAFE();
507a1b205bfSknakahara rv = rip6_input(mp, offp, proto);
508a1b205bfSknakahara SOFTNET_UNLOCK_IF_NET_MPSAFE();
509a1b205bfSknakahara return rv;
51039091335Sitojun }
51139091335Sitojun #endif
51239091335Sitojun
51328922b99Sitojun static int
encap_add(struct encaptab * ep)51451ad03a9Sperry encap_add(struct encaptab *ep)
51539091335Sitojun {
51639091335Sitojun
5177899e09eSknakahara KASSERT(encap_lock_held());
518b71542e5Sknakahara
5197899e09eSknakahara PSLIST_WRITER_INSERT_HEAD(&encap_table, ep, chain);
52028922b99Sitojun
5217899e09eSknakahara return 0;
52228922b99Sitojun }
52328922b99Sitojun
52428922b99Sitojun static int
encap_remove(struct encaptab * ep)52551ad03a9Sperry encap_remove(struct encaptab *ep)
52628922b99Sitojun {
52728922b99Sitojun int error = 0;
52828922b99Sitojun
5297899e09eSknakahara KASSERT(encap_lock_held());
530b71542e5Sknakahara
5317899e09eSknakahara PSLIST_WRITER_REMOVE(ep, chain);
5327899e09eSknakahara
53328922b99Sitojun return error;
53428922b99Sitojun }
53528922b99Sitojun
536a14187ecSriastradh static void
encap_afcheck(int af,const struct sockaddr * sp,const struct sockaddr * dp)53751ad03a9Sperry encap_afcheck(int af, const struct sockaddr *sp, const struct sockaddr *dp)
53828922b99Sitojun {
53928922b99Sitojun
540a14187ecSriastradh KASSERT(sp != NULL && dp != NULL);
541a14187ecSriastradh KASSERT(sp->sa_len == dp->sa_len);
542a14187ecSriastradh KASSERT(af == sp->sa_family && af == dp->sa_family);
54328922b99Sitojun
544cf9f2e25Sriastradh socklen_t len __diagused = sockaddr_getsize_by_family(af);
545a14187ecSriastradh KASSERT(len != 0 && len == sp->sa_len && len == dp->sa_len);
54639091335Sitojun }
54739091335Sitojun
54839091335Sitojun const struct encaptab *
encap_attach_func(int af,int proto,encap_priofunc_t * func,const struct encapsw * esw,void * arg)54951ad03a9Sperry encap_attach_func(int af, int proto,
5500d7c1673Sknakahara encap_priofunc_t *func,
551b546d527Sknakahara const struct encapsw *esw, void *arg)
55239091335Sitojun {
55339091335Sitojun struct encaptab *ep;
55439091335Sitojun int error;
5556284b358Sknakahara #ifndef ENCAP_MPSAFE
55639091335Sitojun int s;
55739091335Sitojun
55839091335Sitojun s = splsoftnet();
5596284b358Sknakahara #endif
560a14187ecSriastradh
561a14187ecSriastradh ASSERT_SLEEPABLE();
562a14187ecSriastradh
56339091335Sitojun /* sanity check on args */
564a14187ecSriastradh KASSERT(func != NULL);
565a14187ecSriastradh KASSERT(af == AF_INET
566a14187ecSriastradh #ifdef INET6
567a14187ecSriastradh || af == AF_INET6
568a14187ecSriastradh #endif
569a14187ecSriastradh );
57039091335Sitojun
571a14187ecSriastradh ep = kmem_alloc(sizeof(*ep), KM_SLEEP);
572c363a9cbScegger memset(ep, 0, sizeof(*ep));
57339091335Sitojun
57439091335Sitojun ep->af = af;
57539091335Sitojun ep->proto = proto;
57639091335Sitojun ep->func = func;
577b546d527Sknakahara ep->esw = esw;
57839091335Sitojun ep->arg = arg;
5797899e09eSknakahara psref_target_init(&ep->psref, encaptab.elem_class);
58039091335Sitojun
58128922b99Sitojun error = encap_add(ep);
58228922b99Sitojun if (error)
5838ab6c3b5Smaxv goto gc;
58439091335Sitojun
58539091335Sitojun error = 0;
5866284b358Sknakahara #ifndef ENCAP_MPSAFE
58739091335Sitojun splx(s);
5886284b358Sknakahara #endif
58939091335Sitojun return ep;
59039091335Sitojun
5918ab6c3b5Smaxv gc:
5928ab6c3b5Smaxv kmem_free(ep, sizeof(*ep));
5936284b358Sknakahara #ifndef ENCAP_MPSAFE
59439091335Sitojun splx(s);
5956284b358Sknakahara #endif
59639091335Sitojun return NULL;
59739091335Sitojun }
59839091335Sitojun
59938a7d489Sknakahara static void
encap_key_init(struct encap_key * key,const struct sockaddr * local,const struct sockaddr * remote)60038a7d489Sknakahara encap_key_init(struct encap_key *key,
60138a7d489Sknakahara const struct sockaddr *local, const struct sockaddr *remote)
60238a7d489Sknakahara {
60338a7d489Sknakahara
60438a7d489Sknakahara memset(key, 0, sizeof(*key));
60538a7d489Sknakahara
60638a7d489Sknakahara sockaddr_copy(&key->local_sa, sizeof(key->local_u), local);
60738a7d489Sknakahara sockaddr_copy(&key->remote_sa, sizeof(key->remote_u), remote);
60838a7d489Sknakahara }
60938a7d489Sknakahara
61038a7d489Sknakahara static void
encap_key_inc(struct encap_key * key)61138a7d489Sknakahara encap_key_inc(struct encap_key *key)
61238a7d489Sknakahara {
61338a7d489Sknakahara
61438a7d489Sknakahara (key->seq)++;
61538a7d489Sknakahara }
61638a7d489Sknakahara
61738a7d489Sknakahara static void
encap_key_dec(struct encap_key * key)61838a7d489Sknakahara encap_key_dec(struct encap_key *key)
61938a7d489Sknakahara {
62038a7d489Sknakahara
62138a7d489Sknakahara (key->seq)--;
62238a7d489Sknakahara }
62338a7d489Sknakahara
62438a7d489Sknakahara static void
encap_key_copy(struct encap_key * dst,const struct encap_key * src)62538a7d489Sknakahara encap_key_copy(struct encap_key *dst, const struct encap_key *src)
62638a7d489Sknakahara {
62738a7d489Sknakahara
62838a7d489Sknakahara memset(dst, 0, sizeof(*dst));
62938a7d489Sknakahara *dst = *src;
63038a7d489Sknakahara }
63138a7d489Sknakahara
63238a7d489Sknakahara /*
63338a7d489Sknakahara * src is always my side, and dst is always remote side.
63438a7d489Sknakahara * Return value will be necessary as input (cookie) for encap_detach().
63538a7d489Sknakahara */
63638a7d489Sknakahara const struct encaptab *
encap_attach_addr(int af,int proto,const struct sockaddr * src,const struct sockaddr * dst,encap_priofunc_t * func,const struct encapsw * esw,void * arg)63738a7d489Sknakahara encap_attach_addr(int af, int proto,
63838a7d489Sknakahara const struct sockaddr *src, const struct sockaddr *dst,
63938a7d489Sknakahara encap_priofunc_t *func,
64038a7d489Sknakahara const struct encapsw *esw, void *arg)
64138a7d489Sknakahara {
64238a7d489Sknakahara struct encaptab *ep;
64338a7d489Sknakahara size_t l;
64438a7d489Sknakahara thmap_t *emap;
64538a7d489Sknakahara void *retep;
64638a7d489Sknakahara struct ip_pack4 *pack4;
64738a7d489Sknakahara #ifdef INET6
64838a7d489Sknakahara struct ip_pack6 *pack6;
64938a7d489Sknakahara #endif
65038a7d489Sknakahara
65138a7d489Sknakahara ASSERT_SLEEPABLE();
65238a7d489Sknakahara
65338a7d489Sknakahara encap_afcheck(af, src, dst);
65438a7d489Sknakahara
65538a7d489Sknakahara switch (af) {
65638a7d489Sknakahara case AF_INET:
65738a7d489Sknakahara l = sizeof(*pack4);
65838a7d489Sknakahara emap = encap_map[0];
65938a7d489Sknakahara break;
66038a7d489Sknakahara #ifdef INET6
66138a7d489Sknakahara case AF_INET6:
66238a7d489Sknakahara l = sizeof(*pack6);
66338a7d489Sknakahara emap = encap_map[1];
66438a7d489Sknakahara break;
66538a7d489Sknakahara #endif
66638a7d489Sknakahara default:
66738a7d489Sknakahara return NULL;
66838a7d489Sknakahara }
66938a7d489Sknakahara
67038a7d489Sknakahara ep = kmem_zalloc(sizeof(*ep), KM_SLEEP);
67138a7d489Sknakahara ep->addrpack = kmem_zalloc(l, KM_SLEEP);
67238a7d489Sknakahara ep->addrpack->sa_len = l & 0xff;
67338a7d489Sknakahara ep->af = af;
67438a7d489Sknakahara ep->proto = proto;
67538a7d489Sknakahara ep->flag = IP_ENCAP_ADDR_ENABLE;
67638a7d489Sknakahara switch (af) {
67738a7d489Sknakahara case AF_INET:
67838a7d489Sknakahara pack4 = (struct ip_pack4 *)ep->addrpack;
67938a7d489Sknakahara ep->src = (struct sockaddr *)&pack4->mine;
68038a7d489Sknakahara ep->dst = (struct sockaddr *)&pack4->yours;
68138a7d489Sknakahara break;
68238a7d489Sknakahara #ifdef INET6
68338a7d489Sknakahara case AF_INET6:
68438a7d489Sknakahara pack6 = (struct ip_pack6 *)ep->addrpack;
68538a7d489Sknakahara ep->src = (struct sockaddr *)&pack6->mine;
68638a7d489Sknakahara ep->dst = (struct sockaddr *)&pack6->yours;
68738a7d489Sknakahara break;
68838a7d489Sknakahara #endif
68938a7d489Sknakahara }
69038a7d489Sknakahara memcpy(ep->src, src, src->sa_len);
69138a7d489Sknakahara memcpy(ep->dst, dst, dst->sa_len);
69238a7d489Sknakahara ep->esw = esw;
69338a7d489Sknakahara ep->arg = arg;
69438a7d489Sknakahara ep->func = func;
69538a7d489Sknakahara psref_target_init(&ep->psref, encaptab.elem_class);
69638a7d489Sknakahara
69738a7d489Sknakahara encap_key_init(&ep->key, src, dst);
69838a7d489Sknakahara while ((retep = thmap_put(emap, &ep->key, sizeof(ep->key), ep)) != ep)
69938a7d489Sknakahara encap_key_inc(&ep->key);
70038a7d489Sknakahara return ep;
70138a7d489Sknakahara }
70238a7d489Sknakahara
70338a7d489Sknakahara
70428922b99Sitojun /* XXX encap4_ctlinput() is necessary if we set DF=1 on outer IPv4 header */
70528922b99Sitojun
70628922b99Sitojun #ifdef INET6
70715e29e98Sad void *
encap6_ctlinput(int cmd,const struct sockaddr * sa,void * d0)7085493f188Sdyoung encap6_ctlinput(int cmd, const struct sockaddr *sa, void *d0)
70928922b99Sitojun {
71028922b99Sitojun void *d = d0;
71128922b99Sitojun struct ip6_hdr *ip6;
71228922b99Sitojun struct mbuf *m;
71328922b99Sitojun int off;
71428922b99Sitojun struct ip6ctlparam *ip6cp = NULL;
71528922b99Sitojun int nxt;
7167899e09eSknakahara int s;
71728922b99Sitojun struct encaptab *ep;
718b546d527Sknakahara const struct encapsw *esw;
71928922b99Sitojun
72028922b99Sitojun if (sa->sa_family != AF_INET6 ||
72128922b99Sitojun sa->sa_len != sizeof(struct sockaddr_in6))
72215e29e98Sad return NULL;
72328922b99Sitojun
72428922b99Sitojun if ((unsigned)cmd >= PRC_NCMDS)
72515e29e98Sad return NULL;
72628922b99Sitojun if (cmd == PRC_HOSTDEAD)
72728922b99Sitojun d = NULL;
72828922b99Sitojun else if (cmd == PRC_MSGSIZE)
72928922b99Sitojun ; /* special code is present, see below */
73028922b99Sitojun else if (inet6ctlerrmap[cmd] == 0)
73115e29e98Sad return NULL;
73228922b99Sitojun
73328922b99Sitojun /* if the parameter is from icmp6, decode it. */
73428922b99Sitojun if (d != NULL) {
73528922b99Sitojun ip6cp = (struct ip6ctlparam *)d;
73628922b99Sitojun m = ip6cp->ip6c_m;
73728922b99Sitojun ip6 = ip6cp->ip6c_ip6;
73828922b99Sitojun off = ip6cp->ip6c_off;
73928922b99Sitojun nxt = ip6cp->ip6c_nxt;
74028922b99Sitojun
74128922b99Sitojun if (ip6 && cmd == PRC_MSGSIZE) {
74228922b99Sitojun int valid = 0;
74328922b99Sitojun struct encaptab *match;
7447899e09eSknakahara struct psref elem_psref;
74528922b99Sitojun
74628922b99Sitojun /*
74728922b99Sitojun * Check to see if we have a valid encap configuration.
74828922b99Sitojun */
7497899e09eSknakahara match = encap6_lookup(m, off, nxt, OUTBOUND,
7507899e09eSknakahara &elem_psref);
751fe699263Sknakahara if (match) {
75228922b99Sitojun valid++;
7537899e09eSknakahara psref_release(&elem_psref, &match->psref,
7547899e09eSknakahara encaptab.elem_class);
755fe699263Sknakahara }
75628922b99Sitojun
75728922b99Sitojun /*
75828922b99Sitojun * Depending on the value of "valid" and routing table
75928922b99Sitojun * size (mtudisc_{hi,lo}wat), we will:
76028922b99Sitojun * - recalcurate the new MTU and create the
76128922b99Sitojun * corresponding routing entry, or
76228922b99Sitojun * - ignore the MTU change notification.
76328922b99Sitojun */
76428922b99Sitojun icmp6_mtudisc_update((struct ip6ctlparam *)d, valid);
76528922b99Sitojun }
766d7f0f6deSmycroft } else {
767d7f0f6deSmycroft m = NULL;
768d7f0f6deSmycroft ip6 = NULL;
769d7f0f6deSmycroft nxt = -1;
770d7f0f6deSmycroft }
77128922b99Sitojun
77228922b99Sitojun /* inform all listeners */
7737899e09eSknakahara
7747899e09eSknakahara s = pserialize_read_enter();
7757899e09eSknakahara PSLIST_READER_FOREACH(ep, &encap_table, struct encaptab, chain) {
7767899e09eSknakahara struct psref elem_psref;
7777899e09eSknakahara
77828922b99Sitojun if (ep->af != AF_INET6)
77928922b99Sitojun continue;
78028922b99Sitojun if (ep->proto >= 0 && ep->proto != nxt)
78128922b99Sitojun continue;
78228922b99Sitojun
78328922b99Sitojun /* should optimize by looking at address pairs */
78428922b99Sitojun
78528922b99Sitojun /* XXX need to pass ep->arg or ep itself to listeners */
7867899e09eSknakahara psref_acquire(&elem_psref, &ep->psref,
7877899e09eSknakahara encaptab.elem_class);
788b546d527Sknakahara esw = ep->esw;
789b546d527Sknakahara if (esw && esw->encapsw6.pr_ctlinput) {
7907899e09eSknakahara pserialize_read_exit(s);
7917899e09eSknakahara /* pr_ctlinput is sleepable. e.g. rtcache_free */
792e80f1012Sknakahara (*esw->encapsw6.pr_ctlinput)(cmd, sa, d, ep->arg);
7937899e09eSknakahara s = pserialize_read_enter();
794b546d527Sknakahara }
7957899e09eSknakahara psref_release(&elem_psref, &ep->psref,
7967899e09eSknakahara encaptab.elem_class);
79728922b99Sitojun }
7987899e09eSknakahara pserialize_read_exit(s);
79928922b99Sitojun
80028922b99Sitojun rip6_ctlinput(cmd, sa, d0);
80115e29e98Sad return NULL;
80228922b99Sitojun }
80328922b99Sitojun #endif
80428922b99Sitojun
80538a7d489Sknakahara static int
encap_detach_addr(const struct encaptab * ep)80638a7d489Sknakahara encap_detach_addr(const struct encaptab *ep)
80738a7d489Sknakahara {
80838a7d489Sknakahara thmap_t *emap;
80938a7d489Sknakahara struct encaptab *retep;
81038a7d489Sknakahara struct encaptab *target;
81138a7d489Sknakahara void *thgc;
81238a7d489Sknakahara struct encap_key key;
81338a7d489Sknakahara
81438a7d489Sknakahara KASSERT(encap_lock_held());
81538a7d489Sknakahara KASSERT(ep->flag & IP_ENCAP_ADDR_ENABLE);
81638a7d489Sknakahara
81738a7d489Sknakahara switch (ep->af) {
81838a7d489Sknakahara case AF_INET:
81938a7d489Sknakahara emap = encap_map[0];
82038a7d489Sknakahara break;
82138a7d489Sknakahara #ifdef INET6
82238a7d489Sknakahara case AF_INET6:
82338a7d489Sknakahara emap = encap_map[1];
82438a7d489Sknakahara break;
82538a7d489Sknakahara #endif
82638a7d489Sknakahara default:
82738a7d489Sknakahara return EINVAL;
82838a7d489Sknakahara }
82938a7d489Sknakahara
83038a7d489Sknakahara retep = thmap_del(emap, &ep->key, sizeof(ep->key));
83138a7d489Sknakahara if (retep != ep) {
83238a7d489Sknakahara return ENOENT;
83338a7d489Sknakahara }
83438a7d489Sknakahara target = retep;
83538a7d489Sknakahara
83638a7d489Sknakahara /*
83738a7d489Sknakahara * To keep continuity, decrement seq after detached encaptab.
83838a7d489Sknakahara */
83938a7d489Sknakahara encap_key_copy(&key, &ep->key);
84038a7d489Sknakahara encap_key_inc(&key);
84138a7d489Sknakahara while ((retep = thmap_del(emap, &key, sizeof(key))) != NULL) {
84238a7d489Sknakahara void *pp;
84338a7d489Sknakahara
84438a7d489Sknakahara encap_key_dec(&retep->key);
84538a7d489Sknakahara pp = thmap_put(emap, &retep->key, sizeof(retep->key), retep);
84638a7d489Sknakahara KASSERT(retep == pp);
84738a7d489Sknakahara
84838a7d489Sknakahara encap_key_inc(&key);
84938a7d489Sknakahara }
85038a7d489Sknakahara
85138a7d489Sknakahara thgc = thmap_stage_gc(emap);
85238a7d489Sknakahara pserialize_perform(encaptab.psz);
85338a7d489Sknakahara thmap_gc(emap, thgc);
85438a7d489Sknakahara psref_target_destroy(&target->psref, encaptab.elem_class);
85538a7d489Sknakahara kmem_free(target->addrpack, target->addrpack->sa_len);
85638a7d489Sknakahara kmem_free(target, sizeof(*target));
85738a7d489Sknakahara
85838a7d489Sknakahara return 0;
85938a7d489Sknakahara }
86038a7d489Sknakahara
86139091335Sitojun int
encap_detach(const struct encaptab * cookie)86251ad03a9Sperry encap_detach(const struct encaptab *cookie)
86339091335Sitojun {
86439091335Sitojun const struct encaptab *ep = cookie;
8657899e09eSknakahara struct encaptab *p;
86628922b99Sitojun int error;
86739091335Sitojun
8687899e09eSknakahara KASSERT(encap_lock_held());
8697899e09eSknakahara
87038a7d489Sknakahara if (ep->flag & IP_ENCAP_ADDR_ENABLE)
87138a7d489Sknakahara return encap_detach_addr(ep);
87238a7d489Sknakahara
8737899e09eSknakahara PSLIST_WRITER_FOREACH(p, &encap_table, struct encaptab, chain) {
87439091335Sitojun if (p == ep) {
87528922b99Sitojun error = encap_remove(p);
87628922b99Sitojun if (error)
87728922b99Sitojun return error;
8787899e09eSknakahara else
8797899e09eSknakahara break;
8807899e09eSknakahara }
8817899e09eSknakahara }
8827899e09eSknakahara if (p == NULL)
8837899e09eSknakahara return ENOENT;
884b71542e5Sknakahara
8857899e09eSknakahara pserialize_perform(encaptab.psz);
8867899e09eSknakahara psref_target_destroy(&p->psref,
8877899e09eSknakahara encaptab.elem_class);
8887899e09eSknakahara kmem_free(p, sizeof(*p));
88939091335Sitojun
8907899e09eSknakahara return 0;
89139091335Sitojun }
89239091335Sitojun
893c544c867Sknakahara int
encap_lock_enter(void)894b71542e5Sknakahara encap_lock_enter(void)
895b71542e5Sknakahara {
896c544c867Sknakahara int error;
897b71542e5Sknakahara
898c544c867Sknakahara mutex_enter(&encap_whole.lock);
899c544c867Sknakahara while (encap_whole.busy != NULL) {
900c544c867Sknakahara error = cv_wait_sig(&encap_whole.cv, &encap_whole.lock);
901c544c867Sknakahara if (error) {
902c544c867Sknakahara mutex_exit(&encap_whole.lock);
903c544c867Sknakahara return error;
904c544c867Sknakahara }
905c544c867Sknakahara }
906c544c867Sknakahara KASSERT(encap_whole.busy == NULL);
907c544c867Sknakahara encap_whole.busy = curlwp;
908c544c867Sknakahara mutex_exit(&encap_whole.lock);
909c544c867Sknakahara
910c544c867Sknakahara return 0;
911b71542e5Sknakahara }
912b71542e5Sknakahara
913b71542e5Sknakahara void
encap_lock_exit(void)914b71542e5Sknakahara encap_lock_exit(void)
915b71542e5Sknakahara {
916b71542e5Sknakahara
917c544c867Sknakahara mutex_enter(&encap_whole.lock);
918c544c867Sknakahara KASSERT(encap_whole.busy == curlwp);
919c544c867Sknakahara encap_whole.busy = NULL;
920c544c867Sknakahara cv_broadcast(&encap_whole.cv);
921c544c867Sknakahara mutex_exit(&encap_whole.lock);
922b71542e5Sknakahara }
9237899e09eSknakahara
9247899e09eSknakahara bool
encap_lock_held(void)9257899e09eSknakahara encap_lock_held(void)
9267899e09eSknakahara {
9277899e09eSknakahara
928c544c867Sknakahara return (encap_whole.busy == curlwp);
9297899e09eSknakahara }
930