root / arduino-1.0 / libraries / Ethernet / Dhcp.cpp @ 58d82c77
History | View | Annotate | Download (10.2 KB)
1 |
// DHCP Library v0.3 - April 25, 2009
|
---|---|
2 |
// Author: Jordan Terrell - blog.jordanterrell.com
|
3 |
|
4 |
#include "w5100.h" |
5 |
|
6 |
#include <string.h> |
7 |
#include <stdlib.h> |
8 |
#include "Dhcp.h" |
9 |
#include "Arduino.h" |
10 |
#include "util.h" |
11 |
|
12 |
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) |
13 |
{ |
14 |
uint8_t dhcp_state = STATE_DHCP_START; |
15 |
uint8_t messageType = 0;
|
16 |
|
17 |
// zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
|
18 |
memset(_dhcpMacAddr, 0, 26); |
19 |
|
20 |
memcpy((void*)_dhcpMacAddr, (void*)mac, 6); |
21 |
|
22 |
// Pick an initial transaction ID
|
23 |
_dhcpTransactionId = random(1UL, 2000UL); |
24 |
_dhcpInitialTransactionId = _dhcpTransactionId; |
25 |
|
26 |
if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) |
27 |
{ |
28 |
// Couldn't get a socket
|
29 |
return 0; |
30 |
} |
31 |
|
32 |
presend_DHCP(); |
33 |
|
34 |
int result = 0; |
35 |
|
36 |
unsigned long startTime = millis(); |
37 |
|
38 |
while(dhcp_state != STATE_DHCP_LEASED)
|
39 |
{ |
40 |
if(dhcp_state == STATE_DHCP_START)
|
41 |
{ |
42 |
_dhcpTransactionId++; |
43 |
|
44 |
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
|
45 |
dhcp_state = STATE_DHCP_DISCOVER; |
46 |
} |
47 |
else if(dhcp_state == STATE_DHCP_DISCOVER) |
48 |
{ |
49 |
uint32_t respId; |
50 |
messageType = parseDHCPResponse(responseTimeout, respId); |
51 |
if(messageType == DHCP_OFFER)
|
52 |
{ |
53 |
// We'll use the transaction ID that the offer came with,
|
54 |
// rather than the one we were up to
|
55 |
_dhcpTransactionId = respId; |
56 |
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
|
57 |
dhcp_state = STATE_DHCP_REQUEST; |
58 |
} |
59 |
} |
60 |
else if(dhcp_state == STATE_DHCP_REQUEST) |
61 |
{ |
62 |
uint32_t respId; |
63 |
messageType = parseDHCPResponse(responseTimeout, respId); |
64 |
if(messageType == DHCP_ACK)
|
65 |
{ |
66 |
dhcp_state = STATE_DHCP_LEASED; |
67 |
result = 1;
|
68 |
} |
69 |
else if(messageType == DHCP_NAK) |
70 |
dhcp_state = STATE_DHCP_START; |
71 |
} |
72 |
|
73 |
if(messageType == 255) |
74 |
{ |
75 |
messageType = 0;
|
76 |
dhcp_state = STATE_DHCP_START; |
77 |
} |
78 |
|
79 |
if(result != 1 && ((millis() - startTime) > timeout)) |
80 |
break;
|
81 |
} |
82 |
|
83 |
// We're done with the socket now
|
84 |
_dhcpUdpSocket.stop(); |
85 |
_dhcpTransactionId++; |
86 |
|
87 |
return result;
|
88 |
} |
89 |
|
90 |
void DhcpClass::presend_DHCP()
|
91 |
{ |
92 |
} |
93 |
|
94 |
void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
|
95 |
{ |
96 |
uint8_t buffer[32];
|
97 |
memset(buffer, 0, 32); |
98 |
IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address |
99 |
|
100 |
if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) |
101 |
{ |
102 |
// FIXME Need to return errors
|
103 |
return;
|
104 |
} |
105 |
|
106 |
buffer[0] = DHCP_BOOTREQUEST; // op |
107 |
buffer[1] = DHCP_HTYPE10MB; // htype |
108 |
buffer[2] = DHCP_HLENETHERNET; // hlen |
109 |
buffer[3] = DHCP_HOPS; // hops |
110 |
|
111 |
// xid
|
112 |
unsigned long xid = htonl(_dhcpTransactionId); |
113 |
memcpy(buffer + 4, &(xid), 4); |
114 |
|
115 |
// 8, 9 - seconds elapsed
|
116 |
buffer[8] = ((secondsElapsed & 0xff00) >> 8); |
117 |
buffer[9] = (secondsElapsed & 0x00ff); |
118 |
|
119 |
// flags
|
120 |
unsigned short flags = htons(DHCP_FLAGSBROADCAST); |
121 |
memcpy(buffer + 10, &(flags), 2); |
122 |
|
123 |
// ciaddr: already zeroed
|
124 |
// yiaddr: already zeroed
|
125 |
// siaddr: already zeroed
|
126 |
// giaddr: already zeroed
|
127 |
|
128 |
//put data in W5100 transmit buffer
|
129 |
_dhcpUdpSocket.write(buffer, 28);
|
130 |
|
131 |
memset(buffer, 0, 32); // clear local buffer |
132 |
|
133 |
memcpy(buffer, _dhcpMacAddr, 6); // chaddr |
134 |
|
135 |
//put data in W5100 transmit buffer
|
136 |
_dhcpUdpSocket.write(buffer, 16);
|
137 |
|
138 |
memset(buffer, 0, 32); // clear local buffer |
139 |
|
140 |
// leave zeroed out for sname && file
|
141 |
// put in W5100 transmit buffer x 6 (192 bytes)
|
142 |
|
143 |
for(int i = 0; i < 6; i++) { |
144 |
_dhcpUdpSocket.write(buffer, 32);
|
145 |
} |
146 |
|
147 |
// OPT - Magic Cookie
|
148 |
buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); |
149 |
buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); |
150 |
buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); |
151 |
buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); |
152 |
|
153 |
// OPT - message type
|
154 |
buffer[4] = dhcpMessageType;
|
155 |
buffer[5] = 0x01; |
156 |
buffer[6] = messageType; //DHCP_REQUEST; |
157 |
|
158 |
// OPT - client identifier
|
159 |
buffer[7] = dhcpClientIdentifier;
|
160 |
buffer[8] = 0x07; |
161 |
buffer[9] = 0x01; |
162 |
memcpy(buffer + 10, _dhcpMacAddr, 6); |
163 |
|
164 |
// OPT - host name
|
165 |
buffer[16] = hostName;
|
166 |
buffer[17] = strlen(HOST_NAME) + 3; // length of hostname + last 3 bytes of mac address |
167 |
strcpy((char*)&(buffer[18]), HOST_NAME); |
168 |
|
169 |
buffer[24] = _dhcpMacAddr[3]; |
170 |
buffer[25] = _dhcpMacAddr[4]; |
171 |
buffer[26] = _dhcpMacAddr[5]; |
172 |
|
173 |
//put data in W5100 transmit buffer
|
174 |
_dhcpUdpSocket.write(buffer, 27);
|
175 |
|
176 |
if(messageType == DHCP_REQUEST)
|
177 |
{ |
178 |
buffer[0] = dhcpRequestedIPaddr;
|
179 |
buffer[1] = 0x04; |
180 |
buffer[2] = _dhcpLocalIp[0]; |
181 |
buffer[3] = _dhcpLocalIp[1]; |
182 |
buffer[4] = _dhcpLocalIp[2]; |
183 |
buffer[5] = _dhcpLocalIp[3]; |
184 |
|
185 |
buffer[6] = dhcpServerIdentifier;
|
186 |
buffer[7] = 0x04; |
187 |
buffer[8] = _dhcpDhcpServerIp[0]; |
188 |
buffer[9] = _dhcpDhcpServerIp[1]; |
189 |
buffer[10] = _dhcpDhcpServerIp[2]; |
190 |
buffer[11] = _dhcpDhcpServerIp[3]; |
191 |
|
192 |
//put data in W5100 transmit buffer
|
193 |
_dhcpUdpSocket.write(buffer, 12);
|
194 |
} |
195 |
|
196 |
buffer[0] = dhcpParamRequest;
|
197 |
buffer[1] = 0x06; |
198 |
buffer[2] = subnetMask;
|
199 |
buffer[3] = routersOnSubnet;
|
200 |
buffer[4] = dns;
|
201 |
buffer[5] = domainName;
|
202 |
buffer[6] = dhcpT1value;
|
203 |
buffer[7] = dhcpT2value;
|
204 |
buffer[8] = endOption;
|
205 |
|
206 |
//put data in W5100 transmit buffer
|
207 |
_dhcpUdpSocket.write(buffer, 9);
|
208 |
|
209 |
_dhcpUdpSocket.endPacket(); |
210 |
} |
211 |
|
212 |
uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) |
213 |
{ |
214 |
uint8_t type = 0;
|
215 |
uint8_t opt_len = 0;
|
216 |
|
217 |
unsigned long startTime = millis(); |
218 |
|
219 |
while(_dhcpUdpSocket.parsePacket() <= 0) |
220 |
{ |
221 |
if((millis() - startTime) > responseTimeout)
|
222 |
{ |
223 |
return 255; |
224 |
} |
225 |
delay(50);
|
226 |
} |
227 |
// start reading in the packet
|
228 |
RIP_MSG_FIXED fixedMsg; |
229 |
_dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
|
230 |
|
231 |
if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
|
232 |
{ |
233 |
transactionId = ntohl(fixedMsg.xid); |
234 |
if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) |
235 |
{ |
236 |
// Need to read the rest of the packet here regardless
|
237 |
_dhcpUdpSocket.flush(); |
238 |
return 0; |
239 |
} |
240 |
|
241 |
memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
|
242 |
|
243 |
// Skip to the option part
|
244 |
// Doing this a byte at a time so we don't have to put a big buffer
|
245 |
// on the stack (as we don't have lots of memory lying around)
|
246 |
for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) |
247 |
{ |
248 |
_dhcpUdpSocket.read(); // we don't care about the returned byte
|
249 |
} |
250 |
|
251 |
while (_dhcpUdpSocket.available() > 0) |
252 |
{ |
253 |
switch (_dhcpUdpSocket.read())
|
254 |
{ |
255 |
case endOption :
|
256 |
break;
|
257 |
|
258 |
case padOption :
|
259 |
break;
|
260 |
|
261 |
case dhcpMessageType :
|
262 |
opt_len = _dhcpUdpSocket.read(); |
263 |
type = _dhcpUdpSocket.read(); |
264 |
break;
|
265 |
|
266 |
case subnetMask :
|
267 |
opt_len = _dhcpUdpSocket.read(); |
268 |
_dhcpUdpSocket.read(_dhcpSubnetMask, 4);
|
269 |
break;
|
270 |
|
271 |
case routersOnSubnet :
|
272 |
opt_len = _dhcpUdpSocket.read(); |
273 |
_dhcpUdpSocket.read(_dhcpGatewayIp, 4);
|
274 |
for (int i = 0; i < opt_len-4; i++) |
275 |
{ |
276 |
_dhcpUdpSocket.read(); |
277 |
} |
278 |
break;
|
279 |
|
280 |
case dns :
|
281 |
opt_len = _dhcpUdpSocket.read(); |
282 |
_dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
|
283 |
for (int i = 0; i < opt_len-4; i++) |
284 |
{ |
285 |
_dhcpUdpSocket.read(); |
286 |
} |
287 |
break;
|
288 |
|
289 |
case dhcpServerIdentifier :
|
290 |
opt_len = _dhcpUdpSocket.read(); |
291 |
if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || |
292 |
IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() ) |
293 |
{ |
294 |
_dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
|
295 |
} |
296 |
else
|
297 |
{ |
298 |
// Skip over the rest of this option
|
299 |
while (opt_len--)
|
300 |
{ |
301 |
_dhcpUdpSocket.read(); |
302 |
} |
303 |
} |
304 |
break;
|
305 |
|
306 |
case dhcpIPaddrLeaseTime :
|
307 |
default :
|
308 |
opt_len = _dhcpUdpSocket.read(); |
309 |
// Skip over the rest of this option
|
310 |
while (opt_len--)
|
311 |
{ |
312 |
_dhcpUdpSocket.read(); |
313 |
} |
314 |
break;
|
315 |
} |
316 |
} |
317 |
} |
318 |
|
319 |
// Need to skip to end of the packet regardless here
|
320 |
_dhcpUdpSocket.flush(); |
321 |
|
322 |
return type;
|
323 |
} |
324 |
|
325 |
IPAddress DhcpClass::getLocalIp() |
326 |
{ |
327 |
return IPAddress(_dhcpLocalIp);
|
328 |
} |
329 |
|
330 |
IPAddress DhcpClass::getSubnetMask() |
331 |
{ |
332 |
return IPAddress(_dhcpSubnetMask);
|
333 |
} |
334 |
|
335 |
IPAddress DhcpClass::getGatewayIp() |
336 |
{ |
337 |
return IPAddress(_dhcpGatewayIp);
|
338 |
} |
339 |
|
340 |
IPAddress DhcpClass::getDhcpServerIp() |
341 |
{ |
342 |
return IPAddress(_dhcpDhcpServerIp);
|
343 |
} |
344 |
|
345 |
IPAddress DhcpClass::getDnsServerIp() |
346 |
{ |
347 |
return IPAddress(_dhcpDnsServerIp);
|
348 |
} |
349 |
|