Fork for fixes
Embed:
(wiki syntax)
Show/hide line numbers
DhcpClient.cpp
00001 // DHCP Library v0.3 - April 25, 2009 00002 // Author: Jordan Terrell - blog.jordanterrell.com 00003 #include <string.h> 00004 #include <stdlib.h> 00005 #include "DhcpClient.h" 00006 #include "utility/util.h" 00007 00008 /** 00009 * @brief 00010 * @note 00011 * @param 00012 * @retval 00013 */ 00014 int DhcpClient::begin(uint8_t* mac, unsigned long timeout, unsigned long responseTimeout) 00015 { 00016 _dhcpLeaseTime = 0; 00017 _dhcpT1 = 0; 00018 _dhcpT2 = 0; 00019 _lastCheck = 0; 00020 _timeout = timeout; 00021 _responseTimeout = responseTimeout; 00022 00023 // zero out _dhcpMacAddr 00024 memset(_dhcpMacAddr, 0, 6); 00025 resetDhcpLease(); 00026 00027 memcpy((void*)_dhcpMacAddr, (void*)mac, 6); 00028 _dhcp_state = STATE_DHCP_START; 00029 return requestDhcpLease(); 00030 } 00031 00032 /** 00033 * @brief 00034 * @note 00035 * @param 00036 * @retval 00037 */ 00038 void DhcpClient::resetDhcpLease() 00039 { 00040 // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp 00041 memset(_dhcpLocalIp, 0, 5 * 4); 00042 } 00043 00044 //return:0 on error, 1 if request is sent and response is received 00045 int DhcpClient::requestDhcpLease() 00046 { 00047 uint8_t messageType = 0; 00048 00049 // Pick an initial transaction ID 00050 srand(time(NULL)); 00051 _dhcpTransactionId = (rand() % 2000UL) + 1; 00052 _dhcpInitialTransactionId = _dhcpTransactionId; 00053 00054 _dhcpUdpSocket.stop(); 00055 if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) { 00056 // Couldn't get a socket 00057 return 0; 00058 } 00059 00060 presendDhcp(); 00061 00062 volatile int result = 0; 00063 time_t startTime = time(NULL); 00064 00065 while (_dhcp_state != STATE_DHCP_LEASED) { 00066 if (_dhcp_state == STATE_DHCP_START) { 00067 _dhcpTransactionId++; 00068 00069 sendDhcpMessage(DHCP_DISCOVER, (time(NULL) - startTime)); 00070 _dhcp_state = STATE_DHCP_DISCOVER; 00071 } 00072 else 00073 if (_dhcp_state == STATE_DHCP_REREQUEST) { 00074 _dhcpTransactionId++; 00075 sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime)); 00076 _dhcp_state = STATE_DHCP_REQUEST; 00077 } 00078 else 00079 if (_dhcp_state == STATE_DHCP_DISCOVER) { 00080 uint32_t respId; 00081 messageType = parseDhcpResponse(_responseTimeout, respId); 00082 if (messageType == DHCP_OFFER) { 00083 // We'll use the transaction ID that the offer came with, 00084 // rather than the one we were up to 00085 _dhcpTransactionId = respId; 00086 sendDhcpMessage(DHCP_REQUEST, (time(NULL) - startTime)); 00087 _dhcp_state = STATE_DHCP_REQUEST; 00088 } 00089 } 00090 else 00091 if (_dhcp_state == STATE_DHCP_REQUEST) { 00092 uint32_t respId; 00093 messageType = parseDhcpResponse(_responseTimeout, respId); 00094 if (messageType == DHCP_ACK) { 00095 _dhcp_state = STATE_DHCP_LEASED; 00096 result = 1; 00097 00098 //use default lease time if we didn't get it 00099 if (_dhcpLeaseTime == 0) { 00100 _dhcpLeaseTime = DEFAULT_LEASE; 00101 } 00102 00103 //calculate T1 & T2 if we didn't get it 00104 if (_dhcpT1 == 0) { 00105 //T1 should be 50% of _dhcpLeaseTime 00106 _dhcpT1 = _dhcpLeaseTime >> 1; 00107 } 00108 00109 if (_dhcpT2 == 0) { 00110 //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime 00111 _dhcpT2 = _dhcpT1 << 1; 00112 } 00113 00114 _renewInSec = _dhcpT1; 00115 _rebindInSec = _dhcpT2; 00116 } 00117 else 00118 if (messageType == DHCP_NAK) 00119 _dhcp_state = STATE_DHCP_START; 00120 } 00121 00122 if (messageType == 255) { 00123 messageType = 0; 00124 _dhcp_state = STATE_DHCP_START; 00125 } 00126 00127 if ((result != 1) && ((time(NULL) - startTime) > _timeout)) 00128 break; 00129 } 00130 00131 // We're done with the socket now 00132 _dhcpUdpSocket.stop(); 00133 _dhcpTransactionId++; 00134 00135 return result; 00136 } 00137 00138 /** 00139 * @brief 00140 * @note 00141 * @param 00142 * @retval 00143 */ 00144 void DhcpClient::presendDhcp() 00145 { } 00146 00147 /** 00148 * @brief 00149 * @note 00150 * @param 00151 * @retval 00152 */ 00153 void DhcpClient::sendDhcpMessage(uint8_t messageType, uint16_t secondsElapsed) 00154 { 00155 uint8_t buffer[32]; 00156 memset(buffer, 0, 32); 00157 00158 IpAddress dest_addr(255, 255, 255, 255); // Broadcast address 00159 00160 if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) { 00161 // FIXME Need to return errors 00162 return; 00163 } 00164 00165 buffer[0] = DHCP_BOOTREQUEST; // op 00166 buffer[1] = DHCP_HTYPE10MB; // htype 00167 buffer[2] = DHCP_HLENETHERNET; // hlen 00168 buffer[3] = DHCP_HOPS; // hops 00169 // xid 00170 unsigned long xid = htonl(_dhcpTransactionId); 00171 memcpy(buffer + 4, &(xid), 4); 00172 00173 // 8, 9 - seconds elapsed 00174 buffer[8] = ((secondsElapsed & 0xff00) >> 8); 00175 buffer[9] = (secondsElapsed & 0x00ff); 00176 00177 // flags 00178 unsigned short flags = htons(DHCP_FLAGSBROADCAST); 00179 memcpy(buffer + 10, &(flags), 2); 00180 00181 // ciaddr: already zeroed 00182 // yiaddr: already zeroed 00183 // siaddr: already zeroed 00184 // giaddr: already zeroed 00185 //put data in W5100 transmit buffer 00186 _dhcpUdpSocket.write(buffer, 28); 00187 00188 memset(buffer, 0, 32); // clear local buffer 00189 memcpy(buffer, _dhcpMacAddr, 6); // chaddr 00190 //put data in W5100 transmit buffer 00191 _dhcpUdpSocket.write(buffer, 16); 00192 00193 memset(buffer, 0, 32); // clear local buffer 00194 // leave zeroed out for sname && file 00195 // put in W5100 transmit buffer x 6 (192 bytes) 00196 for (int i = 0; i < 6; i++) { 00197 _dhcpUdpSocket.write(buffer, 32); 00198 } 00199 00200 // OPT - Magic Cookie 00201 buffer[0] = (uint8_t) ((MAGIC_COOKIE >> 24) & 0xFF); 00202 buffer[1] = (uint8_t) ((MAGIC_COOKIE >> 16) & 0xFF); 00203 buffer[2] = (uint8_t) ((MAGIC_COOKIE >> 8) & 0xFF); 00204 buffer[3] = (uint8_t) (MAGIC_COOKIE & 0xFF); 00205 00206 // OPT - message type 00207 buffer[4] = dhcpMessageType; 00208 buffer[5] = 0x01; 00209 buffer[6] = messageType; //DHCP_REQUEST; 00210 // OPT - client identifier 00211 buffer[7] = dhcpClientIdentifier; 00212 buffer[8] = 0x07; 00213 buffer[9] = 0x01; 00214 memcpy(buffer + 10, _dhcpMacAddr, 6); 00215 00216 // OPT - host name 00217 buffer[16] = hostName; 00218 buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address 00219 strcpy((char*) &(buffer[18]), HOST_NAME); 00220 00221 printByte((char*) &(buffer[24]), _dhcpMacAddr[3]); 00222 printByte((char*) &(buffer[26]), _dhcpMacAddr[4]); 00223 printByte((char*) &(buffer[28]), _dhcpMacAddr[5]); 00224 00225 //put data in W5100 transmit buffer 00226 _dhcpUdpSocket.write(buffer, 30); 00227 00228 if (messageType == DHCP_REQUEST) { 00229 buffer[0] = dhcpRequestedIPaddr; 00230 buffer[1] = 0x04; 00231 buffer[2] = _dhcpLocalIp[0]; 00232 buffer[3] = _dhcpLocalIp[1]; 00233 buffer[4] = _dhcpLocalIp[2]; 00234 buffer[5] = _dhcpLocalIp[3]; 00235 00236 buffer[6] = dhcpServerIdentifier; 00237 buffer[7] = 0x04; 00238 00239 //buffer[8] = _dhcpDhcpServerIp[0]; 00240 buffer[8] = _dhcpLocalIp[0]; 00241 buffer[9] = _dhcpDhcpServerIp[1]; 00242 buffer[10] = _dhcpDhcpServerIp[2]; 00243 buffer[11] = _dhcpDhcpServerIp[3]; 00244 00245 //put data in W5100 transmit buffer 00246 _dhcpUdpSocket.write(buffer, 12); 00247 } 00248 00249 buffer[0] = dhcpParamRequest; 00250 buffer[1] = 0x07; 00251 buffer[2] = subnetMask; 00252 buffer[3] = routersOnSubnet; 00253 buffer[4] = dns; 00254 buffer[5] = domainName; 00255 buffer[6] = dhcpT1value; 00256 buffer[7] = dhcpT2value; 00257 buffer[8] = userMqtt; 00258 buffer[9] = endOption; 00259 00260 //put data in W5100 transmit buffer 00261 _dhcpUdpSocket.write(buffer, 10); 00262 00263 _dhcpUdpSocket.endPacket(); 00264 } 00265 00266 /** 00267 * @brief 00268 * @note 00269 * @param 00270 * @retval 00271 */ 00272 uint8_t DhcpClient::parseDhcpResponse(unsigned long responseTimeout, uint32_t& transactionId) 00273 { 00274 volatile uint8_t type = 0; 00275 uint8_t opt_len = 0; 00276 00277 unsigned long startTime = time(NULL); 00278 00279 while (_dhcpUdpSocket.parsePacket() <= 0) { 00280 if ((time(NULL) - startTime) > responseTimeout) { 00281 return 255; 00282 } 00283 00284 // wait_ms(50); // wait_ms is depecated 00285 // ThisThread::sleep_for(50); // sleep_for is not IRQ safe 00286 wait_us(50000); // wait_us is IRQ safe and not deprecated 00287 } 00288 00289 // start reading in the packet 00290 RIP_MSG_FIXED fixedMsg; 00291 _dhcpUdpSocket.read((uint8_t*) &fixedMsg, sizeof(RIP_MSG_FIXED)); 00292 00293 if (fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) { 00294 transactionId = ntohl(fixedMsg.xid); 00295 if 00296 ( 00297 memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || 00298 (transactionId < _dhcpInitialTransactionId) || 00299 (transactionId > _dhcpTransactionId) 00300 ) { 00301 // Need to read the rest of the packet here regardless 00302 _dhcpUdpSocket.flush(); 00303 return 0; 00304 } 00305 00306 memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); 00307 00308 // Skip to the option part 00309 // Doing this a byte at a time so we don't have to put a big buffer 00310 // on the stack (as we don't have lots of memory lying around) 00311 for (int i = 0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) { 00312 _dhcpUdpSocket.read(); // we don't care about the returned byte 00313 } 00314 00315 while (_dhcpUdpSocket.available() > 0) { 00316 switch (_dhcpUdpSocket.read()) { 00317 case endOption: 00318 break; 00319 00320 case padOption: 00321 break; 00322 00323 case dhcpMessageType: 00324 opt_len = _dhcpUdpSocket.read(); 00325 type = _dhcpUdpSocket.read(); 00326 break; 00327 00328 case subnetMask: 00329 opt_len = _dhcpUdpSocket.read(); 00330 _dhcpUdpSocket.read(_dhcpSubnetMask, 4); 00331 break; 00332 00333 case routersOnSubnet: 00334 opt_len = _dhcpUdpSocket.read(); 00335 _dhcpUdpSocket.read(_dhcpGatewayIp, 4); 00336 for (int i = 0; i < opt_len - 4; i++) { 00337 _dhcpUdpSocket.read(); 00338 } 00339 break; 00340 00341 case dns: 00342 opt_len = _dhcpUdpSocket.read(); 00343 _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); 00344 for (int i = 0; i < opt_len - 4; i++) { 00345 _dhcpUdpSocket.read(); 00346 } 00347 break; 00348 00349 case dhcpServerIdentifier: 00350 opt_len = _dhcpUdpSocket.read(); 00351 if (*((uint32_t*)_dhcpDhcpServerIp) == 0 || IpAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP()) { 00352 _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); 00353 } 00354 else { 00355 // Skip over the rest of this option 00356 while (opt_len--) { 00357 _dhcpUdpSocket.read(); 00358 } 00359 } 00360 break; 00361 00362 case dhcpT1value: 00363 opt_len = _dhcpUdpSocket.read(); 00364 _dhcpUdpSocket.read((uint8_t*) &_dhcpT1, sizeof(_dhcpT1)); 00365 _dhcpT1 = ntohl(_dhcpT1); 00366 break; 00367 00368 case dhcpT2value: 00369 opt_len = _dhcpUdpSocket.read(); 00370 _dhcpUdpSocket.read((uint8_t*) &_dhcpT2, sizeof(_dhcpT2)); 00371 _dhcpT2 = ntohl(_dhcpT2); 00372 break; 00373 00374 case dhcpIPaddrLeaseTime: 00375 opt_len = _dhcpUdpSocket.read(); 00376 _dhcpUdpSocket.read((uint8_t*) &_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); 00377 _dhcpLeaseTime = ntohl(_dhcpLeaseTime); 00378 _renewInSec = _dhcpLeaseTime; 00379 break; 00380 00381 case userMqtt: 00382 opt_len = _dhcpUdpSocket.read(); 00383 _dhcpUdpSocket.read(_dhcpUserMqttIP, 4); 00384 for (int i = 0; i < opt_len - 4; i++) { 00385 _dhcpUdpSocket.read(); 00386 } 00387 printf("userMqtt\n\r"); 00388 break; 00389 00390 default: 00391 opt_len = _dhcpUdpSocket.read(); 00392 00393 // Skip over the rest of this option 00394 while (opt_len--) { 00395 _dhcpUdpSocket.read(); 00396 } 00397 break; 00398 } 00399 } 00400 } 00401 00402 // Need to skip to end of the packet regardless here 00403 _dhcpUdpSocket.flush(); 00404 00405 return type; 00406 } 00407 00408 /* 00409 returns: 00410 0/DHCP_CHECK_NONE: nothing happened 00411 1/DHCP_CHECK_RENEW_FAIL: renew failed 00412 2/DHCP_CHECK_RENEW_OK: renew success 00413 3/DHCP_CHECK_REBIND_FAIL: rebind fail 00414 4/DHCP_CHECK_REBIND_OK: rebind success 00415 */ 00416 int DhcpClient::checkLease() 00417 { 00418 time_t now = time(NULL); 00419 volatile int rc = DHCP_CHECK_NONE; 00420 if (_lastCheck != 0) { 00421 //calc how many ms past the timeout we are 00422 time_t factor = now - _secTimeout; 00423 00424 //if on or passed the timeout, reduce the counters 00425 if (factor >= 0) { 00426 //next timeout should be now plus 1s 00427 _secTimeout = now + 1; 00428 00429 //reduce the counters by that mouch 00430 //if we can assume that the cycle time (factor) is fairly constant 00431 //and if the remainder is less than cycle time * 2 00432 //do it early instead of late 00433 if (_renewInSec < factor * 2) 00434 _renewInSec = 0; 00435 else 00436 _renewInSec -= factor; 00437 00438 if (_rebindInSec < factor * 2) 00439 _rebindInSec = 0; 00440 else 00441 _rebindInSec -= factor; 00442 } 00443 00444 //if we have a lease but should renew, do it 00445 if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <= 0) { 00446 _dhcp_state = STATE_DHCP_REREQUEST; 00447 rc = 1 + requestDhcpLease(); 00448 } 00449 00450 //if we have a lease or is renewing but should bind, do it 00451 if ((_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <= 0) { 00452 //this should basically restart completely 00453 _dhcp_state = STATE_DHCP_START; 00454 resetDhcpLease(); 00455 rc = 3 + requestDhcpLease(); 00456 } 00457 } 00458 else { 00459 _secTimeout = now + 1; 00460 } 00461 00462 _lastCheck = now; 00463 return rc; 00464 } 00465 00466 /** 00467 * @brief 00468 * @note 00469 * @param 00470 * @retval 00471 */ 00472 IpAddress DhcpClient::getLocalIp() 00473 { 00474 return IpAddress(_dhcpLocalIp); 00475 } 00476 00477 /** 00478 * @brief 00479 * @note 00480 * @param 00481 * @retval 00482 */ 00483 IpAddress DhcpClient::getSubnetMask() 00484 { 00485 return IpAddress(_dhcpSubnetMask); 00486 } 00487 00488 /** 00489 * @brief 00490 * @note 00491 * @param 00492 * @retval 00493 */ 00494 IpAddress DhcpClient::getGatewayIp() 00495 { 00496 return IpAddress(_dhcpGatewayIp); 00497 } 00498 00499 /** 00500 * @brief 00501 * @note 00502 * @param 00503 * @retval 00504 */ 00505 IpAddress DhcpClient::getDhcpServerIp() 00506 { 00507 return IpAddress(_dhcpDhcpServerIp); 00508 } 00509 00510 /** 00511 * @brief 00512 * @note 00513 * @param 00514 * @retval 00515 */ 00516 IpAddress DhcpClient::getDnsServerIp() 00517 { 00518 return IpAddress(_dhcpDnsServerIp); 00519 } 00520 00521 /** 00522 * @brief 00523 * @note 00524 * @param 00525 * @retval 00526 */ 00527 IpAddress DhcpClient::getMqttServerIp() 00528 { 00529 return IpAddress(_dhcpUserMqttIP); 00530 } 00531 00532 /** 00533 * @brief 00534 * @note 00535 * @param 00536 * @retval 00537 */ 00538 void DhcpClient::printByte(char* buf, uint8_t n) 00539 { 00540 char* str = &buf[1]; 00541 buf[0] = '0'; 00542 do { 00543 unsigned long m = n; 00544 n /= 16; 00545 00546 char c = m - 16 * n; 00547 *str-- = c < 10 ? c + '0' : c + 'A' - 10; 00548 } while (n); 00549 }
Generated on Fri Jul 15 2022 22:55:10 by 1.7.2