STREAMS Programming Guide

Appendix A Message Types

Introduction

Defined STREAMS message types differ in their intended purposes, their treatment at the stream head, and in their message-queueing priority.

STREAMS does not prevent a module or driver from generating any message type and sending it in any direction on the stream. However, established processing and direction rules should be observed. Stream head processing according to message type is fixed, although certain parameters can be altered.

The message types found in sys/stream.h are described in this appendix, classified according to their message queueing priority. Ordinary messages are described first, with high-priority messages following. In certain cases, two message types may perform similar functions, differing only in priority. Message construction is described in Chapter 3, STREAMS Application-Level Mechanisms. The use of the word module generally implies module or driver.

Ordinary messages are also called normal or nonpriority messages. Ordinary messages are subject to flow control whereas high priority messages are not.

Ordinary Messages

M_BREAK

Sent to a driver to request that BREAK be transmitted on whatever media the driver is controlling.

The message format is not defined by STREAMS and its use is developer dependent. This message may be considered a special case of an M_CTL message. An M_BREAK message cannot be generated by a user-level process and is always discarded if passed to the stream head.

M_CTL

Generated by modules that send information to a particular module or type of module. M_CTL messages are typically used for intermodule communication, as when adjacent STREAMS protocol modules negotiate the terms of their interface. An M_CTL message cannot be generated by a user-level process and is always discarded if passed to the stream head.

M_DATA

Contain ordinary data. Messages allocated by allocb(9F) are M_DATA type by default. M_DATA messages are generally sent bidirectionally on a stream and their contents can be passed between a process and the stream head. In the getmsg(2) and putmsg(2) system calls, the contents of M_DATA message blocks are referred to as the data part. Messages composed of multiple message blocks typically have M_DATA as the message type for all message blocks following the first.

M_DELAY

Sent to a media driver to request a real-time delay on output. The data buffer associated with this message is expected to contain an integer to indicate the number of machine cycles of delay desired. M_DELAY messages are typically used to prevent transmitted data from exceeding the buffering capacity of slower terminals.

The message format is not defined by STREAMS and its use is developer dependent. Not all media drivers may understand this message. This message may be considered a special case of an M_CTL message. An M_DELAY message cannot be generated by a user-level process and is always discarded if passed to the stream head.

M_IOCTL

Generated by the stream head in response to I_STR, I_LINK, I_UNLINK, I_PLINK, and I_PUNLINK ioctl(2)s (see streamio(7I)). Also generated in response to ioctl calls that contain a command argument value not defined in streamio(7I). When one of these ioctl(2) is received from a user process, the stream head uses values supplied in the call and values from the process to create an M_IOCTL message containing them, then sends the message downstream. M_IOCTL messages perform the general ioctl(2) functions of character device drivers.

For an I_STR ioctl(2), the user values are supplied in a structure of the following form, provided as an argument to the ioctl(2) call (see I_STR in streamio(7I)):


struct strioctl
{
	int   ic_cmd;          /* downstream request */
	int   ic_timout;       /* ACK/NAK timeout */
	int   ic_len;          /* length of data arg */
	char  *ic_dp;          /* ptr to data arg */
};

where ic_cmd is the request (or command) defined by a downstream module or driver, ic_timout is the time the stream head waits for acknowledgment to the M_IOCTL message before timing out, and ic_dp points to an optional data buffer. On input, ic_len contains the length of the data in the buffer passed in and, on return from the call, it contains the length of the data, if any, being returned to the user in the same buffer.

The M_IOCTL message format is one M_IOCTL message block followed by zero or more M_DATA message blocks. STREAMS constructs an M_IOCTL message block by placing an iocblk(9S) structure, defined in <sys/stream.h>, in its data buffer. The iocblk(9S) structure differ for 64-bit and 32-bit architectures.


