Coherent4.2.10/conf/streams/src/strinit.c

Compare this file to the similar file:
Show the results in this format:

/*
 * This file contains the entry points into the STREAMS system called by the
 * Coherent kernel. This includes the startup and the system-call entry
 * points; part of the reason for bundling this stuff together is that when
 * bound into a Driver.a the system-call entry points are referred to by
 * code that comes later in the link, and so are not pulled in unless the
 * requirement for the init routine forces them to be present.
 */

#define	_DDI_DKI	1
#define	_SYSV3		1

#include <common/ccompat.h>
#include <kernel/strmlib.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <stropts.h>
#include <stddef.h>

#define	_KERNEL		1

#include <sys/inode.h>
#include <sys/fd.h>
#include <sys/proc.h>

extern	long		_streams_maxctl;
extern	long		_streams_maxdata;
extern	size_t		_streams_size;
extern	uchar_t		_streams_heap [];

__EXTERN_C__	int	STRMEM_INIT	__PROTO ((uchar_t * _mem,
						  size_t _size));


/*
 *-STATUS:
 *	SVR3
 *
 *-NAME:
 *	getmsg ()	Get next message off a stream
 *
 *-SYNOPSIS:
 *	#include <stropts.h>
 *
 *	int getmsg (int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
 *		    int * flagsp);
 *
 *-DESCRIPTION:
 *	getmsg () retrieves the contents of a message located at the stream
 *	head read queue from a STREAMS file, and places the contents into user
 *	specified buffer(s). The message must contain either a data part, a
 *	control part, or both. The data and control parts of the message are
 *	placed into separate buffers, as described below. The semantics of
 *	each part is defined by the STREAMS module that generated the message.
 *
 *	"fd" specifies a file descriptor referencing an open stream. "ctlptr"
 *	and "dataptr" each point to a "strbuf" structure, which contains the
 *	following members:
 *		int	maxlen;		Maximum buffer length
 *		int	len;		Length of data
 *		void  *	buf;		Pointer to buffer
 *
 *	"buf" points to a buffer in which the data or control information is
 *	to be placed, and "maxlen" indicates the maximum number of bytes this
 *	buffer can hold. On return, "len" contains the number of bytes of data
 *	or control information actually received, or 0 if there is a zero-
 *	length control or data part, or -1 if no data or control information
 *	is present in the message. "flagsp" should point to an integer that
 *	indicates the type of message the user is able to receive. This is
 *	described later.
 *
 *	"ctlptr" is user to hold the control part from the message and
 *	"dataptr" is used to hold the data part from the message. If "ctlptr"
 *	or "dataptr" is NULL or the "maxlen" field is -1, the control or data
 *	part of the message is not processed and is left on the stream head
 *	read queue. If "ctlptr" or "dataptr" is not NULL and there is no
 *	corresponding control or data part of the message on the stream head
 *	read queue, "len" is set to -1. If the "maxlen" field is set to 0
 *	and there is a zero-length control or data part, the zero-length part
 *	is removed from the read queue and "len" is set to 0. If the "maxlen"
 *	field is set to 0 and there are more than zero bytes of control or
 *	data information, that information is left on the read queue and "len"
 *	is set to 0. If the "maxlen" field in "ctlptr" or "dataptr" is less
 *	than, respectively, the control or data part of the message, "maxlen"
 *	bytes are retrieved. In this case, the remainder of the message is
 *	left on the stream head read queue and a non-zero return value is
 *	provided, as described below under DIAGNOSTICS.
 *
 *	By default, getmsg () processes the first available message on the
 *	stream head read queue. However, a user may choose to retrieve only
 *	high priority messages by setting the integer pointed to by "flagsp"
 *	to RS_HIPRI. In this case, getmsg () processes the next message only
 *	if it is a high priority message. If the integer pointed to by
 *	"flagsp" is 0, getmsg () retrieves any message available on the stream
 *	head read queue. In this case, the integer pointed to by "flagsp" will
 *	be set to RS_HIPRI if a high priority message was received, or 0
 *	otherwise.
 *
 *	If O_NDELAY and O_NONBLOCK are clear, getmsg () blocks until a message
 *	of the type specified by "flagsp" is available on the stream head read
 *	queue. If O_NDELAY or O_NONBLOCK has been set and a message of the
 *	specified type is not present on the read, queue, getmsg () fails and
 *	set errno to EAGAIN.
 *
 *	If a hangup occurs on the stream from which messages are to be
 * 	retrieved, getmsg () continues to operate normally, as described
 *	above, until the stream head read queue is empty. Thereafter, it
 *	returns 0 in the "len" fields of "ctlptr" and "dataptr".
 *
 *	getmsg () will fail if one or more of the following are true:
 *
 *	EAGAIN		The O_NDELAY or O_NONBLOCK flag is set and no messages
 *			are available.
 *
 *	EBADF		"fd" is not a valid file descriptor open for reading.
 *
 *	EBADMSG		Queued message to be read is not valid for getmsg ().
 *
 *	EFAULT		"ctlptr", "dataptr" or "flagsp" points outside the
 *			process's allocated address space.
 *
 *	EINTR		A signal was caught during the getmsg () system call.
 *
 *	EINVAL		An illegal value was specified in "flagsp", or the
 *			stream referenced by "fd" is linked under a
 *			multiplexor.
 *
 *	ENOSTR		A stream is not associated with "fd".
 *
 *	getmsg () can also fail if a STREAMS error message had been received
 *	at the stream header before the call to getmsg (). The error returned
 *	is the value contained in the STREAMS error message.
 *
 *-DIAGNOSTICS:
 *	Upon sucessful completion, a non-negative value is returned. A value
 *	of 0 indicates that a full message was read successfully. A return
 *	value of MORECTL indicates that more control information is waiting
 *	for retrieval. A return value of MOREDATA indicates that more data are
 *	waiting for retrieval. A return value of MORECTL | MOREDATA indicates
 *	that both types of information remain. Subsequent getmsg () calls
 *	retrieve the remainder of the information. However, if a message of
 *	higher priority has come in on the stream head read queue, the next
 *	call to getmsg () will retrieve that higher priority message before
 *	retrieving the remainder of the previously received partial message.
 */


