コード例 #1
0
ファイル: bpf.c プロジェクト: repos-holder/openbsd-patches
/* ARGSUSED */
int
bpfioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
{
    struct bpf_d *d;
    int s, error = 0;

    d = bpfilter_lookup(minor(dev));
    if (d->bd_locked && suser(p, 0) != 0) {
        /* list of allowed ioctls when locked and not root */
        switch (cmd) {
        case BIOCGBLEN:
        case BIOCFLUSH:
        case BIOCGDLT:
        case BIOCGDLTLIST:
        case BIOCGETIF:
        case BIOCGRTIMEOUT:
        case BIOCGSTATS:
        case BIOCVERSION:
        case BIOCGRSIG:
        case BIOCGHDRCMPLT:
        case FIONREAD:
        case BIOCLOCK:
        case BIOCSRTIMEOUT:
        case BIOCIMMEDIATE:
        case TIOCGPGRP:
        case BIOCGDIRFILT:
            break;
        default:
            return (EPERM);
        }
    }

    switch (cmd) {

    default:
        error = EINVAL;
        break;

    /*
     * Check for read packet available.
     */
    case FIONREAD:
    {
        int n;

        s = splnet();
        n = d->bd_slen;
        if (d->bd_hbuf)
            n += d->bd_hlen;
        splx(s);

        *(int *)addr = n;
        break;
    }

    /*
     * Get buffer len [for read()].
     */
    case BIOCGBLEN:
        *(u_int *)addr = d->bd_bufsize;
        break;

    /*
     * Set buffer length.
     */
    case BIOCSBLEN:
        if (d->bd_bif != 0)
            error = EINVAL;
        else {
            u_int size = *(u_int *)addr;

            if (size > bpf_maxbufsize)
                *(u_int *)addr = size = bpf_maxbufsize;
            else if (size < BPF_MINBUFSIZE)
                *(u_int *)addr = size = BPF_MINBUFSIZE;
            d->bd_bufsize = size;
        }
        break;

    /*
     * Set link layer read filter.
     */
    case BIOCSETF:
        error = bpf_setf(d, (struct bpf_program *)addr, 0);
        break;

    /*
     * Set link layer write filter.
     */
    case BIOCSETWF:
        error = bpf_setf(d, (struct bpf_program *)addr, 1);
        break;

    /*
     * Flush read packet buffer.
     */
    case BIOCFLUSH:
        s = splnet();
        bpf_reset_d(d);
        splx(s);
        break;

    /*
     * Put interface into promiscuous mode.
     */
    case BIOCPROMISC:
        if (d->bd_bif == 0) {
            /*
             * No interface attached yet.
             */
            error = EINVAL;
            break;
        }
        s = splnet();
        if (d->bd_promisc == 0) {
            error = ifpromisc(d->bd_bif->bif_ifp, 1);
            if (error == 0)
                d->bd_promisc = 1;
        }
        splx(s);
        break;

    /*
     * Get a list of supported device parameters.
     */
    case BIOCGDLTLIST:
        if (d->bd_bif == NULL)
            error = EINVAL;
        else
            error = bpf_getdltlist(d, (struct bpf_dltlist *)addr);
        break;

    /*
     * Get device parameters.
     */
    case BIOCGDLT:
        if (d->bd_bif == 0)
            error = EINVAL;
        else
            *(u_int *)addr = d->bd_bif->bif_dlt;
        break;

    /*
     * Set device parameters.
     */
    case BIOCSDLT:
        if (d->bd_bif == NULL)
            error = EINVAL;
        else
            error = bpf_setdlt(d, *(u_int *)addr);
        break;

    /*
     * Set interface name.
     */
    case BIOCGETIF:
        if (d->bd_bif == 0)
            error = EINVAL;
        else
            bpf_ifname(d->bd_bif->bif_ifp, (struct ifreq *)addr);
        break;

    /*
     * Set interface.
     */
    case BIOCSETIF:
        error = bpf_setif(d, (struct ifreq *)addr);
        break;

    /*
     * Set read timeout.
     */
    case BIOCSRTIMEOUT:
    {
        struct timeval *tv = (struct timeval *)addr;

        /* Compute number of ticks. */
        d->bd_rtout = tv->tv_sec * hz + tv->tv_usec / tick;
        if (d->bd_rtout == 0 && tv->tv_usec != 0)
            d->bd_rtout = 1;
        break;
    }

    /*
     * Get read timeout.
     */
    case BIOCGRTIMEOUT:
    {
        struct timeval *tv = (struct timeval *)addr;

        tv->tv_sec = d->bd_rtout / hz;
        tv->tv_usec = (d->bd_rtout % hz) * tick;
        break;
    }

    /*
     * Get packet stats.
     */
    case BIOCGSTATS:
    {
        struct bpf_stat *bs = (struct bpf_stat *)addr;

        bs->bs_recv = d->bd_rcount;
        bs->bs_drop = d->bd_dcount;
        break;
    }

    /*
     * Set immediate mode.
     */
    case BIOCIMMEDIATE:
        d->bd_immediate = *(u_int *)addr;
        break;

    case BIOCVERSION:
    {
        struct bpf_version *bv = (struct bpf_version *)addr;

        bv->bv_major = BPF_MAJOR_VERSION;
        bv->bv_minor = BPF_MINOR_VERSION;
        break;
    }

    case BIOCGHDRCMPLT:	/* get "header already complete" flag */
        *(u_int *)addr = d->bd_hdrcmplt;
        break;

    case BIOCSHDRCMPLT:	/* set "header already complete" flag */
        d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0;
        break;

    case BIOCLOCK:		/* set "locked" flag (no reset) */
        d->bd_locked = 1;
        break;

    case BIOCGFILDROP:	/* get "filter-drop" flag */
        *(u_int *)addr = d->bd_fildrop;
        break;

    case BIOCSFILDROP:	/* set "filter-drop" flag */
        d->bd_fildrop = *(u_int *)addr ? 1 : 0;
        break;

    case BIOCGDIRFILT:	/* get direction filter */
        *(u_int *)addr = d->bd_dirfilt;
        break;

    case BIOCSDIRFILT:	/* set direction filter */
        d->bd_dirfilt = (*(u_int *)addr) &
                        (BPF_DIRECTION_IN|BPF_DIRECTION_OUT);
        break;

    case FIONBIO:		/* Non-blocking I/O */
        if (*(int *)addr)
            d->bd_rtout = -1;
        else
            d->bd_rtout = 0;
        break;

    case FIOASYNC:		/* Send signal on receive packets */
        d->bd_async = *(int *)addr;
        break;

    /*
     * N.B.  ioctl (FIOSETOWN) and fcntl (F_SETOWN) both end up doing
     * the equivalent of a TIOCSPGRP and hence end up here.  *However*
     * TIOCSPGRP's arg is a process group if it's positive and a process
     * id if it's negative.  This is exactly the opposite of what the
     * other two functions want!  Therefore there is code in ioctl and
     * fcntl to negate the arg before calling here.
     */
    case TIOCSPGRP:		/* Process or group to send signals to */
        d->bd_pgid = *(int *)addr;
        d->bd_siguid = p->p_cred->p_ruid;
        d->bd_sigeuid = p->p_ucred->cr_uid;
        break;

    case TIOCGPGRP:
        *(int *)addr = d->bd_pgid;
        break;

    case BIOCSRSIG:		/* Set receive signal */
    {
        u_int sig;

        sig = *(u_int *)addr;

        if (sig >= NSIG)
            error = EINVAL;
        else
            d->bd_sig = sig;
        break;
    }
    case BIOCGRSIG:
        *(u_int *)addr = d->bd_sig;
        break;
    }
    return (error);
}
コード例 #2
0
ファイル: bpf.c プロジェクト: SbIm/xnu-env
/* ARGSUSED */
int
bpfioctl(dev_t dev, u_long cmd, caddr_t addr, __unused int flags,
    struct proc *p)
{
	struct bpf_d *d;
	int error = 0;

