#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <signal.h>
#include <sys/ioctl.h>
//#include <net/if.h>
//#include <linux/wireless.h>
#include <dirent.h>
#include <string.h>


#include "md5.h"
#include "dhcp_plus.h"

DeviceScript *dConfig;
char resetDns, resetDomain;  //kony modify temporarily extern char resetDns, resetDomain;
//要发送或接收的数据包
pls_crypt_packet send_pkt, receive_pkt;
//加密前的明文或解密后的明文
//struct uncrypt uncrypt_send, uncrypt_receive;
pls_uncrypt_packet uncrypt_send, uncrypt_receive;
sub_option *ptr_opt;

static unsigned short rport;
static unsigned long cver;
static unsigned long lip, rip, wanip;
static unsigned long sip1, sip2, sip3, sip;
static unsigned char send_seq;
unsigned char pls_sts;
static unsigned char pls_retries;
static unsigned char pls_wait_time;
static unsigned char pls_max_timeout;
static unsigned char renewflag;
unsigned int renew_time, keepalive_time, online_time, cnt_keepalive;
int udp_fd;
int recv_len;
struct sockaddr_in laddr, raddr, baddr; 
static unsigned short bport;
struct timeval time_out;
fd_set readfds;
int max_fd = 0;
int select_result;

typedef enum { IP_ADDR, SUBNET_MASK, DEFAULT_GATEWAY, HW_ADDR } ADDR_T;
static unsigned char init_digest[16]={0xef,0x2b,0x13,0xc2,0x07,0xda,0x86,0x54,0x1d,0xb8,0x0d,0x61,0x65,0xc7,0x25,0xf4};
static unsigned char md5digest[16];
static unsigned char temp_key[16];
static unsigned char pls_username[32+1];
static unsigned char pls_pwd[32+1];
static unsigned long tmp_ip;
static unsigned short tmp_port;
//char tmp[36]="ererwerew";
//char tmp1[36]="ererwerew333";
//dConfig->pls_username=tmp;
//dConfig->pls_password=tmp1;
void DoReleaseDHCPC(); //kony add temporarily
void DoStartDHCPC(int flag);//kony add temporarily
/*
int main(int argc,char *argv[])
{
printf("\r\n666666yu\r\n");
printf("\r\nargv[1]=%s\r\n",argv[1]);
sleep(3);
//printf("\r\ndconfig=%s\r\n",dConfig->pls_username);
//struct dConfig *tempPtr=malloc(sizeof(struct dConfig));
//strcpy(pls_username,argv[1]);
//strcpy(pls_pwd,argv[2]);
//strcpy( dConfig->pls_username,argv[1]);
//strcpy( dConfig->pls_password,argv[2]);
printf("\r\n88888\r\n");
//dConfig->pls_username=argv[1];
//dConfig->pls_password=argv[2];
DhcpPls_Status_Machine();
DoDhcpPls(0);
while(1)
{
DhcpPls_Status_Machine();
sleep (60);
}
return 0;
}
*/


//unsigned char encrypt_pwd(unsigned char *passwd, unsigned char *ip, unsigned short port)
unsigned char encrypt_pwd(unsigned char *passwd, unsigned short port)
{
	char orig_str[80], i;
	unsigned char digest[16], pwd[40], ip[4];
	unsigned char len;
	MD5_CONTEXT context;
	memcpy(ip, (unsigned char*)&lip, 4);
#ifdef	FOR_TEST
	//sprintf(orig_str, "10.160.128.197:2056:enus");
	sprintf(orig_str, "10.160.128.203:1049:enus");
#else
	sprintf(orig_str, "%d.%d.%d.%d:%d:enus", *ip, *(ip+1), *(ip+2), *(ip+3), port);
#endif
	DBG_PRINTF("key_str=%s, lip=0x%08x, ", orig_str, lip);
	len = strlen(orig_str);
	MD5Init (&context);
	MD5Update (&context, orig_str, len);
	MD5Final (digest, &context);
	
	memset(pwd, 0, sizeof(pwd));
	len = strlen(passwd);
	DBG_PRINTF("\r\nencrypt_pwd()--len=%d,password=%s\r\n",len,passwd);
	if( len > 32)
	{
		DBG_PRINTF("password over 32bytes!\n");
		strncpy(pwd, passwd, 32);
		len = 32;
	}
	else
		strncpy(pwd, passwd, len);
	if( len%8 )
	{
		for( i=len%8; i < 8; i++)
		{
			pwd[len++] = 0x30;
		}
	}
	DBG_PRINTF("pwd_str=%s, len=%d, lip=0x%08x\n", pwd, len, lip);
	en_DES(digest, pwd, len); 
	memcpy(passwd, pwd, len);
	printb("en_pwd", pwd, len);
	DBG_PRINTF("\r\nencrypt_pwd()-YY-len=%d,password=%s\r\n",len,passwd);
	DBG_PRINTF("lip=0x%08x ", lip);
	return len;
}
	
