net-snmp 5.7
example.c
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 }