linux网络协议栈分析——ioctl的调用流程

原文地址:http://blog.csdn.net/cbmsft/article/details/7214639

 

首先从系统调用开始,ioctl的系统调用在fs/ioctl.c中:

[cpp] view plain copy
  1. SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)  
  2. {  
  3.     ……  
  4.     error = do_vfs_ioctl(filp, fd, cmd, arg);  
  5.     ……  
  6. }  

继续:

[cpp] view plain copy
  1. /* 
  2.  * When you add any new common ioctls to the switches above and below 
  3.  * please update compat_sys_ioctl() too. 
  4.  * 
  5.  * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. 
  6.  * It's just a simple helper for sys_ioctl and compat_sys_ioctl. 
  7.  */  
  8. int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,  
  9.          unsigned long arg)  
  10. {  
  11.     ……  
  12.     default:  
  13.         if (S_ISREG(filp->f_path.dentry->d_inode->i_mode))//正规文件则调用文件系统的接口  
  14.             error = file_ioctl(filp, cmd, arg);  
  15.         else  
  16.             error = vfs_ioctl(filp, cmd, arg);//非正规文件的调用接口  
  17.         break;  
  18.     }  
  19.     return error;  
  20. }  

继续:

[cpp] view plain copy
  1. static long vfs_ioctl(struct file *filp, unsigned int cmd,  
  2.               unsigned long arg)  
  3. {  
  4.     ……    
  5.     if (filp->f_op->unlocked_ioctl) {  
  6.         error = filp->f_op->unlocked_ioctl(filp, cmd, arg);  
  7.         if (error == -ENOIOCTLCMD)  
  8.             error = -EINVAL;  
  9.         goto out;  
  10.     } else if (filp->f_op->ioctl) {  
  11.         lock_kernel();  
  12.         error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,  
  13.                       filp, cmd, arg);  
  14.         unlock_kernel();  
  15.     }  
  16.     ……  
  17. }  

那么网络文件系统的f_op是如何赋值的?再看一遍socket的创建过程:

[cpp] view plain copy
  1. SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)  
  2. {  
  3.     ……  
  4.   
  5.     retval = sock_create(family, type, protocol, &sock);  
  6.   
  7.     retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));  
  8.     ……  
  9. }   

顺着sock_map_fd继续,调用了sock_attach_fd,进而调用了init_file,传递的参数为:socket_file_ops,该参数赋值给file结构:

[cpp] view plain copy
  1. file->f_op = fop;  

另外,sock_attach_fd还做了另外的一个操作:

[cpp] view plain copy
  1. file->private_data = sock;  

socket_file_ops的内容:

[cpp] view plain copy
  1. static const struct file_operations socket_file_ops = {  
  2.     ……    
  3.     .unlocked_ioctl = sock_ioctl,  
  4.     ……  
  5. };  

到此尚未结束,sock_ioctl并没有完成想要的操作,而是:

[cpp] view plain copy
  1. static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)  
  2. {  
  3.     struct socket *sock;  
  4.     struct sock *sk;  
  5.     void __user *argp = (void __user *)arg;  
  6.     int pid, err;  
  7.     struct net *net;  
  8.   
  9.     sock = file->private_data;  
  10.     sk = sock->sk;  
  11.     net = sock_net(sk);  
  12.     ……  
  13.         default:  
  14.             err = sock->ops->ioctl(sock, cmd, arg);  
  15.   
  16.             /* 
  17.              * If this ioctl is unknown try to hand it down 
  18.              * to the NIC driver. 
  19.              */  
  20.             if (err == -ENOIOCTLCMD)  
  21.                 err = dev_ioctl(net, cmd, argp);  
  22.             break;  
  23.     ……  
  24. }  