void SetSocketAddr(struct sockaddr_in *ptr_addr, unsigned int ip, unsigned short port)
{
	//memset(ptr_addr, 0, sizeof(struct sockaddr_in));
	ptr_addr->sin_family = AF_INET;
	ptr_addr->sin_port = port;//htons(port);
	ptr_addr->sin_addr.s_addr = ip;
	memset(ptr_addr->sin_zero, 0, sizeof(ptr_addr->sin_zero));
}
int InitUdp()
{
	if( (udp_fd = socket(AF_INET, SOCK_DGRAM, 0)) <0)
	{
		printf("Create Socket error\n");
		return -1;
	}
    fcntl(udp_fd,F_SETFL,(fcntl(udp_fd,F_GETFL)|O_NONBLOCK));
	return 0;
}
void InitVar()
{
#ifdef	FOR_TEST
	//sprintf(pls_username, "ZZA13000279");
	//sprintf(pls_pwd, "65030521");
	sprintf(pls_username, "HBA19001602");
	sprintf(pls_pwd, "123456");
#else
	//char *tmpconfig="tyttyt";
//strncpy( dConfig->pls_username,tmpconfig,5);
	//dConfig->pls_username=tmpconfig;
	//sprintf(pls_username, "HBA19001602");
	//sprintf(pls_pwd, "123456");
	//strncpy(pls_username, dConfig->pls_username, 32);
	//strncpy(pls_pwd, dConfig->pls_password, 32);
	//strncpy(pls_username, argv[1], 32);
	//strncpy(pls_pwd, argv[2], 32);
#endif
	DBG_PRINTF("\r\nusername=%s,password=%s\r\n",pls_username,pls_pwd);
	rip = htonl(REMOTE_IP);
	rport = htons(REMOTE_PORT);
	cver = htonl(CLIENT_VER);
	sip1 = 0;
	sip2 = 0;
	sip3 = 0;
	send_seq = 1;
	//pls_sts = STS_GET_IP;
	pls_retries = 0;
	pls_wait_time = 0;
	time_out.tv_sec = 0;
	time_out.tv_usec = 0;
	FD_ZERO (&readfds);
	max_fd = 0;
	if( udp_fd > 0)
	{
		close(udp_fd);
		udp_fd = 0;
	}
}
void giveName(char *tempName,char *tempPwd)
{
sprintf(pls_username, tempName);
sprintf(pls_pwd, tempPwd);
}
int CreateSock(unsigned char ReCreate)
{
	if( udp_fd != 0)
	{
		if( ReCreate != PLS_TRUE)
			return PLS_SUCCESS;
		close(udp_fd);
		udp_fd = 0;
	}
	udp_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	if(udp_fd <= 0)
	{
		DBG_PRINTF("CreateSock error\n");
		return PLS_FAIL;
	}
#if	1
        baddr.sin_family=AF_INET; 
        baddr.sin_addr.s_addr=htonl(INADDR_ANY);
		if( bport < 1000)
			bport = 1000;
        baddr.sin_port=htons(++bport); 
		while(bind(udp_fd,(struct sockaddr *)&baddr,sizeof(struct sockaddr_in))<0) 
		{
			DBG_PRINTF("Bind udp_fd at port %d error ",bport);
			baddr.sin_port=htons(++bport); 
        } 
		DBG_PRINTF("Bind udp_fd at port %d Ok ",bport);
#endif
	max_fd = udp_fd;
	FD_ZERO (&readfds);
    fcntl(udp_fd,F_SETFL,(fcntl(udp_fd,F_GETFL)|O_NONBLOCK));
	return PLS_SUCCESS;
}

void SendHangupReq(void)
{
	if( CreateSock(1) != PLS_SUCCESS)
		return ;
	MakeHangupPkt(pls_username);
	raddr.sin_addr.s_addr = sip1;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	pls_wait_time = 0;
	DBG_PRINTF("Send Hang up Request\n");
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
	//SendPktto(udp_fd, &raddr, (unsigned char*)&send_pkt);
	pls_sts = STS_HANGUP_ACK;
	FD_SET (udp_fd, &readfds );
}
void SendReq(void)
{
	pls_wait_time = 0;
	pls_max_timeout = MAX_WAIT_TIME;
	MakeRequstPkt();
	raddr.sin_addr.s_addr = rip;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	pls_wait_time = 0;
	DBG_PRINTF("Send Request\n");
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
	//SendPktto(udp_fd, &raddr, (unsigned char*)&send_pkt);
	pls_sts = STS_REQ_ACK;
	FD_SET (udp_fd, &readfds );
}

int GetWanIp(void)
{	
    struct ifreq ifr;	
	char ifname[]="eth1";
	unsigned long int tempip;
	char *if_addr;
    int skfd = 0;	
    if((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
    {		
        printf("getIfIp: open socket error\n");		
        return -1;	
    }	
    strncpy(ifr.ifr_name, ifname, 16);	
    if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) 
    {		
        close(skfd);		
        printf("getwanip error!\n");
        return -1;	
    }	
    strcpy(if_addr, inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));	
    printf("tempip:%s\n",if_addr);
    tempip=inet_addr(if_addr);//将点分式IP地址转换成无符号长整型
    printf("tempip:%lu\n",tempip);
    close(skfd);	
    return tempip;
}//add end



int getInAddr( char *interface, ADDR_T type, void *pAddr )
{
    struct ifreq ifr;
    int skfd, found=0;
    struct sockaddr_in *addr;

    skfd = socket(AF_INET, SOCK_DGRAM, 0);

    strcpy(ifr.ifr_name, interface);
    if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0)
	return (0);

    if (type == HW_ADDR) {
    	if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) {
		memcpy(pAddr, &ifr.ifr_hwaddr, sizeof(struct sockaddr));
		found = 1;
	}
    }
    else if (type == IP_ADDR) {
	if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
		addr = ((struct sockaddr_in *)&ifr.ifr_addr);
		*((struct in_addr *)pAddr) = *((struct in_addr *)&addr->sin_addr);
		found = 1;
	}
    }
    else if (type == SUBNET_MASK) {
	if (ioctl(skfd, SIOCGIFNETMASK, &ifr) >= 0) {
		addr = ((struct sockaddr_in *)&ifr.ifr_addr);
		*((struct in_addr *)pAddr) = *((struct in_addr *)&addr->sin_addr);
		found = 1;
	}
    }
    close( skfd );
    return found;

}
int GetServerIp(void)
{
#ifdef	FOR_TEST
	return htonl(0xdb58101d);
#else
	//return DBgetSysDefaultRouters();
	return htonl(0xdb58101d);
#endif
}
int CheckGetWanIp(void)
{
	wanip = GetWanIp();
	if(wanip!=-1)
	{
		lip = wanip;
		DBG_PRINTF("GetWanIP OK, wanip=0x%08x\n", wanip);
		sip = GetServerIp();
		DBG_PRINTF("\r\nsip=%08x",sip);
		if( CreateSock(1) != PLS_SUCCESS)
			return PLS_FAIL;
		pls_retries = 0;
		SendReq();
		return PLS_SUCCESS;
	}
	return PLS_FAIL;
}
void SendKeepAlive(unsigned char flag)
{
	if( flag == 1)
		 CreateSock(1);
	else
		 CreateSock(0);
	MakeSecAuthPkt(pls_username);
	raddr.sin_addr.s_addr = sip1;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	pls_wait_time = 0;
	DBG_PRINTF("Send Keep Alive Packet\n");
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
	//SendPktto(udp_fd, &raddr, (unsigned char*)&send_pkt);
	pls_sts = STS_KEEPALIVE_REPLY;
	FD_SET (udp_fd, &readfds );
}

void CheckSecGetWanIp()
{
	wanip = GetWanIp();
	if(wanip)
	{
		lip = wanip;
		DBG_PRINTF("Second GetWanIP OK, wanip=0x%08x\n", wanip);
		pls_sts = STS_CONNECTED;
		cnt_keepalive = 0;
		pls_max_timeout = MAX_WAIT_TIME;
		SendKeepAlive(1);
	}
}
void SendUsernameAuth()
{
	if( CreateSock(1) != PLS_SUCCESS)
	{
		DBG_PRINTF("SendUsernameAuth error\n");
		return;
	} 
	MakeAuthUserPkt(pls_username);
	DBG_PRINTF("sip1=0x%08x, rip=0x%08x\n", sip1, rip);
	printf("\r\nusername=%s,password=%s",pls_username,pls_pwd);
	raddr.sin_addr.s_addr = sip1;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	DBG_PRINTF("Send Username Auth\n");
	pls_wait_time = 0;
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
//	SendPktto(udp_fd, &raddr, (unsigned char*)&send_pkt);
	pls_sts = STS_AUTH_USER_ACK;
	FD_SET (udp_fd, &readfds );
}
void SendPwdAuth()
{
	if( CreateSock(0) != PLS_SUCCESS)
	{
		DBG_PRINTF("SendPwdAuth() error\n");
		return ;
	}
	MakeAuthPwdPkt(pls_username, pls_pwd);
	raddr.sin_addr.s_addr = sip1;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	pls_wait_time = 0;
	DBG_PRINTF("Send Password Auth\n");
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
//	SendPktto(udp_fd, &raddr, (unsigned char*)&send_pkt);
	pls_sts = STS_AUTH_PWD_ACK;
	FD_SET (udp_fd, &readfds );
}
void SendHangupAck()
{
	CreateSock(0);
	MakeHangupAckPkt();
	raddr.sin_addr.s_addr = sip1;
	raddr.sin_port = rport;
	raddr.sin_family = AF_INET;
	pls_wait_time = 0;
	DBG_PRINTF("Send Hangup Ack\n");
	sendto(udp_fd, (unsigned char*)&send_pkt, ntohs(send_pkt.hdr.data_len)+sizeof(pls_header), 0, (struct sockaddr*)&raddr, sizeof(struct sockaddr_in));
}

