/**
******************************************************************************
* @file    			dhcp.c                                                       
* @version 			V1.2										  		
* @date    			2017-11-01								 
* @brief 			  自动获取IP函数 	
*
* @company  		深圳炜世科技有限公司
* @information  WIZnet W5500官方代理商，全程技术支持，价格绝对优势！
* @website  		www.wisioe.com																							 	 				
* @forum        www.w5500.cn																								 		
* @qqGroup      383035001																										 
******************************************************************************
*/

#include <stdio.h>
#include <string.h>	
#include "w5500.h"
#include "socket.h"
#include "dhcp.h"
#include "utility.h"
#include "w5500_conf.h"

//#define DHCP_DEBUG
DHCP_Get DHCP_GET;
uint8*   SRC_MAC_ADDR   = EXTERN_DHCP_MAC;				/*本地MAC地址*/
uint8*   GET_SN_MASK    = EXTERN_DHCP_SN;					/*从DHCP服务器获取到的子网掩码*/
uint8*   GET_GW_IP      = EXTERN_DHCP_GW;					/*从DHCP服务器获取到的网关地址*/
uint8*   GET_DNS_IP     = EXTERN_DHCP_DNS;				/*从DHCP服务器获取到的DNS服务器地址*/
uint8*   DHCP_HOST_NAME = EXTERN_DHCP_NAME;   		/*主机名*/
uint8*   GET_SIP        = EXTERN_DHCP_SIP;				/*从DHCP服务器获取到的本机IP*/
uint8    DHCP_SIP[4] = {0,};											/*已发现的DNS服务器地址*/
uint8    DHCP_REAL_SIP[4] = {0,}; 								/*从DHCP列表中选择使用的DHCP服务器*/
uint8    OLD_SIP[4];        											/*最初获取到的IP地址*/

uint8		dhcp_state       = STATE_DHCP_READY;      /*DHCP客户端状态*/
uint8		dhcp_retry_count = 0;                     /*DHCP重试次数*/
uint8		DHCP_timeout     = 0;                     /*DHCP超时标志位*/
uint32  dhcp_lease_time;													/*租约时间*/
uint32	next_dhcp_time   = 0;											/*DHCP超时时间*/
uint32	dhcp_tick_cnt    = 0;                   	  
uint8		DHCP_timer;

uint8 Conflict_flag = 0;
uint32  DHCP_XID        = DEFAULT_XID;				
uint8 EXTERN_DHCPBUF[1024];
RIP_MSG*  pRIPMSG = (RIP_MSG*)EXTERN_DHCPBUF;			/*DHCP消息指针*/

void  send_DHCP_DISCOVER(void);										/*向DHCP服务器发送发现报文*/
void  send_DHCP_REQUEST(void);										/*向DHCP服务器发送请求报文*/
void  send_DHCP_RELEASE_DECLINE(char msgtype);		/*向DHCP服务器发送释放报文*/

void  reset_DHCP_time(void);        							/*初始化DHCP计时器*/
void  DHCP_timer_handler(void);     							/*DHCP计时器*/
void  check_DHCP_Timeout(void);     							/*检查是否超时*/
uint8 check_leasedIP(void);												/*检查获取的IP是否冲突*/
uint8 parseDHCPMSG(uint16 length);								/*从DHCP服务器接收消息并解析*/

/**
*@brief		DHCP定时初始化
*@param		无
*@return	无
*/
void reset_DHCP_time(void)
{
	dhcp_time = 0;
	dhcp_tick_cnt = 0;
	next_dhcp_time = dhcp_time + DHCP_WAIT_TIME;
	dhcp_retry_count = 0;
}

