Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers snmp_agent_misc.c Source File

snmp_agent_misc.c

Go to the documentation of this file.
00001 /**
00002  * @file snmp_agent_misc.c
00003  * @brief SNMP agent (miscellaneous functions)
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 <limits.h>
00034 #include "core/net.h"
00035 #include "snmp/snmp_agent.h"
00036 #include "snmp/snmp_agent_misc.h"
00037 #include "mibs/mib2_module.h"
00038 #include "crypto.h"
00039 #include "asn1.h"
00040 #include "oid.h"
00041 #include "debug.h"
00042 
00043 //Check TCP/IP stack configuration
00044 #if (SNMP_AGENT_SUPPORT == ENABLED)
00045 
00046 
00047 /**
00048  * @brief Lock MIB bases
00049  **/
00050 
00051 void snmpLockMib(SnmpAgentContext *context)
00052 {
00053    uint_t i;
00054 
00055    //Loop through MIBs
00056    for(i = 0; i < context->mibModuleCount; i++)
00057    {
00058       //Lock access to MIB base
00059       if(context->mibModule[i]->lock != NULL)
00060       {
00061          context->mibModule[i]->lock();
00062       }
00063    }
00064 }
00065 
00066 
00067 /**
00068  * @brief Unlock MIB bases
00069  **/
00070 
00071 void snmpUnlockMib(SnmpAgentContext *context)
00072 {
00073    uint_t i;
00074 
00075    //Loop through MIBs
00076    for(i = 0; i < context->mibModuleCount; i++)
00077    {
00078       //Unlock access to MIB base
00079       if(context->mibModule[i]->unlock != NULL)
00080       {
00081          context->mibModule[i]->unlock();
00082       }
00083    }
00084 }
00085 
00086 
00087 /**
00088  * @brief Initialize a GetResponse-PDU
00089  * @param[in] context Pointer to the SNMP agent context
00090  * @return Error code
00091  **/
00092 
00093 error_t snmpInitResponse(SnmpAgentContext *context)
00094 {
00095    error_t error;
00096 
00097    //Initialize SNMP message
00098    snmpInitMessage(&context->response);
00099 
00100    //SNMP version identifier
00101    context->response.version = context->request.version;
00102 
00103 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
00104    //Community name
00105    context->response.community = context->request.community;
00106    context->response.communityLen = context->request.communityLen;
00107 #endif
00108 
00109 #if (SNMP_V3_SUPPORT == ENABLED)
00110    //Message identifier
00111    context->response.msgId = context->request.msgId;
00112    //Maximum message size supported by the sender
00113    context->response.msgMaxSize = SNMP_MAX_MSG_SIZE;
00114 
00115    //Bit fields which control processing of the message
00116    context->response.msgFlags = context->request.msgFlags &
00117       (SNMP_MSG_FLAG_AUTH | SNMP_MSG_FLAG_PRIV);
00118 
00119    //Security model used by the sender
00120    context->response.msgSecurityModel = context->request.msgSecurityModel;
00121 
00122    //Authoritative engine identifier
00123    context->response.msgAuthEngineId = context->contextEngine;
00124    context->response.msgAuthEngineIdLen = context->contextEngineLen;
00125 
00126    //Number of times the SNMP engine has rebooted
00127    context->response.msgAuthEngineBoots = context->engineBoots;
00128    //Number of seconds since last reboot
00129    context->response.msgAuthEngineTime = context->engineTime;
00130 
00131    //User name
00132    context->response.msgUserName = context->request.msgUserName;
00133    context->response.msgUserNameLen = context->request.msgUserNameLen;
00134 
00135    //Authentication parameters
00136    context->response.msgAuthParameters = NULL;
00137    context->response.msgAuthParametersLen = context->request.msgAuthParametersLen;
00138 
00139    //Privacy parameters
00140    context->response.msgPrivParameters = context->privParameters;
00141    context->response.msgPrivParametersLen = context->request.msgPrivParametersLen;
00142 
00143    //Context engine identifier
00144    context->response.contextEngineId = context->contextEngine;
00145    context->response.contextEngineIdLen = context->contextEngineLen;
00146 
00147    //Context name
00148    context->response.contextName = context->request.contextName;
00149    context->response.contextNameLen = context->request.contextNameLen;
00150 #endif
00151 
00152    //PDU type
00153    context->response.pduType = SNMP_PDU_GET_RESPONSE;
00154    //Request identifier
00155    context->response.requestId = context->request.requestId;
00156 
00157    //Make room for the message header at the beginning of the buffer
00158    error = snmpComputeMessageOverhead(&context->response);
00159    //Return status code
00160    return error;
00161 }
00162 
00163 
00164 /**
00165  * @brief Refresh SNMP engine time
00166  * @param[in] context Pointer to the SNMP agent context
00167  **/
00168 
00169 void snmpRefreshEngineTime(SnmpAgentContext *context)
00170 {
00171 #if (SNMP_V3_SUPPORT == ENABLED)
00172    systime_t delta;
00173    int32_t newEngineTime;
00174 
00175    //Number of seconds elapsed since the last call
00176    delta = (osGetSystemTime() - context->systemTime) / 1000;
00177    //Increment SNMP engine time
00178    newEngineTime = context->engineTime + delta;
00179 
00180    //Check whether the SNMP engine time has rolled over
00181    if(newEngineTime < context->engineTime)
00182    {
00183       //If snmpEngineTime ever reaches its maximum value (2147483647), then
00184       //snmpEngineBoots is incremented as if the SNMP engine has re-booted
00185       //and snmpEngineTime is reset to zero and starts incrementing again
00186       context->engineBoots++;
00187       context->engineTime = 0;
00188    }
00189    else
00190    {
00191       //Update SNMP engine time
00192       context->engineTime = newEngineTime;
00193    }
00194 
00195    //Save timestamp
00196    context->systemTime += delta * 1000;
00197 #endif
00198 }
00199 
00200 
00201 /**
00202  * @brief Replay protection
00203  * @param[in] context Pointer to the SNMP agent context
00204  * @param[in,out] message Pointer to the incoming SNMP message
00205  * @return Error code
00206  **/
00207 
00208 error_t snmpCheckEngineTime(SnmpAgentContext *context, SnmpMessage *message)
00209 {
00210    error_t error = NO_ERROR;
00211 
00212 #if (SNMP_V3_SUPPORT == ENABLED)
00213    //If any of the following conditions is true, then the message is
00214    //considered to be outside of the time window
00215    if(context->engineBoots == INT32_MAX)
00216    {
00217       //The local value of snmpEngineBoots is 2147483647
00218       error = ERROR_NOT_IN_TIME_WINDOW;
00219    }
00220    else if(context->engineBoots != message->msgAuthEngineBoots)
00221    {
00222       //The value of the msgAuthoritativeEngineBoots field differs from
00223       //the local value of snmpEngineBoots
00224       error = ERROR_NOT_IN_TIME_WINDOW;
00225    }
00226    else if((context->engineTime - message->msgAuthEngineTime) > SNMP_TIME_WINDOW ||
00227       (message->msgAuthEngineTime - context->engineTime) > SNMP_TIME_WINDOW)
00228    {
00229       //The value of the msgAuthoritativeEngineTime field differs from the
00230       //local notion of snmpEngineTime by more than +/- 150 seconds
00231       error = ERROR_NOT_IN_TIME_WINDOW;
00232    }
00233 #endif
00234 
00235    //If the message is considered to be outside of the time window then an
00236    //error indication (notInTimeWindow) is returned to the calling module
00237    return error;
00238 }
00239 
00240 
00241 /**
00242  * @brief Find user in the local configuration datastore
00243  * @param[in] context Pointer to the SNMP agent context
00244  * @param[in] name Pointer to the user name
00245  * @param[in] length Length of the user name
00246  * @return Security profile corresponding to the specified user name
00247  **/
00248 
00249 SnmpUserInfo *snmpFindUser(SnmpAgentContext *context,
00250    const char_t *name, size_t length)
00251 {
00252    uint_t i;
00253    SnmpUserInfo *entry;
00254 
00255    //Initialize pointer
00256    entry = NULL;
00257 
00258    //Sanity check
00259    if(name != NULL)
00260    {
00261       //Loop through the local configuration datastore
00262       for(i = 0; i < SNMP_AGENT_MAX_USER_COUNT; i++)
00263       {
00264          //Compare user names
00265          if(strlen(context->userTable[i].name) == length)
00266          {
00267             if(!strncmp(context->userTable[i].name, name, length))
00268             {
00269                //A matching entry has been found
00270                entry = &context->userTable[i];
00271                //We are done
00272                break;
00273             }
00274          }
00275       }
00276    }
00277 
00278    //Return the security profile that corresponds to the specified user name
00279    return entry;
00280 }
00281 
00282 
00283 /**
00284  * @brief Parse variable binding
00285  * @param[in] p Input stream where to read the variable binding
00286  * @param[in] length Number of bytes available in the input stream
00287  * @param[out] var Variable binding
00288  * @param[out] consumed Total number of bytes that have been consumed
00289  * @return Error code
00290  **/
00291 
00292 error_t snmpParseVarBinding(const uint8_t *p,
00293    size_t length, SnmpVarBind *var, size_t *consumed)
00294 {
00295    error_t error;
00296    Asn1Tag tag;
00297 
00298    //The variable binding is encapsulated within a sequence
00299    error = asn1ReadTag(p, length, &tag);
00300    //Failed to decode ASN.1 tag?
00301    if(error)
00302       return error;
00303 
00304    //Enforce encoding, class and type
00305    error = asn1CheckTag(&tag, TRUE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_SEQUENCE);
00306    //The tag does not match the criteria?
00307    if(error)
00308       return error;
00309 
00310    //Total number of bytes that have been consumed
00311    *consumed = tag.totalLength;
00312 
00313    //Point to the first item of the sequence
00314    p = tag.value;
00315    length = tag.length;
00316 
00317    //Read object name
00318    error = asn1ReadTag(p, length, &tag);
00319    //Failed to decode ASN.1 tag?
00320    if(error)
00321       return error;
00322 
00323    //Enforce encoding, class and type
00324    error = asn1CheckTag(&tag, FALSE, ASN1_CLASS_UNIVERSAL, ASN1_TYPE_OBJECT_IDENTIFIER);
00325    //The tag does not match the criteria?
00326    if(error)
00327       return error;
00328 
00329    //Save object identifier
00330    var->oid = tag.value;
00331    var->oidLen = tag.length;
00332 
00333    //Point to the next item
00334    p += tag.totalLength;
00335    length -= tag.totalLength;
00336 
00337    //Read object value
00338    error = asn1ReadTag(p, length, &tag);
00339    //Failed to decode ASN.1 tag?
00340    if(error)
00341       return error;
00342 
00343    //Make sure that the tag is valid
00344    if(tag.constructed)
00345       return ERROR_INVALID_TAG;
00346 
00347    //Save object class
00348    var->objClass = tag.objClass;
00349    //Save object type
00350    var->objType = tag.objType;
00351    //Save object value
00352    var->value = tag.value;
00353    var->valueLen = tag.length;
00354 
00355    //Successful processing
00356    return NO_ERROR;
00357 }
00358 
00359 
00360 /**
00361  * @brief Write variable binding
00362  * @param[in] context Pointer to the SNMP agent context
00363  * @param[in] var Variable binding
00364  * @return Error code
00365  **/
00366 
00367 error_t snmpWriteVarBinding(SnmpAgentContext *context, const SnmpVarBind *var)
00368 {
00369    error_t error;
00370    size_t m;
00371    size_t n;
00372    uint8_t *p;
00373    Asn1Tag tag;
00374 
00375    //The object's name is encoded in ASN.1 format
00376    tag.constructed = FALSE;
00377    tag.objClass = ASN1_CLASS_UNIVERSAL;
00378    tag.objType = ASN1_TYPE_OBJECT_IDENTIFIER;
00379    tag.length = var->oidLen;
00380    tag.value = var->oid;
00381 
00382    //Calculate the total length of the ASN.1 tag
00383    error = asn1WriteTag(&tag, FALSE, NULL, &m);
00384    //Any error to report?
00385    if(error)
00386       return error;
00387 
00388    //The object's value is encoded in ASN.1 format
00389    tag.constructed = FALSE;
00390    tag.objClass = var->objClass;
00391    tag.objType = var->objType;
00392    tag.length = var->valueLen;
00393    tag.value = var->value;
00394 
00395    //Calculate the total length of the ASN.1 tag
00396    error = asn1WriteTag(&tag, FALSE, NULL, &n);
00397    //Any error to report?
00398    if(error)
00399       return error;
00400 
00401    //The variable binding is encapsulated within a sequence
00402    tag.constructed = TRUE;
00403    tag.objClass = ASN1_CLASS_UNIVERSAL;
00404    tag.objType = ASN1_TYPE_SEQUENCE;
00405    tag.length = m + n;
00406    tag.value = NULL;
00407 
00408    //The first pass computes the total length of the sequence
00409    error = asn1WriteTag(&tag, FALSE, NULL, NULL);
00410    //Any error to report?
00411    if(error)
00412       return error;
00413 
00414    //Make sure the buffer is large enough to hold the whole sequence
00415    if((context->response.varBindListLen + tag.totalLength) >
00416       context->response.varBindListMaxLen)
00417    {
00418       //Report an error
00419       return ERROR_BUFFER_OVERFLOW;
00420    }
00421 
00422    //The second pass encodes the sequence in reverse order
00423    p = context->response.varBindList + context->response.varBindListLen +
00424       tag.totalLength;
00425 
00426    //Encode the object's value using ASN.1
00427    tag.constructed = FALSE;
00428    tag.objClass = var->objClass;
00429    tag.objType = var->objType;
00430    tag.length = var->valueLen;
00431    tag.value = var->value;
00432 
00433    //Write the corresponding ASN.1 tag
00434    error = asn1WriteTag(&tag, TRUE, p, &m);
00435    //Any error to report?
00436    if(error)
00437       return error;
00438 
00439    //Move backward
00440    p -= m;
00441 
00442    //Encode the object's name using ASN.1
00443    tag.constructed = FALSE;
00444    tag.objClass = ASN1_CLASS_UNIVERSAL;
00445    tag.objType = ASN1_TYPE_OBJECT_IDENTIFIER;
00446    tag.length = var->oidLen;
00447    tag.value = var->oid;
00448 
00449    //Write the corresponding ASN.1 tag
00450    error = asn1WriteTag(&tag, TRUE, p, &n);
00451    //Any error to report?
00452    if(error)
00453       return error;
00454 
00455    //Move backward
00456    p -= n;
00457 
00458    //The variable binding is encapsulated within a sequence
00459    tag.constructed = TRUE;
00460    tag.objClass = ASN1_CLASS_UNIVERSAL;
00461    tag.objType = ASN1_TYPE_SEQUENCE;
00462    tag.length = m + n;
00463    tag.value = NULL;
00464 
00465    //Write the corresponding ASN.1 tag
00466    error = asn1WriteTag(&tag, TRUE, p, NULL);
00467    //Any error to report?
00468    if(error)
00469       return error;
00470 
00471    //Update the length of the list
00472    context->response.varBindListLen += tag.totalLength;
00473 
00474    //Successful processing
00475    return NO_ERROR;
00476 }
00477 
00478 
00479 /**
00480  * @brief Copy the list of variable bindings
00481  * @param[in] context Pointer to the SNMP agent context
00482  * @return Error code
00483  **/
00484 
00485 error_t snmpCopyVarBindingList(SnmpAgentContext *context)
00486 {
00487    //Sanity check
00488    if(context->request.varBindListLen > context->response.varBindListMaxLen)
00489       return ERROR_BUFFER_OVERFLOW;
00490 
00491    //Copy the list of variable bindings to the response buffer
00492    memcpy(context->response.varBindList, context->request.varBindList,
00493       context->request.varBindListLen);
00494 
00495    //Save the length of the list
00496    context->response.varBindListLen = context->request.varBindListLen;
00497 
00498    //Successful processing
00499    return NO_ERROR;
00500 }
00501 
00502 
00503 /**
00504  * @brief Assign object value
00505  * @param[in] context Pointer to the SNMP agent context
00506  * @param[in] var Variable binding
00507  * @param[in] commit This flag tells whether the changes should be
00508  *   committed to the MIB base
00509  * @return Error code
00510  **/
00511 
00512 error_t snmpSetObjectValue(SnmpAgentContext *context, SnmpVarBind *var, bool_t commit)
00513 {
00514    error_t error;
00515    size_t n;
00516    MibVariant *value;
00517    const MibObject *object;
00518 
00519    //Search the MIB for the specified object
00520    error = snmpFindMibObject(context, var->oid, var->oidLen, &object);
00521    //Cannot found the specified object?
00522    if(error)
00523       return error;
00524 
00525    //Debug message
00526    TRACE_INFO("  %s\r\n", object->name);
00527 
00528    //Make sure the specified object is available for set operations
00529    if(object->access != MIB_ACCESS_WRITE_ONLY &&
00530       object->access != MIB_ACCESS_READ_WRITE)
00531    {
00532       //Report an error
00533       return ERROR_NOT_WRITABLE;
00534    }
00535 
00536    //Check class
00537    if(var->objClass != object->objClass)
00538       return ERROR_WRONG_TYPE;
00539    //Check type
00540    if(var->objType != object->objType)
00541       return ERROR_WRONG_TYPE;
00542 
00543    //Point to the object value
00544    value = (MibVariant *) var->value;
00545    //Get the length of the object value
00546    n = var->valueLen;
00547 
00548    //Check object class
00549    if(object->objClass == ASN1_CLASS_UNIVERSAL)
00550    {
00551       //Check object type
00552       if(object->objType == ASN1_TYPE_INTEGER)
00553       {
00554          int32_t val;
00555 
00556          //Integer objects use ASN.1 encoding rules
00557          error = snmpDecodeInt32(var->value, n, &val);
00558          //Conversion failed?
00559          if(error)
00560             return ERROR_WRONG_ENCODING;
00561 
00562          //Point to the scratch buffer
00563          value = (MibVariant *) context->response.buffer;
00564          //Save resulting value
00565          value->integer = val;
00566          //Integer size
00567          n = sizeof(int32_t);
00568       }
00569    }
00570    else if(object->objClass == ASN1_CLASS_APPLICATION)
00571    {
00572       //Check object type
00573       if(object->objType == MIB_TYPE_IP_ADDRESS)
00574       {
00575          //IpAddress objects have fixed size
00576          if(n != object->valueSize)
00577             return ERROR_WRONG_LENGTH;
00578       }
00579       else if(object->objType == MIB_TYPE_COUNTER32 ||
00580          object->objType == MIB_TYPE_GAUGE32 ||
00581          object->objType == MIB_TYPE_TIME_TICKS)
00582       {
00583          uint32_t val;
00584 
00585          //Counter32, Gauge32 and TimeTicks objects use ASN.1 encoding rules
00586          error = snmpDecodeUnsignedInt32(var->value, n, &val);
00587          //Conversion failed?
00588          if(error)
00589             return ERROR_WRONG_ENCODING;
00590 
00591          //Point to the scratch buffer
00592          value = (MibVariant *) context->response.buffer;
00593          //Save resulting value
00594          value->counter32 = val;
00595          //Integer size
00596          n = sizeof(uint32_t);
00597       }
00598       else if(object->objType == MIB_TYPE_COUNTER64)
00599       {
00600          uint64_t val;
00601 
00602          //Counter64 objects use ASN.1 encoding rules
00603          error = snmpDecodeUnsignedInt64(var->value, n, &val);
00604          //Conversion failed?
00605          if(error)
00606             return ERROR_WRONG_ENCODING;
00607 
00608          //Point to the scratch buffer
00609          value = (MibVariant *) context->response.buffer;
00610          //Save resulting value
00611          value->counter64 = val;
00612          //Integer size
00613          n = sizeof(uint64_t);
00614       }
00615    }
00616 
00617    //Objects can be assigned a value using a callback function
00618    if(object->setValue != NULL)
00619    {
00620       //Check whether the changes shall be committed to the MIB base
00621       if(commit)
00622       {
00623          //Invoke callback function to assign object value
00624          error = object->setValue(object, var->oid, var->oidLen, value, n);
00625       }
00626       else
00627       {
00628          //Successful write operation
00629          error = NO_ERROR;
00630       }
00631    }
00632    //Simple scalar objects can also be attached to a variable
00633    else if(object->value != NULL)
00634    {
00635       //Check the length of the object
00636       if(n <= object->valueSize)
00637       {
00638          //Check whether the changes shall be committed to the MIB base
00639          if(commit)
00640          {
00641             //Record the length of the object value
00642             if(object->valueLen != NULL)
00643                *object->valueLen = n;
00644 
00645             //Set object value
00646             memcpy(object->value, value, n);
00647          }
00648 
00649          //Successful write operation
00650          error = NO_ERROR;
00651       }
00652       else
00653       {
00654          //Invalid length
00655          error = ERROR_WRONG_LENGTH;
00656       }
00657    }
00658    else
00659    {
00660       //Report an error
00661       error = ERROR_WRITE_FAILED;
00662    }
00663 
00664    //Return status code
00665    return error;
00666 }
00667 
00668 
00669 /**
00670  * @brief Retrieve object value
00671  * @param[in] context Pointer to the SNMP agent context
00672  * @param[out] var Variable binding
00673  * @return Error code
00674  **/
00675 
00676 error_t snmpGetObjectValue(SnmpAgentContext *context, SnmpVarBind *var)
00677 {
00678    error_t error;
00679    size_t n;
00680    MibVariant *value;
00681    const MibObject *object;
00682 
00683    //Search the MIB for the specified object
00684    error = snmpFindMibObject(context, var->oid, var->oidLen, &object);
00685    //Cannot found the specified object?
00686    if(error)
00687       return error;
00688 
00689    //Debug message
00690    TRACE_INFO("  %s\r\n", object->name);
00691 
00692    //Make sure the specified object is available for get operations
00693    if(object->access != MIB_ACCESS_READ_ONLY &&
00694       object->access != MIB_ACCESS_READ_WRITE)
00695    {
00696       //Report an error
00697       return ERROR_ACCESS_DENIED;
00698    }
00699 
00700    //Buffer where to store the object value
00701    value = (MibVariant *) (context->response.varBindList +
00702       context->response.varBindListLen + context->response.oidLen);
00703 
00704    //Number of bytes available in the buffer
00705    n = context->response.varBindListMaxLen -
00706       (context->response.varBindListLen + context->response.oidLen);
00707 
00708    //Check object class
00709    if(object->objClass == ASN1_CLASS_UNIVERSAL)
00710    {
00711       //Check object type
00712       if(object->objType == ASN1_TYPE_INTEGER)
00713       {
00714          //Make sure the buffer is large enough
00715          if(n < object->valueSize)
00716             return ERROR_BUFFER_OVERFLOW;
00717 
00718          //Integer objects have fixed size
00719          n = object->valueSize;
00720       }
00721    }
00722    else if(object->objClass == ASN1_CLASS_APPLICATION)
00723    {
00724       //Check object type
00725       if(object->objType == MIB_TYPE_IP_ADDRESS ||
00726          object->objType == MIB_TYPE_COUNTER32 ||
00727          object->objType == MIB_TYPE_GAUGE32 ||
00728          object->objType == MIB_TYPE_TIME_TICKS ||
00729          object->objType == MIB_TYPE_COUNTER64)
00730       {
00731          //Make sure the buffer is large enough
00732          if(n < object->valueSize)
00733             return ERROR_BUFFER_OVERFLOW;
00734 
00735          //IpAddress, Counter32, Gauge32, TimeTicks and
00736          //Counter64 objects have fixed size
00737          n = object->valueSize;
00738       }
00739    }
00740 
00741    //Object value can be retrieved using a callback function
00742    if(object->getValue != NULL)
00743    {
00744       //Invoke callback function to retrieve object value
00745       error = object->getValue(object, var->oid, var->oidLen, value, &n);
00746    }
00747    //Simple scalar objects can also be attached to a variable
00748    else if(object->value != NULL)
00749    {
00750       //Get the length of the object value
00751       if(object->valueLen != NULL)
00752          n = *object->valueLen;
00753 
00754       //Retrieve object value
00755       memcpy(value, object->value, n);
00756       //Successful read operation
00757       error = NO_ERROR;
00758    }
00759    else
00760    {
00761       //Report an error
00762       error = ERROR_READ_FAILED;
00763    }
00764 
00765    //Unable to retrieve object value?
00766    if(error)
00767       return error;
00768 
00769    //Check object class
00770    if(object->objClass == ASN1_CLASS_UNIVERSAL)
00771    {
00772       //Check object type
00773       if(object->objType == ASN1_TYPE_INTEGER)
00774       {
00775          //Encode Integer objects using ASN.1 rules
00776          error = snmpEncodeInt32(value->integer, (uint8_t *) value, &n);
00777       }
00778       else
00779       {
00780          //No conversion required for OctetString and ObjectIdentifier objects
00781          error = NO_ERROR;
00782       }
00783    }
00784    else if(object->objClass == ASN1_CLASS_APPLICATION)
00785    {
00786       //Check object type
00787       if(object->objType == MIB_TYPE_COUNTER32 ||
00788          object->objType == MIB_TYPE_GAUGE32 ||
00789          object->objType == MIB_TYPE_TIME_TICKS)
00790       {
00791          //Encode Counter32, Gauge32 and TimeTicks objects using ASN.1 rules
00792          error = snmpEncodeUnsignedInt32(value->counter32, (uint8_t *) value, &n);
00793       }
00794       else if(object->objType == MIB_TYPE_COUNTER64)
00795       {
00796          //Encode Counter64 objects using ASN.1 rules
00797          error = snmpEncodeUnsignedInt64(value->counter64, (uint8_t *) value, &n);
00798       }
00799       else
00800       {
00801          //No conversion required for Opaque objects
00802          error = NO_ERROR;
00803       }
00804    }
00805 
00806    //Save object class and type
00807    var->objClass = object->objClass;
00808    var->objType = object->objType;
00809 
00810    //Save object value
00811    var->value = (uint8_t *) value;
00812    var->valueLen = n;
00813 
00814    //Return status code
00815    return error;
00816 }
00817 
00818 
00819 /**
00820  * @brief Search MIBs for the next object
00821  * @param[in] context Pointer to the SNMP agent context
00822  * @param[in] var Variable binding
00823  * @return Error pointer
00824  **/
00825 
00826 error_t snmpGetNextObject(SnmpAgentContext *context, SnmpVarBind *var)
00827 {
00828    error_t error;
00829    uint_t i;
00830    uint_t j;
00831    size_t nextOidLen;
00832    uint8_t *nextOid;
00833    const MibObject *object;
00834 
00835    //Buffer where to store the next object identifier
00836    nextOid = context->response.varBindList + context->response.varBindListLen;
00837 
00838    //Loop through MIBs
00839    for(i = 0; i < context->mibModuleCount; i++)
00840    {
00841       //Point the first object of the MIB
00842       object = context->mibModule[i]->objects;
00843 
00844       //Loop through objects
00845       for(j = 0; j < context->mibModule[i]->numObjects; j++)
00846       {
00847          //Scalar or tabular object?
00848          if(object->getNext == NULL)
00849          {
00850             //Take in account the instance sub-identifier to determine
00851             //the length of the OID
00852             nextOidLen = object->oidLen + 1;
00853 
00854             //Make sure the buffer is large enough to hold the entire OID
00855             if((context->response.varBindListLen + nextOidLen) >
00856                context->response.varBindListMaxLen)
00857             {
00858                //Report an error
00859                return ERROR_BUFFER_OVERFLOW;
00860             }
00861 
00862             //Copy object identifier
00863             memcpy(nextOid, object->oid, object->oidLen);
00864             //Append instance sub-identifier
00865             nextOid[nextOidLen - 1] = 0;
00866 
00867             //Perform lexicographical comparison
00868             if(oidComp(var->oid, var->oidLen, nextOid, nextOidLen) < 0)
00869             {
00870                //Replace the original OID with the name of the next object
00871                var->oid = nextOid;
00872                var->oidLen = nextOidLen;
00873 
00874                //Save the length of the OID
00875                context->response.oidLen = nextOidLen;
00876 
00877                //The specified OID lexicographically precedes the name
00878                //of the current object
00879                return NO_ERROR;
00880             }
00881          }
00882          else
00883          {
00884             //Maximum acceptable size of the OID
00885             nextOidLen = context->response.varBindListMaxLen -
00886                context->response.varBindListLen;
00887 
00888             //Search the MIB for the next object
00889             error = object->getNext(object, var->oid, var->oidLen, nextOid, &nextOidLen);
00890 
00891             //Check status code
00892             if(error == NO_ERROR)
00893             {
00894                //Replace the original OID with the name of the next object
00895                var->oid = nextOid;
00896                var->oidLen = nextOidLen;
00897 
00898                //Save the length of the OID
00899                context->response.oidLen = nextOidLen;
00900 
00901                //The specified OID lexicographically precedes the name
00902                //of the current object
00903                return NO_ERROR;
00904             }
00905             if(error != ERROR_OBJECT_NOT_FOUND)
00906             {
00907                //Exit immediately
00908                return error;
00909             }
00910          }
00911 
00912          //Point to the next object in the MIB
00913          object++;
00914       }
00915    }
00916 
00917    //The specified OID does not lexicographically precede the
00918    //name of some object
00919    return ERROR_OBJECT_NOT_FOUND;
00920 }
00921 
00922 
00923 /**
00924  * @brief Search MIBs for the given object
00925  * @param[in] context Pointer to the SNMP agent context
00926  * @param[in] oid Object identifier
00927  * @param[in] oidLen Length of the OID
00928  * @param[out] object Pointer the MIB object descriptor
00929  * @return Error code
00930  **/
00931 
00932 error_t snmpFindMibObject(SnmpAgentContext *context,
00933    const uint8_t *oid, size_t oidLen, const MibObject **object)
00934 {
00935    error_t error;
00936    uint_t i;
00937    uint_t j;
00938    const MibObject *p;
00939 
00940    //Initialize status code
00941    error = ERROR_OBJECT_NOT_FOUND;
00942 
00943    //Loop through MIBs
00944    for(i = 0; i < context->mibModuleCount; i++)
00945    {
00946       //Point the first object of the MIB
00947       p = context->mibModule[i]->objects;
00948 
00949       //Loop through objects
00950       for(j = 0; j < context->mibModule[i]->numObjects; j++)
00951       {
00952          //Check the length of the OID
00953          if(oidLen > p->oidLen)
00954          {
00955             //Compare object names
00956             if(!memcmp(oid, p->oid, p->oidLen))
00957             {
00958                //Scalar object?
00959                if(p->getNext == NULL)
00960                {
00961                   //The instance sub-identifier shall be 0 for scalar objects
00962                   if(oidLen == (p->oidLen + 1) && oid[oidLen - 1] == 0)
00963                   {
00964                      //Return a pointer to the matching object
00965                      *object = p;
00966                      //No error to report
00967                      error = NO_ERROR;
00968                   }
00969                   else
00970                   {
00971                      //No such instance...
00972                      error = ERROR_INSTANCE_NOT_FOUND;
00973                   }
00974                }
00975                //Tabular object?
00976                else
00977                {
00978                   //Return a pointer to the matching object
00979                   *object = p;
00980                   //No error to report
00981                   error = NO_ERROR;
00982                }
00983 
00984                //Exit immediately
00985                break;
00986             }
00987          }
00988 
00989          //Point to the next object in the MIB
00990          p++;
00991       }
00992    }
00993 
00994    //Return status code
00995    return error;
00996 }
00997 
00998 
00999 /**
01000  * @brief Translate status code
01001  * @param[in,out] message Pointer to the outgoing SNMP message
01002  * @param[in] status Status code
01003  * @param[in] index Index of the variable binding in the list that caused an exception
01004  * @return error code
01005  **/
01006 
01007 error_t snmpTranslateStatusCode(SnmpMessage *message, error_t status, uint_t index)
01008 {
01009    //SNMPv1 version?
01010    if(message->version == SNMP_VERSION_1)
01011    {
01012       //Set error-status and error-index fields
01013       switch(status)
01014       {
01015       case NO_ERROR:
01016          //Return noError status code
01017          message->errorStatus = SNMP_ERROR_NONE;
01018          message->errorIndex = 0;
01019          break;
01020 
01021       case ERROR_OBJECT_NOT_FOUND:
01022       case ERROR_INSTANCE_NOT_FOUND:
01023       case ERROR_ACCESS_DENIED:
01024          //Return noSuchName status code
01025          message->errorStatus = SNMP_ERROR_NO_SUCH_NAME;
01026          message->errorIndex = index;
01027 
01028          //Total number of SNMP PDUs which were generated by the SNMP protocol
01029          //entity and for which the value of the error-status field is noSuchName
01030          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutNoSuchNames, 1);
01031          break;
01032 
01033       case ERROR_WRONG_TYPE:
01034       case ERROR_WRONG_LENGTH:
01035       case ERROR_WRONG_ENCODING:
01036       case ERROR_WRONG_VALUE:
01037          //Return badValue status code
01038          message->errorStatus = SNMP_ERROR_BAD_VALUE;
01039          message->errorIndex = index;
01040 
01041          //Total number of SNMP PDUs which were generated by the SNMP protocol
01042          //entity and for which the value of the error-status field is badValue
01043          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutBadValues, 1);
01044          break;
01045 
01046       case ERROR_READ_FAILED:
01047       case ERROR_WRITE_FAILED:
01048       case ERROR_NOT_WRITABLE:
01049          //Return genError status code
01050          message->errorStatus = SNMP_ERROR_GENERIC;
01051          message->errorIndex = index;
01052 
01053          //Total number of SNMP PDUs which were generated by the SNMP protocol
01054          //entity and for which the value of the error-status field is genError
01055          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutGenErrs, 1);
01056          break;
01057 
01058       case ERROR_BUFFER_OVERFLOW:
01059          //Return tooBig status code
01060          message->errorStatus = SNMP_ERROR_TOO_BIG;
01061          message->errorIndex = 0;
01062 
01063          //Total number of SNMP PDUs which were generated by the SNMP protocol
01064          //entity and for which the value of the error-status field is tooBig
01065          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutTooBigs, 1);
01066          break;
01067 
01068       default:
01069          //If the parsing of the request fails, the SNMP agent discards
01070          //the message and performs no further actions
01071          return status;
01072       }
01073    }
01074    //SNMPv2c or SNMPv3 version?
01075    else
01076    {
01077       //Set error-status and error-index fields
01078       switch(status)
01079       {
01080       case NO_ERROR:
01081          //Return noError status code
01082          message->errorStatus = SNMP_ERROR_NONE;
01083          message->errorIndex = 0;
01084          break;
01085 
01086       case ERROR_OBJECT_NOT_FOUND:
01087       case ERROR_INSTANCE_NOT_FOUND:
01088       case ERROR_ACCESS_DENIED:
01089          //Return noAccess status code
01090          message->errorStatus = SNMP_ERROR_NO_ACCESS;
01091          message->errorIndex = index;
01092          break;
01093 
01094       case ERROR_WRONG_TYPE:
01095          //Return wrongType status code
01096          message->errorStatus = SNMP_ERROR_WRONG_TYPE;
01097          message->errorIndex = index;
01098          break;
01099 
01100       case ERROR_WRONG_LENGTH:
01101          //Return wrongLength status code
01102          message->errorStatus = SNMP_ERROR_WRONG_LENGTH;
01103          message->errorIndex = index;
01104          break;
01105 
01106       case ERROR_WRONG_ENCODING:
01107          //Return wrongEncoding status code
01108          message->errorStatus = SNMP_ERROR_WRONG_ENCODING;
01109          message->errorIndex = index;
01110          break;
01111 
01112       case ERROR_WRONG_VALUE:
01113          //Return wrongValue status code
01114          message->errorStatus = SNMP_ERROR_WRONG_VALUE;
01115          message->errorIndex = index;
01116          break;
01117 
01118       case ERROR_READ_FAILED:
01119       case ERROR_WRITE_FAILED:
01120          //Return genError status code
01121          message->errorStatus = SNMP_ERROR_GENERIC;
01122          message->errorIndex = index;
01123 
01124          //Total number of SNMP PDUs which were generated by the SNMP protocol
01125          //entity and for which the value of the error-status field is genError
01126          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutGenErrs, 1);
01127          break;
01128 
01129       case ERROR_NOT_WRITABLE:
01130          //Return notWritable status code
01131          message->errorStatus = SNMP_ERROR_NOT_WRITABLE;
01132          message->errorIndex = index;
01133          break;
01134 
01135       case ERROR_BUFFER_OVERFLOW:
01136          //Return tooBig status code
01137          message->errorStatus = SNMP_ERROR_TOO_BIG;
01138          message->errorIndex = 0;
01139 
01140          //Total number of SNMP PDUs which were generated by the SNMP protocol
01141          //entity and for which the value of the error-status field is tooBig
01142          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutTooBigs, 1);
01143          break;
01144 
01145       default:
01146          //If the parsing of the request fails, the SNMP agent discards
01147          //the message and performs no further actions
01148          return status;
01149       }
01150    }
01151 
01152    //Successful processing
01153    return NO_ERROR;
01154 }
01155 
01156 #endif
01157