1 /* 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright 2026 The FreeBSD Foundation 5 * 6 * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 7 * under sponsorship from the FreeBSD Foundation. 8 */ 9 10 #include <sys/systm.h> 11 #include <sys/conf.h> 12 #include <sys/file.h> 13 #include <sys/filedesc.h> 14 #include <sys/kernel.h> 15 #include <sys/module.h> 16 #include <sys/proc.h> 17 #include <sys/vnode.h> 18 #include <dev/ntsync/ntsyncvar.h> 19 20 #include <machine/../linux/linux.h> 21 #include <machine/../linux/linux_proto.h> 22 #include <compat/linux/linux_common.h> 23 #include <compat/linux/linux_ioctl.h> 24 #include <dev/ntsync/linux_ntsync.h> 25 26 MODULE_DEPEND(linux_ntsync, linux, 1, 1, 1); 27 MODULE_DEPEND(linux_ntsync, ntsync, 1, 1, 1); 28 29 static linux_ioctl_function_t linux_ntsync_ioctl; 30 static struct linux_ioctl_handler linux_ntsync_handler = {linux_ntsync_ioctl, 31 LNTSYNC_IOCTL_MIN, LNTSYNC_IOCTL_MAX}; 32 33 static int 34 linux_ntsync_modevent(module_t mod __unused, int type, void *data __unused) 35 { 36 int error; 37 38 error = 0; 39 switch (type) { 40 case MOD_LOAD: 41 error = linux_ioctl_register_handler(&linux_ntsync_handler); 42 if (error != 0) { 43 printf("linux_ntsync: cannot register ioctl handler, " 44 "error %d\n", error); 45 } else if (bootverbose) 46 printf("linux_ntsync\n"); 47 break; 48 49 case MOD_UNLOAD: 50 linux_ioctl_unregister_handler(&linux_ntsync_handler); 51 break; 52 53 case MOD_SHUTDOWN: 54 break; 55 56 default: 57 error = EOPNOTSUPP; 58 } 59 60 return (error); 61 } 62 63 DEV_MODULE(linux_ntsync, linux_ntsync_modevent, NULL); 64 MODULE_VERSION(linux_ntsync, 1); 65 66 /* XXXKIB no translation of structs */ 67 static void 68 ntsync_lsa_to_sa(struct ntsync_sem_args *sa, 69 const struct linux_ntsync_sem_args *lsa) 70 { 71 memcpy(sa, lsa, sizeof(*sa)); 72 } 73 74 static void 75 ntsync_sa_to_lsa(struct linux_ntsync_sem_args *lsa, 76 const struct ntsync_sem_args *sa) 77 { 78 memcpy(lsa, sa, sizeof(*lsa)); 79 } 80 81 static void 82 ntsync_lma_to_ma(struct ntsync_mutex_args *ma, 83 const struct linux_ntsync_mutex_args *lma) 84 { 85 memcpy(ma, lma, sizeof(*ma)); 86 } 87 88 static void 89 ntsync_ma_to_lma(struct linux_ntsync_mutex_args *ma, 90 const struct ntsync_mutex_args *lma) 91 { 92 memcpy(ma, lma, sizeof(*ma)); 93 } 94 95 static void 96 ntsync_lea_to_ea(struct ntsync_event_args *ea, 97 const struct linux_ntsync_event_args *lea) 98 { 99 memcpy(ea, lea, sizeof(*ea)); 100 } 101 102 static void 103 ntsync_ea_to_lea(struct linux_ntsync_event_args *lea, 104 const struct ntsync_event_args *ea) 105 { 106 memcpy(lea, ea, sizeof(*lea)); 107 } 108 109 static void 110 ntsync_lwa_to_wa(struct ntsync_wait_args *wa, 111 const struct linux_ntsync_wait_args *lwa) 112 { 113 memcpy(wa, lwa, sizeof(*wa)); 114 } 115 116 static void 117 ntsync_wa_to_lwa(struct linux_ntsync_wait_args *lwa, 118 const struct ntsync_wait_args *wa) 119 { 120 memcpy(lwa, wa, sizeof(*lwa)); 121 } 122 123 static int 124 linux_ntsync_cdev_ioctl(struct thread *td, u_long cmd, void *data, 125 struct file *fp) 126 { 127 struct cdev *dev; 128 struct cdevsw *dsw; 129 struct vnode *vp; 130 struct file *fpop; 131 int error, ref; 132 133 if (fp->f_type != DTYPE_VNODE) 134 return (error = ENOIOCTL); 135 136 vp = fp->f_vnode; 137 if (vp->v_type != VCHR) 138 return (ENOIOCTL); 139 dev = vp->v_rdev; 140 dsw = dev_refthread(dev, &ref); 141 if (dsw == NULL) 142 return (ENXIO); 143 if (dsw != &ntsync_cdevsw) { 144 error = ENOIOCTL; 145 } else { 146 fpop = td->td_fpop; 147 td->td_fpop = fp; 148 error = dsw->d_ioctl(dev, cmd, data, 0, td); 149 td->td_fpop = fpop; 150 } 151 dev_relthread(dev, ref); 152 return (error); 153 } 154 155 static int 156 linux_ntsync_ioctl(struct thread *td, struct linux_ioctl_args *args) 157 { 158 struct file *fp; 159 void *data; 160 struct linux_ntsync_sem_args lsa; 161 struct linux_ntsync_mutex_args lma; 162 struct linux_ntsync_event_args lea; 163 struct linux_ntsync_wait_args lwa; 164 struct ntsync_sem_args sa; 165 struct ntsync_mutex_args ma; 166 struct ntsync_event_args ea; 167 struct ntsync_wait_args wa; 168 uint32_t val; 169 int error, error1, lcmd; 170 bool doco; 171 172 lcmd = args->cmd; 173 data = (void *)args->arg; 174 175 error = fget_cap(td, args->fd, &cap_no_rights, NULL, &fp, NULL); 176 if (error != 0) 177 goto out; 178 179 doco = false; 180 switch (lcmd) { 181 case LNTSYNC_IOC_CREATE_SEM: 182 error = copyin(data, &lsa, sizeof(lsa)); 183 ntsync_lsa_to_sa(&sa, &lsa); 184 if (error == 0) { 185 error = linux_ntsync_cdev_ioctl(td, 186 NTSYNC_IOC_CREATE_SEM, &sa, fp); 187 } 188 break; 189 case LNTSYNC_IOC_CREATE_MUTEX: 190 error = copyin(data, &lma, sizeof(lma)); 191 ntsync_lma_to_ma(&ma, &lma); 192 if (error == 0) { 193 error = linux_ntsync_cdev_ioctl(td, 194 NTSYNC_IOC_CREATE_MUTEX, &ma, fp); 195 } 196 break; 197 case LNTSYNC_IOC_CREATE_EVENT: 198 error = copyin(data, &lea, sizeof(lea)); 199 ntsync_lea_to_ea(&ea, &lea); 200 if (error == 0) { 201 error = linux_ntsync_cdev_ioctl(td, 202 NTSYNC_IOC_CREATE_EVENT, &ea, fp); 203 } 204 break; 205 case LNTSYNC_IOC_WAIT_ANY: 206 error = copyin(data, &lwa, sizeof(lwa)); 207 ntsync_lwa_to_wa(&wa, &lwa); 208 if (error == 0) { 209 error = linux_ntsync_cdev_ioctl(td, 210 NTSYNC_IOC_WAIT_ANY, &wa, fp); 211 if (error == 0 || error == EOWNERDEAD) { 212 ntsync_wa_to_lwa(&lwa, &wa); 213 error1 = copyout(&lwa, data, sizeof(lwa)); 214 if (error == 0) 215 error = error1; 216 } 217 } 218 break; 219 case LNTSYNC_IOC_WAIT_ALL: 220 error = copyin(data, &lwa, sizeof(lwa)); 221 ntsync_lwa_to_wa(&wa, &lwa); 222 if (error == 0) { 223 error = linux_ntsync_cdev_ioctl(td, 224 NTSYNC_IOC_WAIT_ALL, &wa, fp); 225 if (error == 0 || error == EOWNERDEAD) { 226 ntsync_wa_to_lwa(&lwa, &wa); 227 error1 = copyout(&lwa, data, sizeof(lwa)); 228 if (error == 0) 229 error = error1; 230 } 231 } 232 break; 233 case LNTSYNC_IOC_SEM_RELEASE: 234 error = copyin(data, &val, sizeof(val)); 235 if (error == 0) { 236 error = ntsync_sem_release(td, fp, &val); 237 if (error == 0) 238 error = copyout(&val, data, sizeof(val)); 239 } 240 break; 241 case LNTSYNC_IOC_SEM_READ: 242 error = ntsync_sem_read(td, fp, &sa); 243 if (error == 0) { 244 ntsync_sa_to_lsa(&lsa, &sa); 245 error = copyout(&lsa, data, sizeof(lsa)); 246 } 247 break; 248 case LNTSYNC_IOC_MUTEX_UNLOCK: 249 error = copyin(data, &lma, sizeof(lma)); 250 ntsync_lma_to_ma(&ma, &lma); 251 if (error == 0) { 252 error = ntsync_mutex_unlock(td, fp, &ma); 253 if (error == 0) { 254 ntsync_ma_to_lma(&lma, &ma); 255 error = copyout(&lma, data, sizeof(lma)); 256 } 257 } 258 break; 259 case LNTSYNC_IOC_MUTEX_KILL: 260 error = copyin(data, &val, sizeof(val)); 261 if (error == 0) 262 error = ntsync_mutex_kill(td, fp, val); 263 break; 264 case LNTSYNC_IOC_MUTEX_READ: 265 error = ntsync_mutex_read(td, fp, &ma, &doco); 266 if (doco) { 267 ntsync_ma_to_lma(&lma, &ma); 268 error1 = copyout(&lma, data, sizeof(lma)); 269 if (error == 0) 270 error = error1; 271 } 272 break; 273 case LNTSYNC_IOC_EVENT_SET: 274 error = ntsync_event_set(td, fp, &val); 275 if (error == 0) 276 error = copyout(&val, data, sizeof(val)); 277 break; 278 case LNTSYNC_IOC_EVENT_RESET: 279 error = ntsync_event_reset(td, fp, &val); 280 if (error == 0) 281 error = copyout(&val, data, sizeof(val)); 282 break; 283 case LNTSYNC_IOC_EVENT_PULSE: 284 error = ntsync_event_pulse(td, fp, &val); 285 if (error == 0) 286 error = copyout(&val, data, sizeof(val)); 287 break; 288 case LNTSYNC_IOC_EVENT_READ: 289 error = ntsync_event_read(td, fp, &ea); 290 if (error == 0) { 291 ntsync_ea_to_lea(&lea, &ea); 292 error = copyout(&lea, data, sizeof(lea)); 293 } 294 break; 295 default: 296 error = ENOTTY; 297 break; 298 } 299 fdrop(fp, td); 300 out: 301 return (error); 302 } 303