linux_ipc.c revision 346838
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1994-1995 S��ren Schmidt
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: stable/11/sys/compat/linux/linux_ipc.c 346838 2019-04-28 14:16:00Z dchagin $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/syscallsubr.h>
35#include <sys/sysproto.h>
36#include <sys/proc.h>
37#include <sys/limits.h>
38#include <sys/msg.h>
39#include <sys/sem.h>
40#include <sys/shm.h>
41#include <sys/stat.h>
42
43#include "opt_compat.h"
44
45#ifdef COMPAT_LINUX32
46#include <machine/../linux32/linux.h>
47#include <machine/../linux32/linux32_proto.h>
48#else
49#include <machine/../linux/linux.h>
50#include <machine/../linux/linux_proto.h>
51#endif
52#include <compat/linux/linux_ipc.h>
53#include <compat/linux/linux_ipc64.h>
54#include <compat/linux/linux_util.h>
55
56/*
57 * old, pre 2.4 kernel
58 */
59struct l_ipc_perm {
60	l_key_t		key;
61	l_uid16_t	uid;
62	l_gid16_t	gid;
63	l_uid16_t	cuid;
64	l_gid16_t	cgid;
65	l_ushort	mode;
66	l_ushort	seq;
67};
68
69struct l_seminfo {
70	l_int semmap;
71	l_int semmni;
72	l_int semmns;
73	l_int semmnu;
74	l_int semmsl;
75	l_int semopm;
76	l_int semume;
77	l_int semusz;
78	l_int semvmx;
79	l_int semaem;
80};
81
82struct l_shminfo {
83	l_int shmmax;
84	l_int shmmin;
85	l_int shmmni;
86	l_int shmseg;
87	l_int shmall;
88};
89
90struct l_shm_info {
91	l_int used_ids;
92	l_ulong shm_tot;  /* total allocated shm */
93	l_ulong shm_rss;  /* total resident shm */
94	l_ulong shm_swp;  /* total swapped shm */
95	l_ulong swap_attempts;
96	l_ulong swap_successes;
97};
98
99struct l_msginfo {
100	l_int msgpool;
101	l_int msgmap;
102	l_int msgmax;
103	l_int msgmnb;
104	l_int msgmni;
105	l_int msgssz;
106	l_int msgtql;
107	l_ushort msgseg;
108};
109
110static void
111bsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo64 *lpp)
112{
113
114	lpp->shmmax = bpp->shmmax;
115	lpp->shmmin = bpp->shmmin;
116	lpp->shmmni = bpp->shmmni;
117	lpp->shmseg = bpp->shmseg;
118	lpp->shmall = bpp->shmall;
119}
120
121static void
122bsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
123{
124
125	lpp->used_ids = bpp->used_ids;
126	lpp->shm_tot = bpp->shm_tot;
127	lpp->shm_rss = bpp->shm_rss;
128	lpp->shm_swp = bpp->shm_swp;
129	lpp->swap_attempts = bpp->swap_attempts;
130	lpp->swap_successes = bpp->swap_successes;
131}
132
133static void
134linux_to_bsd_ipc_perm(struct l_ipc64_perm *lpp, struct ipc_perm *bpp)
135{
136
137	bpp->key = lpp->key;
138	bpp->uid = lpp->uid;
139	bpp->gid = lpp->gid;
140	bpp->cuid = lpp->cuid;
141	bpp->cgid = lpp->cgid;
142	bpp->mode = lpp->mode;
143	bpp->seq = lpp->seq;
144}
145
146static void
147bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc64_perm *lpp)
148{
149
150	lpp->key = bpp->key;
151	lpp->uid = bpp->uid;
152	lpp->gid = bpp->gid;
153	lpp->cuid = bpp->cuid;
154	lpp->cgid = bpp->cgid;
155	lpp->mode = bpp->mode & (S_IRWXU|S_IRWXG|S_IRWXO);
156	lpp->seq = bpp->seq;
157}
158
159struct l_msqid_ds {
160	struct l_ipc_perm	msg_perm;
161	l_uintptr_t		msg_first;	/* first message on queue,unused */
162	l_uintptr_t		msg_last;	/* last message in queue,unused */
163	l_time_t		msg_stime;	/* last msgsnd time */
164	l_time_t		msg_rtime;	/* last msgrcv time */
165	l_time_t		msg_ctime;	/* last change time */
166	l_ulong			msg_lcbytes;	/* Reuse junk fields for 32 bit */
167	l_ulong			msg_lqbytes;	/* ditto */
168	l_ushort		msg_cbytes;	/* current number of bytes on queue */
169	l_ushort		msg_qnum;	/* number of messages in queue */
170	l_ushort		msg_qbytes;	/* max number of bytes on queue */
171	l_pid_t			msg_lspid;	/* pid of last msgsnd */
172	l_pid_t			msg_lrpid;	/* last receive pid */
173};
174
175struct l_semid_ds {
176	struct l_ipc_perm	sem_perm;
177	l_time_t		sem_otime;
178	l_time_t		sem_ctime;
179	l_uintptr_t		sem_base;
180	l_uintptr_t		sem_pending;
181	l_uintptr_t		sem_pending_last;
182	l_uintptr_t		undo;
183	l_ushort		sem_nsems;
184};
185
186struct l_shmid_ds {
187	struct l_ipc_perm	shm_perm;
188	l_int			shm_segsz;
189	l_time_t		shm_atime;
190	l_time_t		shm_dtime;
191	l_time_t		shm_ctime;
192	l_ushort		shm_cpid;
193	l_ushort		shm_lpid;
194	l_short			shm_nattch;
195	l_ushort		private1;
196	l_uintptr_t		private2;
197	l_uintptr_t		private3;
198};
199
200static void
201linux_to_bsd_semid_ds(struct l_semid64_ds *lsp, struct semid_ds *bsp)
202{
203
204	linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
205	bsp->sem_otime = lsp->sem_otime;
206	bsp->sem_ctime = lsp->sem_ctime;
207	bsp->sem_nsems = lsp->sem_nsems;
208}
209
210static void
211bsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid64_ds *lsp)
212{
213
214	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
215	lsp->sem_otime = bsp->sem_otime;
216	lsp->sem_ctime = bsp->sem_ctime;
217	lsp->sem_nsems = bsp->sem_nsems;
218}
219
220static void
221linux_to_bsd_shmid_ds(struct l_shmid64_ds *lsp, struct shmid_ds *bsp)
222{
223
224	linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
225	bsp->shm_segsz = lsp->shm_segsz;
226	bsp->shm_lpid = lsp->shm_lpid;
227	bsp->shm_cpid = lsp->shm_cpid;
228	bsp->shm_nattch = lsp->shm_nattch;
229	bsp->shm_atime = lsp->shm_atime;
230	bsp->shm_dtime = lsp->shm_dtime;
231	bsp->shm_ctime = lsp->shm_ctime;
232}
233
234static void
235bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid64_ds *lsp)
236{
237
238	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
239	lsp->shm_segsz = bsp->shm_segsz;
240	lsp->shm_lpid = bsp->shm_lpid;
241	lsp->shm_cpid = bsp->shm_cpid;
242	lsp->shm_nattch = bsp->shm_nattch;
243	lsp->shm_atime = bsp->shm_atime;
244	lsp->shm_dtime = bsp->shm_dtime;
245	lsp->shm_ctime = bsp->shm_ctime;
246}
247
248static void
249linux_to_bsd_msqid_ds(struct l_msqid64_ds *lsp, struct msqid_ds *bsp)
250{
251
252	linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
253	bsp->msg_cbytes = lsp->msg_cbytes;
254	bsp->msg_qnum = lsp->msg_qnum;
255	bsp->msg_qbytes = lsp->msg_qbytes;
256	bsp->msg_lspid = lsp->msg_lspid;
257	bsp->msg_lrpid = lsp->msg_lrpid;
258	bsp->msg_stime = lsp->msg_stime;
259	bsp->msg_rtime = lsp->msg_rtime;
260	bsp->msg_ctime = lsp->msg_ctime;
261}
262
263static void
264bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid64_ds *lsp)
265{
266
267	bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
268	lsp->msg_cbytes = bsp->msg_cbytes;
269	lsp->msg_qnum = bsp->msg_qnum;
270	lsp->msg_qbytes = bsp->msg_qbytes;
271	lsp->msg_lspid = bsp->msg_lspid;
272	lsp->msg_lrpid = bsp->msg_lrpid;
273	lsp->msg_stime = bsp->msg_stime;
274	lsp->msg_rtime = bsp->msg_rtime;
275	lsp->msg_ctime = bsp->msg_ctime;
276}
277
278static int
279linux_ipc64_perm_to_ipc_perm(struct l_ipc64_perm *in, struct l_ipc_perm *out)
280{
281
282	out->key = in->key;
283	out->uid = in->uid;
284	out->gid = in->gid;
285	out->cuid = in->cuid;
286	out->cgid = in->cgid;
287	out->mode = in->mode;
288	out->seq = in->seq;
289
290	/* Linux does not check overflow */
291	if (out->uid != in->uid || out->gid != in->gid ||
292	    out->cuid != in->cuid || out->cgid != in->cgid ||
293	    out->mode != in->mode)
294		return (EOVERFLOW);
295	else
296		return (0);
297}
298
299static int
300linux_msqid_pullup(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
301{
302	struct l_msqid_ds linux_msqid;
303	int error;
304
305	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
306		return (copyin(uaddr, linux_msqid64, sizeof(*linux_msqid64)));
307	else {
308		error = copyin(uaddr, &linux_msqid, sizeof(linux_msqid));
309		if (error != 0)
310			return (error);
311
312		bzero(linux_msqid64, sizeof(*linux_msqid64));
313
314		linux_msqid64->msg_perm.uid = linux_msqid.msg_perm.uid;
315		linux_msqid64->msg_perm.gid = linux_msqid.msg_perm.gid;
316		linux_msqid64->msg_perm.mode = linux_msqid.msg_perm.mode;
317		if (linux_msqid.msg_qbytes == 0)
318			linux_msqid64->msg_qbytes = linux_msqid.msg_lqbytes;
319		else
320			linux_msqid64->msg_qbytes = linux_msqid.msg_qbytes;
321		return (0);
322	}
323}
324
325static int
326linux_msqid_pushdown(l_int ver, struct l_msqid64_ds *linux_msqid64, caddr_t uaddr)
327{
328	struct l_msqid_ds linux_msqid;
329	int error;
330
331	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
332		return (copyout(linux_msqid64, uaddr, sizeof(*linux_msqid64)));
333	else {
334		bzero(&linux_msqid, sizeof(linux_msqid));
335
336		error = linux_ipc64_perm_to_ipc_perm(&linux_msqid64->msg_perm,
337		    &linux_msqid.msg_perm);
338		if (error != 0)
339			return (error);
340
341		linux_msqid.msg_stime = linux_msqid64->msg_stime;
342		linux_msqid.msg_rtime = linux_msqid64->msg_rtime;
343		linux_msqid.msg_ctime = linux_msqid64->msg_ctime;
344
345		if (linux_msqid64->msg_cbytes > USHRT_MAX)
346			linux_msqid.msg_cbytes = USHRT_MAX;
347		else
348			linux_msqid.msg_cbytes = linux_msqid64->msg_cbytes;
349		linux_msqid.msg_lcbytes = linux_msqid64->msg_cbytes;
350		if (linux_msqid64->msg_qnum > USHRT_MAX)
351			linux_msqid.msg_qnum = USHRT_MAX;
352		else
353			linux_msqid.msg_qnum = linux_msqid64->msg_qnum;
354		if (linux_msqid64->msg_qbytes > USHRT_MAX)
355			linux_msqid.msg_qbytes = USHRT_MAX;
356		else
357			linux_msqid.msg_qbytes = linux_msqid64->msg_qbytes;
358		linux_msqid.msg_lqbytes = linux_msqid64->msg_qbytes;
359		linux_msqid.msg_lspid = linux_msqid64->msg_lspid;
360		linux_msqid.msg_lrpid = linux_msqid64->msg_lrpid;
361
362		/* Linux does not check overflow */
363		if (linux_msqid.msg_stime != linux_msqid64->msg_stime ||
364		    linux_msqid.msg_rtime != linux_msqid64->msg_rtime ||
365		    linux_msqid.msg_ctime != linux_msqid64->msg_ctime)
366			return (EOVERFLOW);
367
368		return (copyout(&linux_msqid, uaddr, sizeof(linux_msqid)));
369	}
370}
371
372static int
373linux_semid_pullup(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
374{
375	struct l_semid_ds linux_semid;
376	int error;
377
378	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
379		return (copyin(uaddr, linux_semid64, sizeof(*linux_semid64)));
380	else {
381		error = copyin(uaddr, &linux_semid, sizeof(linux_semid));
382		if (error != 0)
383			return (error);
384
385		bzero(linux_semid64, sizeof(*linux_semid64));
386
387		linux_semid64->sem_perm.uid = linux_semid.sem_perm.uid;
388		linux_semid64->sem_perm.gid = linux_semid.sem_perm.gid;
389		linux_semid64->sem_perm.mode = linux_semid.sem_perm.mode;
390		return (0);
391	}
392}
393
394static int
395linux_semid_pushdown(l_int ver, struct l_semid64_ds *linux_semid64, caddr_t uaddr)
396{
397	struct l_semid_ds linux_semid;
398	int error;
399
400	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
401		return (copyout(linux_semid64, uaddr, sizeof(*linux_semid64)));
402	else {
403		bzero(&linux_semid, sizeof(linux_semid));
404
405		error = linux_ipc64_perm_to_ipc_perm(&linux_semid64->sem_perm,
406		    &linux_semid.sem_perm);
407		if (error != 0)
408			return (error);
409
410		linux_semid.sem_otime = linux_semid64->sem_otime;
411		linux_semid.sem_ctime = linux_semid64->sem_ctime;
412		linux_semid.sem_nsems = linux_semid64->sem_nsems;
413
414		/* Linux does not check overflow */
415		if (linux_semid.sem_otime != linux_semid64->sem_otime ||
416		    linux_semid.sem_ctime != linux_semid64->sem_ctime ||
417		    linux_semid.sem_nsems != linux_semid64->sem_nsems)
418			return (EOVERFLOW);
419
420		return (copyout(&linux_semid, uaddr, sizeof(linux_semid)));
421	}
422}
423
424static int
425linux_shmid_pullup(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
426{
427	struct l_shmid_ds linux_shmid;
428	int error;
429
430	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
431		return (copyin(uaddr, linux_shmid64, sizeof(*linux_shmid64)));
432	else {
433		error = copyin(uaddr, &linux_shmid, sizeof(linux_shmid));
434		if (error != 0)
435			return (error);
436
437		bzero(linux_shmid64, sizeof(*linux_shmid64));
438
439		linux_shmid64->shm_perm.uid = linux_shmid.shm_perm.uid;
440		linux_shmid64->shm_perm.gid = linux_shmid.shm_perm.gid;
441		linux_shmid64->shm_perm.mode = linux_shmid.shm_perm.mode;
442		return (0);
443	}
444}
445
446static int
447linux_shmid_pushdown(l_int ver, struct l_shmid64_ds *linux_shmid64, caddr_t uaddr)
448{
449	struct l_shmid_ds linux_shmid;
450	int error;
451
452	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
453		return (copyout(linux_shmid64, uaddr, sizeof(*linux_shmid64)));
454	else {
455		bzero(&linux_shmid, sizeof(linux_shmid));
456
457		error = linux_ipc64_perm_to_ipc_perm(&linux_shmid64->shm_perm,
458		    &linux_shmid.shm_perm);
459		if (error != 0)
460			return (error);
461
462		linux_shmid.shm_segsz = linux_shmid64->shm_segsz;
463		linux_shmid.shm_atime = linux_shmid64->shm_atime;
464		linux_shmid.shm_dtime = linux_shmid64->shm_dtime;
465		linux_shmid.shm_ctime = linux_shmid64->shm_ctime;
466		linux_shmid.shm_cpid = linux_shmid64->shm_cpid;
467		linux_shmid.shm_lpid = linux_shmid64->shm_lpid;
468		linux_shmid.shm_nattch = linux_shmid64->shm_nattch;
469
470		/* Linux does not check overflow */
471		if (linux_shmid.shm_segsz != linux_shmid64->shm_segsz ||
472		    linux_shmid.shm_atime != linux_shmid64->shm_atime ||
473		    linux_shmid.shm_dtime != linux_shmid64->shm_dtime ||
474		    linux_shmid.shm_ctime != linux_shmid64->shm_ctime ||
475		    linux_shmid.shm_cpid != linux_shmid64->shm_cpid ||
476		    linux_shmid.shm_lpid != linux_shmid64->shm_lpid ||
477		    linux_shmid.shm_nattch != linux_shmid64->shm_nattch)
478			return (EOVERFLOW);
479
480		return (copyout(&linux_shmid, uaddr, sizeof(linux_shmid)));
481	}
482}
483
484static int
485linux_shminfo_pushdown(l_int ver, struct l_shminfo64 *linux_shminfo64,
486    caddr_t uaddr)
487{
488	struct l_shminfo linux_shminfo;
489
490	if (ver == LINUX_IPC_64 || SV_CURPROC_FLAG(SV_LP64))
491		return (copyout(linux_shminfo64, uaddr,
492		    sizeof(*linux_shminfo64)));
493	else {
494		bzero(&linux_shminfo, sizeof(linux_shminfo));
495
496		linux_shminfo.shmmax = linux_shminfo64->shmmax;
497		linux_shminfo.shmmin = linux_shminfo64->shmmin;
498		linux_shminfo.shmmni = linux_shminfo64->shmmni;
499		linux_shminfo.shmseg = linux_shminfo64->shmseg;
500		linux_shminfo.shmall = linux_shminfo64->shmall;
501
502		return (copyout(&linux_shminfo, uaddr,
503		    sizeof(linux_shminfo)));
504	}
505}
506
507int
508linux_semop(struct thread *td, struct linux_semop_args *args)
509{
510	struct semop_args /* {
511	int	semid;
512	struct	sembuf *sops;
513	int		nsops;
514	} */ bsd_args;
515
516	if (args->nsops < 1 || args->semid < 0)
517		return (EINVAL);
518	bsd_args.semid = args->semid;
519	bsd_args.sops = PTRIN(args->tsops);
520	bsd_args.nsops = args->nsops;
521	return (sys_semop(td, &bsd_args));
522}
523
524int
525linux_semget(struct thread *td, struct linux_semget_args *args)
526{
527	struct semget_args /* {
528	key_t	key;
529	int		nsems;
530	int		semflg;
531	} */ bsd_args;
532
533	if (args->nsems < 0)
534		return (EINVAL);
535	bsd_args.key = args->key;
536	bsd_args.nsems = args->nsems;
537	bsd_args.semflg = args->semflg;
538	return (sys_semget(td, &bsd_args));
539}
540
541int
542linux_semctl(struct thread *td, struct linux_semctl_args *args)
543{
544	struct l_semid64_ds linux_semid64;
545	struct l_seminfo linux_seminfo;
546	struct semid_ds semid;
547	union semun semun;
548	register_t rval;
549	int cmd, error;
550
551	memset(&linux_seminfo, 0, sizeof(linux_seminfo));
552	memset(&linux_semid64, 0, sizeof(linux_semid64));
553
554	switch (args->cmd & ~LINUX_IPC_64) {
555	case LINUX_IPC_RMID:
556		cmd = IPC_RMID;
557		break;
558	case LINUX_GETNCNT:
559		cmd = GETNCNT;
560		break;
561	case LINUX_GETPID:
562		cmd = GETPID;
563		break;
564	case LINUX_GETVAL:
565		cmd = GETVAL;
566		break;
567	case LINUX_GETZCNT:
568		cmd = GETZCNT;
569		break;
570	case LINUX_SETVAL:
571		cmd = SETVAL;
572		semun.val = args->arg.val;
573		break;
574	case LINUX_IPC_SET:
575		cmd = IPC_SET;
576		error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
577		    &linux_semid64, PTRIN(args->arg.buf));
578		if (error != 0)
579			return (error);
580		linux_to_bsd_semid_ds(&linux_semid64, &semid);
581		semun.buf = &semid;
582		return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
583		    td->td_retval));
584	case LINUX_IPC_STAT:
585		cmd = IPC_STAT;
586		semun.buf = &semid;
587		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
588		    &rval);
589		if (error != 0)
590			return (error);
591		bsd_to_linux_semid_ds(&semid, &linux_semid64);
592		return (linux_semid_pushdown(args->cmd & LINUX_IPC_64,
593		    &linux_semid64, PTRIN(args->arg.buf)));
594	case LINUX_SEM_STAT:
595		cmd = SEM_STAT;
596		semun.buf = &semid;
597		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
598		    &rval);
599		if (error != 0)
600			return (error);
601		bsd_to_linux_semid_ds(&semid, &linux_semid64);
602		error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
603		    &linux_semid64, PTRIN(args->arg.buf));
604		if (error == 0)
605			td->td_retval[0] = rval;
606		return (error);
607	case LINUX_IPC_INFO:
608	case LINUX_SEM_INFO:
609		bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
610		    sizeof(linux_seminfo.semmap) );
611		/*
612		 * Linux does not use the semmap field but populates it with
613		 * the defined value from SEMMAP, which really is redefined to
614		 * SEMMNS, which they define as SEMMNI * SEMMSL.  Try to
615		 * simulate this returning our dynamic semmns value.
616		 */
617		linux_seminfo.semmap = linux_seminfo.semmns;
618/* XXX BSD equivalent?
619#define used_semids 10
620#define used_sems 10
621		linux_seminfo.semusz = used_semids;
622		linux_seminfo.semaem = used_sems;
623*/
624		error = copyout(&linux_seminfo,
625		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
626		if (error != 0)
627			return (error);
628		/*
629		 * TODO: Linux return the last assigned id, not the semmni.
630		 */
631		td->td_retval[0] = seminfo.semmni;
632		return (0);
633	case LINUX_GETALL:
634		cmd = GETALL;
635		semun.array = PTRIN(args->arg.array);
636		break;
637	case LINUX_SETALL:
638		cmd = SETALL;
639		semun.array = PTRIN(args->arg.array);
640		break;
641	default:
642		linux_msg(td, "ipc type %d is not implemented",
643		  args->cmd & ~LINUX_IPC_64);
644		return (EINVAL);
645	}
646	return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
647	    td->td_retval));
648}
649
650int
651linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
652{
653	const void *msgp;
654	long mtype;
655	l_long lmtype;
656	int error;
657
658	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
659		return (EINVAL);
660	msgp = PTRIN(args->msgp);
661	if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0)
662		return (error);
663	mtype = (long)lmtype;
664	return (kern_msgsnd(td, args->msqid,
665	    (const char *)msgp + sizeof(lmtype),
666	    args->msgsz, args->msgflg, mtype));
667}
668
669int
670linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
671{
672	void *msgp;
673	long mtype;
674	l_long lmtype;
675	int error;
676
677	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
678		return (EINVAL);
679	msgp = PTRIN(args->msgp);
680	if ((error = kern_msgrcv(td, args->msqid,
681	    (char *)msgp + sizeof(lmtype), args->msgsz,
682	    args->msgtyp, args->msgflg, &mtype)) != 0)
683		return (error);
684	lmtype = (l_long)mtype;
685	return (copyout(&lmtype, msgp, sizeof(lmtype)));
686}
687
688int
689linux_msgget(struct thread *td, struct linux_msgget_args *args)
690{
691	struct msgget_args /* {
692		key_t	key;
693		int	msgflg;
694	} */ bsd_args;
695
696	bsd_args.key = args->key;
697	bsd_args.msgflg = args->msgflg;
698	return (sys_msgget(td, &bsd_args));
699}
700
701int
702linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
703{
704	int error, bsd_cmd;
705	struct l_msqid64_ds linux_msqid64;
706	struct msqid_ds bsd_msqid;
707
708	memset(&linux_msqid64, 0, sizeof(linux_msqid64));
709
710	bsd_cmd = args->cmd & ~LINUX_IPC_64;
711	switch (bsd_cmd) {
712	case LINUX_IPC_INFO:
713	case LINUX_MSG_INFO: {
714		struct l_msginfo linux_msginfo;
715
716		memset(&linux_msginfo, 0, sizeof(linux_msginfo));
717		/*
718		 * XXX MSG_INFO uses the same data structure but returns different
719		 * dynamic counters in msgpool, msgmap, and msgtql fields.
720		 */
721		linux_msginfo.msgpool = (long)msginfo.msgmni *
722		    (long)msginfo.msgmnb / 1024L;	/* XXX MSG_INFO. */
723		linux_msginfo.msgmap = msginfo.msgmnb;	/* XXX MSG_INFO. */
724		linux_msginfo.msgmax = msginfo.msgmax;
725		linux_msginfo.msgmnb = msginfo.msgmnb;
726		linux_msginfo.msgmni = msginfo.msgmni;
727		linux_msginfo.msgssz = msginfo.msgssz;
728		linux_msginfo.msgtql = msginfo.msgtql;	/* XXX MSG_INFO. */
729		linux_msginfo.msgseg = msginfo.msgseg;
730		error = copyout(&linux_msginfo, PTRIN(args->buf),
731		    sizeof(linux_msginfo));
732		if (error == 0)
733		    td->td_retval[0] = msginfo.msgmni;	/* XXX */
734
735		return (error);
736	}
737
738	/*
739	 * TODO: implement this
740	 * case LINUX_MSG_STAT:
741	 */
742	case LINUX_IPC_STAT:
743		/* NOTHING */
744		break;
745
746	case LINUX_IPC_SET:
747		error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
748		    &linux_msqid64, PTRIN(args->buf));
749		if (error != 0)
750			return (error);
751		linux_to_bsd_msqid_ds(&linux_msqid64, &bsd_msqid);
752		break;
753
754	case LINUX_IPC_RMID:
755		/* NOTHING */
756		break;
757
758	default:
759		return (EINVAL);
760		break;
761	}
762
763	error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
764	if (error != 0) {
765		if (bsd_cmd == LINUX_IPC_RMID && error == EACCES)
766			return (EPERM);
767		if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
768			return (error);
769	}
770
771	if (bsd_cmd == LINUX_IPC_STAT) {
772		bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid64);
773		return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
774		    &linux_msqid64, PTRIN(args->buf)));
775	}
776
777	return (0);
778}
779
780int
781linux_shmat(struct thread *td, struct linux_shmat_args *args)
782{
783	struct shmat_args /* {
784		int shmid;
785		void *shmaddr;
786		int shmflg;
787	} */ bsd_args;
788
789	bsd_args.shmid = args->shmid;
790	bsd_args.shmaddr = PTRIN(args->shmaddr);
791	bsd_args.shmflg = args->shmflg;
792	return (sys_shmat(td, &bsd_args));
793}
794
795int
796linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
797{
798	struct shmdt_args /* {
799		void *shmaddr;
800	} */ bsd_args;
801
802	bsd_args.shmaddr = PTRIN(args->shmaddr);
803	return (sys_shmdt(td, &bsd_args));
804}
805
806int
807linux_shmget(struct thread *td, struct linux_shmget_args *args)
808{
809	struct shmget_args /* {
810		key_t key;
811		int size;
812		int shmflg;
813	} */ bsd_args;
814
815	bsd_args.key = args->key;
816	bsd_args.size = args->size;
817	bsd_args.shmflg = args->shmflg;
818	return (sys_shmget(td, &bsd_args));
819}
820
821int
822linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
823{
824	struct l_shmid64_ds linux_shmid64;
825	struct l_shminfo64 linux_shminfo64;
826	struct l_shm_info linux_shm_info;
827	struct shmid_ds bsd_shmid;
828	int error;
829
830	memset(&linux_shm_info, 0, sizeof(linux_shm_info));
831	memset(&linux_shmid64, 0, sizeof(linux_shmid64));
832	memset(&linux_shminfo64, 0, sizeof(linux_shminfo64));
833
834	switch (args->cmd & ~LINUX_IPC_64) {
835
836	case LINUX_IPC_INFO: {
837		struct shminfo bsd_shminfo;
838
839		/* Perform shmctl wanting removed segments lookup */
840		error = kern_shmctl(td, args->shmid, IPC_INFO,
841		    (void *)&bsd_shminfo, NULL);
842		if (error != 0)
843			return (error);
844
845		bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo64);
846
847		return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
848		    &linux_shminfo64, PTRIN(args->buf)));
849	}
850
851	case LINUX_SHM_INFO: {
852		struct shm_info bsd_shm_info;
853
854		/* Perform shmctl wanting removed segments lookup */
855		error = kern_shmctl(td, args->shmid, SHM_INFO,
856		    (void *)&bsd_shm_info, NULL);
857		if (error != 0)
858			return (error);
859
860		bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
861
862		return (copyout(&linux_shm_info, PTRIN(args->buf),
863		    sizeof(struct l_shm_info)));
864	}
865
866	case LINUX_IPC_STAT:
867		/* Perform shmctl wanting removed segments lookup */
868		error = kern_shmctl(td, args->shmid, IPC_STAT,
869		    (void *)&bsd_shmid, NULL);
870		if (error != 0)
871			return (error);
872
873		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
874
875		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
876		    &linux_shmid64, PTRIN(args->buf)));
877
878	case LINUX_SHM_STAT:
879		/* Perform shmctl wanting removed segments lookup */
880		error = kern_shmctl(td, args->shmid, IPC_STAT,
881		    (void *)&bsd_shmid, NULL);
882		if (error != 0)
883			return (error);
884
885		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid64);
886
887		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
888		    &linux_shmid64, PTRIN(args->buf)));
889
890	case LINUX_IPC_SET:
891		error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
892		    &linux_shmid64, PTRIN(args->buf));
893		if (error != 0)
894			return (error);
895
896		linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
897
898		/* Perform shmctl wanting removed segments lookup */
899		return (kern_shmctl(td, args->shmid, IPC_SET,
900		    (void *)&bsd_shmid, NULL));
901
902	case LINUX_IPC_RMID: {
903		void *buf;
904
905		if (args->buf == 0)
906			buf = NULL;
907		else {
908			error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
909			    &linux_shmid64, PTRIN(args->buf));
910			if (error != 0)
911				return (error);
912			linux_to_bsd_shmid_ds(&linux_shmid64, &bsd_shmid);
913			buf = (void *)&bsd_shmid;
914		}
915		return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL));
916	}
917
918	case LINUX_SHM_LOCK:
919		/* FALLTHROUGH */
920	case LINUX_SHM_UNLOCK:
921		/* FALLTHROUGH */
922	default:
923		linux_msg(td, "ipc type %d not implemented",
924		    args->cmd & ~LINUX_IPC_64);
925		return (EINVAL);
926	}
927}
928
929MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
930MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
931MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
932