source: rtos_arduino/trunk/arduino_lib/libraries/Ethernet2/src/Dhcp.cpp@ 136

Last change on this file since 136 was 136, checked in by ertl-honda, 8 years ago

ライブラリとOS及びベーシックなサンプルの追加.

File size: 14.3 KB
Line 
1// DHCP Library v0.3 - April 25, 2009
2// Author: Jordan Terrell - blog.jordanterrell.com
3
4#include "utility/w5500.h"
5
6#include <string.h>
7#include <stdlib.h>
8#include "Dhcp.h"
9#include "Arduino.h"
10#include "utility/util.h"
11
12int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
13{
14 _dhcpLeaseTime=0;
15 _dhcpT1=0;
16 _dhcpT2=0;
17 _lastCheck=0;
18 _timeout = timeout;
19 _responseTimeout = responseTimeout;
20
21 // zero out _dhcpMacAddr
22 memset(_dhcpMacAddr, 0, 6);
23 reset_DHCP_lease();
24
25 memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
26 _dhcp_state = STATE_DHCP_START;
27 return request_DHCP_lease();
28}
29
30void DhcpClass::reset_DHCP_lease(){
31 // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
32 memset(_dhcpLocalIp, 0, 20);
33}
34
35//return:0 on error, 1 if request is sent and response is received
36int DhcpClass::request_DHCP_lease(){
37
38 uint8_t messageType = 0;
39
40
41
42 // Pick an initial transaction ID
43 _dhcpTransactionId = random(1UL, 2000UL);
44 _dhcpInitialTransactionId = _dhcpTransactionId;
45
46 _dhcpUdpSocket.stop();
47 if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
48 {
49 // Couldn't get a socket
50 return 0;
51 }
52
53 presend_DHCP();
54
55 int result = 0;
56
57 unsigned long startTime = millis();
58
59 while(_dhcp_state != STATE_DHCP_LEASED)
60 {
61 if(_dhcp_state == STATE_DHCP_START)
62 {
63 //Serial.println("DHCP_START");
64 _dhcpTransactionId++;
65
66 send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
67 _dhcp_state = STATE_DHCP_DISCOVER;
68 }
69 else if(_dhcp_state == STATE_DHCP_REREQUEST){
70 _dhcpTransactionId++;
71 send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
72 _dhcp_state = STATE_DHCP_REQUEST;
73 }
74 else if(_dhcp_state == STATE_DHCP_DISCOVER)
75 {
76 uint32_t respId;
77
78 messageType = parseDHCPResponse(_responseTimeout, respId);
79 if(messageType == DHCP_OFFER)
80 {
81
82 // We'll use the transaction ID that the offer came with,
83 // rather than the one we were up to
84 _dhcpTransactionId = respId;
85 send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
86 _dhcp_state = STATE_DHCP_REQUEST;
87 }
88 }
89 else if(_dhcp_state == STATE_DHCP_REQUEST)
90 {
91 uint32_t respId;
92 messageType = parseDHCPResponse(_responseTimeout, respId);
93 if(messageType == DHCP_ACK)
94 {
95 _dhcp_state = STATE_DHCP_LEASED;
96 result = 1;
97 //use default lease time if we didn't get it
98 if(_dhcpLeaseTime == 0){
99 _dhcpLeaseTime = DEFAULT_LEASE;
100 }
101 //calculate T1 & T2 if we didn't get it
102 if(_dhcpT1 == 0){
103 //T1 should be 50% of _dhcpLeaseTime
104 _dhcpT1 = _dhcpLeaseTime >> 1;
105 }
106 if(_dhcpT2 == 0){
107 //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
108 _dhcpT2 = _dhcpT1 << 1;
109 }
110 _renewInSec = _dhcpT1;
111 _rebindInSec = _dhcpT2;
112 }
113 else if(messageType == DHCP_NAK)
114 _dhcp_state = STATE_DHCP_START;
115 }
116
117 if(messageType == 255)
118 {
119 messageType = 0;
120 _dhcp_state = STATE_DHCP_START;
121 }
122
123 if(result != 1 && ((millis() - startTime) > _timeout))
124 break;
125 }
126
127 // We're done with the socket now
128 _dhcpUdpSocket.stop();
129 _dhcpTransactionId++;
130
131 return result;
132}
133
134void DhcpClass::presend_DHCP()
135{
136}
137
138void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
139{
140 uint8_t buffer[32];
141 memset(buffer, 0, 32);
142 IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address
143
144 if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
145 {
146 // FIXME Need to return errors
147 return;
148 }
149
150 buffer[0] = DHCP_BOOTREQUEST; // op
151 buffer[1] = DHCP_HTYPE10MB; // htype
152 buffer[2] = DHCP_HLENETHERNET; // hlen
153 buffer[3] = DHCP_HOPS; // hops
154
155 // xid
156 unsigned long xid = htonl(_dhcpTransactionId);
157 memcpy(buffer + 4, &(xid), 4);
158
159 // 8, 9 - seconds elapsed
160 buffer[8] = ((secondsElapsed & 0xff00) >> 8);
161 buffer[9] = (secondsElapsed & 0x00ff);
162
163 // flags
164 unsigned short flags = htons(DHCP_FLAGSBROADCAST);
165 memcpy(buffer + 10, &(flags), 2);
166
167 // ciaddr: already zeroed
168 // yiaddr: already zeroed
169 // siaddr: already zeroed
170 // giaddr: already zeroed
171
172 //put data in w5500 transmit buffer
173 _dhcpUdpSocket.write(buffer, 28);
174
175 memset(buffer, 0, 32); // clear local buffer
176
177 memcpy(buffer, _dhcpMacAddr, 6); // chaddr
178
179 //put data in w5500 transmit buffer
180 _dhcpUdpSocket.write(buffer, 16);
181
182 memset(buffer, 0, 32); // clear local buffer
183
184 // leave zeroed out for sname && file
185 // put in w5500 transmit buffer x 6 (192 bytes)
186
187 for(int i = 0; i < 6; i++) {
188 _dhcpUdpSocket.write(buffer, 32);
189 }
190
191 // OPT - Magic Cookie
192 buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF);
193 buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF);
194 buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF);
195 buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF);
196
197 // OPT - message type
198 buffer[4] = dhcpMessageType;
199 buffer[5] = 0x01;
200 buffer[6] = messageType; //DHCP_REQUEST;
201
202 // OPT - client identifier
203 buffer[7] = dhcpClientIdentifier;
204 buffer[8] = 0x07;
205 buffer[9] = 0x01;
206 memcpy(buffer + 10, _dhcpMacAddr, 6);
207
208 // OPT - host name
209 buffer[16] = hostName;
210 buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address
211 strcpy((char*)&(buffer[18]), HOST_NAME);
212
213 printByte((char*)&(buffer[24]), _dhcpMacAddr[3]);
214 printByte((char*)&(buffer[26]), _dhcpMacAddr[4]);
215 printByte((char*)&(buffer[28]), _dhcpMacAddr[5]);
216
217 //put data in w5500 transmit buffer
218 _dhcpUdpSocket.write(buffer, 30);
219
220 if(messageType == DHCP_REQUEST)
221 {
222 buffer[0] = dhcpRequestedIPaddr;
223 buffer[1] = 0x04;
224 buffer[2] = _dhcpLocalIp[0];
225 buffer[3] = _dhcpLocalIp[1];
226 buffer[4] = _dhcpLocalIp[2];
227 buffer[5] = _dhcpLocalIp[3];
228
229 buffer[6] = dhcpServerIdentifier;
230 buffer[7] = 0x04;
231 buffer[8] = _dhcpDhcpServerIp[0];
232 buffer[9] = _dhcpDhcpServerIp[1];
233 buffer[10] = _dhcpDhcpServerIp[2];
234 buffer[11] = _dhcpDhcpServerIp[3];
235
236 //put data in w5500 transmit buffer
237 _dhcpUdpSocket.write(buffer, 12);
238 }
239
240 buffer[0] = dhcpParamRequest;
241 buffer[1] = 0x06;
242 buffer[2] = subnetMask;
243 buffer[3] = routersOnSubnet;
244 buffer[4] = dns;
245 buffer[5] = domainName;
246 buffer[6] = dhcpT1value;
247 buffer[7] = dhcpT2value;
248 buffer[8] = endOption;
249
250 //put data in w5500 transmit buffer
251 _dhcpUdpSocket.write(buffer, 9);
252
253 _dhcpUdpSocket.endPacket();
254}
255
256uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
257{
258 uint8_t type = 0;
259 uint8_t opt_len = 0;
260
261 unsigned long startTime = millis();
262
263
264
265 while(_dhcpUdpSocket.parsePacket() <= 0)
266 {
267 if((millis() - startTime) > responseTimeout)
268 {
269
270 return 255;
271 }
272 delay(50);
273 }
274
275 // start reading in the packet
276 RIP_MSG_FIXED fixedMsg;
277 _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
278
279 if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
280 {
281 transactionId = ntohl(fixedMsg.xid);
282 if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
283 {
284 // Need to read the rest of the packet here regardless
285 _dhcpUdpSocket.flush();
286 return 0;
287 }
288
289 memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
290
291 // Skip to the option part
292 // Doing this a byte at a time so we don't have to put a big buffer
293 // on the stack (as we don't have lots of memory lying around)
294 for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++)
295 {
296 _dhcpUdpSocket.read(); // we don't care about the returned byte
297 }
298
299 while (_dhcpUdpSocket.available() > 0)
300 {
301 switch (_dhcpUdpSocket.read())
302 {
303 case endOption :
304
305 break;
306
307 case padOption :
308
309 break;
310
311 case dhcpMessageType :
312
313 opt_len = _dhcpUdpSocket.read();
314 type = _dhcpUdpSocket.read();
315 break;
316
317 case subnetMask :
318
319 opt_len = _dhcpUdpSocket.read();
320 _dhcpUdpSocket.read(_dhcpSubnetMask, 4);
321 break;
322
323 case routersOnSubnet :
324
325 opt_len = _dhcpUdpSocket.read();
326 _dhcpUdpSocket.read(_dhcpGatewayIp, 4);
327 for (int i = 0; i < opt_len-4; i++)
328 {
329 _dhcpUdpSocket.read();
330 }
331 break;
332
333 case dns :
334
335 opt_len = _dhcpUdpSocket.read();
336 _dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
337 for (int i = 0; i < opt_len-4; i++)
338 {
339 _dhcpUdpSocket.read();
340 }
341 break;
342
343 case dhcpServerIdentifier :
344
345 opt_len = _dhcpUdpSocket.read();
346 if(((_dhcpDhcpServerIp[0] == 0) && (_dhcpDhcpServerIp[1] == 0) && (_dhcpDhcpServerIp[2] == 0) && (_dhcpDhcpServerIp[3] == 0)) || (IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()))
347 {
348 _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
349 }
350 else
351 {
352 // Skip over the rest of this option
353 while (opt_len--)
354 {
355 _dhcpUdpSocket.read();
356 }
357 }
358 break;
359
360 case dhcpT1value :
361
362 opt_len = _dhcpUdpSocket.read();
363 _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
364 _dhcpT1 = ntohl(_dhcpT1);
365 break;
366
367 case dhcpT2value :
368
369 opt_len = _dhcpUdpSocket.read();
370 _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
371 _dhcpT2 = ntohl(_dhcpT2);
372 break;
373
374 case dhcpIPaddrLeaseTime :
375
376 opt_len = _dhcpUdpSocket.read();
377 _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
378 _dhcpLeaseTime = ntohl(_dhcpLeaseTime);
379 _renewInSec = _dhcpLeaseTime;
380 break;
381
382 default :
383
384 opt_len = _dhcpUdpSocket.read();
385 // Skip over the rest of this option
386 while (opt_len--)
387 {
388 _dhcpUdpSocket.read();
389 }
390 break;
391 }
392 }
393 }
394
395 // Need to skip to end of the packet regardless here
396 _dhcpUdpSocket.flush();
397
398 return type;
399}
400
401
402/*
403 returns:
404 0/DHCP_CHECK_NONE: nothing happened
405 1/DHCP_CHECK_RENEW_FAIL: renew failed
406 2/DHCP_CHECK_RENEW_OK: renew success
407 3/DHCP_CHECK_REBIND_FAIL: rebind fail
408 4/DHCP_CHECK_REBIND_OK: rebind success
409*/
410int DhcpClass::checkLease(){
411 //this uses a signed / unsigned trick to deal with millis overflow
412 unsigned long now = millis();
413 signed long snow = (long)now;
414 int rc=DHCP_CHECK_NONE;
415 if (_lastCheck != 0){
416 signed long factor;
417 //calc how many ms past the timeout we are
418 factor = snow - (long)_secTimeout;
419 //if on or passed the timeout, reduce the counters
420 if ( factor >= 0 ){
421 //next timeout should be now plus 1000 ms minus parts of second in factor
422 _secTimeout = snow + 1000 - factor % 1000;
423 //how many seconds late are we, minimum 1
424 factor = factor / 1000 +1;
425
426 //reduce the counters by that mouch
427 //if we can assume that the cycle time (factor) is fairly constant
428 //and if the remainder is less than cycle time * 2
429 //do it early instead of late
430 if(_renewInSec < factor*2 )
431 _renewInSec = 0;
432 else
433 _renewInSec -= factor;
434
435 if(_rebindInSec < factor*2 )
436 _rebindInSec = 0;
437 else
438 _rebindInSec -= factor;
439 }
440
441 //if we have a lease but should renew, do it
442 if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
443 _dhcp_state = STATE_DHCP_REREQUEST;
444 rc = 1 + request_DHCP_lease();
445 }
446
447 //if we have a lease or is renewing but should bind, do it
448 if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
449 //this should basically restart completely
450 _dhcp_state = STATE_DHCP_START;
451 reset_DHCP_lease();
452 rc = 3 + request_DHCP_lease();
453 }
454 }
455 else{
456 _secTimeout = snow + 1000;
457 }
458
459 _lastCheck = now;
460 return rc;
461}
462
463IPAddress DhcpClass::getLocalIp()
464{
465 return IPAddress(_dhcpLocalIp);
466}
467
468IPAddress DhcpClass::getSubnetMask()
469{
470 return IPAddress(_dhcpSubnetMask);
471}
472
473IPAddress DhcpClass::getGatewayIp()
474{
475 return IPAddress(_dhcpGatewayIp);
476}
477
478IPAddress DhcpClass::getDhcpServerIp()
479{
480 return IPAddress(_dhcpDhcpServerIp);
481}
482
483IPAddress DhcpClass::getDnsServerIp()
484{
485 return IPAddress(_dhcpDnsServerIp);
486}
487
488void DhcpClass::printByte(char * buf, uint8_t n ) {
489 char *str = &buf[1];
490 buf[0]='0';
491 do {
492 unsigned long m = n;
493 n /= 16;
494 char c = m - 16 * n;
495 *str-- = c < 10 ? c + '0' : c + 'A' - 10;
496 } while(n);
497}
Note: See TracBrowser for help on using the repository browser.