-
Notifications
You must be signed in to change notification settings - Fork 1
/
dhcp.c
145 lines (128 loc) · 4.14 KB
/
dhcp.c
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
32
33
34
35
36
37
38
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include "dhcp.h"
#include "error.h"
#include "task.h"
#include "string.h"
#include "stdio.h"
#include "utils.h"
__attribute__ ((aligned (16))) uint8_t dhcp_req_buff[512];
dhcp_packet_t *const dhcp_req = (dhcp_packet_t *)dhcp_req_buff;
__attribute__ ((aligned (16))) uint8_t dhcp_buff[1024];
dhcp_packet_t *const dhcp_packet = (dhcp_packet_t *)dhcp_buff;
int dhcp_check(dhcp_packet_t *dhcp, size_t len, uint32_t xid)
{
if (len < sizeof(dhcp_packet_t) + 4)
{
return -EOOB;
}
if (!(dhcp->op == DHCP_OP_REPLY
&& dhcp->htype == DHCP_HTYPE
&& dhcp->hlen == DHCP_HLEN
&& dhcp->xid == xid
&& dhcp->magic_cookie == DHCP_MAGIC_COOKIE
&& dhcp->options[0] == DHCP_OPTION_MESSAGE_TYPE
&& dhcp->options[1] == 0x01))
{
return -EBADPKT;
}
return 0;
}
__attribute__ ((aligned (16))) uint8_t dhcp_stack[1024];
static struct task dhcp_task;
static void dhcp_entry()
{
if (get_ip_ready() && !ipv4_is_unspecified(get_ifinfo_ipv4()))
{
exit();
}
const uint64_t mac = get_ifinfo_mac();
uint32_t xid = rdcycle() ^ 0xaa55ccdd;
dhcp_req->op = DHCP_OP_REQUEST;
dhcp_req->htype = DHCP_HTYPE;
dhcp_req->hlen = DHCP_HLEN;
dhcp_req->hops = 0;
dhcp_req->xid = xid;
dhcp_req->secs = 0;
dhcp_req->flags = 0;
dhcp_req->ciaddr = ipv4_unspecified();
dhcp_req->yiaddr = ipv4_unspecified();
dhcp_req->siaddr = ipv4_unspecified();
dhcp_req->giaddr = ipv4_unspecified();
memcpy(dhcp_req->chaddr, &mac, DHCP_HLEN);
memset(dhcp_req->reserved, 0, sizeof(dhcp_req->reserved));
dhcp_req->magic_cookie = DHCP_MAGIC_COOKIE;
dhcp_req->options[0] = DHCP_OPTION_MESSAGE_TYPE;
dhcp_req->options[1] = 0x01;
dhcp_req->options[2] = DHCP_MESSAGE_TYPE_DISCOVER;
dhcp_req->options[3] = DHCP_OPTION_END;
printf("DHCP Client: Waiting for DHCP server... ");
ipv6_addr_t saddr;
uint16_t sport;
while (1)
{
send_udp(DHCP_CLIENT_PORT, ipv4_compatible(ipv4_broadcast()), DHCP_SERVER_PORT,
dhcp_req, sizeof(dhcp_packet_t) + 4);
size_t ret = recv_udp(DHCP_CLIENT_PORT, &saddr, &sport, dhcp_buff, sizeof(dhcp_buff),
ipv6_unspecified(), DHCP_SERVER_PORT, 3 * CLOCK_FREQ);
if (ret != 0)
{
if (dhcp_check(dhcp_packet, ret, xid) == 0
&& dhcp_packet->options[2] == DHCP_MESSAGE_TYPE_OFFER)
{
break;
}
}
else
{
printf("timed out, retrying... ");
}
}
ipv4_addr_t dhcp_server_addr = extract_ipv4(saddr);
ipv4_addr_t ip = dhcp_packet->yiaddr;
printf("get ip ");
print_ipv4(ip.u8);
printf(" from ");
print_ipv4(dhcp_server_addr.u8);
printf("\n");
set_ifinfo_ipv4(ip);
set_dhcp_server_ip(ipv4_compatible(dhcp_server_addr));
dhcp_req->options[2] = DHCP_MESSAGE_TYPE_REQUEST;
dhcp_req->options[3] = DHCP_OPTION_REQ_ADDR;
dhcp_req->options[4] = 0x04;
memcpy(&dhcp_req->options[5], ip.u8, 4);
dhcp_req->options[9] = DHCP_OPTION_END;
printf("DHCP Client: Sending request... ");
while (1)
{
send_udp(DHCP_CLIENT_PORT, ipv4_compatible(dhcp_server_addr), DHCP_SERVER_PORT,
dhcp_req, sizeof(dhcp_packet_t) + 10);
ipv6_addr_t saddr;
uint16_t sport;
size_t ret = recv_udp(DHCP_CLIENT_PORT, &saddr, &sport, dhcp_buff, sizeof(dhcp_buff),
ipv4_compatible(dhcp_server_addr), DHCP_SERVER_PORT, CLOCK_FREQ / 4);
if (ret != 0)
{
if (dhcp_check(dhcp_packet, ret, xid) == 0
&& dhcp_packet->options[2] == DHCP_MESSAGE_TYPE_ACK)
{
break;
}
}
else
{
printf("timed out, retrying... ");
}
}
ip = dhcp_packet->yiaddr;
printf("get ip ");
print_ipv4(ip.u8);
printf(" from ");
print_ipv4(dhcp_server_addr.u8);
printf("\n");
set_ifinfo_ipv4(ip);
set_ip_ready(true);
exit();
}
void init_dhcp()
{
create_task(&dhcp_task, (uintptr_t)dhcp_stack + sizeof(dhcp_stack) + STACK_OFFSET, dhcp_entry);
}