内核态
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/netlink.h>
#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER + 1)
#define USER_PORT 50
MODULE_LICENSE("GPL");
MODULE_AUTHOR("arvik");
MODULE_DESCRIPTION("netlink_demo");
static struct sock *netlinkfd = NULL;
int send_msg(int8_t *pbuf, uint16_t len)
{
struct sk_buff *nl_skb;
struct nlmsghdr *nlh;
int ret;
nl_skb = nlmsg_new(len, GFP_ATOMIC);//创建len大小的struct sk_buff并返回
if(!nl_skb)
{
printk("netlink_alloc_skb error\n");
return -1;
}
nlh = nlmsg_put(nl_skb, 0, 0, USER_MSG, len, 0);//-将一个新的netlink消息加入到skb中。如果skb无法存放消息则返回NULL。
if(nlh == NULL)
{
printk("nlmsg_put() error\n");
nlmsg_free(nl_skb);//释放nlmsg_new()创建的skb。
return -1;
}
memcpy(nlmsg_data(nlh), pbuf, len);//把要发送的数据的len长度COPY给struct nlmsghdr *nlh
ret = netlink_unicast(netlinkfd, nl_skb, USER_PORT, MSG_DONTWAIT);//单播信息
return ret;
}
static void recv_cb(struct sk_buff *skb)
{
struct nlmsghdr *nlh = NULL;
void *data = NULL;
printk("skb->len:%u\n", skb->len);
if(skb->len >= nlmsg_total_size(0))//应该是判断接收到的长度是否有效
{
nlh = nlmsg_hdr(skb);//从sk_buff(->data)获取struct nlmsghdr数据结构
data = NLMSG_DATA(nlh);//用于取得消息的数据部分的首地址
if(data)
{
printk("kernel receive data: %s\n", (int8_t *)data);
send_msg(data, nlmsg_len(nlh));//后一个参数应该是消息的长度
}
}
}
struct netlink_kernel_cfg cfg =
{
.input = recv_cb,//接收到信息时的回调函数
};
static int __init test_netlink_init(void)
{
printk("init netlink_demo!\n");
netlinkfd = netlink_kernel_create(&init_net, USER_MSG, &cfg);//创建套接字
if(!netlinkfd)
{
printk(KERN_ERR "can not create a netlink socket!\n");
return -1;
}
printk("netlink demo init ok!\n");
return 0;
}
static void __exit test_netlink_exit(void)
{
sock_release(netlinkfd->sk_socket);
printk(KERN_DEBUG "netlink exit\n!");
}
module_init(test_netlink_init);
module_exit(test_netlink_exit);
用户态
/*******************************
file: u_netlink.c
description: netlink demo
author: arvik
email: 1216601195@qq.com
blog: http://blog.youkuaiyun.com/u012819339
*******************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>
#define NETLINK_USER 22
#define USER_MSG (NETLINK_USER + 1)
#define MSG_LEN 100
#define MAX_PLOAD 100
struct _my_msg
{
struct nlmsghdr hdr;
int8_t data[MSG_LEN];
};
int main(int argc, char **argv)
{
char *data = "hello kernel";
struct sockaddr_nl local, dest_addr;
int skfd;
struct nlmsghdr *nlh = NULL;
struct _my_msg info;
int ret;
skfd = socket(AF_NETLINK, SOCK_RAW, USER_MSG);
if(skfd == -1)
{
printf("create socket error...%s\n", strerror(errno));
return -1;
}
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = 50;
local.nl_groups = 0;
if(bind(skfd, (struct sockaddr *)&local, sizeof(local)) != 0)
{
printf("bind() error\n");
close(skfd);
return -1;
}
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; // to kernel
dest_addr.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 = local.nl_pid; //self port
memcpy(NLMSG_DATA(nlh), data, strlen(data));
ret = sendto(skfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_nl));
if(!ret)
{
perror("sendto error1\n");
close(skfd);
exit(-1);
}
printf("wait kernel msg!\n");
memset(&info, 0, sizeof(info));
ret = recvfrom(skfd, &info, sizeof(struct _my_msg), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if(!ret)
{
perror("recv form kernel error\n");
close(skfd);
exit(-1);
}
printf("msg receive from kernel:%s\n", info.data);
close(skfd);
free((void *)nlh);
return 0;
}
makefile可参考:https://blog.youkuaiyun.com/dj_jeck/article/details/79843189
https://www.cnblogs.com/lilto/p/11878303.html
代码来源:https://blog.youkuaiyun.com/u012819339/article/details/51334600?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param
参考资料:
https://blog.youkuaiyun.com/zllbuaa/article/details/30786729
https://www.cnblogs.com/arnoldlu/p/9532254.html