mirror of
https://git.freebsd.org/src.git
synced 2026-01-16 23:02:24 +00:00
bpf: modularize ifnet(9) part of bpf
Imagine that bpf(9) tapping can happen at any point in the network stack, not necessarily at interface transmit or receive. To achieve that we need a thin layer of abstraction defined by struct bif_methods, that defines how generic bpf layer works with a tap point of this kind. Implement ifnet(9) specific methods in a separate file bpf_ifnet.c. At this point there is 100% compatibility for all existing interfaces, there is no KPI change, yet. The legacy attaching KPI is layered over new ifnet agnostic KPI. The new KPI may change though, as we can implement multiple DLTs per single tap point in a prettier fashion. The new abstraction layer allows us to move all the 802.11 radio injection hacks out of bpf.c into ieee80211_radiotap.c, so do that immediately as a good proof of concept. Reviewed by: bz Differential Revision: https://reviews.freebsd.org/D53872
This commit is contained in:
parent
9d56f84df5
commit
8774a990ee
6 changed files with 656 additions and 515 deletions
|
|
@ -4189,6 +4189,7 @@ net/bpf_buffer.c optional bpf
|
|||
net/bpf_jitter.c optional bpf_jitter
|
||||
net/bpf_filter.c optional bpf | netgraph_bpf
|
||||
net/bpf_zerocopy.c optional bpf
|
||||
net/bpf_ifnet.c optional bpf
|
||||
net/bridgestp.c optional bridge | if_bridge
|
||||
net/dummymbuf.c optional dummymbuf
|
||||
net/ieee8023ad_lacp.c optional lagg
|
||||
|
|
|
|||
726
sys/net/bpf.c
726
sys/net/bpf.c
File diff suppressed because it is too large
Load diff
|
|
@ -407,9 +407,14 @@ SYSCTL_DECL(_net_bpf);
|
|||
* Part of this structure is exposed to external callers to speed up
|
||||
* bpf_peers_present() calls.
|
||||
*/
|
||||
struct mbuf;
|
||||
struct bpf_if;
|
||||
struct bif_methods;
|
||||
CK_LIST_HEAD(bpfd_list, bpf_d);
|
||||
|
||||
struct bpf_if * bpf_attach(const char *, u_int, u_int,
|
||||
const struct bif_methods *, void *);
|
||||
void bpf_detach(struct bpf_if *);
|
||||
void bpf_bufheld(struct bpf_d *d);
|
||||
int bpf_validate(const struct bpf_insn *, int);
|
||||
void bpf_tap(struct bpf_if *, u_char *, u_int);
|
||||
|
|
@ -419,7 +424,6 @@ void bpf_mtap_if(struct ifnet *, struct mbuf *);
|
|||
void bpf_mtap2(struct bpf_if *, void *, u_int, struct mbuf *);
|
||||
void bpf_mtap2_if(struct ifnet *, void *, u_int, struct mbuf *);
|
||||
void bpfattach(struct ifnet *, u_int, u_int);
|
||||
void bpfattach2(struct ifnet *, u_int, u_int, struct bpf_if **);
|
||||
void bpfdetach(struct ifnet *);
|
||||
bool bpf_peers_present_if(struct ifnet *);
|
||||
#ifdef VIMAGE
|
||||
|
|
@ -444,6 +448,28 @@ bpf_peers_present(const struct bpf_if *bpf)
|
|||
bpf_mtap_if((_ifp), (_m))
|
||||
#define BPF_MTAP2(_ifp, _data, _dlen, _m) \
|
||||
bpf_mtap2_if((_ifp), (_data), (_dlen), (_m))
|
||||
|
||||
typedef void bif_attachd_t(void *);
|
||||
typedef void bif_detachd_t(void *);
|
||||
typedef bool bif_chkdir_t(void *, const struct mbuf *, int);
|
||||
typedef int bif_write_t(void *, struct mbuf *, struct mbuf *, int);
|
||||
typedef uint32_t bif_wrsize_t(void *);
|
||||
typedef int bif_promisc_t(void *, bool);
|
||||
typedef int bif_mac_check_receive_t(void *, struct bpf_d *);
|
||||
struct bif_methods {
|
||||
bif_attachd_t *bif_attachd;
|
||||
bif_detachd_t *bif_detachd;
|
||||
bif_chkdir_t *bif_chkdir;
|
||||
bif_promisc_t *bif_promisc;
|
||||
/* Writable taps shall implement the below methods. */
|
||||
bif_write_t *bif_write;
|
||||
bif_wrsize_t *bif_wrsize;
|
||||
bif_mac_check_receive_t *bif_mac_check_receive;
|
||||
};
|
||||
|
||||
/* Ifnet methods implemented in bpf_ifnet.c are shared with net80211. */
|
||||
extern bif_wrsize_t bpf_ifnet_wrsize;
|
||||
extern bif_promisc_t bpf_ifnet_promisc;
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
|
|
|
|||
257
sys/net/bpf_ifnet.c
Normal file
257
sys/net/bpf_ifnet.c
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Copyright (c) 1990, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
* Copyright (c) 2019 Andrey V. Elsukov <ae@FreeBSD.org>
|
||||
* Copyright (c) 2025 Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
*
|
||||
* This code is derived from the Stanford/CMU enet packet filter,
|
||||
* (net/enet.c) distributed as part of 4.3BSD, and code contributed
|
||||
* to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
|
||||
* Berkeley Laboratory.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net/bpfdesc.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_private.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/route.h>
|
||||
|
||||
/* We need to know all the ifnets we support. */
|
||||
#include <net/if_dl.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/firewire.h>
|
||||
#include <net/if_pflog.h>
|
||||
#include <net/if_pfsync.h>
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
static int
|
||||
bpf_ifnet_write(void *arg, struct mbuf *m, struct mbuf *mc, int flags)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
struct route ro = {};
|
||||
struct sockaddr dst = {
|
||||
.sa_family = AF_UNSPEC,
|
||||
};
|
||||
u_int hlen;
|
||||
int error;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
|
||||
if (__predict_false((ifp->if_flags & IFF_UP) == 0)) {
|
||||
m_freem(m);
|
||||
m_freem(mc);
|
||||
return (ENETDOWN);
|
||||
}
|
||||
|
||||
switch (ifp->if_type) {
|
||||
/* DLT_RAW */
|
||||
case IFT_MBIM: /* umb(4) */
|
||||
case IFT_OTHER: /* uhso(4), usie */
|
||||
hlen = 0;
|
||||
break;
|
||||
|
||||
/* DLT_ENC */
|
||||
case IFT_ENC:
|
||||
hlen = 12; /* XXXGL: sizeof(struct enchdr); */
|
||||
break;
|
||||
|
||||
/* DLT_EN10MB */
|
||||
case IFT_ETHER: /* if_ethersubr.c */
|
||||
case IFT_L2VLAN: /* vlan(4) */
|
||||
case IFT_IEEE8023ADLAG: /* lagg(4) */
|
||||
case IFT_INFINIBAND: /* if_infiniband.c */
|
||||
{
|
||||
struct ether_header *eh;
|
||||
|
||||
eh = mtod(m, struct ether_header *);
|
||||
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
|
||||
if (bcmp(ifp->if_broadcastaddr, eh->ether_dhost,
|
||||
ETHER_ADDR_LEN) == 0)
|
||||
m->m_flags |= M_BCAST;
|
||||
else
|
||||
m->m_flags |= M_MCAST;
|
||||
}
|
||||
if (!(flags & BPFD_HDRCMPLT)) {
|
||||
memcpy(eh->ether_shost, IF_LLADDR(ifp),
|
||||
sizeof(eh->ether_shost));
|
||||
}
|
||||
hlen = ETHER_HDR_LEN;
|
||||
break;
|
||||
}
|
||||
/* DLT_APPLE_IP_OVER_IEEE1394 */
|
||||
case IFT_IEEE1394: /* fwip(4) */
|
||||
hlen = sizeof(struct fw_hwaddr);
|
||||
break;
|
||||
|
||||
/* DLT_NULL */
|
||||
case IFT_GIF: /* gif(4) */
|
||||
case IFT_LOOP: /* lo(4), disc(4) */
|
||||
case IFT_PARA: /* plip(4), iic */
|
||||
case IFT_PPP: /* tun(4) */
|
||||
case IFT_PROPVIRTUAL: /* ng_iface(4) */
|
||||
case IFT_WIREGUARD: /* wg(4) */
|
||||
case IFT_STF: /* stf(4) */
|
||||
case IFT_TUNNEL: /* ipsec(4), me(4), gre(4), ovpn(4) */
|
||||
hlen = sizeof(uint32_t);
|
||||
break;
|
||||
|
||||
/* DLT_PFLOG */
|
||||
case IFT_PFLOG:
|
||||
hlen = PFLOG_HDRLEN;
|
||||
break;
|
||||
|
||||
/* DLT_PFSYNC */
|
||||
case IFT_PFSYNC:
|
||||
hlen = PFSYNC_HDRLEN;
|
||||
break;
|
||||
|
||||
default:
|
||||
hlen = 0; /* pacify compiler */
|
||||
KASSERT(0, ("%s: ifp %p type %u not supported", __func__,
|
||||
ifp, ifp->if_type));
|
||||
}
|
||||
|
||||
if (__predict_false(hlen > m->m_len)) {
|
||||
m_freem(m);
|
||||
m_freem(mc);
|
||||
return (EMSGSIZE);
|
||||
};
|
||||
|
||||
if (hlen != 0) {
|
||||
bcopy(mtod(m, const void *), &dst.sa_data, hlen);
|
||||
ro.ro_prepend = (char *)&dst.sa_data;
|
||||
ro.ro_plen = hlen;
|
||||
ro.ro_flags = RT_HAS_HEADER;
|
||||
m->m_pkthdr.len -= hlen;
|
||||
m->m_len -= hlen;
|
||||
m->m_data += hlen;
|
||||
};
|
||||
|
||||
CURVNET_SET(ifp->if_vnet);
|
||||
error = ifp->if_output(ifp, m, &dst, &ro);
|
||||
if (error != 0) {
|
||||
m_freem(mc);
|
||||
} else if (mc != NULL) {
|
||||
mc->m_pkthdr.rcvif = ifp;
|
||||
(void)ifp->if_input(ifp, mc);
|
||||
}
|
||||
CURVNET_RESTORE();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static bool
|
||||
bpf_ifnet_chkdir(void *arg, const struct mbuf *m, int dir)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
struct ifnet *rcvif = m_rcvif(m);
|
||||
|
||||
return ((dir == BPF_D_IN && ifp != rcvif) ||
|
||||
(dir == BPF_D_OUT && ifp == rcvif));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
bpf_ifnet_wrsize(void *arg)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
|
||||
return (ifp->if_mtu);
|
||||
}
|
||||
|
||||
int
|
||||
bpf_ifnet_promisc(void *arg, bool on)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
int error;
|
||||
|
||||
CURVNET_SET(ifp->if_vnet);
|
||||
if ((error = ifpromisc(ifp, on ? 1 : 0)) != 0)
|
||||
if_printf(ifp, "%s: ifpromisc failed (%d)\n", __func__, error);
|
||||
CURVNET_RESTORE();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef MAC
|
||||
static int
|
||||
bpf_ifnet_mac_check_receive(void *arg, struct bpf_d *d)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
|
||||
return (mac_bpfdesc_check_receive(d, ifp));
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct bif_methods bpf_ifnet_methods = {
|
||||
.bif_chkdir = bpf_ifnet_chkdir,
|
||||
.bif_promisc = bpf_ifnet_promisc,
|
||||
.bif_wrsize = bpf_ifnet_wrsize,
|
||||
.bif_write = bpf_ifnet_write,
|
||||
#ifdef MAC
|
||||
.bif_mac_check_receive = bpf_ifnet_mac_check_receive,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Attach an interface to bpf. dlt is the link layer type; hdrlen is the
|
||||
* fixed size of the link header (variable length headers not yet supported).
|
||||
* Legacy KPI to be obsoleted soon.
|
||||
*/
|
||||
void
|
||||
bpfattach(struct ifnet *ifp, u_int dlt, u_int hdrlen)
|
||||
{
|
||||
|
||||
ifp->if_bpf = bpf_attach(ifp->if_xname, dlt, hdrlen,
|
||||
&bpf_ifnet_methods, ifp);
|
||||
if_ref(ifp);
|
||||
if (bootverbose && IS_DEFAULT_VNET(curvnet))
|
||||
if_printf(ifp, "bpf attached\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* The dead_bpf_if is an ugly plug against races at ifnet destroy time that
|
||||
* still exist and are not properly covered by epoch(9).
|
||||
* Legacy KPI to be obsoleted soon.
|
||||
*/
|
||||
void
|
||||
bpfdetach(struct ifnet *ifp)
|
||||
{
|
||||
static const struct bpfd_list dead_bpf_if = CK_LIST_HEAD_INITIALIZER();
|
||||
struct bpf_if *bif;
|
||||
|
||||
bif = ifp->if_bpf;
|
||||
ifp->if_bpf = __DECONST(struct bpf_if *, &dead_bpf_if);
|
||||
bpf_detach(bif);
|
||||
if_rele(ifp);
|
||||
}
|
||||
|
|
@ -1088,35 +1088,7 @@ ieee80211_load_module(const char *modname)
|
|||
#endif
|
||||
}
|
||||
|
||||
static eventhandler_tag wlan_bpfevent;
|
||||
static eventhandler_tag wlan_ifllevent;
|
||||
|
||||
static void
|
||||
bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
|
||||
{
|
||||
/* NB: identify vap's by if_init */
|
||||
if (dlt == DLT_IEEE802_11_RADIO &&
|
||||
ifp->if_init == ieee80211_init) {
|
||||
struct ieee80211vap *vap = ifp->if_softc;
|
||||
/*
|
||||
* Track bpf radiotap listener state. We mark the vap
|
||||
* to indicate if any listener is present and the com
|
||||
* to indicate if any listener exists on any associated
|
||||
* vap. This flag is used by drivers to prepare radiotap
|
||||
* state only when needed.
|
||||
*/
|
||||
if (attach) {
|
||||
ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
atomic_add_int(&vap->iv_ic->ic_montaps, 1);
|
||||
} else if (!bpf_peers_present(vap->iv_rawbpf)) {
|
||||
ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Change MAC address on the vap (if was not started).
|
||||
*/
|
||||
|
|
@ -1385,8 +1357,6 @@ wlan_modevent(module_t mod, int type, void *unused)
|
|||
case MOD_LOAD:
|
||||
if (bootverbose)
|
||||
printf("wlan: <802.11 Link Layer>\n");
|
||||
wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
|
||||
bpf_track, 0, EVENTHANDLER_PRI_ANY);
|
||||
wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
|
||||
wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
|
||||
struct if_clone_addreq req = {
|
||||
|
|
@ -1398,7 +1368,6 @@ wlan_modevent(module_t mod, int type, void *unused)
|
|||
return 0;
|
||||
case MOD_UNLOAD:
|
||||
ifc_detach_cloner(wlan_cloner);
|
||||
EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
|
||||
EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,8 +43,10 @@
|
|||
#include <net/bpf.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_private.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include <net80211/ieee80211_var.h>
|
||||
|
||||
|
|
@ -108,20 +110,6 @@ ieee80211_radiotap_detach(struct ieee80211com *ic)
|
|||
{
|
||||
}
|
||||
|
||||
void
|
||||
ieee80211_radiotap_vattach(struct ieee80211vap *vap)
|
||||
{
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
struct ieee80211_radiotap_header *th = ic->ic_th;
|
||||
|
||||
if (th != NULL && ic->ic_rh != NULL) {
|
||||
/* radiotap DLT for raw 802.11 frames */
|
||||
bpfattach2(vap->iv_ifp, DLT_IEEE802_11_RADIO,
|
||||
sizeof(struct ieee80211_frame) + le16toh(th->it_len),
|
||||
&vap->iv_rawbpf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ieee80211_radiotap_vdetach(struct ieee80211vap *vap)
|
||||
{
|
||||
|
|
@ -372,3 +360,115 @@ radiotap_offset(struct ieee80211_radiotap_header *rh,
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool
|
||||
bpf_ieee80211_chkdir(void *arg, const struct mbuf *m, int dir)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
struct ifnet *rcvif = m_rcvif(m);
|
||||
|
||||
return ((dir == BPF_D_IN && ifp != rcvif) ||
|
||||
(dir == BPF_D_OUT && ifp == rcvif));
|
||||
}
|
||||
|
||||
static void
|
||||
bpf_ieee80211_attach(void *sc)
|
||||
{
|
||||
struct ieee80211vap *vap = if_getsoftc((if_t)sc);
|
||||
|
||||
/*
|
||||
* Track bpf radiotap listener state. We mark the vap
|
||||
* to indicate if any listener is present and the com
|
||||
* to indicate if any listener exists on any associated
|
||||
* vap. This flag is used by drivers to prepare radiotap
|
||||
* state only when needed.
|
||||
*/
|
||||
ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
atomic_add_int(&vap->iv_ic->ic_montaps, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
bpf_ieee80211_detach(void *sc)
|
||||
{
|
||||
struct ieee80211vap *vap = if_getsoftc((if_t)sc);
|
||||
|
||||
if (!bpf_peers_present(vap->iv_rawbpf)) {
|
||||
ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
|
||||
if (vap->iv_opmode == IEEE80211_M_MONITOR)
|
||||
atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bpf_ieee80211_write(void *arg, struct mbuf *m, struct mbuf *mc, int flags)
|
||||
{
|
||||
struct ifnet *ifp = arg;
|
||||
struct sockaddr dst = {
|
||||
.sa_family = AF_IEEE80211,
|
||||
/* XXXGL: value and XXX comment from 246b5467621a */
|
||||
.sa_len = 12, /* XXX != 0 */
|
||||
};
|
||||
struct route ro = {
|
||||
.ro_prepend = (char *)&dst.sa_data,
|
||||
.ro_flags = RT_HAS_HEADER,
|
||||
};
|
||||
const struct ieee80211_bpf_params *p;
|
||||
u_int hlen;
|
||||
int error;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
|
||||
/*
|
||||
* Collect true length from the parameter header.
|
||||
* XXX check ibp_vers
|
||||
*/
|
||||
p = mtod(m, const struct ieee80211_bpf_params *);
|
||||
if (p->ibp_len > sizeof(dst.sa_data)) {
|
||||
m_freem(m);
|
||||
m_freem(mc);
|
||||
return (EMSGSIZE);
|
||||
}
|
||||
hlen = ro.ro_plen = p->ibp_len;
|
||||
bcopy(mtod(m, const void *), &dst.sa_data, hlen);
|
||||
m->m_pkthdr.len -= hlen;
|
||||
m->m_len -= hlen;
|
||||
m->m_data += hlen;
|
||||
|
||||
CURVNET_SET(ifp->if_vnet);
|
||||
error = ifp->if_output(ifp, m, &dst, &ro);
|
||||
if (error != 0) {
|
||||
m_freem(mc);
|
||||
} else if (mc != NULL) {
|
||||
mc->m_pkthdr.rcvif = ifp;
|
||||
(void)ifp->if_input(ifp, mc);
|
||||
}
|
||||
CURVNET_RESTORE();
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static const struct bif_methods bpf_ieee80211_methods = {
|
||||
.bif_chkdir = bpf_ieee80211_chkdir,
|
||||
.bif_attachd = bpf_ieee80211_attach,
|
||||
.bif_detachd = bpf_ieee80211_detach,
|
||||
.bif_promisc = bpf_ifnet_promisc,
|
||||
.bif_wrsize = bpf_ifnet_wrsize,
|
||||
.bif_write = bpf_ieee80211_write,
|
||||
};
|
||||
|
||||
void
|
||||
ieee80211_radiotap_vattach(struct ieee80211vap *vap)
|
||||
{
|
||||
struct ieee80211com *ic = vap->iv_ic;
|
||||
struct ieee80211_radiotap_header *th = ic->ic_th;
|
||||
|
||||
if (th != NULL && ic->ic_rh != NULL) {
|
||||
/* radiotap DLT for raw 802.11 frames */
|
||||
vap->iv_rawbpf = bpf_attach(if_name(vap->iv_ifp),
|
||||
DLT_IEEE802_11_RADIO,
|
||||
sizeof(struct ieee80211_frame) + le16toh(th->it_len),
|
||||
&bpf_ieee80211_methods, vap->iv_ifp);
|
||||
if_ref(vap->iv_ifp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue