inetmib1: Support the MIB2 interface table.

This commit is contained in:
Juan Lang 2008-05-20 20:54:34 -07:00 committed by Alexandre Julliard
parent f913252ea2
commit c531c11734
2 changed files with 293 additions and 1 deletions

View File

@ -17,7 +17,7 @@
*/
#include "config.h"
#include <assert.h>
#include <stdarg.h>
#include <limits.h>
#include "windef.h"
@ -57,6 +57,47 @@ static void copyInt(AsnAny *value, void *src)
value->asnValue.number = *(DWORD *)src;
}
static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
{
AsnAny strValue;
strValue.asnType = type;
strValue.asnValue.string.stream = str;
strValue.asnValue.string.length = len;
strValue.asnValue.string.dynamic = TRUE;
SnmpUtilAsnAnyCpy(value, &strValue);
}
static void copyLengthPrecededString(AsnAny *value, void *src)
{
DWORD len = *(DWORD *)src;
setStringValue(value, ASN_OCTETSTRING, len, (BYTE *)src + sizeof(DWORD));
}
typedef void (*copyValueFunc)(AsnAny *value, void *src);
struct structToAsnValue
{
size_t offset;
copyValueFunc copy;
};
static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
{
/* OIDs are 1-based */
if (!id)
return SNMP_ERRORSTATUS_NOSUCHNAME;
--id;
if (id >= mapLen)
return SNMP_ERRORSTATUS_NOSUCHNAME;
if (!map[id].copy)
return SNMP_ERRORSTATUS_NOSUCHNAME;
map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
return SNMP_ERRORSTATUS_NOERROR;
}
static UINT mib2[] = { 1,3,6,1,2,1 };
static UINT mib2System[] = { 1,3,6,1,2,1,1 };
@ -127,9 +168,158 @@ static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
return TRUE;
}
static void copyOperStatus(AsnAny *value, void *src)
{
value->asnType = ASN_INTEGER;
/* The IPHlpApi definition of operational status differs from the MIB2 one,
* so map it to the MIB2 value.
*/
switch (*(DWORD *)src)
{
case MIB_IF_OPER_STATUS_OPERATIONAL:
value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
break;
case MIB_IF_OPER_STATUS_CONNECTING:
case MIB_IF_OPER_STATUS_CONNECTED:
value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
break;
default:
value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
};
}
static struct structToAsnValue mib2IfEntryMap[] = {
{ FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
{ FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
{ FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
{ FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
{ FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
};
static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
AsnInteger32 *pErrorStatus)
{
AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
pErrorStatus);
switch (bPduType)
{
case SNMP_PDU_GET:
case SNMP_PDU_GETNEXT:
if (!ifTable)
{
/* There is no interface present, so let the caller deal
* with finding the successor.
*/
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
}
else if (!SnmpUtilOidNCmp(&pVarBind->name, &entryOid, entryOid.idLength))
{
UINT tableIndex = 0, item = 0;
*pErrorStatus = 0;
if (pVarBind->name.idLength == entryOid.idLength ||
pVarBind->name.idLength == entryOid.idLength + 1)
{
/* Either the table or an element within the table is specified,
* but the instance is not.
*/
if (bPduType == SNMP_PDU_GET)
{
/* Can't get an interface entry without specifying the
* instance.
*/
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
}
else
{
/* Get the first interface */
tableIndex = 1;
if (pVarBind->name.idLength == entryOid.idLength + 1)
item = pVarBind->name.ids[entryOid.idLength];
else
item = 1;
}
}
else
{
tableIndex = pVarBind->name.ids[entryOid.idLength + 1];
item = pVarBind->name.ids[entryOid.idLength];
if (bPduType == SNMP_PDU_GETNEXT)
{
tableIndex++;
item = 1;
}
}
if (!*pErrorStatus)
{
assert(tableIndex);
assert(item);
if (tableIndex > ifTable->dwNumEntries)
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
else
{
*pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
DEFINE_SIZEOF(mib2IfEntryMap),
&ifTable->table[tableIndex - 1], item, bPduType,
pVarBind);
if (bPduType == SNMP_PDU_GETNEXT)
{
AsnObjectIdentifier oid;
SnmpUtilOidCpy(&pVarBind->name, &entryOid);
oid.idLength = 1;
oid.ids = &item;
SnmpUtilOidAppend(&pVarBind->name, &oid);
oid.idLength = 1;
oid.ids = &ifTable->table[tableIndex - 1].dwIndex;
SnmpUtilOidAppend(&pVarBind->name, &oid);
}
}
}
}
else
{
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
/* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
* need to set it here.
*/
}
break;
case SNMP_PDU_SET:
*pErrorStatus = SNMP_ERRORSTATUS_READONLY;
break;
default:
FIXME("0x%02x: unsupported PDU type\n", bPduType);
*pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
}
return TRUE;
}
/* This list MUST BE lexicographically sorted */
static struct mibImplementation supportedIDs[] = {
{ DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery },
{ DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery },
};
static UINT minSupportedIDLength;

View File

@ -60,7 +60,11 @@ static void testQuery(void)
UINT mib2System[] = { 1,3,6,1,2,1,1 };
UINT mib2If[] = { 1,3,6,1,2,1,2 };
UINT mib2IfTable[] = { 1,3,6,1,2,1,2,2 };
UINT mib2IfDescr[] = { 1,3,6,1,2,1,2,2,1,2 };
UINT mib2IfAdminStatus[] = { 1,3,6,1,2,1,2,2,1,7 };
UINT mib2IfOperStatus[] = { 1,3,6,1,2,1,2,2,1,8 };
SnmpVarBind vars[3], vars2[3];
UINT entry;
pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery");
if (!pQuery)
@ -119,6 +123,104 @@ static void testQuery(void)
/* The index is 1-based rather than 0-based */
ok(index == 1, "expected index 1, got %d\n", index);
/* A Get fails on something that specifies a table (but not a particular
* entry in it)...
*/
vars[0].name.idLength = sizeof(mib2IfDescr) / sizeof(mib2IfDescr[0]);
vars[0].name.ids = mib2IfDescr;
vars[1].name.idLength =
sizeof(mib2IfAdminStatus) / sizeof(mib2IfAdminStatus[0]);
vars[1].name.ids = mib2IfAdminStatus;
vars[2].name.idLength =
sizeof(mib2IfOperStatus) / sizeof(mib2IfOperStatus[0]);
vars[2].name.ids = mib2IfOperStatus;
list.len = 3;
SetLastError(0xdeadbeef);
error = 0xdeadbeef;
index = 0xdeadbeef;
ret = pQuery(SNMP_PDU_GET, &list, &error, &index);
ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError());
ok(error == SNMP_ERRORSTATUS_NOSUCHNAME,
"expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error);
ok(index == 1, "expected index 1, got %d\n", index);
/* but a GetNext succeeds with the same values, because GetNext gets the
* entry after the specified OID, not the entry specified by it. The
* successor to the table is the first entry in the table.
* The OIDs need to be allocated, because GetNext modifies them to indicate
* the end of data.
*/
SnmpUtilOidCpy(&vars2[0].name, &vars[0].name);
SnmpUtilOidCpy(&vars2[1].name, &vars[1].name);
SnmpUtilOidCpy(&vars2[2].name, &vars[2].name);
list.list = vars2;
moreData = TRUE;
entry = 1;
do {
SetLastError(0xdeadbeef);
error = 0xdeadbeef;
index = 0xdeadbeef;
ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index);
ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError());
ok(error == SNMP_ERRORSTATUS_NOERROR,
"expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error);
ok(index == 0, "expected index 0, got %d\n", index);
if (!ret)
moreData = FALSE;
else if (error)
moreData = FALSE;
else if (SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name,
vars[0].name.idLength))
moreData = FALSE;
else if (SnmpUtilOidNCmp(&vars2[1].name, &vars[1].name,
vars[1].name.idLength))
moreData = FALSE;
else if (SnmpUtilOidNCmp(&vars2[2].name, &vars[2].name,
vars[2].name.idLength))
moreData = FALSE;
if (moreData)
{
/* Check the OIDs. For these types of values (display strings and
* integers) they increase by 1 for each element of the table.
*/
ok(vars2[0].name.idLength == vars[0].name.idLength + 1,
"expected length %d, got %d\n", vars[0].name.idLength + 1,
vars2[0].name.idLength);
ok(vars2[0].name.ids[vars2[0].name.idLength - 1] == entry,
"expected %d, got %d\n", entry,
vars2[0].name.ids[vars2[0].name.idLength - 1]);
ok(vars2[1].name.idLength == vars[1].name.idLength + 1,
"expected length %d, got %d\n", vars[1].name.idLength + 1,
vars2[1].name.idLength);
ok(vars2[1].name.ids[vars2[1].name.idLength - 1] == entry,
"expected %d, got %d\n", entry,
vars2[1].name.ids[vars2[1].name.idLength - 1]);
ok(vars2[2].name.idLength == vars[2].name.idLength + 1,
"expected length %d, got %d\n", vars[2].name.idLength + 1,
vars2[2].name.idLength);
ok(vars2[2].name.ids[vars2[2].name.idLength - 1] == entry,
"expected %d, got %d\n", entry,
vars2[2].name.ids[vars2[2].name.idLength - 1]);
++entry;
/* Check the types while we're at it */
ok(vars2[0].value.asnType == ASN_OCTETSTRING,
"expected ASN_OCTETSTRING, got %02x\n", vars2[0].value.asnType);
ok(vars2[1].value.asnType == ASN_INTEGER,
"expected ASN_INTEGER, got %02x\n", vars2[1].value.asnType);
ok(vars2[2].value.asnType == ASN_INTEGER,
"expected ASN_INTEGER, got %02x\n", vars2[2].value.asnType);
/* Check that the operational status of an interface correctly
* follows the MIB2 definition of it, rather than the values
* defined for IPHlpApi's dwOperStatus field.
*/
ok(vars2[2].value.asnValue.unsigned32 <= 2,
"expected a value of 0, 1, or 2, got %u\n",
vars2[2].value.asnValue.unsigned32);
}
} while (moreData);
SnmpUtilVarBindFree(&vars2[0]);
SnmpUtilVarBindFree(&vars2[1]);
SnmpUtilVarBindFree(&vars2[2]);
/* Even though SnmpExtensionInit says this DLL supports the MIB2 system
* variables, the first variable it returns a value for is the first
* interface.