免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2387 | 回复: 2
打印 上一主题 下一主题

[通信方式] 【netlink】recvmsg只收到了个报头,却没数据 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-12-11 17:22 |只看该作者 |倒序浏览
本帖最后由 denallo 于 2013-12-11 19:51 编辑

我自己注册的netlink协议,从用户层将数据发往内核一切正常,不过要是从内核往用户层发数据的话(用netlink_unicast),用户层收得到数据,但是recvmsg返回的数值显示它收到的数据比内核发送的数据少。
补充:刚刚测了下,nlmsg报头的长度是16个字节,然后NLMSG_DATA所指向的数据缓冲区的长度是12个字节,在内核层发送时,netlink_unicast返回的字节数是28个字节,而在用户层接收数据时,recvmsg返回的字节数是16个字节,这大概能证明用户层只收到了nlmsg的报头,却没有收到报头后面的数据吧,在用户层通过NLMSG_DATA(nh)->nlmsg_len == 28,但是不知道为什么数据部分根本没从内核层的nlh复制到用户层的nh中。
一下是内核发送数据的代码

  1. static void kernel_send_msg(struct frwl_msg m)//frwl_msg是我自己定义的
  2. {
  3.         struct sk_buff *nl_skb;
  4.         nl_skb = alloc_skb(NLMSG_SPACE(sizeof(struct frwl_msg)),GFP_ATOMIC);
  5.         if(nl_skb == NULL)
  6.         {
  7.                 printk(KERN_ERR "alloc skb failed\n");
  8.                 return;
  9.         }
  10.         NETLINK_CB(nl_skb).pid = 0;
  11.         NETLINK_CB(nl_skb).dst_group = 0;
  12.         nlh = nlmsg_put(nl_skb,0,0,0,
  13.                         NLMSG_SPACE(sizeof(struct frwl_msg))-sizeof(struct nlmsghdr),0);
  14.         memcpy(NLMSG_DATA(nlh),&m,sizeof(struct frwl_msg));
  15.         printk("sizeof nh:%d\n",sizeof(*nlh));//16
  16.         printk("sizeof data:%d\n",sizeof(*((struct frwl_msg *)NLMSG_DATA(nlh))));//12
  17.         debug_frwl_print(*((struct frwl_msg *)NLMSG_DATA(nlh)),"in send");//这一句的输出表明数据已经成功地复制到nlh的缓冲区里了
  18.         int report = netlink_unicast(kernel_sk,nl_skb,pid,MSG_DONTWAIT);
  19.         printk("report = %d\n",report);//输出28
  20. }
复制代码
然后用户层接收数据的代码如下

  1. void interface_rcv_msg(struct frwl_msg * buff)
  2. {
  3.         struct nlmsghdr *nh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));//MAX_PAYLOAD==2048
  4.         struct iovec iov2 = { nh, sizeof(*nh) };
  5.         struct msghdr msg = {
  6.                 (void *)&nl_dest_addr,
  7.                 sizeof(nl_dest_addr),
  8.                 &iov2,1,NULL,0,0};
  9.         printf("sizeof nlh:%d\n",sizeof(*nh));//输出16
  10.         int len = recvmsg(interface_sk,&msg,0);
  11.         printf("rcvlen=%d\n datalen=%d\n",len,nh->nlmsg_len);//rcvlen=16 datalen=28
  12.         debug_frwl_print(*((struct frwl_msg *)NLMSG_DATA(nh)));//这一句的输出表明nh的缓冲区里一片空白。。。。。。。。。。。
复制代码
求助路过的大牛
大概会是哪里出的问题,给个思路也行。。。。。

对了,内核版本是2.6.32-358.el6.i686
发行版scientific linux 6

论坛徽章:
0
2 [报告]
发表于 2013-12-11 20:42 |只看该作者
原因找到了 iov2的缓冲区大小设置错误,不该用报头的大小作为参数,应该用NLMSG_SPACE(nh)
不过现在又出现了新问题,用NLMSG_DATA(nh)访问从内核接收的数据会导致segmentation fault
用户层新代码如下
  1. void interface_rcv_msg(struct frwl_msg * buff)
  2. {
  3.     struct nlmsghdr *nh = (struct nlmsghdr *)malloc(sizeof(struct frwl_msg));
  4.     struct iovec iov2 = { nh, NLMSG_SPACE(sizeof(struct frwl_msg))};
  5.     struct msghdr msg = {
  6.         (void *)&nl_dest_addr,
  7.         sizeof(nl_dest_addr),
  8.         &iov2,1,NULL,0,0};
  9.     printf("sizeof nlh:%d\n",sizeof(*nh));
  10.     int len = recvmsg(interface_sk,&msg,0);
  11.     printf("rcvlen=%d\ndatalen=%d\n",len,nh->nlmsg_len);
  12.     printf("sizeof data:%d\n",sizeof(*((struct frwl_msg *)NLMSG_DATA(nh))));
  13.     printf("in interface_rcv_msg:\n");
  14.     memcpy((void *)buff,NLMSG_DATA(nh),sizeof(struct frwl_msg));
  15.     printf("%s\n",strerror(errno));//显示SUCCESS
  16.     debug_frwl_print(*buff);//就是在这一句里出错,访问buff指向的数据会造成segmentation fault
  17.     printf("data is at:%d\n",(int)NLMSG_DATA(nh));
复制代码

论坛徽章:
0
3 [报告]
发表于 2013-12-11 22:33 |只看该作者
原因找到了,用户空间里的printf函数访问字符串导致的
细节如下:
frwl_msg中有个数据成员是char *类型,我觉得可能是由于这个char *类型成员在内核被赋值,然后这个地址值又随着frwl_msg结构体传到用户空间,这样用户空间通过这个char指针访问到的便是属于内核的那部分内存,所以被系统KILL了,不知道对不对
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP