#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/kmod.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include "ra8670.h"
#include "xdsl_event.h"


int pid;
int reportState = SLAVE_LINK_DOWN;

extern struct sock *nl_sk;

void receive_netlinkMsg(struct sk_buff *skb) {
	struct nlmsghdr *nlh;
	int msg_size;
	char *msg= "Hello from kernel";

	printk(KERN_INFO "Entering: %s\n", __FUNCTION__);

	msg_size=strlen(msg);

	nlh=(struct nlmsghdr*)skb->data;
	printk(KERN_INFO "Netlink received msg payload:%s\n",(char*)nlmsg_data(nlh));
	pid = nlh->nlmsg_pid; /*pid of sending process */
}

static void send_netlinkMsg(unsigned char *msg) {
	struct nlmsghdr *nlh;
	struct sk_buff *skb_out;
	int msg_size = strlen(msg);		
	int res = 0;
	skb_out = nlmsg_new(msg_size,0);

	if(!skb_out)
	{
		printk(KERN_ERR "Failed to allocate new skb\n");
		return;
	} 
	nlh=nlmsg_put(skb_out,0,0,NLMSG_DONE,msg_size,0);  
	NETLINK_CB(skb_out).dst_group = 0; /* not in mcast group */
	strncpy(nlmsg_data(nlh),msg,msg_size);

	res = nlmsg_unicast(nl_sk,skb_out,pid);

	if(res<0)
		printk(KERN_INFO "Error while sending bak to user\n");
	
}

int remotePhy_evt_notify(unsigned char event, void *data) {	
	int retval=0;
	char msg[16] = {'\0'};

	//snprintf(msgidstr, sizeof(msgidstr)-1, "0x%x", msgid);
	snprintf(msg, sizeof(msg)-1, "%d", event);
	printk("[%s %d]new state_%s_\n", __func__, __LINE__, msg);
	send_netlinkMsg(msg);
//ERROR:
	return retval;	
}

char adsl_showtime = 0;
void ADSL_state(unsigned char LEDstate)
{
		static unsigned char LastStatus = 255;
		if(LastStatus == LEDstate)
			return;
			
		LastStatus = LEDstate;
		adsl_showtime = 0;
		switch((unsigned char)LEDstate){
			case C_AMSW_IDLE:
			case C_AMSW_L3:
			case C_AMSW_ACTIVATING:
			case C_AMSW_END_OF_LD:
				if(SLAVE_LINK_DOWN != reportState)
				{
					reportState = SLAVE_LINK_DOWN;
					remotePhy_evt_notify(SLAVE_LINK_DOWN, NULL);
				}
				break;
			case C_AMSW_SLOWBLINK_STATE:
				if(SLAVE_HANDSHAKE != reportState)
				{
					reportState = SLAVE_HANDSHAKE;
					remotePhy_evt_notify(SLAVE_HANDSHAKE, NULL);
				}
				break;
			case C_AMSW_INITIALIZING:
				if(SLAVE_FULLINIT != reportState)
				{
					reportState = SLAVE_FULLINIT;
					remotePhy_evt_notify(SLAVE_FULLINIT, NULL);
				}
				break;
				
			case C_AMSW_SHOWTIME_L0:
				if(SLAVE_LINK_UP != reportState)
				{
					reportState = SLAVE_LINK_UP;
					remotePhy_evt_notify(SLAVE_LINK_UP, NULL);
				}
				adsl_showtime = 1;
				break;
			case RATE_CHANGE_BY_SRA:
				remotePhy_evt_notify(SLAVE_RATE_CHANGE, NULL);
				break;
			case HS_1ST_MSG_RECEIVED:
				remotePhy_evt_notify(SLAVE_HS_1ST_RECV, NULL);
				break;
			case DSL_STATISTICS:
				remotePhy_evt_notify(SLAVE_DSL_STATISTICS, NULL);
				break;
		}
}