Webserver+3d print

Dependents:   Nucleo

cyclone_tcp/snmp/snmp_agent_dispatch.c

Committer:
Sergunb
Date:
2017-02-04
Revision:
0:8918a71cdbe9

File content as of revision 0:8918a71cdbe9:

/**
 * @file snmp_agent_dispatch.c
 * @brief SNMP message dispatching
 *
 * @section License
 *
 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
 *
 * This file is part of CycloneTCP Open.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * @author Oryx Embedded SARL (www.oryx-embedded.com)
 * @version 1.7.6
 **/

//Switch to the appropriate trace level
#define TRACE_LEVEL SNMP_TRACE_LEVEL

//Dependencies
#include "core/net.h"
#include "snmp/snmp_agent.h"
#include "snmp/snmp_agent_dispatch.h"
#include "snmp/snmp_agent_pdu.h"
#include "snmp/snmp_agent_misc.h"
#include "mibs/mib2_module.h"
#include "crypto.h"
#include "asn1.h"
#include "oid.h"
#include "debug.h"

//Check TCP/IP stack configuration
#if (SNMP_AGENT_SUPPORT == ENABLED)


/**
 * @brief Process incoming SNMP message
 * @param[in] context Pointer to the SNMP agent context
 * @return Error code
 **/

error_t snmpProcessMessage(SnmpAgentContext *context)
{
   error_t error;

   //Total number of messages delivered to the SNMP entity from the
   //transport service
   MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInPkts, 1);

   //Refresh SNMP engine time
   snmpRefreshEngineTime(context);

   //Message parsing initialization
   snmpInitMessage(&context->request);

   //Parse SNMP message header
   error = snmpParseMessageHeader(&context->request);
   //Any error to report?
   if(error)
      return error;

   //The SNMP agent verifies the version number. If there is a mismatch,
   //it discards the datagram and performs no further actions
   if(context->request.version < context->settings.versionMin ||
      context->request.version > context->settings.versionMax)
   {
      //Debug message
      TRACE_WARNING("  Invalid SNMP version!\r\n");
      //Discard incoming SNMP message
      return ERROR_INVALID_VERSION;
   }

#if (SNMP_V1_SUPPORT == ENABLED)
   //SNMPv1 version?
   if(context->request.version == SNMP_VERSION_1)
   {
      //Process incoming SNMPv1 message
      error = snmpv1ProcessMessage(context);
   }
   else
#endif
#if (SNMP_V2C_SUPPORT == ENABLED)
   //SNMPv2c version?
   if(context->request.version == SNMP_VERSION_2C)
   {
      //Process incoming SNMPv2c message
      error = snmpv2cProcessMessage(context);
   }
   else
#endif
#if (SNMP_V3_SUPPORT == ENABLED)
   //SNMPv3 version?
   if(context->request.version == SNMP_VERSION_3)
   {
      //Process incoming SNMPv3 message
      error = snmpv3ProcessMessage(context);
   }
   else
#endif
   //Invalid SNMP version?
   {
      //Debug message
      TRACE_WARNING("  Invalid SNMP version!\r\n");

      //Total number of SNMP messages which were delivered to the SNMP
      //protocol entity and were for an unsupported SNMP version
      MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadVersions, 1);

      //Discard incoming SNMP message
      error = ERROR_INVALID_VERSION;
   }

   //Check status code
   if(error == NO_ERROR)
   {
      //Total number of messages which were passed from the SNMP protocol
      //entity to the transport service
      MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutPkts, 1);
   }
   else if(error == ERROR_INVALID_TAG)
   {
      //Total number of ASN.1 or BER errors encountered by the SNMP protocol
      //entity when decoding received SNMP messages
      MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInASNParseErrs, 1);
   }

   //Return status code
   return error;
}


/**
 * @brief Process incoming SNMPv1 message
 * @param[in] context Pointer to the SNMP agent context
 * @return Error code
 **/

error_t snmpv1ProcessMessage(SnmpAgentContext *context)
{
   error_t error;

#if (SNMP_V1_SUPPORT == ENABLED)
   //Parse community name
   error = snmpParseCommunity(&context->request);
   //Any error to report?
   if(error)
      return error;

   //Information about the community name is extracted from the local
   //configuration datastore
   context->user = snmpFindUser(context, context->request.community,
      context->request.communityLen);

   //Invalid community name?
   if(context->user == NULL)
   {
      //Debug message
      TRACE_WARNING("  Invalid community name!\r\n");

      //Total number of SNMP messages delivered to the SNMP protocol entity
      //which used a SNMP community name not known to said entity
      MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityNames, 1);

      //Report an error
      return ERROR_UNKNOWN_USER_NAME;
   }

   //Process PDU
   error = snmpProcessPdu(context);
   //Any error to report?
   if(error)
      return error;

   //Format SNMP message header
   error = snmpWriteMessageHeader(&context->response);
#else
   //Report an error
   error = ERROR_INVALID_VERSION;
