18774a990SGleb Smirnoff /*-
28774a990SGleb Smirnoff * SPDX-License-Identifier: BSD-3-Clause
38774a990SGleb Smirnoff *
48774a990SGleb Smirnoff * Copyright (c) 1990, 1991, 1993
58774a990SGleb Smirnoff * The Regents of the University of California. All rights reserved.
68774a990SGleb Smirnoff * Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org>
78774a990SGleb Smirnoff * Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
88774a990SGleb Smirnoff *
98774a990SGleb Smirnoff * This code is derived from the Stanford/CMU enet packet filter,
108774a990SGleb Smirnoff * (net/enet.c) distributed as part of 4.3BSD, and code contributed
118774a990SGleb Smirnoff * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
128774a990SGleb Smirnoff * Berkeley Laboratory.
138774a990SGleb Smirnoff *
148774a990SGleb Smirnoff * Redistribution and use in source and binary forms, with or without
158774a990SGleb Smirnoff * modification, are permitted provided that the following conditions
168774a990SGleb Smirnoff * are met:
178774a990SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright
188774a990SGleb Smirnoff * notice, this list of conditions and the following disclaimer.
198774a990SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright
208774a990SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the
218774a990SGleb Smirnoff * documentation and/or other materials provided with the distribution.
228774a990SGleb Smirnoff * 3. Neither the name of the University nor the names of its contributors
238774a990SGleb Smirnoff * may be used to endorse or promote products derived from this software
248774a990SGleb Smirnoff * without specific prior written permission.
258774a990SGleb Smirnoff *
268774a990SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
278774a990SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
288774a990SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
298774a990SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
308774a990SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
318774a990SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
328774a990SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
338774a990SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
348774a990SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
358774a990SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
368774a990SGleb Smirnoff * SUCH DAMAGE.
378774a990SGleb Smirnoff */
388774a990SGleb Smirnoff
398774a990SGleb Smirnoff #include <sys/mbuf.h>
408774a990SGleb Smirnoff #include <sys/socket.h>
418774a990SGleb Smirnoff #include <net/bpf.h>
428774a990SGleb Smirnoff #include <net/bpfdesc.h>
438774a990SGleb Smirnoff #include <net/if.h>
448774a990SGleb Smirnoff #include <net/if_var.h>
458774a990SGleb Smirnoff #include <net/if_private.h>
468774a990SGleb Smirnoff #include <net/if_types.h>
478774a990SGleb Smirnoff #include <net/route.h>
488774a990SGleb Smirnoff
498774a990SGleb Smirnoff /* We need to know all the ifnets we support. */
508774a990SGleb Smirnoff #include <net/if_dl.h>
518774a990SGleb Smirnoff #include <net/ethernet.h>
528774a990SGleb Smirnoff #include <net/firewire.h>
538774a990SGleb Smirnoff #include <net/if_pflog.h>
548774a990SGleb Smirnoff #include <net/if_pfsync.h>
558774a990SGleb Smirnoff
568774a990SGleb Smirnoff #include <security/mac/mac_framework.h>
578774a990SGleb Smirnoff
588774a990SGleb Smirnoff static int
bpf_ifnet_write(void * arg,struct mbuf * m,struct mbuf * mc,int flags)598774a990SGleb Smirnoff bpf_ifnet_write(void *arg, struct mbuf *m, struct mbuf *mc, int flags)
608774a990SGleb Smirnoff {
618774a990SGleb Smirnoff struct ifnet *ifp = arg;
628774a990SGleb Smirnoff struct route ro = {};
638774a990SGleb Smirnoff struct sockaddr dst = {
648774a990SGleb Smirnoff .sa_family = AF_UNSPEC,
658774a990SGleb Smirnoff };
668774a990SGleb Smirnoff u_int hlen;
678774a990SGleb Smirnoff int error;
688774a990SGleb Smirnoff
698774a990SGleb Smirnoff NET_EPOCH_ASSERT();
708774a990SGleb Smirnoff
718774a990SGleb Smirnoff if (__predict_false((ifp->if_flags & IFF_UP) == 0)) {
728774a990SGleb Smirnoff m_freem(m);
738774a990SGleb Smirnoff m_freem(mc);
748774a990SGleb Smirnoff return (ENETDOWN);
758774a990SGleb Smirnoff }
768774a990SGleb Smirnoff
778774a990SGleb Smirnoff switch (ifp->if_type) {
788774a990SGleb Smirnoff /* DLT_RAW */
798774a990SGleb Smirnoff case IFT_MBIM: /* umb(4) */
808774a990SGleb Smirnoff case IFT_OTHER: /* uhso(4), usie */
818774a990SGleb Smirnoff hlen = 0;
828774a990SGleb Smirnoff break;
838774a990SGleb Smirnoff
848774a990SGleb Smirnoff /* DLT_ENC */
858774a990SGleb Smirnoff case IFT_ENC:
868774a990SGleb Smirnoff hlen = 12; /* XXXGL: sizeof(struct enchdr); */
878774a990SGleb Smirnoff break;
888774a990SGleb Smirnoff
898774a990SGleb Smirnoff /* DLT_EN10MB */
908774a990SGleb Smirnoff case IFT_ETHER: /* if_ethersubr.c */
918774a990SGleb Smirnoff case IFT_L2VLAN: /* vlan(4) */
92*fe53a8a8SGleb Smirnoff case IFT_BRIDGE: /* if_bridge(4) */
938774a990SGleb Smirnoff case IFT_IEEE8023ADLAG: /* lagg(4) */
948774a990SGleb Smirnoff case IFT_INFINIBAND: /* if_infiniband.c */
958774a990SGleb Smirnoff {
968774a990SGleb Smirnoff struct ether_header *eh;
978774a990SGleb Smirnoff
988774a990SGleb Smirnoff eh = mtod(m, struct ether_header *);
998774a990SGleb Smirnoff if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
1008774a990SGleb Smirnoff if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost,
1018774a990SGleb Smirnoff ETHER_ADDR_LEN) == 0)
1028774a990SGleb Smirnoff m->m_flags |= M_BCAST;
1038774a990SGleb Smirnoff else
1048774a990SGleb Smirnoff m->m_flags |= M_MCAST;
1058774a990SGleb Smirnoff }
1068774a990SGleb Smirnoff if (!(flags & BPFD_HDRCMPLT)) {
1078774a990SGleb Smirnoff memcpy(eh->ether_shost, IF_LLADDR(ifp),
1088774a990SGleb Smirnoff sizeof(eh->ether_shost));
1098774a990SGleb Smirnoff }
1108774a990SGleb Smirnoff hlen = ETHER_HDR_LEN;
1118774a990SGleb Smirnoff break;
1128774a990SGleb Smirnoff }
1138774a990SGleb Smirnoff /* DLT_APPLE_IP_OVER_IEEE1394 */
1148774a990SGleb Smirnoff case IFT_IEEE1394: /* fwip(4) */
1158774a990SGleb Smirnoff hlen = sizeof(struct fw_hwaddr);
1168774a990SGleb Smirnoff break;
1178774a990SGleb Smirnoff
1188774a990SGleb Smirnoff /* DLT_NULL */
1198774a990SGleb Smirnoff case IFT_GIF: /* gif(4) */
1208774a990SGleb Smirnoff case IFT_LOOP: /* lo(4), disc(4) */
1218774a990SGleb Smirnoff case IFT_PARA: /* plip(4), iic */
1228774a990SGleb Smirnoff case IFT_PPP: /* tun(4) */
1238774a990SGleb Smirnoff case IFT_PROPVIRTUAL: /* ng_iface(4) */
1248774a990SGleb Smirnoff case IFT_WIREGUARD: /* wg(4) */
1258774a990SGleb Smirnoff case IFT_STF: /* stf(4) */
1268774a990SGleb Smirnoff case IFT_TUNNEL: /* ipsec(4), me(4), gre(4), ovpn(4) */
1278774a990SGleb Smirnoff hlen = sizeof(uint32_t);
1288774a990SGleb Smirnoff break;
1298774a990SGleb Smirnoff
1308774a990SGleb Smirnoff /* DLT_PFLOG */
1318774a990SGleb Smirnoff case IFT_PFLOG:
1328774a990SGleb Smirnoff hlen = PFLOG_HDRLEN;
1338774a990SGleb Smirnoff break;
1348774a990SGleb Smirnoff
1358774a990SGleb Smirnoff /* DLT_PFSYNC */
1368774a990SGleb Smirnoff case IFT_PFSYNC:
1378774a990SGleb Smirnoff hlen = PFSYNC_HDRLEN;
1388774a990SGleb Smirnoff break;
1398774a990SGleb Smirnoff
1408774a990SGleb Smirnoff default:
1418774a990SGleb Smirnoff hlen = 0; /* pacify compiler */
1428774a990SGleb Smirnoff KASSERT(0, ("%s: ifp %p type %u not supported", __func__,
1438774a990SGleb Smirnoff ifp, ifp->if_type));
1448774a990SGleb Smirnoff }
1458774a990SGleb Smirnoff
1468774a990SGleb Smirnoff if (__predict_false(hlen > m->m_len)) {
1478774a990SGleb Smirnoff m_freem(m);
1488774a990SGleb Smirnoff m_freem(mc);
1498774a990SGleb Smirnoff return (EMSGSIZE);
1508774a990SGleb Smirnoff };
1518774a990SGleb Smirnoff
1528774a990SGleb Smirnoff if (hlen != 0) {
1538774a990SGleb Smirnoff bcopy(mtod(m, const void *), &dst.sa_data, hlen);
1548774a990SGleb Smirnoff ro.ro_prepend = (char *)&dst.sa_data;
1558774a990SGleb Smirnoff ro.ro_plen = hlen;
1568774a990SGleb Smirnoff ro.ro_flags = RT_HAS_HEADER;
1578774a990SGleb Smirnoff m->m_pkthdr.len -= hlen;
1588774a990SGleb Smirnoff m->m_len -= hlen;
1598774a990SGleb Smirnoff m->m_data += hlen;
1608774a990SGleb Smirnoff };
1618774a990SGleb Smirnoff
1628774a990SGleb Smirnoff CURVNET_SET(ifp->if_vnet);
1638774a990SGleb Smirnoff error = ifp->if_output(ifp, m, &dst, &ro);
1648774a990SGleb Smirnoff if (error != 0) {
1658774a990SGleb Smirnoff m_freem(mc);
1668774a990SGleb Smirnoff } else if (mc != NULL) {
1678774a990SGleb Smirnoff mc->m_pkthdr.rcvif = ifp;
1688774a990SGleb Smirnoff (void)ifp->if_input(ifp, mc);
1698774a990SGleb Smirnoff }
1708774a990SGleb Smirnoff CURVNET_RESTORE();
1718774a990SGleb Smirnoff
1728774a990SGleb Smirnoff return (error);
1738774a990SGleb Smirnoff }
1748774a990SGleb Smirnoff
1758774a990SGleb Smirnoff static bool
bpf_ifnet_chkdir(void * arg,const struct mbuf * m,int dir)1768774a990SGleb Smirnoff bpf_ifnet_chkdir(void *arg, const struct mbuf *m, int dir)
1778774a990SGleb Smirnoff {
1788774a990SGleb Smirnoff struct ifnet *ifp = arg;
1798774a990SGleb Smirnoff struct ifnet *rcvif = m_rcvif(m);
1808774a990SGleb Smirnoff
1818774a990SGleb Smirnoff return ((dir == BPF_D_IN && ifp != rcvif) ||
1828774a990SGleb Smirnoff (dir == BPF_D_OUT && ifp == rcvif));
1838774a990SGleb Smirnoff }
1848774a990SGleb Smirnoff
1858774a990SGleb Smirnoff uint32_t
bpf_ifnet_wrsize(void * arg)1868774a990SGleb Smirnoff bpf_ifnet_wrsize(void *arg)
1878774a990SGleb Smirnoff {
1888774a990SGleb Smirnoff struct ifnet *ifp = arg;
1898774a990SGleb Smirnoff
1908774a990SGleb Smirnoff return (ifp->if_mtu);
1918774a990SGleb Smirnoff }
1928774a990SGleb Smirnoff
1938774a990SGleb Smirnoff int
bpf_ifnet_promisc(void * arg,bool on)1948774a990SGleb Smirnoff bpf_ifnet_promisc(void *arg, bool on)
1958774a990SGleb Smirnoff {
1968774a990SGleb Smirnoff struct ifnet *ifp = arg;
1978774a990SGleb Smirnoff int error;
1988774a990SGleb Smirnoff
1998774a990SGleb Smirnoff CURVNET_SET(ifp->if_vnet);
2008774a990SGleb Smirnoff if ((error = ifpromisc(ifp, on ? 1 : 0)) != 0)
2018774a990SGleb Smirnoff if_printf(ifp, "%s: ifpromisc failed (%d)\n", __func__, error);
2028774a990SGleb Smirnoff CURVNET_RESTORE();
2038774a990SGleb Smirnoff
2048774a990SGleb Smirnoff return (error);
2058774a990SGleb Smirnoff }
2068774a990SGleb Smirnoff
2078774a990SGleb Smirnoff #ifdef MAC
2088774a990SGleb Smirnoff static int
bpf_ifnet_mac_check_receive(void * arg,struct bpf_d * d)2098774a990SGleb Smirnoff bpf_ifnet_mac_check_receive(void *arg, struct bpf_d *d)
2108774a990SGleb Smirnoff {
2118774a990SGleb Smirnoff struct ifnet *ifp = arg;
2128774a990SGleb Smirnoff
2138774a990SGleb Smirnoff return (mac_bpfdesc_check_receive(d, ifp));
2148774a990SGleb Smirnoff }
2158774a990SGleb Smirnoff #endif
2168774a990SGleb Smirnoff
2178774a990SGleb Smirnoff static const struct bif_methods bpf_ifnet_methods = {
2188774a990SGleb Smirnoff .bif_chkdir = bpf_ifnet_chkdir,
2198774a990SGleb Smirnoff .bif_promisc = bpf_ifnet_promisc,
2208774a990SGleb Smirnoff .bif_wrsize = bpf_ifnet_wrsize,
2218774a990SGleb Smirnoff .bif_write = bpf_ifnet_write,
2228774a990SGleb Smirnoff #ifdef MAC
2238774a990SGleb Smirnoff .bif_mac_check_receive = bpf_ifnet_mac_check_receive,
2248774a990SGleb Smirnoff #endif
2258774a990SGleb Smirnoff };
2268774a990SGleb Smirnoff
2278774a990SGleb Smirnoff /*
2288774a990SGleb Smirnoff * Attach an interface to bpf. dlt is the link layer type; hdrlen is the
2298774a990SGleb Smirnoff * fixed size of the link header (variable length headers not yet supported).
2308774a990SGleb Smirnoff * Legacy KPI to be obsoleted soon.
2318774a990SGleb Smirnoff */
2328774a990SGleb Smirnoff void
bpfattach(struct ifnet * ifp,u_int dlt,u_int hdrlen)2338774a990SGleb Smirnoff bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen)
2348774a990SGleb Smirnoff {
2358774a990SGleb Smirnoff
2368774a990SGleb Smirnoff ifp->if_bpf = bpf_attach(ifp->if_xname, dlt, hdrlen,
2378774a990SGleb Smirnoff &bpf_ifnet_methods, ifp);
2388774a990SGleb Smirnoff if_ref(ifp);
2398774a990SGleb Smirnoff if (bootverbose && IS_DEFAULT_VNET(curvnet))
2408774a990SGleb Smirnoff if_printf(ifp, "bpf attached\n");
2418774a990SGleb Smirnoff }
2428774a990SGleb Smirnoff
2438774a990SGleb Smirnoff /*
2448774a990SGleb Smirnoff * The dead_bpf_if is an ugly plug against races at ifnet destroy time that
2458774a990SGleb Smirnoff * still exist and are not properly covered by epoch(9).
2468774a990SGleb Smirnoff * Legacy KPI to be obsoleted soon.
2478774a990SGleb Smirnoff */
2488774a990SGleb Smirnoff void
bpfdetach(struct ifnet * ifp)2498774a990SGleb Smirnoff bpfdetach(struct ifnet *ifp)
2508774a990SGleb Smirnoff {
2518774a990SGleb Smirnoff static const struct bpfd_list dead_bpf_if = CK_LIST_HEAD_INITIALIZER();
2528774a990SGleb Smirnoff struct bpf_if *bif;
2538774a990SGleb Smirnoff
2548774a990SGleb Smirnoff bif = ifp->if_bpf;
2558774a990SGleb Smirnoff ifp->if_bpf = __DECONST(struct bpf_if *, &dead_bpf_if);
2568774a990SGleb Smirnoff bpf_detach(bif);
2578774a990SGleb Smirnoff if_rele(ifp);
2588774a990SGleb Smirnoff }
259