int CheckReqAck()
{
	unsigned char i, *ptr;
	//DBG_PRINTF("Recieve Request Ack ");
	if(uncrypt_receive.hdr.cmd != CMD_REQ_ACK)
	{
		//DBG_PRINTF("Drop\n");
		return PLS_FAIL;
	}
	
	DBG_PRINTF("\r\ncmd Ok=%d\r\n",uncrypt_receive.hdr.cmd);
	//printb("uncrypt_receive.data", uncrypt_receive.data, uncrypt_receive.hdr.data_len);
	for( ptr = uncrypt_receive.data; ptr < uncrypt_receive.data+uncrypt_receive.hdr.data_len; )
	{
		printf("\r\n*ptr=%0x\r\n",*ptr);
		if( *ptr == OPT_AUTH_SIP)
		{
			printf("\r\nhave *ptr=OPT_AUTH_SIP?\r\n");
			if( *(ptr+1) == 0xc)
			{
				memcpy(&sip1, ptr+2, 4);
				//sip1 = ntohl(sip1);
				memcpy(&sip2, ptr+6, 4);
				//sip2 = ntohl(sip2);
				memcpy(&sip3, ptr+10, 4);
				//sip3 = ntohl(sip3);
			}
			else if( *(ptr+1) == 0x8)
			{ 
				memcpy(&sip1, ptr+2, 4);
				//sip1 = ntohl(sip1);
				memcpy(&sip2, ptr+6, 4);
				//sip2 = ntohl(sip2);
				sip3 = 0;
			}
			else if( *(ptr+1) == 0x4)
			{
				memcpy(&sip1, ptr+2, 4);
				//sip1 = ntohl(sip1);
				sip2 = 0;
				sip3 = 0;
			}
			else
			{
				DBG_PRINTF("get dhcp server ip error\n");
				return PLS_FAIL;
			}
		}
#if	0
		else if( *ptr == OPT_LOCAL_IP)
		{
			if ((*(ptr+1) != 4) || (*(long*)(ptr+2) != htonl(lip)))
			{
				DBG_PRINTF("local ip error, htonl(lip)=0x%08x, receive lip=0x%08x\n", htonl(lip), *(long*)(ptr+2));
				return PLS_FAIL;
			}
		}
#endif
		ptr += *(ptr+1) +2;
		printf("\r\nkkkkkk\r\n");
	}
	if( sip1 == 0)
	{
		DBG_PRINTF("No Server ip\n");
		return PLS_FAIL;
	}
	DBG_PRINTF("Receive Request Ack, sip1=0x%x, lip=0x%x\n", sip1, lip);
	pls_retries = 0;
	SendUsernameAuth();
	return PLS_SUCCESS;
}		
int CheckUserAck()
{
	unsigned char i, *ptr, fauth;
	if(uncrypt_receive.hdr.cmd != CMD_AUTH_ACK)
		return PLS_FAIL;
	fauth = 0;
	for( ptr = uncrypt_receive.data; ptr < uncrypt_receive.data+uncrypt_receive.hdr.data_len; )
	{

		if( *ptr == OPT_AUTH_ACK)
		{
			if( *(ptr+1) != 1)
			{
				DBG_PRINTF("Wait Username Ack error\n");
				return PLS_FAIL;
			}
			if( *(ptr+2) == 0x80)
			{
				fauth = 1;
			}
		}
		ptr += *(ptr+1) +2;
	}
	if( fauth == 0)
		return PLS_FAIL;
	DBG_PRINTF("Receive Username auth Ack\n");
	pls_retries = 0; 
	SendPwdAuth();
	return PLS_SUCCESS;
}
int CheckHangupAck()
{
	if(uncrypt_receive.hdr.cmd != CMD_HANGUP_ACK)
		return PLS_FAIL;
	if(renewflag == 1)
	{
		InitVar();
		DoReleaseDHCPC();
		sleep(1);
		DoStartDHCPC(1);
		pls_sts = STS_GET_IP;
		pls_max_timeout = 60;
	}
	else
	{
		InitVar();
		DoReleaseDHCPC();
		sleep(1);
		pls_sts = STS_STOP;
	}
	renewflag = 0;
	return PLS_SUCCESS;
}
int CheckTerimate()
{
	unsigned char i, *ptr;
	if(uncrypt_receive.hdr.cmd != CMD_HANGUP_REQ)
		return PLS_FAIL;
	for( ptr = uncrypt_receive.data; ptr < uncrypt_receive.data+uncrypt_receive.hdr.data_len; )
	{
		if( *ptr == OPT_LOCAL_IP)
		{
#if	0
			if ((*(ptr+1) != 4) || (*(long*)(ptr+2) != htonl(lip)))
			{
				DBG_PRINTF("local ip error, receive lip=0x%08x\n", *(long*)(ptr+2));
				return PLS_FAIL;
			}
#endif
			SendHangupAck();
			DBG_PRINTF("DoDhcpPls3(USER_RENEW) ");
			DoDhcpPls(USER_RENEW);
			return PLS_SUCCESS;
		}
		ptr += *(ptr+1) +2;
	}
	return PLS_SUCCESS;
}

