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; }
static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip); UINT item = 0; BOOL ret = TRUE; 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, pVarBind); if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) ret = setOidWithItem(&pVarBind->name, &myOid, item); } break; case SNMP_PDU_SET: *pErrorStatus = SNMP_ERRORSTATUS_READONLY; ret = FALSE; break; default: FIXME("0x%02x: unsupported PDU type\n", bPduType); *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry); BOOL ret = TRUE; TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), pErrorStatus); switch (bPduType) { case SNMP_PDU_GET: case SNMP_PDU_GETNEXT: if (!udpTable) *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; else { UINT tableIndex = 0, item = 0; *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid, 5, bPduType, (struct GenericTable *)udpTable, sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item, &tableIndex); if (!*pErrorStatus) { assert(tableIndex); assert(item); *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap, DEFINE_SIZEOF(mib2UdpEntryMap), &udpTable->table[tableIndex - 1], item, pVarBind); if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) { AsnObjectIdentifier oid; ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, udpTable->table[tableIndex - 1].dwLocalAddr); if (ret) { oid.idLength = 1; oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort; ret = SnmpUtilOidAppend(&pVarBind->name, &oid); } } } } break; case SNMP_PDU_SET: *pErrorStatus = SNMP_ERRORSTATUS_READONLY; ret = FALSE; break; default: FIXME("0x%02x: unsupported PDU type\n", bPduType); *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry); BOOL ret = TRUE; 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, pVarBind); if (bPduType == SNMP_PDU_GETNEXT) ret = setOidWithItemAndInteger(&pVarBind->name, &entryOid, item, tableIndex); } } } break; case SNMP_PDU_SET: *pErrorStatus = SNMP_ERRORSTATUS_READONLY; ret = FALSE; break; default: FIXME("0x%02x: unsupported PDU type\n", bPduType); *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet); TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), pErrorStatus); switch (bPduType) { case SNMP_PDU_GET: case SNMP_PDU_GETNEXT: if (!ipNetTable) *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; else { UINT tableIndex = 0, item = 0; *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name, &myOid, bPduType, &item, &tableIndex); if (!*pErrorStatus) { assert(tableIndex); assert(item); if (tableIndex > ipNetTable->dwNumEntries) *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; else { *pErrorStatus = mapStructEntryToValue(mib2IpNetMap, DEFINE_SIZEOF(mib2IpNetMap), &ipNetTable[tableIndex - 1], item, bPduType, pVarBind); if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) setOidWithItemAndInteger(&pVarBind->name, &myOid, item, tableIndex); } } } 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 BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind, AsnInteger32 *pErrorStatus) { AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute); UINT tableIndex = 0, item = 0; BOOL ret = TRUE; TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name), pErrorStatus); switch (bPduType) { case SNMP_PDU_GET: case SNMP_PDU_GETNEXT: *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable, sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow, &item, &tableIndex); if (!*pErrorStatus) { assert(tableIndex); assert(item); *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap, DEFINE_SIZEOF(mib2IpRouteMap), &ipRouteTable->table[tableIndex - 1], item, pVarBind); if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, ipRouteTable->table[tableIndex - 1].dwForwardDest); } break; case SNMP_PDU_SET: *pErrorStatus = SNMP_ERRORSTATUS_READONLY; ret = FALSE; break; default: FIXME("0x%02x: unsupported PDU type\n", bPduType); *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }
static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength, UINT *matchingIndex) { int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0; AsnObjectIdentifier oid1 = { idLength, ids}; if (!idLength) return NULL; while (indexLow <= indexHigh) { INT cmp, i = (indexLow + indexHigh) / 2; if (!(cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength))) { *matchingIndex = i; return &supportedIDs[i]; } if (cmp > 0) indexLow = i + 1; else indexHigh = i - 1; } return NULL; }
static void testQuery(void) { BOOL (WINAPI *pQuery)(BYTE, SnmpVarBindList *, AsnInteger32 *, AsnInteger32 *); BOOL ret, moreData, noChange; SnmpVarBindList list; AsnInteger32 error, index; UINT bogus[] = { 1,2,3,4 }; 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 }; UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1,1 }; UINT mib2IpRouteTable[] = { 1,3,6,1,2,1,4,21,1,1 }; UINT mib2UdpTable[] = { 1,3,6,1,2,1,7,5,1,1 }; SnmpVarBind vars[3], vars2[3], vars3[3]; UINT entry; pQuery = (void *)GetProcAddress(inetmib1, "SnmpExtensionQuery"); if (!pQuery) { win_skip("couldn't find SnmpExtensionQuery\n"); return; } /* Crash ret = pQuery(0, NULL, NULL, NULL); ret = pQuery(0, NULL, &error, NULL); ret = pQuery(0, NULL, NULL, &index); ret = pQuery(0, &list, NULL, NULL); ret = pQuery(0, &list, &error, NULL); */ /* An empty list succeeds */ list.len = 0; error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); /* Oddly enough, this "succeeds," even though the OID is clearly * unsupported. */ vars[0].name.idLength = sizeof(bogus) / sizeof(bogus[0]); vars[0].name.ids = bogus; vars[0].value.asnType = 0; list.len = 1; list.list = vars; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR || error == ERROR_FILE_NOT_FOUND /* Win9x */, "expected SNMP_ERRORSTATUS_NOERROR or ERROR_FILE_NOT_FOUND, got %d\n", error); if (error == SNMP_ERRORSTATUS_NOERROR) ok(index == 0, "expected index 0, got %d\n", index); else if (error == ERROR_FILE_NOT_FOUND) ok(index == 1, "expected index 1, got %d\n", index); /* The OID isn't changed either: */ ok(!strcmp("1.2.3.4", SnmpUtilOidToA(&vars[0].name)), "expected 1.2.3.4, got %s\n", SnmpUtilOidToA(&vars[0].name)); /* The table is not an accessible variable, so it fails */ vars[0].name.idLength = sizeof(mib2IfTable) / sizeof(mib2IfTable[0]); vars[0].name.ids = mib2IfTable; SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GET, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOSUCHNAME, "expected SNMP_ERRORSTATUS_NOSUCHNAME, got %d\n", error); /* 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, %d\n", error, index); 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; noChange = FALSE; entry = 0; do { SetLastError(0xdeadbeef); error = 0xdeadbeef; index = 0xdeadbeef; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); 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; else if (!SnmpUtilOidCmp(&vars[0].name, &vars2[0].name) || !SnmpUtilOidCmp(&vars[1].name, &vars2[1].name) || !SnmpUtilOidCmp(&vars[2].name, &vars2[2].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { UINT lastID; /* Check the OIDs. For these types of values (display strings and * integers) they should increase by 1 for each element of the table * according to RFC 1158. Windows sometimes has a weird value in the * table, so allow any value as long as it's greater than the previous * value on Windows. */ 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); lastID = vars2[0].name.ids[vars2[0].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); 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); lastID = vars2[1].name.ids[vars2[1].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); 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); lastID = vars2[2].name.ids[vars2[2].name.idLength - 1]; ok(lastID == entry + 1 || broken(lastID > entry), "expected %d, got %d\n", entry + 1, lastID); entry = lastID; /* 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); } else if (noChange) skip("no change in OID, no MIB2 IF table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); SnmpUtilVarBindFree(&vars2[1]); SnmpUtilVarBindFree(&vars2[2]); /* Even though SnmpExtensionInit says this DLL supports the MIB2 system * variables, on recent systems (at least Win2k) the first variable it * returns a value for is the first interface. */ vars[0].name.idLength = sizeof(mib2System) / sizeof(mib2System[0]); vars[0].name.ids = mib2System; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); ok(error == SNMP_ERRORSTATUS_NOERROR, "expected SNMP_ERRORSTATUS_NOERROR, got %d\n", error); ok(index == 0, "expected index 0, got %d\n", index); vars3[0].name.idLength = sizeof(mib2If) / sizeof(mib2If[0]); vars3[0].name.ids = mib2If; ok(!SnmpUtilOidNCmp(&vars2[0].name, &vars[0].name, vars[0].name.idLength) || !SnmpUtilOidNCmp(&vars2[0].name, &vars3[0].name, vars3[0].name.idLength), "expected 1.3.6.1.2.1.1 or 1.3.6.1.2.1.2, got %s\n", SnmpUtilOidToA(&vars2[0].name)); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP address table */ vars[0].name.idLength = sizeof(mib2IpAddr) / sizeof(mib2IpAddr[0]); vars[0].name.ids = mib2IpAddr; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); 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 (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* This looks uglier than it is: the base OID for the IP * address, 1.3.6.1.2.1.4.20.1.1, is appended with the IP * address of the entry. So e.g. the loopback address is * identified in MIB2 as 1.3.6.1.2.1.4.20.1.1.127.0.0.1 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP address table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the IP route table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2IpRouteTable); vars[0].name.ids = mib2IpRouteTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); 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 (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. * FIXME: don't know if IPv6 addrs are shared with this table. * Don't think so, but I'm not certain. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 4, "expected length %d, got %d\n", vars[0].name.idLength + 4, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* The base OID for the route table, 1.3.6.1.2.1.4.21.1.1, is * appended with the dest IP address of the entry. So e.g. a * route entry for 224.0.0.0 is identified in MIB2 as * 1.3.6.1.2.1.4.21.1.1.224.0.0.0 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 4 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 4 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 IP route table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); /* Check the type and OIDs of the UDP table */ vars[0].name.idLength = DEFINE_SIZEOF(mib2UdpTable); vars[0].name.ids = mib2UdpTable; SnmpUtilOidCpy(&vars2[0].name, &vars[0].name); vars2[0].value.asnType = 0; list.len = 1; list.list = vars2; moreData = TRUE; noChange = FALSE; do { ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); ok(ret, "SnmpExtensionQuery failed: %d, %d\n", error, index); /* FIXME: error and index aren't checked here because the UDP table is * the last OID currently supported by Wine, so the last GetNext fails. * todo_wine is also not effective because it will succeed for all but * the last GetNext. Remove the if (0) if any later OID is supported * by Wine. */ if (0) { 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 (!SnmpUtilOidCmp(&vars2[0].name, &vars[0].name)) { /* If the OID isn't modified, the function isn't implemented on this * platform, skip the remaining tests. */ noChange = TRUE; } if (moreData) { /* Make sure the size of the OID is right. */ ok(vars2[0].name.idLength == vars[0].name.idLength + 5, "expected length %d, got %d\n", vars[0].name.idLength + 5, vars2[0].name.idLength); /* Make sure the type is right */ ok(vars2[0].value.asnType == ASN_IPADDRESS, "expected type ASN_IPADDRESS, got %02x\n", vars2[0].value.asnType); if (vars2[0].value.asnType == ASN_IPADDRESS) { UINT i; /* Again with the ugly: the base OID for the UDP table, * 1.3.6.1.2.1.7.5.1, is appended with the local IP address and * port number of the entry. So e.g. an entry for * 192.168.1.1:4000 is identified in MIB2 as * 1.3.6.1.2.1.7.5.1.192.168.1.1.4000 */ for (i = 0; i < vars2[0].value.asnValue.address.length; i++) { ok(vars2[0].value.asnValue.address.stream[i] == vars2[0].name.ids[vars2[0].name.idLength - 5 + i], "expected ident byte %d to be %d, got %d\n", i, vars2[0].value.asnValue.address.stream[i], vars2[0].name.ids[vars2[0].name.idLength - 5 + i]); } } } else if (noChange) skip("no change in OID, no MIB2 UDP table implementation\n"); } while (moreData && !noChange); SnmpUtilVarBindFree(&vars2[0]); }
/***************************************************************************** * SnmpExtensionQuery [INETMIB1.@] */ 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; BOOL ret = TRUE; 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) ret = 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 (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME && matchingIndex < DEFINE_SIZEOF(supportedIDs); matchingIndex++) { error = SNMP_ERRORSTATUS_NOERROR; impl = &supportedIDs[matchingIndex]; if (impl->query) ret = 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); ret = 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 ret; }