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