int CheckPwdAck()
{
	unsigned char i, *ptr;
	if(uncrypt_receive.hdr.cmd != CMD_AUTH_ACK)
		return PLS_FAIL;
	for( ptr = uncrypt_receive.data; ptr < uncrypt_receive.data+uncrypt_receive.hdr.data_len; )
	{

		if( *ptr == OPT_AUTH_ACK)
		{
			if( *(ptr+1) != 1)
			{
				DBG_PRINTF("Wait Password Ack error\n");
				return PLS_FAIL;
			}
			if( *(ptr+2) != 0x01)
			{
				DBG_PRINTF("Wait Password Ack error 0x%x\n", *(ptr+2));
				return PLS_FAIL;
			}
		}
		else if( *ptr == OPT_BANNER)
		{
			DBG_PRINTF("Receive banner string\n");
		}
		ptr += *(ptr+1) +2;
	}
	DBG_PRINTF("Receive password auth Ack, DhcpRestart()\n");
	if( udp_fd != 0)
		close(udp_fd);
	udp_fd = 0;
	wanip = 0;
	DhcpRestart();
	pls_sts = STS_SEC_GET_IP;
	pls_max_timeout = 60;
	return PLS_SUCCESS;
}
int CheckKeepAliveReply()
{
	unsigned char i, *ptr;
	if(uncrypt_receive.hdr.cmd != CMD_SEC_AUTH_ACK)
		return PLS_FAIL;
	for( ptr = uncrypt_receive.data; ptr < uncrypt_receive.data+uncrypt_receive.hdr.data_len; )
	{
		if( *ptr == OPT_AUTH_ACK)
		{
			if( *(ptr+1) != 1)
			{
				DBG_PRINTF("Wait Sec username Ack error\n");
				return PLS_FAIL;
			}
			if( (*(ptr+2) != 0x01) && (*(ptr+2) != 0x80))
			{
				DBG_PRINTF("Wait Sec username Ack error %d\n", *(ptr+2));
				return PLS_FAIL;
			}
		}
		else if( *ptr == OPT_DHCP_RENEW_TIME)
		{
			if( *(ptr+1) != 4)	return PLS_FAIL;
			renew_time = ntohl(*(long*)(ptr+2));
			DBG_PRINTF("renew time = %d\n", renew_time);
		}
		else if( *ptr == OPT_KEEPALIVE_TIME)
		{
			if( *(ptr+1) != 4)	return PLS_FAIL;
			keepalive_time = ntohl(*(long*)(ptr+2));
			DBG_PRINTF("keepalive_time = %d\n", keepalive_time);
		}
		else if( *ptr == OPT_ONLINE_TIME)
		{
			if( *(ptr+1) != 4)	return PLS_FAIL;
			online_time = ntohl(*(long*)(ptr+2));
			DBG_PRINTF("online_time = %d\n", online_time);
		}
		ptr += *(ptr+1) +2;
	}
	DBG_PRINTF("Receive Keep Alive Reply\n");
	cnt_keepalive = 0;
	pls_sts = STS_CONNECTED;
	return PLS_SUCCESS;
}

void InitSendPkt(pls_uncrypt_packet *uncrypt_pkt, unsigned char cmd)
{
	memset( uncrypt_pkt, 0, sizeof(pls_uncrypt_packet));
	uncrypt_pkt->hdr.ver = MARJOR_VER;
	uncrypt_pkt->hdr.cmd = cmd;
	uncrypt_pkt->hdr.byte5 = 01;
	uncrypt_pkt->hdr.byte6 = 00;
	uncrypt_pkt->hdr.seq = send_seq++;
	uncrypt_pkt->hdr.byte8 = 0x0f;
}
void EncryptSendPkt()
{	
	genkey(temp_key, uncrypt_send.data, uncrypt_send.hdr.data_len);
	//printb("temp_key", temp_key, 10);
	memset((unsigned char *)&send_pkt, 0, sizeof(send_pkt));
	memcpy((unsigned char *)&send_pkt, (unsigned char*)&uncrypt_send, sizeof(pls_header));
	memcpy(send_pkt.content.key, temp_key, 10);
//	printb("uncrypt_send.data", uncrypt_send.data, uncrypt_send.hdr.data_len);
	encrypt_suboption(uncrypt_send.data, uncrypt_send.hdr.data_len, send_pkt.content.key);
	send_pkt.hdr.data_len = htons(send_pkt.hdr.data_len + 10);//加上10bytes的key
}
#if	0
unsigned int SendPktto(int sockfd, struct sockaddr_in *ptr_addr, pls_crypt_packet *pkt)
{
	int len;
	len = sendto( sockfd, pkt, pkt->hdr.data_len+sizeof(pls_header), 0, ptr_addr, sizeof(struct sockaddr_in));
	printf("SendPkt, len=%d\n", len);
	return len;
}
#endif
void MakeHangupPkt(unsigned char *user)
{
	unsigned short pos;
	InitSendPkt(&uncrypt_send, CMD_HANGUP_REQ);
	pos = 0;

	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_USERNAME;
	uncrypt_send.data[pos++] = strlen(user);
	strncpy( uncrypt_send.data+pos, user, MAX_USER_LEN);
	if( strlen(user) > MAX_USER_LEN)
		pos += MAX_USER_LEN;
	else
		pos += strlen(user);

	MakeMd5Digest(pos);
	//uncrypt_send.data[pos++] = OPT_MD5_CHECK;
	//uncrypt_send.data[pos++] = 0x10;
	pos += 18;
	EncryptSendPkt();
}

void MakeRequstPkt()
{
	unsigned short pos;
	InitSendPkt(&uncrypt_send, CMD_REQUST);
	pos = 0;

	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_CVER;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &cver, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_DHCP_SIP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &sip, 4);
	pos += 4;

	MakeMd5Digest(pos);
	//uncrypt_send.data[pos++] = OPT_MD5_CHECK;
	//uncrypt_send.data[pos++] = 0x10;
	pos += 18;
	EncryptSendPkt();
}

