Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

dhcp.c

Go to the documentation of this file.
00001 
00007 /*
00008  *
00009  * Copyright (c) 2001-2003 Leon Woestenberg <leon.woestenberg@gmx.net>
00010  * Copyright (c) 2001-2003 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  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00070  *            Departamento de Informática de Sistemas y Computadores          
00071  *            Universidad Politécnica de Valencia                             
00072  *            Valencia (Spain)    
00073  *            Date: April 2003                                          
00074  *  
00075  */
00076 
00077 #include "lwip/stats.h"
00078 #include "lwip/mem.h"
00079 #include "lwip/udp.h"
00080 #include "lwip/netif.h"
00081 #include "lwip/inet.h"
00082 #include "lwip/ip_addr.h"
00083 #include "netif/etharp.h"
00084 
00085 #include "lwip/sys.h"
00086 #include "lwip/opt.h"
00087 #include "lwip/dhcp.h"
00088 
00091 static u32_t xid = 0xABCD0000;
00092 
00094 static void dhcp_handle_ack(struct netif *netif);
00095 static void dhcp_handle_nak(struct netif *netif);
00096 static void dhcp_handle_offer(struct netif *netif);
00097 
00098 static err_t dhcp_discover(struct netif *netif);
00099 static err_t dhcp_select(struct netif *netif);
00100 static void dhcp_check(struct netif *netif);
00101 static void dhcp_bind(struct netif *netif);
00102 static err_t dhcp_decline(struct netif *netif);
00103 static err_t dhcp_rebind(struct netif *netif);
00104 static err_t dhcp_release(struct netif *netif);
00105 static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state);
00106 
00108 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
00109 static err_t dhcp_unfold_reply(struct dhcp *dhcp);
00110 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
00111 static u8_t dhcp_get_option_byte(u8_t *ptr);
00112 static u16_t dhcp_get_option_short(u8_t *ptr);
00113 static u32_t dhcp_get_option_long(u8_t *ptr);
00114 static void dhcp_free_reply(struct dhcp *dhcp);
00115 
00117 static void dhcp_timeout(struct netif *netif);
00118 static void dhcp_t1_timeout(struct netif *netif);
00119 static void dhcp_t2_timeout(struct netif *netif);
00120 
00123 static err_t dhcp_create_request(struct netif *netif);
00125 static void dhcp_delete_request(struct netif *netif);
00127 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
00129 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
00130 static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
00131 static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
00133 static void dhcp_option_trailer(struct dhcp *dhcp);
00134 
00146 static void dhcp_handle_nak(struct netif *netif) {
00147   struct dhcp *dhcp = netif->dhcp;
00148   u16_t msecs = 10 * 1000;
00149   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_handle_nak()\n"));
00150   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00151   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_handle_nak(): set request timeout %u msecs\n", msecs));
00152   dhcp_set_state(dhcp, DHCP_BACKING_OFF);
00153 }
00154 
00162 static void dhcp_check(struct netif *netif)
00163 {
00164   struct dhcp *dhcp = netif->dhcp;
00165   err_t result;
00166   u16_t msecs;
00167   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_check()\n"));
00168   /* create an ARP query for the offered IP address, expecting that no host
00169      responds, as the IP address should not be in use. */
00170   result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
00171   if (result != ERR_OK) {
00172     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
00173   }
00174   dhcp->tries++;
00175   msecs = 500;
00176   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00177   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_check(): set request timeout %u msecs\n", msecs));
00178   dhcp_set_state(dhcp, DHCP_CHECKING);
00179 }
00180 
00186 static void dhcp_handle_offer(struct netif *netif)
00187 {
00188   struct dhcp *dhcp = netif->dhcp;
00189   /* obtain the server address */
00190   u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
00191   if (option_ptr != NULL)
00192   {
00193     dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00194     DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): server 0x%08lx\n", dhcp->server_ip_addr.addr));
00195     /* remember offered address */
00196     ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
00197     DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08lx\n", dhcp->offered_ip_addr.addr));
00198     dhcp_select(netif);
00199   }
00200 }
00201 
00210 static err_t dhcp_select(struct netif *netif)
00211 {
00212   struct dhcp *dhcp = netif->dhcp;
00213   err_t result;
00214   u32_t msecs;
00215   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_select()\n"));
00216 
00217   /* create and initialize the DHCP message header */
00218   result = dhcp_create_request(netif);
00219   if (result == ERR_OK)
00220   {
00221     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00222     dhcp_option_byte(dhcp, DHCP_REQUEST);
00223 
00224     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00225     dhcp_option_short(dhcp, 576);
00226 
00227     /* MUST request the offered IP address */
00228     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00229     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00230 
00231     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
00232     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
00233 
00234     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3);
00235     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
00236     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
00237     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
00238 
00239     dhcp_option_trailer(dhcp);
00240     /* shrink the pbuf to the actual content length */
00241     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00242 
00243     /* TODO: we really should bind to a specific local interface here
00244        but we cannot specify an unconfigured netif as it is addressless */
00245     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00246     /* send broadcast to any DHCP server */
00247     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
00248     udp_send(dhcp->pcb, dhcp->p_out);
00249     /* reconnect to any (or to server here?!) */
00250     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00251     dhcp_delete_request(netif);
00252     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_select: REQUESTING\n"));
00253     dhcp_set_state(dhcp, DHCP_REQUESTING);
00254   } else {
00255     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
00256   }
00257   dhcp->tries++;
00258   msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;
00259   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00260   DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_select(): set request timeout %u msecs\n", msecs));
00261   return result;
00262 }
00263 
00268 void dhcp_coarse_tmr()
00269 {
00270   struct netif *netif = netif_list;
00271   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_coarse_tmr()\n"));
00272   /* iterate through all network interfaces */
00273   while (netif != NULL) {
00274     /* only act on DHCP configured interfaces */
00275     if (netif->dhcp != NULL) {
00276       /* timer is active (non zero), and triggers (zeroes) now? */
00277       if (netif->dhcp->t2_timeout-- == 1) {
00278         DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
00279         /* this clients' rebind timeout triggered */
00280         dhcp_t2_timeout(netif);
00281       /* timer is active (non zero), and triggers (zeroes) now */
00282       } else if (netif->dhcp->t1_timeout-- == 1) {
00283         DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
00284         /* this clients' renewal timeout triggered */
00285         dhcp_t1_timeout(netif);
00286       }
00287     }
00288     /* proceed to next netif */
00289     netif = netif->next;
00290   }
00291 }
00292 
00299 void dhcp_fine_tmr()
00300 {
00301   struct netif *netif = netif_list;
00302   /* loop through clients */
00303   while (netif != NULL) {
00304     /* only act on DHCP configured interfaces */
00305     if (netif->dhcp != NULL) {
00306       /* timer is active (non zero), and triggers (zeroes) now */
00307       if (netif->dhcp->request_timeout-- == 1) {
00308         DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
00309         /* this clients' request timeout triggered */
00310         dhcp_timeout(netif);
00311       }
00312     }
00313     /* proceed to next network interface */
00314     netif = netif->next;
00315   }
00316 }
00317 
00327 static void dhcp_timeout(struct netif *netif)
00328 {
00329   struct dhcp *dhcp = netif->dhcp;
00330   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_timeout()\n"));
00331   /* back-off period has passed, or server selection timed out */
00332   if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
00333     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
00334     dhcp_discover(netif);
00335   /* receiving the requested lease timed out */
00336   } else if (dhcp->state == DHCP_REQUESTING) {
00337     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
00338     if (dhcp->tries <= 5) {
00339       dhcp_select(netif);
00340     } else {
00341       DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
00342       dhcp_release(netif);
00343       dhcp_discover(netif);
00344     }
00345   /* received no ARP reply for the offered address (which is good) */
00346   } else if (dhcp->state == DHCP_CHECKING) {
00347     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
00348     if (dhcp->tries <= 1) {
00349       dhcp_check(netif);
00350     /* no ARP replies on the offered address, 
00351        looks like the IP address is indeed free */
00352     } else {
00353       /* bind the interface to the offered address */
00354       dhcp_bind(netif);
00355     }
00356   }
00357   /* did not get response to renew request? */
00358   else if (dhcp->state == DHCP_RENEWING) {
00359     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
00360     /* just retry renewal */ 
00361     /* note that the rebind timer will eventually time-out if renew does not work */
00362     dhcp_renew(netif);
00363   /* did not get response to rebind request? */
00364   } else if (dhcp->state == DHCP_REBINDING) {
00365     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
00366     if (dhcp->tries <= 8) {
00367       dhcp_rebind(netif);
00368     } else {
00369       DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
00370       dhcp_release(netif);
00371       dhcp_discover(netif);
00372     }
00373   }
00374 }
00375 
00381 static void dhcp_t1_timeout(struct netif *netif)
00382 {
00383   struct dhcp *dhcp = netif->dhcp;
00384   DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_t1_timeout()\n"));
00385   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
00386     /* just retry to renew */
00387     /* note that the rebind timer will eventually time-out if renew does not work */
00388     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
00389     dhcp_renew(netif);
00390   }
00391 }
00392 
00397 static void dhcp_t2_timeout(struct netif *netif)
00398 {
00399   struct dhcp *dhcp = netif->dhcp;
00400   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout()\n"));
00401   if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
00402     /* just retry to rebind */
00403     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
00404     dhcp_rebind(netif);
00405   }
00406 }
00407 
00413 static void dhcp_handle_ack(struct netif *netif)
00414 {
00415   struct dhcp *dhcp = netif->dhcp;
00416   u8_t *option_ptr;
00417   /* clear options we might not get from the ACK */
00418   dhcp->offered_sn_mask.addr = 0;
00419   dhcp->offered_gw_addr.addr = 0;
00420   dhcp->offered_bc_addr.addr = 0;
00421 
00422   /* lease time given? */
00423   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);
00424   if (option_ptr != NULL) {
00425     /* remember offered lease time */
00426     dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);
00427   }
00428   /* renewal period given? */
00429   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);
00430   if (option_ptr != NULL) {
00431     /* remember given renewal period */
00432     dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);
00433   } else {
00434     /* calculate safe periods for renewal */
00435     dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
00436   }
00437 
00438   /* renewal period given? */
00439   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);
00440   if (option_ptr != NULL) {
00441     /* remember given rebind period */
00442     dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);
00443   } else {
00444     /* calculate safe periods for rebinding */
00445     dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
00446   }
00447 
00448   /* (y)our internet address */
00449   ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
00450 
00451   /* subnet mask */
00452   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);
00453   /* subnet mask given? */
00454   if (option_ptr != NULL) {
00455     dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00456   }
00457 
00458   /* gateway router */
00459   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);
00460   if (option_ptr != NULL) {
00461     dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00462   }
00463 
00464   /* broadcast address */
00465   option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);
00466   if (option_ptr != NULL) {
00467     dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
00468   }
00469 }
00470 
00484 err_t dhcp_start(struct netif *netif)
00485 {
00486   struct dhcp *dhcp = netif->dhcp;
00487   err_t result = ERR_OK;
00488 
00489   LWIP_ASSERT("netif != NULL", netif != NULL);
00490   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_start(netif=%p) %c%c%u\n", netif, netif->name[0], netif->name[1], netif->num));
00491 
00492   if (dhcp == NULL) {
00493     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
00494     dhcp = mem_malloc(sizeof(struct dhcp));
00495     if (dhcp == NULL) {
00496       DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
00497       netif->flags &= ~NETIF_FLAG_DHCP;
00498       return ERR_MEM;
00499     }
00500     /* clear data structure */
00501     memset(dhcp, 0, sizeof(struct dhcp));
00502     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): allocated dhcp"));
00503     dhcp->pcb = udp_new();
00504     if (dhcp->pcb == NULL) {
00505       DEBUGF(DHCP_DEBUG  | DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
00506       mem_free((void *)dhcp);
00507       dhcp = NULL;
00508       netif->flags &= ~NETIF_FLAG_DHCP;
00509       return ERR_MEM;
00510     }
00511     /* store this dhcp client in the netif */
00512     netif->dhcp = dhcp;
00513     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): created new udp pcb\n"));
00514     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
00515   } else {
00516     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
00517   }
00518   /* (re)start the DHCP negotiation */
00519   result = dhcp_discover(netif);
00520   if (result != ERR_OK) {
00521     /* free resources allocated above */
00522     dhcp_stop(netif);
00523   }
00524   return result;
00525 }
00526 
00537 void dhcp_inform(struct netif *netif)
00538 {
00539   struct dhcp *dhcp;
00540   err_t result = ERR_OK;
00541   dhcp = mem_malloc(sizeof(struct dhcp));
00542   if (dhcp == NULL) {
00543     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
00544     return;
00545   }  
00546   memset(dhcp, 0, sizeof(struct dhcp));
00547 
00548   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
00549   dhcp->pcb = udp_new();
00550   if (dhcp->pcb == NULL) {
00551     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
00552     mem_free((void *)dhcp);
00553     return;
00554   }
00555   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
00556   /* create and initialize the DHCP message header */
00557   result = dhcp_create_request(netif);
00558   if (result == ERR_OK) {
00559 
00560     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00561     dhcp_option_byte(dhcp, DHCP_INFORM);
00562 
00563     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00564     /* TODO: use netif->mtu ?! */
00565     dhcp_option_short(dhcp, 576);
00566 
00567     dhcp_option_trailer(dhcp);
00568 
00569     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00570 
00571     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00572     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
00573     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_inform: INFORMING\n"));
00574     udp_send(dhcp->pcb, dhcp->p_out);
00575     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00576     dhcp_delete_request(netif);
00577   } else {
00578     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
00579   }
00580 
00581   if (dhcp != NULL)
00582   {
00583     if (dhcp->pcb != NULL) udp_remove(dhcp->pcb);
00584     dhcp->pcb = NULL;
00585     mem_free((void *)dhcp);
00586   }
00587 }
00588 
00589 #if DHCP_DOES_ARP_CHECK
00590 
00596 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
00597 {
00598   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
00599   /* is this DHCP client doing an ARP check? */
00600   if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
00601     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08lx\n", addr->addr));
00602     /* did a host respond with the address we
00603        were offered by the DHCP server? */
00604     if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
00605       /* we will not accept the offered address */
00606       DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
00607       dhcp_decline(netif);
00608     }
00609   }
00610 }
00611 
00619 static err_t dhcp_decline(struct netif *netif)
00620 {
00621   struct dhcp *dhcp = netif->dhcp;
00622   err_t result = ERR_OK;
00623   u16_t msecs;
00624   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_decline()\n"));
00625   dhcp_set_state(dhcp, DHCP_BACKING_OFF);
00626   /* create and initialize the DHCP message header */
00627   result = dhcp_create_request(netif);
00628   if (result == ERR_OK)
00629   {
00630     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00631     dhcp_option_byte(dhcp, DHCP_DECLINE);
00632 
00633     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00634     dhcp_option_short(dhcp, 576);
00635 
00636     dhcp_option_trailer(dhcp);
00637     /* resize pbuf to reflect true size of options */
00638     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00639 
00640     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00641     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
00642     udp_send(dhcp->pcb, dhcp->p_out);
00643     dhcp_delete_request(netif);
00644     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
00645   } else {
00646     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
00647   }
00648   dhcp->tries++;
00649   msecs = 10*1000;
00650   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00651    DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_decline(): set request timeout %u msecs\n", msecs));
00652   return result;
00653 }
00654 #endif
00655 
00656 
00661 static err_t dhcp_discover(struct netif *netif)
00662 {
00663   struct dhcp *dhcp = netif->dhcp;
00664   err_t result = ERR_OK;
00665   u16_t msecs;
00666   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_discover()\n"));
00667   ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
00668   /* create and initialize the DHCP message header */
00669   result = dhcp_create_request(netif);
00670   if (result == ERR_OK)
00671   {
00672     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: making request\n"));
00673     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00674     dhcp_option_byte(dhcp, DHCP_DISCOVER);
00675 
00676     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00677     dhcp_option_short(dhcp, 576);
00678 
00679     dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3);
00680     dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
00681     dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
00682     dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
00683 
00684     dhcp_option_trailer(dhcp);
00685 
00686     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
00687     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00688 
00689     /* set receive callback function with netif as user data */
00690     udp_recv(dhcp->pcb, dhcp_recv, netif);
00691     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00692     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
00693 
00694     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: send()ing\n"));
00695 
00696     udp_send(dhcp->pcb, dhcp->p_out);
00697     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: bind()ing\n"));
00698     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00699     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: connect()ing\n"));
00700     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00701     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
00702     dhcp_delete_request(netif);
00703     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover: SELECTING\n"));
00704     dhcp_set_state(dhcp, DHCP_SELECTING);
00705   } else {
00706     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
00707   }
00708   dhcp->tries++;
00709   msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;
00710   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00711   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_discover(): set request timeout %u msecs\n", msecs));
00712   return result;
00713 }
00714 
00715 
00721 static void dhcp_bind(struct netif *netif)
00722 {
00723   struct dhcp *dhcp = netif->dhcp;
00724   struct ip_addr sn_mask, gw_addr;
00725   
00726   /* temporary DHCP lease? */
00727   if (dhcp->offered_t1_renew != 0xffffffffUL) {
00728     /* set renewal period timer */
00729     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t1 renewal timer %lu secs\n", dhcp->offered_t1_renew));
00730     dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
00731     if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1;
00732     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %u msecs\n", dhcp->offered_t1_renew*1000));
00733   }
00734   /* set renewal period timer */
00735   if (dhcp->offered_t2_rebind != 0xffffffffUL) {
00736     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_bind(): t2 rebind timer %lu secs\n", dhcp->offered_t2_rebind));
00737     dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
00738     if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1;
00739     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_bind(): set request timeout %u msecs\n", dhcp->offered_t2_rebind*1000));
00740   }
00741   /* copy offered network mask */
00742   ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
00743 
00744   /* subnet mask not given? */
00745   /* TODO: this is not a valid check. what if the network mask is 0? */
00746   if (sn_mask.addr == 0) {
00747     /* choose a safe subnet mask given the network class */
00748     u8_t first_octet = ip4_addr1(&sn_mask);
00749     if (first_octet <= 127) sn_mask.addr = htonl(0xff000000);
00750     else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00);
00751     else sn_mask.addr = htonl(0xffff0000);
00752   }
00753 
00754   ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);
00755   /* gateway address not given? */
00756   if (gw_addr.addr == 0) {
00757     /* copy network address */
00758     gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);
00759     /* use first host address on network as gateway */
00760     gw_addr.addr |= htonl(0x00000001);
00761   }
00762 
00763   DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): IP: 0x%08lx\n", dhcp->offered_ip_addr.addr));
00764   netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
00765   DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): SN: 0x%08lx\n", sn_mask.addr));
00766   netif_set_netmask(netif, &sn_mask);
00767   DEBUGF(DHCP_DEBUG | DBG_STATE, ("dhcp_bind(): GW: 0x%08lx\n", gw_addr.addr));
00768   netif_set_gw(netif, &gw_addr);
00769   /* netif is now bound to DHCP leased address */
00770   dhcp_set_state(dhcp, DHCP_BOUND);
00771 }
00772 
00778 err_t dhcp_renew(struct netif *netif)
00779 {
00780   struct dhcp *dhcp = netif->dhcp;
00781   err_t result;
00782   u16_t msecs;
00783   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_renew()\n"));
00784   dhcp_set_state(dhcp, DHCP_RENEWING);
00785 
00786   /* create and initialize the DHCP message header */
00787   result = dhcp_create_request(netif);
00788   if (result == ERR_OK) {
00789 
00790     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00791     dhcp_option_byte(dhcp, DHCP_REQUEST);
00792 
00793     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00794     /* TODO: use netif->mtu in some way */
00795     dhcp_option_short(dhcp, 576);
00796 
00797 #if 0
00798     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00799     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00800 #endif
00801 
00802 #if 0
00803     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
00804     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
00805 #endif
00806     /* append DHCP message trailer */
00807     dhcp_option_trailer(dhcp);
00808 
00809     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00810 
00811     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00812     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
00813     udp_send(dhcp->pcb, dhcp->p_out);
00814     dhcp_delete_request(netif);
00815 
00816     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew: RENEWING\n"));
00817   } else {
00818     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
00819   }
00820   dhcp->tries++;
00821   /* back-off on retries, but to a maximum of 20 seconds */
00822   msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
00823   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00824    DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_renew(): set request timeout %u msecs\n", msecs));
00825   return result;
00826 }
00827 
00833 static err_t dhcp_rebind(struct netif *netif)
00834 {
00835   struct dhcp *dhcp = netif->dhcp;
00836   err_t result;
00837   u16_t msecs;
00838   DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind()\n"));
00839   dhcp_set_state(dhcp, DHCP_REBINDING);
00840 
00841   /* create and initialize the DHCP message header */
00842   result = dhcp_create_request(netif);
00843   if (result == ERR_OK)
00844   {
00845 
00846     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00847     dhcp_option_byte(dhcp, DHCP_REQUEST);
00848 
00849     dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
00850     dhcp_option_short(dhcp, 576);
00851 
00852 #if 0
00853     dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
00854     dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
00855 
00856     dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
00857     dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
00858 #endif
00859 
00860     dhcp_option_trailer(dhcp);
00861 
00862     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00863 
00864     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00865     udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);
00866     udp_send(dhcp->pcb, dhcp->p_out);
00867     udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
00868     dhcp_delete_request(netif);
00869     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind: REBINDING\n"));
00870   } else {
00871     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
00872   }
00873   dhcp->tries++;
00874   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
00875   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00876    DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_rebind(): set request timeout %u msecs\n", msecs));
00877   return result;
00878 }
00879 
00885 static err_t dhcp_release(struct netif *netif)
00886 {
00887   struct dhcp *dhcp = netif->dhcp;
00888   err_t result;
00889   u16_t msecs;
00890   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_release()\n"));
00891 
00892   /* idle DHCP client */
00893   dhcp_set_state(dhcp, DHCP_OFF);
00894 
00895 
00896   /* create and initialize the DHCP message header */
00897   result = dhcp_create_request(netif);
00898   if (result == ERR_OK) {
00899     dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
00900     dhcp_option_byte(dhcp, DHCP_RELEASE);
00901 
00902     dhcp_option_trailer(dhcp);
00903 
00904     pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
00905 
00906     udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
00907     udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);
00908     udp_send(dhcp->pcb, dhcp->p_out);
00909     dhcp_delete_request(netif);
00910     DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
00911   } else {
00912     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
00913   }
00914   dhcp->tries++;
00915   msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
00916   dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
00917    DEBUGF(DHCP_DEBUG | DBG_TRACE | DBG_STATE, ("dhcp_release(): set request timeout %u msecs\n", msecs));
00918   /* remove IP address from interface */
00919   netif_set_ipaddr(netif, IP_ADDR_ANY);
00920   netif_set_gw(netif, IP_ADDR_ANY);
00921   netif_set_netmask(netif, IP_ADDR_ANY);
00922   /* TODO: netif_down(netif); */
00923   return result;
00924 }
00930 void dhcp_stop(struct netif *netif)
00931 {
00932   struct dhcp *dhcp = netif->dhcp;
00933   DEBUGF(DHCP_DEBUG | DBG_TRACE | 3, ("dhcp_stop()\n"));
00934   /* netif is DHCP configured? */
00935   if (dhcp != NULL)
00936   {
00937     if (dhcp->pcb != NULL)
00938     {
00939       udp_remove(dhcp->pcb);
00940       dhcp->pcb = NULL;
00941     }
00942     if (dhcp->p != NULL)
00943     {
00944       pbuf_free(dhcp->p);
00945       dhcp->p = NULL;
00946     }
00947     /* free unfolded reply */
00948     dhcp_free_reply(dhcp);
00949     mem_free((void *)dhcp);
00950     netif->dhcp = NULL;
00951   }
00952 }
00953 
00954 /*
00955  * Set the DHCP state of a DHCP client.
00956  * 
00957  * If the state changed, reset the number of tries.
00958  *
00959  * TODO: we might also want to reset the timeout here?
00960  */
00961 static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state)
00962 {
00963   if (new_state != dhcp->state)
00964   {
00965     dhcp->state = new_state;
00966     dhcp->tries = 0;
00967   }
00968 }
00969 
00970 /*
00971  * Concatenate an option type and length field to the outgoing
00972  * DHCP message.
00973  *
00974  */
00975 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
00976 {
00977   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN);
00978   dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
00979   dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
00980 }
00981 /*
00982  * Concatenate a single byte to the outgoing DHCP message.
00983  *
00984  */
00985 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value)
00986 {
00987   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
00988   dhcp->msg_out->options[dhcp->options_out_len++] = value;
00989 }                             
00990 static void dhcp_option_short(struct dhcp *dhcp, u16_t value)
00991 {
00992   LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN);
00993   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8;
00994   dhcp->msg_out->options[dhcp->options_out_len++] =  value & 0x00ffU;
00995 }
00996 static void dhcp_option_long(struct dhcp *dhcp, u32_t value)
00997 {
00998   LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN);
00999   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24;
01000   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16;
01001   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8;
01002   dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL);
01003 }
01004 
01015 static err_t dhcp_unfold_reply(struct dhcp *dhcp)
01016 {
01017   struct pbuf *p = dhcp->p;
01018   u8_t *ptr;
01019   u16_t i;
01020   u16_t j = 0;
01021   /* free any left-overs from previous unfolds */
01022   dhcp_free_reply(dhcp);
01023   dhcp->msg_in = NULL;
01024   dhcp->options_in = NULL;
01025   /* options present? */
01026   if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))
01027   {
01028     dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
01029     dhcp->options_in = mem_malloc(dhcp->options_in_len);
01030     if (dhcp->options_in == NULL)
01031     {
01032       DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n")); 
01033       return ERR_MEM;
01034     }
01035   }
01036   dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
01037   if (dhcp->msg_in == NULL)
01038   {
01039     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); 
01040     mem_free((void *)dhcp->options_in);
01041     dhcp->options_in = NULL;
01042     return ERR_MEM;
01043   }
01044 
01045   ptr = (u8_t *)dhcp->msg_in;
01046   /* proceed through struct dhcp_msg */
01047   for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++)
01048   {
01049     *ptr++ = ((u8_t *)p->payload)[j++];
01050     /* reached end of pbuf? */
01051     if (j == p->len)
01052     {
01053       /* proceed to next pbuf in chain */
01054       p = p->next;
01055       j = 0;
01056     }
01057   }
01058   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %u bytes into dhcp->msg_in[]\n", i)); 
01059   if (dhcp->options_in != NULL) {
01060     ptr = (u8_t *)dhcp->options_in;
01061     /* proceed through options */
01062     for (i = 0; i < dhcp->options_in_len; i++) {
01063       *ptr++ = ((u8_t *)p->payload)[j++];
01064       /* reached end of pbuf? */
01065       if (j == p->len) {
01066         /* proceed to next pbuf in chain */
01067         p = p->next;
01068         j = 0;
01069       }
01070     }
01071     DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_unfold_reply(): copied %u bytes to dhcp->options_in[]\n", i)); 
01072   }
01073   return ERR_OK;
01074 }
01075 
01081 static void dhcp_free_reply(struct dhcp *dhcp)
01082 {
01083   if (dhcp->msg_in != NULL) {
01084     mem_free((void *)dhcp->msg_in);
01085     dhcp->msg_in = NULL;
01086   }
01087   if (dhcp->options_in) {
01088     mem_free((void *)dhcp->options_in);
01089     dhcp->options_in = NULL;
01090     dhcp->options_in_len = 0;
01091   }
01092   DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n")); 
01093 }
01094 
01095 
01099 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
01100 {
01101   struct netif *netif = (struct netif *)arg;
01102   struct dhcp *dhcp = netif->dhcp;
01103   struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
01104   u8_t *options_ptr;
01105   u8_t msg_type;
01106   u8_t i;
01107   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("dhcp_recv()\n"));
01108   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->len = %u\n", p->len));
01109   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("pbuf->tot_len = %u\n", p->tot_len));
01110   dhcp->p = p;
01111   if (reply_msg->op != DHCP_BOOTREPLY) {
01112     DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("not a DHCP reply message, but type %u\n", reply_msg->op));
01113     pbuf_free(p);
01114   }
01115   /* iterate through hardware address and match against DHCP message */
01116   for (i = 0; i < netif->hwaddr_len; i++) {
01117     if (netif->hwaddr[i] != reply_msg->chaddr[i]) { 
01118       DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("netif->hwaddr[%u]==%02x != reply_msg->chaddr[%u]==%02x\n",
01119         i, netif->hwaddr[i], i, reply_msg->chaddr[i]));
01120       pbuf_free(p);
01121       return;
01122     }
01123   }
01124   /* match transaction ID against what we expected */
01125   if (ntohl(reply_msg->xid) != dhcp->xid) {
01126     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("transaction id mismatch\n"));
01127     pbuf_free(p);
01128     return;
01129   }
01130   /* option fields could be unfold? */
01131   if (dhcp_unfold_reply(dhcp) != ERR_OK) {
01132     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
01133     pbuf_free(p);
01134     return;
01135   }
01136   
01137   DEBUGF(DHCP_DEBUG | DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
01138   /* obtain pointer to DHCP message type */ 
01139   options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
01140   if (options_ptr == NULL) {
01141     DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); 
01142     pbuf_free(p);
01143     return;
01144   }  
01145 
01146   /* read DHCP message type */
01147   msg_type = dhcp_get_option_byte(options_ptr + 2);
01148   /* message type is DHCP ACK? */
01149   if (msg_type == DHCP_ACK) {
01150     DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_ACK received\n")); 
01151     /* in requesting state? */
01152     if (dhcp->state == DHCP_REQUESTING) {
01153       dhcp_handle_ack(netif);
01154       dhcp->request_timeout = 0;
01155 #if DHCP_DOES_ARP_CHECK
01156       /* check if the acknowledged lease address is already in use */
01157       dhcp_check(netif);
01158 #else
01159       /* bind interface to the acknowledged lease address */
01160       dhcp_bind(netif);
01161 #endif
01162     }
01163     /* already bound to the given lease address? */
01164     else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
01165       dhcp->request_timeout = 0;
01166       dhcp_bind(netif);
01167     }
01168   }
01169   /* received a DHCP_NAK in appropriate state? */
01170   else if ((msg_type == DHCP_NAK) &&
01171     ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || 
01172      (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {
01173     DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_NAK received\n")); 
01174     dhcp->request_timeout = 0;
01175     dhcp_handle_nak(netif);
01176   }
01177   /* received a DHCP_OFFER in DHCP_SELECTING state? */
01178   else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
01179     DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n")); 
01180     dhcp->request_timeout = 0;
01181     /* remember offered lease */
01182     dhcp_handle_offer(netif);
01183   }
01184   pbuf_free(p);
01185 }
01186 
01187 
01188 static err_t dhcp_create_request(struct netif *netif)
01189 {
01190   struct dhcp *dhcp = netif->dhcp;
01191   u16_t i;
01192   LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
01193   LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
01194   dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
01195   if (dhcp->p_out == NULL) {
01196     DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
01197     return ERR_MEM;
01198   }
01199   /* give unique transaction identifier to this request */
01200   dhcp->xid = xid++;  
01201 
01202   dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
01203 
01204   dhcp->msg_out->op = DHCP_BOOTREQUEST;
01205   /* TODO: make link layer independent */  
01206   dhcp->msg_out->htype = DHCP_HTYPE_ETH;  
01207   /* TODO: make link layer independent */  
01208   dhcp->msg_out->hlen = DHCP_HLEN_ETH;  
01209   dhcp->msg_out->hops = 0;
01210   dhcp->msg_out->xid = htonl(dhcp->xid);  
01211   dhcp->msg_out->secs = 0;
01212   dhcp->msg_out->flags = 0;
01213   dhcp->msg_out->ciaddr = netif->ip_addr.addr;
01214   dhcp->msg_out->yiaddr = 0;
01215   dhcp->msg_out->siaddr = 0;
01216   dhcp->msg_out->giaddr = 0;
01217   for (i = 0; i < DHCP_CHADDR_LEN; i++) {
01218     /* copy netif hardware address, pad with zeroes */
01219     dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
01220   }
01221   for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0;
01222   for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0;
01223   dhcp->msg_out->cookie = htonl(0x63825363UL);
01224   dhcp->options_out_len = 0;
01225   /* fill options field with an incrementing array (for debugging purposes) */
01226   for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i;
01227   return ERR_OK;
01228 }
01229 
01230 static void dhcp_delete_request(struct netif *netif)
01231 {
01232   struct dhcp *dhcp = netif->dhcp;
01233   LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL);
01234   LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
01235   pbuf_free(dhcp->p_out);
01236   dhcp->p_out = NULL;
01237   dhcp->msg_out = NULL;
01238 }
01239 
01247 static void dhcp_option_trailer(struct dhcp *dhcp)
01248 {
01249   LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
01250   LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
01251   dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
01252   /* packet is too small, or not 4 byte aligned? */
01253   while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
01254     /* DEBUGF(DHCP_DEBUG, ("dhcp_option_trailer: dhcp->options_out_len=%u, DHCP_OPTIONS_LEN=%u", dhcp->options_out_len, DHCP_OPTIONS_LEN)); */
01255     LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
01256     /* add a fill/padding byte */
01257     dhcp->msg_out->options[dhcp->options_out_len++] = 0;
01258   }
01259 }
01260 
01270 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
01271 {
01272   u8_t overload = DHCP_OVERLOAD_NONE;
01273 
01274   /* options available? */
01275   if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
01276     /* start with options field */
01277     u8_t *options = (u8_t *)dhcp->options_in;
01278     u16_t offset = 0;
01279     /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
01280     while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
01281       /* DEBUGF(DHCP_DEBUG, ("msg_offset=%u, q->len=%u", msg_offset, q->len)); */
01282       /* are the sname and/or file field overloaded with options? */
01283       if (options[offset] == DHCP_OPTION_OVERLOAD) {
01284         DEBUGF(DHCP_DEBUG | DBG_TRACE | 2, ("overloaded message detected\n"));
01285         /* skip option type and length */
01286         offset += 2;
01287         overload = options[offset++];
01288       }
01289       /* requested option found */
01290       else if (options[offset] == option_type) {
01291         DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset %u in options\n", offset));
01292         return &options[offset];
01293       /* skip option */
01294       } else {
01295          DEBUGF(DHCP_DEBUG, ("skipping option %u in options\n", options[offset]));
01296         /* skip option type */
01297         offset++;
01298         /* skip option length, and then length bytes */
01299         offset += 1 + options[offset];
01300       }
01301     }
01302     /* is this an overloaded message? */
01303     if (overload != DHCP_OVERLOAD_NONE) {
01304       u16_t field_len;
01305       if (overload == DHCP_OVERLOAD_FILE) {
01306         DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded file field\n"));
01307         options = (u8_t *)&dhcp->msg_in->file;
01308         field_len = DHCP_FILE_LEN;
01309       } else if (overload == DHCP_OVERLOAD_SNAME) {
01310         DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname field\n"));
01311         options = (u8_t *)&dhcp->msg_in->sname;
01312         field_len = DHCP_SNAME_LEN;
01313       /* TODO: check if else if () is necessary */
01314       } else {
01315         DEBUGF(DHCP_DEBUG | DBG_TRACE | 1, ("overloaded sname and file field\n"));
01316         options = (u8_t *)&dhcp->msg_in->sname;
01317         field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
01318       }
01319       offset = 0;
01320 
01321       /* at least 1 byte to read and no end marker */
01322       while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
01323         if (options[offset] == option_type) {
01324            DEBUGF(DHCP_DEBUG | DBG_TRACE, ("option found at offset=%u\n", offset));
01325           return &options[offset];
01326         /* skip option */
01327         } else {
01328           DEBUGF(DHCP_DEBUG | DBG_TRACE, ("skipping option %u\n", options[offset]));
01329           /* skip option type */
01330           offset++;
01331           offset += 1 + options[offset];
01332         }
01333       }
01334     }
01335   }
01336   return 0;
01337 }
01338 
01347 static u8_t dhcp_get_option_byte(u8_t *ptr)
01348 {
01349   DEBUGF(DHCP_DEBUG, ("option byte value=%u\n", *ptr));
01350   return *ptr;
01351 }                             
01352 
01361 static u16_t dhcp_get_option_short(u8_t *ptr)
01362 {
01363   u16_t value;
01364   value = *ptr++ << 8;
01365   value |= *ptr;
01366   DEBUGF(DHCP_DEBUG, ("option short value=%u\n", value));
01367   return value;
01368 }                             
01369 
01378 static u32_t dhcp_get_option_long(u8_t *ptr)
01379 {
01380   u32_t value;
01381   value = (u32_t)(*ptr++) << 24;
01382   value |= (u32_t)(*ptr++) << 16;
01383   value |= (u32_t)(*ptr++) << 8;
01384   value |= (u32_t)(*ptr++);
01385   DEBUGF(DHCP_DEBUG, ("option long value=%lu\n", value));
01386   return value;
01387 }                             

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4