xref: /freebsd/sys/net/if_enc.c (revision 76039bc84fae9915788b54ff28fe0cc4876952d2)
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