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: releng/10.3/sys/kern/sysv_msg.c 284665 2015-06-21 06:28:26Z trasz $");
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>
66220398Strasz#include <sys/racct.h>
6769449Salfred#include <sys/syscall.h>
68140839Ssobomax#include <sys/syscallsubr.h>
6911626Sbde#include <sys/sysent.h>
7059839Speter#include <sys/sysctl.h>
7159839Speter#include <sys/malloc.h>
7268024Srwatson#include <sys/jail.h>
732729Sdfr
74163606Srwatson#include <security/mac/mac_framework.h>
75163606Srwatson
76219028SnetchildFEATURE(sysv_msg, "System V message queues support");
77219028Snetchild
7859839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
7959839Speter
80205323Skibstatic int msginit(void);
8192723Salfredstatic int msgunload(void);
8292723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
8310358Sjulian
84225617Skmacy
85100523Salfred#ifdef MSG_DEBUG
86100523Salfred#define DPRINTF(a)	printf a
87100523Salfred#else
88194575Srdivacky#define DPRINTF(a)	(void)0
89100523Salfred#endif
902729Sdfr
9192723Salfredstatic void msg_freehdr(struct msg *msghdr);
922729Sdfr
9359839Speter#ifndef MSGSSZ
9459839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
9559839Speter#endif
9659839Speter#ifndef MSGSEG
9759839Speter#define MSGSEG	2048		/* must be less than 32767 */
9859839Speter#endif
9959839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
10059839Speter#ifndef MSGMNB
10159839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
10259839Speter#endif
10359839Speter#ifndef MSGMNI
10459839Speter#define MSGMNI	40
10559839Speter#endif
10659839Speter#ifndef MSGTQL
10759839Speter#define MSGTQL	40
10859839Speter#endif
10959839Speter
11059839Speter/*
11159839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
11259839Speter * config(1m) man page.
11359839Speter *
11459839Speter * Each message is broken up and stored in segments that are msgssz bytes
11559839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
11659839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
11759839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
11859839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
11959839Speter */
12059839Speterstruct msginfo msginfo = {
12159839Speter                MSGMAX,         /* max chars in a message */
12259839Speter                MSGMNI,         /* # of message queue identifiers */
12359839Speter                MSGMNB,         /* max chars in a queue */
12459839Speter                MSGTQL,         /* max messages in system */
12559839Speter                MSGSSZ,         /* size of a message segment */
12659839Speter                		/* (must be small power of 2 greater than 4) */
12759839Speter                MSGSEG          /* number of message segments */
12859839Speter};
12959839Speter
13059839Speter/*
13159839Speter * macros to convert between msqid_ds's and msqid's.
13259839Speter * (specific to this implementation)
13359839Speter */
13459839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
13559839Speter#define MSQID_IX(id)	((id) & 0xffff)
13659839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
13759839Speter
13859839Speter/*
13959839Speter * The rest of this file is specific to this particular implementation.
14059839Speter */
14159839Speter
14259839Speterstruct msgmap {
14359839Speter	short	next;		/* next segment in buffer */
14459839Speter    				/* -1 -> available */
14559839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
14659839Speter};
14759839Speter
14859839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
14959839Speter
15012819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
15112819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
15259839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
15359839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
15459839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
15559839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
156137613Srwatsonstatic struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
157101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
1582729Sdfr
159205323Skibstatic struct syscall_helper_data msg_syscalls[] = {
160205323Skib	SYSCALL_INIT_HELPER(msgctl),
161205323Skib	SYSCALL_INIT_HELPER(msgget),
162205323Skib	SYSCALL_INIT_HELPER(msgsnd),
163205323Skib	SYSCALL_INIT_HELPER(msgrcv),
164205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
165205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
166205323Skib	SYSCALL_INIT_HELPER(msgsys),
167225617Skmacy	SYSCALL_INIT_HELPER_COMPAT(freebsd7_msgctl),
168205323Skib#endif
169205323Skib	SYSCALL_INIT_LAST
170205323Skib};
171205323Skib
172205323Skib#ifdef COMPAT_FREEBSD32
173205323Skib#include <compat/freebsd32/freebsd32.h>
174205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
175205323Skib#include <compat/freebsd32/freebsd32_proto.h>
176205323Skib#include <compat/freebsd32/freebsd32_signal.h>
177205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
178205323Skib#include <compat/freebsd32/freebsd32_util.h>
179205323Skib
180205323Skibstatic struct syscall_helper_data msg32_syscalls[] = {
181205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
182205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
183205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
184225617Skmacy	SYSCALL32_INIT_HELPER_COMPAT(msgget),
185205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
186205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
187205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
188205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
189205323Skib#endif
190205323Skib	SYSCALL_INIT_LAST
191205323Skib};
192205323Skib#endif
193205323Skib
194205323Skibstatic int
19569449Salfredmsginit()
1962729Sdfr{
197205323Skib	int i, error;
1982729Sdfr
19983765Smr	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
20083765Smr	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
20183765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
20283765Smr	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
203139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
204139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
20583765Smr
206111119Simp	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
207111119Simp	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
208111119Simp	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
209137613Srwatson	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
210137613Srwatson	    M_WAITOK);
21159839Speter
2122729Sdfr	/*
2132729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
2142729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
2152729Sdfr	 * or greater than about 256 so ...
2162729Sdfr	 */
2172729Sdfr
2182729Sdfr	i = 8;
2192729Sdfr	while (i < 1024 && i != msginfo.msgssz)
2202729Sdfr		i <<= 1;
2212729Sdfr    	if (i != msginfo.msgssz) {
222100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
223100523Salfred		    msginfo.msgssz));
2242729Sdfr		panic("msginfo.msgssz not a small power of 2");
2252729Sdfr	}
2262729Sdfr
2272729Sdfr	if (msginfo.msgseg > 32767) {
228100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
2292729Sdfr		panic("msginfo.msgseg > 32767");
2302729Sdfr	}
2312729Sdfr
2322729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
2332729Sdfr		if (i > 0)
2342729Sdfr			msgmaps[i-1].next = i;
2352729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
2362729Sdfr	}
2372729Sdfr	free_msgmaps = 0;
2382729Sdfr	nfree_msgmaps = msginfo.msgseg;
2392729Sdfr
2402729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
2412729Sdfr		msghdrs[i].msg_type = 0;
2422729Sdfr		if (i > 0)
2432729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
2442729Sdfr		msghdrs[i].msg_next = NULL;
245140614Srwatson#ifdef MAC
246172930Srwatson		mac_sysvmsg_init(&msghdrs[i]);
247140614Srwatson#endif
2482729Sdfr    	}
2492729Sdfr	free_msghdrs = &msghdrs[0];
2502729Sdfr
2512729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
252137613Srwatson		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
253137613Srwatson		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
254137613Srwatson		msqids[i].u.msg_perm.mode = 0;
255140614Srwatson#ifdef MAC
256172930Srwatson		mac_sysvmsq_init(&msqids[i]);
257140614Srwatson#endif
2582729Sdfr	}
259101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
260205323Skib
261205323Skib	error = syscall_helper_register(msg_syscalls);
262205323Skib	if (error != 0)
263205323Skib		return (error);
264205323Skib#ifdef COMPAT_FREEBSD32
265205323Skib	error = syscall32_helper_register(msg32_syscalls);
266205323Skib	if (error != 0)
267205323Skib		return (error);
268205323Skib#endif
269205323Skib	return (0);
2702729Sdfr}
2712729Sdfr
27269449Salfredstatic int
27369449Salfredmsgunload()
27469449Salfred{
275137613Srwatson	struct msqid_kernel *msqkptr;
27669449Salfred	int msqid;
277140614Srwatson#ifdef MAC
278140614Srwatson	int i;
279140614Srwatson#endif
28069449Salfred
281205323Skib	syscall_helper_unregister(msg_syscalls);
282205323Skib#ifdef COMPAT_FREEBSD32
283205323Skib	syscall32_helper_unregister(msg32_syscalls);
284205323Skib#endif
285205323Skib
28669449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
28769449Salfred		/*
28869449Salfred		 * Look for an unallocated and unlocked msqid_ds.
28969449Salfred		 * msqid_ds's can be locked by msgsnd or msgrcv while
29069449Salfred		 * they are copying the message in/out.  We can't
29169449Salfred		 * re-use the entry until they release it.
29269449Salfred		 */
293137613Srwatson		msqkptr = &msqids[msqid];
294137613Srwatson		if (msqkptr->u.msg_qbytes != 0 ||
295137613Srwatson		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
29669449Salfred			break;
29769449Salfred	}
29869449Salfred	if (msqid != msginfo.msgmni)
29969449Salfred		return (EBUSY);
30069449Salfred
301140614Srwatson#ifdef MAC
302140614Srwatson	for (i = 0; i < msginfo.msgtql; i++)
303172930Srwatson		mac_sysvmsg_destroy(&msghdrs[i]);
304140614Srwatson	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
305172930Srwatson		mac_sysvmsq_destroy(&msqids[msqid]);
306140614Srwatson#endif
30769449Salfred	free(msgpool, M_MSG);
30869449Salfred	free(msgmaps, M_MSG);
30969449Salfred	free(msghdrs, M_MSG);
31069449Salfred	free(msqids, M_MSG);
311101772Salfred	mtx_destroy(&msq_mtx);
31269449Salfred	return (0);
31369449Salfred}
31469449Salfred
31569449Salfred
31669449Salfredstatic int
31769449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
31869449Salfred{
31969449Salfred	int error = 0;
32069449Salfred
32169449Salfred	switch (cmd) {
32269449Salfred	case MOD_LOAD:
323205323Skib		error = msginit();
324205323Skib		if (error != 0)
325205323Skib			msgunload();
32669449Salfred		break;
32769449Salfred	case MOD_UNLOAD:
32869449Salfred		error = msgunload();
32969449Salfred		break;
33069449Salfred	case MOD_SHUTDOWN:
33169449Salfred		break;
33269449Salfred	default:
33369449Salfred		error = EINVAL;
33469449Salfred		break;
33569449Salfred	}
33669449Salfred	return (error);
33769449Salfred}
33869449Salfred
33971038Sdesstatic moduledata_t sysvmsg_mod = {
34071038Sdes	"sysvmsg",
34169449Salfred	&sysvmsg_modload,
34269449Salfred	NULL
34369449Salfred};
34469449Salfred
345194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
34671038SdesMODULE_VERSION(sysvmsg, 1);
34769449Salfred
3482729Sdfrstatic void
3492729Sdfrmsg_freehdr(msghdr)
3502729Sdfr	struct msg *msghdr;
3512729Sdfr{
3522729Sdfr	while (msghdr->msg_ts > 0) {
3532729Sdfr		short next;
3542729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3552729Sdfr			panic("msghdr->msg_spot out of range");
3562729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3572729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3582729Sdfr		free_msgmaps = msghdr->msg_spot;
3592729Sdfr		nfree_msgmaps++;
3602729Sdfr		msghdr->msg_spot = next;
3612729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3622729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3632729Sdfr		else
3642729Sdfr			msghdr->msg_ts = 0;
3652729Sdfr	}
3662729Sdfr	if (msghdr->msg_spot != -1)
3672729Sdfr		panic("msghdr->msg_spot != -1");
3682729Sdfr	msghdr->msg_next = free_msghdrs;
3692729Sdfr	free_msghdrs = msghdr;
370140614Srwatson#ifdef MAC
371172930Srwatson	mac_sysvmsg_cleanup(msghdr);
372140614Srwatson#endif
3732729Sdfr}
3742729Sdfr
37512866Speter#ifndef _SYS_SYSPROTO_H_
3762729Sdfrstruct msgctl_args {
3772729Sdfr	int	msqid;
3782729Sdfr	int	cmd;
37912866Speter	struct	msqid_ds *buf;
3802729Sdfr};
38112866Speter#endif
38212866Speterint
383225617Skmacysys_msgctl(td, uap)
38483366Sjulian	struct thread *td;
3852729Sdfr	register struct msgctl_args *uap;
3862729Sdfr{
3872729Sdfr	int msqid = uap->msqid;
3882729Sdfr	int cmd = uap->cmd;
3892729Sdfr	struct msqid_ds msqbuf;
390140839Ssobomax	int error;
391140839Ssobomax
392165403Sjkim	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
393140839Ssobomax	if (cmd == IPC_SET &&
394140839Ssobomax	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
395140839Ssobomax		return (error);
396141471Sjhb	error = kern_msgctl(td, msqid, cmd, &msqbuf);
397140839Ssobomax	if (cmd == IPC_STAT && error == 0)
398141471Sjhb		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
399140839Ssobomax	return (error);
400140839Ssobomax}
401140839Ssobomax
402140839Ssobomaxint
403141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf)
404140839Ssobomax	struct thread *td;
405140839Ssobomax	int msqid;
406140839Ssobomax	int cmd;
407140839Ssobomax	struct msqid_ds *msqbuf;
408140839Ssobomax{
409140839Ssobomax	int rval, error, msqix;
410137613Srwatson	register struct msqid_kernel *msqkptr;
4112729Sdfr
412192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
41391703Sjhb		return (ENOSYS);
41491703Sjhb
415140839Ssobomax	msqix = IPCID_TO_IX(msqid);
4162729Sdfr
417140839Ssobomax	if (msqix < 0 || msqix >= msginfo.msgmni) {
418140839Ssobomax		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
419100523Salfred		    msginfo.msgmni));
420101772Salfred		return (EINVAL);
4212729Sdfr	}
4222729Sdfr
423140839Ssobomax	msqkptr = &msqids[msqix];
4242729Sdfr
425101772Salfred	mtx_lock(&msq_mtx);
426137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
427100523Salfred		DPRINTF(("no such msqid\n"));
42882607Sdillon		error = EINVAL;
42982607Sdillon		goto done2;
4302729Sdfr	}
431140839Ssobomax	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
432100523Salfred		DPRINTF(("wrong sequence number\n"));
43382607Sdillon		error = EINVAL;
43482607Sdillon		goto done2;
4352729Sdfr	}
436140614Srwatson#ifdef MAC
437172930Srwatson	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
438162468Srwatson	if (error != 0)
439140614Srwatson		goto done2;
440140614Srwatson#endif
4412729Sdfr
44282607Sdillon	error = 0;
4432729Sdfr	rval = 0;
4442729Sdfr
4452729Sdfr	switch (cmd) {
4462729Sdfr
4472729Sdfr	case IPC_RMID:
4482729Sdfr	{
4492729Sdfr		struct msg *msghdr;
450137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
45182607Sdillon			goto done2;
452137613Srwatson
453140614Srwatson#ifdef MAC
454140614Srwatson		/*
455140614Srwatson		 * Check that the thread has MAC access permissions to
456140614Srwatson		 * individual msghdrs.  Note: We need to do this in a
457140614Srwatson		 * separate loop because the actual loop alters the
458140614Srwatson		 * msq/msghdr info as it progresses, and there is no going
459140614Srwatson		 * back if half the way through we discover that the
460140614Srwatson		 * thread cannot free a certain msghdr.  The msq will get
461140614Srwatson		 * into an inconsistent state.
462140614Srwatson		 */
463140614Srwatson		for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
464140614Srwatson		    msghdr = msghdr->msg_next) {
465172930Srwatson			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
466162468Srwatson			if (error != 0)
467140614Srwatson				goto done2;
468140614Srwatson		}
469140614Srwatson#endif
470140614Srwatson
471220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1);
472220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum);
473220398Strasz		racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes);
474220388Strasz		crfree(msqkptr->cred);
475220388Strasz		msqkptr->cred = NULL;
476220388Strasz
4772729Sdfr		/* Free the message headers */
478137613Srwatson		msghdr = msqkptr->u.msg_first;
4792729Sdfr		while (msghdr != NULL) {
4802729Sdfr			struct msg *msghdr_tmp;
4812729Sdfr
4822729Sdfr			/* Free the segments of each message */
483137613Srwatson			msqkptr->u.msg_cbytes -= msghdr->msg_ts;
484137613Srwatson			msqkptr->u.msg_qnum--;
4852729Sdfr			msghdr_tmp = msghdr;
4862729Sdfr			msghdr = msghdr->msg_next;
4872729Sdfr			msg_freehdr(msghdr_tmp);
4882729Sdfr		}
4892729Sdfr
490137613Srwatson		if (msqkptr->u.msg_cbytes != 0)
4912729Sdfr			panic("msg_cbytes is screwed up");
492137613Srwatson		if (msqkptr->u.msg_qnum != 0)
4932729Sdfr			panic("msg_qnum is screwed up");
4942729Sdfr
495137613Srwatson		msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
4962729Sdfr
497140614Srwatson#ifdef MAC
498172930Srwatson		mac_sysvmsq_cleanup(msqkptr);
499140614Srwatson#endif
500140614Srwatson
501137613Srwatson		wakeup(msqkptr);
5022729Sdfr	}
5032729Sdfr
5042729Sdfr		break;
5052729Sdfr
5062729Sdfr	case IPC_SET:
507137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
50882607Sdillon			goto done2;
509140839Ssobomax		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
510170587Srwatson			error = priv_check(td, PRIV_IPC_MSGSIZE);
51182607Sdillon			if (error)
51282607Sdillon				goto done2;
51343426Sphk		}
514140839Ssobomax		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
515100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
516100523Salfred			    "(truncating)\n", msginfo.msgmnb));
517140839Ssobomax			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
5182729Sdfr		}
519140839Ssobomax		if (msqbuf->msg_qbytes == 0) {
520100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
52182607Sdillon			error = EINVAL;		/* non-standard errno! */
52282607Sdillon			goto done2;
5232729Sdfr		}
524140839Ssobomax		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
525140839Ssobomax		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
526137613Srwatson		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
527140839Ssobomax		    (msqbuf->msg_perm.mode & 0777);
528140839Ssobomax		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
529137613Srwatson		msqkptr->u.msg_ctime = time_second;
5302729Sdfr		break;
5312729Sdfr
5322729Sdfr	case IPC_STAT:
533137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
534100523Salfred			DPRINTF(("requester doesn't have read access\n"));
53582607Sdillon			goto done2;
5362729Sdfr		}
537141471Sjhb		*msqbuf = msqkptr->u;
5382729Sdfr		break;
5392729Sdfr
5402729Sdfr	default:
541100523Salfred		DPRINTF(("invalid command %d\n", cmd));
54282607Sdillon		error = EINVAL;
54382607Sdillon		goto done2;
5442729Sdfr	}
5452729Sdfr
54682607Sdillon	if (error == 0)
54783366Sjulian		td->td_retval[0] = rval;
54882607Sdillondone2:
549101772Salfred	mtx_unlock(&msq_mtx);
550141471Sjhb	return (error);
5512729Sdfr}
5522729Sdfr
55312866Speter#ifndef _SYS_SYSPROTO_H_
5542729Sdfrstruct msgget_args {
5552729Sdfr	key_t	key;
5562729Sdfr	int	msgflg;
5572729Sdfr};
55812866Speter#endif
559225617Skmacy
56012866Speterint
561225617Skmacysys_msgget(td, uap)
56283366Sjulian	struct thread *td;
5632729Sdfr	register struct msgget_args *uap;
5642729Sdfr{
56582607Sdillon	int msqid, error = 0;
5662729Sdfr	int key = uap->key;
5672729Sdfr	int msgflg = uap->msgflg;
56891703Sjhb	struct ucred *cred = td->td_ucred;
569137613Srwatson	register struct msqid_kernel *msqkptr = NULL;
5702729Sdfr
571100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
5722729Sdfr
573192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
57491703Sjhb		return (ENOSYS);
57591703Sjhb
576101772Salfred	mtx_lock(&msq_mtx);
5772729Sdfr	if (key != IPC_PRIVATE) {
5782729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
579137613Srwatson			msqkptr = &msqids[msqid];
580137613Srwatson			if (msqkptr->u.msg_qbytes != 0 &&
581137613Srwatson			    msqkptr->u.msg_perm.key == key)
5822729Sdfr				break;
5832729Sdfr		}
5842729Sdfr		if (msqid < msginfo.msgmni) {
585100523Salfred			DPRINTF(("found public key\n"));
5862729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
587100523Salfred				DPRINTF(("not exclusive\n"));
58882607Sdillon				error = EEXIST;
58982607Sdillon				goto done2;
5902729Sdfr			}
591137613Srwatson			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
592137613Srwatson			    msgflg & 0700))) {
593100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
594100523Salfred				    msgflg & 0700));
59582607Sdillon				goto done2;
5962729Sdfr			}
597140614Srwatson#ifdef MAC
598172930Srwatson			error = mac_sysvmsq_check_msqget(cred, msqkptr);
599162468Srwatson			if (error != 0)
600140614Srwatson				goto done2;
601140614Srwatson#endif
6022729Sdfr			goto found;
6032729Sdfr		}
6042729Sdfr	}
6052729Sdfr
606100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
6072729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
6082729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
6092729Sdfr			/*
6102729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
6112729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
6122729Sdfr			 * they are copying the message in/out.  We can't
6132729Sdfr			 * re-use the entry until they release it.
6142729Sdfr			 */
615137613Srwatson			msqkptr = &msqids[msqid];
616137613Srwatson			if (msqkptr->u.msg_qbytes == 0 &&
617137613Srwatson			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
6182729Sdfr				break;
6192729Sdfr		}
6202729Sdfr		if (msqid == msginfo.msgmni) {
621100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
62282607Sdillon			error = ENOSPC;
62382607Sdillon			goto done2;
6242729Sdfr		}
625223825Strasz#ifdef RACCT
626284665Strasz		if (racct_enable) {
627284665Strasz			PROC_LOCK(td->td_proc);
628284665Strasz			error = racct_add(td->td_proc, RACCT_NMSGQ, 1);
629284665Strasz			PROC_UNLOCK(td->td_proc);
630284665Strasz			if (error != 0) {
631284665Strasz				error = ENOSPC;
632284665Strasz				goto done2;
633284665Strasz			}
634220398Strasz		}
635223825Strasz#endif
636100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
637137613Srwatson		msqkptr->u.msg_perm.key = key;
638137613Srwatson		msqkptr->u.msg_perm.cuid = cred->cr_uid;
639137613Srwatson		msqkptr->u.msg_perm.uid = cred->cr_uid;
640137613Srwatson		msqkptr->u.msg_perm.cgid = cred->cr_gid;
641137613Srwatson		msqkptr->u.msg_perm.gid = cred->cr_gid;
642137613Srwatson		msqkptr->u.msg_perm.mode = (msgflg & 0777);
643220399Strasz		msqkptr->cred = crhold(cred);
6442729Sdfr		/* Make sure that the returned msqid is unique */
645137613Srwatson		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
646137613Srwatson		msqkptr->u.msg_first = NULL;
647137613Srwatson		msqkptr->u.msg_last = NULL;
648137613Srwatson		msqkptr->u.msg_cbytes = 0;
649137613Srwatson		msqkptr->u.msg_qnum = 0;
650137613Srwatson		msqkptr->u.msg_qbytes = msginfo.msgmnb;
651137613Srwatson		msqkptr->u.msg_lspid = 0;
652137613Srwatson		msqkptr->u.msg_lrpid = 0;
653137613Srwatson		msqkptr->u.msg_stime = 0;
654137613Srwatson		msqkptr->u.msg_rtime = 0;
655137613Srwatson		msqkptr->u.msg_ctime = time_second;
656140614Srwatson#ifdef MAC
657172930Srwatson		mac_sysvmsq_create(cred, msqkptr);
658140614Srwatson#endif
6592729Sdfr	} else {
660100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
66182607Sdillon		error = ENOENT;
66282607Sdillon		goto done2;
6632729Sdfr	}
6642729Sdfr
6652729Sdfrfound:
6662729Sdfr	/* Construct the unique msqid */
667137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
66882607Sdillondone2:
669101772Salfred	mtx_unlock(&msq_mtx);
67082607Sdillon	return (error);
6712729Sdfr}
6722729Sdfr
67312866Speter#ifndef _SYS_SYSPROTO_H_
6742729Sdfrstruct msgsnd_args {
6752729Sdfr	int	msqid;
676109895Salfred	const void	*msgp;
6772729Sdfr	size_t	msgsz;
6782729Sdfr	int	msgflg;
6792729Sdfr};
68012866Speter#endif
68112866Speterint
682165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
68383366Sjulian	struct thread *td;
684165403Sjkim	int msqid;
685165403Sjkim	const void *msgp;	/* XXX msgp is actually mtext. */
686165403Sjkim	size_t msgsz;
687165403Sjkim	int msgflg;
688165403Sjkim	long mtype;
6892729Sdfr{
690165403Sjkim	int msqix, segs_needed, error = 0;
691137613Srwatson	register struct msqid_kernel *msqkptr;
6922729Sdfr	register struct msg *msghdr;
6932729Sdfr	short next;
694223825Strasz#ifdef RACCT
695220398Strasz	size_t saved_msgsz;
696223825Strasz#endif
6972729Sdfr
698192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
69991703Sjhb		return (ENOSYS);
70091703Sjhb
701101772Salfred	mtx_lock(&msq_mtx);
702165403Sjkim	msqix = IPCID_TO_IX(msqid);
7032729Sdfr
704165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
705165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
706100523Salfred		    msginfo.msgmni));
70782607Sdillon		error = EINVAL;
70882607Sdillon		goto done2;
7092729Sdfr	}
7102729Sdfr
711165403Sjkim	msqkptr = &msqids[msqix];
712137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
713100523Salfred		DPRINTF(("no such message queue id\n"));
71482607Sdillon		error = EINVAL;
71582607Sdillon		goto done2;
7162729Sdfr	}
717165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
718100523Salfred		DPRINTF(("wrong sequence number\n"));
71982607Sdillon		error = EINVAL;
72082607Sdillon		goto done2;
7212729Sdfr	}
7222729Sdfr
723137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
724100523Salfred		DPRINTF(("requester doesn't have write access\n"));
72582607Sdillon		goto done2;
7262729Sdfr	}
7272729Sdfr
728140614Srwatson#ifdef MAC
729172930Srwatson	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
730162468Srwatson	if (error != 0)
731140614Srwatson		goto done2;
732140614Srwatson#endif
733140614Srwatson
734223825Strasz#ifdef RACCT
735284665Strasz	if (racct_enable) {
736284665Strasz		PROC_LOCK(td->td_proc);
737284665Strasz		if (racct_add(td->td_proc, RACCT_MSGQQUEUED, 1)) {
738284665Strasz			PROC_UNLOCK(td->td_proc);
739284665Strasz			error = EAGAIN;
740284665Strasz			goto done2;
741284665Strasz		}
742284665Strasz		saved_msgsz = msgsz;
743284665Strasz		if (racct_add(td->td_proc, RACCT_MSGQSIZE, msgsz)) {
744284665Strasz			racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
745284665Strasz			PROC_UNLOCK(td->td_proc);
746284665Strasz			error = EAGAIN;
747284665Strasz			goto done2;
748284665Strasz		}
749220398Strasz		PROC_UNLOCK(td->td_proc);
750220398Strasz	}
751223825Strasz#endif
752220398Strasz
7532729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
754165403Sjkim	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
755165403Sjkim	    msginfo.msgssz, segs_needed));
7562729Sdfr	for (;;) {
7572729Sdfr		int need_more_resources = 0;
7582729Sdfr
7592729Sdfr		/*
7602729Sdfr		 * check msgsz
7612729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
7622729Sdfr		 */
7632729Sdfr
764137613Srwatson		if (msgsz > msqkptr->u.msg_qbytes) {
765137613Srwatson			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
76682607Sdillon			error = EINVAL;
767220398Strasz			goto done3;
7682729Sdfr		}
7692729Sdfr
770137613Srwatson		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
771100523Salfred			DPRINTF(("msqid is locked\n"));
7722729Sdfr			need_more_resources = 1;
7732729Sdfr		}
774137613Srwatson		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
775100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
7762729Sdfr			need_more_resources = 1;
7772729Sdfr		}
7782729Sdfr		if (segs_needed > nfree_msgmaps) {
779100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
7802729Sdfr			need_more_resources = 1;
7812729Sdfr		}
7822729Sdfr		if (free_msghdrs == NULL) {
783100523Salfred			DPRINTF(("no more msghdrs\n"));
7842729Sdfr			need_more_resources = 1;
7852729Sdfr		}
7862729Sdfr
7872729Sdfr		if (need_more_resources) {
7882729Sdfr			int we_own_it;
7892729Sdfr
7902729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
791100523Salfred				DPRINTF(("need more resources but caller "
792100523Salfred				    "doesn't want to wait\n"));
79382607Sdillon				error = EAGAIN;
794220398Strasz				goto done3;
7952729Sdfr			}
7962729Sdfr
797137613Srwatson			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
798100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
7992729Sdfr				we_own_it = 0;
8002729Sdfr			} else {
8012729Sdfr				/* Force later arrivals to wait for our
8022729Sdfr				   request */
803100523Salfred				DPRINTF(("we own the msqid_ds\n"));
804137613Srwatson				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8052729Sdfr				we_own_it = 1;
8062729Sdfr			}
807164368Sjkim			DPRINTF(("msgsnd:  goodnight\n"));
808137613Srwatson			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
809164368Sjkim			    "msgsnd", hz);
810164368Sjkim			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
8112729Sdfr			if (we_own_it)
812137613Srwatson				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
813164368Sjkim			if (error == EWOULDBLOCK) {
814164368Sjkim				DPRINTF(("msgsnd:  timed out\n"));
815164368Sjkim				continue;
816164368Sjkim			}
81782607Sdillon			if (error != 0) {
818100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
81982607Sdillon				error = EINTR;
820220398Strasz				goto done3;
8212729Sdfr			}
8222729Sdfr
8232729Sdfr			/*
8242729Sdfr			 * Make sure that the msq queue still exists
8252729Sdfr			 */
8262729Sdfr
827137613Srwatson			if (msqkptr->u.msg_qbytes == 0) {
828100523Salfred				DPRINTF(("msqid deleted\n"));
82982607Sdillon				error = EIDRM;
830220398Strasz				goto done3;
8312729Sdfr			}
8322729Sdfr
8332729Sdfr		} else {
834100523Salfred			DPRINTF(("got all the resources that we need\n"));
8352729Sdfr			break;
8362729Sdfr		}
8372729Sdfr	}
8382729Sdfr
8392729Sdfr	/*
8402729Sdfr	 * We have the resources that we need.
8412729Sdfr	 * Make sure!
8422729Sdfr	 */
8432729Sdfr
844137613Srwatson	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
8452729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
8462729Sdfr	if (segs_needed > nfree_msgmaps)
8472729Sdfr		panic("segs_needed > nfree_msgmaps");
848137613Srwatson	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
8492729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
8502729Sdfr	if (free_msghdrs == NULL)
8512729Sdfr		panic("no more msghdrs");
8522729Sdfr
8532729Sdfr	/*
8542729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
8552729Sdfr	 * message
8562729Sdfr	 */
8572729Sdfr
858137613Srwatson	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
8592729Sdfr		panic("msqid_ds is already locked");
860137613Srwatson	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8612729Sdfr
8622729Sdfr	/*
8632729Sdfr	 * Allocate a message header
8642729Sdfr	 */
8652729Sdfr
8662729Sdfr	msghdr = free_msghdrs;
8672729Sdfr	free_msghdrs = msghdr->msg_next;
8682729Sdfr	msghdr->msg_spot = -1;
8692729Sdfr	msghdr->msg_ts = msgsz;
870165403Sjkim	msghdr->msg_type = mtype;
871140614Srwatson#ifdef MAC
872140614Srwatson	/*
873172930Srwatson	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
874140614Srwatson	 * immediately?  Or, should it be checked just before the msg is
875140614Srwatson	 * enqueued in the msgq (as it is done now)?
876140614Srwatson	 */
877172930Srwatson	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
878140614Srwatson#endif
8792729Sdfr
8802729Sdfr	/*
8812729Sdfr	 * Allocate space for the message
8822729Sdfr	 */
8832729Sdfr
8842729Sdfr	while (segs_needed > 0) {
8852729Sdfr		if (nfree_msgmaps <= 0)
8862729Sdfr			panic("not enough msgmaps");
8872729Sdfr		if (free_msgmaps == -1)
8882729Sdfr			panic("nil free_msgmaps");
8892729Sdfr		next = free_msgmaps;
8902729Sdfr		if (next <= -1)
8912729Sdfr			panic("next too low #1");
8922729Sdfr		if (next >= msginfo.msgseg)
8932729Sdfr			panic("next out of range #1");
894100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
8952729Sdfr		free_msgmaps = msgmaps[next].next;
8962729Sdfr		nfree_msgmaps--;
8972729Sdfr		msgmaps[next].next = msghdr->msg_spot;
8982729Sdfr		msghdr->msg_spot = next;
8992729Sdfr		segs_needed--;
9002729Sdfr	}
9012729Sdfr
9022729Sdfr	/*
9032729Sdfr	 * Validate the message type
9042729Sdfr	 */
9052729Sdfr
9062729Sdfr	if (msghdr->msg_type < 1) {
9072729Sdfr		msg_freehdr(msghdr);
908137613Srwatson		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
909137613Srwatson		wakeup(msqkptr);
910165403Sjkim		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
91182607Sdillon		error = EINVAL;
912220398Strasz		goto done3;
9132729Sdfr	}
9142729Sdfr
9152729Sdfr	/*
9162729Sdfr	 * Copy in the message body
9172729Sdfr	 */
9182729Sdfr
9192729Sdfr	next = msghdr->msg_spot;
9202729Sdfr	while (msgsz > 0) {
9212729Sdfr		size_t tlen;
9222729Sdfr		if (msgsz > msginfo.msgssz)
9232729Sdfr			tlen = msginfo.msgssz;
9242729Sdfr		else
9252729Sdfr			tlen = msgsz;
9262729Sdfr		if (next <= -1)
9272729Sdfr			panic("next too low #2");
9282729Sdfr		if (next >= msginfo.msgseg)
9292729Sdfr			panic("next out of range #2");
930101772Salfred		mtx_unlock(&msq_mtx);
931165403Sjkim		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
9322729Sdfr		    tlen)) != 0) {
933101772Salfred			mtx_lock(&msq_mtx);
934100523Salfred			DPRINTF(("error %d copying in message segment\n",
935100523Salfred			    error));
9362729Sdfr			msg_freehdr(msghdr);
937137613Srwatson			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
938137613Srwatson			wakeup(msqkptr);
939220398Strasz			goto done3;
9402729Sdfr		}
941101772Salfred		mtx_lock(&msq_mtx);
9422729Sdfr		msgsz -= tlen;
943165403Sjkim		msgp = (const char *)msgp + tlen;
9442729Sdfr		next = msgmaps[next].next;
9452729Sdfr	}
9462729Sdfr	if (next != -1)
9472729Sdfr		panic("didn't use all the msg segments");
9482729Sdfr
9492729Sdfr	/*
9502729Sdfr	 * We've got the message.  Unlock the msqid_ds.
9512729Sdfr	 */
9522729Sdfr
953137613Srwatson	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
9542729Sdfr
9552729Sdfr	/*
9562729Sdfr	 * Make sure that the msqid_ds is still allocated.
9572729Sdfr	 */
9582729Sdfr
959137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
9602729Sdfr		msg_freehdr(msghdr);
961137613Srwatson		wakeup(msqkptr);
96282607Sdillon		error = EIDRM;
963220398Strasz		goto done3;
9642729Sdfr	}
9652729Sdfr
966140614Srwatson#ifdef MAC
9672729Sdfr	/*
968140614Srwatson	 * Note: Since the task/thread allocates the msghdr and usually
969140614Srwatson	 * primes it with its own MAC label, for a majority of policies, it
970140614Srwatson	 * won't be necessary to check whether the msghdr has access
971172930Srwatson	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
972140614Srwatson	 * suffice in that case.  However, this hook may be required where
973140614Srwatson	 * individual policies derive a non-identical label for the msghdr
974140614Srwatson	 * from the current thread label and may want to check the msghdr
975140614Srwatson	 * enqueue permissions, along with read/write permissions to the
976140614Srwatson	 * msgq.
977140614Srwatson	 */
978172930Srwatson	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
979140614Srwatson	if (error != 0) {
980140614Srwatson		msg_freehdr(msghdr);
981140614Srwatson		wakeup(msqkptr);
982220398Strasz		goto done3;
983140614Srwatson	}
984140614Srwatson#endif
985140614Srwatson
986140614Srwatson	/*
9872729Sdfr	 * Put the message into the queue
9882729Sdfr	 */
989137613Srwatson	if (msqkptr->u.msg_first == NULL) {
990137613Srwatson		msqkptr->u.msg_first = msghdr;
991137613Srwatson		msqkptr->u.msg_last = msghdr;
9922729Sdfr	} else {
993137613Srwatson		msqkptr->u.msg_last->msg_next = msghdr;
994137613Srwatson		msqkptr->u.msg_last = msghdr;
9952729Sdfr	}
996137613Srwatson	msqkptr->u.msg_last->msg_next = NULL;
9972729Sdfr
998137613Srwatson	msqkptr->u.msg_cbytes += msghdr->msg_ts;
999137613Srwatson	msqkptr->u.msg_qnum++;
1000137613Srwatson	msqkptr->u.msg_lspid = td->td_proc->p_pid;
1001137613Srwatson	msqkptr->u.msg_stime = time_second;
10022729Sdfr
1003137613Srwatson	wakeup(msqkptr);
100483366Sjulian	td->td_retval[0] = 0;
1005220398Straszdone3:
1006223825Strasz#ifdef RACCT
1007284665Strasz	if (racct_enable && error != 0) {
1008220398Strasz		PROC_LOCK(td->td_proc);
1009220398Strasz		racct_sub(td->td_proc, RACCT_MSGQQUEUED, 1);
1010220398Strasz		racct_sub(td->td_proc, RACCT_MSGQSIZE, saved_msgsz);
1011220398Strasz		PROC_UNLOCK(td->td_proc);
1012220398Strasz	}
1013223825Strasz#endif
101482607Sdillondone2:
1015101772Salfred	mtx_unlock(&msq_mtx);
101682607Sdillon	return (error);
10172729Sdfr}
10182729Sdfr
1019165403Sjkimint
1020225617Skmacysys_msgsnd(td, uap)
1021165403Sjkim	struct thread *td;
1022165403Sjkim	register struct msgsnd_args *uap;
1023165403Sjkim{
1024165403Sjkim	int error;
1025165403Sjkim	long mtype;
1026165403Sjkim
1027165403Sjkim	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
1028165403Sjkim	    uap->msgsz, uap->msgflg));
1029165403Sjkim
1030165403Sjkim	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
1031165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1032165403Sjkim		return (error);
1033165403Sjkim	}
1034165403Sjkim	return (kern_msgsnd(td, uap->msqid,
1035165403Sjkim	    (const char *)uap->msgp + sizeof(mtype),
1036165403Sjkim	    uap->msgsz, uap->msgflg, mtype));
1037165403Sjkim}
1038165403Sjkim
103912866Speter#ifndef _SYS_SYSPROTO_H_
10402729Sdfrstruct msgrcv_args {
10412729Sdfr	int	msqid;
10422729Sdfr	void	*msgp;
10432729Sdfr	size_t	msgsz;
10442729Sdfr	long	msgtyp;
10452729Sdfr	int	msgflg;
10462729Sdfr};
104712866Speter#endif
104812866Speterint
1049165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype)
105083366Sjulian	struct thread *td;
1051165403Sjkim	int msqid;
1052165403Sjkim	void *msgp;	/* XXX msgp is actually mtext. */
1053165403Sjkim	size_t msgsz;
1054165403Sjkim	long msgtyp;
1055165403Sjkim	int msgflg;
1056165403Sjkim	long *mtype;
10572729Sdfr{
10582729Sdfr	size_t len;
1059137613Srwatson	register struct msqid_kernel *msqkptr;
10602729Sdfr	register struct msg *msghdr;
1061165403Sjkim	int msqix, error = 0;
10622729Sdfr	short next;
10632729Sdfr
1064192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
106591703Sjhb		return (ENOSYS);
106691703Sjhb
1067165403Sjkim	msqix = IPCID_TO_IX(msqid);
10682729Sdfr
1069165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
1070165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1071100523Salfred		    msginfo.msgmni));
1072101772Salfred		return (EINVAL);
10732729Sdfr	}
10742729Sdfr
1075165403Sjkim	msqkptr = &msqids[msqix];
1076101772Salfred	mtx_lock(&msq_mtx);
1077137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
1078100523Salfred		DPRINTF(("no such message queue id\n"));
107982607Sdillon		error = EINVAL;
108082607Sdillon		goto done2;
10812729Sdfr	}
1082165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1083100523Salfred		DPRINTF(("wrong sequence number\n"));
108482607Sdillon		error = EINVAL;
108582607Sdillon		goto done2;
10862729Sdfr	}
10872729Sdfr
1088137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1089100523Salfred		DPRINTF(("requester doesn't have read access\n"));
109082607Sdillon		goto done2;
10912729Sdfr	}
10922729Sdfr
1093140614Srwatson#ifdef MAC
1094172930Srwatson	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1095162468Srwatson	if (error != 0)
1096140614Srwatson		goto done2;
1097140614Srwatson#endif
1098140614Srwatson
10992729Sdfr	msghdr = NULL;
11002729Sdfr	while (msghdr == NULL) {
11012729Sdfr		if (msgtyp == 0) {
1102137613Srwatson			msghdr = msqkptr->u.msg_first;
11032729Sdfr			if (msghdr != NULL) {
11042729Sdfr				if (msgsz < msghdr->msg_ts &&
11052729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
1106100523Salfred					DPRINTF(("first message on the queue "
1107165403Sjkim					    "is too big (want %zu, got %d)\n",
1108100523Salfred					    msgsz, msghdr->msg_ts));
110982607Sdillon					error = E2BIG;
111082607Sdillon					goto done2;
11112729Sdfr				}
1112140614Srwatson#ifdef MAC
1113172930Srwatson				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1114140614Srwatson				    msghdr);
1115162468Srwatson				if (error != 0)
1116140614Srwatson					goto done2;
1117140614Srwatson#endif
1118137613Srwatson				if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1119137613Srwatson					msqkptr->u.msg_first = NULL;
1120137613Srwatson					msqkptr->u.msg_last = NULL;
11212729Sdfr				} else {
1122137613Srwatson					msqkptr->u.msg_first = msghdr->msg_next;
1123137613Srwatson					if (msqkptr->u.msg_first == NULL)
11242729Sdfr						panic("msg_first/last screwed up #1");
11252729Sdfr				}
11262729Sdfr			}
11272729Sdfr		} else {
11282729Sdfr			struct msg *previous;
11292729Sdfr			struct msg **prev;
11302729Sdfr
11312729Sdfr			previous = NULL;
1132137613Srwatson			prev = &(msqkptr->u.msg_first);
11332729Sdfr			while ((msghdr = *prev) != NULL) {
11342729Sdfr				/*
11352729Sdfr				 * Is this message's type an exact match or is
11362729Sdfr				 * this message's type less than or equal to
11372729Sdfr				 * the absolute value of a negative msgtyp?
11382729Sdfr				 * Note that the second half of this test can
11392729Sdfr				 * NEVER be true if msgtyp is positive since
11402729Sdfr				 * msg_type is always positive!
11412729Sdfr				 */
11422729Sdfr
11432729Sdfr				if (msgtyp == msghdr->msg_type ||
11442729Sdfr				    msghdr->msg_type <= -msgtyp) {
1145165403Sjkim					DPRINTF(("found message type %ld, "
1146165403Sjkim					    "requested %ld\n",
1147100523Salfred					    msghdr->msg_type, msgtyp));
11482729Sdfr					if (msgsz < msghdr->msg_ts &&
11492729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
1150100523Salfred						DPRINTF(("requested message "
1151100523Salfred						    "on the queue is too big "
1152165403Sjkim						    "(want %zu, got %hu)\n",
1153100523Salfred						    msgsz, msghdr->msg_ts));
115482607Sdillon						error = E2BIG;
115582607Sdillon						goto done2;
11562729Sdfr					}
1157140614Srwatson#ifdef MAC
1158172930Srwatson					error = mac_sysvmsq_check_msgrcv(
1159140614Srwatson					    td->td_ucred, msghdr);
1160162468Srwatson					if (error != 0)
1161140614Srwatson						goto done2;
1162140614Srwatson#endif
11632729Sdfr					*prev = msghdr->msg_next;
1164137613Srwatson					if (msghdr == msqkptr->u.msg_last) {
11652729Sdfr						if (previous == NULL) {
11662729Sdfr							if (prev !=
1167137613Srwatson							    &msqkptr->u.msg_first)
11682729Sdfr								panic("msg_first/last screwed up #2");
1169137613Srwatson							msqkptr->u.msg_first =
11702729Sdfr							    NULL;
1171137613Srwatson							msqkptr->u.msg_last =
11722729Sdfr							    NULL;
11732729Sdfr						} else {
11742729Sdfr							if (prev ==
1175137613Srwatson							    &msqkptr->u.msg_first)
11762729Sdfr								panic("msg_first/last screwed up #3");
1177137613Srwatson							msqkptr->u.msg_last =
11782729Sdfr							    previous;
11792729Sdfr						}
11802729Sdfr					}
11812729Sdfr					break;
11822729Sdfr				}
11832729Sdfr				previous = msghdr;
11842729Sdfr				prev = &(msghdr->msg_next);
11852729Sdfr			}
11862729Sdfr		}
11872729Sdfr
11882729Sdfr		/*
11892729Sdfr		 * We've either extracted the msghdr for the appropriate
11902729Sdfr		 * message or there isn't one.
11912729Sdfr		 * If there is one then bail out of this loop.
11922729Sdfr		 */
11932729Sdfr
11942729Sdfr		if (msghdr != NULL)
11952729Sdfr			break;
11962729Sdfr
11972729Sdfr		/*
11982729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
11992729Sdfr		 */
12002729Sdfr
12012729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1202165403Sjkim			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1203100523Salfred			    msgtyp));
12042729Sdfr			/* The SVID says to return ENOMSG. */
120582607Sdillon			error = ENOMSG;
120682607Sdillon			goto done2;
12072729Sdfr		}
12082729Sdfr
12092729Sdfr		/*
12102729Sdfr		 * Wait for something to happen
12112729Sdfr		 */
12122729Sdfr
1213100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1214137613Srwatson		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1215164368Sjkim		    "msgrcv", 0);
1216100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
12172729Sdfr
121882607Sdillon		if (error != 0) {
1219164368Sjkim			DPRINTF(("msgrcv:  interrupted system call\n"));
122082607Sdillon			error = EINTR;
122182607Sdillon			goto done2;
12222729Sdfr		}
12232729Sdfr
12242729Sdfr		/*
12252729Sdfr		 * Make sure that the msq queue still exists
12262729Sdfr		 */
12272729Sdfr
1228137613Srwatson		if (msqkptr->u.msg_qbytes == 0 ||
1229165403Sjkim		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1230100523Salfred			DPRINTF(("msqid deleted\n"));
123182607Sdillon			error = EIDRM;
123282607Sdillon			goto done2;
12332729Sdfr		}
12342729Sdfr	}
12352729Sdfr
12362729Sdfr	/*
12372729Sdfr	 * Return the message to the user.
12382729Sdfr	 *
12392729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
12402729Sdfr	 */
12412729Sdfr
1242137613Srwatson	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1243137613Srwatson	msqkptr->u.msg_qnum--;
1244137613Srwatson	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1245137613Srwatson	msqkptr->u.msg_rtime = time_second;
12462729Sdfr
1247220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, 1);
1248220398Strasz	racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msghdr->msg_ts);
1249220398Strasz
12502729Sdfr	/*
12512729Sdfr	 * Make msgsz the actual amount that we'll be returning.
12522729Sdfr	 * Note that this effectively truncates the message if it is too long
12532729Sdfr	 * (since msgsz is never increased).
12542729Sdfr	 */
12552729Sdfr
1256165403Sjkim	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1257100523Salfred	    msghdr->msg_ts));
12582729Sdfr	if (msgsz > msghdr->msg_ts)
12592729Sdfr		msgsz = msghdr->msg_ts;
1260165403Sjkim	*mtype = msghdr->msg_type;
12612729Sdfr
12622729Sdfr	/*
12632729Sdfr	 * Return the segments to the user
12642729Sdfr	 */
12652729Sdfr
12662729Sdfr	next = msghdr->msg_spot;
12672729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
12682729Sdfr		size_t tlen;
12692729Sdfr
127045921Ssada		if (msgsz - len > msginfo.msgssz)
12712729Sdfr			tlen = msginfo.msgssz;
12722729Sdfr		else
127345921Ssada			tlen = msgsz - len;
12742729Sdfr		if (next <= -1)
12752729Sdfr			panic("next too low #3");
12762729Sdfr		if (next >= msginfo.msgseg)
12772729Sdfr			panic("next out of range #3");
1278101772Salfred		mtx_unlock(&msq_mtx);
1279165403Sjkim		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1280101772Salfred		mtx_lock(&msq_mtx);
128182607Sdillon		if (error != 0) {
1282100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1283100523Salfred			    error));
12842729Sdfr			msg_freehdr(msghdr);
1285137613Srwatson			wakeup(msqkptr);
128682607Sdillon			goto done2;
12872729Sdfr		}
1288165403Sjkim		msgp = (char *)msgp + tlen;
12892729Sdfr		next = msgmaps[next].next;
12902729Sdfr	}
12912729Sdfr
12922729Sdfr	/*
12932729Sdfr	 * Done, return the actual number of bytes copied out.
12942729Sdfr	 */
12952729Sdfr
12962729Sdfr	msg_freehdr(msghdr);
1297137613Srwatson	wakeup(msqkptr);
129883366Sjulian	td->td_retval[0] = msgsz;
129982607Sdillondone2:
1300101772Salfred	mtx_unlock(&msq_mtx);
130182607Sdillon	return (error);
13022729Sdfr}
130377461Sdd
1304165403Sjkimint
1305225617Skmacysys_msgrcv(td, uap)
1306165403Sjkim	struct thread *td;
1307165403Sjkim	register struct msgrcv_args *uap;
1308165403Sjkim{
1309165403Sjkim	int error;
1310165403Sjkim	long mtype;
1311165403Sjkim
1312165403Sjkim	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1313165403Sjkim	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1314165403Sjkim
1315165403Sjkim	if ((error = kern_msgrcv(td, uap->msqid,
1316165403Sjkim	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1317165403Sjkim	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1318165403Sjkim		return (error);
1319165403Sjkim	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1320165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1321165403Sjkim	return (error);
1322165403Sjkim}
1323165403Sjkim
132477461Sddstatic int
132577461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
132677461Sdd{
132777461Sdd
132877461Sdd	return (SYSCTL_OUT(req, msqids,
1329137613Srwatson	    sizeof(struct msqid_kernel) * msginfo.msgmni));
133077461Sdd}
133177461Sdd
1332141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1333141710Scsjp    "Maximum message size");
1334141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1335141710Scsjp    "Number of message queue identifiers");
1336141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1337141710Scsjp    "Maximum number of bytes in a queue");
1338141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1339141710Scsjp    "Maximum number of messages in the system");
1340141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1341141710Scsjp    "Size of a message segment");
1342141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1343141710Scsjp    "Number of message segments");
1344217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
134577461Sdd    NULL, 0, sysctl_msqids, "", "Message queue IDs");
1346194894Sjhb
1347205323Skib#ifdef COMPAT_FREEBSD32
1348205323Skibint
1349205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1350205323Skib{
1351205323Skib
1352194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1353194894Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1354205323Skib	switch (uap->which) {
1355205323Skib	case 0:
1356205323Skib		return (freebsd7_freebsd32_msgctl(td,
1357205323Skib		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1358205323Skib	case 2:
1359205323Skib		return (freebsd32_msgsnd(td,
1360205323Skib		    (struct freebsd32_msgsnd_args *)&uap->a2));
1361205323Skib	case 3:
1362205323Skib		return (freebsd32_msgrcv(td,
1363205323Skib		    (struct freebsd32_msgrcv_args *)&uap->a2));
1364205323Skib	default:
1365225617Skmacy		return (sys_msgsys(td, (struct msgsys_args *)uap));
1366205323Skib	}
1367205323Skib#else
1368205323Skib	return (nosys(td, NULL));
1369205323Skib#endif
1370205323Skib}
1371194894Sjhb
1372205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1373205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1374205323Skibint
1375205323Skibfreebsd7_freebsd32_msgctl(struct thread *td,
1376205323Skib    struct freebsd7_freebsd32_msgctl_args *uap)
1377205323Skib{
1378205323Skib	struct msqid_ds msqbuf;
1379205323Skib	struct msqid_ds32_old msqbuf32;
1380205323Skib	int error;
1381205323Skib
1382205323Skib	if (uap->cmd == IPC_SET) {
1383205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1384205323Skib		if (error)
1385205323Skib			return (error);
1386205323Skib		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1387205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1388205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1389205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1390205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1391205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1392205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1393205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1394205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1395205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1396205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1397205323Skib	}
1398205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1399205323Skib	if (error)
1400205323Skib		return (error);
1401205323Skib	if (uap->cmd == IPC_STAT) {
1402205323Skib		bzero(&msqbuf32, sizeof(msqbuf32));
1403205323Skib		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1404205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1405205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1406205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1407205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1408205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1409205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1410205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1411205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1412205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1413205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1414205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1415205323Skib	}
1416205323Skib	return (error);
1417205323Skib}
1418205323Skib#endif
1419205323Skib
1420205323Skibint
1421205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1422205323Skib{
1423205323Skib	struct msqid_ds msqbuf;
1424205323Skib	struct msqid_ds32 msqbuf32;
1425205323Skib	int error;
1426205323Skib
1427205323Skib	if (uap->cmd == IPC_SET) {
1428205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1429205323Skib		if (error)
1430205323Skib			return (error);
1431205323Skib		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1432205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1433205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1434205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1435205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1436205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1437205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1438205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1439205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1440205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1441205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1442205323Skib	}
1443205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1444205323Skib	if (error)
1445205323Skib		return (error);
1446205323Skib	if (uap->cmd == IPC_STAT) {
1447205323Skib		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1448205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1449205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1450205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1451205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1452205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1453205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1454205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1455205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1456205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1457205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1458205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1459205323Skib	}
1460205323Skib	return (error);
1461205323Skib}
1462205323Skib
1463205323Skibint
1464205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1465205323Skib{
1466205323Skib	const void *msgp;
1467205323Skib	long mtype;
1468205323Skib	int32_t mtype32;
1469205323Skib	int error;
1470205323Skib
1471205323Skib	msgp = PTRIN(uap->msgp);
1472205323Skib	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1473205323Skib		return (error);
1474205323Skib	mtype = mtype32;
1475205323Skib	return (kern_msgsnd(td, uap->msqid,
1476205323Skib	    (const char *)msgp + sizeof(mtype32),
1477205323Skib	    uap->msgsz, uap->msgflg, mtype));
1478205323Skib}
1479205323Skib
1480205323Skibint
1481205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1482205323Skib{
1483205323Skib	void *msgp;
1484205323Skib	long mtype;
1485205323Skib	int32_t mtype32;
1486205323Skib	int error;
1487205323Skib
1488205323Skib	msgp = PTRIN(uap->msgp);
1489205323Skib	if ((error = kern_msgrcv(td, uap->msqid,
1490205323Skib	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1491205323Skib	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1492205323Skib		return (error);
1493205323Skib	mtype32 = (int32_t)mtype;
1494205323Skib	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1495205323Skib}
1496205323Skib#endif
1497205323Skib
1498205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1499205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1500205323Skib
1501194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1502194894Sjhbstatic sy_call_t *msgcalls[] = {
1503225617Skmacy	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)sys_msgget,
1504225617Skmacy	(sy_call_t *)sys_msgsnd, (sy_call_t *)sys_msgrcv
1505194894Sjhb};
1506194894Sjhb
1507194894Sjhb/*
1508194894Sjhb * Entry point for all MSG calls.
1509194894Sjhb */
1510194894Sjhbint
1511225617Skmacysys_msgsys(td, uap)
1512194894Sjhb	struct thread *td;
1513194894Sjhb	/* XXX actually varargs. */
1514194894Sjhb	struct msgsys_args /* {
1515194894Sjhb		int	which;
1516194894Sjhb		int	a2;
1517194894Sjhb		int	a3;
1518194894Sjhb		int	a4;
1519194894Sjhb		int	a5;
1520194894Sjhb		int	a6;
1521194894Sjhb	} */ *uap;
1522194894Sjhb{
1523194894Sjhb	int error;
1524194894Sjhb
1525194894Sjhb	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1526194894Sjhb		return (ENOSYS);
1527194894Sjhb	if (uap->which < 0 ||
1528194894Sjhb	    uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
1529194894Sjhb		return (EINVAL);
1530194894Sjhb	error = (*msgcalls[uap->which])(td, &uap->a2);
1531194894Sjhb	return (error);
1532194894Sjhb}
1533194910Sjhb
1534205323Skib#ifndef CP
1535194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1536205323Skib#endif
1537194910Sjhb
1538194910Sjhb#ifndef _SYS_SYSPROTO_H_
1539194910Sjhbstruct freebsd7_msgctl_args {
1540194910Sjhb	int	msqid;
1541194910Sjhb	int	cmd;
1542194910Sjhb	struct	msqid_ds_old *buf;
1543194910Sjhb};
1544194910Sjhb#endif
1545194910Sjhbint
1546194910Sjhbfreebsd7_msgctl(td, uap)
1547194910Sjhb	struct thread *td;
1548194910Sjhb	struct freebsd7_msgctl_args *uap;
1549194910Sjhb{
1550194910Sjhb	struct msqid_ds_old msqold;
1551194910Sjhb	struct msqid_ds msqbuf;
1552194910Sjhb	int error;
1553194910Sjhb
1554194910Sjhb	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1555194910Sjhb	    uap->buf));
1556194910Sjhb	if (uap->cmd == IPC_SET) {
1557194910Sjhb		error = copyin(uap->buf, &msqold, sizeof(msqold));
1558194910Sjhb		if (error)
1559194910Sjhb			return (error);
1560194910Sjhb		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1561194910Sjhb		CP(msqold, msqbuf, msg_first);
1562194910Sjhb		CP(msqold, msqbuf, msg_last);
1563194910Sjhb		CP(msqold, msqbuf, msg_cbytes);
1564194910Sjhb		CP(msqold, msqbuf, msg_qnum);
1565194910Sjhb		CP(msqold, msqbuf, msg_qbytes);
1566194910Sjhb		CP(msqold, msqbuf, msg_lspid);
1567194910Sjhb		CP(msqold, msqbuf, msg_lrpid);
1568194910Sjhb		CP(msqold, msqbuf, msg_stime);
1569194910Sjhb		CP(msqold, msqbuf, msg_rtime);
1570194910Sjhb		CP(msqold, msqbuf, msg_ctime);
1571194910Sjhb	}
1572194910Sjhb	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1573194910Sjhb	if (error)
1574194910Sjhb		return (error);
1575194910Sjhb	if (uap->cmd == IPC_STAT) {
1576194910Sjhb		bzero(&msqold, sizeof(msqold));
1577194910Sjhb		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1578194910Sjhb		CP(msqbuf, msqold, msg_first);
1579194910Sjhb		CP(msqbuf, msqold, msg_last);
1580194910Sjhb		CP(msqbuf, msqold, msg_cbytes);
1581194910Sjhb		CP(msqbuf, msqold, msg_qnum);
1582194910Sjhb		CP(msqbuf, msqold, msg_qbytes);
1583194910Sjhb		CP(msqbuf, msqold, msg_lspid);
1584194910Sjhb		CP(msqbuf, msqold, msg_lrpid);
1585194910Sjhb		CP(msqbuf, msqold, msg_stime);
1586194910Sjhb		CP(msqbuf, msqold, msg_rtime);
1587194910Sjhb		CP(msqbuf, msqold, msg_ctime);
1588194910Sjhb		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1589194910Sjhb	}
1590194910Sjhb	return (error);
1591194910Sjhb}
1592194910Sjhb
1593194910Sjhb#undef CP
1594194910Sjhb
1595194894Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1596194894Sjhb	   COMPAT_FREEBSD7 */
1597