1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
97
98
99
100
101
102
103
104
110
111
115
116
117
120
121
122
125
126
127
128
129
130
131
136
137
138
139
142
143
144
145
146
155
156
163
164
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
196
197
198
201
202
203
204
205
206
207
208
209
213
214
215
216
217
237
241
242
243
244
245
246
247
248
252
256
257
261
271
272
273
274
275
276
277
278
279
280
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
306
307
/* ... */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "cyw43_config.h"
#include "dhcpserver.h"
#include "lwip/udp.h"
6 includes
#define DHCPDISCOVER (1)
#define DHCPOFFER (2)
#define DHCPREQUEST (3)
#define DHCPDECLINE (4)
#define DHCPACK (5)
#define DHCPNACK (6)
#define DHCPRELEASE (7)
#define DHCPINFORM (8)
#define DHCP_OPT_PAD (0)
#define DHCP_OPT_SUBNET_MASK (1)
#define DHCP_OPT_ROUTER (3)
#define DHCP_OPT_DNS (6)
#define DHCP_OPT_HOST_NAME (12)
#define DHCP_OPT_REQUESTED_IP (50)
#define DHCP_OPT_IP_LEASE_TIME (51)
#define DHCP_OPT_MSG_TYPE (53)
#define DHCP_OPT_SERVER_ID (54)
#define DHCP_OPT_PARAM_REQUEST_LIST (55)
#define DHCP_OPT_MAX_MSG_SIZE (57)
#define DHCP_OPT_VENDOR_CLASS_ID (60)
#define DHCP_OPT_CLIENT_ID (61)
#define DHCP_OPT_END (255)
#define PORT_DHCP_SERVER (67)
#define PORT_DHCP_CLIENT (68)
#define DEFAULT_LEASE_TIME_S (24 * 60 * 60)
#define MAC_LEN (6)
#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
27 defines
typedef struct {
uint8_t op;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
uint8_t ciaddr[4];
uint8_t yiaddr[4];
uint8_t siaddr[4];
uint8_t giaddr[4];
uint8_t chaddr[16];
uint8_t sname[64];
uint8_t file[128];
uint8_t options[312];
...} dhcp_msg_t;
static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) {
*udp = udp_new();
if (*udp == NULL) {
return -ENOMEM;
}if (*udp == NULL) { ... }
udp_recv(*udp, cb_udp_recv, (void *)cb_data);
return 0;
}{ ... }
static void dhcp_socket_free(struct udp_pcb **udp) {
if (*udp != NULL) {
udp_remove(*udp);
*udp = NULL;
}if (*udp != NULL) { ... }
}{ ... }
static int dhcp_socket_bind(struct udp_pcb **udp, uint16_t port) {
return udp_bind(*udp, IP_ANY_TYPE, port);
}{ ... }
static int dhcp_socket_sendto(struct udp_pcb **udp, struct netif *nif, const void *buf, size_t len, uint32_t ip, uint16_t port) {
if (len > 0xffff) {
len = 0xffff;
}if (len > 0xffff) { ... }
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
if (p == NULL) {
return -ENOMEM;
}if (p == NULL) { ... }
memcpy(p->payload, buf, len);
ip_addr_t dest;
IP4_ADDR(ip_2_ip4(&dest), ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
err_t err;
if (nif != NULL) {
err = udp_sendto_if(*udp, p, &dest, port, nif);
}if (nif != NULL) { ... } else {
err = udp_sendto(*udp, p, &dest, port);
}else { ... }
pbuf_free(p);
if (err != ERR_OK) {
return err;
}if (err != ERR_OK) { ... }
return len;
}{ ... }
static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) {
for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) {
if (opt[i] == cmd) {
return &opt[i];
}if (opt[i] == cmd) { ... }
i += 2 + opt[i + 1];
}for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { ... }
return NULL;
}{ ... }
static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, const void *data) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = n;
memcpy(o, data, n);
*opt = o + n;
}{ ... }
static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = 1;
*o++ = val;
*opt = o;
}{ ... }
static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) {
uint8_t *o = *opt;
*o++ = cmd;
*o++ = 4;
*o++ = val >> 24;
*o++ = val >> 16;
*o++ = val >> 8;
*o++ = val;
*opt = o;
}{ ... }
static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) {
dhcp_server_t *d = arg;
(void)upcb;
(void)src_addr;
(void)src_port;
dhcp_msg_t dhcp_msg;
#define DHCP_MIN_SIZE (240 + 3)
if (p->tot_len < DHCP_MIN_SIZE) {
goto ignore_request;
}if (p->tot_len < DHCP_MIN_SIZE) { ... }
size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0);
if (len < DHCP_MIN_SIZE) {
goto ignore_request;
}if (len < DHCP_MIN_SIZE) { ... }
dhcp_msg.op = DHCPOFFER;
memcpy(&dhcp_msg.yiaddr, &ip4_addr_get_u32(ip_2_ip4(&d->ip)), 4);
uint8_t *opt = (uint8_t *)&dhcp_msg.options;
opt += 4;
uint8_t *msgtype = opt_find(opt, DHCP_OPT_MSG_TYPE);
if (msgtype == NULL) {
goto ignore_request;
}if (msgtype == NULL) { ... }
switch (msgtype[2]) {
case DHCPDISCOVER: {
int yi = DHCPS_MAX_IP;
for (int i = 0; i < DHCPS_MAX_IP; ++i) {
if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
yi = i;
break;
}if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { ... }
if (yi == DHCPS_MAX_IP) {
if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
yi = i;
}if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { ... }
uint32_t expiry = d->lease[i].expiry << 16 | 0xffff;
if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) {
memset(d->lease[i].mac, 0, MAC_LEN);
yi = i;
}if ((int32_t)(expiry - cyw43_hal_ticks_ms()) < 0) { ... }
}if (yi == DHCPS_MAX_IP) { ... }
}for (int i = 0; i < DHCPS_MAX_IP; ++i) { ... }
if (yi == DHCPS_MAX_IP) {
goto ignore_request;
}if (yi == DHCPS_MAX_IP) { ... }
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER);
break;
...}
case DHCPDISCOVER:
case DHCPREQUEST: {
uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP);
if (o == NULL) {
goto ignore_request;
}if (o == NULL) { ... }
if (memcmp(o + 2, &ip4_addr_get_u32(ip_2_ip4(&d->ip)), 3) != 0) {
goto ignore_request;
}if (memcmp(o + 2, &ip4_addr_get_u32(ip_2_ip4(&d->ip)), 3) != 0) { ... }
uint8_t yi = o[5] - DHCPS_BASE_IP;
if (yi >= DHCPS_MAX_IP) {
goto ignore_request;
}if (yi >= DHCPS_MAX_IP) { ... }
if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) {
}if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { ... } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) {
memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN);
}else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { ... } else {
goto ignore_request;
}else { ... }
d->lease[yi].expiry = (cyw43_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16;
dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi;
opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK);
printf("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n",
dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5],
dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3]);
break;
...}
case DHCPREQUEST:
default:
goto ignore_request;default
}switch (msgtype[2]) { ... }
opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &ip4_addr_get_u32(ip_2_ip4(&d->ip)));
opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &ip4_addr_get_u32(ip_2_ip4(&d->nm)));
opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip4_addr_get_u32(ip_2_ip4(&d->ip)));
opt_write_n(&opt, DHCP_OPT_DNS, 4, &ip4_addr_get_u32(ip_2_ip4(&d->ip)));
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
*opt++ = DHCP_OPT_END;
struct netif *nif = ip_current_input_netif();
dhcp_socket_sendto(&d->udp, nif, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT);
ignore_request:
pbuf_free(p);
}{ ... }
void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) {
ip_addr_copy(d->ip, *ip);
ip_addr_copy(d->nm, *nm);
memset(d->lease, 0, sizeof(d->lease));
if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) {
return;
}if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { ... }
dhcp_socket_bind(&d->udp, PORT_DHCP_SERVER);
}{ ... }
void dhcp_server_deinit(dhcp_server_t *d) {
dhcp_socket_free(&d->udp);
}{ ... }