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.
snmp_common.c
00001 /** 00002 * @file snmp_common.c 00003 * @brief Functions common to SNMP agent and SNMP manager 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00026 * @version 1.7.6 00027 **/ 00028 00029 //Switch to the appropriate trace level 00030 #define TRACE_LEVEL SNMP_TRACE_LEVEL 00031 00032 //Dependencies 00033 #include "core/net.h" 00034 #include "snmp/snmp_agent.h" 00035 #include "snmp/snmp_common.h" 00036 #include "crypto.h" 00037 #include "asn1.h" 00038 #include "debug.h" 00039 00040 //Check TCP/IP stack configuration 00041 #if (SNMP_AGENT_SUPPORT == ENABLED) 00042 00043 00044 /** 00045 * @brief Initialize a SNMP message 00046 * @param[in] message Pointer to the SNMP message 00047 **/ 00048 00049 void snmpInitMessage(SnmpMessage *message) 00050 { 00051 //Current position in the message 00052 message->pos = NULL; 00053 //Length of the message 00054 message->length = 0; 00055 00056 //SNMP version identifier 00057 message->version = SNMP_VERSION_1; 00058 00059 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED) 00060 //Initialize community name 00061 message->community = NULL; 00062 message->communityLen = 0; 00063 #endif 00064 00065 #if (SNMP_V3_SUPPORT == ENABLED) 00066 //Initialize msgGlobalData fields 00067 message->msgId = 0; 00068 message->msgMaxSize = 0; 00069 message->msgFlags = 0; 00070 message->msgSecurityModel = 0; 00071 00072 //Initialize msgSecurityParameters fields 00073 message->msgAuthEngineId = NULL; 00074 message->msgAuthEngineIdLen = 0; 00075 message->msgAuthEngineBoots = 0; 00076 message->msgAuthEngineTime = 0; 00077 message->msgUserName = NULL; 00078 message->msgUserNameLen = 0; 00079 message->msgAuthParameters = NULL; 00080 message->msgAuthParametersLen = 0; 00081 message->msgPrivParameters = NULL; 00082 message->msgPrivParametersLen = 0; 00083 00084 //Initialize scopedPDU fields 00085 message->contextEngineId = NULL; 00086 message->contextEngineIdLen = 0; 00087 message->contextName = NULL; 00088 message->contextNameLen = 0; 00089 #endif 00090 00091 //Initialize PDU fields 00092 message->pduType = SNMP_PDU_GET_REQUEST; 00093 message->requestId = 0; 00094 message->errorStatus = SNMP_ERROR_NONE; 00095 message->errorIndex = 0; 00096 00097 #if (SNMP_V1_SUPPORT == ENABLED) 00098 message->enterpriseOid = NULL; 00099 message->enterpriseOidLen = 0; 00100 message->agentAddr = IPV4_UNSPECIFIED_ADDR; 00101 message->genericTrapType = 0; 00102 message->specificTrapCode = 0; 00103 message->timestamp = 0; 00104 #endif 00105 00106 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED) 00107 message->nonRepeaters = 0; 00108 message->maxRepetitions = 0; 00109 #endif 00110 00111 //Initialize the list of variable bindings 00112 message->varBindList = NULL; 00113 message->varBindListLen = 0; 00114 message->varBindListMaxLen = 0; 00115 message->oidLen = 0; 00116 } 00117 00118 00119 /** 00120 * @brief Compute SNMP message overhead 00121 * @param[in] message Pointer to the SNMP message 00122 **/ 00123 00124 error_t snmpComputeMessageOverhead(SnmpMessage *message) 00125 { 00126 size_t n; 00127 00128 #if (SNMP_V1_SUPPORT == ENABLED) 00129 //SNMPv1 version? 00130 if(message->version == SNMP_VERSION_1) 00131 { 00132 //SNMPv1 message header overhead 00133 n = SNMP_V1_MSG_HEADER_OVERHEAD; 00134 //Take into consideration variable-length fields 00135 n += message->communityLen + message->enterpriseOidLen; 00136 } 00137 else 00138 #endif 00139 #if (SNMP_V2C_SUPPORT == ENABLED) 00140 //SNMPv2c version? 00141 if(message->version == SNMP_VERSION_2C) 00142 { 00143 //SNMPv2c message header overhead 00144 n = SNMP_V2C_MSG_HEADER_OVERHEAD; 00145 //Take into consideration variable-length fields 00146 n += message->communityLen; 00147 } 00148 else 00149 #endif 00150 #if (SNMP_V3_SUPPORT == ENABLED) 00151 //SNMPv3 version? 00152 if(message->version == SNMP_VERSION_3) 00153 { 00154 //SNMPv3 message header overhead 00155 n = SNMP_V3_MSG_HEADER_OVERHEAD; 00156 00157 //Take into consideration variable-length fields 00158 n += message->msgAuthEngineIdLen + message->msgUserNameLen + 00159 message->msgAuthParametersLen + message->msgPrivParametersLen + 00160 message->contextEngineIdLen + message->contextNameLen; 00161 } 00162 else 00163 #endif 00164 //Invalid SNMP version? 00165 { 00166 //Report an error 00167 return ERROR_INVALID_VERSION; 00168 } 00169 00170 //Sanity check 00171 if(n > (SNMP_MAX_MSG_SIZE - SNMP_MSG_ENCRYPTION_OVERHEAD)) 00172 return ERROR_FAILURE; 00173 00174 //Make room for the message header at the beginning of the buffer 00175 message->varBindList = message->buffer + n; 00176 //Maximum length of the variable binding list 00177 message->varBindListMaxLen = (SNMP_MAX_MSG_SIZE - SNMP_MSG_ENCRYPTION_OVERHEAD) - n; 00178 00179 //Successful processing 00180 return NO_ERROR; 00181 } 00182 00183 00184 /** 00185 * @brief Parse SNMP message header 00186 * @param[in,out] message Pointer to the incoming SNMP message 00187 * @return Error code 00188 **/ 00189 00190 error_t snmpParseMessageHeader(SnmpMessage *message) 00191 { 00192 error_t error; 00193 size_t length; 00194 const uint8_t *p; 00195 Asn1Tag tag; 00196 00197 //Point to the first byte of the SNMP message 00198 p = message->buffer; 00199 //Retrieve the length of the SNMP message 00200 length = message->bufferLen; 00201 00202 //The SNMP message is encapsulated within a sequence 00203 error = asn1ReadTag(p, length, &tag); 00204 //Failed to decode ASN.1 tag? 00205 if(error) 00206 return error; 00207 00208 //Enforce encoding, class and type 00209 error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); 00210 //The tag does not match the criteria? 00211 if(error) 00212 return error; 00213 00214 //Point to the first field of the sequence 00215 p = tag.value; 00216 length = tag.length; 00217 00218 //Read version identifier 00219 error = asn1ReadInt32(p, length, &tag, &message->version); 00220 //Failed to decode ASN.1 tag? 00221 if(error) 00222 return error; 00223 00224 //Make sure the SNMP version identifier is valid 00225 if(message->version != SNMP_VERSION_1 && 00226 message->version != SNMP_VERSION_2C && 00227 message->version != SNMP_VERSION_3) 00228 { 00229 //The SNMP version is not acceptable 00230 return ERROR_INVALID_VERSION; 00231 } 00232 00233 //Advance data pointer 00234 message->pos = (uint8_t *) p + tag.totalLength; 00235 //Remaining bytes to process 00236 message->length = length - tag.totalLength; 00237 00238 //Successful processing 00239 return NO_ERROR; 00240 } 00241 00242 00243 /** 00244 * @brief Format SNMP message header 00245 * @param[in,out] message Pointer to the outgoing SNMP message 00246 * @return Error code 00247 **/ 00248 00249 error_t snmpWriteMessageHeader(SnmpMessage *message) 00250 { 00251 error_t error; 00252 size_t n; 00253 Asn1Tag tag; 00254 00255 //SNMPv1 or SNMPv2c version? 00256 if(message->version == SNMP_VERSION_1 || 00257 message->version == SNMP_VERSION_2C) 00258 { 00259 //Write the community name 00260 error = snmpWriteCommunity(message); 00261 //Any error to report? 00262 if(error) 00263 return error; 00264 } 00265 //SNMPv3 version? 00266 else if(message->version == SNMP_VERSION_3) 00267 { 00268 //Write msgSecurityParameters field 00269 error = snmpWriteSecurityParameters(message); 00270 //Any error to report? 00271 if(error) 00272 return error; 00273 00274 //Write msgGlobalData field 00275 error = snmpWriteGlobalData(message); 00276 //Any error to report? 00277 if(error) 00278 return error; 00279 } 00280 //Invalid version? 00281 else 00282 { 00283 //Report an error 00284 return ERROR_INVALID_VERSION; 00285 } 00286 00287 //Write version identifier 00288 error = asn1WriteInt32(message->version, TRUE, message->pos, &n); 00289 //Any error to report? 00290 if(error) 00291 return error; 00292 00293 //Move backward 00294 message->pos -= n; 00295 //Update the length of the message 00296 message->length += n; 00297 00298 //The SNMP message is encapsulated within a sequence 00299 tag.constructed = TRUE; 00300 tag.objClass = ASN1_CLASS_UNIVERSAL; 00301 tag.objType = ASN1_TYPE_SEQUENCE; 00302 tag.length = message->length; 00303 tag.value = NULL; 00304 00305 //Write the corresponding ASN.1 tag 00306 error = asn1WriteTag(&tag, TRUE, message->pos, &n); 00307 //Any error to report? 00308 if(error) 00309 return error; 00310 00311 //Move backward 00312 message->pos -= n; 00313 //Total length of the SNMP message 00314 message->length += n; 00315 00316 //Successful processing 00317 return NO_ERROR; 00318 } 00319 00320 00321 /** 00322 * @brief Parse community name 00323 * @param[in,out] message Pointer to the incoming SNMP message 00324 * @return Error code 00325 **/ 00326 00327 error_t snmpParseCommunity(SnmpMessage *message) 00328 { 00329 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED) 00330 error_t error; 00331 Asn1Tag tag; 00332 00333 //Read community name 00334 error = asn1ReadTag(message->pos, message->length, &tag); 00335 //Failed to decode ASN.1 tag? 00336 if(error) 00337 return error; 00338 00339 //Enforce encoding, class and type 00340 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00341 //The tag does not match the criteria? 00342 if(error) 00343 return error; 00344 00345 //Save community name 00346 message->community = (char_t *) tag.value; 00347 message->communityLen = tag.length; 00348 00349 //Advance data pointer 00350 message->pos += tag.totalLength; 00351 //Remaining bytes to process 00352 message->length -= tag.totalLength; 00353 00354 //No error to report 00355 return NO_ERROR; 00356 #else 00357 //Not implemented 00358 return ERROR_NOT_IMPLEMENTED; 00359 #endif 00360 } 00361 00362 00363 /** 00364 * @brief Format community name 00365 * @param[in,out] message Pointer to the outgoing SNMP message 00366 * @return Error code 00367 **/ 00368 00369 error_t snmpWriteCommunity(SnmpMessage *message) 00370 { 00371 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED) 00372 error_t error; 00373 size_t n; 00374 Asn1Tag tag; 00375 00376 //The community name is an octet string 00377 tag.constructed = FALSE; 00378 tag.objClass = ASN1_CLASS_UNIVERSAL; 00379 tag.objType = ASN1_TYPE_OCTET_STRING; 00380 tag.length = message->communityLen; 00381 tag.value = (uint8_t *) message->community; 00382 00383 //Write the corresponding ASN.1 tag 00384 error = asn1WriteTag(&tag, TRUE, message->pos, &n); 00385 //Any error to report? 00386 if(error) 00387 return error; 00388 00389 //Point to the first byte of the community name 00390 message->pos -= n; 00391 //Total length of the message 00392 message->length += n; 00393 00394 //Successful processing 00395 return NO_ERROR; 00396 #else 00397 //Not implemented 00398 return ERROR_NOT_IMPLEMENTED; 00399 #endif 00400 } 00401 00402 00403 /** 00404 * @brief Parse msgGlobalData field 00405 * @param[in,out] message Pointer to the incoming SNMP message 00406 * @return Error code 00407 **/ 00408 00409 error_t snmpParseGlobalData(SnmpMessage *message) 00410 { 00411 #if (SNMP_V3_SUPPORT == ENABLED) 00412 error_t error; 00413 size_t length; 00414 const uint8_t *p; 00415 Asn1Tag tag; 00416 00417 //Read the msgGlobalData field 00418 error = asn1ReadTag(message->pos, message->length, &tag); 00419 //Failed to decode ASN.1 tag? 00420 if(error) 00421 return error; 00422 00423 //Enforce encoding, class and type 00424 error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); 00425 //The tag does not match the criteria? 00426 if(error) 00427 return error; 00428 00429 //Advance pointer over the msgGlobalData field 00430 message->pos += tag.totalLength; 00431 //Remaining bytes to process 00432 message->length -= tag.totalLength; 00433 00434 //Point to the first field of the sequence 00435 p = tag.value; 00436 length = tag.length; 00437 00438 //The msgID is used between two SNMP entities to coordinate request 00439 //messages and responses 00440 error = asn1ReadInt32(p, length, &tag, &message->msgId); 00441 //Failed to decode ASN.1 tag? 00442 if(error) 00443 return error; 00444 00445 //Make sure the value is in the range 0..2147483647 00446 if(message->msgId < 0) 00447 return ERROR_WRONG_ENCODING; 00448 00449 //Point to the next field 00450 p += tag.totalLength; 00451 length -= tag.totalLength; 00452 00453 //The msgMaxSize field of the message conveys the maximum message size 00454 //supported by the sender of the message 00455 error = asn1ReadInt32(p, length, &tag, &message->msgMaxSize); 00456 //Failed to decode ASN.1 tag? 00457 if(error) 00458 return error; 00459 00460 //Make sure the value is in the range 484..2147483647 00461 if(message->msgMaxSize < 484) 00462 return ERROR_WRONG_ENCODING; 00463 00464 //Point to the next field 00465 p += tag.totalLength; 00466 length -= tag.totalLength; 00467 00468 //The msgFlags field of the message contains several bit fields which 00469 //control processing of the message 00470 error = asn1ReadTag(p, length, &tag); 00471 //Failed to decode ASN.1 tag? 00472 if(error) 00473 return error; 00474 00475 //Enforce encoding, class and type 00476 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00477 //The tag does not match the criteria? 00478 if(error) 00479 return error; 00480 00481 //The msgFlags field consists of a single byte 00482 if(tag.length != sizeof(uint8_t)) 00483 return ERROR_WRONG_ENCODING; 00484 00485 //Save the bit field 00486 message->msgFlags = tag.value[0]; 00487 00488 //Point to the next field 00489 p += tag.totalLength; 00490 length -= tag.totalLength; 00491 00492 //The msgSecurityModel field identifies which security model was used 00493 //by the sender to generate the message 00494 error = asn1ReadInt32(p, length, &tag, &message->msgSecurityModel); 00495 //Failed to decode ASN.1 tag? 00496 if(error) 00497 return error; 00498 00499 //Make sure the value is in the range 1..2147483647 00500 if(message->msgSecurityModel < 1) 00501 return ERROR_WRONG_ENCODING; 00502 00503 //Successful processing 00504 return NO_ERROR; 00505 #else 00506 //Not implemented 00507 return ERROR_NOT_IMPLEMENTED; 00508 #endif 00509 } 00510 00511 00512 /** 00513 * @brief Format msgGlobalData field 00514 * @param[in,out] message Pointer to the outgoing SNMP message 00515 * @return Error code 00516 **/ 00517 00518 error_t snmpWriteGlobalData(SnmpMessage *message) 00519 { 00520 #if (SNMP_V3_SUPPORT == ENABLED) 00521 error_t error; 00522 size_t n; 00523 size_t length; 00524 uint8_t *p; 00525 Asn1Tag tag; 00526 00527 //The msgGlobalData field is encoded in reverse order 00528 p = message->pos; 00529 //Length of the msgGlobalData field 00530 length = 0; 00531 00532 //Write msgSecurityModel field 00533 error = asn1WriteInt32(message->msgSecurityModel, TRUE, p, &n); 00534 //Any error to report? 00535 if(error) 00536 return error; 00537 00538 //Move backward 00539 p -= n; 00540 //Update the length of the msgGlobalData field 00541 length += n; 00542 00543 //The msgFlags field consists of a single byte 00544 tag.constructed = FALSE; 00545 tag.objClass = ASN1_CLASS_UNIVERSAL; 00546 tag.objType = ASN1_TYPE_OCTET_STRING; 00547 tag.length = sizeof(uint8_t); 00548 tag.value = &message->msgFlags; 00549 00550 //Write the corresponding ASN.1 tag 00551 error = asn1WriteTag(&tag, TRUE, p, &n); 00552 //Any error to report? 00553 if(error) 00554 return error; 00555 00556 //Move backward 00557 p -= n; 00558 //Update the length of the msgGlobalData field 00559 length += n; 00560 00561 //Write msgMaxSize field 00562 error = asn1WriteInt32(message->msgMaxSize, TRUE, p, &n); 00563 //Any error to report? 00564 if(error) 00565 return error; 00566 00567 //Move backward 00568 p -= n; 00569 //Update the length of the msgGlobalData field 00570 length += n; 00571 00572 //Write msgID field 00573 error = asn1WriteInt32(message->msgId, TRUE, p, &n); 00574 //Any error to report? 00575 if(error) 00576 return error; 00577 00578 //Move backward 00579 p -= n; 00580 //Update the length of the msgGlobalData field 00581 length += n; 00582 00583 //The parameters are encapsulated within a sequence 00584 tag.constructed = TRUE; 00585 tag.objClass = ASN1_CLASS_UNIVERSAL; 00586 tag.objType = ASN1_TYPE_SEQUENCE; 00587 tag.length = length; 00588 tag.value = NULL; 00589 00590 //Write the corresponding ASN.1 tag 00591 error = asn1WriteTag(&tag, TRUE, p, &n); 00592 //Any error to report? 00593 if(error) 00594 return error; 00595 00596 //Point to the first byte of the msgGlobalData field 00597 message->pos = p - n; 00598 //Total length of the message 00599 message->length += length + n; 00600 00601 //Successful processing 00602 return NO_ERROR; 00603 #else 00604 //Not implemented 00605 return ERROR_NOT_IMPLEMENTED; 00606 #endif 00607 } 00608 00609 00610 /** 00611 * @brief Parse msgSecurityParameters field 00612 * @param[in,out] message Pointer to the incoming SNMP message 00613 * @return Error code 00614 **/ 00615 00616 error_t snmpParseSecurityParameters(SnmpMessage *message) 00617 { 00618 #if (SNMP_V3_SUPPORT == ENABLED) 00619 error_t error; 00620 size_t length; 00621 const uint8_t *p; 00622 Asn1Tag tag; 00623 00624 //Read the msgSecurityParameters field 00625 error = asn1ReadTag(message->pos, message->length, &tag); 00626 //Failed to decode ASN.1 tag? 00627 if(error) 00628 return error; 00629 00630 //Enforce encoding, class and type 00631 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00632 //The tag does not match the criteria? 00633 if(error) 00634 return error; 00635 00636 //Advance pointer over the msgSecurityParameters field 00637 message->pos += tag.totalLength; 00638 //Remaining bytes to process 00639 message->length -= tag.totalLength; 00640 00641 //Point to the very first field of the sequence 00642 p = tag.value; 00643 length = tag.length; 00644 00645 //User-based security model? 00646 if(message->msgSecurityModel == SNMP_SECURITY_MODEL_USM) 00647 { 00648 //The USM security parameters are encapsulated within a sequence 00649 error = asn1ReadTag(p, length, &tag); 00650 //Failed to decode ASN.1 tag? 00651 if(error) 00652 return error; 00653 00654 //Enforce encoding, class and type 00655 error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); 00656 //The tag does not match the criteria? 00657 if(error) 00658 return error; 00659 00660 //Point to the first field of the sequence 00661 p = tag.value; 00662 length = tag.length; 00663 00664 //Read the msgAuthoritativeEngineID field 00665 error = asn1ReadTag(p, length, &tag); 00666 //Failed to decode ASN.1 tag? 00667 if(error) 00668 return error; 00669 00670 //Enforce encoding, class and type 00671 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00672 //The tag does not match the criteria? 00673 if(error) 00674 return error; 00675 00676 //Save authoritative engine identifier 00677 message->msgAuthEngineId = tag.value; 00678 message->msgAuthEngineIdLen = tag.length; 00679 00680 //Point to the next field 00681 p += tag.totalLength; 00682 length -= tag.totalLength; 00683 00684 //Read the msgAuthoritativeEngineBoots field 00685 error = asn1ReadInt32(p, length, &tag, 00686 &message->msgAuthEngineBoots); 00687 //Failed to decode ASN.1 tag? 00688 if(error) 00689 return error; 00690 00691 //Point to the next field 00692 p += tag.totalLength; 00693 length -= tag.totalLength; 00694 00695 //Read the msgAuthoritativeEngineTime field 00696 error = asn1ReadInt32(p, length, &tag, 00697 &message->msgAuthEngineTime); 00698 //Failed to decode ASN.1 tag? 00699 if(error) 00700 return error; 00701 00702 //Point to the next field 00703 p += tag.totalLength; 00704 length -= tag.totalLength; 00705 00706 //Read the msgUserName field 00707 error = asn1ReadTag(p, length, &tag); 00708 //Failed to decode ASN.1 tag? 00709 if(error) 00710 return error; 00711 00712 //Enforce encoding, class and type 00713 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00714 //The tag does not match the criteria? 00715 if(error) 00716 return error; 00717 00718 //Check the length of the user name 00719 if(tag.length > 32) 00720 return ERROR_WRONG_ENCODING; 00721 00722 //Save user name 00723 message->msgUserName = (char_t *) tag.value; 00724 message->msgUserNameLen = tag.length; 00725 00726 //Point to the next field 00727 p += tag.totalLength; 00728 length -= tag.totalLength; 00729 00730 //Read the msgAuthenticationParameters field 00731 error = asn1ReadTag(p, length, &tag); 00732 //Failed to decode ASN.1 tag? 00733 if(error) 00734 return error; 00735 00736 //Enforce encoding, class and type 00737 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00738 //The tag does not match the criteria? 00739 if(error) 00740 return error; 00741 00742 //Save authentication parameters 00743 message->msgAuthParameters = (uint8_t *) tag.value; 00744 message->msgAuthParametersLen = tag.length; 00745 00746 //Point to the next field 00747 p += tag.totalLength; 00748 length -= tag.totalLength; 00749 00750 //Read the msgPrivacyParameters field 00751 error = asn1ReadTag(p, length, &tag); 00752 //Failed to decode ASN.1 tag? 00753 if(error) 00754 return error; 00755 00756 //Enforce encoding, class and type 00757 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 00758 //The tag does not match the criteria? 00759 if(error) 00760 return error; 00761 00762 //Save privacy parameters 00763 message->msgPrivParameters = tag.value; 00764 message->msgPrivParametersLen = tag.length; 00765 } 00766 else 00767 { 00768 //The security model is not supported 00769 return ERROR_FAILURE; 00770 } 00771 00772 //Successful processing 00773 return NO_ERROR; 00774 #else 00775 //Not implemented 00776 return ERROR_NOT_IMPLEMENTED; 00777 #endif 00778 } 00779 00780 00781 /** 00782 * @brief Format msgSecurityParameters field 00783 * @param[in,out] message Pointer to the outgoing SNMP message 00784 * @return Error code 00785 **/ 00786 00787 error_t snmpWriteSecurityParameters(SnmpMessage *message) 00788 { 00789 #if (SNMP_V3_SUPPORT == ENABLED) 00790 error_t error; 00791 size_t n; 00792 size_t length; 00793 uint8_t *p; 00794 Asn1Tag tag; 00795 00796 //The msgSecurityParameters field is encoded in reverse order 00797 p = message->pos; 00798 //Length of the msgSecurityParameters field 00799 length = 0; 00800 00801 //User-based security model? 00802 if(message->msgSecurityModel == SNMP_SECURITY_MODEL_USM) 00803 { 00804 //Encode the msgPrivacyParameters field as an octet string 00805 tag.constructed = FALSE; 00806 tag.objClass = ASN1_CLASS_UNIVERSAL; 00807 tag.objType = ASN1_TYPE_OCTET_STRING; 00808 tag.length = message->msgPrivParametersLen; 00809 tag.value = message->msgPrivParameters; 00810 00811 //Write the corresponding ASN.1 tag 00812 error = asn1WriteTag(&tag, TRUE, p, &n); 00813 //Any error to report? 00814 if(error) 00815 return error; 00816 00817 //Move backward 00818 p -= n; 00819 //Update the length of the msgSecurityParameters field 00820 length += n; 00821 00822 //Authentication required? 00823 if(message->msgAuthParametersLen > 0) 00824 { 00825 //Make room for the message digest 00826 p -= message->msgAuthParametersLen; 00827 //Update the length of the msgSecurityParameters field 00828 length += message->msgAuthParametersLen; 00829 00830 //Clear the message digest 00831 memset(p, 0, message->msgAuthParametersLen); 00832 } 00833 00834 //Save the location of the msgAuthenticationParameters field 00835 message->msgAuthParameters = p; 00836 00837 //Encoded the msgAuthenticationParameters field as an octet string 00838 tag.constructed = FALSE; 00839 tag.objClass = ASN1_CLASS_UNIVERSAL; 00840 tag.objType = ASN1_TYPE_OCTET_STRING; 00841 tag.length = message->msgAuthParametersLen; 00842 tag.value = NULL; 00843 00844 //Write the corresponding ASN.1 tag 00845 error = asn1WriteTag(&tag, TRUE, p, &n); 00846 //Any error to report? 00847 if(error) 00848 return error; 00849 00850 //Move backward 00851 p -= n; 00852 //Update the length of the msgSecurityParameters field 00853 length += n; 00854 00855 //Encode the msgUserName field as an octet string 00856 tag.constructed = FALSE; 00857 tag.objClass = ASN1_CLASS_UNIVERSAL; 00858 tag.objType = ASN1_TYPE_OCTET_STRING; 00859 tag.length = message->msgUserNameLen; 00860 tag.value = (uint8_t *) message->msgUserName; 00861 00862 //Write the corresponding ASN.1 tag 00863 error = asn1WriteTag(&tag, TRUE, p, &n); 00864 //Any error to report? 00865 if(error) 00866 return error; 00867 00868 //Move backward 00869 p -= n; 00870 //Update the length of the msgSecurityParameters field 00871 length += n; 00872 00873 //Write the msgAuthoritativeEngineTime field 00874 error = asn1WriteInt32(message->msgAuthEngineTime, TRUE, p, &n); 00875 //Any error to report? 00876 if(error) 00877 return error; 00878 00879 //Move backward 00880 p -= n; 00881 //Update the length of the msgSecurityParameters field 00882 length += n; 00883 00884 //Write the msgAuthoritativeEngineBoots field 00885 error = asn1WriteInt32(message->msgAuthEngineBoots, TRUE, p, &n); 00886 //Any error to report? 00887 if(error) 00888 return error; 00889 00890 //Move backward 00891 p -= n; 00892 //Update the length of the msgSecurityParameters field 00893 length += n; 00894 00895 //The msgAuthoritativeEngineID field is an octet string 00896 tag.constructed = FALSE; 00897 tag.objClass = ASN1_CLASS_UNIVERSAL; 00898 tag.objType = ASN1_TYPE_OCTET_STRING; 00899 tag.length = message->msgAuthEngineIdLen; 00900 tag.value = message->msgAuthEngineId; 00901 00902 //Write the corresponding ASN.1 tag 00903 error = asn1WriteTag(&tag, TRUE, p, &n); 00904 //Any error to report? 00905 if(error) 00906 return error; 00907 00908 //Move backward 00909 p -= n; 00910 //Update the length of the msgSecurityParameters field 00911 length += n; 00912 00913 //The USM security parameters are encapsulated within a sequence 00914 tag.constructed = TRUE; 00915 tag.objClass = ASN1_CLASS_UNIVERSAL; 00916 tag.objType = ASN1_TYPE_SEQUENCE; 00917 tag.length = length; 00918 tag.value = NULL; 00919 00920 //Write the corresponding ASN.1 tag 00921 error = asn1WriteTag(&tag, TRUE, p, &n); 00922 //Any error to report? 00923 if(error) 00924 return error; 00925 00926 //Move backward 00927 p -= n; 00928 //Update the length of the msgSecurityParameters field 00929 length += n; 00930 } 00931 else 00932 { 00933 //The security model is not supported 00934 return ERROR_FAILURE; 00935 } 00936 00937 //The security parameters are encapsulated within an octet string 00938 tag.constructed = FALSE; 00939 tag.objClass = ASN1_CLASS_UNIVERSAL; 00940 tag.objType = ASN1_TYPE_OCTET_STRING; 00941 tag.length = length; 00942 tag.value = NULL; 00943 00944 //Write the corresponding ASN.1 tag 00945 error = asn1WriteTag(&tag, TRUE, p, &n); 00946 //Any error to report? 00947 if(error) 00948 return error; 00949 00950 //Point to the first byte of the msgSecurityParameters field 00951 message->pos = p - n; 00952 //Total length of the message 00953 message->length += length + n; 00954 00955 //Successful processing 00956 return NO_ERROR; 00957 #else 00958 //Not implemented 00959 return ERROR_NOT_IMPLEMENTED; 00960 #endif 00961 } 00962 00963 00964 /** 00965 * @brief Parse scopedPDU field 00966 * @param[in,out] message Pointer to the incoming SNMP message 00967 * @return Error code 00968 **/ 00969 00970 error_t snmpParseScopedPdu(SnmpMessage *message) 00971 { 00972 #if (SNMP_V3_SUPPORT == ENABLED) 00973 error_t error; 00974 size_t length; 00975 const uint8_t *p; 00976 Asn1Tag tag; 00977 00978 //Read the scopedPDU field 00979 error = asn1ReadTag(message->pos, message->length, &tag); 00980 //Failed to decode ASN.1 tag? 00981 if(error) 00982 return error; 00983 00984 //Enforce encoding, class and type 00985 error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); 00986 //The tag does not match the criteria? 00987 if(error) 00988 return error; 00989 00990 //Point to the first field of the sequence 00991 p = tag.value; 00992 length = tag.length; 00993 00994 //Read contextEngineID field 00995 error = asn1ReadTag(p, length, &tag); 00996 //Failed to decode ASN.1 tag? 00997 if(error) 00998 return error; 00999 01000 //Enforce encoding, class and type 01001 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 01002 //The tag does not match the criteria? 01003 if(error) 01004 return error; 01005 01006 //Save context engine identifier 01007 message->contextEngineId = tag.value; 01008 message->contextEngineIdLen = tag.length; 01009 01010 //Point to the next field 01011 p += tag.totalLength; 01012 length -= tag.totalLength; 01013 01014 //Read contextName field 01015 error = asn1ReadTag(p, length, &tag); 01016 //Failed to decode ASN.1 tag? 01017 if(error) 01018 return error; 01019 01020 //Enforce encoding, class and type 01021 error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OCTET_STRING); 01022 //The tag does not match the criteria? 01023 if(error) 01024 return error; 01025 01026 //Save context name 01027 message->contextName = tag.value; 01028 message->contextNameLen = tag.length; 01029 01030 //Point to the first byte of the PDU 01031 message->pos = (uint8_t *) p + tag.totalLength; 01032 //Length of the PDU 01033 message->length = length - tag.totalLength; 01034 01035 //Return status code 01036 return error; 01037 #else 01038 //Not implemented 01039 return ERROR_NOT_IMPLEMENTED; 01040 #endif 01041 } 01042 01043 01044 /** 01045 * @brief Format scopedPDU 01046 * @param[in,out] message Pointer to the outgoing SNMP message 01047 * @return Error code 01048 **/ 01049 01050 error_t snmpWriteScopedPdu(SnmpMessage *message) 01051 { 01052 #if (SNMP_V3_SUPPORT == ENABLED) 01053 error_t error; 01054 size_t n; 01055 size_t length; 01056 uint8_t *p; 01057 Asn1Tag tag; 01058 01059 //Point to the first byte of the PDU 01060 p = message->pos; 01061 //Retrieve the length of the PDU 01062 length = message->length; 01063 01064 //The contextName is an octet string 01065 tag.constructed = FALSE; 01066 tag.objClass = ASN1_CLASS_UNIVERSAL; 01067 tag.objType = ASN1_TYPE_OCTET_STRING; 01068 tag.length = message->contextNameLen; 01069 tag.value = message->contextName; 01070 01071 //Write the corresponding ASN.1 tag 01072 error = asn1WriteTag(&tag, TRUE, p, &n); 01073 //Any error to report? 01074 if(error) 01075 return error; 01076 01077 //Move backward 01078 p -= n; 01079 //Update the length of the scopedPduData 01080 length += n; 01081 01082 //The contextEngineID is an octet string 01083 tag.constructed = FALSE; 01084 tag.objClass = ASN1_CLASS_UNIVERSAL; 01085 tag.objType = ASN1_TYPE_OCTET_STRING; 01086 tag.length = message->contextEngineIdLen; 01087 tag.value = message->contextEngineId; 01088 01089 //Write the corresponding ASN.1 tag 01090 error = asn1WriteTag(&tag, TRUE, p, &n); 01091 //Any error to report? 01092 if(error) 01093 return error; 01094 01095 //Move backward 01096 p -= n; 01097 //Update the length of the scopedPduData 01098 length += n; 01099 01100 //The scopedPduData is encapsulated within a sequence 01101 tag.constructed = TRUE; 01102 tag.objClass = ASN1_CLASS_UNIVERSAL; 01103 tag.objType = ASN1_TYPE_SEQUENCE; 01104 tag.length = length; 01105 tag.value = NULL; 01106 01107 //Write the corresponding ASN.1 tag 01108 error = asn1WriteTag(&tag, TRUE, p, &n); 01109 //Any error to report? 01110 if(error) 01111 return error; 01112 01113 //Point to the first byte of the scopedPDU 01114 message->pos = p - n; 01115 //Length of the scopedPDU 01116 message->length = length + n; 01117 01118 //Successful processing 01119 return NO_ERROR; 01120 #else 01121 //Not implemented 01122 return ERROR_NOT_IMPLEMENTED; 01123 #endif 01124 } 01125 01126 01127 /** 01128 * @brief Parse PDU header 01129 * @param[in,out] message Pointer to the incoming SNMP message 01130 * @return Error code 01131 **/ 01132 01133 error_t snmpParsePduHeader(SnmpMessage *message) 01134 { 01135 error_t error; 01136 size_t length; 01137 const uint8_t *p; 01138 Asn1Tag tag; 01139 01140 //The PDU is encapsulated within a sequence 01141 error = asn1ReadTag(message->pos, message->length, &tag); 01142 //Failed to decode ASN.1 tag? 01143 if(error) 01144 return error; 01145 01146 //Check encoding 01147 if(tag.constructed != TRUE) 01148 return ERROR_WRONG_ENCODING; 01149 //Enforce class 01150 if(tag.objClass != ASN1_CLASS_CONTEXT_SPECIFIC) 01151 return ERROR_INVALID_CLASS; 01152 01153 //Save PDU type 01154 message->pduType = (SnmpPduType) tag.objType; 01155 01156 //Point to the first field 01157 p = tag.value; 01158 //Remaining bytes to process 01159 length = tag.length; 01160 01161 //Read request-id field 01162 error = asn1ReadInt32(p, length, &tag, &message->requestId); 01163 //Failed to decode ASN.1 tag? 01164 if(error) 01165 return error; 01166 01167 //Point to the next field 01168 p += tag.totalLength; 01169 length -= tag.totalLength; 01170 01171 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED) 01172 //GetBulkRequest-PDU? 01173 if(message->pduType == SNMP_PDU_GET_BULK_REQUEST) 01174 { 01175 //Read non-repeaters field 01176 error = asn1ReadInt32(p, length, &tag, &message->nonRepeaters); 01177 //Failed to decode ASN.1 tag? 01178 if(error) 01179 return error; 01180 01181 //If the value in the non-repeaters field is less than zero, then the 01182 //value of the field is set to zero 01183 if(message->nonRepeaters < 0) 01184 message->nonRepeaters = 0; 01185 01186 //Point to the next field 01187 p += tag.totalLength; 01188 length -= tag.totalLength; 01189 01190 //Read max-repetitions field 01191 error = asn1ReadInt32(p, length, &tag, &message->maxRepetitions); 01192 //Failed to decode ASN.1 tag? 01193 if(error) 01194 return error; 01195 01196 //If the value in the max-repetitions field is less than zero, then the 01197 //value of the field is set to zero 01198 if(message->maxRepetitions < 0) 01199 message->maxRepetitions = 0; 01200 } 01201 else 01202 #endif 01203 { 01204 //Read error-status field 01205 error = asn1ReadInt32(p, length, &tag, &message->errorStatus); 01206 //Failed to decode ASN.1 tag? 01207 if(error) 01208 return error; 01209 01210 //Point to the next field 01211 p += tag.totalLength; 01212 length -= tag.totalLength; 01213 01214 //Read error-index field 01215 error = asn1ReadInt32(p, length, &tag, &message->errorIndex); 01216 //Failed to decode ASN.1 tag? 01217 if(error) 01218 return error; 01219 } 01220 01221 //Point to the next field 01222 p += tag.totalLength; 01223 length -= tag.totalLength; 01224 01225 //The variable bindings are encapsulated within a sequence 01226 error = asn1ReadTag(p, length, &tag); 01227 //Failed to decode ASN.1 tag? 01228 if(error) 01229 return error; 01230 01231 //Enforce encoding, class and type 01232 error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE); 01233 //The tag does not match the criteria? 01234 if(error) 01235 return error; 01236 01237 //Save the location of the variable binding list 01238 message->varBindList = (uint8_t *) tag.value; 01239 message->varBindListLen = tag.length; 01240 01241 //Successful processing 01242 return NO_ERROR; 01243 } 01244 01245 01246 /** 01247 * @brief Format PDU header 01248 * @param[in,out] message Pointer to the outgoing SNMP message 01249 * @return Error code 01250 **/ 01251 01252 error_t snmpWritePduHeader(SnmpMessage *message) 01253 { 01254 error_t error; 01255 size_t n; 01256 size_t length; 01257 uint8_t *p; 01258 Asn1Tag tag; 01259 01260 //The PDU header will be encoded in reverse order... 01261 p = message->varBindList; 01262 //Length of the PDU 01263 length = message->varBindListLen; 01264 01265 //The variable bindings are encapsulated within a sequence 01266 tag.constructed = TRUE; 01267 tag.objClass = ASN1_CLASS_UNIVERSAL; 01268 tag.objType = ASN1_TYPE_SEQUENCE; 01269 tag.length = length; 01270 tag.value = NULL; 01271 01272 //Write the corresponding ASN.1 tag 01273 error = asn1WriteTag(&tag, TRUE, p, &n); 01274 //Any error to report? 01275 if(error) 01276 return error; 01277 01278 //Move backward 01279 p -= n; 01280 //Update the length of the PDU 01281 length += n; 01282 01283 //GetResponse-PDU, SNMPv2-Trap-PDU or Report-PDU? 01284 if(message->pduType == SNMP_PDU_GET_RESPONSE || 01285 message->pduType == SNMP_PDU_TRAP_V2 || 01286 message->pduType == SNMP_PDU_REPORT) 01287 { 01288 //Write error index 01289 error = asn1WriteInt32(message->errorIndex, TRUE, p, &n); 01290 //Any error to report? 01291 if(error) 01292 return error; 01293 01294 //Move backward 01295 p -= n; 01296 //Update the length of the PDU 01297 length += n; 01298 01299 //Write error status 01300 error = asn1WriteInt32(message->errorStatus, TRUE, p, &n); 01301 //Any error to report? 01302 if(error) 01303 return error; 01304 01305 //Move backward 01306 p -= n; 01307 //Update the length of the PDU 01308 length += n; 01309 01310 //Write request identifier 01311 error = asn1WriteInt32(message->requestId, TRUE, p, &n); 01312 //Any error to report? 01313 if(error) 01314 return error; 01315 01316 //Move backward 01317 p -= n; 01318 //Update the length of the PDU 01319 length += n; 01320 } 01321 #if (SNMP_V1_SUPPORT == ENABLED) 01322 //Trap-PDU? 01323 else if(message->pduType == SNMP_PDU_TRAP) 01324 { 01325 //Encode the object value using ASN.1 rules 01326 error = snmpEncodeUnsignedInt32(message->timestamp, message->buffer, &n); 01327 //Any error to report? 01328 if(error) 01329 return error; 01330 01331 //The time stamp is encoded in ASN.1 format 01332 tag.constructed = FALSE; 01333 tag.objClass = ASN1_CLASS_APPLICATION; 01334 tag.objType = MIB_TYPE_TIME_TICKS; 01335 tag.length = n; 01336 tag.value = message->buffer; 01337 01338 //Write the corresponding ASN.1 tag 01339 error = asn1WriteTag(&tag, TRUE, p, &n); 01340 //Any error to report? 01341 if(error) 01342 return error; 01343 01344 //Move backward 01345 p -= n; 01346 //Update the length of the PDU 01347 length += n; 01348 01349 //Write specific trap code 01350 error = asn1WriteInt32(message->specificTrapCode, TRUE, p, &n); 01351 //Any error to report? 01352 if(error) 01353 return error; 01354 01355 //Move backward 01356 p -= n; 01357 //Update the length of the PDU 01358 length += n; 01359 01360 //Write generic trap type 01361 error = asn1WriteInt32(message->genericTrapType, TRUE, p, &n); 01362 //Any error to report? 01363 if(error) 01364 return error; 01365 01366 //Move backward 01367 p -= n; 01368 //Update the length of the PDU 01369 length += n; 01370 01371 //The agent address is encoded in ASN.1 format 01372 tag.constructed = FALSE; 01373 tag.objClass = ASN1_CLASS_APPLICATION; 01374 tag.objType = MIB_TYPE_IP_ADDRESS; 01375 tag.length = sizeof(Ipv4Addr); 01376 tag.value = (uint8_t *) &message->agentAddr; 01377 01378 //Write the corresponding ASN.1 tag 01379 error = asn1WriteTag(&tag, TRUE, p, &n); 01380 //Any error to report? 01381 if(error) 01382 return error; 01383 01384 //Move backward 01385 p -= n; 01386 //Update the length of the PDU 01387 length += n; 01388 01389 //The enterprise OID is encoded in ASN.1 format 01390 tag.constructed = FALSE; 01391 tag.objClass = ASN1_CLASS_UNIVERSAL; 01392 tag.objType = ASN1_TYPE_OBJECT_IDENTIFIER; 01393 tag.length = message->enterpriseOidLen; 01394 tag.value = message->enterpriseOid; 01395 01396 //Write the corresponding ASN.1 tag 01397 error = asn1WriteTag(&tag, TRUE, p, &n); 01398 //Any error to report? 01399 if(error) 01400 return error; 01401 01402 //Move backward 01403 p -= n; 01404 //Update the length of the PDU 01405 length += n; 01406 } 01407 #endif 01408 //Unknown PDU type? 01409 else 01410 { 01411 //Report an error 01412 return ERROR_FAILURE; 01413 } 01414 01415 //The PDU is encapsulated within a sequence 01416 tag.constructed = TRUE; 01417 tag.objClass = ASN1_CLASS_CONTEXT_SPECIFIC; 01418 tag.objType = message->pduType; 01419 tag.length = length; 01420 tag.value = NULL; 01421 01422 //Write the corresponding ASN.1 tag 01423 error = asn1WriteTag(&tag, TRUE, p, &n); 01424 //Any error to report? 01425 if(error) 01426 return error; 01427 01428 //Point to the first byte of the PDU 01429 message->pos = p - n; 01430 //Total length of the PDU 01431 message->length = length + n; 01432 01433 //Successful processing 01434 return NO_ERROR; 01435 } 01436 01437 01438 /** 01439 * @brief Encode a 32-bit signed integer 01440 * @param[in] value Integer value 01441 * @param[out] dest Buffer where to encode the integer 01442 * @param[out] length Total number of bytes that have been written 01443 * @return Error code 01444 **/ 01445 01446 error_t snmpEncodeInt32(int32_t value, uint8_t *dest, size_t *length) 01447 { 01448 size_t i; 01449 size_t j; 01450 uint8_t *src; 01451 01452 //Check parameters 01453 if(dest == NULL || length == NULL) 01454 return ERROR_INVALID_PARAMETER; 01455 01456 //The integer is encoded MSB first 01457 value = htobe32(value); 01458 //Cast the integer to byte array 01459 src = (uint8_t *) &value; 01460 01461 //An integer value is always encoded in the smallest possible number of octets 01462 for(i = 0; i < 3; i++) 01463 { 01464 //The upper 9 bits shall not have the same value (all 0 or all 1) 01465 if((src[i] != 0x00 || (src[i + 1] & 0x80) != 0x00) && 01466 (src[i] != 0xFF || (src[i + 1] & 0x80) != 0x80)) 01467 { 01468 break; 01469 } 01470 } 01471 01472 //Point to the beginning of the output buffer 01473 j = 0; 01474 01475 //Copy integer value 01476 while(i < 4) 01477 dest[j++] = src[i++]; 01478 01479 //Total number of bytes that have been written 01480 *length = j; 01481 01482 //Successful processing 01483 return NO_ERROR; 01484 } 01485 01486 01487 /** 01488 * @brief Encode a 32-bit unsigned integer 01489 * @param[in] value Integer value 01490 * @param[out] dest Buffer where to encode the integer 01491 * @param[out] length Total number of bytes that have been written 01492 * @return Error code 01493 **/ 01494 01495 error_t snmpEncodeUnsignedInt32(uint32_t value, uint8_t *dest, size_t *length) 01496 { 01497 size_t i; 01498 size_t j; 01499 uint8_t *src; 01500 01501 //Check parameters 01502 if(dest == NULL || length == NULL) 01503 return ERROR_INVALID_PARAMETER; 01504 01505 //The integer is encoded MSB first 01506 value = htobe32(value); 01507 //Cast the integer to byte array 01508 src = (uint8_t *) &value; 01509 01510 //An integer value is always encoded in the smallest possible number of octets 01511 for(i = 0; i < 3; i++) 01512 { 01513 //Check the upper 8 bits 01514 if(src[i] != 0x00) 01515 break; 01516 } 01517 01518 //Point to the beginning of the output buffer 01519 j = 0; 01520 01521 //Check the most significant bit 01522 if(src[i] & 0x80) 01523 dest[j++] = 0; 01524 01525 //Copy integer value 01526 while(i < 4) 01527 dest[j++] = src[i++]; 01528 01529 //Total number of bytes that have been written 01530 *length = j; 01531 01532 //Successful processing 01533 return NO_ERROR; 01534 } 01535 01536 01537 /** 01538 * @brief Encode a 64-bit unsigned integer 01539 * @param[in] value Integer value 01540 * @param[out] dest Buffer where to encode the integer 01541 * @param[out] length Total number of bytes that have been written 01542 * @return Error code 01543 **/ 01544 01545 error_t snmpEncodeUnsignedInt64(uint64_t value, uint8_t *dest, size_t *length) 01546 { 01547 size_t i; 01548 size_t j; 01549 uint8_t *src; 01550 01551 //Check parameters 01552 if(dest == NULL || length == NULL) 01553 return ERROR_INVALID_PARAMETER; 01554 01555 //The integer is encoded MSB first 01556 value = htobe64(value); 01557 //Cast the integer to byte array 01558 src = (uint8_t *) &value; 01559 01560 //An integer value is always encoded in the smallest possible number of octets 01561 for(i = 0; i < 7; i++) 01562 { 01563 //Check the upper 8 bits 01564 if(src[i] != 0x00) 01565 break; 01566 } 01567 01568 //Point to the beginning of the output buffer 01569 j = 0; 01570 01571 //Check the most significant bit 01572 if(src[i] & 0x80) 01573 dest[j++] = 0; 01574 01575 //Copy integer value 01576 while(i < 8) 01577 dest[j++] = src[i++]; 01578 01579 //Total number of bytes that have been written 01580 *length = j; 01581 01582 //Successful processing 01583 return NO_ERROR; 01584 } 01585 01586 01587 /** 01588 * @brief Decode a 32-bit signed integer 01589 * @param[in] src Buffer that contains the encoded value 01590 * @param[in] length Number of bytes to be processed 01591 * @param[out] value Resulting integer value 01592 * @return Error code 01593 **/ 01594 01595 error_t snmpDecodeInt32(const uint8_t *src, size_t length, int32_t *value) 01596 { 01597 size_t i; 01598 01599 //Check parameters 01600 if(src == NULL || value == NULL) 01601 return ERROR_INVALID_PARAMETER; 01602 if(length < 1) 01603 return ERROR_INVALID_PARAMETER; 01604 01605 //The contents octets shall be a two's complement binary 01606 //number equal to the integer value 01607 *value = (src[0] & 0x80) ? -1 : 0; 01608 01609 //Process contents octets 01610 for(i = 0; i < length; i++) 01611 { 01612 //Rotate left operation 01613 *value <<= 8; 01614 //Reconstruct integer value 01615 *value |= src[i]; 01616 } 01617 01618 //Successful processing 01619 return NO_ERROR; 01620 } 01621 01622 01623 /** 01624 * @brief Decode a 32-bit unsigned integer 01625 * @param[in] src Buffer that contains the encoded value 01626 * @param[in] length Number of bytes to be processed 01627 * @param[out] value Resulting integer value 01628 * @return Error code 01629 **/ 01630 01631 error_t snmpDecodeUnsignedInt32(const uint8_t *src, size_t length, uint32_t *value) 01632 { 01633 size_t i; 01634 01635 //Check parameters 01636 if(src == NULL || value == NULL) 01637 return ERROR_INVALID_PARAMETER; 01638 if(length < 1) 01639 return ERROR_INVALID_PARAMETER; 01640 01641 //Only accept non-negative numbers 01642 if(src[0] & 0x80) 01643 return ERROR_FAILURE; 01644 01645 //Initialize integer value 01646 *value = 0; 01647 01648 //Process contents octets 01649 for(i = 0; i < length; i++) 01650 { 01651 //Rotate left operation 01652 *value <<= 8; 01653 //Reconstruct integer value 01654 *value |= src[i]; 01655 } 01656 01657 //Successful processing 01658 return NO_ERROR; 01659 } 01660 01661 01662 /** 01663 * @brief Decode a 64-bit unsigned integer 01664 * @param[in] src Buffer that contains the encoded value 01665 * @param[in] length Number of bytes to be processed 01666 * @param[out] value Resulting integer value 01667 * @return Error code 01668 **/ 01669 01670 error_t snmpDecodeUnsignedInt64(const uint8_t *src, size_t length, uint64_t *value) 01671 { 01672 size_t i; 01673 01674 //Check parameters 01675 if(src == NULL || value == NULL) 01676 return ERROR_INVALID_PARAMETER; 01677 if(length < 1) 01678 return ERROR_INVALID_PARAMETER; 01679 01680 //Only accept non-negative numbers 01681 if(src[0] & 0x80) 01682 return ERROR_FAILURE; 01683 01684 //Initialize integer value 01685 *value = 0; 01686 01687 //Process contents octets 01688 for(i = 0; i < length; i++) 01689 { 01690 //Rotate left operation 01691 *value <<= 8; 01692 //Reconstruct integer value 01693 *value |= src[i]; 01694 } 01695 01696 //Successful processing 01697 return NO_ERROR; 01698 } 01699 01700 #endif 01701
Generated on Tue Jul 12 2022 17:10:16 by
1.7.2