![]() |
![]() |
| ||||||
|
The iocblk(9S), copyreq(9S), and copyresp(9S) structures contain a field indicating the type of ioctl(2) command, a pointer to the user's credentials, and a unique identifier for this ioctl(2). These fields must be preserved. The structure member cq_private is reserved for use by the module. M_COPYIN and M_COPYOUT request messages contain a cq_private field that can be set to contain state information for ioctl(2) processing (which identifies what the subsequent M_IOCDATA response message contains). This state is returned in cp_private in the M_IOCDATA message. This state information determines the next step in processing the message. Keeping the state in the message makes the message self-describing and simplifies the ioctl(2) processing. For each piece of data that the module copies from user space, an M_COPYIN message is sent to the stream head. The M_COPYIN message specifies the user address (cq_addr) and number of bytes (cq_size) to copy from user space. The stream head responds to the M_COPYIN request with a M_IOCDATA message. The b_cont field of the M_IOCDATA mblk contains the contents pointed to by the M_COPYIN request. Likewise, for each piece of data that the module copies to user space, an M_COPYOUT message is sent to the stream head. Specify the user address (cq_addr) and number of bytes to copy (cq_size). The data to be copied is linked to the M_COPYOUT message as one or more M_DATA messages. The stream head responds to M_COPYOUT requests with an M_IOCDATA message, but b_cont is null. After the module has finished processing the ioctl (that is, all M_COPYIN and M_COPYOUT requests have been processed), the ioctl(2) must be acknowledged with an M_IOCACK to indicate successful completion of the command or an M_IOCNAK to indicate failure. If an error occurs when attempting to copy data to or from user address space, the stream head will set cp_rval in the M_IOCDATA message to the error number. In the event of such an error, the M_IOCDATA message should be freed by the module or driver. No acknowledgement of the ioctl(2) is sent in this case. Transparent ioctl ExamplesFollowing are three examples of transparent ioctl(2) processing. Example 8-8 and Example 8-9 illustrate how to use M_COPYIN to copy data from user space. Example 8-10 illustrates how to use M_COPYOUT to copy data to user space. Example 8-11 is a more complex example showing state transitions that combine M_COPYIN and M_COPYOUT. In these examples the message blocks are reused to avoid the overhead of allocating, copying, and releasing messages. This is standard practice. The stream head guarantees that the size of the message block containing an iocblk(9S) structure is large enough to also hold the copyreq(9S) and copyresp(9S) structures. M_COPYIN ExampleNote - Please see the copyin section in Writing Device Drivers for information on the 64-bit data structure macros. Example 8-8 illustrates the processing of a transparent ioctl(2) request only (nontransparent request processing is not shown). In this example, the contents of a user buffer are to be transferred into the kernel as part of an ioctl call of the form
where bufadd is a struct address whose elements are:
This requires two pairs of messages (request and response) following receipt of the M_IOCTL message: the first copyin(9F), shown in Example 8-8, copies the structure (address) , and the second copyin(9F), shown in Example 8-9, copies the buffer (address.ad.addr). Two states are maintained and processed in this example: GETSTRUCT is for copying the address structure and GETADDR for copying the ad_addr of the structure. The transparent part of the SET_ADDR M_IOCTL message processing requires that the address structure be copied from user address space. To accomplish this, the M_IOCTL message processing issues an M_COPYIN request to the stream head. Example 8-8 M_COPYIN: Copy the address Structure
xxwput() verifies that the SET_ADDR is TRANSPARENT to avoid confusion with an I_STR ioctl(2), which uses a value of ioc_cmd equivalent to the command argument of a transparent ioctl(2). The if else statement checks whether the size count is equal to TRANSPARENT. If it is equal, the message was not generated from an I_STR ioctl(2) and the else clause of the if else executes.
The mblk is reused and mapped into a copyreq(9S) structure. The user space address of bufadd is contained in the b_cont of the M_IOCTL mblk. This address and its size are copied into the copyreq(9S) message. The b_cont of the copy request mblk is not needed, so it is freed and then filled with NULL.
Example 8-9 M_COPYIN: Copy the Buffer Address
| ||||||
| ||||||