STREAMS Programming Guide

M_COPYOUT Example


Note -

Please see copyout() section in the Writing Device Driversfor information on the 64-bit data structure macros.


Example 8-8 returns option values for this Stream device by placing them in the user's options structure. This is done by a transparent ioctl(2) call of the form


struct options optadd;

ioctl(fd, GET_OPTIONS,(caddr_t) &optadd) 

or by an I_STR call

	struct strioctl opts_strioctl;
	structure options optadd;

	opts_strioctl.ic_cmd = GET_OPTIONS;
	opts_strioctl.ic_timeout = -1
	opts_strioctl.ic_len = sizeof (struct options);
	opts_strioctl.ic_dp = (char *)&optadd;
	ioctl(fd, I_STR, (caddr_t) &opts_strioctl) 

In the I_STR case, opts_strioctl.ic_dp points to the options structure, optadd.

Example 8-8 illustrates support of both the I_STR and transparent forms of ioctl(2). The transparent form requires a single M_COPYOUT message following receipt of the M_IOCTL to copyout the contents of the structure. xxwput is the write-side put procedure of module or driver xx.

This example first checks if the ioctl(2) command is transparent [line 22]. If it is, the message is reused as an M_COPYOUT copy request message [lines 24-32]. The pointer to the receiving buffer is in the linked message and is copied into cq_addr [lines 26-27]. Since only a single copy out is being done, no state information needs to be stored in cq_private. The original linked message is freed, in case it isn't big enough to hold the request [lines 32-33]. 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)

A new linked message is allocated to hold the option request [lines 32-40]. When using the transparent ioctl(2) the 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 a M_IOCACK message [lines 59-73]. ioc_error, ioc_count, and ioc_rval are cleared to prevent any stale data from being passed back to the Stream head [lines 69-71].

If the message is not transparent (is issued through an I_STR ioctl(2)) the data is sent with the M_IOCACK acknowledgment message and copied into the buffer specified by the strioctl data structure [lines 50-51].


Example 8-8 M_COPYOUT Example

	struct options {						/* same members as in user space */
		int			op_one;
		int			op_two;
		short			op_three;
		long			op_four;
	};

	static int
	xxwput (queue_t *q, mblk_t *mp)
	{
		struct iocblk *iocbp;
		struct copyreq *cqp;
		struct copyresp *csp;
		int transparent = 0;

		switch (mp->b_datap->db_type) {
			.
			.
			.
			case M_IOCTL:
				iocbp = (struct iocblk *)mp->b_rptr;
				switch (iocbp->ioc_cmd) {
					case GET_OPTIONS:
						if (iocbp->ioc_count == TRANSPARENT) {
							transparent = 1;
							cqp = (struct copyreq *)mp->b_rptr;
							cqp->cq_size = sizeof(struct options);
							/* Get struct address from linked M_DATA block */
							cqp->cq_addr = (caddr_t) 
														*(caddr_t *)mp->b_cont->b_rptr;
							cqp->cq_flag = 0;
							/* No state necessary - we will only ever get one 
							 * M_IOCDATA from the Stream head indicating success or 
							 * failure for the copyout */
						}
						if (mp->b_cont)
							freemsg(mp->b_cont);
						if ((mp->b_cont = 
									allocb(sizeof(struct options), BPRI_MED)) == NULL) {
							mp->b_datap->db_type = M_IOCNAK;
							iocbp->ioc_error = EAGAIN;
							qreply(q, mp);
							break;
						}
						/* 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);
						}
						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:
				csp = (struct copyresp *)mp->b_rptr;
				/* M_IOCDATA not for us */
				if (csp->cmd != GET_OPTIONS) {
					/*if module/pass on, if driver/free message*/
					break;
				}
				if ( csp->cp_rval ) {
					freemsg(mp);	/* failure */
					return (0);
				}
				/* Data successfully copied out, ack */

				/* 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;
				.
				.
				.
			} /* switch (mp->b_datap->db_type) */
			return (0);