Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers snmp_common.c Source File

snmp_common.c

Go to the documentation of this file.
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