测试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:

  1. 初始化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__);

}

用户层:

  1. 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与用户进程通信的更多相关文章

  1. 图文详解 Android Binder跨进程通信机制 原理

    图文详解 Android Binder跨进程通信机制 原理 目录 目录 1. Binder到底是什么? 中文即 粘合剂,意思为粘合了两个不同的进程 网上有很多对Binder的定义,但都说不清楚:Bin ...

  2. Linux间的进程通信;以及子进程的创建

    "-----第六天-----------------------------------------------------------------------------" .版 ...

  3. Android随笔之——跨进程通信(一) Activity篇

    在Android应用开发中,我们会碰到跨进程通信的情况,例如:你用QQ通讯录打电话的时候会调用系统的拨号应用.某些新闻客户端可以将新闻分享到QQ.微信等应用,这些都是跨进程通信的情况.简而言之,就是一 ...

  4. linux之间进程通信

    进程间通信方式:                    同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存. 必备基础: f ...

  5. MINIX3 进程通信分析

    MINIX3 进程通信分析 6.1MINIX3 进程通信概要 MINIX3 的进程通信是 MINIX3 内核部分最重要的一个部件,我个人认为其实这 是内核中的“内核”,怎么来理解这个概念呢?其实 MI ...

  6. Linux系统编程@进程通信(一)

    进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统 ...

  7. [转]WINDOW进程通信的几种方式

    windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...

  8. Unix 进程通信基本概念

    一:通信分为两类: 控制信息的传递: 低级通信 大批量数据的传递: 高级通信 二:基本的通信方式 (a)主从式通信: 通信的双方存在一种隶属关系, 其中主进程是通信过程的控制者,而从进程是通信过程的从 ...

  9. [置顶] 简单解析linux下进程通信方法

    linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...

随机推荐

  1. Win7 32位 遇到微软 silverlight 5.0安装失败的解决办法

    刚开始,也是尝试下载安装,多次都是到99%,提示安装失败! 也查找了很多网上朋友分享的办法,还是不行.重新建立一个管理员账号,还是不行. 后来反复不断的测试,找到原因了,安装99%不成功,但是卸载程序 ...

  2. 洛谷 P3371 【模板】单源最短路径(堆优化dijkstra)

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...

  3. Shiro的subject实质上是当前执行用户的特定视图。

    Shiro的subject实质上是当前执行用户的特定视图. 通过org.apache.shiro.SecurityUtils可以查询当前执行用户: Subject currentUser = Secu ...

  4. MySQL性能优化之max_connections配置

    MySQL的最大连接数,增加该值增加mysqld 要求的文件描述符的数量.如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于M ...

  5. 5-Java-C(小题答案)

    1. a[i][j]=a[i-1][j-1]+a[i-1][j] 2.1835421 3.93 4.1572836

  6. bdflush - 将dirty缓存写回到磁盘的核心守护进程

    总览(SYNOPSIS) bdflush [opt] 描述(DESCRIPTION) bdflush 被用来启动核心守护进程将内存中的dirty缓存写到磁盘上.真正清洁工作是一个核心程序完成的. bd ...

  7. ALTER SEQUENCE - 更改一个序列生成器的定义

    SYNOPSIS ALTER SEQUENCE name [ INCREMENT [ BY ] increment ] [ MINVALUE minvalue | NO MINVALUE ] [ MA ...

  8. C#线程锁使用全功略

    C#线程锁使用全功略 前两篇简单介绍了线程同步lock,Monitor,同步事件EventWaitHandler,互斥体Mutex的基本用法,在此基础上,我们对 它们用法进行比较,并给出什么时候需要锁 ...

  9. OpenMP用法大全

    OpenMP基本概念OpenMP是一种用于共享内存并行系统的多线程程序设计方案,支持的编程语言包括C.C++和Fortran.OpenMP提供了对并行算法的高层抽象描述,特别适合在多核CPU机器上的并 ...

  10. js 技巧 (十)广告JS代码效果大全 【3】

    3.[允许关闭]     与前面两个代码不同的是,广告图下方增加了一个图片按纽,允许访客点击关闭广告图片,下面文本框中就是实现效果所需代码: var delta=0.015;     var coll ...