#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <linux/if_packet.h>
#include <linux/if.h>

#include "raw_sock.h"
#include "protocol.h"
#include "protocol_udp.h"

/****************************************************************************
 * Function   : 	csum
 * Description: 	计算校验和

 * Input      : 	addr  : 数据起始地址
 				count : 数据长度
 * Output     : 	N/A
 * Return     :	返回校验值
****************************************************************************/
LOCAL unsigned short csum(unsigned char *addr, int count, enum OSI_LAYER_TYPE layer)
{
	unsigned int sum = 0;

	if (!addr)
	{
		return 0;
	}

	while (count > 1)
	{
		/*  This is the inner loop */
		sum   += htons(*(unsigned short *)addr);
		addr  += 2;
		count -= 2;
	}
	/*  Add left-over byte, if any */
	if (count > 0)
	{
		if (DATALINK_LAYER == layer)
		{
			sum += (*addr & 0x00FF) << 8 & 0x0000FF00;//used to be *addr

		}
		else if (NETWORK_LAYER == layer)
		{
			sum += *addr;
		}
		else
		{
			sum += *addr;
		}
	}

	/*  Fold 32-bit sum to 16 bits */
	while (sum >> 16)
	{
		sum = (sum & 0xffff) + (sum >> 16);
	}

	return ~sum;
}


/****************************************************************************
 * Function   : 	check_hdr_validity
 * Description: 	协议头部合法性检查

 * Input      : 	ph : 协议头指针
 				
 * Output     : 	N/A
 * Return     :	合法性通过返回OK，否则返回ERROR
****************************************************************************/
STATUS check_hdr_validity(PROTOCOL_HDR *ph, enum OSI_LAYER_TYPE layer)
{
	if (!ph)
	{
		return ERROR;
	}
	
	DPRINT_DBG("check_hdr_validity ph->version:%d,ph->type:%d,ph->hlen:%d\n",ph->version,ph->type,ph->hlen);
#if 1
	if ((ph->version != PROTOCOL_VERSION) || (ph->type <= TYPE_BASE) || (ph->type >= TYPE_MAX)
		|| (ph->hlen != PROTOCOL_HDR_SIZE) || (ntohs(ph->dlen) > PROTOCOL_BODY_LEN)
		|| ((ntohl(ph->magicnum) != MAGIC_NUM)))
	{
		DPRINT_ERR("protocol header error\n");
		return ERROR;
	}
#endif
#if 0
	if (0 != csum((unsigned char *)ph, ph->hlen + ntohs(ph->dlen), layer))
	{
		DPRINT_ERR("csum error\n");
		return ERROR;
	}

#endif
	return OK;
}


/****************************************************************************
 * Function   : 	copy_msg_element
 * Description: 	拷贝ME数据部分

 * Input      : 	meh : ME结构指针
 				buf : 目的缓存
 				len : 拷贝数据长度
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
LOCAL STATUS copy_msg_element(MSG_ELEMENT_HDR *meh, char *buf, int len)
{
	if ((!meh) || (!buf) || (len < 0))
	{
		return ERROR;
	}
		
	memcpy(buf, meh->data, len);

	return OK;
}

/****************************************************************************
 * Function   : 	eth_header_init
 * Description: 	以太网头部初始化

 * Input      : 	fbuf     : 帧缓存
 				dmac_str : 目的MAC地址
 				smac_str : 源MAC地址
 				pt       : 协议类型
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS eth_header_init(char *fbuf, char *dmac_str, char *smac_str, unsigned short pt)
{
	ETH_ADDR dmac_hex;
	ETH_ADDR smac_hex;
	ETH_HEADER *eth;
	
	if (!fbuf || !dmac_str || !smac_str)
	{
		return ERROR;
	}

	mac_string2mac_hex(dmac_str, &dmac_hex);
	mac_string2mac_hex(smac_str, &smac_hex);
	
	/* 填充以太网头部 */
	eth = (ETH_HEADER *)fbuf;

	memcpy((void *)eth->ether_dhost, (void *)dmac_hex.ether_addr_octet, ETH_ALEN);
	memcpy((void *)eth->ether_shost, (void *)smac_hex.ether_addr_octet, ETH_ALEN);
	eth->ether_type = htons(pt);
	
	return OK;
}


