Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
8.  STREAMS Kernel-Level Mechanisms General ioctl Processing Transparent ioctl Examples M_COPYOUT Example  Previous   Contents   Next 
   
 

As an optimization, the following code checks the size of the message for reuse:

mp->b_cont->b_datap->db_lim 
- mp->b_cont->b_datap->db_base >= sizeof (struct options)


Note - Hardening Information. After message reuse, make sure to retain the relation:

db_base <= b_rptr <= b_wptr <= db_lim

A new linked message is allocated to hold the option request. When using the transparent ioctl(2) M_COPYOUT command, data contained in the linked message is passed to the stream head. The stream head will copy the data to the user's address space and issue an M_IOCDATA in response to the M_COPYOUT message, which the module must acknowledge in an M_IOCACK message.

            /* hypothetical routine */
				xx_get_options(mp->b_cont);
				if (transparent) {
					mp->b_datap->db_type = M_COPYOUT;
					mp->b_wptr = mp->b_rptr + sizeof(struct copyreq);
				} else {
					mp->b_datap->db_type = M_IOCACK;
					iocbp->ioc_count = sizeof(struct options);
				}

If the message is not transparent (is issued through an I_STR ioctl(2)), the data is sent with the M_IOCACK acknowledgement message and copied into the buffer specified by the strioctl data structure. ioc_error, ioc_count, and ioc_rval are cleared to prevent any stale data from being passed back to the stream head.

           /* reuse M_IOCDATA for ack */
				mp->b_datap->db_type = M_IOCACK;
				mp->b_wptr = 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;

Bidirectional Data Transfer Example

Example 8-11 illustrates bidirectional data transfer between the kernel and application during transparent ioctl(2) processing. It also shows how to use more complex state information.

The user wants to send and receive data from user buffers as part of a transparent ioctl(2) call of the form:

	ioctl(fd, XX_IOCTL, (caddr_t) &addr_xxdata) 

Example 8-11 Bidirectional Data Transfer

struct xxdata {             /* same members in user space */
   int         x_inlen;     /* number of bytes copied in */
   caddr_t     x_inaddr;    /* buf addr of data copied in */
   int         x_outlen;    /* number of bytes copied out */
   caddr_t     x_outaddr;   /* buf addr of data copied out */
};
/* State information for ioctl processing */
struct state {
		int         st_state;    /* see below */
		struct xxdata		st_data;		/* see above */
};
/* state values */

#define GETSTRUC     0   /* get xxdata structure */
#define GETINDATA    1   /* get data from x_inaddr */
#define PUTOUTDATA   2   /* get response from M_COPYOUT */

static void xxioc(queue_t *q, mblk_t *mp);

static int
xxwput (queue_t *q, 	mblk_t *mp) {
		struct iocblk *iocbp;
		struct copyreq *cqp;
		struct state *stp;
		mblk_t *tmp;

		switch (mp->b_datap->db_type) {
			.
			.
			.
			case M_IOCTL:
				iocbp = (struct iocblk *)mp->b_rptr;
				switch (iocbp->ioc_cmd) {
				case XX_IOCTL:
				/* do non-transparent processing. (See I_STR ioctl
				 * processing discussed in previous section.)
				 */
				/*Reuse M_IOCTL block for M_COPYIN request*/

				cqp = (struct copyreq *)mp->b_rptr;

				/* Get structure's user address from
				 * linked M_DATA block */

				cqp->cq_addr = (caddr_t)
				 *(long *)mp->b_cont->b_rptr;
				freemsg(mp->b_cont);
				mp->b_cont = NULL;

				/* Allocate state buffer */

				if ((tmp = allocb(sizeof(struct state),
				 BPRI_MED)) == NULL) {
						mp->b_datap->db_type = M_IOCNAK;
						iocbp->ioc_error = EAGAIN;
						qreply(q, mp);
						break;
				}
				tmp->b_wptr += sizeof(struct state);
				stp = (struct state *)tmp->b_rptr;
				stp->st_state = GETSTRUCT;
				cqp->cq_private = tmp;

				/* Finish describing M_COPYIN message */

				cqp->cq_size = sizeof(struct xxdata);
				cqp->cq_flag = 0;
				mp->b_datap->db_type = M_COPYIN;
				mp->b_wptr=mp->b_rptr+sizeof(struct copyreq);
				qreply(q, mp);
				break;

			default: /* M_IOCTL not for us */
				/* if module, pass on */
				/* if driver, nak ioctl */
				break;

			} /* switch (iocbp->ioc_cmd) */
			break;

	case M_IOCDATA:
			xxioc(q, mp);   /*all M_IOCDATA processing here*/
			break;
			.
			.
			.
	} /* switch (mp->b_datap->db_type) */
}

Three pairs of messages are required following the M_IOCTL message:

  1. case GETSTRUCT copies the structure into the message buffer.

  2. case GETINDATA copies the user buffer into the message buffer.

  3. case PUTOUTDATA copies the second message buffer into the user buffer.

 
 
 
  Previous   Contents   Next