Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net/bpf_ifnet.c
96280 views
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 <[email protected]>
7
* Copyright (c) 2025 Gleb Smirnoff <[email protected]>
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_PFLOG */
131
case IFT_PFLOG:
132
hlen = PFLOG_HDRLEN;
133
break;
134
135
/* DLT_PFSYNC */
136
case IFT_PFSYNC:
137
hlen = PFSYNC_HDRLEN;
138
break;
139
140
default:
141
hlen = 0; /* pacify compiler */
142
KASSERT(0, ("%s: ifp %p type %u not supported", __func__,
143
ifp, ifp->if_type));
144
}
145
146
if (__predict_false(hlen > m->m_len)) {
147
m_freem(m);
148
m_freem(mc);
149
return (EMSGSIZE);
150
};
151
152
if (hlen != 0) {
153
bcopy(mtod(m, const void *), &dst.sa_data, hlen);
154
ro.ro_prepend = (char *)&dst.sa_data;
155
ro.ro_plen = hlen;
156
ro.ro_flags = RT_HAS_HEADER;
157
m->m_pkthdr.len -= hlen;
158
m->m_len -= hlen;
159
m->m_data += hlen;
160
};
161
162
CURVNET_SET(ifp->if_vnet);
163
error = ifp->if_output(ifp, m, &dst, &ro);
164
if (error != 0) {
165
m_freem(mc);
166
} else if (mc != NULL) {
167
mc->m_pkthdr.rcvif = ifp;
168
(void)ifp->if_input(ifp, mc);
169
}
170
CURVNET_RESTORE();
171
172
return (error);
173
}
174
175
static bool
176
bpf_ifnet_chkdir(void *arg, const struct mbuf *m, int dir)
177
{
178
struct ifnet *ifp = arg;
179
struct ifnet *rcvif = m_rcvif(m);
180
181
return ((dir == BPF_D_IN && ifp != rcvif) ||
182
(dir == BPF_D_OUT && ifp == rcvif));
183
}
184
185
uint32_t
186
bpf_ifnet_wrsize(void *arg)
187
{
188
struct ifnet *ifp = arg;
189
190
return (ifp->if_mtu);
191
}
192
193
int
194
bpf_ifnet_promisc(void *arg, bool on)
195
{
196
struct ifnet *ifp = arg;
197
int error;
198
199
CURVNET_SET(ifp->if_vnet);
200
if ((error = ifpromisc(ifp, on ? 1 : 0)) != 0)
201
if_printf(ifp, "%s: ifpromisc failed (%d)\n", __func__, error);
202
CURVNET_RESTORE();
203
204
return (error);
205
}
206
207
#ifdef MAC
208
static int
209
bpf_ifnet_mac_check_receive(void *arg, struct bpf_d *d)
210
{
211
struct ifnet *ifp = arg;
212
213
return (mac_bpfdesc_check_receive(d, ifp));
214
}
215
#endif
216
217
static const struct bif_methods bpf_ifnet_methods = {
218
.bif_chkdir = bpf_ifnet_chkdir,
219
.bif_promisc = bpf_ifnet_promisc,
220
.bif_wrsize = bpf_ifnet_wrsize,
221
.bif_write = bpf_ifnet_write,
222
#ifdef MAC
223
.bif_mac_check_receive = bpf_ifnet_mac_check_receive,
224
#endif
225
};
226
227
/*
228
* Attach an interface to bpf. dlt is the link layer type; hdrlen is the
229
* fixed size of the link header (variable length headers not yet supported).
230
* Legacy KPI to be obsoleted soon.
231
*/
232
void
233
bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen)
234
{
235
236
ifp->if_bpf = bpf_attach(ifp->if_xname, dlt, hdrlen,
237
&bpf_ifnet_methods, ifp);
238
if_ref(ifp);
239
if (bootverbose && IS_DEFAULT_VNET(curvnet))
240
if_printf(ifp, "bpf attached\n");
241
}
242
243
/*
244
* The dead_bpf_if is an ugly plug against races at ifnet destroy time that
245
* still exist and are not properly covered by epoch(9).
246
* Legacy KPI to be obsoleted soon.
247
*/
248
void
249
bpfdetach(struct ifnet *ifp)
250
{
251
static const struct bpfd_list dead_bpf_if = CK_LIST_HEAD_INITIALIZER();
252
struct bpf_if *bif;
253
254
bif = ifp->if_bpf;
255
ifp->if_bpf = __DECONST(struct bpf_if *, &dead_bpf_if);
256
bpf_detach(bif);
257
if_rele(ifp);
258
}
259
260