/****************************************************************************
 * Function   : 	protocol_header_init
 * Description: 	协议头部初始化

 * Input      : 	ph   : 协议头指针
 				type : 帧类型
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS protocol_header_init(PROTOCOL_HDR *ph, enum PROTOCOL_TYPE type)
{
	if (!ph || (type >= TYPE_MAX || type <= TYPE_BASE))
	{
		return ERROR;
	}
	
	memset(ph, 0, PROTOCOL_HDR_SIZE);
	
	ph->version = PROTOCOL_VERSION;
	ph->type = type;
	ph->hlen = PROTOCOL_HDR_SIZE;
	ph->dlen = htons(0);
	ph->checksum = htons(0);
	ph->magicnum = htonl(MAGIC_NUM);
	ph->seqnum = htons(0);
	
	return OK;
}


/****************************************************************************
 * Function   : 	advertisement_content_update
 * Description: 	更新g_adv_buf.content

 * Input      : 		
 * Output     : 	N/A
 * Return     :	如果g_adv_buf.content有更新则返回TRUE，否则返回FALSE
****************************************************************************/
BOOL advertisement_content_update(void)
{
	ME_DEVNAME   dev_name = {0};
	ME_DEVSN	dev_sn = {0};
	ME_DEVVER  dev_ver = {0};
	ME_DEVHWVER  dev_hwver = {0};
	ME_NETMASK	dev_netmask = {0};
	ME_IPADDR	dev_ip = {0};
	ME_MACADDR	dev_mac = {0};
	ME_SSHPORT	dev_ssh_port = {0};
	ME_SSHENC	dev_ssh_enc = {0};

	ADV_CONTENT *content = NULL;
	
	int flag = FALSE;

	flag = FALSE;

	DATA_LOCK(g_adv_frame);

	content = &g_adv_frame.content;

	/* 设备型号 */
	if ((OK == get_product_name(dev_name.name)) && strcmp(dev_name.name, content->dev_name.name))
	{
		flag = TRUE;
		dstrlcpy(content->dev_name.name, dev_name.name, sizeof(content->dev_name.name));
	}

	/* 设备SN */
	if ((OK == get_board_sn(dev_sn.sn)) &&  strcmp(dev_sn.sn, content->dev_sn.sn))
	{
		flag = TRUE;
		dstrlcpy(content->dev_sn.sn, dev_sn.sn, sizeof(content->dev_sn.sn));

	}

	/* 设备固件版本 */
	get_software_ver(dev_ver.ver);
	if (strcmp(dev_ver.ver, content->dev_ver.ver))
	{
		flag = TRUE;
		dstrlcpy(content->dev_ver.ver, dev_ver.ver, sizeof(content->dev_ver.ver));

	}
	
	/* 设备硬件版本 */
	if ((OK == get_hardware_ver(dev_hwver.hwver)) &&  strcmp(dev_hwver.hwver, content->dev_hwver.hwver))
	{
		flag = TRUE;
		dstrlcpy(content->dev_hwver.hwver, dev_hwver.hwver, sizeof(content->dev_hwver.hwver));
	}

	/* 设备IP */
	if ((OK == get_local_ipaddr(g_wan_ifname,dev_ip.ip)) &&  strcmp(dev_ip.ip, content->dev_ip.ip))
	{
		flag = TRUE;
		dstrlcpy(content->dev_ip.ip, dev_ip.ip, sizeof(content->dev_ip.ip));
	}

	/* 设备掩码 */
	if ((OK == get_local_netmask(g_wan_ifname,dev_netmask.netmask)) &&  strcmp(dev_netmask.netmask, content->dev_netmask.netmask))
	{
		flag = TRUE;
		dstrlcpy(content->dev_netmask.netmask, dev_netmask.netmask, sizeof(content->dev_netmask.netmask));
	}

	/* 设备MAC */
	if ((OK == get_local_macaddr(g_wan_ifname,dev_mac.mac)) &&  strcmp(dev_mac.mac, content->dev_mac.mac))
	{
		flag = TRUE;
		dstrlcpy(content->dev_mac.mac, dev_mac.mac, sizeof(content->dev_mac.mac));
	}

	/* 设备SSH端口 */
	if ((OK == get_local_ssh_port(&dev_ssh_port.sshport))
		&& (content->dev_sshport.sshport != dev_ssh_port.sshport))
	{
		flag = TRUE;
		content->dev_sshport.sshport = dev_ssh_port.sshport;
	}

	/* 设备SSH秘钥登录状态 */
	dev_ssh_enc.sshenc = get_local_ssh_enc_status();
		
	DPRINT_DBG("dev_ssh_enc.sshenc:%d, content->dev_sshenc.sshenc:%d\n",dev_ssh_enc.sshenc,content->dev_sshenc.sshenc);
	if (content->dev_sshenc.sshenc != dev_ssh_enc.sshenc)
	{
		flag = TRUE;
		content->dev_sshenc.sshenc = dev_ssh_enc.sshenc;
	}

	DATA_UNLOCK(g_adv_frame);

	return flag;
}
/****************************************************************************
 * Function   : 	advertisement_buf_update
 * Description: 	构造ipc信息广播帧，该帧中包含以下内容:
 				(1) 设备名称
 				(2) 设备MAC地址
 				(3) 设备IP地址
 				(4) 设备uuid

 * Input      :
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS advertisement_buf_update(enum OSI_LAYER_TYPE layer)
{
	PROTOCOL_HDR *ph;
	
	ME_DEVVER	*mm;
	ME_DEVHWVER	*ma;
	ME_IPADDR	*mi;
	ME_SSHPORT  *mh;
	ME_SSHENC   *mo;
	
	ADV_CONTENT *content;
	MSG_ELEMENT_HDR *meh;
	ME_DEVNAME   *md = NULL;
	ME_DEVSN  *minfo;
	ME_NETMASK *ms = NULL;
	ME_MACADDR *mc = NULL;

	char *frame;
	
	int ret;

	frame = g_adv_buf;
	DATA_LOCK(g_adv_frame);
	content = &g_adv_frame.content;
	ret = eth_header_init(frame, BROADCAST_MAC_ADDR,  content->dev_mac.mac, ETH_P_TP);
	if (ret != OK)
	{
		DPRINT_ERR("eth header init failed\n");
 		return ERROR;
	}

	ph = (PROTOCOL_HDR *)(frame + sizeof(ETH_HEADER));
	ret = protocol_header_init(ph, 1);
	if (ret != OK)
	{
		DPRINT_ERR("protocol header init failed\n");
 		return ERROR;
	}
	
	/* ----- 填充协议payload ----- */
	/* ----- 设备型号 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVNAME);
	md  = (ME_DEVNAME *)(meh->data);

	dstrlcpy(md->name, content->dev_name.name, sizeof(md->name));

	meh->length = htons(strlen(md->name));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备SN ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVSN);
	minfo = (ME_DEVSN *)(meh->data);

	dstrlcpy(minfo->sn, content->dev_sn.sn, sizeof(minfo->sn));
	meh->length = htons(strlen(minfo->sn));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备固件版本 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVVER);
	mm = (ME_DEVVER *)(meh->data);

	
	dstrlcpy(mm->ver, content->dev_ver.ver, sizeof(mm->ver));
	meh->length = htons(strlen(mm->ver));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备硬件版本 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVHWVER);
	ma = (ME_DEVHWVER *)(meh->data);
	
	dstrlcpy(ma->hwver, content->dev_hwver.hwver, sizeof(ma->hwver));

	meh->length = htons(strlen(ma->hwver));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);
	
	/* ----- 设备IP ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVIP);
	mi = (ME_IPADDR *)(meh->data);
	
	dstrlcpy(mi->ip, content->dev_ip.ip, sizeof(mi->ip));
	
	meh->length = htons(strlen(mi->ip));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备掩码 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVNETMASK);
	ms = (ME_NETMASK *)(meh->data);

	dstrlcpy(ms->netmask, content->dev_netmask.netmask, sizeof(ms->netmask));

	meh->length = htons(strlen(ms->netmask));
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备MAC ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVNETMAC);
	mc = (ME_MACADDR *)(meh->data);

	dstrlcpy(mc->mac, content->dev_mac.mac, sizeof(mc->mac));

	meh->length = htons(strlen(mc->mac));
	
	DPRINT_DBG("mac:%s, length:%d\n",mc->mac,meh->length);
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);


	/* ----- 设备SSH  端口 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVSSHPORT);
	mh = (ME_SSHPORT *)(meh->data);
	
	mh->sshport = htonl(content->dev_sshport.sshport);
	
	meh->length = htons(sizeof(mh->sshport));
	
	DPRINT_DBG("ssh port:%d, length:%d\n",mh->sshport,meh->length);
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);

	/* ----- 设备SSH秘钥登录状态 ----- */
	meh = (MSG_ELEMENT_HDR *)((char *)ph + ph->hlen + ph->dlen);
	meh->type = htons(ME_T_DEVSSHENC);
	mo = (ME_SSHENC *)(meh->data);

	mo->sshenc = htonl(content->dev_sshenc.sshenc);
	
	meh->length = htons(sizeof(mo->sshenc));
	
	DPRINT_DBG("ssh venc:%d, length:%d\n",mo->sshenc,meh->length);
	ph->dlen += sizeof(MSG_ELEMENT_HDR) + ntohs(meh->length);


	/* 计算校验和 */
	ph->dlen = htons(ph->dlen);
	ph->checksum = htons(csum((unsigned char *)ph, ph->hlen + ntohs(ph->dlen),layer));

	g_adv_frame.data_len = sizeof(ETH_HEADER) + sizeof(PROTOCOL_HDR) + ntohs(ph->dlen);

	DATA_UNLOCK(g_adv_frame);
	return OK;
}


