linux_ipc.c revision 293522
1100784Sfenner/*-
2100784Sfenner * Copyright (c) 1994-1995 S��ren Schmidt
3100784Sfenner * All rights reserved.
4100784Sfenner *
5100784Sfenner * Redistribution and use in source and binary forms, with or without
6100784Sfenner * modification, are permitted provided that the following conditions
7100784Sfenner * are met:
8100784Sfenner * 1. Redistributions of source code must retain the above copyright
9100784Sfenner *    notice, this list of conditions and the following disclaimer
10100784Sfenner *    in this position and unchanged.
11100784Sfenner * 2. Redistributions in binary form must reproduce the above copyright
12100784Sfenner *    notice, this list of conditions and the following disclaimer in the
13100784Sfenner *    documentation and/or other materials provided with the distribution.
14100784Sfenner * 3. The name of the author may not be used to endorse or promote products
15100784Sfenner *    derived from this software without specific prior written permission
16100784Sfenner *
17100784Sfenner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18100784Sfenner * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19100784Sfenner * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20100784Sfenner * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21100784Sfenner * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22100784Sfenner * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23100784Sfenner * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24100784Sfenner * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25100784Sfenner * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26100784Sfenner * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27100784Sfenner */
28100784Sfenner
29100784Sfenner#include <sys/cdefs.h>
30100784Sfenner__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_ipc.c 293522 2016-01-09 15:56:01Z dchagin $");
31100784Sfenner
32100905Sfenner#include <sys/param.h>
33100905Sfenner#include <sys/systm.h>
34100784Sfenner#include <sys/syscallsubr.h>
35100784Sfenner#include <sys/sysproto.h>
36100784Sfenner#include <sys/proc.h>
37100784Sfenner#include <sys/limits.h>
38100784Sfenner#include <sys/msg.h>
39100784Sfenner#include <sys/sem.h>
40100784Sfenner#include <sys/shm.h>
41100784Sfenner
42100784Sfenner#include "opt_compat.h"
43100784Sfenner
44100784Sfenner#ifdef COMPAT_LINUX32
45100784Sfenner#include <machine/../linux32/linux.h>
46100784Sfenner#include <machine/../linux32/linux32_proto.h>
47100784Sfenner#include <machine/../linux32/linux32_ipc64.h>
48100784Sfenner#else
49100784Sfenner#include <machine/../linux/linux.h>
50100784Sfenner#include <machine/../linux/linux_proto.h>
51100784Sfenner#include <machine/../linux/linux_ipc64.h>
52100784Sfenner#endif
53100784Sfenner#include <compat/linux/linux_ipc.h>
54100784Sfenner#include <compat/linux/linux_util.h>
55100784Sfenner
56100784Sfennerstruct l_seminfo {
57100784Sfenner	l_int semmap;
58100784Sfenner	l_int semmni;
59100784Sfenner	l_int semmns;
60100784Sfenner	l_int semmnu;
61100784Sfenner	l_int semmsl;
62100784Sfenner	l_int semopm;
63100784Sfenner	l_int semume;
64100784Sfenner	l_int semusz;
65100784Sfenner	l_int semvmx;
66100784Sfenner	l_int semaem;
67100784Sfenner};
68100784Sfenner
69100784Sfennerstruct l_shminfo {
70100784Sfenner	l_int shmmax;
71100784Sfenner	l_int shmmin;
72100784Sfenner	l_int shmmni;
73100784Sfenner	l_int shmseg;
74100784Sfenner	l_int shmall;
75100784Sfenner};
76100784Sfenner
77100784Sfennerstruct l_shm_info {
78100784Sfenner	l_int used_ids;
79100784Sfenner	l_ulong shm_tot;  /* total allocated shm */
80100784Sfenner	l_ulong shm_rss;  /* total resident shm */
81100784Sfenner	l_ulong shm_swp;  /* total swapped shm */
82100784Sfenner	l_ulong swap_attempts;
83100784Sfenner	l_ulong swap_successes;
84100784Sfenner};
85100784Sfenner
86100784Sfennerstruct l_msginfo {
87100784Sfenner	l_int msgpool;
88100784Sfenner	l_int msgmap;
89100784Sfenner	l_int msgmax;
90100784Sfenner	l_int msgmnb;
91100784Sfenner	l_int msgmni;
92100784Sfenner	l_int msgssz;
93100784Sfenner	l_int msgtql;
94100784Sfenner	l_ushort msgseg;
95100784Sfenner};
96100784Sfenner
97100784Sfennerstatic void
98100784Sfennerbsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp)
99100784Sfenner{
100100784Sfenner
101100784Sfenner	lpp->shmmax = bpp->shmmax;
102100784Sfenner	lpp->shmmin = bpp->shmmin;
103100784Sfenner	lpp->shmmni = bpp->shmmni;
104100784Sfenner	lpp->shmseg = bpp->shmseg;
105100784Sfenner	lpp->shmall = bpp->shmall;
106100784Sfenner}
107100784Sfenner
108100784Sfennerstatic void
109100784Sfennerbsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
110100784Sfenner{
111100784Sfenner
112100784Sfenner	lpp->used_ids = bpp->used_ids ;
113100784Sfenner	lpp->shm_tot = bpp->shm_tot ;
114100784Sfenner	lpp->shm_rss = bpp->shm_rss ;
115100784Sfenner	lpp->shm_swp = bpp->shm_swp ;
116100784Sfenner	lpp->swap_attempts = bpp->swap_attempts ;
117100784Sfenner	lpp->swap_successes = bpp->swap_successes ;
118100784Sfenner}
119100784Sfenner
120100784Sfennerstatic void
121100784Sfennerlinux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
122100784Sfenner{
123100784Sfenner
124100784Sfenner	bpp->key = lpp->key;
125100784Sfenner	bpp->uid = lpp->uid;
126100784Sfenner	bpp->gid = lpp->gid;
127100784Sfenner	bpp->cuid = lpp->cuid;
128100784Sfenner	bpp->cgid = lpp->cgid;
129100784Sfenner	bpp->mode = lpp->mode;
130100784Sfenner	bpp->seq = lpp->seq;
131100784Sfenner}
132100784Sfenner
133100784Sfenner
134100784Sfennerstatic void
135100784Sfennerbsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp)
136100784Sfenner{
137100784Sfenner
138100784Sfenner	lpp->key = bpp->key;
139100784Sfenner	lpp->uid = bpp->uid;
140100784Sfenner	lpp->gid = bpp->gid;
141100784Sfenner	lpp->cuid = bpp->cuid;
142100784Sfenner	lpp->cgid = bpp->cgid;
143100784Sfenner	lpp->mode = bpp->mode;
144100784Sfenner	lpp->seq = bpp->seq;
145100784Sfenner}
146100784Sfenner
147100784Sfennerstruct l_msqid_ds {
148100784Sfenner	struct l_ipc_perm	msg_perm;
149100784Sfenner	l_uintptr_t		msg_first;	/* first message on queue,unused */
150100784Sfenner	l_uintptr_t		msg_last;	/* last message in queue,unused */
151100784Sfenner	l_time_t		msg_stime;	/* last msgsnd time */
152100784Sfenner	l_time_t		msg_rtime;	/* last msgrcv time */
153100784Sfenner	l_time_t		msg_ctime;	/* last change time */
154100784Sfenner	l_ulong			msg_lcbytes;	/* Reuse junk fields for 32 bit */
155100784Sfenner	l_ulong			msg_lqbytes;	/* ditto */
156100784Sfenner	l_ushort		msg_cbytes;	/* current number of bytes on queue */
157100784Sfenner	l_ushort		msg_qnum;	/* number of messages in queue */
158100784Sfenner	l_ushort		msg_qbytes;	/* max number of bytes on queue */
159100784Sfenner	l_pid_t			msg_lspid;	/* pid of last msgsnd */
160100784Sfenner	l_pid_t			msg_lrpid;	/* last receive pid */
161100784Sfenner}
162100784Sfenner#if defined(__amd64__) && defined(COMPAT_LINUX32)
163100784Sfenner__packed
164100784Sfenner#endif
165100784Sfenner;
166100784Sfenner
167100784Sfennerstruct l_semid_ds {
168100784Sfenner	struct l_ipc_perm	sem_perm;
169100784Sfenner	l_time_t		sem_otime;
170100784Sfenner	l_time_t		sem_ctime;
171100784Sfenner	l_uintptr_t		sem_base;
172100784Sfenner	l_uintptr_t		sem_pending;
173100784Sfenner	l_uintptr_t		sem_pending_last;
174100784Sfenner	l_uintptr_t		undo;
175100784Sfenner	l_ushort		sem_nsems;
176100784Sfenner}
177100784Sfenner#if defined(__amd64__) && defined(COMPAT_LINUX32)
178100784Sfenner__packed
179100784Sfenner#endif
180100784Sfenner;
181100784Sfenner
182100784Sfennerstruct l_shmid_ds {
183100784Sfenner	struct l_ipc_perm	shm_perm;
184100784Sfenner	l_int			shm_segsz;
185100784Sfenner	l_time_t		shm_atime;
186100784Sfenner	l_time_t		shm_dtime;
187100784Sfenner	l_time_t		shm_ctime;
188100784Sfenner	l_ushort		shm_cpid;
189100784Sfenner	l_ushort		shm_lpid;
190100784Sfenner	l_short			shm_nattch;
191100784Sfenner	l_ushort		private1;
192100784Sfenner	l_uintptr_t		private2;
193100784Sfenner	l_uintptr_t		private3;
194100784Sfenner};
195100784Sfenner
196100905Sfennerstatic void
197100784Sfennerlinux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp)
198100905Sfenner{
199100784Sfenner
200100784Sfenner	linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
201100784Sfenner	bsp->sem_otime = lsp->sem_otime;
202100784Sfenner	bsp->sem_ctime = lsp->sem_ctime;
203100784Sfenner	bsp->sem_nsems = lsp->sem_nsems;
204100784Sfenner	bsp->sem_base = PTRIN(lsp->sem_base);
205100784Sfenner}
206100784Sfenner
207100784Sfennerstatic void
208100784Sfennerbsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp)
209100784Sfenner{
210100784Sfenner
211100784Sfenner	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
212100784Sfenner	lsp->sem_otime = bsp->sem_otime;
213100784Sfenner	lsp->sem_ctime = bsp->sem_ctime;
214100784Sfenner	lsp->sem_nsems = bsp->sem_nsems;
215100784Sfenner	lsp->sem_base = PTROUT(bsp->sem_base);
216100784Sfenner}
217100784Sfenner
218100784Sfennerstatic void
219100784Sfennerlinux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp)
220100784Sfenner{
221
222	linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
223	bsp->shm_segsz = lsp->shm_segsz;
224	bsp->shm_lpid = lsp->shm_lpid;
225	bsp->shm_cpid = lsp->shm_cpid;
226	bsp->shm_nattch = lsp->shm_nattch;
227	bsp->shm_atime = lsp->shm_atime;
228	bsp->shm_dtime = lsp->shm_dtime;
229	bsp->shm_ctime = lsp->shm_ctime;
230}
231
232static void
233bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp)
234{
235
236	bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
237	if (bsp->shm_segsz > INT_MAX)
238		lsp->shm_segsz = INT_MAX;
239	else
240		lsp->shm_segsz = bsp->shm_segsz;
241	lsp->shm_lpid = bsp->shm_lpid;
242	lsp->shm_cpid = bsp->shm_cpid;
243	if (bsp->shm_nattch > SHRT_MAX)
244		lsp->shm_nattch = SHRT_MAX;
245	else
246		lsp->shm_nattch = bsp->shm_nattch;
247	lsp->shm_atime = bsp->shm_atime;
248	lsp->shm_dtime = bsp->shm_dtime;
249	lsp->shm_ctime = bsp->shm_ctime;
250	lsp->private3 = 0;
251}
252
253static void
254linux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp)
255{
256
257	linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
258	bsp->msg_cbytes = lsp->msg_cbytes;
259	bsp->msg_qnum = lsp->msg_qnum;
260	bsp->msg_qbytes = lsp->msg_qbytes;
261	bsp->msg_lspid = lsp->msg_lspid;
262	bsp->msg_lrpid = lsp->msg_lrpid;
263	bsp->msg_stime = lsp->msg_stime;
264	bsp->msg_rtime = lsp->msg_rtime;
265	bsp->msg_ctime = lsp->msg_ctime;
266}
267
268static void
269bsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp)
270{
271
272	bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
273	lsp->msg_cbytes = bsp->msg_cbytes;
274	lsp->msg_qnum = bsp->msg_qnum;
275	lsp->msg_qbytes = bsp->msg_qbytes;
276	lsp->msg_lspid = bsp->msg_lspid;
277	lsp->msg_lrpid = bsp->msg_lrpid;
278	lsp->msg_stime = bsp->msg_stime;
279	lsp->msg_rtime = bsp->msg_rtime;
280	lsp->msg_ctime = bsp->msg_ctime;
281}
282
283static void
284linux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out)
285{
286
287	/* XXX: do we really need to do something here? */
288	out->key = in->key;
289	out->uid = in->uid;
290	out->gid = in->gid;
291	out->cuid = in->cuid;
292	out->cgid = in->cgid;
293	out->mode = in->mode;
294	out->seq = in->seq;
295}
296
297static int
298linux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
299{
300	struct l_msqid64_ds linux_msqid64;
301	int error;
302
303	if (ver == LINUX_IPC_64) {
304		error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64));
305		if (error != 0)
306			return (error);
307
308		bzero(linux_msqid, sizeof(*linux_msqid));
309
310		linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid;
311		linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid;
312		linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode;
313
314		if (linux_msqid64.msg_qbytes > USHRT_MAX)
315			linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes;
316		else
317			linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes;
318	} else
319		error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid));
320
321	return (error);
322}
323
324static int
325linux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
326{
327	struct l_msqid64_ds linux_msqid64;
328
329	if (ver == LINUX_IPC_64) {
330		bzero(&linux_msqid64, sizeof(linux_msqid64));
331
332		linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm,
333		    &linux_msqid64.msg_perm);
334
335		linux_msqid64.msg_stime = linux_msqid->msg_stime;
336		linux_msqid64.msg_rtime = linux_msqid->msg_rtime;
337		linux_msqid64.msg_ctime = linux_msqid->msg_ctime;
338
339		if (linux_msqid->msg_cbytes == 0)
340			linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes;
341		else
342			linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes;
343
344		linux_msqid64.msg_qnum = linux_msqid->msg_qnum;
345
346		if (linux_msqid->msg_qbytes == 0)
347			linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes;
348		else
349			linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes;
350
351		linux_msqid64.msg_lspid = linux_msqid->msg_lspid;
352		linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid;
353
354		return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64)));
355	} else
356		return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid)));
357}
358
359static int
360linux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
361{
362	struct l_semid64_ds linux_semid64;
363	int error;
364
365	if (ver == LINUX_IPC_64) {
366		error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64));
367		if (error != 0)
368			return (error);
369
370		bzero(linux_semid, sizeof(*linux_semid));
371
372		linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid;
373		linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid;
374		linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode;
375	} else
376		error = copyin(uaddr, linux_semid, sizeof(*linux_semid));
377
378	return (error);
379}
380
381static int
382linux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
383{
384	struct l_semid64_ds linux_semid64;
385
386	if (ver == LINUX_IPC_64) {
387		bzero(&linux_semid64, sizeof(linux_semid64));
388
389		linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm,
390		    &linux_semid64.sem_perm);
391
392		linux_semid64.sem_otime = linux_semid->sem_otime;
393		linux_semid64.sem_ctime = linux_semid->sem_ctime;
394		linux_semid64.sem_nsems = linux_semid->sem_nsems;
395
396		return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64)));
397	} else
398		return (copyout(linux_semid, uaddr, sizeof(*linux_semid)));
399}
400
401static int
402linux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
403{
404	struct l_shmid64_ds linux_shmid64;
405	int error;
406
407	if (ver == LINUX_IPC_64) {
408		error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64));
409		if (error != 0)
410			return (error);
411
412		bzero(linux_shmid, sizeof(*linux_shmid));
413
414		linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid;
415		linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid;
416		linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode;
417	} else
418		error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid));
419
420	return (error);
421}
422
423static int
424linux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
425{
426	struct l_shmid64_ds linux_shmid64;
427
428	/*
429	 * XXX: This is backwards and loses information in shm_nattch
430	 * and shm_segsz.  We should probably either expose the BSD
431	 * shmid structure directly and convert it to either the
432	 * non-64 or 64 variant directly or the code should always
433	 * convert to the 64 variant and then truncate values into the
434	 * non-64 variant if needed since the 64 variant has more
435	 * precision.
436	 */
437	if (ver == LINUX_IPC_64) {
438		bzero(&linux_shmid64, sizeof(linux_shmid64));
439
440		linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm,
441		    &linux_shmid64.shm_perm);
442
443		linux_shmid64.shm_segsz = linux_shmid->shm_segsz;
444		linux_shmid64.shm_atime = linux_shmid->shm_atime;
445		linux_shmid64.shm_dtime = linux_shmid->shm_dtime;
446		linux_shmid64.shm_ctime = linux_shmid->shm_ctime;
447		linux_shmid64.shm_cpid = linux_shmid->shm_cpid;
448		linux_shmid64.shm_lpid = linux_shmid->shm_lpid;
449		linux_shmid64.shm_nattch = linux_shmid->shm_nattch;
450
451		return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64)));
452	} else
453		return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid)));
454}
455
456static int
457linux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo,
458    caddr_t uaddr)
459{
460	struct l_shminfo64 linux_shminfo64;
461
462	if (ver == LINUX_IPC_64) {
463		bzero(&linux_shminfo64, sizeof(linux_shminfo64));
464
465		linux_shminfo64.shmmax = linux_shminfo->shmmax;
466		linux_shminfo64.shmmin = linux_shminfo->shmmin;
467		linux_shminfo64.shmmni = linux_shminfo->shmmni;
468		linux_shminfo64.shmseg = linux_shminfo->shmseg;
469		linux_shminfo64.shmall = linux_shminfo->shmall;
470
471		return (copyout(&linux_shminfo64, uaddr,
472		    sizeof(linux_shminfo64)));
473	} else
474		return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo)));
475}
476
477int
478linux_semop(struct thread *td, struct linux_semop_args *args)
479{
480	struct semop_args /* {
481	int	semid;
482	struct	sembuf *sops;
483	int		nsops;
484	} */ bsd_args;
485
486	bsd_args.semid = args->semid;
487	bsd_args.sops = PTRIN(args->tsops);
488	bsd_args.nsops = args->nsops;
489	return (sys_semop(td, &bsd_args));
490}
491
492int
493linux_semget(struct thread *td, struct linux_semget_args *args)
494{
495	struct semget_args /* {
496	key_t	key;
497	int		nsems;
498	int		semflg;
499	} */ bsd_args;
500
501	if (args->nsems < 0)
502		return (EINVAL);
503	bsd_args.key = args->key;
504	bsd_args.nsems = args->nsems;
505	bsd_args.semflg = args->semflg;
506	return (sys_semget(td, &bsd_args));
507}
508
509int
510linux_semctl(struct thread *td, struct linux_semctl_args *args)
511{
512	struct l_semid_ds linux_semid;
513	struct l_seminfo linux_seminfo;
514	struct semid_ds semid;
515	union semun semun;
516	register_t rval;
517	int cmd, error;
518
519	switch (args->cmd & ~LINUX_IPC_64) {
520	case LINUX_IPC_RMID:
521		cmd = IPC_RMID;
522		break;
523	case LINUX_GETNCNT:
524		cmd = GETNCNT;
525		break;
526	case LINUX_GETPID:
527		cmd = GETPID;
528		break;
529	case LINUX_GETVAL:
530		cmd = GETVAL;
531		break;
532	case LINUX_GETZCNT:
533		cmd = GETZCNT;
534		break;
535	case LINUX_SETVAL:
536		cmd = SETVAL;
537		semun.val = args->arg.val;
538		break;
539	case LINUX_IPC_SET:
540		cmd = IPC_SET;
541		error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
542		    &linux_semid, PTRIN(args->arg.buf));
543		if (error)
544			return (error);
545		linux_to_bsd_semid_ds(&linux_semid, &semid);
546		semun.buf = &semid;
547		return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
548		    td->td_retval));
549	case LINUX_IPC_STAT:
550	case LINUX_SEM_STAT:
551		if ((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
552			cmd = IPC_STAT;
553		else
554			cmd = SEM_STAT;
555		semun.buf = &semid;
556		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
557		    &rval);
558		if (error)
559			return (error);
560		bsd_to_linux_semid_ds(&semid, &linux_semid);
561		error = linux_semid_pushdown(args->cmd & LINUX_IPC_64,
562		    &linux_semid, PTRIN(args->arg.buf));
563		if (error == 0)
564			td->td_retval[0] = (cmd == SEM_STAT) ? rval : 0;
565		return (error);
566	case LINUX_IPC_INFO:
567	case LINUX_SEM_INFO:
568		bcopy(&seminfo, &linux_seminfo.semmni, sizeof(linux_seminfo) -
569		    sizeof(linux_seminfo.semmap) );
570		/*
571		 * Linux does not use the semmap field but populates it with
572		 * the defined value from SEMMAP, which really is redefined to
573		 * SEMMNS, which they define as SEMMNI * SEMMSL.  Try to
574		 * simulate this returning our dynamic semmns value.
575		 */
576		linux_seminfo.semmap = linux_seminfo.semmns;
577/* XXX BSD equivalent?
578#define used_semids 10
579#define used_sems 10
580		linux_seminfo.semusz = used_semids;
581		linux_seminfo.semaem = used_sems;
582*/
583		error = copyout(&linux_seminfo,
584		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
585		if (error)
586			return (error);
587		td->td_retval[0] = seminfo.semmni;
588		return (0);			/* No need for __semctl call */
589	case LINUX_GETALL:
590		cmd = GETALL;
591		semun.val = args->arg.val;
592		break;
593	case LINUX_SETALL:
594		cmd = SETALL;
595		semun.val = args->arg.val;
596		break;
597	default:
598		linux_msg(td, "ipc type %d is not implemented",
599		  args->cmd & ~LINUX_IPC_64);
600		return (EINVAL);
601	}
602	return (kern_semctl(td, args->semid, args->semnum, cmd, &semun,
603	    td->td_retval));
604}
605
606int
607linux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
608{
609	const void *msgp;
610	long mtype;
611	l_long lmtype;
612	int error;
613
614	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
615		return (EINVAL);
616	msgp = PTRIN(args->msgp);
617	if ((error = copyin(msgp, &lmtype, sizeof(lmtype))) != 0)
618		return (error);
619	mtype = (long)lmtype;
620	return (kern_msgsnd(td, args->msqid,
621	    (const char *)msgp + sizeof(lmtype),
622	    args->msgsz, args->msgflg, mtype));
623}
624
625int
626linux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
627{
628	void *msgp;
629	long mtype;
630	l_long lmtype;
631	int error;
632
633	if ((l_long)args->msgsz < 0 || args->msgsz > (l_long)msginfo.msgmax)
634		return (EINVAL);
635	msgp = PTRIN(args->msgp);
636	if ((error = kern_msgrcv(td, args->msqid,
637	    (char *)msgp + sizeof(lmtype), args->msgsz,
638	    args->msgtyp, args->msgflg, &mtype)) != 0)
639		return (error);
640	lmtype = (l_long)mtype;
641	return (copyout(&lmtype, msgp, sizeof(lmtype)));
642}
643
644int
645linux_msgget(struct thread *td, struct linux_msgget_args *args)
646{
647	struct msgget_args /* {
648		key_t	key;
649		int	msgflg;
650	} */ bsd_args;
651
652	bsd_args.key = args->key;
653	bsd_args.msgflg = args->msgflg;
654	return (sys_msgget(td, &bsd_args));
655}
656
657int
658linux_msgctl(struct thread *td, struct linux_msgctl_args *args)
659{
660	int error, bsd_cmd;
661	struct l_msqid_ds linux_msqid;
662	struct msqid_ds bsd_msqid;
663
664	bsd_cmd = args->cmd & ~LINUX_IPC_64;
665	switch (bsd_cmd) {
666	case LINUX_IPC_INFO:
667	case LINUX_MSG_INFO: {
668		struct l_msginfo linux_msginfo;
669
670		/*
671		 * XXX MSG_INFO uses the same data structure but returns different
672		 * dynamic counters in msgpool, msgmap, and msgtql fields.
673		 */
674		linux_msginfo.msgpool = (long)msginfo.msgmni *
675		    (long)msginfo.msgmnb / 1024L;	/* XXX MSG_INFO. */
676		linux_msginfo.msgmap = msginfo.msgmnb;	/* XXX MSG_INFO. */
677		linux_msginfo.msgmax = msginfo.msgmax;
678		linux_msginfo.msgmnb = msginfo.msgmnb;
679		linux_msginfo.msgmni = msginfo.msgmni;
680		linux_msginfo.msgssz = msginfo.msgssz;
681		linux_msginfo.msgtql = msginfo.msgtql;	/* XXX MSG_INFO. */
682		linux_msginfo.msgseg = msginfo.msgseg;
683		error = copyout(&linux_msginfo, PTRIN(args->buf),
684		    sizeof(linux_msginfo));
685		if (error == 0)
686		    td->td_retval[0] = msginfo.msgmni;	/* XXX */
687
688		return (error);
689	}
690
691	/*
692	 * TODO: implement this
693	 * case LINUX_MSG_STAT:
694	 */
695	case LINUX_IPC_STAT:
696		/* NOTHING */
697		break;
698
699	case LINUX_IPC_SET:
700		error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
701		    &linux_msqid, PTRIN(args->buf));
702		if (error)
703			return (error);
704		linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid);
705		break;
706
707	case LINUX_IPC_RMID:
708		/* NOTHING */
709		break;
710
711	default:
712		return (EINVAL);
713		break;
714	}
715
716	error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
717	if (error != 0)
718		if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
719			return (error);
720
721	if (bsd_cmd == LINUX_IPC_STAT) {
722		bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid);
723		return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
724		    &linux_msqid, PTRIN(args->buf)));
725	}
726
727	return (0);
728}
729
730int
731linux_shmat(struct thread *td, struct linux_shmat_args *args)
732{
733	struct shmat_args /* {
734		int shmid;
735		void *shmaddr;
736		int shmflg;
737	} */ bsd_args;
738	int error;
739#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
740	l_uintptr_t addr;
741#endif
742
743	bsd_args.shmid = args->shmid;
744	bsd_args.shmaddr = PTRIN(args->shmaddr);
745	bsd_args.shmflg = args->shmflg;
746	if ((error = sys_shmat(td, &bsd_args)))
747		return (error);
748#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
749	addr = td->td_retval[0];
750	if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr))))
751		return (error);
752	td->td_retval[0] = 0;
753#endif
754	return (0);
755}
756
757int
758linux_shmdt(struct thread *td, struct linux_shmdt_args *args)
759{
760	struct shmdt_args /* {
761		void *shmaddr;
762	} */ bsd_args;
763
764	bsd_args.shmaddr = PTRIN(args->shmaddr);
765	return (sys_shmdt(td, &bsd_args));
766}
767
768int
769linux_shmget(struct thread *td, struct linux_shmget_args *args)
770{
771	struct shmget_args /* {
772		key_t key;
773		int size;
774		int shmflg;
775	} */ bsd_args;
776
777	bsd_args.key = args->key;
778	bsd_args.size = args->size;
779	bsd_args.shmflg = args->shmflg;
780	return (sys_shmget(td, &bsd_args));
781}
782
783int
784linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
785{
786	struct l_shmid_ds linux_shmid;
787	struct l_shminfo linux_shminfo;
788	struct l_shm_info linux_shm_info;
789	struct shmid_ds bsd_shmid;
790	int error;
791
792	switch (args->cmd & ~LINUX_IPC_64) {
793
794	case LINUX_IPC_INFO: {
795		struct shminfo bsd_shminfo;
796
797		/* Perform shmctl wanting removed segments lookup */
798		error = kern_shmctl(td, args->shmid, IPC_INFO,
799		    (void *)&bsd_shminfo, NULL);
800		if (error)
801			return (error);
802
803		bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo);
804
805		return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
806		    &linux_shminfo, PTRIN(args->buf)));
807	}
808
809	case LINUX_SHM_INFO: {
810		struct shm_info bsd_shm_info;
811
812		/* Perform shmctl wanting removed segments lookup */
813		error = kern_shmctl(td, args->shmid, SHM_INFO,
814		    (void *)&bsd_shm_info, NULL);
815		if (error)
816			return (error);
817
818		bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
819
820		return (copyout(&linux_shm_info, PTRIN(args->buf),
821		    sizeof(struct l_shm_info)));
822	}
823
824	case LINUX_IPC_STAT:
825		/* Perform shmctl wanting removed segments lookup */
826		error = kern_shmctl(td, args->shmid, IPC_STAT,
827		    (void *)&bsd_shmid, NULL);
828		if (error)
829			return (error);
830
831		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
832
833		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
834		    &linux_shmid, PTRIN(args->buf)));
835
836	case LINUX_SHM_STAT:
837		/* Perform shmctl wanting removed segments lookup */
838		error = kern_shmctl(td, args->shmid, IPC_STAT,
839		    (void *)&bsd_shmid, NULL);
840		if (error)
841			return (error);
842
843		bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
844
845		return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
846		    &linux_shmid, PTRIN(args->buf)));
847
848	case LINUX_IPC_SET:
849		error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
850		    &linux_shmid, PTRIN(args->buf));
851		if (error)
852			return (error);
853
854		linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
855
856		/* Perform shmctl wanting removed segments lookup */
857		return (kern_shmctl(td, args->shmid, IPC_SET,
858		    (void *)&bsd_shmid, NULL));
859
860	case LINUX_IPC_RMID: {
861		void *buf;
862
863		if (args->buf == 0)
864			buf = NULL;
865		else {
866			error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
867			    &linux_shmid, PTRIN(args->buf));
868			if (error)
869				return (error);
870			linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
871			buf = (void *)&bsd_shmid;
872		}
873		return (kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL));
874	}
875
876	case LINUX_SHM_LOCK:
877		/* FALLTHROUGH */
878	case LINUX_SHM_UNLOCK:
879		/* FALLTHROUGH */
880	default:
881		linux_msg(td, "ipc type %d not implemented",
882		    args->cmd & ~LINUX_IPC_64);
883		return (EINVAL);
884	}
885}
886
887MODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
888MODULE_DEPEND(linux, sysvsem, 1, 1, 1);
889MODULE_DEPEND(linux, sysvshm, 1, 1, 1);
890