net-snmp 5.7
|
00001 /* 00002 * Template MIB group implementation - example.c 00003 * 00004 */ 00005 00006 /* 00007 * include important headers 00008 */ 00009 #include <net-snmp/net-snmp-config.h> 00010 #if HAVE_STDLIB_H 00011 #include <stdlib.h> 00012 #endif 00013 #if HAVE_STRING_H 00014 #include <string.h> 00015 #else 00016 #include <strings.h> 00017 #endif 00018 00019 #include <net-snmp/net-snmp-includes.h> 00020 #include <net-snmp/agent/net-snmp-agent-includes.h> 00021 00022 /* 00023 * header_generic() comes from here 00024 */ 00025 #include "util_funcs/header_generic.h" 00026 00027 /* 00028 * include our .h file 00029 */ 00030 #include "example.h" 00031 00032 00033 /* 00034 * Certain objects can be set via configuration file directives. 00035 * These variables hold the values for such objects, as they need to 00036 * be accessible to both the config handlers, and the callback routine. 00037 */ 00038 #define EXAMPLE_STR_LEN 300 00039 #define EXAMPLE_STR_DEFAULT "life the universe and everything" 00040 int example_int = 42; 00041 char example_str[EXAMPLE_STR_LEN]; 00042 00043 /* 00044 * Forward declarations for the config handlers 00045 */ 00046 void example_parse_config_exampleint(const char *token, 00047 char *cptr); 00048 void example_parse_config_examplestr(const char *token, 00049 char *cptr); 00050 void example_free_config_exampleint(void); 00051 void example_free_config_examplestr(void); 00052 00053 00054 /********************* 00055 * 00056 * Initialisation & common implementation functions 00057 * 00058 *********************/ 00059 00060 /* 00061 * This array structure defines a representation of the 00062 * MIB being implemented. 00063 * 00064 * The type of the array is 'struct variableN', where N is 00065 * large enough to contain the longest OID sub-component 00066 * being loaded. This will normally be the maximum value 00067 * of the fifth field in each line. In this case, the second 00068 * and third entries are both of size 2, so we're using 00069 * 'struct variable2' 00070 * 00071 * The supported values for N are listed in <agent/var_struct.h> 00072 * If the value you need is not listed there, simply use the 00073 * next largest that is. 00074 * 00075 * The format of each line is as follows 00076 * (using the first entry as an example): 00077 * 1: EXAMPLESTRING: 00078 * The magic number defined in the example header file. 00079 * This is passed to the callback routine and is used 00080 * to determine which object is being queried. 00081 * 2: ASN_OCTET_STR: 00082 * The type of the object. 00083 * Valid types are listed in <snmp_impl.h> 00084 * 3: NETSNMP_OLDAPI_RONLY (or NETSNMP_OLDAPI_RWRITE): 00085 * Whether this object can be SET or not. 00086 * 4: var_example: 00087 * The callback routine, used when the object is queried. 00088 * This will usually be the same for all objects in a module 00089 * and is typically defined later in this file. 00090 * 5: 1: 00091 * The length of the OID sub-component (the next field) 00092 * 6: {1}: 00093 * The OID sub-components of this entry. 00094 * In other words, the bits of the full OID that differ 00095 * between the various entries of this array. 00096 * This value is appended to the common prefix (defined later) 00097 * to obtain the full OID of each entry. 00098 */ 00099 struct variable2 example_variables[] = { 00100 {EXAMPLESTRING, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, 00101 var_example, 1, {1}}, 00102 {EXAMPLEINTEGER, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, 00103 var_example, 2, {2, 1}}, 00104 {EXAMPLEOBJECTID, ASN_OBJECT_ID, NETSNMP_OLDAPI_RONLY, 00105 var_example, 2, {2, 2}}, 00106 {EXAMPLETIMETICKS, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, 00107 var_example, 1, {3}}, 00108 {EXAMPLEIPADDRESS, ASN_IPADDRESS, NETSNMP_OLDAPI_RONLY, 00109 var_example, 1, {4}}, 00110 {EXAMPLECOUNTER, ASN_COUNTER, NETSNMP_OLDAPI_RONLY, 00111 var_example, 1, {5}}, 00112 {EXAMPLEGAUGE, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, 00113 var_example, 1, {6}}, 00114 {EXAMPLETRIGGERTRAP, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, 00115 var_example, 1, {7}}, 00116 {EXAMPLETRIGGERTRAP2, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, 00117 var_example, 1, {8}} 00118 }; 00119 00120 /* 00121 * This array defines the OID of the top of the mib tree that we're 00122 * registering underneath. 00123 * Note that this needs to be the correct size for the OID being 00124 * registered, so that the length of the OID can be calculated. 00125 * The format given here is the simplest way to achieve this. 00126 */ 00127 oid example_variables_oid[] = { 1, 3, 6, 1, 4, 1, 2021, 254 }; 00128 00129 00130 00131 /* 00132 * This function is called at the time the agent starts up 00133 * to do any initializations that might be required. 00134 * 00135 * In theory it is optional and can be omitted if no 00136 * initialization is needed. In practise, every module 00137 * will need to register itself (or the objects being 00138 * implemented will not appear in the MIB tree), and this 00139 * registration is typically done here. 00140 * 00141 * If this function is added or removed, you must re-run 00142 * the configure script, to detect this change. 00143 */ 00144 void 00145 init_example(void) 00146 { 00147 /* 00148 * Register ourselves with the agent to handle our mib tree. 00149 * The arguments are: 00150 * descr: A short description of the mib group being loaded. 00151 * var: The variable structure to load. 00152 * (the name of the variable structure defined above) 00153 * vartype: The type of this variable structure 00154 * theoid: The OID pointer this MIB is being registered underneath. 00155 */ 00156 REGISTER_MIB("example", example_variables, variable2, 00157 example_variables_oid); 00158 00159 00160 /* 00161 * Register config handlers for the two objects that can be set 00162 * via configuration file directive. 00163 * Also set a default value for the string object. Note that the 00164 * example integer variable was initialised above. 00165 */ 00166 strncpy(example_str, EXAMPLE_STR_DEFAULT, EXAMPLE_STR_LEN); 00167 00168 snmpd_register_config_handler("exampleint", 00169 example_parse_config_exampleint, 00170 example_free_config_exampleint, 00171 "exampleint value"); 00172 snmpd_register_config_handler("examplestr", 00173 example_parse_config_examplestr, 00174 example_free_config_examplestr, 00175 "examplestr value"); 00176 snmpd_register_config_handler("examplestring", 00177 example_parse_config_examplestr, 00178 example_free_config_examplestr, 00179 "examplestring value"); 00180 00181 /* 00182 * One common requirement is to read values from the kernel. 00183 * This is usually initialised here, to speed up access when the 00184 * information is read in, as a response to an incoming request. 00185 * 00186 * This module doesn't actually use this mechanism, 00187 * so this call is commented out here. 00188 */ 00189 /* 00190 * auto_nlist( "example_symbol", 0, 0 ); 00191 */ 00192 } 00193 00194 /********************* 00195 * 00196 * Configuration file handling functions 00197 * 00198 *********************/ 00199 00200 void 00201 example_parse_config_exampleint(const char *token, char *cptr) 00202 { 00203 example_int = atoi(cptr); 00204 } 00205 00206 void 00207 example_parse_config_examplestr(const char *token, char *cptr) 00208 { 00209 /* 00210 * Make sure the string fits in the space allocated for it. 00211 */ 00212 if (strlen(cptr) < EXAMPLE_STR_LEN) 00213 strcpy(example_str, cptr); 00214 else { 00215 /* 00216 * Truncate the string if necessary. 00217 * An alternative approach would be to log an error, 00218 * and discard this value altogether. 00219 */ 00220 strncpy(example_str, cptr, EXAMPLE_STR_LEN - 4); 00221 example_str[EXAMPLE_STR_LEN - 4] = 0; 00222 strcat(example_str, "..."); 00223 example_str[EXAMPLE_STR_LEN - 1] = 0; 00224 } 00225 } 00226 00227 /* 00228 * We don't need to do anything special when closing down 00229 */ 00230 void 00231 example_free_config_exampleint(void) 00232 { 00233 } 00234 00235 void 00236 example_free_config_examplestr(void) 00237 { 00238 } 00239 00240 /********************* 00241 * 00242 * System specific implementation functions 00243 * 00244 *********************/ 00245 00246 /* 00247 * Define the callback function used in the example_variables structure. 00248 * This is called whenever an incoming request refers to an object 00249 * within this sub-tree. 00250 * 00251 * Four of the parameters are used to pass information in. 00252 * These are: 00253 * vp The entry from the 'example_variables' array for the 00254 * object being queried. 00255 * name The OID from the request. 00256 * length The length of this OID. 00257 * exact A flag to indicate whether this is an 'exact' request 00258 * (GET/SET) or an 'inexact' one (GETNEXT/GETBULK). 00259 * 00260 * Four of the parameters are used to pass information back out. 00261 * These are: 00262 * name The OID being returned. 00263 * length The length of this OID. 00264 * var_len The length of the answer being returned. 00265 * write_method A pointer to the SET function for this object. 00266 * 00267 * Note that name & length serve a dual purpose in both roles. 00268 */ 00269 00270 u_char * 00271 var_example(struct variable *vp, 00272 oid * name, 00273 size_t * length, 00274 int exact, size_t * var_len, WriteMethod ** write_method) 00275 { 00276 /* 00277 * The result returned from this function needs to be a pointer to 00278 * static data (so that it can be accessed from outside). 00279 * Define suitable variables for any type of data we may return. 00280 */ 00281 static char string[EXAMPLE_STR_LEN]; /* for EXAMPLESTRING */ 00282 static oid oid_ret[8]; /* for EXAMPLEOBJECTID */ 00283 static long long_ret; /* for everything else */ 00284 00285 /* 00286 * Before returning an answer, we need to check that the request 00287 * refers to a valid instance of this object. The utility routine 00288 * 'header_generic' can be used to do this for scalar objects. 00289 * 00290 * This routine 'header_simple_table' does the same thing for "simple" 00291 * tables. (See the AGENT.txt file for the definition of a simple table). 00292 * 00293 * Both these utility routines also set up default values for the 00294 * return arguments (assuming the check succeeded). 00295 * The name and length are set suitably for the current object, 00296 * var_len assumes that the result is an integer of some form, 00297 * and write_method assumes that the object cannot be set. 00298 * 00299 * If these assumptions are correct, this callback routine simply 00300 * needs to return a pointer to the appropriate value (using 'long_ret'). 00301 * Otherwise, 'var_len' and/or 'write_method' should be set suitably. 00302 */ 00303 DEBUGMSGTL(("example", "var_example entered\n")); 00304 if (header_generic(vp, name, length, exact, var_len, write_method) == 00305 MATCH_FAILED) 00306 return NULL; 00307 00308 00309 /* 00310 * Many object will need to obtain data from the operating system in 00311 * order to return the appropriate value. Typically, this is done 00312 * here - immediately following the 'header' call, and before the 00313 * switch statement. This is particularly appropriate if a single 00314 * interface call can return data for all the objects supported. 00315 * 00316 * This example module does not rely on external data, so no such 00317 * calls are needed in this case. 00318 */ 00319 00320 /* 00321 * Now use the magic number from the variable pointer 'vp' to 00322 * select the particular object being queried. 00323 * In each case, one of the static objects is set up with the 00324 * appropriate information, and returned mapped to a 'u_char *' 00325 */ 00326 switch (vp->magic) { 00327 case EXAMPLESTRING: 00328 strcpy(string, example_str); 00329 /* 00330 * Note that the assumption that the answer will be an 00331 * integer does not hold true in this case, so the length 00332 * of the answer needs to be set explicitly. 00333 */ 00334 *var_len = strlen(string); 00335 return (u_char *) string; 00336 00337 case EXAMPLEINTEGER: 00338 /* 00339 * Here the length assumption is correct, but the 00340 * object is writeable, so we need to set the 00341 * write_method pointer as well as the current value. 00342 */ 00343 long_ret = example_int; 00344 *write_method = write_exampleint; 00345 return (u_char *) & long_ret; 00346 00347 case EXAMPLEOBJECTID: 00348 oid_ret[0] = 1; 00349 oid_ret[1] = 3; 00350 oid_ret[2] = 6; 00351 oid_ret[3] = 1; 00352 oid_ret[4] = 4; 00353 oid_ret[5] = oid_ret[6] = oid_ret[7] = 42; 00354 /* 00355 * Again, the assumption regarding the answer length is wrong. 00356 */ 00357 *var_len = 8 * sizeof(oid); 00358 return (u_char *) oid_ret; 00359 00360 case EXAMPLETIMETICKS: 00361 /* 00362 * Here both assumptions are correct, 00363 * so we just need to set up the answer. 00364 */ 00365 long_ret = 363136200; /* 42 days, 42 minutes and 42.0 seconds */ 00366 return (u_char *) & long_ret; 00367 00368 case EXAMPLEIPADDRESS: 00369 /* 00370 * ipaddresses get returned as a long. ick 00371 */ 00372 /* 00373 * we're returning 127.0.0.1 00374 */ 00375 long_ret = ntohl(INADDR_LOOPBACK); 00376 return (u_char *) & long_ret; 00377 00378 case EXAMPLECOUNTER: 00379 long_ret = 42; 00380 return (u_char *) & long_ret; 00381 00382 case EXAMPLEGAUGE: 00383 long_ret = 42; /* Do we detect a theme running through these answers? */ 00384 return (u_char *) & long_ret; 00385 00386 case EXAMPLETRIGGERTRAP: 00387 /* 00388 * This object is essentially "write-only". 00389 * It only exists to trigger the sending of a trap. 00390 * Reading it will always return 0. 00391 */ 00392 long_ret = 0; 00393 *write_method = write_exampletrap; 00394 return (u_char *) & long_ret; 00395 00396 case EXAMPLETRIGGERTRAP2: 00397 /* 00398 * This object is essentially "write-only". 00399 * It only exists to trigger the sending of a v2 trap. 00400 * Reading it will always return 0. 00401 */ 00402 long_ret = 0; 00403 *write_method = write_exampletrap2; 00404 return (u_char *) & long_ret; 00405 00406 default: 00407 /* 00408 * This will only be triggered if there's a problem with 00409 * the coding of the module. SNMP requests that reference 00410 * a non-existant OID will be directed elsewhere. 00411 * If this branch is reached, log an error, so that 00412 * the problem can be investigated. 00413 */ 00414 DEBUGMSGTL(("snmpd", "unknown sub-id %d in examples/var_example\n", 00415 vp->magic)); 00416 } 00417 /* 00418 * If we fall through to here, fail by returning NULL. 00419 * This is essentially a continuation of the 'default' case above. 00420 */ 00421 return NULL; 00422 } 00423 00424 /********************* 00425 * 00426 * Writeable object SET handling routines 00427 * 00428 *********************/ 00429 int 00430 write_exampleint(int action, 00431 u_char * var_val, 00432 u_char var_val_type, 00433 size_t var_val_len, 00434 u_char * statP, oid * name, size_t name_len) 00435 { 00436 /* 00437 * Define an arbitrary maximum permissible value 00438 */ 00439 #define MAX_EXAMPLE_INT 100 00440 static long intval; 00441 static long old_intval; 00442 00443 switch (action) { 00444 case RESERVE1: 00445 /* 00446 * Check that the value being set is acceptable 00447 */ 00448 if (var_val_type != ASN_INTEGER) { 00449 DEBUGMSGTL(("example", "%x not integer type", var_val_type)); 00450 return SNMP_ERR_WRONGTYPE; 00451 } 00452 if (var_val_len > sizeof(long)) { 00453 DEBUGMSGTL(("example", "wrong length %" NETSNMP_PRIz "u", 00454 var_val_len)); 00455 return SNMP_ERR_WRONGLENGTH; 00456 } 00457 00458 intval = *((long *) var_val); 00459 if (intval > MAX_EXAMPLE_INT) { 00460 DEBUGMSGTL(("example", "wrong value %lx", intval)); 00461 return SNMP_ERR_WRONGVALUE; 00462 } 00463 break; 00464 00465 case RESERVE2: 00466 /* 00467 * This is conventially where any necesary 00468 * resources are allocated (e.g. calls to malloc) 00469 * Here, we are using static variables 00470 * so don't need to worry about this. 00471 */ 00472 break; 00473 00474 case FREE: 00475 /* 00476 * This is where any of the above resources 00477 * are freed again (because one of the other 00478 * values being SET failed for some reason). 00479 * Again, since we are using static variables 00480 * we don't need to worry about this either. 00481 */ 00482 break; 00483 00484 case ACTION: 00485 /* 00486 * Set the variable as requested. 00487 * Note that this may need to be reversed, 00488 * so save any information needed to do this. 00489 */ 00490 old_intval = example_int; 00491 example_int = intval; 00492 break; 00493 00494 case UNDO: 00495 /* 00496 * Something failed, so re-set the 00497 * variable to its previous value 00498 * (and free any allocated resources). 00499 */ 00500 example_int = old_intval; 00501 break; 00502 00503 case COMMIT: 00504 /* 00505 * Everything worked, so we can discard any 00506 * saved information, and make the change 00507 * permanent (e.g. write to the config file). 00508 * We also free any allocated resources. 00509 * 00510 * In this case, there's nothing to do. 00511 */ 00512 break; 00513 00514 } 00515 return SNMP_ERR_NOERROR; 00516 } 00517 00518 int 00519 write_exampletrap(int action, 00520 u_char * var_val, 00521 u_char var_val_type, 00522 size_t var_val_len, 00523 u_char * statP, oid * name, size_t name_len) 00524 { 00525 long intval; 00526 00527 DEBUGMSGTL(("example", "write_exampletrap entered: action=%d\n", 00528 action)); 00529 switch (action) { 00530 case RESERVE1: 00531 /* 00532 * The only acceptable value is the integer 1 00533 */ 00534 if (var_val_type != ASN_INTEGER) { 00535 DEBUGMSGTL(("example", "%x not integer type", var_val_type)); 00536 return SNMP_ERR_WRONGTYPE; 00537 } 00538 if (var_val_len > sizeof(long)) { 00539 DEBUGMSGTL(("example", "wrong length %" NETSNMP_PRIz "u", 00540 var_val_len)); 00541 return SNMP_ERR_WRONGLENGTH; 00542 } 00543 00544 intval = *((long *) var_val); 00545 if (intval != 1) { 00546 DEBUGMSGTL(("example", "wrong value %lx", intval)); 00547 return SNMP_ERR_WRONGVALUE; 00548 } 00549 break; 00550 00551 case RESERVE2: 00552 /* 00553 * No resources are required.... 00554 */ 00555 break; 00556 00557 case FREE: 00558 /* 00559 * ... so no resources need be freed 00560 */ 00561 break; 00562 00563 case ACTION: 00564 /* 00565 * Having triggered the sending of a trap, 00566 * it would be impossible to revoke this, 00567 * so we can't actually invoke the action here. 00568 */ 00569 break; 00570 00571 case UNDO: 00572 /* 00573 * We haven't done anything yet, 00574 * so there's nothing to undo 00575 */ 00576 break; 00577 00578 case COMMIT: 00579 /* 00580 * Everything else worked, so it's now safe 00581 * to trigger the trap. 00582 * Note that this is *only* acceptable since 00583 * the trap sending routines are "failsafe". 00584 * (In fact, they can fail, but they return no 00585 * indication of this, which is the next best thing!) 00586 */ 00587 DEBUGMSGTL(("example", "write_exampletrap sending the trap\n")); 00588 send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 99); 00589 DEBUGMSGTL(("example", "write_exampletrap trap sent\n")); 00590 break; 00591 00592 } 00593 return SNMP_ERR_NOERROR; 00594 } 00595 00596 /* 00597 * this documents how to send a SNMPv2 (and higher) trap via the 00598 * send_v2trap() API. 00599 * 00600 * Coding SNMP-v2 Trap: 00601 * 00602 * The SNMPv2-Trap PDU contains at least a pair of object names and 00603 * values: - sysUpTime.0 whose value is the time in hundredths of a 00604 * second since the netwok management portion of system was last 00605 * reinitialized. - snmpTrapOID.0 which is part of the trap group SNMPv2 00606 * MIB whose value is the object-id of the specific trap you have defined 00607 * in your own MIB. Other variables can be added to caracterize the 00608 * trap. 00609 * 00610 * The function send_v2trap adds automaticallys the two objects but the 00611 * value of snmpTrapOID.0 is 0.0 by default. If you want to add your trap 00612 * name, you have to reconstruct this object and to add your own 00613 * variable. 00614 * 00615 */ 00616 00617 00618 00619 int 00620 write_exampletrap2(int action, 00621 u_char * var_val, 00622 u_char var_val_type, 00623 size_t var_val_len, 00624 u_char * statP, oid * name, size_t name_len) 00625 { 00626 long intval; 00627 00628 /* 00629 * these variales will be used when we send the trap 00630 */ 00631 oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; /* snmpTrapOID.0 */ 00632 oid demo_trap[] = { 1, 3, 6, 1, 4, 1, 2021, 13, 990 }; /*demo-trap */ 00633 oid example_string_oid[] = 00634 { 1, 3, 6, 1, 4, 1, 2021, 254, 1, 0 }; 00635 static netsnmp_variable_list var_trap; 00636 static netsnmp_variable_list var_obj; 00637 00638 DEBUGMSGTL(("example", "write_exampletrap2 entered: action=%d\n", 00639 action)); 00640 switch (action) { 00641 case RESERVE1: 00642 /* 00643 * The only acceptable value is the integer 1 00644 */ 00645 if (var_val_type != ASN_INTEGER) { 00646 DEBUGMSGTL(("example", "%x not integer type", var_val_type)); 00647 return SNMP_ERR_WRONGTYPE; 00648 } 00649 if (var_val_len > sizeof(long)) { 00650 DEBUGMSGTL(("example", "wrong length %" NETSNMP_PRIz "u", 00651 var_val_len)); 00652 return SNMP_ERR_WRONGLENGTH; 00653 } 00654 00655 intval = *((long *) var_val); 00656 if (intval != 1) { 00657 DEBUGMSGTL(("example", "wrong value %lx", intval)); 00658 return SNMP_ERR_WRONGVALUE; 00659 } 00660 break; 00661 00662 case RESERVE2: 00663 /* 00664 * No resources are required.... 00665 */ 00666 break; 00667 00668 case FREE: 00669 /* 00670 * ... so no resources need be freed 00671 */ 00672 break; 00673 00674 case ACTION: 00675 /* 00676 * Having triggered the sending of a trap, 00677 * it would be impossible to revoke this, 00678 * so we can't actually invoke the action here. 00679 */ 00680 break; 00681 00682 case UNDO: 00683 /* 00684 * We haven't done anything yet, 00685 * so there's nothing to undo 00686 */ 00687 break; 00688 00689 case COMMIT: 00690 /* 00691 * Everything else worked, so it's now safe 00692 * to trigger the trap. 00693 * Note that this is *only* acceptable since 00694 * the trap sending routines are "failsafe". 00695 * (In fact, they can fail, but they return no 00696 * indication of this, which is the next best thing!) 00697 */ 00698 00699 /* 00700 * trap definition objects 00701 */ 00702 00703 var_trap.next_variable = &var_obj; /* next variable */ 00704 var_trap.name = objid_snmptrap; /* snmpTrapOID.0 */ 00705 var_trap.name_length = sizeof(objid_snmptrap) / sizeof(oid); /* number of sub-ids */ 00706 var_trap.type = ASN_OBJECT_ID; 00707 var_trap.val.objid = demo_trap; /* demo-trap objid */ 00708 var_trap.val_len = sizeof(demo_trap); /* length in bytes (not number of subids!) */ 00709 00710 00711 /* 00712 * additional objects 00713 */ 00714 00715 00716 var_obj.next_variable = NULL; /* No more variables after this one */ 00717 var_obj.name = example_string_oid; 00718 var_obj.name_length = sizeof(example_string_oid) / sizeof(oid); /* number of sub-ids */ 00719 var_obj.type = ASN_OCTET_STR; /* type of variable */ 00720 var_obj.val.string = (unsigned char *) example_str; /* value */ 00721 var_obj.val_len = strlen(example_str); 00722 DEBUGMSGTL(("example", "write_exampletrap2 sending the v2 trap\n")); 00723 send_v2trap(&var_trap); 00724 DEBUGMSGTL(("example", "write_exampletrap2 v2 trap sent\n")); 00725 00726 break; 00727 00728 } 00729 return SNMP_ERR_NOERROR; 00730 }