inetmib1: Support the MIB2 interface table.
This commit is contained in:
parent
f913252ea2
commit
c531c11734
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue