Sample MIB Source File

The MIB source files perform the actual resolving of MIB variables. It contains the following header files: Windows.h, Snmp.h, and Testmib.h.

/*********************************************************************/
#include <windows.h>
#include <snmp.h>
#include "testmib.h"    // Contains definitions for the table structure
                        // describing the MIB. 
// If an addition or deletion to the MIB is necessary, there are 
// several places in the code that must be checked and possibly 
// changed. The last field in each MIB entry is used to point to the 
// NEXT leaf variable. If an addition or deletion is made, these 
// pointers might need to be updated to reflect the modification.

UINT OID_Prefix[] = {1, 3, 6, 1, 4, 1, 12};
                        // The prefix to all of these MIB variables is 
                        // 1.3.6.1.4.1.12
AsnObjectIdentifier MIB_OidPrefix = 
                                {OID_SIZEOF(OID_Prefix), OID_Prefix};
UINT MIB_toaster[] = {2};
                        
// Definition of leaf variables under the toaster group. All leaf 
// variables have a zero appended to their OID to indicate that it is 
// the only instance of this variable and that it exists.
UINT MIB_toasterManufacturer[] = {2, 1, 0};
UINT MIB_toasterModelNumber[]  = {2, 2, 0};
UINT MIB_toasterControl[]      = {2, 3, 0};
UINT MIB_toasterDoneness[]     = {2, 4, 0};
UINT MIB_toasterToastType[]    = {2, 5, 0};

// Storage definitions for MIB 
char MIB_toasterManStor[]      = "Microsoft Corporation";
char MIB_toasterModelStor[]    = 
          "Example SNMP Extension Agent for Windows CE (TOASTER-MIB).";
AsnInteger MIB_toasterControlStor   = 1;
AsnInteger MIB_toasterDonenessStor  = 2;
AsnInteger MIB_toasterToastTypeStor = 3;

// MIB definiton
MIB_ENTRY Mib[] = {
      {{OID_SIZEOF(MIB_toasterManufacturer), MIB_toasterManufacturer},
        &MIB_toasterManStor, ASN_RFC1213_DISPSTRING,
        MIB_ACCESS_READ, MIB_leaf_func, &Mib[1]},

      {{OID_SIZEOF(MIB_toasterModelNumber), MIB_toasterModelNumber},
        &MIB_toasterModelStor, ASN_RFC1213_DISPSTRING,
        MIB_ACCESS_READ, MIB_leaf_func, &Mib[2]},

      {{OID_SIZEOF(MIB_toasterControl), MIB_toasterControl},
        &MIB_toasterControlStor, ASN_INTEGER,
        MIB_ACCESS_READWRITE, MIB_control_func, &Mib[3]},

      {{OID_SIZEOF(MIB_toasterDoneness), MIB_toasterDoneness},
        &MIB_toasterDonenessStor, ASN_INTEGER,
        MIB_ACCESS_READWRITE, MIB_doneness_func, &Mib[4]},

      {{OID_SIZEOF(MIB_toasterToastType), MIB_toasterToastType},
        &MIB_toasterToastTypeStor, ASN_INTEGER,
        MIB_ACCESS_READWRITE, MIB_toasttype_func, NULL}};

UINT MIB_num_variables = sizeof Mib / sizeof (MIB_ENTRY);