#endif

   //Return status code
   return error;
}


/**
 * @brief Process incoming SNMPv2c message
 * @param[in] context Pointer to the SNMP agent context
 * @return Error code
 **/

error_t snmpv2cProcessMessage(SnmpAgentContext *context)
{
   error_t error;

#if (SNMP_V2C_SUPPORT == ENABLED)
   //Parse community name
   error = snmpParseCommunity(&context->request);
   //Any error to report?
   if(error)
      return error;

   //Information about the community name is extracted from the local
   //configuration datastore
   context->user = snmpFindUser(context, context->request.community,
      context->request.communityLen);

   //Invalid community name?
   if(context->user == NULL)
   {
      //Debug message
      TRACE_WARNING("  Invalid community name!\r\n");

      //Total number of SNMP messages delivered to the SNMP protocol entity
      //which used a SNMP community name not known to said entity
      MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityNames, 1);

      //Report an error
      return ERROR_UNKNOWN_USER_NAME;
   }

   //Process PDU
   error = snmpProcessPdu(context);
   //Any error to report?
   if(error)
      return error;

   //Format SNMP message header
   error = snmpWriteMessageHeader(&context->response);
#else
   //Report an error
   error = ERROR_INVALID_VERSION;
#endif

   //Return status code
   return error;
}


/**
 * @brief Process incoming SNMPv3 message
 * @param[in] context Pointer to the SNMP agent context
 * @return Error code
 **/

error_t snmpv3ProcessMessage(SnmpAgentContext *context)
{
   error_t error;

#if (SNMP_V3_SUPPORT == ENABLED)
   //Parse msgGlobalData field
   error = snmpParseGlobalData(&context->request);
   //Any error to report?
   if(error)
      return error;

   //Parse msgSecurityParameters field
   error = snmpParseSecurityParameters(&context->request);
   //Any error to report?
   if(error)
      return error;

   //Start of exception handling block
   do
   {
      //Information about the value of the msgUserName field is extracted
      //from the local configuration datastore
      context->user = snmpFindUser(context, context->request.msgUserName,
         context->request.msgUserNameLen);

      //Check security parameters
      error = snmpCheckSecurityParameters(context->user, &context->request,
         context->contextEngine, context->contextEngineLen);
      //Invalid security parameters?
      if(error)
         break;

      //Check whether the authFlag is set
      if(context->request.msgFlags & SNMP_MSG_FLAG_AUTH)
      {
         //Authenticate incoming SNMP message
         error = snmpAuthIncomingMessage(context->user, &context->request);
         //Data authentication failed?
         if(error)
            break;

         //Replay protection
         error = snmpCheckEngineTime(context, &context->request);
         //Message outside of the time window?
         if(error)
            break;
      }

      //Check whether the privFlag is set
      if(context->request.msgFlags & SNMP_MSG_FLAG_PRIV)
      {
         //Decrypt data
         error = snmpDecryptData(context->user, &context->request);
         //Data decryption failed?
         if(error)
            break;
      }

      //End of exception handling block
   } while(0);

   //Check error indication
   if(error == ERROR_UNSUPPORTED_SECURITY_LEVEL ||
      error == ERROR_NOT_IN_TIME_WINDOW ||
      error == ERROR_UNKNOWN_USER_NAME ||
      error == ERROR_UNKNOWN_ENGINE_ID ||
      error == ERROR_AUTHENTICATION_FAILED ||
      error == ERROR_DECRYPTION_FAILED)
   {
      //Report the error indication to the remote SNMP engine using a Report-PDU
      error = snmpFormatReportPdu(context, error);
      //Any error to report?
      if(error)
         return error;
   }
   else if(error == NO_ERROR)
   {
      //Parse scopedPDU
      error = snmpParseScopedPdu(&context->request);
      //Any error to report?
      if(error)
         return error;

      //Process PDU
      error = snmpProcessPdu(context);
      //Any error to report?
      if(error)
         return error;
   }
   else
   {
      //Stop processing
      return error;
   }

   //Format scopedPDU
   error = snmpWriteScopedPdu(&context->response);
   //Any error to report?
   if(error)
      return error;

   //Check whether the privFlag is set
   if(context->response.msgFlags & SNMP_MSG_FLAG_PRIV)
   {
      //Encrypt data
      error = snmpEncryptData(context->user, &context->response, &context->salt);
      //Any error to report?
      if(error)
         return error;
   }

   //Format SNMP message header
   error = snmpWriteMessageHeader(&context->response);
   //Any error to report?
   if(error)
      return error;

   //Check whether the authFlag is set
   if(context->response.msgFlags & SNMP_MSG_FLAG_AUTH)
   {
      //Authenticate outgoing SNMP message
      error = snmpAuthOutgoingMessage(context->user, &context->response);
      //Any error to report?
      if(error)
         return error;
   }
#else
   //Report an error
   error = ERROR_INVALID_VERSION;
#endif

   //Return status code
   return error;
}

#endif