This chapter describes the ifnet STREAMS module and dlb STREAMS pseudodriver communication bridges. Before reading it, you should be familiar with basic STREAMS and sockets concepts and have reviewed the information in Chapter 4 and Chapter 5.
The Digital UNIX network programming environment supports the STREAMS and sockets frameworks for network programming. However, there is no native communication path at the data link layer between the two frameworks. The term coexistence refers to the ability to exchange data between the sockets and STREAMS frameworks. The term communication bridge refers to the software (ifnet STREAMS module or the dlb STREAMS pseudodriver) that enables the two frameworks to exchange data at the data link layer.
Programs written to sockets and STREAMS must intercommunicate for the following reasons:
For example, if your system is running a STREAMS device driver and you have an application that uses the TCP/IP implemented on Digital UNIX, which is sockets-based, you need a path by which the data gets from the sockets-based protocols stack to the STREAMS device driver and back again. The ifnet STREAMS module allows an application using TCP/IP to exchange data with a STREAMS device driver. Section 7.1 describes the ifnet STREAMS module.
Conversely, if you have a STREAMS protocol stack implemented on your system but want to use the BSD device driver implemented on Digital UNIX, you need a path by which the data gets from the STREAMS protocol stack to the BSD device driver and back again. The dlb STREAMS pseudodriver allows the STREAMS protocol stack to route its data to the BSD device driver. Section 7.2 describes the dlb STREAMS pseudodriver.
The ifnet STREAMS module is a communication bridge that allows STREAMS network drivers to access sockets-based network protocols. The ifnet STREAMS module functions like any other STREAMS module, being pushed on the Stream above the STREAMS device driver. Once it is on the Stream, it handles all of the translation required between the DLPI interface of the STREAMS driver and the BSD ifnet layer. The ifnet STREAMS module exports both standard STREAMS interfaces as well as ifnet layer interfaces.
Note that STREAMS network drivers can also continue to use STREAMS-based network protocols while using the ifnet STREAMS module.
Figure 7-1 highlights the ifnet STREAMS module and shows its place in the network programming environment.
This section describes how to prepare the system running the STREAMS driver to use the ifnet STREAMS module.
Note
The ifnet STREAMS module only supports Ethernet STREAMS device drivers.
This section also lists the DLPI primitives that the STREAMS driver must support in order for the ifnet STREAMS module to operate successfully.
If your device driver supports the primitives listed in Section 7.1.1.2, no source code changes to either the driver or STREAMS kernel code are needed for you to use the ifnet STREAMS module.
To use the ifnet STREAMS module, the STRIFNET and DLPI options must be configured in your kernel and you must set up STREAMS for the driver.
The STRIFNET and DLPI options may have been configured into your system at installation time. (For information on configuring options during installation, see the Installation Guide.) You can check to see if the options are configured, by issuing the following command:
#
/usr/sbin/strsetup -c
If ifnet and dlb appear in the Name column, the options are configured in you kernel. If not, you must add them using the doconfig command.
To configure STRIFNET and DLPI into your kernel, perform the following steps:
Enter a name for the kernel configuration file. [HOST1]:
[RETURN]
A configuration file with the name 'HOST1' already exists.
Do you want to replace it? (y/n) [n]:
y
Saving /sys/conf/HOST1 as /sys/conf/HOST1.bck
*** KERNEL CONFIGURATION AND BUILD PROCEDURE ***
Note
The STRIFNET and DLPI options are not available from this menu. To include these options, you must edit the configuration file, as shown in the following step.
Do you want to edit the configuration file? (y/n) [n]:
y
Using ed to edit the configuration file. Press return when ready,
or type 'quit' to skip the editing session:
2153
48a
options DLPI
options STRIFNET
\.
1,$w
2185
q
*** PERFORMING KERNEL BUILD ***
The following example shows the output from the strsetup -c command:
#
/usr/sbin/strsetup -c
STREAMS Configuration Information...Thu Nov 9 08:38:17 1995
Name Type Major Module ID ---- ---- ----- --------- clone 32 0 dlb device 52 5010 dlpi device 53 800 kinfo device 54 5020 log device 55 44 nuls device 56 5001 echo device 57 5000 sad device 58 45 pipe device 59 5304 xtisoUDP device 60 5010 xtisoTCP device 61 5010 xtisoUDP+ device 62 5010 xtisoTCP+ device 63 5010 ptm device 64 7609 pts device 6 7608 bba device 65 24880 lat device 5 5 pppif module 6002 pppasync module 6000 pppcomp module 6001 bufcall module 0 ifnet module 5501 null module 5002 pass module 5003 errm module 5003 ptem module 5003 spass module 5007 rspass module 5008 pipemod module 5303 timod module 5006 tirdwr module 0 ldtty module 7701
Configured devices = 16, modules = 15
For more detailed information on reconfiguring your kernel or the doconfig command see the System Administration manual and the doconfig(8) reference page.
To set up STREAMS for the driver you must do the following:
/* * Application program to set up the "pifnet" streams for IP * and ARP. This must be run prior to ifconfig */ #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <stropts.h> #include <sys/ioctl.h> #include <signal.h> #include "dlpihdr.h"
#define IP_PROTOCOL 0x800 #define ARP_PROTOCOL 0x806 #define PIFNET_IOCTL_UNIT 1236
main(argc, argv) int argc; char *argv[]; { extern char *getenv(); char *p; short unit = 0; char devName[256];
if (argc != 3) usage(); strcpy(devName, argv[1]); unit = atoi(argv[2]);
sigignore(SIGHUP); setupStream(devName, unit, IP_PROTOCOL); setupStream(devName, unit, ARP_PROTOCOL);
/* * sleep forever to keep the Streams alive. */ if (fork()) /* detach */ exit(); pause(); }
usage() { fprintf(stderr, "usage: pifnetd devname unit-number\n"); exit(1); }
setupStream(devName, unit, serviceClass) char *devName; short unit; u_long serviceClass; { int fd, status; dl_bind_req_t bindreq; dl_bind_ack_t bindack; int flags; struct strioctl str; struct strbuf pstrbufctl, pstrbufdata, gstrbufctl, \ gstrbufdata; char ebuf[256];
/* * build the stream */ fd = open(devName, O_RDWR, 0); if (fd < 0) { sprintf(ebuf, " open '%s' failed", devName); perror(ebuf); exit(1); } if (ioctl(fd, I_PUSH, "ifnet") < 0) { sprintf(ebuf, " ioctl I_PUSH failed"); perror(ebuf); exit(1); }
/* * tell pifnet the unit number for the device */ str.ic_cmd = PIFNET_IOCTL_UNIT; str.ic_timout = 15; str.ic_len = sizeof (short); str.ic_dp = (char *) &unit; status = ioctl(fd, I_STR, &str); if (status < 0) { sprintf(ebuf, " %s - ioctl"); perror(ebuf); exit(1); }
/* * bind the stream to a protocol */ bindreq.dl_primitive = DL_BIND_REQ; bindreq.dl_sap = serviceClass; bindreq.dl_max_conind = 0; bindreq.dl_service_mode = DL_CLDLS; bindreq.dl_conn_mgmt = 0; bindreq.dl_xidtest_flg = 0; pstrbufctl.len = sizeof(dl_bind_req_t); pstrbufctl.buf = (void *)&bindreq;
pstrbufdata.buf = (char *)0; pstrbufdata.len = -1; pstrbufdata.maxlen = 0;
status = putmsg(fd, &pstrbufctl, (struct strbuf *)0, 0); if (status < 0) { perror("putmsg"); exit(1); }
/* * Check requested binding */ gstrbufctl.buf = (char *)&bindack; gstrbufctl.maxlen = sizeof(dl_bind_ack_t); gstrbufctl.len = 0; status = getmsg(fd, &gstrbufctl, (struct strbuf *)0, &flags); if (status < 0) { perror("getmsg"); exit(1); }
if (bindack.dl_primitive != DL_BIND_ACK) { errno = EPROTO; perror(" DL_BIND_ACK"); exit(1); } }
In this sample application the driver's name is /dev/streams/ln. The application creates two Streams; one for the Internet Protocol (IP) and one for the Address Resolution Protocol (ARP). After setting up the Streams, the application must keep running, using the pause command, in order to keep the Streams alive.
Note that, if the driver is a style-2 driver, you must add a DL_ATTACH_REQ to the application program. For more information about the DL_ATTACH_REQ primitive or style-2 drivers, see the DLPI specification in /usr/share/doclib/dlpi/dlpi.ps.
The executable can be located in any directory.
Although you can manually start the program each time you reboot, it is easiest to add a line to the /sbin/init.d/inet file to run it automatically when the system reboots. Be sure to add the line before the system's ifconfig lines.
In the following example, each time the system reboots, the /sbin/init.d/inet file runs a program called run_ifnet, which resides in the /etc directory:
# place command invoking executable BEFORE \
.
.
.
# # Enable network # case $1 in .start') echo "Configuring network" /sbin/hostname $HOSTNAME echo "hostname: \c" /sbin/hostname if [ "$NETDEV_0" != '' ]; then echo >/tmp/ifconfig_"$NETDEV_0".tmp
/sbin/ifconfig $NETDEV_0 $IFCONFIG_0 > \ /tmp/ifconfig_"$NETDEV_0".tmp 2>&1 if [ $? != 0 ]; then ERROR=`cat /tmp/ifconfig_"$NETDEV_0".tmp` if [ "$ERROR" = "$ERRSTRING" ]; then /sbin/ifconfig $NETDEV_0 up else echo "$0: $ERROR" fi fi rm /tmp/ifconfig_"$NETDEV_0".tmp fi
.
.
.
Use the /usr/sbin/shutdown -r command to shut down your system and have it reboot automatically; for example:
#
/usr/sbin/shutdown -r now
Note that the STREAMS device driver can be a style-1 or a style-2 DLPI provider, as described in the Data Link Provider Interface specification, which is located in /usr/share/doclib/dlpi/dlpi.ps. Note that you must have the OSFPGMR400 subset installed to access the DLPI specification on line.
The driver must support the following DLPI primitives. For detailed information about these primitives and how to use them, see the DLPI specification: DL_PHYS_ADDR_REQ/DL_PHYS_ADDR_ACK DL_BIND_REQ/DL_BIND_ACK DL_UNBIND_REQ DL_UNITDATA_REQ/DL_UNITDATA_IND/DL_UDERROR_IND DL_OK_ACK/DL_ERROR_ACK
The dlb STREAMS pseudodevice driver allows you to bridge BSD-style device drivers and STREAMS protocol stacks. The STREAMS pseudodevice driver is the Stream end in a Stream wanting to communicate with BSD-based drivers. The STREAMS pseudodevice driver provided by Digital UNIX has two interfaces, a subset of the DLPI interface that communicates with STREAMS protocol stacks and another interface that accesses the ifnet layer interface of the sockets framework.
Figure 7-2 highlights the dlb STREAMS pseudodriver and shows its place in the network programming environment.
The dlb STREAMS pseudodriver supports the following connectionless mode primitive and media types. For detailed information about these primitives and how to use them, see the Data Link Provider Interface specification which is in /usr/share/doclib/dlpi/dlpi.ps. DL_ATTACH_REQ/DL_DETACH_REQ/DL_OK_ACK DL_BIND_REQ/DL_BIND_ACK/DL_UNBIND_REQ DL_ENABMULTI_REQ/DL_DISABLMULTI_REQ DL_PROMISCON_REQ/DL_PROMISCONOFF_REQ DL_PHYS_ADDR_REQ/DL_PHYS_ADDR_ACK DL_SET_PHYS_ADDR_REQ DL_UNITDATA_REQ/DL_UNITDATA_IND DL_SUBS_BIND_REQ/DL_SUBS_BIND_ACK DL_SUBS_UNBIND_REQ/DL_SUBS_UNBIND_ACK
The Ethernet bus (DL_ETHER) is the media type supported by the STREAMS pseudodriver.
To use the dlb STREAMS pseudodriver the DLPI option must be configured into your kernel. The DLPI option may have been configured into your system at installation time.
You can check to see if the DLPI option is configured by issuing the following command:
#
/usr/sbin/strsetup -c
If dlb appears in the Name column, the option is configured in you kernel. If not, you must add it using the doconfig command.
For a description of how to reconfigure your kernel with the doconfig command, see Section 7.1.1.1.
For more information on reconfiguring your kernel or the doconfig command see the System Administration manual and the doconfig(8) reference page. For information on configuring options during installation, see the Installation Guide.