2577 lines
52 KiB
C
2577 lines
52 KiB
C
/*
|
||
|
||
Copyright (c) 1992-1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
snmppdus.c
|
||
|
||
Abstract:
|
||
|
||
Contains routines for manipulating SNMP PDUs.
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
10-Feb-1997 DonRyan
|
||
Rewrote to implement SNMPv2 support.
|
||
|
||
*/
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Include files //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#include "globals.h"
|
||
#include "snmppdus.h"
|
||
#include "snmpmgmt.h"
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Private definitions //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
#define BERERR ((LONG)-1)
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Private procedures //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
|
||
LONG
|
||
DoLenLen(
|
||
LONG lLen
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates number of bytes required to encode length.
|
||
|
||
Arguments:
|
||
|
||
lLen - length of interest.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine len length
|
||
if (0x80 > lLen) return (1);
|
||
if (0x100 > lLen) return (2);
|
||
if (0x10000 > lLen) return (3);
|
||
if (0x1000000 > lLen) return (4);
|
||
|
||
SNMPDBG((
|
||
SNMP_LOG_ERROR,
|
||
"SNMP: SVC: length field too large.\n"
|
||
));
|
||
|
||
// failure
|
||
return BERERR;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenInt(
|
||
AsnInteger32 nValue
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of integer.
|
||
|
||
Arguments:
|
||
|
||
nValue - integer data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// negative?
|
||
if (nValue < 0) {
|
||
|
||
// determine length of negative int
|
||
if ((ULONG)0x80 >= -nValue) return (1);
|
||
if ((ULONG)0x8000 >= -nValue) return (2);
|
||
if ((ULONG)0x800000 >= -nValue) return (3);
|
||
|
||
} else {
|
||
|
||
// determine length of positive int
|
||
if ((ULONG)0x80 > nValue) return (1);
|
||
if ((ULONG)0x8000 > nValue) return (2);
|
||
if ((ULONG)0x800000 > nValue) return (3);
|
||
}
|
||
|
||
// default
|
||
return (4);
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenIntEx(
|
||
AsnInteger32 nValue
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of integer (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
nValue - integer data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// negative?
|
||
if (nValue < 0) {
|
||
|
||
// determine length of negative int
|
||
if ((ULONG)0x80 >= -nValue) return (3);
|
||
if ((ULONG)0x8000 >= -nValue) return (4);
|
||
if ((ULONG)0x800000 >= -nValue) return (5);
|
||
|
||
} else {
|
||
|
||
// determine length of positive int
|
||
if ((ULONG)0x80 > nValue) return (3);
|
||
if ((ULONG)0x8000 > nValue) return (4);
|
||
if ((ULONG)0x800000 > nValue) return (5);
|
||
}
|
||
|
||
// default
|
||
return (6);
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenUInt(
|
||
AsnUnsigned32 nValue
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates encoded length of unsigned integer.
|
||
|
||
Arguments:
|
||
|
||
nValue - integer data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine length of unsigned int
|
||
if ((ULONG)0x80 > nValue) return (1);
|
||
if ((ULONG)0x8000 > nValue) return (2);
|
||
if ((ULONG)0x800000 > nValue) return (3);
|
||
if ((ULONG)0x80000000 > nValue) return (4);
|
||
|
||
// default
|
||
return (5);
|
||
}
|
||
|
||
|
||
|
||
LONG
|
||
FindLenUIntEx(
|
||
AsnUnsigned32 nValue
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates encoded length of unsigned integer (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
nValue - integer data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine length of unsigned int
|
||
if ((ULONG)0x80 > nValue) return (3);
|
||
if ((ULONG)0x8000 > nValue) return (4);
|
||
if ((ULONG)0x800000 > nValue) return (5);
|
||
if ((ULONG)0x80000000 > nValue) return (6);
|
||
|
||
// default
|
||
return (7);
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenCntr64(
|
||
AsnCounter64 * pCntr64
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates encoded length of 64-bit counter.
|
||
|
||
Arguments:
|
||
|
||
pCntr64 - counter data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// retrieve 64-bit unsigned value
|
||
ULONGLONG nValue = pCntr64->QuadPart;
|
||
|
||
// determine length of unsigned int
|
||
if ((ULONGLONG)0x80 > nValue) return (1);
|
||
if ((ULONGLONG)0x8000 > nValue) return (2);
|
||
if ((ULONGLONG)0x800000 > nValue) return (3);
|
||
if ((ULONGLONG)0x80000000 > nValue) return (4);
|
||
if ((ULONGLONG)0x8000000000 > nValue) return (5);
|
||
if ((ULONGLONG)0x800000000000 > nValue) return (6);
|
||
if ((ULONGLONG)0x80000000000000 > nValue) return (7);
|
||
if ((ULONGLONG)0x8000000000000000 > nValue) return (8);
|
||
|
||
// default
|
||
return (9);
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenCntr64Ex(
|
||
AsnCounter64 * pCntr64
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates encoded length of 64-bit counter (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pCntr64 - counter data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// retrieve 64-bit unsigned value
|
||
ULONGLONG nValue = pCntr64->QuadPart;
|
||
|
||
// determine length of unsigned int
|
||
if ((ULONGLONG)0x80 > nValue) return (3);
|
||
if ((ULONGLONG)0x8000 > nValue) return (4);
|
||
if ((ULONGLONG)0x800000 > nValue) return (5);
|
||
if ((ULONGLONG)0x80000000 > nValue) return (6);
|
||
if ((ULONGLONG)0x8000000000 > nValue) return (7);
|
||
if ((ULONGLONG)0x800000000000 > nValue) return (8);
|
||
if ((ULONGLONG)0x80000000000000 > nValue) return (9);
|
||
if ((ULONGLONG)0x8000000000000000 > nValue) return (10);
|
||
|
||
// default
|
||
return (11);
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenOctets(
|
||
AsnOctetString * pOctets
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of octet string.
|
||
|
||
Arguments:
|
||
|
||
pOctets - pointer to octet string.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// return size
|
||
return pOctets->length;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenOctetsEx(
|
||
AsnOctetString * pOctets
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of octet string (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pOctets - pointer to octet string.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lLenLen;
|
||
|
||
// calculate bytes needed to encode
|
||
lLenLen = DoLenLen(pOctets->length);
|
||
|
||
// return total size
|
||
return (lLenLen != BERERR)
|
||
? (pOctets->length + lLenLen + 1)
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenOid(
|
||
AsnObjectIdentifier * pOid
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of object identifier.
|
||
|
||
Arguments:
|
||
|
||
pOid - pointer object identifier.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lDataLen;
|
||
|
||
// first two
|
||
lDataLen = 1;
|
||
|
||
// assume first two oids present
|
||
for (i = 2; i < pOid->idLength; i++) {
|
||
|
||
if (0x80 > pOid->ids[i]) {
|
||
lDataLen += 1;
|
||
} else if (0x4000 > pOid->ids[i]) {
|
||
lDataLen += 2;
|
||
} else if (0x200000 > pOid->ids[i]) {
|
||
lDataLen += 3;
|
||
} else if (0x10000000 > pOid->ids[i]) {
|
||
lDataLen += 4;
|
||
} else {
|
||
lDataLen += 5;
|
||
}
|
||
}
|
||
|
||
// return size
|
||
return (pOid->idLength >= 2) ? lDataLen : BERERR;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenOidEx(
|
||
AsnObjectIdentifier * pOid
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Calculates length of object identifier (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pOid - pointer object identifier.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lLenLen;
|
||
LONG lDataLen;
|
||
|
||
// first two
|
||
lDataLen = 1;
|
||
|
||
// assume first two oids present
|
||
for (i = 2; i < pOid->idLength; i++) {
|
||
|
||
if (0x80 > pOid->ids[i]) {
|
||
lDataLen += 1;
|
||
} else if (0x4000 > pOid->ids[i]) {
|
||
lDataLen += 2;
|
||
} else if (0x200000 > pOid->ids[i]) {
|
||
lDataLen += 3;
|
||
} else if (0x10000000 > pOid->ids[i]) {
|
||
lDataLen += 4;
|
||
} else {
|
||
lDataLen += 5;
|
||
}
|
||
}
|
||
|
||
// calculate len length
|
||
lLenLen = DoLenLen(lDataLen);
|
||
|
||
// return total size
|
||
return ((lLenLen != BERERR) &&
|
||
(pOid->idLength >= 2))
|
||
? (lDataLen + lLenLen + 1)
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenAsnAny(
|
||
AsnAny * pAny
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding value.
|
||
|
||
Arguments:
|
||
|
||
pAny - pointer to variable binding value.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine syntax
|
||
switch (pAny->asnType) {
|
||
|
||
case ASN_OCTETSTRING:
|
||
case ASN_IPADDRESS:
|
||
case ASN_OPAQUE:
|
||
|
||
return FindLenOctets(&pAny->asnValue.string);
|
||
|
||
case ASN_OBJECTIDENTIFIER:
|
||
|
||
return FindLenOid(&pAny->asnValue.object);
|
||
|
||
case ASN_NULL:
|
||
case SNMP_EXCEPTION_NOSUCHOBJECT:
|
||
case SNMP_EXCEPTION_NOSUCHINSTANCE:
|
||
case SNMP_EXCEPTION_ENDOFMIBVIEW:
|
||
|
||
return (0);
|
||
|
||
case ASN_INTEGER32:
|
||
|
||
return FindLenInt(pAny->asnValue.number);
|
||
|
||
case ASN_COUNTER32:
|
||
case ASN_GAUGE32:
|
||
case ASN_TIMETICKS:
|
||
case ASN_UNSIGNED32:
|
||
|
||
return FindLenUInt(pAny->asnValue.unsigned32);
|
||
|
||
case ASN_COUNTER64:
|
||
|
||
return FindLenCntr64(&pAny->asnValue.counter64);
|
||
}
|
||
|
||
return BERERR;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenAsnAnyEx(
|
||
AsnAny * pAny
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding value (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pAny - pointer to variable binding value.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine syntax
|
||
switch (pAny->asnType) {
|
||
|
||
case ASN_OCTETSTRING:
|
||
case ASN_IPADDRESS:
|
||
case ASN_OPAQUE:
|
||
|
||
return FindLenOctetsEx(&pAny->asnValue.string);
|
||
|
||
case ASN_OBJECTIDENTIFIER:
|
||
|
||
return FindLenOidEx(&pAny->asnValue.object);
|
||
|
||
case ASN_NULL:
|
||
case SNMP_EXCEPTION_NOSUCHOBJECT:
|
||
case SNMP_EXCEPTION_NOSUCHINSTANCE:
|
||
case SNMP_EXCEPTION_ENDOFMIBVIEW:
|
||
|
||
return (2);
|
||
|
||
case ASN_INTEGER32:
|
||
|
||
return FindLenIntEx(pAny->asnValue.number);
|
||
|
||
case ASN_COUNTER32:
|
||
case ASN_GAUGE32:
|
||
case ASN_TIMETICKS:
|
||
case ASN_UNSIGNED32:
|
||
|
||
return FindLenUIntEx(pAny->asnValue.unsigned32);
|
||
|
||
case ASN_COUNTER64:
|
||
|
||
return FindLenCntr64Ex(&pAny->asnValue.counter64);
|
||
}
|
||
|
||
return BERERR;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenVarBind(
|
||
SnmpVarBind * pVb
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding.
|
||
|
||
Arguments:
|
||
|
||
pVb - pointer to variable binding.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lLenLen;
|
||
LONG lOidLen;
|
||
LONG lValueLen;
|
||
|
||
// determine length of name
|
||
lOidLen = FindLenOidEx(&pVb->name);
|
||
|
||
// determine length of value
|
||
lValueLen = FindLenAsnAnyEx(&pVb->value);
|
||
|
||
// return total size
|
||
return ((lOidLen != BERERR) &&
|
||
(lValueLen != BERERR))
|
||
? (lOidLen + lValueLen)
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenVarBindEx(
|
||
SnmpVarBind * pVb
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pVb - pointer to variable binding.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lLenLen;
|
||
LONG lOidLen;
|
||
LONG lValueLen;
|
||
|
||
// determine length of name
|
||
lOidLen = FindLenOidEx(&pVb->name);
|
||
|
||
// determine length of value
|
||
lValueLen = FindLenAsnAnyEx(&pVb->value);
|
||
|
||
// determine length of varbind length
|
||
lLenLen = DoLenLen(lOidLen + lValueLen);
|
||
|
||
// return total size
|
||
return ((lLenLen != BERERR) &&
|
||
(lOidLen != BERERR) &&
|
||
(lValueLen != BERERR))
|
||
? (lOidLen + lValueLen + lLenLen + 1)
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenVarBindList(
|
||
SnmpVarBindList * pVbl
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding list.
|
||
|
||
Arguments:
|
||
|
||
pVbl - pointer to variable binding list.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lVbLen = 0;
|
||
LONG lVblLen = 0;
|
||
|
||
// process each variable binding in the list
|
||
for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
|
||
|
||
// determine length of variable binding
|
||
lVbLen = FindLenVarBindEx(&pVbl->list[i]);
|
||
|
||
// add to total
|
||
lVblLen += lVbLen;
|
||
}
|
||
|
||
// return total size
|
||
return (lVbLen != BERERR)
|
||
? lVblLen
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
LONG
|
||
FindLenVarBindListEx(
|
||
SnmpVarBindList * pVbl
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Find length of variable binding list (including type and lenlen).
|
||
|
||
Arguments:
|
||
|
||
pVbl - pointer to variable binding list.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lVbLen = 0;
|
||
LONG lVblLen = 0;
|
||
LONG lLenLen;
|
||
|
||
// process each variable binding in the list
|
||
for (i = 0; (lVbLen != BERERR) && (i < pVbl->len); i++) {
|
||
|
||
// determine length of variable binding
|
||
lVbLen = FindLenVarBindEx(&pVbl->list[i]);
|
||
|
||
// add to total
|
||
lVblLen += lVbLen;
|
||
}
|
||
|
||
// determine list length
|
||
lLenLen = DoLenLen(lVblLen);
|
||
|
||
// return total size
|
||
return ((lVbLen != BERERR) &&
|
||
(lLenLen != BERERR))
|
||
? (lVblLen + lLenLen + 1)
|
||
: BERERR
|
||
;
|
||
}
|
||
|
||
|
||
VOID
|
||
AddNull(
|
||
LPBYTE * ppByte,
|
||
INT nType
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds null into stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
*/
|
||
|
||
{
|
||
// encode actual syntax
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
*(*ppByte)++ = 0x00;
|
||
}
|
||
|
||
|
||
VOID
|
||
AddLen(
|
||
LPBYTE * ppByte,
|
||
LONG lLenLen,
|
||
LONG lDataLen
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds data length field to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
lLenLen - length of data length.
|
||
|
||
lDataLen - actual data length.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
if (lLenLen == 1) {
|
||
*(*ppByte)++ = (BYTE)lDataLen;
|
||
} else {
|
||
*(*ppByte)++ = (BYTE)(0x80 + lLenLen - 1);
|
||
for (i = 1; i < lLenLen; i++) {
|
||
*(*ppByte)++ = (BYTE)((lDataLen >>
|
||
(8 * (lLenLen - i - 1))) & 0xFF);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
LONG
|
||
AddInt(
|
||
LPBYTE * ppByte,
|
||
INT nType,
|
||
AsnInteger32 nInteger32
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds integer to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax of integer.
|
||
|
||
nInteger32 - actual data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
LONG lLenLen;
|
||
|
||
// determine length of integer
|
||
lDataLen = FindLenInt(nInteger32);
|
||
|
||
// lenlen
|
||
lLenLen = 1;
|
||
|
||
// encode nType of integer
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
|
||
// encode length of integer
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// add encoded integer
|
||
for (i = 0; i < lDataLen; i++) {
|
||
*(*ppByte)++ = (BYTE)(nInteger32 >>
|
||
(8 * ((lDataLen - 1) - i) & 0xFF));
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddUInt(
|
||
LPBYTE * ppByte,
|
||
INT nType,
|
||
AsnUnsigned32 nUnsigned32
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds unsigned integer to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax of integer.
|
||
|
||
nUnsigned32 - actual data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
LONG lLenLen;
|
||
|
||
// determine length of integer
|
||
lDataLen = FindLenUInt(nUnsigned32);
|
||
|
||
// < 127 octets
|
||
lLenLen = 1;
|
||
|
||
// encode actual syntax
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
|
||
// encode data length
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// analyze length
|
||
if (lDataLen == 5) {
|
||
|
||
// put 00 in first octet
|
||
*(*ppByte)++ = (BYTE)0;
|
||
|
||
// encode unsigned integer
|
||
for (i = 1; i < lDataLen; i++) {
|
||
*(*ppByte)++ = (BYTE)(nUnsigned32 >>
|
||
(8 * ((lDataLen - 1) - i) & 0xFF));
|
||
}
|
||
|
||
} else {
|
||
|
||
// encode unsigned integer
|
||
for (i = 0; i < lDataLen; i++) {
|
||
*(*ppByte)++ = (BYTE)(nUnsigned32 >>
|
||
(8 * ((lDataLen - 1) - i) & 0xFF));
|
||
}
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddCntr64(
|
||
LPBYTE * ppByte,
|
||
INT nType,
|
||
AsnCounter64 * pCntr64
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds 64-bit counter to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax of counter.
|
||
|
||
pCntr64 - actual data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
LONG lLenLen;
|
||
|
||
// determine length of counter64
|
||
lDataLen = FindLenCntr64(pCntr64);
|
||
|
||
// < 127 octets
|
||
lLenLen = 1;
|
||
|
||
// encode actual syntax
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
|
||
// encode data length
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// adjust lDataLen
|
||
if (lDataLen == 9) {
|
||
// put 00 in first octet
|
||
*(*ppByte)++ = (BYTE)0;
|
||
lDataLen--;
|
||
}
|
||
|
||
// encode counter data
|
||
for (i = lDataLen; i > 4; i--) {
|
||
*(*ppByte)++ = (BYTE)(pCntr64->HighPart >>
|
||
(8 * (i - 5) & 0xFF));
|
||
}
|
||
for (; i > 0; i--) {
|
||
*(*ppByte)++ = (BYTE)(pCntr64->LowPart >>
|
||
(8 * (i - 1) & 0xFF));
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddOctets(
|
||
LPBYTE * ppByte,
|
||
INT nType,
|
||
AsnOctetString * pOctets
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds octet string to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax of string.
|
||
|
||
pOctets - actual data.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lLenLen;
|
||
LONG lDataLen;
|
||
|
||
// determine oid length
|
||
if ((lDataLen = FindLenOctets(pOctets)) == BERERR)
|
||
return BERERR;
|
||
|
||
// calculate octet string length
|
||
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
|
||
return BERERR;
|
||
|
||
// encode actual syntax
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
|
||
// encode octet string length
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// usless copy avoided
|
||
if (*ppByte != pOctets->stream)
|
||
{
|
||
// encode actual octets
|
||
for (i = 0; i < pOctets->length; i++)
|
||
*(*ppByte)++ = pOctets->stream[i];
|
||
}
|
||
else
|
||
{
|
||
(*ppByte) += pOctets->length;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddOid(
|
||
LPBYTE * ppByte,
|
||
INT nType,
|
||
AsnObjectIdentifier * pOid
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds object identifier to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
nType - exact syntax of object identifier.
|
||
|
||
pOid - pointer to object identifier.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
LONG lLenLen = 0;
|
||
LONG lDataLen;
|
||
|
||
// determine oid length
|
||
if ((lDataLen = FindLenOid(pOid)) == BERERR)
|
||
return BERERR;
|
||
|
||
// calculate number of bytes required for length
|
||
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
|
||
return BERERR;
|
||
|
||
// add syntax to stream
|
||
*(*ppByte)++ = (BYTE)(0xFF & nType);
|
||
|
||
// add object identifier length
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// add first subid
|
||
if (pOid->idLength < 2)
|
||
*(*ppByte)++ = (BYTE)(pOid->ids[0] * 40);
|
||
else
|
||
*(*ppByte)++ = (BYTE)((pOid->ids[0] * 40) + pOid->ids[1]);
|
||
|
||
// walk remaining subidentifiers
|
||
for (i = 2; i < pOid->idLength; i++) {
|
||
|
||
if (pOid->ids[i] < 0x80) {
|
||
|
||
// 0 - 0x7f
|
||
*(*ppByte)++ = (BYTE)pOid->ids[i];
|
||
|
||
} else if (pOid->ids[i] < 0x4000) {
|
||
|
||
// 0x80 - 0x3fff
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
|
||
|
||
} else if (pOid->ids[i] < 0x200000) {
|
||
|
||
// 0x4000 - 0x1FFFFF
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
|
||
|
||
} else if (pOid->ids[i] < 0x10000000) {
|
||
|
||
// 0x200000 - 0xFFfffff
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 21) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
|
||
|
||
} else {
|
||
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 28) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 21) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 14) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)
|
||
(((pOid->ids[i]) >> 7) | 0x80); // set high bit
|
||
*(*ppByte)++ = (BYTE)(pOid->ids[i] & 0x7f);
|
||
}
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddAsnAny(
|
||
LPBYTE * ppByte,
|
||
AsnAny * pAny
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds variable binding value to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pAny - variable binding value.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine syntax
|
||
switch (pAny->asnType) {
|
||
|
||
case ASN_COUNTER32:
|
||
case ASN_GAUGE32:
|
||
case ASN_TIMETICKS:
|
||
case ASN_UNSIGNED32:
|
||
|
||
return AddUInt(
|
||
ppByte,
|
||
(INT)pAny->asnType,
|
||
pAny->asnValue.unsigned32
|
||
);
|
||
|
||
case ASN_INTEGER32:
|
||
|
||
return AddInt(
|
||
ppByte,
|
||
(INT)pAny->asnType,
|
||
pAny->asnValue.number
|
||
);
|
||
|
||
case ASN_OBJECTIDENTIFIER:
|
||
|
||
return AddOid(
|
||
ppByte,
|
||
(INT)pAny->asnType,
|
||
&pAny->asnValue.object
|
||
);
|
||
|
||
case ASN_COUNTER64:
|
||
|
||
return AddCntr64(
|
||
ppByte,
|
||
(INT)pAny->asnType,
|
||
&pAny->asnValue.counter64
|
||
);
|
||
|
||
case ASN_OCTETSTRING:
|
||
case ASN_IPADDRESS:
|
||
case ASN_OPAQUE:
|
||
|
||
return AddOctets(
|
||
ppByte,
|
||
(INT)pAny->asnType,
|
||
&pAny->asnValue.string
|
||
);
|
||
|
||
case ASN_NULL:
|
||
case SNMP_EXCEPTION_NOSUCHOBJECT:
|
||
case SNMP_EXCEPTION_NOSUCHINSTANCE:
|
||
case SNMP_EXCEPTION_ENDOFMIBVIEW:
|
||
|
||
AddNull(ppByte, (INT)pAny->asnType);
|
||
return (0);
|
||
}
|
||
|
||
return BERERR;
|
||
}
|
||
|
||
|
||
LONG
|
||
AddVarBind(
|
||
LPBYTE * ppByte,
|
||
SnmpVarBind * pVb
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds variable binding to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pVb - pointer to variable binding.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lLenLen;
|
||
LONG lDataLen;
|
||
|
||
// determine actual length of varbind data
|
||
if ((lDataLen = FindLenVarBind(pVb)) == BERERR)
|
||
return BERERR;
|
||
|
||
// determine length of varbind data length
|
||
if ((lLenLen = DoLenLen(lDataLen)) == BERERR)
|
||
return BERERR;
|
||
|
||
// encode as sequence
|
||
*(*ppByte)++ = ASN_SEQUENCE;
|
||
|
||
// encode data length
|
||
AddLen(ppByte, lLenLen, lDataLen);
|
||
|
||
// encode variable binding name
|
||
if (AddOid(ppByte, ASN_OBJECTIDENTIFIER, &pVb->name) == BERERR)
|
||
return BERERR;
|
||
|
||
// encode variable binding value
|
||
if (AddAsnAny(ppByte, &pVb->value) == BERERR)
|
||
return BERERR;
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
AddVarBindList(
|
||
LPBYTE * ppByte,
|
||
SnmpVarBindList * pVbl
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Adds variable binding list to current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pVbl - pointer to variable binding list.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
UINT i;
|
||
|
||
// add each variable binding
|
||
for (i = 0; i < pVbl->len; i++) {
|
||
if (AddVarBind(ppByte, &pVbl->list[i]) == BERERR)
|
||
return BERERR;
|
||
}
|
||
|
||
return (0);
|
||
}
|
||
|
||
|
||
LONG
|
||
ParseLength(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse length from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lLenLen;
|
||
LONG lDataLen;
|
||
|
||
lDataLen = (LONG)*(*ppByte)++;
|
||
|
||
if (lDataLen < 0x80)
|
||
return (lDataLen);
|
||
|
||
// check for long form
|
||
lLenLen = lDataLen & 0x7f;
|
||
|
||
// validate long form
|
||
if ((lLenLen > 4) || (lLenLen < 1))
|
||
return BERERR;
|
||
|
||
lDataLen = 0L;
|
||
|
||
for (i = 0; i < lLenLen; i++) {
|
||
lDataLen = (lDataLen << 8) + *(*ppByte)++;
|
||
}
|
||
|
||
if (*ppByte > pLastByte)
|
||
return BERERR;
|
||
|
||
return (lDataLen);
|
||
}
|
||
|
||
|
||
LONG
|
||
ParseType(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse type from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
Return Values:
|
||
|
||
Returns BERERR if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
SHORT nType = *(*ppByte)++;
|
||
|
||
if (*ppByte > pLastByte)
|
||
return BERERR;
|
||
|
||
switch (nType) {
|
||
|
||
case ASN_INTEGER32:
|
||
case ASN_OCTETSTRING:
|
||
case ASN_OBJECTIDENTIFIER:
|
||
case ASN_SEQUENCE:
|
||
case ASN_IPADDRESS:
|
||
case ASN_COUNTER32:
|
||
case ASN_GAUGE32:
|
||
case ASN_TIMETICKS:
|
||
case ASN_OPAQUE:
|
||
case ASN_UNSIGNED32:
|
||
case ASN_COUNTER64:
|
||
case ASN_NULL:
|
||
case SNMP_EXCEPTION_NOSUCHOBJECT:
|
||
case SNMP_EXCEPTION_NOSUCHINSTANCE:
|
||
case SNMP_EXCEPTION_ENDOFMIBVIEW:
|
||
case SNMP_PDU_GET:
|
||
case SNMP_PDU_GETNEXT:
|
||
case SNMP_PDU_RESPONSE:
|
||
case SNMP_PDU_SET:
|
||
case SNMP_PDU_V1TRAP:
|
||
case SNMP_PDU_GETBULK:
|
||
case SNMP_PDU_INFORM:
|
||
case SNMP_PDU_TRAP:
|
||
break;
|
||
|
||
default:
|
||
nType = BERERR;
|
||
break;
|
||
}
|
||
|
||
return (LONG)(SHORT)(nType);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseNull(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse null from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lDataLen;
|
||
|
||
if (!(ParseType(ppByte, pLastByte)))
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if (lDataLen != 0)
|
||
return (FALSE);
|
||
|
||
if (*ppByte > pLastByte)
|
||
return (FALSE);
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseSequence(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
LONG * plDataLen
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse sequence from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
plDataLen - pointer to receive sequence length.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lDataLen;
|
||
|
||
if ((ParseType(ppByte, pLastByte)) != ASN_SEQUENCE)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if (*ppByte > pLastByte)
|
||
return (FALSE);
|
||
|
||
if (plDataLen)
|
||
*plDataLen = lDataLen;
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseInt(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnInteger32 * pInteger32
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse integer from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pInteger32 - pointer to receive integer.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lSign;
|
||
LONG lDataLen;
|
||
|
||
if (ParseType(ppByte, pLastByte) == BERERR)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if (lDataLen > 4)
|
||
return (FALSE);
|
||
|
||
lSign = ((*(*ppByte) & 0x80) == 0x00) ? 0x00 : 0xFF;
|
||
|
||
*pInteger32 = 0;
|
||
|
||
for (i = 0; i < lDataLen; i++)
|
||
*pInteger32 = (*pInteger32 << 8) + (UINT)*(*ppByte)++;
|
||
|
||
// sign-extend upper bits
|
||
for (i = lDataLen; i < 4; i++)
|
||
*pInteger32 = *pInteger32 + (lSign << i * 8);
|
||
|
||
if (*ppByte > pLastByte)
|
||
return (FALSE);
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseUInt(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnUnsigned32 * pUnsigned32
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse unsigned integer from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pUnsigned32 - pointer to receive integer.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
|
||
if (ParseType(ppByte, pLastByte) == BERERR)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen > 5) || ((lDataLen > 4) && (*(*ppByte) != 0x00)))
|
||
return (FALSE);
|
||
|
||
// leading null octet?
|
||
if (*(*ppByte) == 0x00) {
|
||
(*ppByte)++; // if so, skip it
|
||
lDataLen--; // and don't count it
|
||
}
|
||
|
||
*pUnsigned32 = 0;
|
||
|
||
for (i = 0; i < lDataLen; i++)
|
||
*pUnsigned32 = (*pUnsigned32 << 8) + (UINT)*(*ppByte)++;
|
||
|
||
if (*ppByte > pLastByte)
|
||
return (FALSE);
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseCntr64(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnCounter64 * pCntr64
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse 64-bit counter from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pCntr64 - pointer to receive counter.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
LONG nType;
|
||
|
||
// initialize
|
||
pCntr64->HighPart = 0L;
|
||
pCntr64->LowPart = 0L;
|
||
|
||
if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if (nType != ASN_COUNTER64)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen > 9) || ((lDataLen > 8) && (*(*ppByte) != 0x00)))
|
||
return (FALSE);
|
||
|
||
// leading null octet?
|
||
if (*(*ppByte) == 0x00) {
|
||
(*ppByte)++; // if so, skip it
|
||
lDataLen--; // and don't count it
|
||
}
|
||
|
||
for (i = 0; i < lDataLen; i++) {
|
||
pCntr64->HighPart = (pCntr64->HighPart << 8) +
|
||
(pCntr64->LowPart >> 24);
|
||
pCntr64->LowPart = (pCntr64->LowPart << 8) +
|
||
(unsigned long) *(*ppByte)++;
|
||
}
|
||
|
||
if (*ppByte > pLastByte)
|
||
return (FALSE);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseOctets(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnOctetString * pOctets
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse octet string from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pOctets - pointer to receive string.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG errCode;
|
||
// initialize
|
||
pOctets->length = 0;
|
||
pOctets->stream = NULL;
|
||
pOctets->dynamic = FALSE;
|
||
|
||
if (ParseType(ppByte, pLastByte) == BERERR)
|
||
return (FALSE);
|
||
|
||
// make sure no conversion to UINT is done before testing
|
||
// (pOctets->length is UINT)
|
||
if ((errCode = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
pOctets->length = (UINT)errCode;
|
||
|
||
// avoid wrapping around on machines with 4-byte pointers
|
||
if ((((*ppByte) + pOctets->length) < *ppByte) ||
|
||
((*ppByte) + pOctets->length) > pLastByte)
|
||
return (FALSE);
|
||
|
||
// validate length
|
||
if (pOctets->length) {
|
||
|
||
// point into buffer
|
||
pOctets->stream = *ppByte; // WARNING! WARNING!
|
||
}
|
||
|
||
*ppByte += pOctets->length;
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseOid(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnObjectIdentifier * pOid
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse object identifier from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pOid - pointer to receive oid.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG i;
|
||
LONG lDataLen;
|
||
LONG nType;
|
||
|
||
// initialize
|
||
pOid->idLength = 0;
|
||
pOid->ids = NULL;
|
||
|
||
if ((nType = ParseType(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
if (nType != ASN_OBJECTIDENTIFIER)
|
||
return (FALSE);
|
||
|
||
if ((lDataLen = ParseLength(ppByte, pLastByte)) == BERERR)
|
||
return (FALSE);
|
||
|
||
|
||
if (lDataLen <= 0) //--ft 03/02/98 removed trailing "|| lDataLen > SNMP_MAX_OID_LEN)"
|
||
{ // check is done in the while loop below
|
||
SNMPDBG((
|
||
SNMP_LOG_ERROR,
|
||
"SNMP: SVC: ParseOid: lDataLen <= 0, lDataLen=%d.\n",
|
||
lDataLen
|
||
));
|
||
return (FALSE);
|
||
}
|
||
|
||
// BUG# 486089
|
||
// the ((lDataLen + 2) * sizeof(UINT)) expression might cause overflow in
|
||
// SnmpUtilMemAlloc below. adding one more check to limit its max. value.
|
||
if ( lDataLen > (pLastByte - (*ppByte)) )
|
||
{
|
||
SNMPDBG((
|
||
SNMP_LOG_ERROR,
|
||
"SNMP: SVC: ParseOid: invalid lDataLen=%d, pLastByte=%p, *ppByte=%p.\n",
|
||
lDataLen, pLastByte, *ppByte
|
||
));
|
||
return (FALSE);
|
||
}
|
||
|
||
pOid->ids = SnmpUtilMemAlloc((DWORD)((lDataLen + 2) * sizeof(UINT)));
|
||
|
||
if (pOid->ids == NULL)
|
||
return (FALSE);
|
||
|
||
// pOid->ids array space is pre-zero'd via SnmpUtilMemAlloc()
|
||
while (lDataLen && (pOid->idLength < SNMP_MAX_OID_LEN))
|
||
{
|
||
pOid->ids[pOid->idLength] =
|
||
(pOid->ids[pOid->idLength] << 7) | (*(*ppByte) & 0x7F);
|
||
if ((*(*ppByte)++ & 0x80) == 0)
|
||
{ // on the last octet of this sub-id
|
||
if (pOid->idLength == 0) // check for first sub-id
|
||
{ // ASN.1/BER packs two into it
|
||
pOid->ids[1] = pOid->ids[0];
|
||
pOid->ids[0] /= 40;
|
||
if (pOid->ids[0] > 2)
|
||
pOid->ids[0] = 2;
|
||
pOid->ids[1] -= (pOid->ids[0] * 40);
|
||
pOid->idLength++; // extra bump
|
||
}
|
||
pOid->idLength++; // increment the count on sub-id
|
||
}
|
||
lDataLen--; // note: *ppByte is incremented in the if statement above
|
||
} // end_while (lDataLen)
|
||
|
||
// BUG 506192
|
||
// Invalid OID BER of the form like "06 07 FF FF FF FF FF FF FF"
|
||
// causes pOid->idLength becomes 0. Each subidentifier should be
|
||
// encoded as a non-negative integer using as few 7-bit blocks as possible.
|
||
// The blocks are packed in octets with the first bit of each octet equal
|
||
// to 1 except for the last octet of each subidentifier. The example above
|
||
// does not have the last octet. Added the (0 == pOid->idLength) test below.
|
||
if (lDataLen || (0 == pOid->idLength))
|
||
{
|
||
// the above while loop is terminated without finishing the parsing of the stream
|
||
SnmpUtilMemFree(pOid->ids);
|
||
pOid->ids = NULL;
|
||
pOid->idLength = 0;
|
||
return (FALSE);
|
||
}
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseAsnAny(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
AsnAny * pAny
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse variable binding value from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pAny - pointer to variable binding value.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
// determine asn type
|
||
switch (pAny->asnType) {
|
||
|
||
case ASN_COUNTER32:
|
||
case ASN_GAUGE32:
|
||
case ASN_TIMETICKS:
|
||
case ASN_UNSIGNED32:
|
||
|
||
return ParseUInt(
|
||
ppByte,
|
||
pLastByte,
|
||
&pAny->asnValue.unsigned32
|
||
);
|
||
|
||
case ASN_INTEGER32:
|
||
|
||
return ParseInt(
|
||
ppByte,
|
||
pLastByte,
|
||
&pAny->asnValue.number
|
||
);
|
||
|
||
case ASN_OBJECTIDENTIFIER:
|
||
|
||
return ParseOid(
|
||
ppByte,
|
||
pLastByte,
|
||
&pAny->asnValue.object
|
||
);
|
||
|
||
case ASN_COUNTER64:
|
||
|
||
return ParseCntr64(
|
||
ppByte,
|
||
pLastByte,
|
||
&pAny->asnValue.counter64
|
||
);
|
||
|
||
case ASN_OCTETSTRING:
|
||
case ASN_IPADDRESS:
|
||
case ASN_OPAQUE:
|
||
|
||
return ParseOctets(
|
||
ppByte,
|
||
pLastByte,
|
||
&pAny->asnValue.string
|
||
);
|
||
|
||
case ASN_NULL:
|
||
case SNMP_EXCEPTION_NOSUCHOBJECT:
|
||
case SNMP_EXCEPTION_NOSUCHINSTANCE:
|
||
case SNMP_EXCEPTION_ENDOFMIBVIEW:
|
||
|
||
return ParseNull(ppByte, pLastByte);
|
||
}
|
||
|
||
return (FALSE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseVarBind(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
SnmpVarBind * pVb
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse variable binding from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pVb - pointer to variable binding.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
if (!(ParseSequence(ppByte, pLastByte, NULL)))
|
||
return (FALSE);
|
||
|
||
if (!(ParseOid(ppByte, pLastByte, &pVb->name)))
|
||
return (FALSE);
|
||
|
||
pVb->value.asnType = (UINT)*(*ppByte);
|
||
|
||
if (!(ParseAsnAny(ppByte, pLastByte, &pVb->value)))
|
||
{
|
||
// free memory allocated by ParseOid
|
||
SnmpUtilOidFree(&pVb->name);
|
||
return (FALSE);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
BOOL
|
||
ParseVarBindList(
|
||
LPBYTE * ppByte,
|
||
LPBYTE pLastByte,
|
||
SnmpVarBindList * pVbl
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parse variable binding from current stream.
|
||
|
||
Arguments:
|
||
|
||
ppByte - pointer to pointer to current stream.
|
||
|
||
pLastByte - pointer to end of current stream.
|
||
|
||
pVbl - pointer to variable binding list.
|
||
|
||
Return Values:
|
||
|
||
Returns FALSE if unsuccessful.
|
||
|
||
*/
|
||
|
||
{
|
||
SnmpVarBind Vb;
|
||
SnmpVarBind * pVb = NULL;
|
||
|
||
// initialize
|
||
pVbl->list = NULL;
|
||
pVbl->len = 0;
|
||
|
||
// loop while data is left
|
||
while (*ppByte < pLastByte) {
|
||
|
||
if (!(ParseVarBind(ppByte, pLastByte, &Vb)))
|
||
return (FALSE);
|
||
|
||
// copy pointer
|
||
pVb = pVbl->list;
|
||
|
||
// attempt to allocate new variable binding
|
||
pVb = SnmpUtilMemReAlloc(pVb, (pVbl->len + 1) * sizeof(SnmpVarBind));
|
||
|
||
// validate
|
||
if (pVb == NULL)
|
||
{
|
||
SnmpUtilVarBindFree(&Vb);
|
||
return FALSE;
|
||
}
|
||
// update varbind
|
||
pVb[pVbl->len] = Vb;
|
||
|
||
// update list
|
||
pVbl->list = pVb;
|
||
pVbl->len++;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
// //
|
||
// Public procedures (based on snmp\manager\winsnmp\dll\wsnmp_bn.c) //
|
||
// //
|
||
///////////////////////////////////////////////////////////////////////////////
|
||
typedef UNALIGNED LONG* PUALONG;
|
||
|
||
BOOL
|
||
BuildMessage(
|
||
AsnInteger32 nVersion,
|
||
AsnOctetString * pCommunity,
|
||
PSNMP_PDU pPdu,
|
||
PBYTE pMessage,
|
||
PDWORD pMessageSize
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Builds outgoing SNMP PDU based on structure.
|
||
|
||
Arguments:
|
||
|
||
nVersion - SNMP version.
|
||
|
||
pCommunity - pointer to community string.
|
||
|
||
pPdu - pointer to PDU data structure.
|
||
|
||
pMessage - pointer to buffer in which to build message.
|
||
|
||
pMessageSize - pointer to receive size of message.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG nVbDataLength;
|
||
LONG nVbLenLength;
|
||
LONG nVbTotalLength;
|
||
LONG nPduDataLength;
|
||
LONG nPduLenLength;
|
||
LONG nPduTotalLength;
|
||
LONG nMsgDataLength;
|
||
LONG nMsgLenLength;
|
||
LONG nMsgTotalLength;
|
||
LONG nMsgAvailLength;
|
||
LONG nTmpDataLength;
|
||
|
||
LPBYTE tmpPtr = pMessage;
|
||
|
||
// determine bytes available
|
||
nMsgAvailLength = *pMessageSize;
|
||
|
||
// find length of variable bindings list
|
||
if ((nVbDataLength = FindLenVarBindList(&pPdu->Vbl)) == BERERR)
|
||
return FALSE;
|
||
|
||
// find length of length of variable bindings
|
||
if ((nVbLenLength = DoLenLen(nVbDataLength)) == BERERR)
|
||
return FALSE;
|
||
|
||
// calculate total bytes required to encode varbinds
|
||
nVbTotalLength = 1 + nVbLenLength + nVbDataLength;
|
||
|
||
// determine pdu nType
|
||
switch (pPdu->nType) {
|
||
|
||
case SNMP_PDU_GET:
|
||
case SNMP_PDU_GETNEXT:
|
||
case SNMP_PDU_RESPONSE:
|
||
case SNMP_PDU_SET:
|
||
case SNMP_PDU_GETBULK:
|
||
case SNMP_PDU_INFORM:
|
||
case SNMP_PDU_TRAP:
|
||
|
||
// calculate bytes required to encode pdu entries
|
||
nPduDataLength = FindLenIntEx(pPdu->Pdu.NormPdu.nRequestId)
|
||
+ FindLenIntEx(pPdu->Pdu.NormPdu.nErrorStatus)
|
||
+ FindLenIntEx(pPdu->Pdu.NormPdu.nErrorIndex)
|
||
+ nVbTotalLength;
|
||
break;
|
||
|
||
case SNMP_PDU_V1TRAP:
|
||
|
||
// calculate bytes required to encode pdu entries
|
||
nPduDataLength = FindLenIntEx(pPdu->Pdu.TrapPdu.nGenericTrap)
|
||
+ FindLenIntEx(pPdu->Pdu.TrapPdu.nSpecificTrap)
|
||
+ FindLenUIntEx(pPdu->Pdu.TrapPdu.nTimeticks)
|
||
+ nVbTotalLength;
|
||
|
||
// find oid length
|
||
if ((nTmpDataLength =
|
||
FindLenOidEx(&pPdu->Pdu.TrapPdu.EnterpriseOid)) == BERERR)
|
||
return FALSE;
|
||
|
||
// add EnterpriseOid oid length
|
||
nPduDataLength += nTmpDataLength;
|
||
|
||
// find address length
|
||
if ((nTmpDataLength =
|
||
FindLenOctetsEx(&pPdu->Pdu.TrapPdu.AgentAddr)) == BERERR)
|
||
return FALSE;
|
||
|
||
// add agent address length
|
||
nPduDataLength += nTmpDataLength;
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
// find length of pdu length
|
||
if ((nPduLenLength = DoLenLen(nPduDataLength)) == BERERR)
|
||
return FALSE;
|
||
|
||
// calculate total bytes required to encode pdu
|
||
nPduTotalLength = 1 + nPduLenLength + nPduDataLength;
|
||
|
||
// find length of message data
|
||
nMsgDataLength = FindLenUIntEx(nVersion)
|
||
+ FindLenOctetsEx(pCommunity)
|
||
+ nPduTotalLength;
|
||
|
||
// find length of message data length
|
||
nMsgLenLength = DoLenLen(nMsgDataLength);
|
||
|
||
// calculate total bytes required to encode message
|
||
nMsgTotalLength = 1 + nMsgLenLength + nMsgDataLength;
|
||
|
||
// record bytes required
|
||
*pMessageSize = nMsgTotalLength;
|
||
|
||
// make sure message fits in buffer
|
||
if (nMsgTotalLength <= nMsgAvailLength) {
|
||
LONG oldLength; // the length of the request PDU
|
||
LONG delta; // difference between the request PDU length and the responce PDU length
|
||
BYTE *newStream;// new location for the community stream inside the response PDU.
|
||
|
||
// encode message as asn sequence
|
||
*tmpPtr++ = ASN_SEQUENCE;
|
||
|
||
// the pointer to the community string points either directly in the incoming buffer
|
||
// (for req PDUs) or in the TRAP_DESTINATION_LIST_ENTRY for the outgoing traps.
|
||
// In the first case, when building the outgoing message on the same buffer as the
|
||
// incoming message, we need to take care to no overwrite the community name (in case
|
||
// the length field is larger than for the initial message). Hence, in this case only
|
||
// we shift the community name with a few octets, as many as the difference between the
|
||
// encodings of the two lengths (the length of the outgoing response - the length of the
|
||
// incoming request).
|
||
if (pPdu->nType != SNMP_PDU_V1TRAP)
|
||
{
|
||
// here tmpPtr points exactly to the length of the request pdu
|
||
oldLength = *(PUALONG)tmpPtr; // bug# 176433
|
||
// compute the offset the community stream should be shifted with
|
||
delta = nMsgLenLength - ((oldLength & 0x80) ? (oldLength & 0x7f) + 1 : 1);
|
||
newStream = pCommunity->stream + delta;
|
||
// pCommunity->stream is shifted regardles memory regions overlapp
|
||
memmove(newStream, pCommunity->stream, pCommunity->length);
|
||
// make old community to point to the new location
|
||
pCommunity->stream = newStream;
|
||
}
|
||
|
||
// encode global message information
|
||
AddLen(&tmpPtr, nMsgLenLength, nMsgDataLength);
|
||
AddUInt(&tmpPtr, ASN_INTEGER32, nVersion);
|
||
AddOctets(&tmpPtr, ASN_OCTETSTRING, pCommunity);
|
||
|
||
// encode pdu header information
|
||
*tmpPtr++ = (BYTE)pPdu->nType;
|
||
AddLen(&tmpPtr, nPduLenLength, nPduDataLength);
|
||
|
||
// determine pdu nType
|
||
switch (pPdu->nType) {
|
||
|
||
case SNMP_PDU_RESPONSE:
|
||
case SNMP_PDU_TRAP:
|
||
|
||
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nRequestId);
|
||
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorStatus);
|
||
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.NormPdu.nErrorIndex);
|
||
break;
|
||
|
||
case SNMP_PDU_V1TRAP:
|
||
|
||
if (AddOid(
|
||
&tmpPtr,
|
||
ASN_OBJECTIDENTIFIER,
|
||
&pPdu->Pdu.TrapPdu.EnterpriseOid)== BERERR)
|
||
return FALSE;
|
||
|
||
if (AddOctets(
|
||
&tmpPtr,
|
||
ASN_IPADDRESS,
|
||
&pPdu->Pdu.TrapPdu.AgentAddr) == BERERR)
|
||
return FALSE;
|
||
|
||
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nGenericTrap);
|
||
AddInt(&tmpPtr, ASN_INTEGER32, pPdu->Pdu.TrapPdu.nSpecificTrap);
|
||
AddUInt(&tmpPtr, ASN_TIMETICKS, pPdu->Pdu.TrapPdu.nTimeticks);
|
||
break;
|
||
|
||
case SNMP_PDU_GET:
|
||
case SNMP_PDU_GETNEXT:
|
||
case SNMP_PDU_SET:
|
||
case SNMP_PDU_INFORM:
|
||
case SNMP_PDU_GETBULK:
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
// encode variable bindings
|
||
*tmpPtr++ = ASN_SEQUENCE;
|
||
|
||
AddLen(&tmpPtr, nVbLenLength, nVbDataLength);
|
||
|
||
if (AddVarBindList(&tmpPtr, &pPdu->Vbl) == BERERR)
|
||
return FALSE;
|
||
|
||
// success
|
||
return TRUE;
|
||
}
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|
||
|
||
BOOL
|
||
ParseMessage(
|
||
AsnInteger32 * pVersion,
|
||
AsnOctetString * pCommunity,
|
||
PSNMP_PDU pPdu,
|
||
PBYTE pMessage,
|
||
DWORD dwMessageSize
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Parses incoming SNMP PDU into structure.
|
||
|
||
Arguments:
|
||
|
||
pVersion - pointer to receive SNMP version.
|
||
|
||
pCommunity - pointer to receive community string.
|
||
|
||
pPdu - pointer to receive remaining PDU data.
|
||
|
||
pMessage - pointer to message to parse.
|
||
|
||
dwMessageSize - number of bytes in message.
|
||
|
||
Return Values:
|
||
|
||
Returns true if successful.
|
||
|
||
*/
|
||
|
||
{
|
||
LONG lLength;
|
||
LPBYTE pByte;
|
||
LPBYTE pLastByte;
|
||
|
||
// initialize community
|
||
pCommunity->stream = NULL;
|
||
pCommunity->length = 0;
|
||
|
||
// initialize vbl
|
||
pPdu->Vbl.len = 0;
|
||
pPdu->Vbl.list = NULL;
|
||
|
||
// validate pointer
|
||
if (!(pByte = pMessage))
|
||
goto cleanup;
|
||
|
||
// set limit based on packet size
|
||
pLastByte = pByte + dwMessageSize;
|
||
|
||
// decode asn sequence message wrapper
|
||
if (!(ParseSequence(&pByte, pLastByte, &lLength)))
|
||
goto cleanup;
|
||
|
||
// check for packet fragments
|
||
if (pLastByte < (pByte + lLength))
|
||
goto cleanup;
|
||
|
||
// re-adjust based on data
|
||
pLastByte = pByte + lLength;
|
||
|
||
// decode snmp version
|
||
if (!(ParseUInt(&pByte, pLastByte, pVersion)))
|
||
goto cleanup;
|
||
|
||
// validate snmp version
|
||
if ((*pVersion != SNMP_VERSION_1) &&
|
||
(*pVersion != SNMP_VERSION_2C))
|
||
{
|
||
// register version mismatch into the management structure
|
||
mgmtCTick(CsnmpInBadVersions);
|
||
|
||
goto cleanup;
|
||
}
|
||
|
||
// decode community string
|
||
if (!(ParseOctets(&pByte, pLastByte, pCommunity)))
|
||
goto cleanup;
|
||
|
||
// decode nType of incoming pdu
|
||
if ((pPdu->nType = ParseType(&pByte, pLastByte)) == BERERR)
|
||
goto cleanup;
|
||
|
||
// decode length of incoming pdu
|
||
if ((lLength = ParseLength(&pByte, pLastByte)) == BERERR)
|
||
goto cleanup;
|
||
|
||
// validate length
|
||
if (pByte + lLength > pLastByte)
|
||
goto cleanup;
|
||
|
||
// determine pdu nType
|
||
switch (pPdu->nType) {
|
||
|
||
case SNMP_PDU_GET:
|
||
case SNMP_PDU_GETNEXT:
|
||
case SNMP_PDU_SET:
|
||
|
||
// decode the pdu header information
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nRequestId)))
|
||
goto cleanup;
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorStatus)))
|
||
goto cleanup;
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.NormPdu.nErrorIndex)))
|
||
goto cleanup;
|
||
|
||
// update the management counters for the incoming errorStatus coding
|
||
mgmtUtilUpdateErrStatus(IN_errStatus, pPdu->Pdu.NormPdu.nErrorStatus);
|
||
|
||
// no reason here to have any ErrorStatus and ErrorIndex.
|
||
// initialize error status variables to NOERROR
|
||
pPdu->Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
|
||
pPdu->Pdu.NormPdu.nErrorIndex = 0;
|
||
|
||
break;
|
||
|
||
case SNMP_PDU_GETBULK:
|
||
|
||
// decode the getbulk pdu header information
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nRequestId)))
|
||
goto cleanup;
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nNonRepeaters)))
|
||
goto cleanup;
|
||
if (!(ParseInt(&pByte, pLastByte, &pPdu->Pdu.BulkPdu.nMaxRepetitions)))
|
||
goto cleanup;
|
||
|
||
// see if value needs to be adjusted
|
||
if (pPdu->Pdu.BulkPdu.nNonRepeaters < 0) {
|
||
|
||
// adjust non-repeaters to zero
|
||
pPdu->Pdu.BulkPdu.nNonRepeaters = 0;
|
||
}
|
||
|
||
// see if value needs to be adjusted
|
||
if (pPdu->Pdu.BulkPdu.nMaxRepetitions < 0) {
|
||
|
||
// adjust max-repetitions to zero
|
||
pPdu->Pdu.BulkPdu.nMaxRepetitions = 0;
|
||
}
|
||
|
||
// initialize status information
|
||
pPdu->Pdu.BulkPdu.nErrorStatus = SNMP_ERRORSTATUS_NOERROR;
|
||
pPdu->Pdu.BulkPdu.nErrorIndex = 0;
|
||
|
||
break;
|
||
|
||
case SNMP_PDU_INFORM:
|
||
case SNMP_PDU_RESPONSE:
|
||
case SNMP_PDU_TRAP:
|
||
case SNMP_PDU_V1TRAP:
|
||
default:
|
||
goto cleanup;
|
||
}
|
||
|
||
// parse over sequence
|
||
if (!(ParseSequence(&pByte, pLastByte, NULL)))
|
||
goto cleanup;
|
||
|
||
// parse variable binding list
|
||
if (!(ParseVarBindList(&pByte, pLastByte, &pPdu->Vbl)))
|
||
goto cleanup;
|
||
|
||
// success
|
||
return TRUE;
|
||
|
||
cleanup:
|
||
|
||
// cleanup community string
|
||
SnmpUtilOctetsFree(pCommunity);
|
||
|
||
// cleanup any allocated varbinds
|
||
SnmpUtilVarBindListFree(&pPdu->Vbl);
|
||
|
||
// failure
|
||
return FALSE;
|
||
}
|