Skip to content

Commit a1252f6

Browse files
committed
[lwIP] Add DHCP server implementation
1 parent 068e2f9 commit a1252f6

File tree

3 files changed

+426
-0
lines changed

3 files changed

+426
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from building import *
2+
3+
cwd = GetCurrentDir()
4+
src = Glob('*.c')
5+
6+
CPPPATH = [cwd]
7+
8+
group = DefineGroup('LwIP', src, depend = ['RT_USING_LWIP', 'LWIP_USING_DHCPD'], CPPPATH = CPPPATH)
9+
10+
Return('group')
Lines changed: 380 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,380 @@
1+
/*
2+
* File : dhcp_server.c
3+
* A simple DHCP server implementation
4+
*
5+
* This file is part of RT-Thread RTOS
6+
* COPYRIGHT (C) 2013-2015, Shanghai Real-Thread Technology Co., Ltd
7+
* http://www.rt-thread.com
8+
*
9+
* This program is free software; you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation; either version 2 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License along
20+
* with this program; if not, write to the Free Software Foundation, Inc.,
21+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22+
*
23+
* Change Logs:
24+
* Date Author Notes
25+
* 2013-01-30 aozima the first version
26+
* 2013-08-08 aozima support different network segments.
27+
* 2015-01-30 bernard release to RT-Thread RTOS.
28+
*/
29+
30+
#include <stdio.h>
31+
#include <stdint.h>
32+
#include <rtthread.h>
33+
34+
#include <lwip/opt.h>
35+
#include <lwip/sockets.h>
36+
#include <lwip/inet_chksum.h>
37+
#include <netif/etharp.h>
38+
#include <netif/ethernetif.h>
39+
#include <lwip/ip.h>
40+
41+
/* DHCP server option */
42+
43+
/* allocated client ip range */
44+
#ifndef DHCPD_CLIENT_IP_MIN
45+
#define DHCPD_CLIENT_IP_MIN 2
46+
#endif
47+
#ifndef DHCPD_CLIENT_IP_MAX
48+
#define DHCPD_CLIENT_IP_MAX 254
49+
#endif
50+
51+
/* the DHCP server address */
52+
#ifndef DHCPD_SERVER_IPADDR0
53+
#define DHCPD_SERVER_IPADDR0 192UL
54+
#define DHCPD_SERVER_IPADDR1 168UL
55+
#define DHCPD_SERVER_IPADDR2 169UL
56+
#define DHCPD_SERVER_IPADDR3 1UL
57+
#endif
58+
59+
//#define DHCP_DEBUG_PRINTF
60+
61+
#ifdef DHCP_DEBUG_PRINTF
62+
#define DEBUG_PRINTF rt_kprintf("[DHCP] "); rt_kprintf
63+
#else
64+
#define DEBUG_PRINTF(...)
65+
#endif /* DHCP_DEBUG_PRINTF */
66+
67+
/* we need some routines in the DHCP of lwIP */
68+
#undef LWIP_DHCP
69+
#define LWIP_DHCP 1
70+
#include <lwip/dhcp.h>
71+
72+
/* buffer size for receive DHCP packet */
73+
#define BUFSZ 1024
74+
75+
static uint8_t next_client_ip = DHCPD_CLIENT_IP_MIN;
76+
static rt_err_t _low_level_dhcp_send(struct netif *netif,
77+
const void *buffer,
78+
rt_size_t size)
79+
{
80+
struct pbuf *p;
81+
struct eth_hdr *ethhdr;
82+
struct ip_hdr *iphdr;
83+
struct udp_hdr *udphdr;
84+
85+
p = pbuf_alloc(PBUF_LINK,
86+
SIZEOF_ETH_HDR + sizeof(struct ip_hdr)
87+
+ sizeof(struct udp_hdr) + size,
88+
PBUF_RAM);
89+
if (p == RT_NULL) return -RT_ENOMEM;
90+
91+
ethhdr = (struct eth_hdr *)p->payload;
92+
iphdr = (struct ip_hdr *)((char *)ethhdr + SIZEOF_ETH_HDR);
93+
udphdr = (struct udp_hdr *)((char *)iphdr + sizeof(struct ip_hdr));
94+
95+
ETHADDR32_COPY(&ethhdr->dest, (struct eth_addr *)&ethbroadcast);
96+
ETHADDR16_COPY(&ethhdr->src, netif->hwaddr);
97+
ethhdr->type = PP_HTONS(ETHTYPE_IP);
98+
99+
iphdr->src.addr = 0x00000000; /* src: 0.0.0.0 */
100+
iphdr->dest.addr = 0xFFFFFFFF; /* src: 255.255.255.255 */
101+
102+
IPH_VHL_SET(iphdr, 4, IP_HLEN / 4);
103+
IPH_TOS_SET(iphdr, 0x00);
104+
IPH_LEN_SET(iphdr, htons(IP_HLEN + sizeof(struct udp_hdr) + size));
105+
IPH_ID_SET(iphdr, htons(2));
106+
IPH_OFFSET_SET(iphdr, 0);
107+
IPH_TTL_SET(iphdr, 255);
108+
IPH_PROTO_SET(iphdr, IP_PROTO_UDP);
109+
IPH_CHKSUM_SET(iphdr, 0);
110+
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
111+
112+
udphdr->src = htons(DHCP_SERVER_PORT);
113+
udphdr->dest = htons(DHCP_CLIENT_PORT);
114+
udphdr->len = htons(sizeof(struct udp_hdr) + size);
115+
udphdr->chksum = 0;
116+
117+
memcpy((char *)udphdr + sizeof(struct udp_hdr),
118+
buffer, size);
119+
120+
return netif->linkoutput(netif, p);
121+
}
122+
123+
static void dhcpd_thread_entry(void *parameter)
124+
{
125+
struct netif *netif = RT_NULL;
126+
int sock;
127+
int bytes_read;
128+
char *recv_data;
129+
rt_uint32_t addr_len;
130+
struct sockaddr_in server_addr, client_addr;
131+
struct dhcp_msg *msg;
132+
int optval = 1;
133+
134+
/* get ethernet interface. */
135+
netif = (struct netif*) parameter;
136+
RT_ASSERT(netif != RT_NULL);
137+
138+
/* our DHCP server information */
139+
DEBUG_PRINTF("DHCP server IP: %d.%d.%d.%d client IP: %d.%d.%d.%d-%d\n",
140+
DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
141+
DHCPD_SERVER_IPADDR2, DHCPD_SERVER_IPADDR3,
142+
DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
143+
DHCPD_SERVER_IPADDR2, DHCPD_CLIENT_IP_MIN, DHCPD_CLIENT_IP_MAX);
144+
145+
/* allocate buffer for receive */
146+
recv_data = rt_malloc(BUFSZ);
147+
if (recv_data == RT_NULL)
148+
{
149+
/* No memory */
150+
DEBUG_PRINTF("Out of memory\n");
151+
return;
152+
}
153+
154+
/* create a socket with UDP */
155+
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
156+
{
157+
DEBUG_PRINTF("create socket failed, errno = %d\n", errno);
158+
rt_free(recv_data);
159+
return;
160+
}
161+
162+
/* set to receive broadcast packet */
163+
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval));
164+
165+
/* initialize server address */
166+
server_addr.sin_family = AF_INET;
167+
server_addr.sin_port = htons(DHCP_SERVER_PORT);
168+
server_addr.sin_addr.s_addr = INADDR_ANY;
169+
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
170+
171+
/* bind socket to the server address */
172+
if (bind(sock, (struct sockaddr *)&server_addr,
173+
sizeof(struct sockaddr)) == -1)
174+
{
175+
/* bind failed. */
176+
DEBUG_PRINTF("bind server address failed, errno=%d\n", errno);
177+
rt_free(recv_data);
178+
return;
179+
}
180+
181+
addr_len = sizeof(struct sockaddr);
182+
DEBUG_PRINTF("DHCP server listen on port %d...\n", DHCP_SERVER_PORT);
183+
184+
while (1)
185+
{
186+
bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
187+
(struct sockaddr *)&client_addr, &addr_len);
188+
if (bytes_read < DHCP_MSG_LEN)
189+
{
190+
DEBUG_PRINTF("packet too short, wait for next!\n");
191+
continue;
192+
}
193+
194+
msg = (struct dhcp_msg *)recv_data;
195+
/* check message type to make sure we can handle it */
196+
if ((msg->op != DHCP_BOOTREQUEST) || (msg->cookie != PP_HTONL(DHCP_MAGIC_COOKIE)))
197+
{
198+
continue;
199+
}
200+
201+
/* handler. */
202+
{
203+
uint8_t *dhcp_opt;
204+
uint8_t option;
205+
uint8_t length;
206+
207+
uint8_t message_type = 0;
208+
uint8_t finished = 0;
209+
uint32_t request_ip = 0;
210+
211+
dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
212+
while (finished == 0)
213+
{
214+
option = *dhcp_opt;
215+
length = *(dhcp_opt + 1);
216+
217+
switch (option)
218+
{
219+
case DHCP_OPTION_REQUESTED_IP:
220+
request_ip = *(dhcp_opt + 2) << 24 | *(dhcp_opt + 3) << 16
221+
| *(dhcp_opt + 4) << 8 | *(dhcp_opt + 5);
222+
break;
223+
224+
case DHCP_OPTION_END:
225+
finished = 1;
226+
break;
227+
228+
case DHCP_OPTION_MESSAGE_TYPE:
229+
message_type = *(dhcp_opt + 2);
230+
break;
231+
232+
default:
233+
break;
234+
} /* switch(option) */
235+
236+
dhcp_opt += (2 + length);
237+
}
238+
239+
/* reply. */
240+
dhcp_opt = (uint8_t *)msg + DHCP_OPTIONS_OFS;
241+
242+
/* check. */
243+
if (request_ip)
244+
{
245+
uint32_t client_ip = DHCPD_SERVER_IPADDR0 << 24 | DHCPD_SERVER_IPADDR1 << 16
246+
| DHCPD_SERVER_IPADDR2 << 8 | (next_client_ip);
247+
248+
if (request_ip != client_ip)
249+
{
250+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
251+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
252+
*dhcp_opt++ = DHCP_NAK;
253+
*dhcp_opt++ = DHCP_OPTION_END;
254+
255+
DEBUG_PRINTF("requested IP invalid, reply DHCP_NAK\n");
256+
if (netif != RT_NULL)
257+
{
258+
int send_byte = (dhcp_opt - (uint8_t *)msg);
259+
_low_level_dhcp_send(netif, msg, send_byte);
260+
DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
261+
}
262+
next_client_ip++;
263+
if (next_client_ip > DHCPD_CLIENT_IP_MAX)
264+
next_client_ip = DHCPD_CLIENT_IP_MIN;
265+
continue;
266+
}
267+
}
268+
269+
if (message_type == DHCP_DISCOVER)
270+
{
271+
DEBUG_PRINTF("request DHCP_DISCOVER\n");
272+
DEBUG_PRINTF("reply DHCP_OFFER\n");
273+
274+
// DHCP_OPTION_MESSAGE_TYPE
275+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
276+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
277+
*dhcp_opt++ = DHCP_OFFER;
278+
279+
// DHCP_OPTION_SERVER_ID
280+
*dhcp_opt++ = DHCP_OPTION_SERVER_ID;
281+
*dhcp_opt++ = 4;
282+
*dhcp_opt++ = DHCPD_SERVER_IPADDR0;
283+
*dhcp_opt++ = DHCPD_SERVER_IPADDR1;
284+
*dhcp_opt++ = DHCPD_SERVER_IPADDR2;
285+
*dhcp_opt++ = DHCPD_SERVER_IPADDR3;
286+
287+
// DHCP_OPTION_LEASE_TIME
288+
*dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
289+
*dhcp_opt++ = 4;
290+
*dhcp_opt++ = 0x00;
291+
*dhcp_opt++ = 0x01;
292+
*dhcp_opt++ = 0x51;
293+
*dhcp_opt++ = 0x80;
294+
}
295+
else if (message_type == DHCP_REQUEST)
296+
{
297+
DEBUG_PRINTF("request DHCP_REQUEST\n");
298+
DEBUG_PRINTF("reply DHCP_ACK\n");
299+
300+
// DHCP_OPTION_MESSAGE_TYPE
301+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE;
302+
*dhcp_opt++ = DHCP_OPTION_MESSAGE_TYPE_LEN;
303+
*dhcp_opt++ = DHCP_ACK;
304+
305+
// DHCP_OPTION_SERVER_ID
306+
*dhcp_opt++ = DHCP_OPTION_SERVER_ID;
307+
*dhcp_opt++ = 4;
308+
*dhcp_opt++ = DHCPD_SERVER_IPADDR0;
309+
*dhcp_opt++ = DHCPD_SERVER_IPADDR1;
310+
*dhcp_opt++ = DHCPD_SERVER_IPADDR2;
311+
*dhcp_opt++ = DHCPD_SERVER_IPADDR3;
312+
313+
// DHCP_OPTION_SUBNET_MASK
314+
*dhcp_opt++ = DHCP_OPTION_SUBNET_MASK;
315+
*dhcp_opt++ = 4;
316+
*dhcp_opt++ = 0xFF;
317+
*dhcp_opt++ = 0xFF;
318+
*dhcp_opt++ = 0xFF;
319+
*dhcp_opt++ = 0x00;
320+
321+
// DHCP_OPTION_LEASE_TIME
322+
*dhcp_opt++ = DHCP_OPTION_LEASE_TIME;
323+
*dhcp_opt++ = 4;
324+
*dhcp_opt++ = 0x00;
325+
*dhcp_opt++ = 0x01;
326+
*dhcp_opt++ = 0x51;
327+
*dhcp_opt++ = 0x80;
328+
}
329+
else
330+
{
331+
DEBUG_PRINTF("un handle message:%d\n", message_type);
332+
}
333+
334+
// append DHCP_OPTION_END
335+
*dhcp_opt++ = DHCP_OPTION_END;
336+
337+
/* send reply. */
338+
if ((message_type == DHCP_DISCOVER) || (message_type == DHCP_REQUEST))
339+
{
340+
msg->op = DHCP_BOOTREPLY;
341+
IP4_ADDR(&msg->yiaddr,
342+
DHCPD_SERVER_IPADDR0, DHCPD_SERVER_IPADDR1,
343+
DHCPD_SERVER_IPADDR2, next_client_ip);
344+
345+
client_addr.sin_addr.s_addr = INADDR_BROADCAST;
346+
347+
if (netif != RT_NULL)
348+
{
349+
int send_byte = (dhcp_opt - (uint8_t *)msg);
350+
_low_level_dhcp_send(netif, msg, send_byte);
351+
DEBUG_PRINTF("DHCP server send %d byte\n", send_byte);
352+
}
353+
}
354+
} /* handler. */
355+
}
356+
}
357+
358+
void dhcpd_start(char* netif_name)
359+
{
360+
rt_thread_t thread;
361+
struct netif *netif = RT_NULL;
362+
363+
/* find ethernet interface. */
364+
netif = netif_find(netif_name);
365+
if (netif == RT_NULL)
366+
{
367+
DEBUG_PRINTF("Not found network interface:%s\n", netif_name);
368+
}
369+
370+
thread = rt_thread_create("dhcpd",
371+
dhcpd_thread_entry, netif,
372+
1024,
373+
RT_THREAD_PRIORITY_MAX - 3,
374+
2);
375+
if (thread != RT_NULL)
376+
{
377+
rt_thread_startup(thread);
378+
}
379+
}
380+

0 commit comments

Comments
 (0)