netlink 2.6.32內核單播實現


#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通信報文.



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章