/*
* netlink.c
*
* Created on: 2014 * Author: cr
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/netlink.h>
#include <net/sock.h>
//#include "usrlink.h"
//MODULE_LICENSE("Dual BSD/GPL");
//MODULE_AUTHOR("MDAXIA");
struct sock *netlink_fd;
static struct pin_desc *irq_pd;
static struct input_dev *sunxi_buttons_dev;
static struct timer_list buttons_timer;
//static int key_state[2];
static int key_repeat_report[2];
static unsigned long timeout_0 = 0x00;
static unsigned long timer_cnt_0 = 0x00;
static unsigned long timeout_1 = 0x00;
static unsigned long timer_cnt_1 = 0x00;
static void netlink_to_user(int dest, void *buf, int len)
{
struct nlmsghdr *nl;
struct sk_buff *skb;
int size;
//printk( "dest = %d.\n", dest );
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
if(!skb || !buf)
{
printk(KERN_ALERT "netlink_to_user skb of buf null!\n");
return;
}
nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);
//NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_group = 0;
memcpy(NLMSG_DATA(nl), buf, len);
nl->nlmsg_len = (len > 2) ? (len - 0):len;
netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);
//printk(KERN_ALERT "K send packet success\n");
}
static int process_hello_get(int dest, void *buf, int len)
{
printk(KERN_ALERT "In process_hello get!\n");
memcpy(buf, "I known you !", 13);
netlink_to_user(dest, buf, 13);
return NET_OK;
}
static int process_hello_set(int dest, void *buf, int len)
{
//printk( "In process_hello set! %s\n", (char *)buf);
//memcpy(buf, "S known you !", 13);
netlink_to_user(dest, buf, len);
return NET_OK;
}
static void netlink_process_packet(struct nlmsghdr *nl)
{
int ret;
switch(nl->nlmsg_type)
{
case HELLO_GET:
printk( "process_hello_get.\n" );
ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
case HELLO_SET:
printk( "process_hello_set.\n" );
ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);
break;
default:break;
}
}
static void netlink_recv_packet(struct sk_buff *__skb)
{
struct sk_buff *skb;
struct nlmsghdr *nlhdr;
skb = skb_get(__skb);
if(skb->len >= sizeof(struct nlmsghdr))
{
nlhdr = (struct nlmsghdr *)skb->data;
if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&
__skb->len >= nlhdr->nlmsg_len)
{
netlink_process_packet(nlhdr);
}
}
else
printk(KERN_ALERT "Kernel receive msg length error!\n");
}
#if 0
static int __init netlink_init(void)
{
netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);
if(NULL == netlink_fd)
{
printk(KERN_ALERT "Init netlink!\n");
return -1;
}
printk(KERN_ALERT "Init netlink success!\n");
return 0;
}
static void __exit netlink_exit(void)
{
netlink_kernel_release(netlink_fd);
printk(KERN_ALERT "Exit netlink!\n");
}
#endif