根据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;
}