免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1524 | 回复: 3

[内核模块] netlink应用层和内核通信,系统自启动时无法收到内核发送的数据包 [复制链接]

论坛徽章:
0
发表于 2015-11-06 15:50 |显示全部楼层
我现在遇到一个非常奇怪的问题,应用程序向内核发送消息时,内核能够正确获取到消息,记录下应用程序的pid。之后,内核在特定情况下,需要向应用层发包时,应用层却始终收不到包(应用层的recvmsg没有任何响应)。奇怪的是,如果手动起应用程序,就能够正确收到内核发来的数据包。有谁遇到过类似的问题吗?请教了!

#include <linux/init.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#include <linux/autoconf.h>
#include <linux/ip.h>
#include <net/netlink.h>
#include <linux/netfilter_ipv4/ip_hash.h>
#include <uapi/linux/internet_ctrl_netlink.h>

#define DEBUG_IP_HASH 1
#if DEBUG_IP_HASH
#define DEBUG_PRINT(fmt, argx...) printk(fmt, ##argx)
#else
#define DEBUG_PRINT(fmt, argx...)
#endif

#define ip_hash_key(ipaddr) ((ipaddr & 0xffu) ^ ((ipaddr >> 8u) & 0xffu))
#define IP_HASH_TIMEOUT_INTERVAL 60*HZ

u_int phicommUsrPid = 0;
static struct sock *nl_sk = NULL;

IPHashNode *ip_hash_table[MAX_IP_HASH_TABLE];
static struct timer_list ip_hash_timer;

static void ip_hash_timeout(u_long param);
static void ip_hash_poll_init(void);

static int NlSend(char *data, u_int dataLen, u_int dpid, u_int dgrp)
{
    struct sk_buff *skb;
    struct nlmsghdr *nlh;
    int err = 0;

    DEBUG_PRINT("#######func:%s,line:%d phicommUsrPid=%u#####\n",__func__,__LINE__,phicommUsrPid);
#if 0
    int nlLen = NLMSG_SPACE(dataLen);
    skb = alloc_skb(nlLen,GFP_ATOMIC);
#else
    skb = nlmsg_new(dataLen, GFP_ATOMIC);
#endif
    if(skb)
    {
        nlh = nlmsg_put(skb,0,0,0,dataLen,0);
        NETLINK_CB(skb).dst_group = dgrp;

        memcpy(NLMSG_DATA(nlh), data, dataLen);

        if(dgrp != 0)
        {
            netlink_broadcast(nl_sk, skb, 0, dgrp, GFP_ATOMIC);
        }
        else
        {
            err =  netlink_unicast(nl_sk,skb,dpid,MSG_DONTWAIT);
            DEBUG_PRINT("#######func:%s,line:%d err=%d####\n",__func__,__LINE__,err);
        }
    }
    else
    {
        err = -1;
    }
    return err;
}
static void netlinkSendToUser(IPHashNode *ipHashNode,NetlinkConfType confType)
{
    NlMsg    nlData;      

    nlData.msgHead.nlType = INTERNET_CTRL_INFO;
    nlData.confType = confType;
    memcpy(nlData.mac, ipHashNode->conf.userStats.mac, ETH_ALEN);
    nlData.ip = ipHashNode->ip;
    DEBUG_PRINT("#######func:%s,line:%d phicommUsrPid=%u#####\n",__func__,__LINE__,phicommUsrPid);
    if (phicommUsrPid > 0) {
        NlSend((char *)&nlData, sizeof(nlData), phicommUsrPid, 0);
    }
}

static void ip_hash_timeout(u_long param)
{
    int i = 0;
    IPHashNode **hashBufPP = NULL;
    IPHashNode *hashBufP = NULL;

    for (i = 0; i < MAX_IP_HASH_TABLE; i++) {
        hashBufPP = &(ip_hash_table[i]);

        while (*hashBufPP != NULL) {
            if ((*hashBufPP)->status == 0) {
                DEBUG_PRINT("%s %08x:timeout hash %08x\n", __func__, __LINE__, (*hashBufPP)->ip);
                hashBufP = *hashBufPP;
/*ip hash节点超时时,向应用层发送离线消息*/
                netlinkSendToUser(*hashBufPP,IP_OFFLINE);
                *hashBufPP = hashBufP->next;
                kfree(hashBufP);
            } else {
                (*hashBufPP)->status = 0;
                hashBufPP = &((*hashBufPP)->next);
            }
        }
    }

    mod_timer(&ip_hash_timer, jiffies + IP_HASH_TIMEOUT_INTERVAL);
}
static void ip_hash_poll_init(void)
{
    init_timer(&ip_hash_timer);
    ip_hash_timer.expires = jiffies + IP_HASH_TIMEOUT_INTERVAL;   
    ip_hash_timer.data     = 0;               
    ip_hash_timer.function = ip_hash_timeout;  
    add_timer(&ip_hash_timer);
}

