예제 #1
0
int main(int argc, char *argv[])
#endif
{
    fd_set rfds;
    struct timeval tv;
    int server_socket = -1;
    int bytes, retval;
    struct dhcpMessage packet;
    uint8_t *state;
    uint8_t *server_id, *requested;
    uint32_t server_id_align, requested_align;
    unsigned long timeout_end;
    struct option_set *option;
    struct dhcpOfferedAddr *lease;
    struct dhcpOfferedAddr static_lease;
    int max_sock;
    unsigned long num_ips;
    static uint8_t *host = NULL;	//+Wilson03232006
    unsigned int len = 0; //+Wilson03232006

    uint32_t static_lease_ip;

    memset(&server_config, 0, sizeof(struct server_config_t));
    read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);

    /* Start the log, sanitize fd's, and write a pid file */
    start_log_and_pid("udhcpd", server_config.pidfile);

    if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
        memcpy(&server_config.lease, option->data + 2, 4);
        server_config.lease = ntohl(server_config.lease);
    }
    else server_config.lease = LEASE_TIME;

    /* Sanity check */
    num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1;
    if (server_config.max_leases > num_ips) {
        LOG(LOG_ERR, "max_leases value (%lu) not sane, "
            "setting to %lu instead",
            server_config.max_leases, num_ips);
        server_config.max_leases = num_ips;
    }


    leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr));
    read_leases(server_config.lease_file);

    if (read_interface(server_config.interface, &server_config.ifindex,
                       &server_config.server, server_config.arp) < 0)
        return 1;

    DBG_PRINT(printf("[dhcpd]server ip = %d\n", htonl(server_config.server));)
예제 #2
0
static error_code
try_port (RELAYLIB_INFO* rli, u_short port, char *if_name, char *relay_ip)
{
    struct hostent *he;
    struct sockaddr_in local;

    rli->m_listensock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
    if (rli->m_listensock == SOCKET_ERROR) {
	debug_printf ("try_port(%d) failed socket() call\n", port);
        return SR_ERROR_SOCK_BASE;
    }
    make_nonblocking(rli->m_listensock);

    if ('\0' == *relay_ip) {
	if (read_interface(if_name,&local.sin_addr.s_addr) != 0)
	    local.sin_addr.s_addr = htonl(INADDR_ANY);
    } else {
	he = gethostbyname(relay_ip);
	memcpy(&local.sin_addr, he->h_addr_list[0], he->h_length);
    }

    local.sin_family = AF_INET;
    local.sin_port = htons(port);

#ifndef WIN32
    {
        // Prevent port error when restarting quickly after a previous exit
        int opt = 1;
        setsockopt(rli->m_listensock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    }
#endif
                        
    if (bind(rli->m_listensock, (struct sockaddr *)&local, sizeof(local)) == SOCKET_ERROR)
    {
	debug_printf ("try_port(%d) failed bind() call\n", port);
        closesocket(rli->m_listensock);
        rli->m_listensock = SOCKET_ERROR;
        return SR_ERROR_CANT_BIND_ON_PORT;
    }
        
    if (listen(rli->m_listensock, 1) == SOCKET_ERROR)
    {
	debug_printf ("try_port(%d) failed listen() call\n", port);
        closesocket(rli->m_listensock);
        rli->m_listensock = SOCKET_ERROR;
        return SR_ERROR_SOCK_BASE;
    }

    debug_printf ("try_port(%d) succeeded\n", port);
    return SR_SUCCESS;
}
예제 #3
0
static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
		struct sockaddr_in *server_addr, uint32_t gw_ip)
{
	struct dhcpMessage dhcp_msg;
	fd_set rfds;
	size_t packlen;
	socklen_t addr_size;
	struct sockaddr_in client_addr;
	struct timeval tv;
	int i;

	while (!dhcprelay_stopflag) {
		FD_ZERO(&rfds);
		for (i = 0; i < num_sockets; i++)
			FD_SET(fds[i], &rfds);
		tv.tv_sec = SELECT_TIMEOUT;
		tv.tv_usec = 0;
		if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
			/* server */
			if (FD_ISSET(fds[0], &rfds)) {
				packlen = udhcp_get_packet(&dhcp_msg, fds[0]);
				if (packlen > 0) {
					pass_back(&dhcp_msg, packlen, fds);
				}
			}
			for (i = 1; i < num_sockets; i++) {
				/* clients */
				if (!FD_ISSET(fds[i], &rfds))
					continue;
				addr_size = sizeof(struct sockaddr_in);
				packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
							(struct sockaddr *)(&client_addr), &addr_size);
				if (packlen <= 0)
					continue;
				if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL) < 0)
					dhcp_msg.giaddr = gw_ip;
				pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
			}
		}
		xid_expire();
	}
}
예제 #4
0
int dhcprelay_main(int argc, char **argv)
{
	int i, num_sockets, max_socket, fds[MAX_INTERFACES];
	uint32_t gw_ip;
	char **clients;
	struct sockaddr_in server_addr;

	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(67);
	if (argc == 4) {
		if (!inet_aton(argv[3], &server_addr.sin_addr))
			bb_perror_msg_and_die("didn't grok server");
	} else if (argc == 3) {
		server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
	} else {
		bb_show_usage();
	}
	clients = get_client_devices(argv[1], &num_sockets);
	if (!clients) return 0;

	signal(SIGTERM, dhcprelay_signal_handler);
	signal(SIGQUIT, dhcprelay_signal_handler);
	signal(SIGINT, dhcprelay_signal_handler);

	num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket);

	if (read_interface(argv[2], NULL, &gw_ip, NULL) == -1)
		return 1;

	dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);

	if (ENABLE_FEATURE_CLEAN_UP) {
		for (i = 0; i < num_sockets; i++) {
			close(fds[i]);
			free(clients[i]);
		}
	}

	return 0;
}
예제 #5
0
파일: dhcpd.c 프로젝트: vilpalu/GPL_2.6.31
int main(int argc, char *argv[])
#endif
{
	fd_set rfds;
	struct timeval tv;
	int server_socket = -1;
	int bytes, retval;
	struct dhcpMessage packet;
	uint8_t *state;
	uint8_t *server_id, *requested;
	uint32_t server_id_align, requested_align;
	unsigned long timeout_end;
	struct option_set *option;
	struct dhcpOfferedAddr *lease;
	struct dhcpOfferedAddr static_lease;
	int max_sock;
	unsigned long num_ips;

	uint32_t static_lease_ip;
	
	memset(&server_config, 0, sizeof(struct server_config_t));
	read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);

	/* Start the log, sanitize fd's, and write a pid file */
	start_log_and_pid("udhcpd", server_config.pidfile);

	if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}
	else server_config.lease = LEASE_TIME;

	/* it is not impossible */
	if (server_config.end < server_config.start)
	{
		uint32_t tmp_ip = server_config.start;
		server_config.start = server_config.end ;
		server_config.end = tmp_ip;
	}
	
	/* Sanity check */
	num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1;
	if (server_config.max_leases > num_ips) {
		LOG(LOG_ERR, "max_leases value (%lu) not sane, "
			"setting to %lu instead",
			server_config.max_leases, num_ips);
		server_config.max_leases = num_ips;
	}

	if (dhcps_shm_init() != 0)
		return -1;
	
	leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr));
	memset(leases, 0, server_config.max_leases * sizeof(struct dhcpOfferedAddr));

	//read_leases(server_config.lease_file);

	if (read_interface(server_config.interface, &server_config.ifindex,
			   &server_config.server, server_config.arp) < 0)
		return 1;

#ifndef UDHCP_DEBUG
	background(server_config.pidfile); /* hold lock during fork. */
