Fix panic on attaching to non-existent interface (introduced by r233937, pointed by hrs@)
Fix panic on tcpdump being attached to interface being removed (introduced by r233937, pointed by hrs@ and adrian@) Protect most of bpf_setf() by BPF global lock Add several forgotten assertions (thanks to adrian@) Document current locking model inside bpf.c Document EVENTHANDLER(9) usage inside BPF. Approved by: kib(mentor) Tested by: gnn MFC in: 4 weeks
This commit is contained in:
parent
fed7420ced
commit
6c74ff0ea6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=235744
@ -23,7 +23,7 @@
|
|||||||
.\" SUCH DAMAGE.
|
.\" SUCH DAMAGE.
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd January 7, 2005
|
.Dd May 11, 2012
|
||||||
.Dt EVENTHANDLER 9
|
.Dt EVENTHANDLER 9
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -197,6 +197,8 @@ Callbacks invoked when an interface is cloned.
|
|||||||
Callbacks invoked when a new network interface appears.
|
Callbacks invoked when a new network interface appears.
|
||||||
.It Vt ifnet_departure_event
|
.It Vt ifnet_departure_event
|
||||||
Callbacks invoked when a network interface is taken down.
|
Callbacks invoked when a network interface is taken down.
|
||||||
|
.It Vt bpf_track
|
||||||
|
Callbacks invoked when a BPF listener attaches to/detaches from network interface.
|
||||||
.It Vt power_profile_change
|
.It Vt power_profile_change
|
||||||
Callbacks invoked when the power profile of the system changes.
|
Callbacks invoked when the power profile of the system changes.
|
||||||
.It Vt process_exec
|
.It Vt process_exec
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd December 13, 2006
|
.Dd May 11, 2012
|
||||||
.Dt BPF 9
|
.Dt BPF 9
|
||||||
.Os
|
.Os
|
||||||
.\"
|
.\"
|
||||||
@ -246,9 +246,31 @@ The
|
|||||||
function
|
function
|
||||||
returns 0 when the program is not a valid filter program.
|
returns 0 when the program is not a valid filter program.
|
||||||
.\"
|
.\"
|
||||||
|
.Sh EVENT HANDLERS
|
||||||
|
.Nm
|
||||||
|
invokes
|
||||||
|
.Fa bpf_track
|
||||||
|
.Xr EVENTHANDLER 9
|
||||||
|
event each time listener attaches to or detaches from an interface.
|
||||||
|
Pointer to
|
||||||
|
.Pq Vt "struct ifnet *"
|
||||||
|
is passed as the first argument, interface
|
||||||
|
.Fa dlt
|
||||||
|
follows. Last argument indicates listener is attached (1) or
|
||||||
|
detached (0).
|
||||||
|
Note that handler is invoked with
|
||||||
|
.Nm
|
||||||
|
global lock held, which implies restriction on sleeping and calling
|
||||||
|
.Nm
|
||||||
|
subsystem inside
|
||||||
|
.Xr EVENTHANDLER 9
|
||||||
|
dispatcher.
|
||||||
|
Note that handler is not called for write-only listeners.
|
||||||
|
.\"
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr tcpdump 1 ,
|
.Xr tcpdump 1 ,
|
||||||
.Xr bpf 4
|
.Xr bpf 4 ,
|
||||||
|
.Xr EVENTHANDLER 9
|
||||||
.\"
|
.\"
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The Enet packet filter was created in 1980 by Mike Accetta and
|
The Enet packet filter was created in 1980 by Mike Accetta and
|
||||||
|
178
sys/net/bpf.c
178
sys/net/bpf.c
@ -147,6 +147,7 @@ static int bpf_bpfd_cnt;
|
|||||||
|
|
||||||
static void bpf_attachd(struct bpf_d *, struct bpf_if *);
|
static void bpf_attachd(struct bpf_d *, struct bpf_if *);
|
||||||
static void bpf_detachd(struct bpf_d *);
|
static void bpf_detachd(struct bpf_d *);
|
||||||
|
static void bpf_detachd_locked(struct bpf_d *);
|
||||||
static void bpf_freed(struct bpf_d *);
|
static void bpf_freed(struct bpf_d *);
|
||||||
static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **,
|
static int bpf_movein(struct uio *, int, struct ifnet *, struct mbuf **,
|
||||||
struct sockaddr *, int *, struct bpf_insn *);
|
struct sockaddr *, int *, struct bpf_insn *);
|
||||||
@ -206,6 +207,35 @@ static struct filterops bpfread_filtops = {
|
|||||||
.f_event = filt_bpfread,
|
.f_event = filt_bpfread,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LOCKING MODEL USED BY BPF:
|
||||||
|
* Locks:
|
||||||
|
* 1) global lock (BPF_LOCK). Mutex, used to protect interface addition/removal,
|
||||||
|
* some global counters and every bpf_if reference.
|
||||||
|
* 2) Interface lock. Rwlock, used to protect list of BPF descriptors and their filters.
|
||||||
|
* 3) Descriptor lock. Rwlock, used to protect BPF buffers and various structure fields
|
||||||
|
* used by bpf_mtap code.
|
||||||
|
*
|
||||||
|
* Lock order:
|
||||||
|
*
|
||||||
|
* Global lock, interface lock, descriptor lock
|
||||||
|
*
|
||||||
|
* We have to acquire interface lock before descriptor main lock due to BPF_MTAP[2]
|
||||||
|
* working model. In many places (like bpf_detachd) we start with BPF descriptor
|
||||||
|
* (and we need to at least rlock it to get reliable interface pointer). This
|
||||||
|
* gives us potential LOR. As a result, we use global lock to protect from bpf_if
|
||||||
|
* change in every such place.
|
||||||
|
*
|
||||||
|
* Changing d->bd_bif is protected by 1) global lock, 2) interface lock and
|
||||||
|
* 3) descriptor main wlock.
|
||||||
|
* Reading bd_bif can be protected by any of these locks, typically global lock.
|
||||||
|
*
|
||||||
|
* Changing read/write BPF filter is protected by the same three locks,
|
||||||
|
* the same applies for reading.
|
||||||
|
*
|
||||||
|
* Sleeping in global lock is not allowed due to bpfdetach() using it.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper functions for various buffering methods. If the set of buffer
|
* Wrapper functions for various buffering methods. If the set of buffer
|
||||||
* modes expands, we will probably want to introduce a switch data structure
|
* modes expands, we will probably want to introduce a switch data structure
|
||||||
@ -577,6 +607,18 @@ bpf_movein(struct uio *uio, int linktype, struct ifnet *ifp, struct mbuf **mp,
|
|||||||
static void
|
static void
|
||||||
bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
|
bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
|
||||||
{
|
{
|
||||||
|
int op_w;
|
||||||
|
|
||||||
|
BPF_LOCK_ASSERT();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save sysctl value to protect from sysctl change
|
||||||
|
* between reads
|
||||||
|
*/
|
||||||
|
op_w = V_bpf_optimize_writers;
|
||||||
|
|
||||||
|
if (d->bd_bif != NULL)
|
||||||
|
bpf_detachd_locked(d);
|
||||||
/*
|
/*
|
||||||
* Point d at bp, and add d to the interface's list.
|
* Point d at bp, and add d to the interface's list.
|
||||||
* Since there are many applicaiotns using BPF for
|
* Since there are many applicaiotns using BPF for
|
||||||
@ -584,11 +626,13 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
|
|||||||
* we can delay adding d to the list of active listeners until
|
* we can delay adding d to the list of active listeners until
|
||||||
* some filter is configured.
|
* some filter is configured.
|
||||||
*/
|
*/
|
||||||
d->bd_bif = bp;
|
|
||||||
|
|
||||||
BPFIF_WLOCK(bp);
|
BPFIF_WLOCK(bp);
|
||||||
|
BPFD_WLOCK(d);
|
||||||
|
|
||||||
if (V_bpf_optimize_writers != 0) {
|
d->bd_bif = bp;
|
||||||
|
|
||||||
|
if (op_w != 0) {
|
||||||
/* Add to writers-only list */
|
/* Add to writers-only list */
|
||||||
LIST_INSERT_HEAD(&bp->bif_wlist, d, bd_next);
|
LIST_INSERT_HEAD(&bp->bif_wlist, d, bd_next);
|
||||||
/*
|
/*
|
||||||
@ -600,16 +644,15 @@ bpf_attachd(struct bpf_d *d, struct bpf_if *bp)
|
|||||||
} else
|
} else
|
||||||
LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next);
|
LIST_INSERT_HEAD(&bp->bif_dlist, d, bd_next);
|
||||||
|
|
||||||
|
BPFD_WUNLOCK(d);
|
||||||
BPFIF_WUNLOCK(bp);
|
BPFIF_WUNLOCK(bp);
|
||||||
|
|
||||||
BPF_LOCK();
|
|
||||||
bpf_bpfd_cnt++;
|
bpf_bpfd_cnt++;
|
||||||
BPF_UNLOCK();
|
|
||||||
|
|
||||||
CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list",
|
CTR3(KTR_NET, "%s: bpf_attach called by pid %d, adding to %s list",
|
||||||
__func__, d->bd_pid, d->bd_writer ? "writer" : "active");
|
__func__, d->bd_pid, d->bd_writer ? "writer" : "active");
|
||||||
|
|
||||||
if (V_bpf_optimize_writers == 0)
|
if (op_w == 0)
|
||||||
EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1);
|
EVENTHANDLER_INVOKE(bpf_track, bp->bif_ifp, bp->bif_dlt, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -622,8 +665,21 @@ bpf_upgraded(struct bpf_d *d)
|
|||||||
{
|
{
|
||||||
struct bpf_if *bp;
|
struct bpf_if *bp;
|
||||||
|
|
||||||
|
BPF_LOCK_ASSERT();
|
||||||
|
|
||||||
bp = d->bd_bif;
|
bp = d->bd_bif;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Filter can be set several times without specifying interface.
|
||||||
|
* Mark d as reader and exit.
|
||||||
|
*/
|
||||||
|
if (bp == NULL) {
|
||||||
|
BPFD_WLOCK(d);
|
||||||
|
d->bd_writer = 0;
|
||||||
|
BPFD_WUNLOCK(d);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
BPFIF_WLOCK(bp);
|
BPFIF_WLOCK(bp);
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
|
|
||||||
@ -646,6 +702,14 @@ bpf_upgraded(struct bpf_d *d)
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
bpf_detachd(struct bpf_d *d)
|
bpf_detachd(struct bpf_d *d)
|
||||||
|
{
|
||||||
|
BPF_LOCK();
|
||||||
|
bpf_detachd_locked(d);
|
||||||
|
BPF_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bpf_detachd_locked(struct bpf_d *d)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
struct bpf_if *bp;
|
struct bpf_if *bp;
|
||||||
@ -655,7 +719,10 @@ bpf_detachd(struct bpf_d *d)
|
|||||||
|
|
||||||
BPF_LOCK_ASSERT();
|
BPF_LOCK_ASSERT();
|
||||||
|
|
||||||
bp = d->bd_bif;
|
/* Check if descriptor is attached */
|
||||||
|
if ((bp = d->bd_bif) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
BPFIF_WLOCK(bp);
|
BPFIF_WLOCK(bp);
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
|
|
||||||
@ -672,7 +739,6 @@ bpf_detachd(struct bpf_d *d)
|
|||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
BPFIF_WUNLOCK(bp);
|
BPFIF_WUNLOCK(bp);
|
||||||
|
|
||||||
/* We're already protected by global lock. */
|
|
||||||
bpf_bpfd_cnt--;
|
bpf_bpfd_cnt--;
|
||||||
|
|
||||||
/* Call event handler iff d is attached */
|
/* Call event handler iff d is attached */
|
||||||
@ -716,10 +782,7 @@ bpf_dtor(void *data)
|
|||||||
d->bd_state = BPF_IDLE;
|
d->bd_state = BPF_IDLE;
|
||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
funsetown(&d->bd_sigio);
|
funsetown(&d->bd_sigio);
|
||||||
BPF_LOCK();
|
bpf_detachd(d);
|
||||||
if (d->bd_bif)
|
|
||||||
bpf_detachd(d);
|
|
||||||
BPF_UNLOCK();
|
|
||||||
#ifdef MAC
|
#ifdef MAC
|
||||||
mac_bpfdesc_destroy(d);
|
mac_bpfdesc_destroy(d);
|
||||||
#endif /* MAC */
|
#endif /* MAC */
|
||||||
@ -959,6 +1022,7 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
|
|||||||
|
|
||||||
BPF_PID_REFRESH_CUR(d);
|
BPF_PID_REFRESH_CUR(d);
|
||||||
d->bd_wcount++;
|
d->bd_wcount++;
|
||||||
|
/* XXX: locking required */
|
||||||
if (d->bd_bif == NULL) {
|
if (d->bd_bif == NULL) {
|
||||||
d->bd_wdcount++;
|
d->bd_wdcount++;
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
@ -979,6 +1043,7 @@ bpfwrite(struct cdev *dev, struct uio *uio, int ioflag)
|
|||||||
bzero(&dst, sizeof(dst));
|
bzero(&dst, sizeof(dst));
|
||||||
m = NULL;
|
m = NULL;
|
||||||
hlen = 0;
|
hlen = 0;
|
||||||
|
/* XXX: bpf_movein() can sleep */
|
||||||
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp,
|
error = bpf_movein(uio, (int)d->bd_bif->bif_dlt, ifp,
|
||||||
&m, &dst, &hlen, d->bd_wfilter);
|
&m, &dst, &hlen, d->bd_wfilter);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -1298,10 +1363,12 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
|||||||
* Set data link type.
|
* Set data link type.
|
||||||
*/
|
*/
|
||||||
case BIOCSDLT:
|
case BIOCSDLT:
|
||||||
|
BPF_LOCK();
|
||||||
if (d->bd_bif == NULL)
|
if (d->bd_bif == NULL)
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
else
|
else
|
||||||
error = bpf_setdlt(d, *(u_int *)addr);
|
error = bpf_setdlt(d, *(u_int *)addr);
|
||||||
|
BPF_UNLOCK();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1323,7 +1390,9 @@ bpfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
|
|||||||
* Set interface.
|
* Set interface.
|
||||||
*/
|
*/
|
||||||
case BIOCSETIF:
|
case BIOCSETIF:
|
||||||
|
BPF_LOCK();
|
||||||
error = bpf_setif(d, (struct ifreq *)addr);
|
error = bpf_setif(d, (struct ifreq *)addr);
|
||||||
|
BPF_UNLOCK();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1609,6 +1678,23 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
|
|||||||
cmd = BIOCSETWF;
|
cmd = BIOCSETWF;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
|
* Check new filter validness before acquiring any locks.
|
||||||
|
* Allocate memory for new filter, if needed.
|
||||||
|
*/
|
||||||
|
flen = fp->bf_len;
|
||||||
|
if ((flen > bpf_maxinsns) || ((fp->bf_insns == NULL) && (flen != 0)))
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
need_upgrade = 0;
|
||||||
|
size = flen * sizeof(*fp->bf_insns);
|
||||||
|
if (size > 0)
|
||||||
|
fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK);
|
||||||
|
else
|
||||||
|
fcode = NULL; /* Make compiler happy */
|
||||||
|
|
||||||
|
BPF_LOCK();
|
||||||
|
|
||||||
if (cmd == BIOCSETWF) {
|
if (cmd == BIOCSETWF) {
|
||||||
old = d->bd_wfilter;
|
old = d->bd_wfilter;
|
||||||
wfilter = 1;
|
wfilter = 1;
|
||||||
@ -1623,13 +1709,12 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (fp->bf_insns == NULL) {
|
if (fp->bf_insns == NULL) {
|
||||||
if (fp->bf_len != 0)
|
|
||||||
return (EINVAL);
|
|
||||||
/*
|
/*
|
||||||
* Protect filter change by interface lock, too.
|
* Protect filter removal by interface lock.
|
||||||
* The same lock order is used by bpf_detachd().
|
* Additionally, we are protected by global lock here.
|
||||||
*/
|
*/
|
||||||
BPFIF_WLOCK(d->bd_bif);
|
if (d->bd_bif != NULL)
|
||||||
|
BPFIF_WLOCK(d->bd_bif);
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
if (wfilter)
|
if (wfilter)
|
||||||
d->bd_wfilter = NULL;
|
d->bd_wfilter = NULL;
|
||||||
@ -1642,29 +1727,26 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
|
|||||||
reset_d(d);
|
reset_d(d);
|
||||||
}
|
}
|
||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
BPFIF_WUNLOCK(d->bd_bif);
|
if (d->bd_bif != NULL)
|
||||||
|
BPFIF_WUNLOCK(d->bd_bif);
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
free((caddr_t)old, M_BPF);
|
free((caddr_t)old, M_BPF);
|
||||||
#ifdef BPF_JITTER
|
#ifdef BPF_JITTER
|
||||||
if (ofunc != NULL)
|
if (ofunc != NULL)
|
||||||
bpf_destroy_jit_filter(ofunc);
|
bpf_destroy_jit_filter(ofunc);
|
||||||
#endif
|
#endif
|
||||||
|
BPF_UNLOCK();
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
flen = fp->bf_len;
|
|
||||||
if (flen > bpf_maxinsns)
|
|
||||||
return (EINVAL);
|
|
||||||
|
|
||||||
need_upgrade = 0;
|
|
||||||
size = flen * sizeof(*fp->bf_insns);
|
|
||||||
fcode = (struct bpf_insn *)malloc(size, M_BPF, M_WAITOK);
|
|
||||||
if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 &&
|
if (copyin((caddr_t)fp->bf_insns, (caddr_t)fcode, size) == 0 &&
|
||||||
bpf_validate(fcode, (int)flen)) {
|
bpf_validate(fcode, (int)flen)) {
|
||||||
/*
|
/*
|
||||||
* Protect filter change by interface lock, too
|
* Protect filter change by interface lock
|
||||||
* The same lock order is used by bpf_detachd().
|
* Additionally, we are protected by global lock here.
|
||||||
*/
|
*/
|
||||||
BPFIF_WLOCK(d->bd_bif);
|
if (d->bd_bif != NULL)
|
||||||
|
BPFIF_WLOCK(d->bd_bif);
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
if (wfilter)
|
if (wfilter)
|
||||||
d->bd_wfilter = fcode;
|
d->bd_wfilter = fcode;
|
||||||
@ -1687,7 +1769,8 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
|
|||||||
__func__, d->bd_pid, d->bd_writer, need_upgrade);
|
__func__, d->bd_pid, d->bd_writer, need_upgrade);
|
||||||
}
|
}
|
||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
BPFIF_WUNLOCK(d->bd_bif);
|
if (d->bd_bif != NULL)
|
||||||
|
BPFIF_WUNLOCK(d->bd_bif);
|
||||||
if (old != NULL)
|
if (old != NULL)
|
||||||
free((caddr_t)old, M_BPF);
|
free((caddr_t)old, M_BPF);
|
||||||
#ifdef BPF_JITTER
|
#ifdef BPF_JITTER
|
||||||
@ -1699,9 +1782,11 @@ bpf_setf(struct bpf_d *d, struct bpf_program *fp, u_long cmd)
|
|||||||
if (need_upgrade != 0)
|
if (need_upgrade != 0)
|
||||||
bpf_upgraded(d);
|
bpf_upgraded(d);
|
||||||
|
|
||||||
|
BPF_UNLOCK();
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
free((caddr_t)fcode, M_BPF);
|
free((caddr_t)fcode, M_BPF);
|
||||||
|
BPF_UNLOCK();
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1716,6 +1801,8 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
|
|||||||
struct bpf_if *bp;
|
struct bpf_if *bp;
|
||||||
struct ifnet *theywant;
|
struct ifnet *theywant;
|
||||||
|
|
||||||
|
BPF_LOCK_ASSERT();
|
||||||
|
|
||||||
theywant = ifunit(ifr->ifr_name);
|
theywant = ifunit(ifr->ifr_name);
|
||||||
if (theywant == NULL || theywant->if_bpf == NULL)
|
if (theywant == NULL || theywant->if_bpf == NULL)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
@ -1746,15 +1833,8 @@ bpf_setif(struct bpf_d *d, struct ifreq *ifr)
|
|||||||
default:
|
default:
|
||||||
panic("bpf_setif: bufmode %d", d->bd_bufmode);
|
panic("bpf_setif: bufmode %d", d->bd_bufmode);
|
||||||
}
|
}
|
||||||
if (bp != d->bd_bif) {
|
if (bp != d->bd_bif)
|
||||||
if (d->bd_bif)
|
|
||||||
/*
|
|
||||||
* Detach if attached to something else.
|
|
||||||
*/
|
|
||||||
bpf_detachd(d);
|
|
||||||
|
|
||||||
bpf_attachd(d, bp);
|
bpf_attachd(d, bp);
|
||||||
}
|
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
reset_d(d);
|
reset_d(d);
|
||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
@ -2361,10 +2441,9 @@ bpfattach2(struct ifnet *ifp, u_int dlt, u_int hdrlen, struct bpf_if **driverp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detach bpf from an interface. This involves detaching each descriptor
|
* Detach bpf from an interface. This involves detaching each descriptor
|
||||||
* associated with the interface, and leaving bd_bif NULL. Notify each
|
* associated with the interface. Notify each descriptor as it's detached
|
||||||
* descriptor as it's detached so that any sleepers wake up and get
|
* so that any sleepers wake up and get ENXIO.
|
||||||
* ENXIO.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
bpfdetach(struct ifnet *ifp)
|
bpfdetach(struct ifnet *ifp)
|
||||||
@ -2398,6 +2477,13 @@ bpfdetach(struct ifnet *ifp)
|
|||||||
bpf_wakeup(d);
|
bpf_wakeup(d);
|
||||||
BPFD_WUNLOCK(d);
|
BPFD_WUNLOCK(d);
|
||||||
}
|
}
|
||||||
|
/* Free writer-only descriptors */
|
||||||
|
while ((d = LIST_FIRST(&bp->bif_wlist)) != NULL) {
|
||||||
|
bpf_detachd(d);
|
||||||
|
BPFD_WLOCK(d);
|
||||||
|
bpf_wakeup(d);
|
||||||
|
BPFD_WUNLOCK(d);
|
||||||
|
}
|
||||||
rw_destroy(&bp->bif_lock);
|
rw_destroy(&bp->bif_lock);
|
||||||
free(bp, M_BPF);
|
free(bp, M_BPF);
|
||||||
}
|
}
|
||||||
@ -2451,18 +2537,19 @@ bpf_setdlt(struct bpf_d *d, u_int dlt)
|
|||||||
struct ifnet *ifp;
|
struct ifnet *ifp;
|
||||||
struct bpf_if *bp;
|
struct bpf_if *bp;
|
||||||
|
|
||||||
|
BPF_LOCK_ASSERT();
|
||||||
|
|
||||||
if (d->bd_bif->bif_dlt == dlt)
|
if (d->bd_bif->bif_dlt == dlt)
|
||||||
return (0);
|
return (0);
|
||||||
ifp = d->bd_bif->bif_ifp;
|
ifp = d->bd_bif->bif_ifp;
|
||||||
BPF_LOCK();
|
|
||||||
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
|
LIST_FOREACH(bp, &bpf_iflist, bif_next) {
|
||||||
if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
|
if (bp->bif_ifp == ifp && bp->bif_dlt == dlt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BPF_UNLOCK();
|
|
||||||
if (bp != NULL) {
|
if (bp != NULL) {
|
||||||
opromisc = d->bd_promisc;
|
opromisc = d->bd_promisc;
|
||||||
bpf_detachd(d);
|
|
||||||
bpf_attachd(d, bp);
|
bpf_attachd(d, bp);
|
||||||
BPFD_WLOCK(d);
|
BPFD_WLOCK(d);
|
||||||
reset_d(d);
|
reset_d(d);
|
||||||
@ -2522,6 +2609,9 @@ bpf_zero_counters(void)
|
|||||||
BPF_UNLOCK();
|
BPF_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fill filter statistics
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
|
bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
|
||||||
{
|
{
|
||||||
@ -2529,6 +2619,7 @@ bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
|
|||||||
bzero(d, sizeof(*d));
|
bzero(d, sizeof(*d));
|
||||||
BPFD_LOCK_ASSERT(bd);
|
BPFD_LOCK_ASSERT(bd);
|
||||||
d->bd_structsize = sizeof(*d);
|
d->bd_structsize = sizeof(*d);
|
||||||
|
/* XXX: reading should be protected by global lock */
|
||||||
d->bd_immediate = bd->bd_immediate;
|
d->bd_immediate = bd->bd_immediate;
|
||||||
d->bd_promisc = bd->bd_promisc;
|
d->bd_promisc = bd->bd_promisc;
|
||||||
d->bd_hdrcmplt = bd->bd_hdrcmplt;
|
d->bd_hdrcmplt = bd->bd_hdrcmplt;
|
||||||
@ -2553,6 +2644,9 @@ bpfstats_fill_xbpf(struct xbpf_d *d, struct bpf_d *bd)
|
|||||||
d->bd_bufmode = bd->bd_bufmode;
|
d->bd_bufmode = bd->bd_bufmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle `netstat -B' stats request
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
bpf_stats_sysctl(SYSCTL_HANDLER_ARGS)
|
bpf_stats_sysctl(SYSCTL_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user