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 *); 9707ed9a88SAndrew Thompson static int enc_clone_create(struct if_clone *, int, caddr_t); 98bac89dceSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 99*7643141eSZhenlei Huang static void 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 1237029da5cSPawel Biernacki static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1247029da5cSPawel Biernacki "enc sysctl"); 1257029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1267029da5cSPawel Biernacki "enc input sysctl"); 1277029da5cSPawel Biernacki static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1287029da5cSPawel 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); 166ef91a976SAndrey V. Elsukov if (V_enc_sc != NULL) { 167ef91a976SAndrey V. Elsukov if_free(ifp); 168ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 169ef91a976SAndrey V. Elsukov return (EEXIST); 170ef91a976SAndrey V. Elsukov } 171ef91a976SAndrey V. Elsukov V_enc_sc = sc; 17242a58907SGleb Smirnoff if_initname(ifp, encname, unit); 173bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 174bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 175bdea400fSAndrew Thompson ifp->if_output = enc_output; 176bdea400fSAndrew Thompson ifp->if_softc = sc; 177bdea400fSAndrew Thompson if_attach(ifp); 178f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 179bdea400fSAndrew Thompson return (0); 180bdea400fSAndrew Thompson } 181bdea400fSAndrew Thompson 182bdea400fSAndrew Thompson static int 183ef91a976SAndrey V. Elsukov enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 184ef91a976SAndrey V. Elsukov struct route *ro) 185ef91a976SAndrey V. Elsukov { 186ef91a976SAndrey V. Elsukov 187ef91a976SAndrey V. Elsukov m_freem(m); 188ef91a976SAndrey V. Elsukov return (0); 189ef91a976SAndrey V. Elsukov } 190ef91a976SAndrey V. Elsukov 191ef91a976SAndrey V. Elsukov static int 192ef91a976SAndrey V. Elsukov enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 193ef91a976SAndrey V. Elsukov { 194ef91a976SAndrey V. Elsukov 195ef91a976SAndrey V. Elsukov if (cmd != SIOCSIFFLAGS) 196ef91a976SAndrey V. Elsukov return (EINVAL); 197ef91a976SAndrey V. Elsukov if (ifp->if_flags & IFF_UP) 198ef91a976SAndrey V. Elsukov ifp->if_drv_flags |= IFF_DRV_RUNNING; 199ef91a976SAndrey V. Elsukov else 200ef91a976SAndrey V. Elsukov ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 201ef91a976SAndrey V. Elsukov return (0); 202ef91a976SAndrey V. Elsukov } 203ef91a976SAndrey V. Elsukov 20495e8b991SAndrey V. Elsukov static void 20595e8b991SAndrey V. Elsukov enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, 20695e8b991SAndrey V. Elsukov int32_t hhook_type, uint8_t enc, uint8_t af) 20795e8b991SAndrey V. Elsukov { 20895e8b991SAndrey V. Elsukov struct enchdr hdr; 20995e8b991SAndrey V. Elsukov 21095e8b991SAndrey V. Elsukov if (hhook_type == HHOOK_TYPE_IPSEC_IN && 21195e8b991SAndrey V. Elsukov (enc & V_bpf_mask_in) == 0) 21295e8b991SAndrey V. Elsukov return; 21395e8b991SAndrey V. Elsukov else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && 21495e8b991SAndrey V. Elsukov (enc & V_bpf_mask_out) == 0) 21595e8b991SAndrey V. Elsukov return; 216215a18d5SZhenlei Huang if (!bpf_peers_present(ifp->if_bpf)) 21795e8b991SAndrey V. Elsukov return; 21895e8b991SAndrey V. Elsukov hdr.af = af; 21995e8b991SAndrey V. Elsukov hdr.spi = sav->spi; 22095e8b991SAndrey V. Elsukov hdr.flags = 0; 22195e8b991SAndrey V. Elsukov if (sav->alg_enc != SADB_EALG_NONE) 22295e8b991SAndrey V. Elsukov hdr.flags |= M_CONF; 22395e8b991SAndrey V. Elsukov if (sav->alg_auth != SADB_AALG_NONE) 22495e8b991SAndrey V. Elsukov hdr.flags |= M_AUTH; 22595e8b991SAndrey V. Elsukov bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); 22695e8b991SAndrey V. Elsukov } 22795e8b991SAndrey V. Elsukov 228ef91a976SAndrey V. Elsukov /* 229ef91a976SAndrey V. Elsukov * One helper hook function is used by any hook points. 230ef91a976SAndrey V. Elsukov * + from hhook_type we can determine the packet direction: 231ef91a976SAndrey V. Elsukov * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT; 232ef91a976SAndrey V. Elsukov * + from hhook_id we can determine address family: AF_INET or AF_INET6; 233ef91a976SAndrey V. Elsukov * + udata contains pointer to enc_softc; 234ef91a976SAndrey V. Elsukov * + ctx_data contains pointer to struct ipsec_ctx_data. 235ef91a976SAndrey V. Elsukov */ 236ef91a976SAndrey V. Elsukov static int 237ef91a976SAndrey V. Elsukov enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, 238ef91a976SAndrey V. Elsukov void *hdata, struct osd *hosd) 239ef91a976SAndrey V. Elsukov { 240ef91a976SAndrey V. Elsukov struct ipsec_ctx_data *ctx; 241ef91a976SAndrey V. Elsukov struct enc_softc *sc; 242ef91a976SAndrey V. Elsukov struct ifnet *ifp, *rcvif; 243ef91a976SAndrey V. Elsukov struct pfil_head *ph; 244a2256150SGleb Smirnoff int pdir, ret; 245ef91a976SAndrey V. Elsukov 246ef91a976SAndrey V. Elsukov sc = (struct enc_softc *)udata; 247ef91a976SAndrey V. Elsukov ifp = sc->sc_ifp; 248ef91a976SAndrey V. Elsukov if ((ifp->if_flags & IFF_UP) == 0) 249ef91a976SAndrey V. Elsukov return (0); 250ef91a976SAndrey V. Elsukov 251ef91a976SAndrey V. Elsukov ctx = (struct ipsec_ctx_data *)ctx_data; 252ef91a976SAndrey V. Elsukov /* XXX: wrong hook point was used by caller? */ 253ef91a976SAndrey V. Elsukov if (ctx->af != hhook_id) 254ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 255ef91a976SAndrey V. Elsukov 25695e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, ctx->enc, ctx->af); 257ef91a976SAndrey V. Elsukov switch (hhook_type) { 258ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_IN: 259ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 260ef91a976SAndrey V. Elsukov /* Do accounting only once */ 261ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 262ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IBYTES, 263ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 264ef91a976SAndrey V. Elsukov } 265ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_in) == 0) 266ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 267ef91a976SAndrey V. Elsukov pdir = PFIL_IN; 268ef91a976SAndrey V. Elsukov break; 269ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_OUT: 270ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 271ef91a976SAndrey V. Elsukov /* Do accounting only once */ 272ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 273ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OBYTES, 274ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 275ef91a976SAndrey V. Elsukov } 276ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_out) == 0) 277ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 278ef91a976SAndrey V. Elsukov pdir = PFIL_OUT; 279ef91a976SAndrey V. Elsukov break; 280ef91a976SAndrey V. Elsukov default: 281ef91a976SAndrey V. Elsukov return (EINVAL); 282ef91a976SAndrey V. Elsukov } 283ef91a976SAndrey V. Elsukov 284ef91a976SAndrey V. Elsukov switch (hhook_id) { 285ef91a976SAndrey V. Elsukov #ifdef INET 286ef91a976SAndrey V. Elsukov case AF_INET: 287b252313fSGleb Smirnoff ph = V_inet_pfil_head; 288ef91a976SAndrey V. Elsukov break; 289ef91a976SAndrey V. Elsukov #endif 290ef91a976SAndrey V. Elsukov #ifdef INET6 291ef91a976SAndrey V. Elsukov case AF_INET6: 292b252313fSGleb Smirnoff ph = V_inet6_pfil_head; 293ef91a976SAndrey V. Elsukov break; 294ef91a976SAndrey V. Elsukov #endif 295ef91a976SAndrey V. Elsukov default: 296ef91a976SAndrey V. Elsukov ph = NULL; 297ef91a976SAndrey V. Elsukov } 298b252313fSGleb Smirnoff if (ph == NULL || (pdir == PFIL_OUT && !PFIL_HOOKED_OUT(ph)) || 299b252313fSGleb Smirnoff (pdir == PFIL_IN && !PFIL_HOOKED_IN(ph))) 300ef91a976SAndrey V. Elsukov return (0); 301ef91a976SAndrey V. Elsukov /* Make a packet looks like it was received on enc(4) */ 302ef91a976SAndrey V. Elsukov rcvif = (*ctx->mp)->m_pkthdr.rcvif; 303ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = ifp; 304a2256150SGleb Smirnoff if (pdir == PFIL_IN) 305a2256150SGleb Smirnoff ret = pfil_mbuf_in(ph, ctx->mp, ifp, ctx->inp); 306a2256150SGleb Smirnoff else 307a2256150SGleb Smirnoff ret = pfil_mbuf_out(ph, ctx->mp, ifp, ctx->inp); 308a2256150SGleb Smirnoff if (ret != 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 318*7643141eSZhenlei Huang static void 319ef91a976SAndrey V. Elsukov enc_add_hhooks(struct enc_softc *sc) 320ef91a976SAndrey V. Elsukov { 321ef91a976SAndrey V. Elsukov struct hookinfo hki; 322*7643141eSZhenlei Huang int error __diagused; 323ef91a976SAndrey V. Elsukov 324ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 325ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 326ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 327ef91a976SAndrey V. Elsukov #ifdef INET 328ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 329ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 330ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 331ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 332*7643141eSZhenlei Huang MPASS(error == 0); 333ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 334ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 335ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 336*7643141eSZhenlei Huang MPASS(error == 0); 337ef91a976SAndrey V. Elsukov #endif 338ef91a976SAndrey V. Elsukov #ifdef INET6 339ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 340ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 341ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 342ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 343*7643141eSZhenlei Huang MPASS(error == 0); 344ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 345ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 346ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 347*7643141eSZhenlei Huang MPASS(error == 0); 348ef91a976SAndrey V. Elsukov #endif 349ef91a976SAndrey V. Elsukov } 350ef91a976SAndrey V. Elsukov 351ef91a976SAndrey V. Elsukov static void 352ef91a976SAndrey V. Elsukov enc_remove_hhooks(struct enc_softc *sc) 353ef91a976SAndrey V. Elsukov { 354ef91a976SAndrey V. Elsukov struct hookinfo hki; 355ef91a976SAndrey V. Elsukov 356ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 357ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 358ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 359ef91a976SAndrey V. Elsukov #ifdef INET 360ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 361ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 362ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 363ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 364ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 365ef91a976SAndrey V. Elsukov #endif 366ef91a976SAndrey V. Elsukov #ifdef INET6 367ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 368ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 369ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 370ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 371ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 372ef91a976SAndrey V. Elsukov #endif 373ef91a976SAndrey V. Elsukov } 374ef91a976SAndrey V. Elsukov 375ef91a976SAndrey V. Elsukov static void 376ef91a976SAndrey V. Elsukov vnet_enc_init(const void *unused __unused) 377ef91a976SAndrey V. Elsukov { 378ef91a976SAndrey V. Elsukov 379ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 380ef91a976SAndrey V. Elsukov V_enc_cloner = if_clone_simple(encname, enc_clone_create, 381ef91a976SAndrey V. Elsukov enc_clone_destroy, 1); 382ef91a976SAndrey V. Elsukov } 38389856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 384ef91a976SAndrey V. Elsukov vnet_enc_init, NULL); 385ef91a976SAndrey V. Elsukov 386ef91a976SAndrey V. Elsukov static void 38789856f7eSBjoern A. Zeeb vnet_enc_init_proto(void *unused __unused) 38889856f7eSBjoern A. Zeeb { 38989856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 39089856f7eSBjoern A. Zeeb 391*7643141eSZhenlei Huang enc_add_hhooks(V_enc_sc); 39289856f7eSBjoern A. Zeeb } 39389856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 39489856f7eSBjoern A. Zeeb vnet_enc_init_proto, NULL); 39589856f7eSBjoern A. Zeeb 39689856f7eSBjoern A. Zeeb static void 397ef91a976SAndrey V. Elsukov vnet_enc_uninit(const void *unused __unused) 398ef91a976SAndrey V. Elsukov { 39989856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 400ef91a976SAndrey V. Elsukov 401ef91a976SAndrey V. Elsukov if_clone_detach(V_enc_cloner); 402ef91a976SAndrey V. Elsukov } 40389856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 404ef91a976SAndrey V. Elsukov vnet_enc_uninit, NULL); 405ef91a976SAndrey V. Elsukov 40689856f7eSBjoern A. Zeeb /* 40789856f7eSBjoern A. Zeeb * The hhook consumer needs to go before ip[6]_destroy are called on 40889856f7eSBjoern A. Zeeb * SI_ORDER_THIRD. 40989856f7eSBjoern A. Zeeb */ 41089856f7eSBjoern A. Zeeb static void 41189856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook(const void *unused __unused) 41289856f7eSBjoern A. Zeeb { 41389856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 41489856f7eSBjoern A. Zeeb 41589856f7eSBjoern A. Zeeb enc_remove_hhooks(V_enc_sc); 41689856f7eSBjoern A. Zeeb } 41789856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 41889856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook, NULL); 41989856f7eSBjoern A. Zeeb 420ef91a976SAndrey V. Elsukov static int 421bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 422bdea400fSAndrew Thompson { 423ef91a976SAndrey V. Elsukov 424bdea400fSAndrew Thompson switch (type) { 425bdea400fSAndrew Thompson case MOD_LOAD: 426bdea400fSAndrew Thompson case MOD_UNLOAD: 427ef91a976SAndrey V. Elsukov break; 428bdea400fSAndrew Thompson default: 429bdea400fSAndrew Thompson return (EOPNOTSUPP); 430bdea400fSAndrew Thompson } 431bdea400fSAndrew Thompson return (0); 432bdea400fSAndrew Thompson } 433bdea400fSAndrew Thompson 434bdea400fSAndrew Thompson static moduledata_t enc_mod = { 435b3aa4193SJohn Baldwin "if_enc", 436bdea400fSAndrew Thompson enc_modevent, 4379823d527SKevin Lo 0 438bdea400fSAndrew Thompson }; 439bdea400fSAndrew Thompson 44089856f7eSBjoern A. Zeeb DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 44152b8eb0bSAndrey V. Elsukov MODULE_VERSION(if_enc, 1); 442