A    Sample STREAMS Module

The spass module is a simple STREAMS module that passes all messages put to it to the putnext() procedure. The spass module delays the call to putnext() for the service procedure to handle. It has flow control code built in, and both the read and write sides share a service procedure.

The following is the code for the spass module:

#include <sys/stream.h>
#include <sys/stropts.h>
#include <sys/sysconfig.h>
 
static  int     spass_close();
static  int     spass_open();
static  int     spass_rput();
static  int     spass_srv();
static  int     spass_wput();
 
static struct module_info minfo =  {
        0, "spass", 0, INFPSZ, 2048, 128
};
 
static struct qinit rinit = {
    spass_rput, spass_srv, spass_open, spass_close, NULL, &minfo
};
 
static struct qinit winit = {
    spass_wput, spass_srv, NULL, NULL, NULL, &minfo
};
 
struct streamtab spassinfo = { &rinit, &winit };
 
cfg_subsys_attr_t bufcall_attributes[]  = {
    {, 0, 0, 0, 0, 0, 0}    /* must be the last element */
};
 
int
spass_configure(op, indata, indata_size, outdata, outdata_size)
        cfg_op_t        op;
        caddr_t         indata;
        ulong           indata_size;
        caddr_t         outdata;
        ulong           outdata_size;
{
     struct streamadm        sa;
     dev_t                   devno = NODEV;
 
     if (op != CFG_OP_CONFIGURE)
             return EINVAL;
 
     sa.sa_version           = OSF_STREAMS_10;
     sa.sa_flags             = STR_IS_MODULE | STR_SYSV4_OPEN;
     sa.sa_ttys              = 0;
     sa.sa_sync_level        = SQLVL_QUEUE;
     sa.sa_sync_info         = 0;
     strcpy(sa.sa_name,      "spass");
     if ( (devno = strmod_add(devno, &spassinfo, &sa)) == NODEV ) {
             return ENODEV;
     }
 
     return 0;
}
 
/* Called when module is popped or the Stream is closed */
static int
spass_close (q, credp)
     queue_t * q;
     cred_t * credp;
{
     return 0;
}
 
/* Called when module is pushed */
static int
spass_open (q, devp, flag, sflag, credp)
     queue_t * q;
     int     * devp;
     int     flag;
     int     sflag;
     cred_t * credp;
{
     return 0;
}
 
/*
* Called to process a message coming upstream.  All messages
* but flow control messages are put on the read side service
* queue for later processing.
*/
static int
spass_rput (q, mp)
     queue_t * q;
     mblk_t * mp;
{
     switch (mp->b_datap->db_type) {
     case M_FLUSH:
             if (*mp->b_rptr & FLUSHR)
                     flushq(q, 0);
             putnext(q, mp);
             break;
     default:
             putq(q, mp);
             break;
     }
     return 0;
}
 
/*
* Shared by both read and write sides to process messages put
* on the read or write service queues.  When called from the
* write side, sends all messages on the write side queue
* downstream until flow control kicks in or all messages are
* processed.  When called from the read side sends all messages
* on its read side service queue upstreams until flow control
* kicks in or all messages are processed.
*/
static int
spass_srv (q)
     queue_t * q;
{
     mblk_t *        mp;
 
     while (mp = getq(q)) {
             if (!canput(q->q_next))
                  return putbq(q, mp);
             putnext(q, mp);
     }
     return 0;
}
 
/*
* Called to process a message coming downstream.  All messages but
* flow control messages are put on the write side service queue for
* later processing.
*/
static int
spass_wput (q, mp)
     queue_t * q;
     mblk_t *        mp;
{
     switch (mp->b_datap->db_type) {
     case M_FLUSH:
             if (*mp->b_rptr & FLUSHW)
                     flushq(q, 0);
             putnext(q, mp);
             break;
     default:
             putq(q, mp);
             break;
     }
     return 0;
}