/****************************************************************************
 * Function   : 	advertisement_buf_init
 * Description: 	程序启动时调用此函数，用于初始化全局变量g_nvr_adv_buf
 				当程序需要向局域网内部广播配置信息时，需要先检查配置参数
 				是否有更新，如果有更新则更新则重新构造g_nvr_adv_buf.buf
 				
 * Input      : 	
 
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS advertisement_buf_init(void)
{
	int ret = OK;

	memset(&g_adv_frame, 0, sizeof(ADV_FRAME));

	ret = DATA_LOCK_INIT(g_adv_frame);
	if (ret)
	{
		return ret;
	}

	return OK;
}

STATUS advertisement_buf_deinit(void)
{
	DATA_LOCK_DESTROY(g_adv_frame);

	return OK;
}


/****************************************************************************
 * Function   : 	send_advertisement_frame
 * Description: 	向局域网内广播本机配置信息

 * Input      : 	
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS send_advertisement_frame(void)
{
	int rawsock;
	RAW_DATA rawdata;
	
	int ret= ERROR;

	rawsock = g_raw_sock;//raw_socket_init(ETH_P_TP, NET_DEVICE_NAME);
	if (ERROR == rawsock)
	{
		DPRINT_ERR("raw socket init error\n");
		return ERROR;
	}

	if (advertisement_content_update() == TRUE)
	{
		advertisement_buf_update(DATALINK_LAYER);
	}
	DATA_LOCK(g_adv_frame);
	rawdata.len = g_adv_frame.data_len;
	DATA_UNLOCK(g_adv_frame);

	rawdata.data = (void *)g_adv_buf;
	ret = raw_data_send(rawsock, &rawdata);
	if (ret != OK)
	{
		DPRINT_ERR("raw data send error\n");
	}
	
	return ret;
}


/****************************************************************************
 * Function   : 	parse_msg_element
 * Description: 	解析指定类型的ME

 * Input      : 	meh       : ME结构指针
 				total_len : 数据总长度
 				me_type   : ME类型
 				arg       : ME数据缓存
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS parse_msg_element(MSG_ELEMENT_HDR *meh, int total_len, unsigned short me_type, char *arg, int max_len)
{
	int offset, count, flag;
	unsigned short type, length;
	MSG_ELEMENT_HDR *tmp_meh = NULL;
	
	int ret;

	flag = 0;

	if ((!meh) || (total_len < sizeof(MSG_ELEMENT_HDR)) || !arg)
	{
		return ERROR;
	}

	offset = 0;
	count = 0;
	
	while (total_len > 0)
	{
		tmp_meh = (MSG_ELEMENT_HDR *)((char *)meh + offset);

		type   = ntohs(tmp_meh->type);
		length = ntohs(tmp_meh->length);

		if (type == me_type)
		{
			if(length > max_len)
			{
				return ERROR;
			}

			switch (type)
			{
			case ME_T_MACADDR:
				if (count >= MAX_MAC_COUNT)
				{
					return ERROR;
				}
			
				ret = copy_msg_element(tmp_meh, arg + count * STR_MAC_LEN, length);
				if (ret != OK)
				{
					return ERROR;
				}
				else
				{
					count++;
				}
			
				flag = 1;
			
				break;

			case ME_T_DEVNAME:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;

			case ME_T_DEVSN:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;
				
			case ME_T_DEVVER:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}
			
				flag = 1;
			
				break;
				
			case ME_T_DEVHWVER:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}
			
				flag = 1;
			
				break;


			case ME_T_DEVIP:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;

			case ME_T_DEVNETMASK:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;

			case ME_T_DEVSSHPORT:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;

			case ME_T_DEVSSHENC:
				ret = copy_msg_element(tmp_meh, arg, length);
				if (ret != OK)
				{
					return ERROR;
				}

				flag = 1;

				break;
				
			default:
				break;
			}
		}
		
		offset    += sizeof(MSG_ELEMENT_HDR) + length;
		total_len -= sizeof(MSG_ELEMENT_HDR) + length;
	}
	
	return (flag ? OK : ERROR);
}


/****************************************************************************
 * Function   : 	parse_discovery_frame
 * Description: 	解析设备发现帧，判断本机是否属于被发现主机

 * Input      : 	ph : 协议头指针
 				
 * Output     : 	N/A
 * Return     :	本机属于被发现主机返回TRUE,否则返回FALSE
****************************************************************************/
BOOL parse_discovery_frame(PROTOCOL_HDR *ph)
{
	ME_MACADDR mm;
	MSG_ELEMENT_HDR *meh;
	char mac[MAX_MAC_COUNT][STR_MAC_LEN];

	int i, ret, flag;
	
	flag = 0;
	
	if (!ph)
	{
		DPRINT_ERR("invalid argument, ph = NULL\n");
		return FALSE;
	}

	memset(mac, 0, MAX_MAC_COUNT * STR_MAC_LEN);
	
	meh = (MSG_ELEMENT_HDR *)((char *)ph + PROTOCOL_HDR_SIZE);

	ret = parse_msg_element(meh, ntohs(ph->dlen), ME_T_MACADDR, (char *)mac, MAX_MAC_COUNT * STR_MAC_LEN);
	if (ret != OK)
	{
		DPRINT_ERR("parse msg element failed, me type = ME_T_MACADDR\n");
		return TRUE;
	}
	
	for (i = 0; i < STR_MAC_LEN; i++)
	{
		if (mac[0][i] != 0)
		{
			flag = 1;
			break;
		}
	}

	/* 发现所有设备 */
	if (0 == flag)
	{
		return TRUE;
	}

	memset(&mac, 0, sizeof(ME_MACADDR));
	
	ret = get_local_macaddr(g_wan_ifname, mm.mac);
	if (ret != OK)
	{
		DPRINT_ERR("get device mac failed\n");
		return TRUE;
	}
	
	/* 将设备发现帧中指定MAC与本机MAC进行比较 */
	for (i = 0; i < MAX_MAC_COUNT; i++)
	{
		if (!memcmp(mm.mac, mac[i], STR_MAC_LEN))
		{
			return TRUE;
		}
	}

	return FALSE;
}


