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
    评论
### 回答1: 是的,Linux内核中的Netlink机制可以用于在内核空间和用户空间之间进行通信Netlink接口提供了一种标准的方法,使内核模块或其他系统组件能够向用户空间发送消息,并从用户空间接收消息。这些消息可以包含各种信息,例如网络状态、接口状态、路由表等。应用程序可以使用Netlink API来与内核通信,以便获取这些信息,或者更新内核状态。在Linux系统中,许多网络配置和管理工具都使用Netlink接口与内核进行通信。 ### 回答2: Linux使用Netlink作为一种机制,用于与内核空间的应用程序进行通信Netlink是一种面向消息的API,允许应用程序在用户空间与内核空间进行交互。它是一种高性能且可扩展的通信机制,被广泛用于网络和系统管理等领域。 使用Netlink与应用程序通信的主要步骤如下: 首先,应用程序需要创建一个用于与内核通信Netlink套接字。这可以通过调用socket函数,并指定协议族为AF_NETLINK来实现。随后,可以使用bind函数将套接字绑定到特定的Netlink协议。 接下来,应用程序需要定义并初始化一个用于通信Netlink消息结构。该结构包含消息类型、标志、序列号等信息。 然后,应用程序可以使用sendto函数将消息发送给内核。在发送消息之前,需要将消息结构和有效负载数据进行封装,并将其作为参数传递给sendto函数。 在内核空间,可以使用Netlink套接字接收和处理来自应用程序的消息。内核通过调用netlink_unicast函数接收消息,并将其传递给注册的处理函数进行处理。处理函数可以根据消息类型来执行相应的逻辑,并可能生成回复消息。 最后,在应用程序中,可以使用recvfrom函数接收来自内核的回复消息。同样,需要解析回复消息的结构和有效负载数据,并根据需要进行处理。 通过使用Netlink,应用程序可以与内核进行双向通信,以传递和接收关于网络配置、系统状态和其他相关信息的消息。可以使用Netlink API提供的不同类型的消息和属性来满足各种通信需求,并将消息传递到适当的内核模块进行处理。这种灵活性和可扩展性使得Netlink成为Linux系统中重要的通信机制之一。 ### 回答3: Linux中的Netlink是一种用于在内核空间和用户空间之间进行通信的机制。应用程序可以通过使用Netlink套接字与内核进行通信,并获取有关系统状态的信息或发送指令给内核Netlink协议族是Linux内核的一部分,它定义了一组用于通信的协议。应用程序可以通过创建一个Netlink套接字来与内核进行通信Netlink套接字具有与传统套接字相似的接口,但是它们使用不同的协议族。 使用Netlink内核进行通信的应用程序可以执行各种任务,例如: 1. 获取和修改网络接口、路由表、ARP缓存等网络配置信息。 2. 与内核中的网络驱动程序进行通信,以发现接口状态变化或配置更新。 3. 获得内核事件,例如链接状态更改或设备失败。 4. 配置和管理网络协议栈。 5. 监控内核状态和性能。 使用Netlink通信的应用程序通常包含以下步骤: 1. 创建Netlink套接字。应用程序使用socket()函数创建一个Netlink套接字。 2. 绑定套接字到Netlink协议。通过调用bind()函数,将套接字绑定到特定的Netlink协议。 3. 发送和接收消息。应用程序通过send()函数发送消息给内核,并使用recv()函数接收来自内核的消息。 4. 处理消息。应用程序对从内核接收的消息进行解析和处理,以获得所需的信息或执行所需的操作。 总之,通过Linux中的Netlink机制,应用程序可以与内核进行通信,并获取或修改系统状态的信息。这是Linux系统中非常强大和灵活的一个特性,被许多网络和系统管理工具广泛使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值