bpf.c revision b50f3686f8648cf002fd38447a5a22d6cbcd270c
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* $NetBSD: bpf.c,v 1.143 2009/03/11 05:55:22 mrg Exp $ */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copyright (c) 1990, 1991, 1993
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The Regents of the University of California. All rights reserved.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This code is derived from the Stanford/CMU enet packet filter,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * (net/enet.c) distributed as part of 4.3BSD, and code contributed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Berkeley Laboratory.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Redistribution and use in source and binary forms, with or without
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * modification, are permitted provided that the following conditions
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * are met:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 1. Redistributions of source code must retain the above copyright
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * notice, this list of conditions and the following disclaimer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 2. Redistributions in binary form must reproduce the above copyright
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * notice, this list of conditions and the following disclaimer in the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * documentation and/or other materials provided with the distribution.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 3. Neither the name of the University nor the names of its contributors
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * may be used to endorse or promote products derived from this software
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * without specific prior written permission.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * SUCH DAMAGE.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * @(#)bpf.c 8.4 (Berkeley) 1/9/95
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * static char rcsid[] =
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * "Header: bpf.c,v 1.67 96/09/26 22:00:52 leres Exp ";
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Use is subject to license terms.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The BPF implements the following access controls for zones attempting
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to read and write data. Writing of data requires that the net_rawaccess
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * privilege is held whilst reading data requires either net_rawaccess or
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * net_observerability.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * | Shared | Exclusive | Global
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * DLT_IPNET in local zone | Read | Read | Read |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Raw access to local zone NIC | None | Read/Write | Read/Write |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Raw access to all NICs | None | None | Read/Write |
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * -----------------------------+--------+------------+------------+
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The BPF driver is written as a cloning driver: each call to bpfopen()
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * allocates a new minor number. This provides BPF with a 1:1 relationship
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * between open's and close's. There is some amount of "descriptor state"
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * that is kept per open. Pointers to this data are stored in a hash table
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * (bpf_hash) that is index'd by the minor device number for each open file.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/param.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/systm.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/time.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/ioctl.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/queue.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/filio.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/policy.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/cmn_err.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/uio.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/file.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/sysmacros.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/zone.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/socket.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/errno.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/poll.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/dlpi.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/neti.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <net/if.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <net/bpf.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <net/bpfdesc.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <net/dlt.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <netinet/in.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/mac.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/mac_client.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/mac_impl.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/time_std_impl.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/hook.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#include <sys/hook_event.h>
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#define mtod(_v, _t) (_t)((_v)->b_rptr)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#define M_LEN(_m) ((_m)->b_wptr - (_m)->b_rptr)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 4096 is too small for FDDI frames. 8192 is too small for gigabit Ethernet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * jumbos (circa 9k), ATM, or Intel gig/10gig ethernet jumbos (16k).
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#define BPF_BUFSIZE (32 * 1024)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedtypedef void *(*cp_fn_t)(void *, const void *, size_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The default read buffer size, and limit for BIOCSBLEN.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint bpf_bufsize = BPF_BUFSIZE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint bpf_maxbufsize = (16 * 1024 * 1024);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedstatic mod_hash_t *bpf_hash = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Use a mutex to avoid a race condition between gathering the stats/peers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and opening/closing the device.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic kcondvar_t bpf_dlt_waiter;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic kmutex_t bpf_mtx;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic bpf_kstats_t ks_stats;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic bpf_kstats_t bpf_kstats = {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "readWait", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "writeOk", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "writeError", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "receive", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "captured", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed { "dropped", KSTAT_DATA_UINT64 },
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed};
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic kstat_t *bpf_ksp;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * bpf_list is a list of the BPF descriptors currently open
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren ReedLIST_HEAD(, bpf_d) bpf_list;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_allocbufs(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_clear_timeout(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_deliver(struct bpf_d *, cp_fn_t,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed void *, uint_t, uint_t, boolean_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_freed(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_ifname(struct bpf_d *d, char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void *bpf_mcpy(void *, const void *, size_t);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedstatic int bpf_attachd(struct bpf_d *, const char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_detachd(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_setif(struct bpf_d *, char *, int);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_timed_out(void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_wakeup(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void catchpacket(struct bpf_d *, uchar_t *, uint_t, uint_t,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cp_fn_t, struct timeval *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void reset_d(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_getdltlist(struct bpf_d *, struct bpf_dltlist *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int bpf_setdlt(struct bpf_d *, void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_dev_add(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *bpf_dev_find(minor_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *bpf_dev_get(minor_t);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void bpf_dev_remove(struct bpf_d *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_movein(struct uio *uio, int linktype, int mtu, mblk_t **mp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mblk_t *m;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int error;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int hlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int align;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Build a sockaddr based on the data link layer type.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We do this at this level because the ethernet header
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is copied directly into the data field of the sockaddr.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * In the case of SLIP, there is no header and the packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is forwarded as is.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Also, we are careful to leave room at the front of the mbuf
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * for the link level header.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed switch (linktype) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case DLT_EN10MB:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hlen = sizeof (struct ether_header);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case DLT_FDDI:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hlen = 16;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case DLT_NULL:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hlen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case DLT_IPOIB:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hlen = 44;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed default:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EIO);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed align = 4 - (hlen & 3);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed len = uio->uio_resid;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If there aren't enough bytes for a link level header or the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * packet length exceeds the interface mtu, return an error.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (len < hlen || len - hlen > mtu)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EMSGSIZE);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m = allocb(len + align, BPRI_MED);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (m == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = ENOBUFS;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed goto bad;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Insure the data is properly aligned */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (align > 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m->b_rptr += align;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m->b_wptr = m->b_rptr + len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = uiomove(mtod(m, void *), len, UIO_WRITE, uio);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed goto bad;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *mp = m;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbad:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (m != NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed freemsg(m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Attach file to the bpf interface, i.e. make d listen on bp.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedstatic int
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedbpf_attachd(struct bpf_d *d, const char *ifname, int dlt)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpf_provider_list_t *bp;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpf_provider_t *bpr;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed boolean_t zonematch;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zoneid_t niczone;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t mcip;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zoneid_t zone;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uint_t nicdlt;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t mh;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int hdrlen;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int error;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ASSERT(d->bd_bif == NULL);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed ASSERT(d->bd_mcip == NULL);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zone = d->bd_zone;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zonematch = B_TRUE;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reedagain:
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mh = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mcip = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed LIST_FOREACH(bp, &bpf_providers, bpl_next) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpr = bp->bpl_what;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_OPEN(bpr, ifname, &mh, zone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_CLIENT_OPEN(bpr, mh, &mcip);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_DLT(bpr, mh, &nicdlt);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed nicdlt = bpf_dl_to_dlt(nicdlt);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (dlt != -1 && dlt != nicdlt) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = ENOENT;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_ZONE(bpr, mh, &niczone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed DTRACE_PROBE4(bpf__attach, struct bpf_provider_s *, bpr,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t, mh, int, nicdlt, zoneid_t, niczone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (zonematch && niczone != zone) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = ENOENT;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed break;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reednext:
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (mcip != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLIENT_CLOSE(bpr, mcip);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mcip = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (mh != NULL) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLOSE(bpr, mh);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mh = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (zonematch && (zone == GLOBAL_ZONEID)) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed /*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * If we failed to do an exact match for the global
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * zone using the global zoneid, try again in case
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * the network interface is owned by a local zone.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zonematch = B_FALSE;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto again;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed return (error);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_mac = *bpr;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_mcip = mcip;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_bif = mh;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_dlt = nicdlt;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed hdrlen = bpf_dl_hdrsize(nicdlt);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_hdrlen = BPF_WORDALIGN(hdrlen + SIZEOF_BPF_HDR) - hdrlen;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) strlcpy(d->bd_ifname, MBPF_CLIENT_NAME(&d->bd_mac, mcip),
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed sizeof (d->bd_ifname));
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) MBPF_GET_LINKID(&d->bd_mac, d->bd_ifname, &d->bd_linkid,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) MBPF_PROMISC_ADD(&d->bd_mac, d->bd_mcip, 0, d,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed &d->bd_promisc_handle, d->bd_promisc_flags);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Detach a file from its interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_detachd(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uintptr_t mph;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uintptr_t mch;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t mh;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed ASSERT(d->bd_inuse == -1);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mch = d->bd_mcip;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_mcip = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mh = d->bd_bif;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_bif = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Check if this descriptor had requested promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If so, turn it off. There's no need to take any action
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * here, that is done when MBPF_PROMISC_REMOVE is used;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bd_promisc is just a local flag to stop promiscuous mode
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * from being set more than once.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_promisc)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Take device out of "promiscuous" mode. Since we were able to
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * enter "promiscuous" mode, we should be able to turn it off.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Note, this field stores a pointer used to support both
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * promiscuous and non-promiscuous callbacks for packets.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mph = d->bd_promisc_handle;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_handle = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The lock has to be dropped here because mac_promisc_remove may
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * need to wait for mac_promisc_dispatch, which has called into
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf and catchpacket is waiting for bd_lock...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * i.e mac_promisc_remove() needs to be called with none of the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * locks held that are part of the bpf_mtap() call path.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (mph != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_PROMISC_REMOVE(&d->bd_mac, mph);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (mch != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLIENT_CLOSE(&d->bd_mac, mch);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (mh != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLOSE(&d->bd_mac, mh);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Because this function is called with bd_lock held, so it must
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * exit with it held.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed *d->bd_ifname = '\0';
b50f3686f8648cf002fd38447a5a22d6cbcd270cDarren Reed (void) memset(&d->bd_mac, 0, sizeof (d->bd_mac));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfilterattach() is called at load time.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfilterattach(void)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_hash = mod_hash_create_idhash("bpf_dev_tab", 31,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mod_hash_null_keydtor);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (bpf_hash == NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (ENOMEM);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) memcpy(&ks_stats, &bpf_kstats, sizeof (bpf_kstats));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_ksp = kstat_create("bpf", 0, "global", "misc",
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed KSTAT_TYPE_NAMED, sizeof (bpf_kstats) / sizeof (kstat_named_t),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed KSTAT_FLAG_VIRTUAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (bpf_ksp != NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_ksp->ks_data = &ks_stats;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kstat_install(bpf_ksp);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mod_hash_destroy_idhash(bpf_hash);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_hash = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EEXIST);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_init(&bpf_dlt_waiter, NULL, CV_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_init(&bpf_mtx, NULL, MUTEX_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed LIST_INIT(&bpf_list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfilterdetach() is called at unload time.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfilterdetach(void)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (bpf_ksp != NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kstat_delete(bpf_ksp);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_ksp = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mod_hash_destroy_idhash(bpf_hash);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_hash = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_destroy(&bpf_dlt_waiter);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_destroy(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Open ethernet device. Clones.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfopen(dev_t *devp, int flag, int mode, cred_t *cred)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t dmin;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The security policy described at the top of this file is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * enforced here.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((flag & FWRITE) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (secpolicy_net_rawaccess(cred) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EACCES);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((flag & FREAD) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((secpolicy_net_observability(cred) != 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (secpolicy_net_rawaccess(cred) != 0))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EACCES);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((flag & (FWRITE|FREAD)) == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (ENXIO);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * A structure is allocated per open file in BPF to store settings
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * such as buffer capture size, provide private buffers, etc.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d = (struct bpf_d *)kmem_zalloc(sizeof (*d), KM_SLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_bufsize = bpf_bufsize;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_fmode = flag;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_zone = crgetzoneid(cred);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_seesent = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_PHYS|
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed MAC_PROMISC_FLAGS_NO_COPY;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_init(&d->bd_lock, NULL, MUTEX_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_init(&d->bd_wait, NULL, CV_DRIVER, NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Find an unused minor number. Obviously this is an O(n) algorithm
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and doesn't scale particularly well, so if there are large numbers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * of open file descriptors happening in real use, this design may
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * need to be revisited.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed for (dmin = 0; dmin < L_MAXMIN; dmin++)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (bpf_dev_find(dmin) == NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (dmin == L_MAXMIN) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d, sizeof (*d));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (ENXIO);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_dev = dmin;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed LIST_INSERT_HEAD(&bpf_list, d, bd_list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_dev_add(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *devp = makedevice(getmajor(*devp), dmin);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Close the descriptor by detaching it from its interface,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * deallocating its buffers, and marking it free.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Because we only allow a device to be opened once, there is always a
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * 1 to 1 relationship between opens and closes supporting this function.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfclose(dev_t dev, int flag, int otyp, cred_t *cred_p)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = bpf_dev_get(getminor(dev));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed while (d->bd_inuse != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_waiting++;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_waiting--;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mutex_exit(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed return (EINTR);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_waiting--;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_inuse = -1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_state == BPF_WAITING)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_clear_timeout(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_state = BPF_IDLE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_detachd(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed LIST_REMOVE(d, bd_list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_dev_remove(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&bpf_mtx);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_destroy(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_destroy(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_freed(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d, sizeof (*d));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the packet buffers in descriptor d. Move the store buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * into the hold slot, and the free buffer into the store slot.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Zero the length of the new store buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#define ROTATE_BUFFERS(d) \
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (d)->bd_hbuf = (d)->bd_sbuf; \
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (d)->bd_hlen = (d)->bd_slen; \
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (d)->bd_sbuf = (d)->bd_fbuf; \
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (d)->bd_slen = 0; \
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (d)->bd_fbuf = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpfread - read next chunk of packets from buffers
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfread(dev_t dev, struct uio *uio, cred_t *cred)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = bpf_dev_get(getminor(dev));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int timed_out;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ulong_t delay;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int error;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_fmode & FREAD) == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EBADF);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Restrict application to use a buffer the same size as
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the kernel buffers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (uio->uio_resid != d->bd_bufsize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_state == BPF_WAITING)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_clear_timeout(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed timed_out = (d->bd_state == BPF_TIMED_OUT);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_state = BPF_IDLE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If the hold buffer is empty, then do a timed sleep, which
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ends when the timeout expires or when enough packets
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * have arrived to fill the store buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_hbuf == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_nonblock) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_slen == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EWOULDBLOCK);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ROTATE_BUFFERS(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_immediate || timed_out) && d->bd_slen != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * A packet(s) either arrived since the previous
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * read or arrived while we were asleep.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the buffers and return what's here.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ROTATE_BUFFERS(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_read_wait.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed delay = ddi_get_lbolt() + d->bd_rtout;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = cv_timedwait_sig(&d->bd_wait, &d->bd_lock, delay);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINTR);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == -1) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * On a timeout, return what's in the buffer,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * which may be nothing. If there is something
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * in the store buffer, we can rotate the buffers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hbuf)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We filled up the buffer in between
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * getting the timeout and arriving
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * here, so we don't need to rotate.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_slen == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ROTATE_BUFFERS(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * At this point, we know we have something in the hold slot.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Move data from hold buffer into user space.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We know the entire buffer is transferred since
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * we checked above that the read buffer is bpf_bufsize bytes.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = uiomove(d->bd_hbuf, d->bd_hlen, UIO_READ, uio);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_fbuf = d->bd_hbuf;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_hbuf = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_hlen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reeddone:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If there are processes sleeping on this descriptor, wake them up.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * NOTE: the lock for bd_wait is bd_lock and is held by bpf_deliver,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * so there is no code here grabbing it.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_wakeup(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_signal(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_timed_out(void *arg)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = arg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_state == BPF_WAITING) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_state = BPF_TIMED_OUT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_slen != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_signal(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfwrite(dev_t dev, struct uio *uio, cred_t *cred)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = bpf_dev_get(getminor(dev));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uintptr_t mch;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t mtu;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mblk_t *m;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int error;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int dlt;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_fmode & FWRITE) == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EBADF);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_bif == 0 || d->bd_mcip == 0 || d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINTR);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (uio->uio_resid == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_inuse < 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINTR);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed dlt = d->bd_dlt;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mch = d->bd_mcip;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_SDU_GET(&d->bd_mac, d->bd_bif, &mtu);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (dlt == DLT_IPNET) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EIO;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed goto done;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_movein(uio, dlt, mtu, &m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed goto done;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed DTRACE_PROBE4(bpf__tx, struct bpf_d *, d, int, dlt,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uint_t, mtu, mblk_t *, m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (M_LEN(m) > mtu) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EMSGSIZE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed goto done;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_TX(&d->bd_mac, mch, m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The "tx" action here is required to consume the mblk_t.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reeddone:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_write_ok.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed else
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_write_error.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (m != NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed freemsg(m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_inuse == 0) && (d->bd_waiting != 0))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_signal(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The driver frees the mbuf.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Reset a descriptor by flushing its packet buffer and clearing the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * receive and drop counts. Should be called at splnet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedreset_d(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hbuf) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Free the hold buffer. */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_fbuf = d->bd_hbuf;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_hbuf = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_slen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_hlen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rcount = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_dcount = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_ccount = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * FIONREAD Check for read packet available.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGBLEN Get buffer len [for read()].
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSETF Set ethernet read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCFLUSH Flush read packet buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCPROMISC Put interface into promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGDLT Get link layer type.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGETIF Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSETIF Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSRTIMEOUT Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGRTIMEOUT Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGSTATS Get packet stats.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCIMMEDIATE Set immediate mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCVERSION Get filter language version.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCGHDRCMPLT Get "header already complete" flag.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * BIOCSHDRCMPLT Set "header already complete" flag.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfioctl(dev_t dev, int cmd, intptr_t addr, int mode, cred_t *cred, int *rval)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = bpf_dev_get(getminor(dev));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_program prog;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct lifreq lifreq;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct ifreq ifreq;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int error = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Refresh the PID associated with this bpf file.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_state == BPF_WAITING)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_clear_timeout(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_state = BPF_IDLE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed switch (cmd) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed default:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Check for read packet available.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case FIONREAD:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int n;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed n = d->bd_slen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hbuf)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed n += d->bd_hlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *(int *)addr = n;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get buffer len [for read()].
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGBLEN:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = copyout(&d->bd_bufsize, (void *)addr,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_bufsize));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set buffer length.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSBLEN:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &size, sizeof (size)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (size > bpf_maxbufsize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed size = bpf_maxbufsize;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed else if (size < BPF_MINBUFSIZE)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed size = BPF_MINBUFSIZE;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_bufsize = size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = copyout(&size, (void *)addr, sizeof (size));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set link layer read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSETF:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ddi_copyin((void *)addr, &prog, sizeof (prog), mode)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setf(d, &prog);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Flush read packet buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCFLUSH:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed reset_d(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Put interface into promiscuous mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This is a one-way ioctl, it is not used to turn promiscuous
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * mode off.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCPROMISC:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * No interface attached yet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_promisc == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_promisc_handle) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uintptr_t mph;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mph = d->bd_promisc_handle;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_handle = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_PROMISC_REMOVE(&d->bd_mac, mph);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc_flags = MAC_PROMISC_FLAGS_NO_COPY;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_PROMISC_ADD(&d->bd_mac,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_mcip, MAC_CLIENT_PROMISC_ALL, d,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed &d->bd_promisc_handle, d->bd_promisc_flags);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_promisc = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGDLT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed else
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = copyout(&d->bd_dlt, (void *)addr,
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed sizeof (d->bd_dlt));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of supported device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGDLTLIST:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_dltlist list;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &list, sizeof (list)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_getdltlist(d, &list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&list, (void *)addr, sizeof (list)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSDLT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setdlt(d, (void *)addr);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGETIF:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_ifname(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&ifreq, (void *)addr, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSETIF:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &ifreq, sizeof (ifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setif(d, ifreq.ifr_name, sizeof (ifreq.ifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get interface name.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGETLIF:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_ifname(d, lifreq.lifr_name,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (lifreq.lifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((error == 0) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed copyout(&lifreq, (void *)addr, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSETLIF:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lifreq, sizeof (lifreq)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setif(d, lifreq.lifr_name,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (lifreq.lifr_name));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#ifdef _SYSCALL32_IMPL
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSRTIMEOUT32:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct timeval32 tv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Convert the timeout in microseconds to ticks */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_usec);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_rtout == 0) && (tv.tv_usec != 0))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGRTIMEOUT32:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct timeval32 tv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed clock_t ticks;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ticks = drv_hztousec(d->bd_rtout);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_sec = ticks / 1000000;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_usec = ticks - (tv.tv_sec * 1000000);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = copyout(&tv, (void *)addr, sizeof (tv));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of supported device parameters.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGDLTLIST32:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EINVAL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_dltlist32 lst32;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_dltlist list;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &lst32, sizeof (lst32)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed list.bfl_len = lst32.bfl_len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed list.bfl_list = (void *)(uint64_t)lst32.bfl_list;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_getdltlist(d, &list);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (error == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed lst32.bfl_len = list.bfl_len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&lst32, (void *)addr,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (lst32)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set link layer read filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSETF32: {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_program32 prog32;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (ddi_copyin((void *)addr, &prog32, sizeof (prog), mode)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed prog.bf_len = prog32.bf_len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed prog.bf_insns = (void *)(uint64_t)prog32.bf_insns;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = bpf_setf(d, &prog);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed#endif
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSRTIMEOUT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct timeval tv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &tv, sizeof (tv)) != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Convert the timeout in microseconds to ticks */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = drv_usectohz(tv.tv_sec * 1000000 +
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_usec);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((d->bd_rtout == 0) && (tv.tv_usec != 0))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rtout = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get read timeout.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGRTIMEOUT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct timeval tv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed clock_t ticks;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ticks = drv_hztousec(d->bd_rtout);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_sec = ticks / 1000000;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed tv.tv_usec = ticks - (tv.tv_sec * 1000000);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&tv, (void *)addr, sizeof (tv)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get packet stats.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGSTATS:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_stat bs;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bs.bs_recv = d->bd_rcount;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bs.bs_drop = d->bd_dcount;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bs.bs_capt = d->bd_ccount;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&bs, (void *)addr, sizeof (bs)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set immediate mode.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCIMMEDIATE:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &d->bd_immediate,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_immediate)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCVERSION:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_version bv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bv.bv_major = BPF_MAJOR_VERSION;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bv.bv_minor = BPF_MINOR_VERSION;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&bv, (void *)addr, sizeof (bv)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGHDRCMPLT: /* get "header already complete" flag */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&d->bd_hdrcmplt, (void *)addr,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_hdrcmplt)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSHDRCMPLT: /* set "header already complete" flag */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &d->bd_hdrcmplt,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_hdrcmplt)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get "see sent packets" flag
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCGSEESENT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyout(&d->bd_seesent, (void *)addr,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_seesent)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set "see sent" packets flag
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case BIOCSSEESENT:
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &d->bd_seesent,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_seesent)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed case FIONBIO: /* Non-blocking I/O */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin((void *)addr, &d->bd_nonblock,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed sizeof (d->bd_nonblock)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed break;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set d's packet filter program to fp. If this file already has a filter,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * free it and replace it. If the new filter is "empty" (has a 0 size), then
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the result is to just remove and free the existing filter.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Returns EINVAL for bogus requests.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_setf(struct bpf_d *d, struct bpf_program *fp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_insn *fcode, *old;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t flen, size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed size_t oldsize;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (fp->bf_insns == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (fp->bf_len != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed old = d->bd_filter;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed oldsize = d->bd_filter_size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_filter = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_filter_size = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed reset_d(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (old != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(old, oldsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed flen = fp->bf_len;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (flen > BPF_MAXINSNS)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed size = flen * sizeof (*fp->bf_insns);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed fcode = kmem_alloc(size, KM_SLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin(fp->bf_insns, fcode, size) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EFAULT);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (bpf_validate(fcode, (int)flen)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed old = d->bd_filter;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed oldsize = d->bd_filter_size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_filter = fcode;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_filter_size = size;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed reset_d(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (old != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(old, oldsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(fcode, size);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Detach a file from its current interface (if attached at all) and attach
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * to the interface indicated by the name stored in ifname.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Return an errno or 0.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_setif(struct bpf_d *d, char *ifname, int namesize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int unit_seen;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int error = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed char *cp;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int i;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Make sure the provided name has a unit number, and default
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * it to '0' if not specified.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * XXX This is ugly ... do this differently?
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed unit_seen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cp = ifname;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cp[namesize - 1] = '\0'; /* sanity */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (*cp++)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (*cp >= '0' && *cp <= '9')
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed unit_seen = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!unit_seen) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Make sure to leave room for the '\0'. */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed for (i = 0; i < (namesize - 1); ++i) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if ((ifname[i] >= 'a' && ifname[i] <= 'z') ||
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (ifname[i] >= 'A' && ifname[i] <= 'Z'))
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed continue;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ifname[i] = '0';
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Make sure that only one call to this function happens at a time
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * and that we're not interleaving a read/write
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (d->bd_inuse != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (cv_wait_sig(&d->bd_wait, &d->bd_lock) <= 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINTR);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_waiting--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse = -1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_sbuf == 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = bpf_allocbufs(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_bif)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed /*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Detach if attached to something else.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpf_detachd(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = bpf_attachd(d, ifname, -1);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed reset_d(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_waiting != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_signal(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_waiting != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cv_signal(&d->bd_wait);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Try tickle the mac layer into attaching the device...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (bpf_provider_tickle(ifname, d->bd_zone));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy the interface name to the ifreq.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_ifname(struct bpf_d *d, char *buffer, int bufsize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_bif == NULL) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) strlcpy(buffer, d->bd_ifname, bufsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Support for poll() system call
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Return true iff the specific operation will not block indefinitely - with
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the assumption that it is safe to positively acknowledge a request for the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * ability to write to the BPF device.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Otherwise, return false but make a note that a selnotify() must be done.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedint
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpfchpoll(dev_t dev, short events, int anyyet, short *reventsp,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct pollhead **phpp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = bpf_dev_get(getminor(dev));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (events & (POLLIN | POLLRDNORM)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * An imitation of the FIONREAD ioctl code.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hlen != 0 ||
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ((d->bd_immediate || d->bd_state == BPF_TIMED_OUT) &&
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_slen != 0)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *reventsp |= events & (POLLIN | POLLRDNORM);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *reventsp = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!anyyet)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *phpp = &d->bd_poll;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /* Start the read timeout if necessary */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_rtout > 0 && d->bd_state == BPF_IDLE) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_clear_timeout(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Only allow the timeout to be set once.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_callout == 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_callout = timeout(bpf_timed_out,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d, d->bd_rtout);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_state = BPF_WAITING;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy data from an mblk_t chain into a buffer. This works for ipnet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * because the dl_ipnetinfo_t is placed in an mblk_t that leads the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * packet itself.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_mcpy(void *dst_arg, const void *src_arg, size_t len)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed const mblk_t *m;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t count;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uchar_t *dst;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m = src_arg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst = dst_arg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed while (len > 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (m == NULL)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed panic("bpf_mcpy");
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed count = (uint_t)min(M_LEN(m), len);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) memcpy(dst, mtod(m, const void *), count);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed m = m->b_cont;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed dst += count;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed len -= count;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (dst_arg);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Dispatch a packet to all the listeners on interface bp.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * marg pointer to the packet, either a data buffer or an mbuf chain
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * buflen buffer length, if marg is a data buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * cpfn a function that can copy marg into the listener's buffer
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pktlen length of the packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * issent boolean indicating whether the packet was sent or receive
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic inline void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_deliver(struct bpf_d *d, cp_fn_t cpfn, void *marg, uint_t pktlen,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t buflen, boolean_t issent)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct timeval tv;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t slen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!d->bd_seesent && issent)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Accuracy of the packet counters in BPF is vital so it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * is important to protect even the outer ones.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed slen = bpf_filter(d->bd_filter, marg, pktlen, buflen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed DTRACE_PROBE5(bpf__packet, struct bpf_if *, d->bd_bif,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *, d, void *, marg, uint_t, pktlen, uint_t, slen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_rcount++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_receive.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (slen != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uniqtime(&tv);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed catchpacket(d, marg, pktlen, slen, cpfn, &tv);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Incoming linkage from device drivers.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedvoid
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_mtap(void *arg, mac_resource_handle_t mrh, mblk_t *m, boolean_t issent)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cp_fn_t cpfn;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = arg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed uint_t pktlen, buflen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed void *marg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed pktlen = msgdsize(m);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (pktlen == M_LEN(m)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cpfn = (cp_fn_t)memcpy;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed marg = mtod(m, void *);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed buflen = pktlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cpfn = bpf_mcpy;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed marg = m;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed buflen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_deliver(d, cpfn, marg, pktlen, buflen, issent);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Incoming linkage from ipnet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * In ipnet, there is only one event, NH_OBSERVE, that delivers packets
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * from all network interfaces. Thus the tap function needs to apply a
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * filter using the interface index/id to immitate snoop'ing on just the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * specified interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/* ARGSUSED */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedvoid
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_itap(void *arg, mblk_t *m, boolean_t issent, uint_t length)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hook_pkt_observe_t *hdr;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = arg;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hdr = (hook_pkt_observe_t *)m->b_rptr;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (ntohl(hdr->hpo_ifindex) != d->bd_linkid)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_deliver(d, bpf_mcpy, m, length, 0, issent);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Move the packet data from interface memory (pkt) into the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * store buffer. Return 1 if it's time to wakeup a listener (buffer full),
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * otherwise 0. "copy" is the routine called to do the actual data
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * transfer. memcpy is passed in to copy contiguous chunks, while
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_mcpy is passed in to copy mbuf chains. In the latter case,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pkt is really an mbuf.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedcatchpacket(struct bpf_d *d, uchar_t *pkt, uint_t pktlen, uint_t snaplen,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed cp_fn_t cpfn, struct timeval *tv)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_hdr *hp;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int totlen, curlen;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int hdrlen = d->bd_hdrlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int do_wakeup = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ++d->bd_ccount;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_capture.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Figure out how many bytes to move. If the packet is
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * greater or equal to the snapshot length, transfer that
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * much. Otherwise, transfer the whole packet (unless
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * we hit the buffer size limit).
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed totlen = hdrlen + min(snaplen, pktlen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (totlen > d->bd_bufsize)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed totlen = d->bd_bufsize;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Round up the end of the previous packet to the next longword.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed curlen = BPF_WORDALIGN(d->bd_slen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (curlen + totlen > d->bd_bufsize) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * This packet will overflow the storage buffer.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Rotate the buffers if we can, then wakeup any
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * pending reads.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_fbuf == 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * We haven't completed the previous read yet,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * so drop the packet.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ++d->bd_dcount;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ks_stats.kp_dropped.value.ui64++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ROTATE_BUFFERS(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed do_wakeup = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed curlen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed } else if (d->bd_immediate || d->bd_state == BPF_TIMED_OUT) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Immediate mode is set, or the read timeout has
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * already expired during a select call. A packet
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * arrived, so the reader should be woken up.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed do_wakeup = 1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Append the bpf header to the existing buffer before we add
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * on the actual packet data.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp = (struct bpf_hdr *)((char *)d->bd_sbuf + curlen);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp->bh_tstamp.tv_sec = tv->tv_sec;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp->bh_tstamp.tv_usec = tv->tv_usec;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp->bh_datalen = pktlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed hp->bh_hdrlen = (uint16_t)hdrlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Copy the packet data into the store buffer and update its length.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (*cpfn)((uchar_t *)hp + hdrlen, pkt,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (hp->bh_caplen = totlen - hdrlen));
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_slen = curlen + totlen;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Call bpf_wakeup after bd_slen has been updated.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (do_wakeup)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_wakeup(d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Initialize all nonzero fields of a descriptor.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_allocbufs(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_fbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!d->bd_fbuf)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (ENOBUFS);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_sbuf = kmem_zalloc(d->bd_bufsize, KM_NOSLEEP);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (!d->bd_sbuf) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d->bd_fbuf, d->bd_bufsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (ENOBUFS);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_slen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_hlen = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Free buffers currently in use by a descriptor.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Called on close.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_freed(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * At this point the descriptor has been detached from its
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * interface and it yet hasn't been marked free.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_sbuf != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d->bd_sbuf, d->bd_bufsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_hbuf != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d->bd_hbuf, d->bd_bufsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_fbuf != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d->bd_fbuf, d->bd_bufsize);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_filter)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed kmem_free(d->bd_filter, d->bd_filter_size);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Get a list of available data link type of the interface.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_getdltlist(struct bpf_d *d, struct bpf_dltlist *listp)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpf_provider_list_t *bp;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpf_provider_t *bpr;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zoneid_t zoneid;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t mcip;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uint_t nicdlt;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed uintptr_t mh;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int error;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed int n;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed n = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mh = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mcip = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed LIST_FOREACH(bp, &bpf_providers, bpl_next) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed bpr = bp->bpl_what;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_OPEN(bpr, d->bd_ifname, &mh, d->bd_zone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_CLIENT_OPEN(bpr, mh, &mcip);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_ZONE(bpr, mh, &zoneid);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_zone != GLOBAL_ZONEID &&
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_zone != zoneid)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_DLT(bpr, mh, &nicdlt);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed goto next;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed nicdlt = bpf_dl_to_dlt(nicdlt);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (listp->bfl_list != NULL) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (n >= listp->bfl_len) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLIENT_CLOSE(bpr, mcip);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLOSE(bpr, mh);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed break;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * Bumping of bd_inuse ensures the structure does not
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * disappear while the copyout runs and allows the for
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * loop to be continued.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_inuse++;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mutex_exit(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (copyout(&nicdlt,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed listp->bfl_list + n, sizeof (uint_t)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed error = EFAULT;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mutex_enter(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0)
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed break;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_inuse--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed n++;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reednext:
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (mcip != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLIENT_CLOSE(bpr, mcip);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mcip = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (mh != 0) {
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed MBPF_CLOSE(bpr, mh);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mh = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed mutex_exit(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed /*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * It is quite possible that one or more provider to BPF may not
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * know about a link name whlist others do. In that case, so long
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * as we have one success, do not declare an error unless it was
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * an EFAULT as this indicates a problem that needs to be reported.
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if ((error != EFAULT) && (n > 0))
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = 0;
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed listp->bfl_len = n;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * Set the data link type of a BPF instance.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic int
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_setdlt(struct bpf_d *d, void *addr)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed char ifname[LIFNAMSIZ+1];
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed zoneid_t niczone;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int error;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed int dlt;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (copyin(addr, &dlt, sizeof (dlt)) != 0)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EFAULT);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (d->bd_bif == 0) { /* Interface not set */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (d->bd_dlt == dlt) { /* NULL-op */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (0);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = MBPF_GET_ZONE(&d->bd_mac, d->bd_bif, &niczone);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if (error != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * See the matrix at the top of the file for the permissions table
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed * enforced by this driver.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed if ((d->bd_zone != GLOBAL_ZONEID) && (dlt != DLT_IPNET) &&
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (niczone != d->bd_zone)) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (EINVAL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed (void) strlcpy(ifname, d->bd_ifname, sizeof (ifname));
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_inuse = -1;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed bpf_detachd(d);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed error = bpf_attachd(d, ifname, dlt);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed reset_d(d);
b7ea883b48e925772db7fa37388112c84c6d5f5bDarren Reed d->bd_inuse = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (error);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_clear_timeout is called with the bd_lock mutex held, providing it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * with the necessary protection to retrieve and modify bd_callout but it
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * does not hold the lock for its entire duration... see below...
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_clear_timeout(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed timeout_id_t tid = d->bd_callout;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_callout = 0;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse++;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed /*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * If the timeout has fired and is waiting on bd_lock, we could
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * deadlock here because untimeout if bd_lock is held and would
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * wait for bpf_timed_out to finish and it never would.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed if (tid != 0) {
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_exit(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) untimeout(tid);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed mutex_enter(&d->bd_lock);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed }
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed d->bd_inuse--;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * As a cloning device driver, BPF needs to keep track of which device
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * numbers are in use and which ones are not. A hash table, indexed by
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the minor device number, is used to store the pointers to the
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * individual descriptors that are allocated in bpfopen().
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * The functions below present the interface for that hash table to
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * the rest of the driver.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_dev_find(minor_t minor)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_find(bpf_hash, (mod_hash_key_t)(uintptr_t)minor,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (mod_hash_val_t *)&d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_dev_add(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_insert(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (mod_hash_val_t)d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic void
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_dev_remove(struct bpf_d *d)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *stor;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_remove(bpf_hash, (mod_hash_key_t)(uintptr_t)d->bd_dev,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (mod_hash_val_t *)&stor);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ASSERT(stor == d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed/*
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * bpf_def_get should only ever be called for a minor number that exists,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * thus there should always be a pointer in the hash table that corresponds
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed * to it.
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed */
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedstatic struct bpf_d *
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reedbpf_dev_get(minor_t minor)
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed{
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed struct bpf_d *d = NULL;
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (void) mod_hash_find(bpf_hash, (mod_hash_key_t)(uintptr_t)minor,
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed (mod_hash_val_t *)&d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed ASSERT(d != NULL);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed return (d);
0a0e9771ca0211c15f3ac4466b661c145feeb9e4Darren Reed}