diff --git a/dlls/inetmib1/main.c b/dlls/inetmib1/main.c index 2ee0ba9b1a9..5e87b8cd4a4 100644 --- a/dlls/inetmib1/main.c +++ b/dlls/inetmib1/main.c @@ -19,7 +19,7 @@ #include "config.h" #include - +#include #include "windef.h" #include "winbase.h" #include "snmp.h" @@ -51,10 +51,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 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 }; @@ -72,9 +76,11 @@ static void mib2IfNumberInit(void) } } +/* This list MUST BE lexicographically sorted */ static struct mibImplementation supportedIDs[] = { { DEFINE_OID(mib2IfNumber), mib2IfNumberInit }, }; +static UINT minSupportedIDLength; BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference, HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion) @@ -85,14 +91,47 @@ BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference, 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) { @@ -109,8 +148,52 @@ BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList, if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid, mib2oid.idLength)) { - FIXME("%s: stub\n", SnmpUtilOidToA(&pVarBindList->list[i].name)); - error = SNMP_ERRORSTATUS_NOSUCHNAME; + 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; diff --git a/dlls/inetmib1/tests/main.c b/dlls/inetmib1/tests/main.c index 8667995bf74..6e4627e6ff4 100644 --- a/dlls/inetmib1/tests/main.c +++ b/dlls/inetmib1/tests/main.c @@ -117,7 +117,6 @@ static void testQuery(void) ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); /* The index is 1-based rather than 0-based */ - todo_wine ok(index == 1, "expected index 1, got %d\n", index); /* Even though SnmpExtensionInit says this DLL supports the MIB2 system @@ -133,13 +132,13 @@ static void testQuery(void) moreData = TRUE; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); - todo_wine + todo_wine { ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); + } vars[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]); vars[0].name.ids = mib2If; - todo_wine ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength), "expected 1.3.6.1.2.1.2, got %s\n", SnmpUtilOidToA(&vars2[0].name)); SnmpUtilVarBindFree(&vars2[0]);