IPHashNode *get_ip_hash_node (u_long ipaddr, int isCreat, struct sk_buff *skb)
{
    u_int key;
    struct timespec uptime;
    IPHashNode **hashBufPP;
    struct ethhdr *eth;

    key = ip_hash_key(ntohl(ipaddr));
    hashBufPP = &(ip_hash_table[key]);
    //DEBUG_PRINT("%s %d:hash key %d\n", __func__, __LINE__, key);
    while (*hashBufPP != NULL) {
        if ((*hashBufPP)->ip == ipaddr) {
            if(isCreat == 1) {
                isCreat  = 0;
                (*hashBufPP)->status = 1;
            }
            //DEBUG_PRINT("%s %d:find ok hash %pI4, key %d\n", __func__, __LINE__, &ipaddr,key);
            break;
        }
        hashBufPP = &((*hashBufPP)->next);
    }
    if (isCreat == 1) {
        *hashBufPP = (IPHashNode*) kzalloc(sizeof(IPHashNode), GFP_ATOMIC);
        if (*hashBufPP != NULL) {
            (*hashBufPP)->status = 1;
            (*hashBufPP)->ip = ipaddr;
            (*hashBufPP)->conf.iif = -1;

            do_posix_clock_monotonic_gettime(&uptime);
            monotonic_to_bootbased(&uptime);
            (*hashBufPP)->conf.userStats.stTime = (u_long)( uptime.tv_sec);
            (*hashBufPP)->conf.userStats.realtimeflowS.lastClrJiffies = jiffies;

            //DEBUG_PRINT("%s %d:new hash %pI4, key %d\n", __func__, __LINE__, &ipaddr,key);
            eth = eth_hdr(skb);
            if (((unsigned char *)eth) + ETH_HLEN <= skb->data) {
                DEBUG_PRINT("eth get right!\n");
                memcpy((*hashBufPP)->conf.userStats.mac, eth->h_source, ETH_ALEN);
               /*ip hash结点建立时,向应用层发送消息*/
                netlinkSendToUser(*hashBufPP,IP_ONLINE);
            } else {
                DEBUG_PRINT("eth get error!\n");
                memset((*hashBufPP)->conf.userStats.mac, 0, ETH_ALEN);
            }
        }
    }

    return *hashBufPP;

}

void ip_hash_traverse (void (*processFun)(IPHashNode* buf))
{
    int i = 0;
    IPHashNode *hashBufP = NULL;

    for(i = 0; i < MAX_IP_HASH_TABLE; i++) {
        hashBufP = ip_hash_table[i];
        while (hashBufP != NULL) {
            processFun(hashBufP);
            hashBufP = hashBufP->next;
        }
    }
}

void internet_ctrl_conf (struct nlmsghdr *nlh)
{
    NlMsg    *nlData;      
    nlData = (NlMsg *)NLMSG_DATA(nlh);
    IPHashNode *hashBufP = NULL;
    int i = 0;
    DEBUG_PRINT("%d in %s of %s\n", __LINE__, __func__, __FILE__);
    switch (nlData->confType) {   
        case INIT_UNICAST_PID:      
            phicommUsrPid = nlh->nlmsg_pid;         
            DEBUG_PRINT("#######%d in %s of %s, phicommUsrPid=%d#######\n", __LINE__, __func__, __FILE__,phicommUsrPid);
            break;

        default:
            break;
    }
}

