首先从系统调用开始,ioctl的系统调用在fs/ioctl.c中:
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { …… error = do_vfs_ioctl(filp, fd, cmd, arg); …… }
继续:
/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too. * * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. * It's just a simple helper for sys_ioctl and compat_sys_ioctl. */ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg) { …… default: if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))//正规文件则调用文件系统的接口 error = file_ioctl(filp, cmd, arg); else error = vfs_ioctl(filp, cmd, arg);//非正规文件的调用接口 break; } return error; }
继续:
static long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { …… if (filp->f_op->unlocked_ioctl) { error = filp->f_op->unlocked_ioctl(filp, cmd, arg); if (error == -ENOIOCTLCMD) error = -EINVAL; goto out; } else if (filp->f_op->ioctl) { lock_kernel(); error = filp->f_op->ioctl(filp->f_path.dentry->d_inode, filp, cmd, arg); unlock_kernel(); } …… }
那么网络文件系统的f_op是如何赋值的?再看一遍socket的创建过程:
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) { …… retval = sock_create(family, type, protocol, &sock); retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); …… }
顺着sock_map_fd继续,调用了sock_attach_fd,进而调用了init_file,传递的参数为:socket_file_ops,该参数赋值给file结构:
file->f_op = fop;
另外,sock_attach_fd还做了另外的一个操作:
file->private_data = sock;
socket_file_ops的内容:
static const struct file_operations socket_file_ops = { …… .unlocked_ioctl = sock_ioctl, …… };
到此尚未结束,sock_ioctl并没有完成想要的操作,而是:
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); …… default: err = sock->ops->ioctl(sock, cmd, arg); /* * If this ioctl is unknown try to hand it down * to the NIC driver. */ if (err == -ENOIOCTLCMD) err = dev_ioctl(net, cmd, argp); break; …… }
那么ops是从哪里获得的呢:
是从socket在创建inet_create函数中,遍历inetsw链表,获得协议结构,保存在:sock->ops = answer->ops;
真正ops是协议初始化inet_init函数调用inet_register_protosw,把全局数组inetsw_array初始化到inetsw链表中的:
fs_initcall(inet_init);
且看inetsw_array全局数组:
static struct inet_protosw inetsw_array[] = { { .type = SOCK_STREAM, .protocol = IPPROTO_TCP, .prot = &tcp_prot, .ops = &inet_stream_ops, .capability = -1, .no_check = 0, .flags = INET_PROTOSW_PERMANENT | INET_PROTOSW_ICSK, }, { .type = SOCK_DGRAM, .protocol = IPPROTO_UDP, .prot = &udp_prot, .ops = &inet_dgram_ops, .capability = -1, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_PERMANENT, }, { .type = SOCK_RAW, .protocol = IPPROTO_IP, /* wild card */ .prot = &raw_prot, .ops = &inet_sockraw_ops, .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, } };
这就到了具体协议的ioctl中了:
const struct proto_ops inet_stream_ops = { …… .ioctl = inet_ioctl, …… };
哇,这个函数才是我们关注的重点:
int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; struct net *net = sock_net(sk); switch (cmd) { case SIOCGSTAMP: err = sock_get_timestamp(sk, (struct timeval __user *)arg); break; case SIOCGSTAMPNS: err = sock_get_timestampns(sk, (struct timespec __user *)arg); break; case SIOCADDRT: case SIOCDELRT: case SIOCRTMSG: err = ip_rt_ioctl(net, cmd, (void __user *)arg); break; case SIOCDARP: case SIOCGARP: case SIOCSARP: err = arp_ioctl(net, cmd, (void __user *)arg); break; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCSIFFLAGS: err = devinet_ioctl(net, cmd, (void __user *)arg); break; default: if (sk->sk_prot->ioctl) err = sk->sk_prot->ioctl(sk, cmd, arg); else err = -ENOIOCTLCMD; break; } return err; }