前言:进程间通信有:
socket , 共享内存, 消息队列,信号量,信号,环境变量等
一、字符设备驱动框架流程:
二、实列代码跑的效果:
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(命名管道),字符专用或块专用文件
也可以跟下内核的代码:
编译生成的ko文件,sudo insmod ntychannel.ko 报错如下:
获取公钥私钥:https://wiki.gentoo.org/wiki/Signed_kernel_module_support#Enabling_module_signature_verification
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
可以思考下:虚拟文件系统(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中。
还有就是内核和驱动常用的等待队列的函数的说明(有点像条件等待)。
几个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
五、虚拟网络适配器的实现