static int phicomm_user_rcv_msg (struct sk_buff *skb, struct nlmsghdr *nlh)
{
    NetlinkMsgHead *msgHead = NULL;

    DEBUG_PRINT("%d in %s of %s\n", __LINE__, __func__, __FILE__);
    if (skb->len < sizeof(*nlh)) {
        return 1;
    }
    msgHead = (NetlinkMsgHead*)NLMSG_DATA(nlh);
    DEBUG_PRINT("%d in %s of %s, Message receive\n", __LINE__, __func__, __FILE__);
    switch(msgHead->nlType)        
    {
        case INTERNET_CTRL_INFO:      
            internet_ctrl_conf(nlh);            
            break;                        
        default:  
            break;                        
    }            
    return 0;
}

static DEFINE_MUTEX(phicomm_cfg_mutex);

static void phicomm_netlink_rcv(struct sk_buff *skb)
{
        DEBUG_PRINT("%d in %s of %s\n", __LINE__, __func__, __FILE__);
        mutex_lock(&phicomm_cfg_mutex);
        netlink_rcv_skb(skb, &phicomm_user_rcv_msg);
        mutex_unlock(&phicomm_cfg_mutex);
}

static void internet_ctrl_init(void)
{
    struct netlink_kernel_cfg cfg = {
            .input        = phicomm_netlink_rcv,
    };

    DEBUG_PRINT("***********%d in %s of %s**************\n", __LINE__, __func__, __FILE__);

    nl_sk = netlink_kernel_create(&init_net, NETLINK_INTERNET_CONTROLE, &cfg);

    if(!nl_sk){
        DEBUG_PRINT("internet_ctrl_init create netlink socket error.\n");
    }   
}
static int __init ip_hash_init(void)
{
    ip_hash_poll_init();
    internet_ctrl_init();
    return 0;
}

module_init(ip_hash_init);

EXPORT_SYMBOL(phicommUsrPid);
以上是内核代码
_____________________________________________________________________________

论坛徽章:
0
发表于 2015-11-06 15:53 |显示全部楼层
————————————————————————————————————————————————
应用层代码如下:
#include <stdio.h>            
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <uci.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/socket.h>
#include "internet_ctrl_netlink.h"

#if 1
#define DEBUG_PRINTF(fmt, args...)                printf(fmt, ## args)
#else
#define DEBUG_PRINTF(fmt, args...)
#endif

static struct uci_context *uci_ctx;
int nl_sock_fd;

int netlinkSockBind(unsigned int pid, unsigned int grp)                                                                                                                  
{
    struct sockaddr_nl src_addr;   
    int sock_fd;
    /*Create a socket*/      
    sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_INTERNET_CONTROLE);
    DEBUG_PRINTF("%s pid=%d", __func__, pid);
    if(sock_fd == -1) {
        DEBUG_PRINTF("error getting socket: %s", strerror(errno));
    } else {
        /* To prepare binding*/        
        memset(&src_addr, 0, sizeof(src_addr));
        src_addr.nl_family = AF_NETLINK;
        src_addr.nl_pid = pid; /*unicast*/
        src_addr.nl_groups = grp; /*broadcast*/
        int status = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
        if(status == -1) {  
            DEBUG_PRINTF("bind failed: %s", strerror(errno));
            sock_fd = -1;                  
            close(sock_fd);        
        }
    }  

    return sock_fd;           
}

int nlMsgSend (int sock_fd, char *data,unsigned int dataLen, unsigned int dpid, unsigned int dgrp)
{
    struct sockaddr_nl dest_addr;
    struct iovec iov;
    struct msghdr msg;
    char buf[NETLINK_MAX_NLMSGSIZE];
    struct nlmsghdr *nlh = NULL;
    int ret = 0;

    nlh = (struct nlmsghdr*) buf;

    DEBUG_PRINTF("######func:%s,line:%d######\n",__func__,__LINE__);
    if(NLMSG_SPACE(dataLen) <= NETLINK_MAX_NLMSGSIZE) {
        DEBUG_PRINTF("######func:%s,line:%d######\n",__func__,__LINE__);
        memset(buf, 0, sizeof(buf));
        nlh->nlmsg_len = NLMSG_SPACE(dataLen);
        nlh->nlmsg_pid = getpid();
        nlh->nlmsg_flags |= NLM_F_REQUEST;
        nlh->nlmsg_type = 0x26;
        memcpy(NLMSG_DATA(nlh), data, dataLen);

        memset(&dest_addr,0,sizeof(dest_addr));
        dest_addr.nl_family = AF_NETLINK;
        dest_addr.nl_pid = dpid;
        dest_addr.nl_groups = dgrp;

        iov.iov_base = (void *)nlh;
        iov.iov_len = NLMSG_SPACE(dataLen);

        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;

        if(sendmsg(sock_fd,&msg,0) == -1) {
            DEBUG_PRINTF("get error sendmsg = %s\n",strerror(errno));
        }
    }

    return ret;
}

