/* dhcpd.c
 *
 * udhcp DHCP client
 *
 * Russ Dill <Russ.Dill@asu.edu> July 2001
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/file.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <sys/sysinfo.h> /* wuyun, 2010-01-21, for sysinfo() */
#include <regex.h>


#include "dhcpd.h"
#include "dhcpc.h"
#include "options.h"
#include "clientpacket.h"
#include "packet.h"
#include "script.h"
#include "socket.h"
#include "debug.h"
#include "pidfile.h"
//#include "dhcp_plus.h" //added by luo


static int state;
static unsigned long requested_ip = 0;
unsigned long requested_ip_bac = 0;

static unsigned long server_addr;
unsigned long server_addr_bac=0;
unsigned long xid_bac=0;



static unsigned char server_mac[6]; /* wuyun, 2009-09-21, 用于记录DHCP Server的MAC地址，在收到DHCP Offer决定向哪个DHCP Server申请地址时确定 */
//static unsigned char server_mac_bac[6]; 

static unsigned long timeout;
static int packet_num = 0;
static int fd = -1;
static int backup = 0;
static int failurecnt = 0;
static unsigned char backupip[16] = "0.0.0.0";

FILE *fp_ipback;

#define LISTEN_NONE 0
#define LISTEN_KERNEL 1
#define LISTEN_RAW 2
static int listen_mode = LISTEN_NONE;

#define DEFAULT_SCRIPT	"/usr/share/udhcpc/default.script"

struct client_config_t client_config = {
    /* Default options. */
abort_if_no_lease: 0,
                   foreground: 0,
                   quit_after_lease: 0,
                   interface: "eth0",
                   pidfile: NULL,
                   script: DEFAULT_SCRIPT,
                   clientid: NULL,
                   hostname: NULL,
                   ifindex: 0,

                   /* add by Yuanke */
                   mtu:NULL,
                   vendorid:"udhcp "VERSION,

                   arp: "\0\0\0\0\0\0",		/* appease gcc-3.0 */
                   defroute: 1 ,
#ifdef ENABLE_OPT42
                   ntpsvr_req: 0,
#endif
};

/*******************************************************************************
* Function    : GetSysUpTime
* Description : 取得系统启动以来的时常，单位为秒
* Parameters  :
* Return      : 无
* Author      : wuyun / 2010-01-21
* History     :
*******************************************************************************/
inline u_long GetSysUpTime(void)
{
    struct sysinfo info;
    sysinfo(&info);
    return (u_long)info.uptime;
}

static void print_usage(void)
{
    printf(
            "Usage: udhcpcd [OPTIONS]\n\n"
            "  -b, --backupip=IP               Use backup IP on failure\n"
            "  -c, --clientid=CLIENTID         Client identifier\n"
            "  -H, --hostname=HOSTNAME         Client hostname\n"
            "  -f, --foreground                Do not fork after getting lease\n"
            "  -i, --interface=INTERFACE       Interface to use (default: eth0)\n"
            "  -n, --now                       Exit with failure if lease cannot be\n"
            "                                  immediately negotiated.\n"

            /* add by Yuanke*/
            "  -m, --mtu=MTU                   Set MTU.\n"

#ifdef ENABLE_OPT42
            "  -N, --ntpsvr                    Request NTP Servers\n"
#endif
            "  -p, --pidfile=file              Store process ID of daemon in file\n"
            "  -q, --quit                      Quit after obtaining lease\n"
            "  -r, --request=IP                IP address to request (default: none)\n"
            "  -s, --script=file               Run file at dhcp events (default:\n"
            "                                  " DEFAULT_SCRIPT ")\n"

            /* add by Yuanke */
            "  -V, --vendorid=ID               Set vendor id\n"

            "  -v, --version                   Display version\n"
            "  -x, --noroute                   Do not install default route\n"
            );
}
/* just a little helper */

/* Exit and cleanup */
static void exit_client(int retval)
{
    pidfile_delete(client_config.pidfile);
    CLOSE_LOG();
    exit(retval);
}