#if defined(_LP64)
struct iocblk {
	int     ioc_cmd;       /* ioctl command type */
	cred_t  *ioc_cr;       /* full credentials */
	uint    ioc_id;        /* ioctl id */
	uint    ioc_flag;      /* see below */
	size_t  ioc_count;     /* count of bytes in data field */
	int     ioc_rval;      /* return value  */
	int     ioc_error;     /* error code */
};
#else
struct iocblk {
	int     ioc_cmd;       /* ioctl command type */
	cred_t  *ioc_cr;       /* full credentials */
	uint    ioc_id;        /* ioctl id */
	size_t  ioc_count;     /* count of bytes in data field */
	int     ioc_error;     /* error code */
	int     ioc_rval;      /* return value  */
	intt    ioc_fill1;
	uint    ioc_flag;      /* see below */
	int     ioc_filler[2]; /* reserved for future use */
};
#endif  /* _LP64 */

For an I_STR ioctl(2), ioc_cmd corresponds to ic_cmd of the strioctl structure. ioc_cr points to a credentials structure defining the user process's permissions (see cred.hfile).. Its contents can be tested to determine if the user issuing the ioctl(2) call is authorized to do so. For an I_STR ioctl(2), ioc_count is the number of data bytes, if any, contained in the message and corresponds to ic_len.

ioc_id is an identifier generated internally, and is used by the stream head to match each M_IOCTL message sent downstream with response messages sent upstream to the stream head. The response message that completes the stream head processing for the ioctl(2) is an M_IOCACK (positive acknowledgment) or an M_IOCNAK (negative acknowledgment) message.

For an I_STR ioctl(2), if a user supplies data to be sent downstream, the stream head copies the data, pointed to by ic_dp in the strioctl structure, into M_DATA message blocks and links the blocks to the initial M_IOCTL message block. ioc_count is copied from ic_len. If there are no data, ioc_count is zero.

If the stream head does not recognize the command argument of an ioctl(2), the head creates a transparent M_IOCTL message. The format of a transparent M_IOCTL message is one M_IOCTL message block followed by one M_DATA block. The form of the iocblk structure is the same as above. However, ioc_cmd is set to the value of the command argument in the ioctl(2) and ioc_count is set to TRANSPARENT, defined in <sys/stream.h>. TRANSPARENT distinguishes the case where an I_STR ioctl(2) specifies a value of ioc_cmd equivalent to the command argument of a transparent ioctl(2). The M_DATA block of the message contains the value of the arg parameter in the ioctl(2).

The first module or driver that understands the ioc_cmd request contained in the M_IOCTL acts on it. For an I_STR ioctl(2), this action generally includes an immediate upstream transmission of an M_IOCACK message. For transparent M_IOCTLs, this action generally includes the upstream transmission of an M_COPYIN or M_COPYOUT message.

Intermediate modules that do not recognize a particular request must pass the message on. If a driver does not recognize the request, or the receiving module can not acknowledge it, an M_IOCNAK message must be returned.

M_IOCACK and M_IOCNAK message types have the same format as an M_IOCTL message and contain an iocblk structure in the first block. An M_IOCACK block may be linked to following M_DATA blocks. If one of these messages reaches the stream head with an identifier that does not match that of the currently-outstanding M_IOCTL message, the response message is discarded. A common means of ensuring that the correct identifier is returned is for the replying module to convert the M_IOCTL message into the appropriate response type and set ioc_count to 0, if no data is returned. Then, qreply(9F) is used to send the response to the stream head.

In an M_IOCACK or M_IOCNAK message, ioc_error holds any return error condition set by a downstream module. If this value is non-zero, it is returned to the user in errno. Note that both an M_IOCNAK and an M_IOCACK can return an error. However, only an M_IOCACK can have a return value. For an M_IOCACK, ioc_rval holds any return value set by a responding module. For an M_IOCNAK, ioc_rval is ignored by the stream head.

If a module processing an I_STR ioctl(2) is sending data to a user process, it must use the M_IOCACK message that it constructs such that the M_IOCACK block is linked to one or more following M_DATA blocks containing the user data. The module must set ioc_count to the number of data bytes sent. The stream head places the data in the address pointed to by ic_dp in the user I_STR strioctl structure.