#if	__USE_PROTO__
int ugetmsg (fd_t fd, struct strbuf * ctlptr, struct strbuf * dataptr,
	     int * flagsp)
#else
int
ugetmsg (fd, ctlptr, dataptr, flagsp)
fd_t		fd;
struct strbuf *	ctlptr;
struct strbuf *	dataptr;
int	      *	flagsp;
#endif
{
	struct strbuf	ctlbuf;
	struct strbuf *	kctlptr;
	struct strbuf	databuf;
	struct strbuf *	kdataptr;
	__fd_t	      *	fdp;
	int		flags;
	int		retval;
	int		band;

	if ((fdp = fd_get (fd)) == NULL) {
		set_user_error (EBADF);
		return -1;
	}

	if (! S_ISCHR (fdp->f_ip->i_mode) ||
	    fdp->f_ip->i_private == NULL) {
		set_user_error (ENOSTR);
		return;
	}

	if (flagsp == NULL ||
	    ukcopy (flagsp, & flags, sizeof (flags)) != sizeof (flags)) {
	    	set_user_error (EFAULT);
	    	return -1;
	}

	if ((flags & ~ RS_HIPRI) != 0) {
		set_user_error (EINVAL);
		return -1;
	}

	if (ctlptr != NULL) {
		if (ukcopy (ctlptr, & ctlbuf, sizeof (ctlbuf)) !=
		    sizeof (ctlbuf)) {
		    	set_user_error (EFAULT);
		    	return -1;
		}
		kctlptr = & ctlbuf;
	} else
		kctlptr = NULL;

	if (dataptr != NULL) {
		if (ukcopy (dataptr, & databuf, sizeof (databuf)) !=
		    sizeof (databuf)) {
		    	set_user_error (EFAULT);
		    	return -1;
		}
		kdataptr = & databuf;
	} else
		kdataptr = NULL;

	flags = (flags & RS_HIPRI) != 0 ? MSG_HIPRI : MSG_BAND;

	retval = 0;
	band = 0;
	set_user_error (STREAMS_GETPMSG ((shead_t *) fdp->f_ip->i_private,
					 kctlptr, kdataptr, & band, & flags,
					 MAKE_MODE (fdp->f_flag),
					 SELF->p_credp, & retval));

	flags = (flags & MSG_HIPRI) != 0 ? RS_HIPRI : 0;
	kucopy (& flags, flagsp, sizeof (flags));
	if (ctlptr != NULL)
		kucopy (kctlptr, ctlptr, sizeof (ctlbuf));
	if (dataptr != NULL)
		kucopy (kdataptr, dataptr, sizeof (databuf));
	return retval;
}


