|
xxwput() first checks whether the ioctl(2) command is transparent. If it is, the message is reused as an M_COPYOUT copy request message. The pointer to the receiving buffer is in the linked message and is copied into cq_addr. Because 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.
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);
|
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) */
}
|
|