/* * Create a clone network interface. */ int if_clone_create(char *name, int len, caddr_t params) { struct if_clone *ifc; char *dp; int wildcard, bytoff, bitoff; int unit; int err; ifc = if_clone_lookup(name, &unit); if (ifc == NULL) return (EINVAL); ifnet_lock(); if (ifunit(name) != NULL) { ifnet_unlock(); return (EEXIST); } ifnet_unlock(); bytoff = bitoff = 0; wildcard = (unit < 0); /* * Find a free unit if none was given. */ if (wildcard) { while (bytoff < ifc->ifc_bmlen && ifc->ifc_units[bytoff] == 0xff) bytoff++; if (bytoff >= ifc->ifc_bmlen) return (ENOSPC); while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) bitoff++; unit = (bytoff << 3) + bitoff; } if (unit > ifc->ifc_maxunit) return (ENXIO); err = (*ifc->ifc_create)(ifc, unit, params); if (err != 0) return (err); if (!wildcard) { bytoff = unit >> 3; bitoff = unit - (bytoff << 3); }
int pairioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct pair_softc *sc = (struct pair_softc *)ifp->if_softc; struct ifreq *ifr = (struct ifreq *)data; struct if_clone *ifc; struct pair_softc *pairedsc = ifp->if_softc; struct ifnet *oldifp = NULL, *newifp = NULL; int error = 0, unit; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) ifp->if_flags |= IFF_RUNNING; else ifp->if_flags &= ~IFF_RUNNING; break; case SIOCADDMULTI: case SIOCDELMULTI: break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); break; case SIOCSIFPAIR: if (sc->sc_pairedif == ifr->ifr_index) break; /* Cannot link to myself */ if (ifr->ifr_index == ifp->if_index) { error = EINVAL; break; } oldifp = if_get(sc->sc_pairedif); newifp = if_get(ifr->ifr_index); if (newifp != NULL) { pairedsc = newifp->if_softc; if (pairedsc->sc_pairedif != 0) { error = EBUSY; break; } /* Only allow pair(4) interfaces for the pair */ if ((ifc = if_clone_lookup(newifp->if_xname, &unit)) == NULL || strcmp("pair", ifc->ifc_name) != 0) { error = ENODEV; break; } pairedsc->sc_pairedif = ifp->if_index; sc->sc_pairedif = ifr->ifr_index; } else sc->sc_pairedif = 0; if (oldifp != NULL) { pairedsc = oldifp->if_softc; pairedsc->sc_pairedif = 0; } break; case SIOCGIFPAIR: ifr->ifr_index = sc->sc_pairedif; break; default: error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); } if (newifp != NULL || oldifp != NULL) pair_link_state(ifp); if (oldifp != NULL) { pair_link_state(oldifp); if_put(oldifp); } if (newifp != NULL) { pair_link_state(newifp); if_put(newifp); } return (error); }