/****************************************************************************
 * Function   : 	parse_advertisement_frame
 * Description: 	解析设备信息广播帧，得到设备的以下配置参数:
 				(1) 设备MAC
 				(2) 设备IP
 				(3) 设备uuid
 				(4) HTTP服务端口

 * Input      : 	ph : 协议头指针
 				
 * Output     : 	N/A
 * Return     :	解析成功返回OK,出错返回ERROR
****************************************************************************/
STATUS parse_advertisement_frame(PROTOCOL_HDR *ph, ADV_CONTENT *content)
{
	MSG_ELEMENT_HDR *meh;
	int ret = ERROR;
	
	if (!ph || !content)
	{
		return ERROR;
	}

	meh = (MSG_ELEMENT_HDR *)((char *)ph + PROTOCOL_HDR_SIZE);
	/* 解析设备MAC地址 */
	ret = parse_msg_element(meh, ntohs(ph->dlen), ME_T_MACADDR, content->dev_mac.mac, STR_MAC_LEN);
	if (ret != OK)
	{
		DPRINT_ERR("parse msg element failed, me type = ME_T_MACADDR\n");
		return ERROR;
	}

	return OK;
}


/****************************************************************************
 * Function   : 	parse_set_ip_frame
 * Description: 	解析设置IP地址报文，得到将要设置的IP地址、子网掩码和网关
 				
 * Input      : 	ph : 协议头指针
 				mi : ip ME 
 				mn : netmask ME
 				mg : gateway ME
 				
 * Output     : 	N/A
 * Return     :	解析成功返回OK,出错返回ERROR
****************************************************************************/
#if 0