/**
*@brief		发送DISCOVER信息给DHCP服务器
*@param		无
*@return	无
*/
void send_DHCP_DISCOVER(void)
{
	uint8 ip[4] = {255,255,255,255};
	uint16 i=0;
	//the host name modified
	uint8 host_name[12];
	//*((uint32*)DHCP_SIP)=0;
	//*((uint32*)DHCP_REAL_SIP)=0;
	memset((void*)pRIPMSG,0,sizeof(RIP_MSG));				/*清空pRIPMSG的 sizeof(RIP_MSG)	个空间*/
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	pRIPMSG->flags =htons(DHCP_FLAGSBROADCAST);
	pRIPMSG->chaddr[0] = SRC_MAC_ADDR[0];
	pRIPMSG->chaddr[1] = SRC_MAC_ADDR[1];
	pRIPMSG->chaddr[2] = SRC_MAC_ADDR[2];
	pRIPMSG->chaddr[3] = SRC_MAC_ADDR[3];
	pRIPMSG->chaddr[4] = SRC_MAC_ADDR[4];
	pRIPMSG->chaddr[5] = SRC_MAC_ADDR[5];    
	
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8)& 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE& 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = DHCP_DISCOVER;
	
	/*Client identifier*/
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];
	
	// host name
	pRIPMSG->OPT[i++] = hostName;
	// set the host name
	sprintf((char*)host_name,"%.4s-%02X%02X%02X",DEVICE_ID,SRC_MAC_ADDR[3],SRC_MAC_ADDR[4],SRC_MAC_ADDR[5]);
	
	
	pRIPMSG->OPT[i++] = (uint8)strlen((char*)host_name);
	
	strcpy((char*)(&(pRIPMSG->OPT[i])),(char*)host_name);
	
	
	i+=(uint16)strlen((char*)host_name);	
	
	pRIPMSG->OPT[i++] = dhcpParamRequest;
	pRIPMSG->OPT[i++] = 0x06;
	pRIPMSG->OPT[i++] = subnetMask;
	pRIPMSG->OPT[i++] = routersOnSubnet;
	pRIPMSG->OPT[i++] = dns;
	pRIPMSG->OPT[i++] = domainName;
	pRIPMSG->OPT[i++] = dhcpT1value;
	pRIPMSG->OPT[i++] = dhcpT2value;
	pRIPMSG->OPT[i++] = endOption;
	
	/* send broadcasting packet */
	//printf(" send dhcp discover %s\r\n",EXTERN_DHCPBUF);
	//for(uint8 i=0; i<3; i++)
	//Delay_ms(800);
	sendto(SOCK_DHCP, (uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);	
	
	#ifdef DHCP_DEBUG	
	//printf(" sent DHCP_DISCOVER\r\n");
	#endif	
}

