1bdea400fSAndrew Thompson /*- 2bdea400fSAndrew Thompson * Copyright (c) 2006 The FreeBSD Project. 3ef91a976SAndrey V. Elsukov * Copyright (c) 2015 Andrey V. Elsukov <ae@FreeBSD.org> 4bdea400fSAndrew Thompson * All rights reserved. 5bdea400fSAndrew Thompson * 6bdea400fSAndrew Thompson * Redistribution and use in source and binary forms, with or without 7bdea400fSAndrew Thompson * modification, are permitted provided that the following conditions 8bdea400fSAndrew Thompson * are met: 9bdea400fSAndrew Thompson * 10bdea400fSAndrew Thompson * 1. Redistributions of source code must retain the above copyright 11bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer. 12bdea400fSAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 13bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer in the 14bdea400fSAndrew Thompson * documentation and/or other materials provided with the distribution. 15bdea400fSAndrew Thompson * 16bdea400fSAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17bdea400fSAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18bdea400fSAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19bdea400fSAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20bdea400fSAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21bdea400fSAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22bdea400fSAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23bdea400fSAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24bdea400fSAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25bdea400fSAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26bdea400fSAndrew Thompson * SUCH DAMAGE. 27bdea400fSAndrew Thompson * 28bdea400fSAndrew Thompson * $FreeBSD$ 29bdea400fSAndrew Thompson */ 30bdea400fSAndrew Thompson 31a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 32a0ae8f04SBjoern A. Zeeb #include "opt_inet6.h" 33a0ae8f04SBjoern A. Zeeb 34bdea400fSAndrew Thompson #include <sys/param.h> 35bdea400fSAndrew Thompson #include <sys/systm.h> 36766b4e4bSEnji Cooper #include <sys/hhook.h> 37bdea400fSAndrew Thompson #include <sys/kernel.h> 38bdea400fSAndrew Thompson #include <sys/malloc.h> 39bdea400fSAndrew Thompson #include <sys/mbuf.h> 40bdea400fSAndrew Thompson #include <sys/module.h> 41bdea400fSAndrew Thompson #include <machine/bus.h> 42bdea400fSAndrew Thompson #include <sys/rman.h> 43bdea400fSAndrew Thompson #include <sys/socket.h> 44bdea400fSAndrew Thompson #include <sys/sockio.h> 45bdea400fSAndrew Thompson #include <sys/sysctl.h> 46bdea400fSAndrew Thompson 47bdea400fSAndrew Thompson #include <net/if.h> 48766b4e4bSEnji Cooper #include <net/if_enc.h> 4976039bc8SGleb Smirnoff #include <net/if_var.h> 50bdea400fSAndrew Thompson #include <net/if_clone.h> 51bdea400fSAndrew Thompson #include <net/if_types.h> 52bdea400fSAndrew Thompson #include <net/pfil.h> 53bdea400fSAndrew Thompson #include <net/route.h> 54bdea400fSAndrew Thompson #include <net/netisr.h> 55bdea400fSAndrew Thompson #include <net/bpf.h> 56eddfbb76SRobert Watson #include <net/vnet.h> 57bdea400fSAndrew Thompson 58bdea400fSAndrew Thompson #include <netinet/in.h> 59bdea400fSAndrew Thompson #include <netinet/in_systm.h> 60bdea400fSAndrew Thompson #include <netinet/ip.h> 61bdea400fSAndrew Thompson #include <netinet/ip_var.h> 62bdea400fSAndrew Thompson #include <netinet/in_var.h> 63bdea400fSAndrew Thompson 64bdea400fSAndrew Thompson #ifdef INET6 65bdea400fSAndrew Thompson #include <netinet/ip6.h> 66bdea400fSAndrew Thompson #include <netinet6/ip6_var.h> 67bdea400fSAndrew Thompson #endif 68bdea400fSAndrew Thompson 69bdea400fSAndrew Thompson #include <netipsec/ipsec.h> 7019ad9831SBjoern A. Zeeb #include <netipsec/xform.h> 71bdea400fSAndrew Thompson 72bdea400fSAndrew Thompson #define ENCMTU (1024+512) 73bdea400fSAndrew Thompson 74bdea400fSAndrew Thompson /* XXX this define must have the same value as in OpenBSD */ 75bdea400fSAndrew Thompson #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 76bdea400fSAndrew Thompson #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 77bdea400fSAndrew Thompson #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 78bdea400fSAndrew Thompson 79bdea400fSAndrew Thompson struct enchdr { 80bdea400fSAndrew Thompson u_int32_t af; 81bdea400fSAndrew Thompson u_int32_t spi; 82bdea400fSAndrew Thompson u_int32_t flags; 83bdea400fSAndrew Thompson }; 84bdea400fSAndrew Thompson struct enc_softc { 85bdea400fSAndrew Thompson struct ifnet *sc_ifp; 86bdea400fSAndrew Thompson }; 87ef91a976SAndrey V. Elsukov static VNET_DEFINE(struct enc_softc *, enc_sc); 88ef91a976SAndrey V. Elsukov #define V_enc_sc VNET(enc_sc) 89ef91a976SAndrey V. Elsukov static VNET_DEFINE(struct if_clone *, enc_cloner); 90ef91a976SAndrey V. Elsukov #define V_enc_cloner VNET(enc_cloner) 91bdea400fSAndrew Thompson 92bdea400fSAndrew Thompson static int enc_ioctl(struct ifnet *, u_long, caddr_t); 93ef91a976SAndrey V. Elsukov static int enc_output(struct ifnet *, struct mbuf *, 94ef91a976SAndrey V. Elsukov const struct sockaddr *, struct route *); 9507ed9a88SAndrew Thompson static int enc_clone_create(struct if_clone *, int, caddr_t); 96bac89dceSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 97ef91a976SAndrey V. Elsukov static int enc_add_hhooks(struct enc_softc *); 98ef91a976SAndrey V. Elsukov static void enc_remove_hhooks(struct enc_softc *); 99bdea400fSAndrew Thompson 100ef91a976SAndrey V. Elsukov static const char encname[] = "enc"; 10119ad9831SBjoern A. Zeeb 102*95e8b991SAndrey V. Elsukov #define IPSEC_ENC_AFTER_PFIL 0x04 10319ad9831SBjoern A. Zeeb /* 10419ad9831SBjoern A. Zeeb * Before and after are relative to when we are stripping the 10519ad9831SBjoern A. Zeeb * outer IP header. 106*95e8b991SAndrey V. Elsukov * 107*95e8b991SAndrey V. Elsukov * AFTER_PFIL flag used only for bpf_mask_*. It enables BPF capturing 108*95e8b991SAndrey V. Elsukov * after PFIL hook execution. It might be useful when PFIL hook does 109*95e8b991SAndrey V. Elsukov * some changes to the packet, e.g. address translation. If PFIL hook 110*95e8b991SAndrey V. Elsukov * consumes mbuf, nothing will be captured. 11119ad9831SBjoern A. Zeeb */ 112ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, filter_mask_in) = IPSEC_ENC_BEFORE; 113ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, bpf_mask_in) = IPSEC_ENC_BEFORE; 114ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, filter_mask_out) = IPSEC_ENC_BEFORE; 115ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER; 116ef91a976SAndrey V. Elsukov #define V_filter_mask_in VNET(filter_mask_in) 117ef91a976SAndrey V. Elsukov #define V_bpf_mask_in VNET(bpf_mask_in) 118ef91a976SAndrey V. Elsukov #define V_filter_mask_out VNET(filter_mask_out) 119ef91a976SAndrey V. Elsukov #define V_bpf_mask_out VNET(bpf_mask_out) 120ef91a976SAndrey V. Elsukov 1216472ac3dSEd Schouten static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW, 0, "enc sysctl"); 1226472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW, 0, "enc input sysctl"); 1236472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW, 0, "enc output sysctl"); 124ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, 125ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0, 126ef91a976SAndrey V. Elsukov "IPsec input firewall filter mask"); 127ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, 128ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0, 129ef91a976SAndrey V. Elsukov "IPsec input bpf mask"); 130ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, 131ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0, 132ef91a976SAndrey V. Elsukov "IPsec output firewall filter mask"); 133ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, 134ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0, 135ef91a976SAndrey V. Elsukov "IPsec output bpf mask"); 13619ad9831SBjoern A. Zeeb 137bac89dceSAndrew Thompson static void 138bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 139bdea400fSAndrew Thompson { 140ef91a976SAndrey V. Elsukov struct enc_softc *sc; 141bdea400fSAndrew Thompson 142ef91a976SAndrey V. Elsukov sc = ifp->if_softc; 143ef91a976SAndrey V. Elsukov KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc")); 144ef91a976SAndrey V. Elsukov 145bdea400fSAndrew Thompson bpfdetach(ifp); 146bdea400fSAndrew Thompson if_detach(ifp); 147bdea400fSAndrew Thompson if_free(ifp); 148ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 149ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 150bdea400fSAndrew Thompson } 151bdea400fSAndrew Thompson 152bdea400fSAndrew Thompson static int 15307ed9a88SAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 154bdea400fSAndrew Thompson { 155bdea400fSAndrew Thompson struct ifnet *ifp; 156bdea400fSAndrew Thompson struct enc_softc *sc; 157bdea400fSAndrew Thompson 158ef91a976SAndrey V. Elsukov sc = malloc(sizeof(struct enc_softc), M_DEVBUF, 159ef91a976SAndrey V. Elsukov M_WAITOK | M_ZERO); 160bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 161bdea400fSAndrew Thompson if (ifp == NULL) { 162bdea400fSAndrew Thompson free(sc, M_DEVBUF); 163bdea400fSAndrew Thompson return (ENOSPC); 164bdea400fSAndrew Thompson } 165ef91a976SAndrey V. Elsukov if (V_enc_sc != NULL) { 166ef91a976SAndrey V. Elsukov if_free(ifp); 167ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 168ef91a976SAndrey V. Elsukov return (EEXIST); 169ef91a976SAndrey V. Elsukov } 170ef91a976SAndrey V. Elsukov V_enc_sc = sc; 17142a58907SGleb Smirnoff if_initname(ifp, encname, unit); 172bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 173bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 174bdea400fSAndrew Thompson ifp->if_output = enc_output; 175bdea400fSAndrew Thompson ifp->if_softc = sc; 176bdea400fSAndrew Thompson if_attach(ifp); 177f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 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 203*95e8b991SAndrey V. Elsukov static void 204*95e8b991SAndrey V. Elsukov enc_bpftap(struct ifnet *ifp, struct mbuf *m, const struct secasvar *sav, 205*95e8b991SAndrey V. Elsukov int32_t hhook_type, uint8_t enc, uint8_t af) 206*95e8b991SAndrey V. Elsukov { 207*95e8b991SAndrey V. Elsukov struct enchdr hdr; 208*95e8b991SAndrey V. Elsukov 209*95e8b991SAndrey V. Elsukov if (hhook_type == HHOOK_TYPE_IPSEC_IN && 210*95e8b991SAndrey V. Elsukov (enc & V_bpf_mask_in) == 0) 211*95e8b991SAndrey V. Elsukov return; 212*95e8b991SAndrey V. Elsukov else if (hhook_type == HHOOK_TYPE_IPSEC_OUT && 213*95e8b991SAndrey V. Elsukov (enc & V_bpf_mask_out) == 0) 214*95e8b991SAndrey V. Elsukov return; 215*95e8b991SAndrey V. Elsukov if (bpf_peers_present(ifp->if_bpf) == 0) 216*95e8b991SAndrey V. Elsukov return; 217*95e8b991SAndrey V. Elsukov hdr.af = af; 218*95e8b991SAndrey V. Elsukov hdr.spi = sav->spi; 219*95e8b991SAndrey V. Elsukov hdr.flags = 0; 220*95e8b991SAndrey V. Elsukov if (sav->alg_enc != SADB_EALG_NONE) 221*95e8b991SAndrey V. Elsukov hdr.flags |= M_CONF; 222*95e8b991SAndrey V. Elsukov if (sav->alg_auth != SADB_AALG_NONE) 223*95e8b991SAndrey V. Elsukov hdr.flags |= M_AUTH; 224*95e8b991SAndrey V. Elsukov bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), m); 225*95e8b991SAndrey V. Elsukov } 226*95e8b991SAndrey 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; 243ef91a976SAndrey V. Elsukov int pdir; 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 255*95e8b991SAndrey 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: 286ef91a976SAndrey V. Elsukov ph = &V_inet_pfil_hook; 287ef91a976SAndrey V. Elsukov break; 288ef91a976SAndrey V. Elsukov #endif 289ef91a976SAndrey V. Elsukov #ifdef INET6 290ef91a976SAndrey V. Elsukov case AF_INET6: 291ef91a976SAndrey V. Elsukov ph = &V_inet6_pfil_hook; 292ef91a976SAndrey V. Elsukov break; 293ef91a976SAndrey V. Elsukov #endif 294ef91a976SAndrey V. Elsukov default: 295ef91a976SAndrey V. Elsukov ph = NULL; 296ef91a976SAndrey V. Elsukov } 297ef91a976SAndrey V. Elsukov if (ph == NULL || !PFIL_HOOKED(ph)) 298ef91a976SAndrey V. Elsukov return (0); 299ef91a976SAndrey V. Elsukov /* Make a packet looks like it was received on enc(4) */ 300ef91a976SAndrey V. Elsukov rcvif = (*ctx->mp)->m_pkthdr.rcvif; 301ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = ifp; 3021a01e0e7SAndrey V. Elsukov if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, ctx->inp) != 0 || 303ef91a976SAndrey V. Elsukov *ctx->mp == NULL) { 304ef91a976SAndrey V. Elsukov *ctx->mp = NULL; /* consumed by filter */ 305ef91a976SAndrey V. Elsukov return (EACCES); 306ef91a976SAndrey V. Elsukov } 307ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = rcvif; 308*95e8b991SAndrey V. Elsukov enc_bpftap(ifp, *ctx->mp, ctx->sav, hhook_type, 309*95e8b991SAndrey V. Elsukov IPSEC_ENC_AFTER_PFIL, ctx->af); 310ef91a976SAndrey V. Elsukov return (0); 311ef91a976SAndrey V. Elsukov } 312ef91a976SAndrey V. Elsukov 313ef91a976SAndrey V. Elsukov static int 314ef91a976SAndrey V. Elsukov enc_add_hhooks(struct enc_softc *sc) 315ef91a976SAndrey V. Elsukov { 316ef91a976SAndrey V. Elsukov struct hookinfo hki; 317ef91a976SAndrey V. Elsukov int error; 318ef91a976SAndrey V. Elsukov 319ef91a976SAndrey V. Elsukov error = EPFNOSUPPORT; 320ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 321ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 322ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 323ef91a976SAndrey V. Elsukov #ifdef INET 324ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 325ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 326ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 327ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 328ef91a976SAndrey V. Elsukov if (error != 0) 329ef91a976SAndrey V. Elsukov return (error); 330ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 331ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 332ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 333ef91a976SAndrey V. Elsukov if (error != 0) 334ef91a976SAndrey V. Elsukov return (error); 335ef91a976SAndrey V. Elsukov #endif 336ef91a976SAndrey V. Elsukov #ifdef INET6 337ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 338ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 339ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 340ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 341ef91a976SAndrey V. Elsukov if (error != 0) 342ef91a976SAndrey V. Elsukov return (error); 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); 346ef91a976SAndrey V. Elsukov if (error != 0) 347ef91a976SAndrey V. Elsukov return (error); 348ef91a976SAndrey V. Elsukov #endif 349ef91a976SAndrey V. Elsukov return (error); 350ef91a976SAndrey V. Elsukov } 351ef91a976SAndrey V. Elsukov 352ef91a976SAndrey V. Elsukov static void 353ef91a976SAndrey V. Elsukov enc_remove_hhooks(struct enc_softc *sc) 354ef91a976SAndrey V. Elsukov { 355ef91a976SAndrey V. Elsukov struct hookinfo hki; 356ef91a976SAndrey V. Elsukov 357ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 358ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 359ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 360ef91a976SAndrey V. Elsukov #ifdef INET 361ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 362ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 363ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 364ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 365ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 366ef91a976SAndrey V. Elsukov #endif 367ef91a976SAndrey V. Elsukov #ifdef INET6 368ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 369ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 370ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 371ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 372ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 373ef91a976SAndrey V. Elsukov #endif 374ef91a976SAndrey V. Elsukov } 375ef91a976SAndrey V. Elsukov 376ef91a976SAndrey V. Elsukov static void 377ef91a976SAndrey V. Elsukov vnet_enc_init(const void *unused __unused) 378ef91a976SAndrey V. Elsukov { 379ef91a976SAndrey V. Elsukov 380ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 381ef91a976SAndrey V. Elsukov V_enc_cloner = if_clone_simple(encname, enc_clone_create, 382ef91a976SAndrey V. Elsukov enc_clone_destroy, 1); 383ef91a976SAndrey V. Elsukov } 38489856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 385ef91a976SAndrey V. Elsukov vnet_enc_init, NULL); 386ef91a976SAndrey V. Elsukov 387ef91a976SAndrey V. Elsukov static void 38889856f7eSBjoern A. Zeeb vnet_enc_init_proto(void *unused __unused) 38989856f7eSBjoern A. Zeeb { 39089856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 39189856f7eSBjoern A. Zeeb 39289856f7eSBjoern A. Zeeb if (enc_add_hhooks(V_enc_sc) != 0) 39389856f7eSBjoern A. Zeeb enc_clone_destroy(V_enc_sc->sc_ifp); 39489856f7eSBjoern A. Zeeb } 39589856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 39689856f7eSBjoern A. Zeeb vnet_enc_init_proto, NULL); 39789856f7eSBjoern A. Zeeb 39889856f7eSBjoern A. Zeeb static void 399ef91a976SAndrey V. Elsukov vnet_enc_uninit(const void *unused __unused) 400ef91a976SAndrey V. Elsukov { 40189856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 402ef91a976SAndrey V. Elsukov 403ef91a976SAndrey V. Elsukov if_clone_detach(V_enc_cloner); 404ef91a976SAndrey V. Elsukov } 40589856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 406ef91a976SAndrey V. Elsukov vnet_enc_uninit, NULL); 407ef91a976SAndrey V. Elsukov 40889856f7eSBjoern A. Zeeb /* 40989856f7eSBjoern A. Zeeb * The hhook consumer needs to go before ip[6]_destroy are called on 41089856f7eSBjoern A. Zeeb * SI_ORDER_THIRD. 41189856f7eSBjoern A. Zeeb */ 41289856f7eSBjoern A. Zeeb static void 41389856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook(const void *unused __unused) 41489856f7eSBjoern A. Zeeb { 41589856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 41689856f7eSBjoern A. Zeeb 41789856f7eSBjoern A. Zeeb enc_remove_hhooks(V_enc_sc); 41889856f7eSBjoern A. Zeeb } 41989856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 42089856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook, NULL); 42189856f7eSBjoern A. Zeeb 422ef91a976SAndrey V. Elsukov static int 423bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 424bdea400fSAndrew Thompson { 425ef91a976SAndrey V. Elsukov 426bdea400fSAndrew Thompson switch (type) { 427bdea400fSAndrew Thompson case MOD_LOAD: 428bdea400fSAndrew Thompson case MOD_UNLOAD: 429ef91a976SAndrey V. Elsukov break; 430bdea400fSAndrew Thompson default: 431bdea400fSAndrew Thompson return (EOPNOTSUPP); 432bdea400fSAndrew Thompson } 433bdea400fSAndrew Thompson return (0); 434bdea400fSAndrew Thompson } 435bdea400fSAndrew Thompson 436bdea400fSAndrew Thompson static moduledata_t enc_mod = { 437b3aa4193SJohn Baldwin "if_enc", 438bdea400fSAndrew Thompson enc_modevent, 4399823d527SKevin Lo 0 440bdea400fSAndrew Thompson }; 441bdea400fSAndrew Thompson 44289856f7eSBjoern A. Zeeb DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 44352b8eb0bSAndrey V. Elsukov MODULE_VERSION(if_enc, 1); 444