/**********************************************************************
ResolveVarBind
  Resolves a single variable binding. Modifies the variable on a GET
  or a GET-NEXT.
**********************************************************************/
UINT ResolveVarBind (
    IN OUT RFC1157VarBind *VarBind, // Variable Binding to resolve
    IN UINT PduAction)              // Action that is specified in PDU
{
  MIB_ENTRY            *MibPtr;
  AsnObjectIdentifier  TempOid;
  int                  CompResult;
  UINT                 I;
  UINT                 nResult;

  // Search for var bind name in the MIB
  I      = 0;
  MibPtr = NULL;
  while (MibPtr == NULL && I < MIB_num_variables)
  {
    // Construct OID with complete prefix for comparison purposes
    SnmpUtilOidCpy (&TempOid, &MIB_OidPrefix);
    SnmpUtilOidAppend (&TempOid, &Mib[I].Oid);

    // Check for OID in MIB - On a GET-NEXT the OID does not have to 
    // match exactly a variable in the MIB, it must fall only under 
    // the MIB root.
    CompResult = SnmpUtilOidCmp (&VarBind->name, &TempOid);
    if (0 > CompResult)
    {
      // Because there is not an exact match, the only valid action is 
      // GET-NEXT
      if (MIB_ACTION_GETNEXT != PduAction)
      {
        nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Because the match was not exact, but varbind name is within MIB,
      // you are at the NEXT MIB variable down from the one that was specified.
      PduAction = MIB_ACTION_GET;
      MibPtr = &Mib[I];

      // Replace var bind name with new name
      SnmpUtilOidFree (&VarBind->name);
      SnmpUtilOidCpy (&VarBind->name, &MIB_OidPrefix);
      SnmpUtilOidAppend (&VarBind->name, &MibPtr->Oid);
    }
    else
    {
      // An exact match was found.
      if (0 == CompResult)
        MibPtr = &Mib[I];
    }

    // Free OID memory before checking another variable
    SnmpUtilOidFree (&TempOid);

    I++;
  } // while

  // If OID not within scope of MIB, then no such name
  if (MibPtr == NULL)
  {
    nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
    goto Exit;
  }

  // Call function to process request. Each MIB entry has a function 
  // pointer that knows how to process its MIB variable.
  nResult = (*MibPtr->MibFunc) (PduAction, MibPtr, VarBind);

  // Free temp memory
  SnmpUtilOidFree (&TempOid);

Exit:
   return nResult;
} // ResolveVarBind


/**********************************************************************
MIB_leaf_func
  Performs generic actions on LEAF variables in the MIB.
**********************************************************************/
UINT MIB_leaf_func (
    IN UINT Action,
    IN MIB_ENTRY *MibPtr,
    IN RFC1157VarBind *VarBind)
{
  UINT   ErrStat;

  switch (Action)
  {
    case MIB_ACTION_GETNEXT:
      // If there is no GET-NEXT pointer, this is the end of this MIB
      if (MibPtr->MibNext == NULL)
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Set up varbind name of NEXT MIB variable
      SnmpUtilOidFree (&VarBind->name);
      SnmpUtilOidCpy (&VarBind->name, &MIB_OidPrefix);
      SnmpUtilOidAppend (&VarBind->name, &MibPtr->MibNext->Oid);

      // Call function to process request.  Each MIB entry has a 
      // function pointer that knows how to process its MIB variable.
      ErrStat = (*MibPtr->MibNext->MibFunc) (MIB_ACTION_GET,
                  MibPtr->MibNext, VarBind);
      break;

    case MIB_ACTION_GET:
      // Make sure that this variable's ACCESS is GET'able
      if (MibPtr->Access != MIB_ACCESS_READ &&
          MibPtr->Access != MIB_ACCESS_READWRITE)    
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Set up varbind's return value
      VarBind->value.asnType = MibPtr->Type;
      switch (VarBind->value.asnType)
      {
        case ASN_RFC1155_COUNTER:
        case ASN_RFC1155_GAUGE:
        case ASN_INTEGER:
          VarBind->value.asnValue.number = 
                                * (AsnInteger *) (MibPtr->Storage);
          break;

        case ASN_OCTETSTRING: // Entails ASN_RFC1213_DISPSTRING also.
          VarBind->value.asnValue.string.length =
                                strlen ((LPSTR)MibPtr->Storage);

          if (NULL == (VarBind->value.asnValue.string.stream =
               SnmpUtilMemAlloc (VarBind->value.asnValue.string.length*
               sizeof (char))))
          {
            ErrStat = SNMP_ERRORSTATUS_GENERR;
            goto Exit;
          }

          memcpy (VarBind->value.asnValue.string.stream,
                  (LPSTR)MibPtr->Storage,
                  VarBind->value.asnValue.string.length);
          VarBind->value.asnValue.string.dynamic = TRUE;
          break;

        default:
          ErrStat = SNMP_ERRORSTATUS_GENERR;
          goto Exit;
      }
      break;

    case MIB_ACTION_SET:
      // Make sure that this variable's ACCESS is SET'able
      if (MibPtr->Access != MIB_ACCESS_READWRITE &&
      MibPtr->Access != MIB_ACCESS_WRITE)
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Check for proper type before setting
      if (MibPtr->Type != VarBind->value.asnType)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

      // Save value in MIB
      switch (VarBind->value.asnType)
      {
        case ASN_RFC1155_COUNTER:
        case ASN_RFC1155_GAUGE:
        case ASN_INTEGER:
          * (AsnInteger *) (MibPtr->Storage) = 
                                VarBind->value.asnValue.number;
          break;

        case ASN_OCTETSTRING: // Entails ASN_RFC1213_DISPSTRING also.
          // The storage must be adequate to contain the new string
          // including a NULL terminator.
          memcpy ((LPSTR)MibPtr->Storage,
                  VarBind->value.asnValue.string.stream,
                  VarBind->value.asnValue.string.length);
          ((LPSTR)MibPtr->Storage) 
                  [VarBind->value.asnValue.string.length] = '\0';
          break;

        default:
          ErrStat = SNMP_ERRORSTATUS_GENERR;       
          goto Exit;
      }
      break;

    default:
      ErrStat = SNMP_ERRORSTATUS_GENERR;
      goto Exit;
  } // switch

  // Signal no error occurred
  ErrStat = SNMP_ERRORSTATUS_NOERROR;

Exit:
  return ErrStat;
} // MIB_leaf_func


/**********************************************************************
MIB_control_func
  Performs specific actions on the toasterControl MIB variable
**********************************************************************/
UINT MIB_control_func (
    IN UINT Action,
    IN MIB_ENTRY *MibPtr,
    IN RFC1157VarBind *VarBind)
{
  UINT   ErrStat;

  switch (Action)
  {
    case MIB_ACTION_SET:
      // Make sure that this variable's ACCESS is SET'able
      if (MibPtr->Access != MIB_ACCESS_READWRITE &&
      MibPtr->Access != MIB_ACCESS_WRITE)
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Check for proper type before setting
      if (MibPtr->Type != VarBind->value.asnType)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

      // Make sure the value is valid
      if (MIB_TOASTER_UP > VarBind->value.asnValue.number ||
          MIB_TOASTER_DOWN < VarBind->value.asnValue.number)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }
      
    // Let fall through purposefully for further processing by
    // generic leaf function.
    case MIB_ACTION_GETNEXT:
    case MIB_ACTION_GET:
      // Call the more generic function to perform the action
      ErrStat = MIB_leaf_func (Action, MibPtr, VarBind);
      break;

    default:
      ErrStat = SNMP_ERRORSTATUS_GENERR;
      goto Exit;
  } // switch

Exit:
  return ErrStat;
} // MIB_control_func