	lck_mtx_lock(bpf_mlock);

	d = bpf_dtab[minor(dev)];
	if (d == 0 || d == (void *)1) {
		lck_mtx_unlock(bpf_mlock);
		return (ENXIO);
	}

	switch (cmd) {

	default:
		error = EINVAL;
		break;

	/*
	 * Check for read packet available.
	 */
	case FIONREAD:
		{
			int n;

			n = d->bd_slen;
			if (d->bd_hbuf)
				n += d->bd_hlen;

			*(int *)addr = n;
			break;
		}

	case SIOCGIFADDR:
		{
			struct ifnet *ifp;

			if (d->bd_bif == 0)
				error = EINVAL;
			else {
				ifp = d->bd_bif->bif_ifp;
				error = ifnet_ioctl(ifp, 0, cmd, addr);
			}
			break;
		}

	/*
	 * Get buffer len [for read()].
	 */
	case BIOCGBLEN:
		*(u_int *)addr = d->bd_bufsize;
		break;

	/*
	 * Set buffer length.
	 */
	case BIOCSBLEN:
#if BSD < 199103
		error = EINVAL;
#else
		if (d->bd_bif != 0)
			error = EINVAL;
		else {
			u_int size = *(u_int *)addr;

			if (size > bpf_maxbufsize)
				*(u_int *)addr = size = bpf_maxbufsize;
			else if (size < BPF_MINBUFSIZE)
				*(u_int *)addr = size = BPF_MINBUFSIZE;
			d->bd_bufsize = size;
		}
#endif
		break;

	/*
	 * Set link layer read filter.
	 */
	case BIOCSETF32: {
		struct bpf_program32 *prg32 = (struct bpf_program32 *)addr;
		error = bpf_setf(d, prg32->bf_len,
		    CAST_USER_ADDR_T(prg32->bf_insns));
		break;
	}

	case BIOCSETF64: {
		struct bpf_program64 *prg64 = (struct bpf_program64 *)addr;
		error = bpf_setf(d, prg64->bf_len, prg64->bf_insns);
		break;
	}

	/*
	 * Flush read packet buffer.
	 */
	case BIOCFLUSH:
		reset_d(d);
		break;

	/*
	 * Put interface into promiscuous mode.
	 */
	case BIOCPROMISC:
		if (d->bd_bif == 0) {
			/*
			 * No interface attached yet.
			 */
			error = EINVAL;
			break;
		}
		if (d->bd_promisc == 0) {
			lck_mtx_unlock(bpf_mlock);
			error = ifnet_set_promiscuous(d->bd_bif->bif_ifp, 1);
			lck_mtx_lock(bpf_mlock);
			if (error == 0)
				d->bd_promisc = 1;
		}
		break;

	/*
	 * Get device parameters.
	 */
	case BIOCGDLT:
		if (d->bd_bif == 0)
			error = EINVAL;
		else
			*(u_int *)addr = d->bd_bif->bif_dlt;
		break;

	/*
	 * Get a list of supported data link types.
	 */
	case BIOCGDLTLIST:
		if (d->bd_bif == NULL) {
			error = EINVAL;
		} else {
			error = bpf_getdltlist(d,
			    (struct bpf_dltlist *)addr, p);
		}
		break;

	/*
	 * Set data link type.
	 */
	case BIOCSDLT:
			if (d->bd_bif == NULL)
					error = EINVAL;
			else
					error = bpf_setdlt(d, *(u_int *)addr);
			break;

	/*
	 * Get interface name.
	 */
	case BIOCGETIF:
		if (d->bd_bif == 0)
			error = EINVAL;
		else {
			struct ifnet *const ifp = d->bd_bif->bif_ifp;
			struct ifreq *const ifr = (struct ifreq *)addr;

			snprintf(ifr->ifr_name, sizeof(ifr->ifr_name),
			    "%s%d", ifp->if_name, ifp->if_unit);
		}
		break;

	/*
	 * Set interface.
	 */
	case BIOCSETIF: {
		ifnet_t	ifp;
		ifp = ifunit(((struct ifreq *)addr)->ifr_name);
		if (ifp == NULL)
			error = ENXIO;
		else
			error = bpf_setif(d, ifp, 0);
		break;
	}

	/*
	 * Set read timeout.
	 */
	case BIOCSRTIMEOUT:
		{
			struct BPF_TIMEVAL *_tv = (struct BPF_TIMEVAL *)addr;
			struct timeval tv;

			tv.tv_sec  = _tv->tv_sec;
			tv.tv_usec = _tv->tv_usec;

			/*
			 * Subtract 1 tick from tvtohz() since this isn't
			 * a one-shot timer.
			 */
			if ((error = itimerfix(&tv)) == 0)
				d->bd_rtout = tvtohz(&tv) - 1;
			break;
		}

	/*
	 * Get read timeout.
	 */
	case BIOCGRTIMEOUT:
		{
			struct BPF_TIMEVAL *tv = (struct BPF_TIMEVAL *)addr;

			tv->tv_sec = d->bd_rtout / hz;
			tv->tv_usec = (d->bd_rtout % hz) * tick;
			break;
		}

	/*
	 * Get packet stats.
	 */
	case BIOCGSTATS:
		{
			struct bpf_stat *bs = (struct bpf_stat *)addr;

			bs->bs_recv = d->bd_rcount;
			bs->bs_drop = d->bd_dcount;
			break;
		}

	/*
	 * Set immediate mode.
	 */
	case BIOCIMMEDIATE:
		d->bd_immediate = *(u_int *)addr;
		break;

	case BIOCVERSION:
		{
			struct bpf_version *bv = (struct bpf_version *)addr;

			bv->bv_major = BPF_MAJOR_VERSION;
			bv->bv_minor = BPF_MINOR_VERSION;
			break;
		}

	/*
	 * Get "header already complete" flag
	 */
	case BIOCGHDRCMPLT:
		*(u_int *)addr = d->bd_hdrcmplt;
		break;

	/*
	 * Set "header already complete" flag
	 */
	case BIOCSHDRCMPLT:
		d->bd_hdrcmplt = *(u_int *)addr ? 1 : 0;
		break;

	/*
	 * Get "see sent packets" flag
	 */
	case BIOCGSEESENT:
		*(u_int *)addr = d->bd_seesent;
		break;

	/*
	 * Set "see sent packets" flag
	 */
	case BIOCSSEESENT:
		d->bd_seesent = *(u_int *)addr;
		break;

	case FIONBIO:		/* Non-blocking I/O */
		break;

	case FIOASYNC:		/* Send signal on receive packets */
		d->bd_async = *(int *)addr;
		break;
#ifndef __APPLE__
	case FIOSETOWN:
		error = fsetown(*(int *)addr, &d->bd_sigio);
		break;

	case FIOGETOWN:
		*(int *)addr = fgetown(d->bd_sigio);
		break;

	/* This is deprecated, FIOSETOWN should be used instead. */
	case TIOCSPGRP:
		error = fsetown(-(*(int *)addr), &d->bd_sigio);
		break;

	/* This is deprecated, FIOGETOWN should be used instead. */
	case TIOCGPGRP:
		*(int *)addr = -fgetown(d->bd_sigio);
		break;
#endif
	case BIOCSRSIG:		/* Set receive signal */
		{
		 	u_int sig;

			sig = *(u_int *)addr;

			if (sig >= NSIG)
				error = EINVAL;
			else
				d->bd_sig = sig;
			break;
		}
	case BIOCGRSIG:
		*(u_int *)addr = d->bd_sig;
		break;
	}
	
	lck_mtx_unlock(bpf_mlock);

	return (error);
}