用戶空間與內核驅動的交互過程 — ioctl


在Linux內核模塊的開發過程中,經常涉及到運行在用戶空間上的應用程序與內核模塊進行交互,ioctl系統調用是常用的一種方式。本文並不涉及vlan的具體原理,僅通過vconfig與vlan內核模塊進行交互為例,講解通過ioctl系統調用來實現用戶空間與內核驅動交互的過程。

 

1、用戶空間命令行配置工具

vconfig是vlan在用戶空間上的命令行配置工具,在vconfig的源碼中,可以看到在用戶空間上與內核通信部分,其實僅做了三件事。

接收用戶輸入,填充vlan_ioctl_args結構體,vlan_ioctl_args結構體在linux/linux-2.6/include/linux/if_vlan.h中定義。

 1 struct vlan_ioctl_args {
 2     int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
 3     char device1[24];
 4 
 5         union {
 6         char device2[24];
 7         int VID;
 8         unsigned int skb_priority;
 9         unsigned int name_type;
10         unsigned int bind_type;
11         unsigned int flag; /* Matches vlan_dev_info flags */
12         } u;
13 
14     short vlan_qos;   
15 };

創建socket描述符

1    /* We use sockets now, instead of the file descriptor */
2    if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
3       fprintf(stderr, "FATAL:  Couldn't open a socket..go figure!\n");
4       exit(2);
5    }   

ioctl請求

1    /* add */
2    if (strcasecmp(cmd, "add") == 0) {
3       if_request.cmd = ADD_VLAN_CMD;
4       if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
5          fprintf(stderr,"ERROR: trying to add VLAN #%u to IF -:%s:-  error: %s\n",
6                     vid, if_name, strerror(errno));                 
7       }
8    }//if

 

2、內核空間 vlan驅動

vlan驅動工作在內核空間,因此需要相應的內核API去讀取用戶空間的數據。在/linux/linux-2.6/net/8021q/vlan.c的vlan模塊初始化函數vlan_proto_init中使用vlan_ioctl_set注冊vlan_ioctl_handler函數,使之用於響應用戶空間的ioctl請求。

1 vlan_ioctl_set(vlan_ioctl_handler);

在vlan_ioctl_handler函數中,首先使用copy_from_user函數從用戶空間拷貝數據到內核空間。

1 struct vlan_ioctl_args args;
2 
3 if (copy_from_user(&args, arg, sizeof(struct vlan_ioctl_args)))
4         return -EFAULT;

在/linux/linux-2.6/net/socket.c中可以查看到vlan_ioctl_set的定義,它的參數是一個函數指針。當把vlan_ioctl_handler函數作為參數傳遞時,vlan_ioctl_hook指向其首地址,通過這種方式把對特定ioctl的響應處理方法注冊進內核。用戶可以添加不同的命令,只需在模塊的vlan_ioctl_handler中對相應的命令進行解析、響應即可。

 1 static DEFINE_MUTEX(vlan_ioctl_mutex);
 2 static int (*vlan_ioctl_hook) (void __user *arg);
 3 
 4 void vlan_ioctl_set(int (*hook) (void __user *))
 5 {
 6     mutex_lock(&vlan_ioctl_mutex);
 7     vlan_ioctl_hook = hook;
 8     mutex_unlock(&vlan_ioctl_mutex);
 9 }
10 
11 EXPORT_SYMBOL(vlan_ioctl_set);

而后的sock_ioctl函數中調用了vlan_ioctl_hook,void __user *argp指向用戶空間傳遞的參數。

 1 case SIOCGIFVLAN:
 2 case SIOCSIFVLAN:
 3             err = -ENOPKG;
 4             if (!vlan_ioctl_hook)
 5                 request_module("8021q");
 6 
 7             mutex_lock(&vlan_ioctl_mutex);
 8             if (vlan_ioctl_hook)
 9                 err = vlan_ioctl_hook(argp);
10             mutex_unlock(&vlan_ioctl_mutex);
11             break;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM