1111
1212int DhcpClass::beginWithDHCP (uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
1313{
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 ();
1924
2025 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+
2141
2242 // Pick an initial transaction ID
2343 _dhcpTransactionId = random (1UL , 2000UL );
@@ -35,55 +55,75 @@ int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long
3555
3656 unsigned long startTime = millis ();
3757
38- while (dhcp_state != STATE_DHCP_LEASED)
58+ while (_dhcp_state != STATE_DHCP_LEASED)
3959 {
40- if (dhcp_state == STATE_DHCP_START)
60+ if (_dhcp_state == STATE_DHCP_START)
4161 {
4262 _dhcpTransactionId++;
4363
4464 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;
4671 }
47- else if (dhcp_state == STATE_DHCP_DISCOVER)
72+ else if (_dhcp_state == STATE_DHCP_DISCOVER)
4873 {
4974 uint32_t respId;
50- messageType = parseDHCPResponse (responseTimeout , respId);
75+ messageType = parseDHCPResponse (_responseTimeout , respId);
5176 if (messageType == DHCP_OFFER)
5277 {
5378 // We'll use the transaction ID that the offer came with,
5479 // rather than the one we were up to
5580 _dhcpTransactionId = respId;
5681 send_DHCP_MESSAGE (DHCP_REQUEST, ((millis () - startTime) / 1000 ));
57- dhcp_state = STATE_DHCP_REQUEST;
82+ _dhcp_state = STATE_DHCP_REQUEST;
5883 }
5984 }
60- else if (dhcp_state == STATE_DHCP_REQUEST)
85+ else if (_dhcp_state == STATE_DHCP_REQUEST)
6186 {
6287 uint32_t respId;
63- messageType = parseDHCPResponse (responseTimeout , respId);
88+ messageType = parseDHCPResponse (_responseTimeout , respId);
6489 if (messageType == DHCP_ACK)
6590 {
66- dhcp_state = STATE_DHCP_LEASED;
91+ _dhcp_state = STATE_DHCP_LEASED;
6792 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;
68108 }
69109 else if (messageType == DHCP_NAK)
70- dhcp_state = STATE_DHCP_START;
110+ _dhcp_state = STATE_DHCP_START;
71111 }
72112
73113 if (messageType == 255 )
74114 {
75115 messageType = 0 ;
76- dhcp_state = STATE_DHCP_START;
116+ _dhcp_state = STATE_DHCP_START;
77117 }
78118
79- if (result != 1 && ((millis () - startTime) > timeout ))
119+ if (result != 1 && ((millis () - startTime) > _timeout ))
80120 break ;
81121 }
82122
83123 // We're done with the socket now
84124 _dhcpUdpSocket.stop ();
85125 _dhcpTransactionId++;
86-
126+
87127 return result;
88128}
89129
@@ -302,8 +342,26 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
302342 }
303343 }
304344 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+
306358 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+
307365 default :
308366 opt_len = _dhcpUdpSocket.read ();
309367 // Skip over the rest of this option
@@ -322,6 +380,68 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
322380 return type;
323381}
324382
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+
325445IPAddress DhcpClass::getLocalIp ()
326446{
327447 return IPAddress (_dhcpLocalIp);
0 commit comments