/*=========================================================================*/
/*  函数名称: regexMatch                                                   */
/*  函数功能: 字符串匹配函数                                               */
/*  输  入  : pszString 要匹配的字符串                                     */
/*            pszPattern   匹配规则                                        */
/*  输  出  : int   1:匹配成功，0：不匹配                                  */
/*=========================================================================*/
int regexMatch(const char *pszString, const char *pszPattern)
{
    int status;
    regex_t re;

    if (NULL == pszString || NULL == pszPattern)
    {
        return 0;
    }

    if (regcomp(&re, pszPattern, REG_EXTENDED|REG_NOSUB) != 0)
    {
        return 0; /* report error */
    }

    status = regexec(&re, pszString, (size_t) 0, NULL, 0);
    regfree(&re);

    if (status != 0)
    {
        return 0; /* report error */
    }

    return 1; /* match */
}


/*
 * wuyun, 2010-03-22,
 * 将socket的创建移到此函数中去，使逻辑更合理，
 * 并且可以解决DHCP Server发出了DHCP Ack报文仍然重传续租报文的问题。
 */
static void change_mode(int new_mode)
{
#if 0 /* wuyun, 2010-03-22 */
	DEBUG(LOG_INFO, "entering %s listen mode",
		new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
	close(fd);
	fd = -1;
	listen_mode = new_mode;

#else /* wuyun, 2010-03-22 */

    if (listen_mode != new_mode)
    {
        switch (new_mode)
        {
            case LISTEN_NONE:
                if (fd >= 0)
                {
                    close(fd);
                    fd = -1;
                }
                break;

            case LISTEN_KERNEL:
            case LISTEN_RAW:
                if (fd >= 0)
                {
                    close(fd);
                    fd = -1;
                }

                    if (LISTEN_KERNEL == new_mode)
                        fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
                    else
                        fd = raw_socket(client_config.ifindex);

                if (fd < 0)
                {
                    LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno));
                    exit_client(0);
                }
                break;

            default:
                break;
        }

        listen_mode = new_mode;
    }
#endif /* wuyun, 2010-03-22 */
}


/* SIGUSR1 handler (renew) */
static void renew_requested(int sig)
{
    sig = 0;
    if (state == BOUND || state == RENEWING || state == REBINDING)
    {
        change_mode(LISTEN_KERNEL);
        packet_num = 0;
        state = RENEW_REQUESTED;
    }
    else if (state == RELEASED)
	{
        packet_num = 0;
        change_mode(LISTEN_RAW);
        state = INIT_SELECTING;
    }
    LOG(LOG_INFO, "Received SIGUSR1");

    /* Kill any timeouts because the user wants this to hurry along */
    timeout = 0;
}


/* SIGUSR2 handler (release) */
static void release_requested(int sig)
{
    sig = 0;
    /* send release packet */
    if (state == BOUND || state == RENEWING || state == REBINDING) {
        send_release(server_addr, requested_ip); /* unicast */
        run_script(NULL, "deconfig");
    }
    LOG(LOG_INFO, "Received SIGUSR2");
	/*当释放DHCP时，返回给ipconn模块如下信息来更新这些节点值全为0 */
	LOG(LOG_INFO, "Subnet mask 0.0.0.0 obtained");
	LOG(LOG_INFO, "Router 0.0.0.0 obtained");
	LOG(LOG_INFO, "Dns server 0.0.0.0,0.0.0.0 obtained");
	LOG(LOG_INFO, "Lease of 0.0.0.0 obtained, get lease time 0");
	LOG(LOG_INFO, "DHCP Server IP Address 0.0.0.0 obtained");
    change_mode(LISTEN_NONE);
    state = RELEASED;
    timeout = 0x7fffffff;
}



/* SIGTERM handler */
static void terminate(int sig)
{
    sig = 0;
	printf("test:terminate udhcpc\n ");
    LOG(LOG_INFO, "Received SIGTERM");
    exit_client(0);

}

#if 0 /* wuyun, 2009-09-21, 此函数用不到，为去除编译告警去除之 */
static void background(void)
{
    int pid_fd;
    if (client_config.quit_after_lease) {
        exit_client(0);
    } else if (!client_config.foreground) {
        pid_fd = pidfile_acquire(client_config.pidfile); /* hold lock during fork. */
        if (daemon(0, 0) == -1) {
            perror("fork");
            exit_client(1);
        }
        client_config.foreground = 1; /* Do not fork again. */
        pidfile_write_release(pid_fd);
    }
}
#endif

