static errno_t ether_inet6_prmod_ioctl(ifnet_t ifp, protocol_family_t protocol_family, u_long command, void *data) { #pragma unused(protocol_family) int error = 0; switch (command) { case SIOCSIFADDR: /* struct ifaddr pointer */ /* * Note: caller of ifnet_ioctl() passes in pointer to * struct ifaddr as parameter to SIOCSIFADDR, for legacy * reasons. */ if ((ifp->if_flags & IFF_RUNNING) == 0) { ifnet_set_flags(ifp, IFF_UP, IFF_UP); ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL); } break; case SIOCGIFADDR: { /* struct ifreq */ struct ifreq *ifr = (struct ifreq *)(void *)data; (void) ifnet_guarded_lladdr_copy_bytes(ifp, ifr->ifr_addr.sa_data, ETHER_ADDR_LEN); break; } default: error = EOPNOTSUPP; break; } return (error); }
/** * * @see iff_event_func in the darwin kpi. */ static void vboxNetFltDarwinIffEvent(void *pvThis, ifnet_t pIfNet, protocol_family_t eProtocol, const struct kev_msg *pEvMsg) { PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvThis; LogFlow(("vboxNetFltDarwinIffEvent: pThis=%p\n", pThis)); NOREF(pThis); NOREF(pIfNet); NOREF(eProtocol); NOREF(pEvMsg); /* * Watch out for the interface going online / offline. */ if ( VALID_PTR(pThis) && VALID_PTR(pEvMsg) && pEvMsg->vendor_code == KEV_VENDOR_APPLE && pEvMsg->kev_class == KEV_NETWORK_CLASS && pEvMsg->kev_subclass == KEV_DL_SUBCLASS) { if (pThis->u.s.pIfNet == pIfNet) { if (pEvMsg->event_code == KEV_DL_LINK_ON) { if (ASMAtomicUoReadBool(&pThis->u.s.fNeedSetPromiscuous)) { /* failed to bring it online. */ errno_t err = ifnet_set_promiscuous(pIfNet, 1); if (!err) { ASMAtomicWriteBool(&pThis->u.s.fSetPromiscuous, true); ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false); Log(("vboxNetFltDarwinIffEvent: enabled promiscuous mode on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet))); } else Log(("vboxNetFltDarwinIffEvent: ifnet_set_promiscuous failed on %s, err=%d (%d)\n", pThis->szName, err, VBOX_GET_PCOUNT(pIfNet))); } else if ( ASMAtomicUoReadBool(&pThis->u.s.fSetPromiscuous) && !(ifnet_flags(pIfNet) & IFF_PROMISC)) { /* Try fix the inconsistency. */ errno_t err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC); if (!err) err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL); if (!err && (ifnet_flags(pIfNet) & IFF_PROMISC)) Log(("vboxNetFltDarwinIffEvent: fixed IFF_PROMISC on %s (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet))); else Log(("vboxNetFltDarwinIffEvent: failed to fix IFF_PROMISC on %s, err=%d flags=%#x (%d)\n", pThis->szName, err, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet))); } else Log(("vboxNetFltDarwinIffEvent: online, '%s'. flags=%#x (%d)\n", pThis->szName, ifnet_flags(pIfNet), VBOX_GET_PCOUNT(pIfNet))); } else if (pEvMsg->event_code == KEV_DL_LINK_OFF) Log(("vboxNetFltDarwinIffEvent: %s goes down (%d)\n", pThis->szName, VBOX_GET_PCOUNT(pIfNet))); /** @todo KEV_DL_LINK_ADDRESS_CHANGED -> pfnReportMacAddress */ /** @todo KEV_DL_SIFFLAGS -> pfnReportPromiscuousMode */ } else Log(("vboxNetFltDarwinIffEvent: pThis->u.s.pIfNet=%p pIfNet=%p (%d)\n", pThis->u.s.pIfNet, pIfNet, VALID_PTR(pIfNet) ? VBOX_GET_PCOUNT(pIfNet) : -1)); } else if (VALID_PTR(pEvMsg)) Log(("vboxNetFltDarwinIffEvent: vendor_code=%#x kev_class=%#x kev_subclass=%#x event_code=%#x\n", pEvMsg->vendor_code, pEvMsg->kev_class, pEvMsg->kev_subclass, pEvMsg->event_code)); }
void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive) { ifnet_t pIfNet = vboxNetFltDarwinRetainIfNet(pThis); if (pIfNet) { if (pThis->fDisablePromiscuous) { /* * Promiscuous mode should not be used (wireless), we just need to * make sure the interface is up. */ if (fActive) { u_int16_t fIf = ifnet_flags(pIfNet); if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) { ifnet_set_flags(pIfNet, IFF_UP, IFF_UP); ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL); } } } else { /* * This api is a bit weird, the best reference is the code. * * Also, we have a bit or race conditions wrt the maintenance of * host the interface promiscuity for vboxNetFltPortOsIsPromiscuous. */ unsigned const cPromiscBefore = VBOX_GET_PCOUNT(pIfNet); u_int16_t fIf; if (fActive) { Assert(!pThis->u.s.fSetPromiscuous); errno_t err = ENETDOWN; ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, true); /* * Try bring the interface up and running if it's down. */ fIf = ifnet_flags(pIfNet); if ((fIf & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING)) { err = ifnet_set_flags(pIfNet, IFF_UP, IFF_UP); errno_t err2 = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL); if (!err) err = err2; fIf = ifnet_flags(pIfNet); } /* * Is it already up? If it isn't, leave it to the link event or * we'll upset if_pcount (as stated above, ifnet_set_promiscuous is weird). */ if ((fIf & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) { err = ifnet_set_promiscuous(pIfNet, 1); pThis->u.s.fSetPromiscuous = err == 0; if (!err) { ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false); /* check if it actually worked, this stuff is not always behaving well. */ if (!(ifnet_flags(pIfNet) & IFF_PROMISC)) { err = ifnet_set_flags(pIfNet, IFF_PROMISC, IFF_PROMISC); if (!err) err = ifnet_ioctl(pIfNet, 0, SIOCSIFFLAGS, NULL); if (!err) Log(("vboxNetFlt: fixed IFF_PROMISC on %s (%d->%d)\n", pThis->szName, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); else Log(("VBoxNetFlt: failed to fix IFF_PROMISC on %s, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); } } else Log(("VBoxNetFlt: ifnet_set_promiscuous -> err=%d grr! (%d->%d)\n", err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); } else if (!err) Log(("VBoxNetFlt: Waiting for the link to come up... (%d->%d)\n", cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); if (err) LogRel(("VBoxNetFlt: Failed to put '%s' into promiscuous mode, err=%d (%d->%d)\n", pThis->szName, err, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); } else { ASMAtomicWriteBool(&pThis->u.s.fNeedSetPromiscuous, false); if (pThis->u.s.fSetPromiscuous) { errno_t err = ifnet_set_promiscuous(pIfNet, 0); AssertMsg(!err, ("%d\n", err)); NOREF(err); } pThis->u.s.fSetPromiscuous = false; fIf = ifnet_flags(pIfNet); Log(("VBoxNetFlt: fIf=%#x; %d->%d\n", fIf, cPromiscBefore, VBOX_GET_PCOUNT(pIfNet))); } } vboxNetFltDarwinReleaseIfNet(pThis, pIfNet); } }
/* 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); }