/*
 *-STATUS:
 *	SVR3
 *
 *-NAME:
 *	putmsg ()	send a message on a stream
 *
 *-SYNOPSIS:
 *	#include <stropts.h>
 *
 *	int putmsg (int fd, const struct strbuf * ctlptr,
 *		    const struct strbuf * dataptr, int flags);
 *
 *-DESCRIPTION:
 *	putmsg () creates a message from user-specified buffer(s) and sends
 *	the message to a STREAMS file. The message may contain either a data
 *	part, a control part, or both. The data and control parts to be sent
 *	are distinguished by placement in separate buffers, as described
 *	below. The semantics of each part is defined by the STREAMS module
 *	that receives the message.
 *
 *	"fd" specifies a file descriptor referencing an open stream. "ctlptr"
 *	and "dataptr" each point to a "strbuf" structure containing the
 *	following members:
 *		int	maxlen;		Not used
 *		int	len;		Length of data
 *		void  *	buf;		Pointer to buffer
 *
 *	"ctlptr" points to the structure describing the control part, if any,
 *	to be included in the message. The "buf" field in the "strbuf"
 *	structure points to the buffer where the control information resides,
 *	and the "len" field indicates the number of bytes to be sent. The
 *	"maxlen" field is not used in putmsg (). In a similar manner,
 *	"dataptr" specifies the data, if any, to be included in the message.
 *	"flags" indicates what type of message should be sent and is described
 *	later.
 *
 *	To send the data part of a message, "dataptr" must not be NULL and the
 *	"len" field of "dataptr" bust have a value of 0 or greater. To send
 *	the control part of a message, the corresponding values must be set
 *	for "ctlptr". No data or control) part is sent if either "dataptr"
 *	or "ctlptr" is NULL or if the len field of "dataptr" or "ctlptr" is
 *	set to -1.
 *
 *	For putmsg (), if a control part is specified, and flags is set to
 *	RS_HIPRI, a high priority message is sent. If no control part is
 *	specified, and flags is set to RS_HIPRI, putmsg () fails and sets
 *	"errno" to EINVAL. If "flags" is set to 0, a normal priority message
 *	is sent. If no control part and no data part are specified, and
 *	flags is set to 0, no message is sent, and 0 is returned.
 *
 *	The stream head guarantees that the control part of a message
 *	generated by putmsg () is at least 64 bytes in length.
 *
 *	Normally, putmsg () will block if the stream head write queue is full
 *	due to internal flow control conditions. For high-priority messages,
 *	putmsg () does not block on this condition. For other messages,
 *	putmsg () does not block when the write queue is full and O_NDELAY or
 *	O_NONBLOCK has been specified. No partial message is sent.
 *
 *	putmsg () fails if one or more of the following is true:
 *
 *	EAGAIN		A non-priority message was specified, the O_NDELAY or
 *			O_NONBLOCK flag is set and the stream write queue is
 *			full due to internal flow control conditions.
 *
 *	EBADF		"fd" is not a valid file descriptor open for writing.
 *
 *	EFAULT		"ctlptr" or "dataptr" points outside the process's
 *			allocated address space.
 *
 *	EINTR		A signal was caught during the putmsg () system call.
 *
 *	EINVAL		An undefined value was specified in "flags" or "flags"
 *			is set to RS_HIPRI and no control part was supplied.
 *
 *	EINVAL		The stream referenced by "fd" is linked below a
 *			multiplexor.
 *
 *	ENOSR		Buffers could not be allocated for the message that
 *			was to be send due to insufficient STREAMS memory
 *			resources.
 *
 *	ENOSTR		A stream is not associated with "fd".
 *
 *	ENXIO		A hangup condition was generated downstream for the
 *			specified stream, or the other end of the pipe is
 *			closed.
 *
 *	ERANGE		The size of the data part of the message does not fall
 *			within the minimum and maximum packet sizes of the
 *			topmost stream module. This value is also returned if
 *			the control part of the message is larger than the
 *			maximum configured size for the control part of a
 *			message, or if the data part of a message is larger
 *			than the maximum configured size for the data part of
 *			a message.
 *
 *	putmsg () also fails is a STREAMS error message had been processed by
 *	the stream head before the call to putmsg (). The error returned is
 *	the value contained in the STREAMS error message.
 *
 *-DIAGNOSTICS:
 *	Upon successful completion, a value of 0 is returned. Otherwise, a
 *	value of -1 is returned and "errno" is set to indicate the error.
 */

