From 8f66c13e3512821f2f0e3b1bcccd61ed1366eaf0 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Sat, 28 Jun 2008 09:21:14 -0700 Subject: [PATCH] inetmib1: Support the MIB2 UDP table. --- dlls/inetmib1/main.c | 93 ++++++++++++++++++++++++++++++++++++++ dlls/inetmib1/tests/main.c | 63 ++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/dlls/inetmib1/main.c b/dlls/inetmib1/main.c index 2dba6cfef1c..56e52a20bf7 100644 --- a/dlls/inetmib1/main.c +++ b/dlls/inetmib1/main.c @@ -1037,6 +1037,98 @@ static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind, return TRUE; } +static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 }; +static PMIB_UDPTABLE udpTable; + +static void mib2UdpEntryInit(void) +{ + DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE); + + if (ret == ERROR_INSUFFICIENT_BUFFER) + { + udpTable = HeapAlloc(GetProcessHeap(), 0, size); + if (udpTable) + GetUdpTable(udpTable, &size, TRUE); + } +} + +static struct structToAsnValue mib2UdpEntryMap[] = { + { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr }, + { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt }, +}; + +static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst) +{ + MIB_UDPROW *row = dst; + + assert(oid && oid->idLength >= 5); + row->dwLocalAddr = oidToIpAddr(oid); + row->dwLocalPort = oid->ids[4]; +} + +static int compareUdpRow(const void *a, const void *b) +{ + const MIB_UDPROW *key = a, *value = b; + int ret; + + ret = key->dwLocalAddr - value->dwLocalAddr; + if (ret == 0) + ret = key->dwLocalPort - value->dwLocalPort; + return ret; +} + +static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind, + AsnInteger32 *pErrorStatus) +{ + AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry); + + 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, bPduType, pVarBind); + if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT) + { + AsnObjectIdentifier oid; + + setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item, + udpTable->table[tableIndex - 1].dwLocalAddr); + oid.idLength = 1; + oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort; + 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 }, @@ -1048,6 +1140,7 @@ static struct mibImplementation supportedIDs[] = { { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery }, { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery }, { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery }, + { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery }, }; static UINT minSupportedIDLength; diff --git a/dlls/inetmib1/tests/main.c b/dlls/inetmib1/tests/main.c index 012d6d2c458..e2e63f28acf 100644 --- a/dlls/inetmib1/tests/main.c +++ b/dlls/inetmib1/tests/main.c @@ -65,6 +65,7 @@ static void testQuery(void) 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]; UINT entry; @@ -356,6 +357,68 @@ static void testQuery(void) } } while (moreData); 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; + do { + ret = pQuery(SNMP_PDU_GETNEXT, &list, &error, &index); + ok(ret, "SnmpExtensionQuery failed: %d\n", GetLastError()); + /* 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; + 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]); + } + } + } + } while (moreData); + SnmpUtilVarBindFree(&vars2[0]); } START_TEST(main)