STATUS parse_set_ip_frame(PROTOCOL_HDR *ph, ME_IPADDR *mi, ME_NETMASK *mn, ME_GATEWAY *mg)
{
	MSG_ELEMENT_HDR *meh;
	
	int ret;

	if (!ph || !mi ||! mn || !mg)
	{
		return ERROR;
	}
	
	meh = (MSG_ELEMENT_HDR *)((char *)ph + PROTOCOL_HDR_SIZE);

	/* 解析IP地址 */
	ret = parse_msg_element(meh, ntohs(ph->dlen), ME_T_DEVIP, mi->ip, STR_IP_LEN);
	if (ret != OK)
	{
		DPRINT_ERR("parse msg element failed, me type = ME_T_IPADDR\n");
		return ERROR;
	}

	/* 解析子网掩码 */
	ret = parse_msg_element(meh, ntohs(ph->dlen), ME_T_DEVNETMASK, mn->netmask, STR_IP_LEN);
	if (ret != OK)
	{
		DPRINT_ERR("parse msg element failed, me type = ME_T_NETMASK\n");
		return ERROR;
	}
	/* 解析默认网关 */
	ret = parse_msg_element(meh, ntohs(ph->dlen), ME_T_GATEWAY, mg->gateway, STR_IP_LEN);
	if (ret != OK)
	{
		DPRINT_ERR("parse msg element failed, me type = ME_T_GATEWAY\n");
	}
	return OK;
}
#endif

