1 /*	$NetBSD: netbsd32_mqueue.c,v 1.6 2015/12/01 23:56:43 pgoyette Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software developed for The NetBSD Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_mqueue.c,v 1.6 2015/12/01 23:56:43 pgoyette Exp $");
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_compat_netbsd.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/dirent.h>
40 #include <sys/filedesc.h>
41 #include <sys/fcntl.h>
42 #include <sys/module.h>
43 #include <sys/syscallvar.h>
44 
45 #include <compat/netbsd32/netbsd32.h>
46 #include <compat/netbsd32/netbsd32_syscall.h>
47 #include <compat/netbsd32/netbsd32_syscallargs.h>
48 #include <compat/netbsd32/netbsd32_conv.h>
49 
50 extern struct emul emul_netbsd32;
51 
52 int
netbsd32_mq_open(struct lwp * l,const struct netbsd32_mq_open_args * uap,register_t * retval)53 netbsd32_mq_open(struct lwp *l, const struct netbsd32_mq_open_args *uap,
54     register_t *retval)
55 {
56 	/* {
57 		syscallarg(const netbsd32_charp) name;
58 		syscallarg(int) oflag;
59 		syscallarg(mode_t) mode;
60 		syscallarg(struct netbsd32_mq_attrp_t) attr;
61 	} */
62 	struct netbsd32_mq_attr attr32;
63 	struct mq_attr *attr = NULL, a;
64 	int error;
65 
66 	if ((SCARG(uap, oflag) & O_CREAT) && SCARG_P32(uap, attr) != NULL) {
67 		error = copyin(SCARG_P32(uap, attr), &attr32, sizeof(attr32));
68 		if (error)
69 			return error;
70 		netbsd32_to_mq_attr(&attr32, &a);
71 		attr = &a;
72 	}
73 
74 	return mq_handle_open(l, SCARG_P32(uap, name), SCARG(uap, oflag),
75 	    SCARG(uap, mode), attr, retval);
76 }
77 
78 int
netbsd32_mq_close(struct lwp * l,const struct netbsd32_mq_close_args * uap,register_t * retval)79 netbsd32_mq_close(struct lwp *l, const struct netbsd32_mq_close_args *uap,
80     register_t *retval)
81 {
82 	/* {
83 		syscallarg(mqd_t) mqdes;
84 	} */
85 
86 	return netbsd32_close(l, (const void*)uap, retval);
87 }
88 
89 int
netbsd32_mq_unlink(struct lwp * l,const struct netbsd32_mq_unlink_args * uap,register_t * retval)90 netbsd32_mq_unlink(struct lwp *l, const struct netbsd32_mq_unlink_args *uap,
91     register_t *retval)
92 {
93 	/* {
94 		syscallarg(const netbsd32_charp) name;
95 	} */
96 	struct sys_mq_unlink_args ua;
97 
98 	NETBSD32TOP_UAP(name, const char);
99 	return sys_mq_unlink(l, &ua, retval);
100 }
101 
102 int
netbsd32_mq_getattr(struct lwp * l,const struct netbsd32_mq_getattr_args * uap,register_t * retval)103 netbsd32_mq_getattr(struct lwp *l, const struct netbsd32_mq_getattr_args *uap,
104     register_t *retval)
105 {
106 	/* {
107 		syscallarg(mqd_t) mqdes;
108 		syscallarg(netbsd32_mq_attrp_t) mqstat;
109 	} */
110 	struct mqueue *mq;
111 	struct mq_attr attr;
112 	struct netbsd32_mq_attr a32;
113 	int error;
114 
115 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
116 	if (error)
117 		return error;
118 
119 	memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
120 	mutex_exit(&mq->mq_mtx);
121 	fd_putfile((int)SCARG(uap, mqdes));
122 	netbsd32_from_mq_attr(&attr, &a32);
123 	return copyout(&a32, SCARG_P32(uap,mqstat), sizeof(a32));
124 }
125 
126 int
netbsd32_mq_setattr(struct lwp * l,const struct netbsd32_mq_setattr_args * uap,register_t * retval)127 netbsd32_mq_setattr(struct lwp *l, const struct netbsd32_mq_setattr_args *uap,
128     register_t *retval)
129 {
130 	/* {
131 		syscallarg(mqd_t) mqdes;
132 		syscallarg(const netbsd32_mq_attrp_t) mqstat;
133 		syscallarg(netbsd32_mq_attrp_t) omqstat;
134 	} */
135 	struct mqueue *mq;
136 	struct netbsd32_mq_attr attr32;
137 	struct mq_attr attr;
138 	int error, nonblock;
139 
140 	error = copyin(SCARG_P32(uap, mqstat), &attr32, sizeof(attr32));
141 	if (error)
142 		return error;
143 	netbsd32_to_mq_attr(&attr32, &attr);
144 	nonblock = (attr.mq_flags & O_NONBLOCK);
145 
146 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
147 	if (error)
148 		return error;
149 
150 	/* Copy the old attributes, if needed */
151 	if (SCARG_P32(uap, omqstat))
152 		memcpy(&attr, &mq->mq_attrib, sizeof(struct mq_attr));
153 
154 	/* Ignore everything, except O_NONBLOCK */
155 	if (nonblock)
156 		mq->mq_attrib.mq_flags |= O_NONBLOCK;
157 	else
158 		mq->mq_attrib.mq_flags &= ~O_NONBLOCK;
159 
160 	mutex_exit(&mq->mq_mtx);
161 	fd_putfile((int)SCARG(uap, mqdes));
162 
163 	/*
164 	 * Copy the data to the user-space.
165 	 * Note: According to POSIX, the new attributes should not be set in
166 	 * case of fail - this would be violated.
167 	 */
168 	if (SCARG_P32(uap, omqstat)) {
169 		netbsd32_from_mq_attr(&attr, &attr32);
170 		error = copyout(&attr32, SCARG_P32(uap, omqstat),
171 		    sizeof(attr32));
172 	}
173 
174 	return error;
175 }
176 
177 int
netbsd32_mq_notify(struct lwp * l,const struct netbsd32_mq_notify_args * uap,register_t * result)178 netbsd32_mq_notify(struct lwp *l, const struct netbsd32_mq_notify_args *uap,
179     register_t *result)
180 {
181 	/* {
182 		syscallarg(mqd_t) mqdes;
183 		syscallarg(const netbsd32_sigeventp_t) notification;
184 	} */
185 	struct mqueue *mq;
186 	struct netbsd32_sigevent sig32;
187 	int error;
188 
189 	if (SCARG_P32(uap, notification)) {
190 		/* Get the signal from user-space */
191 		error = copyin(SCARG_P32(uap, notification), &sig32,
192 		    sizeof(sig32));
193 		if (error)
194 			return error;
195 		if (sig32.sigev_notify == SIGEV_SIGNAL &&
196 		    (sig32.sigev_signo <=0 || sig32.sigev_signo >= NSIG))
197 			return EINVAL;
198 	}
199 
200 	error = mqueue_get(SCARG(uap, mqdes), 0, &mq);
201 	if (error) {
202 		return error;
203 	}
204 	if (SCARG_P32(uap, notification)) {
205 		/* Register notification: set the signal and target process */
206 		if (mq->mq_notify_proc == NULL) {
207 			netbsd32_to_sigevent(&sig32, &mq->mq_sig_notify);
208 			mq->mq_notify_proc = l->l_proc;
209 		} else {
210 			/* Fail if someone else already registered */
211 			error = EBUSY;
212 		}
213 	} else {
214 		/* Unregister the notification */
215 		mq->mq_notify_proc = NULL;
216 	}
217 	mutex_exit(&mq->mq_mtx);
218 	fd_putfile((int)SCARG(uap, mqdes));
219 
220 	return error;
221 }
222 
223 int
netbsd32_mq_send(struct lwp * l,const struct netbsd32_mq_send_args * uap,register_t * result)224 netbsd32_mq_send(struct lwp *l, const struct netbsd32_mq_send_args *uap,
225     register_t *result)
226 {
227 	/* {
228 		syscallarg(mqd_t) mqdes;
229 		syscallarg(const netbsd32_charp) msg_ptr;
230 		syscallarg(netbsd32_size_t) msg_len;
231 		syscallarg(unsigned) msg_prio;
232 	} */
233 
234 
235 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
236 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), NULL);
237 }
238 
239 int
netbsd32_mq_receive(struct lwp * l,const struct netbsd32_mq_receive_args * uap,register_t * retval)240 netbsd32_mq_receive(struct lwp *l, const struct netbsd32_mq_receive_args *uap,
241     register_t *retval)
242 {
243 	/* {
244 		syscallarg(mqd_t) mqdes;
245 		syscallarg(netbsd32_charp) msg_ptr;
246 		syscallarg(netbsd32_size_t) msg_len;
247 		syscallarg(netbsd32_uintp) msg_prio;
248 	} */
249 	ssize_t mlen;
250 	int error;
251 
252 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
253 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), NULL, &mlen);
254 	if (error == 0)
255 		*retval = mlen;
256 
257 	return error;
258 }
259 
260 int
netbsd32___mq_timedsend50(struct lwp * l,const struct netbsd32___mq_timedsend50_args * uap,register_t * retval)261 netbsd32___mq_timedsend50(struct lwp *l,
262      const struct netbsd32___mq_timedsend50_args *uap, register_t *retval)
263 {
264 	/* {
265 		syscallarg(mqd_t) mqdes;
266 		syscallarg(const netbsd32_charp) msg_ptr;
267 		syscallarg(netbsd32_size_t) msg_len;
268 		syscallarg(unsigned) msg_prio;
269 		syscallarg(const netbsd32_timespecp_t) abs_timeout;
270 	} */
271 	struct timespec ts, *tsp;
272 	struct netbsd32_timespec ts32;
273 	int error;
274 
275 	/* Get and convert time value */
276 	if (SCARG_P32(uap, abs_timeout)) {
277 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
278 		     sizeof(ts32));
279 		if (error)
280 			return error;
281 		netbsd32_to_timespec(&ts32, &ts);
282 		tsp = &ts;
283 	} else {
284 		tsp = NULL;
285 	}
286 
287 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
288 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
289 }
290 
291 int
netbsd32___mq_timedreceive50(struct lwp * l,const struct netbsd32___mq_timedreceive50_args * uap,register_t * retval)292 netbsd32___mq_timedreceive50(struct lwp *l,
293     const struct netbsd32___mq_timedreceive50_args *uap, register_t *retval)
294 {
295 	/* {
296 		syscallarg(mqd_t) mqdes;
297 		syscallarg(netbsd32_charp) msg_ptr;
298 		syscallarg(netbsd32_size_t) msg_len;
299 		syscallarg(netbsd32_uintp) msg_prio;
300 		syscallarg(const netbsd32_timespecp_t) abs_timeout;
301 	} */
302 	struct timespec ts, *tsp;
303 	struct netbsd32_timespec ts32;
304 	ssize_t mlen;
305 	int error;
306 
307 	/* Get and convert time value */
308 	if (SCARG_P32(uap, abs_timeout)) {
309 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
310 		    sizeof(ts32));
311 		if (error)
312 			return error;
313 		netbsd32_to_timespec(&ts32, &ts);
314 		tsp = &ts;
315 	} else {
316 		tsp = NULL;
317 	}
318 
319 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
320 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
321 	if (error == 0)
322 		*retval = mlen;
323 
324 	return error;
325 }
326 
327 #ifdef COMPAT_50
328 
329 int
compat_50_netbsd32_mq_timedsend(struct lwp * l,const struct compat_50_netbsd32_mq_timedsend_args * uap,register_t * retval)330 compat_50_netbsd32_mq_timedsend(struct lwp *l,
331     const struct compat_50_netbsd32_mq_timedsend_args *uap,
332     register_t *retval)
333 {
334 	/* {
335 		syscallarg(mqd_t) mqdes;
336 		syscallarg(const netbsd32_charp) msg_ptr;
337 		syscallarg(netbsd32_size_t) msg_len;
338 		syscallarg(unsigned) msg_prio;
339 		syscallarg(const netbsd32_timespec50p_t) abs_timeout;
340 	} */
341 	struct timespec ts, *tsp;
342 	struct netbsd32_timespec50 ts32;
343 	int error;
344 
345 	/* Get and convert time value */
346 	if (SCARG_P32(uap, abs_timeout)) {
347 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
348 		     sizeof(ts32));
349 		if (error)
350 			return error;
351 		netbsd32_to_timespec50(&ts32, &ts);
352 		tsp = &ts;
353 	} else {
354 		tsp = NULL;
355 	}
356 
357 	return mq_send1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
358 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
359 }
360 
361 int
compat_50_netbsd32_mq_timedreceive(struct lwp * l,const struct compat_50_netbsd32_mq_timedreceive_args * uap,register_t * retval)362 compat_50_netbsd32_mq_timedreceive(struct lwp *l,
363     const struct compat_50_netbsd32_mq_timedreceive_args *uap,
364     register_t *retval)
365 {
366 	/* {
367 		syscallarg(mqd_t) mqdes;
368 		syscallarg(netbsd32_charp) msg_ptr;
369 		syscallarg(netbsd32_size_t) msg_len;
370 		syscallarg(netbsd32_uintp) msg_prio;
371 		syscallarg(const netbsd32_timespec50p_t) abs_timeout;
372 	} */
373 	struct timespec ts, *tsp;
374 	struct netbsd32_timespec50 ts32;
375 	ssize_t mlen;
376 	int error;
377 
378 	/* Get and convert time value */
379 	if (SCARG_P32(uap, abs_timeout)) {
380 		error = copyin(SCARG_P32(uap, abs_timeout), &ts32,
381 		    sizeof(ts32));
382 		if (error)
383 			return error;
384 		netbsd32_to_timespec50(&ts32, &ts);
385 		tsp = &ts;
386 	} else {
387 		tsp = NULL;
388 	}
389 
390 	error = mq_recv1(SCARG(uap, mqdes), SCARG_P32(uap, msg_ptr),
391 	    SCARG(uap, msg_len), SCARG_P32(uap, msg_prio), tsp, &mlen);
392 	if (error == 0)
393 		*retval = mlen;
394 
395 	return error;
396 }
397 
398 #endif /* COMPAT_50 */
399 
400 #define _PKG_ENTRY(name)	\
401 	{ NETBSD32_SYS_ ## name, 0, (sy_call_t *)name }
402 
403 static const struct syscall_package compat_mqueue_syscalls[] = {
404 	_PKG_ENTRY(netbsd32_mq_open),
405 	_PKG_ENTRY(netbsd32_mq_close),
406 	_PKG_ENTRY(netbsd32_mq_unlink),
407 	_PKG_ENTRY(netbsd32_mq_getattr),
408 	_PKG_ENTRY(netbsd32_mq_setattr),
409 	_PKG_ENTRY(netbsd32_mq_notify),
410 	_PKG_ENTRY(netbsd32_mq_send),
411 	_PKG_ENTRY(netbsd32_mq_receive),
412 	_PKG_ENTRY(netbsd32___mq_timedsend50),
413 	_PKG_ENTRY(netbsd32___mq_timedreceive50),
414 #ifdef COMPAT_50
415 	_PKG_ENTRY(compat_50_netbsd32_mq_timedsend),
416 	_PKG_ENTRY(compat_50_netbsd32_mq_timedreceive),
417 #endif
418 	{0, 0, NULL}
419 };
420 
421 MODULE(MODULE_CLASS_EXEC, compat_netbsd32_mqueue, "mqueue,compat_netbsd32");
422 
423 static int
compat_netbsd32_mqueue_modcmd(modcmd_t cmd,void * arg)424 compat_netbsd32_mqueue_modcmd(modcmd_t cmd, void *arg)
425 {
426 	int error;
427 
428 	switch (cmd) {
429 	case MODULE_CMD_INIT:
430 		error = syscall_establish(&emul_netbsd32,
431 		    compat_mqueue_syscalls);
432 		break;
433 	case MODULE_CMD_FINI:
434 		error = syscall_disestablish(&emul_netbsd32,
435 		    compat_mqueue_syscalls);
436 		break;
437 	default:
438 		error = ENOTTY;
439 		break;
440 	}
441 	return error;
442 }
443