/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1990, 1991, 19934* The Regents of the University of California. All rights reserved.5* Copyright (c) 2019 Andrey V. Elsukov <[email protected]>6* Copyright (c) 2025 Gleb Smirnoff <[email protected]>7*8* This code is derived from the Stanford/CMU enet packet filter,9* (net/enet.c) distributed as part of 4.3BSD, and code contributed10* to Berkeley by Steven McCanne and Van Jacobson both of Lawrence11* Berkeley Laboratory.12*13* Redistribution and use in source and binary forms, with or without14* modification, are permitted provided that the following conditions15* are met:16* 1. Redistributions of source code must retain the above copyright17* notice, this list of conditions and the following disclaimer.18* 2. Redistributions in binary form must reproduce the above copyright19* notice, this list of conditions and the following disclaimer in the20* documentation and/or other materials provided with the distribution.21* 3. Neither the name of the University nor the names of its contributors22* may be used to endorse or promote products derived from this software23* without specific prior written permission.24*25* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND26* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE27* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE28* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE29* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL30* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS31* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)32* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT33* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY34* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF35* SUCH DAMAGE.36*/3738#include <sys/mbuf.h>39#include <sys/socket.h>40#include <net/bpf.h>41#include <net/bpfdesc.h>42#include <net/if.h>43#include <net/if_var.h>44#include <net/if_private.h>45#include <net/if_types.h>46#include <net/route.h>4748/* We need to know all the ifnets we support. */49#include <net/if_dl.h>50#include <net/ethernet.h>51#include <net/firewire.h>52#include <net/if_pflog.h>53#include <net/if_pfsync.h>5455#include <security/mac/mac_framework.h>5657static int58bpf_ifnet_write(void *arg, struct mbuf *m, struct mbuf *mc, int flags)59{60struct ifnet *ifp = arg;61struct route ro = {};62struct sockaddr dst = {63.sa_family = AF_UNSPEC,64};65u_int hlen;66int error;6768NET_EPOCH_ASSERT();6970if (__predict_false((ifp->if_flags & IFF_UP) == 0)) {71m_freem(m);72m_freem(mc);73return (ENETDOWN);74}7576switch (ifp->if_type) {77/* DLT_RAW */78case IFT_MBIM: /* umb(4) */79case IFT_OTHER: /* uhso(4), usie */80hlen = 0;81break;8283/* DLT_ENC */84case IFT_ENC:85hlen = 12; /* XXXGL: sizeof(struct enchdr); */86break;8788/* DLT_EN10MB */89case IFT_ETHER: /* if_ethersubr.c */90case IFT_L2VLAN: /* vlan(4) */91case IFT_BRIDGE: /* if_bridge(4) */92case IFT_IEEE8023ADLAG: /* lagg(4) */93case IFT_INFINIBAND: /* if_infiniband.c */94{95struct ether_header *eh;9697eh = mtod(m, struct ether_header *);98if (ETHER_IS_MULTICAST(eh->ether_dhost)) {99if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost,100ETHER_ADDR_LEN) == 0)101m->m_flags |= M_BCAST;102else103m->m_flags |= M_MCAST;104}105if (!(flags & BPFD_HDRCMPLT)) {106memcpy(eh->ether_shost, IF_LLADDR(ifp),107sizeof(eh->ether_shost));108}109hlen = ETHER_HDR_LEN;110break;111}112/* DLT_APPLE_IP_OVER_IEEE1394 */113case IFT_IEEE1394: /* fwip(4) */114hlen = sizeof(struct fw_hwaddr);115break;116117/* DLT_NULL */118case IFT_GIF: /* gif(4) */119case IFT_LOOP: /* lo(4), disc(4) */120case IFT_PARA: /* plip(4), iic */121case IFT_PPP: /* tun(4) */122case IFT_PROPVIRTUAL: /* ng_iface(4) */123case IFT_WIREGUARD: /* wg(4) */124case IFT_STF: /* stf(4) */125case IFT_TUNNEL: /* ipsec(4), me(4), gre(4), ovpn(4) */126hlen = sizeof(uint32_t);127break;128129/* DLT_PFLOG */130case IFT_PFLOG:131hlen = PFLOG_HDRLEN;132break;133134/* DLT_PFSYNC */135case IFT_PFSYNC:136hlen = PFSYNC_HDRLEN;137break;138139default:140hlen = 0; /* pacify compiler */141KASSERT(0, ("%s: ifp %p type %u not supported", __func__,142ifp, ifp->if_type));143}144145if (__predict_false(hlen > m->m_len)) {146m_freem(m);147m_freem(mc);148return (EMSGSIZE);149};150151if (hlen != 0) {152bcopy(mtod(m, const void *), &dst.sa_data, hlen);153ro.ro_prepend = (char *)&dst.sa_data;154ro.ro_plen = hlen;155ro.ro_flags = RT_HAS_HEADER;156m->m_pkthdr.len -= hlen;157m->m_len -= hlen;158m->m_data += hlen;159};160161CURVNET_SET(ifp->if_vnet);162error = ifp->if_output(ifp, m, &dst, &ro);163if (error != 0) {164m_freem(mc);165} else if (mc != NULL) {166mc->m_pkthdr.rcvif = ifp;167(void)ifp->if_input(ifp, mc);168}169CURVNET_RESTORE();170171return (error);172}173174static bool175bpf_ifnet_chkdir(void *arg, const struct mbuf *m, int dir)176{177struct ifnet *ifp = arg;178struct ifnet *rcvif = m_rcvif(m);179180return ((dir == BPF_D_IN && ifp != rcvif) ||181(dir == BPF_D_OUT && ifp == rcvif));182}183184uint32_t185bpf_ifnet_wrsize(void *arg)186{187struct ifnet *ifp = arg;188189return (ifp->if_mtu);190}191192int193bpf_ifnet_promisc(void *arg, bool on)194{195struct ifnet *ifp = arg;196int error;197198CURVNET_SET(ifp->if_vnet);199if ((error = ifpromisc(ifp, on ? 1 : 0)) != 0)200if_printf(ifp, "%s: ifpromisc failed (%d)\n", __func__, error);201CURVNET_RESTORE();202203return (error);204}205206#ifdef MAC207static int208bpf_ifnet_mac_check_receive(void *arg, struct bpf_d *d)209{210struct ifnet *ifp = arg;211212return (mac_bpfdesc_check_receive(d, ifp));213}214#endif215216static const struct bif_methods bpf_ifnet_methods = {217.bif_chkdir = bpf_ifnet_chkdir,218.bif_promisc = bpf_ifnet_promisc,219.bif_wrsize = bpf_ifnet_wrsize,220.bif_write = bpf_ifnet_write,221#ifdef MAC222.bif_mac_check_receive = bpf_ifnet_mac_check_receive,223#endif224};225226/*227* Attach an interface to bpf. dlt is the link layer type; hdrlen is the228* fixed size of the link header (variable length headers not yet supported).229* Legacy KPI to be obsoleted soon.230*/231void232bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen)233{234235ifp->if_bpf = bpf_attach(ifp->if_xname, dlt, hdrlen,236&bpf_ifnet_methods, ifp);237if_ref(ifp);238if (bootverbose && IS_DEFAULT_VNET(curvnet))239if_printf(ifp, "bpf attached\n");240}241242/*243* The dead_bpf_if is an ugly plug against races at ifnet destroy time that244* still exist and are not properly covered by epoch(9).245* Legacy KPI to be obsoleted soon.246*/247void248bpfdetach(struct ifnet *ifp)249{250static const struct bpfd_list dead_bpf_if = CK_LIST_HEAD_INITIALIZER();251struct bpf_if *bif;252253bif = ifp->if_bpf;254ifp->if_bpf = __DECONST(struct bpf_if *, &dead_bpf_if);255bpf_detach(bif);256if_rele(ifp);257}258259260