/****************************************************************************
 * Function   : 	protocol_handler
 * Description: 	协议处理函数

 * Input      : 	ph : 协议头指针
 				smac : 以太网头部地址
 				des_type : 以太网帧目的地址类型
 				
 * Output     : 	N/A
 * Return     :	解析成功返回OK,出错返回ERROR
****************************************************************************/
STATUS protocol_handler(PROTOCOL_HDR *ph, ETH_ADDR *smac, DESTINATION_TYPE des_type)
{
	//ME_IPADDR mi;
	//ME_NETMASK mn;
	//ME_GATEWAY mg;

	int ret = OK;

	if (!ph || !smac)
	{
		return ERROR;
	}

	ret = check_hdr_validity(ph,DATALINK_LAYER);
	if (ret != OK)
	{
		DPRINT_ERR("check validity fail!!!\n");
		return ERROR;
	}
	
	switch (ph->type)
	{
	case TYPE_DISCOVERY:	/* 解析设备发现帧，解析无误发送本机配置信息广播帧 */
		if (des_type != DESTINATION_TYPE_BROADCAST)
		{
			ret = ERROR;
			break;
		}
		ret = parse_discovery_frame(ph);
		if (TRUE == ret)
		{
			DPRINT_DBG("send advertisement frame\n");
			send_advertisement_frame();
		}

		ret = OK;

		break;
#if 0		
		
	case TYPE_SET_IP:
		if (des_type != DESTINATION_TYPE_LOCALHOST)
		{
			ret = OK;
			break;
		}
		memset(&mi, 0, sizeof(ME_IPADDR));
		memset(&mn, 0, sizeof(ME_NETMASK));
		memset(&mg, 0, sizeof(ME_GATEWAY));
		ret = parse_set_ip_frame(ph, &mi, &mn, &mg);
		if (ret != OK)
		{
			DPRINT_ERR("parse set ip frame failed\n");
			ret = ERROR;
			
			break;
		}
#endif
		/*to do set gw ip addr*/

		break;
		
	default:
		
		DPRINT_DBG("not support type %d\n", ph->type);
	}
	
	return ret;
}

