/* * SPDX-License-Identifier: BSD-2-Clause * * Copyright 2026 The FreeBSD Foundation * * This software was developed by Konstantin Belousov * under sponsorship from the FreeBSD Foundation. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include MODULE_DEPEND(linux_ntsync, linux, 1, 1, 1); MODULE_DEPEND(linux_ntsync, ntsync, 1, 1, 1); static linux_ioctl_function_t linux_ntsync_ioctl; static struct linux_ioctl_handler linux_ntsync_handler = {linux_ntsync_ioctl, LNTSYNC_IOCTL_MIN, LNTSYNC_IOCTL_MAX}; static int linux_ntsync_modevent(module_t mod __unused, int type, void *data __unused) { int error; error = 0; switch (type) { case MOD_LOAD: error = linux_ioctl_register_handler(&linux_ntsync_handler); if (error != 0) { printf("linux_ntsync: cannot register ioctl handler, " "error %d\n", error); } else if (bootverbose) printf("linux_ntsync\n"); break; case MOD_UNLOAD: linux_ioctl_unregister_handler(&linux_ntsync_handler); break; case MOD_SHUTDOWN: break; default: error = EOPNOTSUPP; } return (error); } DEV_MODULE(linux_ntsync, linux_ntsync_modevent, NULL); MODULE_VERSION(linux_ntsync, 1); /* XXXKIB no translation of structs */ static void ntsync_lsa_to_sa(struct ntsync_sem_args *sa, const struct linux_ntsync_sem_args *lsa) { memcpy(sa, lsa, sizeof(*sa)); } static void ntsync_sa_to_lsa(struct linux_ntsync_sem_args *lsa, const struct ntsync_sem_args *sa) { memcpy(lsa, sa, sizeof(*lsa)); } static void ntsync_lma_to_ma(struct ntsync_mutex_args *ma, const struct linux_ntsync_mutex_args *lma) { memcpy(ma, lma, sizeof(*ma)); } static void ntsync_ma_to_lma(struct linux_ntsync_mutex_args *ma, const struct ntsync_mutex_args *lma) { memcpy(ma, lma, sizeof(*ma)); } static void ntsync_lea_to_ea(struct ntsync_event_args *ea, const struct linux_ntsync_event_args *lea) { memcpy(ea, lea, sizeof(*ea)); } static void ntsync_ea_to_lea(struct linux_ntsync_event_args *lea, const struct ntsync_event_args *ea) { memcpy(lea, ea, sizeof(*lea)); } static void ntsync_lwa_to_wa(struct ntsync_wait_args *wa, const struct linux_ntsync_wait_args *lwa) { memcpy(wa, lwa, sizeof(*wa)); } static void ntsync_wa_to_lwa(struct linux_ntsync_wait_args *lwa, const struct ntsync_wait_args *wa) { memcpy(lwa, wa, sizeof(*lwa)); } static int linux_ntsync_cdev_ioctl(struct thread *td, u_long cmd, void *data, struct file *fp) { struct cdev *dev; struct cdevsw *dsw; struct vnode *vp; struct file *fpop; int error, ref; if (fp->f_type != DTYPE_VNODE) return (error = ENOIOCTL); vp = fp->f_vnode; if (vp->v_type != VCHR) return (ENOIOCTL); dev = vp->v_rdev; dsw = dev_refthread(dev, &ref); if (dsw == NULL) return (ENXIO); if (dsw != &ntsync_cdevsw) { error = ENOIOCTL; } else { fpop = td->td_fpop; td->td_fpop = fp; error = dsw->d_ioctl(dev, cmd, data, 0, td); td->td_fpop = fpop; } dev_relthread(dev, ref); return (error); } static int linux_ntsync_ioctl(struct thread *td, struct linux_ioctl_args *args) { struct file *fp; void *data; struct linux_ntsync_sem_args lsa; struct linux_ntsync_mutex_args lma; struct linux_ntsync_event_args lea; struct linux_ntsync_wait_args lwa; struct ntsync_sem_args sa; struct ntsync_mutex_args ma; struct ntsync_event_args ea; struct ntsync_wait_args wa; uint32_t val; int error, error1, lcmd; bool doco; lcmd = args->cmd; data = (void *)args->arg; error = fget_cap(td, args->fd, &cap_no_rights, NULL, &fp, NULL); if (error != 0) goto out; doco = false; switch (lcmd) { case LNTSYNC_IOC_CREATE_SEM: error = copyin(data, &lsa, sizeof(lsa)); ntsync_lsa_to_sa(&sa, &lsa); if (error == 0) { error = linux_ntsync_cdev_ioctl(td, NTSYNC_IOC_CREATE_SEM, &sa, fp); } break; case LNTSYNC_IOC_CREATE_MUTEX: error = copyin(data, &lma, sizeof(lma)); ntsync_lma_to_ma(&ma, &lma); if (error == 0) { error = linux_ntsync_cdev_ioctl(td, NTSYNC_IOC_CREATE_MUTEX, &ma, fp); } break; case LNTSYNC_IOC_CREATE_EVENT: error = copyin(data, &lea, sizeof(lea)); ntsync_lea_to_ea(&ea, &lea); if (error == 0) { error = linux_ntsync_cdev_ioctl(td, NTSYNC_IOC_CREATE_EVENT, &ea, fp); } break; case LNTSYNC_IOC_WAIT_ANY: error = copyin(data, &lwa, sizeof(lwa)); ntsync_lwa_to_wa(&wa, &lwa); if (error == 0) { error = linux_ntsync_cdev_ioctl(td, NTSYNC_IOC_WAIT_ANY, &wa, fp); if (error == 0 || error == EOWNERDEAD) { ntsync_wa_to_lwa(&lwa, &wa); error1 = copyout(&lwa, data, sizeof(lwa)); if (error == 0) error = error1; } } break; case LNTSYNC_IOC_WAIT_ALL: error = copyin(data, &lwa, sizeof(lwa)); ntsync_lwa_to_wa(&wa, &lwa); if (error == 0) { error = linux_ntsync_cdev_ioctl(td, NTSYNC_IOC_WAIT_ALL, &wa, fp); if (error == 0 || error == EOWNERDEAD) { ntsync_wa_to_lwa(&lwa, &wa); error1 = copyout(&lwa, data, sizeof(lwa)); if (error == 0) error = error1; } } break; case LNTSYNC_IOC_SEM_RELEASE: error = copyin(data, &val, sizeof(val)); if (error == 0) { error = ntsync_sem_release(td, fp, &val); if (error == 0) error = copyout(&val, data, sizeof(val)); } break; case LNTSYNC_IOC_SEM_READ: error = ntsync_sem_read(td, fp, &sa); if (error == 0) { ntsync_sa_to_lsa(&lsa, &sa); error = copyout(&lsa, data, sizeof(lsa)); } break; case LNTSYNC_IOC_MUTEX_UNLOCK: error = copyin(data, &lma, sizeof(lma)); ntsync_lma_to_ma(&ma, &lma); if (error == 0) { error = ntsync_mutex_unlock(td, fp, &ma); if (error == 0) { ntsync_ma_to_lma(&lma, &ma); error = copyout(&lma, data, sizeof(lma)); } } break; case LNTSYNC_IOC_MUTEX_KILL: error = copyin(data, &val, sizeof(val)); if (error == 0) error = ntsync_mutex_kill(td, fp, val); break; case LNTSYNC_IOC_MUTEX_READ: error = ntsync_mutex_read(td, fp, &ma, &doco); if (doco) { ntsync_ma_to_lma(&lma, &ma); error1 = copyout(&lma, data, sizeof(lma)); if (error == 0) error = error1; } break; case LNTSYNC_IOC_EVENT_SET: error = ntsync_event_set(td, fp, &val); if (error == 0) error = copyout(&val, data, sizeof(val)); break; case LNTSYNC_IOC_EVENT_RESET: error = ntsync_event_reset(td, fp, &val); if (error == 0) error = copyout(&val, data, sizeof(val)); break; case LNTSYNC_IOC_EVENT_PULSE: error = ntsync_event_pulse(td, fp, &val); if (error == 0) error = copyout(&val, data, sizeof(val)); break; case LNTSYNC_IOC_EVENT_READ: error = ntsync_event_read(td, fp, &ea); if (error == 0) { ntsync_ea_to_lea(&lea, &ea); error = copyout(&lea, data, sizeof(lea)); } break; default: error = ENOTTY; break; } fdrop(fp, td); out: return (error); }