If a module processing a transparent ioctl(2) wants to send data to a user process, it can use only an M_COPYOUT message. For a transparent ioctl(2), no data can be sent to the user process in an M_IOCACK message. All data must be sent in a preceding M_COPYOUT message. The stream head ignores any data contained in an M_IOCACK message (in M_DATA blocks) and frees the blocks.

No data can be sent with an M_IOCNAK message for any type of M_IOCTL. The stream head ignores and frees any M_DATA blocks.

The stream head blocks the user process until an M_IOCACK or M_IOCNAK response to the M_IOCTL (same ioc_id) is received. For an M_IOCTL generated from an I_STR ioctl(2), the stream head times out if no response is received in ic_timout interval (the user can specify an explicit interval or specify use of the default interval). For M_IOCTL messages generated from all other ioctl(2)s, the default (infinite) is used.

M_PASSFP

Used by STREAMS to pass a file pointer from the stream head at one end of a stream pipe to the stream head at the other end of the same stream pipe.

The message is generated as a result of an I_SENDFD ioctl(2) (see streamio(7I)) issued by a process to the sending stream head. STREAMS places the M_PASSFP message directly on the destination stream head's read queue to be retrieved by an _RECVFD ioctl(2) (see streamio(7I)). The message is placed without passing it through the stream, that is, it is not seen by any modules or drivers in the stream). This message should never be present on any queue except the read queue of a stream head. Consequently, modules and drivers do not need to recognize this message, and it can be ignored by module and driver developers.

M_PROTO

Intended to contain control information and associated data. The message format is one or more (see note) M_PROTO message blocks followed by zero or more M_DATA message blocks. The semantics of the M_DATA and M_PROTO message block are determined by the STREAMS module that receives the message.

The M_PROTO message block typically contains implementation dependent control information. M_PROTO messages are generally sent bidirectionally on a stream, and their contents can be passed between a process and the stream head. The contents of the first message block of an M_PROTO message is generally referred to as the control part, and the contents of any following M_DATA message blocks are referred to as the data part. In the getmsg(2) and putmsg(2), the control and data parts are passed separately.


Note -

On the write-side, the user can only generate M_PROTO messages containing one M_PROTO message block.


Although its use is not recommended, the format of M_PROTO and M_PCPROTO (generically PROTO) messages sent upstream to the stream head allows multiple PROTO blocks at the beginning of the message. getmsg(2)) compacts the blocks into a single control part when passing them to the user process.

M_RSE

Reserved for internal use. Modules that do not recognize this message must pass it on. Drivers that do not recognize it must free it.

M_SETOPTS

Used to alter some characteristics of the stream head. It is generated by any downstream module, and is interpreted by the stream head. The data buffer of the message has the following structure as defined in stream.h.


struct stroptions {
	uint     so_flags;        /* options to set */
	shor     so_readopt;      /* read option */
	ushort   so_wroff;        /* write offset */
	ssize_t  so_minpsz;       /* minimum read packet size */
	ssize_t  so_maxpsz;       /* maximum read packet size */
	size_t   so_hiwat;        /* read queue high-water mark */
	size_t   so_lowat;        /* read queue low-water mark */
	unsigned char so_band;    /* band for water marks */
	ushort   so_erropt;       /* error option */
	ssize_t  so_maxblk;       /* maximum message block size */
	ushort   so_copyopt;      /* copy options (see stropts.h) */
};

where so_flags specifies which options are to be altered, and can be any combination of the following:

The offset must be less than the maximum message buffer size (system dependent). Under certain circumstances, a write offset may not be inserted. A module or driver must test that b_rptr in the msgb(9S)structure is greater than db_base in the datab(9S) structure to determine that an offset has been inserted in the first message block.


Note -

For conformance with the POSIX standard, it is recommended that new applications use the O_NONBLOCK flag whose behavior is the same as that of O_NDELAY unless otherwise noted.


M_SIG

Sent upstream by modules or drivers to post a signal to a process. When the message reaches the front of the stream head read queue, it evaluates the first data byte of the message as a signal number, defined in <sys/signal.h>. (The signal is not generated until it reaches the front of the stream head read queue.) The associated signal will be sent to processes under the following conditions:

High-Priority Messages

M_COPYIN

Generated by a module or driver and sent upstream to request that the stream head perform a copyin(9F) on behalf of the module or driver. It is valid only after receiving an M_IOCTL message and before an M_IOCACK or M_IOCNAK.

The message format is one M_COPYIN message block containing a copyreq(9S) structure, defined in <sys/stream.h>. Different structures are defined for 64-bit and 32-bit architectures.


#if defined(_LP64)
struct copyreq {
	int      cq_cmd;                /* ioctl command (from ioc_cmd) */
	cred_t   *cq_cr;                /* full credentials (from ioc_cmd) */
	uint     cq_id;                 /* ioctl id (from ioc_id) */
	uint     cq_flag;               /* see below */
	mblk_t   *cq_private;           /* private state information */
	caddr_t  cq_addr;               /* address to copy data to/from */
	size_t   cq_size;               /* number of bytes to copy */
};
#else
struct copyreq {
	int      cq_cmd;                /* ioctl command (from ioc_cmd) */
	cred_t   *cq_cr;                /* full credentials */
	uint     cq_id;                 /* ioctl id (from ioc_id) */
	caddr_t  cq_addr;               /* address to copy data to/from */
	size_t   cq_size;               /* number of bytes to copy */
	uint     cq_flag;               /* see below */
	mblk_t   *cq_private;           /* private state information */
	int      cq_filler[4];          /* reserved for future use */
};
#endif   /* _LP64 */

The first four members of the structure correspond to those of the iocblk(9S) structure in the M_IOCTL message that allows the same message block to be reused for both structures. The stream head guarantees that the message block allocated for the M_IOCTL message is large enough to contain a copyreq(9S). The cq_addr field contains the user space address from which the data is to be copied. The cq_size field is the number of bytes to copy from user space. The cq_flag field is reserved for future use and should be set to zero.

This message should not be queued by a module or driver unless it intends to process the data for the ioctl(2).

M_COPYOUT

Generated by a module or driver and sent upstream to request that the stream head perform a copyout(9F) on behalf of the module or driver. It is valid only after receiving an M_IOCTL message and before an M_IOCACK or M_IOCNAK.

The message format is one M_COPYOUT message block followed by one or more M_DATA blocks. The M_COPYOUT message block contains a copyreq(9S) as described in the M_COPYIN message with the following differences: the cq_addr field contains the user space address to which the data is to be copied. The cq_size field is the number of bytes to copy to user space.

Data to be copied to user space is contained in the linked M_DATA blocks.

This message should not be queued by a module or driver unless it processes the data for the ioctl in some way.


Note -

Please see copyin() and copyout() in the Writing Device Drivers manual.


M_ERROR

Sent upstream by modules or drivers to report some downstream error condition. When the message reaches the stream head, the stream is marked so that all subsequent system calls issued to the stream, excluding close(2) and poll(2), fail with errno set to the first data byte of the message. POLLERR is set if the stream is being poll(2). All processes sleeping on a system call to the stream are awakened. An M_FLUSH message with FLUSHRW is sent downstream.

The stream head maintains two error fields, one for the read-side and one for the write-side. The one-byte format M_ERROR message sets both of these fields to the error specified by the first byte in the message.

The second style of the M_ERROR message is two bytes long. The first byte is the read error and the second byte is the write error. This allows modules to set a different error on the read-side and write-side. If one of the bytes is set to NOERROR, then the field for the corresponding side of the stream is unchanged. This allows a module to ignore an error on one side of the stream. For example, if the stream head was not in an error state and a module sent an M_ERROR message upstream with the first byte set to EPROTO and the second byte set to NOERROR, all subsequent read-like system calls (such as read(2)and getmsg(2)) fail with EPROTO, but all write-like system calls (such as write(2) and putmsg(2)) still succeed. If a byte is set to 0, the error state is cleared for the corresponding side of the stream. The values NOERROR and 0 are not valid for the one-byte form of the M_ERROR message.

M_FLUSH

