My fork of the HTTPServer (working)

Dependents:   DGWWebServer LAN2

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dhcp.c Source File

dhcp.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Dynamic Host Configuration Protocol client
00004  *
00005  */
00006 
00007 /*
00008  *
00009  * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
00010  * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
00011  * All rights reserved.
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *
00016  * 1. Redistributions of source code must retain the above copyright notice,
00017  *    this list of conditions and the following disclaimer.
00018  * 2. Redistributions in binary form must reproduce the above copyright notice,
00019  *    this list of conditions and the following disclaimer in the documentation
00020  *    and/or other materials provided with the distribution.
00021  * 3. The name of the author may not be used to endorse or promote products
00022  *    derived from this software without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00025  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00026  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00027  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00029  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00032  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00033  * OF SUCH DAMAGE.
00034  *
00035  * This file is a contribution to the lwIP TCP/IP stack.
00036  * The Swedish Institute of Computer Science and Adam Dunkels
00037  * are specifically granted permission to redistribute this
00038  * source code.
00039  *
00040  * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
00041  *
00042  * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
00043  * with RFC 2131 and RFC 2132.
00044  *
00045  * TODO:
00046  * - Proper parsing of DHCP messages exploiting file/sname field overloading.
00047  * - Add JavaDoc style documentation (API, internals).
00048  * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
00049  *
00050  * Please coordinate changes and requests with Leon Woestenberg
00051  * <leon.woestenberg@gmx.net>
00052  *
00053  * Integration with your code:
00054  *
00055  * In lwip/dhcp.h
00056  * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
00057  * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
00058  *
00059  * Then have your application call dhcp_coarse_tmr() and
00060  * dhcp_fine_tmr() on the defined intervals.
00061  *
00062  * dhcp_start(struct netif *netif);
00063  * starts a DHCP client instance which configures the interface by
00064  * obtaining an IP address lease and maintaining it.
00065  *
00066  * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
00067  * to remove the DHCP client.
00068  *
00069  */
00070 
00071 #include "lwip/opt.h"
00072 
00073 #if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
00074 
00075 #include "lwip/stats.h"
00076 #include "lwip/mem.h"
00077 #include "lwip/udp.h"
00078 #include "lwip/ip_addr.h"
00079 #include "lwip/netif.h"
00080 #include "lwip/inet.h"
00081 #include "lwip/sys.h"
00082 #include "lwip/dhcp.h "
00083 #include "lwip/autoip.h"
00084 #include "lwip/dns.h"
00085 #include "netif/etharp.h"
00086 
00087 #include <string.h>
00088 
00089 /** Default for DHCP_GLOBAL_XID is 0xABCD0000
00090  * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
00091  *  #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
00092  *  #define DHCP_GLOBAL_XID rand()
00093  */
00094 #ifdef DHCP_GLOBAL_XID_HEADER
00095 #include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
00096 #endif
00097 
00098 /** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
00099  * MTU is checked to be big enough in dhcp_start */
00100 #define DHCP_MAX_MSG_LEN(netif)        (netif->mtu)
00101 #define DHCP_MAX_MSG_LEN_MIN_REQUIRED  576
00102 
00103 /* DHCP client state machine functions */
00104 static void dhcp_handle_ack(struct netif *netif);
00105 static void dhcp_handle_nak(struct netif *netif);
00106 static void dhcp_handle_offer(struct netif *netif);
00107 
00108 static err_t dhcp_discover(struct netif *netif);
00109 static err_t dhcp_select(struct netif *netif);
00110 static void dhcp_check(struct netif *netif);
00111 static void dhcp_bind(struct netif *netif);
00112 #if DHCP_DOES_ARP_CHECK
00113 static err_t dhcp_decline(struct netif *netif);
00114 #endif /* DHCP_DOES_ARP_CHECK */
00115 static err_t dhcp_rebind(struct netif *netif);
00116 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
00117 
00118 /* receive, unfold, parse and free incoming messages */
00119 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
00120 static err_t dhcp_unfold_reply(struct dhcp *dhcp);
00121 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
00122 static u8_t dhcp_get_option_byte(u8_t *ptr);
00123 #if 0
00124 static u16_t dhcp_get_option_short(u8_t *ptr);
00125 #endif
00126 static u32_t dhcp_get_option_long(u8_t *ptr);
00127 static void dhcp_free_reply(struct dhcp *dhcp);
00128 
00129 /* set the DHCP timers */
00130 static void dhcp_timeout(struct netif *netif);
00131 static void dhcp_t1_timeout(struct netif *netif);
00132 static void dhcp_t2_timeout(struct netif *netif);
00133 
00134 /* build outgoing messages */
00135 /* create a DHCP request, fill in common headers */
00136 static err_t dhcp_create_request(struct netif *netif);
00137 /* free a DHCP request */
00138 static void dhcp_delete_request(struct netif *netif);
00139 /* add a DHCP option (type, then length in bytes) */
00140 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
00141 /* add option values */
00142 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
00143 static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
00144 static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
00145 /* always add the DHCP options trailer to end and pad */
00146 static void dhcp_option_trailer(struct dhcp *dhcp);
00147 
00148 /**
00149  * Back-off the DHCP client (because of a received NAK response).
00150  *
00151  * Back-off the DHCP client because of a received NAK. Receiving a
00152  * NAK means the client asked for something non-sensible, for
00153  * example when it tries to renew a lease obtained on another network.
00154  *
00155  * We clear any existing set IP address and restart DHCP negotiation
00156  * afresh (as per RFC2131 3.2.3).
00157  *
00158  * @param netif the netif under DHCP control
00159  */
00160 static void
00161 dhcp_handle_nak(struct netif *netif)
00162 {
00163   struct dhcp *dhcp = netif->dhcp;
00164   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", 
00165     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
00166   /* Set the interface down since the address must no longer be used, as per RFC2131 */
00167   netif_set_down(netif);
00168   /* remove IP address from interface */
00169   netif_set_ipaddr(netif, IP_ADDR_ANY);
00170   netif_set_gw(netif, IP_ADDR_ANY);
00171   netif_set_netmask(netif, IP_ADDR_ANY); 
00172   /* Change to a defined state */
00173   dhcp_set_state(dhcp, DHCP_BACKING_OFF);
00174   /* We can immediately restart discovery */
00175   dhcp_discover(netif);
00176 }
00177 
00178 /**
00179  * Checks if the offered IP address is already in use.
00180  *
00181  * It does so by sending an ARP request for the offered address and
00182  * entering CHECKING state. If no ARP reply is received within a small
00183  * interval, the address is assumed to be free for use by us.
00184  *
00185  * @param netif the netif under DHCP control
00186  */
00187 static void
00188 dhcp_check(struct netif *netif)
00189 {
00190   struct dhcp *dhcp = netif->dhcp;
00191   err_t result;
00192   u16_t msecs;
00193   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
00194     (s16_t)netif->name[1]));
00195   /* create an ARP query for the offered IP address, expecting that no host
00196      responds, as the IP address should not be in use. */
00197   result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
00198   if (result != ERR_OK) {
00199     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
00200   }
00201   dhcp->tries++;
00202   msecs = 500;
00203   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00204   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
00205   dhcp_set_state(dhcp, DHCP_CHECKING);
00206 }
00207 
00208 /**
00209  * Remember the configuration offered by a DHCP server.
00210  *
00211  * @param netif the netif under DHCP control
00212  */
00213 static void
00214 dhcp_handle_offer(struct netif *netif)
00215 {
00216   struct dhcp *dhcp = netif->dhcp;
00217   /* obtain the server address */
00218   u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
00219   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
00220     (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
00221   if (option_ptr != NULL) {
00222     dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00223     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));
00224     /* remember offered address */
00225     ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
00226     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
00227 
00228     dhcp_select(netif);
00229   }
00230 }
00231 
00232 /**
00233  * Select a DHCP server offer out of all offers.
00234  *
00235  * Simply select the first offer received.
00236  *
00237  * @param netif the netif under DHCP control
00238  * @return lwIP specific error (see error.h)
00239  */
00240 static err_t
00241 dhcp_select(struct netif *netif)
00242 {
00243   struct dhcp *dhcp = netif->dhcp;
00244   err_t result;
00245   u16_t msecs;
00246 #if LWIP_NETIF_HOSTNAME
00247   const char *p;
00248 #endif /* LWIP_NETIF_HOSTNAME */
00249 
00250   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
00251 
00252   /* create and initialize the DHCP message header */
00253   result = dhcp_create_request(netif);
00254   if (result == ERR_OK) {
00255     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00256     dhcp_option_byte(dhcp, DHCP_REQUEST);
00257 
00258     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00259     dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
00260 
00261     /* MUST request the offered IP address */
00262     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00263     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00264 
00265     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
00266     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
00267 
00268     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
00269     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
00270     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
00271     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
00272     dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
00273 
00274 #if LWIP_NETIF_HOSTNAME
00275     p = (const char*)netif->hostname;
00276     if (p != NULL) {
00277       dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
00278       while (*p) {
00279         dhcp_option_byte(dhcp, *p++);
00280       }
00281     }
00282 #endif /* LWIP_NETIF_HOSTNAME */
00283 
00284     dhcp_option_trailer(dhcp);
00285     /* shrink the pbuf to the actual content length */
00286     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00287 
00288     /* TODO: we really should bind to a specific local interface here
00289        but we cannot specify an unconfigured netif as it is addressless */
00290     /* send broadcast to any DHCP server */
00291     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
00292     /* reconnect to any (or to server here?!) */
00293     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00294     dhcp_delete_request(netif);
00295     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
00296     dhcp_set_state(dhcp, DHCP_REQUESTING);
00297   } else {
00298     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
00299   }
00300   dhcp->tries++;
00301   msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;
00302   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00303   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
00304   return result;
00305 }
00306 
00307 /**
00308  * The DHCP timer that checks for lease renewal/rebind timeouts.
00309  *
00310  */
00311 void
00312 dhcp_coarse_tmr()
00313 {
00314   struct netif *netif = netif_list;
00315   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
00316   /* iterate through all network interfaces */
00317   while (netif != NULL) {
00318     /* only act on DHCP configured interfaces */
00319     if (netif->dhcp != NULL) {
00320       /* timer is active (non zero), and triggers (zeroes) now? */
00321       if (netif->dhcp->t2_timeout-- == 1) {
00322         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
00323         /* this clients' rebind timeout triggered */
00324         dhcp_t2_timeout(netif);
00325       /* timer is active (non zero), and triggers (zeroes) now */
00326       } else if (netif->dhcp->t1_timeout-- == 1) {
00327         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
00328         /* this clients' renewal timeout triggered */
00329         dhcp_t1_timeout(netif);
00330       }
00331     }
00332     /* proceed to next netif */
00333     netif = netif->next;
00334   }
00335 }
00336 
00337 /**
00338  * DHCP transaction timeout handling
00339  *
00340  * A DHCP server is expected to respond within a short period of time.
00341  * This timer checks whether an outstanding DHCP request is timed out.
00342  * 
00343  */
00344 void
00345 dhcp_fine_tmr()
00346 {
00347   struct netif *netif = netif_list;
00348   /* loop through netif's */
00349   while (netif != NULL) {
00350     /* only act on DHCP configured interfaces */
00351     if (netif->dhcp != NULL) {
00352       /* timer is active (non zero), and is about to trigger now */      
00353       if (netif->dhcp->request_timeout > 1) {
00354         netif->dhcp->request_timeout--;
00355       }
00356       else if (netif->dhcp->request_timeout == 1) {
00357         netif->dhcp->request_timeout--;
00358         /* { netif->dhcp->request_timeout == 0 } */
00359         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
00360         /* this clients' request timeout triggered */
00361         dhcp_timeout(netif);
00362       }
00363     }
00364     /* proceed to next network interface */
00365     netif = netif->next;
00366   }
00367 }
00368 
00369 /**
00370  * A DHCP negotiation transaction, or ARP request, has timed out.
00371  *
00372  * The timer that was started with the DHCP or ARP request has
00373  * timed out, indicating no response was received in time.
00374  *
00375  * @param netif the netif under DHCP control
00376  */
00377 static void
00378 dhcp_timeout(struct netif *netif)
00379 {
00380   struct dhcp *dhcp = netif->dhcp;
00381   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));
00382   /* back-off period has passed, or server selection timed out */
00383   if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
00384     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
00385     dhcp_discover(netif);
00386   /* receiving the requested lease timed out */
00387   } else if (dhcp->state == DHCP_REQUESTING) {
00388     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
00389     if (dhcp->tries <= 5) {
00390       dhcp_select(netif);
00391     } else {
00392       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
00393       dhcp_release(netif);
00394       dhcp_discover(netif);
00395     }
00396   /* received no ARP reply for the offered address (which is good) */
00397   } else if (dhcp->state == DHCP_CHECKING) {
00398     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
00399     if (dhcp->tries <= 1) {
00400       dhcp_check(netif);
00401     /* no ARP replies on the offered address,
00402        looks like the IP address is indeed free */
00403     } else {
00404       /* bind the interface to the offered address */
00405       dhcp_bind(netif);
00406     }
00407   }
00408   /* did not get response to renew request? */
00409   else if (dhcp->state == DHCP_RENEWING) {
00410     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
00411     /* just retry renewal */
00412     /* note that the rebind timer will eventually time-out if renew does not work */
00413     dhcp_renew(netif);
00414   /* did not get response to rebind request? */
00415   } else if (dhcp->state == DHCP_REBINDING) {
00416     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
00417     if (dhcp->tries <= 8) {
00418       dhcp_rebind(netif);
00419     } else {
00420       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
00421       dhcp_release(netif);
00422       dhcp_discover(netif);
00423     }
00424   }
00425 }
00426 
00427 /**
00428  * The renewal period has timed out.
00429  *
00430  * @param netif the netif under DHCP control
00431  */
00432 static void
00433 dhcp_t1_timeout(struct netif *netif)
00434 {
00435   struct dhcp *dhcp = netif->dhcp;
00436   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
00437   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
00438     /* just retry to renew - note that the rebind timer (t2) will
00439      * eventually time-out if renew tries fail. */
00440     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
00441     dhcp_renew(netif);
00442   }
00443 }
00444 
00445 /**
00446  * The rebind period has timed out.
00447  *
00448  * @param netif the netif under DHCP control
00449  */
00450 static void
00451 dhcp_t2_timeout(struct netif *netif)
00452 {
00453   struct dhcp *dhcp = netif->dhcp;
00454   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
00455   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
00456     /* just retry to rebind */
00457     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
00458     dhcp_rebind(netif);
00459   }
00460 }
00461 
00462 /**
00463  * Handle a DHCP ACK packet
00464  *
00465  * @param netif the netif under DHCP control
00466  */
00467 static void
00468 dhcp_handle_ack(struct netif *netif)
00469 {
00470   struct dhcp *dhcp = netif->dhcp;
00471   u8_t *option_ptr;
00472   /* clear options we might not get from the ACK */
00473   dhcp->offered_sn_mask.addr = 0;
00474   dhcp->offered_gw_addr.addr = 0;
00475   dhcp->offered_bc_addr.addr = 0;
00476 
00477   /* lease time given? */
00478   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);
00479   if (option_ptr != NULL) {
00480     /* remember offered lease time */
00481     dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);
00482   }
00483   /* renewal period given? */
00484   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);
00485   if (option_ptr != NULL) {
00486     /* remember given renewal period */
00487     dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);
00488   } else {
00489     /* calculate safe periods for renewal */
00490     dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
00491   }
00492 
00493   /* renewal period given? */
00494   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);
00495   if (option_ptr != NULL) {
00496     /* remember given rebind period */
00497     dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);
00498   } else {
00499     /* calculate safe periods for rebinding */
00500     dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
00501   }
00502 
00503   /* (y)our internet address */
00504   ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
00505 
00506 /**
00507  * Patch #1308
00508  * TODO: we must check if the file field is not overloaded by DHCP options!
00509  */
00510 #if 0
00511   /* boot server address */
00512   ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);
00513   /* boot file name */
00514   if (dhcp->msg_in->file[0]) {
00515     dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);
00516     strcpy(dhcp->boot_file_name, dhcp->msg_in->file);
00517   }
00518 #endif
00519 
00520   /* subnet mask */
00521   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);
00522   /* subnet mask given? */
00523   if (option_ptr != NULL) {
00524     dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00525   }
00526 
00527   /* gateway router */
00528   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);
00529   if (option_ptr != NULL) {
00530     dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00531   }
00532 
00533   /* broadcast address */
00534   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);
00535   if (option_ptr != NULL) {
00536     dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00537   }
00538   
00539   /* DNS servers */
00540   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
00541   if (option_ptr != NULL) {
00542     u8_t n;
00543     dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);
00544     /* limit to at most DHCP_MAX_DNS DNS servers */
00545     if (dhcp->dns_count > DHCP_MAX_DNS)
00546       dhcp->dns_count = DHCP_MAX_DNS;
00547     for (n = 0; n < dhcp->dns_count; n++) {
00548       dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));
00549 #if LWIP_DNS
00550       dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr)));
00551 #endif /* LWIP_DNS */
00552     }
00553 #if LWIP_DNS
00554     dns_setserver( n, (struct ip_addr *)(&ip_addr_any));
00555 #endif /* LWIP_DNS */
00556   }
00557 }
00558 
00559 /**
00560  * Start DHCP negotiation for a network interface.
00561  *
00562  * If no DHCP client instance was attached to this interface,
00563  * a new client is created first. If a DHCP client instance
00564  * was already present, it restarts negotiation.
00565  *
00566  * @param netif The lwIP network interface
00567  * @return lwIP error code
00568  * - ERR_OK - No error
00569  * - ERR_MEM - Out of memory
00570  */
00571 err_t
00572 dhcp_start(struct netif *netif)
00573 {
00574   struct dhcp *dhcp;
00575   err_t result = ERR_OK;
00576 
00577   LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
00578   dhcp = netif->dhcp;
00579   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
00580   /* Remove the flag that says this netif is handled by DHCP,
00581      it is set when we succeeded starting. */
00582   netif->flags &= ~NETIF_FLAG_DHCP;
00583 
00584   /* check MTU of the netif */
00585   if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
00586     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
00587     return ERR_MEM;
00588   }
00589 
00590   /* no DHCP client attached yet? */
00591   if (dhcp == NULL) {
00592     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
00593     dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); // static_cast<struct dhcp *>(x)
00594     if (dhcp == NULL) {
00595       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
00596       return ERR_MEM;
00597     }
00598     /* store this dhcp client in the netif */
00599     netif->dhcp = dhcp;
00600     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
00601   /* already has DHCP client attached */
00602   } else {
00603     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
00604     if (dhcp->pcb != NULL) {
00605       udp_remove(dhcp->pcb);
00606     }
00607     if (dhcp->p != NULL) {
00608       pbuf_free(dhcp->p);
00609     }
00610   }
00611     
00612   /* clear data structure */
00613   memset(dhcp, 0, sizeof(struct dhcp));
00614   /* allocate UDP PCB */
00615   dhcp->pcb = udp_new();
00616   if (dhcp->pcb == NULL) {
00617     LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
00618     mem_free((void *)dhcp);
00619     netif->dhcp = dhcp = NULL;
00620     return ERR_MEM;
00621   }
00622   /* set up local and remote port for the pcb */
00623   udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00624   udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00625   /* set up the recv callback and argument */
00626   udp_recv(dhcp->pcb, dhcp_recv, netif);
00627   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
00628   /* (re)start the DHCP negotiation */
00629   result = dhcp_discover(netif);
00630   if (result != ERR_OK) {
00631     /* free resources allocated above */
00632     dhcp_stop(netif);
00633     return ERR_MEM;
00634   }
00635   /* Set the flag that says this netif is handled by DHCP. */
00636   netif->flags |= NETIF_FLAG_DHCP;
00637   return result;
00638 }
00639 
00640 /**
00641  * Inform a DHCP server of our manual configuration.
00642  *
00643  * This informs DHCP servers of our fixed IP address configuration
00644  * by sending an INFORM message. It does not involve DHCP address
00645  * configuration, it is just here to be nice to the network.
00646  *
00647  * @param netif The lwIP network interface
00648  */
00649 void
00650 dhcp_inform(struct netif *netif)
00651 {
00652   struct dhcp *dhcp, *old_dhcp = netif->dhcp;
00653   err_t result = ERR_OK;
00654   dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); // static_cast<struct dhcp *>(x)
00655   if (dhcp == NULL) {
00656     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
00657     return;
00658   }
00659   netif->dhcp = dhcp;
00660   memset(dhcp, 0, sizeof(struct dhcp));
00661 
00662   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
00663   dhcp->pcb = udp_new();
00664   if (dhcp->pcb == NULL) {
00665     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
00666     mem_free((void *)dhcp);
00667     return;
00668   }
00669   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
00670   /* create and initialize the DHCP message header */
00671   result = dhcp_create_request(netif);
00672   if (result == ERR_OK) {
00673 
00674     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00675     dhcp_option_byte(dhcp, DHCP_INFORM);
00676 
00677     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00678     dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
00679 
00680     dhcp_option_trailer(dhcp);
00681 
00682     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00683 
00684     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00685     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
00686     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
00687     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
00688     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00689     dhcp_delete_request(netif);
00690   } else {
00691     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
00692   }
00693 
00694   if (dhcp->pcb != NULL) {
00695     udp_remove(dhcp->pcb);
00696   }
00697   dhcp->pcb = NULL;
00698   mem_free((void *)dhcp);
00699   netif->dhcp = old_dhcp;
00700 }
00701 
00702 #if DHCP_DOES_ARP_CHECK
00703 /**
00704  * Match an ARP reply with the offered IP address.
00705  *
00706  * @param netif the network interface on which the reply was received
00707  * @param addr The IP address we received a reply from
00708  */
00709 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
00710 {
00711   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
00712   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
00713   /* is a DHCP client doing an ARP check? */
00714   if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
00715     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
00716     /* did a host respond with the address we
00717        were offered by the DHCP server? */
00718     if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
00719       /* we will not accept the offered address */
00720       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
00721       dhcp_decline(netif);
00722     }
00723   }
00724 }
00725 
00726 /**
00727  * Decline an offered lease.
00728  *
00729  * Tell the DHCP server we do not accept the offered address.
00730  * One reason to decline the lease is when we find out the address
00731  * is already in use by another host (through ARP).
00732  *
00733  * @param netif the netif under DHCP control
00734  */
00735 static err_t
00736 dhcp_decline(struct netif *netif)
00737 {
00738   struct dhcp *dhcp = netif->dhcp;
00739   err_t result = ERR_OK;
00740   u16_t msecs;
00741   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));
00742   dhcp_set_state(dhcp, DHCP_BACKING_OFF);
00743   /* create and initialize the DHCP message header */
00744   result = dhcp_create_request(netif);
00745   if (result == ERR_OK) {
00746     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00747     dhcp_option_byte(dhcp, DHCP_DECLINE);
00748 
00749     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00750     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00751 
00752     dhcp_option_trailer(dhcp);
00753     /* resize pbuf to reflect true size of options */
00754     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00755 
00756     /* @todo: should we really connect here? we are performing sendto() */
00757     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00758     /* per section 4.4.4, broadcast DECLINE messages */
00759     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
00760     dhcp_delete_request(netif);
00761     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
00762   } else {
00763     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
00764   }
00765   dhcp->tries++;
00766   msecs = 10*1000;
00767   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00768   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
00769   return result;
00770 }
00771 #endif
00772 
00773 
00774 /**
00775  * Start the DHCP process, discover a DHCP server.
00776  *
00777  * @param netif the netif under DHCP control
00778  */
00779 static err_t
00780 dhcp_discover(struct netif *netif)
00781 {
00782   struct dhcp *dhcp = netif->dhcp;
00783   err_t result = ERR_OK;
00784   u16_t msecs;
00785   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
00786   ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
00787   /* create and initialize the DHCP message header */
00788   result = dhcp_create_request(netif);
00789   if (result == ERR_OK) {
00790     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
00791     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00792     dhcp_option_byte(dhcp, DHCP_DISCOVER);
00793 
00794     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00795     dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
00796 
00797     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
00798     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
00799     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
00800     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
00801     dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
00802 
00803     dhcp_option_trailer(dhcp);
00804 
00805     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
00806     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00807 
00808     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00809     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
00810     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
00811     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
00812     dhcp_delete_request(netif);
00813     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
00814     dhcp_set_state(dhcp, DHCP_SELECTING);
00815   } else {
00816     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
00817   }
00818   dhcp->tries++;
00819 #if LWIP_DHCP_AUTOIP_COOP
00820   /* that means we waited 57 seconds */
00821   if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
00822     dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
00823     autoip_start(netif);
00824   }
00825 #endif /* LWIP_DHCP_AUTOIP_COOP */
00826   msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;
00827   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00828   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
00829   return result;
00830 }
00831 
00832 
00833 /**
00834  * Bind the interface to the offered IP address.
00835  *
00836  * @param netif network interface to bind to the offered address
00837  */
00838 static void
00839 dhcp_bind(struct netif *netif)
00840 {
00841   u32_t timeout;
00842   struct dhcp *dhcp;
00843   struct ip_addr sn_mask, gw_addr;
00844   LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
00845   dhcp = netif->dhcp;
00846   LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
00847   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
00848 
00849   /* temporary DHCP lease? */
00850   if (dhcp->offered_t1_renew != 0xffffffffUL) {
00851     /* set renewal period timer */
00852     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
00853     timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
00854     if(timeout > 0xffff) {
00855       timeout = 0xffff;
00856     }
00857     dhcp->t1_timeout = (u16_t)timeout;
00858     if (dhcp->t1_timeout == 0) {
00859       dhcp->t1_timeout = 1;
00860     }
00861     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
00862   }
00863   /* set renewal period timer */
00864   if (dhcp->offered_t2_rebind != 0xffffffffUL) {
00865     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
00866     timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
00867     if(timeout > 0xffff) {
00868       timeout = 0xffff;
00869     }
00870     dhcp->t2_timeout = (u16_t)timeout;
00871     if (dhcp->t2_timeout == 0) {
00872       dhcp->t2_timeout = 1;
00873     }
00874     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
00875   }
00876   /* copy offered network mask */
00877   ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
00878 
00879   /* subnet mask not given? */
00880   /* TODO: this is not a valid check. what if the network mask is 0? */
00881   if (sn_mask.addr == 0) {
00882     /* choose a safe subnet mask given the network class */
00883     u8_t first_octet = ip4_addr1(&sn_mask);
00884     if (first_octet <= 127) {
00885       sn_mask.addr = htonl(0xff000000);
00886     } else if (first_octet >= 192) {
00887       sn_mask.addr = htonl(0xffffff00);
00888     } else {
00889       sn_mask.addr = htonl(0xffff0000);
00890     }
00891   }
00892 
00893   ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);
00894   /* gateway address not given? */
00895   if (gw_addr.addr == 0) {
00896     /* copy network address */
00897     gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);
00898     /* use first host address on network as gateway */
00899     gw_addr.addr |= htonl(0x00000001);
00900   }
00901 
00902   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
00903   netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
00904   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));
00905   netif_set_netmask(netif, &sn_mask);
00906   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));
00907   netif_set_gw(netif, &gw_addr);
00908   /* bring the interface up */
00909   netif_set_up(netif);
00910   /* netif is now bound to DHCP leased address */
00911   dhcp_set_state(dhcp, DHCP_BOUND);
00912 }
00913 
00914 /**
00915  * Renew an existing DHCP lease at the involved DHCP server.
00916  *
00917  * @param netif network interface which must renew its lease
00918  */
00919 err_t
00920 dhcp_renew(struct netif *netif)
00921 {
00922   struct dhcp *dhcp = netif->dhcp;
00923   err_t result;
00924   u16_t msecs;
00925 #if LWIP_NETIF_HOSTNAME
00926   const char *p;
00927 #endif /* LWIP_NETIF_HOSTNAME */
00928   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));
00929   dhcp_set_state(dhcp, DHCP_RENEWING);
00930 
00931   /* create and initialize the DHCP message header */
00932   result = dhcp_create_request(netif);
00933   if (result == ERR_OK) {
00934 
00935     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00936     dhcp_option_byte(dhcp, DHCP_REQUEST);
00937 
00938     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00939     dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
00940 
00941 #if LWIP_NETIF_HOSTNAME
00942     p = (const char*)netif->hostname;
00943     if (p != NULL) {
00944       dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
00945       while (*p) {
00946         dhcp_option_byte(dhcp, *p++);
00947       }
00948     }
00949 #endif /* LWIP_NETIF_HOSTNAME */
00950 
00951 #if 0
00952     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00953     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00954 #endif
00955 
00956 #if 0
00957     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
00958     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
00959 #endif
00960     /* append DHCP message trailer */
00961     dhcp_option_trailer(dhcp);
00962 
00963     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00964 
00965     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
00966     udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
00967     dhcp_delete_request(netif);
00968 
00969     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
00970   } else {
00971     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
00972   }
00973   dhcp->tries++;
00974   /* back-off on retries, but to a maximum of 20 seconds */
00975   msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
00976   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00977   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
00978   return result;
00979 }
00980 
00981 /**
00982  * Rebind with a DHCP server for an existing DHCP lease.
00983  *
00984  * @param netif network interface which must rebind with a DHCP server
00985  */
00986 static err_t
00987 dhcp_rebind(struct netif *netif)
00988 {
00989   struct dhcp *dhcp = netif->dhcp;
00990   err_t result;
00991   u16_t msecs;
00992 #if LWIP_NETIF_HOSTNAME
00993   const char *p;
00994 #endif /* LWIP_NETIF_HOSTNAME */
00995   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
00996   dhcp_set_state(dhcp, DHCP_REBINDING);
00997 
00998   /* create and initialize the DHCP message header */
00999   result = dhcp_create_request(netif);
01000   if (result == ERR_OK) {
01001 
01002     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
01003     dhcp_option_byte(dhcp, DHCP_REQUEST);
01004 
01005     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
01006     dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
01007 
01008 #if LWIP_NETIF_HOSTNAME
01009     p = (const char*)netif->hostname;
01010     if (p != NULL) {
01011       dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
01012       while (*p) {
01013         dhcp_option_byte(dhcp, *p++);
01014       }
01015     }
01016 #endif /* LWIP_NETIF_HOSTNAME */
01017 
01018 #if 0
01019     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
01020     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
01021 
01022     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
01023     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
01024 #endif
01025 
01026     dhcp_option_trailer(dhcp);
01027 
01028     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
01029 
01030     /* broadcast to server */
01031     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
01032     udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
01033     dhcp_delete_request(netif);
01034     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
01035   } else {
01036     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
01037   }
01038   dhcp->tries++;
01039   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
01040   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
01041   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
01042   return result;
01043 }
01044 
01045 /**
01046  * Release a DHCP lease.
01047  *
01048  * @param netif network interface which must release its lease
01049  */
01050 err_t
01051 dhcp_release(struct netif *netif)
01052 {
01053   struct dhcp *dhcp = netif->dhcp;
01054   err_t result;
01055   u16_t msecs;
01056   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));
01057 
01058   /* idle DHCP client */
01059   dhcp_set_state(dhcp, DHCP_OFF);
01060   /* clean old DHCP offer */
01061   dhcp->server_ip_addr.addr = 0;
01062   dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;
01063   dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;
01064   dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
01065   dhcp->dns_count = 0;
01066   
01067   /* create and initialize the DHCP message header */
01068   result = dhcp_create_request(netif);
01069   if (result == ERR_OK) {
01070     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
01071     dhcp_option_byte(dhcp, DHCP_RELEASE);
01072 
01073     dhcp_option_trailer(dhcp);
01074 
01075     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
01076 
01077     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
01078     udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
01079     dhcp_delete_request(netif);
01080     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
01081   } else {
01082     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
01083   }
01084   dhcp->tries++;
01085   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
01086   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
01087   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
01088   /* bring the interface down */
01089   netif_set_down(netif);
01090   /* remove IP address from interface */
01091   netif_set_ipaddr(netif, IP_ADDR_ANY);
01092   netif_set_gw(netif, IP_ADDR_ANY);
01093   netif_set_netmask(netif, IP_ADDR_ANY);
01094   
01095   /* TODO: netif_down(netif); */
01096   return result;
01097 }
01098 
01099 /**
01100  * Remove the DHCP client from the interface.
01101  *
01102  * @param netif The network interface to stop DHCP on
01103  */
01104 void
01105 dhcp_stop(struct netif *netif)
01106 {
01107   struct dhcp *dhcp = netif->dhcp;
01108   LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
01109   /* Remove the flag that says this netif is handled by DHCP. */
01110   netif->flags &= ~NETIF_FLAG_DHCP;
01111 
01112   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));
01113   /* netif is DHCP configured? */
01114   if (dhcp != NULL) {
01115     if (dhcp->pcb != NULL) {
01116       udp_remove(dhcp->pcb);
01117       dhcp->pcb = NULL;
01118     }
01119     if (dhcp->p != NULL) {
01120       pbuf_free(dhcp->p);
01121       dhcp->p = NULL;
01122     }
01123     /* free unfolded reply */
01124     dhcp_free_reply(dhcp);
01125     mem_free((void *)dhcp);
01126     netif->dhcp = NULL;
01127   }
01128 }
01129 
01130 /*
01131  * Set the DHCP state of a DHCP client.
01132  *
01133  * If the state changed, reset the number of tries.
01134  *
01135  * TODO: we might also want to reset the timeout here?
01136  */
01137 static void
01138 dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
01139 {
01140   if (new_state != dhcp->state) {
01141     dhcp->state = new_state;
01142     dhcp->tries = 0;
01143   }
01144 }
01145 
01146 /*
01147  * Concatenate an option type and length field to the outgoing
01148  * DHCP message.
01149  *
01150  */
01151 static void
01152 dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
01153 {
01154   LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
01155   dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
01156   dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
01157 }
01158 /*
01159  * Concatenate a single byte to the outgoing DHCP message.
01160  *
01161  */
01162 static void
01163 dhcp_option_byte(struct dhcp *dhcp, u8_t value)
01164 {
01165   LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
01166   dhcp->msg_out->options[dhcp->options_out_len++] = value;
01167 }
01168 
01169 static void
01170 dhcp_option_short(struct dhcp *dhcp, u16_t value)
01171 {
01172   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);
01173   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
01174   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);
01175 }
01176 
01177 static void
01178 dhcp_option_long(struct dhcp *dhcp, u32_t value)
01179 {
01180   LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);
01181   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
01182   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
01183   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
01184   dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
01185 }
01186 
01187 /**
01188  * Extract the DHCP message and the DHCP options.
01189  *
01190  * Extract the DHCP message and the DHCP options, each into a contiguous
01191  * piece of memory. As a DHCP message is variable sized by its options,
01192  * and also allows overriding some fields for options, the easy approach
01193  * is to first unfold the options into a conitguous piece of memory, and
01194  * use that further on.
01195  *
01196  */
01197 static err_t
01198 dhcp_unfold_reply(struct dhcp *dhcp)
01199 {
01200   u16_t ret;
01201   LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);
01202   LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;);
01203   /* free any left-overs from previous unfolds */
01204   dhcp_free_reply(dhcp);
01205   /* options present? */
01206   if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {
01207     dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
01208     dhcp->options_in = (struct dhcp_msg *)mem_malloc(dhcp->options_in_len); // static_cast<struct dhcp_msg *>(x)
01209     if (dhcp->options_in == NULL) {
01210       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
01211       return ERR_MEM;
01212     }
01213   }
01214   dhcp->msg_in = (struct dhcp_msg *)mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); // static_cast<struct dhcp_msg *>(x)
01215   if (dhcp->msg_in == NULL) {
01216     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
01217     mem_free((void *)dhcp->options_in);
01218     dhcp->options_in = NULL;
01219     return ERR_MEM;
01220   }
01221 
01222   /** copy the DHCP message without options */
01223   ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
01224   LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
01225   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",
01226      sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));
01227 
01228   if (dhcp->options_in != NULL) {
01229     /** copy the DHCP options */
01230     ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
01231     LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);
01232     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",
01233       dhcp->options_in_len));
01234   }
01235   LWIP_UNUSED_ARG(ret);
01236   return ERR_OK;
01237 }
01238 
01239 /**
01240  * Free the incoming DHCP message including contiguous copy of
01241  * its DHCP options.
01242  *
01243  */
01244 static void dhcp_free_reply(struct dhcp *dhcp)
01245 {
01246   if (dhcp->msg_in != NULL) {
01247     mem_free((void *)dhcp->msg_in);
01248     dhcp->msg_in = NULL;
01249   }
01250   if (dhcp->options_in) {
01251     mem_free((void *)dhcp->options_in);
01252     dhcp->options_in = NULL;
01253     dhcp->options_in_len = 0;
01254   }
01255   LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
01256 }
01257 
01258 
01259 /**
01260  * If an incoming DHCP message is in response to us, then trigger the state machine
01261  */
01262 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
01263 {
01264   struct netif *netif = (struct netif *)arg;
01265   struct dhcp *dhcp = netif->dhcp;
01266   struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
01267   u8_t *options_ptr;
01268   u8_t msg_type;
01269   u8_t i;
01270   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p,
01271     (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),
01272     (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));
01273   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
01274   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
01275   /* prevent warnings about unused arguments */
01276   LWIP_UNUSED_ARG(pcb);
01277   LWIP_UNUSED_ARG(addr);
01278   LWIP_UNUSED_ARG(port);
01279   dhcp->p = p;
01280   /* TODO: check packet length before reading them */
01281   if (reply_msg->op != DHCP_BOOTREPLY) {
01282     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
01283     goto free_pbuf_and_return;
01284   }
01285   /* iterate through hardware address and match against DHCP message */
01286   for (i = 0; i < netif->hwaddr_len; i++) {
01287     if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
01288       LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
01289         (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
01290       goto free_pbuf_and_return;
01291     }
01292   }
01293   /* match transaction ID against what we expected */
01294   if (ntohl(reply_msg->xid) != dhcp->xid) {
01295     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid));
01296     goto free_pbuf_and_return;
01297   }
01298   /* option fields could be unfold? */
01299   if (dhcp_unfold_reply(dhcp) != ERR_OK) {
01300     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
01301     goto free_pbuf_and_return;
01302   }
01303 
01304   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
01305   /* obtain pointer to DHCP message type */
01306   options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
01307   if (options_ptr == NULL) {
01308     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
01309     goto free_pbuf_and_return;
01310   }
01311 
01312   /* read DHCP message type */
01313   msg_type = dhcp_get_option_byte(options_ptr + 2);
01314   /* message type is DHCP ACK? */
01315   if (msg_type == DHCP_ACK) {
01316     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));
01317     /* in requesting state? */
01318     if (dhcp->state == DHCP_REQUESTING) {
01319       dhcp_handle_ack(netif);
01320       dhcp->request_timeout = 0;
01321 #if DHCP_DOES_ARP_CHECK
01322       /* check if the acknowledged lease address is already in use */
01323       dhcp_check(netif);
01324 #else
01325       /* bind interface to the acknowledged lease address */
01326       dhcp_bind(netif);
01327 #endif
01328     }
01329     /* already bound to the given lease address? */
01330     else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
01331       dhcp->request_timeout = 0;
01332       dhcp_bind(netif);
01333     }
01334   }
01335   /* received a DHCP_NAK in appropriate state? */
01336   else if ((msg_type == DHCP_NAK) &&
01337     ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
01338      (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {
01339     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));
01340     dhcp->request_timeout = 0;
01341     dhcp_handle_nak(netif);
01342   }
01343   /* received a DHCP_OFFER in DHCP_SELECTING state? */
01344   else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
01345     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
01346     dhcp->request_timeout = 0;
01347     /* remember offered lease */
01348     dhcp_handle_offer(netif);
01349   }
01350 free_pbuf_and_return:
01351   dhcp_free_reply(dhcp);
01352   pbuf_free(p);
01353   dhcp->p = NULL;
01354 }
01355 
01356 /**
01357  * Create a DHCP request, fill in common headers
01358  *
01359  * @param netif the netif under DHCP control
01360  */
01361 static err_t
01362 dhcp_create_request(struct netif *netif)
01363 {
01364   struct dhcp *dhcp;
01365   u16_t i;
01366 #ifndef DHCP_GLOBAL_XID
01367   /** default global transaction identifier starting value (easy to match
01368    *  with a packet analyser). We simply increment for each new request.
01369    *  Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
01370    *  at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
01371   static u32_t xid = 0xABCD0000;
01372 #else
01373   static u32_t xid;
01374   static u8_t xid_initialised = 0;
01375   if (!xid_initialised) {
01376     xid = DHCP_GLOBAL_XID;
01377     xid_initialised = !xid_initialised;
01378   }
01379 #endif
01380   LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);
01381   dhcp = netif->dhcp;
01382   LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
01383   LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
01384   LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
01385   dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
01386   if (dhcp->p_out == NULL) {
01387     LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
01388     return ERR_MEM;
01389   }
01390   LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",
01391            (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
01392 
01393   /* give unique transaction identifier to this request */
01394   dhcp->xid = xid++;
01395   LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));
01396 
01397   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
01398 
01399   dhcp->msg_out->op = DHCP_BOOTREQUEST;
01400   /* TODO: make link layer independent */
01401   dhcp->msg_out->htype = DHCP_HTYPE_ETH;
01402   /* TODO: make link layer independent */
01403   dhcp->msg_out->hlen = DHCP_HLEN_ETH;
01404   dhcp->msg_out->hops = 0;
01405   dhcp->msg_out->xid = htonl(dhcp->xid);
01406   dhcp->msg_out->secs = 0;
01407   dhcp->msg_out->flags = 0;
01408   dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
01409   dhcp->msg_out->yiaddr.addr = 0;
01410   dhcp->msg_out->siaddr.addr = 0;
01411   dhcp->msg_out->giaddr.addr = 0;
01412   for (i = 0; i < DHCP_CHADDR_LEN; i++) {
01413     /* copy netif hardware address, pad with zeroes */
01414     dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
01415   }
01416   for (i = 0; i < DHCP_SNAME_LEN; i++) {
01417     dhcp->msg_out->sname[i] = 0;
01418   }
01419   for (i = 0; i < DHCP_FILE_LEN; i++) {
01420     dhcp->msg_out->file[i] = 0;
01421   }
01422   dhcp->msg_out->cookie = htonl(0x63825363UL);
01423   dhcp->options_out_len = 0;
01424   /* fill options field with an incrementing array (for debugging purposes) */
01425   for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
01426     dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
01427   }
01428   return ERR_OK;
01429 }
01430 
01431 /**
01432  * Free previously allocated memory used to send a DHCP request.
01433  *
01434  * @param netif the netif under DHCP control
01435  */
01436 static void
01437 dhcp_delete_request(struct netif *netif)
01438 {
01439   struct dhcp *dhcp;
01440   LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;);
01441   dhcp = netif->dhcp;
01442   LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;);
01443   LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL);
01444   LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
01445   if (dhcp->p_out != NULL) {
01446     pbuf_free(dhcp->p_out);
01447   }
01448   dhcp->p_out = NULL;
01449   dhcp->msg_out = NULL;
01450 }
01451 
01452 /**
01453  * Add a DHCP message trailer
01454  *
01455  * Adds the END option to the DHCP message, and if
01456  * necessary, up to three padding bytes.
01457  *
01458  * @param dhcp DHCP state structure
01459  */
01460 static void
01461 dhcp_option_trailer(struct dhcp *dhcp)
01462 {
01463   LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
01464   LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
01465   LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
01466   dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
01467   /* packet is too small, or not 4 byte aligned? */
01468   while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
01469     /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
01470     LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
01471     /* add a fill/padding byte */
01472     dhcp->msg_out->options[dhcp->options_out_len++] = 0;
01473   }
01474 }
01475 
01476 /**
01477  * Find the offset of a DHCP option inside the DHCP message.
01478  *
01479  * @param dhcp DHCP client
01480  * @param option_type
01481  *
01482  * @return a byte offset into the UDP message where the option was found, or
01483  * zero if the given option was not found.
01484  */
01485 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
01486 {
01487   u8_t overload = DHCP_OVERLOAD_NONE;
01488 
01489   /* options available? */
01490   if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
01491     /* start with options field */
01492     u8_t *options = (u8_t *)dhcp->options_in;
01493     u16_t offset = 0;
01494     /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
01495     while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
01496       /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
01497       /* are the sname and/or file field overloaded with options? */
01498       if (options[offset] == DHCP_OPTION_OVERLOAD) {
01499         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));
01500         /* skip option type and length */
01501         offset += 2;
01502         overload = options[offset++];
01503       }
01504       /* requested option found */
01505       else if (options[offset] == option_type) {
01506         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));
01507         return &options[offset];
01508       /* skip option */
01509       } else {
01510          LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));
01511         /* skip option type */
01512         offset++;
01513         /* skip option length, and then length bytes */
01514         offset += 1 + options[offset];
01515       }
01516     }
01517     /* is this an overloaded message? */
01518     if (overload != DHCP_OVERLOAD_NONE) {
01519       u16_t field_len;
01520       if (overload == DHCP_OVERLOAD_FILE) {
01521         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));
01522         options = (u8_t *)&dhcp->msg_in->file;
01523         field_len = DHCP_FILE_LEN;
01524       } else if (overload == DHCP_OVERLOAD_SNAME) {
01525         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));
01526         options = (u8_t *)&dhcp->msg_in->sname;
01527         field_len = DHCP_SNAME_LEN;
01528       /* TODO: check if else if () is necessary */
01529       } else {
01530         LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));
01531         options = (u8_t *)&dhcp->msg_in->sname;
01532         field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
01533       }
01534       offset = 0;
01535 
01536       /* at least 1 byte to read and no end marker */
01537       while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
01538         if (options[offset] == option_type) {
01539            LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));
01540           return &options[offset];
01541         /* skip option */
01542         } else {
01543           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));
01544           /* skip option type */
01545           offset++;
01546           offset += 1 + options[offset];
01547         }
01548       }
01549     }
01550   }
01551   return NULL;
01552 }
01553 
01554 /**
01555  * Return the byte of DHCP option data.
01556  *
01557  * @param client DHCP client.
01558  * @param ptr pointer obtained by dhcp_get_option_ptr().
01559  *
01560  * @return byte value at the given address.
01561  */
01562 static u8_t
01563 dhcp_get_option_byte(u8_t *ptr)
01564 {
01565   LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));
01566   return *ptr;
01567 }
01568 
01569 #if 0 /* currently unused */
01570 /**
01571  * Return the 16-bit value of DHCP option data.
01572  *
01573  * @param client DHCP client.
01574  * @param ptr pointer obtained by dhcp_get_option_ptr().
01575  *
01576  * @return byte value at the given address.
01577  */
01578 static u16_t
01579 dhcp_get_option_short(u8_t *ptr)
01580 {
01581   u16_t value;
01582   value = *ptr++ << 8;
01583   value |= *ptr;
01584   LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));
01585   return value;
01586 }
01587 #endif
01588 
01589 /**
01590  * Return the 32-bit value of DHCP option data.
01591  *
01592  * @param client DHCP client.
01593  * @param ptr pointer obtained by dhcp_get_option_ptr().
01594  *
01595  * @return byte value at the given address.
01596  */
01597 static u32_t dhcp_get_option_long(u8_t *ptr)
01598 {
01599   u32_t value;
01600   value = (u32_t)(*ptr++) << 24;
01601   value |= (u32_t)(*ptr++) << 16;
01602   value |= (u32_t)(*ptr++) << 8;
01603   value |= (u32_t)(*ptr++);
01604   LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));
01605   return value;
01606 }
01607 
01608 #endif /* LWIP_DHCP */