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