JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
STREAMS Programming Guide     Oracle Solaris 11.1 Information Library
search filter icon
search icon

Document Information

Preface

Part I Application Programming Interface

1.  Overview of STREAMS

2.  STREAMS Application-Level Components

3.  STREAMS Application-Level Mechanisms

4.  Application Access to the STREAMS Driver and Module Interfaces

System Calls Used

Module and Driver ioctl Calls

General ioctl Processing

I_STR ioctl Processing

Transparent ioctl Processing

I_LIST ioctl

Other ioctl Commands

Message Direction

Flush Handling

5.  STREAMS Administration

6.  Pipes and Queues

Part II Kernel Interface

7.  STREAMS Framework - Kernel Level

8.  STREAMS Kernel-Level Mechanisms

9.  STREAMS Drivers

10.  STREAMS Modules

11.  Configuring STREAMS Drivers and Modules

12.  Multithreaded STREAMS

13.  STREAMS Multiplex Drivers

Part III Advanced Topics

14.  Debugging STREAMS-based Applications

Part IV Appendixes

A.  Message Types

B.  Kernel Utility Interface Summary

C.  STREAMS-Based Terminal Subsystem

D.  STREAMS FAQ

Glossary

Index

Module and Driver ioctl Calls

STREAMS is a special type of character device driver that is different from the historical character input/output (I/O) mechanism. In this section, the phrases character I/O mechanism and I/O mechanism refer only to that part of the mechanism that existed before STREAMS.

The character I/O mechanism handles all ioctl(2) calls transparently. That is, the kernel expects all ioctl(2) to be handled by the device driver associated with the character special file on which the call is sent. All ioctl(2) calls are sent to the driver, which is expected to perform all validation and processing other than file descriptor validity checking. The operation of any specific ioctl(2) is dependent on the device driver. If the driver requires data to be transferred in from user space, it will use the kernel ddi_copyin function. It may also use ddi_copyout to transfer any data results to user space.

With STREAMS, there are a number of differences from the character I/O mechanism that impart ioctl(2) processing.

First, there is a set of generic STREAMS ioctl(2) command values recognized and processed by the stream head. This is described in streamio(7I). The operation of the generic STREAMS ioctl(2) is generally independent of the presence of any specific module or driver on the stream.

The second difference is the absence of user context in a module and driver when the information associated with the ioctl(2) is received. This prevents use of ddi_copyin(9F) or ddi_copyout(9F) by the module. This also prevents the module and driver from associating any kernel data with the currently running process. (By the time the module or driver receives the ioctl(2), the process generating it probably will no longer be running.)

A third difference is that for the character I/O mechanism, all ioctl(2) are handled by the single driver associated with the file. In STREAMS, there can be multiple modules on a stream and each one can have its own set of ioctl(2) calls. That is, the ioctl(2) that can be used on a stream can change as modules are pushed and popped.

STREAMS provides the capability for user processes to perform control functions on specific modules and drivers in a stream with ioctl(2) calls. Most streamio(7I) ioctl(2) commands go no further than the stream head. They are fully processed there and no related messages are sent downstream. However, certain commands and all unrecognized commands cause the stream head to create an M_IOCTL </function> message, which includes the ioctl(2) arguments, and send the message downstream to be received and processed by a specific module or driver. The M_IOCTL </function> message is the initial message type that carries ioctl(2) information to modules. Other message types are used to complete the ioctl(2) processing in the stream. In general, each module must uniquely recognize and act on specific M_IOCTL </function> messages.

STREAMS ioctl(2) handling is equivalent to the transparent processing of the character I/O mechanism. STREAMS modules and drivers can process ioctl(2) generated by applications that are implemented for a non-STREAMS environment.

General ioctl Processing

STREAMS blocks a user process that issues an ioctl(2) and causes the stream head to generate an M_IOCTL </function> message. The process remains blocked until one of the following occurs:

For an I_STR, the STREAMS module or driver that generates a positive acknowledgement message can also return data to the process in the message. An alternate means to return data is provided with transparent ioctl(2). If the stream head does not receive a positive or negative acknowledgement message in the specified time, the ioctl(2) call fails.

