6.3   Compile-time MIB Extensions

There are six steps involved in making MIB extensions to the SNMPv1 agent:

  1. Define the information to be managed.

  1. Express the information as a MIB definition.

  1. Add the new variables to the system.

  1. Write the method routines

  1. Build the agent.

  1. Integrate the agent into VxWorks.

Each of the above steps is explained in one of the following sections. We are providing an example MIB extension which continues throughout each of the examples in these sections. The extension adds support for the VxWorks system configuration group (sysconfig), which is used to get or set the target's user-name and password. These are objects can be used by VxWorks when accessing a host over a network. In addition, the system can be rebooted by changing the value of the sysState variable.


*   

NOTE: The standard Management Information Base known as MIB-II is defined in the file $WIND_BASE/target/src/snmpv1/agent/snmpMib2.mib. Additional Management Information Base information can be defined in any file, or as part of the MIB-II Management Information Base in snmpMib2.mib. The running example in this section shows the newly-developed MIB in a separate file from the MIB-II standard MIB, snmpMib2.mib. MIB information does not need to be in separate files; we show it that way here for purposes of clarity.

Step 1:   Defining the Information to be Managed

The first step in extending the VxWorks SNMP agent MIB involves defining what information is to be managed with SNMP.

There are many standard MIB definitions available for a wide array of applications. If possible, use a standard MIB module to convey the information. Some of the standard MIB modules are shown in E. SNMP Reference List. In addition, for your convenience, there are MIB modules provided in the directory $WIND_BASE/target/src/snmpv1/mibs.

Step 2:   Creating a MIB Definition

Once the information to be managed with SNMP has been defined, the next step is to have this information expressed in concise MIB format (using a stylized subset of the language Abstract Syntax Notation One, or ASN.1). If you are using a standard MIB module, then this step may already be completed. There is a selection of publicly-available standard MIB modules in the directory $WIND_BASE/target/src/snmpv1/mibs.

The concise MIB format defined by RFC 1212 provides a straightforward method of describing MIB modules. This is the standard method by which SNMP MIB modules are described, and it is the input format expected by the MIB compiler.

Example 6-1:  MIB Definition for the Systems Group

This example illustrates a MIB definition for the systems group, which allows access to the username, password, etc. on a VxWorks system. This document is in ASN.1 format. Filename: demo.mib (Note: this file is not included as part of this distribution.)

        VXDEMO-MIB  
    --FORCE-INCLUDE <mib.h> 
    --FORCE-INCLUDE <snmpdefs.h> 
    --FORCE-INCLUDE "mibhand.h" 
 
        DEFINITIONS ::= BEGIN 
 
    -- Title:            VxWorks Demo MIB version 1.0 
 
    IMPORTS 
        MODULE-IDENTITY,  
        OBJECT-TYPE 
        FROM SNMPv2-SMI 
            enterprises  
                FROM RFC1155-SMI 
            DisplayString 
                FROM RFC1213-MIB 
                ; 
 
    wrs        OBJECT IDENTIFIER ::=     { enterprises 731 } 
    demos        OBJECT IDENTIFIER ::=     { wrs 1 } 
 
    -- Module Identification Definition. 
 
    windDemo MODULE-IDENTITY 
        LAST-UPDATED "9312030000Z" 
        ORGANIZATION "Wind River Systems" 
        CONTACT-INFO 
            "        Technical Support 
 
                    Postal: Wind River Systems 
                    1010 Atlantic Avenue 
                    Alameda, CA  94501 
                    US 
 
                    Tel: +1 800 545 WIND 
                    Fax: +1 510 814 2104 
 
                    E-mail: support@wrs.com" 
        DESCRIPTION 
                "This is the VxWorks demo MIB module.  It is provided as  
                an example of how to make extensions to the VxWorks SNMPv1/v2c 
                Agent MIB." 
 
    ::= { demos 1 } 
 
    windObjects OBJECT IDENTIFIER ::= { windDemo 1 } 
 
    -- Groups in the VxWorks Demo MIB 
 
    sysconfig OBJECT IDENTIFIER ::= { windObjects 1 } 
 
    -- System Configuration Group 
 
    -- This group provides VxWorks system configuration information.   
    -- It is used to get/set the target's user name, and 
    -- password.  These objects are used by VxWorks when accessing  
    -- a host over the network.  In addition, the system can be  
    -- rebooted by changing the value of the sysState variable. 
 
    sysState OBJECT-TYPE 
        SYNTAX  INTEGER { 
            system-running(1), -- System is up and running. 
            system-reboot(2)   -- System is to be rebooted. 
                } 
        MAX-ACCESS read-write 
        STATUS current 
        DESCRIPTION 
            "The VxWorks target status is reported through this 
            field.  The only valid state that this field can be 
            set to is system-reboot.  The system will be rebooted 
            five seconds after changing the state." 
 
        ::= { sysconfig 1 } 
 
    sysUserName OBJECT-TYPE 
        SYNTAX DisplayString (SIZE (0..255)) 
        MAX-ACCESS read-write 
        STATUS current 
        DESCRIPTION 
            "The user name the VxWorks target uses for remote 
            machine access." 
 
        ::= { sysconfig 2 } 
 
    sysUserPassw OBJECT-TYPE 
        SYNTAX DisplayString (SIZE (0..255)) 
        MAX-ACCESS read-write 
        STATUS current 
        DESCRIPTION 
            "The user password the VxWorks target uses for remote 
            machine access." 
 
        ::= { sysconfig 3 } 
 
END 

Step 3:   Adding New Variables to the System

Now that the MIB definition has been defined, the next step is to add any new MIB variables it requires to the system (and create the routines to access and manipulate them). For example, if the MIB module defined a MIB object representing the number of packets received by a network interface, then this step would involve adding the counter to the network interface code (and perhaps a function call to obtain this number).

VxWorks already contains the code to access the user name and password. With this example, we are adding the capability to get or change the system state, including the ability to reboot; this is the only functionality we are adding with this example.

Step 4:   Creating the Method Routines

Once the MIB definition has been written and compiled and the new variables added to the system, the next step is to write method routines to support the new MIB module. The method routines are called by the agent to manipulate the variables that were newly added to the MIB.

The method routines can be written entirely by hand. However, the mibcomp command can be used to generate C stubs and source code for the method routines. See A. The MIB Compiler User's Guide for details.After the stubs have been generated and the method routines document has been reviewed, the next step is to augment the stubs with code specific to your application.

Example 6-2:  Invocation of mibcomp

Compile the demo module demo.mib using mibcomp, making sure to include any standard modules which are referenced by the module (see the IMPORTS section). This example shows the use of the option -start to place the new variables as a subtree under iso.private.enterprises.wrs. (This example is a single command line; the \ character indicates continuation onto the next line.)

% mibcomp -l $WIND_BASE/target/src/snmpv1/mibs -stub -start wrs \ 
-o demo.c rfc1155.smi rfc1213.mib demo.mib

After the stubs have been generated and the method routines document has been reviewed, the next step is to augment the stubs with code specific to your application.

Example 6-3:  Default Output of mibcomp

The following example shows mibcomp default output before user augmentation. Filename: demo.c (Note: this file is not included as part of this distribution.)

#include <asn1.h> 
#include <buffer.h> 
#include <mib.h> 
#include <localio.h> 
#include <snmpdefs.h> 
#include <snmp.h> 
#include <auxfuncs.h> 
#include "mibleaf.h" 
 
/* 
 * Method routines for the sysconfig variables: 
 * 
 *   sysState -- read-write 
 * The VxWorks target status is reported through this 
 * field.  The only valid state that this field can be 
 * set to is system-reboot.  The system will be rebooted 
 * five seconds after changing the state. 
 * 
 *   sysUserName -- read-write 
 * The user name the VxWorks target uses for remote 
 * machine access. 
 * 
 *   sysUserPassw -- read-write 
 * The user password the VxWorks target uses for remote 
 * machine access. 
 */ 
 
/* An internal routine to retrieve the values of the variables, used 
 * by the method routines sysconfig_get and sysconfig_next. 
 * You need to replace the type STRUCT_sysconfig with something 
 * appropriate to your system. */ 
static int 
  sysconfig_get_value(OIDC_T      lastmatch, 
                      SNMP_PKT_T *pktp, 
                      VB_T       *vbp, 
                      STRUCT_sysconfig *data)     /* !!! */ 
{ 
  switch(lastmatch) { 
  case LEAF_sysState: 
    /* Values: 
     *  system-running(1) = VAL_sysState_system_running 
     *  system-reboot(2)  = VAL_sysState_system_reboot 
     */ 
    getproc_got_int32(pktp, vbp, data->sysState);    /* !!! */ 
    break; 
  case LEAF_sysUserName: 
    /* if the data being returned is in dynamic storage and needs 
     * to be free'd, change the 0 argument to a 1. */ 
    getproc_got_string(pktp, vbp, string_length(data->sysUserName),  
        data->sysUserName, 0, VT_STRING);    /* !!! */ 
    break; 
  case LEAF_sysUserPassw: 
    /* if the data being returned is in dynamic storage and needs 
     * to be free'd, change the 0 argument to a 1. */ 
    getproc_got_string(pktp, vbp, string_length(data->sysUserPassw),  
        data->sysUserPassw, 0, VT_STRING);    /* !!! */ 
    break; 
  default: 
    return GEN_ERR; 
  } 
  return NO_ERROR; 
} 
 
