1bdea400fSAndrew Thompson /*- 2bdea400fSAndrew Thompson * Copyright (c) 2006 The FreeBSD Project. 3bdea400fSAndrew Thompson * All rights reserved. 4bdea400fSAndrew Thompson * 5bdea400fSAndrew Thompson * Redistribution and use in source and binary forms, with or without 6bdea400fSAndrew Thompson * modification, are permitted provided that the following conditions 7bdea400fSAndrew Thompson * are met: 8bdea400fSAndrew Thompson * 9bdea400fSAndrew Thompson * 1. Redistributions of source code must retain the above copyright 10bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer. 11bdea400fSAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 12bdea400fSAndrew Thompson * notice, this list of conditions and the following disclaimer in the 13bdea400fSAndrew Thompson * documentation and/or other materials provided with the distribution. 14bdea400fSAndrew Thompson * 15bdea400fSAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16bdea400fSAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17bdea400fSAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18bdea400fSAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19bdea400fSAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20bdea400fSAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21bdea400fSAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22bdea400fSAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23bdea400fSAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24bdea400fSAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25bdea400fSAndrew Thompson * SUCH DAMAGE. 26bdea400fSAndrew Thompson * 27bdea400fSAndrew Thompson * $FreeBSD$ 28bdea400fSAndrew Thompson */ 29bdea400fSAndrew Thompson 30a0ae8f04SBjoern A. Zeeb #include "opt_inet.h" 31a0ae8f04SBjoern A. Zeeb #include "opt_inet6.h" 32a0ae8f04SBjoern A. Zeeb #include "opt_enc.h" 33a0ae8f04SBjoern A. Zeeb 34bdea400fSAndrew Thompson #include <sys/param.h> 35bdea400fSAndrew Thompson #include <sys/systm.h> 36bdea400fSAndrew Thompson #include <sys/kernel.h> 37bdea400fSAndrew Thompson #include <sys/malloc.h> 38bdea400fSAndrew Thompson #include <sys/mbuf.h> 39bdea400fSAndrew Thompson #include <sys/module.h> 40bdea400fSAndrew Thompson #include <machine/bus.h> 41bdea400fSAndrew Thompson #include <sys/rman.h> 42bdea400fSAndrew Thompson #include <sys/socket.h> 43bdea400fSAndrew Thompson #include <sys/sockio.h> 44bdea400fSAndrew Thompson #include <sys/sysctl.h> 45bdea400fSAndrew Thompson 46bdea400fSAndrew Thompson #include <net/if.h> 47*76039bc8SGleb Smirnoff #include <net/if_var.h> 48bdea400fSAndrew Thompson #include <net/if_clone.h> 49bdea400fSAndrew Thompson #include <net/if_types.h> 50bdea400fSAndrew Thompson #include <net/pfil.h> 51bdea400fSAndrew Thompson #include <net/route.h> 52bdea400fSAndrew Thompson #include <net/netisr.h> 53bdea400fSAndrew Thompson #include <net/bpf.h> 54eddfbb76SRobert Watson #include <net/vnet.h> 55bdea400fSAndrew Thompson 56bdea400fSAndrew Thompson #include <netinet/in.h> 57bdea400fSAndrew Thompson #include <netinet/in_systm.h> 58bdea400fSAndrew Thompson #include <netinet/ip.h> 59bdea400fSAndrew Thompson #include <netinet/ip_var.h> 60bdea400fSAndrew Thompson #include <netinet/in_var.h> 61bdea400fSAndrew Thompson 62bdea400fSAndrew Thompson #ifdef INET6 63bdea400fSAndrew Thompson #include <netinet/ip6.h> 64bdea400fSAndrew Thompson #include <netinet6/ip6_var.h> 65bdea400fSAndrew Thompson #endif 66bdea400fSAndrew Thompson 67bdea400fSAndrew Thompson #include <netipsec/ipsec.h> 6819ad9831SBjoern A. Zeeb #include <netipsec/xform.h> 69bdea400fSAndrew Thompson 70bdea400fSAndrew Thompson #define ENCMTU (1024+512) 71bdea400fSAndrew Thompson 72bdea400fSAndrew Thompson /* XXX this define must have the same value as in OpenBSD */ 73bdea400fSAndrew Thompson #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 74bdea400fSAndrew Thompson #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 75bdea400fSAndrew Thompson #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 76bdea400fSAndrew Thompson 77bdea400fSAndrew Thompson struct enchdr { 78bdea400fSAndrew Thompson u_int32_t af; 79bdea400fSAndrew Thompson u_int32_t spi; 80bdea400fSAndrew Thompson u_int32_t flags; 81bdea400fSAndrew Thompson }; 82bdea400fSAndrew Thompson 8397c2a697SVANHULLEBUS Yvan struct ifnet *encif; 84bdea400fSAndrew Thompson static struct mtx enc_mtx; 85bdea400fSAndrew Thompson 86bdea400fSAndrew Thompson struct enc_softc { 87bdea400fSAndrew Thompson struct ifnet *sc_ifp; 88bdea400fSAndrew Thompson }; 89bdea400fSAndrew Thompson 90bdea400fSAndrew Thompson static int enc_ioctl(struct ifnet *, u_long, caddr_t); 91bdea400fSAndrew Thompson static int enc_output(struct ifnet *ifp, struct mbuf *m, 9247e8d432SGleb Smirnoff const struct sockaddr *dst, struct route *ro); 9307ed9a88SAndrew Thompson static int enc_clone_create(struct if_clone *, int, caddr_t); 94bac89dceSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 9542a58907SGleb Smirnoff static struct if_clone *enc_cloner; 9642a58907SGleb Smirnoff static const char encname[] = "enc"; 97bdea400fSAndrew Thompson 9819ad9831SBjoern A. Zeeb /* 9919ad9831SBjoern A. Zeeb * Sysctls. 10019ad9831SBjoern A. Zeeb */ 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 */ 1066472ac3dSEd Schouten static SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW, 0, "enc sysctl"); 10719ad9831SBjoern A. Zeeb 1086472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW, 0, "enc input sysctl"); 10919ad9831SBjoern A. Zeeb static int ipsec_filter_mask_in = ENC_BEFORE; 110f8e4b4efSMatthew D Fleming SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW, 11119ad9831SBjoern A. Zeeb &ipsec_filter_mask_in, 0, "IPsec input firewall filter mask"); 11219ad9831SBjoern A. Zeeb static int ipsec_bpf_mask_in = ENC_BEFORE; 113f8e4b4efSMatthew D Fleming SYSCTL_INT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW, 11419ad9831SBjoern A. Zeeb &ipsec_bpf_mask_in, 0, "IPsec input bpf mask"); 11519ad9831SBjoern A. Zeeb 1166472ac3dSEd Schouten static SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW, 0, "enc output sysctl"); 11719ad9831SBjoern A. Zeeb static int ipsec_filter_mask_out = ENC_BEFORE; 118f8e4b4efSMatthew D Fleming SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW, 11919ad9831SBjoern A. Zeeb &ipsec_filter_mask_out, 0, "IPsec output firewall filter mask"); 12019ad9831SBjoern A. Zeeb static int ipsec_bpf_mask_out = ENC_BEFORE|ENC_AFTER; 121f8e4b4efSMatthew D Fleming SYSCTL_INT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW, 12219ad9831SBjoern A. Zeeb &ipsec_bpf_mask_out, 0, "IPsec output bpf mask"); 12319ad9831SBjoern A. Zeeb 124bac89dceSAndrew Thompson static void 125bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 126bdea400fSAndrew Thompson { 127bac89dceSAndrew Thompson KASSERT(ifp != encif, ("%s: destroying encif", __func__)); 128bdea400fSAndrew Thompson 129bdea400fSAndrew Thompson bpfdetach(ifp); 130bdea400fSAndrew Thompson if_detach(ifp); 131bdea400fSAndrew Thompson if_free(ifp); 132bdea400fSAndrew Thompson } 133bdea400fSAndrew Thompson 134bdea400fSAndrew Thompson static int 13507ed9a88SAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 136bdea400fSAndrew Thompson { 137bdea400fSAndrew Thompson struct ifnet *ifp; 138bdea400fSAndrew Thompson struct enc_softc *sc; 139bdea400fSAndrew Thompson 140bdea400fSAndrew Thompson sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 141bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 142bdea400fSAndrew Thompson if (ifp == NULL) { 143bdea400fSAndrew Thompson free(sc, M_DEVBUF); 144bdea400fSAndrew Thompson return (ENOSPC); 145bdea400fSAndrew Thompson } 146bdea400fSAndrew Thompson 14742a58907SGleb Smirnoff if_initname(ifp, encname, unit); 148bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 149bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 150bdea400fSAndrew Thompson ifp->if_output = enc_output; 151bdea400fSAndrew Thompson ifp->if_snd.ifq_maxlen = ifqmaxlen; 152bdea400fSAndrew Thompson ifp->if_softc = sc; 153bdea400fSAndrew Thompson if_attach(ifp); 154f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 155bdea400fSAndrew Thompson 156bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 157ae4748adSAndrew Thompson /* grab a pointer to enc0, ignore the rest */ 158ae4748adSAndrew Thompson if (encif == NULL) 159bdea400fSAndrew Thompson encif = ifp; 160bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 161bdea400fSAndrew Thompson 162bdea400fSAndrew Thompson return (0); 163bdea400fSAndrew Thompson } 164bdea400fSAndrew Thompson 165bdea400fSAndrew Thompson static int 166bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 167bdea400fSAndrew Thompson { 168bdea400fSAndrew Thompson switch (type) { 169bdea400fSAndrew Thompson case MOD_LOAD: 170bdea400fSAndrew Thompson mtx_init(&enc_mtx, "enc mtx", NULL, MTX_DEF); 17142a58907SGleb Smirnoff enc_cloner = if_clone_simple(encname, enc_clone_create, 172bdad3190SGleb Smirnoff enc_clone_destroy, 1); 173bdea400fSAndrew Thompson break; 174bdea400fSAndrew Thompson case MOD_UNLOAD: 175bdea400fSAndrew Thompson printf("enc module unload - not possible for this module\n"); 176bdea400fSAndrew Thompson return (EINVAL); 177bdea400fSAndrew Thompson default: 178bdea400fSAndrew Thompson return (EOPNOTSUPP); 179bdea400fSAndrew Thompson } 180bdea400fSAndrew Thompson return (0); 181bdea400fSAndrew Thompson } 182bdea400fSAndrew Thompson 183bdea400fSAndrew Thompson static moduledata_t enc_mod = { 184b3aa4193SJohn Baldwin "if_enc", 185bdea400fSAndrew Thompson enc_modevent, 1869823d527SKevin Lo 0 187bdea400fSAndrew Thompson }; 188bdea400fSAndrew Thompson 189b3aa4193SJohn Baldwin DECLARE_MODULE(if_enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 190bdea400fSAndrew Thompson 191bdea400fSAndrew Thompson static int 19247e8d432SGleb Smirnoff enc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 193279aa3d4SKip Macy struct route *ro) 194bdea400fSAndrew Thompson { 195bdea400fSAndrew Thompson m_freem(m); 196bdea400fSAndrew Thompson return (0); 197bdea400fSAndrew Thompson } 198bdea400fSAndrew Thompson 199bdea400fSAndrew Thompson /* 200bdea400fSAndrew Thompson * Process an ioctl request. 201bdea400fSAndrew Thompson */ 202bdea400fSAndrew Thompson /* ARGSUSED */ 203bdea400fSAndrew Thompson static int 204bdea400fSAndrew Thompson enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 205bdea400fSAndrew Thompson { 206bdea400fSAndrew Thompson int error = 0; 207bdea400fSAndrew Thompson 208ae4748adSAndrew Thompson mtx_lock(&enc_mtx); 209ae4748adSAndrew Thompson 210bdea400fSAndrew Thompson switch (cmd) { 211bdea400fSAndrew Thompson 212bdea400fSAndrew Thompson case SIOCSIFFLAGS: 213bdea400fSAndrew Thompson if (ifp->if_flags & IFF_UP) 214bdea400fSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_RUNNING; 215bdea400fSAndrew Thompson else 216bdea400fSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 217bdea400fSAndrew Thompson 218bdea400fSAndrew Thompson break; 219bdea400fSAndrew Thompson 220bdea400fSAndrew Thompson default: 221bdea400fSAndrew Thompson error = EINVAL; 222bdea400fSAndrew Thompson } 223ae4748adSAndrew Thompson 224ae4748adSAndrew Thompson mtx_unlock(&enc_mtx); 225bdea400fSAndrew Thompson return (error); 226bdea400fSAndrew Thompson } 227bdea400fSAndrew Thompson 228bdea400fSAndrew Thompson int 22919ad9831SBjoern A. Zeeb ipsec_filter(struct mbuf **mp, int dir, int flags) 230bdea400fSAndrew Thompson { 231bdea400fSAndrew Thompson int error, i; 232bdea400fSAndrew Thompson struct ip *ip; 233bdea400fSAndrew Thompson 234ae4748adSAndrew Thompson KASSERT(encif != NULL, ("%s: encif is null", __func__)); 23519ad9831SBjoern A. Zeeb KASSERT(flags & (ENC_IN|ENC_OUT), 23619ad9831SBjoern A. Zeeb ("%s: invalid flags: %04x", __func__, flags)); 237ae4748adSAndrew Thompson 238ae4748adSAndrew Thompson if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0) 239bdea400fSAndrew Thompson return (0); 240bdea400fSAndrew Thompson 24119ad9831SBjoern A. Zeeb if (flags & ENC_IN) { 24219ad9831SBjoern A. Zeeb if ((flags & ipsec_filter_mask_in) == 0) 24319ad9831SBjoern A. Zeeb return (0); 24419ad9831SBjoern A. Zeeb } else { 24519ad9831SBjoern A. Zeeb if ((flags & ipsec_filter_mask_out) == 0) 24619ad9831SBjoern A. Zeeb return (0); 24719ad9831SBjoern A. Zeeb } 24819ad9831SBjoern A. Zeeb 249bdea400fSAndrew Thompson /* Skip pfil(9) if no filters are loaded */ 250a0ae8f04SBjoern A. Zeeb if (1 251a0ae8f04SBjoern A. Zeeb #ifdef INET 252a0ae8f04SBjoern A. Zeeb && !PFIL_HOOKED(&V_inet_pfil_hook) 253bdea400fSAndrew Thompson #endif 254a0ae8f04SBjoern A. Zeeb #ifdef INET6 255a0ae8f04SBjoern A. Zeeb && !PFIL_HOOKED(&V_inet6_pfil_hook) 256a0ae8f04SBjoern A. Zeeb #endif 257a0ae8f04SBjoern A. Zeeb ) { 258bdea400fSAndrew Thompson return (0); 259bdea400fSAndrew Thompson } 260bdea400fSAndrew Thompson 261bdea400fSAndrew Thompson i = min((*mp)->m_pkthdr.len, max_protohdr); 262bdea400fSAndrew Thompson if ((*mp)->m_len < i) { 263bdea400fSAndrew Thompson *mp = m_pullup(*mp, i); 264bdea400fSAndrew Thompson if (*mp == NULL) { 265bdea400fSAndrew Thompson printf("%s: m_pullup failed\n", __func__); 266bdea400fSAndrew Thompson return (-1); 267bdea400fSAndrew Thompson } 268bdea400fSAndrew Thompson } 269bdea400fSAndrew Thompson 270bdea400fSAndrew Thompson error = 0; 271bdea400fSAndrew Thompson ip = mtod(*mp, struct ip *); 272bdea400fSAndrew Thompson switch (ip->ip_v) { 273a0ae8f04SBjoern A. Zeeb #ifdef INET 274bdea400fSAndrew Thompson case 4: 275382e8b5aSBjoern A. Zeeb error = pfil_run_hooks(&V_inet_pfil_hook, mp, 276bdea400fSAndrew Thompson encif, dir, NULL); 277bdea400fSAndrew Thompson break; 278a0ae8f04SBjoern A. Zeeb #endif 279bdea400fSAndrew Thompson #ifdef INET6 280bdea400fSAndrew Thompson case 6: 281382e8b5aSBjoern A. Zeeb error = pfil_run_hooks(&V_inet6_pfil_hook, mp, 282bdea400fSAndrew Thompson encif, dir, NULL); 283bdea400fSAndrew Thompson break; 284bdea400fSAndrew Thompson #endif 285bdea400fSAndrew Thompson default: 286bdea400fSAndrew Thompson printf("%s: unknown IP version\n", __func__); 287bdea400fSAndrew Thompson } 288bdea400fSAndrew Thompson 289e361d7d4SAndrew Thompson /* 290e361d7d4SAndrew Thompson * If the mbuf was consumed by the filter for requeueing (dummynet, etc) 291e361d7d4SAndrew Thompson * then error will be zero but we still want to return an error to our 292e361d7d4SAndrew Thompson * caller so the null mbuf isn't forwarded further. 293e361d7d4SAndrew Thompson */ 294e361d7d4SAndrew Thompson if (*mp == NULL && error == 0) 295e361d7d4SAndrew Thompson return (-1); /* Consumed by the filter */ 296bdea400fSAndrew Thompson if (*mp == NULL) 297bdea400fSAndrew Thompson return (error); 298bdea400fSAndrew Thompson if (error != 0) 299bdea400fSAndrew Thompson goto bad; 300bdea400fSAndrew Thompson 301bdea400fSAndrew Thompson return (error); 302bdea400fSAndrew Thompson 303bdea400fSAndrew Thompson bad: 304bdea400fSAndrew Thompson m_freem(*mp); 305bdea400fSAndrew Thompson *mp = NULL; 306bdea400fSAndrew Thompson return (error); 307bdea400fSAndrew Thompson } 308bdea400fSAndrew Thompson 309bdea400fSAndrew Thompson void 31019ad9831SBjoern A. Zeeb ipsec_bpf(struct mbuf *m, struct secasvar *sav, int af, int flags) 311bdea400fSAndrew Thompson { 31219ad9831SBjoern A. Zeeb int mflags; 313bdea400fSAndrew Thompson struct enchdr hdr; 314bdea400fSAndrew Thompson 315ae4748adSAndrew Thompson KASSERT(encif != NULL, ("%s: encif is null", __func__)); 31619ad9831SBjoern A. Zeeb KASSERT(flags & (ENC_IN|ENC_OUT), 31719ad9831SBjoern A. Zeeb ("%s: invalid flags: %04x", __func__, flags)); 318bdea400fSAndrew Thompson 319ae4748adSAndrew Thompson if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0) 320bdea400fSAndrew Thompson return; 321bdea400fSAndrew Thompson 32219ad9831SBjoern A. Zeeb if (flags & ENC_IN) { 32319ad9831SBjoern A. Zeeb if ((flags & ipsec_bpf_mask_in) == 0) 32419ad9831SBjoern A. Zeeb return; 32519ad9831SBjoern A. Zeeb } else { 32619ad9831SBjoern A. Zeeb if ((flags & ipsec_bpf_mask_out) == 0) 32719ad9831SBjoern A. Zeeb return; 32819ad9831SBjoern A. Zeeb } 32919ad9831SBjoern A. Zeeb 3300dea849aSJohn Baldwin if (bpf_peers_present(encif->if_bpf)) { 33119ad9831SBjoern A. Zeeb mflags = 0; 33219ad9831SBjoern A. Zeeb hdr.spi = 0; 33319ad9831SBjoern A. Zeeb if (!sav) { 33419ad9831SBjoern A. Zeeb struct m_tag *mtag; 33519ad9831SBjoern A. Zeeb mtag = m_tag_find(m, PACKET_TAG_IPSEC_IN_DONE, NULL); 33619ad9831SBjoern A. Zeeb if (mtag != NULL) { 33719ad9831SBjoern A. Zeeb struct tdb_ident *tdbi; 33819ad9831SBjoern A. Zeeb tdbi = (struct tdb_ident *) (mtag + 1); 33919ad9831SBjoern A. Zeeb if (tdbi->alg_enc != SADB_EALG_NONE) 34019ad9831SBjoern A. Zeeb mflags |= M_CONF; 34119ad9831SBjoern A. Zeeb if (tdbi->alg_auth != SADB_AALG_NONE) 34219ad9831SBjoern A. Zeeb mflags |= M_AUTH; 34319ad9831SBjoern A. Zeeb hdr.spi = tdbi->spi; 34419ad9831SBjoern A. Zeeb } 34519ad9831SBjoern A. Zeeb } else { 346bdea400fSAndrew Thompson if (sav->alg_enc != SADB_EALG_NONE) 34719ad9831SBjoern A. Zeeb mflags |= M_CONF; 348bdea400fSAndrew Thompson if (sav->alg_auth != SADB_AALG_NONE) 34919ad9831SBjoern A. Zeeb mflags |= M_AUTH; 35019ad9831SBjoern A. Zeeb hdr.spi = sav->spi; 35119ad9831SBjoern A. Zeeb } 352bdea400fSAndrew Thompson 353bdea400fSAndrew Thompson /* 354bdea400fSAndrew Thompson * We need to prepend the address family as a four byte 355bdea400fSAndrew Thompson * field. Cons up a dummy header to pacify bpf. This 356bdea400fSAndrew Thompson * is safe because bpf will only read from the mbuf 357bdea400fSAndrew Thompson * (i.e., it won't try to free it or keep a pointer a 358bdea400fSAndrew Thompson * to it). 359bdea400fSAndrew Thompson */ 360bdea400fSAndrew Thompson hdr.af = af; 36119ad9831SBjoern A. Zeeb /* hdr.spi already set above */ 36219ad9831SBjoern A. Zeeb hdr.flags = mflags; 363bdea400fSAndrew Thompson 364f0ac1eedSAndrew Thompson bpf_mtap2(encif->if_bpf, &hdr, sizeof(hdr), m); 365bdea400fSAndrew Thompson } 366bdea400fSAndrew Thompson } 367