【linux驱动】用户空间程序与内核模块交互-- IOCTL和Netlink

创建自定义的IOCTL(输入/输出控制)或Netlink命令以便用户空间程序与内核模块交互涉及几个步骤。这里将分别介绍这两种方法。

一、IOCTL 方法

1. 定义IOCTL命令

在内核模块中,需要使用宏定义你的IOCTL命令。通常情况下,IOCTL命令包括了一个命令编号、请求类型的方向(读/写/两者)以及数据大小:

#include <linux/ioctl.h>

#define MY_IOCTL_TYPE 'x'  // 通常是一个字符

#define MY_IOCTL_CMD1 _IOR(MY_IOCTL_TYPE, 1, my_data_struct)
#define MY_IOCTL_CMD2 _IOW(MY_IOCTL_TYPE, 2, my_data_struct)
// ...

2. 实现ioctl函数

在你的内核模块中,实现ioctl系统调用的函数处理:

static long my_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    my_data_struct data;
    switch (cmd) {
        case MY_IOCTL_CMD1:
            if (copy_from_user(&data, (my_data_struct __user *)arg, sizeof(data)))
                return -EFAULT;
            // 处理MY_IOCTL_CMD1
            break;
        case MY_IOCTL_CMD2:
            // 处理MY_IOCTL_CMD2
            if (copy_to_user((my_data_struct __user *)arg, &data, sizeof(data)))
                return -EFAULT;
            break;
        default:
            return -ENOTTY; // 未知的命令
    }
    return 0; // 成功
}

const struct file_operations fops = {
    .unlocked_ioctl = my_ioctl,
    // 其他的file_operations成员
};

3. 在用户空间调用IOCTL

应用程序使用`ioctl`系统调用与内核模块交流:

#include <sys/ioctl.h>
#include <fcntl.h>

int fd = open("/dev/mydevice", O_RDWR);
my_data_struct data;
// 设置 data
ioctl(fd, MY_IOCTL_CMD2, &data);
// 读取 data
ioctl(fd, MY_IOCTL_CMD1, &data);
close(fd);

二、Netlink 方法

1. 初始化Netlink Socket

在内核模块中,创建并初始化Netlink Socket:

#include <net/sock.h>
struct sock *nl_sk = NULL;

static void nl_recv_msg(struct sk_buff *skb) {
    // 从skb中解析出消息并处理
}

static int __init my_module_init(void) {
    struct netlink_kernel_cfg cfg = {
        .input = nl_recv_msg,
    };
    nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
    if (!nl_sk) {
        pr_err("Error creating socket.\n");
        return -10;
    }

    return 0;
}

2. 实现Netlink消息处理函数

如上所示,`nl_recv_msg`是在用户空间发送消息到内核时调用的接收消息处理函数。处理逻辑根据具体需求实现。

3. 用户空间程序

在用户空间程序中,使用Netlink进行通讯:

#include <sys/socket.h>
#include <linux/netlink.h>

struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
int nl_sock;

// 创建Netlink Socket
nl_sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);

// 初始化地址结构
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); // 自进程ID

bind(nl_sock, (struct sockaddr*)&src_addr, sizeof(src_addr));

memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;   // 对端的ID,0表示内核
dest_addr.nl_groups = 0; // 无组播

// 发送消息到内核

记得在模块中注册Netlink操作,并且在模块退出时释放Netlink Socket,用户空间程序需要负责构造和解码Netlink消息。以上只是一个概述,实现时往往需要处理更多的细节和错误情况。

三、创建一个字符设备让用户空间程序进行读写操作,内核模块可以对这些操作进行响应

在Linux中,字符设备是可以进行按字节流读写操作的设备。创建一个字符设备使得用户空间的程序可以打开、读写、关闭等操作,并使得内核模块能够对这些操作进行响应,通常是通过实现一个设备驱动来完成的。`ioctl`是一个系统调用,用于设备特定的操作,如配置或获取设备信息。在字符设备驱动中实现`ioctl`是可选的,取决于设备是否需要提供额外的设备控制功能。

以下是创建和注册字符设备的基本步骤:

1. 分配设备号:

使用`alloc_chrdev_region`来动态申请主设备号和从设备号,或者使用`register_chrdev_region`如果你希望静态指定设备号。

2. 创建设备类和设备节点:

通常采用`class_create`创建一个设备类,并使用`device_create`创建设备节点。设备节点是用户空间与设备交云的接口,在`/dev/`目录下创建。

3. 初始化`cdev`结构:

`cdev`结构代表字符设备的内核结构。使用`cdev_init`来初始化`cdev`结构,并关联该结构与之前定义的文件操作函数集合。

4. 添加 cdev 到内核中:

使用`cdev_add`将`cdev`结构添加到内核中,设备就会变为活跃状态,用户空间就可以访问它了。

5. 实现文件操作函数:

定义一个包含`open`、`release`、`read`、`write`等操作的`file_operations`结构,这样用户空间应用就可以通过系统调用来操作驱动。