/**
*@brief		将请求消息发送到DHCP服务器
*@param		无
*@return	无
*/
void send_DHCP_REQUEST(void)
{
	uint8  ip[4];
	uint16 i = 0;
	//uint16 len=0;
	uint8  host_name[12];
	
	memset((void*)pRIPMSG,0,sizeof(RIP_MSG));
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	
	if(dhcp_state < STATE_DHCP_LEASED)
		pRIPMSG->flags = htons(DHCP_FLAGSBROADCAST);
	else
	{
		pRIPMSG->flags = 0;		// For Unicast
		memcpy(pRIPMSG->ciaddr,GET_SIP,4);
	}		
	
	memcpy(pRIPMSG->chaddr,SRC_MAC_ADDR,6);
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE & 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = DHCP_REQUEST;
	
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];	
	
	if(dhcp_state < STATE_DHCP_LEASED)
	{
		pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
		pRIPMSG->OPT[i++] = 0x04;
		pRIPMSG->OPT[i++] = GET_SIP[0];
		pRIPMSG->OPT[i++] = GET_SIP[1];
		pRIPMSG->OPT[i++] = GET_SIP[2];
		pRIPMSG->OPT[i++] = GET_SIP[3];
		
		pRIPMSG->OPT[i++] = dhcpServerIdentifier;
		pRIPMSG->OPT[i++] = 0x04;
		pRIPMSG->OPT[i++] = DHCP_SIP[0];
		pRIPMSG->OPT[i++] = DHCP_SIP[1];
		pRIPMSG->OPT[i++] = DHCP_SIP[2];
		pRIPMSG->OPT[i++] = DHCP_SIP[3];
	}
	
	// host name
	pRIPMSG->OPT[i++] = hostName;
	//set the host name
	sprintf((char*)host_name,(char*)"%.4s-%02X%02X%02X",DEVICE_ID,SRC_MAC_ADDR[3],SRC_MAC_ADDR[4],SRC_MAC_ADDR[5]);
	pRIPMSG->OPT[i++] = (uint8)strlen((char*)host_name);	
	strcpy((char*)&(pRIPMSG->OPT[i]),(char*)host_name);
	i+=strlen((char*)host_name);
		
	pRIPMSG->OPT[i++] = dhcpParamRequest;
	pRIPMSG->OPT[i++] = 0x08;
	pRIPMSG->OPT[i++] = subnetMask;
	pRIPMSG->OPT[i++] = routersOnSubnet;
	pRIPMSG->OPT[i++] = dns;
	pRIPMSG->OPT[i++] = domainName;
	pRIPMSG->OPT[i++] = dhcpT1value;
	pRIPMSG->OPT[i++] = dhcpT2value;
	pRIPMSG->OPT[i++] = performRouterDiscovery;
	pRIPMSG->OPT[i++] = staticRoute;
	pRIPMSG->OPT[i++] = endOption;
	
	/* send broadcasting packet */
	if(dhcp_state < STATE_DHCP_LEASED) memset(ip,0xFF,4);
	else 
		memcpy(ip,DHCP_SIP,4);
		sendto(SOCK_DHCP, (const uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
	#ifdef DHCP_DEBUG
		//printf(" sent DHCP_REQUEST\r\n");
	#endif
}

/**
*@brief		发送释放消息
*@param		msgtype:是否为7
*@return	无
*/
void send_DHCP_RELEASE_DECLINE(char msgtype)
{
	uint16 i =0;
	uint8  ip[4];
	
	memset((void*)pRIPMSG,0,sizeof(RIP_MSG));
	
	pRIPMSG->op = DHCP_BOOTREQUEST;
	pRIPMSG->htype = DHCP_HTYPE10MB;
	pRIPMSG->hlen = DHCP_HLENETHERNET;
	pRIPMSG->hops = DHCP_HOPS;
	pRIPMSG->xid = htonl(DHCP_XID);
	pRIPMSG->secs = htons(DHCP_SECS);
	pRIPMSG->flags =0;// DHCP_FLAGSBROADCAST;
	
	memcpy(pRIPMSG->chaddr,SRC_MAC_ADDR,6);
	
	/* MAGIC_COOKIE */
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 24) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 16) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)((MAGIC_COOKIE >> 8) & 0xFF);
	pRIPMSG->OPT[i++] = (uint8)(MAGIC_COOKIE & 0xFF);
	
	/* Option Request Param. */
	pRIPMSG->OPT[i++] = dhcpMessageType;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = ((!msgtype) ? DHCP_RELEASE : DHCP_DECLINE);
	
	pRIPMSG->OPT[i++] = dhcpClientIdentifier;
	pRIPMSG->OPT[i++] = 0x07;
	pRIPMSG->OPT[i++] = 0x01;
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[0];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[1];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[2];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[3];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[4];
	pRIPMSG->OPT[i++] = SRC_MAC_ADDR[5];	
	
	pRIPMSG->OPT[i++] = dhcpServerIdentifier;
	pRIPMSG->OPT[i++] = 0x04;
	pRIPMSG->OPT[i++] = DHCP_SIP[0];
	pRIPMSG->OPT[i++] = DHCP_SIP[1];
	pRIPMSG->OPT[i++] = DHCP_SIP[2];
	pRIPMSG->OPT[i++] = DHCP_SIP[3];
	
	if(msgtype)
	{
	pRIPMSG->OPT[i++] = dhcpRequestedIPaddr;
	pRIPMSG->OPT[i++] = 0x04;
	pRIPMSG->OPT[i++] = GET_SIP[0];
	pRIPMSG->OPT[i++] = GET_SIP[1];
	pRIPMSG->OPT[i++] = GET_SIP[2];
	pRIPMSG->OPT[i++] = GET_SIP[3];		
	#ifdef DHCP_DEBUG		
	//printf(" sent DHCP_DECLINE\r\n");
	#endif		
	}
	#ifdef DHCP_DEBUG	
	else
	{
	printf(" sent DHCP_RELEASE\r\n");
	}
	#endif	
	
	pRIPMSG->OPT[i++] = endOption;	
	
	
	if(msgtype) memset(ip,0xFF,4);
	else 
	memcpy(ip,DHCP_SIP,4);
	// printf(" send dhcp decline\r\n");
	sendto(SOCK_DHCP, (uint8 *)pRIPMSG, sizeof(RIP_MSG), ip, DHCP_SERVER_PORT);
}

