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 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 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 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 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 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 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 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 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 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 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 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 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 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