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 10219ad9831SBjoern A. Zeeb /* 10319ad9831SBjoern A. Zeeb * Before and after are relative to when we are stripping the 10419ad9831SBjoern A. Zeeb * outer IP header. 10519ad9831SBjoern A. Zeeb */ 106ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, filter_mask_in) = IPSEC_ENC_BEFORE; 107ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, bpf_mask_in) = IPSEC_ENC_BEFORE; 108ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, filter_mask_out) = IPSEC_ENC_BEFORE; 109ef91a976SAndrey V. Elsukov static VNET_DEFINE(int, bpf_mask_out) = IPSEC_ENC_BEFORE | IPSEC_ENC_AFTER; 110ef91a976SAndrey V. Elsukov #define V_filter_mask_in VNET(filter_mask_in) 111ef91a976SAndrey V. Elsukov #define V_bpf_mask_in VNET(bpf_mask_in) 112ef91a976SAndrey V. Elsukov #define V_filter_mask_out VNET(filter_mask_out) 113ef91a976SAndrey V. Elsukov #define V_bpf_mask_out VNET(bpf_mask_out) 114ef91a976SAndrey V. Elsukov 1156472ac3dSEd Schouten static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW, 0, "enc sysctl"); 1166472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW, 0, "enc input sysctl"); 1176472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW, 0, "enc output sysctl"); 118ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, 119ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_in), 0, 120ef91a976SAndrey V. Elsukov "IPsec input firewall filter mask"); 121ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, 122ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_in), 0, 123ef91a976SAndrey V. Elsukov "IPsec input bpf mask"); 124ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, 125ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(filter_mask_out), 0, 126ef91a976SAndrey V. Elsukov "IPsec output firewall filter mask"); 127ef91a976SAndrey V. Elsukov SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, 128ef91a976SAndrey V. Elsukov CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(bpf_mask_out), 0, 129ef91a976SAndrey V. Elsukov "IPsec output bpf mask"); 13019ad9831SBjoern A. Zeeb 131bac89dceSAndrew Thompson static void 132bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 133bdea400fSAndrew Thompson { 134ef91a976SAndrey V. Elsukov struct enc_softc *sc; 135bdea400fSAndrew Thompson 136ef91a976SAndrey V. Elsukov sc = ifp->if_softc; 137ef91a976SAndrey V. Elsukov KASSERT(sc == V_enc_sc, ("sc != ifp->if_softc")); 138ef91a976SAndrey V. Elsukov 139bdea400fSAndrew Thompson bpfdetach(ifp); 140bdea400fSAndrew Thompson if_detach(ifp); 141bdea400fSAndrew Thompson if_free(ifp); 142ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 143ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 144bdea400fSAndrew Thompson } 145bdea400fSAndrew Thompson 146bdea400fSAndrew Thompson static int 14707ed9a88SAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 148bdea400fSAndrew Thompson { 149bdea400fSAndrew Thompson struct ifnet *ifp; 150bdea400fSAndrew Thompson struct enc_softc *sc; 151bdea400fSAndrew Thompson 152ef91a976SAndrey V. Elsukov sc = malloc(sizeof(struct enc_softc), M_DEVBUF, 153ef91a976SAndrey V. Elsukov M_WAITOK | M_ZERO); 154bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 155bdea400fSAndrew Thompson if (ifp == NULL) { 156bdea400fSAndrew Thompson free(sc, M_DEVBUF); 157bdea400fSAndrew Thompson return (ENOSPC); 158bdea400fSAndrew Thompson } 159ef91a976SAndrey V. Elsukov if (V_enc_sc != NULL) { 160ef91a976SAndrey V. Elsukov if_free(ifp); 161ef91a976SAndrey V. Elsukov free(sc, M_DEVBUF); 162ef91a976SAndrey V. Elsukov return (EEXIST); 163ef91a976SAndrey V. Elsukov } 164ef91a976SAndrey V. Elsukov V_enc_sc = sc; 16542a58907SGleb Smirnoff if_initname(ifp, encname, unit); 166bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 167bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 168bdea400fSAndrew Thompson ifp->if_output = enc_output; 169bdea400fSAndrew Thompson ifp->if_softc = sc; 170bdea400fSAndrew Thompson if_attach(ifp); 171f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 172bdea400fSAndrew Thompson return (0); 173bdea400fSAndrew Thompson } 174bdea400fSAndrew Thompson 175bdea400fSAndrew Thompson static int 176ef91a976SAndrey V. Elsukov enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 177ef91a976SAndrey V. Elsukov struct route *ro) 178ef91a976SAndrey V. Elsukov { 179ef91a976SAndrey V. Elsukov 180ef91a976SAndrey V. Elsukov m_freem(m); 181ef91a976SAndrey V. Elsukov return (0); 182ef91a976SAndrey V. Elsukov } 183ef91a976SAndrey V. Elsukov 184ef91a976SAndrey V. Elsukov static int 185ef91a976SAndrey V. Elsukov enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 186ef91a976SAndrey V. Elsukov { 187ef91a976SAndrey V. Elsukov 188ef91a976SAndrey V. Elsukov if (cmd != SIOCSIFFLAGS) 189ef91a976SAndrey V. Elsukov return (EINVAL); 190ef91a976SAndrey V. Elsukov if (ifp->if_flags & IFF_UP) 191ef91a976SAndrey V. Elsukov ifp->if_drv_flags |= IFF_DRV_RUNNING; 192ef91a976SAndrey V. Elsukov else 193ef91a976SAndrey V. Elsukov ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 194ef91a976SAndrey V. Elsukov return (0); 195ef91a976SAndrey V. Elsukov } 196ef91a976SAndrey V. Elsukov 197ef91a976SAndrey V. Elsukov /* 198ef91a976SAndrey V. Elsukov * One helper hook function is used by any hook points. 199ef91a976SAndrey V. Elsukov * + from hhook_type we can determine the packet direction: 200ef91a976SAndrey V. Elsukov * HHOOK_TYPE_IPSEC_IN or HHOOK_TYPE_IPSEC_OUT; 201ef91a976SAndrey V. Elsukov * + from hhook_id we can determine address family: AF_INET or AF_INET6; 202ef91a976SAndrey V. Elsukov * + udata contains pointer to enc_softc; 203ef91a976SAndrey V. Elsukov * + ctx_data contains pointer to struct ipsec_ctx_data. 204ef91a976SAndrey V. Elsukov */ 205ef91a976SAndrey V. Elsukov static int 206ef91a976SAndrey V. Elsukov enc_hhook(int32_t hhook_type, int32_t hhook_id, void *udata, void *ctx_data, 207ef91a976SAndrey V. Elsukov void *hdata, struct osd *hosd) 208ef91a976SAndrey V. Elsukov { 209ef91a976SAndrey V. Elsukov struct enchdr hdr; 210ef91a976SAndrey V. Elsukov struct ipsec_ctx_data *ctx; 211ef91a976SAndrey V. Elsukov struct enc_softc *sc; 212ef91a976SAndrey V. Elsukov struct ifnet *ifp, *rcvif; 213ef91a976SAndrey V. Elsukov struct pfil_head *ph; 214ef91a976SAndrey V. Elsukov int pdir; 215ef91a976SAndrey V. Elsukov 216ef91a976SAndrey V. Elsukov sc = (struct enc_softc *)udata; 217ef91a976SAndrey V. Elsukov ifp = sc->sc_ifp; 218ef91a976SAndrey V. Elsukov if ((ifp->if_flags & IFF_UP) == 0) 219ef91a976SAndrey V. Elsukov return (0); 220ef91a976SAndrey V. Elsukov 221ef91a976SAndrey V. Elsukov ctx = (struct ipsec_ctx_data *)ctx_data; 222ef91a976SAndrey V. Elsukov /* XXX: wrong hook point was used by caller? */ 223ef91a976SAndrey V. Elsukov if (ctx->af != hhook_id) 224ef91a976SAndrey V. Elsukov return (EPFNOSUPPORT); 225ef91a976SAndrey V. Elsukov 226ef91a976SAndrey V. Elsukov if (((hhook_type == HHOOK_TYPE_IPSEC_IN && 227ef91a976SAndrey V. Elsukov (ctx->enc & V_bpf_mask_in) != 0) || 228ef91a976SAndrey V. Elsukov (hhook_type == HHOOK_TYPE_IPSEC_OUT && 229ef91a976SAndrey V. Elsukov (ctx->enc & V_bpf_mask_out) != 0)) && 230ef91a976SAndrey V. Elsukov bpf_peers_present(ifp->if_bpf) != 0) { 231ef91a976SAndrey V. Elsukov hdr.af = ctx->af; 232ef91a976SAndrey V. Elsukov hdr.spi = ctx->sav->spi; 233ef91a976SAndrey V. Elsukov hdr.flags = 0; 234ef91a976SAndrey V. Elsukov if (ctx->sav->alg_enc != SADB_EALG_NONE) 235ef91a976SAndrey V. Elsukov hdr.flags |= M_CONF; 236ef91a976SAndrey V. Elsukov if (ctx->sav->alg_auth != SADB_AALG_NONE) 237ef91a976SAndrey V. Elsukov hdr.flags |= M_AUTH; 238ef91a976SAndrey V. Elsukov bpf_mtap2(ifp->if_bpf, &hdr, sizeof(hdr), *ctx->mp); 239ef91a976SAndrey V. Elsukov } 240ef91a976SAndrey V. Elsukov 241ef91a976SAndrey V. Elsukov switch (hhook_type) { 242ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_IN: 243ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 244ef91a976SAndrey V. Elsukov /* Do accounting only once */ 245ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 246ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_IBYTES, 247ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 248ef91a976SAndrey V. Elsukov } 249ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_in) == 0) 250ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 251ef91a976SAndrey V. Elsukov pdir = PFIL_IN; 252ef91a976SAndrey V. Elsukov break; 253ef91a976SAndrey V. Elsukov case HHOOK_TYPE_IPSEC_OUT: 254ef91a976SAndrey V. Elsukov if (ctx->enc == IPSEC_ENC_BEFORE) { 255ef91a976SAndrey V. Elsukov /* Do accounting only once */ 256ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 257ef91a976SAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OBYTES, 258ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.len); 259ef91a976SAndrey V. Elsukov } 260ef91a976SAndrey V. Elsukov if ((ctx->enc & V_filter_mask_out) == 0) 261ef91a976SAndrey V. Elsukov return (0); /* skip pfil processing */ 262ef91a976SAndrey V. Elsukov pdir = PFIL_OUT; 263ef91a976SAndrey V. Elsukov break; 264ef91a976SAndrey V. Elsukov default: 265ef91a976SAndrey V. Elsukov return (EINVAL); 266ef91a976SAndrey V. Elsukov } 267ef91a976SAndrey V. Elsukov 268ef91a976SAndrey V. Elsukov switch (hhook_id) { 269ef91a976SAndrey V. Elsukov #ifdef INET 270ef91a976SAndrey V. Elsukov case AF_INET: 271ef91a976SAndrey V. Elsukov ph = &V_inet_pfil_hook; 272ef91a976SAndrey V. Elsukov break; 273ef91a976SAndrey V. Elsukov #endif 274ef91a976SAndrey V. Elsukov #ifdef INET6 275ef91a976SAndrey V. Elsukov case AF_INET6: 276ef91a976SAndrey V. Elsukov ph = &V_inet6_pfil_hook; 277ef91a976SAndrey V. Elsukov break; 278ef91a976SAndrey V. Elsukov #endif 279ef91a976SAndrey V. Elsukov default: 280ef91a976SAndrey V. Elsukov ph = NULL; 281ef91a976SAndrey V. Elsukov } 282ef91a976SAndrey V. Elsukov if (ph == NULL || !PFIL_HOOKED(ph)) 283ef91a976SAndrey V. Elsukov return (0); 284ef91a976SAndrey V. Elsukov /* Make a packet looks like it was received on enc(4) */ 285ef91a976SAndrey V. Elsukov rcvif = (*ctx->mp)->m_pkthdr.rcvif; 286ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = ifp; 287ef91a976SAndrey V. Elsukov if (pfil_run_hooks(ph, ctx->mp, ifp, pdir, NULL) != 0 || 288ef91a976SAndrey V. Elsukov *ctx->mp == NULL) { 289ef91a976SAndrey V. Elsukov *ctx->mp = NULL; /* consumed by filter */ 290ef91a976SAndrey V. Elsukov return (EACCES); 291ef91a976SAndrey V. Elsukov } 292ef91a976SAndrey V. Elsukov (*ctx->mp)->m_pkthdr.rcvif = rcvif; 293ef91a976SAndrey V. Elsukov return (0); 294ef91a976SAndrey V. Elsukov } 295ef91a976SAndrey V. Elsukov 296ef91a976SAndrey V. Elsukov static int 297ef91a976SAndrey V. Elsukov enc_add_hhooks(struct enc_softc *sc) 298ef91a976SAndrey V. Elsukov { 299ef91a976SAndrey V. Elsukov struct hookinfo hki; 300ef91a976SAndrey V. Elsukov int error; 301ef91a976SAndrey V. Elsukov 302ef91a976SAndrey V. Elsukov error = EPFNOSUPPORT; 303ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 304ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 305ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 306ef91a976SAndrey V. Elsukov #ifdef INET 307ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 308ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 309ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], 310ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 311ef91a976SAndrey V. Elsukov if (error != 0) 312ef91a976SAndrey V. Elsukov return (error); 313ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 314ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], 315ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 316ef91a976SAndrey V. Elsukov if (error != 0) 317ef91a976SAndrey V. Elsukov return (error); 318ef91a976SAndrey V. Elsukov #endif 319ef91a976SAndrey V. Elsukov #ifdef INET6 320ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 321ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 322ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], 323ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 324ef91a976SAndrey V. Elsukov if (error != 0) 325ef91a976SAndrey V. Elsukov return (error); 326ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 327ef91a976SAndrey V. Elsukov error = hhook_add_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], 328ef91a976SAndrey V. Elsukov &hki, HHOOK_WAITOK); 329ef91a976SAndrey V. Elsukov if (error != 0) 330ef91a976SAndrey V. Elsukov return (error); 331ef91a976SAndrey V. Elsukov #endif 332ef91a976SAndrey V. Elsukov return (error); 333ef91a976SAndrey V. Elsukov } 334ef91a976SAndrey V. Elsukov 335ef91a976SAndrey V. Elsukov static void 336ef91a976SAndrey V. Elsukov enc_remove_hhooks(struct enc_softc *sc) 337ef91a976SAndrey V. Elsukov { 338ef91a976SAndrey V. Elsukov struct hookinfo hki; 339ef91a976SAndrey V. Elsukov 340ef91a976SAndrey V. Elsukov hki.hook_func = enc_hhook; 341ef91a976SAndrey V. Elsukov hki.hook_helper = NULL; 342ef91a976SAndrey V. Elsukov hki.hook_udata = sc; 343ef91a976SAndrey V. Elsukov #ifdef INET 344ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET; 345ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 346ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET], &hki); 347ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 348ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET], &hki); 349ef91a976SAndrey V. Elsukov #endif 350ef91a976SAndrey V. Elsukov #ifdef INET6 351ef91a976SAndrey V. Elsukov hki.hook_id = AF_INET6; 352ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_IN; 353ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_in[HHOOK_IPSEC_INET6], &hki); 354ef91a976SAndrey V. Elsukov hki.hook_type = HHOOK_TYPE_IPSEC_OUT; 355ef91a976SAndrey V. Elsukov hhook_remove_hook(V_ipsec_hhh_out[HHOOK_IPSEC_INET6], &hki); 356ef91a976SAndrey V. Elsukov #endif 357ef91a976SAndrey V. Elsukov } 358ef91a976SAndrey V. Elsukov 359ef91a976SAndrey V. Elsukov static void 360ef91a976SAndrey V. Elsukov vnet_enc_init(const void *unused __unused) 361ef91a976SAndrey V. Elsukov { 362ef91a976SAndrey V. Elsukov 363ef91a976SAndrey V. Elsukov V_enc_sc = NULL; 364ef91a976SAndrey V. Elsukov V_enc_cloner = if_clone_simple(encname, enc_clone_create, 365ef91a976SAndrey V. Elsukov enc_clone_destroy, 1); 366ef91a976SAndrey V. Elsukov } 36789856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init, SI_SUB_PSEUDO, SI_ORDER_ANY, 368ef91a976SAndrey V. Elsukov vnet_enc_init, NULL); 369ef91a976SAndrey V. Elsukov 370ef91a976SAndrey V. Elsukov static void 37189856f7eSBjoern A. Zeeb vnet_enc_init_proto(void *unused __unused) 37289856f7eSBjoern A. Zeeb { 37389856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 37489856f7eSBjoern A. Zeeb 37589856f7eSBjoern A. Zeeb if (enc_add_hhooks(V_enc_sc) != 0) 37689856f7eSBjoern A. Zeeb enc_clone_destroy(V_enc_sc->sc_ifp); 37789856f7eSBjoern A. Zeeb } 37889856f7eSBjoern A. Zeeb VNET_SYSINIT(vnet_enc_init_proto, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 37989856f7eSBjoern A. Zeeb vnet_enc_init_proto, NULL); 38089856f7eSBjoern A. Zeeb 38189856f7eSBjoern A. Zeeb static void 382ef91a976SAndrey V. Elsukov vnet_enc_uninit(const void *unused __unused) 383ef91a976SAndrey V. Elsukov { 38489856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 385ef91a976SAndrey V. Elsukov 386ef91a976SAndrey V. Elsukov if_clone_detach(V_enc_cloner); 387ef91a976SAndrey V. Elsukov } 38889856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit, SI_SUB_INIT_IF, SI_ORDER_ANY, 389ef91a976SAndrey V. Elsukov vnet_enc_uninit, NULL); 390ef91a976SAndrey V. Elsukov 39189856f7eSBjoern A. Zeeb /* 39289856f7eSBjoern A. Zeeb * The hhook consumer needs to go before ip[6]_destroy are called on 39389856f7eSBjoern A. Zeeb * SI_ORDER_THIRD. 39489856f7eSBjoern A. Zeeb */ 39589856f7eSBjoern A. Zeeb static void 39689856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook(const void *unused __unused) 39789856f7eSBjoern A. Zeeb { 39889856f7eSBjoern A. Zeeb KASSERT(V_enc_sc != NULL, ("%s: V_enc_sc is %p\n", __func__, V_enc_sc)); 39989856f7eSBjoern A. Zeeb 40089856f7eSBjoern A. Zeeb enc_remove_hhooks(V_enc_sc); 40189856f7eSBjoern A. Zeeb } 40289856f7eSBjoern A. Zeeb VNET_SYSUNINIT(vnet_enc_uninit_hhook, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, 40389856f7eSBjoern A. Zeeb vnet_enc_uninit_hhook, NULL); 40489856f7eSBjoern A. Zeeb 405ef91a976SAndrey V. Elsukov static int 406bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 407bdea400fSAndrew Thompson { 408ef91a976SAndrey V. Elsukov 409bdea400fSAndrew Thompson switch (type) { 410bdea400fSAndrew Thompson case MOD_LOAD: 411bdea400fSAndrew Thompson case MOD_UNLOAD: 412ef91a976SAndrey V. Elsukov break; 413bdea400fSAndrew Thompson default: 414bdea400fSAndrew Thompson return (EOPNOTSUPP); 415bdea400fSAndrew Thompson } 416bdea400fSAndrew Thompson return (0); 417bdea400fSAndrew Thompson } 418bdea400fSAndrew Thompson 419bdea400fSAndrew Thompson static moduledata_t enc_mod = { 420b3aa4193SJohn Baldwin "if_enc", 421bdea400fSAndrew Thompson enc_modevent, 4229823d527SKevin Lo 0 423bdea400fSAndrew Thompson }; 424bdea400fSAndrew Thompson 42589856f7eSBjoern A. Zeeb DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 426*52b8eb0bSAndrey V. Elsukov MODULE_VERSION(if_enc, 1); 427