例如,以下代码段演示了以上步骤的基本框架:

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>

static int major;
static struct class *my_class;
static struct cdev my_cdev;

static int my_open(struct inode *inode, struct file *file)
{
    // 打开设备的代码
    return 0;
}

static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos)
{
    // 读取设备的代码
    return 0; // 返回读取的字节数
}

static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *f_pos)
{
    // 写入设备的代码
    return count; // 返回写入的字节数
}

static int my_release(struct inode *inode, struct file *file)
{
    // 关闭设备的代码
    return 0;
}

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .read = my_read,
    .write = my_write,
    .release = my_release,
    // 如果你需要使用ioctl,则在这里添加.unlocked_ioctl = my_ioctl,
};

static int __init my_init(void)
{
    dev_t dev_id;
    
    // 1. 分配设备号
    if (alloc_chrdev_region(&dev_id, 0, 1, "my_device") < 0) {
        return -1;
    }
    major = MAJOR(dev_id);
    
    // 2. 创建设备类和设备节点
    my_class = class_create(THIS_MODULE, "my_device_class");
    device_create(my_class, NULL, dev_id, NULL, "mydevice");
    
    // 3. 初始化cdev结构
    cdev_init(&my_cdev, &my_fops);
    
    // 4. 添加cdev到内核中
    if (cdev_add(&my_cdev, dev_id, 1) < 0) {
        unregister_chrdev_region(dev_id, 1);
        return -1;
    }
    
    return 0;
}

