通用netlink的基本使用(2) NETLINK_GENERIC

根据family name 动态获得family id

内核代码

#include <net/genetlink.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

//接收消息后的回调函数
int test_ctl_function(struct sk_buff *skb, struct genl_info *info)
{
    printk("get process pid=%d  cmd=%d pid=%d type=%d len=%d\n",info->snd_pid,info->genlhdr->cmd,info->nlhdr->nlmsg_pid,info->nlhdr->nlmsg_type,info->nlhdr->nlmsg_len);

    return 0;
}

struct genl_family test_ctl = {
    .id=0, //此family id 为0 表示动态分配
    .name="testnet",  //family name  在应用层根据此名字获得动态分配的family id
    .version=1,
};

struct genl_ops test_ctl_ops={
    .cmd = 100, //消息命令字 接收带此消息 会调用下面的回调函数
    .doit = test_ctl_function,//接收消息后的回调函数
};

static int __init testnlk_init(void)
{
    if(genl_register_family(&test_ctl) != 0)
    {
        printk("register faimly error\n");
        return -1;
    }

    if(genl_register_ops(&test_ctl,&test_ctl_ops) !=  0)
    {
        printk("Register ops error\n");
        goto out;
    }

    return 0;
out:
    genl_unregister_family(&test_ctl);
    return 0;
}

static void __exit testnlk_exit(void)
{
    genl_unregister_ops(&test_ctl,&test_ctl_ops);
    genl_unregister_family(&test_ctl);

}

module_init(testnlk_init);
module_exit(testnlk_exit);
MODULE_LICENSE("GPL");

应用层代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>

struct mymsg{
    struct nlmsghdr nhdr;
    struct genlmsghdr  genhdr;
    char buffer[1024];
};

int main(int argc,char *argv[])
{
    int skfd;
    struct sockaddr_nl addr={0};
    struct mymsg msg={0};
    struct mymsg rcmsg={0};
    int ret;
    struct nlattr *natr;

    skfd = socket(AF_NETLINK,SOCK_RAW,NETLINK_GENERIC);
    if(skfd < 0)
    {
        printf("socket error\n");
        return -1;
    }
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = getpid();

    if(bind(skfd,(struct sockaddr *)&addr,sizeof(addr)) < 0 )
    {
        printf("Bind error\n");
        goto out;
    }

    //发送信息到内核
    addr.nl_family = AF_NETLINK;
    addr.nl_pid = 0;

    //设置消息头
    msg.nhdr.nlmsg_type = GENL_ID_CTRL; //从内核获得type
    msg.nhdr.nlmsg_pid = getpid();
    msg.nhdr.nlmsg_flags = NLM_F_REQUEST;
    msg.nhdr.nlmsg_len  = NLMSG_LENGTH(GENL_HDRLEN); //nlmsghdr头长 + gennlmsg头长
	
	msg.genhdr.cmd = CTRL_CMD_GETFAMILY;//根据family 名称获得family id
    msg.genhdr.version = 0x02;

    natr = (struct nlattr*)(NLMSG_DATA(&msg)+GENL_HDRLEN);
    natr->nla_type = CTRL_ATTR_FAMILY_NAME;
    natr->nla_len = sizeof("testnet")+NLA_HDRLEN;
    strcpy((char*)natr+NLA_HDRLEN,"testnet"); //此处根据这个family name获得family id
    msg.nhdr.nlmsg_len += NLMSG_ALIGN(natr->nla_len);

    ret = sendto(skfd,(char*)&msg,msg.nhdr.nlmsg_len,0,(struct sockaddr *)&addr,sizeof(addr));
    if(ret <= 0)
    {
        printf("send error\n");
    }

    //接收返回的family id
    ret = recv(skfd,&rcmsg,sizeof(rcmsg),0);
    if(ret < 0)
        goto out;

    //错误检查
    if(!NLMSG_OK((struct nlmsghdr*)&msg,ret) || msg.nhdr.nlmsg_type == NLMSG_ERROR)
    {
        printf(" error happed\n");
        goto out;
    }
    
	//获得属性值
    natr = (struct nlattr*)(NLMSG_DATA(&rcmsg)+GENL_HDRLEN);
    natr = (struct nlattr*)(NLA_ALIGN(natr->nla_len)+(char*)natr);
    if(natr->nla_type == CTRL_ATTR_FAMILY_ID)
    {
        printf("id = %d\n",*((unsigned short *)(char*)natr+NLA_HDRLEN));
    }
    else
    {
        printf("Get id error type[%d]\n",natr->nla_type);
    }

out:
    close(skfd);
    return 0;
}
                       

猜你喜欢

转载自blog.csdn.net/yldfree/article/details/82498719
今日推荐