/****************************************************************************
 * Function   : 	get_local_ipaddr
 * Description: 	获取本机指定网络设备IP地址

 * Input      : 	dev_name : 设备名称
 				ipaddr   : IP地址指针
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS get_local_ipaddr(char *dev_name, char *ipaddr)
{
	int sock;
	struct ifreq ifr_ip;

	if (!dev_name || !ipaddr)
	{
		return ERROR;
	}
	
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
	{
		perror("socket");
		return ERROR;
	}

	memset(&ifr_ip, 0, sizeof(struct ifreq));

	dstrlcpy(ifr_ip.ifr_name, dev_name, sizeof(ifr_ip.ifr_name));

	if (ioctl(sock, SIOCGIFADDR, &ifr_ip) < 0)
	{
		perror("ioctl");
		close(sock);
		return ERROR;
	}

	close(sock);
	
	dstrlcpy(ipaddr, (char*)inet_ntoa(((struct sockaddr_in *)(&ifr_ip.ifr_addr))->sin_addr), STR_IP_LEN);
		
	return OK;
}

/****************************************************************************
 * Function   : 	get_local_netmask
 * Description: 	获取本机指定网络设备子网掩码

 * Input      : 	dev_name : 设备名称
 				netmask  : IP地址指针
 				
 * Output     : 	N/A
 * Return     :	成功返回OK，出错返回ERROR
****************************************************************************/
STATUS get_local_netmask(char *dev_name, char *netmask)
{
	int sock;
	struct ifreq ifr_mask;
	struct sockaddr_in *net_mask;
	
	if (!dev_name || !netmask)
	{
		return ERROR;
	}
	
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
	{
		perror("socket");
		return ERROR;
	}

	memset(&ifr_mask, 0, sizeof(struct ifreq));

	dstrlcpy(ifr_mask.ifr_name, dev_name, sizeof(ifr_mask.ifr_name));

	if (ioctl(sock, SIOCGIFNETMASK, &ifr_mask) < 0)
	{
		perror("ioctl");
		close(sock);
		return ERROR;
	}
	
	close(sock);

	net_mask = (struct sockaddr_in *)&(ifr_mask.ifr_netmask);
	dstrlcpy(netmask, inet_ntoa(net_mask->sin_addr), STR_IP_LEN);
	
	return OK;
}


STATUS get_local_macaddr(char *dev_name, char *mac)
{
	int sock;
	struct ifreq ifr_mac;

	if (!dev_name || !mac)
	{
		return ERROR;
	}
	
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0)
	{
		perror("socket");
		return ERROR;
	}

	memset(&ifr_mac, 0, sizeof(struct ifreq));

	dstrlcpy(ifr_mac.ifr_name, dev_name, sizeof(ifr_mac.ifr_name));

	if (ioctl(sock, SIOCGIFHWADDR, &ifr_mac) < 0)
	{
		perror("ioctl");
		close(sock);
		return ERROR;
	}

	close(sock);

	snprintf(mac, STR_MAC_LEN, "%02x-%02x-%02x-%02x-%02x-%02x",
		(ifr_mac.ifr_hwaddr.sa_data[0] & 0xFF), (ifr_mac.ifr_hwaddr.sa_data[1] & 0xFF),
		(ifr_mac.ifr_hwaddr.sa_data[2] & 0xFF), (ifr_mac.ifr_hwaddr.sa_data[3] & 0xFF),
		(ifr_mac.ifr_hwaddr.sa_data[4] & 0xFF), (ifr_mac.ifr_hwaddr.sa_data[5] & 0xFF));

	return OK;
}

