bpf.c revision b7ea883b48e925772db7fa37388112c84c6d5f5b
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* $NetBSD: bpf.c,v 1.143 2009/03/11 05:55:22 mrg Exp $ */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copyright (c) 1990, 1991, 1993
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The Regents of the University of California. All rights reserved.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This code is derived from the Stanford/CMU enet packet filter,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * (net/enet.c) distributed as part of 4.3BSD, and code contributed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Berkeley Laboratory.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Redistribution and use in source and binary forms, with or without
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * modification, are permitted provided that the following conditions
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 1. Redistributions of source code must retain the above copyright
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * notice, this list of conditions and the following disclaimer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 2. Redistributions in binary form must reproduce the above copyright
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * notice, this list of conditions and the following disclaimer in the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * documentation and/or other materials provided with the distribution.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 3. Neither the name of the University nor the names of its contributors
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * may be used to endorse or promote products derived from this software
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * without specific prior written permission.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * SUCH DAMAGE.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * @(#)bpf.c 8.4 (Berkeley) 1/9/95
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * static char rcsid[] =
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * "Header: bpf.c,v 1.67 96/09/26 22:00:52 leres Exp ";
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Use is subject to license terms.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The BPF implements the following access controls for zones attempting
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to read and write data. Writing of data requires that the net_rawaccess
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * privilege is held whilst reading data requires either net_rawaccess or
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * net_observerability.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * | Shared | Exclusive | Global
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * DLT_IPNET in local zone | Read | Read | Read |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Raw access to local zone NIC | None | Read/Write | Read/Write |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Raw access to all NICs | None | None | Read/Write |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The BPF driver is written as a cloning driver: each call to bpfopen()
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * allocates a new minor number. This provides BPF with a 1:1 relationship
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * between open's and close's. There is some amount of "descriptor state"
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * that is kept per open. Pointers to this data are stored in a hash table
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * (bpf_hash) that is index'd by the minor device number for each open file.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 4096 is too small for FDDI frames. 8192 is too small for gigabit Ethernet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * jumbos (circa 9k), ATM, or Intel gig/10gig ethernet jumbos (16k).
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedtypedef void *(*cp_fn_t)(void *, const void *, size_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The default read buffer size, and limit for BIOCSBLEN.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Use a mutex to avoid a race condition between gathering the stats/peers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and opening/closing the device.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * bpf_list is a list of the BPF descriptors currently open
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_ifname(struct bpf_d *d, char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void *bpf_mcpy(void *, const void *, size_t);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedstatic int bpf_attachd(struct bpf_d *, const char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_setif(struct bpf_d *, char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_timed_out(void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void catchpacket(struct bpf_d *, uchar_t *, uint_t, uint_t,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_movein(struct uio *uio, int linktype, int mtu, mblk_t **mp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Build a sockaddr based on the data link layer type.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We do this at this level because the ethernet header
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is copied directly into the data field of the sockaddr.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * In the case of SLIP, there is no header and the packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is forwarded as is.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Also, we are careful to leave room at the front of the mbuf
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * for the link level header.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If there aren't enough bytes for a link level header or the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * packet length exceeds the interface mtu, return an error.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Insure the data is properly aligned */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = uiomove(mtod(m, void *), len, UIO_WRITE, uio);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Attach file to the bpf interface, i.e. make d listen on bp.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedbpf_attachd(struct bpf_d *d, const char *ifname, int dlt)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed DTRACE_PROBE4(bpf__attach, struct bpf_provider_s *, bpr,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * If we failed to do an exact match for the global
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * zone using the global zoneid, try again in case
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * the network interface is owned by a local zone.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) strlcpy(d->bd_ifname, MBPF_CLIENT_NAME(&d->bd_mac, mcip),
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed sizeof (d->bd_ifname));
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) MBPF_GET_LINKID(&d->bd_mac, d->bd_ifname, &d->bd_linkid,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) MBPF_PROMISC_ADD(&d->bd_mac, d->bd_mcip, 0, d,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Detach a file from its interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Check if this descriptor had requested promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If so, turn it off. There's no need to take any action
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * here, that is done when MBPF_PROMISC_REMOVE is used;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bd_promisc is just a local flag to stop promiscuous mode
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * from being set more than once.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Take device out of "promiscuous" mode. Since we were able to
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * enter "promiscuous" mode, we should be able to turn it off.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Note, this field stores a pointer used to support both
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * promiscuous and non-promiscuous callbacks for packets.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The lock has to be dropped here because mac_promisc_remove may
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * need to wait for mac_promisc_dispatch, which has called into
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf and catchpacket is waiting for bd_lock...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * i.e mac_promisc_remove() needs to be called with none of the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * locks held that are part of the bpf_mtap() call path.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Because this function is called with bd_lock held, so it must
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * exit with it held.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfilterattach() is called at load time.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_hash = mod_hash_create_idhash("bpf_dev_tab", 31,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) memcpy(&ks_stats, &bpf_kstats, sizeof (bpf_kstats));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_ksp = kstat_create("bpf", 0, "global", "misc",
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed KSTAT_TYPE_NAMED, sizeof (bpf_kstats) / sizeof (kstat_named_t),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_init(&bpf_dlt_waiter, NULL, CV_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfilterdetach() is called at unload time.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Open ethernet device. Clones.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfopen(dev_t *devp, int flag, int mode, cred_t *cred)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The security policy described at the top of this file is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * enforced here.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * A structure is allocated per open file in BPF to store settings
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * such as buffer capture size, provide private buffers, etc.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d = (struct bpf_d *)kmem_zalloc(sizeof (*d), KM_SLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_PHYS|
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_init(&d->bd_lock, NULL, MUTEX_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Find an unused minor number. Obviously this is an O(n) algorithm
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and doesn't scale particularly well, so if there are large numbers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * of open file descriptors happening in real use, this design may
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * need to be revisited.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d, sizeof (*d));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Close the descriptor by detaching it from its interface,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * deallocating its buffers, and marking it free.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Because we only allow a device to be opened once, there is always a
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 1 to 1 relationship between opens and closes supporting this function.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed while (d->bd_inuse != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d, sizeof (*d));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the packet buffers in descriptor d. Move the store buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * into the hold slot, and the free buffer into the store slot.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Zero the length of the new store buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfread - read next chunk of packets from buffers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfread(dev_t dev, struct uio *uio, cred_t *cred)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Restrict application to use a buffer the same size as
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the kernel buffers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If the hold buffer is empty, then do a timed sleep, which
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ends when the timeout expires or when enough packets
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * have arrived to fill the store buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_hbuf == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_slen == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_immediate || timed_out) && d->bd_slen != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * A packet(s) either arrived since the previous
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * read or arrived while we were asleep.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the buffers and return what's here.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = cv_timedwait_sig(&d->bd_wait, &d->bd_lock, delay);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * On a timeout, return what's in the buffer,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * which may be nothing. If there is something
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * in the store buffer, we can rotate the buffers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We filled up the buffer in between
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * getting the timeout and arriving
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * here, so we don't need to rotate.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_slen == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * At this point, we know we have something in the hold slot.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Move data from hold buffer into user space.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We know the entire buffer is transferred since
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * we checked above that the read buffer is bpf_bufsize bytes.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = uiomove(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If there are processes sleeping on this descriptor, wake them up.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * NOTE: the lock for bd_wait is bd_lock and is held by bpf_deliver,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * so there is no code here grabbing it.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfwrite(dev_t dev, struct uio *uio, cred_t *cred)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_bif == 0 || d->bd_mcip == 0 || d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_inuse < 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed DTRACE_PROBE4(bpf__tx, struct bpf_d *, d, int, dlt,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The "tx" action here is required to consume the mblk_t.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The driver frees the mbuf.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Reset a descriptor by flushing its packet buffer and clearing the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * receive and drop counts. Should be called at splnet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Free the hold buffer. */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * FIONREAD Check for read packet available.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGBLEN Get buffer len [for read()].
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSETF Set ethernet read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCFLUSH Flush read packet buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCPROMISC Put interface into promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGDLT Get link layer type.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGETIF Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSETIF Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSRTIMEOUT Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGRTIMEOUT Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGSTATS Get packet stats.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCIMMEDIATE Set immediate mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCVERSION Get filter language version.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGHDRCMPLT Get "header already complete" flag.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSHDRCMPLT Set "header already complete" flag.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfioctl(dev_t dev, int cmd, intptr_t addr, int mode, cred_t *cred, int *rval)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Refresh the PID associated with this bpf file.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Check for read packet available.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *(int *)addr = n;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get buffer len [for read()].
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set buffer length.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &size, sizeof (size)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = copyout(&size, (void *)addr, sizeof (size));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set link layer read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ddi_copyin((void *)addr, &prog, sizeof (prog), mode)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Flush read packet buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Put interface into promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This is a one-way ioctl, it is not used to turn promiscuous
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * No interface attached yet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_promisc == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_COPY;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get device parameters.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed sizeof (d->bd_dlt));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of supported device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &list, sizeof (list)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&list, (void *)addr, sizeof (list)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_ifname(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&ifreq, (void *)addr, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setif(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&lifreq, (void *)addr, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Convert the timeout in microseconds to ticks */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = copyout(&tv, (void *)addr, sizeof (tv));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of supported device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lst32, sizeof (lst32)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed list.bfl_list = (void *)(uint64_t)lst32.bfl_list;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (lst32)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set link layer read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ddi_copyin((void *)addr, &prog32, sizeof (prog), mode)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Convert the timeout in microseconds to ticks */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&tv, (void *)addr, sizeof (tv)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get packet stats.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&bs, (void *)addr, sizeof (bs)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set immediate mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_immediate)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&bv, (void *)addr, sizeof (bv)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGHDRCMPLT: /* get "header already complete" flag */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_hdrcmplt)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSHDRCMPLT: /* set "header already complete" flag */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_hdrcmplt)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get "see sent packets" flag
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_seesent)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set "see sent" packets flag
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_seesent)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_nonblock)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set d's packet filter program to fp. If this file already has a filter,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * free it and replace it. If the new filter is "empty" (has a 0 size), then
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the result is to just remove and free the existing filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Returns EINVAL for bogus requests.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_setf(struct bpf_d *d, struct bpf_program *fp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Detach a file from its current interface (if attached at all) and attach
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * to the interface indicated by the name stored in ifname.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Return an errno or 0.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_setif(struct bpf_d *d, char *ifname, int namesize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Make sure the provided name has a unit number, and default
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * it to '0' if not specified.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * XXX This is ugly ... do this differently?
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Make sure to leave room for the '\0'. */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Make sure that only one call to this function happens at a time
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and that we're not interleaving a read/write
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_inuse != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Detach if attached to something else.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Try tickle the mac layer into attaching the device...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (bpf_provider_tickle(ifname, d->bd_zone));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy the interface name to the ifreq.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_ifname(struct bpf_d *d, char *buffer, int bufsize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Support for poll() system call
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Return true iff the specific operation will not block indefinitely - with
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the assumption that it is safe to positively acknowledge a request for the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ability to write to the BPF device.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Otherwise, return false but make a note that a selnotify() must be done.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfchpoll(dev_t dev, short events, int anyyet, short *reventsp,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * An imitation of the FIONREAD ioctl code.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hlen != 0 ||
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Start the read timeout if necessary */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Only allow the timeout to be set once.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy data from an mblk_t chain into a buffer. This works for ipnet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * because the dl_ipnetinfo_t is placed in an mblk_t that leads the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * packet itself.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_mcpy(void *dst_arg, const void *src_arg, size_t len)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (len > 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) memcpy(dst, mtod(m, const void *), count);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Dispatch a packet to all the listeners on interface bp.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * marg pointer to the packet, either a data buffer or an mbuf chain
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * buflen buffer length, if marg is a data buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * cpfn a function that can copy marg into the listener's buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pktlen length of the packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * issent boolean indicating whether the packet was sent or receive
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_deliver(struct bpf_d *d, cp_fn_t cpfn, void *marg, uint_t pktlen,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Accuracy of the packet counters in BPF is vital so it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is important to protect even the outer ones.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed DTRACE_PROBE5(bpf__packet, struct bpf_if *, d->bd_bif,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *, d, void *, marg, uint_t, pktlen, uint_t, slen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Incoming linkage from device drivers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_mtap(void *arg, mac_resource_handle_t mrh, mblk_t *m, boolean_t issent)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_deliver(d, cpfn, marg, pktlen, buflen, issent);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Incoming linkage from ipnet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * In ipnet, there is only one event, NH_OBSERVE, that delivers packets
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * from all network interfaces. Thus the tap function needs to apply a
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * filter using the interface index/id to immitate snoop'ing on just the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * specified interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_itap(void *arg, mblk_t *m, boolean_t issent, uint_t length)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Move the packet data from interface memory (pkt) into the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * store buffer. Return 1 if it's time to wakeup a listener (buffer full),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * otherwise 0. "copy" is the routine called to do the actual data
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * transfer. memcpy is passed in to copy contiguous chunks, while
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_mcpy is passed in to copy mbuf chains. In the latter case,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pkt is really an mbuf.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedcatchpacket(struct bpf_d *d, uchar_t *pkt, uint_t pktlen, uint_t snaplen,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Figure out how many bytes to move. If the packet is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * greater or equal to the snapshot length, transfer that
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * much. Otherwise, transfer the whole packet (unless
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * we hit the buffer size limit).
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Round up the end of the previous packet to the next longword.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This packet will overflow the storage buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the buffers if we can, then wakeup any
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pending reads.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_fbuf == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We haven't completed the previous read yet,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * so drop the packet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Immediate mode is set, or the read timeout has
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * already expired during a select call. A packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * arrived, so the reader should be woken up.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Append the bpf header to the existing buffer before we add
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * on the actual packet data.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy the packet data into the store buffer and update its length.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Call bpf_wakeup after bd_slen has been updated.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Initialize all nonzero fields of a descriptor.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_fbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_sbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Free buffers currently in use by a descriptor.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Called on close.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * At this point the descriptor has been detached from its
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * interface and it yet hasn't been marked free.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_sbuf != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of available data link type of the interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *listp)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_OPEN(bpr, d->bd_ifname, &mh, d->bd_zone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Bumping of bd_inuse ensures the structure does not
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * disappear while the copyout runs and allows the for
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * loop to be continued.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * It is quite possible that one or more provider to BPF may not
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * know about a link name whlist others do. In that case, so long
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * as we have one success, do not declare an error unless it was
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * an EFAULT as this indicates a problem that needs to be reported.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set the data link type of a BPF instance.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_ZONE(&d->bd_mac, d->bd_bif, &niczone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * See the matrix at the top of the file for the permissions table
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * enforced by this driver.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if ((d->bd_zone != GLOBAL_ZONEID) && (dlt != DLT_IPNET) &&
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) strlcpy(ifname, d->bd_ifname, sizeof (ifname));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_clear_timeout is called with the bd_lock mutex held, providing it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * with the necessary protection to retrieve and modify bd_callout but it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * does not hold the lock for its entire duration... see below...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If the timeout has fired and is waiting on bd_lock, we could
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * deadlock here because untimeout if bd_lock is held and would
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * wait for bpf_timed_out to finish and it never would.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * As a cloning device driver, BPF needs to keep track of which device
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * numbers are in use and which ones are not. A hash table, indexed by
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the minor device number, is used to store the pointers to the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * individual descriptors that are allocated in bpfopen().
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The functions below present the interface for that hash table to
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the rest of the driver.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_find(bpf_hash, (mod_hash_key_t)(uintptr_t)minor,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_insert(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_remove(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_def_get should only ever be called for a minor number that exists,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * thus there should always be a pointer in the hash table that corresponds
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *