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