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; } /* Start the log, sanitize fd's, and write a pid file */ udhcp_start_log_and_pid(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 = 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; /* When running on a bridge, the ifindex may have changed (e.g. if * member interfaces were added/removed or if the status of the * bridge changed). * Workaround: refresh it here before processing the next packet */ read_interface(client_config.interface, &client_config.ifindex, NULL, client_config.arp); 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); } max_fd = udhcp_sp_fd_set(&rfds, fd); 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 (!client_config.retries || (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"); return 1; } /* wait to try again */ packet_num = 0; timeout = now + 60; } break; case RENEW_REQUESTED: case REQUESTING: if (!client_config.retries || (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(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("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; } if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == 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 */ unsigned int lease_tmp = 0; memcpy(&lease_tmp, temp, 4); lease = ntohl(lease_tmp); } if (!arpping(packet.yiaddr, (uint32_t) 0, client_config.arp, client_config.interface) ) { bb_info_msg("Offered address is in use " "(got ARP reply), declining"); send_decline(xid, server_addr, packet.yiaddr); if (state != REQUESTING) udhcp_run_script(NULL, "deconfig"); change_mode(LISTEN_RAW); state = INIT_SELECTING; requested_ip = 0; timeout = now + 20; 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; 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(); return 0; } 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))) {
int main(int argc, char *argv[]) #endif { char *temp, *message; unsigned long t1 = 0, t2 = 0, xid = 0; unsigned long start = 0, lease; fd_set rfds; int fd, retval; struct timeval tv; int c, len; struct ifreq ifr; struct dhcpMessage packet; struct in_addr temp_addr; int pid_fd; static struct option options[] = { {"clientid", required_argument, 0, 'c'}, {"foreground", no_argument, 0, 'f'}, {"hostname", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"interface", required_argument, 0, 'i'}, {"now", no_argument, 0, 'n'}, {"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'}, {"6rd", no_argument, 0, '6'}, {0, 0, 0, 0} }; /* get options */ while (1) { int option_index = 0; // brcm c = getopt_long(argc, argv, "c:fH:hi:np:qr:s:d:v:6I:D:O:S:P:", 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 = malloc(len + 2); client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; client_config.clientid[OPT_LEN] = len; strncpy(client_config.clientid + 2, optarg, len); break; case 'f': client_config.foreground = 1; break; case 'H': len = strlen(optarg) > 255 ? 255 : strlen(optarg); if (client_config.hostname) free(client_config.hostname); client_config.hostname = malloc(len + 2); client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; client_config.hostname[OPT_LEN] = len; strncpy(client_config.hostname + 2, optarg, len); break; case 'h': print_usage(); return 0; case 'i': client_config.interface = optarg; // brcm strcpy(session_path, 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; // brcm case 'd': strcpy(vendor_class_id, optarg); en_vendor_class_id=1; break; case '6': ipv6rd_opt = 1; break; case 's': client_config.script = optarg; break; case 'v': printf("udhcpcd, version %s\n\n", VERSION); break; case 'I': strcpy(iaid, optarg); en_client_id = 1; break; case 'D': strcpy(duid, optarg); en_client_id = 1; break; case 'O': strcpy(oui_125, optarg); en_125 = 1; break; case 'S': strcpy(sn_125, optarg); en_125 = 1; break; case 'P': strcpy(prod_125, optarg); en_125 = 1; break; } } // brcm if (strlen(session_path) > 0) { sprintf(status_path, "%s/%s/%s", _PATH_WAN_DIR, session_path, _PATH_MSG); sprintf(pid_path, "%s/%s/%s", _PATH_WAN_DIR, session_path, _PATH_PID); } OPEN_LOG("udhcpc"); #ifdef VERBOSE cmsLog_setLevel(LOG_LEVEL_DEBUG); #else cmsLog_setLevel(DEFAULT_LOG_LEVEL); #endif LOG(LOG_INFO, "udhcp client (v%s) started", VERSION); cmsMsg_init(EID_DHCPC, &msgHandle); pid_fd = pidfile_acquire(client_config.pidfile); pidfile_write_release(pid_fd); if ((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) >= 0) { strcpy(ifr.ifr_name, client_config.interface); if (ioctl(fd, SIOCGIFINDEX, &ifr) == 0) { DEBUG(LOG_INFO, "adapter index %d", ifr.ifr_ifindex); client_config.ifindex = ifr.ifr_ifindex; } else { LOG(LOG_ERR, "SIOCGIFINDEX failed! %s", strerror(errno)); exit_client(1); } if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) { memcpy(client_config.arp, ifr.ifr_hwaddr.sa_data, 6); DEBUG(LOG_INFO, "adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", client_config.arp[0], client_config.arp[1], client_config.arp[2], client_config.arp[3], client_config.arp[4], client_config.arp[5]); } else { LOG(LOG_ERR, "SIOCGIFHWADDR failed! %s", strerror(errno)); exit_client(1); } } else { LOG(LOG_ERR, "socket failed! %s", strerror(errno)); exit_client(1); } close(fd); fd = -1; /* setup signal handlers */ signal(SIGUSR1, renew_requested); signal(SIGUSR2, release_requested); signal(SIGTERM, terminate); state = INIT_SELECTING; // brcm // run_script(NULL, "deconfig"); // brcm setStatus(0); for (;;) { // brcm if ((old_mode != listen_mode) || (fd == -1)) { old_mode = listen_mode; /* * After dhcpc runs as daemon(backgroud)mode, fd 0-2 be closed. * The sock fd may be 0. */ if (fd >= 0) { close(fd); fd = -1; } if (listen_mode == LISTEN_RAW) { if ((fd = raw_socket(client_config.ifindex)) < 0) { LOG(LOG_ERR, "couldn't create raw socket -- au revoir"); exit_client(0); } } else if (listen_mode == LISTEN_KERNEL) { if ((fd = listen_socket(INADDR_ANY, CLIENT_PORT, client_config.interface)) < 0) { LOG(LOG_ERR, "couldn't create server socket -- au revoir"); exit_client(0); } } else fd = -1; } tv.tv_sec = timeout - time(0); tv.tv_usec = 0; FD_ZERO(&rfds); if (listen_mode) FD_SET(fd, &rfds); if (tv.tv_sec > 0) { retval = select(fd + 1, &rfds, NULL, NULL, &tv); } else retval = 0; /* If we already timed out, fall through */ if (retval == 0) { /* timeout dropped to zero */ switch (state) { case INIT_SELECTING: // brcm setStatus(0); if (packet_num < 3) { if (packet_num == 0) xid = random_xid(); /* send discover packet */ send_discover(xid, requested_ip); /* broadcast */ timeout = time(0) + ((packet_num == 2) ? REQ_TIMEOUT : 2); packet_num++; } 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 = time(0) + INIT_TIMEOUT; } 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 = time(0) + ((packet_num == 2) ? REQ_TIMEOUT : 2); packet_num++; } else { /* timed out, go back to init state */ state = INIT_SELECTING; timeout = time(0); packet_num = 0; listen_mode = LISTEN_RAW; } break; case BOUND: /* Lease is starting to run out, time to enter renewing state */ state = RENEWING; listen_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 = time(0) + (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 = time(0); packet_num = 0; listen_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 = 0xffffffff; break; } } else if (retval > 0 && listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) { /* a packet is ready, read it */ if (listen_mode == LISTEN_KERNEL) { if (get_packet(&packet, fd) < 0) continue; } else { if (get_raw_packet(&packet, fd) < 0) continue; } if (packet.xid != xid) { DEBUG(LOG_INFO, "Ignoring XID %lx (our xid is %lx)", (unsigned long) packet.xid, xid); continue; } if ((message = (char *)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 = (char *)get_option(&packet, DHCP_SERVER_ID))) { memcpy(&server_addr, temp, 4); xid = packet.xid; requested_ip = packet.yiaddr; /* enter requesting state */ state = REQUESTING; timeout = time(0); 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 = (char *)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 = time(0); timeout = t1 + start; requested_ip = packet.yiaddr; run_script(&packet, ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); state = BOUND; listen_mode = LISTEN_NONE; // brcm close(fd); fd = -1; setStatus(1); background(); } else if (*message == DHCPNAK) { /* return to init state */ LOG(LOG_INFO, "Received DHCP NAK"); if (state != REQUESTING) run_script(NULL, "deconfig"); state = INIT_SELECTING; timeout = time(0); requested_ip = 0; packet_num = 0; listen_mode = LISTEN_RAW; // brcm setStatus(0); } break; case BOUND: case RELEASED: /* ignore all packets */ break; } } else if (retval == -1 && errno == EINTR) {
int udhcpc_main(int argc, char *argv[]) { 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; time_t now; int max_fd; int sig; #if 1 FILE *f; f=fopen("/var/run/udhcpc.pid","w"); fprintf(f,"%d",getpid()); fclose(f); #endif static const 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'}, {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': bb_error_msg("version %s\n", VERSION); return(0); break; default: bb_show_usage(); } } start_log("client"); if (read_interface(client_config.interface, &client_config.ifindex, NULL, client_config.arp) < 0) return(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); } background(client_config.pidfile); /* setup signal handlers */ udhcp_set_signal_pipe(SIGUSR2); 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, %m"); return(0); } } if (fd >= 0) FD_SET(fd, &rfds); FD_SET(udhcp_signal_pipe[0], &rfds); if (tv.tv_sec > 0) { DEBUG(LOG_INFO, "Waiting on select...\n"); max_fd = udhcp_signal_pipe[0] > fd ? udhcp_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."); 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 < 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, %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; } 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) return(0); if (!client_config.foreground) client_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(udhcp_signal_pipe[0], &rfds)) {
/*---------------------------------------------------------------------------*/ static PT_THREAD(handle_dhcp(void)) { PT_BEGIN(&s.pt); /* try_again:*/ s.state = STATE_SENDING; s.ticks = CLOCK_SECOND; do { send_discover(); timer_set(&s.timer, s.ticks); uip_flags = 0; PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); if(uip_newdata() && parse_msg() == DHCPOFFER) { s.state = STATE_OFFER_RECEIVED; break; } if(s.ticks < CLOCK_SECOND * 60) { s.ticks *= 2; } } while(s.state != STATE_OFFER_RECEIVED); s.ticks = CLOCK_SECOND; do { send_request(); timer_set(&s.timer, s.ticks); uip_flags = 0; PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer)); if(uip_newdata() && parse_msg() == DHCPACK) { s.state = STATE_CONFIG_RECEIVED; break; } if(s.ticks <= CLOCK_SECOND * 10) { s.ticks += CLOCK_SECOND; } else { PT_RESTART(&s.pt); } } while(s.state != STATE_CONFIG_RECEIVED); #if 0 printf("Got IP address %d.%d.%d.%d\n", uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr), uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr)); printf("Got netmask %d.%d.%d.%d\n", uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask), uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask)); printf("Got DNS server %d.%d.%d.%d\n", uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr), uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr)); printf("Got default router %d.%d.%d.%d\n", uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router), uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router)); printf("Lease expires in %ld seconds\n", ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1])); #endif dhcpc_configured(&s); /* timer_stop(&s.timer);*/ /* * PT_END restarts the thread so we do this instead. Eventually we * should reacquire expired leases here. */ while(1) { PT_YIELD(&s.pt); } PT_END(&s.pt); }
/*---------------------------------------------------------------------------*/ static PT_THREAD(handle_dhcp(process_event_t ev, void *data)) { clock_time_t ticks; PT_BEGIN(&s.pt); init: xid++; s.state = STATE_SENDING; s.ticks = CLOCK_SECOND; while (1) { while(ev != tcpip_event) { tcpip_poll_udp(s.conn); PT_YIELD(&s.pt); } send_discover(); etimer_set(&s.etimer, s.ticks); do { PT_YIELD(&s.pt); if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPOFFER) { parse_msg(); s.state = STATE_OFFER_RECEIVED; goto selecting; } } while (!etimer_expired(&s.etimer)); if(s.ticks < CLOCK_SECOND * 60) { s.ticks *= 2; } } selecting: xid++; s.ticks = CLOCK_SECOND; do { while(ev != tcpip_event) { tcpip_poll_udp(s.conn); PT_YIELD(&s.pt); } send_request(); etimer_set(&s.etimer, s.ticks); do { PT_YIELD(&s.pt); if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) { parse_msg(); s.state = STATE_CONFIG_RECEIVED; goto bound; } } while (!etimer_expired(&s.etimer)); if(s.ticks <= CLOCK_SECOND * 10) { s.ticks += CLOCK_SECOND; } else { goto init; } } while(s.state != STATE_CONFIG_RECEIVED); bound: #if 0 printf("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.ipaddr)); printf("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.netmask)); printf("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.dnsaddr)); printf("Got default router %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.default_router)); printf("Lease expires in %ld seconds\n", uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])); #endif dhcpc_configured(&s); #define MAX_TICKS (~((clock_time_t)0) / 2) #define MAX_TICKS32 (~((uint32_t)0)) #define IMIN(a, b) ((a) < (b) ? (a) : (b)) if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 <= MAX_TICKS32) { s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) )*CLOCK_SECOND/2; } else { s.ticks = MAX_TICKS32; } while(s.ticks > 0) { ticks = IMIN(s.ticks, MAX_TICKS); s.ticks -= ticks; etimer_set(&s.etimer, ticks); PT_YIELD_UNTIL(&s.pt, etimer_expired(&s.etimer)); } if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 <= MAX_TICKS32) { s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) )*CLOCK_SECOND/2; } else { s.ticks = MAX_TICKS32; } /* renewing: */ xid++; do { while(ev != tcpip_event) { tcpip_poll_udp(s.conn); PT_YIELD(&s.pt); } send_request(); ticks = IMIN(s.ticks / 2, MAX_TICKS); s.ticks -= ticks; etimer_set(&s.etimer, ticks); do { PT_YIELD(&s.pt); if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) { parse_msg(); goto bound; } } while(!etimer_expired(&s.etimer)); } while(s.ticks >= CLOCK_SECOND*3); /* rebinding: */ /* lease_expired: */ dhcpc_unconfigured(&s); goto init; PT_END(&s.pt); }
static PT_THREAD (handle_dhcp (void)) { PT_BEGIN (&dhcpcState->pt); dhcpcState->state = STATE_SENDING; dhcpcState->ticks = CLOCK_SECOND; do { send_discover (); timer_set (&dhcpcState->timer, dhcpcState->ticks); PT_WAIT_UNTIL (&dhcpcState->pt, uip_newdata () || timer_expired (&dhcpcState->timer)); if (uip_newdata () && (parse_msg () == DHCPOFFER)) { uip_flags &= ~UIP_NEWDATA; dhcpcState->state = STATE_OFFER_RECEIVED; break; } uip_flags &= ~UIP_NEWDATA; if (dhcpcState->ticks < CLOCK_SECOND * 60) dhcpcState->ticks *= 2; else { dhcpcState->ipaddr [0] = dhcpcState->ipaddr [1] = 0; goto dhcpcf; } } while (dhcpcState->state != STATE_OFFER_RECEIVED); dhcpcState->ticks = CLOCK_SECOND; do { send_request (); timer_set (&dhcpcState->timer, dhcpcState->ticks); PT_WAIT_UNTIL (&dhcpcState->pt, uip_newdata () || timer_expired (&dhcpcState->timer)); if (uip_newdata () && (parse_msg () == DHCPACK)) { uip_flags &= ~UIP_NEWDATA; dhcpcState->state = STATE_CONFIG_RECEIVED; break; } uip_flags &= ~UIP_NEWDATA; if (dhcpcState->ticks <= CLOCK_SECOND * 10) dhcpcState->ticks += CLOCK_SECOND; else PT_RESTART (&dhcpcState->pt); } while (dhcpcState->state != STATE_CONFIG_RECEIVED); dhcpcf: dhcpc_configured (dhcpcState); /* timer_stop (&dhcpcState->timer);*/ /* * PT_END restarts the thread so we do this instead. Eventually we * should reacquire expired leases here. */ while (1) PT_YIELD (&dhcpcState->pt); PT_END (&dhcpcState->pt); }
static void handle_dhcp(process_event_t message) { time_t seconds; switch( dhcpc_state.state ) { case DHCP_STATE_INITIAL: dhcpc_state.state = DHCP_STATE_DISCOVER; xid++; send_discover(); stimer_set(&dhcpc_state.stimer, (time_t)10 ); // normally set the timer for 60 seconds, // but because the ARP table is empty give DHCP server only 10 seconds. break; case DHCP_STATE_DISCOVER: if( !stimer_expired(&dhcpc_state.stimer) && message == DHCP_OFFER ) { parse_msg(); dhcpc_state.state = DHCP_STATE_REQUEST; xid++; send_request(); stimer_set(&dhcpc_state.stimer, (time_t)10 ); // set the timer for 10 seconds } else { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_REQUEST: if( !stimer_expired(&dhcpc_state.stimer) && message == DHCP_ACK ) { parse_msg(); dhcpc_state.state = DHCP_STATE_LEASED; PRINTF("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.ipaddr)); PRINTF("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.netmask)); PRINTF("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.dnsaddr)); PRINTF("Got default router %d.%d.%d.%d\n", uip_ipaddr_to_quad(&dhcpc_state.default_router)); PRINTF("Lease expires in %ld seconds\n", uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1])); dhcpc_configured(&dhcpc_state); #define MAX_TICKS (~((time_t)0) / 2) #define MAX_TICKS32 (~((time_t)0)) if((uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1]))/2 <= MAX_TICKS32) { seconds = ( uip_ntohs(dhcpc_state.lease_time[0])*65536ul + uip_ntohs(dhcpc_state.lease_time[1]) )/2; } else { seconds = MAX_TICKS32; } stimer_set(&dhcpc_state.stimer, seconds); // set the timer for half of lease_time seconds } else { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_LEASED: if( stimer_expired(&dhcpc_state.stimer) ) { dhcpc_state.state = DHCP_STATE_INITIAL; } break; case DHCP_STATE_REREQUEST: case DHCP_STATE_RELEASE: default: dhcpc_state.state = DHCP_STATE_INITIAL; break; } }
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))) {
static void dhcp_run(void) { static bool udp_open_fail = FALSE; if(di.state == DHCP_STATE_INIT && di.action != DHCP_ACT_START) { DBG("wrong attempt"); return; } else if(GetUDPSocketStatus(di.sock) == SOCKSTAT_CLOSED) { if(udp_open_fail == TRUE && !IS_TIME_PASSED(dhcp_run_tick, DHCP_RETRY_DELAY)) goto RET_ALARM; if(UDPOpen(di.sock, DHCP_CLIENT_PORT) == RET_OK) { if(dhcp_async) sockwatch_open(di.sock, dhcp_async_cb); udp_open_fail = FALSE; dhcp_run_tick = wizpf_get_systick(); dhcp_run_cnt = 0; } else { ERR("UDPOpen fail"); udp_open_fail = TRUE; dhcp_run_tick = wizpf_get_systick(); goto RET_ALARM; } } switch(di.state) { case DHCP_STATE_INIT: if(dhcp_run_cnt==0 && !IS_TIME_PASSED(dhcp_run_tick, DHCP_OPEN_DELAY)) goto RET_ALARM; if(dhcp_run_cnt < DHCP_SEND_RETRY_COUNT) { dhcp_run_cnt++; if(send_discover() == RET_OK) { // Discover ok if(dhcp_async) { DBG("DHCP Discovery Send Async"); sockwatch_set(di.sock, WATCH_SOCK_UDP_SEND); return; // alarm set is not needed } else { DBG("DHCP Discovery Sent"); SET_STATE(DHCP_STATE_SEARCHING); dhcp_run_tick = wizpf_get_systick(); } } else { ERRA("DHCP Discovery SEND fail - (%d)times", dhcp_run_cnt); dhcp_run_tick = wizpf_get_systick(); } } else { ERRA("DHCP Discovery SEND fail - (%d)times", dhcp_run_cnt); dhcp_run_cnt = 0; UDPClose(di.sock); if(dhcp_async) sockwatch_close(di.sock); dhcp_fail(); return; // alarm set is not needed } break; case DHCP_STATE_SEARCHING: if(!IS_TIME_PASSED(dhcp_run_tick, DHCP_RETRY_DELAY)) { int8 ret = recv_handler(); if(ret == DHCP_MSG_OFFER) { SET_STATE(DHCP_STATE_SELECTING); dhcp_run_tick = wizpf_get_systick(); dhcp_run_cnt = 0; } else if(ret != RET_NOK) DBGCRTCA(TRUE, "recv wrong packet(%d)", ret); } else { ERRA("DHCP Offer RECV fail - for (%d)msec", DHCP_RETRY_DELAY); SET_STATE(DHCP_STATE_INIT); dhcp_run_tick = wizpf_get_systick(); } break; case DHCP_STATE_SELECTING: if(dhcp_run_cnt < DHCP_SEND_RETRY_COUNT) { dhcp_run_cnt++; if(send_request() == RET_OK) { // Request ok if(dhcp_async) { DBG("DHCP Request Send Async"); sockwatch_set(di.sock, WATCH_SOCK_UDP_SEND); return; // alarm set is not needed } else { DBG("DHCP Request Sent"); SET_STATE(DHCP_STATE_REQUESTING); dhcp_run_tick = wizpf_get_systick(); } } else { ERRA("DHCP Request SEND fail - (%d)times", dhcp_run_cnt); dhcp_run_tick = wizpf_get_systick(); } } else { ERRA("DHCP Request SEND fail - (%d)times", dhcp_run_cnt); dhcp_run_cnt = 0; UDPClose(di.sock); if(dhcp_async) sockwatch_close(di.sock); dhcp_fail(); return; // alarm set is not needed } break; case DHCP_STATE_REQUESTING: if(!IS_TIME_PASSED(dhcp_run_tick, DHCP_RETRY_DELAY)) { int8 ret = recv_handler(); if(ret == DHCP_MSG_ACK) { // Recv ACK LOG("DHCP Success"); SET_STATE(DHCP_STATE_IP_CHECK); dhcp_run_tick = wizpf_get_systick(); dhcp_run_cnt = 0; } else if(ret == DHCP_MSG_NAK) { // Recv NAK if(di.action == DHCP_ACT_START) { SET_STATE(DHCP_STATE_INIT); dhcp_run_tick = wizpf_get_systick(); } else { SET_STATE(DHCP_STATE_BOUND); } dhcp_run_cnt = 0; } else if(ret != RET_NOK) DBGCRTCA(TRUE, "recv wrong packet(%d)", ret); } else { ERRA("DHCP ACK RECV fail - for (%d)msec", DHCP_RETRY_DELAY); if(di.action == DHCP_ACT_START) { SET_STATE(DHCP_STATE_INIT); dhcp_run_tick = wizpf_get_systick(); } else { SET_STATE(DHCP_STATE_BOUND); } } break; case DHCP_STATE_IP_CHECK: //if(send_checker() == RET_OK) { SET_STATE(DHCP_STATE_BOUND); workinfo.DHCP = NETINFO_DHCP_STABLE; SetNetInfo(&workinfo); if(di.ip_update) di.ip_update(); LOGA("DHCP ok - New IP (%d.%d.%d.%d)", workinfo.IP[0], workinfo.IP[1], workinfo.IP[2], workinfo.IP[3]); //bound_tick = wizpf_get_systick(); UDPClose(di.sock); if(dhcp_async) sockwatch_close(di.sock); //} else { // SET_STATE(DHCP_STATE_INIT); // ERR("IP Addr conflicted - IP(%d.%d.%d.%d)", workinfo.IP[0], workinfo.IP[1], workinfo.IP[2], workinfo.IP[3]); // send_rel_dec(DHCP_MSG_DECLINE); // if(di.ip_conflict) (*di.ip_conflict)(); //} break; case DHCP_STATE_BOUND: return; // alarm set is not needed default: ERRA("wrong state(%d)", di.state); return; // alarm set is not needed } RET_ALARM: if(dhcp_alarm) alarm_set(10, dhcp_alarm_cb, 0); }
void Casan::loop () { Msg in (l2_) ; Msg out (l2_) ; l2net::l2_recv_t ret ; uint8_t oldstatus ; long int hlid ; l2addr *srcaddr ; int mtu ; // mtu announced by master in assoc msg oldstatus = status_ ; // keep old value for debug display sync_time (curtime) ; // get current time retrans_.loop (*l2_, curtime) ; // check needed retransmissions srcaddr = NULL ; ret = in.recv () ; // get received message if (ret == l2net::RECV_OK) srcaddr = l2_->get_src () ; // get a new address switch (status_) { case SL_COLDSTART : send_discover (out) ; twait_.init (curtime) ; status_ = SL_WAITING_UNKNOWN ; break ; case SL_WAITING_UNKNOWN : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; change_master (hlid, -1) ; // don't change mtu twait_.init (curtime) ; status_ = SL_WAITING_KNOWN ; } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; change_master (-1, mtu) ; // "unknown" hlid send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } } if (status_ == SL_WAITING_UNKNOWN && twait_.next (curtime)) send_discover (out) ; break ; case SL_WAITING_KNOWN : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; change_master (hlid, -1) ; // don't change mtu } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; change_master (-1, mtu) ; // unknown hlid send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } } if (status_ == SL_WAITING_KNOWN) { if (twait_.expired (curtime)) { reset_master () ; // master_ is no longer known send_discover (out) ; twait_.init (curtime) ; // reset timer status_ = SL_WAITING_UNKNOWN ; } else if (twait_.next (curtime)) { send_discover (out) ; } } break ; case SL_RUNNING : case SL_RENEW : if (ret == l2net::RECV_OK) { retrans_.check_msg_received (in) ; if (is_ctl_msg (in)) { if (is_hello (in, hlid)) { DBGLN1 (F ("Received a CTL HELLO msg")) ; if (! same_master (srcaddr) || hlid != hlid_) { int oldhlid = hlid_ ; change_master (hlid, 0) ; // reset mtu if (oldhlid != -1) { twait_.init (curtime) ; status_ = SL_WAITING_KNOWN ; } } } else if (is_assoc (in, sttl_, mtu)) { DBGLN1 (F ("Received a CTL ASSOC msg")) ; if (same_master (srcaddr)) { negociate_mtu (mtu) ; send_assoc_answer (in, out) ; trenew_.init (curtime, sttl_) ; status_ = SL_RUNNING ; } } else DBGLN1 (F (RED ("Unkwnon CTL"))) ; } else // request for a normal resource { // deduplicate () ; process_request (in, out) ; out.send (*master_) ; } } else if (ret == l2net::RECV_TRUNCATED) { DBGLN1 (F (RED ("Request too large"))) ; out.set_type (COAP_TYPE_ACK) ; out.set_id (in.get_id ()) ; out.set_token (in.get_token ()) ; option o (option::MO_Size1, l2_->mtu ()) ; out.push_option (o) ; out.set_code (COAP_CODE_TOO_LARGE) ; out.send (*master_) ; } check_observed_resources (out) ; if (status_ == SL_RUNNING && trenew_.renew (curtime)) { send_discover (out) ; status_ = SL_RENEW ; } if (status_ == SL_RENEW && trenew_.next (curtime)) { send_discover (out) ; } if (status_ == SL_RENEW && trenew_.expired (curtime)) { reset_master () ; // master_ is no longer known send_discover (out) ; twait_.init (curtime) ; // reset timer status_ = SL_WAITING_UNKNOWN ; } break ; default : DBGLN1 (F ("Error : casan status not known")) ; DBGLN1 (status_) ; break ; } if (oldstatus != status_) { DBG1 (F ("Status: " C_GREEN)) ; print_status (oldstatus) ; DBG1 (F (C_RESET " -> " C_GREEN)) ; print_status (status_) ; DBGLN1 (F (C_RESET)) ; } if (srcaddr != NULL) delete srcaddr ; }
void dhcp_net_main(void) { if(uip_newdata()) { switch (uip_udp_conn->appstate.dhcp.state) { case STATE_DISCOVERING: if (parse_msg() == DHCPOFFER) { send_request(); uip_flags &= ~UIP_NEWDATA; uip_udp_conn->appstate.dhcp.state = STATE_REQUESTING; uip_udp_conn->appstate.dhcp.retry_timer = 2; // retry uip_udp_conn->appstate.dhcp.retry_counter = 1; tick_sec = 0; } break; case STATE_REQUESTING: if (parse_msg() == DHCPACK) { uip_udp_conn->appstate.dhcp.state = STATE_CONFIGURED; uip_sethostaddr(uip_udp_conn->appstate.dhcp.ipaddr); uip_setdraddr(uip_udp_conn->appstate.dhcp.default_router); uip_setnetmask(uip_udp_conn->appstate.dhcp.netmask); #ifdef DNS_SUPPORT resolv_conf(uip_udp_conn->appstate.dhcp.dnsaddr); // eeprom_save(dns_server, &uip_udp_conn->appstate.dhcp.dnsaddr, IPADDR_LEN); #endif // eeprom_save(ip, &uip_udp_conn->appstate.dhcp.ipaddr, IPADDR_LEN); // eeprom_save(netmask, &uip_udp_conn->appstate.dhcp.netmask, IPADDR_LEN); // eeprom_save(gateway, &uip_udp_conn->appstate.dhcp.default_router, IPADDR_LEN); // eeprom_update_chksum(); /* Remove the bootp connection */ uip_udp_remove(uip_udp_conn); } break; } } else { // No data yet switch (uip_udp_conn->appstate.dhcp.state) { case STATE_INITIAL: case STATE_DISCOVERING: if (tick_sec>uip_udp_conn->appstate.dhcp.retry_timer) { send_discover(); uip_flags &= ~UIP_NEWDATA; uip_udp_conn->appstate.dhcp.state = STATE_DISCOVERING; if (uip_udp_conn->appstate.dhcp.retry_counter++>10) return dhcp_set_static(); uip_udp_conn->appstate.dhcp.retry_timer = 2 * uip_udp_conn->appstate.dhcp.retry_counter; // retry tick_sec = 0; } break; case STATE_REQUESTING: if (tick_sec>uip_udp_conn->appstate.dhcp.retry_timer) { send_request(); uip_flags &= ~UIP_NEWDATA; if (uip_udp_conn->appstate.dhcp.retry_counter++>10) return dhcp_set_static(); uip_udp_conn->appstate.dhcp.retry_timer = 2; // retry tick_sec = 0; } break; } } }