Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers snmp_agent.c Source File

snmp_agent.c

Go to the documentation of this file.
00001 /**
00002  * @file snmp_agent.c
00003  * @brief SNMP agent (Simple Network Management Protocol)
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  * @section Description
00026  *
00027  * SNMP is a simple protocol by which management information for a network
00028  * element may be inspected or altered by logically remote users. Refer
00029  * to the following RFCs for complete details:
00030  * - RFC 1157: A Simple Network Management Protocol (SNMP)
00031  * - RFC 1905: Protocol Operations for Version 2 of the Simple Network
00032  *     Management Protocol (SNMPv2)
00033  * - RFC 3410: Introduction and Applicability Statements for Internet
00034  *     Standard Management Framework
00035  * - RFC 3411: An Architecture for Describing SNMP Management Frameworks
00036  * - RFC 3412: Message Processing and Dispatching for the SNMP
00037  * - RFC 3413: Simple Network Management Protocol (SNMP) Applications
00038  * - RFC 3584: Coexistence between Version 1, Version 2, and Version 3 of
00039  *     SNMP Framework
00040  *
00041  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00042  * @version 1.7.6
00043  **/
00044 
00045 //Switch to the appropriate trace level
00046 #define TRACE_LEVEL SNMP_TRACE_LEVEL
00047 
00048 //Dependencies
00049 #include "core/net.h"
00050 #include "snmp/snmp_agent.h"
00051 #include "snmp/snmp_agent_dispatch.h"
00052 #include "snmp/snmp_agent_pdu.h"
00053 #include "snmp/snmp_agent_misc.h"
00054 #include "mibs/mib2_module.h"
00055 #include "crypto.h"
00056 #include "asn1.h"
00057 #include "oid.h"
00058 #include "debug.h"
00059 
00060 //Check TCP/IP stack configuration
00061 #if (SNMP_AGENT_SUPPORT == ENABLED)
00062 
00063 
00064 /**
00065  * @brief Initialize settings with default values
00066  * @param[out] settings Structure that contains SNMP agent settings
00067  **/
00068 
00069 void snmpAgentGetDefaultSettings(SnmpAgentSettings *settings)
00070 {
00071    //The SNMP agent is not bound to any interface
00072    settings->interface = NULL;
00073 
00074    //Minimum version accepted by the SNMP agent
00075    settings->versionMin = SNMP_VERSION_1;
00076    //Maximum version accepted by the SNMP agent
00077    settings->versionMax = SNMP_VERSION_3;
00078 
00079    //SNMP port number
00080    settings->port = SNMP_PORT;
00081    //SNMP trap port number
00082    settings->trapPort = SNMP_TRAP_PORT;
00083 
00084    //Random data generation callback function
00085    settings->randCallback = NULL;
00086 }
00087 
00088 
00089 /**
00090  * @brief SNMP agent initialization
00091  * @param[in] context Pointer to the SNMP agent context
00092  * @param[in] settings SNMP agent specific settings
00093  * @return Error code
00094  **/
00095 
00096 error_t snmpAgentInit(SnmpAgentContext *context, const SnmpAgentSettings *settings)
00097 {
00098    error_t error;
00099 
00100    //Debug message
00101    TRACE_INFO("Initializing SNMP agent...\r\n");
00102 
00103    //Ensure the parameters are valid
00104    if(context == NULL || settings == NULL)
00105       return ERROR_INVALID_PARAMETER;
00106 
00107    //Check minimum and maximum SNMP versions
00108    if(settings->versionMin > settings->versionMax)
00109       return ERROR_INVALID_PARAMETER;
00110 
00111    //Clear the SNMP agent context
00112    memset(context, 0, sizeof(SnmpAgentContext));
00113 
00114    //Save user settings
00115    context->settings = *settings;
00116 
00117 #if (SNMP_V3_SUPPORT == ENABLED)
00118    //Get current time
00119    context->systemTime = osGetSystemTime();
00120 
00121    //Each SNMP engine maintains two values, snmpEngineBoots and snmpEngineTime,
00122    //which taken together provide an indication of time at that SNMP engine
00123    context->engineBoots = 1;
00124    context->engineTime = 0;
00125 
00126    //Check whether SNMPv3 is supported
00127    if(settings->versionMin <= SNMP_VERSION_3 &&
00128       settings->versionMax >= SNMP_VERSION_3)
00129    {
00130       //Make sure a random number generator has been registered
00131       if(settings->randCallback == NULL)
00132          return ERROR_INVALID_PARAMETER;
00133 
00134       //The salt integer is initialized to an arbitrary value at boot time
00135       error = settings->randCallback((uint8_t *) &context->salt, sizeof(context->salt));
00136       //Any error to report?
00137       if(error)
00138          return error;
00139    }
00140 #endif
00141 
00142    //Create a mutex to prevent simultaneous access to SNMP agent context
00143    if(!osCreateMutex(&context->mutex))
00144    {
00145       //Failed to create mutex
00146       return ERROR_OUT_OF_RESOURCES;
00147    }
00148 
00149    //Open a UDP socket
00150    context->socket = socketOpen(SOCKET_TYPE_DGRAM, SOCKET_IP_PROTO_UDP);
00151 
00152    //Failed to open socket?
00153    if(!context->socket)
00154    {
00155       //Clean up side effects
00156       osDeleteMutex(&context->mutex);
00157       //Report an error
00158       return ERROR_OPEN_FAILED;
00159    }
00160 
00161    //Start of exception handling block
00162    do
00163    {
00164       //Explicitly associate the socket with the relevant interface
00165       error = socketBindToInterface(context->socket, settings->interface);
00166       //Unable to bind the socket to the desired interface?
00167       if(error)
00168          break;
00169 
00170       //The SNMP agent listens for messages on port 161
00171       error = socketBind(context->socket, &IP_ADDR_ANY, settings->port);
00172       //Unable to bind the socket to the desired port?
00173       if(error)
00174          break;
00175 
00176       //End of exception handling block
00177    } while(0);
00178 
00179    //Any error to report?
00180    if(error)
00181    {
00182       //Clean up side effects
00183       osDeleteMutex(&context->mutex);
00184       //Close underlying socket
00185       socketClose(context->socket);
00186    }
00187 
00188    //Return status code
00189    return error;
00190 }
00191 
00192 
00193 /**
00194  * @brief Start SNMP agent
00195  * @param[in] context Pointer to the SNMP agent context
00196  * @return Error code
00197  **/
00198 
00199 error_t snmpAgentStart(SnmpAgentContext *context)
00200 {
00201    OsTask *task;
00202 
00203    //Debug message
00204    TRACE_INFO("Starting SNMP agent...\r\n");
00205 
00206    //Make sure the SNMP agent context is valid
00207    if(context == NULL)
00208       return ERROR_INVALID_PARAMETER;
00209 
00210    //Start the SNMP agent service
00211    task = osCreateTask("SNMP Agent", (OsTaskCode) snmpAgentTask,
00212       context, SNMP_AGENT_STACK_SIZE, SNMP_AGENT_PRIORITY);
00213 
00214    //Unable to create the task?
00215    if(task == OS_INVALID_HANDLE)
00216       return ERROR_OUT_OF_RESOURCES;
00217 
00218    //The SNMP agent has successfully started
00219    return NO_ERROR;
00220 }
00221 
00222 
00223 /**
00224  * @brief Load a MIB module
00225  * @param[in] context Pointer to the SNMP agent context
00226  * @param[in] module Pointer the MIB module to be loaded
00227  * @return Error code
00228  **/
00229 
00230 error_t snmpAgentLoadMib(SnmpAgentContext *context, const MibModule *module)
00231 {
00232    error_t error;
00233    uint_t i;
00234    uint_t j;
00235 
00236    //Check parameters
00237    if(context == NULL || module == NULL)
00238       return ERROR_INVALID_PARAMETER;
00239    if(module->numObjects < 1)
00240       return ERROR_INVALID_PARAMETER;
00241 
00242    //Acquire exclusive access to the SNMP agent context
00243    osAcquireMutex(&context->mutex);
00244 
00245    //Loop through existing MIBs
00246    for(i = 0; i < context->mibModuleCount; i++)
00247    {
00248       //Check whether the specified MIB module is already loaded
00249       if(context->mibModule[i] == module)
00250          break;
00251    }
00252 
00253    //MIB module found?
00254    if(i < context->mibModuleCount)
00255    {
00256       //Prevent the SNMP agent from loading the specified MIB multiple times
00257       error = NO_ERROR;
00258    }
00259    else
00260    {
00261       //Make sure there is enough room to add the specified MIB
00262       if(context->mibModuleCount < SNMP_AGENT_MAX_MIB_COUNT)
00263       {
00264          //Loop through existing MIBs
00265          for(i = 0; i < context->mibModuleCount; i++)
00266          {
00267             //Compare object identifiers
00268             if(oidComp(module->objects[0].oid, module->objects[0].oidLen,
00269                context->mibModule[i]->objects[0].oid, context->mibModule[i]->objects[0].oidLen) < 0)
00270             {
00271                //Make room for the new MIB
00272                for(j = context->mibModuleCount; j > i; j--)
00273                   context->mibModule[j] = context->mibModule[j - 1];
00274 
00275                //We are done
00276                break;
00277             }
00278          }
00279 
00280          //Insert the new MIB to the list
00281          context->mibModule[i] = module;
00282          //Update the number of MIBs
00283          context->mibModuleCount++;
00284 
00285          //Successful processing
00286          error = NO_ERROR;
00287       }
00288       else
00289       {
00290          //Failed to load the specified MIB
00291          error = ERROR_OUT_OF_RESOURCES;
00292       }
00293    }
00294 
00295    //Release exclusive access to the SNMP agent context
00296    osReleaseMutex(&context->mutex);
00297 
00298    //Return status code
00299    return error;
00300 }
00301 
00302 
00303 /**
00304  * @brief Unload a MIB module
00305  * @param[in] context Pointer to the SNMP agent context
00306  * @param[in] module Pointer the MIB module to be unloaded
00307  * @return Error code
00308  **/
00309 
00310 error_t snmpAgentUnloadMib(SnmpAgentContext *context, const MibModule *module)
00311 {
00312    error_t error;
00313    uint_t i;
00314    uint_t j;
00315 
00316    //Check parameters
00317    if(context == NULL || module == NULL)
00318       return ERROR_INVALID_PARAMETER;
00319 
00320    //Acquire exclusive access to the SNMP agent context
00321    osAcquireMutex(&context->mutex);
00322 
00323    //Loop through existing MIBs
00324    for(i = 0; i < context->mibModuleCount; i++)
00325    {
00326       //Check whether the specified MIB module is already loaded
00327       if(context->mibModule[i] == module)
00328          break;
00329    }
00330 
00331    //MIB module found?
00332    if(i < context->mibModuleCount)
00333    {
00334       //Update the number of MIBs
00335       context->mibModuleCount--;
00336 
00337       //Remove the specified MIB from the list
00338       for(j = i; j < context->mibModuleCount; j++)
00339          context->mibModule[j] = context->mibModule[j + 1];
00340 
00341       //Successful processing
00342       error = NO_ERROR;
00343    }
00344    else
00345    {
00346       //Failed to unload the specified MIB
00347       error = ERROR_NOT_FOUND;
00348    }
00349 
00350    //Release exclusive access to the SNMP agent context
00351    osReleaseMutex(&context->mutex);
00352 
00353    //Return status code
00354    return error;
00355 }
00356 
00357 
00358 /**
00359  * @brief Set the value of the snmpEngineBoots variable
00360  * @param[in] context Pointer to the SNMP agent context
00361  * @param[in] engineBoots Number of times the SNMP engine has re-booted
00362  * @return Error code
00363  **/
00364 
00365 error_t snmpAgentSetEngineBoots(SnmpAgentContext *context, int32_t engineBoots)
00366 {
00367 #if (SNMP_V3_SUPPORT == ENABLED)
00368    //Check parameters
00369    if(context == NULL)
00370       return ERROR_INVALID_PARAMETER;
00371    if(engineBoots < 0)
00372       return ERROR_OUT_OF_RANGE;
00373 
00374    //Acquire exclusive access to the SNMP agent context
00375    osAcquireMutex(&context->mutex);
00376 
00377    //Get current time
00378    context->systemTime = osGetSystemTime();
00379 
00380    //Set the value of the snmpEngineBoots
00381    context->engineBoots = engineBoots;
00382    //The snmpEngineTime is reset to zero
00383    context->engineTime = 0;
00384 
00385    //Release exclusive access to the SNMP agent context
00386    osReleaseMutex(&context->mutex);
00387 
00388    //Successful processing
00389    return NO_ERROR;
00390 #else
00391    //Not implemented
00392    return ERROR_NOT_IMPLEMENTED;
00393 #endif
00394 }
00395 
00396 
00397 /**
00398  * @brief Get the value of the snmpEngineBoots variable
00399  * @param[in] context Pointer to the SNMP agent context
00400  * @param[out] engineBoots Number of times the SNMP engine has re-booted
00401  * @return Error code
00402  **/
00403 
00404 error_t snmpAgentGetEngineBoots(SnmpAgentContext *context, int32_t *engineBoots)
00405 {
00406 #if (SNMP_V3_SUPPORT == ENABLED)
00407    //Check parameters
00408    if(context == NULL || engineBoots == NULL)
00409       return ERROR_INVALID_PARAMETER;
00410 
00411    //Acquire exclusive access to the SNMP agent context
00412    osAcquireMutex(&context->mutex);
00413    //Get the current value of the snmpEngineBoots
00414    *engineBoots = context->engineBoots;
00415    //Release exclusive access to the SNMP agent context
00416    osReleaseMutex(&context->mutex);
00417 
00418    //Successful processing
00419    return NO_ERROR;
00420 #else
00421    //Not implemented
00422    return ERROR_NOT_IMPLEMENTED;
00423 #endif
00424 }
00425 
00426 
00427 /**
00428  * @brief Set enterprise OID
00429  * @param[in] context Pointer to the SNMP agent context
00430  * @param[in] enterpriseOid Pointer to the enterprise OID
00431  * @param[in] enterpriseOidLen Length of the enterprise OID
00432  * @return Error code
00433  **/
00434 
00435 error_t snmpAgentSetEnterpriseOid(SnmpAgentContext *context,
00436    const uint8_t *enterpriseOid, size_t enterpriseOidLen)
00437 {
00438    //Check parameters
00439    if(context == NULL || enterpriseOid == NULL)
00440       return ERROR_INVALID_PARAMETER;
00441    if(enterpriseOidLen > SNMP_MAX_OID_SIZE)
00442       return ERROR_INVALID_PARAMETER;
00443 
00444    //Acquire exclusive access to the SNMP agent context
00445    osAcquireMutex(&context->mutex);
00446 
00447    //Set enterprise OID
00448    memcpy(context->enterpriseOid, enterpriseOid, enterpriseOidLen);
00449    //Save the length of the enterprise OID
00450    context->enterpriseOidLen = enterpriseOidLen;
00451 
00452    //Release exclusive access to the SNMP agent context
00453    osReleaseMutex(&context->mutex);
00454 
00455    //Successful processing
00456    return NO_ERROR;
00457 }
00458 
00459 
00460 /**
00461  * @brief Set context engine identifier
00462  * @param[in] context Pointer to the SNMP agent context
00463  * @param[in] contextEngine Pointer to the context engine identifier
00464  * @param[in] contextEngineLen Length of the context engine identifier
00465  * @return Error code
00466  **/
00467 
00468 error_t snmpAgentSetContextEngine(SnmpAgentContext *context,
00469    const void *contextEngine, size_t contextEngineLen)
00470 {
00471 #if (SNMP_V3_SUPPORT == ENABLED)
00472    //Check parameters
00473    if(context == NULL || contextEngine == NULL)
00474       return ERROR_INVALID_PARAMETER;
00475    if(contextEngineLen > SNMP_MAX_CONTEXT_ENGINE_SIZE)
00476       return ERROR_INVALID_PARAMETER;
00477 
00478    //Acquire exclusive access to the SNMP agent context
00479    osAcquireMutex(&context->mutex);
00480 
00481    //Set context engine identifier
00482    memcpy(context->contextEngine, contextEngine, contextEngineLen);
00483    //Save the length of the context engine identifier
00484    context->contextEngineLen = contextEngineLen;
00485 
00486    //Release exclusive access to the SNMP agent context
00487    osReleaseMutex(&context->mutex);
00488 
00489    //Successful processing
00490    return NO_ERROR;
00491 #else
00492    //Not implemented
00493    return ERROR_NOT_IMPLEMENTED;
00494 #endif
00495 }
00496 
00497 
00498 /**
00499  * @brief Set context name
00500  * @param[in] context Pointer to the SNMP agent context
00501  * @param[in] contextName NULL-terminated string that contains the context name
00502  * @return Error code
00503  **/
00504 
00505 error_t snmpAgentSetContextName(SnmpAgentContext *context,
00506    const char_t *contextName)
00507 {
00508 #if (SNMP_V3_SUPPORT == ENABLED)
00509    size_t n;
00510 
00511    //Check parameters
00512    if(context == NULL || contextName == NULL)
00513       return ERROR_INVALID_PARAMETER;
00514 
00515    //Retrieve the length of the context name
00516    n = strlen(contextName);
00517 
00518    //Make sure the context name is valid
00519    if(n > SNMP_MAX_CONTEXT_NAME_LEN)
00520       return ERROR_INVALID_LENGTH;
00521 
00522    //Acquire exclusive access to the SNMP agent context
00523    osAcquireMutex(&context->mutex);
00524    //Set context name
00525    strcpy(context->contextName, contextName);
00526    //Release exclusive access to the SNMP agent context
00527    osReleaseMutex(&context->mutex);
00528 
00529    //Successful processing
00530    return NO_ERROR;
00531 #else
00532    //Not implemented
00533    return ERROR_NOT_IMPLEMENTED;
00534 #endif
00535 }
00536 
00537 
00538 /**
00539  * @brief Create a new community string
00540  * @param[in] context Pointer to the SNMP agent context
00541  * @param[in] community NULL-terminated string that contains the community name
00542  * @param[in] mode Access rights
00543  * @return Error code
00544  **/
00545 
00546 error_t snmpAgentCreateCommunity(SnmpAgentContext *context,
00547    const char_t *community, SnmpAccess mode)
00548 {
00549 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
00550    //Add the community string to the local configuration datastore
00551    return snmpAgentCreateUser(context, community, mode, SNMP_KEY_FORMAT_NONE,
00552       SNMP_AUTH_PROTOCOL_NONE, NULL, SNMP_PRIV_PROTOCOL_NONE, NULL);
00553 #else
00554    //Not implemented
00555    return ERROR_NOT_IMPLEMENTED;
00556 #endif
00557 }
00558 
00559 
00560 /**
00561  * @brief Remove a community string
00562  * @param[in] context Pointer to the SNMP agent context
00563  * @param[in] community NULL-terminated string that contains the community name
00564  * @return Error code
00565  **/
00566 
00567 error_t snmpAgentDeleteCommunity(SnmpAgentContext *context, const char_t *community)
00568 {
00569 #if (SNMP_V1_SUPPORT == ENABLED || SNMP_V2C_SUPPORT == ENABLED)
00570    //Remove the community string from the local configuration datastore
00571    return snmpAgentDeleteUser(context, community);
00572 #else
00573    //Not implemented
00574    return ERROR_NOT_IMPLEMENTED;
00575 #endif
00576 }
00577 
00578 
00579 /**
00580  * @brief Create a new user
00581  * @param[in] context Pointer to the SNMP agent context
00582  * @param[in] username NULL-terminated string that contains the user name
00583  * @param[in] mode Access rights
00584  * @param[in] keyFormat Key format (ASCII password or raw key)
00585  * @param[in] authProtocol Authentication type
00586  * @param[in] authKey Key to be used for data authentication
00587  * @param[in] privProtocol Privacy type
00588  * @param[in] privKey Key to be used for data encryption
00589  * @return Error code
00590  **/
00591 
00592 error_t snmpAgentCreateUser(SnmpAgentContext *context,
00593    const char_t *username, SnmpAccess mode, SnmpKeyFormat keyFormat,
00594    SnmpAuthProtocol authProtocol, const void *authKey,
00595    SnmpPrivProtocol privProtocol, const void *privKey)
00596 {
00597    error_t error;
00598    uint_t i;
00599    size_t n;
00600    SnmpUserInfo *entry;
00601    SnmpUserInfo *firstFreeEntry;
00602 
00603    //Check parameters
00604    if(context == NULL || username == NULL)
00605       return ERROR_INVALID_PARAMETER;
00606 
00607    //Data authentication?
00608    if(authProtocol != SNMP_AUTH_PROTOCOL_NONE)
00609    {
00610       //Check key format
00611       if(keyFormat != SNMP_KEY_FORMAT_TEXT && keyFormat != SNMP_KEY_FORMAT_RAW)
00612          return ERROR_INVALID_PARAMETER;
00613 
00614       //Data authentication requires a key
00615       if(authKey == NULL)
00616          return ERROR_INVALID_PARAMETER;
00617    }
00618 
00619    //Data confidentiality?
00620    if(privProtocol != SNMP_PRIV_PROTOCOL_NONE)
00621    {
00622       //Check key format
00623       if(keyFormat != SNMP_KEY_FORMAT_TEXT && keyFormat != SNMP_KEY_FORMAT_RAW)
00624          return ERROR_INVALID_PARAMETER;
00625 
00626       //Data confidentiality requires a key
00627       if(privKey == NULL)
00628          return ERROR_INVALID_PARAMETER;
00629 
00630       //There is no provision for data confidentiality without data authentication
00631       if(authProtocol == SNMP_AUTH_PROTOCOL_NONE)
00632          return ERROR_INVALID_PARAMETER;
00633    }
00634 
00635    //Retrieve the length of the user name
00636    n = strlen(username);
00637 
00638    //Make sure the user name is valid
00639    if(n == 0 || n > SNMP_MAX_USER_NAME_LEN)
00640       return ERROR_INVALID_LENGTH;
00641 
00642    //Acquire exclusive access to the SNMP agent context
00643    osAcquireMutex(&context->mutex);
00644 
00645    //Keep track of the first free entry
00646    firstFreeEntry = NULL;
00647 
00648    //Loop through the list of users
00649    for(i = 0; i < SNMP_AGENT_MAX_USER_COUNT; i++)
00650    {
00651       //Point to the current entry
00652       entry = &context->userTable[i];
00653 
00654       //Check if the entry is currently in use
00655       if(entry->name[0] != '\0')
00656       {
00657          //Check whether the user name already exists
00658          if(!strcmp(entry->name, username))
00659             break;
00660       }
00661       else
00662       {
00663          //Keep track of the first free entry
00664          if(firstFreeEntry == NULL)
00665             firstFreeEntry = entry;
00666       }
00667    }
00668 
00669    //If the specified user name does not exist, then a new
00670    //entry should be created
00671    if(i >= SNMP_AGENT_MAX_USER_COUNT)
00672       entry = firstFreeEntry;
00673 
00674    //Check whether the service list runs out of space
00675    if(entry != NULL)
00676    {
00677       //Save user name
00678       strcpy(entry->name, username);
00679       //Access rights
00680       entry->mode = mode;
00681 
00682       //Successful processing
00683       error = NO_ERROR;
00684 
00685 #if (SNMP_V3_SUPPORT == ENABLED)
00686       //Authentication protocol
00687       entry->authProtocol = authProtocol;
00688       //Privacy protocol
00689       entry->privProtocol = privProtocol;
00690 
00691       //Data authentication?
00692       if(authProtocol != SNMP_AUTH_PROTOCOL_NONE)
00693       {
00694          //ASCII password or raw key?
00695          if(keyFormat == SNMP_KEY_FORMAT_TEXT)
00696          {
00697             //Generate the authentication key from the provided password
00698             error = snmpGenerateKey(authProtocol, authKey, context->contextEngine,
00699                context->contextEngineLen, &entry->authKey);
00700          }
00701          else
00702          {
00703             //Save the authentication key
00704             memcpy(&entry->authKey, authKey, sizeof(SnmpKey));
00705          }
00706       }
00707 
00708       //Check status code
00709       if(!error)
00710       {
00711          //Data confidentiality?
00712          if(privProtocol != SNMP_PRIV_PROTOCOL_NONE)
00713          {
00714             //ASCII password or raw key?
00715             if(keyFormat == SNMP_KEY_FORMAT_TEXT)
00716             {
00717                //Generate the privacy key from the provided password
00718                error = snmpGenerateKey(authProtocol, privKey, context->contextEngine,
00719                   context->contextEngineLen, &entry->privKey);
00720             }
00721             else
00722             {
00723                //Save the privacy key
00724                memcpy(&entry->privKey, privKey, sizeof(SnmpKey));
00725             }
00726          }
00727       }
00728 
00729       //Check status code
00730       if(error)
00731       {
00732          //Clean up side effects
00733          memset(entry, 0, sizeof(SnmpUserInfo));
00734       }
00735 #endif
00736    }
00737    else
00738    {
00739       //Unable to add new user
00740       error = ERROR_OUT_OF_RESOURCES;
00741    }
00742 
00743    //Release exclusive access to the SNMP agent context
00744    osReleaseMutex(&context->mutex);
00745 
00746    //Return error code
00747    return error;
00748 }
00749 
00750 
00751 /**
00752  * @brief Remove existing user
00753  * @param[in] context Pointer to the SNMP agent context
00754  * @param[in] username NULL-terminated string that contains the user name
00755  * @return Error code
00756  **/
00757 
00758 error_t snmpAgentDeleteUser(SnmpAgentContext *context, const char_t *username)
00759 {
00760    error_t error;
00761    uint_t i;
00762    SnmpUserInfo *entry;
00763 
00764    //Acquire exclusive access to the SNMP agent context
00765    osAcquireMutex(&context->mutex);
00766 
00767    //Loop through the list of users
00768    for(i = 0; i < SNMP_AGENT_MAX_USER_COUNT; i++)
00769    {
00770       //Point to the current entry
00771       entry = &context->userTable[i];
00772 
00773       //Compare user names
00774       if(!strcmp(entry->name, username))
00775          break;
00776    }
00777 
00778    //User name found?
00779    if(i < SNMP_AGENT_MAX_USER_COUNT)
00780    {
00781       //Clear the security profile of the user
00782       memset(entry, 0, sizeof(SnmpUserInfo));
00783       //Successful processing
00784       error = NO_ERROR;
00785    }
00786    else
00787    {
00788       //The specified user name does not exist
00789       error = ERROR_NOT_FOUND;
00790    }
00791 
00792    //Release exclusive access to the SNMP agent context
00793    osReleaseMutex(&context->mutex);
00794 
00795    //Return status code
00796    return error;
00797 }
00798 
00799 
00800 /**
00801  * @brief Send SNMP trap message
00802  * @param[in] context Pointer to the SNMP agent context
00803  * @param[in] destIpAddr Destination IP address
00804  * @param[in] version SNMP version identifier
00805  * @param[in] username User name or community name
00806  * @param[in] genericTrapType Generic trap type
00807  * @param[in] specificTrapCode Specific code
00808  * @param[in] objectList List of object names
00809  * @param[in] objectListSize Number of entries in the list
00810  * @return Error code
00811  **/
00812 
00813 error_t snmpAgentSendTrap(SnmpAgentContext *context, const IpAddr *destIpAddr,
00814    SnmpVersion version, const char_t *username, uint_t genericTrapType,
00815    uint_t specificTrapCode, const SnmpTrapObject *objectList, uint_t objectListSize)
00816 {
00817    error_t error;
00818 
00819    //Check parameters
00820    if(context == NULL || destIpAddr == NULL || username == NULL)
00821       return ERROR_INVALID_PARAMETER;
00822 
00823    //Make sure the list of objects is valid
00824    if(objectListSize > 0 && objectList == NULL)
00825       return ERROR_INVALID_PARAMETER;
00826 
00827    //Acquire exclusive access to the SNMP agent context
00828    osAcquireMutex(&context->mutex);
00829 
00830    //Refresh SNMP engine time
00831    snmpRefreshEngineTime(context);
00832 
00833    //Start of exception handling block
00834    do
00835    {
00836 #if (SNMP_V1_SUPPORT == ENABLED)
00837       //SNMPv1 version?
00838       if(version == SNMP_VERSION_1)
00839       {
00840          //Format Trap-PDU
00841          error = snmpFormatTrapPdu(context, version, username,
00842             genericTrapType, specificTrapCode, objectList, objectListSize);
00843          //Any error to report?
00844          if(error)
00845             break;
00846 
00847          //Format SMNP message header
00848          error = snmpWriteMessageHeader(&context->response);
00849          //Any error to report?
00850          if(error)
00851             break;
00852       }
00853       else
00854 #endif
00855 #if (SNMP_V2C_SUPPORT == ENABLED)
00856       //SNMPv2c version?
00857       if(version == SNMP_VERSION_2C)
00858       {
00859          //Format SNMPv2-Trap-PDU
00860          error = snmpFormatTrapPdu(context, version, username,
00861             genericTrapType, specificTrapCode, objectList, objectListSize);
00862          //Any error to report?
00863          if(error)
00864             break;
00865 
00866          //Format SMNP message header
00867          error = snmpWriteMessageHeader(&context->response);
00868          //Any error to report?
00869          if(error)
00870             break;
00871       }
00872       else
00873 #endif
00874 #if (SNMP_V3_SUPPORT == ENABLED)
00875       //SNMPv3 version?
00876       if(version == SNMP_VERSION_3)
00877       {
00878          //Information about the user name is extracted from the local
00879          //configuration datastore
00880          context->user = snmpFindUser(context, username, strlen(username));
00881 
00882          //Invalid user name?
00883          if(context->user == NULL)
00884          {
00885             //Report an error
00886             error = ERROR_UNKNOWN_USER_NAME;
00887             //Exit immediately
00888             break;
00889          }
00890 
00891          //Format SNMPv2-Trap-PDU
00892          error = snmpFormatTrapPdu(context, version, username,
00893             genericTrapType, specificTrapCode, objectList, objectListSize);
00894          //Any error to report?
00895          if(error)
00896             break;
00897 
00898          //Format scopedPDU
00899          error = snmpWriteScopedPdu(&context->response);
00900          //Any error to report?
00901          if(error)
00902             break;
00903 
00904          //Check whether the privFlag is set
00905          if(context->response.msgFlags & SNMP_MSG_FLAG_PRIV)
00906          {
00907             //Encrypt data
00908             error = snmpEncryptData(context->user, &context->response, &context->salt);
00909             //Any error to report?
00910             if(error)
00911                break;
00912          }
00913 
00914          //Format SMNP message header
00915          error = snmpWriteMessageHeader(&context->response);
00916          //Any error to report?
00917          if(error)
00918             break;
00919 
00920          //Check whether the authFlag is set
00921          if(context->response.msgFlags & SNMP_MSG_FLAG_AUTH)
00922          {
00923             //Authenticate outgoing SNMP message
00924             error = snmpAuthOutgoingMessage(context->user, &context->response);
00925             //Any error to report?
00926             if(error)
00927                break;
00928          }
00929       }
00930       else
00931 #endif
00932       //Invalid SNMP version?
00933       {
00934          //Debug message
00935          TRACE_WARNING("  Invalid SNMP version!\r\n");
00936          //Report an error
00937          error = ERROR_INVALID_VERSION;
00938          //Exit immediately
00939          break;
00940       }
00941 
00942       //Total number of messages which were passed from the SNMP protocol
00943       //entity to the transport service
00944       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutPkts, 1);
00945 
00946       //Debug message
00947       TRACE_INFO("Sending SNMP message to %s port %" PRIu16
00948          " (%" PRIuSIZE " bytes)...\r\n",
00949          ipAddrToString(destIpAddr, NULL),
00950          context->settings.trapPort, context->response.length);
00951 
00952       //Display the contents of the SNMP message
00953       TRACE_DEBUG_ARRAY("  ", context->response.pos, context->response.length);
00954       //Display ASN.1 structure
00955       asn1DumpObject(context->response.pos, context->response.length, 0);
00956 
00957       //Send SNMP trap message
00958       error = socketSendTo(context->socket, destIpAddr, context->settings.trapPort,
00959          context->response.pos, context->response.length, NULL, 0);
00960 
00961       //End of exception handling block
00962    } while(0);
00963 
00964    //Release exclusive access to the SNMP agent context
00965    osReleaseMutex(&context->mutex);
00966 
00967    //Return status code
00968    return error;
00969 }
00970 
00971 
00972 /**
00973  * @brief SNMP agent task
00974  * @param[in] context Pointer to the SNMP agent context
00975  **/
00976 
00977 void snmpAgentTask(SnmpAgentContext *context)
00978 {
00979    error_t error;
00980 
00981 #if (NET_RTOS_SUPPORT == ENABLED)
00982    //Main loop
00983    while(1)
00984    {
00985 #endif
00986       //Wait for an incoming datagram
00987       error = socketReceiveFrom(context->socket, &context->remoteIpAddr,
00988          &context->remotePort, context->request.buffer,
00989          SNMP_MAX_MSG_SIZE, &context->request.bufferLen, 0);
00990 
00991       //Any datagram received?
00992       if(!error)
00993       {
00994          //Acquire exclusive access to the SNMP agent context
00995          osAcquireMutex(&context->mutex);
00996 
00997          //Debug message
00998          TRACE_INFO("\r\nSNMP message received from %s port %" PRIu16
00999             " (%" PRIuSIZE " bytes)...\r\n",
01000             ipAddrToString(&context->remoteIpAddr, NULL),
01001             context->remotePort, context->request.bufferLen);
01002 
01003          //Display the contents of the SNMP message
01004          TRACE_DEBUG_ARRAY("  ", context->request.buffer, context->request.bufferLen);
01005          //Dump ASN.1 structure
01006          asn1DumpObject(context->request.buffer, context->request.bufferLen, 0);
01007 
01008          //Process incoming SNMP message
01009          error = snmpProcessMessage(context);
01010 
01011          //Check status code
01012          if(!error)
01013          {
01014             //Debug message
01015             TRACE_INFO("Sending SNMP message to %s port %" PRIu16
01016                " (%" PRIuSIZE " bytes)...\r\n",
01017                ipAddrToString(&context->remoteIpAddr, NULL),
01018                context->remotePort, context->response.length);
01019 
01020             //Display the contents of the SNMP message
01021             TRACE_DEBUG_ARRAY("  ", context->response.pos, context->response.length);
01022             //Display ASN.1 structure
01023             asn1DumpObject(context->response.pos, context->response.length, 0);
01024 
01025             //Send SNMP response message
01026             socketSendTo(context->socket, &context->remoteIpAddr, context->remotePort,
01027                context->response.pos, context->response.length, NULL, 0);
01028          }
01029 
01030          //Release exclusive access to the SNMP agent context
01031          osReleaseMutex(&context->mutex);
01032       }
01033 #if (NET_RTOS_SUPPORT == ENABLED)
01034    }
01035 #endif
01036 }
01037 
01038 #endif
01039