Requests all modules and drivers that receive it to flush their message queues (discard all messages in those queues) as indicated in the message. An M_FLUSH can originate at the stream head, or in any module or driver. The first byte of the message contains flags that specify one of the following actions:

Each module passes this message to its neighbor after flushing its appropriate queues until the message reaches one of the ends of the stream.

Drivers are expected to include the following processing for M_FLUSH messages. When an M_FLUSH message is sent downstream through the write queues in a stream, the driver at the stream end discards it if the message action indicates that the read queues in the stream are not to be flushed (only FLUSHW set). If the message indicates that the read queues are to be flushed, the driver shuts off the FLUSHW flag, and sends the message up the stream's read queues.

When a flush message is sent up a stream's read-side, the stream head checks to see if the write-side of the stream is to be flushed. If only FLUSHR is set, the stream head discards the message. However, if the write-side of the stream is to be flushed, the stream head sets the M_FLUSH flag to FLUSHW and sends the message down the stream's write side. All modules that queue messages must identify and process this message type.

If FLUSHBAND is set, the second byte of the message contains the value of the priority band to flush.

M_HANGUP

Sent upstream by a driver to report that it can no longer send data upstream. As example, this might be due to an error, or to a remote line connection being dropped. When the message reaches the stream head, the stream is marked so that all subsequent write(2) and putmsg(2) calls issued to the stream will fail and return an ENXIO error. Those ioctl(2) that cause messages to be sent downstream are also failed. POLLHUP is set if the stream is being poll(2).

Subsequent read(2) or getmsg(2) calls to the stream will not generate an error. These calls will return any messages (according to their function) that were on, or in transit to, the stream head read queue before the M_HANGUP message was received. When all such messages have been read, read(2) returns 0 and getmsg(2) will set each of its two length fields to 0.

This message also causes a SIGHUP signal to be sent to the controlling process instead of the foreground process group, since the allocation and deallocation of controlling terminals to a session is the responsibility of the controlling process.

M_IOCACK

Signals the positive acknowledgment of a previous M_IOCTL message. The message format is one M_IOCACK block (containing an iocblk(9S) structure, see M_IOCTL) followed by zero or more M_DATA blocks. The iocblk(9S) may contain a value in ioc_rval to be returned to the user process. It may also contain a value in ioc_error to be returned to the user process in errno.

If this message is responding to an I_STR ioctl (see streamio(7I)), it may contain data from the receiving module or driver to be sent to the user process. In this case, message format is one M_IOCACK block followed by one or more M_DATA blocks containing the user data. The stream head returns the data to the user if there is a corresponding outstanding M_IOCTL request. Otherwise, the M_IOCACK message is ignored and all blocks in the message are freed.

Data cannot be returned in an M_IOCACK message responding to a transparent M_IOCTL. The data must have been sent with preceding M_COPYOUT message(s). If any M_DATA blocks follow the M_IOCACK block, the stream head ignores and frees them.

The format and use of this message type is described further under M_IOCTL.

M_IOCDATA

Generated by the stream head and sent downstream as a response to an M_COPYIN or M_COPYOUT message. The message format is one M_IOCDATA message block followed by zero or more M_DATA blocks. The M_IOCDATA message block contains a copyresp(9S), defined in sys/stream.h.


#if     defined(_LP64)
struct copyresp {
	int      cp_cmd;          /* ioctl command (from ioc_cmd) */
	cred_t   *cp_cr;          /* full credentials (from ioc_cmd) */
	uint     cp_id;           /* ioctl id (from ioc_id) */
	uint     cp_flag;         /* see above */
	mblk_t   *cp_private;     /* private state information */
	caddr_t  cp_rval;         /* status of request: 0 -> success */
                           /*   non-zero -> failure */
};
#else
struct copyresp {
	int      cp_cmd;          /* ioctl command (from ioc_cmd) */
	cred_t   *cp_cr;          /* full credentials */
	uint     cp_id;           /* ioctl id (from ioc_id) */
	caddr_t  cp_rval          /* status of request: 0 -> success */
                           /*   non-zero -> failure */
	size_t   cp_pad1;
	uint     cp_pad2;
	mblk_t   *cp_private;     /* private state information */
	uint     cp_flag;         /* see above */
	int      cp_filler[3];
};
#endif  /* _LP64 */

