linux_ipc.c revision 159991
1191783Srmacklem/*-
2191783Srmacklem * Copyright (c) 1994-1995 S�ren Schmidt
3191783Srmacklem * All rights reserved.
4191783Srmacklem *
5191783Srmacklem * Redistribution and use in source and binary forms, with or without
6191783Srmacklem * modification, are permitted provided that the following conditions
7191783Srmacklem * are met:
8191783Srmacklem * 1. Redistributions of source code must retain the above copyright
9191783Srmacklem *    notice, this list of conditions and the following disclaimer
10191783Srmacklem *    in this position and unchanged.
11191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright
12191783Srmacklem *    notice, this list of conditions and the following disclaimer in the
13191783Srmacklem *    documentation and/or other materials provided with the distribution.
14191783Srmacklem * 3. The name of the author may not be used to endorse or promote products
15191783Srmacklem *    derived from this software without specific prior written permission
16191783Srmacklem *
17191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18191783Srmacklem * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19191783Srmacklem * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20191783Srmacklem * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21191783Srmacklem * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22191783Srmacklem * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23191783Srmacklem * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24191783Srmacklem * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25191783Srmacklem * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26191783Srmacklem * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27191783Srmacklem */
28191783Srmacklem
29191783Srmacklem#include <sys/cdefs.h>
30191783Srmacklem__FBSDID("$FreeBSD: head/sys/compat/linux/linux_ipc.c 159991 2006-06-27 18:28:50Z jhb $");
31191783Srmacklem
32191783Srmacklem#include <sys/param.h>
33191783Srmacklem#include <sys/systm.h>
34191783Srmacklem#include <sys/syscallsubr.h>
35191783Srmacklem#include <sys/sysproto.h>
36207785Srmacklem#include <sys/proc.h>
37191783Srmacklem#include <sys/limits.h>
38191783Srmacklem#include <sys/msg.h>
39191783Srmacklem#include <sys/sem.h>
40191783Srmacklem#include <sys/shm.h>
41191783Srmacklem
42191783Srmacklem#include "opt_compat.h"
43191783Srmacklem
44191783Srmacklem#ifdef COMPAT_LINUX32
45191783Srmacklem#include <machine/../linux32/linux.h>
46191783Srmacklem#include <machine/../linux32/linux32_proto.h>
47191783Srmacklem#include <machine/../linux32/linux32_ipc64.h>
48191783Srmacklem#else
49191783Srmacklem#include <machine/../linux/linux.h>
50191783Srmacklem#include <machine/../linux/linux_proto.h>
51191783Srmacklem#include <machine/../linux/linux_ipc64.h>
52193066Sjamie#endif
53191783Srmacklem#include <compat/linux/linux_ipc.h>
54191783Srmacklem#include <compat/linux/linux_util.h>
55191783Srmacklem
56191783Srmacklemstruct l_seminfo {
57191783Srmacklem	l_int semmap;
58191783Srmacklem	l_int semmni;
59191783Srmacklem	l_int semmns;
60191783Srmacklem	l_int semmnu;
61191783Srmacklem	l_int semmsl;
62191783Srmacklem	l_int semopm;
63191783Srmacklem	l_int semume;
64191783Srmacklem	l_int semusz;
65191783Srmacklem	l_int semvmx;
66191783Srmacklem	l_int semaem;
67191783Srmacklem};
68191783Srmacklem
69191783Srmacklemstruct l_shminfo {
70191783Srmacklem	l_int shmmax;
71191783Srmacklem	l_int shmmin;
72191783Srmacklem	l_int shmmni;
73191783Srmacklem	l_int shmseg;
74191783Srmacklem	l_int shmall;
75191783Srmacklem};
76191783Srmacklem
77191783Srmacklemstruct l_shm_info {
78191783Srmacklem	l_int used_ids;
79191783Srmacklem	l_ulong shm_tot;  /* total allocated shm */
80191783Srmacklem	l_ulong shm_rss;  /* total resident shm */
81191783Srmacklem	l_ulong shm_swp;  /* total swapped shm */
82191783Srmacklem	l_ulong swap_attempts;
83191783Srmacklem	l_ulong swap_successes;
84191783Srmacklem};
85191783Srmacklem
86191783Srmacklemstatic void
87191783Srmacklembsd_to_linux_shminfo( struct shminfo *bpp, struct l_shminfo *lpp)
88191783Srmacklem{
89191783Srmacklem	lpp->shmmax = bpp->shmmax;
90191783Srmacklem	lpp->shmmin = bpp->shmmin;
91191783Srmacklem	lpp->shmmni = bpp->shmmni;
92191783Srmacklem	lpp->shmseg = bpp->shmseg;
93191783Srmacklem	lpp->shmall = bpp->shmall;
94191783Srmacklem}
95191783Srmacklem
96191783Srmacklemstatic void
97191783Srmacklembsd_to_linux_shm_info( struct shm_info *bpp, struct l_shm_info *lpp)
98191783Srmacklem{
99191783Srmacklem	lpp->used_ids = bpp->used_ids ;
100191783Srmacklem	lpp->shm_tot = bpp->shm_tot ;
101191783Srmacklem	lpp->shm_rss = bpp->shm_rss ;
102191783Srmacklem	lpp->shm_swp = bpp->shm_swp ;
103191783Srmacklem	lpp->swap_attempts = bpp->swap_attempts ;
104191783Srmacklem	lpp->swap_successes = bpp->swap_successes ;
105191783Srmacklem}
106191783Srmacklem
107191783Srmacklemstruct l_ipc_perm {
108191783Srmacklem	l_key_t		key;
109191783Srmacklem	l_uid16_t	uid;
110191783Srmacklem	l_gid16_t	gid;
111191783Srmacklem	l_uid16_t	cuid;
112191783Srmacklem	l_gid16_t	cgid;
113191783Srmacklem	l_ushort	mode;
114191783Srmacklem	l_ushort	seq;
115191783Srmacklem};
116191783Srmacklem
117191783Srmacklemstatic void
118191783Srmacklemlinux_to_bsd_ipc_perm(struct l_ipc_perm *lpp, struct ipc_perm *bpp)
119191783Srmacklem{
120191783Srmacklem    bpp->key = lpp->key;
121191783Srmacklem    bpp->uid = lpp->uid;
122191783Srmacklem    bpp->gid = lpp->gid;
123191783Srmacklem    bpp->cuid = lpp->cuid;
124191783Srmacklem    bpp->cgid = lpp->cgid;
125191783Srmacklem    bpp->mode = lpp->mode;
126191783Srmacklem    bpp->seq = lpp->seq;
127191783Srmacklem}
128191783Srmacklem
129191783Srmacklem
130191783Srmacklemstatic void
131191783Srmacklembsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct l_ipc_perm *lpp)
132191783Srmacklem{
133191783Srmacklem    lpp->key = bpp->key;
134191783Srmacklem    lpp->uid = bpp->uid;
135191783Srmacklem    lpp->gid = bpp->gid;
136191783Srmacklem    lpp->cuid = bpp->cuid;
137191783Srmacklem    lpp->cgid = bpp->cgid;
138191783Srmacklem    lpp->mode = bpp->mode;
139191783Srmacklem    lpp->seq = bpp->seq;
140191783Srmacklem}
141191783Srmacklem
142191783Srmacklemstruct l_msqid_ds {
143248188Sglebius	struct l_ipc_perm	msg_perm;
144191783Srmacklem	l_uintptr_t		msg_first;	/* first message on queue,unused */
145207170Srmacklem	l_uintptr_t		msg_last;	/* last message in queue,unused */
146248188Sglebius	l_time_t		msg_stime;	/* last msgsnd time */
147191783Srmacklem	l_time_t		msg_rtime;	/* last msgrcv time */
148191783Srmacklem	l_time_t		msg_ctime;	/* last change time */
149191783Srmacklem	l_ulong			msg_lcbytes;	/* Reuse junk fields for 32 bit */
150248188Sglebius	l_ulong			msg_lqbytes;	/* ditto */
151191783Srmacklem	l_ushort		msg_cbytes;	/* current number of bytes on queue */
152207170Srmacklem	l_ushort		msg_qnum;	/* number of messages in queue */
153248188Sglebius	l_ushort		msg_qbytes;	/* max number of bytes on queue */
154191783Srmacklem	l_pid_t			msg_lspid;	/* pid of last msgsnd */
155191783Srmacklem	l_pid_t			msg_lrpid;	/* last receive pid */
156191783Srmacklem}
157248188Sglebius#if defined(__amd64__) && defined(COMPAT_LINUX32)
158191783Srmacklem__packed
159207170Srmacklem#endif
160248188Sglebius;
161191783Srmacklem
162191783Srmacklemstruct l_semid_ds {
163191783Srmacklem	struct l_ipc_perm	sem_perm;
164191783Srmacklem	l_time_t		sem_otime;
165248188Sglebius	l_time_t		sem_ctime;
166191783Srmacklem	l_uintptr_t		sem_base;
167207170Srmacklem	l_uintptr_t		sem_pending;
168248188Sglebius	l_uintptr_t		sem_pending_last;
169191783Srmacklem	l_uintptr_t		undo;
170191783Srmacklem	l_ushort		sem_nsems;
171191783Srmacklem}
172191783Srmacklem#if defined(__amd64__) && defined(COMPAT_LINUX32)
173191783Srmacklem__packed
174191783Srmacklem#endif
175191783Srmacklem;
176191783Srmacklem
177191783Srmacklemstruct l_shmid_ds {
178191783Srmacklem	struct l_ipc_perm	shm_perm;
179191783Srmacklem	l_int			shm_segsz;
180191783Srmacklem	l_time_t		shm_atime;
181191783Srmacklem	l_time_t		shm_dtime;
182191783Srmacklem	l_time_t		shm_ctime;
183192152Srmacklem	l_ushort		shm_cpid;
184192152Srmacklem	l_ushort		shm_lpid;
185192152Srmacklem	l_short			shm_nattch;
186192152Srmacklem	l_ushort		private1;
187192152Srmacklem	l_uintptr_t		private2;
188192152Srmacklem	l_uintptr_t		private3;
189192152Srmacklem};
190192152Srmacklem
191192152Srmacklemstatic void
192192152Srmacklemlinux_to_bsd_semid_ds(struct l_semid_ds *lsp, struct semid_ds *bsp)
193192152Srmacklem{
194192152Srmacklem    linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm);
195192152Srmacklem    bsp->sem_otime = lsp->sem_otime;
196192152Srmacklem    bsp->sem_ctime = lsp->sem_ctime;
197192152Srmacklem    bsp->sem_nsems = lsp->sem_nsems;
198192152Srmacklem    bsp->sem_base = PTRIN(lsp->sem_base);
199192152Srmacklem}
200192152Srmacklem
201192152Srmacklemstatic void
202192152Srmacklembsd_to_linux_semid_ds(struct semid_ds *bsp, struct l_semid_ds *lsp)
203192152Srmacklem{
204192152Srmacklem	bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm);
205192152Srmacklem	lsp->sem_otime = bsp->sem_otime;
206192152Srmacklem	lsp->sem_ctime = bsp->sem_ctime;
207192152Srmacklem	lsp->sem_nsems = bsp->sem_nsems;
208192152Srmacklem	lsp->sem_base = PTROUT(bsp->sem_base);
209192152Srmacklem}
210192152Srmacklem
211192152Srmacklemstatic void
212192152Srmacklemlinux_to_bsd_shmid_ds(struct l_shmid_ds *lsp, struct shmid_ds *bsp)
213192152Srmacklem{
214192152Srmacklem    linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm);
215192152Srmacklem    bsp->shm_segsz = lsp->shm_segsz;
216192152Srmacklem    bsp->shm_lpid = lsp->shm_lpid;
217192152Srmacklem    bsp->shm_cpid = lsp->shm_cpid;
218192152Srmacklem    bsp->shm_nattch = lsp->shm_nattch;
219192152Srmacklem    bsp->shm_atime = lsp->shm_atime;
220192152Srmacklem    bsp->shm_dtime = lsp->shm_dtime;
221192152Srmacklem    bsp->shm_ctime = lsp->shm_ctime;
222192152Srmacklem    /* this goes (yet) SOS */
223192152Srmacklem    bsp->shm_internal = PTRIN(lsp->private3);
224192152Srmacklem}
225192152Srmacklem
226192152Srmacklemstatic void
227192152Srmacklembsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct l_shmid_ds *lsp)
228192152Srmacklem{
229192152Srmacklem    bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm);
230192152Srmacklem    lsp->shm_segsz = bsp->shm_segsz;
231244042Srmacklem    lsp->shm_lpid = bsp->shm_lpid;
232244042Srmacklem    lsp->shm_cpid = bsp->shm_cpid;
233244042Srmacklem    lsp->shm_nattch = bsp->shm_nattch;
234244042Srmacklem    lsp->shm_atime = bsp->shm_atime;
235244042Srmacklem    lsp->shm_dtime = bsp->shm_dtime;
236244042Srmacklem    lsp->shm_ctime = bsp->shm_ctime;
237244042Srmacklem    /* this goes (yet) SOS */
238244042Srmacklem    lsp->private3 = PTROUT(bsp->shm_internal);
239244042Srmacklem}
240244042Srmacklem
241244042Srmacklemstatic void
242244042Srmacklemlinux_to_bsd_msqid_ds(struct l_msqid_ds *lsp, struct msqid_ds *bsp)
243244042Srmacklem{
244244042Srmacklem    linux_to_bsd_ipc_perm(&lsp->msg_perm, &bsp->msg_perm);
245244042Srmacklem    bsp->msg_cbytes = lsp->msg_cbytes;
246244042Srmacklem    bsp->msg_qnum = lsp->msg_qnum;
247244042Srmacklem    bsp->msg_qbytes = lsp->msg_qbytes;
248244042Srmacklem    bsp->msg_lspid = lsp->msg_lspid;
249244042Srmacklem    bsp->msg_lrpid = lsp->msg_lrpid;
250244042Srmacklem    bsp->msg_stime = lsp->msg_stime;
251244042Srmacklem    bsp->msg_rtime = lsp->msg_rtime;
252244042Srmacklem    bsp->msg_ctime = lsp->msg_ctime;
253244042Srmacklem}
254244042Srmacklem
255244042Srmacklemstatic void
256244042Srmacklembsd_to_linux_msqid_ds(struct msqid_ds *bsp, struct l_msqid_ds *lsp)
257244042Srmacklem{
258244042Srmacklem    bsd_to_linux_ipc_perm(&bsp->msg_perm, &lsp->msg_perm);
259192781Srmacklem    lsp->msg_cbytes = bsp->msg_cbytes;
260192781Srmacklem    lsp->msg_qnum = bsp->msg_qnum;
261192781Srmacklem    lsp->msg_qbytes = bsp->msg_qbytes;
262192152Srmacklem    lsp->msg_lspid = bsp->msg_lspid;
263192152Srmacklem    lsp->msg_lrpid = bsp->msg_lrpid;
264192152Srmacklem    lsp->msg_stime = bsp->msg_stime;
265192152Srmacklem    lsp->msg_rtime = bsp->msg_rtime;
266192152Srmacklem    lsp->msg_ctime = bsp->msg_ctime;
267192152Srmacklem}
268192152Srmacklem
269192152Srmacklemstatic void
270192152Srmacklemlinux_ipc_perm_to_ipc64_perm(struct l_ipc_perm *in, struct l_ipc64_perm *out)
271192152Srmacklem{
272192152Srmacklem
273192152Srmacklem	/* XXX: do we really need to do something here? */
274192152Srmacklem	out->key = in->key;
275192152Srmacklem	out->uid = in->uid;
276192152Srmacklem	out->gid = in->gid;
277192152Srmacklem	out->cuid = in->cuid;
278192152Srmacklem	out->cgid = in->cgid;
279192152Srmacklem	out->mode = in->mode;
280192152Srmacklem	out->seq = in->seq;
281192152Srmacklem}
282192152Srmacklem
283192152Srmacklemstatic int
284192152Srmacklemlinux_msqid_pullup(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
285192152Srmacklem{
286192152Srmacklem	struct l_msqid64_ds linux_msqid64;
287192152Srmacklem	int error;
288192152Srmacklem
289192152Srmacklem	if (ver == LINUX_IPC_64) {
290192152Srmacklem		error = copyin(uaddr, &linux_msqid64, sizeof(linux_msqid64));
291192152Srmacklem		if (error != 0)
292244042Srmacklem			return (error);
293244042Srmacklem
294244042Srmacklem		bzero(linux_msqid, sizeof(*linux_msqid));
295244042Srmacklem
296244042Srmacklem		linux_msqid->msg_perm.uid = linux_msqid64.msg_perm.uid;
297244042Srmacklem		linux_msqid->msg_perm.gid = linux_msqid64.msg_perm.gid;
298244042Srmacklem		linux_msqid->msg_perm.mode = linux_msqid64.msg_perm.mode;
299244042Srmacklem
300244042Srmacklem		if (linux_msqid64.msg_qbytes > USHRT_MAX)
301244042Srmacklem			linux_msqid->msg_lqbytes = linux_msqid64.msg_qbytes;
302244042Srmacklem		else
303244042Srmacklem			linux_msqid->msg_qbytes = linux_msqid64.msg_qbytes;
304244042Srmacklem	} else {
305244042Srmacklem		error = copyin(uaddr, linux_msqid, sizeof(*linux_msqid));
306192152Srmacklem	}
307192152Srmacklem	return (error);
308192152Srmacklem}
309192152Srmacklem
310192152Srmacklemstatic int
311223280Srmacklemlinux_msqid_pushdown(l_int ver, struct l_msqid_ds *linux_msqid, caddr_t uaddr)
312192152Srmacklem{
313192152Srmacklem	struct l_msqid64_ds linux_msqid64;
314192152Srmacklem
315192152Srmacklem	if (ver == LINUX_IPC_64) {
316192152Srmacklem		bzero(&linux_msqid64, sizeof(linux_msqid64));
317192152Srmacklem
318192152Srmacklem		linux_ipc_perm_to_ipc64_perm(&linux_msqid->msg_perm,
319192152Srmacklem		    &linux_msqid64.msg_perm);
320192152Srmacklem
321192152Srmacklem		linux_msqid64.msg_stime = linux_msqid->msg_stime;
322192152Srmacklem		linux_msqid64.msg_rtime = linux_msqid->msg_rtime;
323192152Srmacklem		linux_msqid64.msg_ctime = linux_msqid->msg_ctime;
324192152Srmacklem
325192152Srmacklem		if (linux_msqid->msg_cbytes == 0)
326192152Srmacklem			linux_msqid64.msg_cbytes = linux_msqid->msg_lcbytes;
327192152Srmacklem		else
328192152Srmacklem			linux_msqid64.msg_cbytes = linux_msqid->msg_cbytes;
329192152Srmacklem
330192152Srmacklem		linux_msqid64.msg_qnum = linux_msqid->msg_qnum;
331192152Srmacklem
332192152Srmacklem		if (linux_msqid->msg_qbytes == 0)
333192152Srmacklem			linux_msqid64.msg_qbytes = linux_msqid->msg_lqbytes;
334192152Srmacklem		else
335192152Srmacklem			linux_msqid64.msg_qbytes = linux_msqid->msg_qbytes;
336192152Srmacklem
337192152Srmacklem		linux_msqid64.msg_lspid = linux_msqid->msg_lspid;
338244042Srmacklem		linux_msqid64.msg_lrpid = linux_msqid->msg_lrpid;
339244042Srmacklem
340244042Srmacklem		return (copyout(&linux_msqid64, uaddr, sizeof(linux_msqid64)));
341244042Srmacklem	} else {
342244042Srmacklem		return (copyout(linux_msqid, uaddr, sizeof(*linux_msqid)));
343244042Srmacklem	}
344244042Srmacklem}
345244042Srmacklem
346244042Srmacklemstatic int
347244042Srmacklemlinux_semid_pullup(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
348244042Srmacklem{
349244042Srmacklem	struct l_semid64_ds linux_semid64;
350244042Srmacklem	int error;
351244042Srmacklem
352244042Srmacklem	if (ver == LINUX_IPC_64) {
353244042Srmacklem		error = copyin(uaddr, &linux_semid64, sizeof(linux_semid64));
354244042Srmacklem		if (error != 0)
355244042Srmacklem			return (error);
356244042Srmacklem
357244042Srmacklem		bzero(linux_semid, sizeof(*linux_semid));
358244042Srmacklem
359223280Srmacklem		linux_semid->sem_perm.uid = linux_semid64.sem_perm.uid;
360192152Srmacklem		linux_semid->sem_perm.gid = linux_semid64.sem_perm.gid;
361192152Srmacklem		linux_semid->sem_perm.mode = linux_semid64.sem_perm.mode;
362192152Srmacklem	} else {
363192152Srmacklem		error = copyin(uaddr, linux_semid, sizeof(*linux_semid));
364192152Srmacklem	}
365192152Srmacklem	return (error);
366192152Srmacklem}
367192152Srmacklem
368192152Srmacklemstatic int
369192152Srmacklemlinux_semid_pushdown(l_int ver, struct l_semid_ds *linux_semid, caddr_t uaddr)
370192152Srmacklem{
371192152Srmacklem	struct l_semid64_ds linux_semid64;
372192152Srmacklem
373192152Srmacklem	if (ver == LINUX_IPC_64) {
374192152Srmacklem		bzero(&linux_semid64, sizeof(linux_semid64));
375192152Srmacklem
376192152Srmacklem		linux_ipc_perm_to_ipc64_perm(&linux_semid->sem_perm,
377192152Srmacklem		    &linux_semid64.sem_perm);
378192152Srmacklem
379192152Srmacklem		linux_semid64.sem_otime = linux_semid->sem_otime;
380192152Srmacklem		linux_semid64.sem_ctime = linux_semid->sem_ctime;
381192152Srmacklem		linux_semid64.sem_nsems = linux_semid->sem_nsems;
382192152Srmacklem
383192152Srmacklem		return (copyout(&linux_semid64, uaddr, sizeof(linux_semid64)));
384192152Srmacklem	} else {
385192152Srmacklem		return (copyout(linux_semid, uaddr, sizeof(*linux_semid)));
386192152Srmacklem	}
387192152Srmacklem}
388192152Srmacklem
389192152Srmacklemstatic int
390192152Srmacklemlinux_shmid_pullup(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
391192152Srmacklem{
392192152Srmacklem	struct l_shmid64_ds linux_shmid64;
393192152Srmacklem	int error;
394192152Srmacklem
395192152Srmacklem	if (ver == LINUX_IPC_64) {
396192152Srmacklem		error = copyin(uaddr, &linux_shmid64, sizeof(linux_shmid64));
397192152Srmacklem		if (error != 0)
398192152Srmacklem			return (error);
399192152Srmacklem
400192152Srmacklem		bzero(linux_shmid, sizeof(*linux_shmid));
401192152Srmacklem
402192152Srmacklem		linux_shmid->shm_perm.uid = linux_shmid64.shm_perm.uid;
403192152Srmacklem		linux_shmid->shm_perm.gid = linux_shmid64.shm_perm.gid;
404192152Srmacklem		linux_shmid->shm_perm.mode = linux_shmid64.shm_perm.mode;
405192152Srmacklem	} else {
406192152Srmacklem		error = copyin(uaddr, linux_shmid, sizeof(*linux_shmid));
407192152Srmacklem	}
408192152Srmacklem	return (error);
409192152Srmacklem}
410192152Srmacklem
411192152Srmacklemstatic int
412192152Srmacklemlinux_shmid_pushdown(l_int ver, struct l_shmid_ds *linux_shmid, caddr_t uaddr)
413192152Srmacklem{
414192152Srmacklem	struct l_shmid64_ds linux_shmid64;
415192152Srmacklem
416192152Srmacklem	if (ver == LINUX_IPC_64) {
417192152Srmacklem		bzero(&linux_shmid64, sizeof(linux_shmid64));
418192152Srmacklem
419192152Srmacklem		linux_ipc_perm_to_ipc64_perm(&linux_shmid->shm_perm,
420192152Srmacklem		    &linux_shmid64.shm_perm);
421192152Srmacklem
422192152Srmacklem		linux_shmid64.shm_segsz = linux_shmid->shm_segsz;
423192152Srmacklem		linux_shmid64.shm_atime = linux_shmid->shm_atime;
424192152Srmacklem		linux_shmid64.shm_dtime = linux_shmid->shm_dtime;
425223280Srmacklem		linux_shmid64.shm_ctime = linux_shmid->shm_ctime;
426192152Srmacklem		linux_shmid64.shm_cpid = linux_shmid->shm_cpid;
427223280Srmacklem		linux_shmid64.shm_lpid = linux_shmid->shm_lpid;
428192152Srmacklem		linux_shmid64.shm_nattch = linux_shmid->shm_nattch;
429191783Srmacklem
430191783Srmacklem		return (copyout(&linux_shmid64, uaddr, sizeof(linux_shmid64)));
431191783Srmacklem	} else {
432191783Srmacklem		return (copyout(linux_shmid, uaddr, sizeof(*linux_shmid)));
433191783Srmacklem	}
434244042Srmacklem}
435191783Srmacklem
436191783Srmacklemstatic int
437191783Srmacklemlinux_shminfo_pushdown(l_int ver, struct l_shminfo *linux_shminfo,
438191783Srmacklem    caddr_t uaddr)
439191783Srmacklem{
440191783Srmacklem	struct l_shminfo64 linux_shminfo64;
441221014Srmacklem
442191783Srmacklem	if (ver == LINUX_IPC_64) {
443191783Srmacklem		bzero(&linux_shminfo64, sizeof(linux_shminfo64));
444191783Srmacklem
445191783Srmacklem		linux_shminfo64.shmmax = linux_shminfo->shmmax;
446191783Srmacklem		linux_shminfo64.shmmin = linux_shminfo->shmmin;
447191783Srmacklem		linux_shminfo64.shmmni = linux_shminfo->shmmni;
448191783Srmacklem		linux_shminfo64.shmseg = linux_shminfo->shmseg;
449191783Srmacklem		linux_shminfo64.shmall = linux_shminfo->shmall;
450191783Srmacklem
451191783Srmacklem		return (copyout(&linux_shminfo64, uaddr,
452191783Srmacklem		    sizeof(linux_shminfo64)));
453191783Srmacklem	} else {
454191783Srmacklem		return (copyout(linux_shminfo, uaddr, sizeof(*linux_shminfo)));
455191783Srmacklem	}
456191783Srmacklem}
457191783Srmacklem
458191783Srmacklemint
459191783Srmacklemlinux_semop(struct thread *td, struct linux_semop_args *args)
460191783Srmacklem{
461191783Srmacklem	struct semop_args /* {
462191783Srmacklem	int	semid;
463191783Srmacklem	struct	sembuf *sops;
464191783Srmacklem	int		nsops;
465191783Srmacklem	} */ bsd_args;
466191783Srmacklem
467191783Srmacklem	bsd_args.semid = args->semid;
468191783Srmacklem	bsd_args.sops = (struct sembuf *)PTRIN(args->tsops);
469191783Srmacklem	bsd_args.nsops = args->nsops;
470191783Srmacklem	return semop(td, &bsd_args);
471191783Srmacklem}
472191783Srmacklem
473191783Srmacklemint
474191783Srmacklemlinux_semget(struct thread *td, struct linux_semget_args *args)
475191783Srmacklem{
476191783Srmacklem	struct semget_args /* {
477191783Srmacklem	key_t	key;
478191783Srmacklem	int		nsems;
479191783Srmacklem	int		semflg;
480191783Srmacklem	} */ bsd_args;
481191783Srmacklem
482191783Srmacklem	if (args->nsems < 0)
483191783Srmacklem		return (EINVAL);
484191783Srmacklem	bsd_args.key = args->key;
485191783Srmacklem	bsd_args.nsems = args->nsems;
486191783Srmacklem	bsd_args.semflg = args->semflg;
487191783Srmacklem	return semget(td, &bsd_args);
488191783Srmacklem}
489191783Srmacklem
490191783Srmacklemint
491191783Srmacklemlinux_semctl(struct thread *td, struct linux_semctl_args *args)
492191783Srmacklem{
493191783Srmacklem	struct l_semid_ds linux_semid;
494191783Srmacklem	struct l_seminfo linux_seminfo;
495191783Srmacklem	struct semid_ds semid;
496191783Srmacklem	union semun semun;
497191783Srmacklem	int cmd, error;
498191783Srmacklem
499191783Srmacklem	switch (args->cmd & ~LINUX_IPC_64) {
500191783Srmacklem	case LINUX_IPC_RMID:
501191783Srmacklem		cmd = IPC_RMID;
502191783Srmacklem		break;
503191783Srmacklem	case LINUX_GETNCNT:
504191783Srmacklem		cmd = GETNCNT;
505191783Srmacklem		break;
506191783Srmacklem	case LINUX_GETPID:
507191783Srmacklem		cmd = GETPID;
508191783Srmacklem		break;
509191783Srmacklem	case LINUX_GETVAL:
510191783Srmacklem		cmd = GETVAL;
511191783Srmacklem		break;
512191783Srmacklem	case LINUX_GETZCNT:
513191783Srmacklem		cmd = GETZCNT;
514191783Srmacklem		break;
515191783Srmacklem	case LINUX_SETVAL:
516191783Srmacklem		cmd = SETVAL;
517191783Srmacklem		semun.val = args->arg.val;
518191783Srmacklem		break;
519191783Srmacklem	case LINUX_IPC_SET:
520191783Srmacklem		cmd = IPC_SET;
521191783Srmacklem		error = linux_semid_pullup(args->cmd & LINUX_IPC_64,
522191783Srmacklem		    &linux_semid, (caddr_t)PTRIN(args->arg.buf));
523191783Srmacklem		if (error)
524191783Srmacklem			return (error);
525191783Srmacklem		linux_to_bsd_semid_ds(&linux_semid, &semid);
526191783Srmacklem		semun.buf = &semid;
527191783Srmacklem		return kern_semctl(td, args->semid, args->semnum, cmd, &semun,
528191783Srmacklem		    UIO_SYSSPACE);
529191783Srmacklem	case LINUX_IPC_STAT:
530191783Srmacklem	case LINUX_SEM_STAT:
531191783Srmacklem		if((args->cmd & ~LINUX_IPC_64) == LINUX_IPC_STAT)
532191783Srmacklem			cmd = IPC_STAT;
533191783Srmacklem		else
534191783Srmacklem			cmd = SEM_STAT;
535191783Srmacklem		semun.buf = &semid;
536191783Srmacklem		error = kern_semctl(td, args->semid, args->semnum, cmd, &semun,
537191783Srmacklem		    UIO_SYSSPACE);
538191783Srmacklem		if (error)
539191783Srmacklem			return (error);
540191783Srmacklem		td->td_retval[0] = (cmd == SEM_STAT) ?
541191783Srmacklem		    IXSEQ_TO_IPCID(args->semid, semid.sem_perm) :
542191783Srmacklem		    0;
543191783Srmacklem		bsd_to_linux_semid_ds(&semid, &linux_semid);
544191783Srmacklem		return (linux_semid_pushdown(args->cmd & LINUX_IPC_64,
545191783Srmacklem		    &linux_semid, (caddr_t)PTRIN(args->arg.buf)));
546191783Srmacklem	case LINUX_IPC_INFO:
547191783Srmacklem	case LINUX_SEM_INFO:
548191783Srmacklem		bcopy(&seminfo, &linux_seminfo, sizeof(linux_seminfo) );
549191783Srmacklem/* XXX BSD equivalent?
550191783Srmacklem#define used_semids 10
551191783Srmacklem#define used_sems 10
552191783Srmacklem		linux_seminfo.semusz = used_semids;
553191783Srmacklem		linux_seminfo.semaem = used_sems;
554191783Srmacklem*/
555191783Srmacklem		error = copyout(&linux_seminfo,
556191783Srmacklem		    PTRIN(args->arg.buf), sizeof(linux_seminfo));
557191783Srmacklem		if (error)
558191783Srmacklem			return error;
559191783Srmacklem		td->td_retval[0] = seminfo.semmni;
560191783Srmacklem		return 0;			/* No need for __semctl call */
561191783Srmacklem	case LINUX_GETALL:
562191783Srmacklem		/* FALLTHROUGH */
563191783Srmacklem	case LINUX_SETALL:
564191783Srmacklem		/* FALLTHROUGH */
565191783Srmacklem	default:
566191783Srmacklem		linux_msg(td, "ipc type %d is not implemented",
567191783Srmacklem		  args->cmd & ~LINUX_IPC_64);
568191783Srmacklem		return EINVAL;
569191783Srmacklem	}
570191783Srmacklem	return kern_semctl(td, args->semid, args->semnum, cmd, &semun,
571191783Srmacklem	    UIO_USERSPACE);
572191783Srmacklem}
573191783Srmacklem
574191783Srmacklemint
575191783Srmacklemlinux_msgsnd(struct thread *td, struct linux_msgsnd_args *args)
576191783Srmacklem{
577191783Srmacklem    struct msgsnd_args /* {
578191783Srmacklem	int     msqid;
579191783Srmacklem	void    *msgp;
580191783Srmacklem	size_t  msgsz;
581191783Srmacklem	int     msgflg;
582191783Srmacklem    } */ bsd_args;
583191783Srmacklem
584191783Srmacklem    bsd_args.msqid = args->msqid;
585191783Srmacklem    bsd_args.msgp = PTRIN(args->msgp);
586191783Srmacklem    bsd_args.msgsz = args->msgsz;
587191783Srmacklem    bsd_args.msgflg = args->msgflg;
588191783Srmacklem    return msgsnd(td, &bsd_args);
589191783Srmacklem}
590191783Srmacklem
591191783Srmacklemint
592191783Srmacklemlinux_msgrcv(struct thread *td, struct linux_msgrcv_args *args)
593191783Srmacklem{
594191783Srmacklem    struct msgrcv_args /* {
595191783Srmacklem	int	msqid;
596191783Srmacklem	void	*msgp;
597191783Srmacklem	size_t	msgsz;
598191783Srmacklem	long	msgtyp;
599191783Srmacklem	int	msgflg;
600191783Srmacklem    } */ bsd_args;
601191783Srmacklem
602205941Srmacklem    bsd_args.msqid = args->msqid;
603191783Srmacklem    bsd_args.msgp = PTRIN(args->msgp);
604191783Srmacklem    bsd_args.msgsz = args->msgsz;
605191783Srmacklem    bsd_args.msgtyp = args->msgtyp;
606191783Srmacklem    bsd_args.msgflg = args->msgflg;
607191783Srmacklem    return msgrcv(td, &bsd_args);
608191783Srmacklem}
609191783Srmacklem
610191783Srmacklemint
611191783Srmacklemlinux_msgget(struct thread *td, struct linux_msgget_args *args)
612191783Srmacklem{
613191783Srmacklem    struct msgget_args /* {
614191783Srmacklem	key_t	key;
615191783Srmacklem	int	msgflg;
616191783Srmacklem    } */ bsd_args;
617191783Srmacklem
618191783Srmacklem    bsd_args.key = args->key;
619191783Srmacklem    bsd_args.msgflg = args->msgflg;
620191783Srmacklem    return msgget(td, &bsd_args);
621191783Srmacklem}
622191783Srmacklem
623191783Srmacklemint
624191783Srmacklemlinux_msgctl(struct thread *td, struct linux_msgctl_args *args)
625191783Srmacklem{
626191783Srmacklem    int error, bsd_cmd;
627191783Srmacklem    struct l_msqid_ds linux_msqid;
628191783Srmacklem    struct msqid_ds bsd_msqid;
629191783Srmacklem
630191783Srmacklem    error = linux_msqid_pullup(args->cmd & LINUX_IPC_64,
631191783Srmacklem      &linux_msqid, (caddr_t)PTRIN(args->buf));
632191783Srmacklem    if (error != 0)
633191783Srmacklem	return (error);
634191783Srmacklem    bsd_cmd = args->cmd & ~LINUX_IPC_64;
635191783Srmacklem    if (bsd_cmd == LINUX_IPC_SET)
636191783Srmacklem	linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid);
637191783Srmacklem
638244042Srmacklem    error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid);
639244042Srmacklem    if (error != 0)
640269398Srmacklem	if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL)
641269398Srmacklem	    return (error);
642269398Srmacklem
643191783Srmacklem    if (bsd_cmd == LINUX_IPC_STAT) {
644191783Srmacklem	bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid);
645191783Srmacklem	return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64,
646191783Srmacklem	  &linux_msqid, (caddr_t)PTRIN(args->buf)));
647191783Srmacklem    }
648191783Srmacklem
649191783Srmacklem    return (0);
650191783Srmacklem}
651191783Srmacklem
652191783Srmacklemint
653191783Srmacklemlinux_shmat(struct thread *td, struct linux_shmat_args *args)
654191783Srmacklem{
655191783Srmacklem    struct shmat_args /* {
656191783Srmacklem	int shmid;
657191783Srmacklem	void *shmaddr;
658191783Srmacklem	int shmflg;
659191783Srmacklem    } */ bsd_args;
660191783Srmacklem    int error;
661191783Srmacklem#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
662191783Srmacklem    l_uintptr_t addr;
663191783Srmacklem#endif
664191783Srmacklem
665191783Srmacklem    bsd_args.shmid = args->shmid;
666191783Srmacklem    bsd_args.shmaddr = PTRIN(args->shmaddr);
667191783Srmacklem    bsd_args.shmflg = args->shmflg;
668191783Srmacklem    if ((error = shmat(td, &bsd_args)))
669191783Srmacklem	return error;
670191783Srmacklem#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
671191783Srmacklem    addr = td->td_retval[0];
672191783Srmacklem    if ((error = copyout(&addr, PTRIN(args->raddr), sizeof(addr))))
673191783Srmacklem	return error;
674191783Srmacklem    td->td_retval[0] = 0;
675191783Srmacklem#endif
676191783Srmacklem    return 0;
677191783Srmacklem}
678191783Srmacklem
679191783Srmacklemint
680194292Srmacklemlinux_shmdt(struct thread *td, struct linux_shmdt_args *args)
681191783Srmacklem{
682191783Srmacklem    struct shmdt_args /* {
683191783Srmacklem	void *shmaddr;
684191783Srmacklem    } */ bsd_args;
685191783Srmacklem
686191783Srmacklem    bsd_args.shmaddr = PTRIN(args->shmaddr);
687191783Srmacklem    return shmdt(td, &bsd_args);
688191783Srmacklem}
689191783Srmacklem
690191783Srmacklemint
691191783Srmacklemlinux_shmget(struct thread *td, struct linux_shmget_args *args)
692191783Srmacklem{
693191783Srmacklem    struct shmget_args /* {
694191783Srmacklem	key_t key;
695191783Srmacklem	int size;
696191783Srmacklem	int shmflg;
697191783Srmacklem    } */ bsd_args;
698191783Srmacklem
699191783Srmacklem    bsd_args.key = args->key;
700191783Srmacklem    bsd_args.size = args->size;
701191783Srmacklem    bsd_args.shmflg = args->shmflg;
702217922Sgnn    return shmget(td, &bsd_args);
703191783Srmacklem}
704217922Sgnn
705191783Srmacklemint
706191783Srmacklemlinux_shmctl(struct thread *td, struct linux_shmctl_args *args)
707191783Srmacklem{
708191783Srmacklem    struct l_shmid_ds linux_shmid;
709191783Srmacklem	struct l_shminfo linux_shminfo;
710191783Srmacklem	struct l_shm_info linux_shm_info;
711191783Srmacklem	struct shmid_ds bsd_shmid;
712191783Srmacklem	size_t bufsz;
713191783Srmacklem    int error;
714191783Srmacklem
715191783Srmacklem    switch (args->cmd & ~LINUX_IPC_64) {
716191783Srmacklem
717191783Srmacklem	case LINUX_IPC_INFO: {
718191783Srmacklem	    struct shminfo bsd_shminfo;
719191783Srmacklem
720191783Srmacklem	    /* Perform shmctl wanting removed segments lookup */
721191783Srmacklem	    error = kern_shmctl(td, args->shmid, IPC_INFO,
722191783Srmacklem	        (void *)&bsd_shminfo, &bufsz);
723191783Srmacklem	    if (error)
724191783Srmacklem		return error;
725191783Srmacklem
726191783Srmacklem	    bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo);
727191783Srmacklem
728191783Srmacklem	    return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
729191783Srmacklem	       &linux_shminfo, (caddr_t)PTRIN(args->buf)));
730191783Srmacklem	}
731205941Srmacklem
732244042Srmacklem	case LINUX_SHM_INFO: {
733244042Srmacklem	    struct shm_info bsd_shm_info;
734244042Srmacklem
735244042Srmacklem	    /* Perform shmctl wanting removed segments lookup */
736244042Srmacklem	    error = kern_shmctl(td, args->shmid, SHM_INFO,
737244042Srmacklem	        (void *)&bsd_shm_info, &bufsz);
738269398Srmacklem	    if (error)
739191783Srmacklem		return error;
740191783Srmacklem
741191783Srmacklem	    bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
742191783Srmacklem
743191783Srmacklem	    return copyout(&linux_shm_info, (caddr_t)PTRIN(args->buf),
744191783Srmacklem	        sizeof(struct l_shm_info));
745191783Srmacklem	}
746191783Srmacklem
747191783Srmacklem	case LINUX_IPC_STAT:
748191783Srmacklem	    /* Perform shmctl wanting removed segments lookup */
749191783Srmacklem	    error = kern_shmctl(td, args->shmid, IPC_STAT,
750191783Srmacklem	        (void *)&bsd_shmid, &bufsz);
751191783Srmacklem	    if (error)
752191783Srmacklem		return error;
753191783Srmacklem
754191783Srmacklem	    bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
755191783Srmacklem
756191783Srmacklem	    return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
757205941Srmacklem	  &linux_shmid, (caddr_t)PTRIN(args->buf)));
758244042Srmacklem
759244042Srmacklem    case LINUX_SHM_STAT:
760244042Srmacklem	/* Perform shmctl wanting removed segments lookup */
761244042Srmacklem	error = kern_shmctl(td, args->shmid, IPC_STAT,
762244042Srmacklem	    (void *)&bsd_shmid, &bufsz);
763244042Srmacklem	if (error)
764269398Srmacklem		return error;
765191783Srmacklem
766191783Srmacklem	bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
767191783Srmacklem
768191783Srmacklem	return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
769191783Srmacklem	   &linux_shmid, (caddr_t)PTRIN(args->buf)));
770191783Srmacklem
771191783Srmacklem    case LINUX_IPC_SET:
772191783Srmacklem	error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
773191783Srmacklem	  &linux_shmid, (caddr_t)PTRIN(args->buf));
774191783Srmacklem	if (error)
775191783Srmacklem    		return error;
776191783Srmacklem
777191783Srmacklem	linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
778191783Srmacklem
779191783Srmacklem	/* Perform shmctl wanting removed segments lookup */
780191783Srmacklem	return kern_shmctl(td, args->shmid, IPC_SET,
781191783Srmacklem	    (void *)&bsd_shmid, &bufsz);
782191783Srmacklem
783191783Srmacklem    case LINUX_IPC_RMID: {
784191783Srmacklem	void *buf;
785229272Sed
786191783Srmacklem	if (args->buf == 0)
787191783Srmacklem    		buf = NULL;
788191783Srmacklem	else {
789191783Srmacklem    		error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
790191783Srmacklem		    &linux_shmid, (caddr_t)PTRIN(args->buf));
791191783Srmacklem		if (error)
792191783Srmacklem			return error;
793191783Srmacklem		linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
794191783Srmacklem		buf = (void *)&bsd_shmid;
795191783Srmacklem	}
796191783Srmacklem	return kern_shmctl(td, args->shmid, IPC_RMID, buf, &bufsz);
797191783Srmacklem    }
798191783Srmacklem
799191783Srmacklem    case LINUX_SHM_LOCK:
800191783Srmacklem    case LINUX_SHM_UNLOCK:
801191783Srmacklem    default:
802191783Srmacklem	linux_msg(td, "ipc typ=%d not implemented", args->cmd & ~LINUX_IPC_64);
803191783Srmacklem	return EINVAL;
804191783Srmacklem    }
805191783Srmacklem}
806191783Srmacklem
807191783SrmacklemMODULE_DEPEND(linux, sysvmsg, 1, 1, 1);
808191783SrmacklemMODULE_DEPEND(linux, sysvsem, 1, 1, 1);
809249592SkenMODULE_DEPEND(linux, sysvshm, 1, 1, 1);
810191783Srmacklem