We have seen that the ioctl system call is
implemented for sockets; SIOCSIFADDR
and
SIOCSIFMAP
are examples of “socket
ioctls.” Now let’s see how the third argument of
the system call is used by networking code.
When the ioctl system call is invoked on a
socket, the command number is one of the symbols defined in
<linux/sockios.h>
, and the function
sock_ioctl directly invokes a protocol-specific
function (where “protocol” refers to the main network protocol being
used, for example, IP or AppleTalk).
Any ioctl command that is not recognized by the
protocol layer is passed to the device layer. These device-related
ioctl commands accept a third argument from user
space, a struct ifreq *
. This structure is defined
in <linux/if.h>
. The
SIOCSIFADDR
and SIOCSIFMAP
commands actually work on the ifreq
structure. The
extra argument to SIOCSIFMAP
, although defined as
ifmap
, is just a field of ifreq
.
In addition to using the standardized calls, each interface can define
its own ioctl commands. The
plip interface, for example, allows the
interface to modify its internal timeout values via
ioctl. The ioctl
implementation for sockets recognizes 16 commands as private to the
interface: SIOCDEVPRIVATE
through
SIOCDEVPRIVATE+15
.
When one of these commands is recognized,
dev->do_ioctl
is called in the relevant
interface driver. The function receives the same struct ifreq *
pointer that the general-purpose
ioctl function uses:
int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
The ifr
pointer points to a kernel-space address
that holds a copy of the structure passed by the user. After
do_ioctl returns, the structure is copied back to
user space; the driver can thus use the private commands to both
receive and return data.
The device-specific commands can choose to use the fields in
struct ifreq
, but they already convey a
standardized meaning, and it’s unlikely that the driver can adapt the
structure to its needs. The field ifr_data
is a
caddr_t
item (a pointer) that is meant to be used
for device-specific needs. The driver and the program used to invoke
its ioctl commands should agree about the use of
ifr_data
. For example,
pppstats uses device-specific commands to
retrieve information from the ppp interface
driver.
It’s not worth showing an implementation of
do_ioctl here, but with the information in this
chapter and the kernel examples, you should be able to write one when
you need it. Note, however, that the plip
implementation uses ifr_data
incorrectly and should
not be used as an example for an ioctl
implementation.