xref: /onnv-gate/usr/src/uts/common/io/bpf/bpf.c (revision 11187:ed4ed49634b9)
110639SDarren.Reed@Sun.COM /*	$NetBSD: bpf.c,v 1.143 2009/03/11 05:55:22 mrg Exp $	*/
210639SDarren.Reed@Sun.COM 
310639SDarren.Reed@Sun.COM /*
410639SDarren.Reed@Sun.COM  * Copyright (c) 1990, 1991, 1993
510639SDarren.Reed@Sun.COM  *	The Regents of the University of California.  All rights reserved.
610639SDarren.Reed@Sun.COM  *
710639SDarren.Reed@Sun.COM  * This code is derived from the Stanford/CMU enet packet filter,
810639SDarren.Reed@Sun.COM  * (net/enet.c) distributed as part of 4.3BSD, and code contributed
910639SDarren.Reed@Sun.COM  * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
1010639SDarren.Reed@Sun.COM  * Berkeley Laboratory.
1110639SDarren.Reed@Sun.COM  *
1210639SDarren.Reed@Sun.COM  * Redistribution and use in source and binary forms, with or without
1310639SDarren.Reed@Sun.COM  * modification, are permitted provided that the following conditions
1410639SDarren.Reed@Sun.COM  * are met:
1510639SDarren.Reed@Sun.COM  * 1. Redistributions of source code must retain the above copyright
1610639SDarren.Reed@Sun.COM  *    notice, this list of conditions and the following disclaimer.
1710639SDarren.Reed@Sun.COM  * 2. Redistributions in binary form must reproduce the above copyright
1810639SDarren.Reed@Sun.COM  *    notice, this list of conditions and the following disclaimer in the
1910639SDarren.Reed@Sun.COM  *    documentation and/or other materials provided with the distribution.
2010639SDarren.Reed@Sun.COM  * 3. Neither the name of the University nor the names of its contributors
2110639SDarren.Reed@Sun.COM  *    may be used to endorse or promote products derived from this software
2210639SDarren.Reed@Sun.COM  *    without specific prior written permission.
2310639SDarren.Reed@Sun.COM  *
2410639SDarren.Reed@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2510639SDarren.Reed@Sun.COM  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2610639SDarren.Reed@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2710639SDarren.Reed@Sun.COM  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2810639SDarren.Reed@Sun.COM  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2910639SDarren.Reed@Sun.COM  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3010639SDarren.Reed@Sun.COM  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3110639SDarren.Reed@Sun.COM  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3210639SDarren.Reed@Sun.COM  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3310639SDarren.Reed@Sun.COM  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3410639SDarren.Reed@Sun.COM  * SUCH DAMAGE.
3510639SDarren.Reed@Sun.COM  *
3610639SDarren.Reed@Sun.COM  *	@(#)bpf.c	8.4 (Berkeley) 1/9/95
3710639SDarren.Reed@Sun.COM  * static char rcsid[] =
3810639SDarren.Reed@Sun.COM  * "Header: bpf.c,v 1.67 96/09/26 22:00:52 leres Exp ";
3910639SDarren.Reed@Sun.COM  */
4010639SDarren.Reed@Sun.COM /*
4110639SDarren.Reed@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
4210639SDarren.Reed@Sun.COM  * Use is subject to license terms.
4310639SDarren.Reed@Sun.COM  */
4410639SDarren.Reed@Sun.COM 
4510639SDarren.Reed@Sun.COM /*
4610639SDarren.Reed@Sun.COM  * The BPF implements the following access controls for zones attempting
4710639SDarren.Reed@Sun.COM  * to read and write data. Writing of data requires that the net_rawaccess
4810639SDarren.Reed@Sun.COM  * privilege is held whilst reading data requires either net_rawaccess or
4910639SDarren.Reed@Sun.COM  * net_observerability.
5010639SDarren.Reed@Sun.COM  *
5110639SDarren.Reed@Sun.COM  *                              | Shared |  Exclusive |   Global
5210639SDarren.Reed@Sun.COM  * -----------------------------+--------+------------+------------+
5310639SDarren.Reed@Sun.COM  * DLT_IPNET in local zone      |  Read  |    Read    |    Read    |
5410639SDarren.Reed@Sun.COM  * -----------------------------+--------+------------+------------+
5510639SDarren.Reed@Sun.COM  * Raw access to local zone NIC |  None  | Read/Write | Read/Write |
5610639SDarren.Reed@Sun.COM  * -----------------------------+--------+------------+------------+
5710639SDarren.Reed@Sun.COM  * Raw access to all NICs       |  None  |    None    | Read/Write |
5810639SDarren.Reed@Sun.COM  * -----------------------------+--------+------------+------------+
5910639SDarren.Reed@Sun.COM  *
6010639SDarren.Reed@Sun.COM  * The BPF driver is written as a cloning driver: each call to bpfopen()
6110639SDarren.Reed@Sun.COM  * allocates a new minor number. This provides BPF with a 1:1 relationship
6210639SDarren.Reed@Sun.COM  * between open's and close's. There is some amount of "descriptor state"
6310639SDarren.Reed@Sun.COM  * that is kept per open. Pointers to this data are stored in a hash table
6410639SDarren.Reed@Sun.COM  * (bpf_hash) that is index'd by the minor device number for each open file.
6510639SDarren.Reed@Sun.COM  */
6610639SDarren.Reed@Sun.COM #include <sys/param.h>
6710639SDarren.Reed@Sun.COM #include <sys/systm.h>
6810639SDarren.Reed@Sun.COM #include <sys/time.h>
6910639SDarren.Reed@Sun.COM #include <sys/ioctl.h>
7010639SDarren.Reed@Sun.COM #include <sys/queue.h>
7110639SDarren.Reed@Sun.COM #include <sys/filio.h>
7210639SDarren.Reed@Sun.COM #include <sys/policy.h>
7310639SDarren.Reed@Sun.COM #include <sys/cmn_err.h>
7410639SDarren.Reed@Sun.COM #include <sys/uio.h>
7510639SDarren.Reed@Sun.COM #include <sys/file.h>
7610639SDarren.Reed@Sun.COM #include <sys/sysmacros.h>
7710639SDarren.Reed@Sun.COM #include <sys/zone.h>
7810639SDarren.Reed@Sun.COM 
7910639SDarren.Reed@Sun.COM #include <sys/socket.h>
8010639SDarren.Reed@Sun.COM #include <sys/errno.h>
8110639SDarren.Reed@Sun.COM #include <sys/poll.h>
8210639SDarren.Reed@Sun.COM #include <sys/dlpi.h>
8310639SDarren.Reed@Sun.COM #include <sys/neti.h>
8410639SDarren.Reed@Sun.COM 
8510639SDarren.Reed@Sun.COM #include <net/if.h>
8610639SDarren.Reed@Sun.COM 
8710639SDarren.Reed@Sun.COM #include <net/bpf.h>
8810639SDarren.Reed@Sun.COM #include <net/bpfdesc.h>
8910639SDarren.Reed@Sun.COM #include <net/dlt.h>
9010639SDarren.Reed@Sun.COM 
9110639SDarren.Reed@Sun.COM #include <netinet/in.h>
9210639SDarren.Reed@Sun.COM #include <sys/mac.h>
9310639SDarren.Reed@Sun.COM #include <sys/mac_client.h>
9410639SDarren.Reed@Sun.COM #include <sys/mac_impl.h>
9510639SDarren.Reed@Sun.COM #include <sys/time_std_impl.h>
9610639SDarren.Reed@Sun.COM #include <sys/hook.h>
9710639SDarren.Reed@Sun.COM #include <sys/hook_event.h>
9810639SDarren.Reed@Sun.COM 
9910639SDarren.Reed@Sun.COM 
10010639SDarren.Reed@Sun.COM #define	mtod(_v, _t)	(_t)((_v)->b_rptr)
10110639SDarren.Reed@Sun.COM #define	M_LEN(_m)	((_m)->b_wptr - (_m)->b_rptr)
10210639SDarren.Reed@Sun.COM 
10310639SDarren.Reed@Sun.COM /*
10410639SDarren.Reed@Sun.COM  * 4096 is too small for FDDI frames. 8192 is too small for gigabit Ethernet
10510639SDarren.Reed@Sun.COM  * jumbos (circa 9k), ATM, or Intel gig/10gig ethernet jumbos (16k).
10610639SDarren.Reed@Sun.COM  */
10710639SDarren.Reed@Sun.COM #define	BPF_BUFSIZE (32 * 1024)
10810639SDarren.Reed@Sun.COM 
10910639SDarren.Reed@Sun.COM typedef void *(*cp_fn_t)(void *, const void *, size_t);
11010639SDarren.Reed@Sun.COM 
11110639SDarren.Reed@Sun.COM /*
11210639SDarren.Reed@Sun.COM  * The default read buffer size, and limit for BIOCSBLEN.
11310639SDarren.Reed@Sun.COM  */
11410639SDarren.Reed@Sun.COM int bpf_bufsize = BPF_BUFSIZE;
11510639SDarren.Reed@Sun.COM int bpf_maxbufsize = (16 * 1024 * 1024);
11611179SDarren.Reed@Sun.COM static mod_hash_t *bpf_hash = NULL;
11710639SDarren.Reed@Sun.COM 
11810639SDarren.Reed@Sun.COM /*
11910639SDarren.Reed@Sun.COM  * Use a mutex to avoid a race condition between gathering the stats/peers
12010639SDarren.Reed@Sun.COM  * and opening/closing the device.
12110639SDarren.Reed@Sun.COM  */
12210639SDarren.Reed@Sun.COM static kcondvar_t bpf_dlt_waiter;
12310639SDarren.Reed@Sun.COM static kmutex_t bpf_mtx;
12410639SDarren.Reed@Sun.COM static bpf_kstats_t ks_stats;
12510639SDarren.Reed@Sun.COM static bpf_kstats_t bpf_kstats = {
12610639SDarren.Reed@Sun.COM 	{ "readWait",		KSTAT_DATA_UINT64 },
12710639SDarren.Reed@Sun.COM 	{ "writeOk",		KSTAT_DATA_UINT64 },
12810639SDarren.Reed@Sun.COM 	{ "writeError",		KSTAT_DATA_UINT64 },
12910639SDarren.Reed@Sun.COM 	{ "receive",		KSTAT_DATA_UINT64 },
13010639SDarren.Reed@Sun.COM 	{ "captured",		KSTAT_DATA_UINT64 },
13110639SDarren.Reed@Sun.COM 	{ "dropped",		KSTAT_DATA_UINT64 },
13210639SDarren.Reed@Sun.COM };
13310639SDarren.Reed@Sun.COM static kstat_t *bpf_ksp;
13410639SDarren.Reed@Sun.COM 
13510639SDarren.Reed@Sun.COM /*
13611179SDarren.Reed@Sun.COM  *  bpf_list is a list of the BPF descriptors currently open
13710639SDarren.Reed@Sun.COM  */
13810639SDarren.Reed@Sun.COM LIST_HEAD(, bpf_d) bpf_list;
13910639SDarren.Reed@Sun.COM 
14010639SDarren.Reed@Sun.COM static int	bpf_allocbufs(struct bpf_d *);
14110639SDarren.Reed@Sun.COM static void	bpf_clear_timeout(struct bpf_d *);
14210639SDarren.Reed@Sun.COM static void	bpf_deliver(struct bpf_d *, cp_fn_t,
14310639SDarren.Reed@Sun.COM 		    void *, uint_t, uint_t, boolean_t);
14410639SDarren.Reed@Sun.COM static void	bpf_freed(struct bpf_d *);
14510639SDarren.Reed@Sun.COM static int	bpf_ifname(struct bpf_d *d, char *, int);
14610639SDarren.Reed@Sun.COM static void	*bpf_mcpy(void *, const void *, size_t);
14711179SDarren.Reed@Sun.COM static int	bpf_attachd(struct bpf_d *, const char *, int);
14810639SDarren.Reed@Sun.COM static void	bpf_detachd(struct bpf_d *);
14910639SDarren.Reed@Sun.COM static int	bpf_setif(struct bpf_d *, char *, int);
15010639SDarren.Reed@Sun.COM static void	bpf_timed_out(void *);
15110639SDarren.Reed@Sun.COM static inline void
15210639SDarren.Reed@Sun.COM 		bpf_wakeup(struct bpf_d *);
15310639SDarren.Reed@Sun.COM static void	catchpacket(struct bpf_d *, uchar_t *, uint_t, uint_t,
15410639SDarren.Reed@Sun.COM 		    cp_fn_t, struct timeval *);
15510639SDarren.Reed@Sun.COM static void	reset_d(struct bpf_d *);
15610639SDarren.Reed@Sun.COM static int	bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
15710639SDarren.Reed@Sun.COM static int	bpf_setdlt(struct bpf_d *, void *);
15810639SDarren.Reed@Sun.COM static void	bpf_dev_add(struct bpf_d *);
15910639SDarren.Reed@Sun.COM static struct bpf_d *bpf_dev_find(minor_t);
16010639SDarren.Reed@Sun.COM static struct bpf_d *bpf_dev_get(minor_t);
16110639SDarren.Reed@Sun.COM static void	bpf_dev_remove(struct bpf_d *);
16210639SDarren.Reed@Sun.COM 
16310639SDarren.Reed@Sun.COM static int
bpf_movein(struct uio * uio,int linktype,int mtu,mblk_t ** mp)16410639SDarren.Reed@Sun.COM bpf_movein(struct uio *uio, int linktype, int mtu, mblk_t **mp)
16510639SDarren.Reed@Sun.COM {
16610639SDarren.Reed@Sun.COM 	mblk_t *m;
16710639SDarren.Reed@Sun.COM 	int error;
16810639SDarren.Reed@Sun.COM 	int len;
16910639SDarren.Reed@Sun.COM 	int hlen;
17010639SDarren.Reed@Sun.COM 	int align;
17110639SDarren.Reed@Sun.COM 
17210639SDarren.Reed@Sun.COM 	/*
17310639SDarren.Reed@Sun.COM 	 * Build a sockaddr based on the data link layer type.
17410639SDarren.Reed@Sun.COM 	 * We do this at this level because the ethernet header
17510639SDarren.Reed@Sun.COM 	 * is copied directly into the data field of the sockaddr.
17610639SDarren.Reed@Sun.COM 	 * In the case of SLIP, there is no header and the packet
17710639SDarren.Reed@Sun.COM 	 * is forwarded as is.
17810639SDarren.Reed@Sun.COM 	 * Also, we are careful to leave room at the front of the mbuf
17910639SDarren.Reed@Sun.COM 	 * for the link level header.
18010639SDarren.Reed@Sun.COM 	 */
18110639SDarren.Reed@Sun.COM 	switch (linktype) {
18210639SDarren.Reed@Sun.COM 
18310639SDarren.Reed@Sun.COM 	case DLT_EN10MB:
18410639SDarren.Reed@Sun.COM 		hlen = sizeof (struct ether_header);
18510639SDarren.Reed@Sun.COM 		break;
18610639SDarren.Reed@Sun.COM 
18710639SDarren.Reed@Sun.COM 	case DLT_FDDI:
18810639SDarren.Reed@Sun.COM 		hlen = 16;
18910639SDarren.Reed@Sun.COM 		break;
19010639SDarren.Reed@Sun.COM 
19110639SDarren.Reed@Sun.COM 	case DLT_NULL:
19210639SDarren.Reed@Sun.COM 		hlen = 0;
19310639SDarren.Reed@Sun.COM 		break;
19410639SDarren.Reed@Sun.COM 
19510639SDarren.Reed@Sun.COM 	case DLT_IPOIB:
19610639SDarren.Reed@Sun.COM 		hlen = 44;
19710639SDarren.Reed@Sun.COM 		break;
19810639SDarren.Reed@Sun.COM 
19910639SDarren.Reed@Sun.COM 	default:
20010639SDarren.Reed@Sun.COM 		return (EIO);
20110639SDarren.Reed@Sun.COM 	}
20210639SDarren.Reed@Sun.COM 
20310639SDarren.Reed@Sun.COM 	align = 4 - (hlen & 3);
20410639SDarren.Reed@Sun.COM 
20510639SDarren.Reed@Sun.COM 	len = uio->uio_resid;
20610639SDarren.Reed@Sun.COM 	/*
20710639SDarren.Reed@Sun.COM 	 * If there aren't enough bytes for a link level header or the
20810639SDarren.Reed@Sun.COM 	 * packet length exceeds the interface mtu, return an error.
20910639SDarren.Reed@Sun.COM 	 */
21010639SDarren.Reed@Sun.COM 	if (len < hlen || len - hlen > mtu)
21110639SDarren.Reed@Sun.COM 		return (EMSGSIZE);
21210639SDarren.Reed@Sun.COM 
21310639SDarren.Reed@Sun.COM 	m = allocb(len + align, BPRI_MED);
21410639SDarren.Reed@Sun.COM 	if (m == NULL) {
21510639SDarren.Reed@Sun.COM 		error = ENOBUFS;
21610639SDarren.Reed@Sun.COM 		goto bad;
21710639SDarren.Reed@Sun.COM 	}
21810639SDarren.Reed@Sun.COM 
21910639SDarren.Reed@Sun.COM 	/* Insure the data is properly aligned */
22010639SDarren.Reed@Sun.COM 	if (align > 0)
22110639SDarren.Reed@Sun.COM 		m->b_rptr += align;
22210639SDarren.Reed@Sun.COM 	m->b_wptr = m->b_rptr + len;
22310639SDarren.Reed@Sun.COM 
22410639SDarren.Reed@Sun.COM 	error = uiomove(mtod(m, void *), len, UIO_WRITE, uio);
22510639SDarren.Reed@Sun.COM 	if (error)
22610639SDarren.Reed@Sun.COM 		goto bad;
22710639SDarren.Reed@Sun.COM 	*mp = m;
22810639SDarren.Reed@Sun.COM 	return (0);
22910639SDarren.Reed@Sun.COM 
23010639SDarren.Reed@Sun.COM bad:
23110639SDarren.Reed@Sun.COM 	if (m != NULL)
23210639SDarren.Reed@Sun.COM 		freemsg(m);
23310639SDarren.Reed@Sun.COM 	return (error);
23410639SDarren.Reed@Sun.COM }
23510639SDarren.Reed@Sun.COM 
23610639SDarren.Reed@Sun.COM 
23710639SDarren.Reed@Sun.COM /*
23810639SDarren.Reed@Sun.COM  * Attach file to the bpf interface, i.e. make d listen on bp.
23910639SDarren.Reed@Sun.COM  */
24011179SDarren.Reed@Sun.COM static int
bpf_attachd(struct bpf_d * d,const char * ifname,int dlt)24111179SDarren.Reed@Sun.COM bpf_attachd(struct bpf_d *d, const char *ifname, int dlt)
24210639SDarren.Reed@Sun.COM {
24311179SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
24411179SDarren.Reed@Sun.COM 	bpf_provider_t *bpr;
24511179SDarren.Reed@Sun.COM 	boolean_t zonematch;
24611179SDarren.Reed@Sun.COM 	zoneid_t niczone;
24711179SDarren.Reed@Sun.COM 	uintptr_t mcip;
24811179SDarren.Reed@Sun.COM 	zoneid_t zone;
24911179SDarren.Reed@Sun.COM 	uint_t nicdlt;
25011179SDarren.Reed@Sun.COM 	uintptr_t mh;
25111179SDarren.Reed@Sun.COM 	int hdrlen;
25211179SDarren.Reed@Sun.COM 	int error;
25310639SDarren.Reed@Sun.COM 
25410639SDarren.Reed@Sun.COM 	ASSERT(d->bd_bif == NULL);
25511179SDarren.Reed@Sun.COM 	ASSERT(d->bd_mcip == NULL);
25611179SDarren.Reed@Sun.COM 	zone = d->bd_zone;
25711179SDarren.Reed@Sun.COM 	zonematch = B_TRUE;
25811179SDarren.Reed@Sun.COM again:
25911179SDarren.Reed@Sun.COM 	mh = 0;
26011179SDarren.Reed@Sun.COM 	mcip = 0;
26111179SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
26211179SDarren.Reed@Sun.COM 		bpr = bp->bpl_what;
26311179SDarren.Reed@Sun.COM 		error = MBPF_OPEN(bpr, ifname, &mh, zone);
26411179SDarren.Reed@Sun.COM 		if (error != 0)
26511179SDarren.Reed@Sun.COM 			goto next;
26611179SDarren.Reed@Sun.COM 		error = MBPF_CLIENT_OPEN(bpr, mh, &mcip);
26711179SDarren.Reed@Sun.COM 		if (error != 0)
26811179SDarren.Reed@Sun.COM 			goto next;
26911179SDarren.Reed@Sun.COM 		error = MBPF_GET_DLT(bpr, mh, &nicdlt);
27011179SDarren.Reed@Sun.COM 		if (error != 0)
27111179SDarren.Reed@Sun.COM 			goto next;
27211179SDarren.Reed@Sun.COM 
27311179SDarren.Reed@Sun.COM 		nicdlt = bpf_dl_to_dlt(nicdlt);
27411179SDarren.Reed@Sun.COM 		if (dlt != -1 && dlt != nicdlt) {
27511179SDarren.Reed@Sun.COM 			error = ENOENT;
27611179SDarren.Reed@Sun.COM 			goto next;
27711179SDarren.Reed@Sun.COM 		}
27811179SDarren.Reed@Sun.COM 
27911179SDarren.Reed@Sun.COM 		error = MBPF_GET_ZONE(bpr, mh, &niczone);
28011179SDarren.Reed@Sun.COM 		if (error != 0)
28111179SDarren.Reed@Sun.COM 			goto next;
28211179SDarren.Reed@Sun.COM 
28311179SDarren.Reed@Sun.COM 		DTRACE_PROBE4(bpf__attach, struct bpf_provider_s *, bpr,
28411179SDarren.Reed@Sun.COM 		    uintptr_t, mh, int, nicdlt, zoneid_t, niczone);
28510639SDarren.Reed@Sun.COM 
28611179SDarren.Reed@Sun.COM 		if (zonematch && niczone != zone) {
28711179SDarren.Reed@Sun.COM 			error = ENOENT;
28811179SDarren.Reed@Sun.COM 			goto next;
28911179SDarren.Reed@Sun.COM 		}
29011179SDarren.Reed@Sun.COM 		break;
29111179SDarren.Reed@Sun.COM next:
29211179SDarren.Reed@Sun.COM 		if (mcip != 0) {
29311179SDarren.Reed@Sun.COM 			MBPF_CLIENT_CLOSE(bpr, mcip);
29411179SDarren.Reed@Sun.COM 			mcip = 0;
29511179SDarren.Reed@Sun.COM 		}
29611179SDarren.Reed@Sun.COM 		if (mh != NULL) {
29711179SDarren.Reed@Sun.COM 			MBPF_CLOSE(bpr, mh);
29811179SDarren.Reed@Sun.COM 			mh = 0;
29911179SDarren.Reed@Sun.COM 		}
30011179SDarren.Reed@Sun.COM 	}
30111179SDarren.Reed@Sun.COM 	if (error != 0) {
30211179SDarren.Reed@Sun.COM 		if (zonematch && (zone == GLOBAL_ZONEID)) {
30311179SDarren.Reed@Sun.COM 			/*
30411179SDarren.Reed@Sun.COM 			 * If we failed to do an exact match for the global
30511179SDarren.Reed@Sun.COM 			 * zone using the global zoneid, try again in case
30611179SDarren.Reed@Sun.COM 			 * the network interface is owned by a local zone.
30711179SDarren.Reed@Sun.COM 			 */
30811179SDarren.Reed@Sun.COM 			zonematch = B_FALSE;
30911179SDarren.Reed@Sun.COM 			goto again;
31011179SDarren.Reed@Sun.COM 		}
31111179SDarren.Reed@Sun.COM 		return (error);
31211179SDarren.Reed@Sun.COM 	}
31311179SDarren.Reed@Sun.COM 
31411179SDarren.Reed@Sun.COM 	d->bd_mac = *bpr;
31511179SDarren.Reed@Sun.COM 	d->bd_mcip = mcip;
31611179SDarren.Reed@Sun.COM 	d->bd_bif = mh;
31711179SDarren.Reed@Sun.COM 	d->bd_dlt = nicdlt;
31811179SDarren.Reed@Sun.COM 	hdrlen = bpf_dl_hdrsize(nicdlt);
31911179SDarren.Reed@Sun.COM 	d->bd_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
32011179SDarren.Reed@Sun.COM 
32111179SDarren.Reed@Sun.COM 	(void) strlcpy(d->bd_ifname, MBPF_CLIENT_NAME(&d->bd_mac, mcip),
32211179SDarren.Reed@Sun.COM 	    sizeof (d->bd_ifname));
32311179SDarren.Reed@Sun.COM 
32411179SDarren.Reed@Sun.COM 	(void) MBPF_GET_LINKID(&d->bd_mac, d->bd_ifname, &d->bd_linkid,
32511179SDarren.Reed@Sun.COM 	    zone);
32611179SDarren.Reed@Sun.COM 	(void) MBPF_PROMISC_ADD(&d->bd_mac, d->bd_mcip, 0, d,
32711179SDarren.Reed@Sun.COM 	    &d->bd_promisc_handle, d->bd_promisc_flags);
32811179SDarren.Reed@Sun.COM 	return (0);
32910639SDarren.Reed@Sun.COM }
33010639SDarren.Reed@Sun.COM 
33110639SDarren.Reed@Sun.COM /*
33210639SDarren.Reed@Sun.COM  * Detach a file from its interface.
33310639SDarren.Reed@Sun.COM  */
33410639SDarren.Reed@Sun.COM static void
bpf_detachd(struct bpf_d * d)33510639SDarren.Reed@Sun.COM bpf_detachd(struct bpf_d *d)
33610639SDarren.Reed@Sun.COM {
33710639SDarren.Reed@Sun.COM 	uintptr_t mph;
33810639SDarren.Reed@Sun.COM 	uintptr_t mch;
33911179SDarren.Reed@Sun.COM 	uintptr_t mh;
34010639SDarren.Reed@Sun.COM 
34111179SDarren.Reed@Sun.COM 	ASSERT(d->bd_inuse == -1);
34210639SDarren.Reed@Sun.COM 	mch = d->bd_mcip;
34310639SDarren.Reed@Sun.COM 	d->bd_mcip = 0;
34411179SDarren.Reed@Sun.COM 	mh = d->bd_bif;
34511179SDarren.Reed@Sun.COM 	d->bd_bif = 0;
34610639SDarren.Reed@Sun.COM 
34710639SDarren.Reed@Sun.COM 	/*
34810639SDarren.Reed@Sun.COM 	 * Check if this descriptor had requested promiscuous mode.
34910639SDarren.Reed@Sun.COM 	 * If so, turn it off. There's no need to take any action
35010639SDarren.Reed@Sun.COM 	 * here, that is done when MBPF_PROMISC_REMOVE is used;
35110639SDarren.Reed@Sun.COM 	 * bd_promisc is just a local flag to stop promiscuous mode
35210639SDarren.Reed@Sun.COM 	 * from being set more than once.
35310639SDarren.Reed@Sun.COM 	 */
35410639SDarren.Reed@Sun.COM 	if (d->bd_promisc)
35510639SDarren.Reed@Sun.COM 		d->bd_promisc = 0;
35610639SDarren.Reed@Sun.COM 
35710639SDarren.Reed@Sun.COM 	/*
35810639SDarren.Reed@Sun.COM 	 * Take device out of "promiscuous" mode.  Since we were able to
35910639SDarren.Reed@Sun.COM 	 * enter "promiscuous" mode, we should be able to turn it off.
36010639SDarren.Reed@Sun.COM 	 * Note, this field stores a pointer used to support both
36110639SDarren.Reed@Sun.COM 	 * promiscuous and non-promiscuous callbacks for packets.
36210639SDarren.Reed@Sun.COM 	 */
36310639SDarren.Reed@Sun.COM 	mph = d->bd_promisc_handle;
36410639SDarren.Reed@Sun.COM 	d->bd_promisc_handle = 0;
36510639SDarren.Reed@Sun.COM 
36610639SDarren.Reed@Sun.COM 	/*
36710639SDarren.Reed@Sun.COM 	 * The lock has to be dropped here because mac_promisc_remove may
36810639SDarren.Reed@Sun.COM 	 * need to wait for mac_promisc_dispatch, which has called into
36910639SDarren.Reed@Sun.COM 	 * bpf and catchpacket is waiting for bd_lock...
37010639SDarren.Reed@Sun.COM 	 * i.e mac_promisc_remove() needs to be called with none of the
37110639SDarren.Reed@Sun.COM 	 * locks held that are part of the bpf_mtap() call path.
37210639SDarren.Reed@Sun.COM 	 */
37310639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
37410639SDarren.Reed@Sun.COM 	if (mph != 0)
37511179SDarren.Reed@Sun.COM 		MBPF_PROMISC_REMOVE(&d->bd_mac, mph);
37610639SDarren.Reed@Sun.COM 
37710639SDarren.Reed@Sun.COM 	if (mch != 0)
37811179SDarren.Reed@Sun.COM 		MBPF_CLIENT_CLOSE(&d->bd_mac, mch);
37910639SDarren.Reed@Sun.COM 
38011179SDarren.Reed@Sun.COM 	if (mh != 0)
38111179SDarren.Reed@Sun.COM 		MBPF_CLOSE(&d->bd_mac, mh);
38210639SDarren.Reed@Sun.COM 
38310639SDarren.Reed@Sun.COM 	/*
38410639SDarren.Reed@Sun.COM 	 * Because this function is called with bd_lock held, so it must
38510639SDarren.Reed@Sun.COM 	 * exit with it held.
38610639SDarren.Reed@Sun.COM 	 */
38710639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
38811179SDarren.Reed@Sun.COM 	*d->bd_ifname = '\0';
389*11187SDarren.Reed@Sun.COM 	(void) memset(&d->bd_mac, 0, sizeof (d->bd_mac));
39010639SDarren.Reed@Sun.COM }
39110639SDarren.Reed@Sun.COM 
39210639SDarren.Reed@Sun.COM 
39310639SDarren.Reed@Sun.COM /*
39410639SDarren.Reed@Sun.COM  * bpfilterattach() is called at load time.
39510639SDarren.Reed@Sun.COM  */
39610639SDarren.Reed@Sun.COM int
bpfilterattach(void)39710639SDarren.Reed@Sun.COM bpfilterattach(void)
39810639SDarren.Reed@Sun.COM {
39910639SDarren.Reed@Sun.COM 
40010639SDarren.Reed@Sun.COM 	bpf_hash = mod_hash_create_idhash("bpf_dev_tab", 31,
40110639SDarren.Reed@Sun.COM 	    mod_hash_null_keydtor);
40210639SDarren.Reed@Sun.COM 	if (bpf_hash == NULL)
40310639SDarren.Reed@Sun.COM 		return (ENOMEM);
40410639SDarren.Reed@Sun.COM 
40510639SDarren.Reed@Sun.COM 	(void) memcpy(&ks_stats, &bpf_kstats, sizeof (bpf_kstats));
40610639SDarren.Reed@Sun.COM 
40710639SDarren.Reed@Sun.COM 	bpf_ksp = kstat_create("bpf", 0, "global", "misc",
40810639SDarren.Reed@Sun.COM 	    KSTAT_TYPE_NAMED, sizeof (bpf_kstats) / sizeof (kstat_named_t),
40910639SDarren.Reed@Sun.COM 	    KSTAT_FLAG_VIRTUAL);
41010639SDarren.Reed@Sun.COM 	if (bpf_ksp != NULL) {
41110639SDarren.Reed@Sun.COM 		bpf_ksp->ks_data = &ks_stats;
41210639SDarren.Reed@Sun.COM 		kstat_install(bpf_ksp);
41310639SDarren.Reed@Sun.COM 	} else {
41410639SDarren.Reed@Sun.COM 		mod_hash_destroy_idhash(bpf_hash);
41510639SDarren.Reed@Sun.COM 		bpf_hash = NULL;
41610639SDarren.Reed@Sun.COM 		return (EEXIST);
41710639SDarren.Reed@Sun.COM 	}
41810639SDarren.Reed@Sun.COM 
41910639SDarren.Reed@Sun.COM 	cv_init(&bpf_dlt_waiter, NULL, CV_DRIVER, NULL);
42010639SDarren.Reed@Sun.COM 	mutex_init(&bpf_mtx, NULL, MUTEX_DRIVER, NULL);
42110639SDarren.Reed@Sun.COM 
42210639SDarren.Reed@Sun.COM 	LIST_INIT(&bpf_list);
42310639SDarren.Reed@Sun.COM 
42410639SDarren.Reed@Sun.COM 	return (0);
42510639SDarren.Reed@Sun.COM }
42610639SDarren.Reed@Sun.COM 
42710639SDarren.Reed@Sun.COM 
42810639SDarren.Reed@Sun.COM /*
42910639SDarren.Reed@Sun.COM  * bpfilterdetach() is called at unload time.
43010639SDarren.Reed@Sun.COM  */
43110639SDarren.Reed@Sun.COM int
bpfilterdetach(void)43210639SDarren.Reed@Sun.COM bpfilterdetach(void)
43310639SDarren.Reed@Sun.COM {
43410639SDarren.Reed@Sun.COM 
43510639SDarren.Reed@Sun.COM 	if (bpf_ksp != NULL) {
43610639SDarren.Reed@Sun.COM 		kstat_delete(bpf_ksp);
43710639SDarren.Reed@Sun.COM 		bpf_ksp = NULL;
43810639SDarren.Reed@Sun.COM 	}
43910639SDarren.Reed@Sun.COM 
44010639SDarren.Reed@Sun.COM 	mod_hash_destroy_idhash(bpf_hash);
44110639SDarren.Reed@Sun.COM 	bpf_hash = NULL;
44210639SDarren.Reed@Sun.COM 
44310639SDarren.Reed@Sun.COM 	cv_destroy(&bpf_dlt_waiter);
44410639SDarren.Reed@Sun.COM 	mutex_destroy(&bpf_mtx);
44510639SDarren.Reed@Sun.COM 
44610639SDarren.Reed@Sun.COM 	return (0);
44710639SDarren.Reed@Sun.COM }
44810639SDarren.Reed@Sun.COM 
44910639SDarren.Reed@Sun.COM /*
45010639SDarren.Reed@Sun.COM  * Open ethernet device. Clones.
45110639SDarren.Reed@Sun.COM  */
45210639SDarren.Reed@Sun.COM /* ARGSUSED */
45310639SDarren.Reed@Sun.COM int
bpfopen(dev_t * devp,int flag,int mode,cred_t * cred)45410639SDarren.Reed@Sun.COM bpfopen(dev_t *devp, int flag, int mode, cred_t *cred)
45510639SDarren.Reed@Sun.COM {
45610639SDarren.Reed@Sun.COM 	struct bpf_d *d;
45710639SDarren.Reed@Sun.COM 	uint_t dmin;
45810639SDarren.Reed@Sun.COM 
45910639SDarren.Reed@Sun.COM 	/*
46010639SDarren.Reed@Sun.COM 	 * The security policy described at the top of this file is
46110639SDarren.Reed@Sun.COM 	 * enforced here.
46210639SDarren.Reed@Sun.COM 	 */
46310639SDarren.Reed@Sun.COM 	if ((flag & FWRITE) != 0) {
46410639SDarren.Reed@Sun.COM 		if (secpolicy_net_rawaccess(cred) != 0)
46510639SDarren.Reed@Sun.COM 			return (EACCES);
46610639SDarren.Reed@Sun.COM 	}
46710639SDarren.Reed@Sun.COM 
46810639SDarren.Reed@Sun.COM 	if ((flag & FREAD) != 0) {
46910639SDarren.Reed@Sun.COM 		if ((secpolicy_net_observability(cred) != 0) &&
47010639SDarren.Reed@Sun.COM 		    (secpolicy_net_rawaccess(cred) != 0))
47110639SDarren.Reed@Sun.COM 			return (EACCES);
47210639SDarren.Reed@Sun.COM 	}
47310639SDarren.Reed@Sun.COM 
47410639SDarren.Reed@Sun.COM 	if ((flag & (FWRITE|FREAD)) == 0)
47510639SDarren.Reed@Sun.COM 		return (ENXIO);
47610639SDarren.Reed@Sun.COM 
47710639SDarren.Reed@Sun.COM 	/*
47810639SDarren.Reed@Sun.COM 	 * A structure is allocated per open file in BPF to store settings
47910639SDarren.Reed@Sun.COM 	 * such as buffer capture size, provide private buffers, etc.
48010639SDarren.Reed@Sun.COM 	 */
48110639SDarren.Reed@Sun.COM 	d = (struct bpf_d *)kmem_zalloc(sizeof (*d), KM_SLEEP);
48210639SDarren.Reed@Sun.COM 	d->bd_bufsize = bpf_bufsize;
48310639SDarren.Reed@Sun.COM 	d->bd_fmode = flag;
48410639SDarren.Reed@Sun.COM 	d->bd_zone = crgetzoneid(cred);
48510639SDarren.Reed@Sun.COM 	d->bd_seesent = 1;
48610639SDarren.Reed@Sun.COM 	d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_PHYS|
48710639SDarren.Reed@Sun.COM 	    MAC_PROMISC_FLAGS_NO_COPY;
48810639SDarren.Reed@Sun.COM 	mutex_init(&d->bd_lock, NULL, MUTEX_DRIVER, NULL);
48910639SDarren.Reed@Sun.COM 	cv_init(&d->bd_wait, NULL, CV_DRIVER, NULL);
49010639SDarren.Reed@Sun.COM 
49110639SDarren.Reed@Sun.COM 	mutex_enter(&bpf_mtx);
49210639SDarren.Reed@Sun.COM 	/*
49310639SDarren.Reed@Sun.COM 	 * Find an unused minor number. Obviously this is an O(n) algorithm
49410639SDarren.Reed@Sun.COM 	 * and doesn't scale particularly well, so if there are large numbers
49510639SDarren.Reed@Sun.COM 	 * of open file descriptors happening in real use, this design may
49610639SDarren.Reed@Sun.COM 	 * need to be revisited.
49710639SDarren.Reed@Sun.COM 	 */
49810639SDarren.Reed@Sun.COM 	for (dmin = 0; dmin < L_MAXMIN; dmin++)
49910639SDarren.Reed@Sun.COM 		if (bpf_dev_find(dmin) == NULL)
50010639SDarren.Reed@Sun.COM 			break;
50110639SDarren.Reed@Sun.COM 	if (dmin == L_MAXMIN) {
50210639SDarren.Reed@Sun.COM 		mutex_exit(&bpf_mtx);
50310639SDarren.Reed@Sun.COM 		kmem_free(d, sizeof (*d));
50410639SDarren.Reed@Sun.COM 		return (ENXIO);
50510639SDarren.Reed@Sun.COM 	}
50610639SDarren.Reed@Sun.COM 	d->bd_dev = dmin;
50710639SDarren.Reed@Sun.COM 	LIST_INSERT_HEAD(&bpf_list, d, bd_list);
50810639SDarren.Reed@Sun.COM 	bpf_dev_add(d);
50910639SDarren.Reed@Sun.COM 	mutex_exit(&bpf_mtx);
51010639SDarren.Reed@Sun.COM 
51110639SDarren.Reed@Sun.COM 	*devp = makedevice(getmajor(*devp), dmin);
51210639SDarren.Reed@Sun.COM 
51310639SDarren.Reed@Sun.COM 	return (0);
51410639SDarren.Reed@Sun.COM }
51510639SDarren.Reed@Sun.COM 
51610639SDarren.Reed@Sun.COM /*
51710639SDarren.Reed@Sun.COM  * Close the descriptor by detaching it from its interface,
51810639SDarren.Reed@Sun.COM  * deallocating its buffers, and marking it free.
51910639SDarren.Reed@Sun.COM  *
52010639SDarren.Reed@Sun.COM  * Because we only allow a device to be opened once, there is always a
52110639SDarren.Reed@Sun.COM  * 1 to 1 relationship between opens and closes supporting this function.
52210639SDarren.Reed@Sun.COM  */
52310639SDarren.Reed@Sun.COM /* ARGSUSED */
52410639SDarren.Reed@Sun.COM int
bpfclose(dev_t dev,int flag,int otyp,cred_t * cred_p)52510639SDarren.Reed@Sun.COM bpfclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
52610639SDarren.Reed@Sun.COM {
52710639SDarren.Reed@Sun.COM 	struct bpf_d *d = bpf_dev_get(getminor(dev));
52810639SDarren.Reed@Sun.COM 
52910639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
53011179SDarren.Reed@Sun.COM 
53111179SDarren.Reed@Sun.COM 	while (d->bd_inuse != 0) {
53211179SDarren.Reed@Sun.COM 		d->bd_waiting++;
53311179SDarren.Reed@Sun.COM 		if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
53411179SDarren.Reed@Sun.COM 			d->bd_waiting--;
53511179SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
53611179SDarren.Reed@Sun.COM 			return (EINTR);
53711179SDarren.Reed@Sun.COM 		}
53811179SDarren.Reed@Sun.COM 		d->bd_waiting--;
53911179SDarren.Reed@Sun.COM 	}
54011179SDarren.Reed@Sun.COM 
54111179SDarren.Reed@Sun.COM 	d->bd_inuse = -1;
54210639SDarren.Reed@Sun.COM 	if (d->bd_state == BPF_WAITING)
54310639SDarren.Reed@Sun.COM 		bpf_clear_timeout(d);
54410639SDarren.Reed@Sun.COM 	d->bd_state = BPF_IDLE;
54510639SDarren.Reed@Sun.COM 	if (d->bd_bif)
54610639SDarren.Reed@Sun.COM 		bpf_detachd(d);
54710639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
54810639SDarren.Reed@Sun.COM 
54910639SDarren.Reed@Sun.COM 	mutex_enter(&bpf_mtx);
55010639SDarren.Reed@Sun.COM 	LIST_REMOVE(d, bd_list);
55110639SDarren.Reed@Sun.COM 	bpf_dev_remove(d);
55210639SDarren.Reed@Sun.COM 	mutex_exit(&bpf_mtx);
55310639SDarren.Reed@Sun.COM 
55410639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
55510639SDarren.Reed@Sun.COM 	mutex_destroy(&d->bd_lock);
55610639SDarren.Reed@Sun.COM 	cv_destroy(&d->bd_wait);
55710639SDarren.Reed@Sun.COM 
55810639SDarren.Reed@Sun.COM 	bpf_freed(d);
55910639SDarren.Reed@Sun.COM 	kmem_free(d, sizeof (*d));
56010639SDarren.Reed@Sun.COM 
56110639SDarren.Reed@Sun.COM 	return (0);
56210639SDarren.Reed@Sun.COM }
56310639SDarren.Reed@Sun.COM 
56410639SDarren.Reed@Sun.COM /*
56510639SDarren.Reed@Sun.COM  * Rotate the packet buffers in descriptor d.  Move the store buffer
56610639SDarren.Reed@Sun.COM  * into the hold slot, and the free buffer into the store slot.
56710639SDarren.Reed@Sun.COM  * Zero the length of the new store buffer.
56810639SDarren.Reed@Sun.COM  */
56910639SDarren.Reed@Sun.COM #define	ROTATE_BUFFERS(d) \
57010639SDarren.Reed@Sun.COM 	(d)->bd_hbuf = (d)->bd_sbuf; \
57110639SDarren.Reed@Sun.COM 	(d)->bd_hlen = (d)->bd_slen; \
57210639SDarren.Reed@Sun.COM 	(d)->bd_sbuf = (d)->bd_fbuf; \
57310639SDarren.Reed@Sun.COM 	(d)->bd_slen = 0; \
57410639SDarren.Reed@Sun.COM 	(d)->bd_fbuf = 0;
57510639SDarren.Reed@Sun.COM /*
57610639SDarren.Reed@Sun.COM  *  bpfread - read next chunk of packets from buffers
57710639SDarren.Reed@Sun.COM  */
57810639SDarren.Reed@Sun.COM /* ARGSUSED */
57910639SDarren.Reed@Sun.COM int
bpfread(dev_t dev,struct uio * uio,cred_t * cred)58010639SDarren.Reed@Sun.COM bpfread(dev_t dev, struct uio *uio, cred_t *cred)
58110639SDarren.Reed@Sun.COM {
58210639SDarren.Reed@Sun.COM 	struct bpf_d *d = bpf_dev_get(getminor(dev));
58310639SDarren.Reed@Sun.COM 	int timed_out;
58410639SDarren.Reed@Sun.COM 	ulong_t delay;
58510639SDarren.Reed@Sun.COM 	int error;
58610639SDarren.Reed@Sun.COM 
58710639SDarren.Reed@Sun.COM 	if ((d->bd_fmode & FREAD) == 0)
58810639SDarren.Reed@Sun.COM 		return (EBADF);
58910639SDarren.Reed@Sun.COM 
59010639SDarren.Reed@Sun.COM 	/*
59110639SDarren.Reed@Sun.COM 	 * Restrict application to use a buffer the same size as
59210639SDarren.Reed@Sun.COM 	 * the kernel buffers.
59310639SDarren.Reed@Sun.COM 	 */
59410639SDarren.Reed@Sun.COM 	if (uio->uio_resid != d->bd_bufsize)
59510639SDarren.Reed@Sun.COM 		return (EINVAL);
59610639SDarren.Reed@Sun.COM 
59710639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
59810639SDarren.Reed@Sun.COM 	if (d->bd_state == BPF_WAITING)
59910639SDarren.Reed@Sun.COM 		bpf_clear_timeout(d);
60010639SDarren.Reed@Sun.COM 	timed_out = (d->bd_state == BPF_TIMED_OUT);
60110639SDarren.Reed@Sun.COM 	d->bd_state = BPF_IDLE;
60210639SDarren.Reed@Sun.COM 	/*
60310639SDarren.Reed@Sun.COM 	 * If the hold buffer is empty, then do a timed sleep, which
60410639SDarren.Reed@Sun.COM 	 * ends when the timeout expires or when enough packets
60510639SDarren.Reed@Sun.COM 	 * have arrived to fill the store buffer.
60610639SDarren.Reed@Sun.COM 	 */
60710639SDarren.Reed@Sun.COM 	while (d->bd_hbuf == 0) {
60810639SDarren.Reed@Sun.COM 		if (d->bd_nonblock) {
60910639SDarren.Reed@Sun.COM 			if (d->bd_slen == 0) {
61010639SDarren.Reed@Sun.COM 				mutex_exit(&d->bd_lock);
61110639SDarren.Reed@Sun.COM 				return (EWOULDBLOCK);
61210639SDarren.Reed@Sun.COM 			}
61310639SDarren.Reed@Sun.COM 			ROTATE_BUFFERS(d);
61410639SDarren.Reed@Sun.COM 			break;
61510639SDarren.Reed@Sun.COM 		}
61610639SDarren.Reed@Sun.COM 
61710639SDarren.Reed@Sun.COM 		if ((d->bd_immediate || timed_out) && d->bd_slen != 0) {
61810639SDarren.Reed@Sun.COM 			/*
61910639SDarren.Reed@Sun.COM 			 * A packet(s) either arrived since the previous
62010639SDarren.Reed@Sun.COM 			 * read or arrived while we were asleep.
62110639SDarren.Reed@Sun.COM 			 * Rotate the buffers and return what's here.
62210639SDarren.Reed@Sun.COM 			 */
62310639SDarren.Reed@Sun.COM 			ROTATE_BUFFERS(d);
62410639SDarren.Reed@Sun.COM 			break;
62510639SDarren.Reed@Sun.COM 		}
62610639SDarren.Reed@Sun.COM 		ks_stats.kp_read_wait.value.ui64++;
62710639SDarren.Reed@Sun.COM 		delay = ddi_get_lbolt() + d->bd_rtout;
62810639SDarren.Reed@Sun.COM 		error = cv_timedwait_sig(&d->bd_wait, &d->bd_lock, delay);
62910639SDarren.Reed@Sun.COM 		if (error == 0) {
63010639SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
63110639SDarren.Reed@Sun.COM 			return (EINTR);
63210639SDarren.Reed@Sun.COM 		}
63310639SDarren.Reed@Sun.COM 		if (error == -1) {
63410639SDarren.Reed@Sun.COM 			/*
63510639SDarren.Reed@Sun.COM 			 * On a timeout, return what's in the buffer,
63610639SDarren.Reed@Sun.COM 			 * which may be nothing.  If there is something
63710639SDarren.Reed@Sun.COM 			 * in the store buffer, we can rotate the buffers.
63810639SDarren.Reed@Sun.COM 			 */
63910639SDarren.Reed@Sun.COM 			if (d->bd_hbuf)
64010639SDarren.Reed@Sun.COM 				/*
64110639SDarren.Reed@Sun.COM 				 * We filled up the buffer in between
64210639SDarren.Reed@Sun.COM 				 * getting the timeout and arriving
64310639SDarren.Reed@Sun.COM 				 * here, so we don't need to rotate.
64410639SDarren.Reed@Sun.COM 				 */
64510639SDarren.Reed@Sun.COM 				break;
64610639SDarren.Reed@Sun.COM 
64710639SDarren.Reed@Sun.COM 			if (d->bd_slen == 0) {
64810639SDarren.Reed@Sun.COM 				mutex_exit(&d->bd_lock);
64910639SDarren.Reed@Sun.COM 				return (0);
65010639SDarren.Reed@Sun.COM 			}
65110639SDarren.Reed@Sun.COM 			ROTATE_BUFFERS(d);
65210639SDarren.Reed@Sun.COM 		}
65310639SDarren.Reed@Sun.COM 	}
65410639SDarren.Reed@Sun.COM 	/*
65510639SDarren.Reed@Sun.COM 	 * At this point, we know we have something in the hold slot.
65610639SDarren.Reed@Sun.COM 	 */
65710639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
65810639SDarren.Reed@Sun.COM 
65910639SDarren.Reed@Sun.COM 	/*
66010639SDarren.Reed@Sun.COM 	 * Move data from hold buffer into user space.
66110639SDarren.Reed@Sun.COM 	 * We know the entire buffer is transferred since
66210639SDarren.Reed@Sun.COM 	 * we checked above that the read buffer is bpf_bufsize bytes.
66310639SDarren.Reed@Sun.COM 	 */
66410639SDarren.Reed@Sun.COM 	error = uiomove(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);
66510639SDarren.Reed@Sun.COM 
66610639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
66710639SDarren.Reed@Sun.COM 	d->bd_fbuf = d->bd_hbuf;
66810639SDarren.Reed@Sun.COM 	d->bd_hbuf = 0;
66910639SDarren.Reed@Sun.COM 	d->bd_hlen = 0;
67010639SDarren.Reed@Sun.COM done:
67110639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
67210639SDarren.Reed@Sun.COM 	return (error);
67310639SDarren.Reed@Sun.COM }
67410639SDarren.Reed@Sun.COM 
67510639SDarren.Reed@Sun.COM 
67610639SDarren.Reed@Sun.COM /*
67710639SDarren.Reed@Sun.COM  * If there are processes sleeping on this descriptor, wake them up.
67810639SDarren.Reed@Sun.COM  * NOTE: the lock for bd_wait is bd_lock and is held by bpf_deliver,
67910639SDarren.Reed@Sun.COM  * so there is no code here grabbing it.
68010639SDarren.Reed@Sun.COM  */
68110639SDarren.Reed@Sun.COM static inline void
bpf_wakeup(struct bpf_d * d)68210639SDarren.Reed@Sun.COM bpf_wakeup(struct bpf_d *d)
68310639SDarren.Reed@Sun.COM {
68410639SDarren.Reed@Sun.COM 	cv_signal(&d->bd_wait);
68510639SDarren.Reed@Sun.COM }
68610639SDarren.Reed@Sun.COM 
68710639SDarren.Reed@Sun.COM static void
bpf_timed_out(void * arg)68810639SDarren.Reed@Sun.COM bpf_timed_out(void *arg)
68910639SDarren.Reed@Sun.COM {
69010639SDarren.Reed@Sun.COM 	struct bpf_d *d = arg;
69110639SDarren.Reed@Sun.COM 
69210639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
69310639SDarren.Reed@Sun.COM 	if (d->bd_state == BPF_WAITING) {
69410639SDarren.Reed@Sun.COM 		d->bd_state = BPF_TIMED_OUT;
69510639SDarren.Reed@Sun.COM 		if (d->bd_slen != 0)
69610639SDarren.Reed@Sun.COM 			cv_signal(&d->bd_wait);
69710639SDarren.Reed@Sun.COM 	}
69810639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
69910639SDarren.Reed@Sun.COM }
70010639SDarren.Reed@Sun.COM 
70110639SDarren.Reed@Sun.COM 
70210639SDarren.Reed@Sun.COM /* ARGSUSED */
70310639SDarren.Reed@Sun.COM int
bpfwrite(dev_t dev,struct uio * uio,cred_t * cred)70410639SDarren.Reed@Sun.COM bpfwrite(dev_t dev, struct uio *uio, cred_t *cred)
70510639SDarren.Reed@Sun.COM {
70610639SDarren.Reed@Sun.COM 	struct bpf_d *d = bpf_dev_get(getminor(dev));
70710639SDarren.Reed@Sun.COM 	uintptr_t mch;
70810639SDarren.Reed@Sun.COM 	uint_t mtu;
70910639SDarren.Reed@Sun.COM 	mblk_t *m;
71010639SDarren.Reed@Sun.COM 	int error;
71110639SDarren.Reed@Sun.COM 	int dlt;
71210639SDarren.Reed@Sun.COM 
71310639SDarren.Reed@Sun.COM 	if ((d->bd_fmode & FWRITE) == 0)
71410639SDarren.Reed@Sun.COM 		return (EBADF);
71510639SDarren.Reed@Sun.COM 
71610639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
71711179SDarren.Reed@Sun.COM 	if (d->bd_bif == 0 || d->bd_mcip == 0 || d->bd_bif == 0) {
71810639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
71910639SDarren.Reed@Sun.COM 		return (EINTR);
72010639SDarren.Reed@Sun.COM 	}
72110639SDarren.Reed@Sun.COM 
72210639SDarren.Reed@Sun.COM 	if (uio->uio_resid == 0) {
72310639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
72410639SDarren.Reed@Sun.COM 		return (0);
72510639SDarren.Reed@Sun.COM 	}
72610639SDarren.Reed@Sun.COM 
72710639SDarren.Reed@Sun.COM 	while (d->bd_inuse < 0) {
72810639SDarren.Reed@Sun.COM 		d->bd_waiting++;
72910639SDarren.Reed@Sun.COM 		if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
73010639SDarren.Reed@Sun.COM 			d->bd_waiting--;
73110639SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
73210639SDarren.Reed@Sun.COM 			return (EINTR);
73310639SDarren.Reed@Sun.COM 		}
73410639SDarren.Reed@Sun.COM 		d->bd_waiting--;
73510639SDarren.Reed@Sun.COM 	}
73610639SDarren.Reed@Sun.COM 
73710639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
73810639SDarren.Reed@Sun.COM 
73911179SDarren.Reed@Sun.COM 	dlt = d->bd_dlt;
74010639SDarren.Reed@Sun.COM 	mch = d->bd_mcip;
74111179SDarren.Reed@Sun.COM 	MBPF_SDU_GET(&d->bd_mac, d->bd_bif, &mtu);
74210639SDarren.Reed@Sun.COM 	d->bd_inuse++;
74310639SDarren.Reed@Sun.COM 
74410639SDarren.Reed@Sun.COM 	m = NULL;
74510639SDarren.Reed@Sun.COM 	if (dlt == DLT_IPNET) {
74610639SDarren.Reed@Sun.COM 		error = EIO;
74710639SDarren.Reed@Sun.COM 		goto done;
74810639SDarren.Reed@Sun.COM 	}
74910639SDarren.Reed@Sun.COM 
75010639SDarren.Reed@Sun.COM 	error = bpf_movein(uio, dlt, mtu, &m);
75110639SDarren.Reed@Sun.COM 	if (error)
75210639SDarren.Reed@Sun.COM 		goto done;
75310639SDarren.Reed@Sun.COM 
75411179SDarren.Reed@Sun.COM 	DTRACE_PROBE4(bpf__tx, struct bpf_d *, d, int, dlt,
75511179SDarren.Reed@Sun.COM 	    uint_t, mtu, mblk_t *, m);
75610639SDarren.Reed@Sun.COM 
75710639SDarren.Reed@Sun.COM 	if (M_LEN(m) > mtu) {
75810639SDarren.Reed@Sun.COM 		error = EMSGSIZE;
75910639SDarren.Reed@Sun.COM 		goto done;
76010639SDarren.Reed@Sun.COM 	}
76110639SDarren.Reed@Sun.COM 
76211179SDarren.Reed@Sun.COM 	error = MBPF_TX(&d->bd_mac, mch, m);
76310639SDarren.Reed@Sun.COM 	/*
76410639SDarren.Reed@Sun.COM 	 * The "tx" action here is required to consume the mblk_t.
76510639SDarren.Reed@Sun.COM 	 */
76610639SDarren.Reed@Sun.COM 	m = NULL;
76710639SDarren.Reed@Sun.COM 
76810639SDarren.Reed@Sun.COM done:
76910639SDarren.Reed@Sun.COM 	if (error == 0)
77010639SDarren.Reed@Sun.COM 		ks_stats.kp_write_ok.value.ui64++;
77110639SDarren.Reed@Sun.COM 	else
77210639SDarren.Reed@Sun.COM 		ks_stats.kp_write_error.value.ui64++;
77310639SDarren.Reed@Sun.COM 	if (m != NULL)
77410639SDarren.Reed@Sun.COM 		freemsg(m);
77510639SDarren.Reed@Sun.COM 
77610639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
77710639SDarren.Reed@Sun.COM 	d->bd_inuse--;
77810639SDarren.Reed@Sun.COM 	if ((d->bd_inuse == 0) && (d->bd_waiting != 0))
77910639SDarren.Reed@Sun.COM 		cv_signal(&d->bd_wait);
78010639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
78110639SDarren.Reed@Sun.COM 
78210639SDarren.Reed@Sun.COM 	/*
78310639SDarren.Reed@Sun.COM 	 * The driver frees the mbuf.
78410639SDarren.Reed@Sun.COM 	 */
78510639SDarren.Reed@Sun.COM 	return (error);
78610639SDarren.Reed@Sun.COM }
78710639SDarren.Reed@Sun.COM 
78810639SDarren.Reed@Sun.COM 
78910639SDarren.Reed@Sun.COM /*
79010639SDarren.Reed@Sun.COM  * Reset a descriptor by flushing its packet buffer and clearing the
79110639SDarren.Reed@Sun.COM  * receive and drop counts.  Should be called at splnet.
79210639SDarren.Reed@Sun.COM  */
79310639SDarren.Reed@Sun.COM static void
reset_d(struct bpf_d * d)79410639SDarren.Reed@Sun.COM reset_d(struct bpf_d *d)
79510639SDarren.Reed@Sun.COM {
79610639SDarren.Reed@Sun.COM 	if (d->bd_hbuf) {
79710639SDarren.Reed@Sun.COM 		/* Free the hold buffer. */
79810639SDarren.Reed@Sun.COM 		d->bd_fbuf = d->bd_hbuf;
79910639SDarren.Reed@Sun.COM 		d->bd_hbuf = 0;
80010639SDarren.Reed@Sun.COM 	}
80110639SDarren.Reed@Sun.COM 	d->bd_slen = 0;
80210639SDarren.Reed@Sun.COM 	d->bd_hlen = 0;
80310639SDarren.Reed@Sun.COM 	d->bd_rcount = 0;
80410639SDarren.Reed@Sun.COM 	d->bd_dcount = 0;
80510639SDarren.Reed@Sun.COM 	d->bd_ccount = 0;
80610639SDarren.Reed@Sun.COM }
80710639SDarren.Reed@Sun.COM 
80810639SDarren.Reed@Sun.COM /*
80910639SDarren.Reed@Sun.COM  *  FIONREAD		Check for read packet available.
81010639SDarren.Reed@Sun.COM  *  BIOCGBLEN		Get buffer len [for read()].
81110639SDarren.Reed@Sun.COM  *  BIOCSETF		Set ethernet read filter.
81210639SDarren.Reed@Sun.COM  *  BIOCFLUSH		Flush read packet buffer.
81310639SDarren.Reed@Sun.COM  *  BIOCPROMISC		Put interface into promiscuous mode.
81410639SDarren.Reed@Sun.COM  *  BIOCGDLT		Get link layer type.
81510639SDarren.Reed@Sun.COM  *  BIOCGETIF		Get interface name.
81610639SDarren.Reed@Sun.COM  *  BIOCSETIF		Set interface.
81710639SDarren.Reed@Sun.COM  *  BIOCSRTIMEOUT	Set read timeout.
81810639SDarren.Reed@Sun.COM  *  BIOCGRTIMEOUT	Get read timeout.
81910639SDarren.Reed@Sun.COM  *  BIOCGSTATS		Get packet stats.
82010639SDarren.Reed@Sun.COM  *  BIOCIMMEDIATE	Set immediate mode.
82110639SDarren.Reed@Sun.COM  *  BIOCVERSION		Get filter language version.
82210639SDarren.Reed@Sun.COM  *  BIOCGHDRCMPLT	Get "header already complete" flag.
82310639SDarren.Reed@Sun.COM  *  BIOCSHDRCMPLT	Set "header already complete" flag.
82410639SDarren.Reed@Sun.COM  */
82510639SDarren.Reed@Sun.COM /* ARGSUSED */
82610639SDarren.Reed@Sun.COM int
bpfioctl(dev_t dev,int cmd,intptr_t addr,int mode,cred_t * cred,int * rval)82710639SDarren.Reed@Sun.COM bpfioctl(dev_t dev, int cmd, intptr_t addr, int mode, cred_t *cred, int *rval)
82810639SDarren.Reed@Sun.COM {
82910639SDarren.Reed@Sun.COM 	struct bpf_d *d = bpf_dev_get(getminor(dev));
83010639SDarren.Reed@Sun.COM 	struct bpf_program prog;
83110639SDarren.Reed@Sun.COM 	struct lifreq lifreq;
83210639SDarren.Reed@Sun.COM 	struct ifreq ifreq;
83310639SDarren.Reed@Sun.COM 	int error = 0;
83410639SDarren.Reed@Sun.COM 	uint_t size;
83510639SDarren.Reed@Sun.COM 
83610639SDarren.Reed@Sun.COM 	/*
83710639SDarren.Reed@Sun.COM 	 * Refresh the PID associated with this bpf file.
83810639SDarren.Reed@Sun.COM 	 */
83910639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
84010639SDarren.Reed@Sun.COM 	if (d->bd_state == BPF_WAITING)
84110639SDarren.Reed@Sun.COM 		bpf_clear_timeout(d);
84210639SDarren.Reed@Sun.COM 	d->bd_state = BPF_IDLE;
84310639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
84410639SDarren.Reed@Sun.COM 
84510639SDarren.Reed@Sun.COM 	switch (cmd) {
84610639SDarren.Reed@Sun.COM 
84710639SDarren.Reed@Sun.COM 	default:
84810639SDarren.Reed@Sun.COM 		error = EINVAL;
84910639SDarren.Reed@Sun.COM 		break;
85010639SDarren.Reed@Sun.COM 
85110639SDarren.Reed@Sun.COM 	/*
85210639SDarren.Reed@Sun.COM 	 * Check for read packet available.
85310639SDarren.Reed@Sun.COM 	 */
85410639SDarren.Reed@Sun.COM 	case FIONREAD:
85510639SDarren.Reed@Sun.COM 		{
85610639SDarren.Reed@Sun.COM 			int n;
85710639SDarren.Reed@Sun.COM 
85810639SDarren.Reed@Sun.COM 			mutex_enter(&d->bd_lock);
85910639SDarren.Reed@Sun.COM 			n = d->bd_slen;
86010639SDarren.Reed@Sun.COM 			if (d->bd_hbuf)
86110639SDarren.Reed@Sun.COM 				n += d->bd_hlen;
86210639SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
86310639SDarren.Reed@Sun.COM 
86410639SDarren.Reed@Sun.COM 			*(int *)addr = n;
86510639SDarren.Reed@Sun.COM 			break;
86610639SDarren.Reed@Sun.COM 		}
86710639SDarren.Reed@Sun.COM 
86810639SDarren.Reed@Sun.COM 	/*
86910639SDarren.Reed@Sun.COM 	 * Get buffer len [for read()].
87010639SDarren.Reed@Sun.COM 	 */
87110639SDarren.Reed@Sun.COM 	case BIOCGBLEN:
87210639SDarren.Reed@Sun.COM 		error = copyout(&d->bd_bufsize, (void *)addr,
87310639SDarren.Reed@Sun.COM 		    sizeof (d->bd_bufsize));
87410639SDarren.Reed@Sun.COM 		break;
87510639SDarren.Reed@Sun.COM 
87610639SDarren.Reed@Sun.COM 	/*
87710639SDarren.Reed@Sun.COM 	 * Set buffer length.
87810639SDarren.Reed@Sun.COM 	 */
87910639SDarren.Reed@Sun.COM 	case BIOCSBLEN:
88010639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &size, sizeof (size)) != 0) {
88110639SDarren.Reed@Sun.COM 			error = EFAULT;
88210639SDarren.Reed@Sun.COM 			break;
88310639SDarren.Reed@Sun.COM 		}
88410639SDarren.Reed@Sun.COM 
88510639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
88610639SDarren.Reed@Sun.COM 		if (d->bd_bif != 0) {
88710639SDarren.Reed@Sun.COM 			error = EINVAL;
88810639SDarren.Reed@Sun.COM 		} else {
88910639SDarren.Reed@Sun.COM 			if (size > bpf_maxbufsize)
89010639SDarren.Reed@Sun.COM 				size = bpf_maxbufsize;
89110639SDarren.Reed@Sun.COM 			else if (size < BPF_MINBUFSIZE)
89210639SDarren.Reed@Sun.COM 				size = BPF_MINBUFSIZE;
89310639SDarren.Reed@Sun.COM 
89410639SDarren.Reed@Sun.COM 			d->bd_bufsize = size;
89510639SDarren.Reed@Sun.COM 		}
89610639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
89710639SDarren.Reed@Sun.COM 
89810639SDarren.Reed@Sun.COM 		if (error == 0)
89910639SDarren.Reed@Sun.COM 			error = copyout(&size, (void *)addr, sizeof (size));
90010639SDarren.Reed@Sun.COM 		break;
90110639SDarren.Reed@Sun.COM 
90210639SDarren.Reed@Sun.COM 	/*
90310639SDarren.Reed@Sun.COM 	 * Set link layer read filter.
90410639SDarren.Reed@Sun.COM 	 */
90510639SDarren.Reed@Sun.COM 	case BIOCSETF:
90610639SDarren.Reed@Sun.COM 		if (ddi_copyin((void *)addr, &prog, sizeof (prog), mode)) {
90710639SDarren.Reed@Sun.COM 			error = EFAULT;
90810639SDarren.Reed@Sun.COM 			break;
90910639SDarren.Reed@Sun.COM 		}
91010639SDarren.Reed@Sun.COM 		error = bpf_setf(d, &prog);
91110639SDarren.Reed@Sun.COM 		break;
91210639SDarren.Reed@Sun.COM 
91310639SDarren.Reed@Sun.COM 	/*
91410639SDarren.Reed@Sun.COM 	 * Flush read packet buffer.
91510639SDarren.Reed@Sun.COM 	 */
91610639SDarren.Reed@Sun.COM 	case BIOCFLUSH:
91710639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
91810639SDarren.Reed@Sun.COM 		reset_d(d);
91910639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
92010639SDarren.Reed@Sun.COM 		break;
92110639SDarren.Reed@Sun.COM 
92210639SDarren.Reed@Sun.COM 	/*
92310639SDarren.Reed@Sun.COM 	 * Put interface into promiscuous mode.
92410639SDarren.Reed@Sun.COM 	 * This is a one-way ioctl, it is not used to turn promiscuous
92510639SDarren.Reed@Sun.COM 	 * mode off.
92610639SDarren.Reed@Sun.COM 	 */
92710639SDarren.Reed@Sun.COM 	case BIOCPROMISC:
92810639SDarren.Reed@Sun.COM 		if (d->bd_bif == 0) {
92910639SDarren.Reed@Sun.COM 			/*
93010639SDarren.Reed@Sun.COM 			 * No interface attached yet.
93110639SDarren.Reed@Sun.COM 			 */
93210639SDarren.Reed@Sun.COM 			error = EINVAL;
93310639SDarren.Reed@Sun.COM 			break;
93410639SDarren.Reed@Sun.COM 		}
93510639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
93610639SDarren.Reed@Sun.COM 		if (d->bd_promisc == 0) {
93710639SDarren.Reed@Sun.COM 
93810639SDarren.Reed@Sun.COM 			if (d->bd_promisc_handle) {
93910639SDarren.Reed@Sun.COM 				uintptr_t mph;
94010639SDarren.Reed@Sun.COM 
94110639SDarren.Reed@Sun.COM 				mph = d->bd_promisc_handle;
94210639SDarren.Reed@Sun.COM 				d->bd_promisc_handle = 0;
94310639SDarren.Reed@Sun.COM 
94410639SDarren.Reed@Sun.COM 				mutex_exit(&d->bd_lock);
94511179SDarren.Reed@Sun.COM 				MBPF_PROMISC_REMOVE(&d->bd_mac, mph);
94610639SDarren.Reed@Sun.COM 				mutex_enter(&d->bd_lock);
94710639SDarren.Reed@Sun.COM 			}
94810639SDarren.Reed@Sun.COM 
94910639SDarren.Reed@Sun.COM 			d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_COPY;
95011179SDarren.Reed@Sun.COM 			error = MBPF_PROMISC_ADD(&d->bd_mac,
95110639SDarren.Reed@Sun.COM 			    d->bd_mcip, MAC_CLIENT_PROMISC_ALL, d,
95210639SDarren.Reed@Sun.COM 			    &d->bd_promisc_handle, d->bd_promisc_flags);
95310639SDarren.Reed@Sun.COM 			if (error == 0)
95410639SDarren.Reed@Sun.COM 				d->bd_promisc = 1;
95510639SDarren.Reed@Sun.COM 		}
95610639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
95710639SDarren.Reed@Sun.COM 		break;
95810639SDarren.Reed@Sun.COM 
95910639SDarren.Reed@Sun.COM 	/*
96010639SDarren.Reed@Sun.COM 	 * Get device parameters.
96110639SDarren.Reed@Sun.COM 	 */
96210639SDarren.Reed@Sun.COM 	case BIOCGDLT:
96310639SDarren.Reed@Sun.COM 		if (d->bd_bif == 0)
96410639SDarren.Reed@Sun.COM 			error = EINVAL;
96510639SDarren.Reed@Sun.COM 		else
96611179SDarren.Reed@Sun.COM 			error = copyout(&d->bd_dlt, (void *)addr,
96711179SDarren.Reed@Sun.COM 			    sizeof (d->bd_dlt));
96810639SDarren.Reed@Sun.COM 		break;
96910639SDarren.Reed@Sun.COM 
97010639SDarren.Reed@Sun.COM 	/*
97110639SDarren.Reed@Sun.COM 	 * Get a list of supported device parameters.
97210639SDarren.Reed@Sun.COM 	 */
97310639SDarren.Reed@Sun.COM 	case BIOCGDLTLIST:
97410639SDarren.Reed@Sun.COM 		if (d->bd_bif == 0) {
97510639SDarren.Reed@Sun.COM 			error = EINVAL;
97610639SDarren.Reed@Sun.COM 		} else {
97710639SDarren.Reed@Sun.COM 			struct bpf_dltlist list;
97810639SDarren.Reed@Sun.COM 
97910639SDarren.Reed@Sun.COM 			if (copyin((void *)addr, &list, sizeof (list)) != 0) {
98010639SDarren.Reed@Sun.COM 				error = EFAULT;
98110639SDarren.Reed@Sun.COM 				break;
98210639SDarren.Reed@Sun.COM 			}
98310639SDarren.Reed@Sun.COM 			error = bpf_getdltlist(d, &list);
98410639SDarren.Reed@Sun.COM 			if ((error == 0) &&
98510639SDarren.Reed@Sun.COM 			    copyout(&list, (void *)addr, sizeof (list)) != 0)
98610639SDarren.Reed@Sun.COM 				error = EFAULT;
98710639SDarren.Reed@Sun.COM 		}
98810639SDarren.Reed@Sun.COM 		break;
98910639SDarren.Reed@Sun.COM 
99010639SDarren.Reed@Sun.COM 	/*
99110639SDarren.Reed@Sun.COM 	 * Set device parameters.
99210639SDarren.Reed@Sun.COM 	 */
99310639SDarren.Reed@Sun.COM 	case BIOCSDLT:
99410639SDarren.Reed@Sun.COM 		error = bpf_setdlt(d, (void *)addr);
99510639SDarren.Reed@Sun.COM 		break;
99610639SDarren.Reed@Sun.COM 
99710639SDarren.Reed@Sun.COM 	/*
99810639SDarren.Reed@Sun.COM 	 * Get interface name.
99910639SDarren.Reed@Sun.COM 	 */
100010639SDarren.Reed@Sun.COM 	case BIOCGETIF:
100110639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
100210639SDarren.Reed@Sun.COM 			error = EFAULT;
100310639SDarren.Reed@Sun.COM 			break;
100410639SDarren.Reed@Sun.COM 		}
100510639SDarren.Reed@Sun.COM 		error = bpf_ifname(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
100610639SDarren.Reed@Sun.COM 		if ((error == 0) &&
100710639SDarren.Reed@Sun.COM 		    copyout(&ifreq, (void *)addr, sizeof (ifreq)) != 0) {
100810639SDarren.Reed@Sun.COM 			error = EFAULT;
100910639SDarren.Reed@Sun.COM 			break;
101010639SDarren.Reed@Sun.COM 		}
101110639SDarren.Reed@Sun.COM 		break;
101210639SDarren.Reed@Sun.COM 
101310639SDarren.Reed@Sun.COM 	/*
101410639SDarren.Reed@Sun.COM 	 * Set interface.
101510639SDarren.Reed@Sun.COM 	 */
101610639SDarren.Reed@Sun.COM 	case BIOCSETIF:
101710639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
101810639SDarren.Reed@Sun.COM 			error = EFAULT;
101910639SDarren.Reed@Sun.COM 			break;
102010639SDarren.Reed@Sun.COM 		}
102110639SDarren.Reed@Sun.COM 		error = bpf_setif(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
102210639SDarren.Reed@Sun.COM 		break;
102310639SDarren.Reed@Sun.COM 
102410639SDarren.Reed@Sun.COM 	/*
102510639SDarren.Reed@Sun.COM 	 * Get interface name.
102610639SDarren.Reed@Sun.COM 	 */
102710639SDarren.Reed@Sun.COM 	case BIOCGETLIF:
102810639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
102910639SDarren.Reed@Sun.COM 			error = EFAULT;
103010639SDarren.Reed@Sun.COM 			break;
103110639SDarren.Reed@Sun.COM 		}
103210639SDarren.Reed@Sun.COM 		error = bpf_ifname(d, lifreq.lifr_name,
103310639SDarren.Reed@Sun.COM 		    sizeof (lifreq.lifr_name));
103410639SDarren.Reed@Sun.COM 		if ((error == 0) &&
103510639SDarren.Reed@Sun.COM 		    copyout(&lifreq, (void *)addr, sizeof (lifreq)) != 0) {
103610639SDarren.Reed@Sun.COM 			error = EFAULT;
103710639SDarren.Reed@Sun.COM 			break;
103810639SDarren.Reed@Sun.COM 		}
103910639SDarren.Reed@Sun.COM 		break;
104010639SDarren.Reed@Sun.COM 
104110639SDarren.Reed@Sun.COM 	/*
104210639SDarren.Reed@Sun.COM 	 * Set interface.
104310639SDarren.Reed@Sun.COM 	 */
104410639SDarren.Reed@Sun.COM 	case BIOCSETLIF:
104510639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
104610639SDarren.Reed@Sun.COM 			error = EFAULT;
104710639SDarren.Reed@Sun.COM 			break;
104810639SDarren.Reed@Sun.COM 		}
104910639SDarren.Reed@Sun.COM 		error = bpf_setif(d, lifreq.lifr_name,
105010639SDarren.Reed@Sun.COM 		    sizeof (lifreq.lifr_name));
105110639SDarren.Reed@Sun.COM 		break;
105210639SDarren.Reed@Sun.COM 
105310639SDarren.Reed@Sun.COM #ifdef _SYSCALL32_IMPL
105410639SDarren.Reed@Sun.COM 	/*
105510639SDarren.Reed@Sun.COM 	 * Set read timeout.
105610639SDarren.Reed@Sun.COM 	 */
105710639SDarren.Reed@Sun.COM 	case BIOCSRTIMEOUT32:
105810639SDarren.Reed@Sun.COM 		{
105910639SDarren.Reed@Sun.COM 			struct timeval32 tv;
106010639SDarren.Reed@Sun.COM 
106110639SDarren.Reed@Sun.COM 			if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
106210639SDarren.Reed@Sun.COM 				error = EFAULT;
106310639SDarren.Reed@Sun.COM 				break;
106410639SDarren.Reed@Sun.COM 			}
106510639SDarren.Reed@Sun.COM 
106610639SDarren.Reed@Sun.COM 			/* Convert the timeout in microseconds to ticks */
106710639SDarren.Reed@Sun.COM 			d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
106810639SDarren.Reed@Sun.COM 			    tv.tv_usec);
106910639SDarren.Reed@Sun.COM 			if ((d->bd_rtout == 0) && (tv.tv_usec != 0))
107010639SDarren.Reed@Sun.COM 				d->bd_rtout = 1;
107110639SDarren.Reed@Sun.COM 			break;
107210639SDarren.Reed@Sun.COM 		}
107310639SDarren.Reed@Sun.COM 
107410639SDarren.Reed@Sun.COM 	/*
107510639SDarren.Reed@Sun.COM 	 * Get read timeout.
107610639SDarren.Reed@Sun.COM 	 */
107710639SDarren.Reed@Sun.COM 	case BIOCGRTIMEOUT32:
107810639SDarren.Reed@Sun.COM 		{
107910639SDarren.Reed@Sun.COM 			struct timeval32 tv;
108010639SDarren.Reed@Sun.COM 			clock_t ticks;
108110639SDarren.Reed@Sun.COM 
108210639SDarren.Reed@Sun.COM 			ticks = drv_hztousec(d->bd_rtout);
108310639SDarren.Reed@Sun.COM 			tv.tv_sec = ticks / 1000000;
108410639SDarren.Reed@Sun.COM 			tv.tv_usec = ticks - (tv.tv_sec * 1000000);
108510639SDarren.Reed@Sun.COM 			error = copyout(&tv, (void *)addr, sizeof (tv));
108610639SDarren.Reed@Sun.COM 			break;
108710639SDarren.Reed@Sun.COM 		}
108810639SDarren.Reed@Sun.COM 
108910639SDarren.Reed@Sun.COM 	/*
109010639SDarren.Reed@Sun.COM 	 * Get a list of supported device parameters.
109110639SDarren.Reed@Sun.COM 	 */
109210639SDarren.Reed@Sun.COM 	case BIOCGDLTLIST32:
109310639SDarren.Reed@Sun.COM 		if (d->bd_bif == 0) {
109410639SDarren.Reed@Sun.COM 			error = EINVAL;
109510639SDarren.Reed@Sun.COM 		} else {
109610639SDarren.Reed@Sun.COM 			struct bpf_dltlist32 lst32;
109710639SDarren.Reed@Sun.COM 			struct bpf_dltlist list;
109810639SDarren.Reed@Sun.COM 
109910639SDarren.Reed@Sun.COM 			if (copyin((void *)addr, &lst32, sizeof (lst32)) != 0) {
110010639SDarren.Reed@Sun.COM 				error = EFAULT;
110110639SDarren.Reed@Sun.COM 				break;
110210639SDarren.Reed@Sun.COM 			}
110310639SDarren.Reed@Sun.COM 
110410639SDarren.Reed@Sun.COM 			list.bfl_len = lst32.bfl_len;
110510639SDarren.Reed@Sun.COM 			list.bfl_list = (void *)(uint64_t)lst32.bfl_list;
110610639SDarren.Reed@Sun.COM 			error = bpf_getdltlist(d, &list);
110710639SDarren.Reed@Sun.COM 			if (error == 0) {
110810639SDarren.Reed@Sun.COM 				lst32.bfl_len = list.bfl_len;
110910639SDarren.Reed@Sun.COM 
111010639SDarren.Reed@Sun.COM 				if (copyout(&lst32, (void *)addr,
111110639SDarren.Reed@Sun.COM 				    sizeof (lst32)) != 0)
111210639SDarren.Reed@Sun.COM 					error = EFAULT;
111310639SDarren.Reed@Sun.COM 			}
111410639SDarren.Reed@Sun.COM 		}
111510639SDarren.Reed@Sun.COM 		break;
111610639SDarren.Reed@Sun.COM 
111710639SDarren.Reed@Sun.COM 	/*
111810639SDarren.Reed@Sun.COM 	 * Set link layer read filter.
111910639SDarren.Reed@Sun.COM 	 */
112010639SDarren.Reed@Sun.COM 	case BIOCSETF32: {
112110639SDarren.Reed@Sun.COM 		struct bpf_program32 prog32;
112210639SDarren.Reed@Sun.COM 
112310639SDarren.Reed@Sun.COM 		if (ddi_copyin((void *)addr, &prog32, sizeof (prog), mode)) {
112410639SDarren.Reed@Sun.COM 			error = EFAULT;
112510639SDarren.Reed@Sun.COM 			break;
112610639SDarren.Reed@Sun.COM 		}
112710639SDarren.Reed@Sun.COM 		prog.bf_len = prog32.bf_len;
112810639SDarren.Reed@Sun.COM 		prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
112910639SDarren.Reed@Sun.COM 		error = bpf_setf(d, &prog);
113010639SDarren.Reed@Sun.COM 		break;
113110639SDarren.Reed@Sun.COM 	}
113210639SDarren.Reed@Sun.COM #endif
113310639SDarren.Reed@Sun.COM 
113410639SDarren.Reed@Sun.COM 	/*
113510639SDarren.Reed@Sun.COM 	 * Set read timeout.
113610639SDarren.Reed@Sun.COM 	 */
113710639SDarren.Reed@Sun.COM 	case BIOCSRTIMEOUT:
113810639SDarren.Reed@Sun.COM 		{
113910639SDarren.Reed@Sun.COM 			struct timeval tv;
114010639SDarren.Reed@Sun.COM 
114110639SDarren.Reed@Sun.COM 			if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
114210639SDarren.Reed@Sun.COM 				error = EFAULT;
114310639SDarren.Reed@Sun.COM 				break;
114410639SDarren.Reed@Sun.COM 			}
114510639SDarren.Reed@Sun.COM 
114610639SDarren.Reed@Sun.COM 			/* Convert the timeout in microseconds to ticks */
114710639SDarren.Reed@Sun.COM 			d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
114810639SDarren.Reed@Sun.COM 			    tv.tv_usec);
114910639SDarren.Reed@Sun.COM 			if ((d->bd_rtout == 0) && (tv.tv_usec != 0))
115010639SDarren.Reed@Sun.COM 				d->bd_rtout = 1;
115110639SDarren.Reed@Sun.COM 			break;
115210639SDarren.Reed@Sun.COM 		}
115310639SDarren.Reed@Sun.COM 
115410639SDarren.Reed@Sun.COM 	/*
115510639SDarren.Reed@Sun.COM 	 * Get read timeout.
115610639SDarren.Reed@Sun.COM 	 */
115710639SDarren.Reed@Sun.COM 	case BIOCGRTIMEOUT:
115810639SDarren.Reed@Sun.COM 		{
115910639SDarren.Reed@Sun.COM 			struct timeval tv;
116010639SDarren.Reed@Sun.COM 			clock_t ticks;
116110639SDarren.Reed@Sun.COM 
116210639SDarren.Reed@Sun.COM 			ticks = drv_hztousec(d->bd_rtout);
116310639SDarren.Reed@Sun.COM 			tv.tv_sec = ticks / 1000000;
116410639SDarren.Reed@Sun.COM 			tv.tv_usec = ticks - (tv.tv_sec * 1000000);
116510639SDarren.Reed@Sun.COM 			if (copyout(&tv, (void *)addr, sizeof (tv)) != 0)
116610639SDarren.Reed@Sun.COM 				error = EFAULT;
116710639SDarren.Reed@Sun.COM 			break;
116810639SDarren.Reed@Sun.COM 		}
116910639SDarren.Reed@Sun.COM 
117010639SDarren.Reed@Sun.COM 	/*
117110639SDarren.Reed@Sun.COM 	 * Get packet stats.
117210639SDarren.Reed@Sun.COM 	 */
117310639SDarren.Reed@Sun.COM 	case BIOCGSTATS:
117410639SDarren.Reed@Sun.COM 		{
117510639SDarren.Reed@Sun.COM 			struct bpf_stat bs;
117610639SDarren.Reed@Sun.COM 
117710639SDarren.Reed@Sun.COM 			bs.bs_recv = d->bd_rcount;
117810639SDarren.Reed@Sun.COM 			bs.bs_drop = d->bd_dcount;
117910639SDarren.Reed@Sun.COM 			bs.bs_capt = d->bd_ccount;
118010639SDarren.Reed@Sun.COM 			if (copyout(&bs, (void *)addr, sizeof (bs)) != 0)
118110639SDarren.Reed@Sun.COM 				error = EFAULT;
118210639SDarren.Reed@Sun.COM 			break;
118310639SDarren.Reed@Sun.COM 		}
118410639SDarren.Reed@Sun.COM 
118510639SDarren.Reed@Sun.COM 	/*
118610639SDarren.Reed@Sun.COM 	 * Set immediate mode.
118710639SDarren.Reed@Sun.COM 	 */
118810639SDarren.Reed@Sun.COM 	case BIOCIMMEDIATE:
118910639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &d->bd_immediate,
119010639SDarren.Reed@Sun.COM 		    sizeof (d->bd_immediate)) != 0)
119110639SDarren.Reed@Sun.COM 			error = EFAULT;
119210639SDarren.Reed@Sun.COM 		break;
119310639SDarren.Reed@Sun.COM 
119410639SDarren.Reed@Sun.COM 	case BIOCVERSION:
119510639SDarren.Reed@Sun.COM 		{
119610639SDarren.Reed@Sun.COM 			struct bpf_version bv;
119710639SDarren.Reed@Sun.COM 
119810639SDarren.Reed@Sun.COM 			bv.bv_major = BPF_MAJOR_VERSION;
119910639SDarren.Reed@Sun.COM 			bv.bv_minor = BPF_MINOR_VERSION;
120010639SDarren.Reed@Sun.COM 			if (copyout(&bv, (void *)addr, sizeof (bv)) != 0)
120110639SDarren.Reed@Sun.COM 				error = EFAULT;
120210639SDarren.Reed@Sun.COM 			break;
120310639SDarren.Reed@Sun.COM 		}
120410639SDarren.Reed@Sun.COM 
120510639SDarren.Reed@Sun.COM 	case BIOCGHDRCMPLT:	/* get "header already complete" flag */
120610639SDarren.Reed@Sun.COM 		if (copyout(&d->bd_hdrcmplt, (void *)addr,
120710639SDarren.Reed@Sun.COM 		    sizeof (d->bd_hdrcmplt)) != 0)
120810639SDarren.Reed@Sun.COM 			error = EFAULT;
120910639SDarren.Reed@Sun.COM 		break;
121010639SDarren.Reed@Sun.COM 
121110639SDarren.Reed@Sun.COM 	case BIOCSHDRCMPLT:	/* set "header already complete" flag */
121210639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &d->bd_hdrcmplt,
121310639SDarren.Reed@Sun.COM 		    sizeof (d->bd_hdrcmplt)) != 0)
121410639SDarren.Reed@Sun.COM 			error = EFAULT;
121510639SDarren.Reed@Sun.COM 		break;
121610639SDarren.Reed@Sun.COM 
121710639SDarren.Reed@Sun.COM 	/*
121810639SDarren.Reed@Sun.COM 	 * Get "see sent packets" flag
121910639SDarren.Reed@Sun.COM 	 */
122010639SDarren.Reed@Sun.COM 	case BIOCGSEESENT:
122110639SDarren.Reed@Sun.COM 		if (copyout(&d->bd_seesent, (void *)addr,
122210639SDarren.Reed@Sun.COM 		    sizeof (d->bd_seesent)) != 0)
122310639SDarren.Reed@Sun.COM 			error = EFAULT;
122410639SDarren.Reed@Sun.COM 		break;
122510639SDarren.Reed@Sun.COM 
122610639SDarren.Reed@Sun.COM 	/*
122710639SDarren.Reed@Sun.COM 	 * Set "see sent" packets flag
122810639SDarren.Reed@Sun.COM 	 */
122910639SDarren.Reed@Sun.COM 	case BIOCSSEESENT:
123010639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &d->bd_seesent,
123110639SDarren.Reed@Sun.COM 		    sizeof (d->bd_seesent)) != 0)
123210639SDarren.Reed@Sun.COM 			error = EFAULT;
123310639SDarren.Reed@Sun.COM 		break;
123410639SDarren.Reed@Sun.COM 
123510639SDarren.Reed@Sun.COM 	case FIONBIO:		/* Non-blocking I/O */
123610639SDarren.Reed@Sun.COM 		if (copyin((void *)addr, &d->bd_nonblock,
123710639SDarren.Reed@Sun.COM 		    sizeof (d->bd_nonblock)) != 0)
123810639SDarren.Reed@Sun.COM 			error = EFAULT;
123910639SDarren.Reed@Sun.COM 		break;
124010639SDarren.Reed@Sun.COM 	}
124110639SDarren.Reed@Sun.COM 	return (error);
124210639SDarren.Reed@Sun.COM }
124310639SDarren.Reed@Sun.COM 
124410639SDarren.Reed@Sun.COM /*
124510639SDarren.Reed@Sun.COM  * Set d's packet filter program to fp.  If this file already has a filter,
124610639SDarren.Reed@Sun.COM  * free it and replace it. If the new filter is "empty" (has a 0 size), then
124710639SDarren.Reed@Sun.COM  * the result is to just remove and free the existing filter.
124810639SDarren.Reed@Sun.COM  * Returns EINVAL for bogus requests.
124910639SDarren.Reed@Sun.COM  */
125010639SDarren.Reed@Sun.COM int
bpf_setf(struct bpf_d * d,struct bpf_program * fp)125110639SDarren.Reed@Sun.COM bpf_setf(struct bpf_d *d, struct bpf_program *fp)
125210639SDarren.Reed@Sun.COM {
125310639SDarren.Reed@Sun.COM 	struct bpf_insn *fcode, *old;
125410639SDarren.Reed@Sun.COM 	uint_t flen, size;
125510639SDarren.Reed@Sun.COM 	size_t oldsize;
125610639SDarren.Reed@Sun.COM 
125710639SDarren.Reed@Sun.COM 	if (fp->bf_insns == 0) {
125810639SDarren.Reed@Sun.COM 		if (fp->bf_len != 0)
125910639SDarren.Reed@Sun.COM 			return (EINVAL);
126010639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
126110639SDarren.Reed@Sun.COM 		old = d->bd_filter;
126210639SDarren.Reed@Sun.COM 		oldsize = d->bd_filter_size;
126310639SDarren.Reed@Sun.COM 		d->bd_filter = 0;
126410639SDarren.Reed@Sun.COM 		d->bd_filter_size = 0;
126510639SDarren.Reed@Sun.COM 		reset_d(d);
126610639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
126710639SDarren.Reed@Sun.COM 		if (old != 0)
126810639SDarren.Reed@Sun.COM 			kmem_free(old, oldsize);
126910639SDarren.Reed@Sun.COM 		return (0);
127010639SDarren.Reed@Sun.COM 	}
127110639SDarren.Reed@Sun.COM 	flen = fp->bf_len;
127210639SDarren.Reed@Sun.COM 	if (flen > BPF_MAXINSNS)
127310639SDarren.Reed@Sun.COM 		return (EINVAL);
127410639SDarren.Reed@Sun.COM 
127510639SDarren.Reed@Sun.COM 	size = flen * sizeof (*fp->bf_insns);
127610639SDarren.Reed@Sun.COM 	fcode = kmem_alloc(size, KM_SLEEP);
127710639SDarren.Reed@Sun.COM 	if (copyin(fp->bf_insns, fcode, size) != 0)
127810639SDarren.Reed@Sun.COM 		return (EFAULT);
127910639SDarren.Reed@Sun.COM 
128010639SDarren.Reed@Sun.COM 	if (bpf_validate(fcode, (int)flen)) {
128110639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
128210639SDarren.Reed@Sun.COM 		old = d->bd_filter;
128310639SDarren.Reed@Sun.COM 		oldsize = d->bd_filter_size;
128410639SDarren.Reed@Sun.COM 		d->bd_filter = fcode;
128510639SDarren.Reed@Sun.COM 		d->bd_filter_size = size;
128610639SDarren.Reed@Sun.COM 		reset_d(d);
128710639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
128810639SDarren.Reed@Sun.COM 		if (old != 0)
128910639SDarren.Reed@Sun.COM 			kmem_free(old, oldsize);
129010639SDarren.Reed@Sun.COM 
129110639SDarren.Reed@Sun.COM 		return (0);
129210639SDarren.Reed@Sun.COM 	}
129310639SDarren.Reed@Sun.COM 	kmem_free(fcode, size);
129410639SDarren.Reed@Sun.COM 	return (EINVAL);
129510639SDarren.Reed@Sun.COM }
129610639SDarren.Reed@Sun.COM 
129710639SDarren.Reed@Sun.COM /*
129810639SDarren.Reed@Sun.COM  * Detach a file from its current interface (if attached at all) and attach
129911179SDarren.Reed@Sun.COM  * to the interface indicated by the name stored in ifname.
130010639SDarren.Reed@Sun.COM  * Return an errno or 0.
130110639SDarren.Reed@Sun.COM  */
130210639SDarren.Reed@Sun.COM static int
bpf_setif(struct bpf_d * d,char * ifname,int namesize)130310639SDarren.Reed@Sun.COM bpf_setif(struct bpf_d *d, char *ifname, int namesize)
130410639SDarren.Reed@Sun.COM {
130510639SDarren.Reed@Sun.COM 	int unit_seen;
130611179SDarren.Reed@Sun.COM 	int error = 0;
130710639SDarren.Reed@Sun.COM 	char *cp;
130810639SDarren.Reed@Sun.COM 	int i;
130910639SDarren.Reed@Sun.COM 
131010639SDarren.Reed@Sun.COM 	/*
131110639SDarren.Reed@Sun.COM 	 * Make sure the provided name has a unit number, and default
131210639SDarren.Reed@Sun.COM 	 * it to '0' if not specified.
131310639SDarren.Reed@Sun.COM 	 * XXX This is ugly ... do this differently?
131410639SDarren.Reed@Sun.COM 	 */
131510639SDarren.Reed@Sun.COM 	unit_seen = 0;
131610639SDarren.Reed@Sun.COM 	cp = ifname;
131710639SDarren.Reed@Sun.COM 	cp[namesize - 1] = '\0';	/* sanity */
131810639SDarren.Reed@Sun.COM 	while (*cp++)
131910639SDarren.Reed@Sun.COM 		if (*cp >= '0' && *cp <= '9')
132010639SDarren.Reed@Sun.COM 			unit_seen = 1;
132110639SDarren.Reed@Sun.COM 	if (!unit_seen) {
132210639SDarren.Reed@Sun.COM 		/* Make sure to leave room for the '\0'. */
132310639SDarren.Reed@Sun.COM 		for (i = 0; i < (namesize - 1); ++i) {
132410639SDarren.Reed@Sun.COM 			if ((ifname[i] >= 'a' && ifname[i] <= 'z') ||
132510639SDarren.Reed@Sun.COM 			    (ifname[i] >= 'A' && ifname[i] <= 'Z'))
132610639SDarren.Reed@Sun.COM 				continue;
132710639SDarren.Reed@Sun.COM 			ifname[i] = '0';
132810639SDarren.Reed@Sun.COM 		}
132910639SDarren.Reed@Sun.COM 	}
133010639SDarren.Reed@Sun.COM 
133110639SDarren.Reed@Sun.COM 	/*
133210639SDarren.Reed@Sun.COM 	 * Make sure that only one call to this function happens at a time
133310639SDarren.Reed@Sun.COM 	 * and that we're not interleaving a read/write
133410639SDarren.Reed@Sun.COM 	 */
133510639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
133610639SDarren.Reed@Sun.COM 	while (d->bd_inuse != 0) {
133710639SDarren.Reed@Sun.COM 		d->bd_waiting++;
133810639SDarren.Reed@Sun.COM 		if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
133910639SDarren.Reed@Sun.COM 			d->bd_waiting--;
134010639SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
134110639SDarren.Reed@Sun.COM 			return (EINTR);
134210639SDarren.Reed@Sun.COM 		}
134310639SDarren.Reed@Sun.COM 		d->bd_waiting--;
134410639SDarren.Reed@Sun.COM 	}
134510639SDarren.Reed@Sun.COM 	d->bd_inuse = -1;
134610639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
134710639SDarren.Reed@Sun.COM 
134811179SDarren.Reed@Sun.COM 	if (d->bd_sbuf == 0)
134911179SDarren.Reed@Sun.COM 		error = bpf_allocbufs(d);
135010639SDarren.Reed@Sun.COM 
135111179SDarren.Reed@Sun.COM 	if (error == 0) {
135210639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
135311179SDarren.Reed@Sun.COM 		if (d->bd_bif)
135411179SDarren.Reed@Sun.COM 			/*
135511179SDarren.Reed@Sun.COM 			 * Detach if attached to something else.
135611179SDarren.Reed@Sun.COM 			 */
135711179SDarren.Reed@Sun.COM 			bpf_detachd(d);
135810639SDarren.Reed@Sun.COM 
135911179SDarren.Reed@Sun.COM 		error = bpf_attachd(d, ifname, -1);
136010639SDarren.Reed@Sun.COM 		reset_d(d);
136110639SDarren.Reed@Sun.COM 		d->bd_inuse = 0;
136210639SDarren.Reed@Sun.COM 		if (d->bd_waiting != 0)
136310639SDarren.Reed@Sun.COM 			cv_signal(&d->bd_wait);
136410639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
136510639SDarren.Reed@Sun.COM 		return (error);
136610639SDarren.Reed@Sun.COM 	}
136710639SDarren.Reed@Sun.COM 
136810639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
136910639SDarren.Reed@Sun.COM 	d->bd_inuse = 0;
137010639SDarren.Reed@Sun.COM 	if (d->bd_waiting != 0)
137110639SDarren.Reed@Sun.COM 		cv_signal(&d->bd_wait);
137210639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
137310639SDarren.Reed@Sun.COM 
137410639SDarren.Reed@Sun.COM 	/*
137510639SDarren.Reed@Sun.COM 	 * Try tickle the mac layer into attaching the device...
137610639SDarren.Reed@Sun.COM 	 */
137710639SDarren.Reed@Sun.COM 	return (bpf_provider_tickle(ifname, d->bd_zone));
137810639SDarren.Reed@Sun.COM }
137910639SDarren.Reed@Sun.COM 
138010639SDarren.Reed@Sun.COM /*
138110639SDarren.Reed@Sun.COM  * Copy the interface name to the ifreq.
138210639SDarren.Reed@Sun.COM  */
138310639SDarren.Reed@Sun.COM static int
bpf_ifname(struct bpf_d * d,char * buffer,int bufsize)138410639SDarren.Reed@Sun.COM bpf_ifname(struct bpf_d *d, char *buffer, int bufsize)
138510639SDarren.Reed@Sun.COM {
138610639SDarren.Reed@Sun.COM 
138710639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
138811179SDarren.Reed@Sun.COM 	if (d->bd_bif == NULL) {
138910639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
139010639SDarren.Reed@Sun.COM 		return (EINVAL);
139110639SDarren.Reed@Sun.COM 	}
139210639SDarren.Reed@Sun.COM 
139311179SDarren.Reed@Sun.COM 	(void) strlcpy(buffer, d->bd_ifname, bufsize);
139410639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
139510639SDarren.Reed@Sun.COM 
139610639SDarren.Reed@Sun.COM 	return (0);
139710639SDarren.Reed@Sun.COM }
139810639SDarren.Reed@Sun.COM 
139910639SDarren.Reed@Sun.COM /*
140010639SDarren.Reed@Sun.COM  * Support for poll() system call
140110639SDarren.Reed@Sun.COM  *
140210639SDarren.Reed@Sun.COM  * Return true iff the specific operation will not block indefinitely - with
140310639SDarren.Reed@Sun.COM  * the assumption that it is safe to positively acknowledge a request for the
140410639SDarren.Reed@Sun.COM  * ability to write to the BPF device.
140510639SDarren.Reed@Sun.COM  * Otherwise, return false but make a note that a selnotify() must be done.
140610639SDarren.Reed@Sun.COM  */
140710639SDarren.Reed@Sun.COM int
bpfchpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)140810639SDarren.Reed@Sun.COM bpfchpoll(dev_t dev, short events, int anyyet, short *reventsp,
140910639SDarren.Reed@Sun.COM     struct pollhead **phpp)
141010639SDarren.Reed@Sun.COM {
141110639SDarren.Reed@Sun.COM 	struct bpf_d *d = bpf_dev_get(getminor(dev));
141210639SDarren.Reed@Sun.COM 
141310639SDarren.Reed@Sun.COM 	if (events & (POLLIN | POLLRDNORM)) {
141410639SDarren.Reed@Sun.COM 		/*
141510639SDarren.Reed@Sun.COM 		 * An imitation of the FIONREAD ioctl code.
141610639SDarren.Reed@Sun.COM 		 */
141710639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
141810639SDarren.Reed@Sun.COM 		if (d->bd_hlen != 0 ||
141910639SDarren.Reed@Sun.COM 		    ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
142010639SDarren.Reed@Sun.COM 		    d->bd_slen != 0)) {
142110639SDarren.Reed@Sun.COM 			*reventsp |= events & (POLLIN | POLLRDNORM);
142210639SDarren.Reed@Sun.COM 		} else {
142310639SDarren.Reed@Sun.COM 			*reventsp = 0;
142410639SDarren.Reed@Sun.COM 			if (!anyyet)
142510639SDarren.Reed@Sun.COM 				*phpp = &d->bd_poll;
142610639SDarren.Reed@Sun.COM 			/* Start the read timeout if necessary */
142710639SDarren.Reed@Sun.COM 			if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
142810639SDarren.Reed@Sun.COM 				bpf_clear_timeout(d);
142910639SDarren.Reed@Sun.COM 				/*
143010639SDarren.Reed@Sun.COM 				 * Only allow the timeout to be set once.
143110639SDarren.Reed@Sun.COM 				 */
143210639SDarren.Reed@Sun.COM 				if (d->bd_callout == 0)
143310639SDarren.Reed@Sun.COM 					d->bd_callout = timeout(bpf_timed_out,
143410639SDarren.Reed@Sun.COM 					    d, d->bd_rtout);
143510639SDarren.Reed@Sun.COM 				d->bd_state = BPF_WAITING;
143610639SDarren.Reed@Sun.COM 			}
143710639SDarren.Reed@Sun.COM 		}
143810639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
143910639SDarren.Reed@Sun.COM 	}
144010639SDarren.Reed@Sun.COM 
144110639SDarren.Reed@Sun.COM 	return (0);
144210639SDarren.Reed@Sun.COM }
144310639SDarren.Reed@Sun.COM 
144410639SDarren.Reed@Sun.COM /*
144510639SDarren.Reed@Sun.COM  * Copy data from an mblk_t chain into a buffer. This works for ipnet
144610639SDarren.Reed@Sun.COM  * because the dl_ipnetinfo_t is placed in an mblk_t that leads the
144710639SDarren.Reed@Sun.COM  * packet itself.
144810639SDarren.Reed@Sun.COM  */
144910639SDarren.Reed@Sun.COM static void *
bpf_mcpy(void * dst_arg,const void * src_arg,size_t len)145010639SDarren.Reed@Sun.COM bpf_mcpy(void *dst_arg, const void *src_arg, size_t len)
145110639SDarren.Reed@Sun.COM {
145210639SDarren.Reed@Sun.COM 	const mblk_t *m;
145310639SDarren.Reed@Sun.COM 	uint_t count;
145410639SDarren.Reed@Sun.COM 	uchar_t *dst;
145510639SDarren.Reed@Sun.COM 
145610639SDarren.Reed@Sun.COM 	m = src_arg;
145710639SDarren.Reed@Sun.COM 	dst = dst_arg;
145810639SDarren.Reed@Sun.COM 	while (len > 0) {
145910639SDarren.Reed@Sun.COM 		if (m == NULL)
146010639SDarren.Reed@Sun.COM 			panic("bpf_mcpy");
146110639SDarren.Reed@Sun.COM 		count = (uint_t)min(M_LEN(m), len);
146210639SDarren.Reed@Sun.COM 		(void) memcpy(dst, mtod(m, const void *), count);
146310639SDarren.Reed@Sun.COM 		m = m->b_cont;
146410639SDarren.Reed@Sun.COM 		dst += count;
146510639SDarren.Reed@Sun.COM 		len -= count;
146610639SDarren.Reed@Sun.COM 	}
146710639SDarren.Reed@Sun.COM 	return (dst_arg);
146810639SDarren.Reed@Sun.COM }
146910639SDarren.Reed@Sun.COM 
147010639SDarren.Reed@Sun.COM /*
147110639SDarren.Reed@Sun.COM  * Dispatch a packet to all the listeners on interface bp.
147210639SDarren.Reed@Sun.COM  *
147310639SDarren.Reed@Sun.COM  * marg    pointer to the packet, either a data buffer or an mbuf chain
147410639SDarren.Reed@Sun.COM  * buflen  buffer length, if marg is a data buffer
147510639SDarren.Reed@Sun.COM  * cpfn    a function that can copy marg into the listener's buffer
147610639SDarren.Reed@Sun.COM  * pktlen  length of the packet
147710639SDarren.Reed@Sun.COM  * issent  boolean indicating whether the packet was sent or receive
147810639SDarren.Reed@Sun.COM  */
147910639SDarren.Reed@Sun.COM static inline void
bpf_deliver(struct bpf_d * d,cp_fn_t cpfn,void * marg,uint_t pktlen,uint_t buflen,boolean_t issent)148010639SDarren.Reed@Sun.COM bpf_deliver(struct bpf_d *d, cp_fn_t cpfn, void *marg, uint_t pktlen,
148110639SDarren.Reed@Sun.COM     uint_t buflen, boolean_t issent)
148210639SDarren.Reed@Sun.COM {
148310639SDarren.Reed@Sun.COM 	struct timeval tv;
148410639SDarren.Reed@Sun.COM 	uint_t slen;
148510639SDarren.Reed@Sun.COM 
148610639SDarren.Reed@Sun.COM 	if (!d->bd_seesent && issent)
148710639SDarren.Reed@Sun.COM 		return;
148810639SDarren.Reed@Sun.COM 
148910639SDarren.Reed@Sun.COM 	/*
149010639SDarren.Reed@Sun.COM 	 * Accuracy of the packet counters in BPF is vital so it
149110639SDarren.Reed@Sun.COM 	 * is important to protect even the outer ones.
149210639SDarren.Reed@Sun.COM 	 */
149310639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
149410639SDarren.Reed@Sun.COM 	slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
149510639SDarren.Reed@Sun.COM 	DTRACE_PROBE5(bpf__packet, struct bpf_if *, d->bd_bif,
149610639SDarren.Reed@Sun.COM 	    struct bpf_d *, d, void *, marg, uint_t, pktlen, uint_t, slen);
149710639SDarren.Reed@Sun.COM 	d->bd_rcount++;
149810639SDarren.Reed@Sun.COM 	ks_stats.kp_receive.value.ui64++;
149910639SDarren.Reed@Sun.COM 	if (slen != 0) {
150010639SDarren.Reed@Sun.COM 		uniqtime(&tv);
150110639SDarren.Reed@Sun.COM 		catchpacket(d, marg, pktlen, slen, cpfn, &tv);
150210639SDarren.Reed@Sun.COM 	}
150310639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
150410639SDarren.Reed@Sun.COM }
150510639SDarren.Reed@Sun.COM 
150610639SDarren.Reed@Sun.COM /*
150710639SDarren.Reed@Sun.COM  * Incoming linkage from device drivers.
150810639SDarren.Reed@Sun.COM  */
150910639SDarren.Reed@Sun.COM /* ARGSUSED */
151010639SDarren.Reed@Sun.COM void
bpf_mtap(void * arg,mac_resource_handle_t mrh,mblk_t * m,boolean_t issent)151110639SDarren.Reed@Sun.COM bpf_mtap(void *arg, mac_resource_handle_t mrh, mblk_t *m, boolean_t issent)
151210639SDarren.Reed@Sun.COM {
151310639SDarren.Reed@Sun.COM 	cp_fn_t cpfn;
151410639SDarren.Reed@Sun.COM 	struct bpf_d *d = arg;
151510639SDarren.Reed@Sun.COM 	uint_t pktlen, buflen;
151610639SDarren.Reed@Sun.COM 	void *marg;
151710639SDarren.Reed@Sun.COM 
151810639SDarren.Reed@Sun.COM 	pktlen = msgdsize(m);
151910639SDarren.Reed@Sun.COM 
152010639SDarren.Reed@Sun.COM 	if (pktlen == M_LEN(m)) {
152110639SDarren.Reed@Sun.COM 		cpfn = (cp_fn_t)memcpy;
152210639SDarren.Reed@Sun.COM 		marg = mtod(m, void *);
152310639SDarren.Reed@Sun.COM 		buflen = pktlen;
152410639SDarren.Reed@Sun.COM 	} else {
152510639SDarren.Reed@Sun.COM 		cpfn = bpf_mcpy;
152610639SDarren.Reed@Sun.COM 		marg = m;
152710639SDarren.Reed@Sun.COM 		buflen = 0;
152810639SDarren.Reed@Sun.COM 	}
152910639SDarren.Reed@Sun.COM 
153010639SDarren.Reed@Sun.COM 	bpf_deliver(d, cpfn, marg, pktlen, buflen, issent);
153110639SDarren.Reed@Sun.COM }
153210639SDarren.Reed@Sun.COM 
153310639SDarren.Reed@Sun.COM /*
153410639SDarren.Reed@Sun.COM  * Incoming linkage from ipnet.
153510639SDarren.Reed@Sun.COM  * In ipnet, there is only one event, NH_OBSERVE, that delivers packets
153610639SDarren.Reed@Sun.COM  * from all network interfaces. Thus the tap function needs to apply a
153710639SDarren.Reed@Sun.COM  * filter using the interface index/id to immitate snoop'ing on just the
153810639SDarren.Reed@Sun.COM  * specified interface.
153910639SDarren.Reed@Sun.COM  */
154010639SDarren.Reed@Sun.COM /* ARGSUSED */
154110639SDarren.Reed@Sun.COM void
bpf_itap(void * arg,mblk_t * m,boolean_t issent,uint_t length)154210639SDarren.Reed@Sun.COM bpf_itap(void *arg, mblk_t *m, boolean_t issent, uint_t length)
154310639SDarren.Reed@Sun.COM {
154410639SDarren.Reed@Sun.COM 	hook_pkt_observe_t *hdr;
154510639SDarren.Reed@Sun.COM 	struct bpf_d *d = arg;
154610639SDarren.Reed@Sun.COM 
154710639SDarren.Reed@Sun.COM 	hdr = (hook_pkt_observe_t *)m->b_rptr;
154811179SDarren.Reed@Sun.COM 	if (ntohl(hdr->hpo_ifindex) != d->bd_linkid)
154910639SDarren.Reed@Sun.COM 		return;
155010639SDarren.Reed@Sun.COM 	bpf_deliver(d, bpf_mcpy, m, length, 0, issent);
155110639SDarren.Reed@Sun.COM 
155210639SDarren.Reed@Sun.COM }
155310639SDarren.Reed@Sun.COM 
155410639SDarren.Reed@Sun.COM /*
155510639SDarren.Reed@Sun.COM  * Move the packet data from interface memory (pkt) into the
155610639SDarren.Reed@Sun.COM  * store buffer.  Return 1 if it's time to wakeup a listener (buffer full),
155710639SDarren.Reed@Sun.COM  * otherwise 0.  "copy" is the routine called to do the actual data
155810639SDarren.Reed@Sun.COM  * transfer.  memcpy is passed in to copy contiguous chunks, while
155910639SDarren.Reed@Sun.COM  * bpf_mcpy is passed in to copy mbuf chains.  In the latter case,
156010639SDarren.Reed@Sun.COM  * pkt is really an mbuf.
156110639SDarren.Reed@Sun.COM  */
156210639SDarren.Reed@Sun.COM static void
catchpacket(struct bpf_d * d,uchar_t * pkt,uint_t pktlen,uint_t snaplen,cp_fn_t cpfn,struct timeval * tv)156310639SDarren.Reed@Sun.COM catchpacket(struct bpf_d *d, uchar_t *pkt, uint_t pktlen, uint_t snaplen,
156410639SDarren.Reed@Sun.COM     cp_fn_t cpfn, struct timeval *tv)
156510639SDarren.Reed@Sun.COM {
156610639SDarren.Reed@Sun.COM 	struct bpf_hdr *hp;
156710639SDarren.Reed@Sun.COM 	int totlen, curlen;
156811179SDarren.Reed@Sun.COM 	int hdrlen = d->bd_hdrlen;
156910639SDarren.Reed@Sun.COM 	int do_wakeup = 0;
157010639SDarren.Reed@Sun.COM 
157110639SDarren.Reed@Sun.COM 	++d->bd_ccount;
157210639SDarren.Reed@Sun.COM 	ks_stats.kp_capture.value.ui64++;
157310639SDarren.Reed@Sun.COM 	/*
157410639SDarren.Reed@Sun.COM 	 * Figure out how many bytes to move.  If the packet is
157510639SDarren.Reed@Sun.COM 	 * greater or equal to the snapshot length, transfer that
157610639SDarren.Reed@Sun.COM 	 * much.  Otherwise, transfer the whole packet (unless
157710639SDarren.Reed@Sun.COM 	 * we hit the buffer size limit).
157810639SDarren.Reed@Sun.COM 	 */
157910639SDarren.Reed@Sun.COM 	totlen = hdrlen + min(snaplen, pktlen);
158010639SDarren.Reed@Sun.COM 	if (totlen > d->bd_bufsize)
158110639SDarren.Reed@Sun.COM 		totlen = d->bd_bufsize;
158210639SDarren.Reed@Sun.COM 
158310639SDarren.Reed@Sun.COM 	/*
158410639SDarren.Reed@Sun.COM 	 * Round up the end of the previous packet to the next longword.
158510639SDarren.Reed@Sun.COM 	 */
158610639SDarren.Reed@Sun.COM 	curlen = BPF_WORDALIGN(d->bd_slen);
158710639SDarren.Reed@Sun.COM 	if (curlen + totlen > d->bd_bufsize) {
158810639SDarren.Reed@Sun.COM 		/*
158910639SDarren.Reed@Sun.COM 		 * This packet will overflow the storage buffer.
159010639SDarren.Reed@Sun.COM 		 * Rotate the buffers if we can, then wakeup any
159110639SDarren.Reed@Sun.COM 		 * pending reads.
159210639SDarren.Reed@Sun.COM 		 */
159310639SDarren.Reed@Sun.COM 		if (d->bd_fbuf == 0) {
159410639SDarren.Reed@Sun.COM 			/*
159510639SDarren.Reed@Sun.COM 			 * We haven't completed the previous read yet,
159610639SDarren.Reed@Sun.COM 			 * so drop the packet.
159710639SDarren.Reed@Sun.COM 			 */
159810639SDarren.Reed@Sun.COM 			++d->bd_dcount;
159910639SDarren.Reed@Sun.COM 			ks_stats.kp_dropped.value.ui64++;
160010639SDarren.Reed@Sun.COM 			return;
160110639SDarren.Reed@Sun.COM 		}
160210639SDarren.Reed@Sun.COM 		ROTATE_BUFFERS(d);
160310639SDarren.Reed@Sun.COM 		do_wakeup = 1;
160410639SDarren.Reed@Sun.COM 		curlen = 0;
160510639SDarren.Reed@Sun.COM 	} else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) {
160610639SDarren.Reed@Sun.COM 		/*
160710639SDarren.Reed@Sun.COM 		 * Immediate mode is set, or the read timeout has
160810639SDarren.Reed@Sun.COM 		 * already expired during a select call.  A packet
160910639SDarren.Reed@Sun.COM 		 * arrived, so the reader should be woken up.
161010639SDarren.Reed@Sun.COM 		 */
161110639SDarren.Reed@Sun.COM 		do_wakeup = 1;
161210639SDarren.Reed@Sun.COM 	}
161310639SDarren.Reed@Sun.COM 
161410639SDarren.Reed@Sun.COM 	/*
161510639SDarren.Reed@Sun.COM 	 * Append the bpf header to the existing buffer before we add
161610639SDarren.Reed@Sun.COM 	 * on the actual packet data.
161710639SDarren.Reed@Sun.COM 	 */
161810639SDarren.Reed@Sun.COM 	hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen);
161910639SDarren.Reed@Sun.COM 	hp->bh_tstamp.tv_sec = tv->tv_sec;
162010639SDarren.Reed@Sun.COM 	hp->bh_tstamp.tv_usec = tv->tv_usec;
162110639SDarren.Reed@Sun.COM 	hp->bh_datalen = pktlen;
162210639SDarren.Reed@Sun.COM 	hp->bh_hdrlen = (uint16_t)hdrlen;
162310639SDarren.Reed@Sun.COM 	/*
162410639SDarren.Reed@Sun.COM 	 * Copy the packet data into the store buffer and update its length.
162510639SDarren.Reed@Sun.COM 	 */
162610639SDarren.Reed@Sun.COM 	(*cpfn)((uchar_t *)hp + hdrlen, pkt,
162710639SDarren.Reed@Sun.COM 	    (hp->bh_caplen = totlen - hdrlen));
162810639SDarren.Reed@Sun.COM 	d->bd_slen = curlen + totlen;
162910639SDarren.Reed@Sun.COM 
163010639SDarren.Reed@Sun.COM 	/*
163110639SDarren.Reed@Sun.COM 	 * Call bpf_wakeup after bd_slen has been updated.
163210639SDarren.Reed@Sun.COM 	 */
163310639SDarren.Reed@Sun.COM 	if (do_wakeup)
163410639SDarren.Reed@Sun.COM 		bpf_wakeup(d);
163510639SDarren.Reed@Sun.COM }
163610639SDarren.Reed@Sun.COM 
163710639SDarren.Reed@Sun.COM /*
163810639SDarren.Reed@Sun.COM  * Initialize all nonzero fields of a descriptor.
163910639SDarren.Reed@Sun.COM  */
164010639SDarren.Reed@Sun.COM static int
bpf_allocbufs(struct bpf_d * d)164110639SDarren.Reed@Sun.COM bpf_allocbufs(struct bpf_d *d)
164210639SDarren.Reed@Sun.COM {
164310639SDarren.Reed@Sun.COM 
164410639SDarren.Reed@Sun.COM 	d->bd_fbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
164510639SDarren.Reed@Sun.COM 	if (!d->bd_fbuf)
164610639SDarren.Reed@Sun.COM 		return (ENOBUFS);
164710639SDarren.Reed@Sun.COM 	d->bd_sbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
164810639SDarren.Reed@Sun.COM 	if (!d->bd_sbuf) {
164910639SDarren.Reed@Sun.COM 		kmem_free(d->bd_fbuf, d->bd_bufsize);
165010639SDarren.Reed@Sun.COM 		return (ENOBUFS);
165110639SDarren.Reed@Sun.COM 	}
165210639SDarren.Reed@Sun.COM 	d->bd_slen = 0;
165310639SDarren.Reed@Sun.COM 	d->bd_hlen = 0;
165410639SDarren.Reed@Sun.COM 	return (0);
165510639SDarren.Reed@Sun.COM }
165610639SDarren.Reed@Sun.COM 
165710639SDarren.Reed@Sun.COM /*
165810639SDarren.Reed@Sun.COM  * Free buffers currently in use by a descriptor.
165910639SDarren.Reed@Sun.COM  * Called on close.
166010639SDarren.Reed@Sun.COM  */
166110639SDarren.Reed@Sun.COM static void
bpf_freed(struct bpf_d * d)166210639SDarren.Reed@Sun.COM bpf_freed(struct bpf_d *d)
166310639SDarren.Reed@Sun.COM {
166410639SDarren.Reed@Sun.COM 	/*
166510639SDarren.Reed@Sun.COM 	 * At this point the descriptor has been detached from its
166610639SDarren.Reed@Sun.COM 	 * interface and it yet hasn't been marked free.
166710639SDarren.Reed@Sun.COM 	 */
166810639SDarren.Reed@Sun.COM 	if (d->bd_sbuf != 0) {
166910639SDarren.Reed@Sun.COM 		kmem_free(d->bd_sbuf, d->bd_bufsize);
167010639SDarren.Reed@Sun.COM 		if (d->bd_hbuf != 0)
167110639SDarren.Reed@Sun.COM 			kmem_free(d->bd_hbuf, d->bd_bufsize);
167210639SDarren.Reed@Sun.COM 		if (d->bd_fbuf != 0)
167310639SDarren.Reed@Sun.COM 			kmem_free(d->bd_fbuf, d->bd_bufsize);
167410639SDarren.Reed@Sun.COM 	}
167510639SDarren.Reed@Sun.COM 	if (d->bd_filter)
167610639SDarren.Reed@Sun.COM 		kmem_free(d->bd_filter, d->bd_filter_size);
167710639SDarren.Reed@Sun.COM }
167810639SDarren.Reed@Sun.COM 
167910639SDarren.Reed@Sun.COM /*
168010639SDarren.Reed@Sun.COM  * Get a list of available data link type of the interface.
168110639SDarren.Reed@Sun.COM  */
168210639SDarren.Reed@Sun.COM static int
bpf_getdltlist(struct bpf_d * d,struct bpf_dltlist * listp)168310639SDarren.Reed@Sun.COM bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *listp)
168410639SDarren.Reed@Sun.COM {
168511179SDarren.Reed@Sun.COM 	bpf_provider_list_t *bp;
168611179SDarren.Reed@Sun.COM 	bpf_provider_t *bpr;
168711179SDarren.Reed@Sun.COM 	zoneid_t zoneid;
168811179SDarren.Reed@Sun.COM 	uintptr_t mcip;
168911179SDarren.Reed@Sun.COM 	uint_t nicdlt;
169011179SDarren.Reed@Sun.COM 	uintptr_t mh;
169111179SDarren.Reed@Sun.COM 	int error;
169211179SDarren.Reed@Sun.COM 	int n;
169310639SDarren.Reed@Sun.COM 
169410639SDarren.Reed@Sun.COM 	n = 0;
169511179SDarren.Reed@Sun.COM 	mh = 0;
169611179SDarren.Reed@Sun.COM 	mcip = 0;
169710639SDarren.Reed@Sun.COM 	error = 0;
169811179SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
169911179SDarren.Reed@Sun.COM 	LIST_FOREACH(bp, &bpf_providers, bpl_next) {
170011179SDarren.Reed@Sun.COM 		bpr = bp->bpl_what;
170111179SDarren.Reed@Sun.COM 		error = MBPF_OPEN(bpr, d->bd_ifname, &mh, d->bd_zone);
170211179SDarren.Reed@Sun.COM 		if (error != 0)
170311179SDarren.Reed@Sun.COM 			goto next;
170411179SDarren.Reed@Sun.COM 		error = MBPF_CLIENT_OPEN(bpr, mh, &mcip);
170511179SDarren.Reed@Sun.COM 		if (error != 0)
170611179SDarren.Reed@Sun.COM 			goto next;
170711179SDarren.Reed@Sun.COM 		error = MBPF_GET_ZONE(bpr, mh, &zoneid);
170811179SDarren.Reed@Sun.COM 		if (error != 0)
170911179SDarren.Reed@Sun.COM 			goto next;
171010639SDarren.Reed@Sun.COM 		if (d->bd_zone != GLOBAL_ZONEID &&
171111179SDarren.Reed@Sun.COM 		    d->bd_zone != zoneid)
171211179SDarren.Reed@Sun.COM 			goto next;
171311179SDarren.Reed@Sun.COM 		error = MBPF_GET_DLT(bpr, mh, &nicdlt);
171411179SDarren.Reed@Sun.COM 		if (error != 0)
171511179SDarren.Reed@Sun.COM 			goto next;
171611179SDarren.Reed@Sun.COM 		nicdlt = bpf_dl_to_dlt(nicdlt);
171710639SDarren.Reed@Sun.COM 		if (listp->bfl_list != NULL) {
171811179SDarren.Reed@Sun.COM 			if (n >= listp->bfl_len) {
171911179SDarren.Reed@Sun.COM 				MBPF_CLIENT_CLOSE(bpr, mcip);
172011179SDarren.Reed@Sun.COM 				MBPF_CLOSE(bpr, mh);
172111179SDarren.Reed@Sun.COM 				break;
172211179SDarren.Reed@Sun.COM 			}
172310639SDarren.Reed@Sun.COM 			/*
172411179SDarren.Reed@Sun.COM 			 * Bumping of bd_inuse ensures the structure does not
172510639SDarren.Reed@Sun.COM 			 * disappear while the copyout runs and allows the for
172610639SDarren.Reed@Sun.COM 			 * loop to be continued.
172710639SDarren.Reed@Sun.COM 			 */
172811179SDarren.Reed@Sun.COM 			d->bd_inuse++;
172911179SDarren.Reed@Sun.COM 			mutex_exit(&d->bd_lock);
173011179SDarren.Reed@Sun.COM 			if (copyout(&nicdlt,
173110639SDarren.Reed@Sun.COM 			    listp->bfl_list + n, sizeof (uint_t)) != 0)
173210639SDarren.Reed@Sun.COM 				error = EFAULT;
173311179SDarren.Reed@Sun.COM 			mutex_enter(&d->bd_lock);
173411179SDarren.Reed@Sun.COM 			if (error != 0)
173511179SDarren.Reed@Sun.COM 				break;
173611179SDarren.Reed@Sun.COM 			d->bd_inuse--;
173710639SDarren.Reed@Sun.COM 		}
173810639SDarren.Reed@Sun.COM 		n++;
173911179SDarren.Reed@Sun.COM next:
174011179SDarren.Reed@Sun.COM 		if (mcip != 0) {
174111179SDarren.Reed@Sun.COM 			MBPF_CLIENT_CLOSE(bpr, mcip);
174211179SDarren.Reed@Sun.COM 			mcip = 0;
174311179SDarren.Reed@Sun.COM 		}
174411179SDarren.Reed@Sun.COM 		if (mh != 0) {
174511179SDarren.Reed@Sun.COM 			MBPF_CLOSE(bpr, mh);
174611179SDarren.Reed@Sun.COM 			mh = 0;
174711179SDarren.Reed@Sun.COM 		}
174810639SDarren.Reed@Sun.COM 	}
174911179SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
175011179SDarren.Reed@Sun.COM 
175111179SDarren.Reed@Sun.COM 	/*
175211179SDarren.Reed@Sun.COM 	 * It is quite possible that one or more provider to BPF may not
175311179SDarren.Reed@Sun.COM 	 * know about a link name whlist others do. In that case, so long
175411179SDarren.Reed@Sun.COM 	 * as we have one success, do not declare an error unless it was
175511179SDarren.Reed@Sun.COM 	 * an EFAULT as this indicates a problem that needs to be reported.
175611179SDarren.Reed@Sun.COM 	 */
175711179SDarren.Reed@Sun.COM 	if ((error != EFAULT) && (n > 0))
175811179SDarren.Reed@Sun.COM 		error = 0;
175911179SDarren.Reed@Sun.COM 
176010639SDarren.Reed@Sun.COM 	listp->bfl_len = n;
176110639SDarren.Reed@Sun.COM 	return (error);
176210639SDarren.Reed@Sun.COM }
176310639SDarren.Reed@Sun.COM 
176410639SDarren.Reed@Sun.COM /*
176510639SDarren.Reed@Sun.COM  * Set the data link type of a BPF instance.
176610639SDarren.Reed@Sun.COM  */
176710639SDarren.Reed@Sun.COM static int
bpf_setdlt(struct bpf_d * d,void * addr)176810639SDarren.Reed@Sun.COM bpf_setdlt(struct bpf_d *d, void *addr)
176910639SDarren.Reed@Sun.COM {
177010639SDarren.Reed@Sun.COM 	char ifname[LIFNAMSIZ+1];
177111179SDarren.Reed@Sun.COM 	zoneid_t niczone;
177210639SDarren.Reed@Sun.COM 	int error;
177310639SDarren.Reed@Sun.COM 	int dlt;
177410639SDarren.Reed@Sun.COM 
177510639SDarren.Reed@Sun.COM 	if (copyin(addr, &dlt, sizeof (dlt)) != 0)
177610639SDarren.Reed@Sun.COM 		return (EFAULT);
177711179SDarren.Reed@Sun.COM 
177810639SDarren.Reed@Sun.COM 	mutex_enter(&d->bd_lock);
177910639SDarren.Reed@Sun.COM 
178010639SDarren.Reed@Sun.COM 	if (d->bd_bif == 0) {			/* Interface not set */
178110639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
178210639SDarren.Reed@Sun.COM 		return (EINVAL);
178310639SDarren.Reed@Sun.COM 	}
178411179SDarren.Reed@Sun.COM 	if (d->bd_dlt == dlt) {	/* NULL-op */
178510639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
178610639SDarren.Reed@Sun.COM 		return (0);
178710639SDarren.Reed@Sun.COM 	}
178810639SDarren.Reed@Sun.COM 
178911179SDarren.Reed@Sun.COM 	error = MBPF_GET_ZONE(&d->bd_mac, d->bd_bif, &niczone);
179011179SDarren.Reed@Sun.COM 	if (error != 0) {
179111179SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
179211179SDarren.Reed@Sun.COM 		return (error);
179311179SDarren.Reed@Sun.COM 	}
179411179SDarren.Reed@Sun.COM 
179510639SDarren.Reed@Sun.COM 	/*
179610639SDarren.Reed@Sun.COM 	 * See the matrix at the top of the file for the permissions table
179710639SDarren.Reed@Sun.COM 	 * enforced by this driver.
179810639SDarren.Reed@Sun.COM 	 */
179910639SDarren.Reed@Sun.COM 	if ((d->bd_zone != GLOBAL_ZONEID) && (dlt != DLT_IPNET) &&
180011179SDarren.Reed@Sun.COM 	    (niczone != d->bd_zone)) {
180110639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
180210639SDarren.Reed@Sun.COM 		return (EINVAL);
180310639SDarren.Reed@Sun.COM 	}
180410639SDarren.Reed@Sun.COM 
180511179SDarren.Reed@Sun.COM 	(void) strlcpy(ifname, d->bd_ifname, sizeof (ifname));
180611179SDarren.Reed@Sun.COM 	d->bd_inuse = -1;
180710639SDarren.Reed@Sun.COM 	bpf_detachd(d);
180811179SDarren.Reed@Sun.COM 	error = bpf_attachd(d, ifname, dlt);
180910639SDarren.Reed@Sun.COM 	reset_d(d);
181011179SDarren.Reed@Sun.COM 	d->bd_inuse = 0;
181110639SDarren.Reed@Sun.COM 
181210639SDarren.Reed@Sun.COM 	mutex_exit(&d->bd_lock);
181310639SDarren.Reed@Sun.COM 	return (error);
181410639SDarren.Reed@Sun.COM }
181510639SDarren.Reed@Sun.COM 
181610639SDarren.Reed@Sun.COM /*
181710639SDarren.Reed@Sun.COM  * bpf_clear_timeout is called with the bd_lock mutex held, providing it
181810639SDarren.Reed@Sun.COM  * with the necessary protection to retrieve and modify bd_callout but it
181910639SDarren.Reed@Sun.COM  * does not hold the lock for its entire duration... see below...
182010639SDarren.Reed@Sun.COM  */
182110639SDarren.Reed@Sun.COM static void
bpf_clear_timeout(struct bpf_d * d)182210639SDarren.Reed@Sun.COM bpf_clear_timeout(struct bpf_d *d)
182310639SDarren.Reed@Sun.COM {
182410639SDarren.Reed@Sun.COM 	timeout_id_t tid = d->bd_callout;
182510639SDarren.Reed@Sun.COM 	d->bd_callout = 0;
182610639SDarren.Reed@Sun.COM 	d->bd_inuse++;
182710639SDarren.Reed@Sun.COM 
182810639SDarren.Reed@Sun.COM 	/*
182910639SDarren.Reed@Sun.COM 	 * If the timeout has fired and is waiting on bd_lock, we could
183010639SDarren.Reed@Sun.COM 	 * deadlock here because untimeout if bd_lock is held and would
183110639SDarren.Reed@Sun.COM 	 * wait for bpf_timed_out to finish and it never would.
183210639SDarren.Reed@Sun.COM 	 */
183310639SDarren.Reed@Sun.COM 	if (tid != 0) {
183410639SDarren.Reed@Sun.COM 		mutex_exit(&d->bd_lock);
183510639SDarren.Reed@Sun.COM 		(void) untimeout(tid);
183610639SDarren.Reed@Sun.COM 		mutex_enter(&d->bd_lock);
183710639SDarren.Reed@Sun.COM 	}
183810639SDarren.Reed@Sun.COM 
183910639SDarren.Reed@Sun.COM 	d->bd_inuse--;
184010639SDarren.Reed@Sun.COM }
184110639SDarren.Reed@Sun.COM 
184210639SDarren.Reed@Sun.COM /*
184310639SDarren.Reed@Sun.COM  * As a cloning device driver, BPF needs to keep track of which device
184410639SDarren.Reed@Sun.COM  * numbers are in use and which ones are not. A hash table, indexed by
184510639SDarren.Reed@Sun.COM  * the minor device number, is used to store the pointers to the
184610639SDarren.Reed@Sun.COM  * individual descriptors that are allocated in bpfopen().
184710639SDarren.Reed@Sun.COM  * The functions below present the interface for that hash table to
184810639SDarren.Reed@Sun.COM  * the rest of the driver.
184910639SDarren.Reed@Sun.COM  */
185010639SDarren.Reed@Sun.COM static struct bpf_d *
bpf_dev_find(minor_t minor)185110639SDarren.Reed@Sun.COM bpf_dev_find(minor_t minor)
185210639SDarren.Reed@Sun.COM {
185310639SDarren.Reed@Sun.COM 	struct bpf_d *d = NULL;
185410639SDarren.Reed@Sun.COM 
185510639SDarren.Reed@Sun.COM 	(void) mod_hash_find(bpf_hash, (mod_hash_key_t)(uintptr_t)minor,
185610639SDarren.Reed@Sun.COM 	    (mod_hash_val_t *)&d);
185710639SDarren.Reed@Sun.COM 
185810639SDarren.Reed@Sun.COM 	return (d);
185910639SDarren.Reed@Sun.COM }
186010639SDarren.Reed@Sun.COM 
186110639SDarren.Reed@Sun.COM static void
bpf_dev_add(struct bpf_d * d)186210639SDarren.Reed@Sun.COM bpf_dev_add(struct bpf_d *d)
186310639SDarren.Reed@Sun.COM {
186410639SDarren.Reed@Sun.COM 	(void) mod_hash_insert(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
186510639SDarren.Reed@Sun.COM 	    (mod_hash_val_t)d);
186610639SDarren.Reed@Sun.COM }
186710639SDarren.Reed@Sun.COM 
186810639SDarren.Reed@Sun.COM static void
bpf_dev_remove(struct bpf_d * d)186910639SDarren.Reed@Sun.COM bpf_dev_remove(struct bpf_d *d)
187010639SDarren.Reed@Sun.COM {
187110639SDarren.Reed@Sun.COM 	struct bpf_d *stor;
187210639SDarren.Reed@Sun.COM 
187310639SDarren.Reed@Sun.COM 	(void) mod_hash_remove(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
187410639SDarren.Reed@Sun.COM 	    (mod_hash_val_t *)&stor);
187510639SDarren.Reed@Sun.COM 	ASSERT(stor == d);
187610639SDarren.Reed@Sun.COM }
187710639SDarren.Reed@Sun.COM 
187810639SDarren.Reed@Sun.COM /*
187910639SDarren.Reed@Sun.COM  * bpf_def_get should only ever be called for a minor number that exists,
188010639SDarren.Reed@Sun.COM  * thus there should always be a pointer in the hash table that corresponds
188110639SDarren.Reed@Sun.COM  * to it.
188210639SDarren.Reed@Sun.COM  */
188310639SDarren.Reed@Sun.COM static struct bpf_d *
bpf_dev_get(minor_t minor)188410639SDarren.Reed@Sun.COM bpf_dev_get(minor_t minor)
188510639SDarren.Reed@Sun.COM {
188610639SDarren.Reed@Sun.COM 	struct bpf_d *d = NULL;
188710639SDarren.Reed@Sun.COM 
188810639SDarren.Reed@Sun.COM 	(void) mod_hash_find(bpf_hash, (mod_hash_key_t)(uintptr_t)minor,
188910639SDarren.Reed@Sun.COM 	    (mod_hash_val_t *)&d);
189010639SDarren.Reed@Sun.COM 	ASSERT(d != NULL);
189110639SDarren.Reed@Sun.COM 
189210639SDarren.Reed@Sun.COM 	return (d);
189310639SDarren.Reed@Sun.COM }
1894