void MakeAuthUserPkt(unsigned char *user)
{
	unsigned short pos;
	InitSendPkt(&uncrypt_send, CMD_AUTH);
	pos = 0;

	DBG_PRINTF("MakeAuthUserPkt(): lip=0x%08x ", lip);
	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_CVER;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &cver, 4);
	pos += 4;
	
	uncrypt_send.data[pos++] = OPT_USERNAME;
	uncrypt_send.data[pos++] = strlen(user);
	strncpy( uncrypt_send.data+pos, user, MAX_USER_LEN);
	if( strlen(user) > MAX_USER_LEN)
		pos += MAX_USER_LEN;
	else
		pos += strlen(user);

	MakeMd5Digest(pos);
	pos += 18;
	EncryptSendPkt();
}
void MakeHangupAckPkt()
{
	unsigned short pos;
	InitSendPkt(&uncrypt_send, CMD_HANGUP_ACK);
	pos = 0;

	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_CVER;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &cver, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_DHCP_SIP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &sip, 4);
	pos += 4;

	MakeMd5Digest(pos);
	//uncrypt_send.data[pos++] = OPT_MD5_CHECK;
	//uncrypt_send.data[pos++] = 0x10;
	pos += 18;
	EncryptSendPkt();
}
void MakeAuthPwdPkt(unsigned char *user, unsigned char *pwd)
{
	unsigned short pos;
	unsigned char en_len;
	unsigned char en_pwd[42]; 
	struct sockaddr_in tmp_sock;
	int socklen=sizeof(struct sockaddr_in);
	unsigned char temp_str[200], *temp_ptr, i;
	printf("\r\n[]MakeAuthPwdPkt()user=%s,password=%s",user,pwd);
	sprintf(en_pwd, "%s", pwd);
	getsockname(udp_fd,(struct sockaddr*)&tmp_sock,&socklen);
	tmp_ip = lip;
	tmp_port = ntohs(tmp_sock.sin_port);
	//en_len = encrypt_pwd(en_pwd, &tmp_ip, tmp_port);
	en_len = encrypt_pwd(en_pwd, tmp_port);

	DBG_PRINTF("lip1=0x%08x ", lip);
	InitSendPkt(&uncrypt_send, CMD_AUTH);
	pos = 0;

	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	DBG_PRINTF("MakeAuthPwdPkt() lip=0x%08x, ", lip);
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_CVER;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &cver, 4);
	pos += 4;
	
	uncrypt_send.data[pos++] = OPT_USERNAME;
	uncrypt_send.data[pos++] = strlen(user);
	strncpy( uncrypt_send.data+pos, user, MAX_USER_LEN);
	if( strlen(user) > MAX_USER_LEN)
		pos += MAX_USER_LEN;
	else
		pos += strlen(user);

	uncrypt_send.data[pos++] = OPT_PASSWORD;
	uncrypt_send.data[pos++] = en_len+2;
	uncrypt_send.data[pos++] = strlen(pwd);
	uncrypt_send.data[pos++] = 1;
	memcpy( uncrypt_send.data+pos, en_pwd, en_len);
	pos += en_len;

	MakeMd5Digest(pos);
	pos += 18;
	memset(temp_str, 0, sizeof(temp_str));
	temp_ptr = temp_str;
	for( i=0; i < pos; i++)
	{
		sprintf(temp_ptr, "%02x ", uncrypt_send.data[i]); 
		temp_ptr += 3;
	}
	*temp_ptr = 0;
	DBG_PRINTF("data = %s\n", temp_str);
	EncryptSendPkt();
}

void MakeSecAuthPkt(unsigned char *user)
{
	unsigned short pos;
	InitSendPkt(&uncrypt_send, CMD_SEC_AUTH);
	pos = 0;

	uncrypt_send.data[pos++] = OPT_LOCAL_IP;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &lip, 4);
	pos += 4;

	uncrypt_send.data[pos++] = OPT_CVER;
	uncrypt_send.data[pos++] = 4;
	memcpy( uncrypt_send.data+pos, &cver, 4);
	pos += 4;
	
	uncrypt_send.data[pos++] = OPT_USERNAME;
	uncrypt_send.data[pos++] = strlen(user);
	strncpy( uncrypt_send.data+pos, user, MAX_USER_LEN);
	if( strlen(user) > MAX_USER_LEN)
		pos += MAX_USER_LEN;
	else
		pos += strlen(user);

	MakeMd5Digest(pos);
	pos += 18;
	EncryptSendPkt();
}
void GetMd5Digest(unsigned char *digest, unsigned char *str, unsigned long len)
{
	MD5_CONTEXT context;
//	sprintf(orig_str, "%02x%02x%02x%02x:%02x%02x:enus", *ip, *(ip+1), *(ip+2), *(ip+3), *(port), *(port+1));
//	len = strlen(orig_str);
	MD5Init (&context);
	MD5Update (&context, str, len);
	MD5Final (digest, &context);
}
void MakeMd5Digest(unsigned short pos)
{
	uncrypt_send.data[pos++] = OPT_MD5_CHECK;
	uncrypt_send.data[pos++] = 0x10;
	memcpy(uncrypt_send.data+pos, init_digest, 16);
	uncrypt_send.hdr.data_len = pos+16;
	genkey(temp_key, uncrypt_send.data, uncrypt_send.hdr.data_len);
	//printb("temp_key", temp_key, 10);

	memset((unsigned char *)&send_pkt, 0, sizeof(send_pkt));
	memcpy((unsigned char *)&send_pkt, (unsigned char*)&uncrypt_send, sizeof(pls_header));
	memcpy(send_pkt.content.key, temp_key, 10);
	encrypt_suboption(uncrypt_send.data, uncrypt_send.hdr.data_len, send_pkt.content.key);

//	memset(temp, 0, sizeof(temp));
//	memcpy(temp, un_hdr, 8);
	memcpy(send_pkt.content.key, temp_key, 10);
//	memcpy(temp+8+10, send_pkt.content.crypt_data, uncrypt_send.len);
	GetMd5Digest(md5digest, (unsigned char*)&send_pkt, send_pkt.hdr.data_len);
	//printb("digest new", md5digest, 16);
	memcpy(uncrypt_send.data+pos, md5digest, 16);
}

