版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、原文地址 HYPERLINK /jh/4/822500.html /jh/4/822500.html发表于:2010-05-27,修改于:2010-06-22 16:12,已浏览244次,有评论3条推荐投诉作者: Kendo2006-9-3这是一篇学习笔记,主要是对Linux系统内核空间与用户空间通信的实现与分析中的源码imp2的分析。其中的源码, 可以到以下URL下载: HYPERLINK /developerworks/cn/linux/l-netlink/imp2.tar.gz /developerworks/cn/linux/l-netlink/imp2.tar.gzsize=3参考文
2、档/sizeLinux 系统内核空间与用户空间通信的实现与分析 陈鑫 HYPERLINK /developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux /developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux在 Linux 下用户空间与内核空间数据交换的方式 杨燚 HYPERLINK /developerworks/cn/linux/l-kerns-usrs/ /developerworks/cn/linux/l-kerns-usrs/size=3理论篇/size在 Li
3、nux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用 netlink 套接字实现的,例如 iprote2网络管理工具,它与内核的交互就全部使用了 netlink,著名的内核包过滤框架Netfilter在与用户空间的通读,也 在最新版本中改变为netlink,无疑,它将是Linux用户态与内核态交流的主要方法之一。它的通信依据是一个对应于进程 的标识,一般定为该进程的ID。当通信的一端处于中断过程时,该标识为0。当使用netlink套接字进行通信,通信的双 方都是用户态进程,则使用方法类似于消息队列。但通信双方有一端是中断过程,使用方法则不同。netlink套接字的最
4、大 特点是对中断过程的支持,它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线程,而是通过另一个软中断 调用用户事先指定的接收函数。工作原理如图:中断过程用户态进程软中断中断过程进程发送数据临界冈进程发送数据(使用自旋 锁来使內核 线程与中断 过程同歩)中断过程发送数据如图所示,这里使用了软中断而不是内核线程来接收数据,这样就可以保证数据接收的实时性。当 netlink 套接字用于内核空间与用户空间的通信时,在用户空间的创建方法和一般套接字使用类似,但内核空间的创建方法则不同,下图是 netlink 套接字实现此类通信时创建的过程:#define NETLINK_ROUTE 0#de
5、fine NETLINK_ROUTE 0*/#define NETLINK_W11*/#define NETLINK_USERSOCK2s */#define NETLINK_FIREWALL3*/#define NETLINK_INET_DIAG4*/#define NETLINK_NFLOG5#define NETLINK_XFRM6#define NETLINK_SELINUX7#define NETLINK_ISCSI8#define NETLINK_AUDIT9#define NETLINK_FIB_LOOKUP10#define NETLINK_CONNECTOR11用户空间 用户
6、态应用使用标准的 socket 与内核通讯,标准的 socket API 的函 数,socket。,bind(), sendmsg(), recvmsg()和 close()很容易地应用至U netlink socket。 为了创建一个netlink socket,用户需要使用如下参数调用socket。: socket(AF_NETLINK, SOCK_RAW, netlink_type)netlink对应的协议簇是AF_NETLINK,第二个参数必须是SOCK_RAW或SOCK_DGRAM,第三个参数指定netlink 协议类型,它可以是一个自定义的类型,也可以使用内核预定义的类型:/* R
7、outing/device hook/* 1-wire subsystem/* Reserved for user mode socket protocol/* Firewalling hook/* INET socket monitoring/* netfilter/iptables ULOG */* ipsec */* SELinux event notifications */* Open-iSCSI */* auditing */ TOC o 1-5 h z #define NETLINK_NETFILTER12#define NETLINK_IP6_FW13#define NETLI
8、NK_DNRTMSG14#define NETLINK_KOBJECT_UEVENT 15 #define NETLINK_GENERIC16/* netfilter subsystem */* DECnet routing messages */* Kernel messages to userspace */同样地,socket函数返回的套接字,可以交给bing等函数调用:static int skfd;skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);if(skfd receive_queue) != NULL)struct nlmsghdr *n
9、lh = NULL;if(skb-len = sizeof(struct nlmsghdr)/*获取数据中的 nlmsghdr 结构的报头*/ nlh = (struct nlmsghdr *)skb-data;if(nlh-nlmsg_len = sizeof(struct nlmsghdr)& (skb-len = nlh-nlmsg_len)/*长度的全法性校验完成后,处理应用程序自定义消息类型,主要是对用户PID的保存,即为内核保存“把消息发送给谁”*/ if(nlh-nlmsg_type = IMP2_U_PID) write_lock_bh(&user_proc.pid);user
10、_proc.pid = nlh-nlmsg_pid;write_unlock_bh(&user_proc.pid);else if(nlh-nlmsg_ type = IMP2_CL0SE)/ *应用程序关闭*/write_lock_bh(&user_proc.pid);if(nlh-nlmsg_pid = user_proc.pid)user_proc.pid = 0;write_unlock_bh(&user_proc.pid);kfree_skb(skb);up(&receive_sem);/*返回信号量*/while(nlfd & nlfd-receive_queue.qlen);因为
11、内核模块可能同时被多个进程同时调用,所以函数中使用了信号量和锁来进行互斥。skb = skb_dequeue(&sk-& gt;receive_queue)用于取得socket sk的接收队列上的消息,返回为一个struct sk_buff的结构,skb-data指向实 际的 netlink 消息。程序中注册了一个Netfilter钩子,钩子函数是get_icmp,它截获ICMP数据包,然后调用send_to_user函数将数据发 送给应用空间进程。发送的数据是info结构变量,它是struct packet_info结构,这个结构包含了来源/目的地址两个成 员。 Netfilter Hook
12、 不是本文描述的重点,略过。send_to_user用于将数据发送给用户空间进程,发送调用的是API函数netlink_unicast完成的:int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock)7参数sk为函数netlink_kernel_create()返回的套接字,参数skb存放待发送的消息,它的data字段指向要发送的 netlink消息结构,而skb的控制块保存了消息的地址信息,参数pid为接收消息进程的pid,参数nonblock表示该函数 是否为非阻塞,如果为 1,该函数将在
13、没有接收缓存可利用时立即返回,而如果为 0,该函数在没有接收缓存可利用时睡眠。 向用户空间进程发送的消息包含三个部份:netlink消息头部、数据部份和控制字段,控制字段包含了内核发送netlink消 息时,需要设置的目标地址与源地址,内核中消息是通过sk_buff来管理的,linux/netlink.h中定义了 NETLINK_CB宏 来方便消息的地址设置:#define NETLINK_CB(skb)(*(struct netlink_skb_parms*)&(skb)-cb)例如:NETLINK_CB(skb).pid = 0;NETLINK_CB(skb).dst_pid = 0;NE
14、TLINK_CB(skb).dst_group = 1;字段pid表示消息发送者进程ID,也即源地址,对于内核,它为0, dst_pid表示消息接收者进程ID,也即目标地址, 如果目标为组或内核,它设置为0,否则dst_group表示目标组地址,如果它目标为某一进程或内核,dst_group应当 设置为 0。static int send_to_user(struct packet_info *info)int ret;int size;unsigned char *old_tail;struct sk_buff *skb;struct nlmsghdr *nlh;struct packet_
15、info *packet; /*计算消息总长:消息首部加上数据加度*/ size = NLMSG_SPACE(sizeof(*info);/*分配一个新的套接字缓存*/skb = alloc_skb(size, GFP_ATOMIC);old_tail = skb-tail;/*初始化一个 netlink 消息首部*/nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh); /*跳过消息首部,指向数据区*/ packet = NLMSG_DATA(nlh);/*初始化数据区*/ memset(packet, 0, sizeof(stru
16、ct packet_info);/*填充待发送的数据*/ packet-src = info-src;packet-dest = info-dest;/*计算 skb 两次长度之差,即 netlink 的长度总和*/ nlh-nlmsg_len = skb-tail - old_tail;/*设置控制字段*/ NETLINK_CB(skb).dst_groups = 0;/*发送数据*/ read_lock_bh(&user_proc.lock);ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT); read_unlock
17、_bh(&user_proc.lock);函数初始化netlink消息首部,填充数据区,然后设置控制字段,这三部份都包含在skb_buff中,最后调用netlink_unicast 函数把数据发送出去。函数中调用了 netlink的一个重要的宏NLMSG_PUT,它用于初始化netlink消息首部:#define NLMSG_PUT(skb, pid, seq, type, len) ( if (skb_tailroom(skb) nlmsg_type = type;nlh-nlmsg_len = size; nlh-nlmsg_flags = 0;nlh-nlmsg_pid = pid; n
18、lh-nlmsg_seq = seq;return nlh; 这个宏一个需要注意的地方是调用了 nlmsg_failure标签,所以在程序中应该定义这个标签。在内核中使用函数 sock_release 来释放函数 netlink_kernel_create()创建的 netlink socket: void sock_release(struct socket * sock);程序在退出模块中释放 netlink sockets 和 netfilter hook:static void _exit fini(void) if(nlfd) sock_release(nlfd-socket);/*
19、 释放 netlink socket*/nf_unregister_hook(&imp2_ops);/* 撤锁 netfilter 钩子 */转自: HYPERLINK /jh/4/822500.html /jh/4/822500.html 代码摘自: HYPERLINK /developerworks/cn/linux/l-netlink/imp2.tar.gz /developerworks/cn/linux/l-netlink/imp2.tar.gz flw2 兄修改了如上代码,使之可以在 2.6.25 上可以运行: HYPERLINK /bbs/viewthread.php?tid=1
20、015818&extra=&page=2 /bbs/viewthread.php?tid=1015818&extra=&page=2 可以在 2.6.9 上运行的代码:imp2_k.c#ifndef _KERNEL_#define _KERNEL_#endif#ifndef MODULE#define MODULE#endif#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include i
21、mp2.hDECLARE_MUTEX(receive_sem); static struct sock *nlfd;struct_u32 pid; rwlock_t lock;user_proc;static void kernel_receive(struct sock *sk, int len)dostruct sk_buff *skb; if(down_trylock(&receive_sem)return; while(skb = skb_dequeue(&sk-sk_receive_queue) != NULL) struct nlmsghdr *nlh = NULL; if(skb
22、-len = sizeof(struct nlmsghdr)nlh = (struct nlmsghdr *)skb-data; if(nlh-nlmsg_len = sizeof(struct nlmsghdr) & (skb-len = nlh-nlmsg_len) if(nlh-nlmsg_type = IMP2_U_PID) write_lock_bh(&user_proc.pid); user_proc.pid = nlh-nlmsg_pid; write_unlock_bh(&user_proc.pid); else if(nlh-nlmsg_type = IMP2_CLOSE)
23、write_lock_bh(&user_proc.pid); if(nlh-nlmsg_pid = user_proc.pid) user_proc.pid = 0;write_unlock_bh(&user_proc.pid); kfree_skb(skb); up(&receive_sem);while(nlfd & nlfd-sk_receive_queue.qlen);static int send_to_user(struct packet_info *info)int ret;int size; unsigned char *old_tail;struct sk_buff *skb
24、; struct nlmsghdr *nlh;struct packet_info *packet;size = NLMSG_SPACE(sizeof(*info); skb = alloc_skb(size, GFP_ATOMIC);old_tail = skb-tail;nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh); packet = NLMSG_DATA(nlh);memset(packet, 0, sizeof(struct packet_info); packet-src = info-src;packet-dest
25、 = info-dest; nlh-nlmsg_len = skb-tail - old_tail;NETLINK_CB(skb).dst_groups = 0; read_lock_bh(&user_proc.lock);ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT); read_unlock_bh(&user_proc.lock);return ret; nlmsg_failure:if(skb) kfree_skb(skb);return -1;static unsigned int get_icmp(unsig
26、ned int hook, struct sk_buff *pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)struct iphdr *iph = (*pskb)-nh.iph;struct packet_info info; if(iph-protocol = IPPROTO_ICMP) read_lock_bh(&user_proc.lock);if(user_proc.pid != 0) read_unlock_bh(&user_proc.lock)
27、; info.src = iph-saddr; info.dest = iph-daddr; send_to_user(&info); elseread_unlock_bh(&user_proc.lock); return NF_ACCEPT;static struct nf_hook_ops imp2_ops =.hook = get_icmp,.pf = PF_INET,.hooknum = NF_IP_PRE_ROUTING, .priority = NF_IP_PRI_FILTER -1,;static int _init init(void) rwlock_init(&user_pr
28、oc.lock);nlfd = netlink_kernel_create(NL_IMP2, kernel_receive); if(!nlfd)printk(can not create a netlink socketn); return -1; return nf_register_hook(&imp2_ops); static void _exit fini(void) if(nlfd) sock_release(nlfd-sk_socket); nf_unregister_hook(&imp2_ops); module_init(init); module_exit(fini);可以
29、在 2.6.29 上运行的代码:imp2 k.c#ifndef _KERNEL_#define KERNEL#endif#ifndef MODULE#define MODULE#endif#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include imp2.hDECLARE_MUTEX(receive_sem);static struct sock *nlfd;struct _u32 p
30、id;rwlock_t lock;user_proc;static void kernel_receive(struet sk_buff *skb)struet nlmsghdr *nlh = NULL;/printk(%s: skbuser: %dn, _func_, atomic_read(&skbusers);return;if (down_trylock (&receive_sem)return;if(skblen nlmsg_len = sizeof(struet nlmsghdr)& (skblen nlh nlmsg_lenif (nlhnlmsg_type = IMP2_U_P
31、ID) write_lock_bh(&user_proc. lock); user_proc. pid = nlhnlmsg_pid;write_unlock_bh(&user_proc. lock); else if (nlhnlmsg_type = IMP2_CL0SE) write_lock_bh(&user_proc. lock);if (nlhnlmsg_pid = user_proc. pid) user_proc. pid = 0;write_unlock_bh(&user_proc. lock);/kfree_skb(skb);out:up (&receive_sem);sta
32、tic int send_to_user(struet packet_info *info)int ret;int size;unsigned char *old_tail;struct sk_buff *skb;struct nlmsghdr *nlh;struct packet_info *packet;size = NLMSG_SPACE(sizeof(*info);skb = alloc_skb(size, GFP_ATOMIC);old_tail = skb-tail;nlh = NLMSG_PUT (skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh);
33、packet = NLMSG_DATA(nlh);memset(packet, 0, sizeof(struet packet_info);packet-src = info-src;packet-dest 二 infodest; nlh-nlmsg_len = skb-tail old_tail;NETLINK_CB(skb). dst_group = 0; read_lock_bh(&user_proc. lock);ret 二 netlink_unicast(nlfd, skb, user_proc. pid, MSG_DONTWAIT); read_unlock_bh(&user_pr
34、oc. lock);return ret;nlmsg_failure:if(skb)kfree_skb (skb);return -1;static unsigned int get_icmp(unsigned int hook,struet sk_buff *pskb,const struet net_device *in,const struet net_device *out, int (*okfn)(struet sk_buff *)printk(sn, _func_);struet iphdr *iph = (struet iphdr *)skb_network_header(psk
35、b); struet packet_info info;if(iph-protoeol = IPPR0T0_ICMP) read_lock_bh(&user_proc. lock); if (user_proc. pid != 0) read_unlock_bh(&user_proc. lock);info. sre = iph-saddr;info. dest 二 iph-daddr; send_to_user(&info);elseread_unlock_bh(&user_proc. lock);return NF_STOLEN;static struet nf_hook_ops imp2
36、_ops =.hook = get_iemp,.pf = PF_INET,.hooknum = NF_INET_PRE_ROUTING,.priority = NF_IP_PRI_FIRST,;static int _init init(void)rwlock_init(&user_proc. lock);/nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);nlfd = netlink_kernel_create(&init_net, NL_IMP2, 0, kernel_receive, NULL, THIS_MODULE);if (
37、!nlfd) printk(can not create a netlink socketn);return -1;return nf_register_hook(&imp2_ops);static void _exit fini(void)if(nlfd) sock_release(nlfdsk_socket);nf_unregister_hook(&imp2_ops); module_init(init); module_exit(fini);struet sockaddr_nl kpeer;struet msg_to_kernel message;memse t(&kpeer, 0, s
38、izeof(kpeer);kpeer.nl_family = AF_NETLINK;kpeer.nl_pid = 0;kpeer.nl_groups = 0;memset(&message, 0, sizeof(message);message.hdr.nlmsg_len = NLMSG_LENGTH(0);message.hdr.nlmsg_flags = 0;message.hdr.nlmsg_type = IMP2_CL0SE;message.hdr.nlmsg_pid = get pid();send to (skfd, & message, message.hdr.nlmsg_len, 0, (st ruc t sockaddr *)(&kpeersend to (skfd, & message, message.hdr.nlmsg_len, 0,(struet sockaddr*)&kpeer, sizeof(kpeer);while(l)kpeerlen = sizeof(struet sockaddr_nl);rcvl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 研究生活应对策略模板
- 2024年公开课:从《陈情表》看古代忠诚与智谋
- 2024教师招聘教师资格考试面试试讲稿小学数学原理15 三角形
- 2023年施工员之装饰施工专业管理实务题库及完整答案
- 2024年视角:《剪羊毛》音乐课件的创新发展
- 军训日记2000字模板
- 写观察日记200字左右
- 2024年塔吊行业劳务派遣协议模板
- 兴趣爱好的自我评价
- 2024公司高层向企业借款协议范例
- 锂电池供应商的合作协议书范文
- 杭州市2025届高三教学质量检测(一模) 英语试题卷(含答案解析)
- 培训教学课件模板
- 系统架构师论文(经典范文6篇)
- 农业科技园区发展规划
- 降低患者外出检查漏检率-品管圈课件
- 五年级上册生命安全教育全册教案
- 2024年中国烟花鞭炮市场调查研究报告
- 第二单元 成长的时空(知识清单)-【上好课】2024-2025学年六年级道德与法治全一册同步课堂(统编版五四制2024)
- 国开2024年秋《机电控制工程基础》形考任务4答案
- JBT 1306-2024 电动单梁起重机(正式版)
评论
0/150
提交评论