Esempio n. 1
0
/*
 * Detach a file from its interface.
 */
void
bpf_detachd(struct bpf_d *d)
{
    struct bpf_d **p;
    struct bpf_if *bp;

    bp = d->bd_bif;
    /*
     * Check if this descriptor had requested promiscuous mode.
     * If so, turn it off.
     */
    if (d->bd_promisc) {
        int error;

        d->bd_promisc = 0;
        error = ifpromisc(bp->bif_ifp, 0);
        if (error && !(error == EINVAL || error == ENODEV))
            /*
             * Something is really wrong if we were able to put
             * the driver into promiscuous mode, but can't
             * take it out.
             */
            panic("bpf: ifpromisc failed");
    }
    /* Remove d from the interface's descriptor list. */
    p = &bp->bif_dlist;
    while (*p != d) {
        p = &(*p)->bd_next;
        if (*p == 0)
            panic("bpf_detachd: descriptor not in list");
    }
    *p = (*p)->bd_next;
    if (bp->bif_dlist == 0)
        /*
         * Let the driver know that there are no more listeners.
         */
        *d->bd_bif->bif_driverp = 0;
    d->bd_bif = 0;
}
Esempio n. 2
0
/* 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);
}
Esempio n. 3
0
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
{
    struct ifnet *ifp;
    struct ifreq ifreq;
    int error;
    node_p node;
    struct ng_mesg *msg;
    struct ngm_connect *con;
    struct ngm_rmhook *rm;
    char path[NG_PATHSIZ];

    Log(("%s: fActive:%d\n", __func__, fActive));

    ifp = ASMAtomicUoReadPtrT(&pThis->u.s.ifp, struct ifnet *);
    VBOXCURVNET_SET(ifp->if_vnet);
    node = ASMAtomicUoReadPtrT(&pThis->u.s.node, node_p);

    memset(&ifreq, 0, sizeof(struct ifreq));
    /* Activate interface */
    if (fActive)
    {
        pThis->u.s.flags = ifp->if_flags;
        ifpromisc(ifp, 1);

        /* ng_ether nodes are named after the interface name */
        snprintf(path, sizeof(path), "%s:", ifp->if_xname);

        /*
         * Send a netgraph connect message to the ng_ether node
         * assigned to the bridged interface. Connecting
         * the hooks 'lower' (ng_ether) to out 'input'.
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
                     sizeof(struct ngm_connect), M_NOWAIT);
        if (msg == NULL)
            return;
        con = (struct ngm_connect *)msg->data;
        snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:", ifp->if_xname);
        strlcpy(con->ourhook, "lower", NG_HOOKSIZ);
        strlcpy(con->peerhook, "input", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);

        /*
         * Do the same for the hooks 'upper' (ng_ether) and our
         * 'output' hook.
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_CONNECT,
                     sizeof(struct ngm_connect), M_NOWAIT);
        if (msg == NULL)
            return;
        con = (struct ngm_connect *)msg->data;
        snprintf(con->path, NG_PATHSIZ, "vboxnetflt_%s:",
                 ifp->if_xname);
        strlcpy(con->ourhook, "upper", sizeof(con->ourhook));
        strlcpy(con->peerhook, "output", sizeof(con->peerhook));
        NG_SEND_MSG_PATH(error, node, msg, path, 0);
    }
    else
    {
        /* De-activate interface */
        pThis->u.s.flags = 0;
        ifpromisc(ifp, 0);

        /* Disconnect msgs are addressed to ourself */
        snprintf(path, sizeof(path), "vboxnetflt_%s:", ifp->if_xname);

        /*
         * Send a netgraph message to disconnect our 'input' hook
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
                     sizeof(struct ngm_rmhook), M_NOWAIT);
        if (msg == NULL)
            return;
        rm = (struct ngm_rmhook *)msg->data;
        strlcpy(rm->ourhook, "input", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);

        /*
         * Send a netgraph message to disconnect our 'output' hook
         */
        NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_RMHOOK,
                     sizeof(struct ngm_rmhook), M_NOWAIT);
        if (msg == NULL)
            return;
        rm = (struct ngm_rmhook *)msg->data;
        strlcpy(rm->ourhook, "output", NG_HOOKSIZ);
        NG_SEND_MSG_PATH(error, node, msg, path, 0);
    }
    VBOXCURVNET_RESTORE();
}