A module that receives an unrecognized M_IOCTL message must pass it on unchanged. A driver that receives an unrecognized M_IOCTL must produce a negative acknowledgement.

The two STREAMS ioctl(2) mechanisms, I_STR and transparent, are described next. (Here, I_STR means the streamio(7I) I_STR command and implies the related STREAMS processing unless noted otherwise.) I_STR has a restricted format and restricted addressing for transferring ioctl(2)-related data between user and kernel space. It requires only a single pair of messages to complete ioctl(2) processing. The transparent mechanism is more general and has almost no restrictions on ioctl(2) data format and addressing. The transparent mechanism generally requires that multiple pairs of messages be exchanged between the stream head and module to complete the processing.

This is a rather simplistic view. Nothing prevents a given ioctl(2) from being issued either directly (transparent) or by means of I_STR. Furthermore, ioctl(2) calls issued through I_STR potentially can require further processing of the form typically associated with transparent ioctl(2).

I_STR ioctl Processing

The I_STR ioctl(2) provides a capability for user applications to perform module and driver control functions on STREAMS files. I_STR allows an application to specify the ioctl(2) timeout. It encourages that all user ioctl(2) data (to be received by the destination module) be placed in a single block that is pointed to from the user strioctl structure. The module can also return data to this block.

Transparent ioctl Processing

The transparent STREAMS ioctl(2) mechanism enables application programs to perform module and driver control functions with ioctl(2) calls other than I_STR. It transparently supports applications developed prior to the introduction of STREAMS. It alleviates the need to recode and recompile the user-level software to run over STREAMS files. More importantly, applications do not have to package their ioctl(2) requests into the form demanded by I_STR.

The mechanism extends the data transfer capability for STREAMS ioctl(2) calls beyond those provided in the I_STR form. Modules and drivers can transfer data between their kernel space and user space in any ioctl(2) that has a value of the command argument not defined in streamio(7I). These ioctl(2) are known as transparent ioctl(2) to differentiate them from the I_STR form. Existing applications that use non-STREAMS character devices require transparent processing for ioctl(2) if the device driver is converted to STREAMS. The ioctl(2) data can be in any format mutually understood by the user application and module.

The transparent mechanism also supports STREAMS applications that send ioctl(2) data to a driver or module in a single call, where the data may not be in a form readily embedded in a single user block. For example, the data may be contained in nested structures and different user space buffers.

I_LIST ioctl

The I_LIST ioctl(2) supports the strconf(1) and strchg(1) commands that are used to query or change the configuration of a stream. Only the root user or an owner of a STREAMS device can alter the configuration of that stream.

strchg(1) does the following:

strconf(1) does the following:

The I_LIST ioctl(2), illustrated in Example 4-1, performs two functions. When the third argument of the ioctl(2) call is NULL,