#ifdef COMBINED_BINARY
int udhcpc(int argc, char *argv[])
#else
asd
int main(int argc, char *argv[])
#endif
{
    unsigned char *temp, *message;
    unsigned long t1 = 0, t2 = 0, xid = 0;
    unsigned long start = 0, lease;
    fd_set rfds;
    int i, k, retval;
    struct timeval tv;
    int c, len;
    struct dhcpMessage packet;
    struct in_addr temp_addr,temp_inet,temp_server;
    int pid_fd;
    time_t now;
    char calline[50];
    char * strbuf;
    char * bufpos;
    unsigned long mtu;
	u_char  *subopt = NULL;
    u_char  svrmac[6]; /* wuyun, 2009-09-21, to hold dhcp svr mac address */
	char szDstIp[16] = {0};
	char szDstMask[16] = {0};
	char szGwIp[16] = {0};
	int entry;
	int iMaskLen = 0;
	int iIpLen = 0;
	unsigned char szIpAddr[4];
	
    static struct option arg_options[] = {
        {"backupip",	required_argument,		0, 'b'},
        {"clientid",	required_argument,	0, 'c'},
        {"foreground",	no_argument,		0, 'f'},
        {"hostname",	required_argument,	0, 'H'},
        {"help",	no_argument,		0, 'h'},
        {"interface",	required_argument,	0, 'i'},
        {"now", 	no_argument,		0, 'n'},

        #ifdef ENABLE_OPT42
        /* 添加-N参数，作显示NTP Servers使用*/
        {"ntpsrv", 	no_argument,		0, 'N'},
        #endif

        {"pidfile",	required_argument,	0, 'p'},
        {"quit",	no_argument,		0, 'q'},
        {"request",	required_argument,	0, 'r'},
        {"script",	required_argument,	0, 's'},
        {"version",	no_argument,		0, 'v'},
        {"noroute",	no_argument,		0, 'x'},

        /* add by Yuanke */
        {"vendorid", required_argument, 0, 'V'},
        {"mtu", required_argument, 0, 'm'},

        {0, 0, 0, 0}
    };

    /* get options */
    while (1) {
        int option_index = 0;

        #ifdef ENABLE_OPT42
        c = getopt_long(argc, argv, "b:c:fH:hi:m:nNp:qr:s:vV:x", arg_options, &option_index);
        #else
        c = getopt_long(argc, argv, "b:c:fH:hi:m:np:qr:s:vV:x", arg_options, &option_index);
        #endif

        if (c == -1) break;

        switch (c) {
            case 'b':
                strcpy(backupip,optarg);
                backup = 1;
                break;
            case 'c':
                len = strlen(optarg) > 255 ? 255 : strlen(optarg);
                if (client_config.clientid) free(client_config.clientid);
                client_config.clientid = malloc(len + 2);
                client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
                client_config.clientid[OPT_LEN] = len;
                client_config.clientid[OPT_DATA] = '\0';
                strncpy(client_config.clientid + 3, optarg, len - 1);
                break;
            case 'f':
                client_config.foreground = 1;
                break;
            case 'H':
                len = strlen(optarg) > 255 ? 255 : strlen(optarg);
                if (client_config.hostname) free(client_config.hostname);
                client_config.hostname = malloc(len + 2);
                client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
                client_config.hostname[OPT_LEN] = len;
                strncpy(client_config.hostname + 2, optarg, len);
                break;
            case 'h':
                print_usage();
                return 0;
            case 'i':
                client_config.interface =  optarg;
                break;
            case 'n':
                client_config.abort_if_no_lease = 1;
                break;

            #ifdef ENABLE_OPT42
            case 'N':
                /* 设置NTP Servers为Request Option */
                for (i = 0; options[i].code != 0; i++)
				{
                    if (options[i].code == DHCP_NTP_SERVER)
					{
                        options[i].flags |= OPTION_REQ;
                        client_config.ntpsvr_req = 1;
                        break;
                    }
                }
                break;
            #endif

            /* add by Yuanke */
            case 'm':
                if ((regexMatch(optarg, "^[0-9]{1,4}$"))
                        && (1541 > atoi(optarg))
                        && (0 < atoi(optarg)))
                {
                    sscanf(optarg, "%u", &mtu);
                    client_config.mtu[OPT_CODE] = DHCP_MTU;
                    client_config.mtu[OPT_LEN] = 2;
                    *(unsigned short *)(client_config.mtu+2) = htons(mtu);
                }
                else
                {
                    printf("MTU must be numeric and value in [1, 1540]!\n");
                    return 0;
                }

                break;

            case 'p':
                client_config.pidfile = optarg;
                break;
            case 'q':
                client_config.quit_after_lease = 1;
                break;
            case 'r':
                requested_ip = inet_addr(optarg);
                break;
            case 's':
                client_config.script = optarg;
                break;
            case 'v':
                printf("udhcpcd, version %s\n\n", VERSION);
                exit_client(0);

            /* add by Yuanke */
            case 'V':
                if (strlen(optarg) >= sizeof("udhcp "VERSION))
                {
                    printf("vendor id length must in [1, %d)\n", sizeof("udhcp "VERSION));
                    return 0;
                }
                client_config.vendorid = optarg;
                break;

            case 'x':
                client_config.defroute = 0;
                break;
        }
    }

    OPEN_LOG("udhcpc");
    LOG(LOG_INFO, "udhcp client (v%s) started", VERSION);

    pid_fd = pidfile_acquire(client_config.pidfile);
    pidfile_write_release(pid_fd);

    if (read_interface(client_config.interface, &client_config.ifindex,
                NULL, client_config.arp) < 0)
        exit_client(1);

    if (!client_config.clientid) {
        client_config.clientid = malloc(6 + 3);
        client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
        client_config.clientid[OPT_LEN] = 7;
        client_config.clientid[OPT_DATA] = 1;
        memcpy(client_config.clientid + 3, client_config.arp, 6);
    }

    /* setup signal handlers */

    signal(SIGUSR1, renew_requested);
    signal(SIGUSR2, release_requested);
    signal(SIGTERM, terminate);

    state = INIT_SELECTING;
    run_script(NULL, "deconfig");
    change_mode(LISTEN_RAW);

	srand(*(unsigned int *)&client_config.arp[2]);

    timeout =  GetSysUpTime() + 2;
    DEBUG(LOG_INFO, "timeout: %ul, %ul\n", GetSysUpTime(), timeout);

	fp_ipback=fopen("/var/dhcpc_ipback","r");
	if(fp_ipback!=NULL)
		{
		fscanf(fp_ipback,"%lu,%lu,%lu",&server_addr_bac,&requested_ip_bac,&xid_bac);

		temp_server.s_addr=server_addr_bac;
		LOG(LOG_INFO, "DHCP Server IP Address %s obtained", inet_ntoa(temp_server));
		fclose(fp_ipback);
		}
	if((server_addr_bac!=0)&&(requested_ip_bac!=0))
	{
	 state = REQUESTING; 
	}

    for (;;)
	{
        tv.tv_sec = timeout - GetSysUpTime();

        #if 0 /* wuyun, 2010-03-22, 移到change_mode函数中去，逻辑更合理，并且可以解决DHCP Server发出了DHCP Ack报文仍然重传续租报文的问题 */
        if (listen_mode != LISTEN_NONE && fd < 0)
		{
            if (listen_mode == LISTEN_KERNEL)
			{
                fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
			}
            else
			{
                fd = raw_socket(client_config.ifindex);
			}

            if (fd < 0)
			{
                LOG(LOG_ERR, "FATAL: couldn't listen on socket, %s", strerror(errno)/*sys_errlist[errno]*/);
                exit_client(0);
            }
        }
        #endif

        if (tv.tv_sec > 0)
		{
            DEBUG(LOG_INFO, "Waiting on select..., tv.tv_sec: %d\n", tv.tv_sec);
            FD_ZERO(&rfds);
            if (fd >= 0) FD_SET(fd, &rfds);

            #if 0 /* wuyun, 2009-09-01, 重传时间改成随机值 */
            tv.tv_usec = 0;
            #else
            tv.tv_usec = (rand()%100) * 1000; /* 100ms以内 */
            #endif
            retval = select(fd + 1, &rfds, NULL, NULL, &tv);
        }
		else
			retval = 0; /* If we already timed out, fall through */

        DEBUG(LOG_INFO, "Come on, baby! retval: %d\n", retval);
        now = GetSysUpTime();

        if (retval == 0)
		{
            /* timeout dropped to zero */
            switch (state)
			{
                case INIT_SELECTING:

                    if (packet_num < 3)
					{
                        if (packet_num == 0)
                            xid = random_xid();

                        /* send discover packet */
			
						//requested_ip=requested_ip_bac;

                        send_discover(xid, requested_ip); /* broadcast */

						timeout = now + (1 << (++packet_num));
                    }
                    else
                    {	
                        if((backup == 1) && (failurecnt >= 2))
                        {
                            sprintf(calline,"ifconfig %s %s",client_config.interface,backupip);
                            system(calline);
                            LOG(LOG_INFO, "Static-Lease of %s",backupip);
                            exit_client(1);

                        }
                        else if (client_config.abort_if_no_lease)
                        {
                            LOG(LOG_INFO, "No lease, failing.");
                            exit_client(1);
                        }
                        /* wait to try again */
                        failurecnt++;
                        packet_num = 0;
                        timeout = now + 5;
                    }
						
                    break;
                case RENEW_REQUESTED:
                case REQUESTING:
                    if (packet_num < 3)
                    {
                        /* send request packet */
                        if (state == RENEW_REQUESTED)
						{
	                        #if 0 /* wuyun, 2009-09-21, 使用新的接口发送DHCP续租报文 */
							send_renew(xid, server_addr, requested_ip); /* unicast */
	                        #else
	                        send_renew(xid, server_addr, requested_ip, server_mac); /* unicast */
	                        #endif
						}
                        else
						{
							server_addr=server_addr_bac;
							requested_ip=requested_ip_bac;
							xid=xid_bac;
							DEBUG(LOG_INFO, "Come on, baby! xid_bac: %d\n", xid_bac);
							send_selecting(xid, server_addr, requested_ip); /* broadcast */
						}

						timeout = now + (1 << (++packet_num));
                    }
                    else
                    {
                        /* timed out, go back to init state */
                        state = INIT_SELECTING;
                        timeout = now;
                        packet_num = 0;
                        change_mode(LISTEN_RAW);
                    }
                    break;
                case BOUND:
                    /* Lease is starting to run out, time to enter renewing state */
                    state = RENEWING;
                    change_mode(LISTEN_KERNEL);
                    DEBUG(LOG_INFO, "Entering renew state");
                    /* fall right through */
                case RENEWING:
                    /* Either set a new T1, or enter REBINDING state */
                    if ((t2 - t1) <= (lease / 14400 + 1))
					{
                        /* timed out, enter rebinding state */
                        state = REBINDING;
                        timeout = now + (t2 - t1);
                        DEBUG(LOG_INFO, "Entering rebinding state");
                    } else {
                        /* send a request packet */
	                    #if 0 /* wuyun, 2009-09-21 */
	                    send_renew(xid, server_addr, requested_ip); /* unicast */
	                    #else
	                    send_renew(xid, server_addr, requested_ip, server_mac); /* unicast */
	                    #endif

                        t1 = (t2 - t1) / 2 + t1;
                        timeout = t1 + start;
                    }
                    break;
                case REBINDING:
                    /* Either set a new T2, or enter INIT state */
                    if ((lease - t2) <= (lease / 14400 + 1))
					{
                        /* timed out, enter init state */
                        state = INIT_SELECTING;
                        run_script(NULL, "deconfig");
                        LOG(LOG_INFO, "Lease lost, entering init state");
                        timeout = now;
                        packet_num = 0;
                        change_mode(LISTEN_RAW);
                    }
					else
					{
						/* send a request packet */
	                    #if 0 /* wuyun, 2009-09-21 */
	                    send_renew(xid, 0, requested_ip); /* broadcast */
	                    #else
	                    send_renew(xid, INADDR_BROADCAST, requested_ip, MAC_BCAST_ADDR); /* broadcast */
	                    #endif

                        t2 = (lease - t2) / 2 + t2;
                        timeout = t2 + start;
                    }
                    break;
                case RELEASED:
                    /* yah, I know, *you* say it would never happen */
                    timeout = 0x7fffffff;
                    break;
            }
        }
		else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds))
		{
            /* a packet is ready, read it */
            if (listen_mode == LISTEN_KERNEL)
                len = get_packet(&packet, fd);
            else
			{
                #if 0 /* wuyun, 2009-09-21 */
                len = get_raw_packet(&packet, fd);
                #else
                len = get_raw_packet(&packet, fd, svrmac);
                #endif
			}

            if (len == -1 && errno != EINTR)
			{
                int mode;
                DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno)/*sys_errlist[errno]*/);

                /* just close and reopen */
                mode = listen_mode;
                change_mode(LISTEN_NONE);
                change_mode(mode);
            }
            if (len < 0) continue;

            /* wuyun, 2009-09-22, It's necessary to check bootp op code, because broadcast packets from other clients can be also received by us  */
            if (packet.op != BOOTREPLY)
            {
                DEBUG(LOG_INFO, "Ignoring boot reply");
                continue;
            }

            if (packet.xid != xid)
            {
                DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
                        (unsigned long) packet.xid, xid);
                continue;
            }

            /* wuyun, 2009-09-18, It's necessary to check the client mac address, because broadcast packets to other clients can be also received by us  */
            if (0 != memcmp(packet.chaddr, client_config.arp, sizeof(client_config.arp)))
            {
                DEBUG(LOG_INFO, "Client MAC Address not match, ignored.");
                continue;
            }

            if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL)
            {
                DEBUG(LOG_ERR, "couldnt get option from packet -- ignoring");
                continue;
            }

            switch (state)
			{
                case INIT_SELECTING:
                    /* Must be a DHCPOFFER to one of our xid's */
                    if (*message == DHCPOFFER)
                	{
                        if ((temp = get_option(&packet, DHCP_SERVER_ID)))
                        {
                            memcpy(&server_addr, temp, 4);
							
                            xid = packet.xid;
							xid_bac=packet.xid;
							DEBUG(LOG_INFO, "Come on, baby! packet.xid: %d\n", xid_bac);
							DEBUG(LOG_INFO, "Come on, baby! packet.xid: %d\n", packet.xid);
                            requested_ip = packet.yiaddr;

							memcpy(&server_addr_bac, temp, 4); //add by wujunyong :save the offered server ip and client ip to /var/dhcpc_ipback
							requested_ip_bac=requested_ip;
							fp_ipback=fopen("/var/dhcpc_ipback","w+");
							if(fp_ipback!=NULL)
								{
									if((server_addr_bac!=0)&&(server_addr_bac!=0))
										fprintf(fp_ipback,"%lu,%lu,%lu",server_addr_bac,requested_ip_bac,xid_bac);
									fclose(fp_ipback);
								}	//add end wujunyong

							//LOG(LOG_INFO, "Router %s obtained", inet_ntoa(temp_inet));
							temp_server.s_addr=server_addr_bac;
							//LOG(LOG_INFO, "DHCP Server IP Address %s obtained", inet_ntoa(( struct in_addr)server_addr_bac));
							LOG(LOG_INFO, "DHCP Server IP Address %s obtained", inet_ntoa(temp_server));
							temp_server.s_addr=requested_ip_bac;
							LOG(LOG_INFO, "DHCP Our IP Address %s obtained", inet_ntoa(temp_server));
                            memcpy(server_mac, svrmac, sizeof(server_mac)); /* wuyun, 2009-09-21, save dhcp svr mac address */
							//memcpy(server_mac_bac, svrmac, sizeof(server_mac)); 
                            /* enter requesting state */
                            state = REQUESTING;
                            timeout = now;
                            packet_num = 0;
                        }
						else
						{
                            DEBUG(LOG_ERR, "No server ID in message");
                        }
                    }
                    break;
                case RENEW_REQUESTED:
                case REQUESTING:
                case RENEWING:
                case REBINDING:
	                /* wuyun, 2009-08-22, 检查报文是否来自请求的DHCP Server，如果不是则忽略 */
					if (NULL == (temp = get_option(&packet, DHCP_SERVER_ID)))
	                {
						DEBUG(LOG_ERR, "Bad Ack: No server id");
	                    continue; /* 忽略此报文 */
					}
	                //if (server_addr != *(u_long *)temp)
	                if (memcmp(&server_addr,temp,sizeof(server_addr)))
	                {
						DEBUG(LOG_INFO, "Ack not from requested server");
	                    continue; /* 忽略此报文 */
	                }
	
                    if (*message == DHCPACK)
					{
                        if (!(temp = get_option(&packet, DHCP_LEASE_TIME)))
						{
                            LOG(LOG_ERR, "No lease time with ACK, using 1 hour lease");
                            lease = 60 * 60;
                        }
						else
						{
                            memcpy(&lease, temp, 4);
                            lease = ntohl(lease);
                        }

                        /* enter bound state */
                        t1 = lease / 2;

                        /* little fixed point for n * .875 */
                        t2 = (lease * 0x7) >> 3;
                        temp_addr.s_addr = packet.yiaddr;

                        if (!(temp = get_option(&packet, DHCP_SUBNET)))
                            memset(&temp_inet.s_addr, 0x00, 4);
                        else
                            memcpy(&temp_inet.s_addr, temp, 4);
                        LOG(LOG_INFO, "Subnet mask %s obtained", inet_ntoa(temp_inet));

                        if(temp = get_option(&packet,DHCP_ROUTER))
                        {
                            memcpy(&temp_inet.s_addr,temp,4);
                            LOG(LOG_INFO, "Router %s obtained", inet_ntoa(temp_inet));
                        }

                        /* 添加这段代码，匹配Dns 服务器*/
                        if(temp = get_option(&packet, DHCP_DNS_SERVER))
                        {
                            strbuf = (char *)malloc(indefinite_optlen * 4 + 1);
                            if (strbuf)
							{
                                memset(strbuf, 0, indefinite_optlen * 4 + 1);
                                i = 0;
                                bufpos = strbuf;
                                while (i < indefinite_optlen)
                                {
                                    sprintf(bufpos, "%d.%d.%d.%d%s", temp[i], temp[i+1], temp[i+2],
                                            temp[i+3], ((i+4)==temp[OPT_LEN-2])?"":",");
                                    i += 4;
                                    bufpos += strlen(bufpos);
                                }
                                *bufpos = '\0';
                                LOG(LOG_INFO, "Dns server %s obtained", strbuf);
                                free(strbuf);
                            }

                            #ifdef ENABLE_OPT250
                            free_option(temp);
                            #endif
                        }


                        #ifdef ENABLE_OPT15
                        /* 添加这段代码，匹配Domain Name */
                        if (temp = get_option(&packet, DHCP_DOMAIN_NAME))
						{
                            strbuf = (char *)malloc(indefinite_optlen + 1);
                            if (strbuf)
							{
                                memset(strbuf, 0, indefinite_optlen + 1);
                                memcpy(strbuf, temp, indefinite_optlen);
                                strbuf[indefinite_optlen + 1] = '\0';
                                LOG(LOG_INFO, "Domain Name:%s", strbuf);
                                free(strbuf);
                            }
                            #ifdef ENABLE_OPT250
                            free_option(temp);
                            #endif
                        }
                        #endif

                        #ifdef ENABLE_OPT42
                        /* 添加这段代码，匹配NTPServers */
                        if (client_config.ntpsvr_req)
						{
                            if (temp = get_option(&packet, DHCP_NTP_SERVER))
							{
                                strbuf = (char *)malloc(indefinite_optlen * 4 + 1);
                                if (strbuf)
								{
                                    memset(strbuf, 0, indefinite_optlen * 4 + 1);
                                    i = 0;
                                    bufpos = strbuf;
                                    while (i < indefinite_optlen)
									{
                                        sprintf(bufpos, "%d.%d.%d.%d%s", temp[i], temp[i+1], temp[i+2],
                                                temp[i+3], ((i+4)==temp[OPT_LEN-2])?"":",");
                                        i += 4;
                                        bufpos += strlen(bufpos);
                                    }
                                    *bufpos = '\0';
                                    LOG(LOG_INFO, "NTP Server:%s", strbuf);
                                    free(strbuf);
                                }
                            }
                            #ifdef ENABLE_OPT250
                            free_option(temp);
                            #endif
                        }
                        #endif

                        #ifdef ENABLE_OPT43
                        /*
                          Get ACS Url/user/pwd from Option 43

                          Format of the value field of the ACS parameter sub-option

                          Code   Len   Vendor-specific information
                          +-----+-----+-----+-----+---
                          |  43 |  n  |  i1 |  i2 | ...
                          +-----+-----+-----+-----+---

                          SubCode Len     acs url/user/pwd
                          +-----+-----+-----+-----+-----+-----+
                          |  1  |  n  |url 0x20 user 0x20 pass|
                          +-----+-----+-----+-----+-----+-----+
                        */
                        if (   (NULL != (temp = get_option(&packet, DHCP_VENDOR_SPEC_INFO))) /* 存在Option 43 */
                            && (0 == verify_opt43(temp - 2)) /* 格式正确 */
                            && (NULL != (subopt = get_opt43_sub(temp - 2, 1))) /* 存在ACS地址子选项 */
                            && (subopt[1] != 0) /* 长度不能为空 */
                        )
                        {
                            char szAcs[256] = {0};
                            memcpy(szAcs, subopt+2, subopt[1]);
                            LOG(LOG_INFO, "ACS Server:%s", szAcs);
                        }
                        #endif

                        start = now;
                        timeout = t1 + start;
                        requested_ip = packet.yiaddr;
                        if(client_config.defroute == 1)
                            run_script(&packet, ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
                        else
                            run_script(&packet, "altbound");

                        LOG(LOG_INFO, "Lease of %s obtained, get lease time %ld",
                                inet_ntoa(temp_addr),lease);

                        /* 用于确定匹配完成*/
                        LOG(LOG_INFO, "Lease obtained, entering bound state");
                        state = BOUND;
                        change_mode(LISTEN_NONE);

						entry = 0;
						#ifdef ENABLE_OPT121
						/* 处理classless static routing table*/
                        if(temp = get_option(&packet, DHCP_CLASSLESS_STATIC_ROUTE_TBL))
                        {
                            i = 0;
							len = temp[OPT_LEN-2];
							printf( "lne = %d--xiao", len );
                            while (i < len && entry < MAX_ROUTE_ENTRY)
                            {	
								iMaskLen = temp[i++];
								iIpLen = (iMaskLen-1)/8 + 1;
			
                         		memset( szIpAddr, 0, 4 );
								for( k=0; k<iMaskLen; k++ )
								{
									szIpAddr[3-(31-k)/8] += 1 << (31-k)%8;
								}
	
								sprintf(szDstMask, "%d.%d.%d.%d", szIpAddr[0], szIpAddr[1], szIpAddr[2], szIpAddr[3]);
						
								memset( szIpAddr, 0, 4 );
								for( k=0; k<iIpLen; k++ )
									szIpAddr[k] = temp[i++];
								
                                sprintf(szDstIp, "%d.%d.%d.%d", szIpAddr[0], szIpAddr[1], szIpAddr[2], szIpAddr[3]);
				               
								sprintf(szGwIp, "%d.%d.%d.%d", temp[i], temp[i+1], temp[i+2],temp[i+3]);
								i += 4;
								
								LOG(LOG_INFO, "Route info:%s/%s/%s/%s", szDstIp, szDstMask, szGwIp,client_config.interface);
								entry ++;
                            }
                        
                        }
						#endif
						
						#ifdef ENABLE_OPT33
						/* 处理static routing table*/
                        if(temp = get_option(&packet, DHCP_STATIC_ROUTE_TBL))
                        {						
                            i = 0;
                			sprintf(szDstMask, "255.255.255.255");
                            while (i < temp[OPT_LEN-2]/8 && entry < MAX_ROUTE_ENTRY) 
                            {
                                sprintf(szDstIp, "%d.%d.%d.%d", temp[i*8], temp[i*8+1], temp[i*8+2],
                                        temp[i*8+3]);
				
								sprintf(szGwIp, "%d.%d.%d.%d", temp[i*8+4], temp[i*8+5], temp[i*8+6],
                                        temp[i*8+7]);

								LOG(LOG_INFO, "Route info:%s/%s/%s/%s", szDstIp, szDstMask, szGwIp,client_config.interface);

								i++;
								entry ++;
                            }
                        
                        }
						#endif
						entry = 0;
						//background();
                    }
					else if (*message == DHCPNAK)
					{
                        /* return to init state */
                        run_script(&packet, "nak");
                        if (state != REQUESTING)
                            run_script(NULL, "deconfig");
                        LOG(LOG_INFO, "Received DHCP NAK");
                        state = INIT_SELECTING;
                        timeout = now;
                        requested_ip = 0;
                    	memcpy(server_mac, MAC_BCAST_ADDR, sizeof(server_mac)); /* wuyun, 2009-09-21, reset dhcp svr mac address */
                        packet_num = 0;
                        change_mode(LISTEN_RAW);
                        sleep(3); /* avoid excessive network traffic */
                    }
                    break;
                    /* case BOUND, RELEASED: - ignore all packets */
            }
        }
		else if (retval == -1 && errno == EINTR)
		{
            /* a signal was caught */

        }
		else
		{
            /* An error occured */
            DEBUG(LOG_ERR, "Error on select");
        }

    }
    return 0;
}

