X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Fudhcp%2Fdhcpc.c;h=9a2fe35e4d169e0b03047cef61e441d4ea4f46c9;hb=695fa51c80047eb25cc82e6e1630b4545a6bc0b6;hp=077098f42952600419db48d9b7b9372ecac6cb89;hpb=4248c33a8528564213d0787770e64b224d134c26;p=oweals%2Fbusybox.git diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 077098f42..9a2fe35e4 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -7,9 +7,7 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ - #include - /* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ #define WANT_PIDFILE 1 #include "common.h" @@ -25,14 +23,20 @@ static int sockfd = -1; #define LISTEN_RAW 2 static smallint listen_mode; +/* initial state: (re)start DHCP negotiation */ #define INIT_SELECTING 0 +/* discover was sent, DHCPOFFER reply received */ #define REQUESTING 1 +/* select/renew was sent, DHCPACK reply received */ #define BOUND 2 +/* half of lease passed, want to renew it by sending unicast renew requests */ #define RENEWING 3 +/* renew requests were not answered, lease is almost over, send broadcast renew */ #define REBINDING 4 -#define INIT_REBOOT 5 -#define RENEW_REQUESTED 6 -#define RELEASED 7 +/* manually requested renew (SIGUSR1) */ +#define RENEW_REQUESTED 5 +/* release, possibly manually requested (SIGUSR2) */ +#define RELEASED 6 static smallint state; /* struct client_config_t client_config is in bb_common_bufsiz1 */ @@ -42,7 +46,10 @@ static smallint state; static void change_listen_mode(int new_mode) { log1("Entering listen mode: %s", - new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); + new_mode != LISTEN_NONE + ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") + : "none" + ); listen_mode = new_mode; if (sockfd >= 0) { @@ -349,14 +356,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) tv.tv_sec = timeout - already_waited_sec; tv.tv_usec = 0; retval = 0; /* If we already timed out, fall through, else... */ - if (tv.tv_sec > 0) { + if ((int)tv.tv_sec > 0) { timestamp_before_wait = (unsigned)monotonic_sec(); log1("Waiting on select..."); retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); if (retval < 0) { /* EINTR? A signal was caught, don't panic */ - if (errno == EINTR) + if (errno == EINTR) { + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; continue; + } /* Else: an error occured, panic! */ bb_perror_msg_and_die("select"); } @@ -374,9 +383,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) if (packet_num < discover_retries) { if (packet_num == 0) xid = random_xid(); - - send_discover(xid, requested_ip); /* broadcast */ - + /* broadcast */ + send_discover(xid, requested_ip); timeout = discover_timeout; packet_num++; continue; @@ -400,44 +408,41 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) timeout = tryagain_timeout; packet_num = 0; continue; - case RENEW_REQUESTED: case REQUESTING: if (packet_num < discover_retries) { - /* send request packet */ - if (state == RENEW_REQUESTED) /* unicast */ - send_renew(xid, server_addr, requested_ip); - else /* broadcast */ - send_select(xid, server_addr, requested_ip); - + /* send broadcast select packet */ + send_select(xid, server_addr, requested_ip); timeout = discover_timeout; packet_num++; continue; } - /* timed out, go back to init state */ - if (state == RENEW_REQUESTED) - udhcp_run_script(NULL, "deconfig"); - change_listen_mode(LISTEN_RAW); - /* "discover...select...discover..." loops + /* Timed out, go back to init state. + * "discover...select...discover..." loops * were seen in the wild. Treat them similarly * to "no response to discover" case */ - if (state == REQUESTING) { - state = INIT_SELECTING; - goto leasefail; - } + change_listen_mode(LISTEN_RAW); state = INIT_SELECTING; - timeout = 0; - packet_num = 0; - continue; + goto leasefail; case BOUND: - /* Half of the lease passed, time to enter renewing state */ + /* 1/2 lease passed, enter renewing state */ + state = RENEWING; change_listen_mode(LISTEN_KERNEL); log1("Entering renew state"); - state = RENEWING; /* fall right through */ + case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ + case_RENEW_REQUESTED: case RENEWING: if (timeout > 60) { - /* send a request packet */ - send_renew(xid, server_addr, requested_ip); /* unicast */ + /* send an unicast renew request */ + /* Sometimes observed to fail (EADDRNOTAVAIL) to bind + * a new UDP socket for sending inside send_renew. + * I hazard to guess existing listening socket + * is somehow conflicting with it, but why is it + * not deterministic then?! Strange. + * Anyway, it does recover by eventually failing through + * into INIT_SELECTING state. + */ + send_renew(xid, server_addr, requested_ip); timeout >>= 1; continue; } @@ -446,18 +451,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) state = REBINDING; /* fall right through */ case REBINDING: + /* Switch to bcast receive */ + change_listen_mode(LISTEN_RAW); /* Lease is *really* about to run out, * try to find DHCP server using broadcast */ if (timeout > 0) { - /* send a request packet */ - send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); /* broadcast */ + /* send a broadcast renew request */ + send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); timeout >>= 1; continue; } /* Timed out, enter init state */ bb_info_msg("Lease lost, entering init state"); udhcp_run_script(NULL, "deconfig"); - change_listen_mode(LISTEN_RAW); state = INIT_SELECTING; /*timeout = 0; - already is */ packet_num = 0; @@ -476,9 +482,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (udhcp_sp_read(&rfds)) { case SIGUSR1: perform_renew(); + if (state == RENEW_REQUESTED) + goto case_RENEW_REQUESTED; /* Start things over */ packet_num = 0; - /* Kill any timeouts because the user wants this to hurry along */ + /* Kill any timeouts, user wants this to hurry along */ timeout = 0; continue; case SIGUSR2: @@ -562,9 +570,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) already_waited_sec = 0; } continue; - case RENEW_REQUESTED: case REQUESTING: case RENEWING: + case RENEW_REQUESTED: case REBINDING: if (*message == DHCPACK) { temp = get_option(&packet, DHCP_LEASE_TIME); @@ -621,8 +629,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) inet_ntoa(temp_addr), (unsigned)lease_seconds); } requested_ip = packet.yiaddr; - udhcp_run_script(&packet, - ((state == RENEWING || state == REBINDING) ? "renew" : "bound")); + udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); state = BOUND; change_listen_mode(LISTEN_NONE); @@ -631,6 +638,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) perform_release(requested_ip, server_addr); goto ret0; } + /* future renew failures should not exit (JM) */ + opt &= ~OPT_n; #if BB_MMU /* NOMMU case backgrounded earlier */ if (!(opt & OPT_f)) { client_background();