if ((mods = ioctl(s, I_LIST, 0)) < 0) {

the return value of the call indicates the number of modules, plus the driver, present on the stream. For example, if there are two modules above the driver, 3 is returned. On failure, errno may be set to a value specified in streamio(7I). The second function of the I_LIST ioctl(2) is to copy the module names found on the stream to the user-supplied buffer. The address of the buffer in user space and the size of the buffer are passed to the ioctl(2) through a structure str_mlist that is defined as:

struct str_mlist {
        char l_name[FMNAMESZ+1]; /* space for holding a module name*/
};
    
    struct str_list {
        int sl_nmods;        /* #of modules for which space is allocated */
        struct str_mlist *sl_modlist;    /*addr of buf for names*/
};

Here sl_nmods is the number of modules in the sl_modlist array that the user has allocated. Each element in the array must be at least FMNAMESZ+1 bytes long. The array is FMNAMESZ+1 so the extra byte can hold the NULL character at the end of the string. FMNAMESZ is defined by <sys/conf.h>.

The amount of space to allocate for module names is indicated by the number of modules in the STREAM. This is not completely reliable because another module might be pushed onto the stream after the application invokes the I_LIST ioctl(2) with the NULL argument and before it invokes the I_LIST ioctl(2) with the structure argument.

The I_LIST call with arg pointing to the str_list structure returns the number of entries that have been filled into the sl_modlist array (the number represents the number of modules including the driver). If there is not enough space in the sl_modlist array or sl_nmods is less than 1, the I_LIST call fails and errno is set to EINVAL. If arg or the sl_modlist array points outside the allocated address space, EFAULT is returned.

Example 4-1 I_LIST ioctl

#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>

main(int argc, const char **argv)
{
        int    s, i;
        unsigned int    mods;
        struct str_list    mod_list;struct str_mlist *mlist;
        /* Get a socket... */

        if ((s = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
            perror("socket: ");
            exit(1);
        }

        /* Determine the number of modules in the stream */    
        if ((mods = ioctl(s, I_LIST, 0)) < 0) {
            perror("I_LIST ioctl");
        }
        if (mods == 0) {
            printf("No modules\n");
            exit(1);
        } else {
            printf("%d modules\n", mods);
        }

        /* Allocate memory for all of the module names */
        mlist = (struct str_mlist *)
        calloc(mods, sizeof (struct str_mlist));
        if (mlist == 0) {
            perror("malloc failure");
            exit(1);
        }
        mod_list.sl_modlist = mlist;
        mod_list.sl_nmods = mods;
        /* Do the ioctl and get the module names... */
        if (ioctl(s, I_LIST, &mod_list) < 0) {
            exit(1);
        }

        /* Print out the name of the modules... */
        for (i = 0; i < mods; i++) {
            printf("s: %s\n", mod_list.sl_modlist[i].l_name);
        }

        /* Free the calloc'd structures... */
        free(mlist);
        return(0);
}

Other ioctl Commands

streamio(7I) details the ioctl(2) commands shown in Table 4-2.

Table 4-2 Other ioctl Commands

ioctl Calls
Description
I_ANCHOR
Prevents the removal of a STREAMS module with an I_POP call. Any process can place an anchor on a stream, but once placed, an anchor can only be removed by a privileged process.
I_LOOK
Retrieves the name of the module just below the stream head
I_FLUSH
Flushes all input or output queues
I_FLUSHBAND
Flushes a band of messages
I_FIND
Compares the names of all modules present in the stream to a specific name
I_PEEK
Enables the user to look at information in the first message on the stream head read queue without taking the message off the queue
I_SRDOPT
Sets the read mode using a series of flag options in the argument
I_GRDOPT
Indicates the read mode in an int
I_NREAD
Counts the data bytes in data blocks in the first message on the stream head read queue
I_FDINSERT
Creates a message from a user buffer, adds information about another stream, and sends the message downstream
I_SWROPT
Sets the write mode using the value of the argument
I_GWROPT
Returns the current write mode setting
I_SENDFD
Requests that the stream send a message with file pointer to the stream head at the other end of a STREAMS pipe
I_RECVFD
Retrieves the file descriptor of the message sent by an I_SENDFD ioctl(2) over a STREAMS pipe
I_ATMARK
Lets the application see if the current message on the stream head read queue is marked by a module downstream
I_CKBAND
Checks if the message of a given priority band exists on the stream head read queue
I_GETBAND
Returns the priority band of the first message on the stream head read queue
I_CANPUT
Checks if a certain band is writable
I_SETCLTIME
Enables the user to set the time the stream head will delay when a stream is closing if data exists on the write queues
I_GETCLTIME
Returns the close time delay
I_LINK
Connects two streams
I_UNLINK
Disconnects two streams
I_PLINK
Connects two streams with a persistent link below a multiplexing driver
I_PUNLINK
Disconnects two streams that have been connected with a persistent link

Message Direction

Various system calls let the user create messages and send them downstream and prioritize the messages.

Table 4-3 Send and Receive Messages

Creates a message from the caller supplied control and data buffers and sends the message downstream
Does the same as putmsg(2) and enables the caller to specify a priority band for the message
Retrieves M_DATA, M_PROTO, or M_PCPROTO or high priority messages from the stream head, and places the contents into two user buffers
Does the same as getmsg(2) and enables the caller to specify a priority band for the message

The stream head guarantees that the control part of a message generated by putmsg(2) is at least 64 bytes long. This promotes reusability of the buffer. When the buffer is a reasonable size, modules and drivers may reuse the buffer for other headers.

stropts.h contains the specification of strbuf, which describes the control and data buffers.