From ea20d6b793039753d0cd9c3f9bca894bb8e68a47 Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Tue, 20 May 2008 20:57:51 -0700 Subject: [PATCH] inetmib1: Support the MIB2 IP address table. --- dlls/inetmib1/main.c | 166 +++++++++++++++++++++++++++++++++++++ dlls/inetmib1/tests/main.c | 57 +++++++++++++ 2 files changed, 223 insertions(+) diff --git a/dlls/inetmib1/main.c b/dlls/inetmib1/main.c index deefc7aba4c..7263ca5a4b0 100644 --- a/dlls/inetmib1/main.c +++ b/dlls/inetmib1/main.c @@ -98,6 +98,11 @@ static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map, 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 }; @@ -408,6 +413,166 @@ static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind, 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 = 0; + if (!ipAddrTable) + { + /* There is no address present, so let the caller deal with + * finding the successor. + */ + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + } + else if (!SnmpUtilOidNCmp(&pVarBind->name, &myOid, myOid.idLength) && + pVarBind->name.idLength < myOid.idLength + 5) + { + /* 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 address */ + tableIndex = 1; + if (pVarBind->name.idLength == myOid.idLength + 1) + item = pVarBind->name.ids[myOid.idLength]; + else + item = 1; + } + } + else if (!SnmpUtilOidNCmp(&pVarBind->name, &myOid, myOid.idLength) && + pVarBind->name.idLength == myOid.idLength + 5) + { + item = pVarBind->name.ids[myOid.idLength]; + if (!item) + { + if (bPduType == SNMP_PDU_GET) + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + else + { + tableIndex = 1; + item = 1; + } + } + else if (item - 1 >= DEFINE_SIZEOF(mib2IpAddrMap)) + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + else + { + DWORD addr; + UINT i; + + /* Map the IDs to an IP address in little-endian order */ + addr = + (BYTE)pVarBind->name.ids[myOid.idLength + 4] << 24 | + (BYTE)pVarBind->name.ids[myOid.idLength + 3] << 16 | + (BYTE)pVarBind->name.ids[myOid.idLength + 2] << 8 | + (BYTE)pVarBind->name.ids[myOid.idLength + 1]; + /* Find the item whose address matches */ + for (i = 0; !tableIndex && i < ipAddrTable->dwNumEntries; i++) + if (addr == ipAddrTable->table[i].dwAddr) + tableIndex = i + 1; + if (bPduType == SNMP_PDU_GETNEXT) + { + if (!tableIndex) + { + /* No address matched, so let caller find successor */ + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + } + else + { + /* We want the successor to the matching address */ + tableIndex++; + } + } + if (tableIndex > ipAddrTable->dwNumEntries) + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + } + } + else + { + /* Some item after the address table was requested, so let the + * caller deal with finding a successor. + */ + *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; + } + 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 mib2Icmp[] = { 1,3,6,1,2,1,5 }; static MIB_ICMP icmpStats; @@ -508,6 +673,7 @@ 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(mib2Icmp), mib2IcmpInit, mib2IcmpQuery }, }; static UINT minSupportedIDLength; diff --git a/dlls/inetmib1/tests/main.c b/dlls/inetmib1/tests/main.c index ada858b81b4..4193d5625c2 100644 --- a/dlls/inetmib1/tests/main.c +++ b/dlls/inetmib1/tests/main.c @@ -63,6 +63,7 @@ static void testQuery(void) 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 }; SnmpVarBind vars[3], vars2[3]; UINT entry; @@ -242,6 +243,62 @@ static void testQuery(void) 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]); + + /* 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\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; + 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]); + } + } + } + } while (moreData); + SnmpUtilVarBindFree(&vars2[0]); } START_TEST(main)