/* * 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; }
/* 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); }
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(); }