void ReSendPkt()
{
	DBG_PRINTF("ReSendPkt() pls_retries=%d, renewflag=%d  ", pls_retries, renewflag); 
	if( pls_retries++ >= MAX_RETRIES)
	{
		if( (pls_sts == STS_HANGUP_ACK ) && (renewflag == 0))
		{
			DBG_PRINTF("Hangup Dhcp Plus Ok! ");
			InitVar();
			DoReleaseDHCPC();
			sleep(1);
			pls_sts = STS_STOP;
			return;
		}
		pls_sts = STS_GET_IP;
		pls_max_timeout = 60;
		DBG_PRINTF("DoDhcpPls1(USER_RENEW) ");
		DoDhcpPls(USER_RENEW);
		return ;
	}
	switch( pls_sts)
	{
		case	STS_GET_IP:
			DBG_PRINTF("ReSendPkt(),pls_sts=STS_GET_IP,pls_max_timeout=%d,pls_wait_time=%d\n", pls_max_timeout,pls_wait_time);
			DBG_PRINTF("DoDhcpPls2(USER_RENEW) ");
			DoDhcpPls(USER_RENEW);
			break;
		case	STS_REQ_ACK:
			SendReq();
			break;
		case	STS_AUTH_USER_ACK:
			SendUsernameAuth();
			break;
		case	STS_AUTH_PWD_ACK:
			SendPwdAuth();
			break;
		case	STS_SEC_GET_IP:
			DhcpRestart();
			break;
		//case	STS_SEC_AUTH:
		//	SendSecUser();
		//	break
		case	STS_KEEPALIVE_REPLY:
			SendKeepAlive(1);
			//CheckKeepAliveReply();
			break;
		//case	STS_WAIT_KEEPALIVE:
		//	CheckKeepAlive();
		//	break;
		default:
			break;
	}
}

//userflag = 0, start.
//userflag = 1, renew.
//userflag = 2, hangup
int DoDhcpPls(char userflag)
{
	if( userflag == 0)
		DBG_PRINTF("START DoDhcpPls() ");
	else if( userflag == 1)
		DBG_PRINTF("ReStart DoDhcpPls() ");
	else if( userflag == 2)
		DBG_PRINTF("Stop DoDhcpPls() ");
	DBG_PRINTF("\r\n test by luo about start1\r\n");
	if(userflag == USER_HANGUP)
	{
		if( pls_sts == STS_STOP)
		{
			InitVar();
		}
		else if( pls_sts == STS_CONNECTED)
		{
			renewflag = 0;
			SendHangupReq();
		}
		else
		{
			InitVar();
			pls_sts = STS_STOP;
			//DoReleaseDHCPC();
		}
		return PLS_SUCCESS;
	}
	else if( (userflag == USER_START) && (pls_sts == STS_STOP))
	{
			DBG_PRINTF("\r\n pls_ste=%d\r\n",pls_sts);
			resetDns = 1;
			resetDomain = 1;
			bport = 1000;
			InitVar();
			DoStartDHCPC(0);
			sleep(5);
			DBG_PRINTF("\r\n dhcp relay");
			pls_sts = STS_GET_IP;
			pls_max_timeout = 60;
	}
	else if(userflag == USER_RENEW)
	{
		resetDns = 1;
		resetDomain = 1;
		if( pls_sts == STS_CONNECTED)
		{
			renewflag = 1;
			SendHangupReq();
		}
		else if( pls_sts != STS_STOP)
		{
			InitVar();
			pls_sts = STS_GET_IP;
			pls_max_timeout = 60;
			DoReleaseDHCPC();
			sleep(1);
			DoStartDHCPC(1);
		}
		else
		{
			InitVar();
			DoStartDHCPC(0);
			pls_sts = STS_GET_IP;
			pls_max_timeout = 60;
		}
	}
	DBG_PRINTF("pls_max_timeout=%d, pls_wait_time=%d\n", pls_max_timeout,pls_wait_time);
	DBG_PRINTF("\r\n pls_sts,next=%d\r\n",pls_sts);
}
	
struct sockaddr_in taddr;
int taddrlen=sizeof(taddr);

//dhcp plus的主程序，每隔段时间调用一次，也可以由alarm触发，用于检测dhcp plus的状态，并做相应的处理。
//每检测一次pls_retries加一，当进入下一个状态时pls_retries被清零。

//pls_wait_time 等待一个回应包时，最多等待此函数执行的次数。每收到一个正确的包或发出一个包后，此值被清零。
//当超过之后，重新发送请求包，pls_retries加一。