void 
  sysconfig_get(OIDC_T      lastmatch, 
                int         compc, 
                OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
  STRUCT_sysconfig data;                             /* !!! */ 
  int error; 
 
  /* find all the varbinds that share the same getproc and instance */ 
  snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
 
  /* check that the instance is exactly .0 */ 
  if (!((compc == 1) && (*compl == 0))) 
    for ( ; vbp; vbp = vbp->vb_link) 
      getproc_nosuchins(pktp, vbp); 
/* grab the actual data for this variable.  this lookup routine  
* probably have to be changed for your system.  for scalar variables 
   * there might not even be any lookup routine. */ 
  else if (sysconfig_lookup(&data) != 0)            /* !!! */ 
    for ( ; vbp; vbp = vbp->vb_link) 
      getproc_error(pktp, vbp, GEN_ERR); 
  else { 
    /* retrieve all the values from the same data structure */ 
    for ( ; vbp; vbp = vbp->vb_link) { 
      if ((error = sysconfig_get_value(vbp->vb_ml.ml_last_match, pktp,  
            vbp, &data)) != NO_ERROR) 
        getproc_error(pktp, vbp, error); 
    } 
  } 
} 
 
void 
  sysconfig_next(OIDC_T      lastmatch, 
                 int         compc, 
                 OIDC_T     *compl, 
                 SNMP_PKT_T *pktp, 
                 VB_T       *vbp) 
{ 
  STRUCT_sysconfig data;           /* !!! */ 
  OIDC_T instance = 0; 
 
  /* the only time there's a next for a scalar is if we're given 
   * no instance at all. */ 
  if (compc != 0) 
    nextproc_no_next(pktp, vbp); 
  /* grab the data for these variables.  you'll probably have to change 
   * this lookup routine for your system.  for scalar variables there 
   * might not even be any lookup routine. */ 
  else if (sysconfig_lookup(&data));               /* !!! */ 
    getproc_error(pktp, vbp, GEN_ERR); 
  else { 
    /* find all the varbinds in this group and retrieve their 
     * values from the same data structure */ 
    for (snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
        vbp; vbp = vbp->vb_link) { 
      nextproc_next_instance(pktp, vbp, 1, &instance); 
      sysconfig_get_value(vbp->vb_ml.ml_last_match, pktp, vbp, &data); 
    } 
  } 
} 
 
void 
  sysconfig_test(OIDC_T      lastmatch, 
                 int         compc, 
                 OIDC_T     *compl, 
                 SNMP_PKT_T *pktp, 
                 VB_T       *vbp) 
{ 
  VB_T *group_vbp; 
 
  /* Only scalar variables here, check for .0 */ 
  if (!((compc == 1) && (*compl == 0))) { 
    testproc_error(pktp, vbp, NO_SUCH_NAME); 
    return; 
  } 
 
  /* find all the varbinds that share the same getproc and instance and 
   * group them together. */ 
  snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
 
  /* now check each varbind */ 
  for (group_vbp = vbp; 
       group_vbp; 
       group_vbp = group_vbp->vb_link) { 
    /* !!! Add any value checking you wish to do. */ 
    switch (group_vbp->vb_ml.ml_last_match) { 
    case LEAF_sysState: 
      /* !!! modify this switch to give an error for values your 
       * implementation doesn't allow */ 
      switch (VB_GET_INT32(group_vbp)) { 
      case VAL_sysState_system_running: 
      case VAL_sysState_system_reboot: 
        break; 
      default: 
        testproc_error(pktp, group_vbp, WRONG_VALUE); 
        continue; 
      } 
      testproc_good(pktp, group_vbp); 
      break; 
    case LEAF_sysUserName: 
 
      { ALENGTH_T length = EBufferUsed(VB_GET_STRING(group_vbp)); 
 
        /* !!! These are the lengths from the MIB.  Modify if your 
         * implementation differs. */ 
        if (!((length >= MINSIZE_sysUserName) && 
              (length <= MAXSIZE_sysUserName))) { 
          testproc_error(pktp, group_vbp, WRONG_VALUE); 
          break; 
        } 
      } 
      testproc_good(pktp, group_vbp); 
      break; 
    case LEAF_sysUserPassw: 
 
      { ALENGTH_T length = EBufferUsed(VB_GET_STRING(group_vbp)); 
 
        /* !!! These are the lengths from the MIB.  Modify if your 
         * implementation differs. */ 
        if (!((length >= MINSIZE_sysUserPassw) && 
              (length <= MAXSIZE_sysUserPassw))) { 
          testproc_error(pktp, group_vbp, WRONG_VALUE); 
          break; 
        } 
      } 
      testproc_good(pktp, group_vbp); 
      break; 
    default: 
      testproc_error(pktp, group_vbp, GEN_ERR); 
      return; 
    } 
  } 
} 
 
