xref: /freebsd/sys/netipsec/subr_ipsec.c (revision fcf596178b5f2be36424ecbc1b6a3224b29c91d2)
1*fcf59617SAndrey V. Elsukov /*-
2*fcf59617SAndrey V. Elsukov  * Copyright (c) 2016 Andrey V. Elsukov <ae@FreeBSD.org>
3*fcf59617SAndrey V. Elsukov  * All rights reserved.
4*fcf59617SAndrey V. Elsukov  *
5*fcf59617SAndrey V. Elsukov  * Redistribution and use in source and binary forms, with or without
6*fcf59617SAndrey V. Elsukov  * modification, are permitted provided that the following conditions
7*fcf59617SAndrey V. Elsukov  * are met:
8*fcf59617SAndrey V. Elsukov  *
9*fcf59617SAndrey V. Elsukov  * 1. Redistributions of source code must retain the above copyright
10*fcf59617SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer.
11*fcf59617SAndrey V. Elsukov  * 2. Redistributions in binary form must reproduce the above copyright
12*fcf59617SAndrey V. Elsukov  *    notice, this list of conditions and the following disclaimer in the
13*fcf59617SAndrey V. Elsukov  *    documentation and/or other materials provided with the distribution.
14*fcf59617SAndrey V. Elsukov  *
15*fcf59617SAndrey V. Elsukov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*fcf59617SAndrey V. Elsukov  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*fcf59617SAndrey V. Elsukov  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*fcf59617SAndrey V. Elsukov  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*fcf59617SAndrey V. Elsukov  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*fcf59617SAndrey V. Elsukov  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*fcf59617SAndrey V. Elsukov  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*fcf59617SAndrey V. Elsukov  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*fcf59617SAndrey V. Elsukov  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*fcf59617SAndrey V. Elsukov  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*fcf59617SAndrey V. Elsukov  */
26*fcf59617SAndrey V. Elsukov 
27*fcf59617SAndrey V. Elsukov #include "opt_inet.h"
28*fcf59617SAndrey V. Elsukov #include "opt_inet6.h"
29*fcf59617SAndrey V. Elsukov #include "opt_ipsec.h"
30*fcf59617SAndrey V. Elsukov 
31*fcf59617SAndrey V. Elsukov #include <sys/cdefs.h>
32*fcf59617SAndrey V. Elsukov __FBSDID("$FreeBSD$");
33*fcf59617SAndrey V. Elsukov 
34*fcf59617SAndrey V. Elsukov #include <sys/param.h>
35*fcf59617SAndrey V. Elsukov #include <sys/systm.h>
36*fcf59617SAndrey V. Elsukov #include <sys/kernel.h>
37*fcf59617SAndrey V. Elsukov #include <sys/lock.h>
38*fcf59617SAndrey V. Elsukov #include <sys/malloc.h>
39*fcf59617SAndrey V. Elsukov #include <sys/mbuf.h>
40*fcf59617SAndrey V. Elsukov #include <sys/module.h>
41*fcf59617SAndrey V. Elsukov #include <sys/priv.h>
42*fcf59617SAndrey V. Elsukov #include <sys/socket.h>
43*fcf59617SAndrey V. Elsukov #include <sys/sockopt.h>
44*fcf59617SAndrey V. Elsukov #include <sys/syslog.h>
45*fcf59617SAndrey V. Elsukov #include <sys/proc.h>
46*fcf59617SAndrey V. Elsukov 
47*fcf59617SAndrey V. Elsukov #include <netinet/in.h>
48*fcf59617SAndrey V. Elsukov #include <netinet/in_pcb.h>
49*fcf59617SAndrey V. Elsukov #include <netinet/ip.h>
50*fcf59617SAndrey V. Elsukov #include <netinet/ip6.h>
51*fcf59617SAndrey V. Elsukov 
52*fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h>
53*fcf59617SAndrey V. Elsukov #include <netipsec/ipsec.h>
54*fcf59617SAndrey V. Elsukov #include <netipsec/ipsec6.h>
55*fcf59617SAndrey V. Elsukov #include <netipsec/key.h>
56*fcf59617SAndrey V. Elsukov #include <netipsec/key_debug.h>
57*fcf59617SAndrey V. Elsukov 
58*fcf59617SAndrey V. Elsukov #include <machine/atomic.h>
59*fcf59617SAndrey V. Elsukov /*
60*fcf59617SAndrey V. Elsukov  * This file is build in the kernel only when 'options IPSEC' or
61*fcf59617SAndrey V. Elsukov  * 'options IPSEC_SUPPORT' is enabled.
62*fcf59617SAndrey V. Elsukov  */
63*fcf59617SAndrey V. Elsukov 
64*fcf59617SAndrey V. Elsukov #ifdef INET
65*fcf59617SAndrey V. Elsukov void
66*fcf59617SAndrey V. Elsukov ipsec4_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
67*fcf59617SAndrey V. Elsukov     union sockaddr_union *dst)
68*fcf59617SAndrey V. Elsukov {
69*fcf59617SAndrey V. Elsukov 	static const struct sockaddr_in template = {
70*fcf59617SAndrey V. Elsukov 		sizeof (struct sockaddr_in),
71*fcf59617SAndrey V. Elsukov 		AF_INET,
72*fcf59617SAndrey V. Elsukov 		0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
73*fcf59617SAndrey V. Elsukov 	};
74*fcf59617SAndrey V. Elsukov 
75*fcf59617SAndrey V. Elsukov 	src->sin = template;
76*fcf59617SAndrey V. Elsukov 	dst->sin = template;
77*fcf59617SAndrey V. Elsukov 
78*fcf59617SAndrey V. Elsukov 	if (m->m_len < sizeof (struct ip)) {
79*fcf59617SAndrey V. Elsukov 		m_copydata(m, offsetof(struct ip, ip_src),
80*fcf59617SAndrey V. Elsukov 			   sizeof (struct  in_addr),
81*fcf59617SAndrey V. Elsukov 			   (caddr_t) &src->sin.sin_addr);
82*fcf59617SAndrey V. Elsukov 		m_copydata(m, offsetof(struct ip, ip_dst),
83*fcf59617SAndrey V. Elsukov 			   sizeof (struct  in_addr),
84*fcf59617SAndrey V. Elsukov 			   (caddr_t) &dst->sin.sin_addr);
85*fcf59617SAndrey V. Elsukov 	} else {
86*fcf59617SAndrey V. Elsukov 		const struct ip *ip = mtod(m, const struct ip *);
87*fcf59617SAndrey V. Elsukov 		src->sin.sin_addr = ip->ip_src;
88*fcf59617SAndrey V. Elsukov 		dst->sin.sin_addr = ip->ip_dst;
89*fcf59617SAndrey V. Elsukov 	}
90*fcf59617SAndrey V. Elsukov }
91*fcf59617SAndrey V. Elsukov #endif
92*fcf59617SAndrey V. Elsukov #ifdef INET6
93*fcf59617SAndrey V. Elsukov void
94*fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
95*fcf59617SAndrey V. Elsukov     union sockaddr_union *dst)
96*fcf59617SAndrey V. Elsukov {
97*fcf59617SAndrey V. Elsukov 	struct ip6_hdr ip6buf;
98*fcf59617SAndrey V. Elsukov 	const struct ip6_hdr *ip6;
99*fcf59617SAndrey V. Elsukov 
100*fcf59617SAndrey V. Elsukov 	if (m->m_len >= sizeof(*ip6))
101*fcf59617SAndrey V. Elsukov 		ip6 = mtod(m, const struct ip6_hdr *);
102*fcf59617SAndrey V. Elsukov 	else {
103*fcf59617SAndrey V. Elsukov 		m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
104*fcf59617SAndrey V. Elsukov 		ip6 = &ip6buf;
105*fcf59617SAndrey V. Elsukov 	}
106*fcf59617SAndrey V. Elsukov 
107*fcf59617SAndrey V. Elsukov 	bzero(&src->sin6, sizeof(struct sockaddr_in6));
108*fcf59617SAndrey V. Elsukov 	src->sin6.sin6_family = AF_INET6;
109*fcf59617SAndrey V. Elsukov 	src->sin6.sin6_len = sizeof(struct sockaddr_in6);
110*fcf59617SAndrey V. Elsukov 	bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
111*fcf59617SAndrey V. Elsukov 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
112*fcf59617SAndrey V. Elsukov 		src->sin6.sin6_addr.s6_addr16[1] = 0;
113*fcf59617SAndrey V. Elsukov 		src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
114*fcf59617SAndrey V. Elsukov 	}
115*fcf59617SAndrey V. Elsukov 
116*fcf59617SAndrey V. Elsukov 	bzero(&dst->sin6, sizeof(struct sockaddr_in6));
117*fcf59617SAndrey V. Elsukov 	dst->sin6.sin6_family = AF_INET6;
118*fcf59617SAndrey V. Elsukov 	dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
119*fcf59617SAndrey V. Elsukov 	bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
120*fcf59617SAndrey V. Elsukov 	if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
121*fcf59617SAndrey V. Elsukov 		dst->sin6.sin6_addr.s6_addr16[1] = 0;
122*fcf59617SAndrey V. Elsukov 		dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
123*fcf59617SAndrey V. Elsukov 	}
124*fcf59617SAndrey V. Elsukov }
125*fcf59617SAndrey V. Elsukov #endif
126*fcf59617SAndrey V. Elsukov 
127*fcf59617SAndrey V. Elsukov #ifdef IPSEC_SUPPORT
128*fcf59617SAndrey V. Elsukov /*
129*fcf59617SAndrey V. Elsukov  * Declare IPSEC_SUPPORT as module even if IPSEC is defined.
130*fcf59617SAndrey V. Elsukov  * tcpmd5.ko module depends from IPSEC_SUPPORT.
131*fcf59617SAndrey V. Elsukov  */
132*fcf59617SAndrey V. Elsukov #define	IPSEC_MODULE_INCR	2
133*fcf59617SAndrey V. Elsukov static int
134*fcf59617SAndrey V. Elsukov ipsec_kmod_enter(volatile u_int *cntr)
135*fcf59617SAndrey V. Elsukov {
136*fcf59617SAndrey V. Elsukov 	u_int old, new;
137*fcf59617SAndrey V. Elsukov 
138*fcf59617SAndrey V. Elsukov 	do {
139*fcf59617SAndrey V. Elsukov 		old = *cntr;
140*fcf59617SAndrey V. Elsukov 		if ((old & IPSEC_MODULE_ENABLED) == 0)
141*fcf59617SAndrey V. Elsukov 			return (ENXIO);
142*fcf59617SAndrey V. Elsukov 		new = old + IPSEC_MODULE_INCR;
143*fcf59617SAndrey V. Elsukov 	} while(atomic_cmpset_acq_int(cntr, old, new) == 0);
144*fcf59617SAndrey V. Elsukov 	return (0);
145*fcf59617SAndrey V. Elsukov }
146*fcf59617SAndrey V. Elsukov 
147*fcf59617SAndrey V. Elsukov static void
148*fcf59617SAndrey V. Elsukov ipsec_kmod_exit(volatile u_int *cntr)
149*fcf59617SAndrey V. Elsukov {
150*fcf59617SAndrey V. Elsukov 	u_int old, new;
151*fcf59617SAndrey V. Elsukov 
152*fcf59617SAndrey V. Elsukov 	do {
153*fcf59617SAndrey V. Elsukov 		old = *cntr;
154*fcf59617SAndrey V. Elsukov 		new = old - IPSEC_MODULE_INCR;
155*fcf59617SAndrey V. Elsukov 	} while (atomic_cmpset_rel_int(cntr, old, new) == 0);
156*fcf59617SAndrey V. Elsukov }
157*fcf59617SAndrey V. Elsukov 
158*fcf59617SAndrey V. Elsukov static void
159*fcf59617SAndrey V. Elsukov ipsec_kmod_drain(volatile u_int *cntr)
160*fcf59617SAndrey V. Elsukov {
161*fcf59617SAndrey V. Elsukov 	u_int old, new;
162*fcf59617SAndrey V. Elsukov 
163*fcf59617SAndrey V. Elsukov 	do {
164*fcf59617SAndrey V. Elsukov 		old = *cntr;
165*fcf59617SAndrey V. Elsukov 		new = old & ~IPSEC_MODULE_ENABLED;
166*fcf59617SAndrey V. Elsukov 	} while (atomic_cmpset_acq_int(cntr, old, new) == 0);
167*fcf59617SAndrey V. Elsukov 	while (atomic_cmpset_int(cntr, 0, 0) == 0)
168*fcf59617SAndrey V. Elsukov 		pause("ipsecd", hz/2);
169*fcf59617SAndrey V. Elsukov }
170*fcf59617SAndrey V. Elsukov 
171*fcf59617SAndrey V. Elsukov #define	METHOD_DECL(...)	__VA_ARGS__
172*fcf59617SAndrey V. Elsukov #define	METHOD_ARGS(...)	__VA_ARGS__
173*fcf59617SAndrey V. Elsukov #define	IPSEC_KMOD_METHOD(type, name, sc, method, decl, args)		\
174*fcf59617SAndrey V. Elsukov type name (decl)							\
175*fcf59617SAndrey V. Elsukov {									\
176*fcf59617SAndrey V. Elsukov 	type ret = (type)ipsec_kmod_enter(&sc->enabled);		\
177*fcf59617SAndrey V. Elsukov 	if (ret == 0) {							\
178*fcf59617SAndrey V. Elsukov 		ret = (*sc->methods->method)(args);			\
179*fcf59617SAndrey V. Elsukov 		ipsec_kmod_exit(&sc->enabled);				\
180*fcf59617SAndrey V. Elsukov 	}								\
181*fcf59617SAndrey V. Elsukov 	return (ret);							\
182*fcf59617SAndrey V. Elsukov }
183*fcf59617SAndrey V. Elsukov 
184*fcf59617SAndrey V. Elsukov #ifndef TCP_SIGNATURE
185*fcf59617SAndrey V. Elsukov /* Declare TCP-MD5 support as kernel module. */
186*fcf59617SAndrey V. Elsukov static struct tcpmd5_support tcpmd5_ipsec = {
187*fcf59617SAndrey V. Elsukov 	.enabled = 0,
188*fcf59617SAndrey V. Elsukov 	.methods = NULL
189*fcf59617SAndrey V. Elsukov };
190*fcf59617SAndrey V. Elsukov struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
191*fcf59617SAndrey V. Elsukov 
192*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
193*fcf59617SAndrey V. Elsukov     input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
194*fcf59617SAndrey V. Elsukov 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
195*fcf59617SAndrey V. Elsukov )
196*fcf59617SAndrey V. Elsukov 
197*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
198*fcf59617SAndrey V. Elsukov     output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
199*fcf59617SAndrey V. Elsukov 	struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
200*fcf59617SAndrey V. Elsukov )
201*fcf59617SAndrey V. Elsukov 
202*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
203*fcf59617SAndrey V. Elsukov     pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
204*fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
205*fcf59617SAndrey V. Elsukov )
206*fcf59617SAndrey V. Elsukov 
207*fcf59617SAndrey V. Elsukov void
208*fcf59617SAndrey V. Elsukov tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
209*fcf59617SAndrey V. Elsukov {
210*fcf59617SAndrey V. Elsukov 
211*fcf59617SAndrey V. Elsukov 	KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
212*fcf59617SAndrey V. Elsukov 	tcp_ipsec_support->methods = methods;
213*fcf59617SAndrey V. Elsukov 	tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
214*fcf59617SAndrey V. Elsukov }
215*fcf59617SAndrey V. Elsukov 
216*fcf59617SAndrey V. Elsukov void
217*fcf59617SAndrey V. Elsukov tcpmd5_support_disable(void)
218*fcf59617SAndrey V. Elsukov {
219*fcf59617SAndrey V. Elsukov 
220*fcf59617SAndrey V. Elsukov 	if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
221*fcf59617SAndrey V. Elsukov 		ipsec_kmod_drain(&tcp_ipsec_support->enabled);
222*fcf59617SAndrey V. Elsukov 		tcp_ipsec_support->methods = NULL;
223*fcf59617SAndrey V. Elsukov 	}
224*fcf59617SAndrey V. Elsukov }
225*fcf59617SAndrey V. Elsukov #endif
226*fcf59617SAndrey V. Elsukov 
227*fcf59617SAndrey V. Elsukov static int
228*fcf59617SAndrey V. Elsukov ipsec_support_modevent(module_t mod, int type, void *data)
229*fcf59617SAndrey V. Elsukov {
230*fcf59617SAndrey V. Elsukov 
231*fcf59617SAndrey V. Elsukov 	switch (type) {
232*fcf59617SAndrey V. Elsukov 	case MOD_LOAD:
233*fcf59617SAndrey V. Elsukov 		return (0);
234*fcf59617SAndrey V. Elsukov 	case MOD_UNLOAD:
235*fcf59617SAndrey V. Elsukov 		return (EBUSY);
236*fcf59617SAndrey V. Elsukov 	default:
237*fcf59617SAndrey V. Elsukov 		return (EOPNOTSUPP);
238*fcf59617SAndrey V. Elsukov 	}
239*fcf59617SAndrey V. Elsukov }
240*fcf59617SAndrey V. Elsukov 
241*fcf59617SAndrey V. Elsukov static moduledata_t ipsec_support_mod = {
242*fcf59617SAndrey V. Elsukov 	"ipsec_support",
243*fcf59617SAndrey V. Elsukov 	ipsec_support_modevent,
244*fcf59617SAndrey V. Elsukov 	0
245*fcf59617SAndrey V. Elsukov };
246*fcf59617SAndrey V. Elsukov DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
247*fcf59617SAndrey V. Elsukov     SI_ORDER_ANY);
248*fcf59617SAndrey V. Elsukov MODULE_VERSION(ipsec_support, 1);
249*fcf59617SAndrey V. Elsukov 
250*fcf59617SAndrey V. Elsukov #ifndef IPSEC
251*fcf59617SAndrey V. Elsukov /*
252*fcf59617SAndrey V. Elsukov  * IPsec support is build as kernel module.
253*fcf59617SAndrey V. Elsukov  */
254*fcf59617SAndrey V. Elsukov #ifdef INET
255*fcf59617SAndrey V. Elsukov static struct ipsec_support ipv4_ipsec = {
256*fcf59617SAndrey V. Elsukov 	.enabled = 0,
257*fcf59617SAndrey V. Elsukov 	.methods = NULL
258*fcf59617SAndrey V. Elsukov };
259*fcf59617SAndrey V. Elsukov struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
260*fcf59617SAndrey V. Elsukov 
261*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
262*fcf59617SAndrey V. Elsukov     udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
263*fcf59617SAndrey V. Elsukov 	int off, int af), METHOD_ARGS(m, off, af)
264*fcf59617SAndrey V. Elsukov )
265*fcf59617SAndrey V. Elsukov 
266*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
267*fcf59617SAndrey V. Elsukov     udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
268*fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
269*fcf59617SAndrey V. Elsukov )
270*fcf59617SAndrey V. Elsukov #endif
271*fcf59617SAndrey V. Elsukov 
272*fcf59617SAndrey V. Elsukov #ifdef INET6
273*fcf59617SAndrey V. Elsukov static struct ipsec_support ipv6_ipsec = {
274*fcf59617SAndrey V. Elsukov 	.enabled = 0,
275*fcf59617SAndrey V. Elsukov 	.methods = NULL
276*fcf59617SAndrey V. Elsukov };
277*fcf59617SAndrey V. Elsukov struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
278*fcf59617SAndrey V. Elsukov #endif
279*fcf59617SAndrey V. Elsukov 
280*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
281*fcf59617SAndrey V. Elsukov     input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
282*fcf59617SAndrey V. Elsukov 	int offset, int proto), METHOD_ARGS(m, offset, proto)
283*fcf59617SAndrey V. Elsukov )
284*fcf59617SAndrey V. Elsukov 
285*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
286*fcf59617SAndrey V. Elsukov     check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
287*fcf59617SAndrey V. Elsukov 	struct inpcb *inp), METHOD_ARGS(m, inp)
288*fcf59617SAndrey V. Elsukov )
289*fcf59617SAndrey V. Elsukov 
290*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
291*fcf59617SAndrey V. Elsukov     forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
292*fcf59617SAndrey V. Elsukov     (m)
293*fcf59617SAndrey V. Elsukov )
294*fcf59617SAndrey V. Elsukov 
295*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc,
296*fcf59617SAndrey V. Elsukov     output, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
297*fcf59617SAndrey V. Elsukov 	struct inpcb *inp), METHOD_ARGS(m, inp)
298*fcf59617SAndrey V. Elsukov )
299*fcf59617SAndrey V. Elsukov 
300*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
301*fcf59617SAndrey V. Elsukov     pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
302*fcf59617SAndrey V. Elsukov 	struct sockopt *sopt), METHOD_ARGS(inp, sopt)
303*fcf59617SAndrey V. Elsukov )
304*fcf59617SAndrey V. Elsukov 
305*fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
306*fcf59617SAndrey V. Elsukov     hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
307*fcf59617SAndrey V. Elsukov     (inp)
308*fcf59617SAndrey V. Elsukov )
309*fcf59617SAndrey V. Elsukov 
310*fcf59617SAndrey V. Elsukov static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
311*fcf59617SAndrey V. Elsukov     capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
312*fcf59617SAndrey V. Elsukov 	u_int cap), METHOD_ARGS(m, cap)
313*fcf59617SAndrey V. Elsukov )
314*fcf59617SAndrey V. Elsukov 
315*fcf59617SAndrey V. Elsukov int
316*fcf59617SAndrey V. Elsukov ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
317*fcf59617SAndrey V. Elsukov     u_int cap)
318*fcf59617SAndrey V. Elsukov {
319*fcf59617SAndrey V. Elsukov 
320*fcf59617SAndrey V. Elsukov 	/*
321*fcf59617SAndrey V. Elsukov 	 * Since PF_KEY is build in the kernel, we can directly
322*fcf59617SAndrey V. Elsukov 	 * call key_havesp() without additional synchronizations.
323*fcf59617SAndrey V. Elsukov 	 */
324*fcf59617SAndrey V. Elsukov 	if (cap == IPSEC_CAP_OPERABLE)
325*fcf59617SAndrey V. Elsukov 		return (key_havesp(IPSEC_DIR_INBOUND) != 0 ||
326*fcf59617SAndrey V. Elsukov 		    key_havesp(IPSEC_DIR_OUTBOUND) != 0);
327*fcf59617SAndrey V. Elsukov 	return (ipsec_kmod_caps(sc, m, cap));
328*fcf59617SAndrey V. Elsukov }
329*fcf59617SAndrey V. Elsukov 
330*fcf59617SAndrey V. Elsukov void
331*fcf59617SAndrey V. Elsukov ipsec_support_enable(struct ipsec_support * const sc,
332*fcf59617SAndrey V. Elsukov     const struct ipsec_methods * const methods)
333*fcf59617SAndrey V. Elsukov {
334*fcf59617SAndrey V. Elsukov 
335*fcf59617SAndrey V. Elsukov 	KASSERT(sc->enabled == 0, ("IPsec already enabled"));
336*fcf59617SAndrey V. Elsukov 	sc->methods = methods;
337*fcf59617SAndrey V. Elsukov 	sc->enabled |= IPSEC_MODULE_ENABLED;
338*fcf59617SAndrey V. Elsukov }
339*fcf59617SAndrey V. Elsukov 
340*fcf59617SAndrey V. Elsukov void
341*fcf59617SAndrey V. Elsukov ipsec_support_disable(struct ipsec_support * const sc)
342*fcf59617SAndrey V. Elsukov {
343*fcf59617SAndrey V. Elsukov 
344*fcf59617SAndrey V. Elsukov 	if (sc->enabled & IPSEC_MODULE_ENABLED) {
345*fcf59617SAndrey V. Elsukov 		ipsec_kmod_drain(&sc->enabled);
346*fcf59617SAndrey V. Elsukov 		sc->methods = NULL;
347*fcf59617SAndrey V. Elsukov 	}
348*fcf59617SAndrey V. Elsukov }
349*fcf59617SAndrey V. Elsukov #endif /* !IPSEC */
350*fcf59617SAndrey V. Elsukov #endif /* IPSEC_SUPPORT */
351