/* * IOCTL handler */ int hatm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr = (struct ifreq *)data; struct ifaddr *ifa = (struct ifaddr *)data; struct hatm_softc *sc = ifp->if_softc; struct atmio_vcctable *vtab; int error = 0; switch (cmd) { case SIOCSIFADDR: mtx_lock(&sc->mtx); ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) hatm_initialize(sc); switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: case AF_INET6: ifa->ifa_rtrequest = atm_rtrequest; break; #endif default: break; } mtx_unlock(&sc->mtx); break; case SIOCSIFFLAGS: mtx_lock(&sc->mtx); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { hatm_initialize(sc); } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { hatm_stop(sc); } } mtx_unlock(&sc->mtx); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); break; case SIOCSIFMTU: /* * Set the interface MTU. */ if (ifr->ifr_mtu > ATMMTU) error = EINVAL; else ifp->if_mtu = ifr->ifr_mtu; break; case SIOCATMGVCCS: /* return vcc table */ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 1); error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) + vtab->count * sizeof(vtab->vccs[0])); free(vtab, M_DEVBUF); break; case SIOCATMGETVCCS: /* netgraph internal use */ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, HE_MAX_VCCS, sc->open_vccs, &sc->mtx, 0); if (vtab == NULL) { error = ENOMEM; break; } *(void **)data = vtab; break; case SIOCATMOPENVCC: /* kernel internal use */ error = hatm_open_vcc(sc, (struct atmio_openvcc *)data); break; case SIOCATMCLOSEVCC: /* kernel internal use */ error = hatm_close_vcc(sc, (struct atmio_closevcc *)data); break; default: DBG(sc, IOCTL, ("cmd=%08lx arg=%p", cmd, data)); error = EINVAL; break; } return (error); }
int patm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ifreq *ifr = (struct ifreq *)data; struct ifaddr *ifa = (struct ifaddr *)data; struct patm_softc *sc = ifp->if_softc; int error = 0; uint32_t cfg; struct atmio_vcctable *vtab; switch (cmd) { case SIOCSIFADDR: mtx_lock(&sc->mtx); ifp->if_flags |= IFF_UP; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) patm_initialize(sc); switch (ifa->ifa_addr->sa_family) { #ifdef INET case AF_INET: case AF_INET6: ifa->ifa_rtrequest = atm_rtrequest; break; #endif default: break; } mtx_unlock(&sc->mtx); break; case SIOCSIFFLAGS: mtx_lock(&sc->mtx); if (ifp->if_flags & IFF_UP) { if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { patm_initialize(sc); } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { patm_stop(sc); } } mtx_unlock(&sc->mtx); break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->media, cmd); /* * We need to toggle unassigned/idle cells ourself because * the 77252 generates null cells for spacing. When switching * null cells of it gets the timing wrong. */ mtx_lock(&sc->mtx); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if (sc->utopia.state & UTP_ST_UNASS) { if (!(sc->flags & PATM_UNASS)) { cfg = patm_nor_read(sc, IDT_NOR_CFG); cfg &= ~IDT_CFG_IDLECLP; patm_nor_write(sc, IDT_NOR_CFG, cfg); sc->flags |= PATM_UNASS; } } else { if (sc->flags & PATM_UNASS) { cfg = patm_nor_read(sc, IDT_NOR_CFG); cfg |= IDT_CFG_IDLECLP; patm_nor_write(sc, IDT_NOR_CFG, cfg); sc->flags &= ~PATM_UNASS; } } } else { if (sc->utopia.state & UTP_ST_UNASS) sc->flags |= PATM_UNASS; else sc->flags &= ~PATM_UNASS; } mtx_unlock(&sc->mtx); break; case SIOCSIFMTU: /* * Set the interface MTU. */ if (ifr->ifr_mtu > ATMMTU) error = EINVAL; else ifp->if_mtu = ifr->ifr_mtu; break; case SIOCATMOPENVCC: /* kernel internal use */ error = patm_open_vcc(sc, (struct atmio_openvcc *)data); break; case SIOCATMCLOSEVCC: /* kernel internal use */ error = patm_close_vcc(sc, (struct atmio_closevcc *)data); break; case SIOCATMGVCCS: /* external use */ #ifdef CPU_CHERI #error Unvalidatable ifr_data use. Unsafe with CheriABI. #endif /* return vcc table */ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 1); error = copyout(vtab, ifr->ifr_data, sizeof(*vtab) + vtab->count * sizeof(vtab->vccs[0])); free(vtab, M_DEVBUF); break; case SIOCATMGETVCCS: /* netgraph internal use */ vtab = atm_getvccs((struct atmio_vcc **)sc->vccs, sc->mmap->max_conn, sc->vccs_open, &sc->mtx, 0); if (vtab == NULL) { error = ENOMEM; break; } *(void **)data = vtab; break; default: patm_debug(sc, IOCTL, "unknown cmd=%08lx arg=%p", cmd, data); error = EINVAL; break; } return (error); }