sysv_msg.c revision 217555
1139804Simp/*-
22729Sdfr * Implementation of SVID messages
32729Sdfr *
42729Sdfr * Author:  Daniel Boulet
52729Sdfr *
62729Sdfr * Copyright 1993 Daniel Boulet and RTMX Inc.
72729Sdfr *
82729Sdfr * This system call was implemented by Daniel Boulet under contract from RTMX.
92729Sdfr *
102729Sdfr * Redistribution and use in source forms, with and without modification,
112729Sdfr * are permitted provided that this entire comment appears intact.
122729Sdfr *
132729Sdfr * Redistribution in binary form may occur without any restrictions.
142729Sdfr * Obviously, it would be nice if you gave credit where credit is due
152729Sdfr * but requiring it would be too onerous.
162729Sdfr *
172729Sdfr * This software is provided ``AS IS'' without any warranties of any kind.
182729Sdfr */
19140614Srwatson/*-
20140614Srwatson * Copyright (c) 2003-2005 McAfee, Inc.
21140614Srwatson * All rights reserved.
22140614Srwatson *
23140614Srwatson * This software was developed for the FreeBSD Project in part by McAfee
24140614Srwatson * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
25140614Srwatson * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
26140614Srwatson * program.
27140614Srwatson *
28140614Srwatson * Redistribution and use in source and binary forms, with or without
29140614Srwatson * modification, are permitted provided that the following conditions
30140614Srwatson * are met:
31140614Srwatson * 1. Redistributions of source code must retain the above copyright
32140614Srwatson *    notice, this list of conditions and the following disclaimer.
33140614Srwatson * 2. Redistributions in binary form must reproduce the above copyright
34140614Srwatson *    notice, this list of conditions and the following disclaimer in the
35140614Srwatson *    documentation and/or other materials provided with the distribution.
36140614Srwatson *
37140614Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
38140614Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39140614Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40140614Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
41140614Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42140614Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43140614Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44140614Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45140614Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46140614Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47140614Srwatson * SUCH DAMAGE.
48140614Srwatson */
492729Sdfr
50116182Sobrien#include <sys/cdefs.h>
51116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/sysv_msg.c 217555 2011-01-18 21:14:18Z mdf $");
52116182Sobrien
53194894Sjhb#include "opt_compat.h"
5459839Speter#include "opt_sysvipc.h"
5559839Speter
562729Sdfr#include <sys/param.h>
572729Sdfr#include <sys/systm.h>
5811626Sbde#include <sys/sysproto.h>
592729Sdfr#include <sys/kernel.h>
60164033Srwatson#include <sys/priv.h>
612729Sdfr#include <sys/proc.h>
6282607Sdillon#include <sys/lock.h>
6382607Sdillon#include <sys/mutex.h>
64129882Sphk#include <sys/module.h>
652729Sdfr#include <sys/msg.h>
6669449Salfred#include <sys/syscall.h>
67140839Ssobomax#include <sys/syscallsubr.h>
6811626Sbde#include <sys/sysent.h>
6959839Speter#include <sys/sysctl.h>
7059839Speter#include <sys/malloc.h>
7168024Srwatson#include <sys/jail.h>
722729Sdfr
73163606Srwatson#include <security/mac/mac_framework.h>
74163606Srwatson
7559839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
7659839Speter
77205323Skibstatic int msginit(void);
7892723Salfredstatic int msgunload(void);
7992723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
8010358Sjulian
81100523Salfred#ifdef MSG_DEBUG
82100523Salfred#define DPRINTF(a)	printf a
83100523Salfred#else
84194575Srdivacky#define DPRINTF(a)	(void)0
85100523Salfred#endif
862729Sdfr
8792723Salfredstatic void msg_freehdr(struct msg *msghdr);
882729Sdfr
8959839Speter#ifndef MSGSSZ
9059839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
9159839Speter#endif
9259839Speter#ifndef MSGSEG
9359839Speter#define MSGSEG	2048		/* must be less than 32767 */
9459839Speter#endif
9559839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
9659839Speter#ifndef MSGMNB
9759839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
9859839Speter#endif
9959839Speter#ifndef MSGMNI
10059839Speter#define MSGMNI	40
10159839Speter#endif
10259839Speter#ifndef MSGTQL
10359839Speter#define MSGTQL	40
10459839Speter#endif
10559839Speter
10659839Speter/*
10759839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
10859839Speter * config(1m) man page.
10959839Speter *
11059839Speter * Each message is broken up and stored in segments that are msgssz bytes
11159839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
11259839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
11359839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
11459839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
11559839Speter */
11659839Speterstruct msginfo msginfo = {
11759839Speter                MSGMAX,         /* max chars in a message */
11859839Speter                MSGMNI,         /* # of message queue identifiers */
11959839Speter                MSGMNB,         /* max chars in a queue */
12059839Speter                MSGTQL,         /* max messages in system */
12159839Speter                MSGSSZ,         /* size of a message segment */
12259839Speter                		/* (must be small power of 2 greater than 4) */
12359839Speter                MSGSEG          /* number of message segments */
12459839Speter};
12559839Speter
12659839Speter/*
12759839Speter * macros to convert between msqid_ds's and msqid's.
12859839Speter * (specific to this implementation)
12959839Speter */
13059839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
13159839Speter#define MSQID_IX(id)	((id) & 0xffff)
13259839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
13359839Speter
13459839Speter/*
13559839Speter * The rest of this file is specific to this particular implementation.
13659839Speter */
13759839Speter
13859839Speterstruct msgmap {
13959839Speter	short	next;		/* next segment in buffer */
14059839Speter    				/* -1 -> available */
14159839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
14259839Speter};
14359839Speter
14459839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
14559839Speter
14612819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
14712819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
14859839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
14959839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
15059839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
15159839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
152137613Srwatsonstatic struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
153101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
1542729Sdfr
155205323Skibstatic struct syscall_helper_data msg_syscalls[] = {
156205323Skib	SYSCALL_INIT_HELPER(msgctl),
157205323Skib	SYSCALL_INIT_HELPER(msgget),
158205323Skib	SYSCALL_INIT_HELPER(msgsnd),
159205323Skib	SYSCALL_INIT_HELPER(msgrcv),
160205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
161205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
162205323Skib	SYSCALL_INIT_HELPER(msgsys),
163205323Skib	SYSCALL_INIT_HELPER(freebsd7_msgctl),
164205323Skib#endif
165205323Skib	SYSCALL_INIT_LAST
166205323Skib};
167205323Skib
168205323Skib#ifdef COMPAT_FREEBSD32
169205323Skib#include <compat/freebsd32/freebsd32.h>
170205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
171205323Skib#include <compat/freebsd32/freebsd32_proto.h>
172205323Skib#include <compat/freebsd32/freebsd32_signal.h>
173205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
174205323Skib#include <compat/freebsd32/freebsd32_util.h>
175205323Skib
176205323Skibstatic struct syscall_helper_data msg32_syscalls[] = {
177205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
178205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
179205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
180205323Skib	SYSCALL32_INIT_HELPER(msgget),
181205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
182205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
183205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
184205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
185205323Skib#endif
186205323Skib	SYSCALL_INIT_LAST
187205323Skib};
188205323Skib#endif
189205323Skib
190205323Skibstatic int
19169449Salfredmsginit()
1922729Sdfr{
193205323Skib	int i, error;
1942729Sdfr
19583765Smr	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
19683765Smr	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
19783765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
19883765Smr	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
199139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
200139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
20183765Smr
202111119Simp	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
203111119Simp	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
204111119Simp	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
205137613Srwatson	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
206137613Srwatson	    M_WAITOK);
20759839Speter
2082729Sdfr	/*
2092729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
2102729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
2112729Sdfr	 * or greater than about 256 so ...
2122729Sdfr	 */
2132729Sdfr
2142729Sdfr	i = 8;
2152729Sdfr	while (i < 1024 && i != msginfo.msgssz)
2162729Sdfr		i <<= 1;
2172729Sdfr    	if (i != msginfo.msgssz) {
218100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
219100523Salfred		    msginfo.msgssz));
2202729Sdfr		panic("msginfo.msgssz not a small power of 2");
2212729Sdfr	}
2222729Sdfr
2232729Sdfr	if (msginfo.msgseg > 32767) {
224100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
2252729Sdfr		panic("msginfo.msgseg > 32767");
2262729Sdfr	}
2272729Sdfr
2282729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
2292729Sdfr		if (i > 0)
2302729Sdfr			msgmaps[i-1].next = i;
2312729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
2322729Sdfr	}
2332729Sdfr	free_msgmaps = 0;
2342729Sdfr	nfree_msgmaps = msginfo.msgseg;
2352729Sdfr
2362729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
2372729Sdfr		msghdrs[i].msg_type = 0;
2382729Sdfr		if (i > 0)
2392729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
2402729Sdfr		msghdrs[i].msg_next = NULL;
241140614Srwatson#ifdef MAC
242172930Srwatson		mac_sysvmsg_init(&msghdrs[i]);
243140614Srwatson#endif
2442729Sdfr    	}
2452729Sdfr	free_msghdrs = &msghdrs[0];
2462729Sdfr
2472729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
248137613Srwatson		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
249137613Srwatson		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
250137613Srwatson		msqids[i].u.msg_perm.mode = 0;
251140614Srwatson#ifdef MAC
252172930Srwatson		mac_sysvmsq_init(&msqids[i]);
253140614Srwatson#endif
2542729Sdfr	}
255101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
256205323Skib
257205323Skib	error = syscall_helper_register(msg_syscalls);
258205323Skib	if (error != 0)
259205323Skib		return (error);
260205323Skib#ifdef COMPAT_FREEBSD32
261205323Skib	error = syscall32_helper_register(msg32_syscalls);
262205323Skib	if (error != 0)
263205323Skib		return (error);
264205323Skib#endif
265205323Skib	return (0);
2662729Sdfr}
2672729Sdfr
26869449Salfredstatic int
26969449Salfredmsgunload()
27069449Salfred{
271137613Srwatson	struct msqid_kernel *msqkptr;
27269449Salfred	int msqid;
273140614Srwatson#ifdef MAC
274140614Srwatson	int i;
275140614Srwatson#endif
27669449Salfred
277205323Skib	syscall_helper_unregister(msg_syscalls);
278205323Skib#ifdef COMPAT_FREEBSD32
279205323Skib	syscall32_helper_unregister(msg32_syscalls);
280205323Skib#endif
281205323Skib
28269449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
28369449Salfred		/*
28469449Salfred		 * Look for an unallocated and unlocked msqid_ds.
28569449Salfred		 * msqid_ds's can be locked by msgsnd or msgrcv while
28669449Salfred		 * they are copying the message in/out.  We can't
28769449Salfred		 * re-use the entry until they release it.
28869449Salfred		 */
289137613Srwatson		msqkptr = &msqids[msqid];
290137613Srwatson		if (msqkptr->u.msg_qbytes != 0 ||
291137613Srwatson		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
29269449Salfred			break;
29369449Salfred	}
29469449Salfred	if (msqid != msginfo.msgmni)
29569449Salfred		return (EBUSY);
29669449Salfred
297140614Srwatson#ifdef MAC
298140614Srwatson	for (i = 0; i < msginfo.msgtql; i++)
299172930Srwatson		mac_sysvmsg_destroy(&msghdrs[i]);
300140614Srwatson	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
301172930Srwatson		mac_sysvmsq_destroy(&msqids[msqid]);
302140614Srwatson#endif
30369449Salfred	free(msgpool, M_MSG);
30469449Salfred	free(msgmaps, M_MSG);
30569449Salfred	free(msghdrs, M_MSG);
30669449Salfred	free(msqids, M_MSG);
307101772Salfred	mtx_destroy(&msq_mtx);
30869449Salfred	return (0);
30969449Salfred}
31069449Salfred
31169449Salfred
31269449Salfredstatic int
31369449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
31469449Salfred{
31569449Salfred	int error = 0;
31669449Salfred
31769449Salfred	switch (cmd) {
31869449Salfred	case MOD_LOAD:
319205323Skib		error = msginit();
320205323Skib		if (error != 0)
321205323Skib			msgunload();
32269449Salfred		break;
32369449Salfred	case MOD_UNLOAD:
32469449Salfred		error = msgunload();
32569449Salfred		break;
32669449Salfred	case MOD_SHUTDOWN:
32769449Salfred		break;
32869449Salfred	default:
32969449Salfred		error = EINVAL;
33069449Salfred		break;
33169449Salfred	}
33269449Salfred	return (error);
33369449Salfred}
33469449Salfred
33571038Sdesstatic moduledata_t sysvmsg_mod = {
33671038Sdes	"sysvmsg",
33769449Salfred	&sysvmsg_modload,
33869449Salfred	NULL
33969449Salfred};
34069449Salfred
341194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
34271038SdesMODULE_VERSION(sysvmsg, 1);
34369449Salfred
3442729Sdfrstatic void
3452729Sdfrmsg_freehdr(msghdr)
3462729Sdfr	struct msg *msghdr;
3472729Sdfr{
3482729Sdfr	while (msghdr->msg_ts > 0) {
3492729Sdfr		short next;
3502729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3512729Sdfr			panic("msghdr->msg_spot out of range");
3522729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3532729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3542729Sdfr		free_msgmaps = msghdr->msg_spot;
3552729Sdfr		nfree_msgmaps++;
3562729Sdfr		msghdr->msg_spot = next;
3572729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3582729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3592729Sdfr		else
3602729Sdfr			msghdr->msg_ts = 0;
3612729Sdfr	}
3622729Sdfr	if (msghdr->msg_spot != -1)
3632729Sdfr		panic("msghdr->msg_spot != -1");
3642729Sdfr	msghdr->msg_next = free_msghdrs;
3652729Sdfr	free_msghdrs = msghdr;
366140614Srwatson#ifdef MAC
367172930Srwatson	mac_sysvmsg_cleanup(msghdr);
368140614Srwatson#endif
3692729Sdfr}
3702729Sdfr
37112866Speter#ifndef _SYS_SYSPROTO_H_
3722729Sdfrstruct msgctl_args {
3732729Sdfr	int	msqid;
3742729Sdfr	int	cmd;
37512866Speter	struct	msqid_ds *buf;
3762729Sdfr};
37712866Speter#endif
37812866Speterint
37983366Sjulianmsgctl(td, uap)
38083366Sjulian	struct thread *td;
3812729Sdfr	register struct msgctl_args *uap;
3822729Sdfr{
3832729Sdfr	int msqid = uap->msqid;
3842729Sdfr	int cmd = uap->cmd;
3852729Sdfr	struct msqid_ds msqbuf;
386140839Ssobomax	int error;
387140839Ssobomax
388165403Sjkim	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
389140839Ssobomax	if (cmd == IPC_SET &&
390140839Ssobomax	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
391140839Ssobomax		return (error);
392141471Sjhb	error = kern_msgctl(td, msqid, cmd, &msqbuf);
393140839Ssobomax	if (cmd == IPC_STAT && error == 0)
394141471Sjhb		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
395140839Ssobomax	return (error);
396140839Ssobomax}
397140839Ssobomax
398140839Ssobomaxint
399141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf)
400140839Ssobomax	struct thread *td;
401140839Ssobomax	int msqid;
402140839Ssobomax	int cmd;
403140839Ssobomax	struct msqid_ds *msqbuf;
404140839Ssobomax{
405140839Ssobomax	int rval, error, msqix;
406137613Srwatson	register struct msqid_kernel *msqkptr;
4072729Sdfr
408192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
40991703Sjhb		return (ENOSYS);
41091703Sjhb
411140839Ssobomax	msqix = IPCID_TO_IX(msqid);
4122729Sdfr
413140839Ssobomax	if (msqix < 0 || msqix >= msginfo.msgmni) {
414140839Ssobomax		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
415100523Salfred		    msginfo.msgmni));
416101772Salfred		return (EINVAL);
4172729Sdfr	}
4182729Sdfr
419140839Ssobomax	msqkptr = &msqids[msqix];
4202729Sdfr
421101772Salfred	mtx_lock(&msq_mtx);
422137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
423100523Salfred		DPRINTF(("no such msqid\n"));
42482607Sdillon		error = EINVAL;
42582607Sdillon		goto done2;
4262729Sdfr	}
427140839Ssobomax	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
428100523Salfred		DPRINTF(("wrong sequence number\n"));
42982607Sdillon		error = EINVAL;
43082607Sdillon		goto done2;
4312729Sdfr	}
432140614Srwatson#ifdef MAC
433172930Srwatson	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
434162468Srwatson	if (error != 0)
435140614Srwatson		goto done2;
436140614Srwatson#endif
4372729Sdfr
43882607Sdillon	error = 0;
4392729Sdfr	rval = 0;
4402729Sdfr
4412729Sdfr	switch (cmd) {
4422729Sdfr
4432729Sdfr	case IPC_RMID:
4442729Sdfr	{
4452729Sdfr		struct msg *msghdr;
446137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
44782607Sdillon			goto done2;
448137613Srwatson
449140614Srwatson#ifdef MAC
450140614Srwatson		/*
451140614Srwatson		 * Check that the thread has MAC access permissions to
452140614Srwatson		 * individual msghdrs.  Note: We need to do this in a
453140614Srwatson		 * separate loop because the actual loop alters the
454140614Srwatson		 * msq/msghdr info as it progresses, and there is no going
455140614Srwatson		 * back if half the way through we discover that the
456140614Srwatson		 * thread cannot free a certain msghdr.  The msq will get
457140614Srwatson		 * into an inconsistent state.
458140614Srwatson		 */
459140614Srwatson		for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
460140614Srwatson		    msghdr = msghdr->msg_next) {
461172930Srwatson			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
462162468Srwatson			if (error != 0)
463140614Srwatson				goto done2;
464140614Srwatson		}
465140614Srwatson#endif
466140614Srwatson
4672729Sdfr		/* Free the message headers */
468137613Srwatson		msghdr = msqkptr->u.msg_first;
4692729Sdfr		while (msghdr != NULL) {
4702729Sdfr			struct msg *msghdr_tmp;
4712729Sdfr
4722729Sdfr			/* Free the segments of each message */
473137613Srwatson			msqkptr->u.msg_cbytes -= msghdr->msg_ts;
474137613Srwatson			msqkptr->u.msg_qnum--;
4752729Sdfr			msghdr_tmp = msghdr;
4762729Sdfr			msghdr = msghdr->msg_next;
4772729Sdfr			msg_freehdr(msghdr_tmp);
4782729Sdfr		}
4792729Sdfr
480137613Srwatson		if (msqkptr->u.msg_cbytes != 0)
4812729Sdfr			panic("msg_cbytes is screwed up");
482137613Srwatson		if (msqkptr->u.msg_qnum != 0)
4832729Sdfr			panic("msg_qnum is screwed up");
4842729Sdfr
485137613Srwatson		msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
4862729Sdfr
487140614Srwatson#ifdef MAC
488172930Srwatson		mac_sysvmsq_cleanup(msqkptr);
489140614Srwatson#endif
490140614Srwatson
491137613Srwatson		wakeup(msqkptr);
4922729Sdfr	}
4932729Sdfr
4942729Sdfr		break;
4952729Sdfr
4962729Sdfr	case IPC_SET:
497137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
49882607Sdillon			goto done2;
499140839Ssobomax		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
500170587Srwatson			error = priv_check(td, PRIV_IPC_MSGSIZE);
50182607Sdillon			if (error)
50282607Sdillon				goto done2;
50343426Sphk		}
504140839Ssobomax		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
505100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
506100523Salfred			    "(truncating)\n", msginfo.msgmnb));
507140839Ssobomax			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
5082729Sdfr		}
509140839Ssobomax		if (msqbuf->msg_qbytes == 0) {
510100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
51182607Sdillon			error = EINVAL;		/* non-standard errno! */
51282607Sdillon			goto done2;
5132729Sdfr		}
514140839Ssobomax		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
515140839Ssobomax		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
516137613Srwatson		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
517140839Ssobomax		    (msqbuf->msg_perm.mode & 0777);
518140839Ssobomax		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
519137613Srwatson		msqkptr->u.msg_ctime = time_second;
5202729Sdfr		break;
5212729Sdfr
5222729Sdfr	case IPC_STAT:
523137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
524100523Salfred			DPRINTF(("requester doesn't have read access\n"));
52582607Sdillon			goto done2;
5262729Sdfr		}
527141471Sjhb		*msqbuf = msqkptr->u;
5282729Sdfr		break;
5292729Sdfr
5302729Sdfr	default:
531100523Salfred		DPRINTF(("invalid command %d\n", cmd));
53282607Sdillon		error = EINVAL;
53382607Sdillon		goto done2;
5342729Sdfr	}
5352729Sdfr
53682607Sdillon	if (error == 0)
53783366Sjulian		td->td_retval[0] = rval;
53882607Sdillondone2:
539101772Salfred	mtx_unlock(&msq_mtx);
540141471Sjhb	return (error);
5412729Sdfr}
5422729Sdfr
54312866Speter#ifndef _SYS_SYSPROTO_H_
5442729Sdfrstruct msgget_args {
5452729Sdfr	key_t	key;
5462729Sdfr	int	msgflg;
5472729Sdfr};
54812866Speter#endif
54912866Speterint
55083366Sjulianmsgget(td, uap)
55183366Sjulian	struct thread *td;
5522729Sdfr	register struct msgget_args *uap;
5532729Sdfr{
55482607Sdillon	int msqid, error = 0;
5552729Sdfr	int key = uap->key;
5562729Sdfr	int msgflg = uap->msgflg;
55791703Sjhb	struct ucred *cred = td->td_ucred;
558137613Srwatson	register struct msqid_kernel *msqkptr = NULL;
5592729Sdfr
560100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
5612729Sdfr
562192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
56391703Sjhb		return (ENOSYS);
56491703Sjhb
565101772Salfred	mtx_lock(&msq_mtx);
5662729Sdfr	if (key != IPC_PRIVATE) {
5672729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
568137613Srwatson			msqkptr = &msqids[msqid];
569137613Srwatson			if (msqkptr->u.msg_qbytes != 0 &&
570137613Srwatson			    msqkptr->u.msg_perm.key == key)
5712729Sdfr				break;
5722729Sdfr		}
5732729Sdfr		if (msqid < msginfo.msgmni) {
574100523Salfred			DPRINTF(("found public key\n"));
5752729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
576100523Salfred				DPRINTF(("not exclusive\n"));
57782607Sdillon				error = EEXIST;
57882607Sdillon				goto done2;
5792729Sdfr			}
580137613Srwatson			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
581137613Srwatson			    msgflg & 0700))) {
582100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
583100523Salfred				    msgflg & 0700));
58482607Sdillon				goto done2;
5852729Sdfr			}
586140614Srwatson#ifdef MAC
587172930Srwatson			error = mac_sysvmsq_check_msqget(cred, msqkptr);
588162468Srwatson			if (error != 0)
589140614Srwatson				goto done2;
590140614Srwatson#endif
5912729Sdfr			goto found;
5922729Sdfr		}
5932729Sdfr	}
5942729Sdfr
595100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
5962729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
5972729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
5982729Sdfr			/*
5992729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
6002729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
6012729Sdfr			 * they are copying the message in/out.  We can't
6022729Sdfr			 * re-use the entry until they release it.
6032729Sdfr			 */
604137613Srwatson			msqkptr = &msqids[msqid];
605137613Srwatson			if (msqkptr->u.msg_qbytes == 0 &&
606137613Srwatson			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
6072729Sdfr				break;
6082729Sdfr		}
6092729Sdfr		if (msqid == msginfo.msgmni) {
610100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
61182607Sdillon			error = ENOSPC;
61282607Sdillon			goto done2;
6132729Sdfr		}
614100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
615137613Srwatson		msqkptr->u.msg_perm.key = key;
616137613Srwatson		msqkptr->u.msg_perm.cuid = cred->cr_uid;
617137613Srwatson		msqkptr->u.msg_perm.uid = cred->cr_uid;
618137613Srwatson		msqkptr->u.msg_perm.cgid = cred->cr_gid;
619137613Srwatson		msqkptr->u.msg_perm.gid = cred->cr_gid;
620137613Srwatson		msqkptr->u.msg_perm.mode = (msgflg & 0777);
6212729Sdfr		/* Make sure that the returned msqid is unique */
622137613Srwatson		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
623137613Srwatson		msqkptr->u.msg_first = NULL;
624137613Srwatson		msqkptr->u.msg_last = NULL;
625137613Srwatson		msqkptr->u.msg_cbytes = 0;
626137613Srwatson		msqkptr->u.msg_qnum = 0;
627137613Srwatson		msqkptr->u.msg_qbytes = msginfo.msgmnb;
628137613Srwatson		msqkptr->u.msg_lspid = 0;
629137613Srwatson		msqkptr->u.msg_lrpid = 0;
630137613Srwatson		msqkptr->u.msg_stime = 0;
631137613Srwatson		msqkptr->u.msg_rtime = 0;
632137613Srwatson		msqkptr->u.msg_ctime = time_second;
633140614Srwatson#ifdef MAC
634172930Srwatson		mac_sysvmsq_create(cred, msqkptr);
635140614Srwatson#endif
6362729Sdfr	} else {
637100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
63882607Sdillon		error = ENOENT;
63982607Sdillon		goto done2;
6402729Sdfr	}
6412729Sdfr
6422729Sdfrfound:
6432729Sdfr	/* Construct the unique msqid */
644137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
64582607Sdillondone2:
646101772Salfred	mtx_unlock(&msq_mtx);
64782607Sdillon	return (error);
6482729Sdfr}
6492729Sdfr
65012866Speter#ifndef _SYS_SYSPROTO_H_
6512729Sdfrstruct msgsnd_args {
6522729Sdfr	int	msqid;
653109895Salfred	const void	*msgp;
6542729Sdfr	size_t	msgsz;
6552729Sdfr	int	msgflg;
6562729Sdfr};
65712866Speter#endif
65812866Speterint
659165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
66083366Sjulian	struct thread *td;
661165403Sjkim	int msqid;
662165403Sjkim	const void *msgp;	/* XXX msgp is actually mtext. */
663165403Sjkim	size_t msgsz;
664165403Sjkim	int msgflg;
665165403Sjkim	long mtype;
6662729Sdfr{
667165403Sjkim	int msqix, segs_needed, error = 0;
668137613Srwatson	register struct msqid_kernel *msqkptr;
6692729Sdfr	register struct msg *msghdr;
6702729Sdfr	short next;
6712729Sdfr
672192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
67391703Sjhb		return (ENOSYS);
67491703Sjhb
675101772Salfred	mtx_lock(&msq_mtx);
676165403Sjkim	msqix = IPCID_TO_IX(msqid);
6772729Sdfr
678165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
679165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
680100523Salfred		    msginfo.msgmni));
68182607Sdillon		error = EINVAL;
68282607Sdillon		goto done2;
6832729Sdfr	}
6842729Sdfr
685165403Sjkim	msqkptr = &msqids[msqix];
686137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
687100523Salfred		DPRINTF(("no such message queue id\n"));
68882607Sdillon		error = EINVAL;
68982607Sdillon		goto done2;
6902729Sdfr	}
691165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
692100523Salfred		DPRINTF(("wrong sequence number\n"));
69382607Sdillon		error = EINVAL;
69482607Sdillon		goto done2;
6952729Sdfr	}
6962729Sdfr
697137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
698100523Salfred		DPRINTF(("requester doesn't have write access\n"));
69982607Sdillon		goto done2;
7002729Sdfr	}
7012729Sdfr
702140614Srwatson#ifdef MAC
703172930Srwatson	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
704162468Srwatson	if (error != 0)
705140614Srwatson		goto done2;
706140614Srwatson#endif
707140614Srwatson
7082729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
709165403Sjkim	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
710165403Sjkim	    msginfo.msgssz, segs_needed));
7112729Sdfr	for (;;) {
7122729Sdfr		int need_more_resources = 0;
7132729Sdfr
7142729Sdfr		/*
7152729Sdfr		 * check msgsz
7162729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
7172729Sdfr		 */
7182729Sdfr
719137613Srwatson		if (msgsz > msqkptr->u.msg_qbytes) {
720137613Srwatson			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
72182607Sdillon			error = EINVAL;
72282607Sdillon			goto done2;
7232729Sdfr		}
7242729Sdfr
725137613Srwatson		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
726100523Salfred			DPRINTF(("msqid is locked\n"));
7272729Sdfr			need_more_resources = 1;
7282729Sdfr		}
729137613Srwatson		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
730100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
7312729Sdfr			need_more_resources = 1;
7322729Sdfr		}
7332729Sdfr		if (segs_needed > nfree_msgmaps) {
734100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
7352729Sdfr			need_more_resources = 1;
7362729Sdfr		}
7372729Sdfr		if (free_msghdrs == NULL) {
738100523Salfred			DPRINTF(("no more msghdrs\n"));
7392729Sdfr			need_more_resources = 1;
7402729Sdfr		}
7412729Sdfr
7422729Sdfr		if (need_more_resources) {
7432729Sdfr			int we_own_it;
7442729Sdfr
7452729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
746100523Salfred				DPRINTF(("need more resources but caller "
747100523Salfred				    "doesn't want to wait\n"));
74882607Sdillon				error = EAGAIN;
74982607Sdillon				goto done2;
7502729Sdfr			}
7512729Sdfr
752137613Srwatson			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
753100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
7542729Sdfr				we_own_it = 0;
7552729Sdfr			} else {
7562729Sdfr				/* Force later arrivals to wait for our
7572729Sdfr				   request */
758100523Salfred				DPRINTF(("we own the msqid_ds\n"));
759137613Srwatson				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
7602729Sdfr				we_own_it = 1;
7612729Sdfr			}
762164368Sjkim			DPRINTF(("msgsnd:  goodnight\n"));
763137613Srwatson			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
764164368Sjkim			    "msgsnd", hz);
765164368Sjkim			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
7662729Sdfr			if (we_own_it)
767137613Srwatson				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
768164368Sjkim			if (error == EWOULDBLOCK) {
769164368Sjkim				DPRINTF(("msgsnd:  timed out\n"));
770164368Sjkim				continue;
771164368Sjkim			}
77282607Sdillon			if (error != 0) {
773100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
77482607Sdillon				error = EINTR;
77582607Sdillon				goto done2;
7762729Sdfr			}
7772729Sdfr
7782729Sdfr			/*
7792729Sdfr			 * Make sure that the msq queue still exists
7802729Sdfr			 */
7812729Sdfr
782137613Srwatson			if (msqkptr->u.msg_qbytes == 0) {
783100523Salfred				DPRINTF(("msqid deleted\n"));
78482607Sdillon				error = EIDRM;
78582607Sdillon				goto done2;
7862729Sdfr			}
7872729Sdfr
7882729Sdfr		} else {
789100523Salfred			DPRINTF(("got all the resources that we need\n"));
7902729Sdfr			break;
7912729Sdfr		}
7922729Sdfr	}
7932729Sdfr
7942729Sdfr	/*
7952729Sdfr	 * We have the resources that we need.
7962729Sdfr	 * Make sure!
7972729Sdfr	 */
7982729Sdfr
799137613Srwatson	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
8002729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
8012729Sdfr	if (segs_needed > nfree_msgmaps)
8022729Sdfr		panic("segs_needed > nfree_msgmaps");
803137613Srwatson	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
8042729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
8052729Sdfr	if (free_msghdrs == NULL)
8062729Sdfr		panic("no more msghdrs");
8072729Sdfr
8082729Sdfr	/*
8092729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
8102729Sdfr	 * message
8112729Sdfr	 */
8122729Sdfr
813137613Srwatson	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
8142729Sdfr		panic("msqid_ds is already locked");
815137613Srwatson	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8162729Sdfr
8172729Sdfr	/*
8182729Sdfr	 * Allocate a message header
8192729Sdfr	 */
8202729Sdfr
8212729Sdfr	msghdr = free_msghdrs;
8222729Sdfr	free_msghdrs = msghdr->msg_next;
8232729Sdfr	msghdr->msg_spot = -1;
8242729Sdfr	msghdr->msg_ts = msgsz;
825165403Sjkim	msghdr->msg_type = mtype;
826140614Srwatson#ifdef MAC
827140614Srwatson	/*
828172930Srwatson	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
829140614Srwatson	 * immediately?  Or, should it be checked just before the msg is
830140614Srwatson	 * enqueued in the msgq (as it is done now)?
831140614Srwatson	 */
832172930Srwatson	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
833140614Srwatson#endif
8342729Sdfr
8352729Sdfr	/*
8362729Sdfr	 * Allocate space for the message
8372729Sdfr	 */
8382729Sdfr
8392729Sdfr	while (segs_needed > 0) {
8402729Sdfr		if (nfree_msgmaps <= 0)
8412729Sdfr			panic("not enough msgmaps");
8422729Sdfr		if (free_msgmaps == -1)
8432729Sdfr			panic("nil free_msgmaps");
8442729Sdfr		next = free_msgmaps;
8452729Sdfr		if (next <= -1)
8462729Sdfr			panic("next too low #1");
8472729Sdfr		if (next >= msginfo.msgseg)
8482729Sdfr			panic("next out of range #1");
849100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
8502729Sdfr		free_msgmaps = msgmaps[next].next;
8512729Sdfr		nfree_msgmaps--;
8522729Sdfr		msgmaps[next].next = msghdr->msg_spot;
8532729Sdfr		msghdr->msg_spot = next;
8542729Sdfr		segs_needed--;
8552729Sdfr	}
8562729Sdfr
8572729Sdfr	/*
8582729Sdfr	 * Validate the message type
8592729Sdfr	 */
8602729Sdfr
8612729Sdfr	if (msghdr->msg_type < 1) {
8622729Sdfr		msg_freehdr(msghdr);
863137613Srwatson		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
864137613Srwatson		wakeup(msqkptr);
865165403Sjkim		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
86682607Sdillon		error = EINVAL;
86782607Sdillon		goto done2;
8682729Sdfr	}
8692729Sdfr
8702729Sdfr	/*
8712729Sdfr	 * Copy in the message body
8722729Sdfr	 */
8732729Sdfr
8742729Sdfr	next = msghdr->msg_spot;
8752729Sdfr	while (msgsz > 0) {
8762729Sdfr		size_t tlen;
8772729Sdfr		if (msgsz > msginfo.msgssz)
8782729Sdfr			tlen = msginfo.msgssz;
8792729Sdfr		else
8802729Sdfr			tlen = msgsz;
8812729Sdfr		if (next <= -1)
8822729Sdfr			panic("next too low #2");
8832729Sdfr		if (next >= msginfo.msgseg)
8842729Sdfr			panic("next out of range #2");
885101772Salfred		mtx_unlock(&msq_mtx);
886165403Sjkim		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
8872729Sdfr		    tlen)) != 0) {
888101772Salfred			mtx_lock(&msq_mtx);
889100523Salfred			DPRINTF(("error %d copying in message segment\n",
890100523Salfred			    error));
8912729Sdfr			msg_freehdr(msghdr);
892137613Srwatson			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
893137613Srwatson			wakeup(msqkptr);
89482607Sdillon			goto done2;
8952729Sdfr		}
896101772Salfred		mtx_lock(&msq_mtx);
8972729Sdfr		msgsz -= tlen;
898165403Sjkim		msgp = (const char *)msgp + tlen;
8992729Sdfr		next = msgmaps[next].next;
9002729Sdfr	}
9012729Sdfr	if (next != -1)
9022729Sdfr		panic("didn't use all the msg segments");
9032729Sdfr
9042729Sdfr	/*
9052729Sdfr	 * We've got the message.  Unlock the msqid_ds.
9062729Sdfr	 */
9072729Sdfr
908137613Srwatson	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
9092729Sdfr
9102729Sdfr	/*
9112729Sdfr	 * Make sure that the msqid_ds is still allocated.
9122729Sdfr	 */
9132729Sdfr
914137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
9152729Sdfr		msg_freehdr(msghdr);
916137613Srwatson		wakeup(msqkptr);
91782607Sdillon		error = EIDRM;
91882607Sdillon		goto done2;
9192729Sdfr	}
9202729Sdfr
921140614Srwatson#ifdef MAC
9222729Sdfr	/*
923140614Srwatson	 * Note: Since the task/thread allocates the msghdr and usually
924140614Srwatson	 * primes it with its own MAC label, for a majority of policies, it
925140614Srwatson	 * won't be necessary to check whether the msghdr has access
926172930Srwatson	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
927140614Srwatson	 * suffice in that case.  However, this hook may be required where
928140614Srwatson	 * individual policies derive a non-identical label for the msghdr
929140614Srwatson	 * from the current thread label and may want to check the msghdr
930140614Srwatson	 * enqueue permissions, along with read/write permissions to the
931140614Srwatson	 * msgq.
932140614Srwatson	 */
933172930Srwatson	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
934140614Srwatson	if (error != 0) {
935140614Srwatson		msg_freehdr(msghdr);
936140614Srwatson		wakeup(msqkptr);
937140614Srwatson		goto done2;
938140614Srwatson	}
939140614Srwatson#endif
940140614Srwatson
941140614Srwatson	/*
9422729Sdfr	 * Put the message into the queue
9432729Sdfr	 */
944137613Srwatson	if (msqkptr->u.msg_first == NULL) {
945137613Srwatson		msqkptr->u.msg_first = msghdr;
946137613Srwatson		msqkptr->u.msg_last = msghdr;
9472729Sdfr	} else {
948137613Srwatson		msqkptr->u.msg_last->msg_next = msghdr;
949137613Srwatson		msqkptr->u.msg_last = msghdr;
9502729Sdfr	}
951137613Srwatson	msqkptr->u.msg_last->msg_next = NULL;
9522729Sdfr
953137613Srwatson	msqkptr->u.msg_cbytes += msghdr->msg_ts;
954137613Srwatson	msqkptr->u.msg_qnum++;
955137613Srwatson	msqkptr->u.msg_lspid = td->td_proc->p_pid;
956137613Srwatson	msqkptr->u.msg_stime = time_second;
9572729Sdfr
958137613Srwatson	wakeup(msqkptr);
95983366Sjulian	td->td_retval[0] = 0;
96082607Sdillondone2:
961101772Salfred	mtx_unlock(&msq_mtx);
96282607Sdillon	return (error);
9632729Sdfr}
9642729Sdfr
965165403Sjkimint
966165403Sjkimmsgsnd(td, uap)
967165403Sjkim	struct thread *td;
968165403Sjkim	register struct msgsnd_args *uap;
969165403Sjkim{
970165403Sjkim	int error;
971165403Sjkim	long mtype;
972165403Sjkim
973165403Sjkim	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
974165403Sjkim	    uap->msgsz, uap->msgflg));
975165403Sjkim
976165403Sjkim	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
977165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
978165403Sjkim		return (error);
979165403Sjkim	}
980165403Sjkim	return (kern_msgsnd(td, uap->msqid,
981165403Sjkim	    (const char *)uap->msgp + sizeof(mtype),
982165403Sjkim	    uap->msgsz, uap->msgflg, mtype));
983165403Sjkim}
984165403Sjkim
98512866Speter#ifndef _SYS_SYSPROTO_H_
9862729Sdfrstruct msgrcv_args {
9872729Sdfr	int	msqid;
9882729Sdfr	void	*msgp;
9892729Sdfr	size_t	msgsz;
9902729Sdfr	long	msgtyp;
9912729Sdfr	int	msgflg;
9922729Sdfr};
99312866Speter#endif
99412866Speterint
995165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype)
99683366Sjulian	struct thread *td;
997165403Sjkim	int msqid;
998165403Sjkim	void *msgp;	/* XXX msgp is actually mtext. */
999165403Sjkim	size_t msgsz;
1000165403Sjkim	long msgtyp;
1001165403Sjkim	int msgflg;
1002165403Sjkim	long *mtype;
10032729Sdfr{
10042729Sdfr	size_t len;
1005137613Srwatson	register struct msqid_kernel *msqkptr;
10062729Sdfr	register struct msg *msghdr;
1007165403Sjkim	int msqix, error = 0;
10082729Sdfr	short next;
10092729Sdfr
1010192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
101191703Sjhb		return (ENOSYS);
101291703Sjhb
1013165403Sjkim	msqix = IPCID_TO_IX(msqid);
10142729Sdfr
1015165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
1016165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1017100523Salfred		    msginfo.msgmni));
1018101772Salfred		return (EINVAL);
10192729Sdfr	}
10202729Sdfr
1021165403Sjkim	msqkptr = &msqids[msqix];
1022101772Salfred	mtx_lock(&msq_mtx);
1023137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
1024100523Salfred		DPRINTF(("no such message queue id\n"));
102582607Sdillon		error = EINVAL;
102682607Sdillon		goto done2;
10272729Sdfr	}
1028165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1029100523Salfred		DPRINTF(("wrong sequence number\n"));
103082607Sdillon		error = EINVAL;
103182607Sdillon		goto done2;
10322729Sdfr	}
10332729Sdfr
1034137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1035100523Salfred		DPRINTF(("requester doesn't have read access\n"));
103682607Sdillon		goto done2;
10372729Sdfr	}
10382729Sdfr
1039140614Srwatson#ifdef MAC
1040172930Srwatson	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1041162468Srwatson	if (error != 0)
1042140614Srwatson		goto done2;
1043140614Srwatson#endif
1044140614Srwatson
10452729Sdfr	msghdr = NULL;
10462729Sdfr	while (msghdr == NULL) {
10472729Sdfr		if (msgtyp == 0) {
1048137613Srwatson			msghdr = msqkptr->u.msg_first;
10492729Sdfr			if (msghdr != NULL) {
10502729Sdfr				if (msgsz < msghdr->msg_ts &&
10512729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
1052100523Salfred					DPRINTF(("first message on the queue "
1053165403Sjkim					    "is too big (want %zu, got %d)\n",
1054100523Salfred					    msgsz, msghdr->msg_ts));
105582607Sdillon					error = E2BIG;
105682607Sdillon					goto done2;
10572729Sdfr				}
1058140614Srwatson#ifdef MAC
1059172930Srwatson				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1060140614Srwatson				    msghdr);
1061162468Srwatson				if (error != 0)
1062140614Srwatson					goto done2;
1063140614Srwatson#endif
1064137613Srwatson				if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1065137613Srwatson					msqkptr->u.msg_first = NULL;
1066137613Srwatson					msqkptr->u.msg_last = NULL;
10672729Sdfr				} else {
1068137613Srwatson					msqkptr->u.msg_first = msghdr->msg_next;
1069137613Srwatson					if (msqkptr->u.msg_first == NULL)
10702729Sdfr						panic("msg_first/last screwed up #1");
10712729Sdfr				}
10722729Sdfr			}
10732729Sdfr		} else {
10742729Sdfr			struct msg *previous;
10752729Sdfr			struct msg **prev;
10762729Sdfr
10772729Sdfr			previous = NULL;
1078137613Srwatson			prev = &(msqkptr->u.msg_first);
10792729Sdfr			while ((msghdr = *prev) != NULL) {
10802729Sdfr				/*
10812729Sdfr				 * Is this message's type an exact match or is
10822729Sdfr				 * this message's type less than or equal to
10832729Sdfr				 * the absolute value of a negative msgtyp?
10842729Sdfr				 * Note that the second half of this test can
10852729Sdfr				 * NEVER be true if msgtyp is positive since
10862729Sdfr				 * msg_type is always positive!
10872729Sdfr				 */
10882729Sdfr
10892729Sdfr				if (msgtyp == msghdr->msg_type ||
10902729Sdfr				    msghdr->msg_type <= -msgtyp) {
1091165403Sjkim					DPRINTF(("found message type %ld, "
1092165403Sjkim					    "requested %ld\n",
1093100523Salfred					    msghdr->msg_type, msgtyp));
10942729Sdfr					if (msgsz < msghdr->msg_ts &&
10952729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
1096100523Salfred						DPRINTF(("requested message "
1097100523Salfred						    "on the queue is too big "
1098165403Sjkim						    "(want %zu, got %hu)\n",
1099100523Salfred						    msgsz, msghdr->msg_ts));
110082607Sdillon						error = E2BIG;
110182607Sdillon						goto done2;
11022729Sdfr					}
1103140614Srwatson#ifdef MAC
1104172930Srwatson					error = mac_sysvmsq_check_msgrcv(
1105140614Srwatson					    td->td_ucred, msghdr);
1106162468Srwatson					if (error != 0)
1107140614Srwatson						goto done2;
1108140614Srwatson#endif
11092729Sdfr					*prev = msghdr->msg_next;
1110137613Srwatson					if (msghdr == msqkptr->u.msg_last) {
11112729Sdfr						if (previous == NULL) {
11122729Sdfr							if (prev !=
1113137613Srwatson							    &msqkptr->u.msg_first)
11142729Sdfr								panic("msg_first/last screwed up #2");
1115137613Srwatson							msqkptr->u.msg_first =
11162729Sdfr							    NULL;
1117137613Srwatson							msqkptr->u.msg_last =
11182729Sdfr							    NULL;
11192729Sdfr						} else {
11202729Sdfr							if (prev ==
1121137613Srwatson							    &msqkptr->u.msg_first)
11222729Sdfr								panic("msg_first/last screwed up #3");
1123137613Srwatson							msqkptr->u.msg_last =
11242729Sdfr							    previous;
11252729Sdfr						}
11262729Sdfr					}
11272729Sdfr					break;
11282729Sdfr				}
11292729Sdfr				previous = msghdr;
11302729Sdfr				prev = &(msghdr->msg_next);
11312729Sdfr			}
11322729Sdfr		}
11332729Sdfr
11342729Sdfr		/*
11352729Sdfr		 * We've either extracted the msghdr for the appropriate
11362729Sdfr		 * message or there isn't one.
11372729Sdfr		 * If there is one then bail out of this loop.
11382729Sdfr		 */
11392729Sdfr
11402729Sdfr		if (msghdr != NULL)
11412729Sdfr			break;
11422729Sdfr
11432729Sdfr		/*
11442729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
11452729Sdfr		 */
11462729Sdfr
11472729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1148165403Sjkim			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1149100523Salfred			    msgtyp));
11502729Sdfr			/* The SVID says to return ENOMSG. */
115182607Sdillon			error = ENOMSG;
115282607Sdillon			goto done2;
11532729Sdfr		}
11542729Sdfr
11552729Sdfr		/*
11562729Sdfr		 * Wait for something to happen
11572729Sdfr		 */
11582729Sdfr
1159100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1160137613Srwatson		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1161164368Sjkim		    "msgrcv", 0);
1162100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
11632729Sdfr
116482607Sdillon		if (error != 0) {
1165164368Sjkim			DPRINTF(("msgrcv:  interrupted system call\n"));
116682607Sdillon			error = EINTR;
116782607Sdillon			goto done2;
11682729Sdfr		}
11692729Sdfr
11702729Sdfr		/*
11712729Sdfr		 * Make sure that the msq queue still exists
11722729Sdfr		 */
11732729Sdfr
1174137613Srwatson		if (msqkptr->u.msg_qbytes == 0 ||
1175165403Sjkim		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1176100523Salfred			DPRINTF(("msqid deleted\n"));
117782607Sdillon			error = EIDRM;
117882607Sdillon			goto done2;
11792729Sdfr		}
11802729Sdfr	}
11812729Sdfr
11822729Sdfr	/*
11832729Sdfr	 * Return the message to the user.
11842729Sdfr	 *
11852729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
11862729Sdfr	 */
11872729Sdfr
1188137613Srwatson	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1189137613Srwatson	msqkptr->u.msg_qnum--;
1190137613Srwatson	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1191137613Srwatson	msqkptr->u.msg_rtime = time_second;
11922729Sdfr
11932729Sdfr	/*
11942729Sdfr	 * Make msgsz the actual amount that we'll be returning.
11952729Sdfr	 * Note that this effectively truncates the message if it is too long
11962729Sdfr	 * (since msgsz is never increased).
11972729Sdfr	 */
11982729Sdfr
1199165403Sjkim	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1200100523Salfred	    msghdr->msg_ts));
12012729Sdfr	if (msgsz > msghdr->msg_ts)
12022729Sdfr		msgsz = msghdr->msg_ts;
1203165403Sjkim	*mtype = msghdr->msg_type;
12042729Sdfr
12052729Sdfr	/*
12062729Sdfr	 * Return the segments to the user
12072729Sdfr	 */
12082729Sdfr
12092729Sdfr	next = msghdr->msg_spot;
12102729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
12112729Sdfr		size_t tlen;
12122729Sdfr
121345921Ssada		if (msgsz - len > msginfo.msgssz)
12142729Sdfr			tlen = msginfo.msgssz;
12152729Sdfr		else
121645921Ssada			tlen = msgsz - len;
12172729Sdfr		if (next <= -1)
12182729Sdfr			panic("next too low #3");
12192729Sdfr		if (next >= msginfo.msgseg)
12202729Sdfr			panic("next out of range #3");
1221101772Salfred		mtx_unlock(&msq_mtx);
1222165403Sjkim		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1223101772Salfred		mtx_lock(&msq_mtx);
122482607Sdillon		if (error != 0) {
1225100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1226100523Salfred			    error));
12272729Sdfr			msg_freehdr(msghdr);
1228137613Srwatson			wakeup(msqkptr);
122982607Sdillon			goto done2;
12302729Sdfr		}
1231165403Sjkim		msgp = (char *)msgp + tlen;
12322729Sdfr		next = msgmaps[next].next;
12332729Sdfr	}
12342729Sdfr
12352729Sdfr	/*
12362729Sdfr	 * Done, return the actual number of bytes copied out.
12372729Sdfr	 */
12382729Sdfr
12392729Sdfr	msg_freehdr(msghdr);
1240137613Srwatson	wakeup(msqkptr);
124183366Sjulian	td->td_retval[0] = msgsz;
124282607Sdillondone2:
1243101772Salfred	mtx_unlock(&msq_mtx);
124482607Sdillon	return (error);
12452729Sdfr}
124677461Sdd
1247165403Sjkimint
1248165403Sjkimmsgrcv(td, uap)
1249165403Sjkim	struct thread *td;
1250165403Sjkim	register struct msgrcv_args *uap;
1251165403Sjkim{
1252165403Sjkim	int error;
1253165403Sjkim	long mtype;
1254165403Sjkim
1255165403Sjkim	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1256165403Sjkim	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1257165403Sjkim
1258165403Sjkim	if ((error = kern_msgrcv(td, uap->msqid,
1259165403Sjkim	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1260165403Sjkim	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1261165403Sjkim		return (error);
1262165403Sjkim	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1263165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1264165403Sjkim	return (error);
1265165403Sjkim}
1266165403Sjkim
126777461Sddstatic int
126877461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
126977461Sdd{
127077461Sdd
127177461Sdd	return (SYSCTL_OUT(req, msqids,
1272137613Srwatson	    sizeof(struct msqid_kernel) * msginfo.msgmni));
127377461Sdd}
127477461Sdd
1275141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1276141710Scsjp    "Maximum message size");
1277141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1278141710Scsjp    "Number of message queue identifiers");
1279141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1280141710Scsjp    "Maximum number of bytes in a queue");
1281141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1282141710Scsjp    "Maximum number of messages in the system");
1283141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1284141710Scsjp    "Size of a message segment");
1285141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1286141710Scsjp    "Number of message segments");
1287217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
128877461Sdd    NULL, 0, sysctl_msqids, "", "Message queue IDs");
1289194894Sjhb
1290205323Skib#ifdef COMPAT_FREEBSD32
1291205323Skibint
1292205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1293205323Skib{
1294205323Skib
1295194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1296194894Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1297205323Skib	switch (uap->which) {
1298205323Skib	case 0:
1299205323Skib		return (freebsd7_freebsd32_msgctl(td,
1300205323Skib		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1301205323Skib	case 2:
1302205323Skib		return (freebsd32_msgsnd(td,
1303205323Skib		    (struct freebsd32_msgsnd_args *)&uap->a2));
1304205323Skib	case 3:
1305205323Skib		return (freebsd32_msgrcv(td,
1306205323Skib		    (struct freebsd32_msgrcv_args *)&uap->a2));
1307205323Skib	default:
1308205323Skib		return (msgsys(td, (struct msgsys_args *)uap));
1309205323Skib	}
1310205323Skib#else
1311205323Skib	return (nosys(td, NULL));
1312205323Skib#endif
1313205323Skib}
1314194894Sjhb
1315205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1316205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1317205323Skibint
1318205323Skibfreebsd7_freebsd32_msgctl(struct thread *td,
1319205323Skib    struct freebsd7_freebsd32_msgctl_args *uap)
1320205323Skib{
1321205323Skib	struct msqid_ds msqbuf;
1322205323Skib	struct msqid_ds32_old msqbuf32;
1323205323Skib	int error;
1324205323Skib
1325205323Skib	if (uap->cmd == IPC_SET) {
1326205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1327205323Skib		if (error)
1328205323Skib			return (error);
1329205323Skib		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1330205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1331205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1332205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1333205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1334205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1335205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1336205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1337205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1338205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1339205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1340205323Skib	}
1341205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1342205323Skib	if (error)
1343205323Skib		return (error);
1344205323Skib	if (uap->cmd == IPC_STAT) {
1345205323Skib		bzero(&msqbuf32, sizeof(msqbuf32));
1346205323Skib		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1347205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1348205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1349205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1350205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1351205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1352205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1353205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1354205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1355205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1356205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1357205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1358205323Skib	}
1359205323Skib	return (error);
1360205323Skib}
1361205323Skib#endif
1362205323Skib
1363205323Skibint
1364205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1365205323Skib{
1366205323Skib	struct msqid_ds msqbuf;
1367205323Skib	struct msqid_ds32 msqbuf32;
1368205323Skib	int error;
1369205323Skib
1370205323Skib	if (uap->cmd == IPC_SET) {
1371205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1372205323Skib		if (error)
1373205323Skib			return (error);
1374205323Skib		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1375205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1376205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1377205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1378205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1379205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1380205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1381205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1382205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1383205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1384205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1385205323Skib	}
1386205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1387205323Skib	if (error)
1388205323Skib		return (error);
1389205323Skib	if (uap->cmd == IPC_STAT) {
1390205323Skib		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1391205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1392205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1393205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1394205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1395205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1396205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1397205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1398205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1399205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1400205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1401205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1402205323Skib	}
1403205323Skib	return (error);
1404205323Skib}
1405205323Skib
1406205323Skibint
1407205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1408205323Skib{
1409205323Skib	const void *msgp;
1410205323Skib	long mtype;
1411205323Skib	int32_t mtype32;
1412205323Skib	int error;
1413205323Skib
1414205323Skib	msgp = PTRIN(uap->msgp);
1415205323Skib	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1416205323Skib		return (error);
1417205323Skib	mtype = mtype32;
1418205323Skib	return (kern_msgsnd(td, uap->msqid,
1419205323Skib	    (const char *)msgp + sizeof(mtype32),
1420205323Skib	    uap->msgsz, uap->msgflg, mtype));
1421205323Skib}
1422205323Skib
1423205323Skibint
1424205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1425205323Skib{
1426205323Skib	void *msgp;
1427205323Skib	long mtype;
1428205323Skib	int32_t mtype32;
1429205323Skib	int error;
1430205323Skib
1431205323Skib	msgp = PTRIN(uap->msgp);
1432205323Skib	if ((error = kern_msgrcv(td, uap->msqid,
1433205323Skib	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1434205323Skib	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1435205323Skib		return (error);
1436205323Skib	mtype32 = (int32_t)mtype;
1437205323Skib	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1438205323Skib}
1439205323Skib#endif
1440205323Skib
1441205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1442205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1443205323Skib
1444194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1445194894Sjhbstatic sy_call_t *msgcalls[] = {
1446194910Sjhb	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget,
1447194894Sjhb	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
1448194894Sjhb};
1449194894Sjhb
1450194894Sjhb/*
1451194894Sjhb * Entry point for all MSG calls.
1452194894Sjhb */
1453194894Sjhbint
1454194894Sjhbmsgsys(td, uap)
1455194894Sjhb	struct thread *td;
1456194894Sjhb	/* XXX actually varargs. */
1457194894Sjhb	struct msgsys_args /* {
1458194894Sjhb		int	which;
1459194894Sjhb		int	a2;
1460194894Sjhb		int	a3;
1461194894Sjhb		int	a4;
1462194894Sjhb		int	a5;
1463194894Sjhb		int	a6;
1464194894Sjhb	} */ *uap;
1465194894Sjhb{
1466194894Sjhb	int error;
1467194894Sjhb
1468194894Sjhb	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1469194894Sjhb		return (ENOSYS);
1470194894Sjhb	if (uap->which < 0 ||
1471194894Sjhb	    uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
1472194894Sjhb		return (EINVAL);
1473194894Sjhb	error = (*msgcalls[uap->which])(td, &uap->a2);
1474194894Sjhb	return (error);
1475194894Sjhb}
1476194910Sjhb
1477205323Skib#ifndef CP
1478194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1479205323Skib#endif
1480194910Sjhb
1481194910Sjhb#ifndef _SYS_SYSPROTO_H_
1482194910Sjhbstruct freebsd7_msgctl_args {
1483194910Sjhb	int	msqid;
1484194910Sjhb	int	cmd;
1485194910Sjhb	struct	msqid_ds_old *buf;
1486194910Sjhb};
1487194910Sjhb#endif
1488194910Sjhbint
1489194910Sjhbfreebsd7_msgctl(td, uap)
1490194910Sjhb	struct thread *td;
1491194910Sjhb	struct freebsd7_msgctl_args *uap;
1492194910Sjhb{
1493194910Sjhb	struct msqid_ds_old msqold;
1494194910Sjhb	struct msqid_ds msqbuf;
1495194910Sjhb	int error;
1496194910Sjhb
1497194910Sjhb	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1498194910Sjhb	    uap->buf));
1499194910Sjhb	if (uap->cmd == IPC_SET) {
1500194910Sjhb		error = copyin(uap->buf, &msqold, sizeof(msqold));
1501194910Sjhb		if (error)
1502194910Sjhb			return (error);
1503194910Sjhb		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1504194910Sjhb		CP(msqold, msqbuf, msg_first);
1505194910Sjhb		CP(msqold, msqbuf, msg_last);
1506194910Sjhb		CP(msqold, msqbuf, msg_cbytes);
1507194910Sjhb		CP(msqold, msqbuf, msg_qnum);
1508194910Sjhb		CP(msqold, msqbuf, msg_qbytes);
1509194910Sjhb		CP(msqold, msqbuf, msg_lspid);
1510194910Sjhb		CP(msqold, msqbuf, msg_lrpid);
1511194910Sjhb		CP(msqold, msqbuf, msg_stime);
1512194910Sjhb		CP(msqold, msqbuf, msg_rtime);
1513194910Sjhb		CP(msqold, msqbuf, msg_ctime);
1514194910Sjhb	}
1515194910Sjhb	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1516194910Sjhb	if (error)
1517194910Sjhb		return (error);
1518194910Sjhb	if (uap->cmd == IPC_STAT) {
1519194910Sjhb		bzero(&msqold, sizeof(msqold));
1520194910Sjhb		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1521194910Sjhb		CP(msqbuf, msqold, msg_first);
1522194910Sjhb		CP(msqbuf, msqold, msg_last);
1523194910Sjhb		CP(msqbuf, msqold, msg_cbytes);
1524194910Sjhb		CP(msqbuf, msqold, msg_qnum);
1525194910Sjhb		CP(msqbuf, msqold, msg_qbytes);
1526194910Sjhb		CP(msqbuf, msqold, msg_lspid);
1527194910Sjhb		CP(msqbuf, msqold, msg_lrpid);
1528194910Sjhb		CP(msqbuf, msqold, msg_stime);
1529194910Sjhb		CP(msqbuf, msqold, msg_rtime);
1530194910Sjhb		CP(msqbuf, msqold, msg_ctime);
1531194910Sjhb		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1532194910Sjhb	}
1533194910Sjhb	return (error);
1534194910Sjhb}
1535194910Sjhb
1536194910Sjhb#undef CP
1537194910Sjhb
1538194894Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1539194894Sjhb	   COMPAT_FREEBSD7 */
1540