STREAMS Programming Guide

I_STR ioctl(2) Processing

Neither the transparent nor nontransparent method implements ioctl(2) in the Stream head, but in the Streams driver or module itself. 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 following:

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-6, illustrates processing associated with an I_STR ioctl(2). lpdoioctl is called by lp write-side put or service procedure to process M_IOCTL messages:


Example 8-6 I_STR ioctl(2)

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);
		}
	}

lpdoioctl illustrates driver M_IOCTL processing, which also applies to modules. In this example, only one command is recognized, SET_OPTIONS. ioc_count contains the number of user-supplied data bytes. For this example, ioc_count must equal the size of a short.

Once the command has been verified [lines 20-24], lpsetopt (not shown here) is called to process the request [lines 26-27]. lpsetopt returns 0 if the request is satisfied, otherwise an error number is returned.

If ioc_error is nonzero, on receipt of the acknowledgment the Stream head returns -1 to the application's ioctl(2) request and sets errno to the value of ioc_error. The ioctl(2) is acknowledged [lines 30-33). 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.

This example is for a driver. In the default case, for unrecognized commands, or for malformed requests, a nak is generated [lines 34-38). This is done by changing the message type to an M_IOCNAK and sending it back up stream. A module does not acknowledge (nak) an unrecognized command, but passes the message on. A module does not acknowledge (nak) a malformed request.