void 
  sysconfig_set(OIDC_T      lastmatch, 
                int         compc, 
                OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
  for ( ; vbp; vbp = vbp->vb_link) { 
    switch (vbp->vb_ml.ml_last_match) { 
    case LEAF_sysState: 
      sysState = VB_GET_INT32(vbp);                   /* !!! */ 
      setproc_good(pktp, vbp); 
      break; 
    case LEAF_sysUserName: 
      sysUserName = VB_GET_STRING(vbp);                   /* !!! */ 
      setproc_good(pktp, vbp); 
      break; 
    case LEAF_sysUserPassw: 
      sysUserPassw = VB_GET_STRING(vbp);                   /* !!! */ 
      setproc_good(pktp, vbp); 
      break; 
    default: 
      setproc_error(pktp, vbp, COMMIT_FAILED); 
      return; 
    } 
  } 
}

Example 6-4:  Augmented mibcomp Output

The following example shows demo.c after it has been augmented by a MIB designer, complete with method routines.

#include <asn1.h> 
#include <buffer.h> 
#include <mib.h> 
#include <localio.h> 
#include <snmpdefs.h> 
#include <snmp.h> 
#include <auxfuncs.h> 
#include "mibleaf.h" 
/* 
 * Method routines for the sysconfig variables: 
 * 
 *   sysState -- read-write 
 * The VxWorks target status is reported through this 
 * field.  The only valid state that this field can be 
 * set to is system-reboot.  The system will be rebooted 
 * five seconds after changing the state. 
 * 
 *   sysUserName -- read-write 
 * The user name the VxWorks target uses for remote 
 * machine access. 
 * 
 *   sysUserPassw -- read-write 
 * The user password the VxWorks target uses for remote 
 * machine access. 
 */ 
 
/* An internal routine to retrieve the values of the variables, used 
 * by the method routines sysconfig_get and sysconfig_next. 
 * You need to replace the type STRUCT_sysconfig with something 
 * appropriate to your system. */ 
 
 
/* ###############################################  
 
   This is a structure we define to set and retrieve the prameters 
   of thie sysconfig group 
*/ 
 
typedef  struct 
    { 
    int     sysState; 
    char    sysUserName [MAXSIZE_sysUserName + 1]; 
    char    sysUserPassw [MAXSIZE_sysUserPassw + 1]; 
    }  STRUCT_sysconfig; 
 
/* ############################################### 
   Define an instance of this structure.  
*/ 
 
 
 
 
static  STRUCT_sysconfig sysVars; 
 
/* This routine is a utility routine which will be used by both the  
   the get and the next method routine. It takes the STRUCT_sysconfig 
   structure we defined above as input and extracts the appropriate value  
   from it for installaltion into the response packet with the relevant 
   getproc procedure. This STRUCT_sysconfig structure would have been 
   filled in with the required value from within the get or next method 
   routine as appropriate. 
*/ 
 
static int 
  sysconfig_get_value(OIDC_T      lastmatch, 
                      SNMP_PKT_T *pktp, 
                      VB_T       *vbp, 
                      STRUCT_sysconfig *data)     /* !!! */ 
{ 
  switch(lastmatch) { 
 
  case LEAF_sysState: 
    /* Values: 
     *  system-running(1) = VAL_sysState_system_running 
     *  system-reboot(2)  = VAL_sysState_system_reboot 
     */ 
    getproc_got_int32(pktp, vbp, data->sysState);    /* !!! */ 
    break; 
 
  case LEAF_sysUserName: 
    /* if the data being returned is in dynamic storage and needs 
     * to be free'd, change the 0 argument to a 1. */ 
 
    getproc_got_string(pktp, vbp, strlen (data->sysUserName), 
                        data->sysUserName, 0, VT_STRING);    /* !!! */ 
    break; 
 
  case LEAF_sysUserPassw: 
    /* if the data being returned is in dynamic storage and needs 
     * to be free'd, change the 0 argument to a 1. */ 
    getproc_got_string(pktp, vbp, strlen(data->sysUserPassw), 
                        data->sysUserPassw, 0, VT_STRING);    /* !!! */ 
    break; 
 
  default: 
    return GEN_ERR; 
  } 
  return NO_ERROR; 
} 
 
