windows-nt/Source/XPSP1/NT/net/dhcp/dhcpmib/dhcpmib.c
2020-09-26 16:20:57 +08:00

1544 lines
44 KiB
C

/*++ BUILD Version: 0001 // Increment this if a change has global effects
Copyright (c) 1991 Microsoft Corporation
Module Name:
dhcpmib.c
Abstract:
DHCP SNMP Extension Agent for Windows NT.
These files (dhcpmibm.c, dhcpmib.c, and dhcpmib.h) provide an example of
how to structure an Extension Agent DLL which works in conjunction with
the SNMP Extendible Agent for Windows NT.
Extensive comments have been included to describe its structure and
operation. See also "Microsoft Windows/NT SNMP Programmer's Reference".
Created:
15-Jan-1994
Revision History:
Pradeep Bahl 1/11/94
--*/
// This Extension Agent implements the DHCP MIB. It's
// definition follows here:
//
//
// Necessary includes.
#include <stdio.h>
#include <stdlib.h>
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <winbase.h> //for SYSTEMTIME def
#include <rpc.h>
#include "dhcpapi.h"
#include <string.h>
#include <time.h>
#include <search.h>
// Contains definitions for the table structure describing the MIB. This
// is used in conjunction with winsmib.c where the MIB requests are resolved.
#include "dhcpmib.h"
// 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 deletetion is made, these pointers
// may need to be updated to reflect the modification.
#define LOCAL_ADD L"127.0.0.1"
//
// Used by MIBStat
//
#define TMST(x) x.wHour,\
x.wMinute,\
x.wSecond,\
x.wMonth,\
x.wDay,\
x.wYear
#define PRINTTIME(Var, x) sprintf(Var, "%02u:%02u:%02u on %02u:%02u:%04u.\n", TMST(x))
//
// All MIB variables in the common group have 1 as their first id
//
#define COMMON_VAL_M(pMib) ((pMib)->Oid.ids[0] == 1)
//
// All MIB variables in the scope group have 2 as their first id
//
#define SCOPE_VAL_M(pMib) ((pMib)->Oid.ids[0] == 2)
static LPDHCP_MIB_INFO spMibInfo = NULL;
//
// The prefix to all of the DHCP MIB variables is 1.3.6.1.4.1.311.1.3
//
// The last digit -- 3 is for the DHCP MIB
//
UINT OID_Prefix[] = { 1, 3, 6, 1, 4, 1, 311, 1, 3 };
AsnObjectIdentifier MIB_OidPrefix = { OID_SIZEOF(OID_Prefix), OID_Prefix };
BOOL fDhcpMibVarsAccessed = FALSE;
//
// Definition of the Dhcp MIB (not used)
//
//UINT MIB_Dhcp[] = { 3 };
//
// OID definitions for MIB
//
//
// Definition of group and leaf variables under the wins group
// All leaf variables have a zero appended to their OID to indicate
// that it is the only instance of this variable and it exists.
//
UINT MIB_Parameters[] = { 1 };
UINT MIB_DhcpStartTime[] = { 1, 1, 0 };
UINT MIB_NoOfDiscovers[] = { 1, 2, 0 };
UINT MIB_NoOfRequests[] = { 1, 3, 0 };
UINT MIB_NoOfReleases[] = { 1, 4, 0 };
UINT MIB_NoOfOffers[] = { 1, 5, 0 };
UINT MIB_NoOfAcks[] = { 1, 6, 0 };
UINT MIB_NoOfNacks[] = { 1, 7, 0 };
UINT MIB_NoOfDeclines[] = { 1, 8, 0 };
//
// Scope table
//
UINT MIB_Scope[] = { 2 };
UINT MIB_ScopeTable[] = { 2, 1};
UINT MIB_ScopeTableEntry[] = { 2, 1, 1};
//
// //
// Storage definitions for MIB //
// //
char MIB_DhcpStartTimeStore[80];
AsnCounter MIB_NoOfDiscoversStore;
AsnCounter MIB_NoOfRequestsStore;
AsnCounter MIB_NoOfReleasesStore;
AsnCounter MIB_NoOfOffersStore;
AsnCounter MIB_NoOfAcksStore;
AsnCounter MIB_NoOfNacksStore;
AsnCounter MIB_NoOfDeclinesStore;
static
UINT
MIB_Table(
IN DWORD Index,
IN UINT Action,
IN PMIB_ENTRY pMibPtr,
IN RFC1157VarBind *VarBind
);
static
UINT
ScopeTable(
IN UINT Action,
IN PMIB_ENTRY pMibPtr,
IN RFC1157VarBind *VarBind
);
static
UINT
MIB_leaf_func(
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
);
static
UINT
MIB_Stat(
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
);
static
DWORD
GetMibInfo (
LPWSTR DhcpAdd,
LPDHCP_MIB_INFO *ppMibInfo
);
//
// MIB definiton
//
MIB_ENTRY Mib[] = {
//parameters
{ { OID_SIZEOF(MIB_Parameters), MIB_Parameters },
NULL, ASN_RFC1155_OPAQUE,
MIB_NOACCESS, NULL, &Mib[1] },
{ { OID_SIZEOF(MIB_DhcpStartTime), MIB_DhcpStartTime },
&MIB_DhcpStartTimeStore, ASN_RFC1213_DISPSTRING,
MIB_ACCESS_READ, MIB_Stat, &Mib[2] },
{ { OID_SIZEOF(MIB_NoOfDiscovers), MIB_NoOfDiscovers },
&MIB_NoOfDiscoversStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[3] },
{ { OID_SIZEOF(MIB_NoOfRequests), MIB_NoOfRequests },
&MIB_NoOfRequestsStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[4] },
{ { OID_SIZEOF(MIB_NoOfReleases), MIB_NoOfReleases },
&MIB_NoOfReleasesStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[5] },
{ { OID_SIZEOF(MIB_NoOfOffers), MIB_NoOfOffers },
&MIB_NoOfOffersStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[6] },
{ { OID_SIZEOF(MIB_NoOfAcks), MIB_NoOfAcks },
&MIB_NoOfAcksStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[7] },
{ { OID_SIZEOF(MIB_NoOfNacks), MIB_NoOfNacks },
&MIB_NoOfNacksStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[8] },
{ { OID_SIZEOF(MIB_NoOfDeclines), MIB_NoOfDeclines },
&MIB_NoOfDeclinesStore, ASN_RFC1155_COUNTER,
MIB_ACCESS_READ, MIB_Stat, &Mib[9] },
//
// Scope
//
{ { OID_SIZEOF(MIB_Scope), MIB_Scope },
NULL, ASN_RFC1155_OPAQUE,
MIB_NOACCESS, NULL, &Mib[10] },
{ { OID_SIZEOF(MIB_ScopeTable), MIB_ScopeTable },
NULL, ASN_RFC1155_OPAQUE,
MIB_ACCESS_READ, NULL, &Mib[11] },
{ { OID_SIZEOF(MIB_ScopeTableEntry), MIB_ScopeTableEntry },
NULL, ASN_SEQUENCE,
MIB_ACCESS_READ, ScopeTable, NULL }
};
//
// defines pertaining to tables
//
#define SCOPE_OIDLEN (MIB_PREFIX_LEN + OID_SIZEOF(MIB_ScopeTableEntry))
#define NO_FLDS_IN_SCOPE_ROW 4
#define SCOPE_TABLE_INDEX 0
#define NUM_TABLES sizeof(Tables)/sizeof(TAB_INFO_T)
UINT MIB_num_variables = sizeof Mib / sizeof( MIB_ENTRY );
//
// table structure containing the functions to invoke for different actions
// on the table
//
typedef struct _TAB_INFO_T {
UINT (*ti_get)(
RFC1157VarBind *VarBind
);
UINT (*ti_getf)(
RFC1157VarBind *VarBind,
PMIB_ENTRY pMibEntry
);
UINT (*ti_getn)(
RFC1157VarBind *VarBind,
PMIB_ENTRY pMibEntry
);
UINT (*ti_set)(
RFC1157VarBind *VarBind
);
PMIB_ENTRY pMibPtr;
} TAB_INFO_T, *PTAB_INFO_T;
static
UINT
ScopeGetNext(
IN RFC1157VarBind *VarBind,
IN PMIB_ENTRY pMibPtr
);
static
UINT
ScopeGet(
IN RFC1157VarBind *VarBind
);
static
UINT
ScopeGetFirst(
IN RFC1157VarBind *VarBind,
IN PMIB_ENTRY pMibPtr
);
static
UINT
ScopeMatch(
IN RFC1157VarBind *VarBind,
IN LPDWORD pIndex,
IN LPDWORD pField,
IN UINT PduAction,
IN LPBOOL pfFirst
);
extern
UINT
ScopeFindNext(
INT SubnetIndex
);
static
int
__cdecl
CompareScopes(
const VOID *pKey1,
const VOID *pKey2
);
static
UINT
GetNextVar(
IN RFC1157VarBind *pVarBind,
IN PMIB_ENTRY pMibPtr
);
TAB_INFO_T Tables[] = {
ScopeGet,
ScopeGetFirst,
ScopeGetNext,
NULL,
&Mib[11]
};
UINT
ResolveVarBind(
IN OUT RFC1157VarBind *VarBind, // Variable Binding to resolve
IN UINT PduAction // Action specified in PDU
)
//
// ResolveVarBind
// Resolves a single variable binding. Modifies the variable on a GET
// or a GET-NEXT.
//
// Notes:
//
// Return Codes:
// Standard PDU error codes.
//
// Error Codes:
// None.
//
{
MIB_ENTRY *MibPtr;
AsnObjectIdentifier TempOid;
int CompResult;
UINT I;
UINT nResult;
DWORD TableIndex;
BOOL fTableMatch = FALSE;
//
// Check the Tables array
//
// See if the prefix of the variable matches the prefix of
// any of the tables
//
for (TableIndex = 0; TableIndex < NUM_TABLES; TableIndex++)
{
//
// Construct OID with complete prefix for comparison purposes
//
SnmpUtilOidCpy( &TempOid, &MIB_OidPrefix );
SnmpUtilOidAppend( &TempOid, &Tables[TableIndex].pMibPtr->Oid );
//
// is there a match with the prefix oid of a table entry
//
if (
SnmpUtilOidNCmp(
&VarBind->name,
&TempOid,
MIB_PREFIX_LEN +
Tables[TableIndex].pMibPtr->Oid.idLength
) == 0
)
{
//
// the prefix string of the var. matched the oid
// of a table.
//
MibPtr = Tables[TableIndex].pMibPtr;
fTableMatch = TRUE;
break;
}
// Free OID memory before checking with another table entry
SnmpUtilOidFree( &TempOid );
}
//
// There was an exact match with a table entry's prefix.
//
if ( fTableMatch)
{
if (
(SnmpUtilOidCmp(
&VarBind->name,
&TempOid
) == 0)
)
{
//
// The oid specified is a prefix of a table entry. if the operation
// is not GETNEXT, return NOSUCHNAME
//
if (PduAction != MIB_GETNEXT)
{
SnmpUtilOidFree( &TempOid );
nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
goto Exit;
}
else
{
UINT TableEntryIds[1];
AsnObjectIdentifier TableEntryOid = {
OID_SIZEOF(TableEntryIds), TableEntryIds };
//
// Replace var bind name with new name
//
//
// A sequence item oid always starts with a field no.
// The first item has a field no of 1.
//
TableEntryIds[0] = 1;
SnmpUtilOidAppend( &VarBind->name, &TableEntryOid);
//
// Get the first entry in the table
//
PduAction = MIB_GETFIRST;
}
}
SnmpUtilOidFree( &TempOid );
//
// if there was no exact match with a prefix entry, then we
// don't touch the PduAction value specified.
//
}
else
{
//
// There was no match with any table entry. Let us see if there is
// a match with a group entry, a table, or a leaf variable
//
//
// 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 exactly
// match a variable in the MIB, it must only fall under the MIB root.
//
CompResult = SnmpUtilOidCmp( &VarBind->name, &TempOid );
//
// If CompResult is negative, the only valid operation is GET_NEXT
//
if ( CompResult < 0)
{
//
// This could be the oid of a leaf (without a 0)
// or it could be an invalid oid (in between two valid oids)
// The next oid might be that of a group or a table or table
// entry. In that case, we do not change the PduAction
//
if (PduAction == MIB_GETNEXT)
{
MibPtr = &Mib[I];
SnmpUtilOidFree( &VarBind->name );
SnmpUtilOidCpy( &VarBind->name, &MIB_OidPrefix );
SnmpUtilOidAppend( &VarBind->name, &MibPtr->Oid );
if (
(MibPtr->Type != ASN_RFC1155_OPAQUE)
&&
(MibPtr->Type != ASN_SEQUENCE)
)
{
PduAction = MIB_GET;
}
}
else
{
nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
SnmpUtilOidFree( &TempOid );
goto Exit;
}
SnmpUtilOidFree( &TempOid );
break;
}
else
{
//
// An exact match was found ( a group, table, or leaf).
//
if ( CompResult == 0)
{
MibPtr = &Mib[I];
}
}
//
// Free OID memory before checking another variable
//
SnmpUtilOidFree( &TempOid );
I++;
} // while
} // end of else
//
// if there was a match
//
if (MibPtr != NULL)
{
//
// the function will be NULL only if the match was with a group
// or a sequence (table). If the match was with a table entry
// (entire VarBind string match or partial string match), we
// function would be a table function
//
if (MibPtr->MibFunc == NULL)
{
if(PduAction != MIB_GETNEXT)
{
nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
goto Exit;
}
else
{
//
// Get the next variable which allows access
//
nResult = GetNextVar(VarBind, MibPtr);
goto Exit;
}
}
}
else
{
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 );
Exit:
return nResult;
} // ResolveVarBind
//
// MIB_leaf_func
// Performs generic actions on LEAF variables in the MIB.
//
// Notes:
//
// Return Codes:
// Standard PDU error codes.
//
// Error Codes:
// None.
//
UINT MIB_leaf_func(
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
)
{
UINT ErrStat;
switch ( Action )
{
case MIB_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;
}
ErrStat = GetNextVar(VarBind, MibPtr);
if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
{
goto Exit;
}
break;
case MIB_GETFIRST: // fall through
case MIB_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_NOACCESS;
goto Exit;
}
// Setup varbind's return value
VarBind->value.asnType = MibPtr->Type;
switch ( VarBind->value.asnType )
{
case ASN_RFC1155_COUNTER:
VarBind->value.asnValue.number = *(AsnCounter *)(MibPtr->Storage);
break;
case ASN_RFC1155_GAUGE:
case ASN_INTEGER:
VarBind->value.asnValue.number = *(AsnInteger *)(MibPtr->Storage);
break;
case ASN_RFC1155_IPADDRESS:
//
// fall through
//
case ASN_OCTETSTRING:
if (VarBind->value.asnType == ASN_RFC1155_IPADDRESS)
{
VarBind->value.asnValue.string.length = 4;
}
else
{
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_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_NOTWRITABLE;
goto Exit;
}
// Check for proper type before setting
if ( MibPtr->Type != VarBind->value.asnType )
{
ErrStat = SNMP_ERRORSTATUS_WRONGTYPE;
goto Exit;
}
// Save value in MIB
switch ( VarBind->value.asnType )
{
case ASN_RFC1155_COUNTER:
*(AsnCounter *)(MibPtr->Storage) = VarBind->value.asnValue.number;
break;
case ASN_RFC1155_GAUGE:
case ASN_INTEGER:
*(AsnInteger *)(MibPtr->Storage) = VarBind->value.asnValue.number;
break;
case ASN_RFC1155_IPADDRESS:
//
// fall through
//
case ASN_OCTETSTRING:
// 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';
if ( VarBind->value.asnValue.string.dynamic)
{
SnmpUtilMemFree( VarBind->value.asnValue.string.stream);
}
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_Stat
// Performs specific actions on the different MIB variable
//
// Notes:
//
// Return Codes:
// Standard PDU error codes.
//
// Error Codes:
// None.
//
UINT MIB_Stat(
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
)
{
DWORD Status;
UINT ErrStat;
SYSTEMTIME DhcpStartTime;
switch ( Action )
{
case MIB_SET:
ErrStat = MIB_leaf_func( Action, MibPtr, VarBind );
break;
case MIB_GETNEXT:
ErrStat = MIB_leaf_func( Action, MibPtr, VarBind );
break;
case MIB_GETFIRST:
//
// fall through
//
case MIB_GET:
//
// Call the DhcpStatus function to get the statistics
//
Status = GetMibInfo(LOCAL_ADD, &spMibInfo);
if (Status == ERROR_SUCCESS)
{
if (FileTimeToSystemTime(
(FILETIME *)&spMibInfo->ServerStartTime,
&DhcpStartTime
) == FALSE)
{
goto Exit;
}
if (MibPtr->Storage == &MIB_DhcpStartTimeStore)
{
PRINTTIME(MIB_DhcpStartTimeStore, DhcpStartTime);
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfDiscoversStore)
{
MIB_NoOfDiscoversStore = spMibInfo->Discovers;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfRequestsStore)
{
MIB_NoOfRequestsStore = spMibInfo->Requests;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfReleasesStore)
{
MIB_NoOfReleasesStore = spMibInfo->Releases;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfOffersStore)
{
MIB_NoOfOffersStore = spMibInfo->Offers;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfAcksStore)
{
MIB_NoOfAcksStore = spMibInfo->Acks;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfNacksStore)
{
MIB_NoOfNacksStore = spMibInfo->Naks;
goto LEAF1;
}
if (MibPtr->Storage == &MIB_NoOfDeclinesStore)
{
MIB_NoOfNacksStore = spMibInfo->Naks;
goto LEAF1;
}
ErrStat = SNMP_ERRORSTATUS_GENERR;
goto Exit;
}
else
{
printf("Error from DhcpStatus = (%d)\n", Status);
ErrStat = (Status == RPC_S_SERVER_UNAVAILABLE) ?
SNMP_ERRORSTATUS_NOSUCHNAME :
SNMP_ERRORSTATUS_GENERR;
goto Exit;
}
LEAF1:
// 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_Stat
DWORD GetMibInfo (
LPWSTR DhcpAdd,
LPDHCP_MIB_INFO *ppMibInfo
)
{
DWORD Status = ERROR_SUCCESS;
if (!fDhcpMibVarsAccessed)
{
//
// The Dhcp server does a single node allocation. So we
// we need to free only spMibInfo.
//
if (spMibInfo != NULL)
{
#if 0
if (spMibInfo->ScopeInfo != NULL)
{
DhcpRpcFreeMemory(spMibInfo->ScopeInfo);
spMibInfo->ScopeInfo = NULL;
}
#endif
DhcpRpcFreeMemory(spMibInfo);
spMibInfo = NULL;
}
Status = DhcpGetMibInfo(LOCAL_ADD, &spMibInfo);
if (Status == ERROR_SUCCESS)
{
if (spMibInfo->Scopes > 1)
{
ASSERT(spMibInfo->ScopeInfo != NULL);
qsort(spMibInfo->ScopeInfo,(size_t)spMibInfo->Scopes,
sizeof(SCOPE_MIB_INFO),CompareScopes );
}
fDhcpMibVarsAccessed = TRUE;
}
else
{
fDhcpMibVarsAccessed = FALSE;
}
}
return(Status);
}
int
__cdecl
CompareScopes(
const VOID *pKey1,
const VOID *pKey2
)
{
const LPSCOPE_MIB_INFO pScopeKey1 = (LPSCOPE_MIB_INFO)pKey1;
const LPSCOPE_MIB_INFO pScopeKey2 = (LPSCOPE_MIB_INFO)pKey2;
if( pScopeKey1->Subnet < pScopeKey2->Subnet)
return -1;
if (pScopeKey1->Subnet != pScopeKey2->Subnet )
return 1;
return 0;
}
UINT
GetNextVar(
IN RFC1157VarBind *pVarBind,
IN MIB_ENTRY *pMibPtr
)
{
UINT ErrStat;
while (pMibPtr != NULL)
{
if (pMibPtr->MibNext != NULL)
{
//
// Setup var bind name of NEXT MIB variable
//
SnmpUtilOidFree( &pVarBind->name );
SnmpUtilOidCpy( &pVarBind->name, &MIB_OidPrefix );
SnmpUtilOidAppend( &pVarBind->name, &pMibPtr->MibNext->Oid );
//
// If the func. ptr is NULL and the type of the mib variable
// is anything but OPAQUE, call function to process the
// MIB variable
//
if (
(pMibPtr->MibNext->MibFunc != NULL)
&&
(pMibPtr->MibNext->Type != ASN_RFC1155_OPAQUE)
)
{
ErrStat = (*pMibPtr->MibNext->MibFunc)( MIB_GETFIRST,
pMibPtr->MibNext, pVarBind );
if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
{
goto Exit;
}
break;
}
else
{
pMibPtr = pMibPtr->MibNext;
}
}
else
{
ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
break;
}
}
if (pMibPtr == NULL)
{
ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
}
Exit:
return(ErrStat);
}
UINT
ScopeTable(
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
)
{
DWORD status;
if (Action == MIB_SET)
{
return(SNMP_ERRORSTATUS_READONLY);
}
//
// if the length indicates a 0 or partial key, then only the get next
// operation is allowed. The field and the full key
// have a length of 5
//
if (VarBind->name.idLength <= (SCOPE_OIDLEN + 4))
{
if ((Action == MIB_GET) || (Action == MIB_SET))
{
return(SNMP_ERRORSTATUS_NOSUCHNAME);
}
}
status = GetMibInfo(LOCAL_ADD, &spMibInfo);
if (status != ERROR_SUCCESS)
{
if (Action == MIB_GETNEXT)
{
return(GetNextVar(VarBind, MibPtr));
}
else
{
return (status == RPC_S_SERVER_UNAVAILABLE) ?
SNMP_ERRORSTATUS_NOSUCHNAME :
SNMP_ERRORSTATUS_GENERR;
}
}
return( MIB_Table(SCOPE_TABLE_INDEX, Action, MibPtr, VarBind) );
}
UINT
MIB_Table(
IN DWORD Index,
IN UINT Action,
IN MIB_ENTRY *MibPtr,
IN RFC1157VarBind *VarBind
)
{
UINT ErrStat;
switch(Action)
{
case(MIB_GET):
ErrStat = (*Tables[Index].ti_get)(VarBind);
break;
case(MIB_GETFIRST):
ErrStat = (*Tables[Index].ti_getf)(VarBind, MibPtr);
break;
case(MIB_GETNEXT):
ErrStat = (*Tables[Index].ti_getn)(VarBind, MibPtr);
break;
case(MIB_SET):
ErrStat = (*Tables[Index].ti_set)(VarBind);
break;
default:
ErrStat = SNMP_ERRORSTATUS_GENERR;
break;
}
return(ErrStat);
} //MIB_Table
UINT
ScopeGet(
IN RFC1157VarBind *VarBind
)
{
UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
DWORD Field;
DWORD Index;
LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
ErrStat = ScopeMatch(VarBind, &Index, &Field, MIB_GET, NULL);
if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
{
return(ErrStat);
}
switch(Field)
{
case 1: //subnet itself
VarBind->value.asnType = ASN_RFC1155_IPADDRESS;
VarBind->value.asnValue.string.length = sizeof(ULONG);
if ( NULL ==
(VarBind->value.asnValue.string.stream =
SnmpUtilMemAlloc(VarBind->value.asnValue.string.length
)) )
{
ErrStat = SNMP_ERRORSTATUS_GENERR;
goto Exit;
}
//
// SNMP expects the MSB to be in the first byte, MSB-1
// to be in the second, ....
//
VarBind->value.asnValue.string.stream[0] =
(BYTE)((pScope + Index)->Subnet >> 24);
VarBind->value.asnValue.string.stream[1] =
(BYTE)(((pScope + Index)->Subnet >> 16) & 0xFF);
VarBind->value.asnValue.string.stream[2] =
(BYTE)(((pScope + Index)->Subnet >> 8) & 0xFF);
VarBind->value.asnValue.string.stream[3] =
(BYTE)((pScope + Index)->Subnet & 0xFF );
VarBind->value.asnValue.address.dynamic = TRUE;
break;
case 2: // NumAddressesInUse
VarBind->value.asnType = ASN_RFC1155_COUNTER;
VarBind->value.asnValue.number =
(AsnCounter)((pScope + Index)->
NumAddressesInuse);
break;
case 3: // NumAddressesFree
VarBind->value.asnType = ASN_RFC1155_COUNTER;
VarBind->value.asnValue.number =
(AsnCounter)((pScope + Index)->
NumAddressesFree);
break;
case 4: // NumPendingOffers
VarBind->value.asnType = ASN_RFC1155_COUNTER;
VarBind->value.asnValue.number =
(AsnCounter)((pScope + Index)->
NumPendingOffers);
break;
default:
ErrStat = SNMP_ERRORSTATUS_BADVALUE;
break;
}
Exit:
return(ErrStat);
} // ScopeGet
UINT
ScopeGetNext(
IN RFC1157VarBind *VarBind,
IN MIB_ENTRY *MibPtr
)
{
DWORD OidIndex;
INT Index;
DWORD FieldNo;
UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
BOOL fFirst;
LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
//
// Check if the name passed matches any in the table (i.e. table of
// of ADD_KEY_T structures. If there is a match, the address
// of the ip address key and the matching field's no. are returned
//
ErrStat = ScopeMatch(VarBind, &Index, &FieldNo, MIB_GETNEXT, &fFirst);
if (
(ErrStat != SNMP_ERRORSTATUS_NOERROR)
&&
(ErrStat != SNMP_ERRORSTATUS_NOSUCHNAME)
)
{
return(GetNextVar(VarBind, MibPtr));
}
//
// We were passed an oid that is less than all oids in the table. Set
// the Index to -1 so that we retrieve the first record in the table
//
if (fFirst)
{
Index = -1;
}
//
// Since the operation is GETNEXT, get the next IP address (i.e. one
// that is lexicographically bigger. If there is none, we must increment
// the field value and move back to the lexically first item in the table
// If the new field value is more than the largest supported, we call
// the MibFunc of the next MIB entry.
//
if ((Index = ScopeFindNext(Index)) < 0)
{
//
// if we were trying to retrieve the second or subsequent record
// we must increment the field number nd get the first record in
// the table. If we were retrieving the first record, then
// we should get the next var.
//
if (!fFirst)
{
Index = ScopeFindNext(-1);
}
else
{
return(GetNextVar(VarBind, MibPtr));
}
//
// If either there is no entry in the table or if we have
// exhausted all fields of the entry, call the function
// of the next mib entry.
//
if (
(++FieldNo > NO_FLDS_IN_SCOPE_ROW) || (Index < 0)
)
{
return(GetNextVar(VarBind, MibPtr));
}
}
if (VarBind->name.idLength <= (SCOPE_OIDLEN + 4))
{
UINT TableEntryIds[5]; //field and subnet mask have a length of 5
AsnObjectIdentifier TableEntryOid = {OID_SIZEOF(TableEntryIds),
TableEntryIds };
SnmpUtilOidFree( &VarBind->name);
SnmpUtilOidCpy(&VarBind->name, &MIB_OidPrefix);
SnmpUtilOidAppend(&VarBind->name, &MibPtr->Oid);
TableEntryIds[0] = (UINT)FieldNo;
OidIndex = 1;
TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 24);
TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 16 & 0xFF);
TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 8 & 0xFF);
TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet & 0xFF);
TableEntryOid.idLength = OidIndex;
SnmpUtilOidAppend(&VarBind->name, &TableEntryOid);
}
else
{
//
// The fixed part of the objid is corect. Update the rest.
//
OidIndex = SCOPE_OIDLEN;
VarBind->name.ids[OidIndex++] = (UINT)FieldNo;
VarBind->name.ids[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 24);
VarBind->name.ids[OidIndex++] = (UINT)(((pScope + Index)->Subnet >> 16) & 0xFF);
VarBind->name.ids[OidIndex++] = (UINT)(((pScope + Index)->Subnet >> 8) & 0xFF);
VarBind->name.ids[OidIndex++] = (UINT)((pScope + Index)->Subnet & 0xFF);
VarBind->name.idLength = OidIndex;
}
//
// Get the value
//
ErrStat = ScopeGet(VarBind);
return(ErrStat);
}
UINT
ScopeMatch(
IN RFC1157VarBind *VarBind,
IN LPDWORD pIndex,
IN LPDWORD pField,
IN UINT PduAction,
IN LPBOOL pfFirst
)
{
DWORD OidIndex;
DWORD Index;
DWORD ScopeIndex;
DWORD Add = 0;
UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
INT CmpVal;
DWORD AddLen;
LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
ASSERT(PduAction != MIB_SET);
if (pfFirst != NULL)
{
*pfFirst = FALSE;
}
//
// If there are no keys, return error
//
if (spMibInfo->Scopes == 0)
{
if (PduAction == MIB_GETNEXT)
{
*pfFirst = TRUE;
}
else
{
ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
}
goto Exit;
}
//
// fixed part of the PullPnr table entries
//
OidIndex = SCOPE_OIDLEN;
//
// if the field specified is more than the max. in the table entry
// barf
//
if (
(*pField = VarBind->name.ids[OidIndex++]) >
(DWORD)NO_FLDS_IN_SCOPE_ROW
)
{
if (PduAction == MIB_GETNEXT)
{
*pIndex = spMibInfo->Scopes - 1;
goto Exit;
}
else
{
ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
goto Exit;
}
}
//
// get the length of key specified
//
AddLen = VarBind->name.idLength - (SCOPE_OIDLEN + 1);
ScopeIndex = OidIndex;
for (Index = 0; Index < AddLen; Index++)
{
Add = Add | (((BYTE)(VarBind->name.ids[ScopeIndex++])) << (24 - (Index * 8)));
}
//
// Check if the address specified matches with one of the keys
//
for (Index = 0; Index < spMibInfo->Scopes; Index++, pScope++)
{
if (Add == pScope->Subnet)
{
*pIndex = Index;
return(SNMP_ERRORSTATUS_NOERROR);
}
else
{
//
// if passed in value is greater, continue on to
// the next item. The list is in ascending order
//
if (Add > pScope->Subnet)
{
continue;
}
else
{
//
// the list element is > passed in value,
// break out of the loop
//
break;
}
}
}
//
// if no match, but field is GetNext, return the (highest index - 1)
// reached above. This is because, ScopeFindNext will be called by
// the caller
//
if (PduAction == MIB_GETNEXT)
{
if (Index == 0)
{
*pfFirst = TRUE;
}
else
{
*pIndex = Index - 1;
}
ErrStat = SNMP_ERRORSTATUS_NOERROR;
}
else
{
ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
}
Exit:
return(ErrStat);
}
UINT
ScopeFindNext(
INT SubKeyIndex
)
{
DWORD i;
LONG nextif;
LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
//
// if SubKeyIndex is 0 or more, search for the key next to
// the key passed.
//
for (nextif = -1, i = 0 ; i < spMibInfo->Scopes; i++)
{
if (SubKeyIndex >= 0)
{
if (
(pScope + i)->Subnet <=
(pScope + SubKeyIndex)->Subnet
)
{
//
// This item is lexicographically less or equal,
// continue
//
continue;
}
else
{
//
// We found an item that is > than the item indicated
// to us. Break out of the loop
//
nextif = i;
break;
}
}
else
{
#if 0
//
// if we want the first entry, then continue until
// we get an entry that is lexicographically same or
// greater
//
if (
(nextif < 0)
||
(pScope + (i - 1))->Subnet < (pScope + nextif)->Subnet
)
{
nextif = i;
}
#endif
nextif = 0;
break;
}
}
return(nextif);
}
UINT
ScopeGetFirst(
IN RFC1157VarBind *VarBind,
IN MIB_ENTRY *MibPtr
)
{
LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
INT Iface;
UINT TableEntryIds[5];
AsnObjectIdentifier TableEntryOid = { OID_SIZEOF(TableEntryIds),
TableEntryIds };
UINT ErrStat;
//
// If there is no entry in the table, go to the next MIB variable
//
if (spMibInfo->Scopes == 0)
{
return(GetNextVar(VarBind, MibPtr));
}
//
// Get the first entry in the table
//
Iface = ScopeFindNext(-1);
//
// Write the object Id into the binding list and call get
// func
//
SnmpUtilOidFree( &VarBind->name );
SnmpUtilOidCpy( &VarBind->name, &MIB_OidPrefix );
SnmpUtilOidAppend( &VarBind->name, &MibPtr->Oid );
//
// The fixed part of the objid is correct. Update the rest.
//
TableEntryIds[0] = 1;
TableEntryIds[1] = (UINT)((pScope + Iface)->Subnet >> 24);
TableEntryIds[2] = (UINT)(((pScope + Iface)->Subnet >> 16) & 0xFF);
TableEntryIds[3] = (UINT)(((pScope + Iface)->Subnet >> 8) & 0xFF);
TableEntryIds[4] = (UINT)((pScope + Iface)->Subnet & 0xFF);
SnmpUtilOidAppend( &VarBind->name, &TableEntryOid );
ErrStat = ScopeGet(VarBind);
return(ErrStat);
}