Linux内核编程--字符设备文件,进行进程间通信,弄清open调用流程

前言:进程间通信有:

socket ,  共享内存, 消息队列,信号量,信号,环境变量等

一、字符设备驱动框架流程:

字符设备驱动框架流程:

二、实列代码跑的效果:

发送数据
接收数据
Makefile
我们可以单独看mmap和poll

poll的实现主要是使用的内核,驱动程序常用的等待队列

关于系统调用:(以调用open函数)

系统调用触发中断,中断会去找系统调用表通过基地址寻址调用内核sys_open, 然后调用file_operations里的函数。

open与channel_open有什么联系??

1. 调用open

2.触发int ox80的中断,中断的入口函数system_call

3.在system_call里面,调用sys_call_table,系统调用表

4.在unistd.h里,设置系统调用ID, (fork id 2 , read id is 3)

5. sys_call_table通过基地址寻址,sys_call_table+%eax*4-->

6. 调用内核函数sys_open

7. sys_调用file_operations对应的接口

fd位于应用层,而file位于内核层,他们都同属进程相关的概念。在linux中,同一个文件(对应于唯一的inode)可以被不同的进程打开多次,而每次打开都会获得file数据结构。而每个进程都会维护一个已经打开的file数组,fd就是对应file结构的数组下标。因此,file和fd在进程范围内是一一对应的关系。

inode ------- file_ops

fd ------file数组对应,根据fd找到file->file_ops

struct file {

    const struct file_operations *f_op;

     unsigned int f_flags;// 可读,可写

}

系统调用open,能找到channel_open().流程是这样:open("/dev/ntychannel",) --->每个进程都会被分配个file结构体,---》file结构体里又有个inode, 但是每个文件都有一个inode,inode里有设备号,根据96和0,找到是哪个设备,---》然后通过cdev_init & cdev_add, 把设备cdev和file_operations联系起来。

下面这幅图比较形象:

mknod /dev/ntychennel c 96 0   与ko文件里写的设备号就对应起来

c:字符设备  96:主设备号   0:次设备号

cat /proc/devices:   查看设备号

mknod 用指定名称产生一个FIFO(命名管道),字符专用或块专用文件



上面3张图是一张,因为屏幕小,截不了

也可以跟下内核的代码:

select内部也是调用了poll
虚拟内存结构图


编译生成的ko文件,sudo insmod ntychannel.ko 报错如下:

内核对新加的木块需要验证,现在是验证失败,因为是ubuntu系统上,内核没有编译。最上的跑的结果是我在ubuntu14.04的结果,因为内核从哪个版本开始(不记得版本),就需要验证了

获取公钥私钥:https://wiki.gentoo.org/wiki/Signed_kernel_module_support#Enabling_module_signature_verification

openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform PEM -out signing_key.pem signing_key.x509  -keyout signing_key.priv

sudo su 

openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform DER -out signing_key.x509 -keyout signing_key.pem

对Ko文件加验证

可以思考下:虚拟文件系统(VFS)对mmap前期做了哪些操作?

mmap_pgoff: mmap调用通过这开始进入SYSCALL_DEFINE6(mmap_pgoff)

mmap_pgoff: 检查flags标志位

do_mmap_pgoff:再一次检查各标志位以及边界是否越界,是否多次做映射。get_unmapped_area从共享内存区获取一块没有使用的地址。检查需要映射的文件是否安全。再调用mmap_region()里调用file->f_op->mmap(file, vma)

mmap_region: 主要负责创建和初始化虚拟内存区域,并加入红黑树节点进行管理

Linux内核提供了remap_pfn_range函数: 来实现将内核空间的内存映射到用户空间

将内核空间的内存映射到用户空间,或者说是将用户空间的一个vma虚拟内存区映射到以page开始的一段连续物理页面上

poll的调用流程:

SYSCALL_DEFINE3(poll): 一开始将超时时间转换,然后调用do_sys_poll,如果在poll调用被阻塞时收到signal,do_sys_poll则产生EINR错误;此时返回ERESTART_RESTARTBLOCK,通知内核处理完信号后自动通过sys_restart_syscall重启poll调用(这个过程对用户进程而言是透明的),

do_sys_poll:调用了copy_from_user,把用户空间的pollfd全部copy到内核空间的poll_list中(与epoll的比较效率问题了),初始化poll_wqueues,调用do_poll

do_poll:  1.遍历poll_list,对每个pollfd进行do_pollfd操作,如果pollfd不能满足poll要求(IO没有就绪),poll会自动将进程添加到文件的poll等待队列中;如果pollfd满足poll要求(已有IO就绪),将计数count++,poll_table制成NULL。如果timeout时间内,没有则返回-EINTER。

do_pollfd: 调用fget_light根据fd获取到文件file对象,调用文种文件系统的poll方法,将返回事件取pollfd->events|POLLERR|POLLHUP子集后,放入pollfd->revents中。

do_pollfd()函数
对应文件文件系统的具体poll方法


还有就是内核和驱动常用的等待队列的函数的说明(有点像条件等待)。

几个API是POLL实现的调用的几个内核函数:

wait_event_interruptible(channel->inq, have_data);

在进程执行过程中,有时候需要等待某个条件满足而进行进程阻塞。

常用的一种方法就是让调用者进程暂时挂起,直到目标进程返回结果后,再唤醒等待的进程。

wake_up(&channel->inq); 唤醒等待队列中进程

poll_wait(): 把本进程挂入某个队列

mknod: mknod 函数用于创建各种类型的文件,包括普通文件、特殊文件以及设备文件

设备文件是文件系统中代表设备的特殊文件。与普通的文件相比,设备文件在磁盘(或宿主文件系统所的在其它设备)上只占用一个索引节点,而没有任何用于存放数据的记录块与之相联系。当然,这是因为设备文件的目的并不在于存储和读取数据,而只在于为应用程序提供一条通向具体设备的途径,使应用程序可以跟具体设备建立起连接。

普通文件(以及某些特殊文件)可以通过系统调用 open 来创建,只要在调用参数中或上 O_CREAT 标志,就可以让open函数在目标文件不存在时先创建这个文件。当然也可通过调用 creat() 来直接创建文件,事实上 sys_creat() 就是通过 sys_open() 实现的。可是这两个系统调用都不能用来创建设备文件,因为设备文件的创建需要有一个参数来传递设备号,而 open 和 creat 函数都不包括这个参数。此时就是 mknod 函数存在的意义了。

https://www.1024sou.com/article/363306.html  netlink 协议栈实战

一、libnet库下载:

官网下载地址:

https://github.com/sam-github/libnet

http://sourceforge.net/projects/libnet-dev/

http://packetfactory.openwall.net/projects/libnet/index.html

二、libnet库编译:

CSDN博客上的编译:

http://blog.csdn.net/kanguolaikanguolaik/article/details/9358665

三、libnet库简单示例:

官网示例代码:

http://packetfactory.openwall.net/projects/libnet/dist/deprecated/manual/index.html

四、libnet文档:

官网文档:

http://packetfactory.openwall.net/projects/libnet/dist/deprecated/manual/index.html

五、虚拟网络适配器的实现

你可能感兴趣的:(Linux内核编程--字符设备文件,进行进程间通信,弄清open调用流程)