This is an old revision of the document!


How net-based IOCTL calls are made – prerequisite for other wiki pages.

UAPI links:

Kernel links:

From ethtool, which has a send_ioctl() wrapper:

#ifndef TEST_ETHTOOL
int send_ioctl(struct cmd_context *ctx, void *cmd)
{
        ctx->ifr.ifr_data = cmd;
        return ioctl(ctx->fd, SIOCETHTOOL, &ctx->ifr);
}
#endif

See The new way of ioctl().

From net/socket.c:

static const struct file_operations socket_file_ops = {
	.owner =	THIS_MODULE,
	.llseek =	no_llseek,
	.read_iter =	sock_read_iter,
	.write_iter =	sock_write_iter,
	.poll =		sock_poll,
	.unlocked_ioctl = sock_ioctl,   <-- this one
#ifdef CONFIG_COMPAT
	.compat_ioctl = compat_sock_ioctl,
#endif
	.mmap =		sock_mmap,
	.release =	sock_close,
	.fasync =	sock_fasync,
	.sendpage =	sock_sendpage,
	.splice_write = generic_splice_sendpage,
	.splice_read =	sock_splice_read,
};

Also from net/socket.c:

static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
        struct socket *sock;
        struct sock *sk;
        void __user *argp = (void __user *)arg;
        int pid, err;
        struct net *net;

        sock = file->private_data;
        sk = sock->sk;
        net = sock_net(sk);
        if (unlikely(cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))) {
                struct ifreq ifr;
                bool need_copyout;
                if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
                        return -EFAULT;
                err = dev_ioctl(net, cmd, &ifr, &need_copyout);
                if (!err && need_copyout)
                        if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
                                return -EFAULT;
        } else
#ifdef CONFIG_WEXT_CORE
        if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
                err = wext_handle_ioctl(net, cmd, argp);
        } else
#endif
                switch (cmd) {
                case FIOSETOWN:
                case SIOCSPGRP:
                        err = -EFAULT;
                        if (get_user(pid, (int __user *)argp))
                                break;
                        err = f_setown(sock->file, pid, 1);
                        break;
                case FIOGETOWN:
                case SIOCGPGRP:
                        err = put_user(f_getown(sock->file),
                                       (int __user *)argp);
                        break;
                case SIOCGIFBR:
                case SIOCSIFBR:
                case SIOCBRADDBR:
                case SIOCBRDELBR:
                        err = -ENOPKG;
                        if (!br_ioctl_hook)
                                request_module("bridge");

                        mutex_lock(&br_ioctl_mutex);
                        if (br_ioctl_hook)
                                err = br_ioctl_hook(net, cmd, argp);
                        mutex_unlock(&br_ioctl_mutex);
                        break;
                case SIOCGIFVLAN:
                case SIOCSIFVLAN:
                        err = -ENOPKG;
                        if (!vlan_ioctl_hook)
                                request_module("8021q");

                        mutex_lock(&vlan_ioctl_mutex);
                        if (vlan_ioctl_hook)
                                err = vlan_ioctl_hook(net, argp);
                        mutex_unlock(&vlan_ioctl_mutex);
                        break;
                case SIOCADDDLCI:
                case SIOCDELDLCI:
                        err = -ENOPKG;
                        if (!dlci_ioctl_hook)
                                request_module("dlci");

                        mutex_lock(&dlci_ioctl_mutex);
                        if (dlci_ioctl_hook)
                                err = dlci_ioctl_hook(cmd, argp);
                        mutex_unlock(&dlci_ioctl_mutex);
                        break;
                case SIOCGSKNS:
                        err = -EPERM;
                        if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                                break;

                        err = open_related_ns(&net->ns, get_net_ns);
                        break;
                default:
                        err = sock_do_ioctl(net, sock, cmd, arg);    <-- there
                        break;
                }
        return err;
}

Still in net/socket.c:

static long sock_do_ioctl(struct net *net, struct socket *sock,
                                 unsigned int cmd, unsigned long arg)
{
        int err;
        void __user *argp = (void __user *)arg;

        err = sock->ops->ioctl(sock, cmd, arg);

        /*
         * If this ioctl is unknown try to hand it down
         * to the NIC driver.
         */
        if (err != -ENOIOCTLCMD)
                return err;

        if (cmd == SIOCGIFCONF) {
                struct ifconf ifc;
                if (copy_from_user(&ifc, argp, sizeof(struct ifconf)))
                        return -EFAULT;
                rtnl_lock();
                err = dev_ifconf(net, &ifc, sizeof(struct ifreq));
                rtnl_unlock();
                if (!err && copy_to_user(argp, &ifc, sizeof(struct ifconf)))
                        err = -EFAULT;
        } else {
                struct ifreq ifr;
                bool need_copyout;
                if (copy_from_user(&ifr, argp, sizeof(struct ifreq)))
                        return -EFAULT;
                err = dev_ioctl(net, cmd, &ifr, &need_copyout);    <-- here???
                if (!err && need_copyout)
                        if (copy_to_user(argp, &ifr, sizeof(struct ifreq)))
                                return -EFAULT;
        }
        return err;
}
  • net_ioctl.1535990133.txt.gz
  • Last modified: 2018/09/03 15:55
  • by rpjday