Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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