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/param.h>
32fcf59617SAndrey V. Elsukov #include <sys/systm.h>
33fcf59617SAndrey V. Elsukov #include <sys/kernel.h>
34fcf59617SAndrey V. Elsukov #include <sys/lock.h>
35fcf59617SAndrey V. Elsukov #include <sys/malloc.h>
36fcf59617SAndrey V. Elsukov #include <sys/mbuf.h>
37fcf59617SAndrey V. Elsukov #include <sys/module.h>
38fcf59617SAndrey V. Elsukov #include <sys/priv.h>
39fcf59617SAndrey V. Elsukov #include <sys/socket.h>
40fcf59617SAndrey V. Elsukov #include <sys/sockopt.h>
41fcf59617SAndrey V. Elsukov #include <sys/syslog.h>
42fcf59617SAndrey V. Elsukov #include <sys/proc.h>
43fcf59617SAndrey V. Elsukov
44fcf59617SAndrey V. Elsukov #include <netinet/in.h>
45fcf59617SAndrey V. Elsukov #include <netinet/in_pcb.h>
46fcf59617SAndrey V. Elsukov #include <netinet/ip.h>
47fcf59617SAndrey V. Elsukov #include <netinet/ip6.h>
48fcf59617SAndrey V. Elsukov
49fcf59617SAndrey V. Elsukov #include <netipsec/ipsec_support.h>
50fcf59617SAndrey V. Elsukov #include <netipsec/ipsec.h>
51fcf59617SAndrey V. Elsukov #include <netipsec/ipsec6.h>
52fcf59617SAndrey V. Elsukov #include <netipsec/key.h>
53fcf59617SAndrey V. Elsukov #include <netipsec/key_debug.h>
540ddfd867SAndrey V. Elsukov #include <netipsec/xform.h>
55fcf59617SAndrey V. Elsukov
56fcf59617SAndrey V. Elsukov #include <machine/atomic.h>
57fcf59617SAndrey V. Elsukov /*
58fcf59617SAndrey V. Elsukov * This file is build in the kernel only when 'options IPSEC' or
59fcf59617SAndrey V. Elsukov * 'options IPSEC_SUPPORT' is enabled.
60fcf59617SAndrey V. Elsukov */
61fcf59617SAndrey V. Elsukov
62fcf59617SAndrey V. Elsukov #ifdef INET
63fcf59617SAndrey V. Elsukov void
ipsec4_setsockaddrs(const struct mbuf * m,const struct ip * ip1,union sockaddr_union * src,union sockaddr_union * dst)64*0ff2d00dSKonstantin Belousov ipsec4_setsockaddrs(const struct mbuf *m, const struct ip *ip1,
65*0ff2d00dSKonstantin Belousov union sockaddr_union *src, union sockaddr_union *dst)
66fcf59617SAndrey V. Elsukov {
67fcf59617SAndrey V. Elsukov static const struct sockaddr_in template = {
68fcf59617SAndrey V. Elsukov sizeof (struct sockaddr_in),
69fcf59617SAndrey V. Elsukov AF_INET,
70fcf59617SAndrey V. Elsukov 0, { 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }
71fcf59617SAndrey V. Elsukov };
72fcf59617SAndrey V. Elsukov
73fcf59617SAndrey V. Elsukov src->sin = template;
74fcf59617SAndrey V. Elsukov dst->sin = template;
75fcf59617SAndrey V. Elsukov
76*0ff2d00dSKonstantin Belousov src->sin.sin_addr = ip1->ip_src;
77*0ff2d00dSKonstantin Belousov dst->sin.sin_addr = ip1->ip_dst;
78fcf59617SAndrey V. Elsukov }
79fcf59617SAndrey V. Elsukov #endif
80fcf59617SAndrey V. Elsukov #ifdef INET6
81fcf59617SAndrey V. Elsukov void
ipsec6_setsockaddrs(const struct mbuf * m,union sockaddr_union * src,union sockaddr_union * dst)82fcf59617SAndrey V. Elsukov ipsec6_setsockaddrs(const struct mbuf *m, union sockaddr_union *src,
83fcf59617SAndrey V. Elsukov union sockaddr_union *dst)
84fcf59617SAndrey V. Elsukov {
85fcf59617SAndrey V. Elsukov struct ip6_hdr ip6buf;
86fcf59617SAndrey V. Elsukov const struct ip6_hdr *ip6;
87fcf59617SAndrey V. Elsukov
88fcf59617SAndrey V. Elsukov if (m->m_len >= sizeof(*ip6))
89fcf59617SAndrey V. Elsukov ip6 = mtod(m, const struct ip6_hdr *);
90fcf59617SAndrey V. Elsukov else {
91fcf59617SAndrey V. Elsukov m_copydata(m, 0, sizeof(ip6buf), (caddr_t)&ip6buf);
92fcf59617SAndrey V. Elsukov ip6 = &ip6buf;
93fcf59617SAndrey V. Elsukov }
94fcf59617SAndrey V. Elsukov
95fcf59617SAndrey V. Elsukov bzero(&src->sin6, sizeof(struct sockaddr_in6));
96fcf59617SAndrey V. Elsukov src->sin6.sin6_family = AF_INET6;
97fcf59617SAndrey V. Elsukov src->sin6.sin6_len = sizeof(struct sockaddr_in6);
98fcf59617SAndrey V. Elsukov bcopy(&ip6->ip6_src, &src->sin6.sin6_addr, sizeof(ip6->ip6_src));
99fcf59617SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src)) {
100fcf59617SAndrey V. Elsukov src->sin6.sin6_addr.s6_addr16[1] = 0;
101fcf59617SAndrey V. Elsukov src->sin6.sin6_scope_id = ntohs(ip6->ip6_src.s6_addr16[1]);
102fcf59617SAndrey V. Elsukov }
103fcf59617SAndrey V. Elsukov
104fcf59617SAndrey V. Elsukov bzero(&dst->sin6, sizeof(struct sockaddr_in6));
105fcf59617SAndrey V. Elsukov dst->sin6.sin6_family = AF_INET6;
106fcf59617SAndrey V. Elsukov dst->sin6.sin6_len = sizeof(struct sockaddr_in6);
107fcf59617SAndrey V. Elsukov bcopy(&ip6->ip6_dst, &dst->sin6.sin6_addr, sizeof(ip6->ip6_dst));
108fcf59617SAndrey V. Elsukov if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst)) {
109fcf59617SAndrey V. Elsukov dst->sin6.sin6_addr.s6_addr16[1] = 0;
110fcf59617SAndrey V. Elsukov dst->sin6.sin6_scope_id = ntohs(ip6->ip6_dst.s6_addr16[1]);
111fcf59617SAndrey V. Elsukov }
112fcf59617SAndrey V. Elsukov }
113fcf59617SAndrey V. Elsukov #endif
114fcf59617SAndrey V. Elsukov
115fcf59617SAndrey V. Elsukov #define IPSEC_MODULE_INCR 2
116fcf59617SAndrey V. Elsukov static int
ipsec_kmod_enter(volatile u_int * cntr)117fcf59617SAndrey V. Elsukov ipsec_kmod_enter(volatile u_int *cntr)
118fcf59617SAndrey V. Elsukov {
119fcf59617SAndrey V. Elsukov u_int old, new;
120fcf59617SAndrey V. Elsukov
121fcf59617SAndrey V. Elsukov do {
122fcf59617SAndrey V. Elsukov old = *cntr;
123fcf59617SAndrey V. Elsukov if ((old & IPSEC_MODULE_ENABLED) == 0)
124fcf59617SAndrey V. Elsukov return (ENXIO);
125fcf59617SAndrey V. Elsukov new = old + IPSEC_MODULE_INCR;
126fcf59617SAndrey V. Elsukov } while(atomic_cmpset_acq_int(cntr, old, new) == 0);
127fcf59617SAndrey V. Elsukov return (0);
128fcf59617SAndrey V. Elsukov }
129fcf59617SAndrey V. Elsukov
130fcf59617SAndrey V. Elsukov static void
ipsec_kmod_exit(volatile u_int * cntr)131fcf59617SAndrey V. Elsukov ipsec_kmod_exit(volatile u_int *cntr)
132fcf59617SAndrey V. Elsukov {
133fcf59617SAndrey V. Elsukov u_int old, new;
134fcf59617SAndrey V. Elsukov
135fcf59617SAndrey V. Elsukov do {
136fcf59617SAndrey V. Elsukov old = *cntr;
137fcf59617SAndrey V. Elsukov new = old - IPSEC_MODULE_INCR;
138fcf59617SAndrey V. Elsukov } while (atomic_cmpset_rel_int(cntr, old, new) == 0);
139fcf59617SAndrey V. Elsukov }
140fcf59617SAndrey V. Elsukov
141fcf59617SAndrey V. Elsukov static void
ipsec_kmod_drain(volatile u_int * cntr)142fcf59617SAndrey V. Elsukov ipsec_kmod_drain(volatile u_int *cntr)
143fcf59617SAndrey V. Elsukov {
144fcf59617SAndrey V. Elsukov u_int old, new;
145fcf59617SAndrey V. Elsukov
146fcf59617SAndrey V. Elsukov do {
147fcf59617SAndrey V. Elsukov old = *cntr;
148fcf59617SAndrey V. Elsukov new = old & ~IPSEC_MODULE_ENABLED;
149fcf59617SAndrey V. Elsukov } while (atomic_cmpset_acq_int(cntr, old, new) == 0);
150fcf59617SAndrey V. Elsukov while (atomic_cmpset_int(cntr, 0, 0) == 0)
151fcf59617SAndrey V. Elsukov pause("ipsecd", hz/2);
152fcf59617SAndrey V. Elsukov }
153fcf59617SAndrey V. Elsukov
1540ddfd867SAndrey V. Elsukov static LIST_HEAD(xforms_list, xformsw) xforms = LIST_HEAD_INITIALIZER();
1550ddfd867SAndrey V. Elsukov static struct mtx xforms_lock;
1560ddfd867SAndrey V. Elsukov MTX_SYSINIT(xfroms_list, &xforms_lock, "IPsec transforms list", MTX_DEF);
1570ddfd867SAndrey V. Elsukov #define XFORMS_LOCK() mtx_lock(&xforms_lock)
1580ddfd867SAndrey V. Elsukov #define XFORMS_UNLOCK() mtx_unlock(&xforms_lock)
1590ddfd867SAndrey V. Elsukov
1600ddfd867SAndrey V. Elsukov void
xform_attach(void * data)1610ddfd867SAndrey V. Elsukov xform_attach(void *data)
1620ddfd867SAndrey V. Elsukov {
1630ddfd867SAndrey V. Elsukov struct xformsw *xsp, *entry;
1640ddfd867SAndrey V. Elsukov
1650ddfd867SAndrey V. Elsukov xsp = (struct xformsw *)data;
1660ddfd867SAndrey V. Elsukov XFORMS_LOCK();
1670ddfd867SAndrey V. Elsukov LIST_FOREACH(entry, &xforms, chain) {
1680ddfd867SAndrey V. Elsukov if (entry->xf_type == xsp->xf_type) {
1690ddfd867SAndrey V. Elsukov XFORMS_UNLOCK();
1700ddfd867SAndrey V. Elsukov printf("%s: failed to register %s xform\n",
1710ddfd867SAndrey V. Elsukov __func__, xsp->xf_name);
1720ddfd867SAndrey V. Elsukov return;
1730ddfd867SAndrey V. Elsukov }
1740ddfd867SAndrey V. Elsukov }
1750ddfd867SAndrey V. Elsukov LIST_INSERT_HEAD(&xforms, xsp, chain);
1760ddfd867SAndrey V. Elsukov xsp->xf_cntr = IPSEC_MODULE_ENABLED;
1770ddfd867SAndrey V. Elsukov XFORMS_UNLOCK();
1780ddfd867SAndrey V. Elsukov }
1790ddfd867SAndrey V. Elsukov
1800ddfd867SAndrey V. Elsukov void
xform_detach(void * data)1810ddfd867SAndrey V. Elsukov xform_detach(void *data)
1820ddfd867SAndrey V. Elsukov {
1830ddfd867SAndrey V. Elsukov struct xformsw *xsp = (struct xformsw *)data;
1840ddfd867SAndrey V. Elsukov
1850ddfd867SAndrey V. Elsukov XFORMS_LOCK();
1860ddfd867SAndrey V. Elsukov LIST_REMOVE(xsp, chain);
1870ddfd867SAndrey V. Elsukov XFORMS_UNLOCK();
1880ddfd867SAndrey V. Elsukov
1890ddfd867SAndrey V. Elsukov /* Delete all SAs related to this xform. */
1900ddfd867SAndrey V. Elsukov key_delete_xform(xsp);
1910ddfd867SAndrey V. Elsukov if (xsp->xf_cntr & IPSEC_MODULE_ENABLED)
1920ddfd867SAndrey V. Elsukov ipsec_kmod_drain(&xsp->xf_cntr);
1930ddfd867SAndrey V. Elsukov }
1940ddfd867SAndrey V. Elsukov
1950ddfd867SAndrey V. Elsukov /*
1960ddfd867SAndrey V. Elsukov * Initialize transform support in an sav.
1970ddfd867SAndrey V. Elsukov */
1980ddfd867SAndrey V. Elsukov int
xform_init(struct secasvar * sav,u_short xftype)1990ddfd867SAndrey V. Elsukov xform_init(struct secasvar *sav, u_short xftype)
2000ddfd867SAndrey V. Elsukov {
2010ddfd867SAndrey V. Elsukov struct xformsw *entry;
2020ddfd867SAndrey V. Elsukov int ret;
2030ddfd867SAndrey V. Elsukov
2040ddfd867SAndrey V. Elsukov IPSEC_ASSERT(sav->tdb_xform == NULL,
2050ddfd867SAndrey V. Elsukov ("tdb_xform is already initialized"));
2060ddfd867SAndrey V. Elsukov
2070ddfd867SAndrey V. Elsukov XFORMS_LOCK();
2080ddfd867SAndrey V. Elsukov LIST_FOREACH(entry, &xforms, chain) {
2090ddfd867SAndrey V. Elsukov if (entry->xf_type == xftype) {
2100ddfd867SAndrey V. Elsukov ret = ipsec_kmod_enter(&entry->xf_cntr);
2110ddfd867SAndrey V. Elsukov XFORMS_UNLOCK();
2120ddfd867SAndrey V. Elsukov if (ret != 0)
2130ddfd867SAndrey V. Elsukov return (ret);
2140ddfd867SAndrey V. Elsukov ret = (*entry->xf_init)(sav, entry);
2150ddfd867SAndrey V. Elsukov ipsec_kmod_exit(&entry->xf_cntr);
2160ddfd867SAndrey V. Elsukov return (ret);
2170ddfd867SAndrey V. Elsukov }
2180ddfd867SAndrey V. Elsukov }
2190ddfd867SAndrey V. Elsukov XFORMS_UNLOCK();
2200ddfd867SAndrey V. Elsukov return (EINVAL);
2210ddfd867SAndrey V. Elsukov }
2220ddfd867SAndrey V. Elsukov
2230ddfd867SAndrey V. Elsukov #ifdef IPSEC_SUPPORT
2240ddfd867SAndrey V. Elsukov /*
2250ddfd867SAndrey V. Elsukov * IPSEC_SUPPORT - loading of ipsec.ko and tcpmd5.ko is supported.
2260ddfd867SAndrey V. Elsukov * IPSEC + IPSEC_SUPPORT - loading tcpmd5.ko is supported.
2270ddfd867SAndrey V. Elsukov * IPSEC + TCP_SIGNATURE - all is build in the kernel, do not build
2280ddfd867SAndrey V. Elsukov * IPSEC_SUPPORT.
2290ddfd867SAndrey V. Elsukov */
2300ddfd867SAndrey V. Elsukov #if !defined(IPSEC) || !defined(TCP_SIGNATURE)
231fcf59617SAndrey V. Elsukov #define METHOD_DECL(...) __VA_ARGS__
232fcf59617SAndrey V. Elsukov #define METHOD_ARGS(...) __VA_ARGS__
233fcf59617SAndrey V. Elsukov #define IPSEC_KMOD_METHOD(type, name, sc, method, decl, args) \
234fcf59617SAndrey V. Elsukov type name (decl) \
235fcf59617SAndrey V. Elsukov { \
236fcf59617SAndrey V. Elsukov type ret = (type)ipsec_kmod_enter(&sc->enabled); \
237fcf59617SAndrey V. Elsukov if (ret == 0) { \
238fcf59617SAndrey V. Elsukov ret = (*sc->methods->method)(args); \
239fcf59617SAndrey V. Elsukov ipsec_kmod_exit(&sc->enabled); \
240fcf59617SAndrey V. Elsukov } \
241fcf59617SAndrey V. Elsukov return (ret); \
242fcf59617SAndrey V. Elsukov }
243fcf59617SAndrey V. Elsukov
244ddc9f8e8SAndrey V. Elsukov static int
ipsec_support_modevent(module_t mod,int type,void * data)245ddc9f8e8SAndrey V. Elsukov ipsec_support_modevent(module_t mod, int type, void *data)
246ddc9f8e8SAndrey V. Elsukov {
247ddc9f8e8SAndrey V. Elsukov
248ddc9f8e8SAndrey V. Elsukov switch (type) {
249ddc9f8e8SAndrey V. Elsukov case MOD_LOAD:
250ddc9f8e8SAndrey V. Elsukov return (0);
251ddc9f8e8SAndrey V. Elsukov case MOD_UNLOAD:
252ddc9f8e8SAndrey V. Elsukov return (EBUSY);
253ddc9f8e8SAndrey V. Elsukov default:
254ddc9f8e8SAndrey V. Elsukov return (EOPNOTSUPP);
255ddc9f8e8SAndrey V. Elsukov }
256ddc9f8e8SAndrey V. Elsukov }
257ddc9f8e8SAndrey V. Elsukov
258ddc9f8e8SAndrey V. Elsukov static moduledata_t ipsec_support_mod = {
259ddc9f8e8SAndrey V. Elsukov "ipsec_support",
260ddc9f8e8SAndrey V. Elsukov ipsec_support_modevent,
261ddc9f8e8SAndrey V. Elsukov 0
262ddc9f8e8SAndrey V. Elsukov };
263ddc9f8e8SAndrey V. Elsukov DECLARE_MODULE(ipsec_support, ipsec_support_mod, SI_SUB_PROTO_DOMAIN,
264ddc9f8e8SAndrey V. Elsukov SI_ORDER_ANY);
265ddc9f8e8SAndrey V. Elsukov MODULE_VERSION(ipsec_support, 1);
266ddc9f8e8SAndrey V. Elsukov #endif /* !IPSEC || !TCP_SIGNATURE */
267ddc9f8e8SAndrey V. Elsukov
268fcf59617SAndrey V. Elsukov #ifndef TCP_SIGNATURE
269fcf59617SAndrey V. Elsukov /* Declare TCP-MD5 support as kernel module. */
270fcf59617SAndrey V. Elsukov static struct tcpmd5_support tcpmd5_ipsec = {
271fcf59617SAndrey V. Elsukov .enabled = 0,
272fcf59617SAndrey V. Elsukov .methods = NULL
273fcf59617SAndrey V. Elsukov };
274fcf59617SAndrey V. Elsukov struct tcpmd5_support * const tcp_ipsec_support = &tcpmd5_ipsec;
275fcf59617SAndrey V. Elsukov
IPSEC_KMOD_METHOD(int,tcpmd5_kmod_input,sc,input,METHOD_DECL (struct tcpmd5_support * const sc,struct mbuf * m,struct tcphdr * th,u_char * buf),METHOD_ARGS (m,th,buf))276fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_input, sc,
277fcf59617SAndrey V. Elsukov input, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
278fcf59617SAndrey V. Elsukov struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
279fcf59617SAndrey V. Elsukov )
280fcf59617SAndrey V. Elsukov
281fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_output, sc,
282fcf59617SAndrey V. Elsukov output, METHOD_DECL(struct tcpmd5_support * const sc, struct mbuf *m,
283fcf59617SAndrey V. Elsukov struct tcphdr *th, u_char *buf), METHOD_ARGS(m, th, buf)
284fcf59617SAndrey V. Elsukov )
285fcf59617SAndrey V. Elsukov
286fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, tcpmd5_kmod_pcbctl, sc,
287fcf59617SAndrey V. Elsukov pcbctl, METHOD_DECL(struct tcpmd5_support * const sc, struct inpcb *inp,
288fcf59617SAndrey V. Elsukov struct sockopt *sopt), METHOD_ARGS(inp, sopt)
289fcf59617SAndrey V. Elsukov )
290fcf59617SAndrey V. Elsukov
291fcf59617SAndrey V. Elsukov void
292fcf59617SAndrey V. Elsukov tcpmd5_support_enable(const struct tcpmd5_methods * const methods)
293fcf59617SAndrey V. Elsukov {
294fcf59617SAndrey V. Elsukov
295fcf59617SAndrey V. Elsukov KASSERT(tcp_ipsec_support->enabled == 0, ("TCP-MD5 already enabled"));
296fcf59617SAndrey V. Elsukov tcp_ipsec_support->methods = methods;
297fcf59617SAndrey V. Elsukov tcp_ipsec_support->enabled |= IPSEC_MODULE_ENABLED;
298fcf59617SAndrey V. Elsukov }
299fcf59617SAndrey V. Elsukov
300fcf59617SAndrey V. Elsukov void
tcpmd5_support_disable(void)301fcf59617SAndrey V. Elsukov tcpmd5_support_disable(void)
302fcf59617SAndrey V. Elsukov {
303fcf59617SAndrey V. Elsukov
304fcf59617SAndrey V. Elsukov if (tcp_ipsec_support->enabled & IPSEC_MODULE_ENABLED) {
305fcf59617SAndrey V. Elsukov ipsec_kmod_drain(&tcp_ipsec_support->enabled);
306fcf59617SAndrey V. Elsukov tcp_ipsec_support->methods = NULL;
307fcf59617SAndrey V. Elsukov }
308fcf59617SAndrey V. Elsukov }
309ddc9f8e8SAndrey V. Elsukov #endif /* !TCP_SIGNATURE */
310fcf59617SAndrey V. Elsukov
311fcf59617SAndrey V. Elsukov #ifndef IPSEC
312fcf59617SAndrey V. Elsukov /*
313fcf59617SAndrey V. Elsukov * IPsec support is build as kernel module.
314fcf59617SAndrey V. Elsukov */
315fcf59617SAndrey V. Elsukov #ifdef INET
316fcf59617SAndrey V. Elsukov static struct ipsec_support ipv4_ipsec = {
317fcf59617SAndrey V. Elsukov .enabled = 0,
318fcf59617SAndrey V. Elsukov .methods = NULL
319fcf59617SAndrey V. Elsukov };
320fcf59617SAndrey V. Elsukov struct ipsec_support * const ipv4_ipsec_support = &ipv4_ipsec;
321122dd78cSLexi Winter #endif
322122dd78cSLexi Winter
323122dd78cSLexi Winter #ifdef INET6
324122dd78cSLexi Winter static struct ipsec_support ipv6_ipsec = {
325122dd78cSLexi Winter .enabled = 0,
326122dd78cSLexi Winter .methods = NULL
327122dd78cSLexi Winter };
328122dd78cSLexi Winter struct ipsec_support * const ipv6_ipsec_support = &ipv6_ipsec;
329122dd78cSLexi Winter #endif
330fcf59617SAndrey V. Elsukov
IPSEC_KMOD_METHOD(int,ipsec_kmod_udp_input,sc,udp_input,METHOD_DECL (struct ipsec_support * const sc,struct mbuf * m,int off,int af),METHOD_ARGS (m,off,af))331fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_input, sc,
332fcf59617SAndrey V. Elsukov udp_input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
333fcf59617SAndrey V. Elsukov int off, int af), METHOD_ARGS(m, off, af)
334fcf59617SAndrey V. Elsukov )
335fcf59617SAndrey V. Elsukov
336fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_udp_pcbctl, sc,
337fcf59617SAndrey V. Elsukov udp_pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
338fcf59617SAndrey V. Elsukov struct sockopt *sopt), METHOD_ARGS(inp, sopt)
339fcf59617SAndrey V. Elsukov )
340fcf59617SAndrey V. Elsukov
341fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_input, sc,
342fcf59617SAndrey V. Elsukov input, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
343fcf59617SAndrey V. Elsukov int offset, int proto), METHOD_ARGS(m, offset, proto)
344fcf59617SAndrey V. Elsukov )
345fcf59617SAndrey V. Elsukov
346fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_check_policy, sc,
347fcf59617SAndrey V. Elsukov check_policy, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
348fcf59617SAndrey V. Elsukov struct inpcb *inp), METHOD_ARGS(m, inp)
349fcf59617SAndrey V. Elsukov )
350fcf59617SAndrey V. Elsukov
351fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_forward, sc,
352fcf59617SAndrey V. Elsukov forward, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m),
353fcf59617SAndrey V. Elsukov (m)
354fcf59617SAndrey V. Elsukov )
355fcf59617SAndrey V. Elsukov
356d9d59bb1SWojciech Macek IPSEC_KMOD_METHOD(int, ipsec_kmod_ctlinput, sc,
3579f69c0b8SHans Petter Selasky ctlinput, METHOD_DECL(struct ipsec_support * const sc,
3589f69c0b8SHans Petter Selasky ipsec_ctlinput_param_t param), METHOD_ARGS(param)
359d9d59bb1SWojciech Macek )
360d9d59bb1SWojciech Macek
36100524fd4SKonstantin Belousov IPSEC_KMOD_METHOD(int, ipsec_kmod_output, sc, output,
36200524fd4SKonstantin Belousov METHOD_DECL(struct ipsec_support * const sc, struct ifnet *ifp,
36300524fd4SKonstantin Belousov struct mbuf *m, struct inpcb *inp, u_long mtu),
36400524fd4SKonstantin Belousov METHOD_ARGS(ifp, m, inp, mtu)
365fcf59617SAndrey V. Elsukov )
366fcf59617SAndrey V. Elsukov
367fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(int, ipsec_kmod_pcbctl, sc,
368fcf59617SAndrey V. Elsukov pcbctl, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp,
369fcf59617SAndrey V. Elsukov struct sockopt *sopt), METHOD_ARGS(inp, sopt)
370fcf59617SAndrey V. Elsukov )
371fcf59617SAndrey V. Elsukov
372fcf59617SAndrey V. Elsukov IPSEC_KMOD_METHOD(size_t, ipsec_kmod_hdrsize, sc,
373fcf59617SAndrey V. Elsukov hdrsize, METHOD_DECL(struct ipsec_support * const sc, struct inpcb *inp),
374fcf59617SAndrey V. Elsukov (inp)
375fcf59617SAndrey V. Elsukov )
376fcf59617SAndrey V. Elsukov
377fcf59617SAndrey V. Elsukov static IPSEC_KMOD_METHOD(int, ipsec_kmod_caps, sc,
378fcf59617SAndrey V. Elsukov capability, METHOD_DECL(struct ipsec_support * const sc, struct mbuf *m,
379fcf59617SAndrey V. Elsukov u_int cap), METHOD_ARGS(m, cap)
380fcf59617SAndrey V. Elsukov )
381fcf59617SAndrey V. Elsukov
382fcf59617SAndrey V. Elsukov int
383fcf59617SAndrey V. Elsukov ipsec_kmod_capability(struct ipsec_support * const sc, struct mbuf *m,
384fcf59617SAndrey V. Elsukov u_int cap)
385fcf59617SAndrey V. Elsukov {
386fcf59617SAndrey V. Elsukov
387fcf59617SAndrey V. Elsukov /*
388fcf59617SAndrey V. Elsukov * Since PF_KEY is build in the kernel, we can directly
389fcf59617SAndrey V. Elsukov * call key_havesp() without additional synchronizations.
390fcf59617SAndrey V. Elsukov */
391fcf59617SAndrey V. Elsukov if (cap == IPSEC_CAP_OPERABLE)
392c1bfe8c5SMateusz Guzik return (key_havesp_any());
393fcf59617SAndrey V. Elsukov return (ipsec_kmod_caps(sc, m, cap));
394fcf59617SAndrey V. Elsukov }
395fcf59617SAndrey V. Elsukov
396fcf59617SAndrey V. Elsukov void
ipsec_support_enable(struct ipsec_support * const sc,const struct ipsec_methods * const methods)397fcf59617SAndrey V. Elsukov ipsec_support_enable(struct ipsec_support * const sc,
398fcf59617SAndrey V. Elsukov const struct ipsec_methods * const methods)
399fcf59617SAndrey V. Elsukov {
400fcf59617SAndrey V. Elsukov
401fcf59617SAndrey V. Elsukov KASSERT(sc->enabled == 0, ("IPsec already enabled"));
402fcf59617SAndrey V. Elsukov sc->methods = methods;
403fcf59617SAndrey V. Elsukov sc->enabled |= IPSEC_MODULE_ENABLED;
404fcf59617SAndrey V. Elsukov }
405fcf59617SAndrey V. Elsukov
406fcf59617SAndrey V. Elsukov void
ipsec_support_disable(struct ipsec_support * const sc)407fcf59617SAndrey V. Elsukov ipsec_support_disable(struct ipsec_support * const sc)
408fcf59617SAndrey V. Elsukov {
409fcf59617SAndrey V. Elsukov
410fcf59617SAndrey V. Elsukov if (sc->enabled & IPSEC_MODULE_ENABLED) {
411fcf59617SAndrey V. Elsukov ipsec_kmod_drain(&sc->enabled);
412fcf59617SAndrey V. Elsukov sc->methods = NULL;
413fcf59617SAndrey V. Elsukov }
414fcf59617SAndrey V. Elsukov }
415fcf59617SAndrey V. Elsukov #endif /* !IPSEC */
416fcf59617SAndrey V. Elsukov #endif /* IPSEC_SUPPORT */
417