#include <linux/socket.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <net/sock.h>
#include <net/tcp_states.h>

/* Sollte in .../include/linux/netlink.h stehen */
#define NETLINK_TEST 25

#define MY_NL_COMMAND 0x11
#define MY_MESSAGE "Answer from Kernel"

static struct sock *nl_sk = NULL;
static DEFINE_MUTEX(nltest_mutex);

static void
nltest_netlink_server(struct sk_buff *skb)
{
 struct nlmsghdr *nlh, *hdr;
 u32 pid;
 struct sk_buff *ret_skb;
 char *data_ptr;

 printk("nltest_netlink_server(%p)\n", skb);
 BUG_ON(!skb);
 nlh = nlmsg_hdr(skb);
 pid = nlh->nlmsg_pid;
 printk("pid: %d, seq: %d, data: \"%s\"\n",
        pid, nlh->nlmsg_seq,
        (char *)nlmsg_data(nlh));

 /* Antwort verschicken  */
 ret_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
 if (ret_skb == NULL) {
   printk("%s: no mem\n", __FUNCTION__);
   return;
 }

 /* Header vorbereiten */
 hdr = nlmsg_put(ret_skb,0,nlh->nlmsg_seq,
   NLMSG_DONE, strlen(MY_MESSAGE),0);
 if(IS_ERR(hdr)) {
   printk("nlmsg_put failed\n");
   nlmsg_free( ret_skb );
   return;
 }

 data_ptr = nlmsg_data(hdr);
 strcpy(data_ptr, MY_MESSAGE);
 nlmsg_end( ret_skb, nlh );

 netlink_unicast(nl_sk, ret_skb, pid, MSG_DONTWAIT);
}

static int
__init nltest_module_init(void)
{
 printk("nltest_module_init\n");
 nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST,
   0, nltest_netlink_server, &nltest_mutex, THIS_MODULE );
 return 0;
}

static void
__exit nltest_module_exit(void)
{
 printk("nltest_module_exit\n");
 if( nl_sk )
   sock_release(nl_sk->sk_socket);
}

module_init(nltest_module_init);
module_exit(nltest_module_exit);
MODULE_LICENSE("GPL");