xref: /freebsd/sys/netipsec/subr_ipsec.c (revision d9d59bb1af142e7575032dd6c51fc64580de84df)
1fcf59617SAndrey V. Elsukov /*-
2fcf59617SAndrey V. Elsukov  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
3fcf59617SAndrey V. Elsukov  * All rights reserved.
4fcf59617SAndrey V. Elsukov  *
5fcf59617SAndrey V. Elsukov  * Redistribution and use in source and binary forms, with or without
6fcf59617SAndrey V. Elsukov  * modification, are permitted provided that the following conditions
7fcf59617SAndrey V. Elsukov  * are met:
8fcf59617SAndrey V. Elsukov  *
9fcf59617SAndrey V. Elsukov  * 1. Redistributions of source code must retain the above copyright
10fcf59617SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer.
11fcf59617SAndrey V. Elsukov  * 2. Redistributions in binary form must reproduce the above copyright
12fcf59617SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer in the
13fcf59617SAndrey V. Elsukov  *    documentation and/or other materials provided with the distribution.
14fcf59617SAndrey V. Elsukov  *
15fcf59617SAndrey V. Elsukov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16fcf59617SAndrey V. Elsukov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17fcf59617SAndrey V. Elsukov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18fcf59617SAndrey V. Elsukov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19fcf59617SAndrey V. Elsukov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20fcf59617SAndrey V. Elsukov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21fcf59617SAndrey V. Elsukov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22fcf59617SAndrey V. Elsukov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23fcf59617SAndrey V. Elsukov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24fcf59617SAndrey V. Elsukov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25fcf59617SAndrey V. Elsukov  */
26fcf59617SAndrey V. Elsukov 
27fcf59617SAndrey V. Elsukov #include "opt_inet.h"
28fcf59617SAndrey V. Elsukov #include "opt_inet6.h"
29fcf59617SAndrey V. Elsukov #include "opt_ipsec.h"
30fcf59617SAndrey V. Elsukov 
31fcf59617SAndrey V. Elsukov #include <sys/cdefs.h>
32fcf59617SAndrey V. Elsukov __FBSDID("$FreeBSD$");
33fcf59617SAndrey V. Elsukov 
34fcf59617SAndrey V. Elsukov #include <sys/param.h>
35fcf59617SAndrey V. Elsukov #include <sys/systm.h>
36fcf59617SAndrey V. Elsukov #include <sys/kernel.h>
37fcf59617SAndrey V. Elsukov #include <sys/lock.h>
38fcf59617SAndrey V. Elsukov #include <sys/malloc.h>
39fcf59617SAndrey V. Elsukov #include <sys/mbuf.h>
40fcf59617SAndrey V. Elsukov #include <sys/module.h>
41fcf59617SAndrey V. Elsukov #include <sys/priv.h>
42fcf59617SAndrey V. Elsukov #include <sys/socket.h>
43fcf59617SAndrey V. Elsukov #include <sys/sockopt.h>
44fcf59617SAndrey V. Elsukov #include <sys/syslog.h>
45fcf59617SAndrey V. Elsukov #include <sys/proc.h>
46fcf59617SAndrey V. Elsukov 
47fcf59617SAndrey V. Elsukov #include <netinet/in.h>
48fcf59617SAndrey V. Elsukov #include <netinet/in_pcb.h>
49fcf59617SAndrey V. Elsukov #include <netinet/ip.h>
50fcf59617SAndrey V. Elsukov #include <netinet/ip6.h>
51fcf59617SAndrey V. Elsukov 
52fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h>
53fcf59617SAndrey V. Elsukov #include <netipsec/ipsec.h>
54fcf59617SAndrey V. Elsukov #include <netipsec/ipsec6.h>
55fcf59617SAndrey V. Elsukov #include <netipsec/key.h>
56fcf59617SAndrey V. Elsukov #include <netipsec/key_debug.h>
570ddfd867SAndrey V. Elsukov #include <netipsec/xform.h>
58fcf59617SAndrey V. Elsukov 
59fcf59617SAndrey V. Elsukov #include <machine/atomic.h>
60fcf59617SAndrey V. Elsukov /*
61fcf59617SAndrey V. Elsukov  * This file is build in the kernel only when 'options IPSEC' or
62fcf59617SAndrey V. Elsukov  * 'options IPSEC_SUPPORT' is enabled.
63fcf59617SAndrey V. Elsukov  */
64fcf59617SAndrey V. Elsukov 
65fcf59617SAndrey V. Elsukov #ifdef INET
66fcf59617SAndrey V. Elsukov void
67fcf59617SAndrey V. Elsukov ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
68fcf59617SAndrey V. Elsukov     union sockaddr_union *dst)
69fcf59617SAndrey V. Elsukov {
70fcf59617SAndrey V. Elsukov 	static const struct sockaddr_in template = {
71fcf59617SAndrey V. Elsukov 		sizeof (struct sockaddr_in),
72fcf59617SAndrey V. Elsukov 		AF_INET,
73fcf59617SAndrey V. Elsukov 		0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
74fcf59617SAndrey V. Elsukov 	};
75fcf59617SAndrey V. Elsukov 
76fcf59617SAndrey V. Elsukov 	src->sin = template;
77fcf59617SAndrey V. Elsukov 	dst->sin = template;
78fcf59617SAndrey V. Elsukov 
79fcf59617SAndrey V. Elsukov 	if (m->m_len < sizeof (struct ip)) {
80fcf59617SAndrey V. Elsukov 		m_copydata(m, offsetof(struct ip, ip_src),
81fcf59617SAndrey V. Elsukov 			   sizeof (struct  in_addr),
82fcf59617SAndrey V. Elsukov 			   (caddr_t) &src->sin.sin_addr);
83fcf59617SAndrey V. Elsukov 		m_copydata(m, offsetof(struct ip, ip_dst),
84fcf59617SAndrey V. Elsukov 			   sizeof (struct  in_addr),
85fcf59617SAndrey V. Elsukov 			   (caddr_t) &dst->sin.sin_addr);
86fcf59617SAndrey V. Elsukov 	} else {
87fcf59617SAndrey V. Elsukov 		const struct ip *ip = mtod(m, const struct ip *);
88fcf59617SAndrey V. Elsukov 		src->sin.sin_addr = ip->ip_src;
89fcf59617SAndrey V. Elsukov 		dst->sin.sin_addr = ip->ip_dst;
90fcf59617SAndrey V. Elsukov 	}
91fcf59617SAndrey V. Elsukov }
92fcf59617SAndrey V. Elsukov #endif
93fcf59617SAndrey V. Elsukov #ifdef INET6
94fcf59617SAndrey V. Elsukov void
95fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
96fcf59617SAndrey V. Elsukov     union sockaddr_union *dst)
97fcf59617SAndrey V. Elsukov {
98fcf59617SAndrey V. Elsukov 	struct ip6_hdr ip6buf;
99fcf59617SAndrey V. Elsukov 	const struct ip6_hdr *ip6;
100fcf59617SAndrey V. Elsukov 
101fcf59617SAndrey V. Elsukov 	if (m->m_len >= sizeof(*ip6))
102fcf59617SAndrey V. Elsukov 		ip6 = mtod(m, const struct ip6_hdr *);
103fcf59617SAndrey V. Elsukov 	else {
104fcf59617SAndrey V. Elsukov 		m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
105fcf59617SAndrey V. Elsukov 		ip6 = &ip6buf;
106fcf59617SAndrey V. Elsukov 	}
107fcf59617SAndrey V. Elsukov 
108fcf59617SAndrey V. Elsukov 	bzero(&src->sin6, sizeof(struct sockaddr_in6));
109fcf59617SAndrey V. Elsukov 	src->sin6.sin6_family = AF_INET6;
110fcf59617SAndrey V. Elsukov 	src->sin6.sin6_len = sizeof(struct sockaddr_in6);
111fcf59617SAndrey V. Elsukov 	bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
112fcf59617SAndrey V. Elsukov 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
113fcf59617SAndrey V. Elsukov 		src->sin6.sin6_addr.s6_addr16[1] = 0;
114fcf59617SAndrey V. Elsukov 		src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
115fcf59617SAndrey V. Elsukov 	}
116fcf59617SAndrey V. Elsukov 
117fcf59617SAndrey V. Elsukov 	bzero(&dst->sin6, sizeof(struct sockaddr_in6));
118fcf59617SAndrey V. Elsukov 	dst->sin6.sin6_family = AF_INET6;
119fcf59617SAndrey V. Elsukov 	dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
120fcf59617SAndrey V. Elsukov 	bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
121fcf59617SAndrey V. Elsukov 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
122fcf59617SAndrey V. Elsukov 		dst->sin6.sin6_addr.s6_addr16[1] = 0;
123fcf59617SAndrey V. Elsukov 		dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
124fcf59617SAndrey V. Elsukov 	}
125fcf59617SAndrey V. Elsukov }
126fcf59617SAndrey V. Elsukov #endif
127fcf59617SAndrey V. Elsukov 
128fcf59617SAndrey V. Elsukov #define	IPSEC_MODULE_INCR	2
129fcf59617SAndrey V. Elsukov static int
130fcf59617SAndrey V. Elsukov ipsec_kmod_enter(volatile u_int *cntr)
131fcf59617SAndrey V. Elsukov {
132fcf59617SAndrey V. Elsukov 	u_int old, new;
133fcf59617SAndrey V. Elsukov 
134fcf59617SAndrey V. Elsukov 	do {
135fcf59617SAndrey V. Elsukov 		old = *cntr;
136fcf59617SAndrey V. Elsukov 		if ((old & IPSEC_MODULE_ENABLED) == 0)
137fcf59617SAndrey V. Elsukov 			return (ENXIO);
138fcf59617SAndrey V. Elsukov 		new = old + IPSEC_MODULE_INCR;
139fcf59617SAndrey V. Elsukov 	} while(atomic_cmpset_acq_int(cntr, old, new) == 0);
140fcf59617SAndrey V. Elsukov 	return (0);
141fcf59617SAndrey V. Elsukov }
142fcf59617SAndrey V. Elsukov 
143fcf59617SAndrey V. Elsukov static void
144fcf59617SAndrey V. Elsukov ipsec_kmod_exit(volatile u_int *cntr)
145fcf59617SAndrey V. Elsukov {
146fcf59617SAndrey V. Elsukov 	u_int old, new;
147fcf59617SAndrey V. Elsukov 
148fcf59617SAndrey V. Elsukov 	do {
149fcf59617SAndrey V. Elsukov 		old = *cntr;
150fcf59617SAndrey V. Elsukov 		new = old - IPSEC_MODULE_INCR;
151fcf59617SAndrey V. Elsukov 	} while (atomic_cmpset_rel_int(cntr, old, new) == 0);
152fcf59617SAndrey V. Elsukov }
153fcf59617SAndrey V. Elsukov 
154fcf59617SAndrey V. Elsukov static void
155fcf59617SAndrey V. Elsukov ipsec_kmod_drain(volatile u_int *cntr)
156fcf59617SAndrey V. Elsukov {
157fcf59617SAndrey V. Elsukov 	u_int old, new;
158fcf59617SAndrey V. Elsukov 
159fcf59617SAndrey V. Elsukov 	do {
160fcf59617SAndrey V. Elsukov 		old = *cntr;
161fcf59617SAndrey V. Elsukov 		new = old & ~IPSEC_MODULE_ENABLED;
162fcf59617SAndrey V. Elsukov 	} while (atomic_cmpset_acq_int(cntr, old, new) == 0);
163fcf59617SAndrey V. Elsukov 	while (atomic_cmpset_int(cntr, 0, 0) == 0)
164fcf59617SAndrey V. Elsukov 		pause("ipsecd", hz/2);
165fcf59617SAndrey V. Elsukov }
166fcf59617SAndrey V. Elsukov 
1670ddfd867SAndrey V. Elsukov static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
1680ddfd867SAndrey V. Elsukov static struct mtx xforms_lock;
1690ddfd867SAndrey V. Elsukov MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
1700ddfd867SAndrey V. Elsukov #define	XFORMS_LOCK()		mtx_lock(&xforms_lock)
1710ddfd867SAndrey V. Elsukov #define	XFORMS_UNLOCK()		mtx_unlock(&xforms_lock)
1720ddfd867SAndrey V. Elsukov 
1730ddfd867SAndrey V. Elsukov void
1740ddfd867SAndrey V. Elsukov xform_attach(void *data)
1750ddfd867SAndrey V. Elsukov {
1760ddfd867SAndrey V. Elsukov 	struct xformsw *xsp, *entry;
1770ddfd867SAndrey V. Elsukov 
1780ddfd867SAndrey V. Elsukov 	xsp = (struct xformsw *)data;
1790ddfd867SAndrey V. Elsukov 	XFORMS_LOCK();
1800ddfd867SAndrey V. Elsukov 	LIST_FOREACH(entry, &xforms, chain) {
1810ddfd867SAndrey V. Elsukov 		if (entry->xf_type == xsp->xf_type) {
1820ddfd867SAndrey V. Elsukov 			XFORMS_UNLOCK();
1830ddfd867SAndrey V. Elsukov 			printf("%s: failed to register %s xform\n",
1840ddfd867SAndrey V. Elsukov 			    __func__, xsp->xf_name);
1850ddfd867SAndrey V. Elsukov 			return;
1860ddfd867SAndrey V. Elsukov 		}
1870ddfd867SAndrey V. Elsukov 	}
1880ddfd867SAndrey V. Elsukov 	LIST_INSERT_HEAD(&xforms, xsp, chain);
1890ddfd867SAndrey V. Elsukov 	xsp->xf_cntr = IPSEC_MODULE_ENABLED;
1900ddfd867SAndrey V. Elsukov 	XFORMS_UNLOCK();
1910ddfd867SAndrey V. Elsukov }
1920ddfd867SAndrey V. Elsukov 
1930ddfd867SAndrey V. Elsukov void
1940ddfd867SAndrey V. Elsukov xform_detach(void *data)
1950ddfd867SAndrey V. Elsukov {
1960ddfd867SAndrey V. Elsukov 	struct xformsw *xsp = (struct xformsw *)data;
1970ddfd867SAndrey V. Elsukov 
1980ddfd867SAndrey V. Elsukov 	XFORMS_LOCK();
1990ddfd867SAndrey V. Elsukov 	LIST_REMOVE(xsp, chain);
2000ddfd867SAndrey V. Elsukov 	XFORMS_UNLOCK();
2010ddfd867SAndrey V. Elsukov 
2020ddfd867SAndrey V. Elsukov 	/* Delete all SAs related to this xform. */
2030ddfd867SAndrey V. Elsukov 	key_delete_xform(xsp);
2040ddfd867SAndrey V. Elsukov 	if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
2050ddfd867SAndrey V. Elsukov 		ipsec_kmod_drain(&xsp->xf_cntr);
2060ddfd867SAndrey V. Elsukov }
2070ddfd867SAndrey V. Elsukov 
2080ddfd867SAndrey V. Elsukov /*
2090ddfd867SAndrey V. Elsukov  * Initialize transform support in an sav.
2100ddfd867SAndrey V. Elsukov  */
2110ddfd867SAndrey V. Elsukov int
2120ddfd867SAndrey V. Elsukov xform_init(struct secasvar *sav, u_short xftype)
2130ddfd867SAndrey V. Elsukov {
2140ddfd867SAndrey V. Elsukov 	struct xformsw *entry;
2150ddfd867SAndrey V. Elsukov 	int ret;
2160ddfd867SAndrey V. Elsukov 
2170ddfd867SAndrey V. Elsukov 	IPSEC_ASSERT(sav->tdb_xform == NULL,
2180ddfd867SAndrey V. Elsukov 	    ("tdb_xform is already initialized"));
2190ddfd867SAndrey V. Elsukov 
2200ddfd867SAndrey V. Elsukov 	XFORMS_LOCK();
2210ddfd867SAndrey V. Elsukov 	LIST_FOREACH(entry, &xforms, chain) {
2220ddfd867SAndrey V. Elsukov 		if (entry->xf_type == xftype) {
2230ddfd867SAndrey V. Elsukov 			ret = ipsec_kmod_enter(&entry->xf_cntr);
2240ddfd867SAndrey V. Elsukov 			XFORMS_UNLOCK();
2250ddfd867SAndrey V. Elsukov 			if (ret != 0)
2260ddfd867SAndrey V. Elsukov 				return (ret);
2270ddfd867SAndrey V. Elsukov 			ret = (*entry->xf_init)(sav, entry);
2280ddfd867SAndrey V. Elsukov 			ipsec_kmod_exit(&entry->xf_cntr);
2290ddfd867SAndrey V. Elsukov 			return (ret);
2300ddfd867SAndrey V. Elsukov 		}
2310ddfd867SAndrey V. Elsukov 	}
2320ddfd867SAndrey V. Elsukov 	XFORMS_UNLOCK();
2330ddfd867SAndrey V. Elsukov 	return (EINVAL);
2340ddfd867SAndrey V. Elsukov }
2350ddfd867SAndrey V. Elsukov 
2360ddfd867SAndrey V. Elsukov #ifdef IPSEC_SUPPORT
2370ddfd867SAndrey V. Elsukov /*
2380ddfd867SAndrey V. Elsukov  * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
2390ddfd867SAndrey V. Elsukov  * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
2400ddfd867SAndrey V. Elsukov  * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
2410ddfd867SAndrey V. Elsukov  *   IPSEC_SUPPORT.
2420ddfd867SAndrey V. Elsukov  */
2430ddfd867SAndrey V. Elsukov #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
244fcf59617SAndrey V. Elsukov #define	METHOD_DECL(...)	__VA_ARGS__
245fcf59617SAndrey V. Elsukov #define	METHOD_ARGS(...)	__VA_ARGS__
246fcf59617SAndrey V. Elsukov #define	IPSEC_KMOD_METHOD(type, name, sc, method, decl, args)		\
247fcf59617SAndrey V. Elsukov type name (decl)							\
248fcf59617SAndrey V. Elsukov {									\
249fcf59617SAndrey V. Elsukov 	type ret = (type)ipsec_kmod_enter(&sc->enabled);		\
250fcf59617SAndrey V. Elsukov 	if (ret == 0) {							\
251fcf59617SAndrey V. Elsukov 		ret = (*sc->methods->method)(args);			\
252fcf59617SAndrey V. Elsukov 		ipsec_kmod_exit(&sc->enabled);				\
253fcf59617SAndrey V. Elsukov 	}								\
254fcf59617SAndrey V. Elsukov 	return (ret);							\
255fcf59617SAndrey V. Elsukov }
256fcf59617SAndrey V. Elsukov 
257ddc9f8e8SAndrey V. Elsukov static int
258ddc9f8e8SAndrey V. Elsukov ipsec_support_modevent(module_t mod, int type, void *data)
259ddc9f8e8SAndrey V. Elsukov {
260ddc9f8e8SAndrey V. Elsukov 
261ddc9f8e8SAndrey V. Elsukov 	switch (type) {
262ddc9f8e8SAndrey V. Elsukov 	case MOD_LOAD:
263ddc9f8e8SAndrey V. Elsukov 		return (0);
264ddc9f8e8SAndrey V. Elsukov 	case MOD_UNLOAD:
265ddc9f8e8SAndrey V. Elsukov 		return (EBUSY);
266ddc9f8e8SAndrey V. Elsukov 	default:
267ddc9f8e8SAndrey V. Elsukov 		return (EOPNOTSUPP);
268ddc9f8e8SAndrey V. Elsukov 	}
269ddc9f8e8SAndrey V. Elsukov }
270ddc9f8e8SAndrey V. Elsukov 
271ddc9f8e8SAndrey V. Elsukov static moduledata_t ipsec_support_mod = {
272ddc9f8e8SAndrey V. Elsukov 	"ipsec_support",
273ddc9f8e8SAndrey V. Elsukov 	ipsec_support_modevent,
274ddc9f8e8SAndrey V. Elsukov 	0
275ddc9f8e8SAndrey V. Elsukov };
276ddc9f8e8SAndrey V. Elsukov DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
277ddc9f8e8SAndrey V. Elsukov     SI_ORDER_ANY);
278ddc9f8e8SAndrey V. Elsukov MODULE_VERSION(ipsec_support, 1);
279ddc9f8e8SAndrey V. Elsukov #endif /* !IPSEC || !TCP_SIGNATURE */
280ddc9f8e8SAndrey V. Elsukov 
281fcf59617SAndrey V. Elsukov #ifndef TCP_SIGNATURE
282fcf59617SAndrey V. Elsukov /* Declare TCP-MD5 support as kernel module. */
283fcf59617SAndrey V. Elsukov static struct tcpmd5_support tcpmd5_ipsec = {
284fcf59617SAndrey V. Elsukov 	.enabled = 0,
285fcf59617SAndrey V. Elsukov 	.methods = NULL
286fcf59617SAndrey V. Elsukov };
287fcf59617SAndrey V. Elsukov struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
288fcf59617SAndrey V. Elsukov 
289fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
290fcf59617SAndrey V. Elsukov     input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
291fcf59617SAndrey V. Elsukov 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
292fcf59617SAndrey V. Elsukov )
293fcf59617SAndrey V. Elsukov 
294fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
295fcf59617SAndrey V. Elsukov     output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
296fcf59617SAndrey V. Elsukov 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
297fcf59617SAndrey V. Elsukov )
298fcf59617SAndrey V. Elsukov 
299fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
300fcf59617SAndrey V. Elsukov     pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
301fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
302fcf59617SAndrey V. Elsukov )
303fcf59617SAndrey V. Elsukov 
304fcf59617SAndrey V. Elsukov void
305fcf59617SAndrey V. Elsukov tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
306fcf59617SAndrey V. Elsukov {
307fcf59617SAndrey V. Elsukov 
308fcf59617SAndrey V. Elsukov 	KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
309fcf59617SAndrey V. Elsukov 	tcp_ipsec_support->methods = methods;
310fcf59617SAndrey V. Elsukov 	tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
311fcf59617SAndrey V. Elsukov }
312fcf59617SAndrey V. Elsukov 
313fcf59617SAndrey V. Elsukov void
314fcf59617SAndrey V. Elsukov tcpmd5_support_disable(void)
315fcf59617SAndrey V. Elsukov {
316fcf59617SAndrey V. Elsukov 
317fcf59617SAndrey V. Elsukov 	if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
318fcf59617SAndrey V. Elsukov 		ipsec_kmod_drain(&tcp_ipsec_support->enabled);
319fcf59617SAndrey V. Elsukov 		tcp_ipsec_support->methods = NULL;
320fcf59617SAndrey V. Elsukov 	}
321fcf59617SAndrey V. Elsukov }
322ddc9f8e8SAndrey V. Elsukov #endif /* !TCP_SIGNATURE */
323fcf59617SAndrey V. Elsukov 
324fcf59617SAndrey V. Elsukov #ifndef IPSEC
325fcf59617SAndrey V. Elsukov /*
326fcf59617SAndrey V. Elsukov  * IPsec support is build as kernel module.
327fcf59617SAndrey V. Elsukov  */
328fcf59617SAndrey V. Elsukov #ifdef INET
329fcf59617SAndrey V. Elsukov static struct ipsec_support ipv4_ipsec = {
330fcf59617SAndrey V. Elsukov 	.enabled = 0,
331fcf59617SAndrey V. Elsukov 	.methods = NULL
332fcf59617SAndrey V. Elsukov };
333fcf59617SAndrey V. Elsukov struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
334fcf59617SAndrey V. Elsukov 
335fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
336fcf59617SAndrey V. Elsukov     udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
337fcf59617SAndrey V. Elsukov 	int off, int af), METHOD_ARGS(m, off, af)
338fcf59617SAndrey V. Elsukov )
339fcf59617SAndrey V. Elsukov 
340fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
341fcf59617SAndrey V. Elsukov     udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
342fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
343fcf59617SAndrey V. Elsukov )
344fcf59617SAndrey V. Elsukov #endif
345fcf59617SAndrey V. Elsukov 
346fcf59617SAndrey V. Elsukov #ifdef INET6
347fcf59617SAndrey V. Elsukov static struct ipsec_support ipv6_ipsec = {
348fcf59617SAndrey V. Elsukov 	.enabled = 0,
349fcf59617SAndrey V. Elsukov 	.methods = NULL
350fcf59617SAndrey V. Elsukov };
351fcf59617SAndrey V. Elsukov struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
352fcf59617SAndrey V. Elsukov #endif
353fcf59617SAndrey V. Elsukov 
354fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
355fcf59617SAndrey V. Elsukov     input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
356fcf59617SAndrey V. Elsukov 	int offset, int proto), METHOD_ARGS(m, offset, proto)
357fcf59617SAndrey V. Elsukov )
358fcf59617SAndrey V. Elsukov 
359fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
360fcf59617SAndrey V. Elsukov     check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
361fcf59617SAndrey V. Elsukov 	struct inpcb *inp), METHOD_ARGS(m, inp)
362fcf59617SAndrey V. Elsukov )
363fcf59617SAndrey V. Elsukov 
364fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
365fcf59617SAndrey V. Elsukov     forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
366fcf59617SAndrey V. Elsukov     (m)
367fcf59617SAndrey V. Elsukov )
368fcf59617SAndrey V. Elsukov 
369*d9d59bb1SWojciech Macek IPSEC_KMOD_METHOD(int, ipsec_kmod_ctlinput, sc,
370*d9d59bb1SWojciech Macek     ctlinput, METHOD_DECL(struct ipsec_support * const sc, int code,
371*d9d59bb1SWojciech Macek         struct sockaddr *sa, void *v), METHOD_ARGS(code, sa, v)
372*d9d59bb1SWojciech Macek )
373*d9d59bb1SWojciech Macek 
374fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
375fcf59617SAndrey V. Elsukov     output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
376fcf59617SAndrey V. Elsukov 	struct inpcb *inp), METHOD_ARGS(m, inp)
377fcf59617SAndrey V. Elsukov )
378fcf59617SAndrey V. Elsukov 
379fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
380fcf59617SAndrey V. Elsukov     pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
381fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
382fcf59617SAndrey V. Elsukov )
383fcf59617SAndrey V. Elsukov 
384fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
385fcf59617SAndrey V. Elsukov     hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
386fcf59617SAndrey V. Elsukov     (inp)
387fcf59617SAndrey V. Elsukov )
388fcf59617SAndrey V. Elsukov 
389fcf59617SAndrey V. Elsukov static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
390fcf59617SAndrey V. Elsukov     capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
391fcf59617SAndrey V. Elsukov 	u_int cap), METHOD_ARGS(m, cap)
392fcf59617SAndrey V. Elsukov )
393fcf59617SAndrey V. Elsukov 
394fcf59617SAndrey V. Elsukov int
395fcf59617SAndrey V. Elsukov ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
396fcf59617SAndrey V. Elsukov     u_int cap)
397fcf59617SAndrey V. Elsukov {
398fcf59617SAndrey V. Elsukov 
399fcf59617SAndrey V. Elsukov 	/*
400fcf59617SAndrey V. Elsukov 	 * Since PF_KEY is build in the kernel, we can directly
401fcf59617SAndrey V. Elsukov 	 * call key_havesp() without additional synchronizations.
402fcf59617SAndrey V. Elsukov 	 */
403fcf59617SAndrey V. Elsukov 	if (cap == IPSEC_CAP_OPERABLE)
404fcf59617SAndrey V. Elsukov 		return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
405fcf59617SAndrey V. Elsukov 		    key_havesp(IPSEC_DIR_OUTBOUND) != 0);
406fcf59617SAndrey V. Elsukov 	return (ipsec_kmod_caps(sc, m, cap));
407fcf59617SAndrey V. Elsukov }
408fcf59617SAndrey V. Elsukov 
409fcf59617SAndrey V. Elsukov void
410fcf59617SAndrey V. Elsukov ipsec_support_enable(struct ipsec_support * const sc,
411fcf59617SAndrey V. Elsukov     const struct ipsec_methods * const methods)
412fcf59617SAndrey V. Elsukov {
413fcf59617SAndrey V. Elsukov 
414fcf59617SAndrey V. Elsukov 	KASSERT(sc->enabled == 0, ("IPsec already enabled"));
415fcf59617SAndrey V. Elsukov 	sc->methods = methods;
416fcf59617SAndrey V. Elsukov 	sc->enabled |= IPSEC_MODULE_ENABLED;
417fcf59617SAndrey V. Elsukov }
418fcf59617SAndrey V. Elsukov 
419fcf59617SAndrey V. Elsukov void
420fcf59617SAndrey V. Elsukov ipsec_support_disable(struct ipsec_support * const sc)
421fcf59617SAndrey V. Elsukov {
422fcf59617SAndrey V. Elsukov 
423fcf59617SAndrey V. Elsukov 	if (sc->enabled & IPSEC_MODULE_ENABLED) {
424fcf59617SAndrey V. Elsukov 		ipsec_kmod_drain(&sc->enabled);
425fcf59617SAndrey V. Elsukov 		sc->methods = NULL;
426fcf59617SAndrey V. Elsukov 	}
427fcf59617SAndrey V. Elsukov }
428fcf59617SAndrey V. Elsukov #endif /* !IPSEC */
429fcf59617SAndrey V. Elsukov #endif /* IPSEC_SUPPORT */
430