1bdea400fSAndrew Thompson /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni *
4bdea400fSAndrew Thompson * Copyright (c) 2006 The FreeBSD Project.
5ef91a976SAndrey V. Elsukov * Copyright (c) 2015 Andrey V. Elsukov <ae@FreeBSD.org>
6bdea400fSAndrew Thompson * All rights reserved.
7bdea400fSAndrew Thompson *
8bdea400fSAndrew Thompson * Redistribution and use in source and binary forms, with or without
9bdea400fSAndrew Thompson * modification, are permitted provided that the following conditions
10bdea400fSAndrew Thompson * are met:
11bdea400fSAndrew Thompson *
12bdea400fSAndrew Thompson * 1. Redistributions of source code must retain the above copyright
13bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer.
14bdea400fSAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright
15bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer in the
16bdea400fSAndrew Thompson * documentation and/or other materials provided with the distribution.
17bdea400fSAndrew Thompson *
18bdea400fSAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19bdea400fSAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20bdea400fSAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21bdea400fSAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22bdea400fSAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23bdea400fSAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24bdea400fSAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25bdea400fSAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26bdea400fSAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27bdea400fSAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28bdea400fSAndrew Thompson * SUCH DAMAGE.
29bdea400fSAndrew Thompson */
30bdea400fSAndrew Thompson
31a0ae8f04SBjoern A. Zeeb #include "opt_inet.h"
32a0ae8f04SBjoern A. Zeeb #include "opt_inet6.h"
3328d2a72bSJohn Baldwin #include "opt_ipsec.h"
34a0ae8f04SBjoern A. Zeeb
35bdea400fSAndrew Thompson #include <sys/param.h>
36bdea400fSAndrew Thompson #include <sys/systm.h>
37766b4e4bSEnji Cooper #include <sys/hhook.h>
38bdea400fSAndrew Thompson #include <sys/kernel.h>
39bdea400fSAndrew Thompson #include <sys/malloc.h>
40bdea400fSAndrew Thompson #include <sys/mbuf.h>
41bdea400fSAndrew Thompson #include <sys/module.h>
42bdea400fSAndrew Thompson #include <machine/bus.h>
43bdea400fSAndrew Thompson #include <sys/rman.h>
44bdea400fSAndrew Thompson #include <sys/socket.h>
45bdea400fSAndrew Thompson #include <sys/sockio.h>
46bdea400fSAndrew Thompson #include <sys/sysctl.h>
47bdea400fSAndrew Thompson
48bdea400fSAndrew Thompson #include <net/if.h>
49766b4e4bSEnji Cooper #include <net/if_enc.h>
5076039bc8SGleb Smirnoff #include <net/if_var.h>
512c2b37adSJustin Hibbits #include <net/if_private.h>
52bdea400fSAndrew Thompson #include <net/if_clone.h>
53bdea400fSAndrew Thompson #include <net/if_types.h>
54bdea400fSAndrew Thompson #include <net/pfil.h>
55bdea400fSAndrew Thompson #include <net/route.h>
56bdea400fSAndrew Thompson #include <net/netisr.h>
57bdea400fSAndrew Thompson #include <net/bpf.h>
58eddfbb76SRobert Watson #include <net/vnet.h>
59bdea400fSAndrew Thompson
60bdea400fSAndrew Thompson #include <netinet/in.h>
61bdea400fSAndrew Thompson #include <netinet/in_systm.h>
62bdea400fSAndrew Thompson #include <netinet/ip.h>
63bdea400fSAndrew Thompson #include <netinet/ip_var.h>
64bdea400fSAndrew Thompson #include <netinet/in_var.h>
65bdea400fSAndrew Thompson
66bdea400fSAndrew Thompson #ifdef INET6
67bdea400fSAndrew Thompson #include <netinet/ip6.h>
68bdea400fSAndrew Thompson #include <netinet6/ip6_var.h>
69bdea400fSAndrew Thompson #endif
70bdea400fSAndrew Thompson
71bdea400fSAndrew Thompson #include <netipsec/ipsec.h>
7219ad9831SBjoern A. Zeeb #include <netipsec/xform.h>
73bdea400fSAndrew Thompson
74bdea400fSAndrew Thompson #define ENCMTU (1024+512)
75bdea400fSAndrew Thompson
76bdea400fSAndrew Thompson /* XXX this define must have the same value as in OpenBSD */
77bdea400fSAndrew Thompson #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */
78bdea400fSAndrew Thompson #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */
79bdea400fSAndrew Thompson #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */
80bdea400fSAndrew Thompson
81bdea400fSAndrew Thompson struct enchdr {
82bdea400fSAndrew Thompson u_int32_t af;
83bdea400fSAndrew Thompson u_int32_t spi;
84bdea400fSAndrew Thompson u_int32_t flags;
85bdea400fSAndrew Thompson };
86bdea400fSAndrew Thompson struct enc_softc {
87bdea400fSAndrew Thompson struct ifnet *sc_ifp;
88bdea400fSAndrew Thompson };
895f901c92SAndrew Turner VNET_DEFINE_STATIC(struct enc_softc *, enc_sc);
90ef91a976SAndrey V. Elsukov #define V_enc_sc VNET(enc_sc)
915f901c92SAndrew Turner VNET_DEFINE_STATIC(struct if_clone *, enc_cloner);
92ef91a976SAndrey V. Elsukov #define V_enc_cloner VNET(enc_cloner)
93bdea400fSAndrew Thompson
94bdea400fSAndrew Thompson static int enc_ioctl(struct ifnet *, u_long, caddr_t);
95ef91a976SAndrey V. Elsukov static int enc_output(struct ifnet *, struct mbuf *,
96ef91a976SAndrey V. Elsukov const struct sockaddr *, struct route *);
97*eacad82fSZhenlei Huang static int enc_clone_create(struct if_clone *, char *, size_t,
98*eacad82fSZhenlei Huang struct ifc_data *, struct ifnet **);
99*eacad82fSZhenlei Huang static int enc_clone_destroy(struct if_clone *, struct ifnet *, uint32_t);
1007643141eSZhenlei Huang static void enc_add_hhooks(struct enc_softc *);
101ef91a976SAndrey V. Elsukov static void enc_remove_hhooks(struct enc_softc *);
102bdea400fSAndrew Thompson
103ef91a976SAndrey V. Elsukov static const char encname[] = "enc";
10419ad9831SBjoern A. Zeeb
10595e8b991SAndrey V. Elsukov #define IPSEC_ENC_AFTER_PFIL 0x04
10619ad9831SBjoern A. Zeeb /*
10719ad9831SBjoern A. Zeeb * Before and after are relative to when we are stripping the
10819ad9831SBjoern A. Zeeb * outer IP header.
10995e8b991SAndrey V. Elsukov *
11095e8b991SAndrey V. Elsukov * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing
11195e8b991SAndrey V. Elsukov * after PFIL hook execution. It might be useful when PFIL hook does
11295e8b991SAndrey V. Elsukov * some changes to the packet, e.g. address translation. If PFIL hook
11395e8b991SAndrey V. Elsukov * consumes mbuf, nothing will be captured.
11419ad9831SBjoern A. Zeeb */
1155f901c92SAndrew Turner VNET_DEFINE_STATIC(int, filter_mask_in) = IPSEC_ENC_BEFORE;
1165f901c92SAndrew Turner VNET_DEFINE_STATIC(int, bpf_mask_in) = IPSEC_ENC_BEFORE;
1175f901c92SAndrew Turner VNET_DEFINE_STATIC(int, filter_mask_out) = IPSEC_ENC_BEFORE;
1185f901c92SAndrew Turner VNET_DEFINE_STATIC(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER;
119ef91a976SAndrey V. Elsukov #define V_filter_mask_in VNET(filter_mask_in)
120ef91a976SAndrey V. Elsukov #define V_bpf_mask_in VNET(bpf_mask_in)
121ef91a976SAndrey V. Elsukov #define V_filter_mask_out VNET(filter_mask_out)
122ef91a976SAndrey V. Elsukov #define V_bpf_mask_out VNET(bpf_mask_out)
123ef91a976SAndrey V. Elsukov
1247029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1257029da5cSPawel Biernacki "enc sysctl");
1267029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1277029da5cSPawel Biernacki "enc input sysctl");
1287029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1297029da5cSPawel Biernacki "enc output sysctl");
130ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask,
131ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0,
132ef91a976SAndrey V. Elsukov "IPsec input firewall filter mask");
133ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask,
134ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0,
135ef91a976SAndrey V. Elsukov "IPsec input bpf mask");
136ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask,
137ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0,
138ef91a976SAndrey V. Elsukov "IPsec output firewall filter mask");
139ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask,
140ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0,
141ef91a976SAndrey V. Elsukov "IPsec output bpf mask");
14219ad9831SBjoern A. Zeeb
143*eacad82fSZhenlei Huang static int
enc_clone_destroy(struct if_clone * ifc,struct ifnet * ifp,uint32_t flags)144*eacad82fSZhenlei Huang enc_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
145bdea400fSAndrew Thompson {
146ef91a976SAndrey V. Elsukov struct enc_softc *sc;
147bdea400fSAndrew Thompson
148*eacad82fSZhenlei Huang if (ifp->if_dunit == 0 && (flags & IFC_F_FORCE) == 0)
149*eacad82fSZhenlei Huang return (EINVAL);
150*eacad82fSZhenlei Huang
151ef91a976SAndrey V. Elsukov sc = ifp->if_softc;
152ef91a976SAndrey V. Elsukov KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc"));
153ef91a976SAndrey V. Elsukov
154bdea400fSAndrew Thompson bpfdetach(ifp);
155bdea400fSAndrew Thompson if_detach(ifp);
156bdea400fSAndrew Thompson if_free(ifp);
157ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF);
158*eacad82fSZhenlei Huang return (0);
159bdea400fSAndrew Thompson }
160bdea400fSAndrew Thompson
161bdea400fSAndrew Thompson static int
enc_clone_create(struct if_clone * ifc,char * name,size_t len,struct ifc_data * ifd,struct ifnet ** ifpp)162*eacad82fSZhenlei Huang enc_clone_create(struct if_clone *ifc, char *name, size_t len,
163*eacad82fSZhenlei Huang struct ifc_data *ifd, struct ifnet **ifpp)
164bdea400fSAndrew Thompson {
165bdea400fSAndrew Thompson struct ifnet *ifp;
166bdea400fSAndrew Thompson struct enc_softc *sc;
167bdea400fSAndrew Thompson
168*eacad82fSZhenlei Huang sc = malloc(sizeof(struct enc_softc), M_DEVBUF, M_WAITOK | M_ZERO);
169bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC);
170*eacad82fSZhenlei Huang if_initname(ifp, encname, ifd->unit);
171bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU;
172bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl;
173bdea400fSAndrew Thompson ifp->if_output = enc_output;
174bdea400fSAndrew Thompson ifp->if_softc = sc;
175bdea400fSAndrew Thompson if_attach(ifp);
176f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr));
177*eacad82fSZhenlei Huang *ifpp = ifp;
178bdea400fSAndrew Thompson return (0);
179bdea400fSAndrew Thompson }
180bdea400fSAndrew Thompson
181bdea400fSAndrew Thompson static int
enc_output(struct ifnet * ifp,struct mbuf * m,const struct sockaddr * dst,struct route * ro)182ef91a976SAndrey V. Elsukov enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
183ef91a976SAndrey V. Elsukov struct route *ro)
184ef91a976SAndrey V. Elsukov {
185ef91a976SAndrey V. Elsukov
186ef91a976SAndrey V. Elsukov m_freem(m);
187ef91a976SAndrey V. Elsukov return (0);
188ef91a976SAndrey V. Elsukov }
189ef91a976SAndrey V. Elsukov
190ef91a976SAndrey V. Elsukov static int
enc_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)191ef91a976SAndrey V. Elsukov enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
192ef91a976SAndrey V. Elsukov {
193ef91a976SAndrey V. Elsukov
194ef91a976SAndrey V. Elsukov if (cmd != SIOCSIFFLAGS)
195ef91a976SAndrey V. Elsukov return (EINVAL);
196ef91a976SAndrey V. Elsukov if (ifp->if_flags & IFF_UP)
197ef91a976SAndrey V. Elsukov ifp->if_drv_flags |= IFF_DRV_RUNNING;
198ef91a976SAndrey V. Elsukov else
199ef91a976SAndrey V. Elsukov ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
200ef91a976SAndrey V. Elsukov return (0);
201ef91a976SAndrey V. Elsukov }
202ef91a976SAndrey V. Elsukov
20395e8b991SAndrey V. Elsukov static void
enc_bpftap(struct ifnet * ifp,struct mbuf * m,const struct secasvar * sav,int32_t hhook_type,uint8_t enc,uint8_t af)20495e8b991SAndrey V. Elsukov enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav,
20595e8b991SAndrey V. Elsukov int32_t hhook_type, uint8_t enc, uint8_t af)
20695e8b991SAndrey V. Elsukov {
20795e8b991SAndrey V. Elsukov struct enchdr hdr;
20895e8b991SAndrey V. Elsukov
20995e8b991SAndrey V. Elsukov if (hhook_type == HHOOK_TYPE_IPSEC_IN &&
21095e8b991SAndrey V. Elsukov (enc & V_bpf_mask_in) == 0)
21195e8b991SAndrey V. Elsukov return;
21295e8b991SAndrey V. Elsukov else if (hhook_type == HHOOK_TYPE_IPSEC_OUT &&
21395e8b991SAndrey V. Elsukov (enc & V_bpf_mask_out) == 0)
21495e8b991SAndrey V. Elsukov return;
215215a18d5SZhenlei Huang if (!bpf_peers_present(ifp->if_bpf))
21695e8b991SAndrey V. Elsukov return;
21795e8b991SAndrey V. Elsukov hdr.af = af;
21895e8b991SAndrey V. Elsukov hdr.spi = sav->spi;
21995e8b991SAndrey V. Elsukov hdr.flags = 0;
22095e8b991SAndrey V. Elsukov if (sav->alg_enc != SADB_EALG_NONE)
22195e8b991SAndrey V. Elsukov hdr.flags |= M_CONF;
22295e8b991SAndrey V. Elsukov if (sav->alg_auth != SADB_AALG_NONE)
22395e8b991SAndrey V. Elsukov hdr.flags |= M_AUTH;
22495e8b991SAndrey V. Elsukov bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m);
22595e8b991SAndrey V. Elsukov }
22695e8b991SAndrey V. Elsukov
227ef91a976SAndrey V. Elsukov /*
228ef91a976SAndrey V. Elsukov * One helper hook function is used by any hook points.
229ef91a976SAndrey V. Elsukov * + from hhook_type we can determine the packet direction:
230ef91a976SAndrey V. Elsukov * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT;
231ef91a976SAndrey V. Elsukov * + from hhook_id we can determine address family: AF_INET or AF_INET6;
232ef91a976SAndrey V. Elsukov * + udata contains pointer to enc_softc;
233ef91a976SAndrey V. Elsukov * + ctx_data contains pointer to struct ipsec_ctx_data.
234ef91a976SAndrey V. Elsukov */
235ef91a976SAndrey V. Elsukov static int
enc_hhook(int32_t hhook_type,int32_t hhook_id,void * udata,void * ctx_data,void * hdata,struct osd * hosd)236ef91a976SAndrey V. Elsukov enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data,
237ef91a976SAndrey V. Elsukov void *hdata, struct osd *hosd)
238ef91a976SAndrey V. Elsukov {
239ef91a976SAndrey V. Elsukov struct ipsec_ctx_data *ctx;
240ef91a976SAndrey V. Elsukov struct enc_softc *sc;
241ef91a976SAndrey V. Elsukov struct ifnet *ifp, *rcvif;
242ef91a976SAndrey V. Elsukov struct pfil_head *ph;
243a2256150SGleb Smirnoff int pdir, ret;
244ef91a976SAndrey V. Elsukov
245ef91a976SAndrey V. Elsukov sc = (struct enc_softc *)udata;
246ef91a976SAndrey V. Elsukov ifp = sc->sc_ifp;
247ef91a976SAndrey V. Elsukov if ((ifp->if_flags & IFF_UP) == 0)
248ef91a976SAndrey V. Elsukov return (0);
249ef91a976SAndrey V. Elsukov
250ef91a976SAndrey V. Elsukov ctx = (struct ipsec_ctx_data *)ctx_data;
251ef91a976SAndrey V. Elsukov /* XXX: wrong hook point was used by caller? */
252ef91a976SAndrey V. Elsukov if (ctx->af != hhook_id)
253ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT);
254ef91a976SAndrey V. Elsukov
25595e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af);
256ef91a976SAndrey V. Elsukov switch (hhook_type) {
257ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_IN:
258ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) {
259ef91a976SAndrey V. Elsukov /* Do accounting only once */
260ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
261ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IBYTES,
262ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len);
263ef91a976SAndrey V. Elsukov }
264ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_in) == 0)
265ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */
266ef91a976SAndrey V. Elsukov pdir = PFIL_IN;
267ef91a976SAndrey V. Elsukov break;
268ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_OUT:
269ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) {
270ef91a976SAndrey V. Elsukov /* Do accounting only once */
271ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
272ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OBYTES,
273ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len);
274ef91a976SAndrey V. Elsukov }
275ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_out) == 0)
276ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */
277ef91a976SAndrey V. Elsukov pdir = PFIL_OUT;
278ef91a976SAndrey V. Elsukov break;
279ef91a976SAndrey V. Elsukov default:
280ef91a976SAndrey V. Elsukov return (EINVAL);
281ef91a976SAndrey V. Elsukov }
282ef91a976SAndrey V. Elsukov
283ef91a976SAndrey V. Elsukov switch (hhook_id) {
284ef91a976SAndrey V. Elsukov #ifdef INET
285ef91a976SAndrey V. Elsukov case AF_INET:
286b252313fSGleb Smirnoff ph = V_inet_pfil_head;
287ef91a976SAndrey V. Elsukov break;
288ef91a976SAndrey V. Elsukov #endif
289ef91a976SAndrey V. Elsukov #ifdef INET6
290ef91a976SAndrey V. Elsukov case AF_INET6:
291b252313fSGleb Smirnoff ph = V_inet6_pfil_head;
292ef91a976SAndrey V. Elsukov break;
293ef91a976SAndrey V. Elsukov #endif
294ef91a976SAndrey V. Elsukov default:
295ef91a976SAndrey V. Elsukov ph = NULL;
296ef91a976SAndrey V. Elsukov }
297b252313fSGleb Smirnoff if (ph == NULL || (pdir == PFIL_OUT && !PFIL_HOOKED_OUT(ph)) ||
298b252313fSGleb Smirnoff (pdir == PFIL_IN && !PFIL_HOOKED_IN(ph)))
299ef91a976SAndrey V. Elsukov return (0);
300ef91a976SAndrey V. Elsukov /* Make a packet looks like it was received on enc(4) */
301ef91a976SAndrey V. Elsukov rcvif = (*ctx->mp)->m_pkthdr.rcvif;
302ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = ifp;
303a2256150SGleb Smirnoff if (pdir == PFIL_IN)
304a2256150SGleb Smirnoff ret = pfil_mbuf_in(ph, ctx->mp, ifp, ctx->inp);
305a2256150SGleb Smirnoff else
306a2256150SGleb Smirnoff ret = pfil_mbuf_out(ph, ctx->mp, ifp, ctx->inp);
307a2256150SGleb Smirnoff if (ret != PFIL_PASS) {
308ef91a976SAndrey V. Elsukov *ctx->mp = NULL; /* consumed by filter */
309ef91a976SAndrey V. Elsukov return (EACCES);
310ef91a976SAndrey V. Elsukov }
311ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = rcvif;
31295e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type,
31395e8b991SAndrey V. Elsukov IPSEC_ENC_AFTER_PFIL, ctx->af);
314ef91a976SAndrey V. Elsukov return (0);
315ef91a976SAndrey V. Elsukov }
316ef91a976SAndrey V. Elsukov
3177643141eSZhenlei Huang static void
enc_add_hhooks(struct enc_softc * sc)318ef91a976SAndrey V. Elsukov enc_add_hhooks(struct enc_softc *sc)
319ef91a976SAndrey V. Elsukov {
320ef91a976SAndrey V. Elsukov struct hookinfo hki;
3217643141eSZhenlei Huang int error __diagused;
322ef91a976SAndrey V. Elsukov
323ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook;
324ef91a976SAndrey V. Elsukov hki.hook_helper = NULL;
325ef91a976SAndrey V. Elsukov hki.hook_udata = sc;
326ef91a976SAndrey V. Elsukov #ifdef INET
327ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET;
328ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN;
329ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET],
330ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK);
3317643141eSZhenlei Huang MPASS(error == 0);
332ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT;
333ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET],
334ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK);
3357643141eSZhenlei Huang MPASS(error == 0);
336ef91a976SAndrey V. Elsukov #endif
337ef91a976SAndrey V. Elsukov #ifdef INET6
338ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6;
339ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN;
340ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6],
341ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK);
3427643141eSZhenlei Huang MPASS(error == 0);
343ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT;
344ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6],
345ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK);
3467643141eSZhenlei Huang MPASS(error == 0);
347ef91a976SAndrey V. Elsukov #endif
348ef91a976SAndrey V. Elsukov }
349ef91a976SAndrey V. Elsukov
350ef91a976SAndrey V. Elsukov static void
enc_remove_hhooks(struct enc_softc * sc)351ef91a976SAndrey V. Elsukov enc_remove_hhooks(struct enc_softc *sc)
352ef91a976SAndrey V. Elsukov {
353ef91a976SAndrey V. Elsukov struct hookinfo hki;
354ef91a976SAndrey V. Elsukov
355ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook;
356ef91a976SAndrey V. Elsukov hki.hook_helper = NULL;
357ef91a976SAndrey V. Elsukov hki.hook_udata = sc;
358ef91a976SAndrey V. Elsukov #ifdef INET
359ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET;
360ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN;
361ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki);
362ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT;
363ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki);
364ef91a976SAndrey V. Elsukov #endif
365ef91a976SAndrey V. Elsukov #ifdef INET6
366ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6;
367ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN;
368ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki);
369ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT;
370ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki);
371ef91a976SAndrey V. Elsukov #endif
372ef91a976SAndrey V. Elsukov }
373ef91a976SAndrey V. Elsukov
374ef91a976SAndrey V. Elsukov static void
vnet_enc_init(const void * unused __unused)375ef91a976SAndrey V. Elsukov vnet_enc_init(const void *unused __unused)
376ef91a976SAndrey V. Elsukov {
377*eacad82fSZhenlei Huang struct ifnet *ifp;
378ef91a976SAndrey V. Elsukov
379*eacad82fSZhenlei Huang struct if_clone_addreq req = {
380*eacad82fSZhenlei Huang .create_f = enc_clone_create,
381*eacad82fSZhenlei Huang .destroy_f = enc_clone_destroy,
382*eacad82fSZhenlei Huang .flags = IFC_F_AUTOUNIT | IFC_F_LIMITUNIT,
383*eacad82fSZhenlei Huang .maxunit = 0,
384*eacad82fSZhenlei Huang };
385*eacad82fSZhenlei Huang V_enc_cloner = ifc_attach_cloner(encname, &req);
386*eacad82fSZhenlei Huang struct ifc_data ifd = { .unit = 0 };
387*eacad82fSZhenlei Huang ifc_create_ifp(encname, &ifd, &ifp);
388*eacad82fSZhenlei Huang V_enc_sc = ifp->if_softc;
389ef91a976SAndrey V. Elsukov }
39089856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
391ef91a976SAndrey V. Elsukov vnet_enc_init, NULL);
392ef91a976SAndrey V. Elsukov
393ef91a976SAndrey V. Elsukov static void
vnet_enc_init_proto(void * unused __unused)39489856f7eSBjoern A. Zeeb vnet_enc_init_proto(void *unused __unused)
39589856f7eSBjoern A. Zeeb {
39689856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));
39789856f7eSBjoern A. Zeeb
3987643141eSZhenlei Huang enc_add_hhooks(V_enc_sc);
39989856f7eSBjoern A. Zeeb }
40089856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
40189856f7eSBjoern A. Zeeb vnet_enc_init_proto, NULL);
40289856f7eSBjoern A. Zeeb
40389856f7eSBjoern A. Zeeb static void
vnet_enc_uninit(const void * unused __unused)404ef91a976SAndrey V. Elsukov vnet_enc_uninit(const void *unused __unused)
405ef91a976SAndrey V. Elsukov {
40689856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));
407ef91a976SAndrey V. Elsukov
408*eacad82fSZhenlei Huang ifc_detach_cloner(V_enc_cloner);
409*eacad82fSZhenlei Huang V_enc_sc = NULL;
410ef91a976SAndrey V. Elsukov }
41189856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY,
412ef91a976SAndrey V. Elsukov vnet_enc_uninit, NULL);
413ef91a976SAndrey V. Elsukov
41489856f7eSBjoern A. Zeeb /*
41589856f7eSBjoern A. Zeeb * The hhook consumer needs to go before ip[6]_destroy are called on
41689856f7eSBjoern A. Zeeb * SI_ORDER_THIRD.
41789856f7eSBjoern A. Zeeb */
41889856f7eSBjoern A. Zeeb static void
vnet_enc_uninit_hhook(const void * unused __unused)41989856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook(const void *unused __unused)
42089856f7eSBjoern A. Zeeb {
42189856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc));
42289856f7eSBjoern A. Zeeb
42389856f7eSBjoern A. Zeeb enc_remove_hhooks(V_enc_sc);
42489856f7eSBjoern A. Zeeb }
42589856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH,
42689856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook, NULL);
42789856f7eSBjoern A. Zeeb
428ef91a976SAndrey V. Elsukov static int
enc_modevent(module_t mod,int type,void * data)429bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data)
430bdea400fSAndrew Thompson {
431ef91a976SAndrey V. Elsukov
432bdea400fSAndrew Thompson switch (type) {
433bdea400fSAndrew Thompson case MOD_LOAD:
434bdea400fSAndrew Thompson case MOD_UNLOAD:
435ef91a976SAndrey V. Elsukov break;
436bdea400fSAndrew Thompson default:
437bdea400fSAndrew Thompson return (EOPNOTSUPP);
438bdea400fSAndrew Thompson }
439bdea400fSAndrew Thompson return (0);
440bdea400fSAndrew Thompson }
441bdea400fSAndrew Thompson
442bdea400fSAndrew Thompson static moduledata_t enc_mod = {
443b3aa4193SJohn Baldwin "if_enc",
444bdea400fSAndrew Thompson enc_modevent,
4459823d527SKevin Lo 0
446bdea400fSAndrew Thompson };
447bdea400fSAndrew Thompson
44889856f7eSBjoern A. Zeeb DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
44952b8eb0bSAndrey V. Elsukov MODULE_VERSION(if_enc, 1);
450