Linux内核层与用户侧通信netlink

1. 案例:笔者需要实现用户层与内核驱动模块adc.ko之间的通信,通信机制采用netlink;

2. 驱动模块adc.ko增加以下相应的定义及函数

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/netlink.h>


#define NETLINK_TEST    30
#define MSG_LEN         125
#define USER_PORT       100

struct sock *nlsk = NULL;
extern struct net init_net;

static int netlink_send_msg(char *buf, int len)
{
    struct sk_buff *nl_skb;
    struct nlmsghdr *nlh;

    int ret;

    /* 创建sk_buff 空间 */
    nl_skb = nlmsg_new(len, GFP_ATOMIC);
    if(!nl_skb)
    {
        printk("netlink alloc failure\n");
        return -1;
    }

    /* 设置netlink消息头部 */
    nlh = nlmsg_put(nl_skb, 0, 0, NETLINK_TEST, len, 0);
    if(nlh == NULL)
    {
        printk("nlmsg_put failaure \n");
        nlmsg_free(nl_skb);
        return -1;
    }


    /* 拷贝数据发送 */
    memcpy(nlmsg_data(nlh), buf, len);
    ret = netlink_unicast(nlsk, nl_skb, USER_PORT, MSG_DONTWAIT);

    return ret;
}


static void netlink_recv_msg(struct sk_buff *skb)
{
    struct nlmsghdr *nlh = NULL;
    char *umsg = NULL;
    //char *kmsg = "hello users!!!";

    if(skb->len >= nlmsg_total_size(0))
    {
        nlh = nlmsg_hdr(skb);
        umsg = NLMSG_DATA(nlh);
        if(umsg)
        {
            //printk("kernel recv from user: %s\n", umsg);
            netlink_send_msg((char*)&g_hardware_version, 1);
        }
    }
}

struct netlink_kernel_cfg cfg = { 
    .input  = netlink_recv_msg, /* set recv callback */
};

static int __init init_adc_netlink(void)
{
    nlsk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_TEST, &cfg);
    if(nlsk == NULL){   
        printk("netlink_kernel_create error !\n");
        return -1; 
    }   
    printk("init_adc_netlink ok.\n");  
    return 0;  
}



static void exit_adc_net_link(void)
{
    if (nlsk){
        netlink_kernel_release(nlsk); /* release ..*/
        nlsk = NULL;
    }   
    printk("exit_adc_net_link ok!\n");
}


module_init(init_adc_netlink);
module_exit(exit_adc_net_link);

3. 应用程序增加获取内核模块的接口函数


#define NETLINK_TEST    30
#define MSG_LEN            125
#define MAX_PLOAD        125

typedef struct _user_msg_info{
    struct nlmsghdr hdr;
    char  msg[MSG_LEN];
} user_msg_info;

//描述:获取硬件的版本
//参数:@pbHardVer 返回的硬件版本
//返回:成功返回true,反之为false
bool GetHardVerByAdc(BYTE *pbHardVer)
{
    int skfd;
    int ret;
    user_msg_info u_info;
    socklen_t len;
    struct nlmsghdr *nlh = NULL;
    struct sockaddr_nl saddr, daddr;
    char *umsg = "hello netlink!!";
     
    /* 创建NETLINK socket */
    skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
    if(skfd == -1)
    {
        perror("create socket error\n");
        return false;
    }


    memset(&saddr, 0, sizeof(saddr));
    saddr.nl_family = AF_NETLINK; //AF_NETLINK
    saddr.nl_pid = 100;  //端口号(port ID) 
    saddr.nl_groups = 0;
    if(bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0)
    {
        perror("bind() error\n");
        close(skfd);
        return false;
    }
    memset(&daddr, 0, sizeof(daddr));
    daddr.nl_family = AF_NETLINK;
    daddr.nl_pid = 0; // to kernel 
    daddr.nl_groups = 0;
     
    nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PLOAD));
    memset(nlh, 0, sizeof(struct nlmsghdr));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PLOAD);
    nlh->nlmsg_flags = 0;
    nlh->nlmsg_type = 0;
    nlh->nlmsg_seq = 0;
    nlh->nlmsg_pid = saddr.nl_pid; //self port
     
    memcpy(NLMSG_DATA(nlh), umsg, strlen(umsg));
    ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&daddr, sizeof(struct sockaddr_nl));
    if(!ret)
    {
        perror("sendto error\n");
        close(skfd);
        return false;

    }
    //printf("send kernel:%s\n", umsg);
     
    memset(&u_info, 0, sizeof(u_info));
    len = sizeof(struct sockaddr_nl);
    ret = recvfrom(skfd, &u_info, sizeof(user_msg_info), 0, (struct sockaddr *)&daddr, &len);
    if(!ret)
    {
        perror("recv form kernel error\n");
        close(skfd);
        return false;

    }
    //printf("from kernel:%s, %02x\n", u_info.msg, u_info.msg);
    *pbHardVer = u_info.msg[0];
    close(skfd);
    free((void *)nlh);
    return true;
}

void main()
{
    BYTE bHardware;
	if (GetHardVerByAdc(&bHardware))
        printf("GetHardVerByAdc ok bHardware=%0d.\n", bHardware);  
}

4. 运行接口

GetHardVerByAdc ok bHardware=126.

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值