/**	 
*@brief	 	解析获得的DHCP消息
*@param		length:解析消息长度
*@return	0：解析失败  其他：解析成功
*/
uint8 parseDHCPMSG(uint16 length)
{
	uint8  svr_addr[6];
	uint16 svr_port;
	uint16 len;
	uint8  * p;
	uint8  * e;
	uint8  type;
	uint8  opt_len = 0;
	
	len = recvfrom(SOCK_DHCP, (uint8 *)pRIPMSG, length, svr_addr, &svr_port);
	
	#ifdef DHCP_DEBUG
		printf(" DHCP_SIP:%u.%u.%u.%u\r\n",DHCP_SIP[0],DHCP_SIP[1],DHCP_SIP[2],DHCP_SIP[3]);
		printf(" DHCP_RIP:%u.%u.%u.%u\r\n",DHCP_REAL_SIP[0],DHCP_REAL_SIP[1],DHCP_REAL_SIP[2],DHCP_REAL_SIP[3]);
		printf(" svr_addr:%u.%u.%u.%u\r\n",svr_addr[0],svr_addr[1],svr_addr[2],svr_addr[3]);
	#endif	
	
	if(pRIPMSG->op != DHCP_BOOTREPLY || svr_port != DHCP_SERVER_PORT)
	{
		#ifdef DHCP_DEBUG	   
		printf(" DHCP : NO DHCP MSG\r\n");
		#endif		
		return 0;
	}
	if(memcmp(pRIPMSG->chaddr,SRC_MAC_ADDR,6) != 0 || pRIPMSG->xid != htonl(DHCP_XID))
	{
		#ifdef DHCP_DEBUG
		printf(" No My DHCP Message. This message is ignored.\r\n");
		printf(" \tSRC_MAC_ADDR(%02X.%02X.%02X.",SRC_MAC_ADDR[0],SRC_MAC_ADDR[1],SRC_MAC_ADDR[2]);
		printf(" %02X.%02X.%02X)",SRC_MAC_ADDR[3],SRC_MAC_ADDR[4],SRC_MAC_ADDR[5]);
		printf(" , pRIPMSG->chaddr(%02X.%02X.%02X.",(char)pRIPMSG->chaddr[0],(char)pRIPMSG->chaddr[1],(char)pRIPMSG->chaddr[2]);
		printf(" %02X.%02X.%02X)",pRIPMSG->chaddr[3],pRIPMSG->chaddr[4],pRIPMSG->chaddr[5]);
		printf(" \tpRIPMSG->xid(%08X), DHCP_XID(%08X)",pRIPMSG->xid,(DHCP_XID));
		printf(" \tpRIMPMSG->yiaddr:%d.%d.%d.%d\r\n",pRIPMSG->yiaddr[0],pRIPMSG->yiaddr[1],pRIPMSG->yiaddr[2],pRIPMSG->yiaddr[3]);
		#endif				
		return 0;
	}
	
	if( *((uint32*)DHCP_SIP) != 0x00000000 )
	{
		if( *((uint32*)DHCP_REAL_SIP) != *((uint32*)svr_addr) && 
		*((uint32*)DHCP_SIP) != *((uint32*)svr_addr) ) 
		{
			#ifdef DHCP_DEBUG		
			printf(" Another DHCP sever send a response message. This is ignored.\r\n");
			printf(" \tIP:%u.%u.%u.%u\r\n",svr_addr[0],svr_addr[1],svr_addr[2],svr_addr[3]);
			#endif				
			return 0;								
		}
	}	
	memcpy(GET_SIP,pRIPMSG->yiaddr,4);
	
	#ifdef DHCP_DEBUG	
	printf(" DHCP MSG received\r\n");
	printf(" yiaddr : %u.%u.%u.%u\r\n",GET_SIP[0],GET_SIP[1],GET_SIP[2],GET_SIP[3]);
	#endif	
	type = 0;
	p = (uint8 *)(&pRIPMSG->op);
	p = p + 240;
	e = p + (len - 240);
	#ifdef DHCP_DEBUG
	printf(" p : %08X  e : %08X  len : %d\r\n", (uint32)p, (uint32)e, len);
	#endif
	while ( p < e ) 
	{
		switch ( *p++ ) 
		{
			case endOption :
				return type;
		
			case padOption :
				break;
			
			case dhcpMessageType :
				opt_len = *p++;
				type = *p;
				#ifdef DHCP_DEBUG			
				printf(" dhcpMessageType : %02X\r\n", type);
				#endif			
				break;
			
			case subnetMask :
				opt_len =* p++;
				memcpy(GET_SN_MASK,p,4);
				#ifdef DHCP_DEBUG
				printf(" subnetMask : ");
				printf(" %u.%u.%u.%u\r\n",GET_SN_MASK[0],GET_SN_MASK[1],GET_SN_MASK[2],GET_SN_MASK[3]);
				#endif			
				break;
			
			case routersOnSubnet :
				opt_len = *p++;
				memcpy(GET_GW_IP,p,4);
				#ifdef DHCP_DEBUG
				printf(" routersOnSubnet : ");
				printf(" %u.%u.%u.%u\r\n",GET_GW_IP[0],GET_GW_IP[1],GET_GW_IP[2],GET_GW_IP[3]);
				#endif			
				break;
			
			case dns :
				opt_len = *p++;
				memcpy(GET_DNS_IP,p,4);
				break;
			
			case dhcpIPaddrLeaseTime :
				opt_len = *p++;
				dhcp_lease_time = ntohl(*((uint32*)p));
				#ifdef DHCP_DEBUG			
				printf(" dhcpIPaddrLeaseTime : %d\r\n", dhcp_lease_time);
				#endif			
				break;
			
			case dhcpServerIdentifier :
				opt_len = *p++;
				#ifdef DHCP_DEBUG						
				printf(" DHCP_SIP : %u.%u.%u.%u\r\n", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
				#endif			
				if( *((uint32*)DHCP_SIP) == 0 || 
				*((uint32*)DHCP_REAL_SIP) == *((uint32*)svr_addr) || 
				*((uint32*)DHCP_SIP) == *((uint32*)svr_addr) )
				{
					memcpy(DHCP_SIP,p,4);
					memcpy(DHCP_REAL_SIP,svr_addr,4);	// Copy the real ip address of my DHCP server
					#ifdef DHCP_DEBUG						
					printf(" My dhcpServerIdentifier : ");
					printf(" %u.%u.%u.%u\r\n", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
					printf(" My DHCP server real IP address : ");
					printf(" %u.%u.%u.%u\r\n", DHCP_REAL_SIP[0], DHCP_REAL_SIP[1], DHCP_REAL_SIP[2], DHCP_REAL_SIP[3]);
					#endif						
				}
				else
				{
				#ifdef DHCP_DEBUG			   
				printf(" Another dhcpServerIdentifier : \r\n");
				printf(" \tMY(%u.%u.%u.%u) ", DHCP_SIP[0], DHCP_SIP[1], DHCP_SIP[2], DHCP_SIP[3]);
				printf(" Another(%u.%u.%u.%u)\r\n", svr_addr[0], svr_addr[1], svr_addr[2], svr_addr[3]);
				#endif				
				}
				break;
				
			default :
				opt_len = *p++;
				#ifdef DHCP_DEBUG			
				printf(" opt_len : %u\r\n", opt_len);
				#endif			
				break;
		} // switch
		p+=opt_len;
	} // while	
	return 0;
}

/**	
*@brief	 	检查DHCP状态
*@param		s: socket数
*@return	返回得到的DHCP状态
*					DHCP_RET_NONE: 未获取到IP地址
*					DHCP_RET_TIMEOUT:超时
*					DHCP_RET_UPDATE: 获取成功
*					DHCP_RET_CONFLICT:IP地址冲突
*/
uint8 check_DHCP_state(SOCKET s) 
{
	uint16 len;   																			/*定义一个表示接收数据大小变量*/
	uint8  type;																				/*定义一个表示接收封包类型变量*/
	
	type = 0;
	if(getSn_SR(s)!=SOCK_CLOSED)                        /*socket处于打开状态*/
	{
		if ((len = getSn_RX_RSR(s)) > 0)									/*接收到数据*/
		{
			type = parseDHCPMSG(len);												/*解析收到的封包类型*/
		}
	}
	else																								/*socket处于关闭状态，重新初始化socket*/
	{
		if(dhcp_state == STATE_DHCP_READY)
		{
			//init_dhcp_client();
			#ifdef DHCP_DEBUG			
			printf(" state : STATE_DHCP_READY\r\n");
			#endif	   	
		}	
		if(!socket(SOCK_DHCP,Sn_MR_UDP,DHCP_CLIENT_PORT,0x00))/*初始化socket和端口*/
		{
			#ifdef DHCP_DEBUG	   
			printf(" Fail to create the DHCPC_SOCK(%u)\r\n",SOCK_DHCP);
			#endif   
			return DHCP_RET_ERR;														/*socket初始化错误*/
		}
	}
	switch ( dhcp_state )
	{
		case STATE_DHCP_READY:													  /*DHCP初始化状态*/
			DHCP_timeout = 0;																/*DHCP超时标志设置为1*/
			reset_DHCP_time();															/*复位超时时间*/
			send_DHCP_DISCOVER();														/*发送DISCOVER包*/
	
			DHCP_timer = 0;																	/*set_timer0(DHCP_timer_handler);  */ 	
			dhcp_state = STATE_DHCP_DISCOVER;								/*DHCP的DISCOVER状态*/
			break;	 
  
		case STATE_DHCP_DISCOVER:
			if (type == DHCP_OFFER) 
			{
				reset_DHCP_time();														/*复位超时时间*/
				send_DHCP_REQUEST();													/*发送REQUEST包*/
				dhcp_state = STATE_DHCP_REQUEST;
				#ifdef DHCP_DEBUG			
				printf(" state : STATE_DHCP_REQUEST\r\n");
				#endif			
			}
			else 
				check_DHCP_Timeout();													/*检查是否超时*/
			break;
		
		case STATE_DHCP_REQUEST :													/*DHCP的REQUEST状态*/
			if (type == DHCP_ACK) 													/*接收到DHCP服务器回应的off封包*/
			{
				reset_DHCP_time();
				if (check_leasedIP()) 
				{
					#ifdef DHCP_DEBUG					
					printf(" state : STATE_DHCP_LEASED\r\n");
					#endif		
					dhcp_state = STATE_DHCP_LEASED;
					return DHCP_RET_UPDATE;
				} 
				else 
				{
					#ifdef DHCP_DEBUG					
					printf(" state : STATE_DHCP_DISCOVER\r\n");
					#endif				
					dhcp_state = STATE_DHCP_DISCOVER;
					return DHCP_RET_CONFLICT;
				}
			}	
			else if (type == DHCP_NAK) 
			{
				reset_DHCP_time();														/*复位超时时间*/
				dhcp_state = STATE_DHCP_DISCOVER;
				#ifdef DHCP_DEBUG				
				printf(" state : STATE_DHCP_DISCOVER\r\n");
				#endif			
			}
			else 
				check_DHCP_Timeout();													/*检查是否超时*/
			break;
			
		case STATE_DHCP_LEASED :
			if ((dhcp_lease_time != 0xffffffff) && (dhcp_time>(dhcp_lease_time/2))) 
			{
				type = 0;
				memcpy(OLD_SIP,GET_SIP,4);
				DHCP_XID++;
				send_DHCP_REQUEST();
				dhcp_state = STATE_DHCP_REREQUEST;
				#ifdef DHCP_DEBUG
				printf(" state : STATE_DHCP_REREQUEST\r\n");
				#endif
				reset_DHCP_time();
			}
			break;
		case STATE_DHCP_REREQUEST :
			if (type == DHCP_ACK) 
			{
				if(memcmp(OLD_SIP,GET_SIP,4)!=0)	
				{
					#ifdef DHCP_DEBUG
					printf(" The IP address from the DHCP server is updated.\r\n");
					printf(" OLD_SIP=%u.%u.%u.%u",OLD_SIP[0],OLD_SIP[1],OLD_SIP[2],OLD_SIP[3]);
					printf(" GET_SIP=%u.%u.%u.%u\r\n",GET_SIP[0],GET_SIP[1],GET_SIP[2],GET_SIP[3]);
					#endif
					return DHCP_RET_UPDATE;
				}
				#ifdef DHCP_DEBUG
				else
				{
					printf(" state : STATE_DHCP_LEASED : same IP\r\n");
				}
				#endif
				reset_DHCP_time();
				dhcp_state = STATE_DHCP_LEASED;
			} 
			else if (type == DHCP_NAK) 
			{
				reset_DHCP_time();
				dhcp_state = STATE_DHCP_DISCOVER;
				#ifdef DHCP_DEBUG
				printf(" state : STATE_DHCP_DISCOVER\r\n");
				#endif
			} 
			else 
				check_DHCP_Timeout();
			break;
			
			default :
				dhcp_state = STATE_DHCP_READY;
				break;
	}
	if (DHCP_timeout == 1)
	{
		//kill_timer0(DHCP_timer);
		dhcp_state = STATE_DHCP_READY;
		return DHCP_RET_TIMEOUT;
	}
	return DHCP_RET_NONE;
}

/**	
*@brief	 	检查DHCP请求释放超时
*@param		无
*@return	无
*/
void check_DHCP_Timeout(void)
{
	if(dhcp_retry_count < MAX_DHCP_RETRY) 
	{
		if(dhcp_time > next_dhcp_time) 
		{
			dhcp_time = 0;
			next_dhcp_time = dhcp_time + DHCP_WAIT_TIME;
			dhcp_retry_count++;
			switch ( dhcp_state ) 
			{
				case STATE_DHCP_DISCOVER :
					#ifdef DHCP_DEBUG			   
					printf(" <<timeout>> state : STATE_DHCP_DISCOVER\r\n");
					#endif				
					send_DHCP_DISCOVER();
					break;
				
				case STATE_DHCP_REQUEST :
					#ifdef DHCP_DEBUG			   
					printf(" <<timeout>> state : STATE_DHCP_REQUEST\r\n");
					#endif				
					send_DHCP_REQUEST();
					break;		
				
				case STATE_DHCP_REREQUEST :
					#ifdef DHCP_DEBUG			   
					printf(" <<timeout>> state : STATE_DHCP_REREQUEST\r\n");
					#endif				
					send_DHCP_REQUEST();
					break;
				
				default :
					break;
			}
		}
	} 
	else 
	{
		reset_DHCP_time();
		DHCP_timeout = 1;
	
		send_DHCP_DISCOVER();
		dhcp_state = STATE_DHCP_DISCOVER;
		#ifdef DHCP_DEBUG		
		printf(" timeout : state : STATE_DHCP_DISCOVER\r\n");
		#endif		
	}
}

/**	
*@brief	  检查获取的IP是否冲突
*@param		无
*@return	无
*/
uint8 check_leasedIP(void)
{
	#ifdef DHCP_DEBUG
		printf(" <Check the IP Conflict %d.%d.%d.%d: ",GET_SIP[0],GET_SIP[1],GET_SIP[2],GET_SIP[3]);
	#endif
	// sendto is complete. that means there is a node which has a same IP.

	if ( sendto(SOCK_DHCP, (const uint8*)"CHECK_IP_CONFLICT", 17, GET_SIP, 5000))
	{
		#ifdef DHCP_DEBUG
		printf(" Conflict>\r\n");
		#endif
		send_DHCP_RELEASE_DECLINE(1);
		return 0;
	}
	#ifdef DHCP_DEBUG
		printf(" No Conflict>\r\n");
	#endif
	return 1;
}
	
/**	
*@brief	 	DHCP 定时器操作
*@param		无
*@return	无
*/
void DHCP_timer_handler(void)
{
	if(dhcp_tick_cnt++ > 1000)
	{
		dhcp_tick_cnt = 0;
		dhcp_time++;
	}
}

/**		 
*@brief	  初始化DHCP客户端
*@param		无
*@return	无
*/
void init_dhcp_client(void)
{
	uint8 ip_0[4]={0,};
	DHCP_XID = 0x12345678;
	memset(OLD_SIP,0,sizeof(OLD_SIP));
	memset(DHCP_SIP,0,sizeof(DHCP_SIP));
	memset(DHCP_REAL_SIP,0,sizeof(GET_SN_MASK));
	
	/*clear ip setted flag */
	iinchip_init();
	setSUBR(ip_0);
	setGAR(ip_0);
	setSIPR(ip_0);
	printf(" mac=%02x:%02x:%02x:%02x:%02x:%02x\r\n",SRC_MAC_ADDR[0],SRC_MAC_ADDR[1],SRC_MAC_ADDR[2],SRC_MAC_ADDR[3],SRC_MAC_ADDR[4],SRC_MAC_ADDR[5]);  
	
	dhcp_state = STATE_DHCP_READY;
	#ifdef DHCP_DEBUG
	printf(" init_dhcp_client:%u\r\n",SOCK_DHCP);
	#endif   
}
/**	
*@brief	 	执行DHCP Client
*@param		无
*@return	无
*/
void do_dhcp(void)
{
	uint8 dhcpret=0;
	ip_from=IP_FROM_DHCP;	                             /*IP配置方法选择为DHCP*/
	dhcp_timer_init();																 /*初始化DHCP定时器*/
	if(Conflict_flag == 1)
	{
		init_dhcp_client();				                       /*初始化DHCP客户端*/ 
		Conflict_flag =0;
	}
	
	dhcpret = check_DHCP_state(SOCK_DHCP);             /*获取DHCP服务状态*/
	
	switch(dhcpret)
	{
		case DHCP_RET_NONE:                              /*IP地址获取不成功*/ 
			break;
		
		case DHCP_RET_TIMEOUT:                           /*IP地址获取超时*/ 
			break;
		
		case DHCP_RET_UPDATE:                            /*成功获取到IP地址*/ 
			dhcp_ok=1; 
		  set_w5500_ip();                                /*将获取到的IP地址写入W5500寄存器*/ 
			printf(" 已从DHCP服务器成功获得IP地址\r\n");
		  
	    break;
		
		case DHCP_RET_CONFLICT:                          /*IP地址获取冲突*/ 
			printf(" 从DHCP获取IP地址失败\r\n");
      dhcp_state = STATE_DHCP_READY; 
      printf(" 重试中\r\n");
      dhcp_ok=0; 
			break;     

		default:
			break;
	}
}
