/* Finds the first successor to the value in the table that does matches oid, * using makeKey to convert the oid to a key for comparison. A successor is * a value that does not match oid, so if multiple entries match an oid, only * the first will ever be returned using this method. * Returns the successor's 1-based index if found, or 0 if not found. */ static UINT findNextOidInTable(AsnObjectIdentifier *oid, struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, compareFunc compare) { UINT index = 0; void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize); if (key) { makeKey(oid, key); index = findValueInTable(key, table, tableEntrySize, compare); if (index == 0) { /* Not found in table. If it's less than the first entry, return * the first index. Otherwise just return 0 and let the caller * handle finding the successor. */ if (compare(key, table->entries) < 0) index = 1; } else { /* Skip any entries that match the same key. This enumeration will * be incomplete, but it's what Windows appears to do if there are * multiple entries with the same index in a table, and it avoids * an infinite loop. */ for (++index; index <= table->numEntries && compare(key, &table->entries[tableEntrySize * (index - 1)]) == 0; ++index) ; } HeapFree(GetProcessHeap(), 0, key); } return index; }
/* Finds the first value in the table that matches oid, using makeKey to * convert the oid to a key for comparison. Returns the value's 1-based * index if found, or 0 if not found. */ static UINT findOidInTable(AsnObjectIdentifier *oid, struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey, compareFunc compare) { UINT index = 0; void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize); if (key) { makeKey(oid, key); index = findValueInTable(key, table, tableEntrySize, compare); HeapFree(GetProcessHeap(), 0, key); } 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, oidToKeyFunc makeKey, compareFunc compare, 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 = findValueInTable(&ipOid, table, tableEntrySize, makeKey, compare) + 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 = findValueInTable(&ipOid, table, tableEntrySize, makeKey, compare); if (!*instance) ret = SNMP_ERRORSTATUS_NOSUCHNAME; } } else ret = SNMP_ERRORSTATUS_NOSUCHNAME; } return ret; }