inetmib1: Support the MIB2 interface table.
This commit is contained in:
parent
f913252ea2
commit
c531c11734
@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include <assert.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
@ -57,6 +57,47 @@ static void copyInt(AsnAny *value, void *src)
|
|||||||
value->asnValue.number = *(DWORD *)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 mib2[] = { 1,3,6,1,2,1 };
|
||||||
static UINT mib2System[] = { 1,3,6,1,2,1,1 };
|
static UINT mib2System[] = { 1,3,6,1,2,1,1 };
|
||||||
|
|
||||||
@ -127,9 +168,158 @@ static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|||||||
return TRUE;
|
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 */
|
/* This list MUST BE lexicographically sorted */
|
||||||
static struct mibImplementation supportedIDs[] = {
|
static struct mibImplementation supportedIDs[] = {
|
||||||
{ DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery },
|
{ DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery },
|
||||||
|
{ DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery },
|
||||||
};
|
};
|
||||||
static UINT minSupportedIDLength;
|
static UINT minSupportedIDLength;
|
||||||
|
|
||||||
|
@ -60,7 +60,11 @@ static void testQuery(void)
|
|||||||
UINT mib2System[] = { 1,3,6,1,2,1,1 };
|
UINT mib2System[] = { 1,3,6,1,2,1,1 };
|
||||||
UINT mib2If[] = { 1,3,6,1,2,1,2 };
|
UINT mib2If[] = { 1,3,6,1,2,1,2 };
|
||||||
UINT mib2IfTable[] = { 1,3,6,1,2,1,2,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];
|
SnmpVarBind vars[3], vars2[3];
|
||||||
|
UINT entry;
|
||||||
|
|
||||||
pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery");
|
pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery");
|
||||||
if (!pQuery)
|
if (!pQuery)
|
||||||
@ -119,6 +123,104 @@ static void testQuery(void)
|
|||||||
/* The index is 1-based rather than 0-based */
|
/* The index is 1-based rather than 0-based */
|
||||||
ok(index == 1, "expected index 1, got %d\n", index);
|
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
|
/* Even though SnmpExtensionInit says this DLL supports the MIB2 system
|
||||||
* variables, the first variable it returns a value for is the first
|
* variables, the first variable it returns a value for is the first
|
||||||
* interface.
|
* interface.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user