1bdea400fSAndrew Thompson /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 31bdea400fSAndrew Thompson */ 32bdea400fSAndrew Thompson 33a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 34a0ae8f04SBjoern A. Zeeb #include "opt_inet6.h" 35a0ae8f04SBjoern A. Zeeb 36bdea400fSAndrew Thompson #include <sys/param.h> 37bdea400fSAndrew Thompson #include <sys/systm.h> 38766b4e4bSEnji Cooper #include <sys/hhook.h> 39bdea400fSAndrew Thompson #include <sys/kernel.h> 40bdea400fSAndrew Thompson #include <sys/malloc.h> 41bdea400fSAndrew Thompson #include <sys/mbuf.h> 42bdea400fSAndrew Thompson #include <sys/module.h> 43bdea400fSAndrew Thompson #include <machine/bus.h> 44bdea400fSAndrew Thompson #include <sys/rman.h> 45bdea400fSAndrew Thompson #include <sys/socket.h> 46bdea400fSAndrew Thompson #include <sys/sockio.h> 47bdea400fSAndrew Thompson #include <sys/sysctl.h> 48bdea400fSAndrew Thompson 49bdea400fSAndrew Thompson #include <net/if.h> 50766b4e4bSEnji Cooper #include <net/if_enc.h> 5176039bc8SGleb Smirnoff #include <net/if_var.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 *); 9707ed9a88SAndrew Thompson static int enc_clone_create(struct if_clone *, int, caddr_t); 98bac89dceSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 99ef91a976SAndrey V. Elsukov static int enc_add_hhooks(struct enc_softc *); 100ef91a976SAndrey V. Elsukov static void enc_remove_hhooks(struct enc_softc *); 101bdea400fSAndrew Thompson 102ef91a976SAndrey V. Elsukov static const char encname[] = "enc"; 10319ad9831SBjoern A. Zeeb 10495e8b991SAndrey V. Elsukov #define IPSEC_ENC_AFTER_PFIL 0x04 10519ad9831SBjoern A. Zeeb /* 10619ad9831SBjoern A. Zeeb * Before and after are relative to when we are stripping the 10719ad9831SBjoern A. Zeeb * outer IP header. 10895e8b991SAndrey V. Elsukov * 10995e8b991SAndrey V. Elsukov * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing 11095e8b991SAndrey V. Elsukov * after PFIL hook execution. It might be useful when PFIL hook does 11195e8b991SAndrey V. Elsukov * some changes to the packet, e.g. address translation. If PFIL hook 11295e8b991SAndrey V. Elsukov * consumes mbuf, nothing will be captured. 11319ad9831SBjoern A. Zeeb */ 1145f901c92SAndrew Turner VNET_DEFINE_STATIC(int, filter_mask_in) = IPSEC_ENC_BEFORE; 1155f901c92SAndrew Turner VNET_DEFINE_STATIC(int, bpf_mask_in) = IPSEC_ENC_BEFORE; 1165f901c92SAndrew Turner VNET_DEFINE_STATIC(int, filter_mask_out) = IPSEC_ENC_BEFORE; 1175f901c92SAndrew Turner VNET_DEFINE_STATIC(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER; 118ef91a976SAndrey V. Elsukov #define V_filter_mask_in VNET(filter_mask_in) 119ef91a976SAndrey V. Elsukov #define V_bpf_mask_in VNET(bpf_mask_in) 120ef91a976SAndrey V. Elsukov #define V_filter_mask_out VNET(filter_mask_out) 121ef91a976SAndrey V. Elsukov #define V_bpf_mask_out VNET(bpf_mask_out) 122ef91a976SAndrey V. Elsukov 123*7029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 124*7029da5cSPawel Biernacki "enc sysctl"); 125*7029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 126*7029da5cSPawel Biernacki "enc input sysctl"); 127*7029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 128*7029da5cSPawel Biernacki "enc output sysctl"); 129ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, 130ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0, 131ef91a976SAndrey V. Elsukov "IPsec input firewall filter mask"); 132ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, 133ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0, 134ef91a976SAndrey V. Elsukov "IPsec input bpf mask"); 135ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, 136ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0, 137ef91a976SAndrey V. Elsukov "IPsec output firewall filter mask"); 138ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, 139ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0, 140ef91a976SAndrey V. Elsukov "IPsec output bpf mask"); 14119ad9831SBjoern A. Zeeb 142bac89dceSAndrew Thompson static void 143bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 144bdea400fSAndrew Thompson { 145ef91a976SAndrey V. Elsukov struct enc_softc *sc; 146bdea400fSAndrew Thompson 147ef91a976SAndrey V. Elsukov sc = ifp->if_softc; 148ef91a976SAndrey V. Elsukov KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc")); 149ef91a976SAndrey V. Elsukov 150bdea400fSAndrew Thompson bpfdetach(ifp); 151bdea400fSAndrew Thompson if_detach(ifp); 152bdea400fSAndrew Thompson if_free(ifp); 153ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 154ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 155bdea400fSAndrew Thompson } 156bdea400fSAndrew Thompson 157bdea400fSAndrew Thompson static int 15807ed9a88SAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 159bdea400fSAndrew Thompson { 160bdea400fSAndrew Thompson struct ifnet *ifp; 161bdea400fSAndrew Thompson struct enc_softc *sc; 162bdea400fSAndrew Thompson 163ef91a976SAndrey V. Elsukov sc = malloc(sizeof(struct enc_softc), M_DEVBUF, 164ef91a976SAndrey V. Elsukov M_WAITOK | M_ZERO); 165bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 166bdea400fSAndrew Thompson if (ifp == NULL) { 167bdea400fSAndrew Thompson free(sc, M_DEVBUF); 168bdea400fSAndrew Thompson return (ENOSPC); 169bdea400fSAndrew Thompson } 170ef91a976SAndrey V. Elsukov if (V_enc_sc != NULL) { 171ef91a976SAndrey V. Elsukov if_free(ifp); 172ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 173ef91a976SAndrey V. Elsukov return (EEXIST); 174ef91a976SAndrey V. Elsukov } 175ef91a976SAndrey V. Elsukov V_enc_sc = sc; 17642a58907SGleb Smirnoff if_initname(ifp, encname, unit); 177bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 178bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 179bdea400fSAndrew Thompson ifp->if_output = enc_output; 180bdea400fSAndrew Thompson ifp->if_softc = sc; 181bdea400fSAndrew Thompson if_attach(ifp); 182f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 183bdea400fSAndrew Thompson return (0); 184bdea400fSAndrew Thompson } 185bdea400fSAndrew Thompson 186bdea400fSAndrew Thompson static int 187ef91a976SAndrey V. Elsukov enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 188ef91a976SAndrey V. Elsukov struct route *ro) 189ef91a976SAndrey V. Elsukov { 190ef91a976SAndrey V. Elsukov 191ef91a976SAndrey V. Elsukov m_freem(m); 192ef91a976SAndrey V. Elsukov return (0); 193ef91a976SAndrey V. Elsukov } 194ef91a976SAndrey V. Elsukov 195ef91a976SAndrey V. Elsukov static int 196ef91a976SAndrey V. Elsukov enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 197ef91a976SAndrey V. Elsukov { 198ef91a976SAndrey V. Elsukov 199ef91a976SAndrey V. Elsukov if (cmd != SIOCSIFFLAGS) 200ef91a976SAndrey V. Elsukov return (EINVAL); 201ef91a976SAndrey V. Elsukov if (ifp->if_flags & IFF_UP) 202ef91a976SAndrey V. Elsukov ifp->if_drv_flags |= IFF_DRV_RUNNING; 203ef91a976SAndrey V. Elsukov else 204ef91a976SAndrey V. Elsukov ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 205ef91a976SAndrey V. Elsukov return (0); 206ef91a976SAndrey V. Elsukov } 207ef91a976SAndrey V. Elsukov 20895e8b991SAndrey V. Elsukov static void 20995e8b991SAndrey V. Elsukov enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, 21095e8b991SAndrey V. Elsukov int32_t hhook_type, uint8_t enc, uint8_t af) 21195e8b991SAndrey V. Elsukov { 21295e8b991SAndrey V. Elsukov struct enchdr hdr; 21395e8b991SAndrey V. Elsukov 21495e8b991SAndrey V. Elsukov if (hhook_type == HHOOK_TYPE_IPSEC_IN && 21595e8b991SAndrey V. Elsukov (enc & V_bpf_mask_in) == 0) 21695e8b991SAndrey V. Elsukov return; 21795e8b991SAndrey V. Elsukov else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && 21895e8b991SAndrey V. Elsukov (enc & V_bpf_mask_out) == 0) 21995e8b991SAndrey V. Elsukov return; 22095e8b991SAndrey V. Elsukov if (bpf_peers_present(ifp->if_bpf) == 0) 22195e8b991SAndrey V. Elsukov return; 22295e8b991SAndrey V. Elsukov hdr.af = af; 22395e8b991SAndrey V. Elsukov hdr.spi = sav->spi; 22495e8b991SAndrey V. Elsukov hdr.flags = 0; 22595e8b991SAndrey V. Elsukov if (sav->alg_enc != SADB_EALG_NONE) 22695e8b991SAndrey V. Elsukov hdr.flags |= M_CONF; 22795e8b991SAndrey V. Elsukov if (sav->alg_auth != SADB_AALG_NONE) 22895e8b991SAndrey V. Elsukov hdr.flags |= M_AUTH; 22995e8b991SAndrey V. Elsukov bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); 23095e8b991SAndrey V. Elsukov } 23195e8b991SAndrey V. Elsukov 232ef91a976SAndrey V. Elsukov /* 233ef91a976SAndrey V. Elsukov * One helper hook function is used by any hook points. 234ef91a976SAndrey V. Elsukov * + from hhook_type we can determine the packet direction: 235ef91a976SAndrey V. Elsukov * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT; 236ef91a976SAndrey V. Elsukov * + from hhook_id we can determine address family: AF_INET or AF_INET6; 237ef91a976SAndrey V. Elsukov * + udata contains pointer to enc_softc; 238ef91a976SAndrey V. Elsukov * + ctx_data contains pointer to struct ipsec_ctx_data. 239ef91a976SAndrey V. Elsukov */ 240ef91a976SAndrey V. Elsukov static int 241ef91a976SAndrey V. Elsukov enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, 242ef91a976SAndrey V. Elsukov void *hdata, struct osd *hosd) 243ef91a976SAndrey V. Elsukov { 244ef91a976SAndrey V. Elsukov struct ipsec_ctx_data *ctx; 245ef91a976SAndrey V. Elsukov struct enc_softc *sc; 246ef91a976SAndrey V. Elsukov struct ifnet *ifp, *rcvif; 247ef91a976SAndrey V. Elsukov struct pfil_head *ph; 248ef91a976SAndrey V. Elsukov int pdir; 249ef91a976SAndrey V. Elsukov 250ef91a976SAndrey V. Elsukov sc = (struct enc_softc *)udata; 251ef91a976SAndrey V. Elsukov ifp = sc->sc_ifp; 252ef91a976SAndrey V. Elsukov if ((ifp->if_flags & IFF_UP) == 0) 253ef91a976SAndrey V. Elsukov return (0); 254ef91a976SAndrey V. Elsukov 255ef91a976SAndrey V. Elsukov ctx = (struct ipsec_ctx_data *)ctx_data; 256ef91a976SAndrey V. Elsukov /* XXX: wrong hook point was used by caller? */ 257ef91a976SAndrey V. Elsukov if (ctx->af != hhook_id) 258ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 259ef91a976SAndrey V. Elsukov 26095e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); 261ef91a976SAndrey V. Elsukov switch (hhook_type) { 262ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_IN: 263ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 264ef91a976SAndrey V. Elsukov /* Do accounting only once */ 265ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 266ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IBYTES, 267ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 268ef91a976SAndrey V. Elsukov } 269ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_in) == 0) 270ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 271ef91a976SAndrey V. Elsukov pdir = PFIL_IN; 272ef91a976SAndrey V. Elsukov break; 273ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_OUT: 274ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 275ef91a976SAndrey V. Elsukov /* Do accounting only once */ 276ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 277ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OBYTES, 278ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 279ef91a976SAndrey V. Elsukov } 280ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_out) == 0) 281ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 282ef91a976SAndrey V. Elsukov pdir = PFIL_OUT; 283ef91a976SAndrey V. Elsukov break; 284ef91a976SAndrey V. Elsukov default: 285ef91a976SAndrey V. Elsukov return (EINVAL); 286ef91a976SAndrey V. Elsukov } 287ef91a976SAndrey V. Elsukov 288ef91a976SAndrey V. Elsukov switch (hhook_id) { 289ef91a976SAndrey V. Elsukov #ifdef INET 290ef91a976SAndrey V. Elsukov case AF_INET: 291b252313fSGleb Smirnoff ph = V_inet_pfil_head; 292ef91a976SAndrey V. Elsukov break; 293ef91a976SAndrey V. Elsukov #endif 294ef91a976SAndrey V. Elsukov #ifdef INET6 295ef91a976SAndrey V. Elsukov case AF_INET6: 296b252313fSGleb Smirnoff ph = V_inet6_pfil_head; 297ef91a976SAndrey V. Elsukov break; 298ef91a976SAndrey V. Elsukov #endif 299ef91a976SAndrey V. Elsukov default: 300ef91a976SAndrey V. Elsukov ph = NULL; 301ef91a976SAndrey V. Elsukov } 302b252313fSGleb Smirnoff if (ph == NULL || (pdir == PFIL_OUT && !PFIL_HOOKED_OUT(ph)) || 303b252313fSGleb Smirnoff (pdir == PFIL_IN && !PFIL_HOOKED_IN(ph))) 304ef91a976SAndrey V. Elsukov return (0); 305ef91a976SAndrey V. Elsukov /* Make a packet looks like it was received on enc(4) */ 306ef91a976SAndrey V. Elsukov rcvif = (*ctx->mp)->m_pkthdr.rcvif; 307ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = ifp; 308b252313fSGleb Smirnoff if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != PFIL_PASS) { 309ef91a976SAndrey V. Elsukov *ctx->mp = NULL; /* consumed by filter */ 310ef91a976SAndrey V. Elsukov return (EACCES); 311ef91a976SAndrey V. Elsukov } 312ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = rcvif; 31395e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, 31495e8b991SAndrey V. Elsukov IPSEC_ENC_AFTER_PFIL, ctx->af); 315ef91a976SAndrey V. Elsukov return (0); 316ef91a976SAndrey V. Elsukov } 317ef91a976SAndrey V. Elsukov 318ef91a976SAndrey V. Elsukov static int 319ef91a976SAndrey V. Elsukov enc_add_hhooks(struct enc_softc *sc) 320ef91a976SAndrey V. Elsukov { 321ef91a976SAndrey V. Elsukov struct hookinfo hki; 322ef91a976SAndrey V. Elsukov int error; 323ef91a976SAndrey V. Elsukov 324ef91a976SAndrey V. Elsukov error = EPFNOSUPPORT; 325ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 326ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 327ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 328ef91a976SAndrey V. Elsukov #ifdef INET 329ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 330ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 331ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 332ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 333ef91a976SAndrey V. Elsukov if (error != 0) 334ef91a976SAndrey V. Elsukov return (error); 335ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 336ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 337ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 338ef91a976SAndrey V. Elsukov if (error != 0) 339ef91a976SAndrey V. Elsukov return (error); 340ef91a976SAndrey V. Elsukov #endif 341ef91a976SAndrey V. Elsukov #ifdef INET6 342ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 343ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 344ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 345ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 346ef91a976SAndrey V. Elsukov if (error != 0) 347ef91a976SAndrey V. Elsukov return (error); 348ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 349ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 350ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 351ef91a976SAndrey V. Elsukov if (error != 0) 352ef91a976SAndrey V. Elsukov return (error); 353ef91a976SAndrey V. Elsukov #endif 354ef91a976SAndrey V. Elsukov return (error); 355ef91a976SAndrey V. Elsukov } 356ef91a976SAndrey V. Elsukov 357ef91a976SAndrey V. Elsukov static void 358ef91a976SAndrey V. Elsukov enc_remove_hhooks(struct enc_softc *sc) 359ef91a976SAndrey V. Elsukov { 360ef91a976SAndrey V. Elsukov struct hookinfo hki; 361ef91a976SAndrey V. Elsukov 362ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 363ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 364ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 365ef91a976SAndrey V. Elsukov #ifdef INET 366ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 367ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 368ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 369ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 370ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 371ef91a976SAndrey V. Elsukov #endif 372ef91a976SAndrey V. Elsukov #ifdef INET6 373ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 374ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 375ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 376ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 377ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 378ef91a976SAndrey V. Elsukov #endif 379ef91a976SAndrey V. Elsukov } 380ef91a976SAndrey V. Elsukov 381ef91a976SAndrey V. Elsukov static void 382ef91a976SAndrey V. Elsukov vnet_enc_init(const void *unused __unused) 383ef91a976SAndrey V. Elsukov { 384ef91a976SAndrey V. Elsukov 385ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 386ef91a976SAndrey V. Elsukov V_enc_cloner = if_clone_simple(encname, enc_clone_create, 387ef91a976SAndrey V. Elsukov enc_clone_destroy, 1); 388ef91a976SAndrey V. Elsukov } 38989856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 390ef91a976SAndrey V. Elsukov vnet_enc_init, NULL); 391ef91a976SAndrey V. Elsukov 392ef91a976SAndrey V. Elsukov static void 39389856f7eSBjoern A. Zeeb vnet_enc_init_proto(void *unused __unused) 39489856f7eSBjoern A. Zeeb { 39589856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 39689856f7eSBjoern A. Zeeb 39789856f7eSBjoern A. Zeeb if (enc_add_hhooks(V_enc_sc) != 0) 39889856f7eSBjoern A. Zeeb enc_clone_destroy(V_enc_sc->sc_ifp); 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 408ef91a976SAndrey V. Elsukov if_clone_detach(V_enc_cloner); 409ef91a976SAndrey V. Elsukov } 41089856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 411ef91a976SAndrey V. Elsukov vnet_enc_uninit, NULL); 412ef91a976SAndrey V. Elsukov 41389856f7eSBjoern A. Zeeb /* 41489856f7eSBjoern A. Zeeb * The hhook consumer needs to go before ip[6]_destroy are called on 41589856f7eSBjoern A. Zeeb * SI_ORDER_THIRD. 41689856f7eSBjoern A. Zeeb */ 41789856f7eSBjoern A. Zeeb static void 41889856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook(const void *unused __unused) 41989856f7eSBjoern A. Zeeb { 42089856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 42189856f7eSBjoern A. Zeeb 42289856f7eSBjoern A. Zeeb enc_remove_hhooks(V_enc_sc); 42389856f7eSBjoern A. Zeeb } 42489856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 42589856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook, NULL); 42689856f7eSBjoern A. Zeeb 427ef91a976SAndrey V. Elsukov static int 428bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 429bdea400fSAndrew Thompson { 430ef91a976SAndrey V. Elsukov 431bdea400fSAndrew Thompson switch (type) { 432bdea400fSAndrew Thompson case MOD_LOAD: 433bdea400fSAndrew Thompson case MOD_UNLOAD: 434ef91a976SAndrey V. Elsukov break; 435bdea400fSAndrew Thompson default: 436bdea400fSAndrew Thompson return (EOPNOTSUPP); 437bdea400fSAndrew Thompson } 438bdea400fSAndrew Thompson return (0); 439bdea400fSAndrew Thompson } 440bdea400fSAndrew Thompson 441bdea400fSAndrew Thompson static moduledata_t enc_mod = { 442b3aa4193SJohn Baldwin "if_enc", 443bdea400fSAndrew Thompson enc_modevent, 4449823d527SKevin Lo 0 445bdea400fSAndrew Thompson }; 446bdea400fSAndrew Thompson 44789856f7eSBjoern A. Zeeb DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 44852b8eb0bSAndrey V. Elsukov MODULE_VERSION(if_enc, 1); 449