static void __exit my_exit(void)
{
    dev_t dev_id = MKDEV(major, 0);
    
    // 5. 从系统中删除cdev
    cdev_del(&my_cdev);
    
    // 销毁设备节点和设备类
    device_destroy(my_class, dev_id);
    class_destroy(my_class);
    
    // 释放设备号
    unregister_chrdev_region(dev_id, 1);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");

在`my_fops`中,你可以实现`.unlocked_ioctl`(或`.ioctl`,取决于内核版本)来响应`ioctl`调用。请注意,这只是一个简单的框架。在实际的驱动实现中,你将需要填充这些函数,处理错误情况,并且可能需要处理并发控制和同步问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/329892.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RHCE9学习指南 第21章 用bash写脚本

grep的用法是&#xff1a; grep 关键字 file 意思是从file中过滤出含有关键字的行。 例如&#xff0c;grep root /var/log/messages&#xff0c;意思是从/var/log/messages中过滤出含有root的行。这里很明确的是过滤含有“root”的行。 如果我要是想在/var/log/messages中过滤…

IPv6自动隧道---6to4隧道

IPv6 over IPv4自动隧道特点 由于IPv4兼容IPv6隧道要求每一个主机都要有一个合法的IP地址,而且通讯的主机要支持双栈、支持IPv4兼容IPv6隧道,不适合大面积部署。目前该技术已经被6to4隧道所代替。 6to4隧道 集手动隧道和自动隧道的优点于一身,提出6to4的目的是为IPv4网络…

git 常规操作及设置

git 常规操作及设置 Git是一个分布式版本控制系统&#xff0c;可以用来跟踪文件的修改历史并与其他人进行协作开发。下面是一些常见的Git操作及设置&#xff1a; 初始化仓库&#xff1a;使用命令git init在当前目录创建一个新的Git仓库。 克隆仓库&#xff1a;使用命令git clo…

web terminal - 如何在mac os上运行gotty

gotty可以让你使用web terminal的方式与环境进行交互&#xff0c;实现终端效果 假设你已经配置好了go环境&#xff0c;首先使用go get github.com/yudai/gotty命令获取可执行文件&#xff0c;默认会安装在$GOPATH/bin这个目录下&#xff0c;注意如果你的go版本比较高&#xff…

【elementUI】el-select相关问题

官方使用DEMO <template><el-select v-model"value" placeholder"请选择"><el-optionv-for"item in options":key"item.value":label"item.label":value"item.value"></el-option></…

CTF CRYPTO 密码学-4

题目名称&#xff1a;奇怪的先生 题目描述&#xff1a; 描述:oss先生将三个培根的中间一只移到了左边,然后咬了一小口最后一根&#xff0c;说真好吃&#xff0c;真是个奇怪的先生&#xff01; 密文&#xff1a;VlM5WnlXc0ZibEhmMmE1ZHYxMDlhVkdmMlk5WmtRPT0 分析 应该是根据题…

Firefox 100 正式发布

五月三日&#xff0c;Firefox发布了它的第100个版本&#xff0c;来回顾一下Firefox是如何走到今天这一步的&#xff0c;以及在第100个版本中发布了哪些功能。 回顾 2004年&#xff0c;《纽约时报》上宣布了Firefox 1.0的发布&#xff0c;这个广告列出了为第一版做出贡献的每一…

物联网中的通信技术

阅读引言&#xff1a; 本文主要大致为大家带来物联网中的常见的通信方式的知识梳理。 目录 一、概述 二、无线通信技术 1.物联网电子标签 RFID 1.1 RFID 概念 1.2 RFID 系统组成 2.WI-FI技术 3.UWB技术 4.ZigBee技术 5.NFC技术 6.蓝牙技术 7.EnOcean技术 一、概述 物…

Spring06

一、SpirngMvc的基本概念 Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架&#xff0c;本质上相当于 Servlet。 MVC&#xff08;Model View Controller&#xff09;&#xff0c;一种用于设计创建Web应用程序的开发模式 Model&#xff08;模型&#xff…

苹果电脑(Mac)的node版本安装以及升降级

在开发过程中&#xff0c;对于不同的开发环境或者较老的项目可能需要切换不同的node版本&#xff0c;此过程会涉及到node版本的升级与降级&#xff0c;安装node版本管理模块n&#xff08;sudo命令&#xff09;。 全局安装n模块 sudo npm install n -g//输入后回车&#xff0c…

自动驾驶轨迹规划之碰撞检测(三)

欢迎大家关注我的B站&#xff1a; 偷吃薯片的Zheng同学的个人空间-偷吃薯片的Zheng同学个人主页-哔哩哔哩视频 (bilibili.com) 目录 1.基于圆覆盖 2.BVH 3.MATLAB自动驾驶工具箱 4 ROS内置的模型 自动驾驶轨迹规划之碰撞检测&#xff08;一&#xff09;-CSDN博客 自动驾…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用相机日志跟踪功能(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用相机日志跟踪功能&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机NEOAPI SDK和短曝光功能的技术背景Baumer工业相机通过NEOAPI SDK使用相机日志跟踪功能1.引用合适的类文件2.通过NEOAPI SDK使用相机日志跟踪功能3.通…

C# 实现单线程异步互斥锁

文章目录 前言一、异步互斥锁的作用是什么&#xff1f;示例一、创建和销毁 二、如何实现&#xff1f;1、标识&#xff08;1&#xff09;标识是否锁住&#xff08;2&#xff09;加锁&#xff08;3&#xff09;解锁 2、异步通知&#xff08;1&#xff09;创建对象&#xff08;2&a…

Docker篇之修改docker默认磁盘占用目录

一、前言 通常情况下&#xff0c;当我们默认安装docker服务时&#xff0c;在不指定默认存储路径时&#xff0c;docker会自动创建目录&#xff0c;经常会出现打满根目录的情况。 默认存储路径为&#xff1a;/var/lib/docker 下 可通过如下进行查询&#xff1a; docker info输出…

UKP3d的管道编辑

山西这家用户在使用UKP3d时&#xff0c;提出以下问题&#xff1a; 1、stp导入的模型怎么测量距离&#xff1b;另外需要把某一个点移动至原点坐标&#xff0c;这个怎么操作呢&#xff1f; 回复&#xff1a;dist&#xff08;主要是捕捉点&#xff0c;推荐使用&#xff08;开启精…

国产阿里的Copilot能提效30%吗?

国产阿里的Copilot能提效30%吗&#xff1f; Copilot简介 GitHub 和 OpenAI 共同打造的一款编程神器–Copilot&#xff0c; 这是一款立足于人工智能技术的编程助手。在此基础上&#xff0c;借助于 GitHub 庞大的代码库和来自全球的开源社区帮助&#xff0c;搭配 OpenAI 在自然…

VS+QT编译环境中字符乱码问题详解

字符乱码问题详解 1 编码字符集与字符编码方式2 字符乱码原因3 字符乱码解决方案 在解释字符乱码问题之前&#xff0c;我们需要先理清一些基本概念 1 编码字符集与字符编码方式 编码字符集 编码字符集是所有字符以及对应代码值的集合。编码字符集中的每个字符都对应一个唯一的…

进阶Docker4:网桥模式、主机模式与自定义网络

目录 网络相关 子网掩码 网关 规则 docke网络配置 bridge模式 host模式 创建自定义网络(自定义IP) 网络相关 IP 子网掩码 网关 DNS 端口号 子网掩码 互联网是由许多小型网络构成的&#xff0c;每个网络上都有许多主机&#xff0c;这样便构成了一个有层次的结构。 IP 地…

【开源】基于JAVA语言的智慧家政系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询家政服务4.2 新增单条服务订单4.3 新增留言反馈4.4 小程序登录4.5 小程序数据展示 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的智慧家政系统&#xff0…

OB SQL引擎和存储引擎

文章目录 一 SQL引擎1.1 双模共存1.2 基本操作1.3 查看SQL的执行计划 二 存储引擎2.1 传统数据库存在的问题2.2 LSM-Tree存储2.3 OceanBase转储和合并2.4 控制内存数据落盘2.5 LSMTree存储压缩 三 备份恢复3.1 物理备份系统架构3.2 物理恢复系统架构 一 SQL引擎 1.1 双模共存 …