Kernel与用户进程通信
测试IPv6 ready logo rfc 3315的时候,遇到一个问题,要求在收到ICMPv6 RA的时候,DHCPv6 Client要发Solicit消息。在平常的应用中,都是启动DHCPv6 Client后,client每隔一段时间就会发送Solicit,而并不是要在收到RA的时候发送。于是就修改了下kernel和client的代码,使得在kernel收到RA消息时,发送消息给DHCPv6 Client,使client发送Solicit。
思路为:使用netlink_kernel_create建立消息机制。在DHCPv6 Client初始化的时候,新建类型为NETLINK_RTK_ICMP6_RA 的netlink socket,监听kernel的消息,并且把自己的pid发送给kernel, kernel 收到消息后,存储pid为全局变量。当kernel收到RA包后,将发送消息给pid的用户进程。用户进程收到消息,发送solicit。
Kernel中接收ICMPv6 RA的代码在linux-3.10/net/ipv6/ndisc.c。
Kernel:
- 初始化IPC
在ndisc_init()中加上进程通信的socket。
//create netlink socket
struct netlink_kernel_cfg cfg = {
.input = nl_icmp_input,
};
printk("%s: before netlink_kernel_create\n", __func__);
icmp6_ra_sock = netlink_kernel_create(&init_net, NETLINK_RTK_ICMP6_RA, &cfg);
if (icmp6_ra_sock == NULL) {
printk(KERN_ERR "Netlink[Kernel] Cannot create netlink socket for ipv6 ra.\n");
return -EAFNOSUPPORT;
}
printk("Netlink[Kernel] create netlink socket for ipv6 ra ok.\n");
其中NETLINK_RTK_ICMP6_RA 为在netlink.h中定义的一个类型。nl_icmp_input用于接收用户层发来的信息。
2. 接收DHCPv6 Client发来的pid 信息
static void nl_icmp_input(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
char str[100];
struct completion cmpl;
int i=10;
skb = skb_get (__skb);
if(skb->len >= NLMSG_SPACE(0))
{
nlh = nlmsg_hdr(skb);
memcpy(str, NLMSG_DATA(nlh), sizeof(str));
printk("Message received:%s\n",str) ;
DHCP6C_PID = nlh->nlmsg_pid;
printk("DHCP PID = %d:%s\n", DHCP6C_PID) ;
kfree_skb(skb);
}
return;
}
3. 收到RA后,发消息给用户进程
在ndisc_router_discovery中,确认RA包ok后,发送消息。
if (icmp6_ra_sock) {
printk("%s: ra socket is not null\n", __func__);
payloadLen = NLMSG_SPACE(payloadLen);
/*Alloc skb ,this check helps to call the fucntion from interrupt context */
if(in_atomic())
{
skb_ra = alloc_skb(payloadLen, GFP_ATOMIC);
}
else
{
skb_ra = alloc_skb(payloadLen, GFP_KERNEL);
}
if(!skb_ra)
{
printk(KERN_ERR "failed to alloc skb in %s",__FUNCTION__);
return;
}
nl_msgHdr = (struct nlmsghdr *)skb_ra->data;
nl_msgHdr->nlmsg_type = MESSAGE_ICMP6_RA;
nl_msgHdr->nlmsg_pid=0;/*from kernel */
nl_msgHdr->nlmsg_len = payloadLen;
nl_msgHdr->nlmsg_flags =0;
NETLINK_CB(skb_ra).portid = 0; /*from kernel */
skb_ra->len = payloadLen;
err = netlink_unicast(icmp6_ra_sock, skb_ra, DHCP6C_PID, MSG_DONTWAIT); //send to dhcp6c
if (err < 0)
printk("%s: nfnetlink_unicast icmpv6 ra socket fail\n", __func__);
else
printk("%s: nfnetlink_unicast icmpv6 ra socket ok\n", __func__);
}
用户层:
- Dhcp6c 初始化,并发送pid给kernel
int init_ra_monitor_fd()
{
int ret = 0;
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
struct msghdr msg;
int state_smg = 0;
int pid = getpid();
if ((rasock = socket(AF_NETLINK, SOCK_RAW, NETLINK_RTK_ICMP6_RA)) < 0)
{
printf("Could not open netlink socket for kernel monitor\n");
return 1;
}
else
{
printf("kernelMonitorFd=%d\n", rasock);
}
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = pid;
src_addr.nl_groups = 0; // multicast
if (bind(rasock, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0)
{
printf("Could not bind netlink socket for kernel monitor\n");
close(rasock);
rasock = -1;
return 1;
}
/* Tell kernel dhcp6c pid, kernel will send messages to dhcp6c when it receive ICMPv6 RA */
/* Fix IPv6 Ready logo rfc3315 */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = 0;
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
if(!nlh){
printf("malloc nlmsghdr error!\n");
close(rasock);
return -1;
}
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = pid;
nlh->nlmsg_flags = 0;
sprintf(NLMSG_DATA(nlh), "%d", pid);
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&dest_addr;
msg.msg_namelen = sizeof(dest_addr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
printf("state_smg\n");
state_smg = sendmsg(rasock, &msg, 0);
if(state_smg == -1)
{
printf("get error sendmsg = %s\n",strerror(errno));
}
}
2. 等待接收消息
// add to read sockets
if (rasock >= 0) {
FD_SET(rasock, &r);
maxsock = (rasock > maxsock) ? rasock : maxsock;
}
//wait
ret = select(maxsock + 1, &r, NULL, NULL, w);
if (FD_ISSET(rasock, &r)) {
printf("%s: have receive the ra message\n", __func__);
dhcp6_ra_recv(); //send solicit
}
Kernel与用户进程通信的更多相关文章
- 图文详解 Android Binder跨进程通信机制 原理
图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...
- Linux间的进程通信;以及子进程的创建
"-----第六天-----------------------------------------------------------------------------" .版 ...
- Android随笔之——跨进程通信(一) Activity篇
在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...
- linux之间进程通信
进程间通信方式: 同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存. 必备基础: f ...
- MINIX3 进程通信分析
MINIX3 进程通信分析 6.1MINIX3 进程通信概要 MINIX3 的进程通信是 MINIX3 内核部分最重要的一个部件,我个人认为其实这 是内核中的“内核”,怎么来理解这个概念呢?其实 MI ...
- Linux系统编程@进程通信(一)
进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...
- [转]WINDOW进程通信的几种方式
windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...
- Unix 进程通信基本概念
一:通信分为两类: 控制信息的传递: 低级通信 大批量数据的传递: 高级通信 二:基本的通信方式 (a)主从式通信: 通信的双方存在一种隶属关系, 其中主进程是通信过程的控制者,而从进程是通信过程的从 ...
- [置顶] 简单解析linux下进程通信方法
linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...
随机推荐
- jboss中JVM监控
1)打开 http://server-name-or-ip/jmx-console/HtmlAdaptor2)在 jboss.system 节点找到 type=ServerInfo ,点击进入3)找到 ...
- iOS开发 数据缓存-数据库
iOS中数据存储方式 Plist(NSArray\NSDictionary) Preference(偏好设置\NSUserDefaults) NSCoding (NSKeyedArchiver\NSk ...
- iTOP-4412开发板全新升级支持4G全网通模块
开发板支持4G,GPS,CAN,485,WIFI蓝牙,重力加速度计,陀螺仪等模块. 核心板参数 尺寸:6cm*7cm 高度:连同连接器在内0.26cm CPU:Exynos4412,四核Cortex- ...
- cookie和session的用法用途,执行流程,区别联系
1.为什么要有cookie/session?在客户端浏览器向服务器发送请求,服务器做出响应之后,二者便会断开连接(一次会话结束).那么下次用户再来请求服务器,服务器没有任何办法去识别此用户是谁.比如w ...
- java实现搜索文件夹中所有文件包含的关键字的文件路径(递归搜索)
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io ...
- 11-2 numpy/pandas/matplotlib模块
目录 numpy模块 一维数组 二维数组 列表list和numpy的区别 获取多维数组的行和列 多维数组的索引 高级功能 多维数组的合并 通过函数方法创建多维数组 矩阵的运算 求最大值最小值 nump ...
- 【Hadoop】一、分布式数据库HBase简介
1.分布式数据库特点 说到数据库,我们最熟悉的是类似于mysql这样的关系型数据库,称为RDBMS.关系型数据库作为一种数据存储和数据检索的关键技术,它支持SQL语言的结构化查询,但是它天生不是为 ...
- eclipse 的开发环境配置
一.基础环境设置 1.jdk下载配置 2.JRE下载配置 3.Eclipse下载 4.Eclipde 与JRE配置,见图 二.PHP环境设置 1.apache + PHP 配置. 详见随笔文章:Ecl ...
- layui timeline使用
使用layui timeline过程记录: layui官网时间线介绍比较少,可能是太简单了,这里把时间线通过请求后台数据.再自动填写到对应区块,进行了封装: 代码如下: function timeli ...
- 路径工具类NSPathUtilities
路径工具类NSPathUtilities.h 路径类NSPathUtilities.h包含了 NSString的函数和分类扩展,他允许你操作路径名.应该竟可能的使用这些函数,以便使程序更独立于文件系统 ...