From 103ba9b0fc8b50fcf10bf3a13d78168432608398 Mon Sep 17 00:00:00 2001 From: stoklund Date: Mon, 24 Aug 2009 13:12:37 +0000 Subject: [PATCH] The DHCP client should enter the REBOOTING state when connecting to a new network. If DHCP has bound to an address, it must be verified after netif_set_link_up. --- src/core/dhcp.c | 86 +++++++++++++++++++++++++++++++++++++++++ src/core/netif.c | 17 +++++++- src/include/lwip/dhcp.h | 2 + 3 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/core/dhcp.c b/src/core/dhcp.c index df0f9788..6e0ec290 100644 --- a/src/core/dhcp.c +++ b/src/core/dhcp.c @@ -100,6 +100,8 @@ #define DHCP_MAX_MSG_LEN(netif) (netif->mtu) #define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 +#define REBOOT_TRIES 2 + /* DHCP client state machine functions */ static void dhcp_handle_ack(struct netif *netif); static void dhcp_handle_nak(struct netif *netif); @@ -113,6 +115,7 @@ static void dhcp_bind(struct netif *netif); static err_t dhcp_decline(struct netif *netif); #endif /* DHCP_DOES_ARP_CHECK */ static err_t dhcp_rebind(struct netif *netif); +static err_t dhcp_reboot(struct netif *netif); static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); /* receive, unfold, parse and free incoming messages */ @@ -421,6 +424,12 @@ dhcp_timeout(struct netif *netif) dhcp_release(netif); dhcp_discover(netif); } + } else if (dhcp->state == DHCP_REBOOTING) { + if (dhcp->tries < REBOOT_TRIES) { + dhcp_reboot(netif); + } else { + dhcp_discover(netif); + } } } @@ -705,6 +714,36 @@ dhcp_inform(struct netif *netif) netif->dhcp = old_dhcp; } +/** Handle a possible change in the network configuration. + * + * This enters the REBOOTING state to verify that the currently bound + * address is still valid. + */ +void +dhcp_network_changed(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + if (!dhcp) + return; + switch (dhcp->state) { + case DHCP_REBINDING: + case DHCP_RENEWING: + case DHCP_BOUND: + case DHCP_REBOOTING: + netif_set_down(netif); + dhcp->tries = 0; + dhcp_reboot(netif); + break; + case DHCP_OFF: + /* stay off */ + break; + default: + dhcp->tries = 0; + dhcp_discover(netif); + break; + } +} + #if DHCP_DOES_ARP_CHECK /** * Match an ARP reply with the offered IP address. @@ -1054,6 +1093,53 @@ dhcp_rebind(struct netif *netif) return result; } +/** + * Enter REBOOTING state to verify an existing lease + * + * @param netif network interface which must reboot + */ +static err_t +dhcp_reboot(struct netif *netif) +{ + struct dhcp *dhcp = netif->dhcp; + err_t result; + u16_t msecs; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); + dhcp_set_state(dhcp, DHCP_REBOOTING); + + /* create and initialize the DHCP message header */ + result = dhcp_create_request(netif); + if (result == ERR_OK) { + + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, DHCP_REQUEST); + + dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(dhcp, 576); + + dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); + dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + + dhcp_option_trailer(dhcp); + + pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + + /* broadcast to server */ + udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); + udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_request(netif); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_reboot: could not allocate DHCP request\n")); + } + dhcp->tries++; + msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; + dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); + return result; +} + + /** * Release a DHCP lease. * diff --git a/src/core/netif.c b/src/core/netif.c index d8be7970..977371e2 100644 --- a/src/core/netif.c +++ b/src/core/netif.c @@ -55,6 +55,9 @@ #if LWIP_AUTOIP #include "lwip/autoip.h" #endif /* LWIP_AUTOIP */ +#if LWIP_DHCP +#include "lwip/dhcp.h" +#endif /* LWIP_DHCP */ #if LWIP_NETIF_STATUS_CALLBACK #define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } @@ -410,7 +413,13 @@ void netif_set_up(struct netif *netif) etharp_gratuitous(netif); } #endif /* LWIP_ARP */ - + +#if LWIP_IGMP + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups( netif); + } +#endif /* LWIP_IGMP */ } } @@ -463,6 +472,12 @@ void netif_set_link_up(struct netif *netif ) { netif->flags |= NETIF_FLAG_LINK_UP; +#if LWIP_DHCP + if (netif->dhcp) { + dhcp_network_changed(netif); + } +#endif /* LWIP_DHCP */ + #if LWIP_AUTOIP if (netif->autoip) { autoip_network_changed(netif); diff --git a/src/include/lwip/dhcp.h b/src/include/lwip/dhcp.h index 825dba6e..842a75ad 100644 --- a/src/include/lwip/dhcp.h +++ b/src/include/lwip/dhcp.h @@ -124,6 +124,8 @@ err_t dhcp_release(struct netif *netif); void dhcp_stop(struct netif *netif); /** inform server of our manual IP address */ void dhcp_inform(struct netif *netif); +/** Handle a possible change in the network configuration */ +void dhcp_network_changed(struct netif *netif); /** if enabled, check whether the offered IP address is not in use, using ARP */ #if DHCP_DOES_ARP_CHECK