xref: /nrf52832-nimble/rt-thread/components/net/lwip_dhcpd/dhcp_server.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * File      : dhcp_server.c
3  *             A simple DHCP server implementation
4  *
5  * COPYRIGHT (C) 2011-2018, Shanghai Real-Thread Technology Co., Ltd
6  * http://www.rt-thread.com
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  *    this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
23  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
25  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
28  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
29  * OF SUCH DAMAGE.
30  *
31  * Change Logs:
32  * Date           Author       Notes
33  * 2013-01-30     aozima       the first version
34  * 2013-08-08     aozima       support different network segments.
35  * 2015-01-30     bernard      release to RT-Thread RTOS.
36  * 2017-12-27     aozima       add [mac-ip] table support.
37  */
38 
39 #include <stdio.h>
40 #include <stdint.h>
41 #include <rtthread.h>
42 
43 #include <lwip/opt.h>
44 #include <lwip/sockets.h>
45 #include <lwip/inet_chksum.h>
46 #include <netif/etharp.h>
47 #include <netif/ethernetif.h>
48 #include <lwip/ip.h>
49 #include <lwip/init.h>
50 
51 #if (LWIP_VERSION) >= 0x02000000U
52     #include <lwip/prot/dhcp.h>
53 #endif
54 
55 /* DHCP server option */
56 
57 /* allocated client ip range */
58 #ifndef DHCPD_CLIENT_IP_MIN
59     #define DHCPD_CLIENT_IP_MIN     2
60 #endif
61 #ifndef DHCPD_CLIENT_IP_MAX
62     #define DHCPD_CLIENT_IP_MAX     254
63 #endif
64 
65 /* the DHCP server address */
66 #ifndef DHCPD_SERVER_IP
67     #define DHCPD_SERVER_IP "192.168.169.1"
68 #endif
69 
70 //#define DHCP_DEBUG_PRINTF
71 
72 #ifdef  DHCP_DEBUG_PRINTF
73     #define DEBUG_PRINTF        rt_kprintf("[DHCP] "); rt_kprintf
74 #else
75     #define DEBUG_PRINTF(...)
76 #endif /* DHCP_DEBUG_PRINTF */
77 
78 /* we need some routines in the DHCP of lwIP */
79 #undef  LWIP_DHCP
80 #define LWIP_DHCP   1
81 #include <lwip/dhcp.h>
82 
83 /* buffer size for receive DHCP packet */
84 #define BUFSZ               1024
85 
86 #ifndef MAC_ADDR_LEN
87     #define MAC_ADDR_LEN     6
88 #endif
89 
90 #ifndef MAC_TABLE_LEN
91     #define MAC_TABLE_LEN     4
92 #endif
93 
94 struct mac_addr_t
95 {
96     uint8_t add[MAC_ADDR_LEN];
97 };
98 
99 struct mac_ip_item_t
100 {
101     struct mac_addr_t mac_addr;
102     uint8_t ip_addr_3;
103 };
104 
_low_level_dhcp_send(struct netif * netif,const void * buffer,rt_size_t size)105 static rt_err_t _low_level_dhcp_send(struct netif *netif,
106                                      const void *buffer,
107                                      rt_size_t size)
108 {
109     struct pbuf *p;
110     struct eth_hdr *ethhdr;
111     struct ip_hdr *iphdr;
112     struct udp_hdr *udphdr;
113 
114     p = pbuf_alloc(PBUF_LINK,
115                    SIZEOF_ETH_HDR + sizeof(struct ip_hdr)
116                    + sizeof(struct udp_hdr) + size,
117                    PBUF_RAM);
118     if (p == RT_NULL) return -RT_ENOMEM;
119 
120     ethhdr = (struct eth_hdr *)p->payload;
121     iphdr  = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR);
122     udphdr = (struct udp_hdr *)((char *)iphdr + sizeof(struct ip_hdr));
123 
124     ETHADDR32_COPY(&ethhdr->dest, (struct eth_addr *)&ethbroadcast);
125     ETHADDR16_COPY(&ethhdr->src, netif->hwaddr);
126     ethhdr->type = PP_HTONS(ETHTYPE_IP);
127 
128     iphdr->src.addr  = 0x00000000; /* src: 0.0.0.0 */
129     iphdr->dest.addr = 0xFFFFFFFF; /* src: 255.255.255.255 */
130 
131     IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
132     IPH_TOS_SET(iphdr, 0x00);
133     IPH_LEN_SET(iphdr, htons(IP_HLEN + sizeof(struct udp_hdr) + size));
134     IPH_ID_SET(iphdr, htons(2));
135     IPH_OFFSET_SET(iphdr, 0);
136     IPH_TTL_SET(iphdr, 255);
137     IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
138     IPH_CHKSUM_SET(iphdr, 0);
139     IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
140 
141     udphdr->src = htons(DHCP_SERVER_PORT);
142     udphdr->dest = htons(DHCP_CLIENT_PORT);
143     udphdr->len = htons(sizeof(struct udp_hdr) + size);
144     udphdr->chksum = 0;
145 
146     memcpy((char *)udphdr + sizeof(struct udp_hdr),
147            buffer, size);
148 
149     netif->linkoutput(netif, p);
150     pbuf_free(p);
151 
152     return RT_EOK;
153 }
154 
get_ip(struct mac_addr_t * p_mac_addr)155 static uint8_t get_ip(struct mac_addr_t *p_mac_addr)
156 {
157     static uint8_t next_client_ip = DHCPD_CLIENT_IP_MIN;
158     static struct mac_ip_item_t mac_table[MAC_TABLE_LEN];
159     static int offset = 0;
160 
161     struct mac_addr_t bad_mac;
162     int i;
163     uint8_t ip_addr_3;
164 
165     rt_memset(&bad_mac, 0, sizeof(bad_mac));
166     if (!rt_memcmp(&bad_mac, p_mac_addr, sizeof(bad_mac)))
167     {
168         DEBUG_PRINTF("mac address all zero");
169         ip_addr_3 = DHCPD_CLIENT_IP_MAX;
170         goto _return;
171     }
172 
173     rt_memset(&bad_mac, 0xFF, sizeof(bad_mac));
174     if (!rt_memcmp(&bad_mac, p_mac_addr, sizeof(bad_mac)))
175     {
176         DEBUG_PRINTF("mac address all one");
177         ip_addr_3 = DHCPD_CLIENT_IP_MAX;
178         goto _return;
179     }
180 
181     for (i = 0; i < MAC_TABLE_LEN; i++)
182     {
183         if (!rt_memcmp(&mac_table[i].mac_addr, p_mac_addr, sizeof(bad_mac)))
184         {
185             //use old ip
186             ip_addr_3 = mac_table[i].ip_addr_3;
187             DEBUG_PRINTF("return old ip: %d\n", (int)ip_addr_3);
188             goto _return;
189         }
190     }
191 
192     /* add new ip */
193     mac_table[offset].mac_addr = *p_mac_addr;
194     mac_table[offset].ip_addr_3  = next_client_ip;
195     ip_addr_3 = mac_table[offset].ip_addr_3 ;
196 
197     offset++;
198     if (offset >= MAC_TABLE_LEN)
199         offset = 0;
200 
201     next_client_ip++;
202     if (next_client_ip > DHCPD_CLIENT_IP_MAX)
203         next_client_ip = DHCPD_CLIENT_IP_MIN;
204 
205     DEBUG_PRINTF("create new ip: %d\n", (int)ip_addr_3);
206     DEBUG_PRINTF("next_client_ip %d\n", next_client_ip);
207 
208 _return:
209     return ip_addr_3;
210 }
211 
dhcpd_thread_entry(void * parameter)212 static void dhcpd_thread_entry(void *parameter)
213 {
214     struct netif *netif = RT_NULL;
215     int sock;
216     int bytes_read;
217     char *recv_data;
218     rt_uint32_t addr_len;
219     struct sockaddr_in server_addr, client_addr;
220     struct dhcp_msg *msg;
221     int optval = 1;
222     struct mac_addr_t mac_addr;
223     uint8_t DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1, DHCPD_SERVER_IPADDR2, DHCPD_SERVER_IPADDR3;
224 
225     /* get ethernet interface. */
226     netif = (struct netif *) parameter;
227     RT_ASSERT(netif != RT_NULL);
228 
229     /* our DHCP server information */
230     {
231 #if (LWIP_VERSION) >= 0x02000000U
232         ip4_addr_t addr;
233         ip4addr_aton(DHCPD_SERVER_IP, &addr);
234 #else
235         struct ip_addr addr;
236         ipaddr_aton(DHCPD_SERVER_IP, &addr);
237 #endif /* LWIP_VERSION */
238 
239         DHCPD_SERVER_IPADDR0 = (ntohl(addr.addr) >> 24) & 0xFF;
240         DHCPD_SERVER_IPADDR1 = (ntohl(addr.addr) >> 16) & 0xFF;
241         DHCPD_SERVER_IPADDR2 = (ntohl(addr.addr) >>  8) & 0xFF;
242         DHCPD_SERVER_IPADDR3 = (ntohl(addr.addr) >>  0) & 0xFF;
243     }
244     DEBUG_PRINTF("DHCP server IP: %d.%d.%d.%d  client IP: %d.%d.%d.%d-%d\n",
245                  DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
246                  DHCPD_SERVER_IPADDR2, DHCPD_SERVER_IPADDR3,
247                  DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
248                  DHCPD_SERVER_IPADDR2, DHCPD_CLIENT_IP_MIN, DHCPD_CLIENT_IP_MAX);
249 
250     /* allocate buffer for receive */
251     recv_data = rt_malloc(BUFSZ);
252     if (recv_data == RT_NULL)
253     {
254         /* No memory */
255         DEBUG_PRINTF("Out of memory\n");
256         return;
257     }
258 
259     /* create a socket with UDP */
260     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
261     {
262         DEBUG_PRINTF("create socket failed, errno = %d\n", errno);
263         rt_free(recv_data);
264         return;
265     }
266 
267     /* set to receive broadcast packet */
268     setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
269 
270     /* initialize server address */
271     server_addr.sin_family = AF_INET;
272     server_addr.sin_port = htons(DHCP_SERVER_PORT);
273     server_addr.sin_addr.s_addr = INADDR_ANY;
274     rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
275 
276     /* bind socket to the server address */
277     if (bind(sock, (struct sockaddr *)&server_addr,
278              sizeof(struct sockaddr)) == -1)
279     {
280         /* bind failed. */
281         DEBUG_PRINTF("bind server address failed, errno=%d\n", errno);
282         rt_free(recv_data);
283         return;
284     }
285 
286     addr_len = sizeof(struct sockaddr);
287     DEBUG_PRINTF("DHCP server listen on port %d...\n", DHCP_SERVER_PORT);
288 
289     while (1)
290     {
291         bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
292                               (struct sockaddr *)&client_addr, &addr_len);
293         if (bytes_read < DHCP_MSG_LEN)
294         {
295             DEBUG_PRINTF("packet too short, wait for next!\n");
296             continue;
297         }
298 
299         msg = (struct dhcp_msg *)recv_data;
300         /* check message type to make sure we can handle it */
301         if ((msg->op != DHCP_BOOTREQUEST) || (msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)))
302         {
303             continue;
304         }
305 
306         memcpy(mac_addr.add, msg->chaddr, MAC_ADDR_LEN);
307 
308         /* handler. */
309         {
310             uint8_t *dhcp_opt;
311             uint8_t option;
312             uint8_t length;
313 
314             uint8_t message_type = 0;
315             uint8_t finished = 0;
316             uint32_t request_ip  = 0;
317 
318             uint8_t client_ip_3;
319 
320             client_ip_3 = get_ip(&mac_addr);
321 
322             dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
323             while (finished == 0)
324             {
325                 option = *dhcp_opt;
326                 length = *(dhcp_opt + 1);
327 
328                 switch (option)
329                 {
330                 case DHCP_OPTION_REQUESTED_IP:
331                     request_ip = *(dhcp_opt + 2) << 24 | *(dhcp_opt + 3) << 16
332                                  | *(dhcp_opt + 4) << 8 | *(dhcp_opt + 5);
333                     break;
334 
335                 case DHCP_OPTION_END:
336                     finished = 1;
337                     break;
338 
339                 case DHCP_OPTION_MESSAGE_TYPE:
340                     message_type = *(dhcp_opt + 2);
341                     break;
342 
343                 default:
344                     break;
345                 } /* switch(option) */
346 
347                 dhcp_opt += (2 + length);
348             }
349 
350             /* reply. */
351             dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
352 
353             /* check. */
354             if (request_ip)
355             {
356                 uint32_t client_ip = DHCPD_SERVER_IPADDR0 << 24 | DHCPD_SERVER_IPADDR1 << 16
357                                      | DHCPD_SERVER_IPADDR2 << 8 | client_ip_3;
358 
359                 DEBUG_PRINTF("message_type: %d, request_ip: %08X, client_ip: %08X.\n", message_type, request_ip, client_ip);
360 
361                 if (request_ip != client_ip)
362                 {
363                     *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
364                     *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
365                     *dhcp_opt++ = DHCP_NAK;
366                     *dhcp_opt++ = DHCP_OPTION_END;
367 
368                     DEBUG_PRINTF("requested IP invalid, reply DHCP_NAK\n");
369 
370                     if (netif != RT_NULL)
371                     {
372                         int send_byte = (dhcp_opt - (uint8_t *)msg);
373                         _low_level_dhcp_send(netif, msg, send_byte);
374                         DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
375                     }
376 
377                     continue;
378                 }
379             }
380 
381             if (message_type == DHCP_DISCOVER)
382             {
383                 DEBUG_PRINTF("request DHCP_DISCOVER\n");
384                 DEBUG_PRINTF("reply   DHCP_OFFER\n");
385 
386                 // DHCP_OPTION_MESSAGE_TYPE
387                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
388                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
389                 *dhcp_opt++ = DHCP_OFFER;
390 
391                 // DHCP_OPTION_SERVER_ID
392                 *dhcp_opt++ = DHCP_OPTION_SERVER_ID;
393                 *dhcp_opt++ = 4;
394                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
395                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
396                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
397                 *dhcp_opt++ = DHCPD_SERVER_IPADDR3;
398 
399                 // DHCP_OPTION_LEASE_TIME
400                 *dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
401                 *dhcp_opt++ = 4;
402                 *dhcp_opt++ = 0x00;
403                 *dhcp_opt++ = 0x01;
404                 *dhcp_opt++ = 0x51;
405                 *dhcp_opt++ = 0x80;
406             }
407             else if (message_type == DHCP_REQUEST)
408             {
409                 DEBUG_PRINTF("request DHCP_REQUEST\n");
410                 DEBUG_PRINTF("reply   DHCP_ACK\n");
411 
412                 // DHCP_OPTION_MESSAGE_TYPE
413                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
414                 *dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
415                 *dhcp_opt++ = DHCP_ACK;
416 
417                 // DHCP_OPTION_SERVER_ID
418                 *dhcp_opt++ = DHCP_OPTION_SERVER_ID;
419                 *dhcp_opt++ = 4;
420                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
421                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
422                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
423                 *dhcp_opt++ = DHCPD_SERVER_IPADDR3;
424 
425                 // DHCP_OPTION_SUBNET_MASK
426                 *dhcp_opt++ = DHCP_OPTION_SUBNET_MASK;
427                 *dhcp_opt++ = 4;
428                 *dhcp_opt++ = 0xFF;
429                 *dhcp_opt++ = 0xFF;
430                 *dhcp_opt++ = 0xFF;
431                 *dhcp_opt++ = 0x00;
432 
433 #ifdef DHCPD_USING_ROUTER
434                 // DHCP_OPTION_ROUTER
435                 *dhcp_opt++ = DHCP_OPTION_ROUTER;
436                 *dhcp_opt++ = 4;
437                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
438                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
439                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
440                 *dhcp_opt++ = 1;
441 #endif
442 
443                 // DHCP_OPTION_DNS_SERVER, use the default DNS server address in lwIP
444                 *dhcp_opt++ = DHCP_OPTION_DNS_SERVER;
445                 *dhcp_opt++ = 4;
446 
447 #ifndef DHCP_DNS_SERVER_IP
448                 *dhcp_opt++ = DHCPD_SERVER_IPADDR0;
449                 *dhcp_opt++ = DHCPD_SERVER_IPADDR1;
450                 *dhcp_opt++ = DHCPD_SERVER_IPADDR2;
451                 *dhcp_opt++ = 1;
452 #else
453                 {
454 #if (LWIP_VERSION) >= 0x02000000U
455                     ip4_addr_t dns_addr;
456 #else
457                     struct ip_addr dns_addr;
458 #endif /* LWIP_VERSION */
459                     ip4addr_aton(DHCP_DNS_SERVER_IP, &dns_addr);
460 
461                     *dhcp_opt++ = (ntohl(dns_addr.addr) >> 24) & 0xFF;
462                     *dhcp_opt++ = (ntohl(dns_addr.addr) >> 16) & 0xFF;
463                     *dhcp_opt++ = (ntohl(dns_addr.addr) >>  8) & 0xFF;
464                     *dhcp_opt++ = (ntohl(dns_addr.addr) >>  0) & 0xFF;
465                 }
466 #endif
467 
468                 // DHCP_OPTION_LEASE_TIME
469                 *dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
470                 *dhcp_opt++ = 4;
471                 *dhcp_opt++ = 0x00;
472                 *dhcp_opt++ = 0x01;
473                 *dhcp_opt++ = 0x51;
474                 *dhcp_opt++ = 0x80;
475             }
476             else
477             {
478                 DEBUG_PRINTF("un handle message:%d\n", message_type);
479             }
480 
481             // append DHCP_OPTION_END
482             *dhcp_opt++ = DHCP_OPTION_END;
483 
484             /* send reply. */
485             if ((message_type == DHCP_DISCOVER) || (message_type == DHCP_REQUEST))
486             {
487                 msg->op = DHCP_BOOTREPLY;
488                 IP4_ADDR(&msg->yiaddr,
489                          DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
490                          DHCPD_SERVER_IPADDR2, client_ip_3);
491 
492                 client_addr.sin_addr.s_addr = INADDR_BROADCAST;
493 
494                 if (netif != RT_NULL)
495                 {
496                     int send_byte = (dhcp_opt - (uint8_t *)msg);
497                     _low_level_dhcp_send(netif, msg, send_byte);
498                     DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
499                 }
500             }
501         } /* handler. */
502     }
503 }
504 
dhcpd_start(const char * netif_name)505 void dhcpd_start(const char *netif_name)
506 {
507     rt_thread_t thread;
508     struct netif *netif = netif_list;
509 
510     if (strlen(netif_name) > sizeof(netif->name))
511     {
512         rt_kprintf("network interface name too long!\r\n");
513         return;
514     }
515     while (netif != RT_NULL)
516     {
517         if (strncmp(netif_name, netif->name, sizeof(netif->name)) == 0)
518             break;
519 
520         netif = netif->next;
521         if (netif == RT_NULL)
522         {
523             rt_kprintf("network interface: %s not found!\r\n", netif_name);
524             return;
525         }
526     }
527 
528     if (1)
529     {
530         extern void set_if(const char *netif_name, const char *ip_addr, const char *gw_addr, const char *nm_addr);
531 
532         dhcp_stop(netif);
533 
534         set_if(netif_name, DHCPD_SERVER_IP, "0.0.0.0", "255.255.255.0");
535 
536         netif_set_up(netif);
537     }
538 
539     thread = rt_thread_create("dhcpd",
540                               dhcpd_thread_entry, netif,
541                               1024,
542                               RT_THREAD_PRIORITY_MAX - 3,
543                               2);
544     if (thread != RT_NULL)
545     {
546         rt_thread_startup(thread);
547     }
548 }
549 
550