Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:16 by