/* This is the get method routine. After doing some checks on the 
   input varbind we retreive the required values with the appropriate  
   vxworks calls aand call the utility rtn defined above. 
*/ 
 
void 
  sysconfig_get(OIDC_T      lastmatch, 
                int         compc, 
                OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
  int              error; 
 
  /* find all the varbinds that share the same getproc and instance */ 
 
  snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
 
  /* check that the instance is exactly .0 */ 
  if (!((compc == 1) && (*compl == 0))) 
    { 
    for ( ; vbp; vbp = vbp->vb_link) 
      getproc_nosuchins(pktp, vbp); 
    return; 
    } 
 
  sysVars.sysState = VAL_sysState_system_running;  /* System is Running */ 
 
  /* Get data from vxWorks */ 
 
  remCurIdGet (sysVars.sysUserName, sysVars.sysUserPassw);    
 
 
  /* retrieve all the values from the same data structure */ 
 
  for ( ; vbp; vbp = vbp->vb_link) { 
    if ((error = sysconfig_get_value(vbp->vb_ml.ml_last_match, pktp,  
        vbp, &sysVars)) != NO_ERROR) 
      getproc_error(pktp, vbp, error); 
    } 
} 
 
 
/* The next method routine. It is similar to the get routine except the 
   check done is different  
 */ 
 
void 
  sysconfig_next(OIDC_T      lastmatch, 
                 int         compc, 
                 OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
  OIDC_T instance = 0; 
 
  /* the only time there's a next for a scalar is if we're given 
   * no instance at all. */ 
 
  if (compc != 0) 
    { 
    nextproc_no_next(pktp, vbp); 
    return; 
    } 
 
  sysVars.sysState = VAL_sysState_system_running;  /* System is Running */ 
 
  /* Get data from VxWorks */ 
  remCurIdGet (sysVars.sysUserName, sysVars.sysUserPassw);  
 
  for (snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
     vbp; vbp = vbp->vb_link) { 
     nextproc_next_instance(pktp, vbp, 1, &instance); 
     sysconfig_get_value(vbp->vb_ml.ml_last_match, pktp, vbp, &sysVars); 
  } 
} 
 
 
/* The test method routine. We perform a number fo checks on the  
* input varbinds to decide if the set should proceed or not 
*/ 
 
void 
  sysconfig_test(OIDC_T      lastmatch, 
                 int         compc, 
                 OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
  VB_T *group_vbp; 
 
  /* Only scalar variables here, check for .0 */ 
  if (!((compc == 1) && (*compl == 0))) { 
    testproc_error(pktp, vbp, NO_SUCH_NAME); 
    return; 
  } 
 
  /* find all the varbinds that share the same getproc and instance and 
   * group them together. */ 
 
  snmpdGroupByGetprocAndInstance(pktp, vbp, compc, compl); 
 
  /* now check each varbind */ 
 
  for (group_vbp = vbp; 
       group_vbp; 
       group_vbp = group_vbp->vb_link) { 
 
    switch (group_vbp->vb_ml.ml_last_match) { 
 
    case LEAF_sysState: 
 
      switch (VB_GET_INT32(group_vbp)) { 
      case VAL_sysState_system_reboot: 
        break; 
 
      case VAL_sysState_system_running: 
      default: 
        testproc_error(pktp, group_vbp, WRONG_VALUE); 
        continue; 
      } 
 
      testproc_good(pktp, group_vbp); 
      break; 
 
    case LEAF_sysUserName: 
 
      { long length = EBufferUsed(VB_GET_STRING(group_vbp)); 
 
        if (!((length >= MINSIZE_sysUserName) && 
              (length <= MAXSIZE_sysUserName))) { 
          testproc_error(pktp, group_vbp, WRONG_VALUE); 
          break; 
        } 
      } 
      testproc_good(pktp, group_vbp); 
      break; 
 
    case LEAF_sysUserPassw: 
 
      { long length = EBufferUsed(VB_GET_STRING(group_vbp)); 
 
        if (!((length >= MINSIZE_sysUserPassw) && 
              (length <= MAXSIZE_sysUserPassw))) { 
          testproc_error(pktp, group_vbp, WRONG_VALUE); 
          break; 
        } 
      } 
 
      testproc_good(pktp, group_vbp); 
      break; 
 
    default: 
      testproc_error(pktp, group_vbp, GEN_ERR); 
      return; 
    } 
  } 
} 
 
