【Linux5.4】【TUN】代码学习记录(10)–tun_chr_ioctl
用户调用ioctl函数时,tun_chr_ioctl被调用。
tun_chr_ioctl
单纯的封装了__tun_chr_ioctl函数
static long tun_chr_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq));
}
__tun_chr_ioctl
__tun_chr_ioctl实际功能是根据用户调用ioctl时的相应标识进行设置,函数中包含了非常多的if和switch等标识符判断。
目前我只注意了两个关键的部分:
①if (cmd == TUNSETIFF) 里面,调用了tun_set_iff,这个函数非常重要,里面会根据输入的ifr.ifr_name判断是否需要重新创建一个虚拟网卡(可使用命令ifconfig查看以创建并在up状态的虚拟网卡),且如果用户设置ifr.ifr_flags时设置了 IFF_MULTI_QUEUE标识符,创建的虚拟网卡可被其它应用程序使用。
否则虚拟网卡只能对应唯一的应用程序,也就是说其它应用程序输入相同的ifr.ifr_name时在tun_set_iff里会失败,返回错误。
IFF_MULTI_QUEUE标识多个应用程序关联同一个虚拟网卡的能力,不设置时应用程序与其创建的虚拟网卡只能是一对一关系。
②case TUNSETPERSIST,设置持续模式,通过ioctl函数设置此功能,应用程序创建的虚拟网卡不会因为应用程序结束而消失。
static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
unsigned long arg, int ifreq_len)
{
...
if (cmd == TUNSETIFF) {
ret = -EEXIST;
if (tun)
goto unlock;
ifr.ifr_name[IFNAMSIZ-1] = '\0';
/* 调用tun_set_iff,创建网卡和设置网卡名称 */
ret = tun_set_iff(net, file, &ifr);
if (ret)
goto unlock;
if (copy_to_user(argp, &ifr, ifreq_len))
ret = -EFAULT;
goto unlock;
}
...
net = dev_net(tun->dev);
ret = 0;
switch (cmd) {
...
case TUNSETPERSIST:
/* Disable/Enable persist mode. Keep an extra reference to the
* module to prevent the module being unprobed.
* 禁用/启用持久化模式。保留对模块的额外引用,以防止模块未被探测。
*/
if (arg && !(tun->flags & IFF_PERSIST)) {
tun->flags |= IFF_PERSIST;
__module_get(THIS_MODULE);
do_notify = true;
}
if (!arg && (tun->flags & IFF_PERSIST)) {
tun->flags &= ~IFF_PERSIST;
module_put(THIS_MODULE);
do_notify = true;
}
tun_debug(KERN_INFO, tun, "persist %s\n",
arg ? "enabled" : "disabled");
break;
...
}