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 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(ðhdr->dest, (struct eth_addr *)ðbroadcast); 125 ETHADDR16_COPY(ðhdr->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 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 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 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