#endif

	/* Setup the signal pipe */
	udhcp_sp_setup();

	timeout_end = uptime()/*time(0)*/ + server_config.auto_time;
	while(1) { /* loop until universe collapses */		
		if (server_socket < 0)
			if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
				LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
				return 2;
			}

		max_sock = udhcp_sp_fd_set(&rfds, server_socket);
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - uptime()/*time(0)*/;
			tv.tv_usec = 0;
		}
		if (!server_config.auto_time || tv.tv_sec > 0) {
			retval = select(max_sock + 1, &rfds, NULL, NULL,
					server_config.auto_time ? &tv : NULL);
		} else retval = 0; /* If we already timed out, fall through */

		if (retval == 0) {
			write_leases();
			timeout_end = uptime()/*time(0)*/ + server_config.auto_time;
			continue;
		} else if (retval < 0 && errno != EINTR) {
			DEBUG(LOG_INFO, "error on select");
			continue;
		}

		switch (udhcp_sp_read(&rfds)) {
		case SIGUSR1:
			LOG(LOG_INFO, "Received a SIGUSR1");
			
			write_leases();
			/* why not just reset the timeout, eh */
			timeout_end = uptime()/*time(0)*/ + server_config.auto_time;
			continue;
		case SIGUSR2:
			LOG(LOG_INFO, "Received a SIGUSR2, now DHCP SERVER restart");
			
			if (execv(argv[0], argv) == -1)
				printf("errno:%d\n", errno);
			/* NEVER reach here except execv failed! */			
			break;
		case SIGTERM:
			LOG(LOG_INFO, "Received a SIGTERM");
			
			return 0;
		case 0: break;		/* no signal */
		default: continue;	/* signal or error (probably EINTR) */
		}

		if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
			if (bytes == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %m, reopening socket");
				close(server_socket);
				server_socket = -1;
			}
			continue;
		}

		if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
			DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
			continue;
		}

		//printBuf(&packet, sizeof(struct dhcpMessage));
		
		lease = find_lease_by_chaddr(packet.chaddr);

		if (!lease)
		{
			/* Look for a static lease */
			static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);

			/* found */
			if(static_lease_ip)
			{
				memcpy(&static_lease.chaddr, &packet.chaddr, 16);
				static_lease.yiaddr = static_lease_ip;
				static_lease.expires = 0;

				lease = &static_lease;
			}
			/*
			else
			{
				lease = find_lease_by_chaddr(packet.chaddr);
			}
			*/
		}
		
		
		switch (state[0]) {
		case DHCPDISCOVER:
			//DEBUG(LOG_INFO,"received DISCOVER");
			msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv DISCOVER from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0],
				packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);

			if (sendOffer(&packet) < 0) {
				LOG(LOG_ERR, "send OFFER failed");
			}
			break;
 		case DHCPREQUEST:
			//DEBUG(LOG_INFO, "received REQUEST");			
			msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv REQUEST from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0],
							packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);

			requested = get_option(&packet, DHCP_REQUESTED_IP);
			server_id = get_option(&packet, DHCP_SERVER_ID);

			if (requested) memcpy(&requested_align, requested, 4);
			if (server_id) memcpy(&server_id_align, server_id, 4);

			if (lease) {
				if (server_id) {
					/* SELECTING State */
					DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
					if (server_id_align == server_config.server && requested &&
					    requested_align == lease->yiaddr) {
						sendACK(&packet, lease->yiaddr);
					}
					else 
					{
						msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Wrong Server id or request an invalid ip");
						sendNAK(&packet);
					}
				} else {
					if (requested) {
						/* INIT-REBOOT State */
						if (lease->yiaddr == requested_align)
							sendACK(&packet, lease->yiaddr);
						else 
						{
							msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Server id not found and request an invalid ip");
							sendNAK(&packet);
						}
					} else {
						/* RENEWING or REBINDING State */
						if (lease->yiaddr == packet.ciaddr)
							sendACK(&packet, lease->yiaddr);
						else {
							/* don't know what to do!!!! */
							msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Server id and requested ip not found");
							msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:%x %x", lease->yiaddr, packet.ciaddr);
							sendNAK(&packet);
						}
					}
				}

			/* what to do if we have no record of the client */
			} else if (server_id) {
				/* SELECTING State */

			}
			else if (requested) 
			{
				/* INIT-REBOOT State */
				if ((lease = find_lease_by_yiaddr(requested_align))) 
				{
					/* Requested IP already reserved by other one */
					
					if (lease_expired(lease))
					{
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);

						check_and_ack(&packet, requested_align);
					/* make some contention for this address */
					} 
					else	/* still reserved by someone */
					{
						msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:REQUEST ip %x already reserved by %02X:%02X:%02X:%02X:%02X:%02X",
							requested_align, lease->chaddr[0], lease->chaddr[1], lease->chaddr[2],
							lease->chaddr[3], lease->chaddr[4], lease->chaddr[5]);
						sendNAK(&packet);
					}
				}
				else /*if (requested_align < server_config.start ||
					   requested_align > server_config.end)*/ 
				{
					check_and_ack(&packet, requested_align);
				} /* else remain silent */
			} 
			else 
			{
                /* error state, just reply NAK modified by tiger 20090927 */
                 sendNAK(&packet);
			}
			break;
		case DHCPDECLINE:
			//DEBUG(LOG_INFO,"received DECLINE");
			msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv DECLINE from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0],
										packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);
			
			if (lease) {
				memset(lease->chaddr, 0, 16);
				lease->expires = uptime()/*time(0)*/ + server_config.decline_time;
			}
			break;
		case DHCPRELEASE:
			//DEBUG(LOG_INFO,"received RELEASE");			
			msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv RELEASE from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0],
										packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);
			if (lease)
			{
				/* Delete the lease, lsz 080221 */
				#if 1
				memset(lease, 0, sizeof(struct dhcpOfferedAddr));
				#else
				lease->expires = uptime()/*time(0)*/;
				#endif
			}
			
			break;
		case DHCPINFORM:
			//DEBUG(LOG_INFO,"received INFORM");
			msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPS:Recv INFORM from %02X:%02X:%02X:%02X:%02X:%02X", packet.chaddr[0],
										packet.chaddr[1], packet.chaddr[2], packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);
			send_inform(&packet);
			break;
		default:
			LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
		}
	}

	return 0;
}
예제 #6
0
파일: dhcpc.c 프로젝트: foxwolf/yjd
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 retval;
	struct timeval tv;
	int c, len;
	struct dhcpMessage packet;
	struct in_addr temp_addr;
	int pid_fd;
	time_t now;
	int max_fd;
	int sig;

	static struct option arg_options[] = {
		{"clientid",	required_argument,	0, 'c'},
		{"foreground",	no_argument,		0, 'f'},
		{"background",	no_argument,		0, 'b'},
		{"hostname",	required_argument,	0, 'H'},
		{"hostname",    required_argument,      0, 'h'},
		{"interface",	required_argument,	0, 'i'},
		{"now", 	no_argument,		0, 'n'},
		{"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'},
		{"help",	no_argument,		0, '?'},
		{0, 0, 0, 0}
	};

	/* get options */
	while (1) {
		int option_index = 0;
		c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:s:v", arg_options, &option_index);
		if (c == -1) break;
		
		switch (c) {
		case 'c':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			if (client_config.clientid) free(client_config.clientid);
			client_config.clientid = xmalloc(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 + OPT_DATA, optarg, len);
			break;
		case 'f':
			client_config.foreground = 1;
			break;
		case 'b':
			client_config.background_if_no_lease = 1;
			break;
		case 'h':
		case 'H':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			if (client_config.hostname) free(client_config.hostname);
			client_config.hostname = xmalloc(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 'i':
			client_config.interface =  optarg;
			break;
		case 'n':
			client_config.abort_if_no_lease = 1;
			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);
			break;
		default:
			show_usage();
		}
	}

	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 = xmalloc(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 */
	socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
	signal(SIGUSR1, signal_handler);
	signal(SIGUSR2, signal_handler);
	signal(SIGTERM, signal_handler);
	
	state = INIT_SELECTING;
	run_script(NULL, "deconfig");
	change_mode(LISTEN_RAW);

	for (;;) {

		tv.tv_sec = timeout - time(0);
		tv.tv_usec = 0;
		FD_ZERO(&rfds);

		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));
				exit_client(0);
			}
		}
		if (fd >= 0) FD_SET(fd, &rfds);
		FD_SET(signal_pipe[0], &rfds);		

		if (tv.tv_sec > 0) {
			DEBUG(LOG_INFO, "Waiting on select...\n");
			max_fd = signal_pipe[0] > fd ? signal_pipe[0] : fd;
			retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
		} else retval = 0; /* If we already timed out, fall through */

		now = time(0);
		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 */
					send_discover(xid, requested_ip); /* broadcast */
					
					timeout = now + ((packet_num == 2) ? 4 : 2);
					packet_num++;
				} else {
					if (client_config.background_if_no_lease) {
						LOG(LOG_INFO, "No lease, forking to background.");
						background();
					} else if (client_config.abort_if_no_lease) {
						LOG(LOG_INFO, "No lease, failing.");
						exit_client(1);
				  	}
					/* wait to try again */
					packet_num = 0;
					timeout = now + 60;
				}
				break;
			case RENEW_REQUESTED:
			case REQUESTING:
				if (packet_num < 3) {
					/* send request packet */
					if (state == RENEW_REQUESTED)
						send_renew(xid, server_addr, requested_ip); /* unicast */
					else send_selecting(xid, server_addr, requested_ip); /* broadcast */
					
					timeout = now + ((packet_num == 2) ? 10 : 2);
					packet_num++;
				} else {
					/* timed out, go back to init state */
					if (state == RENEW_REQUESTED) run_script(NULL, "deconfig");
					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 */
					send_renew(xid, server_addr, requested_ip); /* unicast */
					
					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;
					LOG(LOG_INFO, "Lease lost, entering init state");
					run_script(NULL, "deconfig");
					timeout = now;
					packet_num = 0;
					change_mode(LISTEN_RAW);
				} else {
					/* send a request packet */
					send_renew(xid, 0, requested_ip); /* broadcast */

					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 len = get_raw_packet(&packet, fd);
			
			if (len == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
				change_mode(listen_mode); /* just close and reopen */
			}
			if (len < 0) continue;
			
			if (packet.xid != xid) {
				DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
					(unsigned long) packet.xid, xid);
				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;
						requested_ip = packet.yiaddr;
						
						/* 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:
				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;
					LOG(LOG_INFO, "Lease of %s obtained, lease time %ld", 
						inet_ntoa(temp_addr), lease);
					start = now;
					timeout = t1 + start;
					requested_ip = packet.yiaddr;
					run_script(&packet,
						   ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));

					state = BOUND;
					change_mode(LISTEN_NONE);
					if (client_config.quit_after_lease) 
						exit_client(0);
					if (!client_config.foreground)
						background();

				} else if (*message == DHCPNAK) {
					/* return to init state */
					LOG(LOG_INFO, "Received DHCP NAK");
					run_script(&packet, "nak");
					if (state != REQUESTING)
						run_script(NULL, "deconfig");
					state = INIT_SELECTING;
					timeout = now;
					requested_ip = 0;
					packet_num = 0;
					change_mode(LISTEN_RAW);
					sleep(3); /* avoid excessive network traffic */
				}
				break;
			/* case BOUND, RELEASED: - ignore all packets */
			}	
		} else if (retval > 0 && FD_ISSET(signal_pipe[0], &rfds)) {
예제 #7
0
/* This state machine is based on the one from udhcpc
   written by Russ Dill */
int dhcp_run (options_t *options)
{
  interface_t *iface;
  int mode = SOCKET_CLOSED;
  int state = STATE_INIT;
  struct timeval tv;
  int xid = 0;
  long timeout = 0;
  fd_set rset;
  int maxfd;
  int retval;
  dhcpmessage_t message;
  dhcp_t *dhcp;
  int type = DHCP_DISCOVER;
  int last_type = DHCP_DISCOVER;
  bool daemonised = false;
  unsigned long start = 0;
  unsigned long last_send = 0;
  int sig;
  unsigned char *buffer = NULL;
  int buffer_len = 0;
  int buffer_pos = 0;

  if (! options || (iface = (read_interface (options->interface,
					     options->metric))) == NULL)
    return -1;

  /* Remove all existing addresses.
     After all, we ARE a DHCP client whose job it is to configure the
     interface. We only do this on start, so persistent addresses can be added
     afterwards by the user if needed. */
  flush_addresses (iface->name);

  dhcp = xmalloc (sizeof (dhcp_t));
  memset (dhcp, 0, sizeof (dhcp_t));

  strcpy (dhcp->classid, options->classid);
  if (options->clientid[0])
    strcpy (dhcp->clientid, options->clientid);
  else
    sprintf (dhcp->clientid, "%s", ether_ntoa (&iface->ethernet_address));

  if (options->requestaddress.s_addr != 0)
    dhcp->address.s_addr = options->requestaddress.s_addr;

  signal_setup ();

  while (1)
    {
      if (timeout > 0 || (options->timeout == 0 &&
			  (state != STATE_INIT || xid)))
	{
	  if (options->timeout == 0 || dhcp->leasetime == -1)
	    {
	      logger (LOG_DEBUG, "waiting on select for infinity");
	      maxfd = signal_fd_set (&rset, iface->fd);
	      retval = select (maxfd + 1, &rset, NULL, NULL, NULL);
	    }
	  else
	    {
	      /* Resend our message if we're getting loads of packets
		 that aren't for us. This mainly happens on Linux as it
		 doesn't have a nice BPF filter. */
	      if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI)
		SEND_MESSAGE (last_type);

	      logger (LOG_DEBUG, "waiting on select for %d seconds",
		      timeout);
	      /* If we're waiting for a reply, then we re-send the last
		 DHCP request periodically in-case of a bad line */
	      retval = 0;
	      while (timeout > 0 && retval == 0)
		{
		  if (iface->fd == -1)
		    tv.tv_sec = SELECT_MAX;
		  else
		    tv.tv_sec = TIMEOUT_MINI;
		  if (timeout < tv.tv_sec)
		    tv.tv_sec = timeout;
		  tv.tv_usec = 0;
		  start = uptime ();
		  maxfd = signal_fd_set (&rset, iface->fd);
		  retval = select (maxfd + 1, &rset, NULL, NULL, &tv);
		  timeout -= uptime () - start;
		  if (retval == 0 && iface->fd != -1 && timeout > 0)
		    SEND_MESSAGE (last_type);
		}
	    }
	}
      else
	retval = 0;

      /* We should always handle our signals first */
      if (retval > 0 && (sig = signal_read (&rset)))
	{
	  switch (sig)
	    {
	    case SIGINT:
	      logger (LOG_INFO, "receieved SIGINT, stopping");
	      retval = 0;
	      goto eexit;

	    case SIGTERM:
	      logger (LOG_INFO, "receieved SIGTERM, stopping");
	      retval = 0;
	      goto eexit;

	    case SIGALRM:

	      logger (LOG_INFO, "receieved SIGALRM, renewing lease");
	      switch (state)
		{
		case STATE_BOUND:
		case STATE_RENEWING:
		case STATE_REBINDING:
		  state = STATE_RENEW_REQUESTED;
		  break;
		case STATE_RENEW_REQUESTED:
		case STATE_REQUESTING:
		case STATE_RELEASED:
		  state = STATE_INIT;
		  break;
		}

	      timeout = 0;
	      xid = 0;
	      break;

	    case SIGHUP:
	      if (state == STATE_BOUND || state == STATE_RENEWING
		  || state == STATE_REBINDING)
		{
		  logger (LOG_INFO, "received SIGHUP, releasing lease");
		  SOCKET_MODE (SOCKET_OPEN);
		  xid = random_xid ();
		  if ((open_socket (iface, false)) >= 0)
		    SEND_MESSAGE (DHCP_RELEASE);
		  SOCKET_MODE (SOCKET_CLOSED);
		  unlink (iface->infofile);
		}
	      else
		logger (LOG_ERR,
			"receieved SIGUP, but no we have lease to release");
	      retval = 0;
	      goto eexit;

	    default:
	      logger (LOG_ERR,
		      "received signal %d, but don't know what to do with it",
		      sig);
	    }
	}
      else if (retval == 0) /* timed out */
	{
	  switch (state)
	    {
	    case STATE_INIT:
	      if (iface->previous_address.s_addr != 0)
		{
		  logger (LOG_ERR, "lost lease");
		  xid = 0;
		  SOCKET_MODE (SOCKET_CLOSED);
		  if (! options->persistent)
		    {
		      free_dhcp (dhcp);
		      memset (dhcp, 0, sizeof (dhcp_t));
		      configure (options, iface, dhcp);
		    }
		  if (! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }
		  break;
		}

	      if (xid == 0)
		xid = random_xid ();
	      else
		{
		  logger (LOG_ERR, "timed out");
		  if (! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }
		}

	      SOCKET_MODE (SOCKET_OPEN);
	      timeout = options->timeout;
	      iface->start_uptime = uptime ();
	      if (dhcp->address.s_addr == 0)
		{
		  logger (LOG_INFO, "broadcasting for a lease");
		  SEND_MESSAGE (DHCP_DISCOVER);
		}
	      else
		{
		  logger (LOG_INFO, "broadcasting for a lease of %s",
			  inet_ntoa (dhcp->address));
		  SEND_MESSAGE (DHCP_REQUEST);
		  state = STATE_REQUESTING;
		}

	      break;
	    case STATE_BOUND:
	    case STATE_RENEW_REQUESTED:
	      state = STATE_RENEWING;
	      xid = random_xid ();
	    case STATE_RENEWING:
	      iface->start_uptime = uptime ();
	      logger (LOG_INFO, "renewing lease of %s", inet_ntoa
		      (dhcp->address));
	      SOCKET_MODE (SOCKET_OPEN);
	      SEND_MESSAGE (DHCP_REQUEST);
	      timeout = dhcp->rebindtime - dhcp->renewaltime;
	      state = STATE_REBINDING;
	      break;
	    case STATE_REBINDING:
	      logger (LOG_ERR, "lost lease, attemping to rebind");
	      SOCKET_MODE (SOCKET_OPEN);
	      SEND_MESSAGE (DHCP_DISCOVER);
	      timeout = dhcp->leasetime - dhcp->rebindtime;
	      state = STATE_INIT;
	      break;
	    case STATE_REQUESTING:
	      logger (LOG_ERR, "timed out");
	      if (! daemonised)
		goto eexit;

	      state = STATE_INIT;
	      SOCKET_MODE (SOCKET_CLOSED);
	      timeout = 0;
	      xid = 0;
	      free_dhcp (dhcp);
	      memset (dhcp, 0, sizeof (dhcp_t));
	      break;

	    case STATE_RELEASED:
	      dhcp->leasetime = -1;
	      break;
	    }
	}
      else if (retval > 0 && mode != SOCKET_CLOSED && FD_ISSET(iface->fd, &rset))
	{

	  /* Allocate our buffer space for BPF.
	     We cannot do this until we have opened our socket as we don't
	     know how much of a buffer we need until then. */
	  if (! buffer)
	    buffer = xmalloc (iface->buffer_length);
	  buffer_len = iface->buffer_length;
	  buffer_pos = -1;

	  /* We loop through until our buffer is empty.
	     The benefit is that if we get >1 DHCP packet in our buffer and
	     the first one fails for any reason, we can use the next. */

	  memset (&message, 0, sizeof (struct dhcpmessage_t));
	  int valid = 0;
	  struct dhcp_t *new_dhcp;
	  new_dhcp = xmalloc (sizeof (dhcp_t));

	  while (buffer_pos != 0)
	    {
	      if (get_packet (iface, (unsigned char *) &message, buffer,
			      &buffer_len, &buffer_pos) < 0)
		break;

	      if (xid != message.xid)
		{
		  logger (LOG_ERR,
			  "ignoring packet with xid %d as it's not ours (%d)",
			  message.xid, xid);
		  continue;
		}

	      logger (LOG_DEBUG, "got a packet with xid %d", message.xid);
	      memset (new_dhcp, 0, sizeof (dhcp_t));
	      if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0)
		{
		  logger (LOG_ERR, "failed to parse packet");
		  free_dhcp (new_dhcp);
		  continue;
		}

	      /* If we got here then the DHCP packet is valid and appears to
		 be for us, so let's clear the buffer as we don't care about
		 any more DHCP packets at this point. */
	      valid = 1;
	      break;
	    }

	  /* No packets for us, so wait until we get one */
	  if (! valid)
	    {
	      free (new_dhcp);
	      continue;
	    }

	  /* new_dhcp is now our master DHCP message */
	  free_dhcp (dhcp);
	  free (dhcp);
	  dhcp = new_dhcp;
	  new_dhcp = NULL;

	  /* We should restart on a NAK */
	  if (type == DHCP_NAK)
	    {
	      logger (LOG_INFO, "received NAK: %s", dhcp->message);
	      state = STATE_INIT;
	      timeout = 0;
	      xid = 0;
	      free_dhcp (dhcp);
	      memset (dhcp, 0, sizeof (dhcp_t));
	      configure (options, iface, dhcp);
	      continue;
	    }

	  switch (state)
	    {
	    case STATE_INIT:
	      if (type == DHCP_OFFER)
		{
		  logger (LOG_INFO, "offered lease of %s",
			  inet_ntoa (dhcp->address));

		  SEND_MESSAGE (DHCP_REQUEST);
		  state = STATE_REQUESTING;
		}
	      break;

	    case STATE_RENEW_REQUESTED:
	    case STATE_REQUESTING:
	    case STATE_RENEWING:
	    case STATE_REBINDING:
	      if (type == DHCP_ACK)
		{
		  SOCKET_MODE (SOCKET_CLOSED);
		  if (options->doarp && iface->previous_address.s_addr !=
		      dhcp->address.s_addr)
		    {
		      if (arp_check (iface, dhcp->address))
			{
			  SOCKET_MODE (SOCKET_OPEN);
			  SEND_MESSAGE (DHCP_DECLINE);
			  SOCKET_MODE (SOCKET_CLOSED);
			  free_dhcp (dhcp);
			  memset (dhcp, 0, sizeof (dhcp));
			  if (daemonised)
			    configure (options, iface, dhcp);

			  xid = 0;
			  state = STATE_INIT;
			  /* RFC 2131 says that we should wait for 10 seconds
			     before doing anything else */
			  sleep (10);
			  continue;
			}
		    }

		  if (! dhcp->leasetime)
		    {
		      dhcp->leasetime = DEFAULT_TIMEOUT;
		      logger(LOG_INFO,
			     "no lease time supplied, assuming %d seconds",
			     dhcp->leasetime);
		    }

		  if (! dhcp->renewaltime) 
		    {
		      dhcp->renewaltime = dhcp->leasetime / 2;
		      logger (LOG_INFO,
			      "no renewal time supplied, assuming %d seconds",
			      dhcp->renewaltime);
		    }

		  if (! dhcp->rebindtime)
		    {
		      dhcp->rebindtime = (dhcp->leasetime * 0x7) >> 3;
		      logger (LOG_INFO,
			      "no rebind time supplied, assuming %d seconds",
			      dhcp->rebindtime);
		    }

		  if (dhcp->leasetime == -1)
		    logger (LOG_INFO, "leased %s for infinity",
			    inet_ntoa (dhcp->address));
		  else
		    logger (LOG_INFO, "leased %s for %u seconds",
			    inet_ntoa (dhcp->address),
			    dhcp->leasetime, dhcp->renewaltime);

		  state = STATE_BOUND;
		  timeout = dhcp->renewaltime;
		  xid = 0;

		  if (configure (options, iface, dhcp) < 0 && ! daemonised)
		    {
		      retval = -1;
		      goto eexit;
		    }

		  if (! daemonised)
		    {
		      if ((daemonise (options->pidfile)) < 0 )
			{
			  retval = -1;
			  goto eexit;
			}
		      daemonised = true;
		    }
		}
	      else if (type == DHCP_OFFER)
		logger (LOG_INFO, "got subsequent offer of %s, ignoring ",
			inet_ntoa (dhcp->address));
	      else
		logger (LOG_ERR,
			"no idea what to do with DHCP type %d at this point",
			type);
	      break;
	    }
static int wpa_supplicant_thread(void)
{
        int exitcode;
        struct wpa_params params;
        struct wpa_global *global;
        HKEY hk, ihk;
        DWORD val, buflen, i;
        LONG ret;

        if (os_program_init())
                return -1;

        os_memset(&params, 0, sizeof(params));
        params.wpa_debug_level = MSG_INFO;

        ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
                           0, KEY_QUERY_VALUE, &hk);
        if (ret != ERROR_SUCCESS) {
                printf("Could not open wpa_supplicant registry key\n");
                return -1;
        }

        buflen = sizeof(val);
        ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
                              (LPBYTE) &val, &buflen);
        if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
                params.wpa_debug_level = val;
        }

        buflen = sizeof(val);
        ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
                              (LPBYTE) &val, &buflen);
        if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
                params.wpa_debug_show_keys = val;
        }

        buflen = sizeof(val);
        ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
                              (LPBYTE) &val, &buflen);
        if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
                params.wpa_debug_timestamp = val;
        }

        buflen = sizeof(val);
        ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
                              (LPBYTE) &val, &buflen);
        if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
                params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
        }

        exitcode = 0;
        global = wpa_supplicant_init(&params);
        if (global == NULL) {
                printf("Failed to initialize wpa_supplicant\n");
                exitcode = -1;
        }

        ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
                           &ihk);
        RegCloseKey(hk);
        if (ret != ERROR_SUCCESS) {
                printf("Could not open wpa_supplicant interfaces registry "
                       "key\n");
                return -1;
        }

        for (i = 0; ; i++) {
                TCHAR name[255];
                DWORD namelen;

                namelen = 255;
                ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
                                   NULL);

                if (ret == ERROR_NO_MORE_ITEMS)
                        break;

                if (ret != ERROR_SUCCESS) {
                        printf("RegEnumKeyEx failed: 0x%x\n",
                               (unsigned int) ret);
                        break;
                }

                if (namelen >= 255)
                        namelen = 255 - 1;
                name[namelen] = '\0';

                wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
                if (read_interface(global, ihk, name) < 0)
                        exitcode = -1;
        }

        RegCloseKey(ihk);

        if (exitcode == 0)
                exitcode = wpa_supplicant_run(global);

        wpa_supplicant_deinit(global);

        os_program_deinit();

        return exitcode;
}
int udhcpd_main(int argc, char **argv)
{
	fd_set rfds;
	struct timeval tv;
	int server_socket = -1, bytes, retval, max_sock;
	struct dhcpMessage packet;
	uint8_t *state, *server_id, *requested;
	uint32_t server_id_align, requested_align, static_lease_ip;
	unsigned timeout_end;
	unsigned num_ips;
	unsigned opt;
	struct option_set *option;
	struct dhcpOfferedAddr *lease, static_lease;

	opt = getopt32(argv, "fS");
	argv += optind;

	if (!(opt & 1)) { /* no -f */
		bb_daemonize_or_rexec(0, argv);
		logmode &= ~LOGMODE_STDIO;
	}

	if (opt & 2) { /* -S */
		openlog(applet_name, LOG_PID, LOG_LOCAL0);
		logmode |= LOGMODE_SYSLOG;
	}

	/* Would rather not do read_config before daemonization -
	 * otherwise NOMMU machines will parse config twice */
	read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);

	/* Make sure fd 0,1,2 are open */
	bb_sanitize_stdio();
	/* Equivalent of doing a fflush after every \n */
	setlinebuf(stdout);

	/* Create pidfile */
	write_pidfile(server_config.pidfile);
	/* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */

	bb_info_msg("%s (v"BB_VER") started", applet_name);

	option = find_option(server_config.options, DHCP_LEASE_TIME);
	server_config.lease = LEASE_TIME;
	if (option) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}

	/* Sanity check */
	num_ips = server_config.end_ip - server_config.start_ip + 1;
	if (server_config.max_leases > num_ips) {
		bb_error_msg("max_leases=%u is too big, setting to %u",
			(unsigned)server_config.max_leases, num_ips);
		server_config.max_leases = num_ips;
	}

	leases = xzalloc(server_config.max_leases * sizeof(*leases));
	read_leases(server_config.lease_file);

	if (read_interface(server_config.interface, &server_config.ifindex,
			   &server_config.server, server_config.arp)) {
		retval = 1;
		goto ret;
	}

	/* Setup the signal pipe */
	udhcp_sp_setup();

	timeout_end = monotonic_sec() + server_config.auto_time;
	while (1) { /* loop until universe collapses */

		if (server_socket < 0) {
			server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
					server_config.interface);
		}

		max_sock = udhcp_sp_fd_set(&rfds, server_socket);
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - monotonic_sec();
			tv.tv_usec = 0;
		}
		retval = 0;
		if (!server_config.auto_time || tv.tv_sec > 0) {
			retval = select(max_sock + 1, &rfds, NULL, NULL,
					server_config.auto_time ? &tv : NULL);
		}
		if (retval == 0) {
			write_leases();
			timeout_end = monotonic_sec() + server_config.auto_time;
			continue;
		}
		if (retval < 0 && errno != EINTR) {
			DEBUG("error on select");
			continue;
		}

		switch (udhcp_sp_read(&rfds)) {
		case SIGUSR1:
			bb_info_msg("Received a SIGUSR1");
			write_leases();
			/* why not just reset the timeout, eh */
			timeout_end = monotonic_sec() + server_config.auto_time;
			continue;
		case SIGTERM:
			bb_info_msg("Received a SIGTERM");
			goto ret0;
		case 0: break;		/* no signal */
		default: continue;	/* signal or error (probably EINTR) */
		}

		bytes = udhcp_recv_packet(&packet, server_socket); /* this waits for a packet - idle */
		if (bytes < 0) {
			if (bytes == -1 && errno != EINTR) {
				DEBUG("error on read, %s, reopening socket", strerror(errno));
				close(server_socket);
				server_socket = -1;
			}
			continue;
		}

		state = get_option(&packet, DHCP_MESSAGE_TYPE);
		if (state == NULL) {
			bb_error_msg("cannot get option from packet, ignoring");
			continue;
		}

		/* Look for a static lease */
		static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);

		if (static_lease_ip) {
			bb_info_msg("Found static lease: %x", static_lease_ip);

			memcpy(&static_lease.chaddr, &packet.chaddr, 16);
			static_lease.yiaddr = static_lease_ip;
			static_lease.expires = 0;

			lease = &static_lease;
		} else {
			lease = find_lease_by_chaddr(packet.chaddr);
		}

		switch (state[0]) {
		case DHCPDISCOVER:
			DEBUG("Received DISCOVER");

			if (sendOffer(&packet) < 0) {
				bb_error_msg("send OFFER failed");
			}
            /* circle test Stat. add by wangpu begin */
            g_offercount ++;
            printf("Circle test: [DHCPS] send OFFER packet num:[%d]\n",g_offercount);
            memset(g_acCmd,0,sizeof(g_acCmd));
            memset(g_interface,0,sizeof(g_interface));
            sprintf(g_interface,"%s",server_config.interface);
            sprintf(g_acCmd,"echo %d > /var/circle/%s",g_offercount,g_interface);
            system(g_acCmd);
            /* circle test Stat. add by wangpu end */
			break;
		case DHCPREQUEST:
			DEBUG("received REQUEST");
			#if 0
			/* ?¡¤??2a¨º? add by wangpu begin */
			   g_offercount ++;
               printf("Circle test: [DHCPS] send OFFER packet num:[%d]\n",g_offercount);
			   memset(g_acCmd,0,sizeof(g_acCmd));
			   memset(g_interface,0,sizeof(g_interface));
			   sprintf(g_interface,"%s",server_config.interface);
			   sprintf(g_acCmd,"echo %d > /var/circle/%s",g_offercount,g_interface);
		       system(g_acCmd);
		    /* ?¡¤??2a¨º? add by wangpu begin */
            #endif
			requested = get_option(&packet, DHCP_REQUESTED_IP);
			server_id = get_option(&packet, DHCP_SERVER_ID);

			if (requested) memcpy(&requested_align, requested, 4);
			if (server_id) memcpy(&server_id_align, server_id, 4);

			if (lease) {
				if (server_id) {
					/* SELECTING State */
					DEBUG("server_id = %08x", ntohl(server_id_align));
					if (server_id_align == server_config.server && requested
					 && requested_align == lease->yiaddr
					) {
						sendACK(&packet, lease->yiaddr);
					}
				} else if (requested) {
					/* INIT-REBOOT State */
					if (lease->yiaddr == requested_align)
						sendACK(&packet, lease->yiaddr);
					else
						sendNAK(&packet);
				} else if (lease->yiaddr == packet.ciaddr) {
					/* RENEWING or REBINDING State */
					sendACK(&packet, lease->yiaddr);
				} else {
					/* don't know what to do!!!! */
					sendNAK(&packet);
				}

			/* what to do if we have no record of the client */
			} else if (server_id) {
				/* SELECTING State */

			} else if (requested) {
				/* INIT-REBOOT State */
				lease = find_lease_by_yiaddr(requested_align);
				if (lease) {
					if (lease_expired(lease)) {
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);
					/* make some contention for this address */
					} else
						sendNAK(&packet);
				} else {
					uint32_t r = ntohl(requested_align);
					if (r < server_config.start_ip
				         || r > server_config.end_ip
					) {
						sendNAK(&packet);
					}
					/* else remain silent */
				}

			} else {
				/* RENEWING or REBINDING State */
			}
			break;
		case DHCPDECLINE:
			DEBUG("Received DECLINE");
			if (lease) {
				memset(lease->chaddr, 0, 16);
				lease->expires = time(0) + server_config.decline_time;
			}
			break;
		case DHCPRELEASE:
			DEBUG("Received RELEASE");
			if (lease)
				lease->expires = time(0);
			break;
		case DHCPINFORM:
			DEBUG("Received INFORM");
			send_inform(&packet);
			break;
		default:
			bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
		}
	}
 ret0:
	retval = 0;
 ret:
	/*if (server_config.pidfile) - server_config.pidfile is never NULL */
		remove_pidfile(server_config.pidfile);
	return retval;
}
예제 #10
0
int udhcpc_main(int argc, char *argv[])
{
	uint8_t *temp, *message;
	unsigned long t1 = 0, t2 = 0, xid = 0;
	unsigned long start = 0, lease;
	fd_set rfds;
	int retval;
	struct timeval tv;
	int c, len;
	struct dhcpMessage packet;
	struct in_addr temp_addr;
	long now;
	int max_fd;
	int sig;
	int no_clientid = 0;

	static const struct option arg_options[] = {
		{"clientid",	required_argument,	0, 'c'},
		{"clientid-none", no_argument,		0, 'C'},
		{"vendorclass",	required_argument,	0, 'V'},
		{"foreground",	no_argument,		0, 'f'},
		{"background",	no_argument,		0, 'b'},
		{"hostname",	required_argument,	0, 'H'},
		{"hostname",	required_argument,	0, 'h'},
		{"fqdn",	required_argument,	0, 'F'},
		{"interface",	required_argument,	0, 'i'},
		{"now",		no_argument,		0, 'n'},
		{"pidfile",	required_argument,	0, 'p'},
		{"quit",	no_argument,		0, 'q'},
		{"request",	required_argument,	0, 'r'},
		{"script",	required_argument,	0, 's'},
		{"timeout",	required_argument,	0, 'T'},
		{"version",	no_argument,		0, 'v'},
		{"retries",	required_argument,	0, 't'},
		{0, 0, 0, 0}
	};

	/* get options */
	while (1) {
		int option_index = 0;
		c = getopt_long(argc, argv, "c:CV:fbH:h:F:i:np:qr:s:T:t:v", arg_options, &option_index);
		if (c == -1) break;

		switch (c) {
		case 'c':
			if (no_clientid) bb_show_usage();
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			free(client_config.clientid);
			client_config.clientid = xmalloc(len + 2);
			client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID;
			client_config.clientid[OPT_LEN] = len;
			client_config.clientid[OPT_DATA] = '\0';
			strncpy((char*)client_config.clientid + OPT_DATA, optarg, len);
			break;
		case 'C':
			if (client_config.clientid) bb_show_usage();
			no_clientid = 1;
			break;
		case 'V':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			free(client_config.vendorclass);
			client_config.vendorclass = xmalloc(len + 2);
			client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
			client_config.vendorclass[OPT_LEN] = len;
			strncpy((char*)client_config.vendorclass + OPT_DATA, optarg, len);
			break;
		case 'f':
			client_config.foreground = 1;
			break;
		case 'b':
			client_config.background_if_no_lease = 1;
			break;
		case 'h':
		case 'H':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			free(client_config.hostname);
			client_config.hostname = xmalloc(len + 2);
			client_config.hostname[OPT_CODE] = DHCP_HOST_NAME;
			client_config.hostname[OPT_LEN] = len;
			strncpy((char*)client_config.hostname + 2, optarg, len);
			break;
		case 'F':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			free(client_config.fqdn);
			client_config.fqdn = xmalloc(len + 5);
			client_config.fqdn[OPT_CODE] = DHCP_FQDN;
			client_config.fqdn[OPT_LEN] = len + 3;
			/* Flags: 0000NEOS
			S: 1 => Client requests Server to update A RR in DNS as well as PTR
			O: 1 => Server indicates to client that DNS has been updated regardless
			E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
			N: 1 => Client requests Server to not update DNS
			*/
			client_config.fqdn[OPT_LEN + 1] = 0x1;
			client_config.fqdn[OPT_LEN + 2] = 0;
			client_config.fqdn[OPT_LEN + 3] = 0;
			strncpy((char*)client_config.fqdn + 5, optarg, len);
			break;
		case 'i':
			client_config.interface =  optarg;
			break;
		case 'n':
			client_config.abort_if_no_lease = 1;
			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 'T':
			client_config.timeout = atoi(optarg);
			break;
		case 't':
			client_config.retries = atoi(optarg);
			break;
		case 'v':
			printf("version %s\n\n", BB_VER);
			return 0;
			break;
		default:
			bb_show_usage();
		}
	}

	/* Start the log, sanitize fd's, and write a pid file */
	udhcp_start_log_and_pid("udhcpc", client_config.pidfile);

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

	/* if not set, and not suppressed, setup the default client ID */
	if (!client_config.clientid && !no_clientid) {
		client_config.clientid = xmalloc(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);
	}

	if (!client_config.vendorclass) {
		client_config.vendorclass = xmalloc(sizeof("udhcp "BB_VER) + 2);
		client_config.vendorclass[OPT_CODE] = DHCP_VENDOR;
		client_config.vendorclass[OPT_LEN] = sizeof("udhcp "BB_VER) - 1;
		client_config.vendorclass[OPT_DATA] = 1;
		memcpy(&client_config.vendorclass[OPT_DATA],
			"udhcp "BB_VER, sizeof("udhcp "BB_VER) - 1);
	}


	/* setup the signal pipe */
	udhcp_sp_setup();

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

	for (;;) {

		tv.tv_sec = timeout - uptime();
		tv.tv_usec = 0;

		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, %m");
				return 0;
			}
		}
		max_fd = udhcp_sp_fd_set(&rfds, fd);

		if (tv.tv_sec > 0) {
			DEBUG(LOG_INFO, "Waiting on select...");
			retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
		} else retval = 0; /* If we already timed out, fall through */

		now = uptime();
		if (retval == 0) {
			/* timeout dropped to zero */
			switch (state) {
			case INIT_SELECTING:
				if (packet_num < client_config.retries) {
					if (packet_num == 0)
						xid = random_xid();

					/* send discover packet */
					send_discover(xid, requested_ip); /* broadcast */

					timeout = now + client_config.timeout;
					packet_num++;
				} else {
					udhcp_run_script(NULL, "leasefail");
					if (client_config.background_if_no_lease) {
						LOG(LOG_INFO, "No lease, forking to background.");
						client_background();
					} else if (client_config.abort_if_no_lease) {
						LOG(LOG_INFO, "No lease, failing.");
						return 1;
					}
					/* wait to try again */
					packet_num = 0;
					timeout = now + 60;
				}
				break;
			case RENEW_REQUESTED:
			case REQUESTING:
				if (packet_num < client_config.retries) {
					/* send request packet */
					if (state == RENEW_REQUESTED)
						send_renew(xid, server_addr, requested_ip); /* unicast */
					else send_selecting(xid, server_addr, requested_ip); /* broadcast */

					timeout = now + ((packet_num == 2) ? 10 : 2);
					packet_num++;
				} else {
					/* timed out, go back to init state */
					if (state == RENEW_REQUESTED) udhcp_run_script(NULL, "deconfig");
					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 */
					send_renew(xid, server_addr, requested_ip); /* unicast */

					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;
					LOG(LOG_INFO, "Lease lost, entering init state");
					udhcp_run_script(NULL, "deconfig");
					timeout = now;
					packet_num = 0;
					change_mode(LISTEN_RAW);
				} else {
					/* send a request packet */
					send_renew(xid, 0, requested_ip); /* broadcast */

					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 = udhcp_get_packet(&packet, fd);
			else len = get_raw_packet(&packet, fd);

			if (len == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %m, reopening socket");
				change_mode(listen_mode); /* just close and reopen */
			}
			if (len < 0) continue;

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

			/* Ignore packets that aren't for us */
			if (memcmp(packet.chaddr, client_config.arp, 6)) {
				DEBUG(LOG_INFO, "packet does not have our chaddr -- ignoring");
				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;
						requested_ip = packet.yiaddr;

						/* 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:
				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;
					LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
						inet_ntoa(temp_addr), lease);
					start = now;
					timeout = t1 + start;
					requested_ip = packet.yiaddr;
					udhcp_run_script(&packet,
						   ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));

					state = BOUND;
					change_mode(LISTEN_NONE);
					if (client_config.quit_after_lease)
						return 0;
					if (!client_config.foreground)
						client_background();

				} else if (*message == DHCPNAK) {
					/* return to init state */
					LOG(LOG_INFO, "Received DHCP NAK");
					udhcp_run_script(&packet, "nak");
					if (state != REQUESTING)
						udhcp_run_script(NULL, "deconfig");
					state = INIT_SELECTING;
					timeout = now;
					requested_ip = 0;
					packet_num = 0;
					change_mode(LISTEN_RAW);
					sleep(3); /* avoid excessive network traffic */
				}
				break;
			/* case BOUND, RELEASED: - ignore all packets */
			}
		} else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
예제 #11
0
파일: dhcpc.c 프로젝트: AlickHill/Lantern
int udhcpc_main(int argc, char **argv)
{
	uint8_t *temp, *message;
	char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
	unsigned long t1 = 0, t2 = 0, xid = 0;
	unsigned long start = 0, lease = 0;
	long now;
	unsigned opt;
	int max_fd;
	int sig;
	int retval;
	int len;
	int no_clientid = 0;
	fd_set rfds;
	struct timeval tv;
	struct dhcpMessage packet;
	struct in_addr temp_addr;

	enum {
		OPT_c = 1 << 0,
		OPT_C = 1 << 1,
		OPT_V = 1 << 2,
		OPT_f = 1 << 3,
		OPT_b = 1 << 4,
		OPT_H = 1 << 5,
		OPT_h = 1 << 6,
		OPT_F = 1 << 7,
		OPT_i = 1 << 8,
		OPT_n = 1 << 9,
		OPT_p = 1 << 10,
		OPT_q = 1 << 11,
		OPT_R = 1 << 12,
		OPT_r = 1 << 13,
		OPT_s = 1 << 14,
		OPT_T = 1 << 15,
		OPT_t = 1 << 16,
		OPT_v = 1 << 17,
	};
#if ENABLE_GETOPT_LONG
	static const struct option arg_options[] = {
		{ "clientid",   required_argument,      0, 'c' },
		{ "clientid-none", no_argument,         0, 'C' },
		{ "vendorclass", required_argument,     0, 'V' },
		{ "foreground", no_argument,            0, 'f' },
		{ "background", no_argument,            0, 'b' },
		{ "hostname",   required_argument,      0, 'H' },
		{ "hostname",   required_argument,      0, 'h' },
		{ "fqdn",       required_argument,      0, 'F' },
		{ "interface",  required_argument,      0, 'i' },
		{ "now",        no_argument,            0, 'n' },
		{ "pidfile",    required_argument,      0, 'p' },
		{ "quit",       no_argument,            0, 'q' },
		{ "release",    no_argument,            0, 'R' },
		{ "request",    required_argument,      0, 'r' },
		{ "script",     required_argument,      0, 's' },
		{ "timeout",    required_argument,      0, 'T' },
		{ "version",    no_argument,            0, 'v' },
		{ "retries",    required_argument,      0, 't' },
		{ 0, 0, 0, 0 }
	};
#endif
	/* Default options. */
	client_config.interface = "eth0";
	client_config.script = DEFAULT_SCRIPT;
	client_config.retries = 3;
	client_config.timeout = 3;

	/* Parse command line */
	opt_complementary = "?:c--C:C--c" // mutually exclusive
	                    ":hH:Hh"; // -h and -H are the same
#if ENABLE_GETOPT_LONG
	applet_long_options = arg_options;
#endif
	opt = getopt32(argc, argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:v",
		&str_c, &str_V, &str_h, &str_h, &str_F,
		&client_config.interface, &client_config.pidfile, &str_r,
		&client_config.script, &str_T, &str_t
		);

	if (opt & OPT_c)
		client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
	if (opt & OPT_C)
		no_clientid = 1;
	if (opt & OPT_V)
		client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
	if (opt & OPT_f)
		client_config.foreground = 1;
	if (opt & OPT_b)
		client_config.background_if_no_lease = 1;
	if (opt & OPT_h)
		client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
	if (opt & OPT_F) {
		client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
		/* Flags: 0000NEOS
		S: 1 => Client requests Server to update A RR in DNS as well as PTR
		O: 1 => Server indicates to client that DNS has been updated regardless
		E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
		N: 1 => Client requests Server to not update DNS
		*/
		client_config.fqdn[OPT_DATA + 0] = 0x1;
		/* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
		/* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
	}
	// if (opt & OPT_i) client_config.interface = ...
	if (opt & OPT_n)
		client_config.abort_if_no_lease = 1;
	// if (opt & OPT_p) client_config.pidfile = ...
	if (opt & OPT_q)
		client_config.quit_after_lease = 1;
	if (opt & OPT_R)
		client_config.release_on_quit = 1;
	if (opt & OPT_r)
		requested_ip = inet_addr(str_r);
	// if (opt & OPT_s) client_config.script = ...
	if (opt & OPT_T)
		client_config.timeout = xatoi_u(str_T);
	if (opt & OPT_t)
		client_config.retries = xatoi_u(str_t);
	if (opt & OPT_v) {
		printf("version %s\n\n", BB_VER);
		return 0;
	}

	if (ENABLE_FEATURE_UDHCP_SYSLOG) {
		openlog(applet_name, LOG_PID, LOG_LOCAL0);
		logmode |= LOGMODE_SYSLOG;
	}

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

	/* Sanitize fd's and write pidfile */
	udhcp_make_pidfile(client_config.pidfile);

	/* if not set, and not suppressed, setup the default client ID */
	if (!client_config.clientid && !no_clientid) {
		client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
		client_config.clientid[OPT_DATA] = 1;
		memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
	}

	if (!client_config.vendorclass)
		client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);

	/* setup the signal pipe */
	udhcp_sp_setup();

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

	for (;;) {
		tv.tv_sec = timeout - uptime();
		tv.tv_usec = 0;

		if (listen_mode != LISTEN_NONE && sockfd < 0) {
			if (listen_mode == LISTEN_KERNEL)
				sockfd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface);
			else
				sockfd = raw_socket(client_config.ifindex);
		}
		max_fd = udhcp_sp_fd_set(&rfds, sockfd);

		if (tv.tv_sec > 0) {
			DEBUG("Waiting on select...");
			retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
		} else retval = 0; /* If we already timed out, fall through */

		now = uptime();
		if (retval == 0) {
			/* timeout dropped to zero */
			switch (state) {
			case INIT_SELECTING:
				if (packet_num < client_config.retries) {
					if (packet_num == 0)
						xid = random_xid();

					/* send discover packet */
					send_discover(xid, requested_ip); /* broadcast */

					timeout = now + client_config.timeout;
					packet_num++;
				} else {
					udhcp_run_script(NULL, "leasefail");
					if (client_config.background_if_no_lease) {
						bb_info_msg("No lease, forking to background");
						client_background();
					} else if (client_config.abort_if_no_lease) {
						bb_info_msg("No lease, failing");
						retval = 1;
						goto ret;
					}
					/* wait to try again */
					packet_num = 0;
					timeout = now + 60;
				}
				break;
			case RENEW_REQUESTED:
			case REQUESTING:
				if (packet_num < client_config.retries) {
					/* send request packet */
					if (state == RENEW_REQUESTED)
						send_renew(xid, server_addr, requested_ip); /* unicast */
					else send_selecting(xid, server_addr, requested_ip); /* broadcast */

					timeout = now + ((packet_num == 2) ? 10 : 2);
					packet_num++;
				} else {
					/* timed out, go back to init state */
					if (state == RENEW_REQUESTED)
						udhcp_run_script(NULL, "deconfig");
					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("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("Entering rebinding state");
				} else {
					/* send a request packet */
					send_renew(xid, server_addr, requested_ip); /* unicast */

					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;
					bb_info_msg("Lease lost, entering init state");
					udhcp_run_script(NULL, "deconfig");
					timeout = now;
					packet_num = 0;
					change_mode(LISTEN_RAW);
				} else {
					/* send a request packet */
					send_renew(xid, 0, requested_ip); /* broadcast */

					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(sockfd, &rfds)) {
			/* a packet is ready, read it */

			if (listen_mode == LISTEN_KERNEL)
				len = udhcp_get_packet(&packet, sockfd);
			else len = get_raw_packet(&packet, sockfd);

			if (len == -1 && errno != EINTR) {
				DEBUG("error on read, %s, reopening socket", strerror(errno));
				change_mode(listen_mode); /* just close and reopen */
			}
			if (len < 0) continue;

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

			/* Ignore packets that aren't for us */
			if (memcmp(packet.chaddr, client_config.arp, 6)) {
				DEBUG("Packet does not have our chaddr - ignoring");
				continue;
			}

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

			switch (state) {
			case INIT_SELECTING:
				/* Must be a DHCPOFFER to one of our xid's */
				if (*message == DHCPOFFER) {
					temp = get_option(&packet, DHCP_SERVER_ID);
					if (temp) {
						/* can be misaligned, thus memcpy */
						memcpy(&server_addr, temp, 4);
						xid = packet.xid;
						requested_ip = packet.yiaddr;

						/* enter requesting state */
						state = REQUESTING;
						timeout = now;
						packet_num = 0;
					} else {
						bb_error_msg("no server ID in message");
					}
				}
				break;
			case RENEW_REQUESTED:
			case REQUESTING:
			case RENEWING:
			case REBINDING:
				if (*message == DHCPACK) {
					temp = get_option(&packet, DHCP_LEASE_TIME);
					if (!temp) {
						bb_error_msg("no lease time with ACK, using 1 hour lease");
						lease = 60 * 60;
					} else {
						/* can be misaligned, thus memcpy */
						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;
					bb_info_msg("Lease of %s obtained, lease time %ld",
						inet_ntoa(temp_addr), lease);
					start = now;
					timeout = t1 + start;
					requested_ip = packet.yiaddr;
					udhcp_run_script(&packet,
						   ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));

					state = BOUND;
					change_mode(LISTEN_NONE);
					if (client_config.quit_after_lease) {
						if (client_config.release_on_quit)
							perform_release();
						goto ret0;
					}
					if (!client_config.foreground)
						client_background();

				} else if (*message == DHCPNAK) {
					/* return to init state */
					bb_info_msg("Received DHCP NAK");
					udhcp_run_script(&packet, "nak");
					if (state != REQUESTING)
						udhcp_run_script(NULL, "deconfig");
					state = INIT_SELECTING;
					timeout = now;
					requested_ip = 0;
					packet_num = 0;
					change_mode(LISTEN_RAW);
					sleep(3); /* avoid excessive network traffic */
				}
				break;
			/* case BOUND, RELEASED: - ignore all packets */
			}
		} else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
예제 #12
0
int main(int argc, char *argv[])
#endif
{
	fd_set rfds;
	struct timeval tv;
	int server_socket = -1;
	int bytes, retval;
	struct dhcpMessage packet;
	uint8_t *state;
	uint8_t *server_id, *requested;
	uint8_t *hostname;
	uint32_t server_id_align, requested_align;
	unsigned long timeout_end;
	struct option_set *option;
	struct dhcpOfferedAddr *lease;
	struct dhcpOfferedAddr static_lease;
	int max_sock;
	unsigned long num_ips;

	uint32_t static_lease_ip;

	memset(&server_config, 0, sizeof(struct server_config_t));
	read_config(argc < 2 ? DHCPD_CONF_FILE : argv[1]);
	read_config_static_leases(DHCPD_STATIC_LEASES_FILE);

	/* Start the log, sanitize fd's, and write a pid file */
	start_log_and_pid("udhcpd", server_config.pidfile);

	if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}
	else server_config.lease = LEASE_TIME;

	/* Sanity check */
	num_ips = ntohl(server_config.end) - ntohl(server_config.start) + 1;
	if (server_config.max_leases > num_ips) {
//		LOG(LOG_ERR, "max_leases value (%lu) not sane, "
//			"setting to %lu instead",
//			server_config.max_leases, num_ips);
		server_config.max_leases = num_ips;
	}

	leases = xcalloc(server_config.max_leases, sizeof(struct dhcpOfferedAddr));
	read_leases(server_config.lease_file);

	if (read_interface(server_config.interface, &server_config.ifindex,
			   &server_config.server, server_config.arp) < 0)
		return 1;

#ifndef UDHCP_DEBUG
	background(server_config.pidfile); /* hold lock during fork. */
#endif

	/* Setup the signal pipe */
	udhcp_sp_setup();

	timeout_end = time(0) + server_config.auto_time;
	while(1) { /* loop until universe collapses */

		if (server_socket < 0)
			if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
				LOG(LOG_ERR, "FATAL: couldn't create server socket, %m");
				return 2;
			}

		max_sock = udhcp_sp_fd_set(&rfds, server_socket);
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - time(0);
			tv.tv_usec = 0;
		}
		if (!server_config.auto_time || tv.tv_sec > 0) {
			retval = select(max_sock + 1, &rfds, NULL, NULL,
					server_config.auto_time ? &tv : NULL);
		} else retval = 0; /* If we already timed out, fall through */

		if (retval == 0) {
			write_leases();
			timeout_end = time(0) + server_config.auto_time;
			continue;
		} else if (retval < 0 && errno != EINTR) {
			DEBUG(LOG_INFO, "error on select");
			continue;
		}

		switch (udhcp_sp_read(&rfds)) {
		case SIGUSR1:
			LOG(LOG_INFO, "Received a SIGUSR1");
			write_leases();
			/* why not just reset the timeout, eh */
			timeout_end = time(0) + server_config.auto_time;
			continue;
		case SIGTERM:
			LOG(LOG_INFO, "Received a SIGTERM");
			return 0;
		case 0: break;		/* no signal */
		default: continue;	/* signal or error (probably EINTR) */
		}

		if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
			if (bytes == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %m, reopening socket");
				close(server_socket);
				server_socket = -1;
			}
			continue;
		}

		if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
			DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
			continue;
		}

		/* Look for a static lease */
		static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);

		if(static_lease_ip)
		{
			printf("Found static lease: %x\n", static_lease_ip);

			memcpy(&static_lease.chaddr, &packet.chaddr, 16);
			static_lease.yiaddr = static_lease_ip;
			static_lease.expires = 0;

			lease = &static_lease;

		}
		else
		{
		lease = find_lease_by_chaddr(packet.chaddr);
		}

		switch (state[0]) {
		case DHCPDISCOVER:
			DEBUG(LOG_INFO,"received DISCOVER");

			if (sendOffer(&packet) < 0) {
				LOG(LOG_ERR, "send OFFER failed");
			}
			break;
 		case DHCPREQUEST:
			DEBUG(LOG_INFO, "received REQUEST");

			requested = get_option(&packet, DHCP_REQUESTED_IP);
			server_id = get_option(&packet, DHCP_SERVER_ID);
			hostname = get_option(&packet, DHCP_HOST_NAME);
			if (requested) memcpy(&requested_align, requested, 4);
			if (server_id) memcpy(&server_id_align, server_id, 4);

			if (lease) {
				if (server_id) {
					/* SELECTING State */
					DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
					if (server_id_align == server_config.server && requested &&
					    requested_align == lease->yiaddr) {
						sendACK(&packet, lease->yiaddr);
					}
				} else {
					if (requested) {
						/* INIT-REBOOT State */
						if (lease->yiaddr == requested_align)
							sendACK(&packet, lease->yiaddr);
						else sendNAK(&packet);
					} else {
						/* RENEWING or REBINDING State */
						if (lease->yiaddr == packet.ciaddr)
							sendACK(&packet, lease->yiaddr);
						else {
							/* don't know what to do!!!! */
							sendNAK(&packet);
						}
					}
				}
				if (hostname) {
					bytes = hostname[-1];
					if (bytes >= (int) sizeof(lease->hostname))
						bytes = sizeof(lease->hostname) - 1;
					strncpy(lease->hostname, hostname, bytes);
					lease->hostname[bytes] = '\0';
				} else
					lease->hostname[0] = '\0';

			/* what to do if we have no record of the client */
			} else if (server_id) {
				/* SELECTING State */

			} else if (requested) {
				/* INIT-REBOOT State */
				if ((lease = find_lease_by_yiaddr(requested_align))) {
					if (lease_expired(lease)) {
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);
					/* make some contention for this address */
					} else sendNAK(&packet);
				} else if (requested_align < server_config.start ||
					   requested_align > server_config.end) {
					sendNAK(&packet);
				} /* else remain silent */

			} else {
				 /* RENEWING or REBINDING State */
			}
			break;
		case DHCPDECLINE:
			DEBUG(LOG_INFO,"received DECLINE");
			if (lease) {
				memset(lease->chaddr, 0, 16);
				lease->expires = time(0) + server_config.decline_time;
			}
			break;
		case DHCPRELEASE:
			DEBUG(LOG_INFO,"received RELEASE");
			if (lease) lease->expires = time(0);
			break;
		case DHCPINFORM:
			DEBUG(LOG_INFO,"received INFORM");
			send_inform(&packet);
			break;
		default:
			LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
		}
	}

	return 0;
}
예제 #13
0
파일: socklib.c 프로젝트: flyingtime/boxee
/*
 * open's a tcp connection to host at port, host can be a dns name or IP,
 * socket_handle gets assigned to the handle for the connection
 */
error_code 
socklib_open(HSOCKET *socket_handle, char *host, int port, char *if_name)
{
    int rc;
    struct sockaddr_in address, local;
    struct hostent *hp;
    int len;

    if (!socket_handle || !host)
	return SR_ERROR_INVALID_PARAM;

    socket_handle->s = socket(AF_INET, SOCK_STREAM, 0);

    if (if_name) {
	if (read_interface(if_name,&local.sin_addr.s_addr) != 0)
	    local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_family = AF_INET;
	local.sin_port = htons(0);
	if (bind(socket_handle->s, (struct sockaddr *)&local, 
		 sizeof(local)) == SOCKET_ERROR) {
	    debug_printf ("Bind failed\n");
	    WSACleanup();
	    closesocket(socket_handle->s);
	    return SR_ERROR_CANT_BIND_ON_INTERFACE;
	}
    }

    if ((address.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
	hp = gethostbyname(host);
	if (hp) {
	    memcpy(&address.sin_addr, hp->h_addr_list[0], hp->h_length);
	} else {
	    debug_printf("resolving hostname: %s failed\n", host);
	    WSACleanup();
	    return SR_ERROR_CANT_RESOLVE_HOSTNAME;
	}
    }
    address.sin_family = AF_INET;
    address.sin_port = htons((unsigned short)port);
    len = sizeof(address);

    rc = connect (socket_handle->s, (struct sockaddr *)&address, len);
    if (rc == SOCKET_ERROR) {
	debug_printf("connect failed\n");
	return SR_ERROR_CONNECT_FAILED;
    }

#ifdef WIN32
    {
	struct timeval timeout = {DEFAULT_TIMEOUT*1000, 0};
	rc = setsockopt (socket_handle->s, SOL_SOCKET,  SO_RCVTIMEO, 
			 (char *)&timeout, sizeof(timeout));
	if (rc == SOCKET_ERROR) {
	    debug_printf("setsockopt failed\n");
	    return SR_ERROR_CANT_SET_SOCKET_OPTIONS;
	}
    }
#endif

    socket_handle->closed = FALSE;
    return SR_SUCCESS;
}
예제 #14
0
int main(int argc, char *argv[])
#endif
{	
	fd_set rfds;
	struct timeval tv;
	int server_socket = -1;
	int bytes, retval;
	struct dhcpMessage packet;
	unsigned char *state;
	unsigned char *server_id, *requested, *hostname;
	u_int32_t server_id_align, requested_align;
	unsigned long timeout_end;
	struct option_set *option;
	struct dhcpOfferedAddr *lease;
	int pid_fd;
	int max_sock;
	int sig;

	/* DD-WRT (belanger) : ignore signals until we're ready */
	signal(SIGUSR1, SIG_IGN);
	signal(SIGUSR2, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	signal(SIGTERM, SIG_IGN);

	OPEN_LOG("udhcpd");
	LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);

	memset(&server_config, 0, sizeof(struct server_config_t));

	if (argc < 2)
		read_config(DHCPD_CONF_FILE);
	else 
		read_config(argv[1]);

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

	if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}
	else server_config.lease = LEASE_TIME;

	leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
	memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
	read_leases(server_config.lease_file);
	read_statics(server_config.statics_file);

	/* DD-WRT (belanger) : write leases now */
	write_leases();

	if (read_interface(server_config.interface, &server_config.ifindex,
			   &server_config.server, server_config.arp) < 0)
		exit_server(1);

#ifndef DEBUGGING
	pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */
	if (daemon(0, 0) == -1) {
		perror("fork");
		exit_server(1);
	}
	pidfile_write_release(pid_fd);
#endif


	socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe);
	signal(SIGUSR1, signal_handler);
	signal(SIGUSR2, signal_handler);
	signal(SIGTERM, signal_handler);
	signal(SIGHUP, signal_handler);

	timeout_end = get_time(0) + server_config.auto_time;
	while(1) { /* loop until universe collapses */

		if (server_socket < 0)
			if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
				LOG(LOG_ERR, "FATAL: couldn't create server socket, %s", strerror(errno));
				exit_server(0);
			}			

		FD_ZERO(&rfds);
		FD_SET(server_socket, &rfds);
		FD_SET(signal_pipe[0], &rfds);
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - get_time(0);
			tv.tv_usec = 0;
		}
		if (!server_config.auto_time || tv.tv_sec > 0) {
			max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
			retval = select(max_sock + 1, &rfds, NULL, NULL, 
					server_config.auto_time ? &tv : NULL);
		} 
		else 
			retval = 0; /* If we already timed out, fall through */

		if (retval == 0) {
			write_leases();
			timeout_end = get_time(0) + server_config.auto_time;
			continue;
		} 
		else if (retval < 0 && errno != EINTR) {
			DEBUG(LOG_INFO, "error on select");
			continue;
		}
		
		if (FD_ISSET(signal_pipe[0], &rfds)) {
			if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
				continue; /* probably just EINTR */
			switch (sig) {
			case SIGUSR1:
				LOG(LOG_INFO, "Received a SIGUSR1");
				write_leases();
				/* why not just reset the timeout, eh */
				timeout_end = get_time(0) + server_config.auto_time;
				continue;
			case SIGUSR2:
				LOG(LOG_INFO, "Received a SIGUSR2");
				delete_leases();
				continue;
			case SIGHUP:
				LOG(LOG_INFO, "Received a SIGHUP");
				read_leases(server_config.lease_file);
				read_statics(server_config.statics_file);
				continue;
			case SIGTERM:
				LOG(LOG_INFO, "Received a SIGTERM");
				exit_server(0);
			}
		}

		if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
			if (bytes == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
				close(server_socket);
				server_socket = -1;
			}
			continue;
		}

		if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
			DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
			continue;
		}

		hostname = get_option(&packet, DHCP_HOST_NAME);

		/* ADDME: look for a static lease */
		    
		/* If a hostname is supplied, and that hostname is a static lease, and that
		   static lease has an FF:FF:FF:FF:FF:FF MAC address, then use that entry. */
		if ( NULL == hostname ||
		     NULL == (lease = find_lease_by_hostname(hostname)) || 
		     (lease->expires != EXPIRES_NEVER) ||
		     0 != memcmp(lease->chaddr, MAC_BCAST_ADDR, strlen(MAC_BCAST_ADDR))) {
		  
		  /* Otherwise, look up the table using the supplied MAC address. */
		  lease = find_lease_by_chaddr(packet.chaddr);

		}

		switch (state[0]) {
		case DHCPDISCOVER:
			LOG(LOG_INFO,"received DISCOVER from %02x:%02x:%02x:%02x:%02x:%02x",
			    packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			    packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);	// modify by honor
			
			if (sendOffer(&packet, lease) < 0) {
				LOG(LOG_ERR, "send OFFER failed");
			}
			break;			
 		case DHCPREQUEST:
			requested = get_option(&packet, DHCP_REQUESTED_IP);
			server_id = get_option(&packet, DHCP_SERVER_ID);

			if (requested) memcpy(&requested_align, requested, 4);
			if (server_id) memcpy(&server_id_align, server_id, 4);
		
			if (requested) {
			  struct in_addr addr;
			  addr.s_addr = requested_align;
			  LOG(LOG_INFO, "received REQUEST for %s from %02x:%02x:%02x:%02x:%02x:%02x",
			      inet_ntoa(addr),
			      packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			      packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);
			}
			else {
			  LOG(LOG_INFO, "received REQUEST from %02x:%02x:%02x:%02x:%02x:%02x",
			      packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			      packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);
			}

			if (lease) { /*ADDME: or static lease */
				if (server_id) {
					/* SELECTING State */
					DEBUG(LOG_INFO, "server_id = %08x", ntohl(server_id_align));
					if (server_id_align == server_config.server && requested && 
					    requested_align == lease->yiaddr) {
						sendACK(&packet, lease->yiaddr);
					}
					else
						sendNAK(&packet); //Sveasoft - shouldn't we let them know we don't like the request?
				} 
				else {
					if (requested) {
						/* INIT-REBOOT State */
						if (lease->yiaddr == requested_align)
							sendACK(&packet, lease->yiaddr);
						else 
							sendNAK(&packet);
					} else {
						/* RENEWING or REBINDING State */
						if (lease->yiaddr == packet.ciaddr)
							sendACK(&packet, lease->yiaddr);
//						else if (!packet.ciaddr)
							/* Accept an invalid request in RENEWING state,
							   where the ciaddr should be set, but is not. */
							/* e.g. Linksys Print Server */
//							sendACK(&packet, lease->yiaddr); //note: let's not support broken stuff - Sveasoft 2005-01-19
						else {
							/* don't know what to do!!!! */
							sendNAK(&packet);
						}
					}						
				}
				if (lease->expires != EXPIRES_NEVER) {
					/* Don't change hostname of static leases */
					if (hostname) {
						bytes = hostname[-1];
						if (bytes >= (int) sizeof(lease->hostname))
							bytes = sizeof(lease->hostname) - 1;
						strncpy(lease->hostname, hostname, bytes);
							lease->hostname[bytes] = '\0';
					} else
						lease->hostname[0] = '\0';
				}
			
			/* what to do if we have no record of the client */
			} 
			else if (server_id) {
				/* SELECTING State */
				sendNAK(&packet);       // by honor

			} 
			else if (requested) {
				/* INIT-REBOOT State */
				if ((lease = find_lease_by_yiaddr(requested_align))) {
					if (lease_expired(lease)) {
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);
					/* make some contention for this address */
					} 
					else 
						sendNAK(&packet);
				} 
				else if (requested_align < server_config.start || 
					 requested_align > server_config.end) {
					sendNAK(&packet);
				} 
				else {
					sendNAK(&packet);
				}

			} 
			else if (packet.ciaddr) {

				/* RENEWING or REBINDING State */
				sendNAK(&packet);
			}
			break;
		case DHCPDECLINE:
			LOG(LOG_INFO,"received DECLINE from %02x:%02x:%02x:%02x:%02x:%02x",
			    packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			    packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);	// modify by honor
			if (lease && lease->expires != EXPIRES_NEVER) {
				memset(lease->chaddr, 0, 16);
				lease->expires = get_time(0) + server_config.decline_time;
			}			
			break;
		case DHCPRELEASE:
			LOG(LOG_INFO,"received RELEASE from %02x:%02x:%02x:%02x:%02x:%02x",
			    packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			    packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);	// modify by honor
			if (lease && lease->expires != EXPIRES_NEVER) 
				lease->expires = get_time(0);
			break;
		case DHCPINFORM:
			LOG(LOG_INFO,"received INFORM from %02x:%02x:%02x:%02x:%02x:%02x",
			    packet.chaddr[0], packet.chaddr[1], packet.chaddr[2], 
			    packet.chaddr[3], packet.chaddr[4], packet.chaddr[5]);	// modify by honor
			send_inform(&packet);
			break;	
		default:
			LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
		}
	}

	return 0;
}
예제 #15
0
파일: dhcpc.c 프로젝트: vilpalu/GPL_2.6.31
int main(int argc, char *argv[])
#endif
{
	uint8_t *temp, *message;
	unsigned long t1 = 0, t2 = 0, xid = 0;
	unsigned long start = 0, lease;
	fd_set rfds;
	int retval;
	struct timeval tv;
	int c, len;
	struct dhcpMessage packet;
	struct in_addr temp_addr;
	long now;
	int max_fd;
	int sig;
	int no_clientid = 0;
	int fail_times = 0;		/* how many times that we fail to find a dhcp server */
	int server_unicast = 0;		


	static const struct option arg_options[] = {
		{"clientid",	required_argument,	0, 'c'},
		{"clientid-none", no_argument,		0, 'C'},
		{"foreground",	no_argument,		0, 'f'},
		{"background",	no_argument,		0, 'b'},
		{"hostname",	required_argument,	0, 'H'},
		{"hostname",    required_argument,      0, 'h'},
		{"interface",	required_argument,	0, 'i'},
		{"now", 	no_argument,		0, 'n'},
		{"pidfile",	required_argument,	0, 'p'},
		{"quit",	no_argument,		0, 'q'},
		{"request",	required_argument,	0, 'r'},
		{"script",	required_argument,	0, 's'},
		{"unicast",	no_argument,		0, 'u'},	/* unicast flag */
		{"version",	no_argument,		0, 'v'},
		{0, 0, 0, 0}
	};

	/* get options */
	while (1) {
		int option_index = 0;
		c = getopt_long(argc, argv, "c:CfbH:h:i:np:qr:s:uv", arg_options, &option_index);
		if (c == -1) break;

		switch (c) {
		case 'c':
			if (no_clientid) show_usage();
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			if (client_config.clientid) free(client_config.clientid);
			client_config.clientid = xmalloc(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 + OPT_DATA, optarg, len);
			break;
		case 'C':
			if (client_config.clientid) show_usage();
			no_clientid = 1;
			break;
		case 'f':
			client_config.foreground = 1;
			break;
		case 'b':
			client_config.background_if_no_lease = 1;
			break;
		case 'h':
		case 'H':
			len = strlen(optarg) > 255 ? 255 : strlen(optarg);
			if (client_config.hostname) free(client_config.hostname);
			client_config.hostname = xmalloc(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 'i':
			client_config.interface =  optarg;
			break;
		case 'n':
			client_config.abort_if_no_lease = 1;
			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 'u':
			server_unicast = 1;
			break;
		case 'v':
			printf("udhcpcd, version %s\n\n", VERSION);
			return 0;
			break;
		default:
			show_usage();
		}
	}

	/* Start the log, sanitize fd's, and write a pid file */
	start_log_and_pid("udhcpc", client_config.pidfile);

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

	/* if not set, and not suppressed, setup the default client ID */
	if (!client_config.clientid && !no_clientid) {
		client_config.clientid = xmalloc(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);
	}

	/* changed by lsz 070621 */
	client_background();
	
	/* setup the signal pipe */
	udhcp_sp_setup();

	//if (dhcpc_shm_init() != 0)
	//	return -1;
	#include "msgq.h"
	dhcp_ipc_fork(DHCPC);

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

	for (;;) {
		tv.tv_sec = timeout - uptime();
		tv.tv_usec = 0;

		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, %m");
				return 0;
			}
		}
		
        /* 
         * select don't return when timeout value is larger than 1.5 hours
         * we just wait multiple times
         * added by tiger 090819, should fix later
         */
        struct timeval tp_timeout;
        #define TP_TIMEOUT_MAX  (30*60)
        
		if (tv.tv_sec > 0) 
		{
            do
            {
                max_fd = udhcp_sp_fd_set(&rfds, fd);
                
                tp_timeout.tv_sec = (tv.tv_sec > TP_TIMEOUT_MAX) ? TP_TIMEOUT_MAX : tv.tv_sec;
                tv.tv_sec -= tp_timeout.tv_sec;                                
                tp_timeout.tv_usec = 0;

                retval = select(max_fd + 1, &rfds, NULL, NULL, &tp_timeout);                
                
            } while (tv.tv_sec > 0 && retval == 0);
		}
		else
		{
			retval = 0; /* If we already timed out, fall through */
		}
        
		now = uptime();
		if (retval == 0) {
			/* timeout dropped to zero */
			switch (state) {
			case INIT_SELECTING:
               
#define     DISCOVER_RETRY_TIMES    5
#define     DISCOVER_INVERT_TIMES   3

				if (packet_num < DISCOVER_RETRY_TIMES) {
					if (packet_num == 0)
					{
						xid = random_xid();
                        /* use user config dhcp flags when first discover, added by tiger 20090821 */
                        if (server_unicast)
                        {
                            set_runtime_dhcp_flags(DHCP_FLAGS_UNICAST);
                        }
                        else
                        {
                            set_runtime_dhcp_flags(DHCP_FLAGS_BROADCAST);                            
                        }
					}

                    /* change runtime dhcp flags when exceed DISCOVER_INVERT_TIMES added by tiger 20090819 apply 11G and XP's option */
                    if (DISCOVER_INVERT_TIMES == packet_num)
                    {                        
                        invert_runtime_dhcp_flags();
                    }
                    
					/* send discover packet */
					//send_discover(xid, requested_ip, server_unicast); /* broadcast */
					/* modified by tiger 20090304, reply mode's setting way changed */
					send_discover(xid, requested_ip);
					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Send DISCOVER with request ip %X and unicast flag %d", requested_ip, get_runtime_dhcp_flags());                    
                    
					timeout = now + ((packet_num == 2) ? 4 : 2);
					packet_num++;
				} else {
					run_script(NULL, "leasefail");
					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC DHCP Service unavailable, recv no OFFER");
					if (client_config.background_if_no_lease) {
						LOG(LOG_INFO, "No lease, forking to background.");
						client_background();
					} else if (client_config.abort_if_no_lease) {
						LOG(LOG_INFO, "No lease, failing.");
						return 1;
				  	}
					/* wait to try again */
					packet_num = 0;
					
					timeout = now + 10 + (fail_times ++) * 30;	
					/* 60->6000, we dont need to try again -- lsz, 080722 */
					/* 6000->30*fail_times -- lsz, 081008 */
				}
				break;
			case RENEW_REQUESTED:
			case REQUESTING:
				if (packet_num < 3) {
					/* send request packet */
					if (state == RENEW_REQUESTED)
					{
						send_renew(xid, server_addr, requested_ip); /* unicast */
					}
					else
					{
						send_selecting(xid, server_addr, requested_ip); /* broadcast */
					}

					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Send REQUEST to server %x with request ip %x", server_addr, requested_ip);

					timeout = now + ((packet_num == 2) ? 10 : 2);
					packet_num++;
				} else {
					/* timed out, go back to init state */
					if (state == RENEW_REQUESTED) run_script(NULL, "deconfig");
					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 */				
					send_renew(xid, server_addr, requested_ip); /* unicast */

					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Send REQUEST to server %x with request ip %x", server_addr, requested_ip);
              
					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;
					LOG(LOG_INFO, "Lease lost, entering init state");
					run_script(NULL, "deconfig");
					timeout = now;
					packet_num = 0;
					change_mode(LISTEN_RAW);
				} else {
					/* send a request packet */
					send_renew(xid, 0, requested_ip); /* broadcast */

					
					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Broadcast REQUEST with request ip %x", requested_ip);
					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 len = get_raw_packet(&packet, fd);

			if (len == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %m, reopening socket");
				change_mode(listen_mode); /* just close and reopen */
			}
			if (len < 0) continue;

			if (packet.xid != xid) {
				DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)",
					(unsigned long) packet.xid, xid);
				continue;
			}
			/* Ignore packets that aren't for us */
			if (memcmp(packet.chaddr, client_config.arp, 6)) {
				DEBUG(LOG_INFO, "packet does not have our chaddr -- ignoring");
				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;
						requested_ip = packet.yiaddr;

						msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Recv OFFER from server %x with ip %x", server_addr, requested_ip);

						/* 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:
				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);
					}

/* RFC 2131 3.1 paragraph 5:
 * "The client receives the DHCPACK message with configuration
 * parameters. The client SHOULD perform a final check on the
 * parameters (e.g., ARP for allocated network address), and notes
 * the duration of the lease specified in the DHCPACK message. At this
 * point, the client is configured. If the client detects that the
 * address is already in use (e.g., through the use of ARP),
 * the client MUST send a DHCPDECLINE message to the server and restarts
 * the configuration process..." 
 * added by tiger 20090827
 */                    
					if (!arpping(packet.yiaddr,
						    (uint32_t) 0,
						    packet.yiaddr,
						    client_config.arp,
						    client_config.interface)
					) {
					
						msglogd (LOG_INFO, LOGTYPE_DHCP, "DHCPC: offered address is in use "
							"(got ARP reply), Send decline");
						send_decline(xid, server_addr, packet.yiaddr);

						if (state != REQUESTING)
							run_script(NULL, "deconfig");
						change_mode(LISTEN_RAW);
						state = INIT_SELECTING;
						requested_ip = 0;
						timeout = now + 12;
						packet_num = 0;
						continue; /* back to main loop */
					}
                    
					/* enter bound state */
					t1 = lease / 2;

					/* little fixed point for n * .875 */
					t2 = (lease * 0x7) >> 3;
					temp_addr.s_addr = packet.yiaddr;
					LOG(LOG_INFO, "Lease of %s obtained, lease time %ld",
						inet_ntoa(temp_addr), lease);
					start = now;
					timeout = t1 + start;
					requested_ip = packet.yiaddr;

					if ((temp = get_option(&packet, DHCP_SERVER_ID))) 
						memcpy(&server_addr, temp, 4);
					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Recv ACK from server %x with ip %x lease time %ld", 
						server_addr, requested_ip, lease);
					
					run_script(&packet,
						   ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));

					fail_times = 0;		/* clear the retry counter */
					state = BOUND;
					change_mode(LISTEN_NONE);
					if (client_config.quit_after_lease)
						return 0;
					if (!client_config.foreground)
						client_background();

				} else if (*message == DHCPNAK) {
					/* return to init state */
					LOG(LOG_INFO, "Received DHCP NAK");

					if ((temp = get_option(&packet, DHCP_SERVER_ID))) 
						memcpy(&server_addr, temp, 4);
					msglogd(LOG_INFO, LOGTYPE_DHCP, "DHCPC Recv NAK from server %x with ip %x", server_addr, requested_ip);

					run_script(&packet, "nak");
					if (state != REQUESTING)
						run_script(NULL, "deconfig");
					state = INIT_SELECTING;
					timeout = now + 3;	/* change by lsz 080905, without this 3 seconds,
										 * the udhcpc will keep on trying and the release
										 * msg cant be recved by udhcpc, even if we are
										 * wan static ip now, the udhcpc is still sending 
										 * discover pkts. 
										 */
					requested_ip = 0;
					packet_num = 0;
					change_mode(LISTEN_RAW);
					//sleep(3); /* avoid excessive network traffic */
				}
				break;
			/* case BOUND, RELEASED: - ignore all packets */
			}
		} 
		else if (retval > 0 && (sig = udhcp_sp_read(&rfds))) {
예제 #16
0
파일: dhcpd.c 프로젝트: GunioRobot/rtn56u
int main(int argc, char *argv[])
#endif
{	
	fd_set rfds;
	struct timeval tv;
	int server_socket = -1;
	int bytes, retval;
	struct dhcpMessage packet;
	unsigned char *state;
	unsigned char *server_id, *requested, *hostname;
	u_int32_t server_id_align, requested_align;
	unsigned long timeout_end;
	struct option_set *option;
	struct dhcpOfferedAddr *lease;
	int pid_fd;
	int max_sock;
	int sig;
	
	OPEN_LOG("udhcpd");
	LOG(LOG_INFO, "udhcp server (v%s) started", VERSION);

	memset(&server_config, 0, sizeof(struct server_config_t));
	
	if (argc < 2)
		read_config(DHCPD_CONF_FILE);
	else read_config(argv[1]);

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

	if ((option = find_option(server_config.options, DHCP_LEASE_TIME))) {
		memcpy(&server_config.lease, option->data + 2, 4);
		server_config.lease = ntohl(server_config.lease);
	}
	else server_config.lease = LEASE_TIME;
	
	leases = malloc(sizeof(struct dhcpOfferedAddr) * server_config.max_leases);
	memset(leases, 0, sizeof(struct dhcpOfferedAddr) * server_config.max_leases);

	// Added by Joey to load static lease
	if (argc>=3)
	{
		load_leases(argv[2]);
	}

	read_leases(server_config.lease_file);

	if (read_interface(server_config.interface, &server_config.ifindex,
			   &server_config.server, server_config.arp) < 0)
		exit_server(1);

#ifndef DEBUGGING
	pid_fd = pidfile_acquire(server_config.pidfile); /* hold lock during fork. */
	if (daemon(0, 0) == -1) {
		perror("fork");
		exit_server(1);
	}
	pidfile_write_release(pid_fd);
#endif

	/* ensure that stdin/stdout/stderr are never returned by pipe() */
	if (fcntl(STDIN_FILENO, F_GETFL) == -1)
		(void) open("/dev/null", O_RDONLY);
	if (fcntl(STDOUT_FILENO, F_GETFL) == -1)
		(void) open("/dev/null", O_WRONLY);
	if (fcntl(STDERR_FILENO, F_GETFL) == -1)
		(void) open("/dev/null", O_WRONLY);

	/* setup signal handlers */
	pipe(signal_pipe);
	signal(SIGUSR1, signal_handler);
	signal(SIGTERM, signal_handler);

	timeout_end = uptime() + server_config.auto_time;
	while(1) { /* loop until universe collapses */

		if (server_socket < 0)
			if ((server_socket = listen_socket(INADDR_ANY, SERVER_PORT, server_config.interface)) < 0) {
				LOG(LOG_ERR, "FATAL: couldn't create server socket, %s", strerror(errno));
				exit_server(0);
			}			

		FD_ZERO(&rfds);
		FD_SET(server_socket, &rfds);
		FD_SET(signal_pipe[0], &rfds);
		if (server_config.auto_time) {
			tv.tv_sec = timeout_end - uptime();
			tv.tv_usec = 0;
		}
		if (!server_config.auto_time || tv.tv_sec > 0) {
			max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
			retval = select(max_sock + 1, &rfds, NULL, NULL, 
					server_config.auto_time ? &tv : NULL);
		} else retval = 0; /* If we already timed out, fall through */

		if (retval == 0) {
			write_leases();
			timeout_end = uptime() + server_config.auto_time;
			continue;
		} else if (retval < 0 && errno != EINTR) {
			DEBUG(LOG_INFO, "error on select");
			continue;
		}
		
		if (FD_ISSET(signal_pipe[0], &rfds)) {
			if (read(signal_pipe[0], &sig, sizeof(sig)) < 0)
				continue; /* probably just EINTR */
			switch (sig) {
			case SIGUSR1:
				LOG(LOG_INFO, "Received a SIGUSR1");
				write_leases();
				/* why not just reset the timeout, eh */
				timeout_end = uptime() + server_config.auto_time;
				continue;
			case SIGTERM:
				LOG(LOG_INFO, "Received a SIGTERM");
				exit_server(0);
			}
		}

		if ((bytes = get_packet(&packet, server_socket)) < 0) { /* this waits for a packet - idle */
			if (bytes == -1 && errno != EINTR) {
				DEBUG(LOG_INFO, "error on read, %s, reopening socket", strerror(errno));
				close(server_socket);
				server_socket = -1;
			}
			continue;
		}

		if ((state = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) {
			DEBUG(LOG_ERR, "couldn't get option from packet, ignoring");
			continue;
		}
		
		server_id = get_option(&packet, DHCP_SERVER_ID);
		if (server_id) {
			memcpy(&server_id_align, server_id, 4);
			if (server_id_align != server_config.server) {
				/* client talks to somebody else */
				DEBUG(LOG_INFO,"server ID %08x doesn't match, ignoring", ntohl(server_id_align));
				continue;
			}
		}

		/* ADDME: look for a static lease */
		lease = find_lease_by_chaddr(packet.chaddr);
		switch (state[0]) {
		case DHCPDISCOVER:
			DEBUG(LOG_INFO,"received DISCOVER");
			
			if (sendOffer(&packet) < 0) {
				LOG(LOG_ERR, "send OFFER failed");
			}
			break;			
 		case DHCPREQUEST:
			DEBUG(LOG_INFO, "received REQUEST");

			requested = get_option(&packet, DHCP_REQUESTED_IP);
			hostname = get_option(&packet, DHCP_HOST_NAME);

			if (requested) memcpy(&requested_align, requested, 4);
		
			if (lease) { /*ADDME: or static lease */
				if (server_id) {
					/* SELECTING State */
					if (requested && 
					    requested_align == lease->yiaddr) {
						sendACK(&packet, lease->yiaddr);
					}
				} else {
					if (requested) {
						/* INIT-REBOOT State */
						if (lease->yiaddr == requested_align)
							sendACK(&packet, lease->yiaddr);
						else sendNAK(&packet);
					} else {
						/* RENEWING or REBINDING State */
						if (lease->yiaddr == packet.ciaddr)
							sendACK(&packet, lease->yiaddr);
						else {
							/* don't know what to do!!!! */
							sendNAK(&packet);
						}
					}						
				}
				if (hostname) {
					bytes = hostname[-1];
					if (bytes >= (int) sizeof(lease->hostname))
						bytes = sizeof(lease->hostname) - 1;
					strncpy(lease->hostname, hostname, bytes);
					lease->hostname[bytes] = '\0';

					if (!is_valid_hostname(lease->hostname))
						lease->hostname[0] = '\0';

				} else
					lease->hostname[0] = '\0';
			
			/* what to do if we have no record of the client */
			} else if (server_id) {
				/* SELECTING State */
				if (requested)
					sendNAK(&packet);

			} else if (requested) {
				/* INIT-REBOOT State */
				if ((lease = find_lease_by_yiaddr(requested_align))) {
					if (lease_expired(lease)) {
						/* probably best if we drop this lease */
						memset(lease->chaddr, 0, 16);
					/* make some contention for this address */
					} else sendNAK(&packet);
				} else if (requested_align < server_config.start || 
					   requested_align > server_config.end) {
					sendNAK(&packet);
				} else {
					sendNAK(&packet);
				}
			} else if (packet.ciaddr) {
				/* RENEWING or REBINDING State */
				sendNAK(&packet);
			}
			break;
		case DHCPDECLINE:
			DEBUG(LOG_INFO,"received DECLINE");
			if (lease) {
				memset(lease->chaddr, 0, 16);
				lease->expires = uptime() + server_config.decline_time;
			}			
			break;
		case DHCPRELEASE:
			DEBUG(LOG_INFO,"received RELEASE");
			if (lease) lease->expires = uptime();
			break;
		case DHCPINFORM:
			DEBUG(LOG_INFO,"received INFORM");
			send_inform(&packet);
			break;	
		default:
			LOG(LOG_WARNING, "unsupported DHCP message (%02x) -- ignoring", state[0]);
		}
	}

	return 0;
}