Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers snmp_agent_pdu.c Source File

snmp_agent_pdu.c

Go to the documentation of this file.
00001 /**
00002  * @file snmp_agent_pdu.c
00003  * @brief SNMP agent (PDU processing)
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_agent_pdu.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 //sysUpTime.0 object (1.3.6.1.2.1.1.3.0)
00047 static const uint8_t sysUpTimeObject[] = {43, 6, 1, 2, 1, 1, 3, 0};
00048 //snmpTrapOID.0 object (1.3.6.1.6.3.1.1.4.1.0)
00049 static const uint8_t snmpTrapOidObject[] = {43, 6, 1, 6, 3, 1, 1, 4, 1, 0};
00050 //snmpTraps object (1.3.6.1.6.3.1.1.5)
00051 static const uint8_t snmpTrapsObject[] = {43, 6, 1, 6, 3, 1, 1, 5};
00052 
00053 
00054 /**
00055  * @brief Process PDU
00056  * @param[in] context Pointer to the SNMP agent context
00057  * @return Error code
00058  **/
00059 
00060 error_t snmpProcessPdu(SnmpAgentContext *context)
00061 {
00062    error_t error;
00063 
00064    //Parse PDU header
00065    error = snmpParsePduHeader(&context->request);
00066    //Any error to report?
00067    if(error)
00068       return error;
00069 
00070    //Check PDU type
00071    switch(context->request.pduType)
00072    {
00073    case SNMP_PDU_GET_REQUEST:
00074    case SNMP_PDU_GET_NEXT_REQUEST:
00075       //Process GetRequest-PDU or GetNextRequest-PDU
00076       error = snmpProcessGetRequestPdu(context);
00077       break;
00078    case SNMP_PDU_GET_BULK_REQUEST:
00079       //Process GetBulkRequest-PDU
00080       error = snmpProcessGetBulkRequestPdu(context);
00081       break;
00082    case SNMP_PDU_SET_REQUEST:
00083       //Process SetRequest-PDU
00084       error = snmpProcessSetRequestPdu(context);
00085       break;
00086    default:
00087       //Invalid PDU type
00088       error = ERROR_INVALID_TYPE;
00089       break;
00090    }
00091 
00092    //Check status code
00093    if(!error)
00094    {
00095       //Total number of SNMP Get-Response PDUs which have been generated
00096       //by the SNMP protocol entity
00097       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutGetResponses, 1);
00098 
00099       //Format PDU header
00100       error = snmpWritePduHeader(&context->response);
00101    }
00102 
00103    //Return status code
00104    return error;
00105 }
00106 
00107 
00108 /**
00109  * @brief Process GetRequest-PDU or GetNextRequest-PDU
00110  * @param[in] context Pointer to the SNMP agent context
00111  * @return Error code
00112  **/
00113 
00114 error_t snmpProcessGetRequestPdu(SnmpAgentContext *context)
00115 {
00116    error_t error;
00117    int_t index;
00118    size_t n;
00119    size_t length;
00120    const uint8_t *p;
00121    SnmpVarBind var;
00122 
00123    //Check PDU type
00124    if(context->request.pduType == SNMP_PDU_GET_REQUEST)
00125    {
00126       //Debug message
00127       TRACE_INFO("Parsing GetRequest-PDU...\r\n");
00128 
00129       //Total number of SNMP Get-Request PDUs which have been accepted and
00130       //processed by the SNMP protocol entity
00131       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInGetRequests, 1);
00132    }
00133    else if(context->request.pduType == SNMP_PDU_GET_NEXT_REQUEST)
00134    {
00135       //Debug message
00136       TRACE_INFO("Parsing GetNextRequest-PDU...\r\n");
00137 
00138       //Total number of SNMP Get-NextRequest PDUs which have been accepted
00139       //and processed by the SNMP protocol entity
00140       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInGetNexts, 1);
00141    }
00142 
00143    //Enforce access policy
00144    if(context->user->mode != SNMP_ACCESS_READ_ONLY &&
00145       context->user->mode != SNMP_ACCESS_READ_WRITE)
00146    {
00147       //Total number of SNMP messages delivered to the SNMP protocol entity
00148       //which represented an SNMP operation which was not allowed by the SNMP
00149       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityUses, 1);
00150 
00151       //Report an error
00152       return ERROR_ACCESS_DENIED;
00153    }
00154 
00155    //Initialize response message
00156    error = snmpInitResponse(context);
00157    //Any error to report?
00158    if(error)
00159       return error;
00160 
00161    //Point to the first variable binding of the request
00162    p = context->request.varBindList;
00163    length = context->request.varBindListLen;
00164 
00165    //Lock access to MIB bases
00166    snmpLockMib(context);
00167 
00168    //Loop through the list
00169    for(index = 1; length > 0; index++)
00170    {
00171       //Parse variable binding
00172       error = snmpParseVarBinding(p, length, &var, &n);
00173       //Failed to parse variable binding?
00174       if(error)
00175          break;
00176 
00177       //Make sure that the object identifier is valid
00178       error = oidCheck(var.oid, var.oidLen);
00179       //Invalid object identifier?
00180       if(error)
00181          break;
00182 
00183       //GetRequest-PDU?
00184       if(context->request.pduType == SNMP_PDU_GET_REQUEST)
00185       {
00186          //Retrieve object value
00187          error = snmpGetObjectValue(context, &var);
00188       }
00189       //GetNextRequest-PDU?
00190       else
00191       {
00192          //Search the MIB for the next object
00193          error = snmpGetNextObject(context, &var);
00194 
00195          //SNMPv1 version?
00196          if(context->request.version == SNMP_VERSION_1)
00197          {
00198             //Check status code
00199             if(error == NO_ERROR)
00200             {
00201                //Retrieve object value
00202                error = snmpGetObjectValue(context, &var);
00203             }
00204             else
00205             {
00206                //Stop immediately
00207                break;
00208             }
00209          }
00210          //SNMPv2c or SNMPv3 version?
00211          else
00212          {
00213             //Check status code
00214             if(error == NO_ERROR)
00215             {
00216                //Retrieve object value
00217                error = snmpGetObjectValue(context, &var);
00218             }
00219             else if(error == ERROR_OBJECT_NOT_FOUND)
00220             {
00221                //The variable binding's value field is set to endOfMibView
00222                var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00223                var.objType = SNMP_EXCEPTION_END_OF_MIB_VIEW;
00224                var.valueLen = 0;
00225 
00226                //Catch exception
00227                error = NO_ERROR;
00228             }
00229             else
00230             {
00231                //Stop immediately
00232                break;
00233             }
00234          }
00235       }
00236 
00237       //Failed to retrieve object value?
00238       if(error)
00239       {
00240          //SNMPv1 version?
00241          if(context->request.version == SNMP_VERSION_1)
00242          {
00243             //Stop immediately
00244             break;
00245          }
00246          //SNMPv2c or SNMPv3 version?
00247          else
00248          {
00249             //Catch exception
00250             if(error == ERROR_ACCESS_DENIED ||
00251                error == ERROR_OBJECT_NOT_FOUND)
00252             {
00253                //The variable binding's value field is set to noSuchObject
00254                var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00255                var.objType = SNMP_EXCEPTION_NO_SUCH_OBJECT;
00256                var.valueLen = 0;
00257             }
00258             else if(error == ERROR_INSTANCE_NOT_FOUND)
00259             {
00260                //The variable binding's value field is set to noSuchInstance
00261                var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00262                var.objType = SNMP_EXCEPTION_NO_SUCH_INSTANCE;
00263                var.valueLen = 0;
00264             }
00265             else
00266             {
00267                //Stop immediately
00268                break;
00269             }
00270          }
00271       }
00272       else
00273       {
00274          //Total number of MIB objects which have been retrieved successfully
00275          //by the SNMP protocol entity as the result of receiving valid SNMP
00276          //Get-Request and Get-NextRequest PDUs
00277          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInTotalReqVars, 1);
00278       }
00279 
00280       //Append variable binding to the list
00281       error = snmpWriteVarBinding(context, &var);
00282       //Any error to report?
00283       if(error)
00284          break;
00285 
00286       //Advance data pointer
00287       p += n;
00288       length -= n;
00289    }
00290 
00291    //Unlock access to MIB bases
00292    snmpUnlockMib(context);
00293 
00294    //Check status code
00295    if(error)
00296    {
00297       //Set error-status and error-index fields
00298       error = snmpTranslateStatusCode(&context->response, error, index);
00299       //If the parsing of the request fails, the SNMP agent discards the message
00300       if(error)
00301          return error;
00302 
00303       //Check whether an alternate Response-PDU should be sent
00304       if(context->response.version != SNMP_VERSION_1 &&
00305          context->response.errorStatus == SNMP_ERROR_TOO_BIG)
00306       {
00307          //The alternate Response-PDU is formatted with the same value in its
00308          //request-id field as the received GetRequest-PDU and an empty
00309          //variable-bindings field
00310          context->response.varBindListLen = 0;
00311       }
00312       else
00313       {
00314          //The Response-PDU is re-formatted with the same values in its request-id
00315          //and variable-bindings fields as the received GetRequest-PDU
00316          error = snmpCopyVarBindingList(context);
00317          //Any error to report?
00318          if(error)
00319             return error;
00320       }
00321    }
00322 
00323    //Successful processing
00324    return NO_ERROR;
00325 }
00326 
00327 
00328 /**
00329  * @brief Process GetBulkRequest-PDU
00330  * @param[in] context Pointer to the SNMP agent context
00331  * @return Error code
00332  **/
00333 
00334 error_t snmpProcessGetBulkRequestPdu(SnmpAgentContext *context)
00335 {
00336 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED)
00337    error_t error;
00338    int_t index;
00339    size_t n;
00340    size_t m;
00341    size_t length;
00342    bool_t endOfMibView;
00343    const uint8_t *p;
00344    const uint8_t *next;
00345    SnmpVarBind var;
00346 
00347    //Debug message
00348    TRACE_INFO("Parsing GetBulkRequest-PDU...\r\n");
00349 
00350    //Make sure the SNMP version identifier is valid
00351    if(context->request.version == SNMP_VERSION_1)
00352    {
00353       //The SNMP version is not acceptable
00354       return ERROR_INVALID_TYPE;
00355    }
00356 
00357    //Enforce access policy
00358    if(context->user->mode != SNMP_ACCESS_READ_ONLY &&
00359       context->user->mode != SNMP_ACCESS_READ_WRITE)
00360    {
00361       //Total number of SNMP messages delivered to the SNMP protocol entity
00362       //which represented an SNMP operation which was not allowed by the SNMP
00363       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityUses, 1);
00364 
00365       //Report an error
00366       return ERROR_ACCESS_DENIED;
00367    }
00368 
00369    //Initialize response message
00370    error = snmpInitResponse(context);
00371    //Any error to report?
00372    if(error)
00373       return error;
00374 
00375    //Point to the first variable binding of the request
00376    p = context->request.varBindList;
00377    length = context->request.varBindListLen;
00378 
00379    //Lock access to MIB bases
00380    snmpLockMib(context);
00381 
00382    //Loop through the list
00383    for(index = 1; length > 0; index++)
00384    {
00385       //The non-repeaters field specifies the number of non-repeating objects
00386       //at the start of the variable binding list
00387       if((index - 1) == context->request.nonRepeaters)
00388       {
00389          //Pointer to the first variable binding that will be processed during
00390          //the next iteration
00391          next = context->response.varBindList + context->response.varBindListLen;
00392 
00393          //Actual size of the variable binding list
00394          m = context->response.varBindListLen;
00395 
00396          //This flag tells whether all variable bindings have the value field
00397          //set to endOfMibView for a given iteration
00398          endOfMibView = TRUE;
00399 
00400          //If the max-repetitions field is zero, the list is trimmed to the
00401          //first non-repeating variable bindings
00402          if(context->request.maxRepetitions == 0)
00403             break;
00404       }
00405 
00406       //Parse variable binding
00407       error = snmpParseVarBinding(p, length, &var, &n);
00408       //Failed to parse variable binding?
00409       if(error)
00410          break;
00411 
00412       //Make sure that the object identifier is valid
00413       error = oidCheck(var.oid, var.oidLen);
00414       //Invalid object identifier?
00415       if(error)
00416          break;
00417 
00418       //Search the MIB for the next object
00419       error = snmpGetNextObject(context, &var);
00420 
00421       //Check status code
00422       if(error == NO_ERROR)
00423       {
00424          //Next object found
00425          endOfMibView = FALSE;
00426          //Retrieve object value
00427          error = snmpGetObjectValue(context, &var);
00428       }
00429       else if(error == ERROR_OBJECT_NOT_FOUND)
00430       {
00431          //The variable binding's value field is set to endOfMibView
00432          var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00433          var.objType = SNMP_EXCEPTION_END_OF_MIB_VIEW;
00434          var.valueLen = 0;
00435 
00436          //Catch exception
00437          error = NO_ERROR;
00438       }
00439       else
00440       {
00441          //Stop immediately
00442          break;
00443       }
00444 
00445       //Failed to retrieve object value?
00446       if(error)
00447       {
00448          //Catch exception
00449          if(error == ERROR_ACCESS_DENIED ||
00450             error == ERROR_OBJECT_NOT_FOUND)
00451          {
00452             //The variable binding's value field is set to noSuchObject
00453             var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00454             var.objType = SNMP_EXCEPTION_NO_SUCH_OBJECT;
00455             var.valueLen = 0;
00456          }
00457          else if(error == ERROR_INSTANCE_NOT_FOUND)
00458          {
00459             //The variable binding's value field is set to noSuchInstance
00460             var.objClass = ASN1_CLASS_CONTEXT_SPECIFIC;
00461             var.objType = SNMP_EXCEPTION_NO_SUCH_INSTANCE;
00462             var.valueLen = 0;
00463          }
00464          else
00465          {
00466             //Stop immediately
00467             break;
00468          }
00469       }
00470       else
00471       {
00472          //Total number of MIB objects which have been retrieved successfully
00473          //by the SNMP protocol entity as the result of receiving valid SNMP
00474          //Get-Request and Get-NextRequest PDUs
00475          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInTotalReqVars, 1);
00476       }
00477 
00478       //Append variable binding to the list
00479       error = snmpWriteVarBinding(context, &var);
00480       //Any error to report?
00481       if(error)
00482          break;
00483 
00484       //Advance data pointer
00485       p += n;
00486       length -= n;
00487 
00488       //Next iteration?
00489       if(length == 0 && index > context->request.nonRepeaters)
00490       {
00491          //Decrement repeat counter
00492          context->request.maxRepetitions--;
00493 
00494          //Last iteration?
00495          if(!context->request.maxRepetitions)
00496             break;
00497          //All variable bindings have the value field set to endOfMibView?
00498          if(endOfMibView)
00499             break;
00500 
00501          //Point to the first variable binding to be processed
00502          p = next;
00503          //Number of bytes to be processed
00504          length = context->response.varBindListLen - m;
00505          //Rewind index
00506          index = context->request.nonRepeaters;
00507       }
00508    }
00509 
00510    //Unlock access to MIB bases
00511    snmpUnlockMib(context);
00512 
00513    //Check status code
00514    if(error == ERROR_BUFFER_OVERFLOW)
00515    {
00516       //If the size of the message containing the requested number of variable
00517       //bindings would be greater than the maximum message size, then the
00518       //response is generated with a lesser number of variable bindings
00519    }
00520    else if(error)
00521    {
00522       //Set error-status and error-index fields
00523       error = snmpTranslateStatusCode(&context->response, error, index);
00524       //If the parsing of the request fails, the SNMP agent discards the message
00525       if(error)
00526          return error;
00527 
00528       //The Response-PDU is re-formatted with the same values in its request-id
00529       //and variable-bindings fields as the received GetRequest-PDU
00530       error = snmpCopyVarBindingList(context);
00531       //Any error to report?
00532       if(error)
00533          return error;
00534    }
00535 
00536    //Successful processing
00537    return NO_ERROR;
00538 #else
00539    //Not implemented
00540    return ERROR_NOT_IMPLEMENTED;
00541 #endif
00542 }
00543 
00544 
00545 /**
00546  * @brief Process SetRequest-PDU
00547  * @param[in] context Pointer to the SNMP agent context
00548  * @return Error code
00549  **/
00550 
00551 error_t snmpProcessSetRequestPdu(SnmpAgentContext *context)
00552 {
00553    error_t error;
00554    int_t index;
00555    size_t n;
00556    size_t length;
00557    const uint8_t *p;
00558    SnmpVarBind var;
00559 
00560    //Debug message
00561    TRACE_INFO("Parsing SetRequest-PDU...\r\n");
00562 
00563    //Total number of SNMP Set-Request PDUs which have been accepted and
00564    //processed by the SNMP protocol entity
00565    MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInSetRequests, 1);
00566 
00567    //Enforce access policy
00568    if(context->user->mode != SNMP_ACCESS_WRITE_ONLY &&
00569       context->user->mode != SNMP_ACCESS_READ_WRITE)
00570    {
00571       //Total number of SNMP messages delivered to the SNMP protocol entity
00572       //which represented an SNMP operation which was not allowed by the SNMP
00573       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityUses, 1);
00574 
00575       //Report an error
00576       return ERROR_ACCESS_DENIED;
00577    }
00578 
00579    //Initialize response message
00580    error = snmpInitResponse(context);
00581    //Any error to report?
00582    if(error)
00583       return error;
00584 
00585    //The variable bindings are processed as a two phase operation. In the
00586    //first phase, each variable binding is validated
00587    p = context->request.varBindList;
00588    length = context->request.varBindListLen;
00589 
00590    //Loop through the list
00591    for(index = 1; length > 0; index++)
00592    {
00593       //Parse variable binding
00594       error = snmpParseVarBinding(p, length, &var, &n);
00595       //Failed to parse variable binding?
00596       if(error)
00597          break;
00598 
00599       //Assign object value
00600       error = snmpSetObjectValue(context, &var, FALSE);
00601       //Any error to report?
00602       if(error)
00603          break;
00604 
00605       //Advance data pointer
00606       p += n;
00607       length -= n;
00608    }
00609 
00610    //If all validations are successful, then each variable is altered in
00611    //the second phase
00612    if(!error)
00613    {
00614       //The changes are committed to the MIB base during the second phase
00615       p = context->request.varBindList;
00616       length = context->request.varBindListLen;
00617 
00618       //Lock access to MIB bases
00619       snmpLockMib(context);
00620 
00621       //Loop through the list
00622       for(index = 1; length > 0; index++)
00623       {
00624          //Parse variable binding
00625          error = snmpParseVarBinding(p, length, &var, &n);
00626          //Failed to parse variable binding?
00627          if(error)
00628             break;
00629 
00630          //Assign object value
00631          error = snmpSetObjectValue(context, &var, TRUE);
00632          //Any error to report?
00633          if(error)
00634             break;
00635 
00636          //Total number of MIB objects which have been altered successfully
00637          //by the SNMP protocol entity as the result of receiving valid
00638          //SNMP Set-Request PDUs
00639          MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInTotalSetVars, 1);
00640 
00641          //Advance data pointer
00642          p += n;
00643          length -= n;
00644       }
00645 
00646       //Unlock access to MIB bases
00647       snmpUnlockMib(context);
00648    }
00649 
00650    //Any error to report?
00651    if(error)
00652    {
00653       //Set error-status and error-index fields
00654       error = snmpTranslateStatusCode(&context->response, error, index);
00655       //If the parsing of the request fails, the SNMP agent discards the message
00656       if(error)
00657          return error;
00658    }
00659 
00660    //The SNMP agent sends back a GetResponse-PDU of identical form
00661    error = snmpCopyVarBindingList(context);
00662    //Return status code
00663    return error;
00664 }
00665 
00666 
00667 /**
00668  * @brief Format Trap-PDU or SNMPv2-Trap-PDU
00669  * @param[in] context Pointer to the SNMP agent context
00670  * @param[in] version SNMP version identifier
00671  * @param[in] username User name or community name
00672  * @param[in] genericTrapType Generic trap type
00673  * @param[in] specificTrapCode Specific code
00674  * @param[in] objectList List of object names
00675  * @param[in] objectListSize Number of entries in the list
00676  * @return Error code
00677  **/
00678 
00679 error_t snmpFormatTrapPdu(SnmpAgentContext *context, SnmpVersion version,
00680    const char_t *username, uint_t genericTrapType, uint_t specificTrapCode,
00681    const SnmpTrapObject *objectList, uint_t objectListSize)
00682 {
00683    error_t error;
00684    uint_t i;
00685    size_t n;
00686    systime_t time;
00687    SnmpMessage *message;
00688    SnmpVarBind var;
00689 
00690    //Point to the SNMP message
00691    message = &context->response;
00692    //Initialize SNMP message
00693    snmpInitMessage(message);
00694 
00695    //SNMP version identifier
00696    message->version = version;
00697 
00698 #if (SNMP_V1_SUPPORT == ENABLED)
00699    //SNMPv1 version?
00700    if(version == SNMP_VERSION_1)
00701    {
00702 #if (IPV4_SUPPORT == ENABLED)
00703       NetInterface *interface;
00704 
00705       //Point to the underlying network interface
00706       interface = context->settings.interface;
00707 #endif
00708 
00709       //Community name
00710       message->community = username;
00711       message->communityLen = strlen(username);
00712 
00713       //Prepare to send a Trap-PDU
00714       message->pduType = SNMP_PDU_TRAP;
00715       //Type of object generating trap
00716       message->enterpriseOid = context->enterpriseOid;
00717       message->enterpriseOidLen = context->enterpriseOidLen;
00718 
00719 #if (IPV4_SUPPORT == ENABLED)
00720       //Address of object generating trap
00721       if(interface != NULL)
00722          message->agentAddr = interface->ipv4Context.addr;
00723 #endif
00724 
00725       //Generic trap type
00726       message->genericTrapType = genericTrapType;
00727       //Specific trap code
00728       message->specificTrapCode = specificTrapCode;
00729       //Timestamp
00730       message->timestamp = osGetSystemTime() / 10;
00731    }
00732    else
00733 #endif
00734 #if (SNMP_V2C_SUPPORT == ENABLED)
00735    //SNMPv2c version?
00736    if(version == SNMP_VERSION_2C)
00737    {
00738       //Community name
00739       message->community = username;
00740       message->communityLen = strlen(username);
00741 
00742       //Prepare to send a SNMPv2-Trap-PDU
00743       message->pduType = SNMP_PDU_TRAP_V2;
00744    }
00745    else
00746 #endif
00747 #if (SNMP_V3_SUPPORT == ENABLED)
00748    //SNMPv3 version?
00749    if(version == SNMP_VERSION_3)
00750    {
00751       //Maximum message size supported by the sender
00752       message->msgMaxSize = SNMP_MAX_MSG_SIZE;
00753 
00754       //Bit fields which control processing of the message
00755       if(context->user->authProtocol != SNMP_AUTH_PROTOCOL_NONE)
00756          message->msgFlags |= SNMP_MSG_FLAG_AUTH;
00757       if(context->user->privProtocol != SNMP_PRIV_PROTOCOL_NONE)
00758          message->msgFlags |= SNMP_MSG_FLAG_PRIV;
00759 
00760       //Security model used by the sender
00761       message->msgSecurityModel = SNMP_SECURITY_MODEL_USM;
00762 
00763       //Authoritative engine identifier
00764       message->msgAuthEngineId = context->contextEngine;
00765       message->msgAuthEngineIdLen = context->contextEngineLen;
00766       //Number of times the SNMP engine has rebooted
00767       message->msgAuthEngineBoots = context->engineBoots;
00768       //Number of seconds since last reboot
00769       message->msgAuthEngineTime = context->engineTime;
00770       //User name
00771       message->msgUserName = username;
00772       message->msgUserNameLen = strlen(username);
00773       //Authentication parameters
00774       message->msgAuthParameters = NULL;
00775 
00776       //Length of the authentication parameters
00777       if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_MD5)
00778          message->msgAuthParametersLen = 12;
00779       else if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_SHA1)
00780          message->msgAuthParametersLen = 12;
00781       else if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_SHA224)
00782          message->msgAuthParametersLen = 16;
00783       else if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_SHA256)
00784          message->msgAuthParametersLen = 24;
00785       else if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_SHA384)
00786          message->msgAuthParametersLen = 32;
00787       else if(context->user->authProtocol == SNMP_AUTH_PROTOCOL_SHA512)
00788          message->msgAuthParametersLen = 48;
00789       else
00790          message->msgAuthParametersLen = 0;
00791 
00792       //Privacy parameters
00793       message->msgPrivParameters = context->privParameters;
00794 
00795       //Length of the privacy parameters
00796       if(context->user->privProtocol == SNMP_PRIV_PROTOCOL_DES)
00797          message->msgPrivParametersLen = 8;
00798       else if(context->user->privProtocol == SNMP_PRIV_PROTOCOL_AES)
00799          message->msgPrivParametersLen = 8;
00800       else
00801          message->msgPrivParametersLen = 0;
00802 
00803       //Context engine identifier
00804       message->contextEngineId = context->contextEngine;
00805       message->contextEngineIdLen = context->contextEngineLen;
00806       //Context name
00807       message->contextName = (uint8_t *) context->contextName;
00808       message->contextNameLen = strlen(context->contextName);
00809 
00810       //Prepare to send a SNMPv2-Trap-PDU
00811       message->pduType = SNMP_PDU_TRAP_V2;
00812    }
00813    else
00814 #endif
00815    //Invalid SNMP version?
00816    {
00817       //Report an error
00818       return ERROR_INVALID_VERSION;
00819    }
00820 
00821    //Make room for the message header at the beginning of the buffer
00822    error = snmpComputeMessageOverhead(&context->response);
00823    //Any error to report?
00824    if(error)
00825       return error;
00826 
00827 #if (SNMP_V2C_SUPPORT == ENABLED || SNMP_V3_SUPPORT == ENABLED)
00828    //SNMPv2c or SNMPv3 version?
00829    if(version == SNMP_VERSION_2C || version == SNMP_VERSION_3)
00830    {
00831       //Get current time
00832       time = osGetSystemTime() / 10;
00833 
00834       //Encode the object value using ASN.1 rules
00835       error = snmpEncodeUnsignedInt32(time, message->buffer, &n);
00836       //Any error to report?
00837       if(error)
00838          return error;
00839 
00840       //The first two variable bindings in the variable binding list of an
00841       //SNMPv2-Trap-PDU are sysUpTime.0 and snmpTrapOID.0 respectively
00842       var.oid = sysUpTimeObject;
00843       var.oidLen = sizeof(sysUpTimeObject);
00844       var.objClass = ASN1_CLASS_APPLICATION;
00845       var.objType = MIB_TYPE_TIME_TICKS;
00846       var.value = message->buffer;
00847       var.valueLen = n;
00848 
00849       //Append sysUpTime.0 to the variable binding list
00850       error = snmpWriteVarBinding(context, &var);
00851       //Any error to report?
00852       if(error)
00853          return error;
00854 
00855       //Generic or enterprise-specific trap?
00856       if(genericTrapType < SNMP_TRAP_ENTERPRISE_SPECIFIC)
00857       {
00858          //Retrieve the length of the snmpTraps OID
00859          n = sizeof(snmpTrapsObject);
00860          //Copy the OID
00861          memcpy(message->buffer, snmpTrapsObject, n);
00862 
00863          //For generic traps, the SNMPv2 snmpTrapOID parameter shall be
00864          //the corresponding trap as defined in section 2 of 3418
00865          message->buffer[n] = genericTrapType + 1;
00866 
00867          //Update the length of the snmpTrapOID parameter
00868          n++;
00869       }
00870       else
00871       {
00872          //Retrieve the length of the enterprise OID
00873          n = context->enterpriseOidLen;
00874 
00875          //For enterprise specific traps, the SNMPv2 snmpTrapOID parameter shall
00876          //be the concatenation of the SNMPv1 enterprise OID and two additional
00877          //sub-identifiers: '0' and the SNMPv1 specific trap parameter
00878          memcpy(message->buffer, context->enterpriseOid, n);
00879 
00880          //Concatenate the '0' sub-identifier
00881          message->buffer[n++] = 0;
00882 
00883          //Concatenate the specific trap parameter
00884          message->buffer[n] = specificTrapCode % 128;
00885 
00886          //Loop as long as necessary
00887          for(i = 1; specificTrapCode > 128; i++)
00888          {
00889             //Split the binary representation into 7 bit chunks
00890             specificTrapCode /= 128;
00891             //Make room for the new chunk
00892             memmove(message->buffer + n + 1, message->buffer + n, i);
00893             //Set the most significant bit in the current chunk
00894             message->buffer[n] = OID_MORE_FLAG | (specificTrapCode % 128);
00895          }
00896 
00897          //Update the length of the snmpTrapOID parameter
00898          n += i;
00899       }
00900 
00901       //The snmpTrapOID.0 variable occurs as the second variable
00902       //binding in every SNMPv2-Trap-PDU
00903       var.oid = snmpTrapOidObject;
00904       var.oidLen = sizeof(snmpTrapOidObject);
00905       var.objClass = ASN1_CLASS_UNIVERSAL;
00906       var.objType = ASN1_TYPE_OBJECT_IDENTIFIER;
00907       var.value = message->buffer;
00908       var.valueLen = n;
00909 
00910       //Append snmpTrapOID.0 to the variable binding list
00911       error = snmpWriteVarBinding(context, &var);
00912       //Any error to report?
00913       if(error)
00914          return error;
00915    }
00916 #endif
00917 
00918    //Loop through the list of objects
00919    for(i = 0; i < objectListSize; i++)
00920    {
00921       //Get object identifier
00922       var.oid = objectList[i].oid;
00923       var.oidLen = objectList[i].oidLen;
00924 
00925       //Retrieve object value
00926       error = snmpGetObjectValue(context, &var);
00927       //Any error to report?
00928       if(error)
00929          return error;
00930 
00931       //Append variable binding to the list
00932       error = snmpWriteVarBinding(context, &var);
00933       //Any error to report?
00934       if(error)
00935          return error;
00936    }
00937 
00938    //Total number of SNMP Trap PDUs which have been generated by
00939    //the SNMP protocol entity
00940    MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutTraps, 1);
00941 
00942    //Format PDU header
00943    error = snmpWritePduHeader(&context->response);
00944    //Return status code
00945    return error;
00946 }
00947 
00948 
00949 /**
00950  * @brief Format Report-PDU
00951  * @param[in] context Pointer to the SNMP agent context
00952  * @param[in] errorIndication Error indication
00953  * @return Error code
00954  **/
00955 
00956 error_t snmpFormatReportPdu(SnmpAgentContext *context, error_t errorIndication)
00957 {
00958    error_t error;
00959 
00960 #if (SNMP_V3_SUPPORT == ENABLED)
00961    size_t n;
00962    SnmpVarBind var;
00963 
00964    //Initialize SNMP message
00965    snmpInitMessage(&context->response);
00966 
00967    //SNMP version identifier
00968    context->response.version = context->request.version;
00969 
00970    //Message identifier
00971    context->response.msgId = context->request.msgId;
00972    //Maximum message size supported by the sender
00973    context->response.msgMaxSize = SNMP_MAX_MSG_SIZE;
00974    //Bit fields which control processing of the message
00975    context->response.msgFlags = 0;
00976    //Security model used by the sender
00977    context->response.msgSecurityModel = SNMP_SECURITY_MODEL_USM;
00978 
00979    //Authoritative engine identifier
00980    context->response.msgAuthEngineId = context->contextEngine;
00981    context->response.msgAuthEngineIdLen = context->contextEngineLen;
00982    //Number of times the SNMP engine has rebooted
00983    context->response.msgAuthEngineBoots = context->engineBoots;
00984    //Number of seconds since last reboot
00985    context->response.msgAuthEngineTime = context->engineTime;
00986 
00987    //Context engine identifier
00988    context->response.contextEngineId = context->contextEngine;
00989    context->response.contextEngineIdLen = context->contextEngineLen;
00990    //Context name
00991    context->response.contextName = (uint8_t *) context->contextName;
00992    context->response.contextNameLen = strlen(context->contextName);
00993 
00994    //PDU type
00995    context->response.pduType = SNMP_PDU_REPORT;
00996    //Request identifier
00997    context->response.requestId = context->request.requestId;
00998 
00999    //Make room for the message header at the beginning of the buffer
01000    error = snmpComputeMessageOverhead(&context->response);
01001    //Any error to report?
01002    if(error)
01003       return error;
01004 
01005    //Encode the object value using ASN.1 rules
01006    error = snmpEncodeUnsignedInt32(1, context->response.buffer, &n);
01007    //Any error to report?
01008    if(error)
01009       return error;
01010 
01011    //Check error indication
01012    switch(errorIndication)
01013    {
01014    case ERROR_UNSUPPORTED_SECURITY_LEVEL:
01015       //Add the usmStatsUnsupportedSecLevels counter in the varBindList
01016       var.oid = usmStatsUnsupportedSecLevelsObject;
01017       var.oidLen = sizeof(usmStatsUnsupportedSecLevelsObject);
01018       break;
01019    case ERROR_NOT_IN_TIME_WINDOW:
01020       //Add the usmStatsNotInTimeWindows counter in the varBindList
01021       var.oid = usmStatsNotInTimeWindowsObject;
01022       var.oidLen = sizeof(usmStatsNotInTimeWindowsObject);
01023       break;
01024    case ERROR_UNKNOWN_USER_NAME:
01025       //Add the usmStatsUnknownUserNames counter in the varBindList
01026       var.oid = usmStatsUnknownUserNamesObject;
01027       var.oidLen = sizeof(usmStatsUnknownUserNamesObject);
01028       break;
01029    case ERROR_UNKNOWN_ENGINE_ID:
01030       //Add the usmStatsUnknownEngineIDs counter in the varBindList
01031       var.oid = usmStatsUnknownEngineIdsObject;
01032       var.oidLen = sizeof(usmStatsUnknownEngineIdsObject);
01033       break;
01034    case ERROR_AUTHENTICATION_FAILED:
01035       //Add the usmStatsWrongDigests counter in the varBindList
01036       var.oid = usmStatsWrongDigestsObject;
01037       var.oidLen = sizeof(usmStatsWrongDigestsObject);
01038       break;
01039    case ERROR_DECRYPTION_FAILED:
01040       //Add the usmStatsDecryptionErrors counter in the varBindList
01041       var.oid = usmStatsDecryptionErrorsObject;
01042       var.oidLen = sizeof(usmStatsDecryptionErrorsObject);
01043       break;
01044    default:
01045       //Just for sanity's sake...
01046       var.oid = NULL;
01047       var.oidLen = 0;
01048       break;
01049    }
01050 
01051    //The counter is encoded in ASN.1 format
01052    var.objClass = ASN1_CLASS_APPLICATION;
01053    var.objType = MIB_TYPE_COUNTER32;
01054    var.value = context->response.buffer;
01055    var.valueLen = n;
01056 
01057    //Append the variable binding list to the varBindList
01058    error = snmpWriteVarBinding(context, &var);
01059    //Any error to report?
01060    if(error)
01061       return error;
01062 
01063    //Format PDU header
01064    error = snmpWritePduHeader(&context->response);
01065 #else
01066    //SNMPv3 is not supported
01067    error = ERROR_NOT_IMPLEMENTED;
01068 #endif
01069 
01070    //Return status code
01071    return error;
01072 }
01073 
01074 #endif
01075