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 30bdea400fSAndrew Thompson #include <sys/param.h> 31bdea400fSAndrew Thompson #include <sys/systm.h> 32bdea400fSAndrew Thompson #include <sys/kernel.h> 33bdea400fSAndrew Thompson #include <sys/malloc.h> 34bdea400fSAndrew Thompson #include <sys/mbuf.h> 35bdea400fSAndrew Thompson #include <sys/module.h> 36bdea400fSAndrew Thompson #include <machine/bus.h> 37bdea400fSAndrew Thompson #include <sys/rman.h> 38bdea400fSAndrew Thompson #include <sys/socket.h> 39bdea400fSAndrew Thompson #include <sys/sockio.h> 40bdea400fSAndrew Thompson #include <sys/sysctl.h> 41bdea400fSAndrew Thompson 42bdea400fSAndrew Thompson #include <net/if.h> 43bdea400fSAndrew Thompson #include <net/if_clone.h> 44bdea400fSAndrew Thompson #include <net/if_types.h> 45bdea400fSAndrew Thompson #include <net/pfil.h> 46bdea400fSAndrew Thompson #include <net/route.h> 47bdea400fSAndrew Thompson #include <net/netisr.h> 48bdea400fSAndrew Thompson #include <net/bpf.h> 49bdea400fSAndrew Thompson #include <net/bpfdesc.h> 50bdea400fSAndrew Thompson 51bdea400fSAndrew Thompson #include <netinet/in.h> 52bdea400fSAndrew Thompson #include <netinet/in_systm.h> 53bdea400fSAndrew Thompson #include <netinet/ip.h> 54bdea400fSAndrew Thompson #include <netinet/ip_var.h> 55bdea400fSAndrew Thompson #include <netinet/in_var.h> 56bdea400fSAndrew Thompson #include "opt_inet6.h" 57bdea400fSAndrew Thompson 58bdea400fSAndrew Thompson #ifdef INET6 59bdea400fSAndrew Thompson #include <netinet/ip6.h> 60bdea400fSAndrew Thompson #include <netinet6/ip6_var.h> 61bdea400fSAndrew Thompson #endif 62bdea400fSAndrew Thompson 6319ad9831SBjoern A. Zeeb #include "opt_enc.h" 64bdea400fSAndrew Thompson #include <netipsec/ipsec.h> 6519ad9831SBjoern A. Zeeb #include <netipsec/xform.h> 66bdea400fSAndrew Thompson 67bdea400fSAndrew Thompson #define ENCMTU (1024+512) 68bdea400fSAndrew Thompson 69bdea400fSAndrew Thompson /* XXX this define must have the same value as in OpenBSD */ 70bdea400fSAndrew Thompson #define M_CONF 0x0400 /* payload was encrypted (ESP-transport) */ 71bdea400fSAndrew Thompson #define M_AUTH 0x0800 /* payload was authenticated (AH or ESP auth) */ 72bdea400fSAndrew Thompson #define M_AUTH_AH 0x2000 /* header was authenticated (AH) */ 73bdea400fSAndrew Thompson 74bdea400fSAndrew Thompson struct enchdr { 75bdea400fSAndrew Thompson u_int32_t af; 76bdea400fSAndrew Thompson u_int32_t spi; 77bdea400fSAndrew Thompson u_int32_t flags; 78bdea400fSAndrew Thompson }; 79bdea400fSAndrew Thompson 80bdea400fSAndrew Thompson static struct ifnet *encif; 81bdea400fSAndrew Thompson static struct mtx enc_mtx; 82bdea400fSAndrew Thompson 83bdea400fSAndrew Thompson struct enc_softc { 84bdea400fSAndrew Thompson struct ifnet *sc_ifp; 85bdea400fSAndrew Thompson }; 86bdea400fSAndrew Thompson 87bdea400fSAndrew Thompson static int enc_ioctl(struct ifnet *, u_long, caddr_t); 88bdea400fSAndrew Thompson static int enc_output(struct ifnet *ifp, struct mbuf *m, 89bdea400fSAndrew Thompson struct sockaddr *dst, struct rtentry *rt); 9007ed9a88SAndrew Thompson static int enc_clone_create(struct if_clone *, int, caddr_t); 91bac89dceSAndrew Thompson static void enc_clone_destroy(struct ifnet *); 92bdea400fSAndrew Thompson 93bdea400fSAndrew Thompson IFC_SIMPLE_DECLARE(enc, 1); 94bdea400fSAndrew Thompson 9519ad9831SBjoern A. Zeeb /* 9619ad9831SBjoern A. Zeeb * Sysctls. 9719ad9831SBjoern A. Zeeb */ 9819ad9831SBjoern A. Zeeb 9919ad9831SBjoern A. Zeeb /* 10019ad9831SBjoern A. Zeeb * Before and after are relative to when we are stripping the 10119ad9831SBjoern A. Zeeb * outer IP header. 10219ad9831SBjoern A. Zeeb */ 10319ad9831SBjoern A. Zeeb SYSCTL_NODE(_net, OID_AUTO, enc, CTLFLAG_RW, 0, "enc sysctl"); 10419ad9831SBjoern A. Zeeb 10519ad9831SBjoern A. Zeeb SYSCTL_NODE(_net_enc, OID_AUTO, in, CTLFLAG_RW, 0, "enc input sysctl"); 10619ad9831SBjoern A. Zeeb static int ipsec_filter_mask_in = ENC_BEFORE; 10719ad9831SBjoern A. Zeeb SYSCTL_XINT(_net_enc_in, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW, 10819ad9831SBjoern A. Zeeb &ipsec_filter_mask_in, 0, "IPsec input firewall filter mask"); 10919ad9831SBjoern A. Zeeb static int ipsec_bpf_mask_in = ENC_BEFORE; 11019ad9831SBjoern A. Zeeb SYSCTL_XINT(_net_enc_in, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW, 11119ad9831SBjoern A. Zeeb &ipsec_bpf_mask_in, 0, "IPsec input bpf mask"); 11219ad9831SBjoern A. Zeeb 11319ad9831SBjoern A. Zeeb SYSCTL_NODE(_net_enc, OID_AUTO, out, CTLFLAG_RW, 0, "enc output sysctl"); 11419ad9831SBjoern A. Zeeb static int ipsec_filter_mask_out = ENC_BEFORE; 11519ad9831SBjoern A. Zeeb SYSCTL_XINT(_net_enc_out, OID_AUTO, ipsec_filter_mask, CTLFLAG_RW, 11619ad9831SBjoern A. Zeeb &ipsec_filter_mask_out, 0, "IPsec output firewall filter mask"); 11719ad9831SBjoern A. Zeeb static int ipsec_bpf_mask_out = ENC_BEFORE|ENC_AFTER; 11819ad9831SBjoern A. Zeeb SYSCTL_XINT(_net_enc_out, OID_AUTO, ipsec_bpf_mask, CTLFLAG_RW, 11919ad9831SBjoern A. Zeeb &ipsec_bpf_mask_out, 0, "IPsec output bpf mask"); 12019ad9831SBjoern A. Zeeb 121bac89dceSAndrew Thompson static void 122bdea400fSAndrew Thompson enc_clone_destroy(struct ifnet *ifp) 123bdea400fSAndrew Thompson { 124bac89dceSAndrew Thompson KASSERT(ifp != encif, ("%s: destroying encif", __func__)); 125bdea400fSAndrew Thompson 126bdea400fSAndrew Thompson bpfdetach(ifp); 127bdea400fSAndrew Thompson if_detach(ifp); 128bdea400fSAndrew Thompson if_free(ifp); 129bdea400fSAndrew Thompson } 130bdea400fSAndrew Thompson 131bdea400fSAndrew Thompson static int 13207ed9a88SAndrew Thompson enc_clone_create(struct if_clone *ifc, int unit, caddr_t params) 133bdea400fSAndrew Thompson { 134bdea400fSAndrew Thompson struct ifnet *ifp; 135bdea400fSAndrew Thompson struct enc_softc *sc; 136bdea400fSAndrew Thompson 137bdea400fSAndrew Thompson sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 138bdea400fSAndrew Thompson ifp = sc->sc_ifp = if_alloc(IFT_ENC); 139bdea400fSAndrew Thompson if (ifp == NULL) { 140bdea400fSAndrew Thompson free(sc, M_DEVBUF); 141bdea400fSAndrew Thompson return (ENOSPC); 142bdea400fSAndrew Thompson } 143bdea400fSAndrew Thompson 144bdea400fSAndrew Thompson if_initname(ifp, ifc->ifc_name, unit); 145bdea400fSAndrew Thompson ifp->if_mtu = ENCMTU; 146bdea400fSAndrew Thompson ifp->if_ioctl = enc_ioctl; 147bdea400fSAndrew Thompson ifp->if_output = enc_output; 148bdea400fSAndrew Thompson ifp->if_snd.ifq_maxlen = ifqmaxlen; 149bdea400fSAndrew Thompson ifp->if_softc = sc; 150bdea400fSAndrew Thompson if_attach(ifp); 151f0ac1eedSAndrew Thompson bpfattach(ifp, DLT_ENC, sizeof(struct enchdr)); 152bdea400fSAndrew Thompson 153bdea400fSAndrew Thompson mtx_lock(&enc_mtx); 154ae4748adSAndrew Thompson /* grab a pointer to enc0, ignore the rest */ 155ae4748adSAndrew Thompson if (encif == NULL) 156bdea400fSAndrew Thompson encif = ifp; 157bdea400fSAndrew Thompson mtx_unlock(&enc_mtx); 158bdea400fSAndrew Thompson 159bdea400fSAndrew Thompson return (0); 160bdea400fSAndrew Thompson } 161bdea400fSAndrew Thompson 162bdea400fSAndrew Thompson static int 163bdea400fSAndrew Thompson enc_modevent(module_t mod, int type, void *data) 164bdea400fSAndrew Thompson { 165bdea400fSAndrew Thompson switch (type) { 166bdea400fSAndrew Thompson case MOD_LOAD: 167bdea400fSAndrew Thompson mtx_init(&enc_mtx, "enc mtx", NULL, MTX_DEF); 168bdea400fSAndrew Thompson if_clone_attach(&enc_cloner); 169bdea400fSAndrew Thompson break; 170bdea400fSAndrew Thompson case MOD_UNLOAD: 171bdea400fSAndrew Thompson printf("enc module unload - not possible for this module\n"); 172bdea400fSAndrew Thompson return (EINVAL); 173bdea400fSAndrew Thompson default: 174bdea400fSAndrew Thompson return (EOPNOTSUPP); 175bdea400fSAndrew Thompson } 176bdea400fSAndrew Thompson return (0); 177bdea400fSAndrew Thompson } 178bdea400fSAndrew Thompson 179bdea400fSAndrew Thompson static moduledata_t enc_mod = { 180bdea400fSAndrew Thompson "enc", 181bdea400fSAndrew Thompson enc_modevent, 182bdea400fSAndrew Thompson 0 183bdea400fSAndrew Thompson }; 184bdea400fSAndrew Thompson 185bdea400fSAndrew Thompson DECLARE_MODULE(enc, enc_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY); 186bdea400fSAndrew Thompson 187bdea400fSAndrew Thompson static int 188bdea400fSAndrew Thompson enc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 189bdea400fSAndrew Thompson struct rtentry *rt) 190bdea400fSAndrew Thompson { 191bdea400fSAndrew Thompson m_freem(m); 192bdea400fSAndrew Thompson return (0); 193bdea400fSAndrew Thompson } 194bdea400fSAndrew Thompson 195bdea400fSAndrew Thompson /* 196bdea400fSAndrew Thompson * Process an ioctl request. 197bdea400fSAndrew Thompson */ 198bdea400fSAndrew Thompson /* ARGSUSED */ 199bdea400fSAndrew Thompson static int 200bdea400fSAndrew Thompson enc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 201bdea400fSAndrew Thompson { 202bdea400fSAndrew Thompson int error = 0; 203bdea400fSAndrew Thompson 204ae4748adSAndrew Thompson mtx_lock(&enc_mtx); 205ae4748adSAndrew Thompson 206bdea400fSAndrew Thompson switch (cmd) { 207bdea400fSAndrew Thompson 208bdea400fSAndrew Thompson case SIOCSIFFLAGS: 209bdea400fSAndrew Thompson if (ifp->if_flags & IFF_UP) 210bdea400fSAndrew Thompson ifp->if_drv_flags |= IFF_DRV_RUNNING; 211bdea400fSAndrew Thompson else 212bdea400fSAndrew Thompson ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 213bdea400fSAndrew Thompson 214bdea400fSAndrew Thompson break; 215bdea400fSAndrew Thompson 216bdea400fSAndrew Thompson default: 217bdea400fSAndrew Thompson error = EINVAL; 218bdea400fSAndrew Thompson } 219ae4748adSAndrew Thompson 220ae4748adSAndrew Thompson mtx_unlock(&enc_mtx); 221bdea400fSAndrew Thompson return (error); 222bdea400fSAndrew Thompson } 223bdea400fSAndrew Thompson 224bdea400fSAndrew Thompson int 22519ad9831SBjoern A. Zeeb ipsec_filter(struct mbuf **mp, int dir, int flags) 226bdea400fSAndrew Thompson { 227bdea400fSAndrew Thompson int error, i; 228bdea400fSAndrew Thompson struct ip *ip; 229bdea400fSAndrew Thompson 230ae4748adSAndrew Thompson KASSERT(encif != NULL, ("%s: encif is null", __func__)); 23119ad9831SBjoern A. Zeeb KASSERT(flags & (ENC_IN|ENC_OUT), 23219ad9831SBjoern A. Zeeb ("%s: invalid flags: %04x", __func__, flags)); 233ae4748adSAndrew Thompson 234ae4748adSAndrew Thompson if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0) 235bdea400fSAndrew Thompson return (0); 236bdea400fSAndrew Thompson 23719ad9831SBjoern A. Zeeb if (flags & ENC_IN) { 23819ad9831SBjoern A. Zeeb if ((flags & ipsec_filter_mask_in) == 0) 23919ad9831SBjoern A. Zeeb return (0); 24019ad9831SBjoern A. Zeeb } else { 24119ad9831SBjoern A. Zeeb if ((flags & ipsec_filter_mask_out) == 0) 24219ad9831SBjoern A. Zeeb return (0); 24319ad9831SBjoern A. Zeeb } 24419ad9831SBjoern A. Zeeb 245bdea400fSAndrew Thompson /* Skip pfil(9) if no filters are loaded */ 246bdea400fSAndrew Thompson if (!(PFIL_HOOKED(&inet_pfil_hook) 247bdea400fSAndrew Thompson #ifdef INET6 248bdea400fSAndrew Thompson || PFIL_HOOKED(&inet6_pfil_hook) 249bdea400fSAndrew Thompson #endif 250bdea400fSAndrew Thompson )) { 251bdea400fSAndrew Thompson return (0); 252bdea400fSAndrew Thompson } 253bdea400fSAndrew Thompson 254bdea400fSAndrew Thompson i = min((*mp)->m_pkthdr.len, max_protohdr); 255bdea400fSAndrew Thompson if ((*mp)->m_len < i) { 256bdea400fSAndrew Thompson *mp = m_pullup(*mp, i); 257bdea400fSAndrew Thompson if (*mp == NULL) { 258bdea400fSAndrew Thompson printf("%s: m_pullup failed\n", __func__); 259bdea400fSAndrew Thompson return (-1); 260bdea400fSAndrew Thompson } 261bdea400fSAndrew Thompson } 262bdea400fSAndrew Thompson 263bdea400fSAndrew Thompson error = 0; 264bdea400fSAndrew Thompson ip = mtod(*mp, struct ip *); 265bdea400fSAndrew Thompson switch (ip->ip_v) { 266bdea400fSAndrew Thompson case 4: 267bdea400fSAndrew Thompson /* 268bdea400fSAndrew Thompson * before calling the firewall, swap fields the same as 269bdea400fSAndrew Thompson * IP does. here we assume the header is contiguous 270bdea400fSAndrew Thompson */ 271bdea400fSAndrew Thompson ip->ip_len = ntohs(ip->ip_len); 272bdea400fSAndrew Thompson ip->ip_off = ntohs(ip->ip_off); 273bdea400fSAndrew Thompson 274bdea400fSAndrew Thompson error = pfil_run_hooks(&inet_pfil_hook, mp, 275bdea400fSAndrew Thompson encif, dir, NULL); 276bdea400fSAndrew Thompson 277bdea400fSAndrew Thompson if (*mp == NULL || error != 0) 278bdea400fSAndrew Thompson break; 279bdea400fSAndrew Thompson 280bdea400fSAndrew Thompson /* restore byte ordering */ 281bdea400fSAndrew Thompson ip = mtod(*mp, struct ip *); 282bdea400fSAndrew Thompson ip->ip_len = htons(ip->ip_len); 283bdea400fSAndrew Thompson ip->ip_off = htons(ip->ip_off); 284bdea400fSAndrew Thompson break; 285bdea400fSAndrew Thompson 286bdea400fSAndrew Thompson #ifdef INET6 287bdea400fSAndrew Thompson case 6: 288bdea400fSAndrew Thompson error = pfil_run_hooks(&inet6_pfil_hook, mp, 289bdea400fSAndrew Thompson encif, dir, NULL); 290bdea400fSAndrew Thompson break; 291bdea400fSAndrew Thompson #endif 292bdea400fSAndrew Thompson default: 293bdea400fSAndrew Thompson printf("%s: unknown IP version\n", __func__); 294bdea400fSAndrew Thompson } 295bdea400fSAndrew Thompson 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