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); 116*11179SDarren.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 /* 136*11179SDarren.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); 147*11179SDarren.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 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 */ 240*11179SDarren.Reed@Sun.COM static int 241*11179SDarren.Reed@Sun.COM bpf_attachd(struct bpf_d *d, const char *ifname, int dlt) 24210639SDarren.Reed@Sun.COM { 243*11179SDarren.Reed@Sun.COM bpf_provider_list_t *bp; 244*11179SDarren.Reed@Sun.COM bpf_provider_t *bpr; 245*11179SDarren.Reed@Sun.COM boolean_t zonematch; 246*11179SDarren.Reed@Sun.COM zoneid_t niczone; 247*11179SDarren.Reed@Sun.COM uintptr_t mcip; 248*11179SDarren.Reed@Sun.COM zoneid_t zone; 249*11179SDarren.Reed@Sun.COM uint_t nicdlt; 250*11179SDarren.Reed@Sun.COM uintptr_t mh; 251*11179SDarren.Reed@Sun.COM int hdrlen; 252*11179SDarren.Reed@Sun.COM int error; 25310639SDarren.Reed@Sun.COM 25410639SDarren.Reed@Sun.COM ASSERT(d->bd_bif == NULL); 255*11179SDarren.Reed@Sun.COM ASSERT(d->bd_mcip == NULL); 256*11179SDarren.Reed@Sun.COM zone = d->bd_zone; 257*11179SDarren.Reed@Sun.COM zonematch = B_TRUE; 258*11179SDarren.Reed@Sun.COM again: 259*11179SDarren.Reed@Sun.COM mh = 0; 260*11179SDarren.Reed@Sun.COM mcip = 0; 261*11179SDarren.Reed@Sun.COM LIST_FOREACH(bp, &bpf_providers, bpl_next) { 262*11179SDarren.Reed@Sun.COM bpr = bp->bpl_what; 263*11179SDarren.Reed@Sun.COM error = MBPF_OPEN(bpr, ifname, &mh, zone); 264*11179SDarren.Reed@Sun.COM if (error != 0) 265*11179SDarren.Reed@Sun.COM goto next; 266*11179SDarren.Reed@Sun.COM error = MBPF_CLIENT_OPEN(bpr, mh, &mcip); 267*11179SDarren.Reed@Sun.COM if (error != 0) 268*11179SDarren.Reed@Sun.COM goto next; 269*11179SDarren.Reed@Sun.COM error = MBPF_GET_DLT(bpr, mh, &nicdlt); 270*11179SDarren.Reed@Sun.COM if (error != 0) 271*11179SDarren.Reed@Sun.COM goto next; 272*11179SDarren.Reed@Sun.COM 273*11179SDarren.Reed@Sun.COM nicdlt = bpf_dl_to_dlt(nicdlt); 274*11179SDarren.Reed@Sun.COM if (dlt != -1 && dlt != nicdlt) { 275*11179SDarren.Reed@Sun.COM error = ENOENT; 276*11179SDarren.Reed@Sun.COM goto next; 277*11179SDarren.Reed@Sun.COM } 278*11179SDarren.Reed@Sun.COM 279*11179SDarren.Reed@Sun.COM error = MBPF_GET_ZONE(bpr, mh, &niczone); 280*11179SDarren.Reed@Sun.COM if (error != 0) 281*11179SDarren.Reed@Sun.COM goto next; 282*11179SDarren.Reed@Sun.COM 283*11179SDarren.Reed@Sun.COM DTRACE_PROBE4(bpf__attach, struct bpf_provider_s *, bpr, 284*11179SDarren.Reed@Sun.COM uintptr_t, mh, int, nicdlt, zoneid_t, niczone); 28510639SDarren.Reed@Sun.COM 286*11179SDarren.Reed@Sun.COM if (zonematch && niczone != zone) { 287*11179SDarren.Reed@Sun.COM error = ENOENT; 288*11179SDarren.Reed@Sun.COM goto next; 289*11179SDarren.Reed@Sun.COM } 290*11179SDarren.Reed@Sun.COM break; 291*11179SDarren.Reed@Sun.COM next: 292*11179SDarren.Reed@Sun.COM if (mcip != 0) { 293*11179SDarren.Reed@Sun.COM MBPF_CLIENT_CLOSE(bpr, mcip); 294*11179SDarren.Reed@Sun.COM mcip = 0; 295*11179SDarren.Reed@Sun.COM } 296*11179SDarren.Reed@Sun.COM if (mh != NULL) { 297*11179SDarren.Reed@Sun.COM MBPF_CLOSE(bpr, mh); 298*11179SDarren.Reed@Sun.COM mh = 0; 299*11179SDarren.Reed@Sun.COM } 300*11179SDarren.Reed@Sun.COM } 301*11179SDarren.Reed@Sun.COM if (error != 0) { 302*11179SDarren.Reed@Sun.COM if (zonematch && (zone == GLOBAL_ZONEID)) { 303*11179SDarren.Reed@Sun.COM /* 304*11179SDarren.Reed@Sun.COM * If we failed to do an exact match for the global 305*11179SDarren.Reed@Sun.COM * zone using the global zoneid, try again in case 306*11179SDarren.Reed@Sun.COM * the network interface is owned by a local zone. 307*11179SDarren.Reed@Sun.COM */ 308*11179SDarren.Reed@Sun.COM zonematch = B_FALSE; 309*11179SDarren.Reed@Sun.COM goto again; 310*11179SDarren.Reed@Sun.COM } 311*11179SDarren.Reed@Sun.COM return (error); 312*11179SDarren.Reed@Sun.COM } 313*11179SDarren.Reed@Sun.COM 314*11179SDarren.Reed@Sun.COM d->bd_mac = *bpr; 315*11179SDarren.Reed@Sun.COM d->bd_mcip = mcip; 316*11179SDarren.Reed@Sun.COM d->bd_bif = mh; 317*11179SDarren.Reed@Sun.COM d->bd_dlt = nicdlt; 318*11179SDarren.Reed@Sun.COM hdrlen = bpf_dl_hdrsize(nicdlt); 319*11179SDarren.Reed@Sun.COM d->bd_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen; 320*11179SDarren.Reed@Sun.COM 321*11179SDarren.Reed@Sun.COM (void) strlcpy(d->bd_ifname, MBPF_CLIENT_NAME(&d->bd_mac, mcip), 322*11179SDarren.Reed@Sun.COM sizeof (d->bd_ifname)); 323*11179SDarren.Reed@Sun.COM 324*11179SDarren.Reed@Sun.COM (void) MBPF_GET_LINKID(&d->bd_mac, d->bd_ifname, &d->bd_linkid, 325*11179SDarren.Reed@Sun.COM zone); 326*11179SDarren.Reed@Sun.COM (void) MBPF_PROMISC_ADD(&d->bd_mac, d->bd_mcip, 0, d, 327*11179SDarren.Reed@Sun.COM &d->bd_promisc_handle, d->bd_promisc_flags); 328*11179SDarren.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 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; 339*11179SDarren.Reed@Sun.COM uintptr_t mh; 34010639SDarren.Reed@Sun.COM 341*11179SDarren.Reed@Sun.COM ASSERT(d->bd_inuse == -1); 34210639SDarren.Reed@Sun.COM mch = d->bd_mcip; 34310639SDarren.Reed@Sun.COM d->bd_mcip = 0; 344*11179SDarren.Reed@Sun.COM mh = d->bd_bif; 345*11179SDarren.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) 375*11179SDarren.Reed@Sun.COM MBPF_PROMISC_REMOVE(&d->bd_mac, mph); 37610639SDarren.Reed@Sun.COM 37710639SDarren.Reed@Sun.COM if (mch != 0) 378*11179SDarren.Reed@Sun.COM MBPF_CLIENT_CLOSE(&d->bd_mac, mch); 37910639SDarren.Reed@Sun.COM 380*11179SDarren.Reed@Sun.COM if (mh != 0) 381*11179SDarren.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); 388*11179SDarren.Reed@Sun.COM *d->bd_ifname = '\0'; 389*11179SDarren.Reed@Sun.COM 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 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 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 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 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); 530*11179SDarren.Reed@Sun.COM 531*11179SDarren.Reed@Sun.COM while (d->bd_inuse != 0) { 532*11179SDarren.Reed@Sun.COM d->bd_waiting++; 533*11179SDarren.Reed@Sun.COM if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) { 534*11179SDarren.Reed@Sun.COM d->bd_waiting--; 535*11179SDarren.Reed@Sun.COM mutex_exit(&d->bd_lock); 536*11179SDarren.Reed@Sun.COM return (EINTR); 537*11179SDarren.Reed@Sun.COM } 538*11179SDarren.Reed@Sun.COM d->bd_waiting--; 539*11179SDarren.Reed@Sun.COM } 540*11179SDarren.Reed@Sun.COM 541*11179SDarren.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 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 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 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 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); 717*11179SDarren.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 739*11179SDarren.Reed@Sun.COM dlt = d->bd_dlt; 74010639SDarren.Reed@Sun.COM mch = d->bd_mcip; 741*11179SDarren.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 754*11179SDarren.Reed@Sun.COM DTRACE_PROBE4(bpf__tx, struct bpf_d *, d, int, dlt, 755*11179SDarren.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 762*11179SDarren.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 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 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); 945*11179SDarren.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; 950*11179SDarren.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 966*11179SDarren.Reed@Sun.COM error = copyout(&d->bd_dlt, (void *)addr, 967*11179SDarren.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 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 1299*11179SDarren.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 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; 1306*11179SDarren.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 1348*11179SDarren.Reed@Sun.COM if (d->bd_sbuf == 0) 1349*11179SDarren.Reed@Sun.COM error = bpf_allocbufs(d); 135010639SDarren.Reed@Sun.COM 1351*11179SDarren.Reed@Sun.COM if (error == 0) { 135210639SDarren.Reed@Sun.COM mutex_enter(&d->bd_lock); 1353*11179SDarren.Reed@Sun.COM if (d->bd_bif) 1354*11179SDarren.Reed@Sun.COM /* 1355*11179SDarren.Reed@Sun.COM * Detach if attached to something else. 1356*11179SDarren.Reed@Sun.COM */ 1357*11179SDarren.Reed@Sun.COM bpf_detachd(d); 135810639SDarren.Reed@Sun.COM 1359*11179SDarren.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 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); 1388*11179SDarren.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 1393*11179SDarren.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 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 * 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 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 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 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; 1548*11179SDarren.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 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; 1568*11179SDarren.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 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 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 168310639SDarren.Reed@Sun.COM bpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *listp) 168410639SDarren.Reed@Sun.COM { 1685*11179SDarren.Reed@Sun.COM bpf_provider_list_t *bp; 1686*11179SDarren.Reed@Sun.COM bpf_provider_t *bpr; 1687*11179SDarren.Reed@Sun.COM zoneid_t zoneid; 1688*11179SDarren.Reed@Sun.COM uintptr_t mcip; 1689*11179SDarren.Reed@Sun.COM uint_t nicdlt; 1690*11179SDarren.Reed@Sun.COM uintptr_t mh; 1691*11179SDarren.Reed@Sun.COM int error; 1692*11179SDarren.Reed@Sun.COM int n; 169310639SDarren.Reed@Sun.COM 169410639SDarren.Reed@Sun.COM n = 0; 1695*11179SDarren.Reed@Sun.COM mh = 0; 1696*11179SDarren.Reed@Sun.COM mcip = 0; 169710639SDarren.Reed@Sun.COM error = 0; 1698*11179SDarren.Reed@Sun.COM mutex_enter(&d->bd_lock); 1699*11179SDarren.Reed@Sun.COM LIST_FOREACH(bp, &bpf_providers, bpl_next) { 1700*11179SDarren.Reed@Sun.COM bpr = bp->bpl_what; 1701*11179SDarren.Reed@Sun.COM error = MBPF_OPEN(bpr, d->bd_ifname, &mh, d->bd_zone); 1702*11179SDarren.Reed@Sun.COM if (error != 0) 1703*11179SDarren.Reed@Sun.COM goto next; 1704*11179SDarren.Reed@Sun.COM error = MBPF_CLIENT_OPEN(bpr, mh, &mcip); 1705*11179SDarren.Reed@Sun.COM if (error != 0) 1706*11179SDarren.Reed@Sun.COM goto next; 1707*11179SDarren.Reed@Sun.COM error = MBPF_GET_ZONE(bpr, mh, &zoneid); 1708*11179SDarren.Reed@Sun.COM if (error != 0) 1709*11179SDarren.Reed@Sun.COM goto next; 171010639SDarren.Reed@Sun.COM if (d->bd_zone != GLOBAL_ZONEID && 1711*11179SDarren.Reed@Sun.COM d->bd_zone != zoneid) 1712*11179SDarren.Reed@Sun.COM goto next; 1713*11179SDarren.Reed@Sun.COM error = MBPF_GET_DLT(bpr, mh, &nicdlt); 1714*11179SDarren.Reed@Sun.COM if (error != 0) 1715*11179SDarren.Reed@Sun.COM goto next; 1716*11179SDarren.Reed@Sun.COM nicdlt = bpf_dl_to_dlt(nicdlt); 171710639SDarren.Reed@Sun.COM if (listp->bfl_list != NULL) { 1718*11179SDarren.Reed@Sun.COM if (n >= listp->bfl_len) { 1719*11179SDarren.Reed@Sun.COM MBPF_CLIENT_CLOSE(bpr, mcip); 1720*11179SDarren.Reed@Sun.COM MBPF_CLOSE(bpr, mh); 1721*11179SDarren.Reed@Sun.COM break; 1722*11179SDarren.Reed@Sun.COM } 172310639SDarren.Reed@Sun.COM /* 1724*11179SDarren.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 */ 1728*11179SDarren.Reed@Sun.COM d->bd_inuse++; 1729*11179SDarren.Reed@Sun.COM mutex_exit(&d->bd_lock); 1730*11179SDarren.Reed@Sun.COM if (copyout(&nicdlt, 173110639SDarren.Reed@Sun.COM listp->bfl_list + n, sizeof (uint_t)) != 0) 173210639SDarren.Reed@Sun.COM error = EFAULT; 1733*11179SDarren.Reed@Sun.COM mutex_enter(&d->bd_lock); 1734*11179SDarren.Reed@Sun.COM if (error != 0) 1735*11179SDarren.Reed@Sun.COM break; 1736*11179SDarren.Reed@Sun.COM d->bd_inuse--; 173710639SDarren.Reed@Sun.COM } 173810639SDarren.Reed@Sun.COM n++; 1739*11179SDarren.Reed@Sun.COM next: 1740*11179SDarren.Reed@Sun.COM if (mcip != 0) { 1741*11179SDarren.Reed@Sun.COM MBPF_CLIENT_CLOSE(bpr, mcip); 1742*11179SDarren.Reed@Sun.COM mcip = 0; 1743*11179SDarren.Reed@Sun.COM } 1744*11179SDarren.Reed@Sun.COM if (mh != 0) { 1745*11179SDarren.Reed@Sun.COM MBPF_CLOSE(bpr, mh); 1746*11179SDarren.Reed@Sun.COM mh = 0; 1747*11179SDarren.Reed@Sun.COM } 174810639SDarren.Reed@Sun.COM } 1749*11179SDarren.Reed@Sun.COM mutex_exit(&d->bd_lock); 1750*11179SDarren.Reed@Sun.COM 1751*11179SDarren.Reed@Sun.COM /* 1752*11179SDarren.Reed@Sun.COM * It is quite possible that one or more provider to BPF may not 1753*11179SDarren.Reed@Sun.COM * know about a link name whlist others do. In that case, so long 1754*11179SDarren.Reed@Sun.COM * as we have one success, do not declare an error unless it was 1755*11179SDarren.Reed@Sun.COM * an EFAULT as this indicates a problem that needs to be reported. 1756*11179SDarren.Reed@Sun.COM */ 1757*11179SDarren.Reed@Sun.COM if ((error != EFAULT) && (n > 0)) 1758*11179SDarren.Reed@Sun.COM error = 0; 1759*11179SDarren.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 176810639SDarren.Reed@Sun.COM bpf_setdlt(struct bpf_d *d, void *addr) 176910639SDarren.Reed@Sun.COM { 177010639SDarren.Reed@Sun.COM char ifname[LIFNAMSIZ+1]; 1771*11179SDarren.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); 1777*11179SDarren.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 } 1784*11179SDarren.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 1789*11179SDarren.Reed@Sun.COM error = MBPF_GET_ZONE(&d->bd_mac, d->bd_bif, &niczone); 1790*11179SDarren.Reed@Sun.COM if (error != 0) { 1791*11179SDarren.Reed@Sun.COM mutex_exit(&d->bd_lock); 1792*11179SDarren.Reed@Sun.COM return (error); 1793*11179SDarren.Reed@Sun.COM } 1794*11179SDarren.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) && 1800*11179SDarren.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 1805*11179SDarren.Reed@Sun.COM (void) strlcpy(ifname, d->bd_ifname, sizeof (ifname)); 1806*11179SDarren.Reed@Sun.COM d->bd_inuse = -1; 180710639SDarren.Reed@Sun.COM bpf_detachd(d); 1808*11179SDarren.Reed@Sun.COM error = bpf_attachd(d, ifname, dlt); 180910639SDarren.Reed@Sun.COM reset_d(d); 1810*11179SDarren.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 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 * 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 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 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 * 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