最近遇到比较多的问题同样的ioctl命令,对于有些网卡,执行此命令可以被up起来,对于某些网卡却无法被up起来,于是就研究了下ioctl命令
问题
为啥同样的ioctl命令对一些网卡生效,能将网卡up起来,而一些网卡却完全不感冒(内核未出现任何异常日志),无法被up起来
分析
在网上查了些资料,发现ioctl命令最终调用的还是网卡驱动中的接口,那就很好理解了,因为驱动中没有提供相应接口(假设网卡固件已支持该up处理逻辑),导致ioctl无法调用到驱动中的up接口(驱动也没有日志提示说不支持),所以就导致了同样的ioctl对于一些网卡可以正常up操作,而一些网卡却不行(当然若驱动中支持了up接口,也还需要网卡固件同样也能支持才可以)
实验
了解了以上大致原因后,自己写模块和用户态程序,验证一下即可,此处以字符设备为例(驱动分块设备、字符设备和网络设备,每类设备都有相应的驱动程序框架,按此框架,初始化相关结构体,关联相关处理函数即可)
内核驱动(ko模块):
/*************************************************************************
> File Name: lz_test.c
> Author:lizhong
> Mail:423810942@qq.com
> Created Time:Tue 27 Aug 2019 06:22:47 PM PDT
> Instruction:
************************************************************************/
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/slab.h>
#include<linux/fs.h>
#include<linux/device.h>
#include<asm/io.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("StayrealS");
MODULE_DESCRIPTION("Driver as a lz test");
#define DEVICE_NAME "lz_test"
#define CLASS_NAME "lz_test_module"
static int lz_test_ioctl(struct file* filp, unsigned int cmd, unsigned long arg);
static int major_number;
static struct class* test_module_class = NULL;
static struct device* test_module_device = NULL;
static const struct file_operations tmf = {
.owner = THIS_MODULE,
.unlocked_ioctl = lz_test_ioctl
};
static int lz_test_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case 0:
printk("ioctl cmd is LZ_TEST_CL\n");
break;
default:
printk("ioctl cmd is other\n");
return -EINVAL;
}
return 0;
}
static int __init lz_test_init(void)
{
printk("start init lz_test ko\n");
major_number = register_chrdev(0, DEVICE_NAME, &tmf);
test_module_class = class_create(THIS_MODULE, CLASS_NAME);
test_module_device = device_create(test_module_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME);
printk("end init lz_test ko\n");
return 0;
}
static void __exit lz_test_exit(void)
{
printk("start uinit lz_test ko\n");
device_destroy(test_module_class, MKDEV(major_number, 0));
class_destroy(test_module_class);
unregister_chrdev(major_number, DEVICE_NAME);
printk("end unint lz_test ko\n");
}
module_init(lz_test_init);
module_exit(lz_test_exit);
Makefile(注意指定清楚内核源码目录环境变量)
MODULE_NAME := lz_test
obj-m := ${MODULE_NAME}.o
PWD := $(shell pwd)
all:
$(MAKE) -C $(KSRCDIR) M=$(PWD)
clean:
$(MAKE) -C $(KSRCDIR) M=$(PWD) clean
用户态程序(c文件):
/*************************************************************************
> File Name: lz_test_user.c
> Author:lizhong
> Mail:423810942@qq.com
> Created Time:Tue 27 Aug 2019 06:30:33 PM PDT
> Instruction:
************************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<sys/ioctl.h>
#include<fcntl.h>
#include"lz_test_user.h"
int main(int argc, char *argv[])
{
int fd = -1;
fd = open("/dev/lz_test", O_RDWR);
ioctl(fd, LZ_TEST_CL);
printf("send ioctl cmd\n");
return 0;
}
头文件:
/*************************************************************************
> File Name: lz_test.h
> Author:lizhong
> Mail:423810942@qq.com
> Created Time:Tue 27 Aug 2019 06:21:34 PM PDT
> Instruction:
************************************************************************/
#ifndef _LZ_TEST_H
#define _LZ_TEST_H
#define LZ_TEST_CL 0
#endif
再编译下用户态程序。之后insmod加载内核驱动,再运行下用户态程序,就可以看到打印出的内核日志了,说明用户态的ioctl最后调用到了该模块注册的操作函数(内核如何注册上这个模块的tmf操作变量,这回就没分析了)