#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_TEST 17
struct
{
__u32 pid;
} user_process; //如果单播的话必须应用层netlink发送报文到内核告知应用程序的pid号.要不然内核无法通过netlink给应用层发送报文.
int send_to_user (char *info);
static struct nf_hook_ops nfho_marker1;
unsigned int hook_mark1(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{
if(user_process.pid == 0)
return;
send_to_user("this message is from kernel");
return NF_ACCEPT;
}
static struct sock *netlinkfd = NULL;
int
send_to_user (char *info) //发送到用户空间
{
int size;
struct sk_buff *skb;
unsigned char *old_tail;
struct nlmsghdr *nlh; //报文头
int retval;
size = NLMSG_SPACE (strlen (info)); //报文大小
skb = alloc_skb (size, GFP_ATOMIC); //分配一个新的套接字缓存,使用GFP_ATOMIC标志进程不>会被置为睡眠
nlh =
nlmsg_put (skb, 0, 0, 0,
NLMSG_SPACE (strlen (info)) - sizeof (struct nlmsghdr), 0);
old_tail = skb->tail;
memcpy (NLMSG_DATA (nlh), info, strlen (info)); //填充数据区
nlh->nlmsg_len = skb->tail - old_tail; //设置消息长度
NETLINK_CB (skb).pid = 0;
NETLINK_CB (skb).dst_group = 0;
printk (KERN_DEBUG "[kernel space] skb->data:%s\n",
(char *) NLMSG_DATA ((struct nlmsghdr *) skb->data));
//发送数据
retval = netlink_unicast (netlinkfd, skb, user_process.pid, MSG_DONTWAIT);
printk(KERN_ALERT "retval = %d\n",retval);
printk (KERN_DEBUG "[kernel space] netlink_unicast return: %d\n", retval);
return 0;
}
void
kernel_receive (struct sk_buff *__skb) //内核从用户空间接收数据
{
struct sk_buff *skb;
struct nlmsghdr *nlh = NULL;
char *data = "This is eric's test message from kernel";
printk (KERN_DEBUG "[kernel space] begin kernel_receive\n");
skb = skb_get (__skb);
if (skb->len >= sizeof (struct nlmsghdr))
{
nlh = (struct nlmsghdr *) skb->data;
if ((nlh->nlmsg_len >= sizeof (struct nlmsghdr))
&& (__skb->len >= nlh->nlmsg_len))
{
user_process.pid = nlh->nlmsg_pid;
printk (KERN_ALERT
"[kernel space] data receive from user are:%s\n",
(char *) NLMSG_DATA (nlh));
printk (KERN_ALERT "[kernel space] user_pid:%d\n",
user_process.pid);
send_to_user (data);
}
}
else
{
printk (KERN_DEBUG "[kernel space] data receive from user are:%s\n",
(char *) NLMSG_DATA (nlmsg_hdr (__skb)));
send_to_user (data);
}
kfree_skb (skb);
}
int __init
test_netlink_init (void)
{
user_process.pid=0;
nfho_marker1.hook=hook_mark1;
nfho_marker1.hooknum=NF_INET_PRE_ROUTING;
nfho_marker1.pf=PF_INET;
nfho_marker1.priority=11;
nf_register_hook(&nfho_marker1);
netlinkfd =
netlink_kernel_create (&init_net, NETLINK_TEST, 0, kernel_receive, NULL,
THIS_MODULE);
if (!netlinkfd)
{
printk (KERN_ERR "can not create a netlink socket\n");
return -1;
}
return 0;
}
void __exit
test_netlink_exit (void)
{
sock_release (netlinkfd->sk_socket);
nf_unregister_hook(&nfho_marker1);
printk (KERN_DEBUG "test_netlink_exit!!\n");
}
module_init (test_netlink_init);
module_exit (test_netlink_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("eric.hu");
应用层:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#define NETLINK_TEST 17
#define MSG_LEN 100
struct msg_to_kernel
{
struct nlmsghdr hdr;
char data[MSG_LEN];
};
struct u_packet_info
{
struct nlmsghdr hdr;
char msg[MSG_LEN];
};
int
main (int argc, char *argv[])
{
char *data = "This message is from eric's space";
//初始化
struct sockaddr_nl local;
struct sockaddr_nl kpeer;
int skfd, ret, kpeerlen = sizeof (struct sockaddr_nl);
struct nlmsghdr *message;
struct u_packet_info info;
char *retval;
message = (struct nlmsghdr *) malloc (1);
skfd = socket (PF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (skfd < 0)
{
printf ("can not create a netlink socket\n");
return -1;
}
memset (&local, 0, sizeof (local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid ();
local.nl_groups = 0;
if (bind (skfd, (struct sockaddr *) &local, sizeof (local)) != 0)
{
printf ("bind() error\n");
return -1;
}
memset (&kpeer, 0, sizeof (kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0;
memset (message, '\0', sizeof (struct nlmsghdr));
message->nlmsg_len = NLMSG_SPACE (strlen (data));
message->nlmsg_flags = 0;
message->nlmsg_type = 0;
message->nlmsg_seq = 0;
message->nlmsg_pid = local.nl_pid;
retval = memcpy (NLMSG_DATA (message), data, strlen (data));
printf ("message sendto kernel are:%s, len:%d\n",
(char *) NLMSG_DATA (message), message->nlmsg_len);
ret =
sendto (skfd, message, message->nlmsg_len, 0, (struct sockaddr *) &kpeer,
sizeof (kpeer));
if (!ret)
{
perror ("send pid:");
exit (-1);
}
//接受内核态确认信息
while(1)
{
ret =
recvfrom (skfd, &info, sizeof (struct u_packet_info), 0,
(struct sockaddr *) &kpeer, &kpeerlen);
if (!ret)
{
perror ("recv form kerner:");
exit (-1);
}
//接受内核态确认信息
while(1)
{
ret =
recvfrom (skfd, &info, sizeof (struct u_packet_info), 0,
(struct sockaddr *) &kpeer, &kpeerlen);
if (!ret)
{
perror ("recv form kerner:");
exit (-1);
}
printf ("message receive from kernel:%s\n", (char *) info.msg);
}
//内核和用户进行通信
close (skfd);
return 0;
}
使用方法插入模块后 启动应用程序挂着看netlink通信报文.