ioctl实验

最近遇到比较多的问题同样的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操作变量,这回就没分析了)