void internetCtrlNlInit(int sock_fd)
{
    NlMsg msg;   
    DEBUG_PRINTF("######func:%s,line:%d######\n",__func__,__LINE__);
    msg.msgHead.nlType = INTERNET_CTRL_INFO;
    msg.confType = INIT_UNICAST_PID;
    nlMsgSend(sock_fd, (char *)&msg, sizeof(msg), 0, 0);
}

static void internetCtrlHandler(NlMsg *msg)
{
    char mac[18];
    char *ip;
    struct in_addr in;
   
    in.s_addr = msg->ip;
    ip = inet_ntoa(in);
    sprintf(mac,"%02x:%02x:%02x:%02x:%02x:%02x",msg->mac[0],msg->mac[1],msg->mac[2],msg->mac[3],msg->mac[4],msg->mac[5]);
    DEBUG_PRINTF("ip = %s, mac = %s\n",ip,mac);
    switch (msg->confType) {
        case IP_ONLINE:
            DEBUG_PRINTF("func:%s,line:%d,ONLINE recv msg from kernel---\n",__func__,__LINE__);
            break;
        case IP_OFFLINE:
            DEBUG_PRINTF("func:%s,line:%d,OFFLINE recv msg from kernel---\n",__func__,__LINE__);
            break;

        default:
            break;
    }

    return ;
}

int main()
{
    struct sockaddr_nl nl_addr;
    struct iovec iov;
    struct msghdr msg;
    char buf[NETLINK_MAX_NLMSGSIZE];
    struct nlmsghdr *nlh = NULL;
    NetlinkMsgHead *msgHead = NULL;

    memset(&msg, 0, sizeof(msg));
    nlh = (struct nlmsghdr*) buf;
    iov.iov_base = (void *)nlh;
    iov.iov_len = NETLINK_MAX_NLMSGSIZE;
    msg.msg_name = (void *)&nl_addr;
    msg.msg_namelen = sizeof(nl_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    DEBUG_PRINTF("######func:%s,line:%d######\n",__func__,__LINE__);
    nl_sock_fd = netlinkSockBind(getpid(), 0);
    if (nl_sock_fd < 0) {
        DEBUG_PRINTF("netlinkSockBind error\n");
        return -1;
    }
    internetCtrlNlInit(nl_sock_fd);
    memset(buf, 0 ,sizeof(buf));
    while(1) {
        memset(buf, 0 ,sizeof(buf));
        if(recvmsg(nl_sock_fd, &msg, 0) > 0) {
            msgHead = (NetlinkMsgHead *)NLMSG_DATA(nlh);
            DEBUG_PRINTF("func:%s,line:%d,recv msg from kernel\n",__func__,__LINE__);
            switch(msgHead->nlType) {         
                case INTERNET_CTRL_INFO:
                    internetCtrlHandler(NLMSG_DATA(nlh));
                    break;
                default:                           
                    break;                 
            }         
        } else {
            DEBUG_PRINTF("func:%s,line:%d,XXXXXXXXXXXXXXXXXXXXXXXX\n",__func__,__LINE__);
        }
    }

    return 0;
}

论坛徽章:
0
发表于 2015-11-06 16:02 |显示全部楼层
1、应用层进程是的device_manage,系统启动时,device_manage进程会由init进程起来,进程起来后,向内核发送自己的pid,内核也能够正确获取到该pid。
2、IP节点建立和删除时,会向内核发送netlink消息,unicast_netlink的返回值也都是大于0的值,此处为36;但是应用层却始终无法获取到内核发来的消息。
3、系统起来后,如果killall device_manage后,在手动执行device_manage进程,那么就能够跟内核正常的交互信息了。

不知道这种情况,各位大虾有没有遇到过,为什么自启动时会出现内核发包,应用层收不到。这时,到底是应用层的问题,还是内核的问题呢?

论坛徽章:
0
发表于 2015-11-09 14:26 |显示全部楼层
原来代码本身没有问题,只是应用程序在自动起来的时候,朝标准输出的内容都不会显示出来.唉,惆怅!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP