Bug 9061

Summary: udhcpc: quick renew and release when link is down doesn't call script to deconfig
Product: Busybox Reporter: Bin Guo <gb2312>
Component: NetworkingAssignee: unassigned
Status: RESOLVED FIXED    
Severity: normal CC: busybox-cvs
Priority: P5    
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Host: Target:
Build:

Description Bin Guo 2016-07-01 22:03:56 UTC
Observed with 1.15.3 but looks like the code is similar: with udhcpc in BOUND=2 state, when the link goes down and external applications ask udhcpc to renew and release the address, which can be simulated by

  killall 1 udhpc; killall 2 udhpc

then udhcpc gets into RELEASED=6 state without calling script for deconfig. This
leaves ip/route still configured with link down and dhcp released.

An instrumented networking/udhcp/udhcpc.c showed this trace:

# link down!
$ killall 1 udhpc; killall 2 udhpc
Performing a DHCP renew
state: 2 -> 5
Sending renew...
Entering released state
state: 5 -> 6  <<<<<<<<<<<<<< not calling script!!!!
# ip/route still present now

This shows:

  SIGUSR1: perform_renew(): state: BOUND=2 -> RENEW_REQUESTED=5
  SIGUSR2: perform_release(): state: RENEW_REQUESTED=5 -> RELEASED=6

RENEW_REQUESTED->RELEASED would not call udhcp_run_script(NULL, "deconfig")
I believe the need to call deconfig should be remembered...

Related functions:

/* Called only on SIGUSR1 */
static void perform_renew(void)
{
    bb_error_msg("performing DHCP renew");
    switch (state) {
    case BOUND:
        change_listen_mode(LISTEN_KERNEL);
    case RENEWING:
    case REBINDING:
        state = RENEW_REQUESTED;
        break; 
    case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
        udhcp_run_script(NULL, "deconfig");
    case REQUESTING:
    case RELEASED:
        change_listen_mode(LISTEN_RAW);
        state = INIT_SELECTING;
        break; 
    case INIT_SELECTING:
        break;
    }
}

static void perform_release(uint32_t server_addr, uint32_t requested_ip)
{   
    char buffer[sizeof("255.255.255.255")];
    struct in_addr temp_addr;

    /* send release packet */
    if (state == BOUND || state == RENEWING || state == REBINDING) {
        temp_addr.s_addr = server_addr;
        strcpy(buffer, inet_ntoa(temp_addr));
        temp_addr.s_addr = requested_ip;
        bb_error_msg("unicasting a release of %s to %s",
                inet_ntoa(temp_addr), buffer);
        send_release(server_addr, requested_ip); /* unicast */
        udhcp_run_script(NULL, "deconfig");
    }   
    bb_error_msg("entering released state");

    change_listen_mode(LISTEN_NONE);
    state = RELEASED;
}
Comment 1 Denys Vlasenko 2016-07-03 18:29:13 UTC
Fixed in git, thanks!