那么ops是从哪里获得的呢:
是从socket在创建inet_create函数中,遍历inetsw链表,获得协议结构,保存在:sock->ops = answer->ops;
真正ops是协议初始化inet_init函数调用inet_register_protosw,把全局数组inetsw_array初始化到inetsw链表中的:
fs_initcall(inet_init);
且看inetsw_array全局数组:

[cpp] view plain copy
  1. static struct inet_protosw inetsw_array[] =  
  2. {  
  3.  {  
  4.   .type =       SOCK_STREAM,  
  5.   .protocol =   IPPROTO_TCP,  
  6.   .prot =       &tcp_prot,  
  7.   .ops =        &inet_stream_ops,  
  8.   .capability = -1,  
  9.   .no_check =   0,  
  10.   .flags =      INET_PROTOSW_PERMANENT |  
  11.          INET_PROTOSW_ICSK,  
  12.  },  
  13.  {  
  14.   .type =       SOCK_DGRAM,  
  15.   .protocol =   IPPROTO_UDP,  
  16.   .prot =       &udp_prot,  
  17.   .ops =        &inet_dgram_ops,  
  18.   .capability = -1,  
  19.   .no_check =   UDP_CSUM_DEFAULT,  
  20.   .flags =      INET_PROTOSW_PERMANENT,  
  21.   },  
  22.  {  
  23.   .type =       SOCK_RAW,  
  24.   .protocol =   IPPROTO_IP, /* wild card */  
  25.   .prot =       &raw_prot,  
  26.   .ops =        &inet_sockraw_ops,  
  27.   .capability = CAP_NET_RAW,  
  28.   .no_check =   UDP_CSUM_DEFAULT,  
  29.   .flags =      INET_PROTOSW_REUSE,  
  30.   }  
  31. };  

这就到了具体协议的ioctl中了:

[cpp] view plain copy
  1. const struct proto_ops inet_stream_ops = {  
  2.     ……    
  3.     .ioctl     = inet_ioctl,  
  4.     ……  
  5. };  

哇,这个函数才是我们关注的重点:

[cpp] view plain copy
  1. int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)  
  2. {  
  3.     struct sock *sk = sock->sk;  
  4.     int err = 0;  
  5.     struct net *net = sock_net(sk);  
  6.   
  7.     switch (cmd) {  
  8.     case SIOCGSTAMP:  
  9.         err = sock_get_timestamp(sk, (struct timeval __user *)arg);  
  10.         break;  
  11.     case SIOCGSTAMPNS:  
  12.         err = sock_get_timestampns(sk, (struct timespec __user *)arg);  
  13.         break;  
  14.     case SIOCADDRT:  
  15.     case SIOCDELRT:  
  16.     case SIOCRTMSG:  
  17.         err = ip_rt_ioctl(net, cmd, (void __user *)arg);  
  18.         break;  
  19.     case SIOCDARP:  
  20.     case SIOCGARP:  
  21.     case SIOCSARP:  
  22.         err = arp_ioctl(net, cmd, (void __user *)arg);  
  23.         break;  
  24.     case SIOCGIFADDR:  
  25.     case SIOCSIFADDR:  
  26.     case SIOCGIFBRDADDR:  
  27.     case SIOCSIFBRDADDR:  
  28.     case SIOCGIFNETMASK:  
  29.     case SIOCSIFNETMASK:  
  30.     case SIOCGIFDSTADDR:  
  31.     case SIOCSIFDSTADDR:  
  32.     case SIOCSIFPFLAGS:  
  33.     case SIOCGIFPFLAGS:  
  34.     case SIOCSIFFLAGS:  
  35.         err = devinet_ioctl(net, cmd, (void __user *)arg);  
  36.         break;  
  37.     default:  
  38.         if (sk->sk_prot->ioctl)  
  39.             err = sk->sk_prot->ioctl(sk, cmd, arg);  
  40.         else  
  41.             err = -ENOIOCTLCMD;  
  42.         break;  
  43.     }  
  44.     return err;  
  45. }  

 

你可能感兴趣的:(linux,ioctl)