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