1 /*
2 * File : dhcp_server_raw.c
3 * A simple DHCP server implementation
4 * COPYRIGHT (C) 2011-2023, Shanghai Real-Thread Technology Co., Ltd
5 * http://www.rt-thread.com
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without modification,
9 * are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
22 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
24 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
28 * OF SUCH DAMAGE.
29 *
30 * Change Logs:
31 * Date Author Notes
32 * 2014-04-01 Ren.Haibo the first version
33 * 2018-06-12 aozima ignore DHCP_OPTION_SERVER_ID.
34 */
35
36 #include <stdio.h>
37 #include <stdint.h>
38
39 #include <rtthread.h>
40
41 #include <lwip/opt.h>
42 #include <lwip/sockets.h>
43 #include <lwip/inet_chksum.h>
44 #include <netif/etharp.h>
45 #include <netif/ethernetif.h>
46 #include <lwip/ip.h>
47 #include <lwip/init.h>
48
49 #if (LWIP_VERSION) < 0x02000000U
50 #error "not support old LWIP"
51 #endif
52
53 #if !LWIP_IPV4
54 #error "must enable IPV4"
55 #endif
56
57 #if (LWIP_VERSION) >= 0x02000000U
58 #include <lwip/prot/dhcp.h>
59 #endif
60
61 /* DHCP server option */
62
63 /* allocated client ip range */
64 #ifndef DHCPD_CLIENT_IP_MIN
65 #define DHCPD_CLIENT_IP_MIN 2
66 #endif
67 #ifndef DHCPD_CLIENT_IP_MAX
68 #define DHCPD_CLIENT_IP_MAX 254
69 #endif
70
71 /* the DHCP server address */
72 #ifndef DHCPD_SERVER_IP
73 #define DHCPD_SERVER_IP "192.168.169.1"
74 #endif
75
76 #define DHCP_DEBUG_PRINTF
77
78 #ifdef DHCP_DEBUG_PRINTF
79 #define DEBUG_PRINTF rt_kprintf("[DHCP] "); rt_kprintf
80 #else
81 #define DEBUG_PRINTF(...)
82 #endif /* DHCP_DEBUG_PRINTF */
83
84 /* we need some routines in the DHCP of lwIP */
85 #undef LWIP_DHCP
86 #define LWIP_DHCP 1
87 #include <lwip/dhcp.h>
88
89 /** Mac address length */
90 #define DHCP_MAX_HLEN 6
91 /** dhcp default live time */
92 #define DHCP_DEFAULT_LIVE_TIME 0x80510100
93
94 /** Minimum length for request before packet is parsed */
95 #define DHCP_MIN_REQUEST_LEN 44
96
97 #define LWIP_NETIF_LOCK(...)
98 #define LWIP_NETIF_UNLOCK(...)
99
100 #ifndef DHCP_SERVER_PORT
101 #define DHCP_SERVER_PORT 67
102 #endif
103
104 /**
105 * The dhcp client node struct.
106 */
107 struct dhcp_client_node
108 {
109 struct dhcp_client_node *next;
110 u8_t chaddr[DHCP_MAX_HLEN];
111 ip4_addr_t ipaddr;
112 u32_t lease_end;
113 };
114
115 /**
116 * The dhcp server struct.
117 */
118 struct dhcp_server
119 {
120 struct dhcp_server *next;
121 struct netif *netif;
122 struct udp_pcb *pcb;
123 struct dhcp_client_node *node_list;
124 ip4_addr_t start;
125 ip4_addr_t end;
126 ip4_addr_t current;
127 };
128
129 static u8_t *dhcp_server_option_find(u8_t *buf, u16_t len, u8_t option);
130
131 /**
132 * The dhcp server struct list.
133 */
134 static struct dhcp_server *lw_dhcp_server;
135
136 /**
137 * Find a dhcp client node by mac address
138 *
139 * @param dhcpserver The dhcp server
140 * @param chaddr Mac address
141 * @param hlen Mac address length
142 * @return dhcp client node
143 */
144 static struct dhcp_client_node *
dhcp_client_find_by_mac(struct dhcp_server * dhcpserver,const u8_t * chaddr,u8_t hlen)145 dhcp_client_find_by_mac(struct dhcp_server *dhcpserver, const u8_t *chaddr, u8_t hlen)
146 {
147 struct dhcp_client_node *node;
148
149 for (node = dhcpserver->node_list; node != NULL; node = node->next)
150 {
151 if (memcmp(node->chaddr, chaddr, hlen) == 0)
152 {
153 return node;
154 }
155 }
156
157 return NULL;
158 }
159
160 /**
161 * Find a dhcp client node by ip address
162 *
163 * @param dhcpserver The dhcp server
164 * @param ip IP address
165 * @return dhcp client node
166 */
167 static struct dhcp_client_node *
dhcp_client_find_by_ip(struct dhcp_server * dhcpserver,const ip4_addr_t * ip)168 dhcp_client_find_by_ip(struct dhcp_server *dhcpserver, const ip4_addr_t *ip)
169 {
170 struct dhcp_client_node *node;
171
172 for (node = dhcpserver->node_list; node != NULL; node = node->next)
173 {
174 if (ip4_addr_cmp(&node->ipaddr, ip))
175 {
176 return node;
177 }
178 }
179
180 return NULL;
181 }
182
183 /**
184 * Find a dhcp client node by dhcp message
185 *
186 * @param dhcpserver is the dhcp server
187 * @param msg is the dhcp message
188 * @param opt_buf is the optional buffer
189 * @param len is the buffer length
190 * @return dhcp client node
191 */
192 static struct dhcp_client_node *
dhcp_client_find(struct dhcp_server * dhcpserver,struct dhcp_msg * msg,u8_t * opt_buf,u16_t len)193 dhcp_client_find(struct dhcp_server *dhcpserver, struct dhcp_msg *msg,
194 u8_t *opt_buf, u16_t len)
195 {
196 u8_t *opt;
197 //u32_t ipaddr;
198 struct dhcp_client_node *node;
199
200 node = dhcp_client_find_by_mac(dhcpserver, msg->chaddr, msg->hlen);
201 if (node != NULL)
202 {
203 return node;
204 }
205
206 opt = dhcp_server_option_find(opt_buf, len, DHCP_OPTION_REQUESTED_IP);
207 if (opt != NULL)
208 {
209 node = dhcp_client_find_by_ip(dhcpserver, (ip4_addr_t *)(&opt[2]));
210 if (node != NULL)
211 {
212 return node;
213 }
214 }
215
216 return NULL;
217 }
218
219 /**
220 * Allocate a dhcp client node by dhcp message
221 *
222 * @param dhcpserver is the dhcp server
223 * @param msg is the dhcp message
224 * @param opt_buf is the optional buffer
225 * @param len is the buffer length
226 * @return dhcp client node
227 */
228 static struct dhcp_client_node *
dhcp_client_alloc(struct dhcp_server * dhcpserver,struct dhcp_msg * msg,u8_t * opt_buf,u16_t len)229 dhcp_client_alloc(struct dhcp_server *dhcpserver, struct dhcp_msg *msg,
230 u8_t *opt_buf, u16_t len)
231 {
232 u8_t *opt;
233 u32_t ipaddr;
234 struct dhcp_client_node *node;
235
236 node = dhcp_client_find_by_mac(dhcpserver, msg->chaddr, msg->hlen);
237 if (node != NULL)
238 {
239 return node;
240 }
241
242 opt = dhcp_server_option_find(opt_buf, len, DHCP_OPTION_REQUESTED_IP);
243 if (opt != NULL)
244 {
245 node = dhcp_client_find_by_ip(dhcpserver, (ip4_addr_t *)(&opt[2]));
246 if (node != NULL)
247 {
248 return node;
249 }
250 }
251
252 dhcp_alloc_again:
253 node = dhcp_client_find_by_ip(dhcpserver, &dhcpserver->current);
254 if (node != NULL)
255 {
256 ipaddr = (ntohl(dhcpserver->current.addr) + 1);
257 if (ipaddr > ntohl(dhcpserver->end.addr))
258 {
259 ipaddr = ntohl(dhcpserver->start.addr);
260 }
261 dhcpserver->current.addr = htonl(ipaddr);
262 goto dhcp_alloc_again;
263 }
264 node = (struct dhcp_client_node *)mem_malloc(sizeof(struct dhcp_client_node));
265 if (node == NULL)
266 {
267 return NULL;
268 }
269 SMEMCPY(node->chaddr, msg->chaddr, msg->hlen);
270 node->ipaddr = dhcpserver->current;
271
272 node->next = dhcpserver->node_list;
273 dhcpserver->node_list = node;
274
275 return node;
276 }
277
278 /**
279 * find option from buffer.
280 *
281 * @param buf The buffer to find option
282 * @param len The buffer length
283 * @param option Which option to find
284 * @return dhcp option buffer
285 */
286 static u8_t *
dhcp_server_option_find(u8_t * buf,u16_t len,u8_t option)287 dhcp_server_option_find(u8_t *buf, u16_t len, u8_t option)
288 {
289 u8_t *end = buf + len;
290 while ((buf < end) && (*buf != DHCP_OPTION_END))
291 {
292 if (*buf == option)
293 {
294 return buf;
295 }
296 buf += (buf[1] + 2);
297 }
298 return NULL;
299 }
300
301 /**
302 * If an incoming DHCP message is in response to us, then trigger the state machine
303 */
304 static void
dhcp_server_recv(void * arg,struct udp_pcb * pcb,struct pbuf * p,const ip_addr_t * recv_addr,u16_t port)305 dhcp_server_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *recv_addr, u16_t port)
306 {
307 struct dhcp_server *dhcp_server = (struct dhcp_server *)arg;
308 struct dhcp_msg *msg;
309 struct pbuf *q;
310 u8_t *opt_buf;
311 u8_t *opt;
312 struct dhcp_client_node *node;
313 u8_t msg_type;
314 u16_t length;
315 ip_addr_t addr = *recv_addr;
316 u32_t tmp;
317
318 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("[%s:%d] %c%c recv %d\n", __FUNCTION__, __LINE__, dhcp_server->netif->name[0], dhcp_server->netif->name[1], p->tot_len));
319 /* prevent warnings about unused arguments */
320 LWIP_UNUSED_ARG(pcb);
321 LWIP_UNUSED_ARG(addr);
322 LWIP_UNUSED_ARG(port);
323
324 if (p->len < DHCP_MIN_REQUEST_LEN)
325 {
326 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP request message or pbuf too short\n"));
327 pbuf_free(p);
328 return;
329 }
330
331 q = pbuf_alloc(PBUF_TRANSPORT, 1500, PBUF_RAM);
332 if (q == NULL)
333 {
334 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloc dhcp_msg failed!\n"));
335 pbuf_free(p);
336 return;
337 }
338 if (q->tot_len < p->tot_len)
339 {
340 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloc dhcp_msg too small %d:%d\n", q->tot_len, p->tot_len));
341 pbuf_free(p);
342 return;
343 }
344
345 pbuf_copy(q, p);
346 pbuf_free(p);
347
348 msg = (struct dhcp_msg *)q->payload;
349 if (msg->op != DHCP_BOOTREQUEST)
350 {
351 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP request message, but type %"U16_F"\n", (u16_t)msg->op));
352 goto free_pbuf_and_return;
353 }
354
355 if (msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE))
356 {
357 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("bad DHCP_MAGIC_COOKIE!\n"));
358 goto free_pbuf_and_return;
359 }
360
361 if (msg->hlen > DHCP_MAX_HLEN)
362 {
363 goto free_pbuf_and_return;
364 }
365
366 opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
367 length = q->tot_len - DHCP_OPTIONS_OFS;
368 opt = dhcp_server_option_find(opt_buf, length, DHCP_OPTION_MESSAGE_TYPE);
369 if (opt)
370 {
371 msg_type = *(opt + 2);
372 if (msg_type == DHCP_DISCOVER)
373 {
374 node = dhcp_client_alloc(dhcp_server, msg, opt_buf, length);
375 if (node == NULL)
376 {
377 goto free_pbuf_and_return;
378 }
379 node->lease_end = DHCP_DEFAULT_LIVE_TIME;
380 /* create dhcp offer and send */
381 msg->op = DHCP_BOOTREPLY;
382 msg->hops = 0;
383 msg->secs = 0;
384 SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
385 msg->sname[0] = '\0';
386 msg->file[0] = '\0';
387 msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
388 SMEMCPY(&msg->yiaddr, &node->ipaddr, 4);
389
390 opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
391 /* add msg type */
392 *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
393 *opt_buf++ = 1;
394 *opt_buf++ = DHCP_OFFER;
395
396 /* add server id */
397 *opt_buf++ = DHCP_OPTION_SERVER_ID;
398 *opt_buf++ = 4;
399 SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
400 opt_buf += 4;
401
402 /* add_lease_time */
403 *opt_buf++ = DHCP_OPTION_LEASE_TIME;
404 *opt_buf++ = 4;
405 tmp = PP_HTONL(DHCP_DEFAULT_LIVE_TIME);
406 SMEMCPY(opt_buf, &tmp, 4);
407 opt_buf += 4;
408
409 /* add config */
410 *opt_buf++ = DHCP_OPTION_SUBNET_MASK;
411 *opt_buf++ = 4;
412 SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->netmask)->addr, 4);
413 opt_buf += 4;
414
415 *opt_buf++ = DHCP_OPTION_DNS_SERVER;
416 *opt_buf++ = 4;
417 #ifdef DHCP_DNS_SERVER_IP
418 {
419 ip_addr_t dns_addr;
420 ipaddr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
421 SMEMCPY(opt_buf, &ip_2_ip4(&dns_addr)->addr, 4);
422 }
423 #else
424 /* default use gatewary dns server */
425 SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
426 #endif /* DHCP_DNS_SERVER_IP */
427 opt_buf += 4;
428
429 *opt_buf++ = DHCP_OPTION_ROUTER;
430 *opt_buf++ = 4;
431 SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->ip_addr)->addr, 4);
432 opt_buf += 4;
433
434 /* add option end */
435 *opt_buf++ = DHCP_OPTION_END;
436
437 length = (u32_t)opt_buf - (u32_t)msg;
438 if (length < q->tot_len)
439 {
440 pbuf_realloc(q, length);
441 }
442
443 ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
444 udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
445 }
446 else
447 {
448 if (1)
449 {
450 if (msg_type == DHCP_REQUEST)
451 {
452 node = dhcp_client_find(dhcp_server, msg, opt_buf, length);
453 if (node != NULL)
454 {
455 /* Send ack */
456 node->lease_end = DHCP_DEFAULT_LIVE_TIME;
457 /* create dhcp offer and send */
458 msg->op = DHCP_BOOTREPLY;
459 msg->hops = 0;
460 msg->secs = 0;
461 SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
462 msg->sname[0] = '\0';
463 msg->file[0] = '\0';
464 msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
465 SMEMCPY(&msg->yiaddr, &node->ipaddr, 4);
466 opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
467
468 /* add msg type */
469 *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
470 *opt_buf++ = 1;
471 *opt_buf++ = DHCP_ACK;
472
473 /* add server id */
474 *opt_buf++ = DHCP_OPTION_SERVER_ID;
475 *opt_buf++ = 4;
476 SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
477 opt_buf += 4;
478
479 /* add_lease_time */
480 *opt_buf++ = DHCP_OPTION_LEASE_TIME;
481 *opt_buf++ = 4;
482 tmp = PP_HTONL(DHCP_DEFAULT_LIVE_TIME);
483 SMEMCPY(opt_buf, &tmp, 4);
484 opt_buf += 4;
485
486 /* add config */
487 *opt_buf++ = DHCP_OPTION_SUBNET_MASK;
488 *opt_buf++ = 4;
489 SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->netmask)->addr, 4);
490 opt_buf += 4;
491
492 *opt_buf++ = DHCP_OPTION_DNS_SERVER;
493 *opt_buf++ = 4;
494 #ifdef DHCP_DNS_SERVER_IP
495 {
496 ip_addr_t dns_addr;
497 ipaddr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
498 SMEMCPY(opt_buf, &ip_2_ip4(&dns_addr)->addr, 4);
499 }
500 #else
501 /* default use gatewary dns server */
502 SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
503 #endif /* DHCP_DNS_SERVER_IP */
504 opt_buf += 4;
505
506 *opt_buf++ = DHCP_OPTION_ROUTER;
507 *opt_buf++ = 4;
508 SMEMCPY(opt_buf, &ip_2_ip4(&dhcp_server->netif->ip_addr)->addr, 4);
509 opt_buf += 4;
510
511 /* add option end */
512 *opt_buf++ = DHCP_OPTION_END;
513
514 length = (u32_t)opt_buf - (u32_t)msg;
515 if (length < q->tot_len)
516 {
517 pbuf_realloc(q, length);
518 }
519
520 ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
521 udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
522 }
523 else
524 {
525 /* Send no ack */
526 /* create dhcp offer and send */
527 msg->op = DHCP_BOOTREPLY;
528 msg->hops = 0;
529 msg->secs = 0;
530 SMEMCPY(&msg->siaddr, &(dhcp_server->netif->ip_addr), 4);
531 msg->sname[0] = '\0';
532 msg->file[0] = '\0';
533 msg->cookie = PP_HTONL(DHCP_MAGIC_COOKIE);
534 memset(&msg->yiaddr, 0, 4);
535 opt_buf = (u8_t *)msg + DHCP_OPTIONS_OFS;
536
537 /* add msg type */
538 *opt_buf++ = DHCP_OPTION_MESSAGE_TYPE;
539 *opt_buf++ = 1;
540 *opt_buf++ = DHCP_NAK;
541
542 /* add server id */
543 *opt_buf++ = DHCP_OPTION_SERVER_ID;
544 *opt_buf++ = 4;
545 SMEMCPY(opt_buf, &(dhcp_server->netif->ip_addr), 4);
546 opt_buf += 4;
547
548 /* add option end */
549 *opt_buf++ = DHCP_OPTION_END;
550 length = (u32_t)opt_buf - (u32_t)msg;
551 if (length < q->tot_len)
552 {
553 pbuf_realloc(q, length);
554 }
555
556 ip_2_ip4(&addr)->addr = INADDR_BROADCAST;
557 udp_sendto_if(pcb, q, &addr, port, dhcp_server->netif);
558 }
559 }
560 else if (msg_type == DHCP_RELEASE)
561 {
562 struct dhcp_client_node *node_prev = NULL;
563
564 for (node = dhcp_server->node_list; node != NULL; node = node->next)
565 {
566 if (memcmp(node->chaddr, msg->chaddr, msg->hlen) == 0)
567 {
568 if (node == dhcp_server->node_list)
569 {
570 dhcp_server->node_list = node->next;
571 }
572 else
573 {
574 node_prev->next = node->next;
575 }
576 break;
577 }
578 node_prev = node;
579 node = node->next;
580 }
581
582 if (node != NULL)
583 {
584 mem_free(node);
585 }
586 }
587 else if (msg_type == DHCP_DECLINE)
588 {
589 ;
590 }
591 else if (msg_type == DHCP_INFORM)
592 {
593 ;
594 }
595 }
596 }
597 }
598
599 free_pbuf_and_return:
600 pbuf_free(q);
601 }
602
603 /**
604 * start dhcp server for a netif
605 *
606 * @param netif The netif which use dhcp server
607 * @param start The Start IP address
608 * @param end The End IP address
609 * @return lwIP error code
610 * - ERR_OK - No error
611 * - ERR_MEM - Out of memory
612 */
613 err_t
dhcp_server_start(struct netif * netif,ip4_addr_t * start,ip4_addr_t * end)614 dhcp_server_start(struct netif *netif, ip4_addr_t *start, ip4_addr_t *end)
615 {
616 struct dhcp_server *dhcp_server;
617
618 /* If this netif alreday use the dhcp server. */
619 for (dhcp_server = lw_dhcp_server; dhcp_server != NULL; dhcp_server = dhcp_server->next)
620 {
621 if (dhcp_server->netif == netif)
622 {
623 dhcp_server->start = *start;
624 dhcp_server->end = *end;
625 dhcp_server->current = *start;
626 return ERR_OK;
627 }
628 }
629
630 dhcp_server = NULL;
631 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): starting new DHCP server\n"));
632 dhcp_server = (struct dhcp_server *)mem_malloc(sizeof(struct dhcp_server));
633 if (dhcp_server == NULL)
634 {
635 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): could not allocate dhcp\n"));
636 return ERR_MEM;
637 }
638
639 /* clear data structure */
640 memset(dhcp_server, 0, sizeof(struct dhcp_server));
641
642 /* store this dhcp server to list */
643 dhcp_server->next = lw_dhcp_server;
644 lw_dhcp_server = dhcp_server;
645 dhcp_server->netif = netif;
646 dhcp_server->node_list = NULL;
647 dhcp_server->start = *start;
648 dhcp_server->end = *end;
649 dhcp_server->current = *start;
650
651 /* allocate UDP PCB */
652 dhcp_server->pcb = udp_new();
653 if (dhcp_server->pcb == NULL)
654 {
655 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): could not obtain pcb\n"));
656 return ERR_MEM;
657 }
658
659 ip_set_option(dhcp_server->pcb, SOF_BROADCAST);
660 /* set up local and remote port for the pcb */
661 udp_bind(dhcp_server->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
662 //udp_connect(dhcp_server->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
663 /* set up the recv callback and argument */
664 udp_recv(dhcp_server->pcb, dhcp_server_recv, dhcp_server);
665 LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_server_start(): starting DHCP server\n"));
666
667 return ERR_OK;
668 }
669
670 extern void set_if(const char *netif_name, const char *ip_addr, const char *gw_addr, const char *nm_addr);
671
dhcpd_start(const char * netif_name)672 void dhcpd_start(const char *netif_name)
673 {
674 struct netif *netif = netif_list;
675 err_t res;
676
677 DEBUG_PRINTF("%s: %s\r\n", __FUNCTION__, netif_name);
678
679 LWIP_NETIF_LOCK();
680 if (strlen(netif_name) > sizeof(netif->name))
681 {
682 DEBUG_PRINTF("network interface name too long!\r\n");
683 goto _exit;
684 }
685
686 while (netif != RT_NULL)
687 {
688 if (strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
689 break;
690
691 netif = netif->next;
692 if (netif == RT_NULL)
693 {
694 DEBUG_PRINTF("network interface: %s not found!\r\n", netif_name);
695 break;
696 }
697 }
698
699 if (netif == RT_NULL)
700 {
701 goto _exit;
702 }
703
704 if (1)
705 {
706 dhcp_stop(netif);
707
708 set_if(netif_name, DHCPD_SERVER_IP, "0.0.0.0", "255.255.255.0");
709
710 netif_set_up(netif);
711 }
712
713 {
714 char str_tmp[4 * 4 + 4] = DHCPD_SERVER_IP;
715 char *p = str_tmp;
716 ip4_addr_t ip_start, ip_end;
717
718 p = strchr(str_tmp, '.');
719 if (p)
720 {
721 p = strchr(p + 1, '.');
722 if (p)
723 {
724 p = strchr(p + 1, '.');
725 }
726 }
727 if (!p)
728 {
729 DEBUG_PRINTF("DHCPD_SERVER_IP: %s error!\r\n", str_tmp);
730 goto _exit;
731 }
732 p = p + 1; /* move to xxx.xxx.xxx.^ */
733
734 sprintf(p, "%d", DHCPD_CLIENT_IP_MIN);
735 ip4addr_aton(str_tmp, &ip_start);
736 DEBUG_PRINTF("ip_start: [%s]\r\n", str_tmp);
737 sprintf(p, "%d", DHCPD_CLIENT_IP_MAX);
738 ip4addr_aton(str_tmp, &ip_end);
739 DEBUG_PRINTF("ip_end: [%s]\r\n", str_tmp);
740
741 res = dhcp_server_start(netif, &ip_start, &ip_end);
742 if (res != 0)
743 {
744 DEBUG_PRINTF("dhcp_server_start res: %s.\r\n", res);
745 }
746 }
747
748 _exit:
749 LWIP_NETIF_UNLOCK();
750 return;
751 }
752
dhcpd_stop(const char * netif_name)753 void dhcpd_stop(const char *netif_name)
754 {
755 struct dhcp_server *dhcp_server, *server_node;
756 struct netif *netif = netif_list;
757 struct dhcp_client_node *node, *next;
758
759 DEBUG_PRINTF("%s: %s\r\n", __FUNCTION__, netif_name);
760
761 LWIP_NETIF_LOCK();
762 if (strlen(netif_name) > sizeof(netif->name))
763 {
764 DEBUG_PRINTF("network interface name too long!\r\n");
765 goto _exit;
766 }
767
768 while (netif != RT_NULL)
769 {
770 if (strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
771 break;
772
773 netif = netif->next;
774 if (netif == RT_NULL)
775 {
776 DEBUG_PRINTF("network interface: %s not found!\r\n", netif_name);
777 break;
778 }
779 }
780
781 if (netif == RT_NULL)
782 {
783 goto _exit;
784 }
785
786 /* If this netif alreday use the dhcp server. */
787 for (dhcp_server = lw_dhcp_server; dhcp_server != NULL; dhcp_server = dhcp_server->next)
788 {
789 if (dhcp_server->netif == netif)
790 {
791 break;
792 }
793 }
794 if (dhcp_server == RT_NULL)
795 {
796 goto _exit;
797 }
798
799 /* remove dhcp server */
800 if (dhcp_server == lw_dhcp_server)
801 {
802 lw_dhcp_server = lw_dhcp_server->next;
803 }
804 else
805 {
806 server_node = lw_dhcp_server;
807 while (server_node->next && server_node->next != dhcp_server)
808 {
809 server_node = server_node->next;
810 }
811 if (server_node->next != RT_NULL)
812 {
813 server_node->next = server_node->next->next;
814 }
815 }
816
817 udp_disconnect(dhcp_server->pcb);
818 udp_remove(dhcp_server->pcb);
819
820 /* remove all client node */
821 for (node = dhcp_server->node_list; node != NULL; node = next)
822 {
823 next = node->next;
824 mem_free(node);
825 }
826
827 mem_free(dhcp_server);
828 set_if(netif_name, "0.0.0.0", "0.0.0.0", "0.0.0.0");
829
830 _exit:
831 LWIP_NETIF_UNLOCK();
832 }
833