59 |
* |
* |
60 |
* How to boot the DHCP client |
* How to boot the DHCP client |
61 |
* |
* |
62 |
* First, call dhcp_init() to initialize the DHCP client. |
* struct dhcp *client = dhcp_start(struct netif *netif); |
|
* |
|
|
* Then, use |
|
|
* struct dhcp_state *client = dhcp_start(struct netif *netif) |
|
63 |
* starts a DHCP client instance which configures the interface by |
* starts a DHCP client instance which configures the interface by |
64 |
* obtaining an IP address lease and maintaining it. |
* obtaining an IP address lease and maintaining it. |
65 |
* |
* |
66 |
* Use dhcp_release(client) to end the lease and use dhcp_stop(client) |
* Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) |
67 |
* to remove the DHCP client. |
* to remove the DHCP client. |
68 |
* |
* |
69 |
*/ |
*/ |
78 |
#include "lwipopts.h" |
#include "lwipopts.h" |
79 |
#include "lwip/dhcp.h" |
#include "lwip/dhcp.h" |
80 |
|
|
|
/** find the active DHCP attached to the given network interface */ |
|
|
struct dhcp_state *dhcp_find_client(struct netif *netif); |
|
|
|
|
81 |
/** transaction identifier, unique over all DHCP requests */ |
/** transaction identifier, unique over all DHCP requests */ |
82 |
static u32_t xid = 0xABCD0000; |
static u32_t xid = 0xABCD0000; |
83 |
|
|
84 |
/** DHCP client state machine functions */ |
/** DHCP client state machine functions */ |
85 |
static void dhcp_handle_ack(struct dhcp_state *state); |
static void dhcp_handle_ack(struct dhcp *dhcp); |
86 |
static void dhcp_handle_nak(struct dhcp_state *state); |
static void dhcp_handle_nak(struct dhcp *dhcp); |
87 |
static void dhcp_handle_offer(struct dhcp_state *state); |
static void dhcp_handle_offer(struct dhcp *dhcp); |
88 |
static err_t dhcp_discover(struct dhcp_state *state); |
|
89 |
static err_t dhcp_select(struct dhcp_state *state); |
static err_t dhcp_discover(struct netif *netif); |
90 |
static void dhcp_check(struct dhcp_state *state); |
static err_t dhcp_select(struct netif *netif); |
91 |
static err_t dhcp_decline(struct dhcp_state *state); |
static void dhcp_check(struct netif *netif); |
92 |
static void dhcp_bind(struct dhcp_state *state); |
static void dhcp_bind(struct netif *netif); |
93 |
static err_t dhcp_rebind(struct dhcp_state *state); |
static err_t dhcp_decline(struct netif *netif); |
94 |
static err_t dhcp_release(struct dhcp_state *state); |
static err_t dhcp_rebind(struct netif *netif); |
95 |
static void dhcp_set_state(struct dhcp_state *state, unsigned char new_state); |
static err_t dhcp_release(struct netif *netif); |
96 |
|
static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state); |
97 |
|
|
98 |
/** receive, unfold, parse and free incoming messages */ |
/** receive, unfold, parse and free incoming messages */ |
99 |
static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); |
static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); |
100 |
static err_t dhcp_unfold_reply(struct dhcp_state *state); |
static err_t dhcp_unfold_reply(struct dhcp *dhcp); |
101 |
static u8_t *dhcp_get_option_ptr(struct dhcp_state *state, u8_t option_type); |
static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type); |
102 |
static u8_t dhcp_get_option_byte(u8_t *ptr); |
static u8_t dhcp_get_option_byte(u8_t *ptr); |
103 |
static u16_t dhcp_get_option_short(u8_t *ptr); |
static u16_t dhcp_get_option_short(u8_t *ptr); |
104 |
static u32_t dhcp_get_option_long(u8_t *ptr); |
static u32_t dhcp_get_option_long(u8_t *ptr); |
105 |
static void dhcp_free_reply(struct dhcp_state *state); |
static void dhcp_free_reply(struct dhcp *dhcp); |
106 |
|
|
107 |
/** set the DHCP timers */ |
/** set the DHCP timers */ |
108 |
static void dhcp_timeout(struct dhcp_state *state); |
static void dhcp_timeout(struct netif *netif); |
109 |
static void dhcp_t1_timeout(struct dhcp_state *state); |
static void dhcp_t1_timeout(struct dhcp *dhcp); |
110 |
static void dhcp_t2_timeout(struct dhcp_state *state); |
static void dhcp_t2_timeout(struct dhcp *dhcp); |
|
|
|
|
#if DHCP_DOES_ARP_CHECK |
|
|
/** called by ARP to notify us of ARP replies */ |
|
|
void dhcp_arp_reply(struct ip_addr *addr); |
|
|
#endif |
|
111 |
|
|
112 |
/** build outgoing messages */ |
/** build outgoing messages */ |
113 |
static err_t dhcp_create_request(struct dhcp_state *state); |
static err_t dhcp_create_request(struct dhcp *dhcp); |
114 |
static void dhcp_delete_request(struct dhcp_state *state); |
static void dhcp_delete_request(struct dhcp *dhcp); |
115 |
static void dhcp_option(struct dhcp_state *state, u8_t option_type, u8_t option_len); |
static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); |
116 |
static void dhcp_option_byte(struct dhcp_state *state, u8_t value); |
static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); |
117 |
static void dhcp_option_short(struct dhcp_state *state, u16_t value); |
static void dhcp_option_short(struct dhcp *dhcp, u16_t value); |
118 |
static void dhcp_option_long(struct dhcp_state *state, u32_t value); |
static void dhcp_option_long(struct dhcp *dhcp, u32_t value); |
119 |
static void dhcp_option_trailer(struct dhcp_state *state); |
static void dhcp_option_trailer(struct dhcp *dhcp); |
120 |
|
|
121 |
/** |
/** |
122 |
* Back-off the DHCP client (because of a received NAK response). |
* Back-off the DHCP client (because of a received NAK response). |
129 |
* |
* |
130 |
* @param state pointer to DHCP state structure |
* @param state pointer to DHCP state structure |
131 |
*/ |
*/ |
132 |
static void dhcp_handle_nak(struct dhcp_state *state) { |
static void dhcp_handle_nak(struct dhcp *dhcp) { |
133 |
|
struct dhcp *dhcp = netif->dhcp; |
134 |
u16_t msecs = 10 * 1000; |
u16_t msecs = 10 * 1000; |
135 |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_nak()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_nak()")); |
136 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
137 |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_nak(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_nak(): set request timeout %u msecs", msecs)); |
138 |
dhcp_set_state(state, DHCP_BACKING_OFF); |
dhcp_set_state(dhcp, DHCP_BACKING_OFF); |
139 |
} |
} |
140 |
|
|
141 |
/** |
/** |
145 |
* entering CHECKING state. If no ARP reply is received within a small |
* entering CHECKING state. If no ARP reply is received within a small |
146 |
* interval, the address is assumed to be free for use by us. |
* interval, the address is assumed to be free for use by us. |
147 |
*/ |
*/ |
148 |
static void dhcp_check(struct dhcp_state *state) |
static void dhcp_check(struct netif *netif) |
149 |
{ |
{ |
150 |
struct dhcp_state *state;; |
struct dhcp *dhcp = netif->dhcp; |
151 |
struct pbuf *p; |
struct pbuf *p; |
152 |
err_t result; |
err_t result; |
153 |
u16_t msecs; |
u16_t msecs; |
154 |
DEBUGF(DHCP_DEBUG, ("dhcp_check()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_check()")); |
155 |
/* create an ARP query for the offered IP address, expecting that no host |
/* create an ARP query for the offered IP address, expecting that no host |
156 |
responds, as the IP address should not be in use. */ |
responds, as the IP address should not be in use. */ |
157 |
p = etharp_query(state->netif, &state->offered_ip_addr, NULL); |
p = etharp_query(netif, &dhcp->offered_ip_addr, NULL); |
158 |
if(p != NULL) |
if (p != NULL) |
159 |
{ |
{ |
160 |
DEBUGF(DHCP_DEBUG, ("dhcp_check(): sending ARP request len %u", p->tot_len)); |
DEBUGF(DHCP_DEBUG, ("dhcp_check(): sending ARP request len %u", p->tot_len)); |
161 |
result = state->netif->linkoutput(state->netif, p); |
result = dhcp->netif->linkoutput(netif, p); |
162 |
pbuf_free(p); |
pbuf_free(p); |
163 |
p = NULL; |
p = NULL; |
164 |
} |
} |
165 |
state->tries++; |
dhcp->tries++; |
166 |
msecs = 500; |
msecs = 500; |
167 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
168 |
DEBUGF(DHCP_DEBUG, ("dhcp_check(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_check(): set request timeout %u msecs", msecs)); |
169 |
dhcp_set_state(state, DHCP_CHECKING); |
dhcp_set_state(dhcp, DHCP_CHECKING); |
170 |
} |
} |
171 |
|
|
172 |
/** |
/** |
174 |
* |
* |
175 |
* @param state pointer to DHCP state structure |
* @param state pointer to DHCP state structure |
176 |
*/ |
*/ |
177 |
static void dhcp_handle_offer(struct dhcp_state *state) |
static void dhcp_handle_offer(struct dhcp *dhcp) |
178 |
{ |
{ |
179 |
/* obtain the server address */ |
/* obtain the server address */ |
180 |
u8_t *option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_SERVER_ID); |
u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID); |
181 |
if (option_ptr != NULL) |
if (option_ptr != NULL) |
182 |
{ |
{ |
183 |
state->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
184 |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_offer(): server 0x%08lx", state->server_ip_addr.addr)); |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_offer(): server 0x%08lx", dhcp->server_ip_addr.addr)); |
185 |
/* remember offered address */ |
/* remember offered address */ |
186 |
ip_addr_set(&state->offered_ip_addr, (struct ip_addr *)&state->msg_in->yiaddr); |
ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); |
187 |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_offer(): offer for 0x%08lx", state->offered_ip_addr.addr)); |
DEBUGF(DHCP_DEBUG, ("dhcp_handle_offer(): offer for 0x%08lx", dhcp->offered_ip_addr.addr)); |
188 |
dhcp_select(state); |
dhcp_select(dhcp); |
189 |
} |
} |
190 |
else |
else |
191 |
{ |
{ |
192 |
//dhcp_start(restart); |
/* dhcp_start(restart); */ |
193 |
} |
} |
194 |
} |
} |
195 |
|
|
198 |
* |
* |
199 |
* Simply select the first offer received. |
* Simply select the first offer received. |
200 |
* |
* |
201 |
* @param state pointer to DHCP state structure |
* @param dhcp pointer to DHCP state structure |
202 |
* @return lwIP specific error (see error.h) |
* @return lwIP specific error (see error.h) |
203 |
*/ |
*/ |
204 |
static err_t dhcp_select(struct dhcp_state *state) |
static err_t dhcp_select(struct dhcp *dhcp) |
205 |
{ |
{ |
206 |
err_t result; |
err_t result; |
207 |
u32_t msecs; |
u32_t msecs; |
208 |
DEBUGF(DHCP_DEBUG, ("dhcp_select()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_select()")); |
209 |
|
|
210 |
// create and initialize the DHCP message header |
/* create and initialize the DHCP message header */ |
211 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
212 |
if (result == ERR_OK) |
if (result == ERR_OK) |
213 |
{ |
{ |
214 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
215 |
dhcp_option_byte(state, DHCP_REQUEST); |
dhcp_option_byte(dhcp, DHCP_REQUEST); |
216 |
|
|
217 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
218 |
dhcp_option_short(state, 576); |
dhcp_option_short(dhcp, 576); |
219 |
|
|
220 |
/* MUST request the offered IP address */ |
/* MUST request the offered IP address */ |
221 |
dhcp_option(state, DHCP_OPTION_REQUESTED_IP, 4); |
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); |
222 |
dhcp_option_long(state, ntohl(state->offered_ip_addr.addr)); |
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); |
|
|
|
|
dhcp_option(state, DHCP_OPTION_SERVER_ID, 4); |
|
|
dhcp_option_long(state, ntohl(state->server_ip_addr.addr)); |
|
|
|
|
|
dhcp_option(state, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3); |
|
|
dhcp_option_byte(state, DHCP_OPTION_SUBNET_MASK); |
|
|
dhcp_option_byte(state, DHCP_OPTION_ROUTER); |
|
|
dhcp_option_byte(state, DHCP_OPTION_BROADCAST); |
|
223 |
|
|
224 |
dhcp_option_trailer(state); |
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); |
225 |
|
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); |
226 |
|
|
227 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3); |
228 |
|
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); |
229 |
|
dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); |
230 |
|
dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); |
231 |
|
|
232 |
|
dhcp_option_trailer(dhcp); |
233 |
|
/* shrink the pbuf to the actual content length */ |
234 |
|
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
235 |
|
|
236 |
/* TODO: we really should bind to a specific local interface here |
/* TODO: we really should bind to a specific local interface here |
237 |
but we cannot specify an unconfigured netif as it is addressless */ |
but we cannot specify an unconfigured netif as it is addressless */ |
238 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
239 |
/* listen to broadcast traffic from a DHCP server */ |
/* send broadcast to any DHCP server */ |
240 |
udp_connect(state->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
241 |
udp_send(state->pcb, state->p_out); |
udp_send(dhcp->pcb, dhcp->p_out); |
242 |
// reconnect to any (or to server here?!) |
/* reconnect to any (or to server here?!) */ |
243 |
udp_connect(state->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
244 |
dhcp_delete_request(state); |
dhcp_delete_request(dhcp); |
245 |
} |
} |
246 |
state->tries++; |
dhcp->tries++; |
247 |
msecs = state->tries < 4 ? state->tries * 1000 : 4 * 1000; |
msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000; |
248 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
249 |
DEBUGF(DHCP_DEBUG, ("dhcp_select(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_select(): set request timeout %u msecs", msecs)); |
250 |
dhcp_set_state(state, DHCP_REQUESTING); |
dhcp_set_state(dhcp, DHCP_REQUESTING); |
251 |
return result; |
return result; |
252 |
} |
} |
253 |
|
|
254 |
/** |
/** |
255 |
* The DHCP timer that checks for lease renewal/rebind timeouts. |
* The DHCP timer that checks for lease renewal/rebind timeouts. |
256 |
* |
* |
|
* @param state pointer to DHCP state structure |
|
257 |
*/ |
*/ |
258 |
void dhcp_coarse_tmr() |
void dhcp_coarse_tmr() |
259 |
{ |
{ |
260 |
struct dhcp_state *list_state = client_list; |
struct netif *netif = netif_list; |
261 |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr():")); |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr():")); |
262 |
// loop through clients |
/* iterate through all network interfaces */ |
263 |
while (list_state != NULL) |
while (netif != NULL) { |
264 |
{ |
/* only act on DHCP configured interfaces */ |
265 |
// timer is active (non zero), and triggers (zeroes) now |
if (netif->dhcp != NULL) { |
266 |
if (list_state->t2_timeout-- == 1) |
/* timer is active (non zero), and triggers (zeroes) now? */ |
267 |
{ |
if (netif->dhcp->t2_timeout-- == 1) { |
268 |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr(): t2 timeout")); |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr(): t2 timeout")); |
269 |
// this clients' rebind timeout triggered |
/* this clients' rebind timeout triggered */ |
270 |
dhcp_t2_timeout(list_state); |
dhcp_t2_timeout(netif); |
271 |
} |
/* timer is active (non zero), and triggers (zeroes) now */ |
272 |
// timer is active (non zero), and triggers (zeroes) now |
} else if (netif->dhcp->t1_timeout-- == 1) { |
273 |
else if (list_state->t1_timeout-- == 1) |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr(): t1 timeout")); |
274 |
{ |
/* this clients' renewal timeout triggered */ |
275 |
DEBUGF(DHCP_DEBUG, ("dhcp_coarse_tmr(): t1 timeout")); |
dhcp_t1_timeout(netif); |
276 |
// this clients' renewal timeout triggered |
} |
|
dhcp_t1_timeout(list_state); |
|
277 |
} |
} |
278 |
// proceed to next timer |
/* proceed to next netif */ |
279 |
list_state = list_state->next; |
netif = netif->next; |
280 |
} |
} |
281 |
} |
} |
282 |
|
|
283 |
/** |
/** |
284 |
* The DHCP timer that handles DHCP negotiotion transaction timeouts. |
* The DHCP timer that handles DHCP negotiation transaction timeouts. |
285 |
* |
* |
286 |
*/ |
*/ |
287 |
void dhcp_fine_tmr() |
void dhcp_fine_tmr() |
288 |
{ |
{ |
289 |
struct dhcp_state *list_state = client_list; |
struct netif *netif = netif_list; |
|
// DEBUGF(DHCP_DEBUG, ("dhcp_fine_tmr():")); |
|
290 |
/* loop through clients */ |
/* loop through clients */ |
291 |
while (list_state != NULL) |
while (netif != NULL) { |
292 |
{ |
/* only act on DHCP configured interfaces */ |
293 |
/* timer is active (non zero), and triggers (zeroes) now */ |
if (netif->dhcp != NULL) { |
294 |
if (list_state->request_timeout-- == 1) |
/* timer is active (non zero), and triggers (zeroes) now */ |
295 |
{ |
if (netif->dhcp->request_timeout-- == 1) { |
296 |
DEBUGF(DHCP_DEBUG, ("dhcp_fine_tmr(): request timeout")); |
DEBUGF(DHCP_DEBUG, ("dhcp_fine_tmr(): request timeout")); |
297 |
/* this clients' request timeout triggered */ |
/* this clients' request timeout triggered */ |
298 |
dhcp_timeout(list_state); |
dhcp_timeout(netif); |
299 |
|
} |
300 |
} |
} |
301 |
/* proceed to next client */ |
/* proceed to next network interface */ |
302 |
list_state = list_state->next; |
netif = netif->next; |
303 |
} |
} |
304 |
} |
} |
305 |
|
|
309 |
* The timer that was started with the DHCP or ARP request has |
* The timer that was started with the DHCP or ARP request has |
310 |
* timed out, indicating no response was received. |
* timed out, indicating no response was received. |
311 |
* |
* |
312 |
* @param state pointer to DHCP state structure |
* @param dhcp pointer to DHCP state structure |
313 |
* |
* |
314 |
*/ |
*/ |
315 |
static void dhcp_timeout(struct dhcp_state *state) |
static void dhcp_timeout(struct netif *netif) |
316 |
{ |
{ |
317 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout()")); |
318 |
/* back-off period has passed, or server selection timed out */ |
/* back-off period has passed, or server selection timed out */ |
319 |
if ((state->state == DHCP_BACKING_OFF) || (state->state == DHCP_SELECTING)) |
if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { |
|
{ |
|
320 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): restarting discovery")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): restarting discovery")); |
321 |
dhcp_discover(state); |
dhcp_discover(dhcp); |
|
} |
|
322 |
/* receiving the requested lease timed out */ |
/* receiving the requested lease timed out */ |
323 |
else if (state->state == DHCP_REQUESTING) |
} else if (dhcp->state == DHCP_REQUESTING) { |
|
{ |
|
324 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REQUESTING, DHCP request timed out")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REQUESTING, DHCP request timed out")); |
325 |
if (state->tries <= 5) |
if (dhcp->tries <= 5) { |
326 |
{ |
dhcp_select(dhcp); |
327 |
dhcp_select(state); |
} else { |
|
} |
|
|
else |
|
|
{ |
|
328 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REQUESTING, releasing, restarting")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REQUESTING, releasing, restarting")); |
329 |
dhcp_release(state); |
dhcp_release(dhcp); |
330 |
dhcp_discover(state); |
dhcp_discover(dhcp); |
331 |
} |
} |
|
} |
|
332 |
/* received no ARP reply for the offered address (which is good) */ |
/* received no ARP reply for the offered address (which is good) */ |
333 |
else if (state->state == DHCP_CHECKING) |
} else if (dhcp->state == DHCP_CHECKING) { |
|
{ |
|
334 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): CHECKING, ARP request timed out")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): CHECKING, ARP request timed out")); |
335 |
if (state->tries <= 1) |
if (dhcp->tries <= 1) { |
336 |
{ |
dhcp_check(netif); |
|
dhcp_check(state); |
|
|
} |
|
337 |
/* no ARP replies on the offered address, |
/* no ARP replies on the offered address, |
338 |
looks like the IP address is indeed free */ |
looks like the IP address is indeed free */ |
339 |
else |
} else { |
|
{ |
|
340 |
/* bind the interface to the offered address */ |
/* bind the interface to the offered address */ |
341 |
dhcp_bind(state); |
dhcp_bind(netif); |
342 |
} |
} |
343 |
} |
} |
344 |
/* did not get response to renew request? */ |
/* did not get response to renew request? */ |
345 |
else if (state->state == DHCP_RENEWING) |
else if (dhcp->state == DHCP_RENEWING) { |
|
{ |
|
346 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): RENEWING, DHCP request timed out")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): RENEWING, DHCP request timed out")); |
347 |
/* just retry renewal */ |
/* just retry renewal */ |
348 |
/* note that the rebind timer will eventually time-out if renew does not work */ |
/* note that the rebind timer will eventually time-out if renew does not work */ |
349 |
dhcp_renew(state); |
dhcp_renew(dhcp); |
|
} |
|
350 |
/* did not get response to rebind request? */ |
/* did not get response to rebind request? */ |
351 |
else if (state->state == DHCP_REBINDING) |
} else if (dhcp->state == DHCP_REBINDING) { |
|
{ |
|
352 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REBINDING, DHCP request timed out")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): REBINDING, DHCP request timed out")); |
353 |
if (state->tries <= 8) |
if (dhcp->tries <= 8) { |
354 |
{ |
dhcp_rebind(dhcp); |
355 |
dhcp_rebind(state); |
} else { |
|
} |
|
|
else |
|
|
{ |
|
356 |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): RELEASING, DISCOVERING")); |
DEBUGF(DHCP_DEBUG, ("dhcp_timeout(): RELEASING, DISCOVERING")); |
357 |
dhcp_release(state); |
dhcp_release(dhcp); |
358 |
dhcp_discover(state); |
dhcp_discover(dhcp); |
359 |
} |
} |
360 |
} |
} |
361 |
} |
} |
363 |
/** |
/** |
364 |
* The renewal period has timed out. |
* The renewal period has timed out. |
365 |
* |
* |
366 |
* @param state pointer to DHCP state structure |
* @param dhcp pointer to DHCP state structure |
367 |
*/ |
*/ |
368 |
static void dhcp_t1_timeout(struct dhcp_state *state) |
static void dhcp_t1_timeout(struct netif *netif) |
369 |
{ |
{ |
370 |
|
struct dhcp *dhcp = netif->dhcp; |
371 |
DEBUGF(DHCP_DEBUG, ("dhcp_t1_timeout()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_t1_timeout()")); |
372 |
if ((state->state == DHCP_REQUESTING) || (state->state == DHCP_BOUND) || (state->state == DHCP_RENEWING)) |
if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { |
|
{ |
|
373 |
/* just retry to renew */ |
/* just retry to renew */ |
374 |
/* note that the rebind timer will eventually time-out if renew does not work */ |
/* note that the rebind timer will eventually time-out if renew does not work */ |
375 |
DEBUGF(DHCP_DEBUG, ("dhcp_t1_timeout(): must renew")); |
DEBUGF(DHCP_DEBUG, ("dhcp_t1_timeout(): must renew")); |
376 |
dhcp_renew(state); |
dhcp_renew(netif); |
377 |
} |
} |
378 |
} |
} |
379 |
|
|
381 |
* The rebind period has timed out. |
* The rebind period has timed out. |
382 |
* |
* |
383 |
*/ |
*/ |
384 |
static void dhcp_t2_timeout(struct dhcp_state *state) |
static void dhcp_t2_timeout(struct netif *netif) |
385 |
{ |
{ |
386 |
|
struct dhcp *dhcp = netif->dhcp; |
387 |
DEBUGF(DHCP_DEBUG, ("dhcp_t2_timeout()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_t2_timeout()")); |
388 |
if ((state->state == DHCP_REQUESTING) || (state->state == DHCP_BOUND) || (state->state == DHCP_RENEWING)) |
if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { |
|
{ |
|
389 |
/* just retry to rebind */ |
/* just retry to rebind */ |
390 |
DEBUGF(DHCP_DEBUG, ("dhcp_t2_timeout(): must rebind")); |
DEBUGF(DHCP_DEBUG, ("dhcp_t2_timeout(): must rebind")); |
391 |
dhcp_rebind(state); |
dhcp_rebind(netif); |
392 |
} |
} |
393 |
} |
} |
394 |
|
|
395 |
/** |
/** |
396 |
* Extract options from the server ACK message. |
* Extract options from the server ACK message. |
397 |
* |
* |
398 |
* @param state pointer to DHCP state structure |
* @param dhcp pointer to DHCP state structure |
399 |
*/ |
*/ |
400 |
static void dhcp_handle_ack(struct dhcp_state *state) |
static void dhcp_handle_ack(struct dhcp *dhcp) |
401 |
{ |
{ |
402 |
u8_t *option_ptr; |
u8_t *option_ptr; |
403 |
/* clear options we might not get from the ACK */ |
/* clear options we might not get from the ACK */ |
404 |
state->offered_sn_mask.addr = 0; |
dhcp->offered_sn_mask.addr = 0; |
405 |
state->offered_gw_addr.addr = 0; |
dhcp->offered_gw_addr.addr = 0; |
406 |
state->offered_bc_addr.addr = 0; |
dhcp->offered_bc_addr.addr = 0; |
407 |
|
|
408 |
/* lease time given? */ |
/* lease time given? */ |
409 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_LEASE_TIME); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME); |
410 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
|
{ |
|
411 |
/* remember offered lease time */ |
/* remember offered lease time */ |
412 |
state->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); |
dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); |
|
/* calculate safe periods for renewal and rebinding */ |
|
|
state->offered_t1_renew = state->offered_t0_lease / 2; |
|
|
state->offered_t2_rebind = state->offered_t0_lease; |
|
413 |
} |
} |
414 |
/* renewal period given? */ |
/* renewal period given? */ |
415 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_T1); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1); |
416 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
|
{ |
|
417 |
/* remember given renewal period */ |
/* remember given renewal period */ |
418 |
state->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); |
dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); |
419 |
|
} else { |
420 |
|
/* calculate safe periods for renewal */ |
421 |
|
dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; |
422 |
} |
} |
423 |
|
|
424 |
/* renewal period given? */ |
/* renewal period given? */ |
425 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_T2); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2); |
426 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
|
{ |
|
427 |
/* remember given rebind period */ |
/* remember given rebind period */ |
428 |
state->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); |
dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); |
429 |
|
} else { |
430 |
|
/* calculate safe periods for rebinding */ |
431 |
|
dhcp->offered_t2_rebind = dhcp->offered_t0_lease; |
432 |
} |
} |
433 |
|
|
434 |
/* (y)our internet address */ |
/* (y)our internet address */ |
435 |
ip_addr_set(&state->offered_ip_addr, &state->msg_in->yiaddr); |
ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr); |
436 |
|
|
437 |
/* subnet mask */ |
/* subnet mask */ |
438 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_SUBNET_MASK); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK); |
439 |
/* subnet mask given? */ |
/* subnet mask given? */ |
440 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
441 |
{ |
dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
state->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
442 |
} |
} |
443 |
|
|
444 |
/* gateway router */ |
/* gateway router */ |
445 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_ROUTER); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER); |
446 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
447 |
{ |
dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
state->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
448 |
} |
} |
449 |
|
|
450 |
/* broadcast address */ |
/* broadcast address */ |
451 |
option_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_BROADCAST); |
option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST); |
452 |
if (option_ptr != NULL) |
if (option_ptr != NULL) { |
453 |
{ |
dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
state->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); |
|
454 |
} |
} |
455 |
} |
} |
456 |
|
|
|
|
|
|
/** |
|
|
* Initialize DHCP. |
|
|
* |
|
|
* Must be called prior to any other dhcp_*() function. |
|
|
* |
|
|
*/ |
|
|
void dhcp_init(void) |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_init()")); |
|
|
/* this would be the proper way to stop all dhcp clients */ |
|
|
/* but we need lwIP to be running at this point */ |
|
|
/* while(client_list) dhcp_stop(client_list); */ |
|
|
client_list = NULL; |
|
|
} |
|
|
|
|
457 |
/** |
/** |
458 |
* Start DHCP negotiation for a network interface. |
* Start DHCP negotiation for a network interface. |
459 |
* |
* |
468 |
* (due to unavailable memory or network resources). |
* (due to unavailable memory or network resources). |
469 |
* |
* |
470 |
*/ |
*/ |
471 |
struct dhcp_state *dhcp_start(struct netif *netif) |
struct dhcp *dhcp_start(struct netif *netif) |
472 |
{ |
{ |
473 |
struct dhcp_state *state = NULL; |
struct dhcp *dhcp = netif->dhcp; |
|
struct dhcp_state *list_state = client_list; |
|
474 |
err_t result = ERR_OK; |
err_t result = ERR_OK; |
475 |
|
|
476 |
DEBUGF(DHCP_DEBUG, ("dhcp_start()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_start(netif=%c%c%u)", netif->, netif->, netif->num)); |
477 |
|
|
478 |
/* find the DHCP client attached to the given interface */ |
if (dhcp == NULL) { |
479 |
state = dhcp_find_client(netif); |
DEBUGF(DHCP_DEBUG, ("dhcp_start(): starting new DHCP client")); |
480 |
DEBUGF(DHCP_DEBUG, ("dhcp_start(): finished parsing through list")); |
dhcp = mem_malloc(sizeof(struct dhcp)); |
481 |
/* a DHCP client already attached to this interface? */ |
if (dhcp == NULL) { |
482 |
if (state != NULL) |
DEBUGF(DHCP_DEBUG, ("dhcp_start(): could not allocate dhcp")); |
483 |
{ |
netif->flags &= ~NETIF_FLAG_DHCP; |
484 |
DEBUGF(DHCP_DEBUG, ("dhcp_start(): already active on interface")); |
return ERR_MEM; |
|
/* just restart the DHCP negotiation */ |
|
|
result = dhcp_discover(state); |
|
|
if (result == ERR_OK) |
|
|
{ |
|
|
return state; |
|
485 |
} |
} |
486 |
else |
/* clear data structure */ |
487 |
{ |
memset(dhcp, 0, sizeof(struct dhcp)); |
488 |
dhcp_stop(state); |
DEBUGF(DHCP_DEBUG, ("dhcp_start(): allocated dhcp")); |
489 |
return NULL; |
dhcp->pcb = udp_new(); |
490 |
|
if (dhcp->pcb == NULL) { |
491 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): could not obtain pcb")); |
492 |
|
mem_free((void *)dhcp); |
493 |
|
dhcp = NULL; |
494 |
|
netif->flags &= ~NETIF_FLAG_DHCP; |
495 |
|
return ERR_MEM; |
496 |
} |
} |
497 |
|
/* store this dhcp client in the netif */ |
498 |
|
netif->dhcp = dhcp; |
499 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): created new udp pcb")); |
500 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): starting DHCP configuration")); |
501 |
|
} else { |
502 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): restarting DHCP configuration")); |
503 |
|
} |
504 |
|
/* (re)start the DHCP negotiation */ |
505 |
|
result = dhcp_discover(netif); |
506 |
|
if (result != ERR_OK) { |
507 |
|
/* free resources allocated above */ |
508 |
|
dhcp_stop(netif); |
509 |
} |
} |
510 |
|
return result; |
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): starting new DHCP client")); |
|
|
state = mem_malloc(sizeof(struct dhcp_state)); |
|
|
if (state == NULL) |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): could not allocate dhcp_state")); |
|
|
return NULL; |
|
|
} |
|
|
memset(state, 0, sizeof(struct dhcp_state)); |
|
|
|
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): allocated dhcp_state")); |
|
|
state->pcb = udp_new(); |
|
|
if (state->pcb == NULL) { |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): could not obtain pcb")); |
|
|
mem_free((void *)state); |
|
|
state = NULL; |
|
|
return NULL; |
|
|
} |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_start(): created new udp pcb")); |
|
|
state->netif = netif; |
|
|
/* enqueue in list of clients */ |
|
|
/* we are last in list */ |
|
|
state->next = NULL; |
|
|
/* empty list? */ |
|
|
if (client_list == NULL) |
|
|
{ |
|
|
/* single item at head of list */ |
|
|
client_list = state; |
|
|
} |
|
|
else |
|
|
{ |
|
|
/* proceed to the last DHCP client state */ |
|
|
while (list_state->next != NULL) list_state = list_state->next; |
|
|
list_state->next = state; |
|
|
} |
|
|
dhcp_discover(state); |
|
|
return state; |
|
511 |
} |
} |
512 |
|
|
513 |
/** |
/** |
522 |
*/ |
*/ |
523 |
void dhcp_inform(struct netif *netif) |
void dhcp_inform(struct netif *netif) |
524 |
{ |
{ |
525 |
struct dhcp_state *state = NULL; |
struct dhcp *dhcp; |
526 |
err_t result = ERR_OK; |
err_t result = ERR_OK; |
527 |
state = mem_malloc(sizeof(struct dhcp_state)); |
dhcp = mem_malloc(sizeof(struct dhcp)); |
528 |
if (state == NULL) |
if (dhcp == NULL) { |
529 |
{ |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): could not allocate dhcp")); |
|
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): could not allocate dhcp_state")); |
|
530 |
return; |
return; |
531 |
} |
} |
532 |
memset(state, 0, sizeof(struct dhcp_state)); |
memset(dhcp, 0, sizeof(struct dhcp)); |
533 |
|
|
534 |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): allocated dhcp_state")); |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): allocated dhcp")); |
535 |
state->pcb = udp_new(); |
dhcp->pcb = udp_new(); |
536 |
if (state->pcb == NULL) { |
if (dhcp->pcb == NULL) { |
537 |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): could not obtain pcb")); |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): could not obtain pcb")); |
538 |
mem_free((void *)state); |
mem_free((void *)dhcp); |
539 |
return; |
return; |
540 |
} |
} |
541 |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): created new udp pcb")); |
DEBUGF(DHCP_DEBUG, ("dhcp_inform(): created new udp pcb")); |
|
state->netif = netif; |
|
|
/* we are last in list */ |
|
|
state->next = NULL; |
|
542 |
/* create and initialize the DHCP message header */ |
/* create and initialize the DHCP message header */ |
543 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
544 |
if (result == ERR_OK) |
if (result == ERR_OK) { |
|
{ |
|
545 |
|
|
546 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
547 |
dhcp_option_byte(state, DHCP_INFORM); |
dhcp_option_byte(dhcp, DHCP_INFORM); |
548 |
|
|
549 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
550 |
dhcp_option_short(state, 576); |
/* TODO: use netif->mtu ?! */ |
551 |
|
dhcp_option_short(dhcp, 576); |
552 |
|
|
553 |
dhcp_option_trailer(state); |
dhcp_option_trailer(dhcp); |
554 |
|
|
555 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
556 |
|
|
557 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
558 |
udp_connect(state->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
559 |
udp_send(state->pcb, state->p_out); |
udp_send(dhcp->pcb, dhcp->p_out); |
560 |
udp_connect(state->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
561 |
dhcp_delete_request(state); |
dhcp_delete_request(dhcp); |
562 |
} |
} |
563 |
|
|
564 |
if (state != NULL) |
if (dhcp != NULL) |
565 |
{ |
{ |
566 |
if (state->pcb != NULL) udp_remove(state->pcb); |
if (dhcp->pcb != NULL) udp_remove(dhcp->pcb); |
567 |
state->pcb = NULL; |
dhcp->pcb = NULL; |
568 |
mem_free((void *)state); |
mem_free((void *)dhcp); |
569 |
} |
} |
570 |
} |
} |
571 |
|
|
576 |
* @param addr The IP address we received a reply from |
* @param addr The IP address we received a reply from |
577 |
* |
* |
578 |
*/ |
*/ |
579 |
void dhcp_arp_reply(struct ip_addr *addr) |
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr) |
580 |
{ |
{ |
581 |
struct dhcp_state *list_state = client_list; |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply()")); |
582 |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply()")); |
/* is this DHCP client doing an ARP check? */ |
583 |
/* loop through clients */ |
if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { |
584 |
while (list_state != NULL) |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08lx", addr->addr)); |
585 |
{ |
/* did a host respond with the address we |
586 |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): list_state %p", list_state)); |
were offered by the DHCP server? */ |
587 |
/* is this DHCP client doing an ARP check? */ |
if (ip_addr_cmp(addr, &dhcp->offered_ip_addr)) { |
588 |
if (list_state->state == DHCP_CHECKING) |
/* we will not accept the offered address */ |
589 |
{ |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): arp reply matched with offered address, declining")); |
590 |
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08lx", addr->addr)); |
dhcp_decline(netif); |
|
/* does a host respond with the address we |
|
|
were offered by the DHCP server? */ |
|
|
if (ip_addr_cmp(addr, &list_state->offered_ip_addr)) |
|
|
{ |
|
|
/* we will not accept the offered address */ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): arp reply matched with offered address, declining")); |
|
|
dhcp_decline(list_state); |
|
|
} |
|
591 |
} |
} |
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_arp_reply(): NOT CHECKING")); |
|
|
} |
|
|
/* proceed to next timer */ |
|
|
list_state = list_state->next; |
|
592 |
} |
} |
593 |
} |
} |
594 |
|
|
599 |
* One reason to decline the lease is when we find out the address |
* One reason to decline the lease is when we find out the address |
600 |
* is already in use by another host (through ARP). |
* is already in use by another host (through ARP). |
601 |
*/ |
*/ |
602 |
static err_t dhcp_decline(struct dhcp_state *state) |
static err_t dhcp_decline(struct netif *netif) |
603 |
{ |
{ |
604 |
|
struct dhcp *dhcp = netif->dhcp; |
605 |
err_t result = ERR_OK; |
err_t result = ERR_OK; |
606 |
u16_t msecs; |
u16_t msecs; |
607 |
DEBUGF(DHCP_DEBUG, ("dhcp_decline()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_decline()")); |
608 |
dhcp_set_state(state, DHCP_BACKING_OFF); |
dhcp_set_state(dhcp, DHCP_BACKING_OFF); |
609 |
/* create and initialize the DHCP message header */ |
/* create and initialize the DHCP message header */ |
610 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
611 |
if (result == ERR_OK) |
if (result == ERR_OK) |
612 |
{ |
{ |
613 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
614 |
dhcp_option_byte(state, DHCP_DECLINE); |
dhcp_option_byte(dhcp, DHCP_DECLINE); |
615 |
|
|
616 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
617 |
dhcp_option_short(state, 576); |
dhcp_option_short(dhcp, 576); |
618 |
|
|
619 |
dhcp_option_trailer(state); |
dhcp_option_trailer(dhcp); |
620 |
// resize pbuf to reflect true size of options |
/* resize pbuf to reflect true size of options */ |
621 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
622 |
|
|
623 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
624 |
udp_connect(state->pcb, &state->server_ip_addr, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); |
625 |
udp_send(state->pcb, state->p_out); |
udp_send(dhcp->pcb, dhcp->p_out); |
626 |
dhcp_delete_request(state); |
dhcp_delete_request(dhcp); |
627 |
} |
} |
628 |
state->tries++; |
dhcp->tries++; |
629 |
msecs = 10*1000; |
msecs = 10*1000; |
630 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
631 |
DEBUGF(DHCP_DEBUG, ("dhcp_decline(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_decline(): set request timeout %u msecs", msecs)); |
632 |
return result; |
return result; |
633 |
} |
} |
638 |
* Start the DHCP process, discover a DHCP server. |
* Start the DHCP process, discover a DHCP server. |
639 |
* |
* |
640 |
*/ |
*/ |
641 |
static err_t dhcp_discover(struct dhcp_state *state) |
static err_t dhcp_discover(struct netif *netif) |
642 |
{ |
{ |
643 |
|
struct dhcp *dhcp = netif->dhcp; |
644 |
err_t result = ERR_OK; |
err_t result = ERR_OK; |
645 |
u16_t msecs; |
u16_t msecs; |
646 |
DEBUGF(DHCP_DEBUG, ("dhcp_discover()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_discover()")); |
647 |
ip_addr_set(&state->offered_ip_addr, IP_ADDR_ANY); |
ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY); |
648 |
// create and initialize the DHCP message header |
/* create and initialize the DHCP message header */ |
649 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
650 |
if (result == ERR_OK) |
if (result == ERR_OK) |
651 |
{ |
{ |
652 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
653 |
dhcp_option_byte(state, DHCP_DISCOVER); |
dhcp_option_byte(dhcp, DHCP_DISCOVER); |
654 |
|
|
655 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
656 |
dhcp_option_short(state, 576); |
dhcp_option_short(dhcp, 576); |
657 |
|
|
658 |
dhcp_option(state, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3); |
dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 3); |
659 |
dhcp_option_byte(state, DHCP_OPTION_SUBNET_MASK); |
dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); |
660 |
dhcp_option_byte(state, DHCP_OPTION_ROUTER); |
dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); |
661 |
dhcp_option_byte(state, DHCP_OPTION_BROADCAST); |
dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); |
662 |
|
|
663 |
dhcp_option_trailer(state); |
dhcp_option_trailer(dhcp); |
664 |
|
|
665 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
666 |
|
|
667 |
udp_recv(state->pcb, dhcp_recv, state); |
/* set receive callback function with netif as user data */ |
668 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_recv(dhcp->pcb, dhcp_recv, netif); |
669 |
udp_connect(state->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
670 |
|
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
671 |
udp_send(state->pcb, state->p_out); |
|
672 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_send(dhcp->pcb, dhcp->p_out); |
673 |
udp_connect(state->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
674 |
dhcp_delete_request(state); |
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
675 |
} |
dhcp_delete_request(dhcp); |
676 |
state->tries++; |
} |
677 |
msecs = state->tries < 4 ? (state->tries + 1) * 1000 : 10 * 1000; |
dhcp->tries++; |
678 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000; |
679 |
|
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
680 |
DEBUGF(DHCP_DEBUG, ("dhcp_discover(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_discover(): set request timeout %u msecs", msecs)); |
681 |
dhcp_set_state(state, DHCP_SELECTING); |
dhcp_set_state(dhcp, DHCP_SELECTING); |
682 |
return result; |
return result; |
683 |
} |
} |
684 |
|
|
686 |
/** |
/** |
687 |
* Bind the interface to the offered IP address. |
* Bind the interface to the offered IP address. |
688 |
* |
* |
689 |
|
* @param netif network interface to bind to the offered address |
690 |
*/ |
*/ |
691 |
static void dhcp_bind(struct dhcp_state *state) |
static void dhcp_bind(struct netif *netif) |
692 |
{ |
{ |
693 |
|
struct dhcp *dhcp = netif->dhcp; |
694 |
struct ip_addr sn_mask, gw_addr; |
struct ip_addr sn_mask, gw_addr; |
695 |
dhcp_set_state(state, DHCP_BOUND); |
|
696 |
/* temporary DHCP lease? */ |
/* temporary DHCP lease? */ |
697 |
if (state->offered_t1_renew != 0xffffffffUL) { |
if (dhcp->offered_t1_renew != 0xffffffffUL) { |
698 |
/* set renewal period timer */ |
/* set renewal period timer */ |
699 |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): t1 renewal timer %lu secs", state->offered_t1_renew)); |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): t1 renewal timer %lu secs", dhcp->offered_t1_renew)); |
700 |
state->t1_timeout = (state->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
dhcp->t1_timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
701 |
if (state->t1_timeout == 0) state->t1_timeout = 1; |
if (dhcp->t1_timeout == 0) dhcp->t1_timeout = 1; |
702 |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): set request timeout %u msecs", state->offered_t1_renew*1000)); |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): set request timeout %u msecs", dhcp->offered_t1_renew*1000)); |
703 |
} |
} |
704 |
/* set renewal period timer */ |
/* set renewal period timer */ |
705 |
if (state->offered_t2_rebind != 0xffffffffUL) |
if (dhcp->offered_t2_rebind != 0xffffffffUL) { |
706 |
{ |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): t2 rebind timer %lu secs", dhcp->offered_t2_rebind)); |
707 |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): t2 rebind timer %lu secs", state->offered_t2_rebind)); |
dhcp->t2_timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
708 |
state->t2_timeout = (state->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; |
if (dhcp->t2_timeout == 0) dhcp->t2_timeout = 1; |
709 |
if (state->t2_timeout == 0) state->t2_timeout = 1; |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): set request timeout %u msecs", dhcp->offered_t2_rebind*1000)); |
|
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): set request timeout %u msecs", state->offered_t2_rebind*1000)); |
|
710 |
} |
} |
711 |
|
/* copy offered network mask */ |
712 |
ip_addr_set(&sn_mask, &state->offered_sn_mask); |
ip_addr_set(&sn_mask, &dhcp->offered_sn_mask); |
713 |
|
|
714 |
/* subnet mask not given? */ |
/* subnet mask not given? */ |
715 |
/* TODO: this is not a valid check. what if the network mask is 0??!! */ |
/* TODO: this is not a valid check. what if the network mask is 0??!! */ |
716 |
if (sn_mask.addr == 0) |
if (sn_mask.addr == 0) { |
|
{ |
|
717 |
/* choose a safe subnet mask given the network class */ |
/* choose a safe subnet mask given the network class */ |
718 |
u8_t first_octet = ip4_addr1(&sn_mask); |
u8_t first_octet = ip4_addr1(&sn_mask); |
719 |
if (first_octet <= 127) sn_mask.addr = htonl(0xff000000); |
if (first_octet <= 127) sn_mask.addr = htonl(0xff000000); |
720 |
else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00); |
else if (first_octet >= 192) sn_mask.addr = htonl(0xffffff00); |
721 |
else sn_mask.addr = htonl(0xffff0000); |
else sn_mask.addr = htonl(0xffff0000); |
722 |
} |
} |
|
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): SN: 0x%08lx", sn_mask.addr)); |
|
|
netif_set_netmask(state->netif, &sn_mask); |
|
723 |
|
|
724 |
ip_addr_set(&gw_addr, &state->offered_gw_addr); |
ip_addr_set(&gw_addr, &dhcp->offered_gw_addr); |
725 |
/* gateway address not given? */ |
/* gateway address not given? */ |
726 |
if (gw_addr.addr == 0) |
if (gw_addr.addr == 0) { |
727 |
{ |
/* copy network address */ |
728 |
gw_addr.addr &= sn_mask.addr; |
gw_addr.addr = (&dhcp->offered_ip_addr & sn_mask.addr); |
729 |
gw_addr.addr |= 0x01000000; |
/* use first host address on network as gateway */ |
730 |
|
gw_addr.addr |= htonl(0x00000001); |
731 |
} |
} |
|
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): GW: 0x%08lx", gw_addr.addr)); |
|
|
netif_set_gw(state->netif, &gw_addr); |
|
732 |
|
|
733 |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): IP: 0x%08lx", state->offered_ip_addr.addr)); |
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): IP: 0x%08lx", dhcp->offered_ip_addr.addr)); |
734 |
netif_set_ipaddr(state->netif, &state->offered_ip_addr); |
netif_set_ipaddr(netif, &dhcp->offered_ip_addr); |
735 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): SN: 0x%08lx", sn_mask.addr)); |
736 |
|
netif_set_netmask(netif, &sn_mask); |
737 |
|
DEBUGF(DHCP_DEBUG, ("dhcp_bind(): GW: 0x%08lx", gw_addr.addr)); |
738 |
|
netif_set_gw(netif, &gw_addr); |
739 |
|
/* netif is now bound to DHCP leased address */ |
740 |
|
dhcp_set_state(dhcp, DHCP_BOUND); |
741 |
} |
} |
742 |
|
|
743 |
/** |
/** |
744 |
* Renew an existing DHCP lease at the involved DHCP server. |
* Renew an existing DHCP lease at the involved DHCP server. |
745 |
* |
* |
746 |
|
* @param netif network interface which must renew its lease |
747 |
*/ |
*/ |
748 |
err_t dhcp_renew(struct dhcp_state *state) |
err_t dhcp_renew(struct netif *netif) |
749 |
{ |
{ |
750 |
|
struct dhcp *dhcp = netif->dhcp; |
751 |
err_t result; |
err_t result; |
752 |
u16_t msecs; |
u16_t msecs; |
753 |
DEBUGF(DHCP_DEBUG, ("dhcp_renew()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_renew()")); |
754 |
dhcp_set_state(state, DHCP_RENEWING); |
dhcp_set_state(dhcp, DHCP_RENEWING); |
755 |
|
|
756 |
// create and initialize the DHCP message header |
/* create and initialize the DHCP message header */ |
757 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
758 |
if (result == ERR_OK) |
if (result == ERR_OK) { |
|
{ |
|
759 |
|
|
760 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
761 |
dhcp_option_byte(state, DHCP_REQUEST); |
dhcp_option_byte(dhcp, DHCP_REQUEST); |
762 |
|
|
763 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
764 |
dhcp_option_short(state, 576); |
/* TODO: use netif->mtu in some way */ |
765 |
|
dhcp_option_short(dhcp, 576); |
766 |
|
|
767 |
#if 0 |
#if 0 |
768 |
dhcp_option(state, DHCP_OPTION_REQUESTED_IP, 4); |
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); |
769 |
dhcp_option_long(state, ntohl(state->offered_ip_addr.addr)); |
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); |
770 |
#endif |
#endif |
771 |
|
|
772 |
#if 0 |
#if 0 |
773 |
dhcp_option(state, DHCP_OPTION_SERVER_ID, 4); |
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); |
774 |
dhcp_option_long(state, ntohl(state->server_ip_addr.addr)); |
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); |
775 |
#endif |
#endif |
776 |
|
/* append DHCP message trailer */ |
777 |
|
dhcp_option_trailer(dhcp); |
778 |
|
|
779 |
dhcp_option_trailer(state); |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
|
|
|
|
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
|
780 |
|
|
781 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
782 |
udp_connect(state->pcb, &state->server_ip_addr, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); |
783 |
udp_send(state->pcb, state->p_out); |
udp_send(dhcp->pcb, dhcp->p_out); |
784 |
dhcp_delete_request(state); |
dhcp_delete_request(dhcp); |
785 |
} |
} |
786 |
state->tries++; |
dhcp->tries++; |
787 |
// back-off on retries, but to a maximum of 20 seconds |
/* back-off on retries, but to a maximum of 20 seconds */ |
788 |
msecs = state->tries < 10 ? state->tries * 2000 : 20 * 1000; |
msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; |
789 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
790 |
DEBUGF(DHCP_DEBUG, ("dhcp_renew(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_renew(): set request timeout %u msecs", msecs)); |
791 |
return result; |
return result; |
792 |
} |
} |
794 |
/** |
/** |
795 |
* Rebind with a DHCP server for an existing DHCP lease. |
* Rebind with a DHCP server for an existing DHCP lease. |
796 |
* |
* |
797 |
|
* @param netif network interface which must rebind with a DHCP server |
798 |
*/ |
*/ |
799 |
static err_t dhcp_rebind(struct dhcp_state *state) |
static err_t dhcp_rebind(struct netif *netif) |
800 |
{ |
{ |
801 |
|
struct dhcp *dhcp = netif->dhcp; |
802 |
err_t result; |
err_t result; |
803 |
u16_t msecs; |
u16_t msecs; |
804 |
DEBUGF(DHCP_DEBUG, ("dhcp_rebind()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_rebind()")); |
805 |
dhcp_set_state(state, DHCP_REBINDING); |
dhcp_set_state(dhcp, DHCP_REBINDING); |
806 |
|
|
807 |
// create and initialize the DHCP message header |
/* create and initialize the DHCP message header */ |
808 |
result = dhcp_create_request(state); |
result = dhcp_create_request(dhcp); |
809 |
if (result == ERR_OK) |
if (result == ERR_OK) |
810 |
{ |
{ |
811 |
|
|
812 |
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
813 |
dhcp_option_byte(state, DHCP_REQUEST); |
dhcp_option_byte(dhcp, DHCP_REQUEST); |
814 |
|
|
815 |
dhcp_option(state, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); |
816 |
dhcp_option_short(state, 576); |
dhcp_option_short(dhcp, 576); |
817 |
|
|
818 |
#if 0 |
#if 0 |
819 |
dhcp_option(state, DHCP_OPTION_REQUESTED_IP, 4); |
dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); |
820 |
dhcp_option_long(state, ntohl(state->offered_ip_addr.addr)); |
dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); |
821 |
|
|
822 |
dhcp_option(state, DHCP_OPTION_SERVER_ID, 4); |
dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); |
823 |
dhcp_option_long(state, ntohl(state->server_ip_addr.addr)); |
dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); |
824 |
#endif |
#endif |
825 |
|
|
826 |
dhcp_option_trailer(state); |
dhcp_option_trailer(dhcp); |
827 |
|
|
828 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
829 |
|
|
830 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
831 |
udp_connect(state->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); |
832 |
udp_send(state->pcb, state->p_out); |
udp_send(dhcp->pcb, dhcp->p_out); |
833 |
udp_connect(state->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); |
834 |
dhcp_delete_request(state); |
dhcp_delete_request(dhcp); |
835 |
} |
} |
836 |
state->tries++; |
dhcp->tries++; |
837 |
msecs = state->tries < 10 ? state->tries * 1000 : 10 * 1000; |
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; |
838 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
839 |
DEBUGF(DHCP_DEBUG, ("dhcp_rebind(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_rebind(): set request timeout %u msecs", msecs)); |
840 |
return result; |
return result; |
841 |
} |
} |
842 |
|
|
843 |
/** |
/** |
844 |
* Rebind with a DHCP server for an existing DHCP lease. |
* Release a DHCP lease. |
845 |
* |
* |
846 |
|
* @param netif network interface which must release its lease |
847 |
*/ |
*/ |
848 |
static err_t dhcp_release(struct dhcp_state *state) |
static err_t dhcp_release(struct netif *netif) |
849 |
{ |
{ |
850 |
|
struct dhcp *dhcp = netif->dhcp; |
851 |
err_t result; |
err_t result; |
852 |
u16_t msecs; |
u16_t msecs; |
853 |
DEBUGF(DHCP_DEBUG, ("dhcp_release()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_release()")); |
854 |
// and idle DHCP client |
/* idle DHCP client */ |
855 |
dhcp_set_state(state, DHCP_OFF); |
dhcp_set_state(dhcp, DHCP_OFF); |
|
|
|
|
// create and initialize the DHCP message header |
|
|
result = dhcp_create_request(state); |
|
|
if (result == ERR_OK) |
|
|
{ |
|
|
dhcp_option(state, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
|
|
dhcp_option_byte(state, DHCP_RELEASE); |
|
856 |
|
|
857 |
dhcp_option_trailer(state); |
/* create and initialize the DHCP message header */ |
858 |
|
result = dhcp_create_request(dhcp); |
859 |
pbuf_realloc(state->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + state->options_out_len); |
if (result == ERR_OK) { |
860 |
|
dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); |
861 |
udp_bind(state->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
dhcp_option_byte(dhcp, DHCP_RELEASE); |
862 |
udp_connect(state->pcb, &state->server_ip_addr, DHCP_SERVER_PORT); |
|
863 |
udp_send(state->pcb, state->p_out); |
dhcp_option_trailer(dhcp); |
864 |
dhcp_delete_request(state); |
|
865 |
} |
pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); |
866 |
state->tries++; |
|
867 |
msecs = state->tries < 10 ? state->tries * 1000 : 10 * 1000; |
udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); |
868 |
state->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); |
869 |
|
udp_send(dhcp->pcb, dhcp->p_out); |
870 |
|
dhcp_delete_request(dhcp); |
871 |
|
} |
872 |
|
dhcp->tries++; |
873 |
|
msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; |
874 |
|
dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; |
875 |
DEBUGF(DHCP_DEBUG, ("dhcp_release(): set request timeout %u msecs", msecs)); |
DEBUGF(DHCP_DEBUG, ("dhcp_release(): set request timeout %u msecs", msecs)); |
876 |
// remove IP address from interface |
/* remove IP address from interface */ |
877 |
netif_set_ipaddr(state->netif, IP_ADDR_ANY); |
netif_set_ipaddr(netif, IP_ADDR_ANY); |
878 |
netif_set_gw(state->netif, IP_ADDR_ANY); |
netif_set_gw(netif, IP_ADDR_ANY); |
879 |
netif_set_netmask(state->netif, IP_ADDR_ANY); |
netif_set_netmask(netif, IP_ADDR_ANY); |
880 |
|
/* TODO: netif_down(netif); */ |
881 |
return result; |
return result; |
882 |
} |
} |
883 |
/** |
/** |
884 |
* Remove the DHCP client from the interface. |
* Remove the DHCP client from the interface. |
885 |
* |
* |
886 |
* @param state The DHCP client state |
* @param netif The network interface to stop DHCP on |
887 |
*/ |
*/ |
888 |
void dhcp_stop(struct dhcp_state *state) |
void dhcp_stop(struct netif *netif) |
889 |
{ |
{ |
890 |
struct dhcp_state *list_state = client_list; |
struct dhcp *dhcp = netif->dhcp; |
891 |
DEBUGF(DHCP_DEBUG, ("dhcp_stop()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_stop()")); |
892 |
LWIP_ASSERT("dhcp_stop: state != NULL", state != NULL); |
LWIP_ASSERT("dhcp_stop: dhcp != NULL", dhcp != NULL); |
893 |
LWIP_ASSERT("dhcp_stop: state->pcb != NULL", state->pcb != NULL); |
LWIP_ASSERT("dhcp_stop: dhcp->pcb != NULL", dhcp->pcb != NULL); |
894 |
|
/* netif is DHCP configured? */ |
895 |
if (state != NULL) |
if (dhcp != NULL) |
896 |
{ |
{ |
897 |
if (state->pcb != NULL) |
if (dhcp->pcb != NULL) |
898 |
{ |
{ |
899 |
udp_remove(state->pcb); |
udp_remove(dhcp->pcb); |
900 |
state->pcb = NULL; |
dhcp->pcb = NULL; |
901 |
} |
} |
902 |
if (state->p != NULL) |
if (dhcp->p != NULL) |
903 |
{ |
{ |
904 |
pbuf_free(state->p); |
pbuf_free(dhcp->p); |
905 |
state->p = NULL; |
dhcp->p = NULL; |
|
} |
|
|
mem_free((void *)state); |
|
|
// at head of list? |
|
|
if (list_state == state) |
|
|
{ |
|
|
// remove ourselves from head |
|
|
client_list = state->next; |
|
|
} |
|
|
// not at head |
|
|
else |
|
|
{ |
|
|
// see if we can find a predecessor? |
|
|
while ((list_state != NULL) && (list_state->next != state)) |
|
|
{ |
|
|
// proceed to next state, if any |
|
|
list_state = list_state->next; |
|
|
} |
|
|
// found a predecessor? |
|
|
if (list_state != NULL) |
|
|
{ |
|
|
// remove ourselves from list |
|
|
list_state->next = state->next; |
|
|
} |
|
906 |
} |
} |
907 |
|
mem_free((void *)dhcp); |
908 |
|
netif->dhcp = NULL; |
909 |
} |
} |
910 |
} |
} |
911 |
|
|
916 |
* |
* |
917 |
* TODO: we might also want to reset the timeout here? |
* TODO: we might also want to reset the timeout here? |
918 |
*/ |
*/ |
919 |
static void dhcp_set_state(struct dhcp_state *state, unsigned char new_state) |
static void dhcp_set_state(struct dhcp *dhcp, unsigned char new_state) |
920 |
{ |
{ |
921 |
if (new_state != state->state) |
if (new_state != dhcp->state) |
922 |
{ |
{ |
923 |
state->state = new_state; |
dhcp->state = new_state; |
924 |
state->tries = 0; |
dhcp->tries = 0; |
925 |
} |
} |
926 |
} |
} |
927 |
|
|
930 |
* DHCP message. |
* DHCP message. |
931 |
* |
* |
932 |
*/ |
*/ |
933 |
static void dhcp_option(struct dhcp_state *state, u8_t option_type, u8_t option_len) |
static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) |
934 |
{ |
{ |
935 |
LWIP_ASSERT("dhcp_option_short: state->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", state->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN); |
LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN); |
936 |
state->msg_out->options[state->options_out_len++] = option_type; |
dhcp->msg_out->options[dhcp->options_out_len++] = option_type; |
937 |
state->msg_out->options[state->options_out_len++] = option_len; |
dhcp->msg_out->options[dhcp->options_out_len++] = option_len; |
938 |
} |
} |
939 |
/* |
/* |
940 |
* Concatenate a single byte to the outgoing DHCP message. |
* Concatenate a single byte to the outgoing DHCP message. |
941 |
* |
* |
942 |
*/ |
*/ |
943 |
static void dhcp_option_byte(struct dhcp_state *state, u8_t value) |
static void dhcp_option_byte(struct dhcp *dhcp, u8_t value) |
944 |
{ |
{ |
945 |
LWIP_ASSERT("dhcp_option_short: state->options_out_len < DHCP_OPTIONS_LEN", state->options_out_len < DHCP_OPTIONS_LEN); |
LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); |
946 |
state->msg_out->options[state->options_out_len++] = value; |
dhcp->msg_out->options[dhcp->options_out_len++] = value; |
947 |
} |
} |
948 |
static void dhcp_option_short(struct dhcp_state *state, u16_t value) |
static void dhcp_option_short(struct dhcp *dhcp, u16_t value) |
949 |
{ |
{ |
950 |
LWIP_ASSERT("dhcp_option_short: state->options_out_len + 2 <= DHCP_OPTIONS_LEN", state->options_out_len + 2 <= DHCP_OPTIONS_LEN); |
LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN); |
951 |
state->msg_out->options[state->options_out_len++] = (value & 0xff00U) >> 8; |
dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff00U) >> 8; |
952 |
state->msg_out->options[state->options_out_len++] = value & 0x00ffU; |
dhcp->msg_out->options[dhcp->options_out_len++] = value & 0x00ffU; |
953 |
} |
} |
954 |
static void dhcp_option_long(struct dhcp_state *state, u32_t value) |
static void dhcp_option_long(struct dhcp *dhcp, u32_t value) |
955 |
{ |
{ |
956 |
LWIP_ASSERT("dhcp_option_long: state->options_out_len + 4 <= DHCP_OPTIONS_LEN", state->options_out_len + 4 <= DHCP_OPTIONS_LEN); |
LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN); |
957 |
state->msg_out->options[state->options_out_len++] = (value & 0xff000000UL) >> 24; |
dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0xff000000UL) >> 24; |
958 |
state->msg_out->options[state->options_out_len++] = (value & 0x00ff0000UL) >> 16; |
dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x00ff0000UL) >> 16; |
959 |
state->msg_out->options[state->options_out_len++] = (value & 0x0000ff00UL) >> 8; |
dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x0000ff00UL) >> 8; |
960 |
state->msg_out->options[state->options_out_len++] = (value & 0x000000ffUL); |
dhcp->msg_out->options[dhcp->options_out_len++] = (value & 0x000000ffUL); |
961 |
} |
} |
962 |
|
|
963 |
/** |
/** |
966 |
* |
* |
967 |
* |
* |
968 |
*/ |
*/ |
969 |
static err_t dhcp_unfold_reply(struct dhcp_state *state) |
static err_t dhcp_unfold_reply(struct dhcp *dhcp) |
970 |
{ |
{ |
971 |
struct pbuf *p = state->p; |
struct pbuf *p = dhcp->p; |
972 |
u8_t *ptr; |
u8_t *ptr; |
973 |
u16_t i; |
u16_t i; |
974 |
u16_t j = 0; |
u16_t j = 0; |
975 |
state->msg_in = NULL; |
dhcp->msg_in = NULL; |
976 |
state->options_in = NULL; |
dhcp->options_in = NULL; |
977 |
/* options present? */ |
/* options present? */ |
978 |
if (state->p->tot_len > sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN) |
if (dhcp->p->tot_len > sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN) |
979 |
{ |
{ |
980 |
state->options_in_len = state->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); |
dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); |
981 |
state->options_in = mem_malloc(state->options_in_len); |
dhcp->options_in = mem_malloc(dhcp->options_in_len); |
982 |
if (state->options_in == NULL) |
if (dhcp->options_in == NULL) |
983 |
{ |
{ |
984 |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): could not allocate state->options")); |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): could not allocate dhcp->options")); |
985 |
return ERR_MEM; |
return ERR_MEM; |
986 |
} |
} |
987 |
} |
} |
988 |
state->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); |
dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); |
989 |
if (state->msg_in == NULL) |
if (dhcp->msg_in == NULL) |
990 |
{ |
{ |
991 |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): could not allocate state->msg_in")); |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in")); |
992 |
mem_free((void *)state->options_in); |
mem_free((void *)dhcp->options_in); |
993 |
state->options_in = NULL; |
dhcp->options_in = NULL; |
994 |
return ERR_MEM; |
return ERR_MEM; |
995 |
} |
} |
996 |
|
|
997 |
ptr = (u8_t *)state->msg_in; |
ptr = (u8_t *)dhcp->msg_in; |
998 |
/* proceed through struct dhcp_msg */ |
/* proceed through struct dhcp_msg */ |
999 |
for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++) |
for (i = 0; i < sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN; i++) |
1000 |
{ |
{ |
1007 |
j = 0; |
j = 0; |
1008 |
} |
} |
1009 |
} |
} |
1010 |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): copied %u bytes into state->msg_in[]", i)); |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): copied %u bytes into dhcp->msg_in[]", i)); |
1011 |
if (state->options_in != NULL) |
if (dhcp->options_in != NULL) { |
1012 |
{ |
ptr = (u8_t *)dhcp->options_in; |
|
ptr = (u8_t *)state->options_in; |
|
1013 |
/* proceed through options */ |
/* proceed through options */ |
1014 |
for (i = 0; i < state->options_in_len; i++) |
for (i = 0; i < dhcp->options_in_len; i++) { |
|
{ |
|
1015 |
*ptr++ = ((u8_t *)p->payload)[j++]; |
*ptr++ = ((u8_t *)p->payload)[j++]; |
1016 |
/* reached end of pbuf? */ |
/* reached end of pbuf? */ |
1017 |
if (j == p->len) |
if (j == p->len) { |
|
{ |
|
1018 |
/* proceed to next pbuf in chain */ |
/* proceed to next pbuf in chain */ |
1019 |
p = p->next; |
p = p->next; |
1020 |
j = 0; |
j = 0; |
1021 |
} |
} |
1022 |
} |
} |
1023 |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): copied %u bytes to state->options_in[]", i)); |
DEBUGF(DHCP_DEBUG, ("dhcp_unfold_reply(): copied %u bytes to dhcp->options_in[]", i)); |
1024 |
} |
} |
1025 |
return ERR_OK; |
return ERR_OK; |
1026 |
} |
} |
1030 |
* its DHCP options. |
* its DHCP options. |
1031 |
* |
* |
1032 |
*/ |
*/ |
1033 |
static void dhcp_free_reply(struct dhcp_state *state) |
static void dhcp_free_reply(struct dhcp *dhcp) |
1034 |
{ |
{ |
1035 |
mem_free((void *)state->msg_in); |
if (dhcp->msg_in != NULL) { |
1036 |
mem_free((void *)state->options_in); |
mem_free((void *)dhcp->msg_in); |
1037 |
|
dhcp->msg_in = NULL; |
1038 |
|
} |
1039 |
|
if (dhcp->options_in) { |
1040 |
|
mem_free((void *)dhcp->options_in); |
1041 |
|
dhcp->options_in = NULL; |
1042 |
|
dhcp->options_in_len = 0; |
1043 |
|
} |
1044 |
DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): freed")); |
DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): freed")); |
|
state->msg_in = NULL; |
|
|
state->options_in = NULL; |
|
|
state->options_in_len = 0; |
|
1045 |
} |
} |
1046 |
|
|
1047 |
|
|
1048 |
/** |
/** |
1049 |
* Match incoming DHCP messages against a DHCP client, and trigger its state machine |
* If an incoming DHCP message is in response to use, then trigger the state machine |
1050 |
*/ |
*/ |
1051 |
static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) |
static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) |
1052 |
{ |
{ |
1053 |
struct dhcp_state *state = (struct dhcp_state *)arg; |
struct netif *netif = (struct netif *)arg; |
1054 |
|
struct dhcp *dhcp = netif->dhcp; |
1055 |
struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; |
struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; |
1056 |
|
u8_t *options_ptr; |
1057 |
|
u8_t msg_type; |
1058 |
|
u8_t i; |
1059 |
DEBUGF(DHCP_DEBUG, ("dhcp_recv()")); |
DEBUGF(DHCP_DEBUG, ("dhcp_recv()")); |
1060 |
DEBUGF(DHCP_DEBUG, ("pbuf->len = %u", p->len)); |
DEBUGF(DHCP_DEBUG, ("pbuf->len = %u", p->len)); |
1061 |
DEBUGF(DHCP_DEBUG, ("pbuf->tot_len = %u", p->tot_len)); |
DEBUGF(DHCP_DEBUG, ("pbuf->tot_len = %u", p->tot_len)); |
1062 |
state->p = p; |
dhcp->p = p; |
1063 |
if (reply_msg->op == DHCP_BOOTREPLY) |
if (reply_msg->op != DHCP_BOOTREPLY) { |
1064 |
{ |
DEBUGF(DHCP_DEBUG, ("not a DHCP reply message, but type %u", reply_msg->op)); |
1065 |
DEBUGF(DHCP_DEBUG, ("state->netif->hwaddr = %02x:%02x:%02x:%02x:%02x:%02x", |
pbuf_free(p); |
1066 |
state->netif->hwaddr[0], state->netif->hwaddr[1], state->netif->hwaddr[2], |
} |
1067 |
state->netif->hwaddr[3], state->netif->hwaddr[4], state->netif->hwaddr[5])); |
/* iterate through hardware address and match against DHCP message */ |
1068 |
// TODO: Add multi network interface support, look up the targetted |
for (i = 0; i < netif->hwaddr_len; i++) { |
1069 |
// interface here. |
if (netif->hwaddr[i] != reply_msg->chaddr[i]) { |
1070 |
if ((state->netif->hwaddr[0] == reply_msg->chaddr[0]) && |
DEBUGF(DHCP_DEBUG, ("netif->hwaddr[%u]==%02x != reply_msg->chaddr[%u]==%02x", |
1071 |
(state->netif->hwaddr[1] == reply_msg->chaddr[1]) && |
i, netif->hwaddr[i], i, reply_msg->chaddr[i])); |
1072 |
(state->netif->hwaddr[2] == reply_msg->chaddr[2]) && |
pbuf_free(p); |
1073 |
(state->netif->hwaddr[3] == reply_msg->chaddr[3]) && |
return; |
1074 |
(state->netif->hwaddr[4] == reply_msg->chaddr[4]) && |
} |
1075 |
(state->netif->hwaddr[5] == reply_msg->chaddr[5])) |
} |
1076 |
{ |
/* match transaction ID against what we expected */ |
1077 |
// check if the transaction ID matches |
if (ntohl(reply_msg->xid) != dhcp->xid) { |
1078 |
if (ntohl(reply_msg->xid) == state->xid) |
DEBUGF(DHCP_DEBUG, ("transaction id mismatch")); |
1079 |
{ |
pbuf_free(p); |
1080 |
// option fields could be unfold? |
return; |
1081 |
if (dhcp_unfold_reply(state) == ERR_OK) |
} |
1082 |
{ |
/* option fields could be unfold? */ |
1083 |
u8_t *options_ptr = NULL; |
if (dhcp_unfold_reply(dhcp) != ERR_OK) { |
1084 |
DEBUGF(DHCP_DEBUG, ("searching DHCP_OPTION_MESSAGE_TYPE")); |
DEBUGF(DHCP_DEBUG, ("problem unfolding DHCP message - too short on memory?")); |
1085 |
options_ptr = dhcp_get_option_ptr(state, DHCP_OPTION_MESSAGE_TYPE); |
pbuf_free(p); |
1086 |
if (options_ptr != NULL) |
return; |
1087 |
{ |
} |
1088 |
u8_t msg_type = dhcp_get_option_byte(options_ptr + 2); |
|
1089 |
if (msg_type == DHCP_ACK) |
DEBUGF(DHCP_DEBUG, ("searching DHCP_OPTION_MESSAGE_TYPE")); |
1090 |
{ |
/* obtain pointer to DHCP message type */ |
1091 |
DEBUGF(DHCP_DEBUG, ("DHCP_ACK received")); |
options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE); |
1092 |
if (state->state == DHCP_REQUESTING) |
if (options_ptr == NULL) { |
1093 |
{ |
DEBUGF(DHCP_DEBUG, ("DHCP_OPTION_MESSAGE_TYPE option not found")); |
1094 |
dhcp_handle_ack(state); |
pbuf_free(p); |
1095 |
state->request_timeout = 0; |
return; |
1096 |
|
} |
1097 |
|
|
1098 |
|
/* read DHCP message type */ |
1099 |
|
msg_type = dhcp_get_option_byte(options_ptr + 2); |
1100 |
|
/* message type is DHCP ACK? */ |
1101 |
|
if (msg_type == DHCP_ACK) { |
1102 |
|
DEBUGF(DHCP_DEBUG, ("DHCP_ACK received")); |
1103 |
|
/* in requesting state? */ |
1104 |
|
if (dhcp->state == DHCP_REQUESTING) { |
1105 |
|
dhcp_handle_ack(dhcp); |
1106 |
|
dhcp->request_timeout = 0; |
1107 |
#if DHCP_DOES_ARP_CHECK |
#if DHCP_DOES_ARP_CHECK |
1108 |
dhcp_check(state); |
/* check if the acknowledged lease address is already in use */ |
1109 |
|
dhcp_check(netif); |
1110 |
#else |
#else |
1111 |
dhcp_bind(state); |
/* bind interface to the acknowledged lease address */ |
1112 |
|
dhcp_bind(netif); |
1113 |
#endif |
#endif |
|
} |
|
|
else if ((state->state == DHCP_REBOOTING) || (state->state == DHCP_REBINDING) ||(state->state == DHCP_RENEWING)) |
|
|
{ |
|
|
state->request_timeout = 0; |
|
|
dhcp_bind(state); |
|
|
} |
|
|
} |
|
|
// received a DHCP_NAK in appropriate state? |
|
|
else if ((msg_type == DHCP_NAK) && |
|
|
((state->state == DHCP_REBOOTING) || (state->state == DHCP_REQUESTING) || |
|
|
(state->state == DHCP_REBINDING) || (state->state == DHCP_RENEWING ))) |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("DHCP_NAK received")); |
|
|
state->request_timeout = 0; |
|
|
dhcp_handle_nak(state); |
|
|
} |
|
|
// received a DHCP_OFFER in DHCP_SELECTING state? |
|
|
else if ((msg_type == DHCP_OFFER) && (state->state == DHCP_SELECTING)) |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("DHCP_OFFER received in DHCP_SELECTING state")); |
|
|
state->request_timeout = 0; |
|
|
dhcp_handle_offer(state); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("DHCP_OPTION_MESSAGE_TYPE option not found")); |
|
|
} |
|
|
dhcp_free_reply(state); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("reply_msg->xid=%lx does not match with state->xid=%lx", |
|
|
ntohl(reply_msg->xid), state->xid)); |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("hardware address did not match")); |
|
|
DEBUGF(DHCP_DEBUG, ("reply_msg->chaddr = %02x:%02x:%02x:%02x:%02x:%02x", |
|
|
reply_msg->chaddr[0], reply_msg->chaddr[1], reply_msg->chaddr[2], |
|
|
reply_msg->chaddr[3], reply_msg->chaddr[4], reply_msg->chaddr[5])); |
|
1114 |
} |
} |
1115 |
|
/* already bound to the given lease address? */ |
1116 |
|
else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { |
1117 |
|
dhcp->request_timeout = 0; |
1118 |
|
dhcp_bind(netif); |
1119 |
|
} |
1120 |
|
} |
1121 |
|
/* received a DHCP_NAK in appropriate state? */ |
1122 |
|
else if ((msg_type == DHCP_NAK) && |
1123 |
|
((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || |
1124 |
|
(dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { |
1125 |
|
DEBUGF(DHCP_DEBUG, ("DHCP_NAK received")); |
1126 |
|
dhcp->request_timeout = 0; |
1127 |
|
dhcp_handle_nak(dhcp); |
1128 |
|
} |
1129 |
|
/* received a DHCP_OFFER in DHCP_SELECTING state? */ |
1130 |
|
else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { |
1131 |
|
DEBUGF(DHCP_DEBUG, ("DHCP_OFFER received in DHCP_SELECTING state")); |
1132 |
|
dhcp->request_timeout = 0; |
1133 |
|
/* remember offered lease */ |
1134 |
|
dhcp_handle_offer(dhcp); |
1135 |
} |
} |
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("not a DHCP reply message, but type %u", reply_msg->op)); |
|
|
} |
|
|
|
|
1136 |
pbuf_free(p); |
pbuf_free(p); |
1137 |
} |
} |
1138 |
|
|
1139 |
|
|
1140 |
static err_t dhcp_create_request(struct dhcp_state *state) |
static err_t dhcp_create_request(struct dhcp *dhcp) |
1141 |
{ |
{ |
1142 |
u16_t i; |
u16_t i; |
1143 |
LWIP_ASSERT("dhcp_create_request: state->p_out == NULL", state->p_out == NULL); |
LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL); |
1144 |
LWIP_ASSERT("dhcp_create_request: state->msg_out == NULL", state->msg_out == NULL); |
LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL); |
1145 |
state->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); |
dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); |
1146 |
if (state->p_out == NULL) |
if (dhcp->p_out == NULL) { |
1147 |
{ |
DEBUGF(DHCP_DEBUG, ("dhcp_create_request(): could not allocate pbuf")); |
|
DEBUGF(DHCP_DEBUG, ("dhcp_create_request(): could not allocate pbuf")); |
|
1148 |
return ERR_MEM; |
return ERR_MEM; |
1149 |
} |
} |
1150 |
state->xid = xid; |
/* give unique transaction identifier to this request */ |
1151 |
xid++; |
dhcp->xid = xid++; |
1152 |
|
|
1153 |
state->msg_out = (struct dhcp_msg *)state->p_out->payload; |
dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; |
1154 |
|
|
1155 |
state->msg_out->op = DHCP_BOOTREQUEST; |
dhcp->msg_out->op = DHCP_BOOTREQUEST; |
1156 |
state->msg_out->htype = DHCP_HTYPE_ETH; |
/* TODO: make link layer independent */ |
1157 |
state->msg_out->hlen = DHCP_HLEN_ETH; |
dhcp->msg_out->htype = DHCP_HTYPE_ETH; |
1158 |
state->msg_out->hops = 0; |
/* TODO: make link layer independent */ |
1159 |
state->msg_out->xid = htonl(state->xid); |
dhcp->msg_out->hlen = DHCP_HLEN_ETH; |
1160 |
state->msg_out->secs = 0; |
dhcp->msg_out->hops = 0; |
1161 |
state->msg_out->flags = 0; |
dhcp->msg_out->xid = htonl(dhcp->xid); |
1162 |
state->msg_out->ciaddr = state->netif->ip_addr.addr; |
dhcp->msg_out->secs = 0; |
1163 |
state->msg_out->yiaddr = 0; |
dhcp->msg_out->flags = 0; |
1164 |
state->msg_out->siaddr = 0; |
dhcp->msg_out->ciaddr = netif->ip_addr.addr; |
1165 |
state->msg_out->giaddr = 0; |
dhcp->msg_out->yiaddr = 0; |
1166 |
for (i = 0; i < DHCP_CHADDR_LEN; i++) state->msg_out->chaddr[i] = state->netif->hwaddr[i]; |
dhcp->msg_out->siaddr = 0; |
1167 |
for (i = 0; i < DHCP_SNAME_LEN; i++) state->msg_out->sname[i] = 0; |
dhcp->msg_out->giaddr = 0; |
1168 |
for (i = 0; i < DHCP_FILE_LEN; i++) state->msg_out->file[i] = 0; |
for (i = 0; i < DHCP_CHADDR_LEN; i++) { |
1169 |
state->msg_out->cookie = htonl(0x63825363UL); |
/* copy netif hardware address, pad with zeroes */ |
1170 |
state->options_out_len = 0; |
dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/; |
1171 |
// fill options field with an incrementing array (for debugging purposes) |
} |
1172 |
for (i = 0; i < DHCP_OPTIONS_LEN; i++) state->msg_out->options[i] = i; |
for (i = 0; i < DHCP_SNAME_LEN; i++) dhcp->msg_out->sname[i] = 0; |
1173 |
|
for (i = 0; i < DHCP_FILE_LEN; i++) dhcp->msg_out->file[i] = 0; |
1174 |
|
dhcp->msg_out->cookie = htonl(0x63825363UL); |
1175 |
|
dhcp->options_out_len = 0; |
1176 |
|
/* fill options field with an incrementing array (for debugging purposes) */ |
1177 |
|
for (i = 0; i < DHCP_OPTIONS_LEN; i++) dhcp->msg_out->options[i] = i; |
1178 |
return ERR_OK; |
return ERR_OK; |
1179 |
} |
} |
1180 |
|
|
1181 |
static void dhcp_delete_request(struct dhcp_state *state) |
static void dhcp_delete_request(struct dhcp *dhcp) |
1182 |
{ |
{ |
1183 |
LWIP_ASSERT("dhcp_free_msg: state->p_out != NULL", state->p_out != NULL); |
LWIP_ASSERT("dhcp_free_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); |
1184 |
LWIP_ASSERT("dhcp_free_msg: state->msg_out != NULL", state->msg_out != NULL); |
LWIP_ASSERT("dhcp_free_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); |
1185 |
pbuf_free(state->p_out); |
pbuf_free(dhcp->p_out); |
1186 |
state->p_out = NULL; |
dhcp->p_out = NULL; |
1187 |
state->msg_out = NULL; |
dhcp->msg_out = NULL; |
1188 |
} |
} |
1189 |
|
|
1190 |
/** |
/** |
1191 |
* Add a DHCP message trailer |
* Add a DHCP message trailer |
1192 |
* |
* |
1193 |
* Adds the END option to the DHCP message, and up to |
* Adds the END option to the DHCP message, and if |
1194 |
* three padding bytes. |
* necessary, up to three padding bytes. |
1195 |
*/ |
*/ |
1196 |
|
|
1197 |
static void dhcp_option_trailer(struct dhcp_state *state) |
static void dhcp_option_trailer(struct dhcp *dhcp) |
1198 |
{ |
{ |
1199 |
LWIP_ASSERT("dhcp_option_trailer: state->msg_out != NULL", state->msg_out != NULL); |
LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL", dhcp->msg_out != NULL); |
1200 |
LWIP_ASSERT("dhcp_option_trailer: state->options_out_len < DHCP_OPTIONS_LEN", state->options_out_len < DHCP_OPTIONS_LEN); |
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); |
1201 |
state->msg_out->options[state->options_out_len++] = DHCP_OPTION_END; |
dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; |
1202 |
// packet is still too small, or not 4 byte aligned? |
/* packet is too small, or not 4 byte aligned? */ |
1203 |
while ((state->options_out_len < DHCP_MIN_OPTIONS_LEN) || (state->options_out_len & 3)) |
while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) { |
1204 |
{ |
/* DEBUGF(DHCP_DEBUG, ("dhcp_option_trailer: dhcp->options_out_len=%u, DHCP_OPTIONS_LEN=%u", dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ |
1205 |
//DEBUGF(DHCP_DEBUG, ("dhcp_option_trailer: state->options_out_len=%u, DHCP_OPTIONS_LEN=%u", state->options_out_len, DHCP_OPTIONS_LEN)); |
LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); |
1206 |
LWIP_ASSERT("dhcp_option_trailer: state->options_out_len < DHCP_OPTIONS_LEN", state->options_out_len < DHCP_OPTIONS_LEN); |
/* add a fill/padding byte */ |
1207 |
state->msg_out->options[state->options_out_len++] = 0; |
dhcp->msg_out->options[dhcp->options_out_len++] = 0; |
1208 |
} |
} |
1209 |
} |
} |
1210 |
|
|
1217 |
* @return a byte offset into the UDP message where the option was found, or |
* @return a byte offset into the UDP message where the option was found, or |
1218 |
* zero if the given option was not found. |
* zero if the given option was not found. |
1219 |
*/ |
*/ |
1220 |
static u8_t *dhcp_get_option_ptr(struct dhcp_state *state, u8_t option_type) |
static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type) |
1221 |
{ |
{ |
1222 |
u8_t overload = DHCP_OVERLOAD_NONE; |
u8_t overload = DHCP_OVERLOAD_NONE; |
1223 |
|
|
1224 |
// options available? |
/* options available? */ |
1225 |
if ((state->options_in != NULL) && (state->options_in_len > 0)) |
if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) { |
1226 |
{ |
/* start with options field */ |
1227 |
// start with options field |
u8_t *options = (u8_t *)dhcp->options_in; |
|
u8_t *options = (u8_t *)state->options_in; |
|
1228 |
u16_t offset = 0; |
u16_t offset = 0; |
1229 |
// at least 1 byte to read and no end marker, then at least 3 bytes to read? |
/* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ |
1230 |
while ((offset < state->options_in_len) && (options[offset] != DHCP_OPTION_END)) |
while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) { |
1231 |
{ |
/* DEBUGF(DHCP_DEBUG, ("msg_offset=%u, q->len=%u", msg_offset, q->len)); */ |
1232 |
//DEBUGF(DHCP_DEBUG, ("msg_offset=%u, q->len=%u", msg_offset, q->len)); |
/* are the sname and/or file field overloaded with options? */ |
1233 |
// are the sname and/or file field overloaded with options? |
if (options[offset] == DHCP_OPTION_OVERLOAD) { |
1234 |
if (options[offset] == DHCP_OPTION_OVERLOAD) |
DEBUGF(DHCP_DEBUG, ("overloaded message detected")); |
1235 |
{ |
/* skip option type and length */ |
|
DEBUGF(DHCP_DEBUG, ("overloaded message detected")); |
|
|
// skip option type and length |
|
1236 |
offset += 2; |
offset += 2; |
1237 |
overload = options[offset++]; |
overload = options[offset++]; |
1238 |
} |
} |
1239 |
// requested option found |
/* requested option found */ |
1240 |
else if (options[offset] == option_type) |
else if (options[offset] == option_type) { |
1241 |
{ |
DEBUGF(DHCP_DEBUG, ("option found at offset %u in options", offset)); |
|
DEBUGF(DHCP_DEBUG, ("option found at offset %u in options", offset)); |
|
1242 |
return &options[offset]; |
return &options[offset]; |
1243 |
} |
/* skip option */ |
1244 |
// skip option |
} else { |
|
else |
|
|
{ |
|
1245 |
DEBUGF(DHCP_DEBUG, ("skipping option %u in options", options[offset])); |
DEBUGF(DHCP_DEBUG, ("skipping option %u in options", options[offset])); |
1246 |
// skip option type |
/* skip option type */ |
1247 |
offset++; |
offset++; |
1248 |
// skip option length, and then length bytes |
/* skip option length, and then length bytes */ |
1249 |
offset += 1 + options[offset]; |
offset += 1 + options[offset]; |
1250 |
} |
} |
1251 |
} |
} |
1252 |
// is this an overloaded message? |
/* is this an overloaded message? */ |
1253 |
if (overload != DHCP_OVERLOAD_NONE) |
if (overload != DHCP_OVERLOAD_NONE) { |
|
{ |
|
1254 |
u16_t field_len; |
u16_t field_len; |
1255 |
if (overload == DHCP_OVERLOAD_FILE) |
if (overload == DHCP_OVERLOAD_FILE) { |
|
{ |
|
1256 |
DEBUGF(DHCP_DEBUG, ("overloaded file field")); |
DEBUGF(DHCP_DEBUG, ("overloaded file field")); |
1257 |
options = (u8_t *)&state->msg_in->file; |
options = (u8_t *)&dhcp->msg_in->file; |
1258 |
field_len = DHCP_FILE_LEN; |
field_len = DHCP_FILE_LEN; |
1259 |
} |
} else if (overload == DHCP_OVERLOAD_SNAME) { |
|
else if (overload == DHCP_OVERLOAD_SNAME) |
|
|
{ |
|
1260 |
DEBUGF(DHCP_DEBUG, ("overloaded sname field")); |
DEBUGF(DHCP_DEBUG, ("overloaded sname field")); |
1261 |
options = (u8_t *)&state->msg_in->sname; |
options = (u8_t *)&dhcp->msg_in->sname; |
1262 |
field_len = DHCP_SNAME_LEN; |
field_len = DHCP_SNAME_LEN; |
1263 |
} |
/* TODO: check if else if () is necessary */ |
1264 |
else // TODO: check if else if () is necessary |
} else { |
|
{ |
|
1265 |
DEBUGF(DHCP_DEBUG, ("overloaded sname and file field")); |
DEBUGF(DHCP_DEBUG, ("overloaded sname and file field")); |
1266 |
options = (u8_t *)&state->msg_in->sname; |
options = (u8_t *)&dhcp->msg_in->sname; |
1267 |
field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; |
field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; |
1268 |
} |
} |
1269 |
offset = 0; |
offset = 0; |
1270 |
|
|
1271 |
// at least 1 byte to read and no end marker |
/* at least 1 byte to read and no end marker */ |
1272 |
while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) |
while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) { |
1273 |
{ |
if (options[offset] == option_type) { |
|
if (options[offset] == option_type) |
|
|
{ |
|
1274 |
DEBUGF(DHCP_DEBUG, ("option found at offset=%u", offset)); |
DEBUGF(DHCP_DEBUG, ("option found at offset=%u", offset)); |
1275 |
return &options[offset]; |
return &options[offset]; |
1276 |
} |
/* skip option */ |
1277 |
// skip option |
} else { |
1278 |
else |
DEBUGF(DHCP_DEBUG, ("skipping option %u", options[offset])); |
1279 |
{ |
/* skip option type */ |
|
DEBUGF(DHCP_DEBUG, ("skipping option %u", options[offset])); |
|
|
// skip option type |
|
1280 |
offset++; |
offset++; |
1281 |
offset += 1 + options[offset]; |
offset += 1 + options[offset]; |
1282 |
} |
} |
1335 |
DEBUGF(DHCP_DEBUG, ("option long value=%lu", value)); |
DEBUGF(DHCP_DEBUG, ("option long value=%lu", value)); |
1336 |
return value; |
return value; |
1337 |
} |
} |
|
|
|
|
/** |
|
|
* Find the DHCP client attached to a network interface. |
|
|
* |
|
|
* Given an network interface, return the corresponding dhcp state |
|
|
* or NULL if the interface was not under DHCP control. |
|
|
*/ |
|
|
struct dhcp_state *dhcp_find_client(struct netif *netif) |
|
|
{ |
|
|
struct dhcp_state *state = NULL; |
|
|
struct dhcp_state *list_state = client_list; |
|
|
|
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_find_client()")); |
|
|
while ((state == NULL) && (list_state != NULL)) |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_find_client(): checking state %p", list_state)); |
|
|
// this interface already has a DHCP client attached |
|
|
if (list_state->netif == netif) |
|
|
{ |
|
|
state = list_state; |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_find_client(): interface already under DHCP control")); |
|
|
} |
|
|
if (list_state->next != NULL) |
|
|
{ |
|
|
// select the next client state |
|
|
list_state = list_state->next; |
|
|
} |
|
|
// reached end of list |
|
|
else |
|
|
{ |
|
|
DEBUGF(DHCP_DEBUG, ("dhcp_find_client(): end of list reached")); |
|
|
break; |
|
|
// { state == NULL } |
|
|
// { list_state is last item in list } |
|
|
} |
|
|
} |
|
|
return state; |
|
|
} |
|