push 7f8c39dca3a5819e8ef115eebf7abed537de3a22
[wine/hacks.git] / dlls / inetmib1 / main.c
blob20fc0b99284bf1ee119c869242176b3254ca450f
1 /*
2 * Copyright 2008 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "config.h"
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "snmp.h"
27 #include "iphlpapi.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
32 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
34 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
36 switch (fdwReason)
38 case DLL_WINE_PREATTACH:
39 return FALSE; /* prefer native version */
40 case DLL_PROCESS_ATTACH:
41 DisableThreadLibraryCalls(hinstDLL);
42 break;
43 case DLL_PROCESS_DETACH:
44 break;
45 default:
46 break;
49 return TRUE;
52 /**
53 * Utility functions
55 static void copyInt(AsnAny *value, void *src)
57 value->asnType = ASN_INTEGER;
58 value->asnValue.number = *(DWORD *)src;
61 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
63 AsnAny strValue;
65 strValue.asnType = type;
66 strValue.asnValue.string.stream = str;
67 strValue.asnValue.string.length = len;
68 strValue.asnValue.string.dynamic = TRUE;
69 SnmpUtilAsnAnyCpy(value, &strValue);
72 static void copyLengthPrecededString(AsnAny *value, void *src)
74 DWORD len = *(DWORD *)src;
76 setStringValue(value, ASN_OCTETSTRING, len, (BYTE *)src + sizeof(DWORD));
79 typedef void (*copyValueFunc)(AsnAny *value, void *src);
81 struct structToAsnValue
83 size_t offset;
84 copyValueFunc copy;
87 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
88 UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
90 /* OIDs are 1-based */
91 if (!id)
92 return SNMP_ERRORSTATUS_NOSUCHNAME;
93 --id;
94 if (id >= mapLen)
95 return SNMP_ERRORSTATUS_NOSUCHNAME;
96 if (!map[id].copy)
97 return SNMP_ERRORSTATUS_NOSUCHNAME;
98 map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
99 return SNMP_ERRORSTATUS_NOERROR;
102 static void copyIpAddr(AsnAny *value, void *src)
104 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
107 static UINT mib2[] = { 1,3,6,1,2,1 };
108 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
110 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
111 AsnInteger32 *pErrorStatus);
113 struct mibImplementation
115 AsnObjectIdentifier name;
116 void (*init)(void);
117 varqueryfunc query;
120 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
121 static PMIB_IFTABLE ifTable;
123 static void mib2IfNumberInit(void)
125 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
127 if (ret == ERROR_INSUFFICIENT_BUFFER)
129 ifTable = HeapAlloc(GetProcessHeap(), 0, size);
130 if (ifTable)
131 GetIfTable(ifTable, &size, FALSE);
135 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
136 AsnInteger32 *pErrorStatus)
138 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
140 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
141 pErrorStatus);
143 switch (bPduType)
145 case SNMP_PDU_GET:
146 case SNMP_PDU_GETNEXT:
147 if ((bPduType == SNMP_PDU_GET &&
148 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
149 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
150 < 0)
152 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
154 copyInt(&pVarBind->value, &numIfs);
155 if (bPduType == SNMP_PDU_GETNEXT)
156 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
157 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
159 else
161 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
162 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
163 * need to set it here.
166 break;
167 case SNMP_PDU_SET:
168 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
169 break;
170 default:
171 FIXME("0x%02x: unsupported PDU type\n", bPduType);
172 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
174 return TRUE;
177 static void copyOperStatus(AsnAny *value, void *src)
179 value->asnType = ASN_INTEGER;
180 /* The IPHlpApi definition of operational status differs from the MIB2 one,
181 * so map it to the MIB2 value.
183 switch (*(DWORD *)src)
185 case MIB_IF_OPER_STATUS_OPERATIONAL:
186 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
187 break;
188 case MIB_IF_OPER_STATUS_CONNECTING:
189 case MIB_IF_OPER_STATUS_CONNECTED:
190 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
191 break;
192 default:
193 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
197 /* Given an OID and a base OID that it must begin with, finds the item and
198 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
199 * foo, returns item 1 and instance 2.
200 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
201 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
202 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
203 * instance, or item 1, instance 1 if either is missing.
205 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
206 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
208 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
210 switch (bPduType)
212 case SNMP_PDU_GETNEXT:
213 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
215 *item = 1;
216 *instance = 1;
218 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
220 if (oid->idLength == base->idLength ||
221 oid->idLength == base->idLength + 1)
223 /* Either the table or an item within the table is specified,
224 * but the instance is not. Get the first instance.
226 *instance = 1;
227 if (oid->idLength == base->idLength + 1)
228 *item = oid->ids[base->idLength];
229 else
230 *item = 1;
232 else
234 *item = oid->ids[base->idLength];
235 *instance = oid->ids[base->idLength + 1] + 1;
238 else
239 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
240 break;
241 default:
242 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
244 if (oid->idLength == base->idLength ||
245 oid->idLength == base->idLength + 1)
247 /* Either the table or an item within the table is specified,
248 * but the instance is not.
250 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
252 else
254 *item = oid->ids[base->idLength];
255 *instance = oid->ids[base->idLength + 1];
258 else
259 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
261 return ret;
264 /* Given an OID and a base OID that it must begin with, finds the item from the
265 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
266 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
267 * SNMP_ERRORSTATUS_NOSUCHNAME.
268 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
269 * 1 if the item is missing.
271 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
272 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
274 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
276 switch (bPduType)
278 case SNMP_PDU_GETNEXT:
279 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
280 *item = 1;
281 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
283 if (oid->idLength == base->idLength)
285 /* The item is missing, assume the first item */
286 *item = 1;
288 else
289 *item = oid->ids[base->idLength] + 1;
291 else
292 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
293 break;
294 default:
295 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
297 if (oid->idLength == base->idLength)
299 /* The item is missing */
300 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
302 else
304 *item = oid->ids[base->idLength];
305 if (!*item)
306 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
309 else
310 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
312 return ret;
315 struct GenericTable
317 DWORD numEntries;
318 BYTE entries[1];
321 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
323 assert(oid && oid->idLength >= 4);
324 /* Map the IDs to an IP address in little-endian order */
325 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
326 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
329 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
330 typedef int (*compareFunc)(const void *key, const void *value);
332 static UINT findValueInTable(AsnObjectIdentifier *oid,
333 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
334 compareFunc compare)
336 UINT index = 0;
337 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
339 if (key)
341 void *value;
343 makeKey(oid, key);
344 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
345 compare);
346 if (value)
347 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize
348 + 1;
349 HeapFree(GetProcessHeap(), 0, key);
351 return index;
354 /* Given an OID and a base OID that it must begin with, finds the item and
355 * element of the table whose IP address matches the instance from the OID.
356 * E.g., given an OID foo.1.2.3.4.5 and a base OID foo, returns item 1 and the
357 * index of the entry in the table whose IP address is 2.3.4.5.
358 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
359 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
360 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
361 * instance, or item 1, instance 1 if either is missing.
363 static AsnInteger32 getItemAndIpAddressInstanceFromOid(AsnObjectIdentifier *oid,
364 AsnObjectIdentifier *base, BYTE bPduType, struct GenericTable *table,
365 size_t tableEntrySize, oidToKeyFunc makeKey, compareFunc compare,
366 UINT *item, UINT *instance)
368 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
370 if (!table)
371 return SNMP_ERRORSTATUS_NOSUCHNAME;
373 switch (bPduType)
375 case SNMP_PDU_GETNEXT:
376 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
378 /* Return the first item and instance from the table */
379 *item = 1;
380 *instance = 1;
382 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
383 oid->idLength < base->idLength + 5)
385 /* Either the table or an item is specified, but the instance is
386 * not.
388 *instance = 1;
389 if (oid->idLength >= base->idLength + 1)
391 *item = oid->ids[base->idLength];
392 if (!*item)
393 *item = 1;
395 else
396 *item = 1;
398 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
399 oid->idLength == base->idLength + 5)
401 *item = oid->ids[base->idLength];
402 if (!*item)
404 *instance = 1;
405 *item = 1;
407 else
409 AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
412 *instance = findValueInTable(&ipOid, table, tableEntrySize,
413 makeKey, compare) + 1;
414 if (*instance > table->numEntries)
415 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
418 else
419 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
420 break;
421 default:
422 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
423 oid->idLength == base->idLength + 5)
425 *item = oid->ids[base->idLength];
426 if (!*item)
427 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
428 else
430 AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
433 *instance = findValueInTable(&ipOid, table, tableEntrySize,
434 makeKey, compare);
435 if (!*instance)
436 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
439 else
440 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
442 return ret;
445 static void setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
446 UINT item)
448 UINT id;
449 AsnObjectIdentifier oid;
451 SnmpUtilOidCpy(dst, base);
452 oid.idLength = 1;
453 oid.ids = &id;
454 id = item;
455 SnmpUtilOidAppend(dst, &oid);
458 static void setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
459 AsnObjectIdentifier *base, UINT item, DWORD addr)
461 UINT id;
462 BYTE *ptr;
463 AsnObjectIdentifier oid;
465 setOidWithItem(dst, base, item);
466 oid.idLength = 1;
467 oid.ids = &id;
468 for (ptr = (BYTE *)&addr; ptr < (BYTE *)&addr + sizeof(DWORD); ptr++)
470 id = *ptr;
471 SnmpUtilOidAppend(dst, &oid);
475 static void setOidWithItemAndInteger(AsnObjectIdentifier *dst,
476 AsnObjectIdentifier *base, UINT item, UINT instance)
478 AsnObjectIdentifier oid;
480 setOidWithItem(dst, base, item);
481 oid.idLength = 1;
482 oid.ids = &instance;
483 SnmpUtilOidAppend(dst, &oid);
486 static struct structToAsnValue mib2IfEntryMap[] = {
487 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
488 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
489 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
490 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
491 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
492 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
493 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
494 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
495 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
496 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
497 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
498 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
499 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
500 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
501 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
502 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
503 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
504 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
505 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
506 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
507 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
510 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
512 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
513 AsnInteger32 *pErrorStatus)
515 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
517 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
518 pErrorStatus);
520 switch (bPduType)
522 case SNMP_PDU_GET:
523 case SNMP_PDU_GETNEXT:
524 if (!ifTable)
526 /* There is no interface present, so let the caller deal
527 * with finding the successor.
529 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
531 else
533 UINT tableIndex = 0, item = 0;
535 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
536 &entryOid, bPduType, &item, &tableIndex);
537 if (!*pErrorStatus)
539 assert(tableIndex);
540 assert(item);
541 if (tableIndex > ifTable->dwNumEntries)
542 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
543 else
545 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
546 DEFINE_SIZEOF(mib2IfEntryMap),
547 &ifTable->table[tableIndex - 1], item, bPduType,
548 pVarBind);
549 if (bPduType == SNMP_PDU_GETNEXT)
550 setOidWithItemAndInteger(&pVarBind->name, &entryOid,
551 item, tableIndex);
555 break;
556 case SNMP_PDU_SET:
557 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
558 break;
559 default:
560 FIXME("0x%02x: unsupported PDU type\n", bPduType);
561 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
563 return TRUE;
566 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
567 static MIB_IPSTATS ipStats;
569 static void mib2IpStatsInit(void)
571 GetIpStatistics(&ipStats);
574 static struct structToAsnValue mib2IpMap[] = {
575 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
576 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
577 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
578 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
579 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
580 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
581 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
582 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
583 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
584 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
585 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
586 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
587 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
588 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
589 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
590 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
591 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
592 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
593 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
594 { 0, NULL }, /* 20: not used, IP addr table */
595 { 0, NULL }, /* 21: not used, route table */
596 { 0, NULL }, /* 22: not used, net to media (ARP) table */
597 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
600 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
601 AsnInteger32 *pErrorStatus)
603 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
604 UINT item = 0;
606 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
607 pErrorStatus);
609 switch (bPduType)
611 case SNMP_PDU_GET:
612 case SNMP_PDU_GETNEXT:
613 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
614 &item);
615 if (!*pErrorStatus)
617 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
618 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
619 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
620 setOidWithItem(&pVarBind->name, &myOid, item);
622 break;
623 case SNMP_PDU_SET:
624 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
625 break;
626 default:
627 FIXME("0x%02x: unsupported PDU type\n", bPduType);
628 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
630 return TRUE;
633 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
634 static PMIB_IPADDRTABLE ipAddrTable;
636 static struct structToAsnValue mib2IpAddrMap[] = {
637 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
638 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
639 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
640 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
641 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
644 static void mib2IpAddrInit(void)
646 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
648 if (ret == ERROR_INSUFFICIENT_BUFFER)
650 ipAddrTable = HeapAlloc(GetProcessHeap(), 0, size);
651 if (ipAddrTable)
652 GetIpAddrTable(ipAddrTable, &size, TRUE);
656 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
658 MIB_IPADDRROW *row = dst;
660 row->dwAddr = oidToIpAddr(oid);
663 static int compareIpAddrRow(const void *a, const void *b)
665 const MIB_IPADDRROW *key = a, *value = b;
667 return key->dwAddr - value->dwAddr;
670 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
671 AsnInteger32 *pErrorStatus)
673 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
674 UINT tableIndex = 0, item = 0;
676 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
677 pErrorStatus);
679 switch (bPduType)
681 case SNMP_PDU_GET:
682 case SNMP_PDU_GETNEXT:
683 *pErrorStatus = getItemAndIpAddressInstanceFromOid(&pVarBind->name,
684 &myOid, bPduType, (struct GenericTable *)ipAddrTable,
685 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
686 &tableIndex);
687 if (!*pErrorStatus)
689 assert(tableIndex);
690 assert(item);
691 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
692 DEFINE_SIZEOF(mib2IpAddrMap),
693 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
694 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
695 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
696 ipAddrTable->table[tableIndex - 1].dwAddr);
698 break;
699 case SNMP_PDU_SET:
700 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
701 break;
702 default:
703 FIXME("0x%02x: unsupported PDU type\n", bPduType);
704 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
706 return TRUE;
709 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
710 static PMIB_IPFORWARDTABLE ipRouteTable;
712 static struct structToAsnValue mib2IpRouteMap[] = {
713 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
714 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
715 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
716 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
717 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
718 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
719 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
720 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
721 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
722 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
723 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
724 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
727 static void mib2IpRouteInit(void)
729 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
731 if (ret == ERROR_INSUFFICIENT_BUFFER)
733 ipRouteTable = HeapAlloc(GetProcessHeap(), 0, size);
734 if (ipRouteTable)
735 GetIpForwardTable(ipRouteTable, &size, TRUE);
739 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
741 MIB_IPFORWARDROW *row = dst;
743 row->dwForwardDest = oidToIpAddr(oid);
746 static int compareIpForwardRow(const void *a, const void *b)
748 const MIB_IPFORWARDROW *key = a, *value = b;
750 return key->dwForwardDest - value->dwForwardDest;
753 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
754 AsnInteger32 *pErrorStatus)
756 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
757 UINT tableIndex = 0, item = 0;
759 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
760 pErrorStatus);
762 switch (bPduType)
764 case SNMP_PDU_GET:
765 case SNMP_PDU_GETNEXT:
766 *pErrorStatus = getItemAndIpAddressInstanceFromOid(&pVarBind->name,
767 &myOid, bPduType, (struct GenericTable *)ipRouteTable,
768 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
769 &item, &tableIndex);
770 if (!*pErrorStatus)
772 assert(tableIndex);
773 assert(item);
774 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
775 DEFINE_SIZEOF(mib2IpRouteMap),
776 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
777 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
778 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
779 ipRouteTable->table[tableIndex - 1].dwForwardDest);
781 break;
782 case SNMP_PDU_SET:
783 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
784 break;
785 default:
786 FIXME("0x%02x: unsupported PDU type\n", bPduType);
787 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
789 return TRUE;
792 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
793 static PMIB_IPNETTABLE ipNetTable;
795 static struct structToAsnValue mib2IpNetMap[] = {
796 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
797 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyLengthPrecededString },
798 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
799 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
802 static void mib2IpNetInit(void)
804 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
806 if (ret == ERROR_INSUFFICIENT_BUFFER)
808 ipNetTable = HeapAlloc(GetProcessHeap(), 0, size);
809 if (ipNetTable)
810 GetIpNetTable(ipNetTable, &size, FALSE);
814 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
815 AsnInteger32 *pErrorStatus)
817 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
819 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
820 pErrorStatus);
822 switch (bPduType)
824 case SNMP_PDU_GET:
825 case SNMP_PDU_GETNEXT:
826 if (!ipNetTable)
827 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
828 else
830 UINT tableIndex = 0, item = 0;
832 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
833 &myOid, bPduType, &item, &tableIndex);
834 if (!*pErrorStatus)
836 assert(tableIndex);
837 assert(item);
838 if (tableIndex > ipNetTable->dwNumEntries)
839 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
840 else
842 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
843 DEFINE_SIZEOF(mib2IpNetMap),
844 &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
845 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
846 setOidWithItemAndInteger(&pVarBind->name, &myOid, item,
847 tableIndex);
851 break;
852 case SNMP_PDU_SET:
853 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
854 break;
855 default:
856 FIXME("0x%02x: unsupported PDU type\n", bPduType);
857 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
859 return TRUE;
862 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
863 static MIB_ICMP icmpStats;
865 static void mib2IcmpInit(void)
867 GetIcmpStatistics(&icmpStats);
870 static struct structToAsnValue mib2IcmpMap[] = {
871 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
872 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
873 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
874 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
875 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
876 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
877 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
878 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
879 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
880 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
881 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
882 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
883 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
884 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
885 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
886 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
887 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
888 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
889 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
890 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
891 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
892 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
893 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
894 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
895 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
896 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
899 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
900 AsnInteger32 *pErrorStatus)
902 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
903 UINT item = 0;
905 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
906 pErrorStatus);
908 switch (bPduType)
910 case SNMP_PDU_GET:
911 case SNMP_PDU_GETNEXT:
912 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
913 &item);
914 if (!*pErrorStatus)
916 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
917 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
918 pVarBind);
919 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
920 setOidWithItem(&pVarBind->name, &myOid, item);
922 break;
923 case SNMP_PDU_SET:
924 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
925 break;
926 default:
927 FIXME("0x%02x: unsupported PDU type\n", bPduType);
928 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
930 return TRUE;
933 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
934 static MIB_TCPSTATS tcpStats;
936 static void mib2TcpInit(void)
938 GetTcpStatistics(&tcpStats);
941 static struct structToAsnValue mib2TcpMap[] = {
942 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
943 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
944 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
945 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
946 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
947 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
948 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
949 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
950 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
951 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
952 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
953 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
954 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
955 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
956 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
959 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
960 AsnInteger32 *pErrorStatus)
962 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
963 UINT item = 0;
965 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
966 pErrorStatus);
968 switch (bPduType)
970 case SNMP_PDU_GET:
971 case SNMP_PDU_GETNEXT:
972 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
973 &item);
974 if (!*pErrorStatus)
976 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
977 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
978 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
979 setOidWithItem(&pVarBind->name, &myOid, item);
981 break;
982 case SNMP_PDU_SET:
983 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
984 break;
985 default:
986 FIXME("0x%02x: unsupported PDU type\n", bPduType);
987 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
989 return TRUE;
992 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
993 static MIB_UDPSTATS udpStats;
995 static void mib2UdpInit(void)
997 GetUdpStatistics(&udpStats);
1000 static struct structToAsnValue mib2UdpMap[] = {
1001 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1002 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1003 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1004 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1007 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1008 AsnInteger32 *pErrorStatus)
1010 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1011 UINT item;
1013 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1014 pErrorStatus);
1016 switch (bPduType)
1018 case SNMP_PDU_GET:
1019 case SNMP_PDU_GETNEXT:
1020 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1021 &item);
1022 if (!*pErrorStatus)
1024 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1025 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
1026 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1027 setOidWithItem(&pVarBind->name, &myOid, item);
1029 break;
1030 case SNMP_PDU_SET:
1031 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1032 break;
1033 default:
1034 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1035 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1037 return TRUE;
1040 /* This list MUST BE lexicographically sorted */
1041 static struct mibImplementation supportedIDs[] = {
1042 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery },
1043 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery },
1044 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery },
1045 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery },
1046 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery },
1047 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery },
1048 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery },
1049 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery },
1050 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery },
1052 static UINT minSupportedIDLength;
1054 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1055 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1057 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1058 UINT i;
1060 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1061 pFirstSupportedRegion);
1063 minSupportedIDLength = UINT_MAX;
1064 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1066 if (supportedIDs[i].init)
1067 supportedIDs[i].init();
1068 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1069 minSupportedIDLength = supportedIDs[i].name.idLength;
1071 *phSubagentTrapEvent = NULL;
1072 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1073 return TRUE;
1076 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1077 UINT *matchingIndex)
1079 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
1080 struct mibImplementation *impl = NULL;
1081 AsnObjectIdentifier oid1 = { idLength, ids};
1083 if (!idLength)
1084 return NULL;
1085 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
1086 i = (indexLow + indexHigh) / 2)
1088 INT cmp;
1090 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
1091 if (!cmp)
1093 impl = &supportedIDs[i];
1094 *matchingIndex = i;
1096 else if (cmp > 0)
1097 indexLow = i + 1;
1098 else
1099 indexHigh = i - 1;
1101 return impl;
1104 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1105 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1107 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1108 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1109 UINT i;
1111 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1112 pErrorStatus, pErrorIndex);
1114 for (i = 0; !error && i < pVarBindList->len; i++)
1116 /* Ignore any OIDs not in MIB2 */
1117 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1118 mib2oid.idLength))
1120 struct mibImplementation *impl = NULL;
1121 UINT len, matchingIndex = 0;
1123 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1124 /* Search for an implementation matching as many octets as possible
1126 for (len = pVarBindList->list[i].name.idLength;
1127 len >= minSupportedIDLength && !impl; len--)
1128 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1129 &matchingIndex);
1130 if (impl && impl->query)
1131 impl->query(bPduType, &pVarBindList->list[i], &error);
1132 else
1133 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1134 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1135 bPduType == SNMP_PDU_GETNEXT)
1137 /* GetNext is special: it finds the successor to the given OID,
1138 * so we have to continue until an implementation handles the
1139 * query or we exhaust the table of supported OIDs.
1141 for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1142 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1143 matchingIndex++)
1145 error = SNMP_ERRORSTATUS_NOERROR;
1146 impl = &supportedIDs[matchingIndex];
1147 if (impl->query)
1148 impl->query(bPduType, &pVarBindList->list[i], &error);
1149 else
1150 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1152 /* If the query still isn't resolved, set the OID to the
1153 * successor to the last entry in the table.
1155 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1157 SnmpUtilOidFree(&pVarBindList->list[i].name);
1158 SnmpUtilOidCpy(&pVarBindList->list[i].name,
1159 &supportedIDs[matchingIndex - 1].name);
1160 pVarBindList->list[i].name.ids[
1161 pVarBindList->list[i].name.idLength - 1] += 1;
1164 if (error)
1165 errorIndex = i + 1;
1168 *pErrorStatus = error;
1169 *pErrorIndex = errorIndex;
1170 return TRUE;