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