xxwput() is the write-side put
procedure for module or driver xx. xxwput allocates a message
block to contain the state structure and reuses the M_IOCTL
to create an M_COPYIN message to read in the xxdata structure.
M_IOCDATA processing is done in xxioc()
as shown in the following example:
Example 8-12 M_IOCDATA Processing
xxioc( /* M_IOCDATA processing */
queue_t *q,
mblk_t *mp)
{
struct iocblk *iocbp;
struct copyreq *cqp;
struct copyresp *csp;
struct state *stp;
mblk_t *xx_indata();
csp = (struct copyresp *)mp->b_rptr;
iocbp = (struct iocblk *)mp->b_rptr;
switch (csp->cp_cmd) {
case XX_IOCTL:
if (csp->cp_rval) { /* failure */
if (csp->cp_private) /* state structure */
freemsg(csp->cp_private);
freemsg(mp);
return;
}
stp = (struct state *)csp->cp_private->b_rptr;
switch (stp->st_state) {
case GETSTRUCT: /* xxdata structure copied in */
/* save structure */
stp->st_data =
*(struct xxdata *)mp->b_cont->b_rptr;
freemsg(mp->b_cont);
mp->b_cont = NULL;
/* Reuse M_IOCDATA to copyin data */
mp->b_datap->db_type = M_COPYIN;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_size = stp->st_data.x_inlen;
cqp->cq_addr = stp->st_data.x_inaddr;
cqp->cq_flag = 0;
stp->st_state = GETINDATA; /* next state */
qreply(q, mp);
break;
case GETINDATA: /* data successfully copied in */
/* Process input, return output */
if ((mp->b_cont = xx_indata(mp->b_cont))
== NULL) { /* hypothetical */
/* fail xx_indata */
mp->b_datap->db_type = M_IOCNAK;
mp->b_wptr = mp->b_rptr +
sizeof(struct iocblk);
iocbp->ioc_error = EIO;
qreply(q, mp);
break;
}
mp->b_datap->db_type = M_COPYOUT;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_size = min(msgdsize(mp->b_cont),
stp->st_data.x_outlen);
cqp->cq_addr = stp->st_data.x_outaddr;
cqp->cq_flag = 0;
stp->st_state = PUTOUTDATA; /* next state */
qreply(q, mp);
break;
case PUTOUTDATA: /* data copied out, ack ioctl */
freemsg(csp->cp_private); /*state structure*/
mp->b_datap->db_type = M_IOCACK;
mp->b_wtpr = mp->b_rptr + sizeof (struct iocblk);
/* can have been overwritten */
iocbp->ioc_error = 0;
iocbp->ioc_count = 0;
iocbp->ioc_rval = 0;
qreply(q, mp);
break;
default: /* invalid state: can't happen */
freemsg(mp->b_cont);
mp->b_cont = NULL;
mp->b_datap->db_type = M_IOCNAK;
mp->b_wptr=mp->b_rptr + sizeof (struct iocblk);
iocbp->ioc_error = EINVAL;
qreply(q, mp);
break;
} /* switch (stp->st_state) */
break;
default: /* M_IOCDATA not for us */
/* if module, pass message on */
/* if driver, free message */
break;
} /* switch (csp->cp_cmd) */
}
|
At case GETSTRUCT, the user xxdata
structure is copied into the module's state structure (pointed to by cp_private in the message) and the M_IOCDATA
message is reused to create a second M_COPYIN message to
read the user data.
At case GETINDATA, the input user data is processed
by xx_indata (not supplied in the example), which frees
the linked M_DATA block and returns the output data message
block. The M_IOCDATA message is reused to create an M_COPYOUT message to write the user data.
At case PUTOUTDATA, the message block containing
the state structure is freed and an acknowledgement is sent upstream.
Care must be taken at the "can't happen" default case since the message block containing the state structure (cp_private) is not returned to the pool because it might not be
valid. This might result in a lost block. The ASSERT helps
find errors in the module if a "can't happen" condition occurs.
I_LIST ioctl(2)Example
The I_LIST ioctl(2) lists the drivers and module in a stream.
Example 8-13 List a Stream's Drivers and Modules
#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;
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){
perror("I_LIST ioctl fetch");
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(mlist);
exit(0);
}
|