The first three members of the structure correspond to those of the iocblk(9S) in the M_IOCTL message that allows the same message blocks to be reused for all of the related transparent messages (M_COPYIN, M_COPYOUT, M_IOCACK, M_IOCNAK). The cp_rval field contains the result of the request at the stream head. Zero indicates success and non-zero indicates failure. If failure is indicated, the module should not generate an M_IOCNAK message. It must abort all ioctl(2) processing, clean up its data structures, and return.

The cp_private field is copied from the cq_private field in the associated M_COPYIN or M_COPYOUT message. It is included in the M_IOCDATA message so the message can be self-describing. This is intended to simplify ioctl(2) processing by modules and drivers.

If the message is in response to an M_COPYIN message and success is indicated, the M_IOCDATA block is followed by M_DATA blocks containing the data copied in.

If an M_IOCDATA block is reused, any unused fields defined for the resultant message block should be cleared (particularly in an M_IOCACK or M_IOCNAK).

This message should not be queued by a module or driver unless it processes the data for the ioctl in some way.

M_IOCNAK

Signals the negative acknowledgment (failure) of a previous M_IOCTL message. Its form is one M_IOCNAK block containing an iocblk(9S). The iocblk(9S) can contain a value in ioc_error to be returned to the user process in errno. Unlike the M_IOCACK, no user data or return value can be sent with this message. If any M_DATA blocks follow the M_IOCNAK block, the stream head ignores and frees them. When the stream head receives an M_IOCNAK, the outstanding ioctl(2) request, if any, fails. The format and use of this message type is described further under M_IOCTL.

M_PCPROTO

The same as the M_PROTO message type, except for the priority and the following additional attributes. When an M_PCPROTO message is placed on a queue, its service procedure is always enabled. The stream head allows only one M_PCPROTO message to be placed in its read queue at a time. If an M_PCPROTO message is already in the queue when another arrives, the second message is discarded and its message blocks freed.

This message is intended to allow data and control information to be sent outside the normal flow control constraints.

getmsg(2) and putmsg(2) refer to messages as high priority messages.

M_PCRSE

Reserved for internal use. Modules that do not recognize this message must pass it on. Drivers that do not recognize it must free it.

M_PCSIG

The same as the M_SIG message, except for the priority. M_PCSIG is often preferable to M_SIG especially in TTY applications, because M_SIG may be queued while M_PCSIG is more likely to get through quickly. For example, if an M_SIG message is generated when the DEL (delete) key is pressed on the terminal and the user has already typed ahead, the M_SIG message becomes queued and the user doesn't get the call until it's too late; it becomes impossible to kill or interrupt a process by pressing a delete key.

M_READ

Generated by the stream head and sent downstream for a read(2) if no messages are waiting to be read at the stream head and if read notification has been enabled. Read notification is enabled with the SO_MREADON flag of the M_SETOPTS message and disabled by use of the SO_MREADOFF flag.

The message content is set to the value of the nbyte parameter (the number of bytes to be read) in read(2).

M_READ notifies modules and drivers of the occurrence of a read. It also supports communication between streams that reside in separate processors. The use of the M_READ message is developer dependent. Modules may take specific action and pass on or free the M_READ message. Modules that do not recognize this message must pass it on. All other drivers may or may not take action and then free the message.

This message cannot be generated by a user-level process and should not be generated by a module or driver. It is always discarded if passed to the stream head.

SO_MREADOFF and M_STOP

Request devices to start or stop their output. They are used to produce momentary pauses in a device's output, not to turn devices on or off.

The message format is not defined by STREAMS and its use is developer dependent. These messages may be considered special cases of an M_CTL message. These messages cannot be generated by a user-level process and each is always discarded if passed to the stream head.

SO_MREADOFFI and M_STOPI

The same as SO_MREADOFF and M_STOP except that SO_MREADOFFI and M_STOPI are used to start and stop input.

M_UNHANGUP

Used to reconnect carrier after it has been dropped.