STREAMS Programming Guide

I_STR ioctl Processing

The transparent and nontransparent methods implement ioctl(2) in the STREAMS driver or module itself, rather than in the stream head. I_STR ioctl(2) (also referred to as nontransparent ioctl(2)) is created when a user requests an I_STR ioctl(2) and specifies a pointer to a strioctl structure as the argument. For example, assuming that fd is an open lp STREAMS device and LP_CRLF is a valid option, the user could make a request by issuing the struct in the following example:


Example 8–6 Struct for Nontransparent ioctl

struct strioctl *str;
short lp_opt = LP_CRLF;

str.ic_cmd = SET_OPTIONS;
str.ic_timout = -1;
str.ic_dp = (char *)&lp_opt;
str.ic_len = sizeof (lp_opt)

ioctl(fd, I_STR, &str);

On receipt of the I_STR ioctl(2) request, the stream head creates an M_IOCTL message. ioc_cmd is set to SET_OPTIONS, ioc_count is set to the value contained in ic_len (in this example sizeof (short)). An M_DATA mblk is linked to the M_IOCTL mblk and the data pointed to by ic_dp is copied into it (in this case LP_CRLF).

Example 8–7 illustrates processing associated with an I_STR ioctl(2). lpdoioctl illustrates driver M_IOCTL processing, which also applies to modules. lpdoioctl is called by lp write-side put or service procedure to process M_IOCTL messages. This example is for a driver.


Example 8–7 I_STR ioctl(2) Driver

static void
lpdoioctl (queue_t *q, mblk_t	 *mp)
{
		struct iocblk *iocp;
		struct lp *lp;

		lp = (struct lp *)q->q_ptr;

		/* 1st block contains iocblk structure */
		iocp = (struct iocblk *)mp->b_rptr;

		switch (iocp->ioc_cmd) {
		  case SET_OPTIONS:
			  /* Count should be exactly one short's worth
			   * (for this example) */
			  if (iocp->ioc_count != sizeof(short))
				  goto iocnak;
			  if (mp->b_cont == NULL)
				  goto lognak; /* not shown in this example */
			  /* Actual data is in 2nd message block */
			  iocp->ioc_error = lpsetopt (lp, *(short *)mp->b_cont->b_rptr)

			  /* ACK the ioctl */
			  mp->b_datap->db_type = M_IOCACK;
			  iocp->ioc_count = 0;
			  qreply(q, mp);
			  break;
		  default:
			  iocnak:
			  /* NAK the ioctl */
			  mp->b_datap->db_type = M_IOCNAK;
			  qreply(q, mp);
		}
	}

This example recognizes only one command, SET_OPTIONS. The ioc_count contains the number of user-supplied data bytes. ioc_count must equal the size of a short.

    switch (iocp->ioc_cmd) {
			case SET_OPTIONS:
				/* Count should be exactly one short's worth
				 * (for this example) */
				if (iocp->ioc_count != sizeof(short))
					goto iocnak;
				if (mp->b_cont == NULL)
					goto lognak; /* not shown in this example */

Once the command has been verified, lpsetopt is called to process the request. lpsetopt returns 0 if the request is satisfied, otherwise an error number is returned. If ioc_error is nonzero, on receipt of the acknowledgement the stream head returns -1 to the application's ioctl(2) request and sets errno to the value of ioc_error.

        /* Actual data is in 2nd message block */
			iocp->ioc_error = lpsetopt (lp, *(short *)mp->b_cont->b_rptr)

The ioctl(2) is acknowledged. This includes changing the M_IOCTL message type to M_IOCACK and setting the ioc_count field to zero to indicate that no data is to be returned to the user. Finally, the message is sent upstream using qreply(9F).

If ioc_count was left nonzero, the stream head would copy that many bytes from the second through the nth message blocks into the user buffer. You must set ioc_count if you want to pass any data back to the user.

           /* ACK the ioctl */
				mp->b_datap->db_type = M_IOCACK;
				iocp->ioc_count = 0;
				qreply(q, mp);
				break;

In the default case for unrecognized commands or malformed requests, a nak is generated. This is done by changing the message type to an M_IOCNAK and sending it back upstream.

          default:
				iocnak:
				/* NAK the ioctl */
				mp->b_datap->db_type = M_IOCNAK;
				qreply(q, mp);

A module does not acknowledge (nak) an unrecognized command, but passes the message on. A module does not acknowledge (nak) a malformed request.