//pls_retries 每一个阶段的请求包最多发送的次数，超过之后整个过程重来，即执行DoDhcpPls(USER_RENEW)。
int DhcpPls_Status_Machine()
{
	if( pls_sts == STS_STOP)
		return PLS_SUCCESS;
	DBG_PRINTF("\r\npls_sts = %d\n", pls_sts);
	if( pls_wait_time++ > pls_max_timeout)
	{
		switch( pls_sts)
		{
			case	STS_GET_IP:
				DBG_PRINTF("Get Wanip Timeout\n");
				break;
			case	STS_REQ_ACK:
				DBG_PRINTF("Wait Request Ack Timeout\n");
				break;
			case	STS_AUTH_USER_ACK:
				DBG_PRINTF("Wait Username Auth Ack Timeout\n");
				break;
			case	STS_AUTH_PWD_ACK:
				DBG_PRINTF("Wait Password Auth Ack Timeout\n");
				break;
			case	STS_SEC_GET_IP:
				DBG_PRINTF("Second Get Wanip Timeout\n");
				break;
			case	STS_KEEPALIVE_REPLY:
				DBG_PRINTF("Wait KeepAlive Reply Timeout\n");
				break;
//			case	STS_CONNECTED:
//				CheckTerimate();
//				break;
			case	STS_HANGUP_ACK:
				DBG_PRINTF("Wait Hang up Ack Timeout, Hang up it!\n");
				InitVar();
				DoReleaseDHCPC();
				sleep(1);
				pls_sts = STS_STOP;
				return;
				break;
			default:
				break;
		}
		ReSendPkt();
		return PLS_SUCCESS;
	}
	if( pls_sts == STS_GET_IP)
	{
		CheckGetWanIp();
		//DBG_PRINTF("CheckGetWanIp() OK\n");
		return PLS_SUCCESS;
	}
	else if(pls_sts == STS_SEC_GET_IP) 
	{
		CheckSecGetWanIp();
		return PLS_SUCCESS;
	}
	else
	{
		if( pls_sts == STS_CONNECTED)
		{
			pls_wait_time = 0;
			if( cnt_keepalive++ == SEND_ECHO_TIME)
			{
				SendKeepAlive(0);
				return PLS_SUCCESS;
			}
		}
		FD_ZERO (&readfds);
		FD_SET (udp_fd, &readfds );
		time_out.tv_sec = 0;
		time_out.tv_usec = 0;
		DBG_PRINTF("\r\npacker 2 start \r\n");
		//DBG_PRINTF("select...");
		DBG_PRINTF("\r\nudp_fd=%d\r\n",udp_fd);
		if( select( udp_fd+1, &readfds, NULL, NULL, &time_out)>=0)
		{
			//DBG_PRINTF(">0");
			DBG_PRINTF("\r\npacker 2 start-select() \r\n");
			if( FD_ISSET( udp_fd, &readfds) )
			{
				DBG_PRINTF("\r\npacker 2 start-FD_ISSET() \r\n");
				memset((unsigned char*)&receive_pkt, 0, sizeof(receive_pkt));
				recv_len = recvfrom( udp_fd, (unsigned char*)&receive_pkt, sizeof(receive_pkt), 0, NULL, NULL);
				receive_pkt.hdr.data_len = ntohs(receive_pkt.hdr.data_len);
				DBG_PRINTF("receive_pkt: recv_len=%d,ver=%d,cmd=%d,data_len=%d,seq=%d, send_seq=%d\n", recv_len,
				receive_pkt.hdr.ver, receive_pkt.hdr.cmd, receive_pkt.hdr.data_len, receive_pkt.hdr.seq, send_seq);
				if( (recv_len != 8+receive_pkt.hdr.data_len) ||
					//(receive_pkt.hdr.seq != send_seq) ||
					//(receive_pkt.hdr.cmd != CMD_REQ_ACK) ||
					(recv_len > DATA_LEN) )
				{
					DBG_PRINTF("recevice data not correct\n");
					//printb("receive_pkt.content ", receive_pkt.content.key, receive_pkt.hdr.data_len);
					return PLS_FAIL;
				}
			}
			else
				return PLS_SUCCESS;
		}
		else
		{
			//DBG_PRINTF("<=0\n");
			DBG_PRINTF("\r\npacker 2 start -SELECT()-ERROR!\r\n");
			return PLS_SUCCESS;
		}
		memset((unsigned char *)&uncrypt_receive, 0, sizeof(uncrypt_receive));
		memcpy((unsigned char *)&uncrypt_receive, (unsigned char*)&receive_pkt, sizeof(pls_header));
		uncrypt_receive.hdr.data_len -= 10;//除去10bytes的key
		decrypt_data(receive_pkt.content.key, receive_pkt.hdr.data_len, uncrypt_receive.data);
		switch( pls_sts)
		{
		//	case	STS_GET_IP:
		//		CheckGetWanIp();
		//		break;
			case	STS_REQ_ACK:
				printf("\r\nSTS_REQ_ACK=%d\r\n",pls_sts);
				CheckReqAck();
				break;
			case	STS_AUTH_USER_ACK:
				CheckUserAck();
				break;
			case	STS_AUTH_PWD_ACK:
				CheckPwdAck();
				break;
			case	STS_KEEPALIVE_REPLY:
				CheckKeepAliveReply();
				break;
//			case	STS_CONNECTED:
//				CheckTerimate();
//				break;
			case	STS_HANGUP_ACK:
				CheckHangupAck();
				break;
			default:
				break;
		}
	}
}
void DhcpRestart()
{
         DBG_PRINTF("DhcpRestart() DoStartDHCPC(1)  ");
	DoStartDHCPC(1); 
}
void StopDhcpPls()
{
	DBG_PRINTF("Stop dhcp plus !\n");
	InitVar();
	pls_sts = STS_STOP;
	DoReleaseDHCPC(); 
	sleep(1);
}
void DoReleaseDHCPC() 
{

        return ;
}
void DoStartDHCPC(int flag)  
{
         system("/sbin/udhcpc -i eth1 -H Hostname -m 1500 -f &");
	//sleep(2000);
      return ;
}
