xref: /freebsd/sys/net/bpf_ifnet.c (revision f9bc005b8ef3b507a5ecbc2d7fe4411ef70eff38)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990, 1991, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org>
7  * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
8  *
9  * This code is derived from the Stanford/CMU enet packet filter,
10  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
11  * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
12  * Berkeley Laboratory.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  */
38 
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <net/bpf.h>
42 #include <net/bpfdesc.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45 #include <net/if_private.h>
46 #include <net/if_types.h>
47 #include <net/route.h>
48 
49 /* We need to know all the ifnets we support. */
50 #include <net/if_dl.h>
51 #include <net/ethernet.h>
52 #include <net/firewire.h>
53 #include <net/if_pflog.h>
54 #include <net/if_pfsync.h>
55 
56 #include <security/mac/mac_framework.h>
57 
58 static int
59 bpf_ifnet_write(void *arg, struct mbuf *m, struct mbuf *mc, int flags)
60 {
61 	struct ifnet *ifp = arg;
62 	struct route ro = {};
63 	struct sockaddr dst = {
64 		.sa_family = AF_UNSPEC,
65 	};
66 	u_int hlen;
67 	int error;
68 
69 	NET_EPOCH_ASSERT();
70 
71 	if (__predict_false((ifp->if_flags & IFF_UP) == 0)) {
72 		m_freem(m);
73 		m_freem(mc);
74 		return (ENETDOWN);
75 	}
76 
77 	switch (ifp->if_type) {
78 	/* DLT_RAW */
79 	case IFT_MBIM:		/* umb(4) */
80 	case IFT_OTHER:		/* uhso(4), usie */
81 		hlen = 0;
82 		break;
83 
84 	/* DLT_ENC */
85 	case IFT_ENC:
86 		hlen = 12; /* XXXGL: sizeof(struct enchdr); */
87 		break;
88 
89 	/* DLT_EN10MB */
90 	case IFT_ETHER:		/* if_ethersubr.c */
91 	case IFT_L2VLAN:	/* vlan(4) */
92 	case IFT_BRIDGE:	/* if_bridge(4) */
93 	case IFT_IEEE8023ADLAG:	/* lagg(4) */
94 	case IFT_INFINIBAND:	/* if_infiniband.c */
95 	{
96 		struct ether_header *eh;
97 
98 		eh = mtod(m, struct ether_header *);
99 		if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
100 			if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost,
101 			    ETHER_ADDR_LEN) == 0)
102 				m->m_flags |= M_BCAST;
103 			else
104 				m->m_flags |= M_MCAST;
105 		}
106 		if (!(flags & BPFD_HDRCMPLT)) {
107 			memcpy(eh->ether_shost, IF_LLADDR(ifp),
108 			    sizeof(eh->ether_shost));
109 		}
110 		hlen = ETHER_HDR_LEN;
111 		break;
112 	}
113 	/* DLT_APPLE_IP_OVER_IEEE1394 */
114 	case IFT_IEEE1394:	/* fwip(4) */
115 		hlen = sizeof(struct fw_hwaddr);
116 		break;
117 
118 	/* DLT_NULL */
119 	case IFT_GIF:		/* gif(4) */
120 	case IFT_LOOP:		/* lo(4), disc(4) */
121 	case IFT_PARA:		/* plip(4), iic */
122 	case IFT_PPP:		/* tun(4) */
123 	case IFT_PROPVIRTUAL:	/* ng_iface(4) */
124 	case IFT_WIREGUARD:	/* wg(4) */
125 	case IFT_STF:		/* stf(4) */
126 	case IFT_TUNNEL:	/* ipsec(4), me(4), gre(4), ovpn(4) */
127 		hlen = sizeof(uint32_t);
128 		break;
129 
130 	/* DLT_PFSYNC */
131 	case IFT_PFSYNC:
132 		hlen = PFSYNC_HDRLEN;
133 		break;
134 
135 	default:
136 		hlen = 0;	/* pacify compiler */
137 		KASSERT(0, ("%s: ifp %p type %u not supported", __func__,
138 		    ifp, ifp->if_type));
139 	}
140 
141 	if (__predict_false(hlen > m->m_len)) {
142 		m_freem(m);
143 		m_freem(mc);
144 		return (EMSGSIZE);
145 	};
146 
147 	if (hlen != 0) {
148 		MPASS(hlen <= sizeof(dst.sa_data));
149 		bcopy(mtod(m, const void *), &dst.sa_data, hlen);
150 		ro.ro_prepend = (char *)&dst.sa_data;
151 		ro.ro_plen = hlen;
152 		ro.ro_flags = RT_HAS_HEADER;
153 		m->m_pkthdr.len -= hlen;
154 		m->m_len -= hlen;
155 		m->m_data += hlen;
156 	};
157 
158 	CURVNET_SET(ifp->if_vnet);
159 	error = ifp->if_output(ifp, m, &dst, &ro);
160 	if (error != 0) {
161 		m_freem(mc);
162 	} else if (mc != NULL) {
163 		mc->m_pkthdr.rcvif = ifp;
164 		(void)ifp->if_input(ifp, mc);
165 	}
166 	CURVNET_RESTORE();
167 
168 	return (error);
169 }
170 
171 static bool
172 bpf_ifnet_chkdir(void *arg, const struct mbuf *m, int dir)
173 {
174 	struct ifnet *ifp = arg;
175 	struct ifnet *rcvif = m_rcvif(m);
176 
177 	return ((dir == BPF_D_IN && ifp != rcvif) ||
178 	    (dir == BPF_D_OUT && ifp == rcvif));
179 }
180 
181 uint32_t
182 bpf_ifnet_wrsize(void *arg)
183 {
184 	struct ifnet *ifp = arg;
185 
186 	return (ifp->if_mtu);
187 }
188 
189 int
190 bpf_ifnet_promisc(void *arg, bool on)
191 {
192 	struct ifnet *ifp = arg;
193 	int error;
194 
195 	CURVNET_SET(ifp->if_vnet);
196 	if ((error = ifpromisc(ifp, on ? 1 : 0)) != 0)
197 		if_printf(ifp, "%s: ifpromisc failed (%d)\n", __func__, error);
198 	CURVNET_RESTORE();
199 
200 	return (error);
201 }
202 
203 #ifdef MAC
204 static int
205 bpf_ifnet_mac_check_receive(void *arg, struct bpf_d *d)
206 {
207 	struct ifnet *ifp = arg;
208 
209 	return (mac_bpfdesc_check_receive(d, ifp));
210 }
211 #endif
212 
213 static const struct bif_methods bpf_ifnet_methods = {
214 	.bif_chkdir = bpf_ifnet_chkdir,
215 	.bif_promisc = bpf_ifnet_promisc,
216 	.bif_wrsize = bpf_ifnet_wrsize,
217 	.bif_write = bpf_ifnet_write,
218 #ifdef MAC
219 	.bif_mac_check_receive = bpf_ifnet_mac_check_receive,
220 #endif
221 };
222 
223 /*
224  * Attach an interface to bpf.  dlt is the link layer type; hdrlen is the
225  * fixed size of the link header (variable length headers not yet supported).
226  * Legacy KPI to be obsoleted soon.
227  */
228 void
229 bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen)
230 {
231 
232 	ifp->if_bpf = bpf_attach(ifp->if_xname, dlt, hdrlen,
233 	    &bpf_ifnet_methods, ifp);
234 	if_ref(ifp);
235 	if (bootverbose && IS_DEFAULT_VNET(curvnet))
236 		if_printf(ifp, "bpf attached\n");
237 }
238 
239 /*
240  * The dead_bpf_if is an ugly plug against races at ifnet destroy time that
241  * still exist and are not properly covered by epoch(9).
242  * Legacy KPI to be obsoleted soon.
243  */
244 void
245 bpfdetach(struct ifnet *ifp)
246 {
247 	static const struct bpfd_list dead_bpf_if = CK_LIST_HEAD_INITIALIZER();
248 	struct bpf_if *bif;
249 
250 	bif = ifp->if_bpf;
251 	ifp->if_bpf = __DECONST(struct bpf_if *, &dead_bpf_if);
252 	bpf_detach(bif);
253 	if_rele(ifp);
254 }
255