1042 lines
35 KiB
C
1042 lines
35 KiB
C
/*
|
|
* Copyright 2008 Juan Lang
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <assert.h>
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "snmp.h"
|
|
#include "iphlpapi.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
|
|
|
|
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
|
{
|
|
TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
|
|
|
|
switch (fdwReason)
|
|
{
|
|
case DLL_WINE_PREATTACH:
|
|
return FALSE; /* prefer native version */
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls(hinstDLL);
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Utility functions
|
|
*/
|
|
static void copyInt(AsnAny *value, void *src)
|
|
{
|
|
value->asnType = ASN_INTEGER;
|
|
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 void copyIpAddr(AsnAny *value, void *src)
|
|
{
|
|
setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
|
|
}
|
|
|
|
static UINT mib2[] = { 1,3,6,1,2,1 };
|
|
static UINT mib2System[] = { 1,3,6,1,2,1,1 };
|
|
|
|
typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus);
|
|
|
|
struct mibImplementation
|
|
{
|
|
AsnObjectIdentifier name;
|
|
void (*init)(void);
|
|
varqueryfunc query;
|
|
};
|
|
|
|
static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
|
|
static PMIB_IFTABLE ifTable;
|
|
|
|
static void mib2IfNumberInit(void)
|
|
{
|
|
DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
|
|
|
|
if (ret == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
ifTable = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (ifTable)
|
|
GetIfTable(ifTable, &size, FALSE);
|
|
}
|
|
}
|
|
|
|
static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
if ((bPduType == SNMP_PDU_GET &&
|
|
!SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
|
|
|| SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
|
|
< 0)
|
|
{
|
|
DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
|
|
|
|
copyInt(&pVarBind->value, &numIfs);
|
|
if (bPduType == SNMP_PDU_GETNEXT)
|
|
SnmpUtilOidCpy(&pVarBind->name, &numberOid);
|
|
*pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
};
|
|
}
|
|
|
|
/* Given an OID and a base OID that it must begin with, finds the item and
|
|
* integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
|
|
* foo, returns item 1 and instance 2.
|
|
* If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
|
|
* missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
|
|
* If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
|
|
* instance, or item 1, instance 1 if either is missing.
|
|
*/
|
|
static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
|
|
AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
|
|
{
|
|
AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GETNEXT:
|
|
if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
|
|
{
|
|
*item = 1;
|
|
*instance = 1;
|
|
}
|
|
else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
|
|
{
|
|
if (oid->idLength == base->idLength ||
|
|
oid->idLength == base->idLength + 1)
|
|
{
|
|
/* Either the table or an item within the table is specified,
|
|
* but the instance is not. Get the first instance.
|
|
*/
|
|
*instance = 1;
|
|
if (oid->idLength == base->idLength + 1)
|
|
*item = oid->ids[base->idLength];
|
|
else
|
|
*item = 1;
|
|
}
|
|
else
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
*instance = oid->ids[base->idLength + 1] + 1;
|
|
}
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
break;
|
|
default:
|
|
if (!SnmpUtilOidNCmp(oid, base, base->idLength))
|
|
{
|
|
if (oid->idLength == base->idLength ||
|
|
oid->idLength == base->idLength + 1)
|
|
{
|
|
/* Either the table or an item within the table is specified,
|
|
* but the instance is not.
|
|
*/
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
else
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
*instance = oid->ids[base->idLength + 1];
|
|
}
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Given an OID and a base OID that it must begin with, finds the item from the
|
|
* OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
|
|
* If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
|
|
* SNMP_ERRORSTATUS_NOSUCHNAME.
|
|
* If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
|
|
* 1 if the item is missing.
|
|
*/
|
|
static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
|
|
AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
|
|
{
|
|
AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GETNEXT:
|
|
if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
|
|
*item = 1;
|
|
else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
|
|
{
|
|
if (oid->idLength == base->idLength)
|
|
{
|
|
/* The item is missing, assume the first item */
|
|
*item = 1;
|
|
}
|
|
else
|
|
*item = oid->ids[base->idLength] + 1;
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
break;
|
|
default:
|
|
if (!SnmpUtilOidNCmp(oid, base, base->idLength))
|
|
{
|
|
if (oid->idLength == base->idLength)
|
|
{
|
|
/* The item is missing */
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
else
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
if (!*item)
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
struct GenericTable
|
|
{
|
|
DWORD numEntries;
|
|
BYTE entries[1];
|
|
};
|
|
|
|
/* Finds the index in table whose IP address (at offset addressOffset within the
|
|
* entry) matches that given the OID, which is assumed to have at least 4 IDs.
|
|
*/
|
|
static UINT findOIDIPAddressInTable(AsnObjectIdentifier *oid,
|
|
struct GenericTable *table, size_t tableEntrySize, size_t addressOffset)
|
|
{
|
|
DWORD addr;
|
|
UINT i, index = 0;
|
|
|
|
/* Map the IDs to an IP address in little-endian order */
|
|
addr = (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
|
|
(BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
|
|
/* Find the item whose address matches */
|
|
for (i = 0; !index && i < table->numEntries; i++)
|
|
{
|
|
DWORD tableAddr =
|
|
*(DWORD *)(table->entries + i * tableEntrySize + addressOffset);
|
|
|
|
if (addr == tableAddr)
|
|
index = i + 1;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
/* Given an OID and a base OID that it must begin with, finds the item and
|
|
* element of the table whose IP address matches the instance from the OID.
|
|
* E.g., given an OID foo.1.2.3.4.5 and a base OID foo, returns item 1 and the
|
|
* index of the entry in the table whose IP address is 2.3.4.5.
|
|
* If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
|
|
* missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
|
|
* If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
|
|
* instance, or item 1, instance 1 if either is missing.
|
|
*/
|
|
static AsnInteger32 getItemAndIpAddressInstanceFromOid(AsnObjectIdentifier *oid,
|
|
AsnObjectIdentifier *base, BYTE bPduType, struct GenericTable *table,
|
|
size_t tableEntrySize, size_t addressOffset, UINT *item, UINT *instance)
|
|
{
|
|
AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
|
|
|
|
if (!table)
|
|
return SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GETNEXT:
|
|
if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
|
|
{
|
|
/* Return the first item and instance from the table */
|
|
*item = 1;
|
|
*instance = 1;
|
|
}
|
|
else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
|
|
oid->idLength < base->idLength + 5)
|
|
{
|
|
/* Either the table or an item is specified, but the instance is
|
|
* not.
|
|
*/
|
|
*instance = 1;
|
|
if (oid->idLength >= base->idLength + 1)
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
if (!*item)
|
|
*item = 1;
|
|
}
|
|
else
|
|
*item = 1;
|
|
}
|
|
else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
|
|
oid->idLength == base->idLength + 5)
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
if (!*item)
|
|
{
|
|
*instance = 1;
|
|
*item = 1;
|
|
}
|
|
else
|
|
{
|
|
AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
|
|
};
|
|
|
|
*instance = findOIDIPAddressInTable(&ipOid, table,
|
|
tableEntrySize, addressOffset) + 1;
|
|
if (*instance > table->numEntries)
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
break;
|
|
default:
|
|
if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
|
|
oid->idLength == base->idLength + 5)
|
|
{
|
|
*item = oid->ids[base->idLength];
|
|
if (!*item)
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
else
|
|
{
|
|
AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
|
|
};
|
|
|
|
*instance = findOIDIPAddressInTable(&ipOid, table,
|
|
tableEntrySize, addressOffset);
|
|
if (!*instance)
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
}
|
|
else
|
|
ret = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
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
|
|
{
|
|
UINT tableIndex = 0, item = 0;
|
|
|
|
*pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
|
|
&entryOid, bPduType, &item, &tableIndex);
|
|
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);
|
|
/* According to RFC1158, the value of the interface
|
|
* index must vary between 1 and ifNumber (the number
|
|
* of interfaces), so use the 1-based table index
|
|
* directly, rather than assuming that IPHlpApi's
|
|
* dwIndex will have the correct range.
|
|
*/
|
|
oid.idLength = 1;
|
|
oid.ids = &tableIndex;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
|
|
static MIB_IPSTATS ipStats;
|
|
|
|
static void mib2IpStatsInit(void)
|
|
{
|
|
GetIpStatistics(&ipStats);
|
|
}
|
|
|
|
static struct structToAsnValue mib2IpMap[] = {
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
|
|
{ 0, NULL }, /* 20: not used, IP addr table */
|
|
{ 0, NULL }, /* 21: not used, route table */
|
|
{ 0, NULL }, /* 22: not used, net to media (ARP) table */
|
|
{ FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
|
|
};
|
|
|
|
static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
|
|
UINT item = 0;
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
*pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
|
|
&item);
|
|
if (!*pErrorStatus)
|
|
{
|
|
*pErrorStatus = mapStructEntryToValue(mib2IpMap,
|
|
DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
|
|
if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
|
|
{
|
|
AsnObjectIdentifier oid;
|
|
|
|
SnmpUtilOidCpy(&pVarBind->name, &myOid);
|
|
oid.idLength = 1;
|
|
oid.ids = &item;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
|
|
static PMIB_IPADDRTABLE ipAddrTable;
|
|
|
|
static struct structToAsnValue mib2IpAddrMap[] = {
|
|
{ FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
|
|
{ FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
|
|
{ FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
|
|
};
|
|
|
|
static void mib2IpAddrInit(void)
|
|
{
|
|
DWORD size = 0, ret = GetIpAddrTable(NULL, &size, FALSE);
|
|
|
|
if (ret == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
ipAddrTable = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (ipAddrTable)
|
|
GetIpAddrTable(ipAddrTable, &size, FALSE);
|
|
}
|
|
}
|
|
|
|
static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
|
|
UINT tableIndex = 0, item = 0;
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
*pErrorStatus = getItemAndIpAddressInstanceFromOid(&pVarBind->name,
|
|
&myOid, bPduType, (struct GenericTable *)ipAddrTable,
|
|
sizeof(MIB_IPADDRROW), FIELD_OFFSET(MIB_IPADDRROW, dwAddr), &item,
|
|
&tableIndex);
|
|
if (!*pErrorStatus)
|
|
{
|
|
assert(tableIndex);
|
|
assert(item);
|
|
*pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
|
|
DEFINE_SIZEOF(mib2IpAddrMap),
|
|
&ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
|
|
if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
|
|
{
|
|
UINT id;
|
|
BYTE *ptr;
|
|
AsnObjectIdentifier oid;
|
|
|
|
SnmpUtilOidCpy(&pVarBind->name, &myOid);
|
|
oid.idLength = 1;
|
|
oid.ids = &id;
|
|
id = item;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
for (ptr = (BYTE *)&ipAddrTable->table[tableIndex - 1].dwAddr;
|
|
ptr < (BYTE *)&ipAddrTable->table[tableIndex - 1].dwAddr +
|
|
sizeof(DWORD); ptr++)
|
|
{
|
|
id = *ptr;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
|
|
static PMIB_IPFORWARDTABLE ipRouteTable;
|
|
|
|
static struct structToAsnValue mib2IpRouteMap[] = {
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
|
|
{ FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
|
|
};
|
|
|
|
static void mib2IpRouteInit(void)
|
|
{
|
|
DWORD size = 0, ret = GetIpForwardTable(NULL, &size, FALSE);
|
|
|
|
if (ret == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
ipRouteTable = HeapAlloc(GetProcessHeap(), 0, size);
|
|
if (ipRouteTable)
|
|
GetIpForwardTable(ipRouteTable, &size, FALSE);
|
|
}
|
|
}
|
|
|
|
static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
|
|
UINT tableIndex = 0, item = 0;
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
*pErrorStatus = getItemAndIpAddressInstanceFromOid(&pVarBind->name,
|
|
&myOid, bPduType, (struct GenericTable *)ipRouteTable,
|
|
sizeof(MIB_IPFORWARDROW),
|
|
FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), &item, &tableIndex);
|
|
if (!*pErrorStatus)
|
|
{
|
|
assert(tableIndex);
|
|
assert(item);
|
|
*pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
|
|
DEFINE_SIZEOF(mib2IpRouteMap),
|
|
&ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
|
|
if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
|
|
{
|
|
UINT id;
|
|
BYTE *ptr;
|
|
AsnObjectIdentifier oid;
|
|
|
|
SnmpUtilOidCpy(&pVarBind->name, &myOid);
|
|
oid.idLength = 1;
|
|
oid.ids = &id;
|
|
id = item;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
for (ptr =
|
|
(BYTE *)&ipRouteTable->table[tableIndex - 1].dwForwardDest;
|
|
ptr <
|
|
(BYTE *)&ipRouteTable->table[tableIndex - 1].dwForwardDest
|
|
+ sizeof(DWORD); ptr++)
|
|
{
|
|
id = *ptr;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
|
|
static MIB_ICMP icmpStats;
|
|
|
|
static void mib2IcmpInit(void)
|
|
{
|
|
GetIcmpStatistics(&icmpStats);
|
|
}
|
|
|
|
static struct structToAsnValue mib2IcmpMap[] = {
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
|
|
{ FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
|
|
};
|
|
|
|
static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
|
|
UINT item = 0;
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
*pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
|
|
&item);
|
|
if (!*pErrorStatus)
|
|
{
|
|
*pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
|
|
DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
|
|
pVarBind);
|
|
if (!*pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier oid;
|
|
|
|
SnmpUtilOidCpy(&pVarBind->name, &myOid);
|
|
oid.idLength = 1;
|
|
oid.ids = &item;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
|
|
static MIB_TCPSTATS tcpStats;
|
|
|
|
static void mib2TcpInit(void)
|
|
{
|
|
GetTcpStatistics(&tcpStats);
|
|
}
|
|
|
|
static struct structToAsnValue mib2TcpMap[] = {
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
|
|
{ FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
|
|
};
|
|
|
|
static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
|
|
AsnInteger32 *pErrorStatus)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
|
|
UINT item = 0;
|
|
|
|
TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
|
|
pErrorStatus);
|
|
|
|
switch (bPduType)
|
|
{
|
|
case SNMP_PDU_GET:
|
|
case SNMP_PDU_GETNEXT:
|
|
*pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
|
|
&item);
|
|
if (!*pErrorStatus)
|
|
{
|
|
*pErrorStatus = mapStructEntryToValue(mib2TcpMap,
|
|
DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
|
|
if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
|
|
{
|
|
AsnObjectIdentifier oid;
|
|
|
|
SnmpUtilOidCpy(&pVarBind->name, &myOid);
|
|
oid.idLength = 1;
|
|
oid.ids = &item;
|
|
SnmpUtilOidAppend(&pVarBind->name, &oid);
|
|
}
|
|
}
|
|
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 },
|
|
{ DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery },
|
|
{ DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery },
|
|
{ DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery },
|
|
{ DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery },
|
|
{ DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery },
|
|
};
|
|
static UINT minSupportedIDLength;
|
|
|
|
BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
|
|
HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
|
|
{
|
|
AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
|
|
UINT i;
|
|
|
|
TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
|
|
pFirstSupportedRegion);
|
|
|
|
minSupportedIDLength = UINT_MAX;
|
|
for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
|
|
{
|
|
if (supportedIDs[i].init)
|
|
supportedIDs[i].init();
|
|
if (supportedIDs[i].name.idLength < minSupportedIDLength)
|
|
minSupportedIDLength = supportedIDs[i].name.idLength;
|
|
}
|
|
*phSubagentTrapEvent = NULL;
|
|
SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
|
|
return TRUE;
|
|
}
|
|
|
|
static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
|
|
UINT *matchingIndex)
|
|
{
|
|
int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
|
|
struct mibImplementation *impl = NULL;
|
|
AsnObjectIdentifier oid1 = { idLength, ids};
|
|
|
|
if (!idLength)
|
|
return NULL;
|
|
for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
|
|
i = (indexLow + indexHigh) / 2)
|
|
{
|
|
INT cmp;
|
|
|
|
cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
|
|
if (!cmp)
|
|
{
|
|
impl = &supportedIDs[i];
|
|
*matchingIndex = i;
|
|
}
|
|
else if (cmp > 0)
|
|
indexLow = i + 1;
|
|
else
|
|
indexHigh = i - 1;
|
|
}
|
|
return impl;
|
|
}
|
|
|
|
BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
|
|
AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
|
|
{
|
|
AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
|
|
AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
|
|
UINT i;
|
|
|
|
TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
|
|
pErrorStatus, pErrorIndex);
|
|
|
|
for (i = 0; !error && i < pVarBindList->len; i++)
|
|
{
|
|
/* Ignore any OIDs not in MIB2 */
|
|
if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
|
|
mib2oid.idLength))
|
|
{
|
|
struct mibImplementation *impl = NULL;
|
|
UINT len, matchingIndex = 0;
|
|
|
|
TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
|
|
/* Search for an implementation matching as many octets as possible
|
|
*/
|
|
for (len = pVarBindList->list[i].name.idLength;
|
|
len >= minSupportedIDLength && !impl; len--)
|
|
impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
|
|
&matchingIndex);
|
|
if (impl && impl->query)
|
|
impl->query(bPduType, &pVarBindList->list[i], &error);
|
|
else
|
|
error = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
|
|
bPduType == SNMP_PDU_GETNEXT)
|
|
{
|
|
/* GetNext is special: it finds the successor to the given OID,
|
|
* so we have to continue until an implementation handles the
|
|
* query or we exhaust the table of supported OIDs.
|
|
*/
|
|
for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
|
|
matchingIndex < DEFINE_SIZEOF(supportedIDs);
|
|
matchingIndex++)
|
|
{
|
|
error = SNMP_ERRORSTATUS_NOERROR;
|
|
impl = &supportedIDs[matchingIndex];
|
|
if (impl->query)
|
|
impl->query(bPduType, &pVarBindList->list[i], &error);
|
|
else
|
|
error = SNMP_ERRORSTATUS_NOSUCHNAME;
|
|
}
|
|
/* If the query still isn't resolved, set the OID to the
|
|
* successor to the last entry in the table.
|
|
*/
|
|
if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
|
|
{
|
|
SnmpUtilOidFree(&pVarBindList->list[i].name);
|
|
SnmpUtilOidCpy(&pVarBindList->list[i].name,
|
|
&supportedIDs[matchingIndex - 1].name);
|
|
pVarBindList->list[i].name.ids[
|
|
pVarBindList->list[i].name.idLength - 1] += 1;
|
|
}
|
|
}
|
|
if (error)
|
|
errorIndex = i + 1;
|
|
}
|
|
}
|
|
*pErrorStatus = error;
|
|
*pErrorIndex = errorIndex;
|
|
return TRUE;
|
|
}
|