Port of LwIP performed by Ralf in 2010. Not recommended for use with recent mbed libraries, but good demos of raw LwIP possible

Dependents:   LwIP_raw_API_serverExample tiny-dtls

Committer:
RodColeman
Date:
Tue Sep 18 14:41:24 2012 +0000
Revision:
0:0791c1fece8e
[mbed] converted /Eth_TCP_Wei_Server/lwip

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RodColeman 0:0791c1fece8e 1 /**
RodColeman 0:0791c1fece8e 2 * @file
RodColeman 0:0791c1fece8e 3 * Dynamic Host Configuration Protocol client
RodColeman 0:0791c1fece8e 4 *
RodColeman 0:0791c1fece8e 5 */
RodColeman 0:0791c1fece8e 6
RodColeman 0:0791c1fece8e 7 /*
RodColeman 0:0791c1fece8e 8 *
RodColeman 0:0791c1fece8e 9 * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>
RodColeman 0:0791c1fece8e 10 * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.
RodColeman 0:0791c1fece8e 11 * All rights reserved.
RodColeman 0:0791c1fece8e 12 *
RodColeman 0:0791c1fece8e 13 * Redistribution and use in source and binary forms, with or without modification,
RodColeman 0:0791c1fece8e 14 * are permitted provided that the following conditions are met:
RodColeman 0:0791c1fece8e 15 *
RodColeman 0:0791c1fece8e 16 * 1. Redistributions of source code must retain the above copyright notice,
RodColeman 0:0791c1fece8e 17 * this list of conditions and the following disclaimer.
RodColeman 0:0791c1fece8e 18 * 2. Redistributions in binary form must reproduce the above copyright notice,
RodColeman 0:0791c1fece8e 19 * this list of conditions and the following disclaimer in the documentation
RodColeman 0:0791c1fece8e 20 * and/or other materials provided with the distribution.
RodColeman 0:0791c1fece8e 21 * 3. The name of the author may not be used to endorse or promote products
RodColeman 0:0791c1fece8e 22 * derived from this software without specific prior written permission.
RodColeman 0:0791c1fece8e 23 *
RodColeman 0:0791c1fece8e 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
RodColeman 0:0791c1fece8e 25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
RodColeman 0:0791c1fece8e 26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
RodColeman 0:0791c1fece8e 27 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
RodColeman 0:0791c1fece8e 28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
RodColeman 0:0791c1fece8e 29 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
RodColeman 0:0791c1fece8e 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
RodColeman 0:0791c1fece8e 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
RodColeman 0:0791c1fece8e 32 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
RodColeman 0:0791c1fece8e 33 * OF SUCH DAMAGE.
RodColeman 0:0791c1fece8e 34 *
RodColeman 0:0791c1fece8e 35 * This file is a contribution to the lwIP TCP/IP stack.
RodColeman 0:0791c1fece8e 36 * The Swedish Institute of Computer Science and Adam Dunkels
RodColeman 0:0791c1fece8e 37 * are specifically granted permission to redistribute this
RodColeman 0:0791c1fece8e 38 * source code.
RodColeman 0:0791c1fece8e 39 *
RodColeman 0:0791c1fece8e 40 * Author: Leon Woestenberg <leon.woestenberg@gmx.net>
RodColeman 0:0791c1fece8e 41 *
RodColeman 0:0791c1fece8e 42 * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform
RodColeman 0:0791c1fece8e 43 * with RFC 2131 and RFC 2132.
RodColeman 0:0791c1fece8e 44 *
RodColeman 0:0791c1fece8e 45 * TODO:
RodColeman 0:0791c1fece8e 46 * - Proper parsing of DHCP messages exploiting file/sname field overloading.
RodColeman 0:0791c1fece8e 47 * - Add JavaDoc style documentation (API, internals).
RodColeman 0:0791c1fece8e 48 * - Support for interfaces other than Ethernet (SLIP, PPP, ...)
RodColeman 0:0791c1fece8e 49 *
RodColeman 0:0791c1fece8e 50 * Please coordinate changes and requests with Leon Woestenberg
RodColeman 0:0791c1fece8e 51 * <leon.woestenberg@gmx.net>
RodColeman 0:0791c1fece8e 52 *
RodColeman 0:0791c1fece8e 53 * Integration with your code:
RodColeman 0:0791c1fece8e 54 *
RodColeman 0:0791c1fece8e 55 * In lwip/dhcp.h
RodColeman 0:0791c1fece8e 56 * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)
RodColeman 0:0791c1fece8e 57 * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)
RodColeman 0:0791c1fece8e 58 *
RodColeman 0:0791c1fece8e 59 * Then have your application call dhcp_coarse_tmr() and
RodColeman 0:0791c1fece8e 60 * dhcp_fine_tmr() on the defined intervals.
RodColeman 0:0791c1fece8e 61 *
RodColeman 0:0791c1fece8e 62 * dhcp_start(struct netif *netif);
RodColeman 0:0791c1fece8e 63 * starts a DHCP client instance which configures the interface by
RodColeman 0:0791c1fece8e 64 * obtaining an IP address lease and maintaining it.
RodColeman 0:0791c1fece8e 65 *
RodColeman 0:0791c1fece8e 66 * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)
RodColeman 0:0791c1fece8e 67 * to remove the DHCP client.
RodColeman 0:0791c1fece8e 68 *
RodColeman 0:0791c1fece8e 69 */
RodColeman 0:0791c1fece8e 70
RodColeman 0:0791c1fece8e 71 #include "lwip/opt.h"
RodColeman 0:0791c1fece8e 72
RodColeman 0:0791c1fece8e 73 #if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */
RodColeman 0:0791c1fece8e 74
RodColeman 0:0791c1fece8e 75 #include "lwip/stats.h"
RodColeman 0:0791c1fece8e 76 #include "lwip/mem.h"
RodColeman 0:0791c1fece8e 77 #include "lwip/udp.h"
RodColeman 0:0791c1fece8e 78 #include "lwip/ip_addr.h"
RodColeman 0:0791c1fece8e 79 #include "lwip/netif.h"
RodColeman 0:0791c1fece8e 80 #include "lwip/inet.h"
RodColeman 0:0791c1fece8e 81 #include "lwip/sys.h"
RodColeman 0:0791c1fece8e 82 #include "lwip/dhcp.h"
RodColeman 0:0791c1fece8e 83 #include "lwip/autoip.h"
RodColeman 0:0791c1fece8e 84 #include "lwip/dns.h"
RodColeman 0:0791c1fece8e 85 #include "netif/etharp.h"
RodColeman 0:0791c1fece8e 86
RodColeman 0:0791c1fece8e 87 #include <string.h>
RodColeman 0:0791c1fece8e 88
RodColeman 0:0791c1fece8e 89 /** Default for DHCP_GLOBAL_XID is 0xABCD0000
RodColeman 0:0791c1fece8e 90 * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g.
RodColeman 0:0791c1fece8e 91 * #define DHCP_GLOBAL_XID_HEADER "stdlib.h"
RodColeman 0:0791c1fece8e 92 * #define DHCP_GLOBAL_XID rand()
RodColeman 0:0791c1fece8e 93 */
RodColeman 0:0791c1fece8e 94 #ifdef DHCP_GLOBAL_XID_HEADER
RodColeman 0:0791c1fece8e 95 #include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */
RodColeman 0:0791c1fece8e 96 #endif
RodColeman 0:0791c1fece8e 97
RodColeman 0:0791c1fece8e 98 /** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU
RodColeman 0:0791c1fece8e 99 * MTU is checked to be big enough in dhcp_start */
RodColeman 0:0791c1fece8e 100 #define DHCP_MAX_MSG_LEN(netif) (netif->mtu)
RodColeman 0:0791c1fece8e 101 #define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576
RodColeman 0:0791c1fece8e 102 /** Minimum length for reply before packet is parsed */
RodColeman 0:0791c1fece8e 103 #define DHCP_MIN_REPLY_LEN 44
RodColeman 0:0791c1fece8e 104
RodColeman 0:0791c1fece8e 105 #define REBOOT_TRIES 2
RodColeman 0:0791c1fece8e 106
RodColeman 0:0791c1fece8e 107 /* DHCP client state machine functions */
RodColeman 0:0791c1fece8e 108 static void dhcp_handle_ack(struct netif *netif);
RodColeman 0:0791c1fece8e 109 static void dhcp_handle_nak(struct netif *netif);
RodColeman 0:0791c1fece8e 110 static void dhcp_handle_offer(struct netif *netif);
RodColeman 0:0791c1fece8e 111
RodColeman 0:0791c1fece8e 112 static err_t dhcp_discover(struct netif *netif);
RodColeman 0:0791c1fece8e 113 static err_t dhcp_select(struct netif *netif);
RodColeman 0:0791c1fece8e 114 static void dhcp_bind(struct netif *netif);
RodColeman 0:0791c1fece8e 115 #if DHCP_DOES_ARP_CHECK
RodColeman 0:0791c1fece8e 116 static void dhcp_check(struct netif *netif);
RodColeman 0:0791c1fece8e 117 static err_t dhcp_decline(struct netif *netif);
RodColeman 0:0791c1fece8e 118 #endif /* DHCP_DOES_ARP_CHECK */
RodColeman 0:0791c1fece8e 119 static err_t dhcp_rebind(struct netif *netif);
RodColeman 0:0791c1fece8e 120 static err_t dhcp_reboot(struct netif *netif);
RodColeman 0:0791c1fece8e 121 static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);
RodColeman 0:0791c1fece8e 122
RodColeman 0:0791c1fece8e 123 /* receive, unfold, parse and free incoming messages */
RodColeman 0:0791c1fece8e 124 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
RodColeman 0:0791c1fece8e 125 static err_t dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p);
RodColeman 0:0791c1fece8e 126 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);
RodColeman 0:0791c1fece8e 127 static u8_t dhcp_get_option_byte(u8_t *ptr);
RodColeman 0:0791c1fece8e 128 #if 0
RodColeman 0:0791c1fece8e 129 static u16_t dhcp_get_option_short(u8_t *ptr);
RodColeman 0:0791c1fece8e 130 #endif
RodColeman 0:0791c1fece8e 131 static u32_t dhcp_get_option_long(u8_t *ptr);
RodColeman 0:0791c1fece8e 132 static void dhcp_free_reply(struct dhcp *dhcp);
RodColeman 0:0791c1fece8e 133
RodColeman 0:0791c1fece8e 134 /* set the DHCP timers */
RodColeman 0:0791c1fece8e 135 static void dhcp_timeout(struct netif *netif);
RodColeman 0:0791c1fece8e 136 static void dhcp_t1_timeout(struct netif *netif);
RodColeman 0:0791c1fece8e 137 static void dhcp_t2_timeout(struct netif *netif);
RodColeman 0:0791c1fece8e 138
RodColeman 0:0791c1fece8e 139 /* build outgoing messages */
RodColeman 0:0791c1fece8e 140 /* create a DHCP request, fill in common headers */
RodColeman 0:0791c1fece8e 141 static err_t dhcp_create_request(struct netif *netif);
RodColeman 0:0791c1fece8e 142 /* free a DHCP request */
RodColeman 0:0791c1fece8e 143 static void dhcp_delete_request(struct netif *netif);
RodColeman 0:0791c1fece8e 144 /* add a DHCP option (type, then length in bytes) */
RodColeman 0:0791c1fece8e 145 static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);
RodColeman 0:0791c1fece8e 146 /* add option values */
RodColeman 0:0791c1fece8e 147 static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);
RodColeman 0:0791c1fece8e 148 static void dhcp_option_short(struct dhcp *dhcp, u16_t value);
RodColeman 0:0791c1fece8e 149 static void dhcp_option_long(struct dhcp *dhcp, u32_t value);
RodColeman 0:0791c1fece8e 150 /* always add the DHCP options trailer to end and pad */
RodColeman 0:0791c1fece8e 151 static void dhcp_option_trailer(struct dhcp *dhcp);
RodColeman 0:0791c1fece8e 152
RodColeman 0:0791c1fece8e 153 /**
RodColeman 0:0791c1fece8e 154 * Back-off the DHCP client (because of a received NAK response).
RodColeman 0:0791c1fece8e 155 *
RodColeman 0:0791c1fece8e 156 * Back-off the DHCP client because of a received NAK. Receiving a
RodColeman 0:0791c1fece8e 157 * NAK means the client asked for something non-sensible, for
RodColeman 0:0791c1fece8e 158 * example when it tries to renew a lease obtained on another network.
RodColeman 0:0791c1fece8e 159 *
RodColeman 0:0791c1fece8e 160 * We clear any existing set IP address and restart DHCP negotiation
RodColeman 0:0791c1fece8e 161 * afresh (as per RFC2131 3.2.3).
RodColeman 0:0791c1fece8e 162 *
RodColeman 0:0791c1fece8e 163 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 164 */
RodColeman 0:0791c1fece8e 165 static void
RodColeman 0:0791c1fece8e 166 dhcp_handle_nak(struct netif *netif)
RodColeman 0:0791c1fece8e 167 {
RodColeman 0:0791c1fece8e 168 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 169 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",
RodColeman 0:0791c1fece8e 170 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
RodColeman 0:0791c1fece8e 171 /* Set the interface down since the address must no longer be used, as per RFC2131 */
RodColeman 0:0791c1fece8e 172 netif_set_down(netif);
RodColeman 0:0791c1fece8e 173 /* remove IP address from interface */
RodColeman 0:0791c1fece8e 174 netif_set_ipaddr(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 175 netif_set_gw(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 176 netif_set_netmask(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 177 /* Change to a defined state */
RodColeman 0:0791c1fece8e 178 dhcp_set_state(dhcp, DHCP_BACKING_OFF);
RodColeman 0:0791c1fece8e 179 /* We can immediately restart discovery */
RodColeman 0:0791c1fece8e 180 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 181 }
RodColeman 0:0791c1fece8e 182
RodColeman 0:0791c1fece8e 183 #if DHCP_DOES_ARP_CHECK
RodColeman 0:0791c1fece8e 184 /**
RodColeman 0:0791c1fece8e 185 * Checks if the offered IP address is already in use.
RodColeman 0:0791c1fece8e 186 *
RodColeman 0:0791c1fece8e 187 * It does so by sending an ARP request for the offered address and
RodColeman 0:0791c1fece8e 188 * entering CHECKING state. If no ARP reply is received within a small
RodColeman 0:0791c1fece8e 189 * interval, the address is assumed to be free for use by us.
RodColeman 0:0791c1fece8e 190 *
RodColeman 0:0791c1fece8e 191 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 192 */
RodColeman 0:0791c1fece8e 193 static void
RodColeman 0:0791c1fece8e 194 dhcp_check(struct netif *netif)
RodColeman 0:0791c1fece8e 195 {
RodColeman 0:0791c1fece8e 196 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 197 err_t result;
RodColeman 0:0791c1fece8e 198 u16_t msecs;
RodColeman 0:0791c1fece8e 199 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],
RodColeman 0:0791c1fece8e 200 (s16_t)netif->name[1]));
RodColeman 0:0791c1fece8e 201 dhcp_set_state(dhcp, DHCP_CHECKING);
RodColeman 0:0791c1fece8e 202 /* create an ARP query for the offered IP address, expecting that no host
RodColeman 0:0791c1fece8e 203 responds, as the IP address should not be in use. */
RodColeman 0:0791c1fece8e 204 result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);
RodColeman 0:0791c1fece8e 205 if (result != ERR_OK) {
RodColeman 0:0791c1fece8e 206 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));
RodColeman 0:0791c1fece8e 207 }
RodColeman 0:0791c1fece8e 208 dhcp->tries++;
RodColeman 0:0791c1fece8e 209 msecs = 500;
RodColeman 0:0791c1fece8e 210 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 211 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 212 }
RodColeman 0:0791c1fece8e 213 #endif /* DHCP_DOES_ARP_CHECK */
RodColeman 0:0791c1fece8e 214
RodColeman 0:0791c1fece8e 215 /**
RodColeman 0:0791c1fece8e 216 * Remember the configuration offered by a DHCP server.
RodColeman 0:0791c1fece8e 217 *
RodColeman 0:0791c1fece8e 218 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 219 */
RodColeman 0:0791c1fece8e 220 static void
RodColeman 0:0791c1fece8e 221 dhcp_handle_offer(struct netif *netif)
RodColeman 0:0791c1fece8e 222 {
RodColeman 0:0791c1fece8e 223 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 224 /* obtain the server address */
RodColeman 0:0791c1fece8e 225 u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);
RodColeman 0:0791c1fece8e 226 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",
RodColeman 0:0791c1fece8e 227 (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));
RodColeman 0:0791c1fece8e 228 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 229 dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
RodColeman 0:0791c1fece8e 230 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));
RodColeman 0:0791c1fece8e 231 /* remember offered address */
RodColeman 0:0791c1fece8e 232 ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);
RodColeman 0:0791c1fece8e 233 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 234
RodColeman 0:0791c1fece8e 235 dhcp_select(netif);
RodColeman 0:0791c1fece8e 236 }
RodColeman 0:0791c1fece8e 237 }
RodColeman 0:0791c1fece8e 238
RodColeman 0:0791c1fece8e 239 /**
RodColeman 0:0791c1fece8e 240 * Select a DHCP server offer out of all offers.
RodColeman 0:0791c1fece8e 241 *
RodColeman 0:0791c1fece8e 242 * Simply select the first offer received.
RodColeman 0:0791c1fece8e 243 *
RodColeman 0:0791c1fece8e 244 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 245 * @return lwIP specific error (see error.h)
RodColeman 0:0791c1fece8e 246 */
RodColeman 0:0791c1fece8e 247 static err_t
RodColeman 0:0791c1fece8e 248 dhcp_select(struct netif *netif)
RodColeman 0:0791c1fece8e 249 {
RodColeman 0:0791c1fece8e 250 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 251 err_t result;
RodColeman 0:0791c1fece8e 252 u16_t msecs;
RodColeman 0:0791c1fece8e 253 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 254 const char *p;
RodColeman 0:0791c1fece8e 255 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 256
RodColeman 0:0791c1fece8e 257 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));
RodColeman 0:0791c1fece8e 258 dhcp_set_state(dhcp, DHCP_REQUESTING);
RodColeman 0:0791c1fece8e 259
RodColeman 0:0791c1fece8e 260 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 261 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 262 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 263 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 264 dhcp_option_byte(dhcp, DHCP_REQUEST);
RodColeman 0:0791c1fece8e 265
RodColeman 0:0791c1fece8e 266 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 267 dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
RodColeman 0:0791c1fece8e 268
RodColeman 0:0791c1fece8e 269 /* MUST request the offered IP address */
RodColeman 0:0791c1fece8e 270 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
RodColeman 0:0791c1fece8e 271 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 272
RodColeman 0:0791c1fece8e 273 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
RodColeman 0:0791c1fece8e 274 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
RodColeman 0:0791c1fece8e 275
RodColeman 0:0791c1fece8e 276 dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
RodColeman 0:0791c1fece8e 277 dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
RodColeman 0:0791c1fece8e 278 dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
RodColeman 0:0791c1fece8e 279 dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
RodColeman 0:0791c1fece8e 280 dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
RodColeman 0:0791c1fece8e 281
RodColeman 0:0791c1fece8e 282 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 283 p = (const char*)netif->hostname;
RodColeman 0:0791c1fece8e 284 if (p != NULL) {
RodColeman 0:0791c1fece8e 285 dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
RodColeman 0:0791c1fece8e 286 while (*p) {
RodColeman 0:0791c1fece8e 287 dhcp_option_byte(dhcp, *p++);
RodColeman 0:0791c1fece8e 288 }
RodColeman 0:0791c1fece8e 289 }
RodColeman 0:0791c1fece8e 290 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 291
RodColeman 0:0791c1fece8e 292 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 293 /* shrink the pbuf to the actual content length */
RodColeman 0:0791c1fece8e 294 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 295
RodColeman 0:0791c1fece8e 296 /* send broadcast to any DHCP server */
RodColeman 0:0791c1fece8e 297 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 298 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 299 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));
RodColeman 0:0791c1fece8e 300 } else {
RodColeman 0:0791c1fece8e 301 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 302 }
RodColeman 0:0791c1fece8e 303 dhcp->tries++;
RodColeman 0:0791c1fece8e 304 msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
RodColeman 0:0791c1fece8e 305 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 306 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 307 return result;
RodColeman 0:0791c1fece8e 308 }
RodColeman 0:0791c1fece8e 309
RodColeman 0:0791c1fece8e 310 /**
RodColeman 0:0791c1fece8e 311 * The DHCP timer that checks for lease renewal/rebind timeouts.
RodColeman 0:0791c1fece8e 312 *
RodColeman 0:0791c1fece8e 313 */
RodColeman 0:0791c1fece8e 314 void
RodColeman 0:0791c1fece8e 315 dhcp_coarse_tmr()
RodColeman 0:0791c1fece8e 316 {
RodColeman 0:0791c1fece8e 317 struct netif *netif = netif_list;
RodColeman 0:0791c1fece8e 318 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));
RodColeman 0:0791c1fece8e 319 /* iterate through all network interfaces */
RodColeman 0:0791c1fece8e 320 while (netif != NULL) {
RodColeman 0:0791c1fece8e 321 /* only act on DHCP configured interfaces */
RodColeman 0:0791c1fece8e 322 if (netif->dhcp != NULL) {
RodColeman 0:0791c1fece8e 323 /* timer is active (non zero), and triggers (zeroes) now? */
RodColeman 0:0791c1fece8e 324 if (netif->dhcp->t2_timeout-- == 1) {
RodColeman 0:0791c1fece8e 325 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));
RodColeman 0:0791c1fece8e 326 /* this clients' rebind timeout triggered */
RodColeman 0:0791c1fece8e 327 dhcp_t2_timeout(netif);
RodColeman 0:0791c1fece8e 328 /* timer is active (non zero), and triggers (zeroes) now */
RodColeman 0:0791c1fece8e 329 } else if (netif->dhcp->t1_timeout-- == 1) {
RodColeman 0:0791c1fece8e 330 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));
RodColeman 0:0791c1fece8e 331 /* this clients' renewal timeout triggered */
RodColeman 0:0791c1fece8e 332 dhcp_t1_timeout(netif);
RodColeman 0:0791c1fece8e 333 }
RodColeman 0:0791c1fece8e 334 }
RodColeman 0:0791c1fece8e 335 /* proceed to next netif */
RodColeman 0:0791c1fece8e 336 netif = netif->next;
RodColeman 0:0791c1fece8e 337 }
RodColeman 0:0791c1fece8e 338 }
RodColeman 0:0791c1fece8e 339
RodColeman 0:0791c1fece8e 340 /**
RodColeman 0:0791c1fece8e 341 * DHCP transaction timeout handling
RodColeman 0:0791c1fece8e 342 *
RodColeman 0:0791c1fece8e 343 * A DHCP server is expected to respond within a short period of time.
RodColeman 0:0791c1fece8e 344 * This timer checks whether an outstanding DHCP request is timed out.
RodColeman 0:0791c1fece8e 345 *
RodColeman 0:0791c1fece8e 346 */
RodColeman 0:0791c1fece8e 347 void
RodColeman 0:0791c1fece8e 348 dhcp_fine_tmr()
RodColeman 0:0791c1fece8e 349 {
RodColeman 0:0791c1fece8e 350 struct netif *netif = netif_list;
RodColeman 0:0791c1fece8e 351 /* loop through netif's */
RodColeman 0:0791c1fece8e 352 while (netif != NULL) {
RodColeman 0:0791c1fece8e 353 /* only act on DHCP configured interfaces */
RodColeman 0:0791c1fece8e 354 if (netif->dhcp != NULL) {
RodColeman 0:0791c1fece8e 355 /* timer is active (non zero), and is about to trigger now */
RodColeman 0:0791c1fece8e 356 if (netif->dhcp->request_timeout > 1) {
RodColeman 0:0791c1fece8e 357 netif->dhcp->request_timeout--;
RodColeman 0:0791c1fece8e 358 }
RodColeman 0:0791c1fece8e 359 else if (netif->dhcp->request_timeout == 1) {
RodColeman 0:0791c1fece8e 360 netif->dhcp->request_timeout--;
RodColeman 0:0791c1fece8e 361 /* { netif->dhcp->request_timeout == 0 } */
RodColeman 0:0791c1fece8e 362 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));
RodColeman 0:0791c1fece8e 363 /* this clients' request timeout triggered */
RodColeman 0:0791c1fece8e 364 dhcp_timeout(netif);
RodColeman 0:0791c1fece8e 365 }
RodColeman 0:0791c1fece8e 366 }
RodColeman 0:0791c1fece8e 367 /* proceed to next network interface */
RodColeman 0:0791c1fece8e 368 netif = netif->next;
RodColeman 0:0791c1fece8e 369 }
RodColeman 0:0791c1fece8e 370 }
RodColeman 0:0791c1fece8e 371
RodColeman 0:0791c1fece8e 372 /**
RodColeman 0:0791c1fece8e 373 * A DHCP negotiation transaction, or ARP request, has timed out.
RodColeman 0:0791c1fece8e 374 *
RodColeman 0:0791c1fece8e 375 * The timer that was started with the DHCP or ARP request has
RodColeman 0:0791c1fece8e 376 * timed out, indicating no response was received in time.
RodColeman 0:0791c1fece8e 377 *
RodColeman 0:0791c1fece8e 378 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 379 */
RodColeman 0:0791c1fece8e 380 static void
RodColeman 0:0791c1fece8e 381 dhcp_timeout(struct netif *netif)
RodColeman 0:0791c1fece8e 382 {
RodColeman 0:0791c1fece8e 383 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 384 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));
RodColeman 0:0791c1fece8e 385 /* back-off period has passed, or server selection timed out */
RodColeman 0:0791c1fece8e 386 if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {
RodColeman 0:0791c1fece8e 387 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));
RodColeman 0:0791c1fece8e 388 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 389 /* receiving the requested lease timed out */
RodColeman 0:0791c1fece8e 390 } else if (dhcp->state == DHCP_REQUESTING) {
RodColeman 0:0791c1fece8e 391 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));
RodColeman 0:0791c1fece8e 392 if (dhcp->tries <= 5) {
RodColeman 0:0791c1fece8e 393 dhcp_select(netif);
RodColeman 0:0791c1fece8e 394 } else {
RodColeman 0:0791c1fece8e 395 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));
RodColeman 0:0791c1fece8e 396 dhcp_release(netif);
RodColeman 0:0791c1fece8e 397 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 398 }
RodColeman 0:0791c1fece8e 399 #if DHCP_DOES_ARP_CHECK
RodColeman 0:0791c1fece8e 400 /* received no ARP reply for the offered address (which is good) */
RodColeman 0:0791c1fece8e 401 } else if (dhcp->state == DHCP_CHECKING) {
RodColeman 0:0791c1fece8e 402 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));
RodColeman 0:0791c1fece8e 403 if (dhcp->tries <= 1) {
RodColeman 0:0791c1fece8e 404 dhcp_check(netif);
RodColeman 0:0791c1fece8e 405 /* no ARP replies on the offered address,
RodColeman 0:0791c1fece8e 406 looks like the IP address is indeed free */
RodColeman 0:0791c1fece8e 407 } else {
RodColeman 0:0791c1fece8e 408 /* bind the interface to the offered address */
RodColeman 0:0791c1fece8e 409 dhcp_bind(netif);
RodColeman 0:0791c1fece8e 410 }
RodColeman 0:0791c1fece8e 411 #endif /* DHCP_DOES_ARP_CHECK */
RodColeman 0:0791c1fece8e 412 }
RodColeman 0:0791c1fece8e 413 /* did not get response to renew request? */
RodColeman 0:0791c1fece8e 414 else if (dhcp->state == DHCP_RENEWING) {
RodColeman 0:0791c1fece8e 415 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));
RodColeman 0:0791c1fece8e 416 /* just retry renewal */
RodColeman 0:0791c1fece8e 417 /* note that the rebind timer will eventually time-out if renew does not work */
RodColeman 0:0791c1fece8e 418 dhcp_renew(netif);
RodColeman 0:0791c1fece8e 419 /* did not get response to rebind request? */
RodColeman 0:0791c1fece8e 420 } else if (dhcp->state == DHCP_REBINDING) {
RodColeman 0:0791c1fece8e 421 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));
RodColeman 0:0791c1fece8e 422 if (dhcp->tries <= 8) {
RodColeman 0:0791c1fece8e 423 dhcp_rebind(netif);
RodColeman 0:0791c1fece8e 424 } else {
RodColeman 0:0791c1fece8e 425 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));
RodColeman 0:0791c1fece8e 426 dhcp_release(netif);
RodColeman 0:0791c1fece8e 427 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 428 }
RodColeman 0:0791c1fece8e 429 } else if (dhcp->state == DHCP_REBOOTING) {
RodColeman 0:0791c1fece8e 430 if (dhcp->tries < REBOOT_TRIES) {
RodColeman 0:0791c1fece8e 431 dhcp_reboot(netif);
RodColeman 0:0791c1fece8e 432 } else {
RodColeman 0:0791c1fece8e 433 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 434 }
RodColeman 0:0791c1fece8e 435 }
RodColeman 0:0791c1fece8e 436 }
RodColeman 0:0791c1fece8e 437
RodColeman 0:0791c1fece8e 438 /**
RodColeman 0:0791c1fece8e 439 * The renewal period has timed out.
RodColeman 0:0791c1fece8e 440 *
RodColeman 0:0791c1fece8e 441 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 442 */
RodColeman 0:0791c1fece8e 443 static void
RodColeman 0:0791c1fece8e 444 dhcp_t1_timeout(struct netif *netif)
RodColeman 0:0791c1fece8e 445 {
RodColeman 0:0791c1fece8e 446 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 447 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));
RodColeman 0:0791c1fece8e 448 if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
RodColeman 0:0791c1fece8e 449 /* just retry to renew - note that the rebind timer (t2) will
RodColeman 0:0791c1fece8e 450 * eventually time-out if renew tries fail. */
RodColeman 0:0791c1fece8e 451 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));
RodColeman 0:0791c1fece8e 452 dhcp_renew(netif);
RodColeman 0:0791c1fece8e 453 }
RodColeman 0:0791c1fece8e 454 }
RodColeman 0:0791c1fece8e 455
RodColeman 0:0791c1fece8e 456 /**
RodColeman 0:0791c1fece8e 457 * The rebind period has timed out.
RodColeman 0:0791c1fece8e 458 *
RodColeman 0:0791c1fece8e 459 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 460 */
RodColeman 0:0791c1fece8e 461 static void
RodColeman 0:0791c1fece8e 462 dhcp_t2_timeout(struct netif *netif)
RodColeman 0:0791c1fece8e 463 {
RodColeman 0:0791c1fece8e 464 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 465 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));
RodColeman 0:0791c1fece8e 466 if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {
RodColeman 0:0791c1fece8e 467 /* just retry to rebind */
RodColeman 0:0791c1fece8e 468 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));
RodColeman 0:0791c1fece8e 469 dhcp_rebind(netif);
RodColeman 0:0791c1fece8e 470 }
RodColeman 0:0791c1fece8e 471 }
RodColeman 0:0791c1fece8e 472
RodColeman 0:0791c1fece8e 473 /**
RodColeman 0:0791c1fece8e 474 * Handle a DHCP ACK packet
RodColeman 0:0791c1fece8e 475 *
RodColeman 0:0791c1fece8e 476 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 477 */
RodColeman 0:0791c1fece8e 478 static void
RodColeman 0:0791c1fece8e 479 dhcp_handle_ack(struct netif *netif)
RodColeman 0:0791c1fece8e 480 {
RodColeman 0:0791c1fece8e 481 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 482 u8_t *option_ptr;
RodColeman 0:0791c1fece8e 483 /* clear options we might not get from the ACK */
RodColeman 0:0791c1fece8e 484 dhcp->offered_sn_mask.addr = 0;
RodColeman 0:0791c1fece8e 485 dhcp->offered_gw_addr.addr = 0;
RodColeman 0:0791c1fece8e 486 dhcp->offered_bc_addr.addr = 0;
RodColeman 0:0791c1fece8e 487
RodColeman 0:0791c1fece8e 488 /* lease time given? */
RodColeman 0:0791c1fece8e 489 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);
RodColeman 0:0791c1fece8e 490 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 491 /* remember offered lease time */
RodColeman 0:0791c1fece8e 492 dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);
RodColeman 0:0791c1fece8e 493 }
RodColeman 0:0791c1fece8e 494 /* renewal period given? */
RodColeman 0:0791c1fece8e 495 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);
RodColeman 0:0791c1fece8e 496 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 497 /* remember given renewal period */
RodColeman 0:0791c1fece8e 498 dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);
RodColeman 0:0791c1fece8e 499 } else {
RodColeman 0:0791c1fece8e 500 /* calculate safe periods for renewal */
RodColeman 0:0791c1fece8e 501 dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;
RodColeman 0:0791c1fece8e 502 }
RodColeman 0:0791c1fece8e 503
RodColeman 0:0791c1fece8e 504 /* renewal period given? */
RodColeman 0:0791c1fece8e 505 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);
RodColeman 0:0791c1fece8e 506 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 507 /* remember given rebind period */
RodColeman 0:0791c1fece8e 508 dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);
RodColeman 0:0791c1fece8e 509 } else {
RodColeman 0:0791c1fece8e 510 /* calculate safe periods for rebinding */
RodColeman 0:0791c1fece8e 511 dhcp->offered_t2_rebind = dhcp->offered_t0_lease;
RodColeman 0:0791c1fece8e 512 }
RodColeman 0:0791c1fece8e 513
RodColeman 0:0791c1fece8e 514 /* (y)our internet address */
RodColeman 0:0791c1fece8e 515 ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);
RodColeman 0:0791c1fece8e 516
RodColeman 0:0791c1fece8e 517 /**
RodColeman 0:0791c1fece8e 518 * Patch #1308
RodColeman 0:0791c1fece8e 519 * TODO: we must check if the file field is not overloaded by DHCP options!
RodColeman 0:0791c1fece8e 520 */
RodColeman 0:0791c1fece8e 521 #if 0
RodColeman 0:0791c1fece8e 522 /* boot server address */
RodColeman 0:0791c1fece8e 523 ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);
RodColeman 0:0791c1fece8e 524 /* boot file name */
RodColeman 0:0791c1fece8e 525 if (dhcp->msg_in->file[0]) {
RodColeman 0:0791c1fece8e 526 dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);
RodColeman 0:0791c1fece8e 527 strcpy(dhcp->boot_file_name, dhcp->msg_in->file);
RodColeman 0:0791c1fece8e 528 }
RodColeman 0:0791c1fece8e 529 #endif
RodColeman 0:0791c1fece8e 530
RodColeman 0:0791c1fece8e 531 /* subnet mask */
RodColeman 0:0791c1fece8e 532 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);
RodColeman 0:0791c1fece8e 533 /* subnet mask given? */
RodColeman 0:0791c1fece8e 534 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 535 dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
RodColeman 0:0791c1fece8e 536 }
RodColeman 0:0791c1fece8e 537
RodColeman 0:0791c1fece8e 538 /* gateway router */
RodColeman 0:0791c1fece8e 539 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);
RodColeman 0:0791c1fece8e 540 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 541 dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
RodColeman 0:0791c1fece8e 542 }
RodColeman 0:0791c1fece8e 543
RodColeman 0:0791c1fece8e 544 /* broadcast address */
RodColeman 0:0791c1fece8e 545 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);
RodColeman 0:0791c1fece8e 546 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 547 dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));
RodColeman 0:0791c1fece8e 548 }
RodColeman 0:0791c1fece8e 549
RodColeman 0:0791c1fece8e 550 /* DNS servers */
RodColeman 0:0791c1fece8e 551 option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);
RodColeman 0:0791c1fece8e 552 if (option_ptr != NULL) {
RodColeman 0:0791c1fece8e 553 u8_t n;
RodColeman 0:0791c1fece8e 554 dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);
RodColeman 0:0791c1fece8e 555 /* limit to at most DHCP_MAX_DNS DNS servers */
RodColeman 0:0791c1fece8e 556 if (dhcp->dns_count > DHCP_MAX_DNS)
RodColeman 0:0791c1fece8e 557 dhcp->dns_count = DHCP_MAX_DNS;
RodColeman 0:0791c1fece8e 558 for (n = 0; n < dhcp->dns_count; n++) {
RodColeman 0:0791c1fece8e 559 dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));
RodColeman 0:0791c1fece8e 560 #if LWIP_DNS
RodColeman 0:0791c1fece8e 561 dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr)));
RodColeman 0:0791c1fece8e 562 #endif /* LWIP_DNS */
RodColeman 0:0791c1fece8e 563 }
RodColeman 0:0791c1fece8e 564 #if LWIP_DNS
RodColeman 0:0791c1fece8e 565 dns_setserver( n, (struct ip_addr *)(&ip_addr_any));
RodColeman 0:0791c1fece8e 566 #endif /* LWIP_DNS */
RodColeman 0:0791c1fece8e 567 }
RodColeman 0:0791c1fece8e 568 }
RodColeman 0:0791c1fece8e 569
RodColeman 0:0791c1fece8e 570 /**
RodColeman 0:0791c1fece8e 571 * Start DHCP negotiation for a network interface.
RodColeman 0:0791c1fece8e 572 *
RodColeman 0:0791c1fece8e 573 * If no DHCP client instance was attached to this interface,
RodColeman 0:0791c1fece8e 574 * a new client is created first. If a DHCP client instance
RodColeman 0:0791c1fece8e 575 * was already present, it restarts negotiation.
RodColeman 0:0791c1fece8e 576 *
RodColeman 0:0791c1fece8e 577 * @param netif The lwIP network interface
RodColeman 0:0791c1fece8e 578 * @return lwIP error code
RodColeman 0:0791c1fece8e 579 * - ERR_OK - No error
RodColeman 0:0791c1fece8e 580 * - ERR_MEM - Out of memory
RodColeman 0:0791c1fece8e 581 */
RodColeman 0:0791c1fece8e 582 err_t
RodColeman 0:0791c1fece8e 583 dhcp_start(struct netif *netif)
RodColeman 0:0791c1fece8e 584 {
RodColeman 0:0791c1fece8e 585 struct dhcp *dhcp;
RodColeman 0:0791c1fece8e 586 err_t result = ERR_OK;
RodColeman 0:0791c1fece8e 587
RodColeman 0:0791c1fece8e 588 LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);
RodColeman 0:0791c1fece8e 589 dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 590 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));
RodColeman 0:0791c1fece8e 591 /* Remove the flag that says this netif is handled by DHCP,
RodColeman 0:0791c1fece8e 592 it is set when we succeeded starting. */
RodColeman 0:0791c1fece8e 593 netif->flags &= ~NETIF_FLAG_DHCP;
RodColeman 0:0791c1fece8e 594
RodColeman 0:0791c1fece8e 595 /* check MTU of the netif */
RodColeman 0:0791c1fece8e 596 if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) {
RodColeman 0:0791c1fece8e 597 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n"));
RodColeman 0:0791c1fece8e 598 return ERR_MEM;
RodColeman 0:0791c1fece8e 599 }
RodColeman 0:0791c1fece8e 600
RodColeman 0:0791c1fece8e 601 /* no DHCP client attached yet? */
RodColeman 0:0791c1fece8e 602 if (dhcp == NULL) {
RodColeman 0:0791c1fece8e 603 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));
RodColeman 0:0791c1fece8e 604 dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
RodColeman 0:0791c1fece8e 605 if (dhcp == NULL) {
RodColeman 0:0791c1fece8e 606 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));
RodColeman 0:0791c1fece8e 607 return ERR_MEM;
RodColeman 0:0791c1fece8e 608 }
RodColeman 0:0791c1fece8e 609 /* store this dhcp client in the netif */
RodColeman 0:0791c1fece8e 610 netif->dhcp = dhcp;
RodColeman 0:0791c1fece8e 611 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));
RodColeman 0:0791c1fece8e 612 /* already has DHCP client attached */
RodColeman 0:0791c1fece8e 613 } else {
RodColeman 0:0791c1fece8e 614 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));
RodColeman 0:0791c1fece8e 615 if (dhcp->pcb != NULL) {
RodColeman 0:0791c1fece8e 616 udp_remove(dhcp->pcb);
RodColeman 0:0791c1fece8e 617 }
RodColeman 0:0791c1fece8e 618 LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL);
RodColeman 0:0791c1fece8e 619 LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
RodColeman 0:0791c1fece8e 620 dhcp->options_in == NULL && dhcp->options_in_len == 0);
RodColeman 0:0791c1fece8e 621 }
RodColeman 0:0791c1fece8e 622
RodColeman 0:0791c1fece8e 623 /* clear data structure */
RodColeman 0:0791c1fece8e 624 memset(dhcp, 0, sizeof(struct dhcp));
RodColeman 0:0791c1fece8e 625 /* allocate UDP PCB */
RodColeman 0:0791c1fece8e 626 dhcp->pcb = udp_new();
RodColeman 0:0791c1fece8e 627 if (dhcp->pcb == NULL) {
RodColeman 0:0791c1fece8e 628 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));
RodColeman 0:0791c1fece8e 629 mem_free((void *)dhcp);
RodColeman 0:0791c1fece8e 630 netif->dhcp = dhcp = NULL;
RodColeman 0:0791c1fece8e 631 return ERR_MEM;
RodColeman 0:0791c1fece8e 632 }
RodColeman 0:0791c1fece8e 633 #if IP_SOF_BROADCAST
RodColeman 0:0791c1fece8e 634 dhcp->pcb->so_options|=SOF_BROADCAST;
RodColeman 0:0791c1fece8e 635 #endif /* IP_SOF_BROADCAST */
RodColeman 0:0791c1fece8e 636 /* set up local and remote port for the pcb */
RodColeman 0:0791c1fece8e 637 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
RodColeman 0:0791c1fece8e 638 udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
RodColeman 0:0791c1fece8e 639 /* set up the recv callback and argument */
RodColeman 0:0791c1fece8e 640 udp_recv(dhcp->pcb, dhcp_recv, netif);
RodColeman 0:0791c1fece8e 641 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));
RodColeman 0:0791c1fece8e 642 /* (re)start the DHCP negotiation */
RodColeman 0:0791c1fece8e 643 result = dhcp_discover(netif);
RodColeman 0:0791c1fece8e 644 if (result != ERR_OK) {
RodColeman 0:0791c1fece8e 645 /* free resources allocated above */
RodColeman 0:0791c1fece8e 646 dhcp_stop(netif);
RodColeman 0:0791c1fece8e 647 return ERR_MEM;
RodColeman 0:0791c1fece8e 648 }
RodColeman 0:0791c1fece8e 649 /* Set the flag that says this netif is handled by DHCP. */
RodColeman 0:0791c1fece8e 650 netif->flags |= NETIF_FLAG_DHCP;
RodColeman 0:0791c1fece8e 651 return result;
RodColeman 0:0791c1fece8e 652 }
RodColeman 0:0791c1fece8e 653
RodColeman 0:0791c1fece8e 654 /**
RodColeman 0:0791c1fece8e 655 * Inform a DHCP server of our manual configuration.
RodColeman 0:0791c1fece8e 656 *
RodColeman 0:0791c1fece8e 657 * This informs DHCP servers of our fixed IP address configuration
RodColeman 0:0791c1fece8e 658 * by sending an INFORM message. It does not involve DHCP address
RodColeman 0:0791c1fece8e 659 * configuration, it is just here to be nice to the network.
RodColeman 0:0791c1fece8e 660 *
RodColeman 0:0791c1fece8e 661 * @param netif The lwIP network interface
RodColeman 0:0791c1fece8e 662 */
RodColeman 0:0791c1fece8e 663 void
RodColeman 0:0791c1fece8e 664 dhcp_inform(struct netif *netif)
RodColeman 0:0791c1fece8e 665 {
RodColeman 0:0791c1fece8e 666 struct dhcp *dhcp, *old_dhcp;
RodColeman 0:0791c1fece8e 667 err_t result = ERR_OK;
RodColeman 0:0791c1fece8e 668 dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp));
RodColeman 0:0791c1fece8e 669 if (dhcp == NULL) {
RodColeman 0:0791c1fece8e 670 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));
RodColeman 0:0791c1fece8e 671 return;
RodColeman 0:0791c1fece8e 672 }
RodColeman 0:0791c1fece8e 673 memset(dhcp, 0, sizeof(struct dhcp));
RodColeman 0:0791c1fece8e 674
RodColeman 0:0791c1fece8e 675 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));
RodColeman 0:0791c1fece8e 676 dhcp->pcb = udp_new();
RodColeman 0:0791c1fece8e 677 if (dhcp->pcb == NULL) {
RodColeman 0:0791c1fece8e 678 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));
RodColeman 0:0791c1fece8e 679 goto free_dhcp_and_return;
RodColeman 0:0791c1fece8e 680 }
RodColeman 0:0791c1fece8e 681 old_dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 682 netif->dhcp = dhcp;
RodColeman 0:0791c1fece8e 683 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));
RodColeman 0:0791c1fece8e 684 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 685 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 686 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 687
RodColeman 0:0791c1fece8e 688 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 689 dhcp_option_byte(dhcp, DHCP_INFORM);
RodColeman 0:0791c1fece8e 690
RodColeman 0:0791c1fece8e 691 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 692 dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
RodColeman 0:0791c1fece8e 693
RodColeman 0:0791c1fece8e 694 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 695
RodColeman 0:0791c1fece8e 696 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 697
RodColeman 0:0791c1fece8e 698 #if IP_SOF_BROADCAST
RodColeman 0:0791c1fece8e 699 dhcp->pcb->so_options|=SOF_BROADCAST;
RodColeman 0:0791c1fece8e 700 #endif /* IP_SOF_BROADCAST */
RodColeman 0:0791c1fece8e 701 udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
RodColeman 0:0791c1fece8e 702 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));
RodColeman 0:0791c1fece8e 703 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 704 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 705 } else {
RodColeman 0:0791c1fece8e 706 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 707 }
RodColeman 0:0791c1fece8e 708
RodColeman 0:0791c1fece8e 709 udp_remove(dhcp->pcb);
RodColeman 0:0791c1fece8e 710 dhcp->pcb = NULL;
RodColeman 0:0791c1fece8e 711 netif->dhcp = old_dhcp;
RodColeman 0:0791c1fece8e 712 free_dhcp_and_return:
RodColeman 0:0791c1fece8e 713 mem_free((void *)dhcp);
RodColeman 0:0791c1fece8e 714 }
RodColeman 0:0791c1fece8e 715
RodColeman 0:0791c1fece8e 716 /** Handle a possible change in the network configuration.
RodColeman 0:0791c1fece8e 717 *
RodColeman 0:0791c1fece8e 718 * This enters the REBOOTING state to verify that the currently bound
RodColeman 0:0791c1fece8e 719 * address is still valid.
RodColeman 0:0791c1fece8e 720 */
RodColeman 0:0791c1fece8e 721 void
RodColeman 0:0791c1fece8e 722 dhcp_network_changed(struct netif *netif)
RodColeman 0:0791c1fece8e 723 {
RodColeman 0:0791c1fece8e 724 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 725 if (!dhcp)
RodColeman 0:0791c1fece8e 726 return;
RodColeman 0:0791c1fece8e 727 switch (dhcp->state) {
RodColeman 0:0791c1fece8e 728 case DHCP_REBINDING:
RodColeman 0:0791c1fece8e 729 case DHCP_RENEWING:
RodColeman 0:0791c1fece8e 730 case DHCP_BOUND:
RodColeman 0:0791c1fece8e 731 case DHCP_REBOOTING:
RodColeman 0:0791c1fece8e 732 netif_set_down(netif);
RodColeman 0:0791c1fece8e 733 dhcp->tries = 0;
RodColeman 0:0791c1fece8e 734 dhcp_reboot(netif);
RodColeman 0:0791c1fece8e 735 break;
RodColeman 0:0791c1fece8e 736 case DHCP_OFF:
RodColeman 0:0791c1fece8e 737 /* stay off */
RodColeman 0:0791c1fece8e 738 break;
RodColeman 0:0791c1fece8e 739 default:
RodColeman 0:0791c1fece8e 740 dhcp->tries = 0;
RodColeman 0:0791c1fece8e 741 dhcp_discover(netif);
RodColeman 0:0791c1fece8e 742 break;
RodColeman 0:0791c1fece8e 743 }
RodColeman 0:0791c1fece8e 744 }
RodColeman 0:0791c1fece8e 745
RodColeman 0:0791c1fece8e 746 #if DHCP_DOES_ARP_CHECK
RodColeman 0:0791c1fece8e 747 /**
RodColeman 0:0791c1fece8e 748 * Match an ARP reply with the offered IP address.
RodColeman 0:0791c1fece8e 749 *
RodColeman 0:0791c1fece8e 750 * @param netif the network interface on which the reply was received
RodColeman 0:0791c1fece8e 751 * @param addr The IP address we received a reply from
RodColeman 0:0791c1fece8e 752 */
RodColeman 0:0791c1fece8e 753 void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)
RodColeman 0:0791c1fece8e 754 {
RodColeman 0:0791c1fece8e 755 LWIP_ERROR("netif != NULL", (netif != NULL), return;);
RodColeman 0:0791c1fece8e 756 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));
RodColeman 0:0791c1fece8e 757 /* is a DHCP client doing an ARP check? */
RodColeman 0:0791c1fece8e 758 if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {
RodColeman 0:0791c1fece8e 759 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));
RodColeman 0:0791c1fece8e 760 /* did a host respond with the address we
RodColeman 0:0791c1fece8e 761 were offered by the DHCP server? */
RodColeman 0:0791c1fece8e 762 if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {
RodColeman 0:0791c1fece8e 763 /* we will not accept the offered address */
RodColeman 0:0791c1fece8e 764 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));
RodColeman 0:0791c1fece8e 765 dhcp_decline(netif);
RodColeman 0:0791c1fece8e 766 }
RodColeman 0:0791c1fece8e 767 }
RodColeman 0:0791c1fece8e 768 }
RodColeman 0:0791c1fece8e 769
RodColeman 0:0791c1fece8e 770 /**
RodColeman 0:0791c1fece8e 771 * Decline an offered lease.
RodColeman 0:0791c1fece8e 772 *
RodColeman 0:0791c1fece8e 773 * Tell the DHCP server we do not accept the offered address.
RodColeman 0:0791c1fece8e 774 * One reason to decline the lease is when we find out the address
RodColeman 0:0791c1fece8e 775 * is already in use by another host (through ARP).
RodColeman 0:0791c1fece8e 776 *
RodColeman 0:0791c1fece8e 777 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 778 */
RodColeman 0:0791c1fece8e 779 static err_t
RodColeman 0:0791c1fece8e 780 dhcp_decline(struct netif *netif)
RodColeman 0:0791c1fece8e 781 {
RodColeman 0:0791c1fece8e 782 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 783 err_t result = ERR_OK;
RodColeman 0:0791c1fece8e 784 u16_t msecs;
RodColeman 0:0791c1fece8e 785 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));
RodColeman 0:0791c1fece8e 786 dhcp_set_state(dhcp, DHCP_BACKING_OFF);
RodColeman 0:0791c1fece8e 787 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 788 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 789 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 790 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 791 dhcp_option_byte(dhcp, DHCP_DECLINE);
RodColeman 0:0791c1fece8e 792
RodColeman 0:0791c1fece8e 793 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
RodColeman 0:0791c1fece8e 794 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 795
RodColeman 0:0791c1fece8e 796 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 797 /* resize pbuf to reflect true size of options */
RodColeman 0:0791c1fece8e 798 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 799
RodColeman 0:0791c1fece8e 800 /* per section 4.4.4, broadcast DECLINE messages */
RodColeman 0:0791c1fece8e 801 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 802 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 803 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));
RodColeman 0:0791c1fece8e 804 } else {
RodColeman 0:0791c1fece8e 805 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 806 }
RodColeman 0:0791c1fece8e 807 dhcp->tries++;
RodColeman 0:0791c1fece8e 808 msecs = 10*1000;
RodColeman 0:0791c1fece8e 809 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 810 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 811 return result;
RodColeman 0:0791c1fece8e 812 }
RodColeman 0:0791c1fece8e 813 #endif
RodColeman 0:0791c1fece8e 814
RodColeman 0:0791c1fece8e 815
RodColeman 0:0791c1fece8e 816 /**
RodColeman 0:0791c1fece8e 817 * Start the DHCP process, discover a DHCP server.
RodColeman 0:0791c1fece8e 818 *
RodColeman 0:0791c1fece8e 819 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 820 */
RodColeman 0:0791c1fece8e 821 static err_t
RodColeman 0:0791c1fece8e 822 dhcp_discover(struct netif *netif)
RodColeman 0:0791c1fece8e 823 {
RodColeman 0:0791c1fece8e 824 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 825 err_t result = ERR_OK;
RodColeman 0:0791c1fece8e 826 u16_t msecs;
RodColeman 0:0791c1fece8e 827 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));
RodColeman 0:0791c1fece8e 828 ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 829 dhcp_set_state(dhcp, DHCP_SELECTING);
RodColeman 0:0791c1fece8e 830 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 831 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 832 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 833 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));
RodColeman 0:0791c1fece8e 834 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 835 dhcp_option_byte(dhcp, DHCP_DISCOVER);
RodColeman 0:0791c1fece8e 836
RodColeman 0:0791c1fece8e 837 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 838 dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
RodColeman 0:0791c1fece8e 839
RodColeman 0:0791c1fece8e 840 dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);
RodColeman 0:0791c1fece8e 841 dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);
RodColeman 0:0791c1fece8e 842 dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);
RodColeman 0:0791c1fece8e 843 dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);
RodColeman 0:0791c1fece8e 844 dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);
RodColeman 0:0791c1fece8e 845
RodColeman 0:0791c1fece8e 846 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 847
RodColeman 0:0791c1fece8e 848 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));
RodColeman 0:0791c1fece8e 849 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 850
RodColeman 0:0791c1fece8e 851 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));
RodColeman 0:0791c1fece8e 852 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 853 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));
RodColeman 0:0791c1fece8e 854 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 855 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));
RodColeman 0:0791c1fece8e 856 } else {
RodColeman 0:0791c1fece8e 857 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 858 }
RodColeman 0:0791c1fece8e 859 dhcp->tries++;
RodColeman 0:0791c1fece8e 860 #if LWIP_DHCP_AUTOIP_COOP
RodColeman 0:0791c1fece8e 861 if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {
RodColeman 0:0791c1fece8e 862 dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;
RodColeman 0:0791c1fece8e 863 autoip_start(netif);
RodColeman 0:0791c1fece8e 864 }
RodColeman 0:0791c1fece8e 865 #endif /* LWIP_DHCP_AUTOIP_COOP */
RodColeman 0:0791c1fece8e 866 msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000;
RodColeman 0:0791c1fece8e 867 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 868 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 869 return result;
RodColeman 0:0791c1fece8e 870 }
RodColeman 0:0791c1fece8e 871
RodColeman 0:0791c1fece8e 872
RodColeman 0:0791c1fece8e 873 /**
RodColeman 0:0791c1fece8e 874 * Bind the interface to the offered IP address.
RodColeman 0:0791c1fece8e 875 *
RodColeman 0:0791c1fece8e 876 * @param netif network interface to bind to the offered address
RodColeman 0:0791c1fece8e 877 */
RodColeman 0:0791c1fece8e 878 static void
RodColeman 0:0791c1fece8e 879 dhcp_bind(struct netif *netif)
RodColeman 0:0791c1fece8e 880 {
RodColeman 0:0791c1fece8e 881 u32_t timeout;
RodColeman 0:0791c1fece8e 882 struct dhcp *dhcp;
RodColeman 0:0791c1fece8e 883 struct ip_addr sn_mask, gw_addr;
RodColeman 0:0791c1fece8e 884 LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);
RodColeman 0:0791c1fece8e 885 dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 886 LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);
RodColeman 0:0791c1fece8e 887 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));
RodColeman 0:0791c1fece8e 888
RodColeman 0:0791c1fece8e 889 /* temporary DHCP lease? */
RodColeman 0:0791c1fece8e 890 if (dhcp->offered_t1_renew != 0xffffffffUL) {
RodColeman 0:0791c1fece8e 891 /* set renewal period timer */
RodColeman 0:0791c1fece8e 892 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));
RodColeman 0:0791c1fece8e 893 timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
RodColeman 0:0791c1fece8e 894 if(timeout > 0xffff) {
RodColeman 0:0791c1fece8e 895 timeout = 0xffff;
RodColeman 0:0791c1fece8e 896 }
RodColeman 0:0791c1fece8e 897 dhcp->t1_timeout = (u16_t)timeout;
RodColeman 0:0791c1fece8e 898 if (dhcp->t1_timeout == 0) {
RodColeman 0:0791c1fece8e 899 dhcp->t1_timeout = 1;
RodColeman 0:0791c1fece8e 900 }
RodColeman 0:0791c1fece8e 901 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));
RodColeman 0:0791c1fece8e 902 }
RodColeman 0:0791c1fece8e 903 /* set renewal period timer */
RodColeman 0:0791c1fece8e 904 if (dhcp->offered_t2_rebind != 0xffffffffUL) {
RodColeman 0:0791c1fece8e 905 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));
RodColeman 0:0791c1fece8e 906 timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;
RodColeman 0:0791c1fece8e 907 if(timeout > 0xffff) {
RodColeman 0:0791c1fece8e 908 timeout = 0xffff;
RodColeman 0:0791c1fece8e 909 }
RodColeman 0:0791c1fece8e 910 dhcp->t2_timeout = (u16_t)timeout;
RodColeman 0:0791c1fece8e 911 if (dhcp->t2_timeout == 0) {
RodColeman 0:0791c1fece8e 912 dhcp->t2_timeout = 1;
RodColeman 0:0791c1fece8e 913 }
RodColeman 0:0791c1fece8e 914 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));
RodColeman 0:0791c1fece8e 915 }
RodColeman 0:0791c1fece8e 916 /* copy offered network mask */
RodColeman 0:0791c1fece8e 917 ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);
RodColeman 0:0791c1fece8e 918
RodColeman 0:0791c1fece8e 919 /* subnet mask not given? */
RodColeman 0:0791c1fece8e 920 /* TODO: this is not a valid check. what if the network mask is 0? */
RodColeman 0:0791c1fece8e 921 if (sn_mask.addr == 0) {
RodColeman 0:0791c1fece8e 922 /* choose a safe subnet mask given the network class */
RodColeman 0:0791c1fece8e 923 u8_t first_octet = ip4_addr1(&sn_mask);
RodColeman 0:0791c1fece8e 924 if (first_octet <= 127) {
RodColeman 0:0791c1fece8e 925 sn_mask.addr = htonl(0xff000000);
RodColeman 0:0791c1fece8e 926 } else if (first_octet >= 192) {
RodColeman 0:0791c1fece8e 927 sn_mask.addr = htonl(0xffffff00);
RodColeman 0:0791c1fece8e 928 } else {
RodColeman 0:0791c1fece8e 929 sn_mask.addr = htonl(0xffff0000);
RodColeman 0:0791c1fece8e 930 }
RodColeman 0:0791c1fece8e 931 }
RodColeman 0:0791c1fece8e 932
RodColeman 0:0791c1fece8e 933 ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);
RodColeman 0:0791c1fece8e 934 /* gateway address not given? */
RodColeman 0:0791c1fece8e 935 if (gw_addr.addr == 0) {
RodColeman 0:0791c1fece8e 936 /* copy network address */
RodColeman 0:0791c1fece8e 937 gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);
RodColeman 0:0791c1fece8e 938 /* use first host address on network as gateway */
RodColeman 0:0791c1fece8e 939 gw_addr.addr |= htonl(0x00000001);
RodColeman 0:0791c1fece8e 940 }
RodColeman 0:0791c1fece8e 941
RodColeman 0:0791c1fece8e 942 #if LWIP_DHCP_AUTOIP_COOP
RodColeman 0:0791c1fece8e 943 if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
RodColeman 0:0791c1fece8e 944 autoip_stop(netif);
RodColeman 0:0791c1fece8e 945 dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
RodColeman 0:0791c1fece8e 946 }
RodColeman 0:0791c1fece8e 947 #endif /* LWIP_DHCP_AUTOIP_COOP */
RodColeman 0:0791c1fece8e 948
RodColeman 0:0791c1fece8e 949 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 950 netif_set_ipaddr(netif, &dhcp->offered_ip_addr);
RodColeman 0:0791c1fece8e 951 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));
RodColeman 0:0791c1fece8e 952 netif_set_netmask(netif, &sn_mask);
RodColeman 0:0791c1fece8e 953 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));
RodColeman 0:0791c1fece8e 954 netif_set_gw(netif, &gw_addr);
RodColeman 0:0791c1fece8e 955 /* bring the interface up */
RodColeman 0:0791c1fece8e 956 netif_set_up(netif);
RodColeman 0:0791c1fece8e 957 /* netif is now bound to DHCP leased address */
RodColeman 0:0791c1fece8e 958 dhcp_set_state(dhcp, DHCP_BOUND);
RodColeman 0:0791c1fece8e 959 }
RodColeman 0:0791c1fece8e 960
RodColeman 0:0791c1fece8e 961 /**
RodColeman 0:0791c1fece8e 962 * Renew an existing DHCP lease at the involved DHCP server.
RodColeman 0:0791c1fece8e 963 *
RodColeman 0:0791c1fece8e 964 * @param netif network interface which must renew its lease
RodColeman 0:0791c1fece8e 965 */
RodColeman 0:0791c1fece8e 966 err_t
RodColeman 0:0791c1fece8e 967 dhcp_renew(struct netif *netif)
RodColeman 0:0791c1fece8e 968 {
RodColeman 0:0791c1fece8e 969 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 970 err_t result;
RodColeman 0:0791c1fece8e 971 u16_t msecs;
RodColeman 0:0791c1fece8e 972 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 973 const char *p;
RodColeman 0:0791c1fece8e 974 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 975 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));
RodColeman 0:0791c1fece8e 976 dhcp_set_state(dhcp, DHCP_RENEWING);
RodColeman 0:0791c1fece8e 977
RodColeman 0:0791c1fece8e 978 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 979 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 980 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 981
RodColeman 0:0791c1fece8e 982 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 983 dhcp_option_byte(dhcp, DHCP_REQUEST);
RodColeman 0:0791c1fece8e 984
RodColeman 0:0791c1fece8e 985 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 986 dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
RodColeman 0:0791c1fece8e 987
RodColeman 0:0791c1fece8e 988 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 989 p = (const char*)netif->hostname;
RodColeman 0:0791c1fece8e 990 if (p != NULL) {
RodColeman 0:0791c1fece8e 991 dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
RodColeman 0:0791c1fece8e 992 while (*p) {
RodColeman 0:0791c1fece8e 993 dhcp_option_byte(dhcp, *p++);
RodColeman 0:0791c1fece8e 994 }
RodColeman 0:0791c1fece8e 995 }
RodColeman 0:0791c1fece8e 996 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 997
RodColeman 0:0791c1fece8e 998 #if 0
RodColeman 0:0791c1fece8e 999 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
RodColeman 0:0791c1fece8e 1000 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 1001 #endif
RodColeman 0:0791c1fece8e 1002
RodColeman 0:0791c1fece8e 1003 #if 0
RodColeman 0:0791c1fece8e 1004 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
RodColeman 0:0791c1fece8e 1005 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
RodColeman 0:0791c1fece8e 1006 #endif
RodColeman 0:0791c1fece8e 1007 /* append DHCP message trailer */
RodColeman 0:0791c1fece8e 1008 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 1009
RodColeman 0:0791c1fece8e 1010 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 1011
RodColeman 0:0791c1fece8e 1012 udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 1013 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 1014
RodColeman 0:0791c1fece8e 1015 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));
RodColeman 0:0791c1fece8e 1016 } else {
RodColeman 0:0791c1fece8e 1017 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 1018 }
RodColeman 0:0791c1fece8e 1019 dhcp->tries++;
RodColeman 0:0791c1fece8e 1020 /* back-off on retries, but to a maximum of 20 seconds */
RodColeman 0:0791c1fece8e 1021 msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;
RodColeman 0:0791c1fece8e 1022 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 1023 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 1024 return result;
RodColeman 0:0791c1fece8e 1025 }
RodColeman 0:0791c1fece8e 1026
RodColeman 0:0791c1fece8e 1027 /**
RodColeman 0:0791c1fece8e 1028 * Rebind with a DHCP server for an existing DHCP lease.
RodColeman 0:0791c1fece8e 1029 *
RodColeman 0:0791c1fece8e 1030 * @param netif network interface which must rebind with a DHCP server
RodColeman 0:0791c1fece8e 1031 */
RodColeman 0:0791c1fece8e 1032 static err_t
RodColeman 0:0791c1fece8e 1033 dhcp_rebind(struct netif *netif)
RodColeman 0:0791c1fece8e 1034 {
RodColeman 0:0791c1fece8e 1035 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1036 err_t result;
RodColeman 0:0791c1fece8e 1037 u16_t msecs;
RodColeman 0:0791c1fece8e 1038 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 1039 const char *p;
RodColeman 0:0791c1fece8e 1040 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 1041 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));
RodColeman 0:0791c1fece8e 1042 dhcp_set_state(dhcp, DHCP_REBINDING);
RodColeman 0:0791c1fece8e 1043
RodColeman 0:0791c1fece8e 1044 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 1045 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 1046 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 1047
RodColeman 0:0791c1fece8e 1048 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 1049 dhcp_option_byte(dhcp, DHCP_REQUEST);
RodColeman 0:0791c1fece8e 1050
RodColeman 0:0791c1fece8e 1051 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 1052 dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif));
RodColeman 0:0791c1fece8e 1053
RodColeman 0:0791c1fece8e 1054 #if LWIP_NETIF_HOSTNAME
RodColeman 0:0791c1fece8e 1055 p = (const char*)netif->hostname;
RodColeman 0:0791c1fece8e 1056 if (p != NULL) {
RodColeman 0:0791c1fece8e 1057 dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));
RodColeman 0:0791c1fece8e 1058 while (*p) {
RodColeman 0:0791c1fece8e 1059 dhcp_option_byte(dhcp, *p++);
RodColeman 0:0791c1fece8e 1060 }
RodColeman 0:0791c1fece8e 1061 }
RodColeman 0:0791c1fece8e 1062 #endif /* LWIP_NETIF_HOSTNAME */
RodColeman 0:0791c1fece8e 1063
RodColeman 0:0791c1fece8e 1064 #if 0
RodColeman 0:0791c1fece8e 1065 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
RodColeman 0:0791c1fece8e 1066 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 1067
RodColeman 0:0791c1fece8e 1068 dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);
RodColeman 0:0791c1fece8e 1069 dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));
RodColeman 0:0791c1fece8e 1070 #endif
RodColeman 0:0791c1fece8e 1071
RodColeman 0:0791c1fece8e 1072 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 1073
RodColeman 0:0791c1fece8e 1074 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 1075
RodColeman 0:0791c1fece8e 1076 /* broadcast to server */
RodColeman 0:0791c1fece8e 1077 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 1078 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 1079 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));
RodColeman 0:0791c1fece8e 1080 } else {
RodColeman 0:0791c1fece8e 1081 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 1082 }
RodColeman 0:0791c1fece8e 1083 dhcp->tries++;
RodColeman 0:0791c1fece8e 1084 msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
RodColeman 0:0791c1fece8e 1085 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 1086 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 1087 return result;
RodColeman 0:0791c1fece8e 1088 }
RodColeman 0:0791c1fece8e 1089
RodColeman 0:0791c1fece8e 1090 /**
RodColeman 0:0791c1fece8e 1091 * Enter REBOOTING state to verify an existing lease
RodColeman 0:0791c1fece8e 1092 *
RodColeman 0:0791c1fece8e 1093 * @param netif network interface which must reboot
RodColeman 0:0791c1fece8e 1094 */
RodColeman 0:0791c1fece8e 1095 static err_t
RodColeman 0:0791c1fece8e 1096 dhcp_reboot(struct netif *netif)
RodColeman 0:0791c1fece8e 1097 {
RodColeman 0:0791c1fece8e 1098 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1099 err_t result;
RodColeman 0:0791c1fece8e 1100 u16_t msecs;
RodColeman 0:0791c1fece8e 1101 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n"));
RodColeman 0:0791c1fece8e 1102 dhcp_set_state(dhcp, DHCP_REBOOTING);
RodColeman 0:0791c1fece8e 1103
RodColeman 0:0791c1fece8e 1104 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 1105 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 1106 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 1107
RodColeman 0:0791c1fece8e 1108 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 1109 dhcp_option_byte(dhcp, DHCP_REQUEST);
RodColeman 0:0791c1fece8e 1110
RodColeman 0:0791c1fece8e 1111 dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);
RodColeman 0:0791c1fece8e 1112 dhcp_option_short(dhcp, 576);
RodColeman 0:0791c1fece8e 1113
RodColeman 0:0791c1fece8e 1114 dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);
RodColeman 0:0791c1fece8e 1115 dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));
RodColeman 0:0791c1fece8e 1116
RodColeman 0:0791c1fece8e 1117 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 1118
RodColeman 0:0791c1fece8e 1119 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 1120
RodColeman 0:0791c1fece8e 1121 /* broadcast to server */
RodColeman 0:0791c1fece8e 1122 udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 1123 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 1124 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n"));
RodColeman 0:0791c1fece8e 1125 } else {
RodColeman 0:0791c1fece8e 1126 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_reboot: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 1127 }
RodColeman 0:0791c1fece8e 1128 dhcp->tries++;
RodColeman 0:0791c1fece8e 1129 msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
RodColeman 0:0791c1fece8e 1130 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 1131 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 1132 return result;
RodColeman 0:0791c1fece8e 1133 }
RodColeman 0:0791c1fece8e 1134
RodColeman 0:0791c1fece8e 1135
RodColeman 0:0791c1fece8e 1136 /**
RodColeman 0:0791c1fece8e 1137 * Release a DHCP lease.
RodColeman 0:0791c1fece8e 1138 *
RodColeman 0:0791c1fece8e 1139 * @param netif network interface which must release its lease
RodColeman 0:0791c1fece8e 1140 */
RodColeman 0:0791c1fece8e 1141 err_t
RodColeman 0:0791c1fece8e 1142 dhcp_release(struct netif *netif)
RodColeman 0:0791c1fece8e 1143 {
RodColeman 0:0791c1fece8e 1144 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1145 err_t result;
RodColeman 0:0791c1fece8e 1146 u16_t msecs;
RodColeman 0:0791c1fece8e 1147 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));
RodColeman 0:0791c1fece8e 1148
RodColeman 0:0791c1fece8e 1149 /* idle DHCP client */
RodColeman 0:0791c1fece8e 1150 dhcp_set_state(dhcp, DHCP_OFF);
RodColeman 0:0791c1fece8e 1151 /* clean old DHCP offer */
RodColeman 0:0791c1fece8e 1152 dhcp->server_ip_addr.addr = 0;
RodColeman 0:0791c1fece8e 1153 dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;
RodColeman 0:0791c1fece8e 1154 dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;
RodColeman 0:0791c1fece8e 1155 dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;
RodColeman 0:0791c1fece8e 1156 dhcp->dns_count = 0;
RodColeman 0:0791c1fece8e 1157
RodColeman 0:0791c1fece8e 1158 /* create and initialize the DHCP message header */
RodColeman 0:0791c1fece8e 1159 result = dhcp_create_request(netif);
RodColeman 0:0791c1fece8e 1160 if (result == ERR_OK) {
RodColeman 0:0791c1fece8e 1161 dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);
RodColeman 0:0791c1fece8e 1162 dhcp_option_byte(dhcp, DHCP_RELEASE);
RodColeman 0:0791c1fece8e 1163
RodColeman 0:0791c1fece8e 1164 dhcp_option_trailer(dhcp);
RodColeman 0:0791c1fece8e 1165
RodColeman 0:0791c1fece8e 1166 pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);
RodColeman 0:0791c1fece8e 1167
RodColeman 0:0791c1fece8e 1168 udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);
RodColeman 0:0791c1fece8e 1169 dhcp_delete_request(netif);
RodColeman 0:0791c1fece8e 1170 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));
RodColeman 0:0791c1fece8e 1171 } else {
RodColeman 0:0791c1fece8e 1172 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));
RodColeman 0:0791c1fece8e 1173 }
RodColeman 0:0791c1fece8e 1174 dhcp->tries++;
RodColeman 0:0791c1fece8e 1175 msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;
RodColeman 0:0791c1fece8e 1176 dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;
RodColeman 0:0791c1fece8e 1177 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));
RodColeman 0:0791c1fece8e 1178 /* bring the interface down */
RodColeman 0:0791c1fece8e 1179 netif_set_down(netif);
RodColeman 0:0791c1fece8e 1180 /* remove IP address from interface */
RodColeman 0:0791c1fece8e 1181 netif_set_ipaddr(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 1182 netif_set_gw(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 1183 netif_set_netmask(netif, IP_ADDR_ANY);
RodColeman 0:0791c1fece8e 1184
RodColeman 0:0791c1fece8e 1185 /* TODO: netif_down(netif); */
RodColeman 0:0791c1fece8e 1186 return result;
RodColeman 0:0791c1fece8e 1187 }
RodColeman 0:0791c1fece8e 1188
RodColeman 0:0791c1fece8e 1189 /**
RodColeman 0:0791c1fece8e 1190 * Remove the DHCP client from the interface.
RodColeman 0:0791c1fece8e 1191 *
RodColeman 0:0791c1fece8e 1192 * @param netif The network interface to stop DHCP on
RodColeman 0:0791c1fece8e 1193 */
RodColeman 0:0791c1fece8e 1194 void
RodColeman 0:0791c1fece8e 1195 dhcp_stop(struct netif *netif)
RodColeman 0:0791c1fece8e 1196 {
RodColeman 0:0791c1fece8e 1197 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1198 LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);
RodColeman 0:0791c1fece8e 1199 /* Remove the flag that says this netif is handled by DHCP. */
RodColeman 0:0791c1fece8e 1200 netif->flags &= ~NETIF_FLAG_DHCP;
RodColeman 0:0791c1fece8e 1201
RodColeman 0:0791c1fece8e 1202 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));
RodColeman 0:0791c1fece8e 1203 /* netif is DHCP configured? */
RodColeman 0:0791c1fece8e 1204 if (dhcp != NULL) {
RodColeman 0:0791c1fece8e 1205 #if LWIP_DHCP_AUTOIP_COOP
RodColeman 0:0791c1fece8e 1206 if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) {
RodColeman 0:0791c1fece8e 1207 autoip_stop(netif);
RodColeman 0:0791c1fece8e 1208 dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF;
RodColeman 0:0791c1fece8e 1209 }
RodColeman 0:0791c1fece8e 1210 #endif /* LWIP_DHCP_AUTOIP_COOP */
RodColeman 0:0791c1fece8e 1211
RodColeman 0:0791c1fece8e 1212 if (dhcp->pcb != NULL) {
RodColeman 0:0791c1fece8e 1213 udp_remove(dhcp->pcb);
RodColeman 0:0791c1fece8e 1214 dhcp->pcb = NULL;
RodColeman 0:0791c1fece8e 1215 }
RodColeman 0:0791c1fece8e 1216 LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
RodColeman 0:0791c1fece8e 1217 dhcp->options_in == NULL && dhcp->options_in_len == 0);
RodColeman 0:0791c1fece8e 1218 mem_free((void *)dhcp);
RodColeman 0:0791c1fece8e 1219 netif->dhcp = NULL;
RodColeman 0:0791c1fece8e 1220 }
RodColeman 0:0791c1fece8e 1221 }
RodColeman 0:0791c1fece8e 1222
RodColeman 0:0791c1fece8e 1223 /*
RodColeman 0:0791c1fece8e 1224 * Set the DHCP state of a DHCP client.
RodColeman 0:0791c1fece8e 1225 *
RodColeman 0:0791c1fece8e 1226 * If the state changed, reset the number of tries.
RodColeman 0:0791c1fece8e 1227 *
RodColeman 0:0791c1fece8e 1228 * TODO: we might also want to reset the timeout here?
RodColeman 0:0791c1fece8e 1229 */
RodColeman 0:0791c1fece8e 1230 static void
RodColeman 0:0791c1fece8e 1231 dhcp_set_state(struct dhcp *dhcp, u8_t new_state)
RodColeman 0:0791c1fece8e 1232 {
RodColeman 0:0791c1fece8e 1233 if (new_state != dhcp->state) {
RodColeman 0:0791c1fece8e 1234 dhcp->state = new_state;
RodColeman 0:0791c1fece8e 1235 dhcp->tries = 0;
RodColeman 0:0791c1fece8e 1236 }
RodColeman 0:0791c1fece8e 1237 }
RodColeman 0:0791c1fece8e 1238
RodColeman 0:0791c1fece8e 1239 /*
RodColeman 0:0791c1fece8e 1240 * Concatenate an option type and length field to the outgoing
RodColeman 0:0791c1fece8e 1241 * DHCP message.
RodColeman 0:0791c1fece8e 1242 *
RodColeman 0:0791c1fece8e 1243 */
RodColeman 0:0791c1fece8e 1244 static void
RodColeman 0:0791c1fece8e 1245 dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)
RodColeman 0:0791c1fece8e 1246 {
RodColeman 0:0791c1fece8e 1247 LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1248 dhcp->msg_out->options[dhcp->options_out_len++] = option_type;
RodColeman 0:0791c1fece8e 1249 dhcp->msg_out->options[dhcp->options_out_len++] = option_len;
RodColeman 0:0791c1fece8e 1250 }
RodColeman 0:0791c1fece8e 1251 /*
RodColeman 0:0791c1fece8e 1252 * Concatenate a single byte to the outgoing DHCP message.
RodColeman 0:0791c1fece8e 1253 *
RodColeman 0:0791c1fece8e 1254 */
RodColeman 0:0791c1fece8e 1255 static void
RodColeman 0:0791c1fece8e 1256 dhcp_option_byte(struct dhcp *dhcp, u8_t value)
RodColeman 0:0791c1fece8e 1257 {
RodColeman 0:0791c1fece8e 1258 LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1259 dhcp->msg_out->options[dhcp->options_out_len++] = value;
RodColeman 0:0791c1fece8e 1260 }
RodColeman 0:0791c1fece8e 1261
RodColeman 0:0791c1fece8e 1262 static void
RodColeman 0:0791c1fece8e 1263 dhcp_option_short(struct dhcp *dhcp, u16_t value)
RodColeman 0:0791c1fece8e 1264 {
RodColeman 0:0791c1fece8e 1265 LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1266 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);
RodColeman 0:0791c1fece8e 1267 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);
RodColeman 0:0791c1fece8e 1268 }
RodColeman 0:0791c1fece8e 1269
RodColeman 0:0791c1fece8e 1270 static void
RodColeman 0:0791c1fece8e 1271 dhcp_option_long(struct dhcp *dhcp, u32_t value)
RodColeman 0:0791c1fece8e 1272 {
RodColeman 0:0791c1fece8e 1273 LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1274 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);
RodColeman 0:0791c1fece8e 1275 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);
RodColeman 0:0791c1fece8e 1276 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);
RodColeman 0:0791c1fece8e 1277 dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));
RodColeman 0:0791c1fece8e 1278 }
RodColeman 0:0791c1fece8e 1279
RodColeman 0:0791c1fece8e 1280 /**
RodColeman 0:0791c1fece8e 1281 * Extract the DHCP message and the DHCP options.
RodColeman 0:0791c1fece8e 1282 *
RodColeman 0:0791c1fece8e 1283 * Extract the DHCP message and the DHCP options, each into a contiguous
RodColeman 0:0791c1fece8e 1284 * piece of memory. As a DHCP message is variable sized by its options,
RodColeman 0:0791c1fece8e 1285 * and also allows overriding some fields for options, the easy approach
RodColeman 0:0791c1fece8e 1286 * is to first unfold the options into a conitguous piece of memory, and
RodColeman 0:0791c1fece8e 1287 * use that further on.
RodColeman 0:0791c1fece8e 1288 *
RodColeman 0:0791c1fece8e 1289 */
RodColeman 0:0791c1fece8e 1290 static err_t
RodColeman 0:0791c1fece8e 1291 dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p)
RodColeman 0:0791c1fece8e 1292 {
RodColeman 0:0791c1fece8e 1293 u16_t ret;
RodColeman 0:0791c1fece8e 1294 LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);
RodColeman 0:0791c1fece8e 1295 /* free any left-overs from previous unfolds */
RodColeman 0:0791c1fece8e 1296 dhcp_free_reply(dhcp);
RodColeman 0:0791c1fece8e 1297 /* options present? */
RodColeman 0:0791c1fece8e 1298 if (p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {
RodColeman 0:0791c1fece8e 1299 dhcp->options_in_len = p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1300 dhcp->options_in = mem_malloc(dhcp->options_in_len);
RodColeman 0:0791c1fece8e 1301 if (dhcp->options_in == NULL) {
RodColeman 0:0791c1fece8e 1302 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));
RodColeman 0:0791c1fece8e 1303 dhcp->options_in_len = 0;
RodColeman 0:0791c1fece8e 1304 return ERR_MEM;
RodColeman 0:0791c1fece8e 1305 }
RodColeman 0:0791c1fece8e 1306 }
RodColeman 0:0791c1fece8e 1307 dhcp->msg_in = (struct dhcp_msg *)mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1308 if (dhcp->msg_in == NULL) {
RodColeman 0:0791c1fece8e 1309 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));
RodColeman 0:0791c1fece8e 1310 if (dhcp->options_in != NULL) {
RodColeman 0:0791c1fece8e 1311 mem_free(dhcp->options_in);
RodColeman 0:0791c1fece8e 1312 dhcp->options_in = NULL;
RodColeman 0:0791c1fece8e 1313 dhcp->options_in_len = 0;
RodColeman 0:0791c1fece8e 1314 }
RodColeman 0:0791c1fece8e 1315 return ERR_MEM;
RodColeman 0:0791c1fece8e 1316 }
RodColeman 0:0791c1fece8e 1317
RodColeman 0:0791c1fece8e 1318 /** copy the DHCP message without options */
RodColeman 0:0791c1fece8e 1319 ret = pbuf_copy_partial(p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);
RodColeman 0:0791c1fece8e 1320 LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1321 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",
RodColeman 0:0791c1fece8e 1322 sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));
RodColeman 0:0791c1fece8e 1323
RodColeman 0:0791c1fece8e 1324 if (dhcp->options_in != NULL) {
RodColeman 0:0791c1fece8e 1325 /** copy the DHCP options */
RodColeman 0:0791c1fece8e 1326 ret = pbuf_copy_partial(p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1327 LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);
RodColeman 0:0791c1fece8e 1328 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",
RodColeman 0:0791c1fece8e 1329 dhcp->options_in_len));
RodColeman 0:0791c1fece8e 1330 }
RodColeman 0:0791c1fece8e 1331 LWIP_UNUSED_ARG(ret);
RodColeman 0:0791c1fece8e 1332 return ERR_OK;
RodColeman 0:0791c1fece8e 1333 }
RodColeman 0:0791c1fece8e 1334
RodColeman 0:0791c1fece8e 1335 /**
RodColeman 0:0791c1fece8e 1336 * Free the incoming DHCP message including contiguous copy of
RodColeman 0:0791c1fece8e 1337 * its DHCP options.
RodColeman 0:0791c1fece8e 1338 */
RodColeman 0:0791c1fece8e 1339 static void dhcp_free_reply(struct dhcp *dhcp)
RodColeman 0:0791c1fece8e 1340 {
RodColeman 0:0791c1fece8e 1341 if (dhcp->msg_in != NULL) {
RodColeman 0:0791c1fece8e 1342 mem_free((void *)dhcp->msg_in);
RodColeman 0:0791c1fece8e 1343 dhcp->msg_in = NULL;
RodColeman 0:0791c1fece8e 1344 }
RodColeman 0:0791c1fece8e 1345 if (dhcp->options_in) {
RodColeman 0:0791c1fece8e 1346 mem_free(dhcp->options_in);
RodColeman 0:0791c1fece8e 1347 dhcp->options_in = NULL;
RodColeman 0:0791c1fece8e 1348 dhcp->options_in_len = 0;
RodColeman 0:0791c1fece8e 1349 }
RodColeman 0:0791c1fece8e 1350 LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));
RodColeman 0:0791c1fece8e 1351 }
RodColeman 0:0791c1fece8e 1352
RodColeman 0:0791c1fece8e 1353 /**
RodColeman 0:0791c1fece8e 1354 * If an incoming DHCP message is in response to us, then trigger the state machine
RodColeman 0:0791c1fece8e 1355 */
RodColeman 0:0791c1fece8e 1356 static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
RodColeman 0:0791c1fece8e 1357 {
RodColeman 0:0791c1fece8e 1358 struct netif *netif = (struct netif *)arg;
RodColeman 0:0791c1fece8e 1359 struct dhcp *dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1360 struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;
RodColeman 0:0791c1fece8e 1361 u8_t *options_ptr;
RodColeman 0:0791c1fece8e 1362 u8_t msg_type;
RodColeman 0:0791c1fece8e 1363 u8_t i;
RodColeman 0:0791c1fece8e 1364 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,
RodColeman 0:0791c1fece8e 1365 (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),
RodColeman 0:0791c1fece8e 1366 (u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));
RodColeman 0:0791c1fece8e 1367 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));
RodColeman 0:0791c1fece8e 1368 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));
RodColeman 0:0791c1fece8e 1369 /* prevent warnings about unused arguments */
RodColeman 0:0791c1fece8e 1370 LWIP_UNUSED_ARG(pcb);
RodColeman 0:0791c1fece8e 1371 LWIP_UNUSED_ARG(addr);
RodColeman 0:0791c1fece8e 1372 LWIP_UNUSED_ARG(port);
RodColeman 0:0791c1fece8e 1373
RodColeman 0:0791c1fece8e 1374 LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL &&
RodColeman 0:0791c1fece8e 1375 dhcp->options_in == NULL && dhcp->options_in_len == 0);
RodColeman 0:0791c1fece8e 1376
RodColeman 0:0791c1fece8e 1377 if (p->len < DHCP_MIN_REPLY_LEN) {
RodColeman 0:0791c1fece8e 1378 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP reply message too short\n"));
RodColeman 0:0791c1fece8e 1379 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1380 }
RodColeman 0:0791c1fece8e 1381
RodColeman 0:0791c1fece8e 1382 if (reply_msg->op != DHCP_BOOTREPLY) {
RodColeman 0:0791c1fece8e 1383 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));
RodColeman 0:0791c1fece8e 1384 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1385 }
RodColeman 0:0791c1fece8e 1386 /* iterate through hardware address and match against DHCP message */
RodColeman 0:0791c1fece8e 1387 for (i = 0; i < netif->hwaddr_len; i++) {
RodColeman 0:0791c1fece8e 1388 if (netif->hwaddr[i] != reply_msg->chaddr[i]) {
RodColeman 0:0791c1fece8e 1389 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",
RodColeman 0:0791c1fece8e 1390 (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));
RodColeman 0:0791c1fece8e 1391 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1392 }
RodColeman 0:0791c1fece8e 1393 }
RodColeman 0:0791c1fece8e 1394 /* match transaction ID against what we expected */
RodColeman 0:0791c1fece8e 1395 if (ntohl(reply_msg->xid) != dhcp->xid) {
RodColeman 0:0791c1fece8e 1396 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));
RodColeman 0:0791c1fece8e 1397 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1398 }
RodColeman 0:0791c1fece8e 1399 /* option fields could be unfold? */
RodColeman 0:0791c1fece8e 1400 if (dhcp_unfold_reply(dhcp, p) != ERR_OK) {
RodColeman 0:0791c1fece8e 1401 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));
RodColeman 0:0791c1fece8e 1402 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1403 }
RodColeman 0:0791c1fece8e 1404
RodColeman 0:0791c1fece8e 1405 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));
RodColeman 0:0791c1fece8e 1406 /* obtain pointer to DHCP message type */
RodColeman 0:0791c1fece8e 1407 options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);
RodColeman 0:0791c1fece8e 1408 if (options_ptr == NULL) {
RodColeman 0:0791c1fece8e 1409 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));
RodColeman 0:0791c1fece8e 1410 goto free_pbuf_and_return;
RodColeman 0:0791c1fece8e 1411 }
RodColeman 0:0791c1fece8e 1412
RodColeman 0:0791c1fece8e 1413 /* read DHCP message type */
RodColeman 0:0791c1fece8e 1414 msg_type = dhcp_get_option_byte(options_ptr + 2);
RodColeman 0:0791c1fece8e 1415 /* message type is DHCP ACK? */
RodColeman 0:0791c1fece8e 1416 if (msg_type == DHCP_ACK) {
RodColeman 0:0791c1fece8e 1417 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));
RodColeman 0:0791c1fece8e 1418 /* in requesting state? */
RodColeman 0:0791c1fece8e 1419 if (dhcp->state == DHCP_REQUESTING) {
RodColeman 0:0791c1fece8e 1420 dhcp_handle_ack(netif);
RodColeman 0:0791c1fece8e 1421 dhcp->request_timeout = 0;
RodColeman 0:0791c1fece8e 1422 #if DHCP_DOES_ARP_CHECK
RodColeman 0:0791c1fece8e 1423 /* check if the acknowledged lease address is already in use */
RodColeman 0:0791c1fece8e 1424 dhcp_check(netif);
RodColeman 0:0791c1fece8e 1425 #else
RodColeman 0:0791c1fece8e 1426 /* bind interface to the acknowledged lease address */
RodColeman 0:0791c1fece8e 1427 dhcp_bind(netif);
RodColeman 0:0791c1fece8e 1428 #endif
RodColeman 0:0791c1fece8e 1429 }
RodColeman 0:0791c1fece8e 1430 /* already bound to the given lease address? */
RodColeman 0:0791c1fece8e 1431 else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {
RodColeman 0:0791c1fece8e 1432 dhcp->request_timeout = 0;
RodColeman 0:0791c1fece8e 1433 dhcp_bind(netif);
RodColeman 0:0791c1fece8e 1434 }
RodColeman 0:0791c1fece8e 1435 }
RodColeman 0:0791c1fece8e 1436 /* received a DHCP_NAK in appropriate state? */
RodColeman 0:0791c1fece8e 1437 else if ((msg_type == DHCP_NAK) &&
RodColeman 0:0791c1fece8e 1438 ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||
RodColeman 0:0791c1fece8e 1439 (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) {
RodColeman 0:0791c1fece8e 1440 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));
RodColeman 0:0791c1fece8e 1441 dhcp->request_timeout = 0;
RodColeman 0:0791c1fece8e 1442 dhcp_handle_nak(netif);
RodColeman 0:0791c1fece8e 1443 }
RodColeman 0:0791c1fece8e 1444 /* received a DHCP_OFFER in DHCP_SELECTING state? */
RodColeman 0:0791c1fece8e 1445 else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {
RodColeman 0:0791c1fece8e 1446 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));
RodColeman 0:0791c1fece8e 1447 dhcp->request_timeout = 0;
RodColeman 0:0791c1fece8e 1448 /* remember offered lease */
RodColeman 0:0791c1fece8e 1449 dhcp_handle_offer(netif);
RodColeman 0:0791c1fece8e 1450 }
RodColeman 0:0791c1fece8e 1451 free_pbuf_and_return:
RodColeman 0:0791c1fece8e 1452 dhcp_free_reply(dhcp);
RodColeman 0:0791c1fece8e 1453 pbuf_free(p);
RodColeman 0:0791c1fece8e 1454 }
RodColeman 0:0791c1fece8e 1455
RodColeman 0:0791c1fece8e 1456 /**
RodColeman 0:0791c1fece8e 1457 * Create a DHCP request, fill in common headers
RodColeman 0:0791c1fece8e 1458 *
RodColeman 0:0791c1fece8e 1459 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 1460 */
RodColeman 0:0791c1fece8e 1461 static err_t
RodColeman 0:0791c1fece8e 1462 dhcp_create_request(struct netif *netif)
RodColeman 0:0791c1fece8e 1463 {
RodColeman 0:0791c1fece8e 1464 struct dhcp *dhcp;
RodColeman 0:0791c1fece8e 1465 u16_t i;
RodColeman 0:0791c1fece8e 1466 #ifndef DHCP_GLOBAL_XID
RodColeman 0:0791c1fece8e 1467 /** default global transaction identifier starting value (easy to match
RodColeman 0:0791c1fece8e 1468 * with a packet analyser). We simply increment for each new request.
RodColeman 0:0791c1fece8e 1469 * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one
RodColeman 0:0791c1fece8e 1470 * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */
RodColeman 0:0791c1fece8e 1471 static u32_t xid = 0xABCD0000;
RodColeman 0:0791c1fece8e 1472 #else
RodColeman 0:0791c1fece8e 1473 static u32_t xid;
RodColeman 0:0791c1fece8e 1474 static u8_t xid_initialised = 0;
RodColeman 0:0791c1fece8e 1475 if (!xid_initialised) {
RodColeman 0:0791c1fece8e 1476 xid = DHCP_GLOBAL_XID;
RodColeman 0:0791c1fece8e 1477 xid_initialised = !xid_initialised;
RodColeman 0:0791c1fece8e 1478 }
RodColeman 0:0791c1fece8e 1479 #endif
RodColeman 0:0791c1fece8e 1480 LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);
RodColeman 0:0791c1fece8e 1481 dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1482 LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);
RodColeman 0:0791c1fece8e 1483 LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);
RodColeman 0:0791c1fece8e 1484 LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);
RodColeman 0:0791c1fece8e 1485 dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);
RodColeman 0:0791c1fece8e 1486 if (dhcp->p_out == NULL) {
RodColeman 0:0791c1fece8e 1487 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));
RodColeman 0:0791c1fece8e 1488 return ERR_MEM;
RodColeman 0:0791c1fece8e 1489 }
RodColeman 0:0791c1fece8e 1490 LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",
RodColeman 0:0791c1fece8e 1491 (dhcp->p_out->len >= sizeof(struct dhcp_msg)));
RodColeman 0:0791c1fece8e 1492
RodColeman 0:0791c1fece8e 1493 /* reuse transaction identifier in retransmissions */
RodColeman 0:0791c1fece8e 1494 if (dhcp->tries==0)
RodColeman 0:0791c1fece8e 1495 xid++;
RodColeman 0:0791c1fece8e 1496 dhcp->xid = xid;
RodColeman 0:0791c1fece8e 1497 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2,
RodColeman 0:0791c1fece8e 1498 ("transaction id xid(%"X32_F")\n", xid));
RodColeman 0:0791c1fece8e 1499
RodColeman 0:0791c1fece8e 1500 dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;
RodColeman 0:0791c1fece8e 1501
RodColeman 0:0791c1fece8e 1502 dhcp->msg_out->op = DHCP_BOOTREQUEST;
RodColeman 0:0791c1fece8e 1503 /* TODO: make link layer independent */
RodColeman 0:0791c1fece8e 1504 dhcp->msg_out->htype = DHCP_HTYPE_ETH;
RodColeman 0:0791c1fece8e 1505 /* TODO: make link layer independent */
RodColeman 0:0791c1fece8e 1506 dhcp->msg_out->hlen = DHCP_HLEN_ETH;
RodColeman 0:0791c1fece8e 1507 dhcp->msg_out->hops = 0;
RodColeman 0:0791c1fece8e 1508 dhcp->msg_out->xid = htonl(dhcp->xid);
RodColeman 0:0791c1fece8e 1509 dhcp->msg_out->secs = 0;
RodColeman 0:0791c1fece8e 1510 dhcp->msg_out->flags = 0;
RodColeman 0:0791c1fece8e 1511 dhcp->msg_out->ciaddr.addr = 0;
RodColeman 0:0791c1fece8e 1512 if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) {
RodColeman 0:0791c1fece8e 1513 dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;
RodColeman 0:0791c1fece8e 1514 }
RodColeman 0:0791c1fece8e 1515 dhcp->msg_out->yiaddr.addr = 0;
RodColeman 0:0791c1fece8e 1516 dhcp->msg_out->siaddr.addr = 0;
RodColeman 0:0791c1fece8e 1517 dhcp->msg_out->giaddr.addr = 0;
RodColeman 0:0791c1fece8e 1518 for (i = 0; i < DHCP_CHADDR_LEN; i++) {
RodColeman 0:0791c1fece8e 1519 /* copy netif hardware address, pad with zeroes */
RodColeman 0:0791c1fece8e 1520 dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;
RodColeman 0:0791c1fece8e 1521 }
RodColeman 0:0791c1fece8e 1522 for (i = 0; i < DHCP_SNAME_LEN; i++) {
RodColeman 0:0791c1fece8e 1523 dhcp->msg_out->sname[i] = 0;
RodColeman 0:0791c1fece8e 1524 }
RodColeman 0:0791c1fece8e 1525 for (i = 0; i < DHCP_FILE_LEN; i++) {
RodColeman 0:0791c1fece8e 1526 dhcp->msg_out->file[i] = 0;
RodColeman 0:0791c1fece8e 1527 }
RodColeman 0:0791c1fece8e 1528 dhcp->msg_out->cookie = htonl(0x63825363UL);
RodColeman 0:0791c1fece8e 1529 dhcp->options_out_len = 0;
RodColeman 0:0791c1fece8e 1530 /* fill options field with an incrementing array (for debugging purposes) */
RodColeman 0:0791c1fece8e 1531 for (i = 0; i < DHCP_OPTIONS_LEN; i++) {
RodColeman 0:0791c1fece8e 1532 dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */
RodColeman 0:0791c1fece8e 1533 }
RodColeman 0:0791c1fece8e 1534 return ERR_OK;
RodColeman 0:0791c1fece8e 1535 }
RodColeman 0:0791c1fece8e 1536
RodColeman 0:0791c1fece8e 1537 /**
RodColeman 0:0791c1fece8e 1538 * Free previously allocated memory used to send a DHCP request.
RodColeman 0:0791c1fece8e 1539 *
RodColeman 0:0791c1fece8e 1540 * @param netif the netif under DHCP control
RodColeman 0:0791c1fece8e 1541 */
RodColeman 0:0791c1fece8e 1542 static void
RodColeman 0:0791c1fece8e 1543 dhcp_delete_request(struct netif *netif)
RodColeman 0:0791c1fece8e 1544 {
RodColeman 0:0791c1fece8e 1545 struct dhcp *dhcp;
RodColeman 0:0791c1fece8e 1546 LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;);
RodColeman 0:0791c1fece8e 1547 dhcp = netif->dhcp;
RodColeman 0:0791c1fece8e 1548 LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;);
RodColeman 0:0791c1fece8e 1549 LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL);
RodColeman 0:0791c1fece8e 1550 LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL);
RodColeman 0:0791c1fece8e 1551 if (dhcp->p_out != NULL) {
RodColeman 0:0791c1fece8e 1552 pbuf_free(dhcp->p_out);
RodColeman 0:0791c1fece8e 1553 }
RodColeman 0:0791c1fece8e 1554 dhcp->p_out = NULL;
RodColeman 0:0791c1fece8e 1555 dhcp->msg_out = NULL;
RodColeman 0:0791c1fece8e 1556 }
RodColeman 0:0791c1fece8e 1557
RodColeman 0:0791c1fece8e 1558 /**
RodColeman 0:0791c1fece8e 1559 * Add a DHCP message trailer
RodColeman 0:0791c1fece8e 1560 *
RodColeman 0:0791c1fece8e 1561 * Adds the END option to the DHCP message, and if
RodColeman 0:0791c1fece8e 1562 * necessary, up to three padding bytes.
RodColeman 0:0791c1fece8e 1563 *
RodColeman 0:0791c1fece8e 1564 * @param dhcp DHCP state structure
RodColeman 0:0791c1fece8e 1565 */
RodColeman 0:0791c1fece8e 1566 static void
RodColeman 0:0791c1fece8e 1567 dhcp_option_trailer(struct dhcp *dhcp)
RodColeman 0:0791c1fece8e 1568 {
RodColeman 0:0791c1fece8e 1569 LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);
RodColeman 0:0791c1fece8e 1570 LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);
RodColeman 0:0791c1fece8e 1571 LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1572 dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;
RodColeman 0:0791c1fece8e 1573 /* packet is too small, or not 4 byte aligned? */
RodColeman 0:0791c1fece8e 1574 while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {
RodColeman 0:0791c1fece8e 1575 /* 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)); */
RodColeman 0:0791c1fece8e 1576 LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);
RodColeman 0:0791c1fece8e 1577 /* add a fill/padding byte */
RodColeman 0:0791c1fece8e 1578 dhcp->msg_out->options[dhcp->options_out_len++] = 0;
RodColeman 0:0791c1fece8e 1579 }
RodColeman 0:0791c1fece8e 1580 }
RodColeman 0:0791c1fece8e 1581
RodColeman 0:0791c1fece8e 1582 /**
RodColeman 0:0791c1fece8e 1583 * Find the offset of a DHCP option inside the DHCP message.
RodColeman 0:0791c1fece8e 1584 *
RodColeman 0:0791c1fece8e 1585 * @param dhcp DHCP client
RodColeman 0:0791c1fece8e 1586 * @param option_type
RodColeman 0:0791c1fece8e 1587 *
RodColeman 0:0791c1fece8e 1588 * @return a byte offset into the UDP message where the option was found, or
RodColeman 0:0791c1fece8e 1589 * zero if the given option was not found.
RodColeman 0:0791c1fece8e 1590 */
RodColeman 0:0791c1fece8e 1591 static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)
RodColeman 0:0791c1fece8e 1592 {
RodColeman 0:0791c1fece8e 1593 u8_t overload = DHCP_OVERLOAD_NONE;
RodColeman 0:0791c1fece8e 1594
RodColeman 0:0791c1fece8e 1595 /* options available? */
RodColeman 0:0791c1fece8e 1596 if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {
RodColeman 0:0791c1fece8e 1597 /* start with options field */
RodColeman 0:0791c1fece8e 1598 u8_t *options = (u8_t *)dhcp->options_in;
RodColeman 0:0791c1fece8e 1599 u16_t offset = 0;
RodColeman 0:0791c1fece8e 1600 /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */
RodColeman 0:0791c1fece8e 1601 while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {
RodColeman 0:0791c1fece8e 1602 /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */
RodColeman 0:0791c1fece8e 1603 /* are the sname and/or file field overloaded with options? */
RodColeman 0:0791c1fece8e 1604 if (options[offset] == DHCP_OPTION_OVERLOAD) {
RodColeman 0:0791c1fece8e 1605 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));
RodColeman 0:0791c1fece8e 1606 /* skip option type and length */
RodColeman 0:0791c1fece8e 1607 offset += 2;
RodColeman 0:0791c1fece8e 1608 overload = options[offset++];
RodColeman 0:0791c1fece8e 1609 }
RodColeman 0:0791c1fece8e 1610 /* requested option found */
RodColeman 0:0791c1fece8e 1611 else if (options[offset] == option_type) {
RodColeman 0:0791c1fece8e 1612 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));
RodColeman 0:0791c1fece8e 1613 return &options[offset];
RodColeman 0:0791c1fece8e 1614 /* skip option */
RodColeman 0:0791c1fece8e 1615 } else {
RodColeman 0:0791c1fece8e 1616 LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));
RodColeman 0:0791c1fece8e 1617 /* skip option type */
RodColeman 0:0791c1fece8e 1618 offset++;
RodColeman 0:0791c1fece8e 1619 /* skip option length, and then length bytes */
RodColeman 0:0791c1fece8e 1620 offset += 1 + options[offset];
RodColeman 0:0791c1fece8e 1621 }
RodColeman 0:0791c1fece8e 1622 }
RodColeman 0:0791c1fece8e 1623 /* is this an overloaded message? */
RodColeman 0:0791c1fece8e 1624 if (overload != DHCP_OVERLOAD_NONE) {
RodColeman 0:0791c1fece8e 1625 u16_t field_len;
RodColeman 0:0791c1fece8e 1626 if (overload == DHCP_OVERLOAD_FILE) {
RodColeman 0:0791c1fece8e 1627 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));
RodColeman 0:0791c1fece8e 1628 options = (u8_t *)&dhcp->msg_in->file;
RodColeman 0:0791c1fece8e 1629 field_len = DHCP_FILE_LEN;
RodColeman 0:0791c1fece8e 1630 } else if (overload == DHCP_OVERLOAD_SNAME) {
RodColeman 0:0791c1fece8e 1631 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));
RodColeman 0:0791c1fece8e 1632 options = (u8_t *)&dhcp->msg_in->sname;
RodColeman 0:0791c1fece8e 1633 field_len = DHCP_SNAME_LEN;
RodColeman 0:0791c1fece8e 1634 /* TODO: check if else if () is necessary */
RodColeman 0:0791c1fece8e 1635 } else {
RodColeman 0:0791c1fece8e 1636 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));
RodColeman 0:0791c1fece8e 1637 options = (u8_t *)&dhcp->msg_in->sname;
RodColeman 0:0791c1fece8e 1638 field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;
RodColeman 0:0791c1fece8e 1639 }
RodColeman 0:0791c1fece8e 1640 offset = 0;
RodColeman 0:0791c1fece8e 1641
RodColeman 0:0791c1fece8e 1642 /* at least 1 byte to read and no end marker */
RodColeman 0:0791c1fece8e 1643 while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {
RodColeman 0:0791c1fece8e 1644 if (options[offset] == option_type) {
RodColeman 0:0791c1fece8e 1645 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));
RodColeman 0:0791c1fece8e 1646 return &options[offset];
RodColeman 0:0791c1fece8e 1647 /* skip option */
RodColeman 0:0791c1fece8e 1648 } else {
RodColeman 0:0791c1fece8e 1649 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));
RodColeman 0:0791c1fece8e 1650 /* skip option type */
RodColeman 0:0791c1fece8e 1651 offset++;
RodColeman 0:0791c1fece8e 1652 offset += 1 + options[offset];
RodColeman 0:0791c1fece8e 1653 }
RodColeman 0:0791c1fece8e 1654 }
RodColeman 0:0791c1fece8e 1655 }
RodColeman 0:0791c1fece8e 1656 }
RodColeman 0:0791c1fece8e 1657 return NULL;
RodColeman 0:0791c1fece8e 1658 }
RodColeman 0:0791c1fece8e 1659
RodColeman 0:0791c1fece8e 1660 /**
RodColeman 0:0791c1fece8e 1661 * Return the byte of DHCP option data.
RodColeman 0:0791c1fece8e 1662 *
RodColeman 0:0791c1fece8e 1663 * @param client DHCP client.
RodColeman 0:0791c1fece8e 1664 * @param ptr pointer obtained by dhcp_get_option_ptr().
RodColeman 0:0791c1fece8e 1665 *
RodColeman 0:0791c1fece8e 1666 * @return byte value at the given address.
RodColeman 0:0791c1fece8e 1667 */
RodColeman 0:0791c1fece8e 1668 static u8_t
RodColeman 0:0791c1fece8e 1669 dhcp_get_option_byte(u8_t *ptr)
RodColeman 0:0791c1fece8e 1670 {
RodColeman 0:0791c1fece8e 1671 LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));
RodColeman 0:0791c1fece8e 1672 return *ptr;
RodColeman 0:0791c1fece8e 1673 }
RodColeman 0:0791c1fece8e 1674
RodColeman 0:0791c1fece8e 1675 #if 0 /* currently unused */
RodColeman 0:0791c1fece8e 1676 /**
RodColeman 0:0791c1fece8e 1677 * Return the 16-bit value of DHCP option data.
RodColeman 0:0791c1fece8e 1678 *
RodColeman 0:0791c1fece8e 1679 * @param client DHCP client.
RodColeman 0:0791c1fece8e 1680 * @param ptr pointer obtained by dhcp_get_option_ptr().
RodColeman 0:0791c1fece8e 1681 *
RodColeman 0:0791c1fece8e 1682 * @return byte value at the given address.
RodColeman 0:0791c1fece8e 1683 */
RodColeman 0:0791c1fece8e 1684 static u16_t
RodColeman 0:0791c1fece8e 1685 dhcp_get_option_short(u8_t *ptr)
RodColeman 0:0791c1fece8e 1686 {
RodColeman 0:0791c1fece8e 1687 u16_t value;
RodColeman 0:0791c1fece8e 1688 value = *ptr++ << 8;
RodColeman 0:0791c1fece8e 1689 value |= *ptr;
RodColeman 0:0791c1fece8e 1690 LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));
RodColeman 0:0791c1fece8e 1691 return value;
RodColeman 0:0791c1fece8e 1692 }
RodColeman 0:0791c1fece8e 1693 #endif
RodColeman 0:0791c1fece8e 1694
RodColeman 0:0791c1fece8e 1695 /**
RodColeman 0:0791c1fece8e 1696 * Return the 32-bit value of DHCP option data.
RodColeman 0:0791c1fece8e 1697 *
RodColeman 0:0791c1fece8e 1698 * @param client DHCP client.
RodColeman 0:0791c1fece8e 1699 * @param ptr pointer obtained by dhcp_get_option_ptr().
RodColeman 0:0791c1fece8e 1700 *
RodColeman 0:0791c1fece8e 1701 * @return byte value at the given address.
RodColeman 0:0791c1fece8e 1702 */
RodColeman 0:0791c1fece8e 1703 static u32_t dhcp_get_option_long(u8_t *ptr)
RodColeman 0:0791c1fece8e 1704 {
RodColeman 0:0791c1fece8e 1705 u32_t value;
RodColeman 0:0791c1fece8e 1706 value = (u32_t)(*ptr++) << 24;
RodColeman 0:0791c1fece8e 1707 value |= (u32_t)(*ptr++) << 16;
RodColeman 0:0791c1fece8e 1708 value |= (u32_t)(*ptr++) << 8;
RodColeman 0:0791c1fece8e 1709 value |= (u32_t)(*ptr++);
RodColeman 0:0791c1fece8e 1710 LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));
RodColeman 0:0791c1fece8e 1711 return value;
RodColeman 0:0791c1fece8e 1712 }
RodColeman 0:0791c1fece8e 1713
RodColeman 0:0791c1fece8e 1714 #endif /* LWIP_DHCP */