/**********************************************************************
MIB_doneness_func
  Performs specific actions on the toasterDoneness MIB variable
**********************************************************************/
UINT MIB_doneness_func (
    IN UINT Action,
    IN MIB_ENTRY *MibPtr,
    IN RFC1157VarBind *VarBind)
{
  UINT   ErrStat;

  switch (Action)
  {
    case MIB_ACTION_SET:
      // Make sure that this variable's ACCESS is SET'able
      if (MibPtr->Access != MIB_ACCESS_READWRITE &&
      MibPtr->Access != MIB_ACCESS_WRITE)
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Check for proper type before setting
      if (MibPtr->Type != VarBind->value.asnType)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

      // Make sure the value is valid
      if (MIB_TOASTER_LIGHTLYWARM > VarBind->value.asnValue.number ||
          MIB_TOASTER_BURNT < VarBind->value.asnValue.number)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

    // Let fall through purposefully for further processing by
    // generic leaf function.
    case MIB_ACTION_GETNEXT:
    case MIB_ACTION_GET:
      // Call the more generic function to perform the action
      ErrStat = MIB_leaf_func (Action, MibPtr, VarBind);
      break;

    default:
      ErrStat = SNMP_ERRORSTATUS_GENERR;
      goto Exit;
  } // switch

Exit:
  return ErrStat;
} // MIB_doneness_func


/**********************************************************************
MIB_toasttype_func
  Performs specific actions on the toasterToastType MIB variable
**********************************************************************/
UINT MIB_toasttype_func (
  IN UINT Action,
  IN MIB_ENTRY *MibPtr,
  IN RFC1157VarBind *VarBind)
{
  UINT   ErrStat;

  switch (Action)
  {
    case MIB_ACTION_SET:
      // Make sure that this variable's ACCESS is SET'able
      if (MibPtr->Access != MIB_ACCESS_READWRITE &&
      MibPtr->Access != MIB_ACCESS_WRITE)
      {
        ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
        goto Exit;
      }

      // Check for proper type before setting
      if (MibPtr->Type != VarBind->value.asnType)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

      // Make sure the value is valid
      if (MIB_TOASTER_WHITEBREAD > VarBind->value.asnValue.number ||
          MIB_TOASTER_OTHERBREAD < VarBind->value.asnValue.number)
      {
        ErrStat = SNMP_ERRORSTATUS_BADVALUE;
        goto Exit;
      }

    // Let fall through purposefully for further processing by
    // generic leaf function.
    case MIB_ACTION_GETNEXT:
    case MIB_ACTION_GET:
      // Call the more generic function to perform the action
      ErrStat = MIB_leaf_func (Action, MibPtr, VarBind);
      break;

    default:
      ErrStat = SNMP_ERRORSTATUS_GENERR;
      goto Exit;
  } // switch

Exit:
  return ErrStat;
} // MIB_toasttype_func

See Also

Developing a MIB

 Last updated on Saturday, April 10, 2004

© 1992-2003 Microsoft Corporation. All rights reserved.