STATUS get_local_ssh_port(unsigned int * port)
{
	char dev_name[DEVNAME_SIZE] = {0};
	if (OK != get_product_name(dev_name))
	{
		return ERROR;
	}
	
	if (0 == strcmp(DEV_NAME_V3_LITE,dev_name))
	{
		*port = 22001;
	}
	else
	{
		*port = 22;
	}
	return OK;
}

unsigned int get_local_ssh_enc_status(void)
{
	int ret = -1;
    char buff[255] = {0};
    char *string = NULL;
	char *string_ = NULL;
	char PasswordAuth[4] = {0};
	char RootPasswordAuth[4] = {0};
	snprintf(buff, sizeof(buff), "uci get dropbear.@dropbear[0].PasswordAuth");
	ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (string)
        {
        	strncpy(PasswordAuth, string, 4);
        	free(string);
        }
    }
	memset(buff,0,255);
	snprintf(buff, sizeof(buff), "uci get dropbear.@dropbear[0].RootPasswordAuth");
	ret = system_reply(buff, &string_);
    if (ret == 0)
    {
        if (string_)
        {
            strncpy(RootPasswordAuth, string_, 4);
        	free(string_);
        }
    }	
	
	if ((0 == strncmp("on",PasswordAuth,strlen("on"))) && (0 == strncmp("on",RootPasswordAuth,strlen("on"))))
	{
		return 0; /*代表用用户名/密码登录*/
	}
	else
	{
		return 1; /*代表使用秘钥登录*/
	}
	
}

STATUS mac_string2mac_hex(char *mac_str, ETH_ADDR *mac_hex)
{
	int tmp[ETH_ALEN] = {0};
	
	int i;
	
	if (!mac_str || !mac_hex)
	{
		return ERROR;
	}
	
	sscanf(mac_str, "%x%*[:-]%x%*[:-]%x%*[:-]%x%*[:-]%x%*[:-]%x", 
		&tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
	
	for (i = 0; i < ETH_ALEN; i++)
	{
		mac_hex->ether_addr_octet[i] = tmp[i];
	}

	return OK;
}


STATUS get_eth_destination_type(ETH_HEADER *eth, DESTINATION_TYPE *type)
{
	ETH_ADDR *dmac_hex = NULL;

	ETH_ADDR smac_hex;
	ETH_ADDR broadcast_hex;
	char smac_str[STR_MAC_LEN] = {0};

	int ret;
	
	if (NULL == eth)
	{
		return ERROR;
	}

	dmac_hex = (ETH_ADDR *)eth->ether_dhost;

	ret = get_local_macaddr(g_wan_ifname, smac_str);
	if (ERROR == ret)
	{
		DPRINT_ERR("get local macaddr failed\n");
		return ERROR;
	}

	mac_string2mac_hex(smac_str, &smac_hex);
	mac_string2mac_hex(BROADCAST_MAC_ADDR, &broadcast_hex);

	if (memcmp(dmac_hex, &smac_hex, ETH_ALEN) == 0)
	{
		*type = DESTINATION_TYPE_LOCALHOST;
	}
	else if (memcmp(dmac_hex, &broadcast_hex, ETH_ALEN) == 0)
	{
		*type = DESTINATION_TYPE_BROADCAST;
	}
	else
	{
		*type = DESTINATION_TYPE_OTHERHOST;
	}

	return OK;
}

STATUS protocol_mac_handler(char *param)
{
	ETH_ADDR *smac_hex = NULL;
	ETH_HEADER *eh = NULL;
	PROTOCOL_HDR * ph = NULL;
	DESTINATION_TYPE des_type;
	
	int ret;

	if (NULL == param)
	{
		return ERROR;
	}
	
	eh = (ETH_HEADER *)param;
	smac_hex = (ETH_ADDR *)eh->ether_shost;
	ph = (PROTOCOL_HDR *)(param + sizeof(ETH_HEADER));

	ret = get_eth_destination_type(eh, &des_type);
	if (ERROR == ret)
	{
		return ERROR;
	}
	
	ret = protocol_handler(ph, smac_hex, des_type);
	if (ret != OK)
	{
		DPRINT_ERR("protocol handler error\n");
	}
	
	return OK;
}




