STREAMS polling and multiplexing

Building a multiplexor

This section builds a protocol multiplexor with the multiplexing configuration shown in ``Protocol multiplexor''. To free users from the need to know about the underlying protocol structure, a user-level daemon process is built to maintain the multiplexing configuration. Users can then access the transport protocol directly by opening the transport protocol (TP) driver device node.

An internetworking protocol driver (IP) routes data from a single upper Stream to one of two lower Streams. This driver supports two STREAMS connections beneath it. These connections are to two distinct networks; one for the IEEE 802.3 standard with the 802.3 driver, and the other to the IEEE 802.4 standard with the 802.4 driver. The TP driver multiplexes upper Streams over a single Stream to the IP driver.

Protocol multiplexor

The following example shows how this daemon process sets up the protocol multiplexor. The necessary declarations and initialization for the daemon program are as follows:

#include <fcntl.h>
#include <stropts.h>

main() { int fd_802_4, fd_802_3, fd_ip, fd_tp;

/* daemon-ize this process */ switch (fork()) { case 0: break; case -1: perror("fork failed"); exit(2); default: exit(0); } setsid();

This multilevel multiplexed Stream configuration is built from the bottom up. Therefore, the example begins by first constructing the Internet Protocol (IP) multiplexor. This multiplexing device driver is treated like any other software driver. It owns a node in the UNIX file system and is opened just like any other STREAMS device driver.

The first step is to open the multiplexing driver and the 802.4 driver, thus creating separate Streams above each driver as shown in ``Before link''. The Stream to the 802.4 driver may now be connected below the multiplexing IP driver using the I_LINK ioctl call.

Before link

The sequence of instructions to this point is

	if ((fd_802_4 = open("/dev/802_4", O_RDWR)) < 0) {
		perror("open of /dev/802_4 failed");

if ((fd_ip = open("/dev/ip", O_RDWR)) < 0) { perror("open of /dev/ip failed"); exit(2); }

/* now link 802.4 to underside of IP */

if (ioctl(fd_ip, I_LINK, fd_802_4) < 0) { perror("I_LINK ioctl failed"); exit(3); }

I_LINK takes two file descriptors as arguments. The first file descriptor, fd_ip, must reference the Stream connected to the multiplexing driver, and the second file descriptor, fd_802_4, must reference the Stream to be connected below the multiplexor. ``IP multiplexor after first link'' shows the state of these Streams following the I_LINK call. The complete Stream to the 802.4 driver has been connected below the IP driver. The Stream head's queues of the 802.4 driver is used by the IP driver to manage the lower half of the multiplexor.

IP multiplexor after first link

I_LINK returns an integer value, called muxid, which is used by the multiplexing driver to identify the Stream just connected below it. This muxid is ignored in the example, but is useful for dismantling a multiplexor or routing data through the multiplexor. Its significance is discussed later.

The following sequence of system calls is used to continue building the internetworking protocol multiplexor (IP):

	if ((fd_802_3 = open("/dev/802_3", O_RDWR)) < 0) {
		perror("open of /dev/802_3 failed");

if (ioctl(fd_ip, I_LINK, fd_802_3) < 0) { perror("I_LINK ioctl failed"); exit(5); }

All links below the IP driver have now been established, giving the configuration in ``IP multiplexor''.

IP multiplexor

The Stream above the multiplexing driver used to establish the lower connections is the controlling Stream and has special significance when dismantling the multiplexing configuration. This will be illustrated later in this section. The Stream referenced by fd_ip is the controlling Stream for the IP multiplexor.

NOTE: The order in which the Streams in the multiplexing configuration are opened is unimportant. If it is necessary to have intermediate modules in the Stream between the IP driver and media drivers, these modules must be added to the Streams associated with the media drivers (using I_PUSH) before the media drivers are attached below the multiplexor.

The number of Streams that can be linked to a multiplexor is restricted by the design of the particular multiplexor. The manual page describing each driver (typically found in Section 7) describes such restrictions. However, only one I_LINK operation is allowed for each lower Stream; a single Stream cannot be linked below two multiplexors simultaneously.

Continuing with the example, the IP driver is now linked below the transport protocol (TP) multiplexing driver. As seen in ``Protocol multiplexor'', only one link is supported below the transport driver. This link is formed by the following sequence of system calls:

	if ((fd_tp = open("/dev/tp", O_RDWR)) < 0) {
		perror("open of /dev/tp failed");

if (ioctl(fd_tp, I_LINK, fd_ip) < 0) { perror("I_LINK ioctl failed"); exit(7); }

The multilevel multiplexing configuration shown in ``TP multiplexor'' has now been created.

TP multiplexor

Because the controlling Stream of the IP multiplexor has been linked below the TP multiplexor, the controlling Stream for the new multilevel multiplexor configuration is the Stream above the TP multiplexor.

At this point, the file descriptors associated with the lower drivers can be closed without affecting the operation of the multiplexor. If these file descriptors are not closed, all later read, write, ioctl, poll, getmsg, and putmsg system calls issued to them will fail because I_LINK associates the Stream head of each linked Stream with the multiplexor, so the user may not access that Stream directly for the duration of the link.

The following sequence of system calls completes the daemon example:


/* Hold multiplexor open forever */ pause(); }

To summarize, ``TP multiplexor'' shows the multilevel protocol multiplexor. The transport driver supports several simultaneous Streams. These Streams are multiplexed over the single Stream connected to the IP multiplexor. The mechanism for establishing multiple Streams above the transport multiplexor is actually a by-product of the way in which Streams are created between a user process and a driver. By opening different minor devices of a STREAMS driver, separate Streams are connected to that driver. Of course, the driver must be designed with the intelligence to route data from the single lower Stream to the appropriate upper Stream.

The daemon process maintains the multiplexed Stream configuration through an open Stream (the controlling Stream) to the transport driver. Meanwhile, other users can access the services of the transport protocol by opening new Streams to the transport driver; they are freed from the need for any unnecessary knowledge of the underlying protocol configurations and subnetworks that support the transport service.

Multilevel multiplexing configurations should be assembled from the bottom up because the passing of ioctls through the multiplexor is determined by the multiplexing driver and cannot generally be relied on.

Next topic: Dismantling a multiplexor
Previous topic: STREAMS multiplexors

© 2004 The SCO Group, Inc. All rights reserved.
UnixWare 7 Release 7.1.4 - 27 April 2004