sysv_msg.c revision 220388
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 220388 2011-04-06 16:59:54Z 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>
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
75219028SnetchildFEATURE(sysv_msg, "System V message queues support");
76219028Snetchild
7759839Speterstatic MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues");
7859839Speter
79205323Skibstatic int msginit(void);
8092723Salfredstatic int msgunload(void);
8192723Salfredstatic int sysvmsg_modload(struct module *, int, void *);
8210358Sjulian
83100523Salfred#ifdef MSG_DEBUG
84100523Salfred#define DPRINTF(a)	printf a
85100523Salfred#else
86194575Srdivacky#define DPRINTF(a)	(void)0
87100523Salfred#endif
882729Sdfr
8992723Salfredstatic void msg_freehdr(struct msg *msghdr);
902729Sdfr
9159839Speter#ifndef MSGSSZ
9259839Speter#define MSGSSZ	8		/* Each segment must be 2^N long */
9359839Speter#endif
9459839Speter#ifndef MSGSEG
9559839Speter#define MSGSEG	2048		/* must be less than 32767 */
9659839Speter#endif
9759839Speter#define MSGMAX	(MSGSSZ*MSGSEG)
9859839Speter#ifndef MSGMNB
9959839Speter#define MSGMNB	2048		/* max # of bytes in a queue */
10059839Speter#endif
10159839Speter#ifndef MSGMNI
10259839Speter#define MSGMNI	40
10359839Speter#endif
10459839Speter#ifndef MSGTQL
10559839Speter#define MSGTQL	40
10659839Speter#endif
10759839Speter
10859839Speter/*
10959839Speter * Based on the configuration parameters described in an SVR2 (yes, two)
11059839Speter * config(1m) man page.
11159839Speter *
11259839Speter * Each message is broken up and stored in segments that are msgssz bytes
11359839Speter * long.  For efficiency reasons, this should be a power of two.  Also,
11459839Speter * it doesn't make sense if it is less than 8 or greater than about 256.
11559839Speter * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of
11659839Speter * two between 8 and 1024 inclusive (and panic's if it isn't).
11759839Speter */
11859839Speterstruct msginfo msginfo = {
11959839Speter                MSGMAX,         /* max chars in a message */
12059839Speter                MSGMNI,         /* # of message queue identifiers */
12159839Speter                MSGMNB,         /* max chars in a queue */
12259839Speter                MSGTQL,         /* max messages in system */
12359839Speter                MSGSSZ,         /* size of a message segment */
12459839Speter                		/* (must be small power of 2 greater than 4) */
12559839Speter                MSGSEG          /* number of message segments */
12659839Speter};
12759839Speter
12859839Speter/*
12959839Speter * macros to convert between msqid_ds's and msqid's.
13059839Speter * (specific to this implementation)
13159839Speter */
13259839Speter#define MSQID(ix,ds)	((ix) & 0xffff | (((ds).msg_perm.seq << 16) & 0xffff0000))
13359839Speter#define MSQID_IX(id)	((id) & 0xffff)
13459839Speter#define MSQID_SEQ(id)	(((id) >> 16) & 0xffff)
13559839Speter
13659839Speter/*
13759839Speter * The rest of this file is specific to this particular implementation.
13859839Speter */
13959839Speter
14059839Speterstruct msgmap {
14159839Speter	short	next;		/* next segment in buffer */
14259839Speter    				/* -1 -> available */
14359839Speter    				/* 0..(MSGSEG-1) -> index of next segment */
14459839Speter};
14559839Speter
14659839Speter#define MSG_LOCKED	01000	/* Is this msqid_ds locked? */
14759839Speter
14812819Sphkstatic int nfree_msgmaps;	/* # of free map entries */
14912819Sphkstatic short free_msgmaps;	/* head of linked list of free map entries */
15059839Speterstatic struct msg *free_msghdrs;/* list of free msg headers */
15159839Speterstatic char *msgpool;		/* MSGMAX byte long msg buffer pool */
15259839Speterstatic struct msgmap *msgmaps;	/* MSGSEG msgmap structures */
15359839Speterstatic struct msg *msghdrs;	/* MSGTQL msg headers */
154137613Srwatsonstatic struct msqid_kernel *msqids;	/* MSGMNI msqid_kernel struct's */
155101772Salfredstatic struct mtx msq_mtx;	/* global mutex for message queues. */
1562729Sdfr
157205323Skibstatic struct syscall_helper_data msg_syscalls[] = {
158205323Skib	SYSCALL_INIT_HELPER(msgctl),
159205323Skib	SYSCALL_INIT_HELPER(msgget),
160205323Skib	SYSCALL_INIT_HELPER(msgsnd),
161205323Skib	SYSCALL_INIT_HELPER(msgrcv),
162205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
163205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
164205323Skib	SYSCALL_INIT_HELPER(msgsys),
165205323Skib	SYSCALL_INIT_HELPER(freebsd7_msgctl),
166205323Skib#endif
167205323Skib	SYSCALL_INIT_LAST
168205323Skib};
169205323Skib
170205323Skib#ifdef COMPAT_FREEBSD32
171205323Skib#include <compat/freebsd32/freebsd32.h>
172205323Skib#include <compat/freebsd32/freebsd32_ipc.h>
173205323Skib#include <compat/freebsd32/freebsd32_proto.h>
174205323Skib#include <compat/freebsd32/freebsd32_signal.h>
175205323Skib#include <compat/freebsd32/freebsd32_syscall.h>
176205323Skib#include <compat/freebsd32/freebsd32_util.h>
177205323Skib
178205323Skibstatic struct syscall_helper_data msg32_syscalls[] = {
179205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgctl),
180205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsnd),
181205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgrcv),
182205323Skib	SYSCALL32_INIT_HELPER(msgget),
183205323Skib	SYSCALL32_INIT_HELPER(freebsd32_msgsys),
184205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
185205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
186205323Skib	SYSCALL32_INIT_HELPER(freebsd7_freebsd32_msgctl),
187205323Skib#endif
188205323Skib	SYSCALL_INIT_LAST
189205323Skib};
190205323Skib#endif
191205323Skib
192205323Skibstatic int
19369449Salfredmsginit()
1942729Sdfr{
195205323Skib	int i, error;
1962729Sdfr
19783765Smr	TUNABLE_INT_FETCH("kern.ipc.msgseg", &msginfo.msgseg);
19883765Smr	TUNABLE_INT_FETCH("kern.ipc.msgssz", &msginfo.msgssz);
19983765Smr	msginfo.msgmax = msginfo.msgseg * msginfo.msgssz;
20083765Smr	TUNABLE_INT_FETCH("kern.ipc.msgmni", &msginfo.msgmni);
201139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgmnb", &msginfo.msgmnb);
202139436Srwatson	TUNABLE_INT_FETCH("kern.ipc.msgtql", &msginfo.msgtql);
20383765Smr
204111119Simp	msgpool = malloc(msginfo.msgmax, M_MSG, M_WAITOK);
205111119Simp	msgmaps = malloc(sizeof(struct msgmap) * msginfo.msgseg, M_MSG, M_WAITOK);
206111119Simp	msghdrs = malloc(sizeof(struct msg) * msginfo.msgtql, M_MSG, M_WAITOK);
207137613Srwatson	msqids = malloc(sizeof(struct msqid_kernel) * msginfo.msgmni, M_MSG,
208137613Srwatson	    M_WAITOK);
20959839Speter
2102729Sdfr	/*
2112729Sdfr	 * msginfo.msgssz should be a power of two for efficiency reasons.
2122729Sdfr	 * It is also pretty silly if msginfo.msgssz is less than 8
2132729Sdfr	 * or greater than about 256 so ...
2142729Sdfr	 */
2152729Sdfr
2162729Sdfr	i = 8;
2172729Sdfr	while (i < 1024 && i != msginfo.msgssz)
2182729Sdfr		i <<= 1;
2192729Sdfr    	if (i != msginfo.msgssz) {
220100523Salfred		DPRINTF(("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz,
221100523Salfred		    msginfo.msgssz));
2222729Sdfr		panic("msginfo.msgssz not a small power of 2");
2232729Sdfr	}
2242729Sdfr
2252729Sdfr	if (msginfo.msgseg > 32767) {
226100523Salfred		DPRINTF(("msginfo.msgseg=%d\n", msginfo.msgseg));
2272729Sdfr		panic("msginfo.msgseg > 32767");
2282729Sdfr	}
2292729Sdfr
2302729Sdfr	for (i = 0; i < msginfo.msgseg; i++) {
2312729Sdfr		if (i > 0)
2322729Sdfr			msgmaps[i-1].next = i;
2332729Sdfr		msgmaps[i].next = -1;	/* implies entry is available */
2342729Sdfr	}
2352729Sdfr	free_msgmaps = 0;
2362729Sdfr	nfree_msgmaps = msginfo.msgseg;
2372729Sdfr
2382729Sdfr	for (i = 0; i < msginfo.msgtql; i++) {
2392729Sdfr		msghdrs[i].msg_type = 0;
2402729Sdfr		if (i > 0)
2412729Sdfr			msghdrs[i-1].msg_next = &msghdrs[i];
2422729Sdfr		msghdrs[i].msg_next = NULL;
243140614Srwatson#ifdef MAC
244172930Srwatson		mac_sysvmsg_init(&msghdrs[i]);
245140614Srwatson#endif
2462729Sdfr    	}
2472729Sdfr	free_msghdrs = &msghdrs[0];
2482729Sdfr
2492729Sdfr	for (i = 0; i < msginfo.msgmni; i++) {
250137613Srwatson		msqids[i].u.msg_qbytes = 0;	/* implies entry is available */
251137613Srwatson		msqids[i].u.msg_perm.seq = 0;	/* reset to a known value */
252137613Srwatson		msqids[i].u.msg_perm.mode = 0;
253140614Srwatson#ifdef MAC
254172930Srwatson		mac_sysvmsq_init(&msqids[i]);
255140614Srwatson#endif
2562729Sdfr	}
257101772Salfred	mtx_init(&msq_mtx, "msq", NULL, MTX_DEF);
258205323Skib
259205323Skib	error = syscall_helper_register(msg_syscalls);
260205323Skib	if (error != 0)
261205323Skib		return (error);
262205323Skib#ifdef COMPAT_FREEBSD32
263205323Skib	error = syscall32_helper_register(msg32_syscalls);
264205323Skib	if (error != 0)
265205323Skib		return (error);
266205323Skib#endif
267205323Skib	return (0);
2682729Sdfr}
2692729Sdfr
27069449Salfredstatic int
27169449Salfredmsgunload()
27269449Salfred{
273137613Srwatson	struct msqid_kernel *msqkptr;
27469449Salfred	int msqid;
275140614Srwatson#ifdef MAC
276140614Srwatson	int i;
277140614Srwatson#endif
27869449Salfred
279205323Skib	syscall_helper_unregister(msg_syscalls);
280205323Skib#ifdef COMPAT_FREEBSD32
281205323Skib	syscall32_helper_unregister(msg32_syscalls);
282205323Skib#endif
283205323Skib
28469449Salfred	for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
28569449Salfred		/*
28669449Salfred		 * Look for an unallocated and unlocked msqid_ds.
28769449Salfred		 * msqid_ds's can be locked by msgsnd or msgrcv while
28869449Salfred		 * they are copying the message in/out.  We can't
28969449Salfred		 * re-use the entry until they release it.
29069449Salfred		 */
291137613Srwatson		msqkptr = &msqids[msqid];
292137613Srwatson		if (msqkptr->u.msg_qbytes != 0 ||
293137613Srwatson		    (msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
29469449Salfred			break;
29569449Salfred	}
29669449Salfred	if (msqid != msginfo.msgmni)
29769449Salfred		return (EBUSY);
29869449Salfred
299140614Srwatson#ifdef MAC
300140614Srwatson	for (i = 0; i < msginfo.msgtql; i++)
301172930Srwatson		mac_sysvmsg_destroy(&msghdrs[i]);
302140614Srwatson	for (msqid = 0; msqid < msginfo.msgmni; msqid++)
303172930Srwatson		mac_sysvmsq_destroy(&msqids[msqid]);
304140614Srwatson#endif
30569449Salfred	free(msgpool, M_MSG);
30669449Salfred	free(msgmaps, M_MSG);
30769449Salfred	free(msghdrs, M_MSG);
30869449Salfred	free(msqids, M_MSG);
309101772Salfred	mtx_destroy(&msq_mtx);
31069449Salfred	return (0);
31169449Salfred}
31269449Salfred
31369449Salfred
31469449Salfredstatic int
31569449Salfredsysvmsg_modload(struct module *module, int cmd, void *arg)
31669449Salfred{
31769449Salfred	int error = 0;
31869449Salfred
31969449Salfred	switch (cmd) {
32069449Salfred	case MOD_LOAD:
321205323Skib		error = msginit();
322205323Skib		if (error != 0)
323205323Skib			msgunload();
32469449Salfred		break;
32569449Salfred	case MOD_UNLOAD:
32669449Salfred		error = msgunload();
32769449Salfred		break;
32869449Salfred	case MOD_SHUTDOWN:
32969449Salfred		break;
33069449Salfred	default:
33169449Salfred		error = EINVAL;
33269449Salfred		break;
33369449Salfred	}
33469449Salfred	return (error);
33569449Salfred}
33669449Salfred
33771038Sdesstatic moduledata_t sysvmsg_mod = {
33871038Sdes	"sysvmsg",
33969449Salfred	&sysvmsg_modload,
34069449Salfred	NULL
34169449Salfred};
34269449Salfred
343194832SjhbDECLARE_MODULE(sysvmsg, sysvmsg_mod, SI_SUB_SYSV_MSG, SI_ORDER_FIRST);
34471038SdesMODULE_VERSION(sysvmsg, 1);
34569449Salfred
3462729Sdfrstatic void
3472729Sdfrmsg_freehdr(msghdr)
3482729Sdfr	struct msg *msghdr;
3492729Sdfr{
3502729Sdfr	while (msghdr->msg_ts > 0) {
3512729Sdfr		short next;
3522729Sdfr		if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg)
3532729Sdfr			panic("msghdr->msg_spot out of range");
3542729Sdfr		next = msgmaps[msghdr->msg_spot].next;
3552729Sdfr		msgmaps[msghdr->msg_spot].next = free_msgmaps;
3562729Sdfr		free_msgmaps = msghdr->msg_spot;
3572729Sdfr		nfree_msgmaps++;
3582729Sdfr		msghdr->msg_spot = next;
3592729Sdfr		if (msghdr->msg_ts >= msginfo.msgssz)
3602729Sdfr			msghdr->msg_ts -= msginfo.msgssz;
3612729Sdfr		else
3622729Sdfr			msghdr->msg_ts = 0;
3632729Sdfr	}
3642729Sdfr	if (msghdr->msg_spot != -1)
3652729Sdfr		panic("msghdr->msg_spot != -1");
3662729Sdfr	msghdr->msg_next = free_msghdrs;
3672729Sdfr	free_msghdrs = msghdr;
368140614Srwatson#ifdef MAC
369172930Srwatson	mac_sysvmsg_cleanup(msghdr);
370140614Srwatson#endif
3712729Sdfr}
3722729Sdfr
37312866Speter#ifndef _SYS_SYSPROTO_H_
3742729Sdfrstruct msgctl_args {
3752729Sdfr	int	msqid;
3762729Sdfr	int	cmd;
37712866Speter	struct	msqid_ds *buf;
3782729Sdfr};
37912866Speter#endif
38012866Speterint
38183366Sjulianmsgctl(td, uap)
38283366Sjulian	struct thread *td;
3832729Sdfr	register struct msgctl_args *uap;
3842729Sdfr{
3852729Sdfr	int msqid = uap->msqid;
3862729Sdfr	int cmd = uap->cmd;
3872729Sdfr	struct msqid_ds msqbuf;
388140839Ssobomax	int error;
389140839Ssobomax
390165403Sjkim	DPRINTF(("call to msgctl(%d, %d, %p)\n", msqid, cmd, uap->buf));
391140839Ssobomax	if (cmd == IPC_SET &&
392140839Ssobomax	    (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0)
393140839Ssobomax		return (error);
394141471Sjhb	error = kern_msgctl(td, msqid, cmd, &msqbuf);
395140839Ssobomax	if (cmd == IPC_STAT && error == 0)
396141471Sjhb		error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds));
397140839Ssobomax	return (error);
398140839Ssobomax}
399140839Ssobomax
400140839Ssobomaxint
401141471Sjhbkern_msgctl(td, msqid, cmd, msqbuf)
402140839Ssobomax	struct thread *td;
403140839Ssobomax	int msqid;
404140839Ssobomax	int cmd;
405140839Ssobomax	struct msqid_ds *msqbuf;
406140839Ssobomax{
407140839Ssobomax	int rval, error, msqix;
408137613Srwatson	register struct msqid_kernel *msqkptr;
4092729Sdfr
410192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
41191703Sjhb		return (ENOSYS);
41291703Sjhb
413140839Ssobomax	msqix = IPCID_TO_IX(msqid);
4142729Sdfr
415140839Ssobomax	if (msqix < 0 || msqix >= msginfo.msgmni) {
416140839Ssobomax		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
417100523Salfred		    msginfo.msgmni));
418101772Salfred		return (EINVAL);
4192729Sdfr	}
4202729Sdfr
421140839Ssobomax	msqkptr = &msqids[msqix];
4222729Sdfr
423101772Salfred	mtx_lock(&msq_mtx);
424137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
425100523Salfred		DPRINTF(("no such msqid\n"));
42682607Sdillon		error = EINVAL;
42782607Sdillon		goto done2;
4282729Sdfr	}
429140839Ssobomax	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
430100523Salfred		DPRINTF(("wrong sequence number\n"));
43182607Sdillon		error = EINVAL;
43282607Sdillon		goto done2;
4332729Sdfr	}
434140614Srwatson#ifdef MAC
435172930Srwatson	error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd);
436162468Srwatson	if (error != 0)
437140614Srwatson		goto done2;
438140614Srwatson#endif
4392729Sdfr
44082607Sdillon	error = 0;
4412729Sdfr	rval = 0;
4422729Sdfr
4432729Sdfr	switch (cmd) {
4442729Sdfr
4452729Sdfr	case IPC_RMID:
4462729Sdfr	{
4472729Sdfr		struct msg *msghdr;
448137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
44982607Sdillon			goto done2;
450137613Srwatson
451140614Srwatson#ifdef MAC
452140614Srwatson		/*
453140614Srwatson		 * Check that the thread has MAC access permissions to
454140614Srwatson		 * individual msghdrs.  Note: We need to do this in a
455140614Srwatson		 * separate loop because the actual loop alters the
456140614Srwatson		 * msq/msghdr info as it progresses, and there is no going
457140614Srwatson		 * back if half the way through we discover that the
458140614Srwatson		 * thread cannot free a certain msghdr.  The msq will get
459140614Srwatson		 * into an inconsistent state.
460140614Srwatson		 */
461140614Srwatson		for (msghdr = msqkptr->u.msg_first; msghdr != NULL;
462140614Srwatson		    msghdr = msghdr->msg_next) {
463172930Srwatson			error = mac_sysvmsq_check_msgrmid(td->td_ucred, msghdr);
464162468Srwatson			if (error != 0)
465140614Srwatson				goto done2;
466140614Srwatson		}
467140614Srwatson#endif
468140614Srwatson
469220388Strasz		crfree(msqkptr->cred);
470220388Strasz		msqkptr->cred = NULL;
471220388Strasz
4722729Sdfr		/* Free the message headers */
473137613Srwatson		msghdr = msqkptr->u.msg_first;
4742729Sdfr		while (msghdr != NULL) {
4752729Sdfr			struct msg *msghdr_tmp;
4762729Sdfr
4772729Sdfr			/* Free the segments of each message */
478137613Srwatson			msqkptr->u.msg_cbytes -= msghdr->msg_ts;
479137613Srwatson			msqkptr->u.msg_qnum--;
4802729Sdfr			msghdr_tmp = msghdr;
4812729Sdfr			msghdr = msghdr->msg_next;
4822729Sdfr			msg_freehdr(msghdr_tmp);
4832729Sdfr		}
4842729Sdfr
485137613Srwatson		if (msqkptr->u.msg_cbytes != 0)
4862729Sdfr			panic("msg_cbytes is screwed up");
487137613Srwatson		if (msqkptr->u.msg_qnum != 0)
4882729Sdfr			panic("msg_qnum is screwed up");
4892729Sdfr
490137613Srwatson		msqkptr->u.msg_qbytes = 0;	/* Mark it as free */
4912729Sdfr
492140614Srwatson#ifdef MAC
493172930Srwatson		mac_sysvmsq_cleanup(msqkptr);
494140614Srwatson#endif
495140614Srwatson
496137613Srwatson		wakeup(msqkptr);
4972729Sdfr	}
4982729Sdfr
4992729Sdfr		break;
5002729Sdfr
5012729Sdfr	case IPC_SET:
502137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M)))
50382607Sdillon			goto done2;
504140839Ssobomax		if (msqbuf->msg_qbytes > msqkptr->u.msg_qbytes) {
505170587Srwatson			error = priv_check(td, PRIV_IPC_MSGSIZE);
50682607Sdillon			if (error)
50782607Sdillon				goto done2;
50843426Sphk		}
509140839Ssobomax		if (msqbuf->msg_qbytes > msginfo.msgmnb) {
510100523Salfred			DPRINTF(("can't increase msg_qbytes beyond %d"
511100523Salfred			    "(truncating)\n", msginfo.msgmnb));
512140839Ssobomax			msqbuf->msg_qbytes = msginfo.msgmnb;	/* silently restrict qbytes to system limit */
5132729Sdfr		}
514140839Ssobomax		if (msqbuf->msg_qbytes == 0) {
515100523Salfred			DPRINTF(("can't reduce msg_qbytes to 0\n"));
51682607Sdillon			error = EINVAL;		/* non-standard errno! */
51782607Sdillon			goto done2;
5182729Sdfr		}
519140839Ssobomax		msqkptr->u.msg_perm.uid = msqbuf->msg_perm.uid;	/* change the owner */
520140839Ssobomax		msqkptr->u.msg_perm.gid = msqbuf->msg_perm.gid;	/* change the owner */
521137613Srwatson		msqkptr->u.msg_perm.mode = (msqkptr->u.msg_perm.mode & ~0777) |
522140839Ssobomax		    (msqbuf->msg_perm.mode & 0777);
523140839Ssobomax		msqkptr->u.msg_qbytes = msqbuf->msg_qbytes;
524137613Srwatson		msqkptr->u.msg_ctime = time_second;
5252729Sdfr		break;
5262729Sdfr
5272729Sdfr	case IPC_STAT:
528137613Srwatson		if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
529100523Salfred			DPRINTF(("requester doesn't have read access\n"));
53082607Sdillon			goto done2;
5312729Sdfr		}
532141471Sjhb		*msqbuf = msqkptr->u;
5332729Sdfr		break;
5342729Sdfr
5352729Sdfr	default:
536100523Salfred		DPRINTF(("invalid command %d\n", cmd));
53782607Sdillon		error = EINVAL;
53882607Sdillon		goto done2;
5392729Sdfr	}
5402729Sdfr
54182607Sdillon	if (error == 0)
54283366Sjulian		td->td_retval[0] = rval;
54382607Sdillondone2:
544101772Salfred	mtx_unlock(&msq_mtx);
545141471Sjhb	return (error);
5462729Sdfr}
5472729Sdfr
54812866Speter#ifndef _SYS_SYSPROTO_H_
5492729Sdfrstruct msgget_args {
5502729Sdfr	key_t	key;
5512729Sdfr	int	msgflg;
5522729Sdfr};
55312866Speter#endif
55412866Speterint
55583366Sjulianmsgget(td, uap)
55683366Sjulian	struct thread *td;
5572729Sdfr	register struct msgget_args *uap;
5582729Sdfr{
55982607Sdillon	int msqid, error = 0;
5602729Sdfr	int key = uap->key;
5612729Sdfr	int msgflg = uap->msgflg;
56291703Sjhb	struct ucred *cred = td->td_ucred;
563137613Srwatson	register struct msqid_kernel *msqkptr = NULL;
5642729Sdfr
565100523Salfred	DPRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
5662729Sdfr
567192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
56891703Sjhb		return (ENOSYS);
56991703Sjhb
570101772Salfred	mtx_lock(&msq_mtx);
5712729Sdfr	if (key != IPC_PRIVATE) {
5722729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
573137613Srwatson			msqkptr = &msqids[msqid];
574137613Srwatson			if (msqkptr->u.msg_qbytes != 0 &&
575137613Srwatson			    msqkptr->u.msg_perm.key == key)
5762729Sdfr				break;
5772729Sdfr		}
5782729Sdfr		if (msqid < msginfo.msgmni) {
579100523Salfred			DPRINTF(("found public key\n"));
5802729Sdfr			if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
581100523Salfred				DPRINTF(("not exclusive\n"));
58282607Sdillon				error = EEXIST;
58382607Sdillon				goto done2;
5842729Sdfr			}
585137613Srwatson			if ((error = ipcperm(td, &msqkptr->u.msg_perm,
586137613Srwatson			    msgflg & 0700))) {
587100523Salfred				DPRINTF(("requester doesn't have 0%o access\n",
588100523Salfred				    msgflg & 0700));
58982607Sdillon				goto done2;
5902729Sdfr			}
591140614Srwatson#ifdef MAC
592172930Srwatson			error = mac_sysvmsq_check_msqget(cred, msqkptr);
593162468Srwatson			if (error != 0)
594140614Srwatson				goto done2;
595140614Srwatson#endif
5962729Sdfr			goto found;
5972729Sdfr		}
5982729Sdfr	}
5992729Sdfr
600100523Salfred	DPRINTF(("need to allocate the msqid_ds\n"));
6012729Sdfr	if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
6022729Sdfr		for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
6032729Sdfr			/*
6042729Sdfr			 * Look for an unallocated and unlocked msqid_ds.
6052729Sdfr			 * msqid_ds's can be locked by msgsnd or msgrcv while
6062729Sdfr			 * they are copying the message in/out.  We can't
6072729Sdfr			 * re-use the entry until they release it.
6082729Sdfr			 */
609137613Srwatson			msqkptr = &msqids[msqid];
610137613Srwatson			if (msqkptr->u.msg_qbytes == 0 &&
611137613Srwatson			    (msqkptr->u.msg_perm.mode & MSG_LOCKED) == 0)
6122729Sdfr				break;
6132729Sdfr		}
6142729Sdfr		if (msqid == msginfo.msgmni) {
615100523Salfred			DPRINTF(("no more msqid_ds's available\n"));
61682607Sdillon			error = ENOSPC;
61782607Sdillon			goto done2;
6182729Sdfr		}
619100523Salfred		DPRINTF(("msqid %d is available\n", msqid));
620137613Srwatson		msqkptr->u.msg_perm.key = key;
621137613Srwatson		msqkptr->u.msg_perm.cuid = cred->cr_uid;
622137613Srwatson		msqkptr->u.msg_perm.uid = cred->cr_uid;
623137613Srwatson		msqkptr->u.msg_perm.cgid = cred->cr_gid;
624137613Srwatson		msqkptr->u.msg_perm.gid = cred->cr_gid;
625137613Srwatson		msqkptr->u.msg_perm.mode = (msgflg & 0777);
626220388Strasz		crhold(cred);
627220388Strasz		msqkptr->cred = cred;
6282729Sdfr		/* Make sure that the returned msqid is unique */
629137613Srwatson		msqkptr->u.msg_perm.seq = (msqkptr->u.msg_perm.seq + 1) & 0x7fff;
630137613Srwatson		msqkptr->u.msg_first = NULL;
631137613Srwatson		msqkptr->u.msg_last = NULL;
632137613Srwatson		msqkptr->u.msg_cbytes = 0;
633137613Srwatson		msqkptr->u.msg_qnum = 0;
634137613Srwatson		msqkptr->u.msg_qbytes = msginfo.msgmnb;
635137613Srwatson		msqkptr->u.msg_lspid = 0;
636137613Srwatson		msqkptr->u.msg_lrpid = 0;
637137613Srwatson		msqkptr->u.msg_stime = 0;
638137613Srwatson		msqkptr->u.msg_rtime = 0;
639137613Srwatson		msqkptr->u.msg_ctime = time_second;
640140614Srwatson#ifdef MAC
641172930Srwatson		mac_sysvmsq_create(cred, msqkptr);
642140614Srwatson#endif
6432729Sdfr	} else {
644100523Salfred		DPRINTF(("didn't find it and wasn't asked to create it\n"));
64582607Sdillon		error = ENOENT;
64682607Sdillon		goto done2;
6472729Sdfr	}
6482729Sdfr
6492729Sdfrfound:
6502729Sdfr	/* Construct the unique msqid */
651137613Srwatson	td->td_retval[0] = IXSEQ_TO_IPCID(msqid, msqkptr->u.msg_perm);
65282607Sdillondone2:
653101772Salfred	mtx_unlock(&msq_mtx);
65482607Sdillon	return (error);
6552729Sdfr}
6562729Sdfr
65712866Speter#ifndef _SYS_SYSPROTO_H_
6582729Sdfrstruct msgsnd_args {
6592729Sdfr	int	msqid;
660109895Salfred	const void	*msgp;
6612729Sdfr	size_t	msgsz;
6622729Sdfr	int	msgflg;
6632729Sdfr};
66412866Speter#endif
66512866Speterint
666165403Sjkimkern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype)
66783366Sjulian	struct thread *td;
668165403Sjkim	int msqid;
669165403Sjkim	const void *msgp;	/* XXX msgp is actually mtext. */
670165403Sjkim	size_t msgsz;
671165403Sjkim	int msgflg;
672165403Sjkim	long mtype;
6732729Sdfr{
674165403Sjkim	int msqix, segs_needed, error = 0;
675137613Srwatson	register struct msqid_kernel *msqkptr;
6762729Sdfr	register struct msg *msghdr;
6772729Sdfr	short next;
6782729Sdfr
679192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
68091703Sjhb		return (ENOSYS);
68191703Sjhb
682101772Salfred	mtx_lock(&msq_mtx);
683165403Sjkim	msqix = IPCID_TO_IX(msqid);
6842729Sdfr
685165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
686165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
687100523Salfred		    msginfo.msgmni));
68882607Sdillon		error = EINVAL;
68982607Sdillon		goto done2;
6902729Sdfr	}
6912729Sdfr
692165403Sjkim	msqkptr = &msqids[msqix];
693137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
694100523Salfred		DPRINTF(("no such message queue id\n"));
69582607Sdillon		error = EINVAL;
69682607Sdillon		goto done2;
6972729Sdfr	}
698165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
699100523Salfred		DPRINTF(("wrong sequence number\n"));
70082607Sdillon		error = EINVAL;
70182607Sdillon		goto done2;
7022729Sdfr	}
7032729Sdfr
704137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) {
705100523Salfred		DPRINTF(("requester doesn't have write access\n"));
70682607Sdillon		goto done2;
7072729Sdfr	}
7082729Sdfr
709140614Srwatson#ifdef MAC
710172930Srwatson	error = mac_sysvmsq_check_msqsnd(td->td_ucred, msqkptr);
711162468Srwatson	if (error != 0)
712140614Srwatson		goto done2;
713140614Srwatson#endif
714140614Srwatson
7152729Sdfr	segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
716165403Sjkim	DPRINTF(("msgsz=%zu, msgssz=%d, segs_needed=%d\n", msgsz,
717165403Sjkim	    msginfo.msgssz, segs_needed));
7182729Sdfr	for (;;) {
7192729Sdfr		int need_more_resources = 0;
7202729Sdfr
7212729Sdfr		/*
7222729Sdfr		 * check msgsz
7232729Sdfr		 * (inside this loop in case msg_qbytes changes while we sleep)
7242729Sdfr		 */
7252729Sdfr
726137613Srwatson		if (msgsz > msqkptr->u.msg_qbytes) {
727137613Srwatson			DPRINTF(("msgsz > msqkptr->u.msg_qbytes\n"));
72882607Sdillon			error = EINVAL;
72982607Sdillon			goto done2;
7302729Sdfr		}
7312729Sdfr
732137613Srwatson		if (msqkptr->u.msg_perm.mode & MSG_LOCKED) {
733100523Salfred			DPRINTF(("msqid is locked\n"));
7342729Sdfr			need_more_resources = 1;
7352729Sdfr		}
736137613Srwatson		if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes) {
737100523Salfred			DPRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
7382729Sdfr			need_more_resources = 1;
7392729Sdfr		}
7402729Sdfr		if (segs_needed > nfree_msgmaps) {
741100523Salfred			DPRINTF(("segs_needed > nfree_msgmaps\n"));
7422729Sdfr			need_more_resources = 1;
7432729Sdfr		}
7442729Sdfr		if (free_msghdrs == NULL) {
745100523Salfred			DPRINTF(("no more msghdrs\n"));
7462729Sdfr			need_more_resources = 1;
7472729Sdfr		}
7482729Sdfr
7492729Sdfr		if (need_more_resources) {
7502729Sdfr			int we_own_it;
7512729Sdfr
7522729Sdfr			if ((msgflg & IPC_NOWAIT) != 0) {
753100523Salfred				DPRINTF(("need more resources but caller "
754100523Salfred				    "doesn't want to wait\n"));
75582607Sdillon				error = EAGAIN;
75682607Sdillon				goto done2;
7572729Sdfr			}
7582729Sdfr
759137613Srwatson			if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0) {
760100523Salfred				DPRINTF(("we don't own the msqid_ds\n"));
7612729Sdfr				we_own_it = 0;
7622729Sdfr			} else {
7632729Sdfr				/* Force later arrivals to wait for our
7642729Sdfr				   request */
765100523Salfred				DPRINTF(("we own the msqid_ds\n"));
766137613Srwatson				msqkptr->u.msg_perm.mode |= MSG_LOCKED;
7672729Sdfr				we_own_it = 1;
7682729Sdfr			}
769164368Sjkim			DPRINTF(("msgsnd:  goodnight\n"));
770137613Srwatson			error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
771164368Sjkim			    "msgsnd", hz);
772164368Sjkim			DPRINTF(("msgsnd:  good morning, error=%d\n", error));
7732729Sdfr			if (we_own_it)
774137613Srwatson				msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
775164368Sjkim			if (error == EWOULDBLOCK) {
776164368Sjkim				DPRINTF(("msgsnd:  timed out\n"));
777164368Sjkim				continue;
778164368Sjkim			}
77982607Sdillon			if (error != 0) {
780100523Salfred				DPRINTF(("msgsnd:  interrupted system call\n"));
78182607Sdillon				error = EINTR;
78282607Sdillon				goto done2;
7832729Sdfr			}
7842729Sdfr
7852729Sdfr			/*
7862729Sdfr			 * Make sure that the msq queue still exists
7872729Sdfr			 */
7882729Sdfr
789137613Srwatson			if (msqkptr->u.msg_qbytes == 0) {
790100523Salfred				DPRINTF(("msqid deleted\n"));
79182607Sdillon				error = EIDRM;
79282607Sdillon				goto done2;
7932729Sdfr			}
7942729Sdfr
7952729Sdfr		} else {
796100523Salfred			DPRINTF(("got all the resources that we need\n"));
7972729Sdfr			break;
7982729Sdfr		}
7992729Sdfr	}
8002729Sdfr
8012729Sdfr	/*
8022729Sdfr	 * We have the resources that we need.
8032729Sdfr	 * Make sure!
8042729Sdfr	 */
8052729Sdfr
806137613Srwatson	if (msqkptr->u.msg_perm.mode & MSG_LOCKED)
8072729Sdfr		panic("msg_perm.mode & MSG_LOCKED");
8082729Sdfr	if (segs_needed > nfree_msgmaps)
8092729Sdfr		panic("segs_needed > nfree_msgmaps");
810137613Srwatson	if (msgsz + msqkptr->u.msg_cbytes > msqkptr->u.msg_qbytes)
8112729Sdfr		panic("msgsz + msg_cbytes > msg_qbytes");
8122729Sdfr	if (free_msghdrs == NULL)
8132729Sdfr		panic("no more msghdrs");
8142729Sdfr
8152729Sdfr	/*
8162729Sdfr	 * Re-lock the msqid_ds in case we page-fault when copying in the
8172729Sdfr	 * message
8182729Sdfr	 */
8192729Sdfr
820137613Srwatson	if ((msqkptr->u.msg_perm.mode & MSG_LOCKED) != 0)
8212729Sdfr		panic("msqid_ds is already locked");
822137613Srwatson	msqkptr->u.msg_perm.mode |= MSG_LOCKED;
8232729Sdfr
8242729Sdfr	/*
8252729Sdfr	 * Allocate a message header
8262729Sdfr	 */
8272729Sdfr
8282729Sdfr	msghdr = free_msghdrs;
8292729Sdfr	free_msghdrs = msghdr->msg_next;
8302729Sdfr	msghdr->msg_spot = -1;
8312729Sdfr	msghdr->msg_ts = msgsz;
832165403Sjkim	msghdr->msg_type = mtype;
833140614Srwatson#ifdef MAC
834140614Srwatson	/*
835172930Srwatson	 * XXXMAC: Should the mac_sysvmsq_check_msgmsq check follow here
836140614Srwatson	 * immediately?  Or, should it be checked just before the msg is
837140614Srwatson	 * enqueued in the msgq (as it is done now)?
838140614Srwatson	 */
839172930Srwatson	mac_sysvmsg_create(td->td_ucred, msqkptr, msghdr);
840140614Srwatson#endif
8412729Sdfr
8422729Sdfr	/*
8432729Sdfr	 * Allocate space for the message
8442729Sdfr	 */
8452729Sdfr
8462729Sdfr	while (segs_needed > 0) {
8472729Sdfr		if (nfree_msgmaps <= 0)
8482729Sdfr			panic("not enough msgmaps");
8492729Sdfr		if (free_msgmaps == -1)
8502729Sdfr			panic("nil free_msgmaps");
8512729Sdfr		next = free_msgmaps;
8522729Sdfr		if (next <= -1)
8532729Sdfr			panic("next too low #1");
8542729Sdfr		if (next >= msginfo.msgseg)
8552729Sdfr			panic("next out of range #1");
856100523Salfred		DPRINTF(("allocating segment %d to message\n", next));
8572729Sdfr		free_msgmaps = msgmaps[next].next;
8582729Sdfr		nfree_msgmaps--;
8592729Sdfr		msgmaps[next].next = msghdr->msg_spot;
8602729Sdfr		msghdr->msg_spot = next;
8612729Sdfr		segs_needed--;
8622729Sdfr	}
8632729Sdfr
8642729Sdfr	/*
8652729Sdfr	 * Validate the message type
8662729Sdfr	 */
8672729Sdfr
8682729Sdfr	if (msghdr->msg_type < 1) {
8692729Sdfr		msg_freehdr(msghdr);
870137613Srwatson		msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
871137613Srwatson		wakeup(msqkptr);
872165403Sjkim		DPRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
87382607Sdillon		error = EINVAL;
87482607Sdillon		goto done2;
8752729Sdfr	}
8762729Sdfr
8772729Sdfr	/*
8782729Sdfr	 * Copy in the message body
8792729Sdfr	 */
8802729Sdfr
8812729Sdfr	next = msghdr->msg_spot;
8822729Sdfr	while (msgsz > 0) {
8832729Sdfr		size_t tlen;
8842729Sdfr		if (msgsz > msginfo.msgssz)
8852729Sdfr			tlen = msginfo.msgssz;
8862729Sdfr		else
8872729Sdfr			tlen = msgsz;
8882729Sdfr		if (next <= -1)
8892729Sdfr			panic("next too low #2");
8902729Sdfr		if (next >= msginfo.msgseg)
8912729Sdfr			panic("next out of range #2");
892101772Salfred		mtx_unlock(&msq_mtx);
893165403Sjkim		if ((error = copyin(msgp, &msgpool[next * msginfo.msgssz],
8942729Sdfr		    tlen)) != 0) {
895101772Salfred			mtx_lock(&msq_mtx);
896100523Salfred			DPRINTF(("error %d copying in message segment\n",
897100523Salfred			    error));
8982729Sdfr			msg_freehdr(msghdr);
899137613Srwatson			msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
900137613Srwatson			wakeup(msqkptr);
90182607Sdillon			goto done2;
9022729Sdfr		}
903101772Salfred		mtx_lock(&msq_mtx);
9042729Sdfr		msgsz -= tlen;
905165403Sjkim		msgp = (const char *)msgp + tlen;
9062729Sdfr		next = msgmaps[next].next;
9072729Sdfr	}
9082729Sdfr	if (next != -1)
9092729Sdfr		panic("didn't use all the msg segments");
9102729Sdfr
9112729Sdfr	/*
9122729Sdfr	 * We've got the message.  Unlock the msqid_ds.
9132729Sdfr	 */
9142729Sdfr
915137613Srwatson	msqkptr->u.msg_perm.mode &= ~MSG_LOCKED;
9162729Sdfr
9172729Sdfr	/*
9182729Sdfr	 * Make sure that the msqid_ds is still allocated.
9192729Sdfr	 */
9202729Sdfr
921137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
9222729Sdfr		msg_freehdr(msghdr);
923137613Srwatson		wakeup(msqkptr);
92482607Sdillon		error = EIDRM;
92582607Sdillon		goto done2;
9262729Sdfr	}
9272729Sdfr
928140614Srwatson#ifdef MAC
9292729Sdfr	/*
930140614Srwatson	 * Note: Since the task/thread allocates the msghdr and usually
931140614Srwatson	 * primes it with its own MAC label, for a majority of policies, it
932140614Srwatson	 * won't be necessary to check whether the msghdr has access
933172930Srwatson	 * permissions to the msgq.  The mac_sysvmsq_check_msqsnd check would
934140614Srwatson	 * suffice in that case.  However, this hook may be required where
935140614Srwatson	 * individual policies derive a non-identical label for the msghdr
936140614Srwatson	 * from the current thread label and may want to check the msghdr
937140614Srwatson	 * enqueue permissions, along with read/write permissions to the
938140614Srwatson	 * msgq.
939140614Srwatson	 */
940172930Srwatson	error = mac_sysvmsq_check_msgmsq(td->td_ucred, msghdr, msqkptr);
941140614Srwatson	if (error != 0) {
942140614Srwatson		msg_freehdr(msghdr);
943140614Srwatson		wakeup(msqkptr);
944140614Srwatson		goto done2;
945140614Srwatson	}
946140614Srwatson#endif
947140614Srwatson
948140614Srwatson	/*
9492729Sdfr	 * Put the message into the queue
9502729Sdfr	 */
951137613Srwatson	if (msqkptr->u.msg_first == NULL) {
952137613Srwatson		msqkptr->u.msg_first = msghdr;
953137613Srwatson		msqkptr->u.msg_last = msghdr;
9542729Sdfr	} else {
955137613Srwatson		msqkptr->u.msg_last->msg_next = msghdr;
956137613Srwatson		msqkptr->u.msg_last = msghdr;
9572729Sdfr	}
958137613Srwatson	msqkptr->u.msg_last->msg_next = NULL;
9592729Sdfr
960137613Srwatson	msqkptr->u.msg_cbytes += msghdr->msg_ts;
961137613Srwatson	msqkptr->u.msg_qnum++;
962137613Srwatson	msqkptr->u.msg_lspid = td->td_proc->p_pid;
963137613Srwatson	msqkptr->u.msg_stime = time_second;
9642729Sdfr
965137613Srwatson	wakeup(msqkptr);
96683366Sjulian	td->td_retval[0] = 0;
96782607Sdillondone2:
968101772Salfred	mtx_unlock(&msq_mtx);
96982607Sdillon	return (error);
9702729Sdfr}
9712729Sdfr
972165403Sjkimint
973165403Sjkimmsgsnd(td, uap)
974165403Sjkim	struct thread *td;
975165403Sjkim	register struct msgsnd_args *uap;
976165403Sjkim{
977165403Sjkim	int error;
978165403Sjkim	long mtype;
979165403Sjkim
980165403Sjkim	DPRINTF(("call to msgsnd(%d, %p, %zu, %d)\n", uap->msqid, uap->msgp,
981165403Sjkim	    uap->msgsz, uap->msgflg));
982165403Sjkim
983165403Sjkim	if ((error = copyin(uap->msgp, &mtype, sizeof(mtype))) != 0) {
984165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
985165403Sjkim		return (error);
986165403Sjkim	}
987165403Sjkim	return (kern_msgsnd(td, uap->msqid,
988165403Sjkim	    (const char *)uap->msgp + sizeof(mtype),
989165403Sjkim	    uap->msgsz, uap->msgflg, mtype));
990165403Sjkim}
991165403Sjkim
99212866Speter#ifndef _SYS_SYSPROTO_H_
9932729Sdfrstruct msgrcv_args {
9942729Sdfr	int	msqid;
9952729Sdfr	void	*msgp;
9962729Sdfr	size_t	msgsz;
9972729Sdfr	long	msgtyp;
9982729Sdfr	int	msgflg;
9992729Sdfr};
100012866Speter#endif
100112866Speterint
1002165403Sjkimkern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype)
100383366Sjulian	struct thread *td;
1004165403Sjkim	int msqid;
1005165403Sjkim	void *msgp;	/* XXX msgp is actually mtext. */
1006165403Sjkim	size_t msgsz;
1007165403Sjkim	long msgtyp;
1008165403Sjkim	int msgflg;
1009165403Sjkim	long *mtype;
10102729Sdfr{
10112729Sdfr	size_t len;
1012137613Srwatson	register struct msqid_kernel *msqkptr;
10132729Sdfr	register struct msg *msghdr;
1014165403Sjkim	int msqix, error = 0;
10152729Sdfr	short next;
10162729Sdfr
1017192895Sjamie	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
101891703Sjhb		return (ENOSYS);
101991703Sjhb
1020165403Sjkim	msqix = IPCID_TO_IX(msqid);
10212729Sdfr
1022165403Sjkim	if (msqix < 0 || msqix >= msginfo.msgmni) {
1023165403Sjkim		DPRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqix,
1024100523Salfred		    msginfo.msgmni));
1025101772Salfred		return (EINVAL);
10262729Sdfr	}
10272729Sdfr
1028165403Sjkim	msqkptr = &msqids[msqix];
1029101772Salfred	mtx_lock(&msq_mtx);
1030137613Srwatson	if (msqkptr->u.msg_qbytes == 0) {
1031100523Salfred		DPRINTF(("no such message queue id\n"));
103282607Sdillon		error = EINVAL;
103382607Sdillon		goto done2;
10342729Sdfr	}
1035165403Sjkim	if (msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1036100523Salfred		DPRINTF(("wrong sequence number\n"));
103782607Sdillon		error = EINVAL;
103882607Sdillon		goto done2;
10392729Sdfr	}
10402729Sdfr
1041137613Srwatson	if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) {
1042100523Salfred		DPRINTF(("requester doesn't have read access\n"));
104382607Sdillon		goto done2;
10442729Sdfr	}
10452729Sdfr
1046140614Srwatson#ifdef MAC
1047172930Srwatson	error = mac_sysvmsq_check_msqrcv(td->td_ucred, msqkptr);
1048162468Srwatson	if (error != 0)
1049140614Srwatson		goto done2;
1050140614Srwatson#endif
1051140614Srwatson
10522729Sdfr	msghdr = NULL;
10532729Sdfr	while (msghdr == NULL) {
10542729Sdfr		if (msgtyp == 0) {
1055137613Srwatson			msghdr = msqkptr->u.msg_first;
10562729Sdfr			if (msghdr != NULL) {
10572729Sdfr				if (msgsz < msghdr->msg_ts &&
10582729Sdfr				    (msgflg & MSG_NOERROR) == 0) {
1059100523Salfred					DPRINTF(("first message on the queue "
1060165403Sjkim					    "is too big (want %zu, got %d)\n",
1061100523Salfred					    msgsz, msghdr->msg_ts));
106282607Sdillon					error = E2BIG;
106382607Sdillon					goto done2;
10642729Sdfr				}
1065140614Srwatson#ifdef MAC
1066172930Srwatson				error = mac_sysvmsq_check_msgrcv(td->td_ucred,
1067140614Srwatson				    msghdr);
1068162468Srwatson				if (error != 0)
1069140614Srwatson					goto done2;
1070140614Srwatson#endif
1071137613Srwatson				if (msqkptr->u.msg_first == msqkptr->u.msg_last) {
1072137613Srwatson					msqkptr->u.msg_first = NULL;
1073137613Srwatson					msqkptr->u.msg_last = NULL;
10742729Sdfr				} else {
1075137613Srwatson					msqkptr->u.msg_first = msghdr->msg_next;
1076137613Srwatson					if (msqkptr->u.msg_first == NULL)
10772729Sdfr						panic("msg_first/last screwed up #1");
10782729Sdfr				}
10792729Sdfr			}
10802729Sdfr		} else {
10812729Sdfr			struct msg *previous;
10822729Sdfr			struct msg **prev;
10832729Sdfr
10842729Sdfr			previous = NULL;
1085137613Srwatson			prev = &(msqkptr->u.msg_first);
10862729Sdfr			while ((msghdr = *prev) != NULL) {
10872729Sdfr				/*
10882729Sdfr				 * Is this message's type an exact match or is
10892729Sdfr				 * this message's type less than or equal to
10902729Sdfr				 * the absolute value of a negative msgtyp?
10912729Sdfr				 * Note that the second half of this test can
10922729Sdfr				 * NEVER be true if msgtyp is positive since
10932729Sdfr				 * msg_type is always positive!
10942729Sdfr				 */
10952729Sdfr
10962729Sdfr				if (msgtyp == msghdr->msg_type ||
10972729Sdfr				    msghdr->msg_type <= -msgtyp) {
1098165403Sjkim					DPRINTF(("found message type %ld, "
1099165403Sjkim					    "requested %ld\n",
1100100523Salfred					    msghdr->msg_type, msgtyp));
11012729Sdfr					if (msgsz < msghdr->msg_ts &&
11022729Sdfr					    (msgflg & MSG_NOERROR) == 0) {
1103100523Salfred						DPRINTF(("requested message "
1104100523Salfred						    "on the queue is too big "
1105165403Sjkim						    "(want %zu, got %hu)\n",
1106100523Salfred						    msgsz, msghdr->msg_ts));
110782607Sdillon						error = E2BIG;
110882607Sdillon						goto done2;
11092729Sdfr					}
1110140614Srwatson#ifdef MAC
1111172930Srwatson					error = mac_sysvmsq_check_msgrcv(
1112140614Srwatson					    td->td_ucred, msghdr);
1113162468Srwatson					if (error != 0)
1114140614Srwatson						goto done2;
1115140614Srwatson#endif
11162729Sdfr					*prev = msghdr->msg_next;
1117137613Srwatson					if (msghdr == msqkptr->u.msg_last) {
11182729Sdfr						if (previous == NULL) {
11192729Sdfr							if (prev !=
1120137613Srwatson							    &msqkptr->u.msg_first)
11212729Sdfr								panic("msg_first/last screwed up #2");
1122137613Srwatson							msqkptr->u.msg_first =
11232729Sdfr							    NULL;
1124137613Srwatson							msqkptr->u.msg_last =
11252729Sdfr							    NULL;
11262729Sdfr						} else {
11272729Sdfr							if (prev ==
1128137613Srwatson							    &msqkptr->u.msg_first)
11292729Sdfr								panic("msg_first/last screwed up #3");
1130137613Srwatson							msqkptr->u.msg_last =
11312729Sdfr							    previous;
11322729Sdfr						}
11332729Sdfr					}
11342729Sdfr					break;
11352729Sdfr				}
11362729Sdfr				previous = msghdr;
11372729Sdfr				prev = &(msghdr->msg_next);
11382729Sdfr			}
11392729Sdfr		}
11402729Sdfr
11412729Sdfr		/*
11422729Sdfr		 * We've either extracted the msghdr for the appropriate
11432729Sdfr		 * message or there isn't one.
11442729Sdfr		 * If there is one then bail out of this loop.
11452729Sdfr		 */
11462729Sdfr
11472729Sdfr		if (msghdr != NULL)
11482729Sdfr			break;
11492729Sdfr
11502729Sdfr		/*
11512729Sdfr		 * Hmph!  No message found.  Does the user want to wait?
11522729Sdfr		 */
11532729Sdfr
11542729Sdfr		if ((msgflg & IPC_NOWAIT) != 0) {
1155165403Sjkim			DPRINTF(("no appropriate message found (msgtyp=%ld)\n",
1156100523Salfred			    msgtyp));
11572729Sdfr			/* The SVID says to return ENOMSG. */
115882607Sdillon			error = ENOMSG;
115982607Sdillon			goto done2;
11602729Sdfr		}
11612729Sdfr
11622729Sdfr		/*
11632729Sdfr		 * Wait for something to happen
11642729Sdfr		 */
11652729Sdfr
1166100523Salfred		DPRINTF(("msgrcv:  goodnight\n"));
1167137613Srwatson		error = msleep(msqkptr, &msq_mtx, (PZERO - 4) | PCATCH,
1168164368Sjkim		    "msgrcv", 0);
1169100523Salfred		DPRINTF(("msgrcv:  good morning (error=%d)\n", error));
11702729Sdfr
117182607Sdillon		if (error != 0) {
1172164368Sjkim			DPRINTF(("msgrcv:  interrupted system call\n"));
117382607Sdillon			error = EINTR;
117482607Sdillon			goto done2;
11752729Sdfr		}
11762729Sdfr
11772729Sdfr		/*
11782729Sdfr		 * Make sure that the msq queue still exists
11792729Sdfr		 */
11802729Sdfr
1181137613Srwatson		if (msqkptr->u.msg_qbytes == 0 ||
1182165403Sjkim		    msqkptr->u.msg_perm.seq != IPCID_TO_SEQ(msqid)) {
1183100523Salfred			DPRINTF(("msqid deleted\n"));
118482607Sdillon			error = EIDRM;
118582607Sdillon			goto done2;
11862729Sdfr		}
11872729Sdfr	}
11882729Sdfr
11892729Sdfr	/*
11902729Sdfr	 * Return the message to the user.
11912729Sdfr	 *
11922729Sdfr	 * First, do the bookkeeping (before we risk being interrupted).
11932729Sdfr	 */
11942729Sdfr
1195137613Srwatson	msqkptr->u.msg_cbytes -= msghdr->msg_ts;
1196137613Srwatson	msqkptr->u.msg_qnum--;
1197137613Srwatson	msqkptr->u.msg_lrpid = td->td_proc->p_pid;
1198137613Srwatson	msqkptr->u.msg_rtime = time_second;
11992729Sdfr
12002729Sdfr	/*
12012729Sdfr	 * Make msgsz the actual amount that we'll be returning.
12022729Sdfr	 * Note that this effectively truncates the message if it is too long
12032729Sdfr	 * (since msgsz is never increased).
12042729Sdfr	 */
12052729Sdfr
1206165403Sjkim	DPRINTF(("found a message, msgsz=%zu, msg_ts=%hu\n", msgsz,
1207100523Salfred	    msghdr->msg_ts));
12082729Sdfr	if (msgsz > msghdr->msg_ts)
12092729Sdfr		msgsz = msghdr->msg_ts;
1210165403Sjkim	*mtype = msghdr->msg_type;
12112729Sdfr
12122729Sdfr	/*
12132729Sdfr	 * Return the segments to the user
12142729Sdfr	 */
12152729Sdfr
12162729Sdfr	next = msghdr->msg_spot;
12172729Sdfr	for (len = 0; len < msgsz; len += msginfo.msgssz) {
12182729Sdfr		size_t tlen;
12192729Sdfr
122045921Ssada		if (msgsz - len > msginfo.msgssz)
12212729Sdfr			tlen = msginfo.msgssz;
12222729Sdfr		else
122345921Ssada			tlen = msgsz - len;
12242729Sdfr		if (next <= -1)
12252729Sdfr			panic("next too low #3");
12262729Sdfr		if (next >= msginfo.msgseg)
12272729Sdfr			panic("next out of range #3");
1228101772Salfred		mtx_unlock(&msq_mtx);
1229165403Sjkim		error = copyout(&msgpool[next * msginfo.msgssz], msgp, tlen);
1230101772Salfred		mtx_lock(&msq_mtx);
123182607Sdillon		if (error != 0) {
1232100523Salfred			DPRINTF(("error (%d) copying out message segment\n",
1233100523Salfred			    error));
12342729Sdfr			msg_freehdr(msghdr);
1235137613Srwatson			wakeup(msqkptr);
123682607Sdillon			goto done2;
12372729Sdfr		}
1238165403Sjkim		msgp = (char *)msgp + tlen;
12392729Sdfr		next = msgmaps[next].next;
12402729Sdfr	}
12412729Sdfr
12422729Sdfr	/*
12432729Sdfr	 * Done, return the actual number of bytes copied out.
12442729Sdfr	 */
12452729Sdfr
12462729Sdfr	msg_freehdr(msghdr);
1247137613Srwatson	wakeup(msqkptr);
124883366Sjulian	td->td_retval[0] = msgsz;
124982607Sdillondone2:
1250101772Salfred	mtx_unlock(&msq_mtx);
125182607Sdillon	return (error);
12522729Sdfr}
125377461Sdd
1254165403Sjkimint
1255165403Sjkimmsgrcv(td, uap)
1256165403Sjkim	struct thread *td;
1257165403Sjkim	register struct msgrcv_args *uap;
1258165403Sjkim{
1259165403Sjkim	int error;
1260165403Sjkim	long mtype;
1261165403Sjkim
1262165403Sjkim	DPRINTF(("call to msgrcv(%d, %p, %zu, %ld, %d)\n", uap->msqid,
1263165403Sjkim	    uap->msgp, uap->msgsz, uap->msgtyp, uap->msgflg));
1264165403Sjkim
1265165403Sjkim	if ((error = kern_msgrcv(td, uap->msqid,
1266165403Sjkim	    (char *)uap->msgp + sizeof(mtype), uap->msgsz,
1267165403Sjkim	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1268165403Sjkim		return (error);
1269165403Sjkim	if ((error = copyout(&mtype, uap->msgp, sizeof(mtype))) != 0)
1270165403Sjkim		DPRINTF(("error %d copying the message type\n", error));
1271165403Sjkim	return (error);
1272165403Sjkim}
1273165403Sjkim
127477461Sddstatic int
127577461Sddsysctl_msqids(SYSCTL_HANDLER_ARGS)
127677461Sdd{
127777461Sdd
127877461Sdd	return (SYSCTL_OUT(req, msqids,
1279137613Srwatson	    sizeof(struct msqid_kernel) * msginfo.msgmni));
128077461Sdd}
128177461Sdd
1282141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0,
1283141710Scsjp    "Maximum message size");
1284141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmni, CTLFLAG_RDTUN, &msginfo.msgmni, 0,
1285141710Scsjp    "Number of message queue identifiers");
1286141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgmnb, CTLFLAG_RDTUN, &msginfo.msgmnb, 0,
1287141710Scsjp    "Maximum number of bytes in a queue");
1288141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgtql, CTLFLAG_RDTUN, &msginfo.msgtql, 0,
1289141710Scsjp    "Maximum number of messages in the system");
1290141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgssz, CTLFLAG_RDTUN, &msginfo.msgssz, 0,
1291141710Scsjp    "Size of a message segment");
1292141710ScsjpSYSCTL_INT(_kern_ipc, OID_AUTO, msgseg, CTLFLAG_RDTUN, &msginfo.msgseg, 0,
1293141710Scsjp    "Number of message segments");
1294217555SmdfSYSCTL_PROC(_kern_ipc, OID_AUTO, msqids, CTLTYPE_OPAQUE | CTLFLAG_RD,
129577461Sdd    NULL, 0, sysctl_msqids, "", "Message queue IDs");
1296194894Sjhb
1297205323Skib#ifdef COMPAT_FREEBSD32
1298205323Skibint
1299205323Skibfreebsd32_msgsys(struct thread *td, struct freebsd32_msgsys_args *uap)
1300205323Skib{
1301205323Skib
1302194894Sjhb#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1303194894Sjhb    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1304205323Skib	switch (uap->which) {
1305205323Skib	case 0:
1306205323Skib		return (freebsd7_freebsd32_msgctl(td,
1307205323Skib		    (struct freebsd7_freebsd32_msgctl_args *)&uap->a2));
1308205323Skib	case 2:
1309205323Skib		return (freebsd32_msgsnd(td,
1310205323Skib		    (struct freebsd32_msgsnd_args *)&uap->a2));
1311205323Skib	case 3:
1312205323Skib		return (freebsd32_msgrcv(td,
1313205323Skib		    (struct freebsd32_msgrcv_args *)&uap->a2));
1314205323Skib	default:
1315205323Skib		return (msgsys(td, (struct msgsys_args *)uap));
1316205323Skib	}
1317205323Skib#else
1318205323Skib	return (nosys(td, NULL));
1319205323Skib#endif
1320205323Skib}
1321194894Sjhb
1322205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1323205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1324205323Skibint
1325205323Skibfreebsd7_freebsd32_msgctl(struct thread *td,
1326205323Skib    struct freebsd7_freebsd32_msgctl_args *uap)
1327205323Skib{
1328205323Skib	struct msqid_ds msqbuf;
1329205323Skib	struct msqid_ds32_old msqbuf32;
1330205323Skib	int error;
1331205323Skib
1332205323Skib	if (uap->cmd == IPC_SET) {
1333205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1334205323Skib		if (error)
1335205323Skib			return (error);
1336205323Skib		freebsd32_ipcperm_old_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1337205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1338205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1339205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1340205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1341205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1342205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1343205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1344205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1345205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1346205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1347205323Skib	}
1348205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1349205323Skib	if (error)
1350205323Skib		return (error);
1351205323Skib	if (uap->cmd == IPC_STAT) {
1352205323Skib		bzero(&msqbuf32, sizeof(msqbuf32));
1353205323Skib		freebsd32_ipcperm_old_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1354205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1355205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1356205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1357205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1358205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1359205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1360205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1361205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1362205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1363205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1364205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1365205323Skib	}
1366205323Skib	return (error);
1367205323Skib}
1368205323Skib#endif
1369205323Skib
1370205323Skibint
1371205323Skibfreebsd32_msgctl(struct thread *td, struct freebsd32_msgctl_args *uap)
1372205323Skib{
1373205323Skib	struct msqid_ds msqbuf;
1374205323Skib	struct msqid_ds32 msqbuf32;
1375205323Skib	int error;
1376205323Skib
1377205323Skib	if (uap->cmd == IPC_SET) {
1378205323Skib		error = copyin(uap->buf, &msqbuf32, sizeof(msqbuf32));
1379205323Skib		if (error)
1380205323Skib			return (error);
1381205323Skib		freebsd32_ipcperm_in(&msqbuf32.msg_perm, &msqbuf.msg_perm);
1382205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_first);
1383205323Skib		PTRIN_CP(msqbuf32, msqbuf, msg_last);
1384205323Skib		CP(msqbuf32, msqbuf, msg_cbytes);
1385205323Skib		CP(msqbuf32, msqbuf, msg_qnum);
1386205323Skib		CP(msqbuf32, msqbuf, msg_qbytes);
1387205323Skib		CP(msqbuf32, msqbuf, msg_lspid);
1388205323Skib		CP(msqbuf32, msqbuf, msg_lrpid);
1389205323Skib		CP(msqbuf32, msqbuf, msg_stime);
1390205323Skib		CP(msqbuf32, msqbuf, msg_rtime);
1391205323Skib		CP(msqbuf32, msqbuf, msg_ctime);
1392205323Skib	}
1393205323Skib	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1394205323Skib	if (error)
1395205323Skib		return (error);
1396205323Skib	if (uap->cmd == IPC_STAT) {
1397205323Skib		freebsd32_ipcperm_out(&msqbuf.msg_perm, &msqbuf32.msg_perm);
1398205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_first);
1399205323Skib		PTROUT_CP(msqbuf, msqbuf32, msg_last);
1400205323Skib		CP(msqbuf, msqbuf32, msg_cbytes);
1401205323Skib		CP(msqbuf, msqbuf32, msg_qnum);
1402205323Skib		CP(msqbuf, msqbuf32, msg_qbytes);
1403205323Skib		CP(msqbuf, msqbuf32, msg_lspid);
1404205323Skib		CP(msqbuf, msqbuf32, msg_lrpid);
1405205323Skib		CP(msqbuf, msqbuf32, msg_stime);
1406205323Skib		CP(msqbuf, msqbuf32, msg_rtime);
1407205323Skib		CP(msqbuf, msqbuf32, msg_ctime);
1408205323Skib		error = copyout(&msqbuf32, uap->buf, sizeof(struct msqid_ds32));
1409205323Skib	}
1410205323Skib	return (error);
1411205323Skib}
1412205323Skib
1413205323Skibint
1414205323Skibfreebsd32_msgsnd(struct thread *td, struct freebsd32_msgsnd_args *uap)
1415205323Skib{
1416205323Skib	const void *msgp;
1417205323Skib	long mtype;
1418205323Skib	int32_t mtype32;
1419205323Skib	int error;
1420205323Skib
1421205323Skib	msgp = PTRIN(uap->msgp);
1422205323Skib	if ((error = copyin(msgp, &mtype32, sizeof(mtype32))) != 0)
1423205323Skib		return (error);
1424205323Skib	mtype = mtype32;
1425205323Skib	return (kern_msgsnd(td, uap->msqid,
1426205323Skib	    (const char *)msgp + sizeof(mtype32),
1427205323Skib	    uap->msgsz, uap->msgflg, mtype));
1428205323Skib}
1429205323Skib
1430205323Skibint
1431205323Skibfreebsd32_msgrcv(struct thread *td, struct freebsd32_msgrcv_args *uap)
1432205323Skib{
1433205323Skib	void *msgp;
1434205323Skib	long mtype;
1435205323Skib	int32_t mtype32;
1436205323Skib	int error;
1437205323Skib
1438205323Skib	msgp = PTRIN(uap->msgp);
1439205323Skib	if ((error = kern_msgrcv(td, uap->msqid,
1440205323Skib	    (char *)msgp + sizeof(mtype32), uap->msgsz,
1441205323Skib	    uap->msgtyp, uap->msgflg, &mtype)) != 0)
1442205323Skib		return (error);
1443205323Skib	mtype32 = (int32_t)mtype;
1444205323Skib	return (copyout(&mtype32, msgp, sizeof(mtype32)));
1445205323Skib}
1446205323Skib#endif
1447205323Skib
1448205323Skib#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1449205323Skib    defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1450205323Skib
1451194894Sjhb/* XXX casting to (sy_call_t *) is bogus, as usual. */
1452194894Sjhbstatic sy_call_t *msgcalls[] = {
1453194910Sjhb	(sy_call_t *)freebsd7_msgctl, (sy_call_t *)msgget,
1454194894Sjhb	(sy_call_t *)msgsnd, (sy_call_t *)msgrcv
1455194894Sjhb};
1456194894Sjhb
1457194894Sjhb/*
1458194894Sjhb * Entry point for all MSG calls.
1459194894Sjhb */
1460194894Sjhbint
1461194894Sjhbmsgsys(td, uap)
1462194894Sjhb	struct thread *td;
1463194894Sjhb	/* XXX actually varargs. */
1464194894Sjhb	struct msgsys_args /* {
1465194894Sjhb		int	which;
1466194894Sjhb		int	a2;
1467194894Sjhb		int	a3;
1468194894Sjhb		int	a4;
1469194894Sjhb		int	a5;
1470194894Sjhb		int	a6;
1471194894Sjhb	} */ *uap;
1472194894Sjhb{
1473194894Sjhb	int error;
1474194894Sjhb
1475194894Sjhb	if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1476194894Sjhb		return (ENOSYS);
1477194894Sjhb	if (uap->which < 0 ||
1478194894Sjhb	    uap->which >= sizeof(msgcalls)/sizeof(msgcalls[0]))
1479194894Sjhb		return (EINVAL);
1480194894Sjhb	error = (*msgcalls[uap->which])(td, &uap->a2);
1481194894Sjhb	return (error);
1482194894Sjhb}
1483194910Sjhb
1484205323Skib#ifndef CP
1485194910Sjhb#define CP(src, dst, fld)	do { (dst).fld = (src).fld; } while (0)
1486205323Skib#endif
1487194910Sjhb
1488194910Sjhb#ifndef _SYS_SYSPROTO_H_
1489194910Sjhbstruct freebsd7_msgctl_args {
1490194910Sjhb	int	msqid;
1491194910Sjhb	int	cmd;
1492194910Sjhb	struct	msqid_ds_old *buf;
1493194910Sjhb};
1494194910Sjhb#endif
1495194910Sjhbint
1496194910Sjhbfreebsd7_msgctl(td, uap)
1497194910Sjhb	struct thread *td;
1498194910Sjhb	struct freebsd7_msgctl_args *uap;
1499194910Sjhb{
1500194910Sjhb	struct msqid_ds_old msqold;
1501194910Sjhb	struct msqid_ds msqbuf;
1502194910Sjhb	int error;
1503194910Sjhb
1504194910Sjhb	DPRINTF(("call to freebsd7_msgctl(%d, %d, %p)\n", uap->msqid, uap->cmd,
1505194910Sjhb	    uap->buf));
1506194910Sjhb	if (uap->cmd == IPC_SET) {
1507194910Sjhb		error = copyin(uap->buf, &msqold, sizeof(msqold));
1508194910Sjhb		if (error)
1509194910Sjhb			return (error);
1510194910Sjhb		ipcperm_old2new(&msqold.msg_perm, &msqbuf.msg_perm);
1511194910Sjhb		CP(msqold, msqbuf, msg_first);
1512194910Sjhb		CP(msqold, msqbuf, msg_last);
1513194910Sjhb		CP(msqold, msqbuf, msg_cbytes);
1514194910Sjhb		CP(msqold, msqbuf, msg_qnum);
1515194910Sjhb		CP(msqold, msqbuf, msg_qbytes);
1516194910Sjhb		CP(msqold, msqbuf, msg_lspid);
1517194910Sjhb		CP(msqold, msqbuf, msg_lrpid);
1518194910Sjhb		CP(msqold, msqbuf, msg_stime);
1519194910Sjhb		CP(msqold, msqbuf, msg_rtime);
1520194910Sjhb		CP(msqold, msqbuf, msg_ctime);
1521194910Sjhb	}
1522194910Sjhb	error = kern_msgctl(td, uap->msqid, uap->cmd, &msqbuf);
1523194910Sjhb	if (error)
1524194910Sjhb		return (error);
1525194910Sjhb	if (uap->cmd == IPC_STAT) {
1526194910Sjhb		bzero(&msqold, sizeof(msqold));
1527194910Sjhb		ipcperm_new2old(&msqbuf.msg_perm, &msqold.msg_perm);
1528194910Sjhb		CP(msqbuf, msqold, msg_first);
1529194910Sjhb		CP(msqbuf, msqold, msg_last);
1530194910Sjhb		CP(msqbuf, msqold, msg_cbytes);
1531194910Sjhb		CP(msqbuf, msqold, msg_qnum);
1532194910Sjhb		CP(msqbuf, msqold, msg_qbytes);
1533194910Sjhb		CP(msqbuf, msqold, msg_lspid);
1534194910Sjhb		CP(msqbuf, msqold, msg_lrpid);
1535194910Sjhb		CP(msqbuf, msqold, msg_stime);
1536194910Sjhb		CP(msqbuf, msqold, msg_rtime);
1537194910Sjhb		CP(msqbuf, msqold, msg_ctime);
1538194910Sjhb		error = copyout(&msqold, uap->buf, sizeof(struct msqid_ds_old));
1539194910Sjhb	}
1540194910Sjhb	return (error);
1541194910Sjhb}
1542194910Sjhb
1543194910Sjhb#undef CP
1544194910Sjhb
1545194894Sjhb#endif	/* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1546194894Sjhb	   COMPAT_FREEBSD7 */
1547