/* This routine reboots the VxWorks target. */ 
void snmpReboot () 
    { 
    printf("\007\007SNMP System Reboot Command in progress\n"); 
    taskDelay (200);    /* Wait 200 ticks before Reboot */ 
    reboot (0);         /* Reboot System */ 
    } 
  
 
void 
  sysconfig_set(OIDC_T      lastmatch, 
                int         compc, 
                OIDC_T     *compl, 
                SNMP_PKT_T *pktp, 
                VB_T       *vbp) 
{ 
 
  for ( ; vbp; vbp = vbp->vb_link) { 
 
    switch (vbp->vb_ml.ml_last_match) { 
 
    case LEAF_sysState: 
 
      sysVars.sysState = VB_GET_INT32(vbp);            
 
      if (taskSpawn ((char*)NULL, 150, VX_NO_STACK_FILL, 1024, 
                (FUNCPTR) snmpReboot, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR) 
          { 
          setproc_error (pktp, vbp, COMMIT_FAILED); 
          return; 
          } 
      else 
          { 
          setproc_good(pktp, vbp); 
          } 
      break; 
 
    case LEAF_sysUserName: 
 
      /* Get data from VxWorks */ 
      remCurIdGet (sysVars.sysUserName, sysVars.sysUserPassw); 
 
      (void) memcpy (sysVars.sysUserName, EBufferStart (VB_GET_STRING(vbp)), 
                     EBufferUsed (VB_GET_STRING(vbp))) ; 
      sysVars.sysUserName [EBufferUsed (VB_GET_STRING(vbp))] = '\0'; 
 
      /* Set data from VxWorks */ 
      remCurIdSet (sysVars.sysUserName, sysVars.sysUserPassw); 
 
      setproc_good(pktp, vbp); 
      break; 
 
    case LEAF_sysUserPassw: 
 
      /* Get data from VxWorks */ 
      remCurIdGet (sysVars.sysUserName, sysVars.sysUserPassw);  
 
      (void) memcpy (sysVars.sysUserPassw, EBufferStart (VB_GET_STRING(vbp)), 
                     EBufferUsed (VB_GET_STRING(vbp))); 
 
      sysVars.sysUserPassw [EBufferUsed (VB_GET_STRING(vbp))] = '\0'; 
 
      /* Set data from VxWorks */ 
      remCurIdSet (sysVars.sysUserName, sysVars.sysUserPassw); 
 
      setproc_good(pktp, vbp); 
      break; 
 
    default: 
      setproc_error(pktp, vbp, COMMIT_FAILED); 
      return; 
    } 
  } 
}

*   

Step 5:   Building the Agent

After the method routines have been written, the next step is to build the agent with the new MIB source. A makefile to help automate this task is provided. Be sure to copy the new MIB file into the agent directory (shown below), or to point to it on the command line.

Example 6-5:  Building the Agent

To rebuild for a SunOS host and an MVME147 target, first enter the following from your working MIB development directory:

% cp demo.c demo.mib $WIND_BASE/target/src/snmpv1/agent
% cd $WIND_BASE/target/src/snmpv1/agent

The build requires three variables: MIBSRC to specify the MIB information file(s); CPU to specify the target CPU type; and TOOL to specify the host tool chain. The CPU and TOOL values must be specified when invoking the make command. CPU and TOOL for a particular host and target can be determined by looking in the makefile provided in the target-specific BSP directory. Both of these values are defined in this file.

Edit your makefile and add demo.o (the object to build) to the make variable OBJ, and add demo.mib to the variable MIBSRC. Then enter:

% make CPU=MC68020 TOOL=gnu clean
% make CPU=MC68020 TOOL=gnu

Step 6:   Integrating the Agent into VxWorks

Rebuild VxWorks. Make sure the VxWorks SNMP agent is configured to be built into the VxWorks image (see 5. Configuring the WindNet SNMPv1/v2c Agent). The next time the target boots, the new variables should be included in the agent MIB.