#if	__USE_PROTO__
int uputmsg (fd_t fd, __CONST__ struct strbuf * ctlptr,
	     __CONST__ struct strbuf * dataptr, int flags)
#else
int
uputmsg (fd, ctlptr, dataptr, flags)
fd_t		fd;
__CONST__ struct strbuf
	      *	ctlptr;
__CONST__ struct strbuf
	      *	dataptr;
int		flags;
#endif
{
	struct strbuf	ctlbuf;
	struct strbuf	databuf;
	__fd_t	      *	fdp;
	int		retval;

	if ((fdp = fd_get (fd)) == NULL) {
		set_user_error (EBADF);
		return -1;
	}

	if ((flags & ~ RS_HIPRI) != 0) {
		set_user_error (EINVAL);
		return -1;
	}

	if (! S_ISCHR (fdp->f_ip->i_mode) ||
	    fdp->f_ip->i_private == NULL) {

		set_user_error (ENOSTR);
		return;
	}
	if (ctlptr != NULL) {
		if (ukcopy (ctlptr, & ctlbuf, sizeof (ctlbuf)) !=
		    sizeof (ctlbuf)) {
		    	set_user_error (EFAULT);
		    	return -1;
		}
		ctlptr = & ctlbuf;
	}
	if (dataptr != NULL) {
		if (ukcopy (dataptr, & databuf, sizeof (databuf)) !=
		    sizeof (databuf)) {
		    	set_user_error (EFAULT);
		    	return -1;
		}
		dataptr = & databuf;
	}
	flags = (flags & RS_HIPRI) != 0 ? MSG_HIPRI : MSG_BAND;

	retval = 0;
	set_user_error (STREAMS_PUTPMSG ((shead_t *) fdp->f_ip->i_private,
					 ctlptr, dataptr, 0, flags,
					 MAKE_MODE (fdp->f_flag),
					 SELF->p_credp, & retval));
	return retval;
}


/*
 * Start things up, in the right order. If we can't proceed, panic.
 */

#if	__USE_PROTO__
void (streamsinit) (void)
#else
void
streamsinit __ARGS (())
#endif
{
	/*
	 * Bootstrap the message allocator. Note that memory management in
	 * Coherent is sane, this is quite simple.
	 */

	while (STRMEM_INIT (_streams_heap, _streams_size) != 0)
		cmn_err (CE_PANIC, "Unable to initalise STREAMS heap");

	str_mem->sm_maxctlsize = _streams_maxctl;
	str_mem->sm_maxdatasize = _streams_maxdata;
}