11
11
12
12
int DhcpClass::beginWithDHCP (uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
13
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 );
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 ();
19
24
20
25
memcpy ((void *)_dhcpMacAddr, (void *)mac, 6 );
26
+ _dhcp_state = STATE_DHCP_START;
27
+ return request_DHCP_lease ();
28
+ }
29
+
30
+ void 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
36
+ int DhcpClass::request_DHCP_lease (){
37
+
38
+ uint8_t messageType = 0 ;
39
+
40
+
21
41
22
42
// Pick an initial transaction ID
23
43
_dhcpTransactionId = random (1UL , 2000UL );
@@ -35,55 +55,75 @@ int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long
35
55
36
56
unsigned long startTime = millis ();
37
57
38
- while (dhcp_state != STATE_DHCP_LEASED)
58
+ while (_dhcp_state != STATE_DHCP_LEASED)
39
59
{
40
- if (dhcp_state == STATE_DHCP_START)
60
+ if (_dhcp_state == STATE_DHCP_START)
41
61
{
42
62
_dhcpTransactionId++;
43
63
44
64
send_DHCP_MESSAGE (DHCP_DISCOVER, ((millis () - startTime) / 1000 ));
45
- dhcp_state = STATE_DHCP_DISCOVER;
65
+ _dhcp_state = STATE_DHCP_DISCOVER;
66
+ }
67
+ else if (_dhcp_state == STATE_DHCP_REREQUEST){
68
+ _dhcpTransactionId++;
69
+ send_DHCP_MESSAGE (DHCP_REQUEST, ((millis () - startTime)/1000 ));
70
+ _dhcp_state = STATE_DHCP_REQUEST;
46
71
}
47
- else if (dhcp_state == STATE_DHCP_DISCOVER)
72
+ else if (_dhcp_state == STATE_DHCP_DISCOVER)
48
73
{
49
74
uint32_t respId;
50
- messageType = parseDHCPResponse (responseTimeout , respId);
75
+ messageType = parseDHCPResponse (_responseTimeout , respId);
51
76
if (messageType == DHCP_OFFER)
52
77
{
53
78
// We'll use the transaction ID that the offer came with,
54
79
// rather than the one we were up to
55
80
_dhcpTransactionId = respId;
56
81
send_DHCP_MESSAGE (DHCP_REQUEST, ((millis () - startTime) / 1000 ));
57
- dhcp_state = STATE_DHCP_REQUEST;
82
+ _dhcp_state = STATE_DHCP_REQUEST;
58
83
}
59
84
}
60
- else if (dhcp_state == STATE_DHCP_REQUEST)
85
+ else if (_dhcp_state == STATE_DHCP_REQUEST)
61
86
{
62
87
uint32_t respId;
63
- messageType = parseDHCPResponse (responseTimeout , respId);
88
+ messageType = parseDHCPResponse (_responseTimeout , respId);
64
89
if (messageType == DHCP_ACK)
65
90
{
66
- dhcp_state = STATE_DHCP_LEASED;
91
+ _dhcp_state = STATE_DHCP_LEASED;
67
92
result = 1 ;
93
+ // use default lease time if we didn't get it
94
+ if (_dhcpLeaseTime == 0 ){
95
+ _dhcpLeaseTime = DEFAULT_LEASE;
96
+ }
97
+ // calculate T1 & T2 if we didn't get it
98
+ if (_dhcpT1 == 0 ){
99
+ // T1 should be 50% of _dhcpLeaseTime
100
+ _dhcpT1 = _dhcpLeaseTime >> 1 ;
101
+ }
102
+ if (_dhcpT2 == 0 ){
103
+ // T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
104
+ _dhcpT2 = _dhcpT1 << 1 ;
105
+ }
106
+ _renewInSec = _dhcpT1;
107
+ _rebindInSec = _dhcpT2;
68
108
}
69
109
else if (messageType == DHCP_NAK)
70
- dhcp_state = STATE_DHCP_START;
110
+ _dhcp_state = STATE_DHCP_START;
71
111
}
72
112
73
113
if (messageType == 255 )
74
114
{
75
115
messageType = 0 ;
76
- dhcp_state = STATE_DHCP_START;
116
+ _dhcp_state = STATE_DHCP_START;
77
117
}
78
118
79
- if (result != 1 && ((millis () - startTime) > timeout ))
119
+ if (result != 1 && ((millis () - startTime) > _timeout ))
80
120
break ;
81
121
}
82
122
83
123
// We're done with the socket now
84
124
_dhcpUdpSocket.stop ();
85
125
_dhcpTransactionId++;
86
-
126
+
87
127
return result;
88
128
}
89
129
@@ -302,8 +342,26 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
302
342
}
303
343
}
304
344
break ;
305
-
345
+
346
+ case dhcpT1value :
347
+ opt_len = _dhcpUdpSocket.read ();
348
+ _dhcpUdpSocket.read ((uint8_t *)&_dhcpT1, sizeof (_dhcpT1));
349
+ _dhcpT1 = ntohl (_dhcpT1);
350
+ break ;
351
+
352
+ case dhcpT2value :
353
+ opt_len = _dhcpUdpSocket.read ();
354
+ _dhcpUdpSocket.read ((uint8_t *)&_dhcpT2, sizeof (_dhcpT2));
355
+ _dhcpT2 = ntohl (_dhcpT2);
356
+ break ;
357
+
306
358
case dhcpIPaddrLeaseTime :
359
+ opt_len = _dhcpUdpSocket.read ();
360
+ _dhcpUdpSocket.read ((uint8_t *)&_dhcpLeaseTime, sizeof (_dhcpLeaseTime));
361
+ _dhcpLeaseTime = ntohl (_dhcpLeaseTime);
362
+ _renewInSec = _dhcpLeaseTime;
363
+ break ;
364
+
307
365
default :
308
366
opt_len = _dhcpUdpSocket.read ();
309
367
// Skip over the rest of this option
@@ -322,6 +380,68 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
322
380
return type;
323
381
}
324
382
383
+
384
+ /*
385
+ returns:
386
+ 0/DHCP_CHECK_NONE: nothing happened
387
+ 1/DHCP_CHECK_RENEW_FAIL: renew failed
388
+ 2/DHCP_CHECK_RENEW_OK: renew success
389
+ 3/DHCP_CHECK_REBIND_FAIL: rebind fail
390
+ 4/DHCP_CHECK_REBIND_OK: rebind success
391
+ */
392
+ int DhcpClass::checkLease (){
393
+ // this uses a signed / unsigned trick to deal with millis overflow
394
+ unsigned long now = millis ();
395
+ signed long snow = (long )now;
396
+ int rc=DHCP_CHECK_NONE;
397
+ if (_lastCheck != 0 ){
398
+ signed long factor;
399
+ // calc how many ms past the timeout we are
400
+ factor = snow - (long )_secTimeout;
401
+ // if on or passed the timeout, reduce the counters
402
+ if ( factor >= 0 ){
403
+ // next timeout should be now plus 1000 ms minus parts of second in factor
404
+ _secTimeout = snow + 1000 - factor % 1000 ;
405
+ // how many seconds late are we, minimum 1
406
+ factor = factor / 1000 +1 ;
407
+
408
+ // reduce the counters by that mouch
409
+ // if we can assume that the cycle time (factor) is fairly constant
410
+ // and if the remainder is less than cycle time * 2
411
+ // do it early instead of late
412
+ if (_renewInSec < factor*2 )
413
+ _renewInSec = 0 ;
414
+ else
415
+ _renewInSec -= factor;
416
+
417
+ if (_rebindInSec < factor*2 )
418
+ _rebindInSec = 0 ;
419
+ else
420
+ _rebindInSec -= factor;
421
+ }
422
+
423
+ // if we have a lease but should renew, do it
424
+ if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0 ){
425
+ _dhcp_state = STATE_DHCP_REREQUEST;
426
+ rc = 1 + request_DHCP_lease ();
427
+ }
428
+
429
+ // if we have a lease or is renewing but should bind, do it
430
+ if ( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0 ){
431
+ // this should basically restart completely
432
+ _dhcp_state = STATE_DHCP_START;
433
+ reset_DHCP_lease ();
434
+ rc = 3 + request_DHCP_lease ();
435
+ }
436
+ }
437
+ else {
438
+ _secTimeout = snow + 1000 ;
439
+ }
440
+
441
+ _lastCheck = now;
442
+ return rc;
443
+ }
444
+
325
445
IPAddress DhcpClass::getLocalIp ()
326
446
{
327
447
return IPAddress (_dhcpLocalIp);
0 commit comments