gdiplus: GdipIsMatrixInvertible implementation with tests.
[wine/multimedia.git] / dlls / inetmib1 / main.c
blob09b408c252e0072d82ad86421934e2302fcebbc7
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 /**
33 * Utility functions
35 static void copyInt(AsnAny *value, void *src)
37 value->asnType = ASN_INTEGER;
38 value->asnValue.number = *(DWORD *)src;
41 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
43 AsnAny strValue;
45 strValue.asnType = type;
46 strValue.asnValue.string.stream = str;
47 strValue.asnValue.string.length = len;
48 strValue.asnValue.string.dynamic = TRUE;
49 SnmpUtilAsnAnyCpy(value, &strValue);
52 static void copyLengthPrecededString(AsnAny *value, void *src)
54 DWORD len = *(DWORD *)src;
56 setStringValue(value, ASN_OCTETSTRING, len, (BYTE *)src + sizeof(DWORD));
59 typedef void (*copyValueFunc)(AsnAny *value, void *src);
61 struct structToAsnValue
63 size_t offset;
64 copyValueFunc copy;
67 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
68 UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
70 /* OIDs are 1-based */
71 if (!id)
72 return SNMP_ERRORSTATUS_NOSUCHNAME;
73 --id;
74 if (id >= mapLen)
75 return SNMP_ERRORSTATUS_NOSUCHNAME;
76 if (!map[id].copy)
77 return SNMP_ERRORSTATUS_NOSUCHNAME;
78 map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
79 return SNMP_ERRORSTATUS_NOERROR;
82 static void copyIpAddr(AsnAny *value, void *src)
84 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
87 static UINT mib2[] = { 1,3,6,1,2,1 };
88 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
90 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
91 AsnInteger32 *pErrorStatus);
93 struct mibImplementation
95 AsnObjectIdentifier name;
96 void (*init)(void);
97 varqueryfunc query;
98 void (*cleanup)(void);
101 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
102 static PMIB_IFTABLE ifTable;
104 static void mib2IfNumberInit(void)
106 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
108 if (ret == ERROR_INSUFFICIENT_BUFFER)
110 ifTable = HeapAlloc(GetProcessHeap(), 0, size);
111 if (ifTable)
112 GetIfTable(ifTable, &size, FALSE);
116 static void mib2IfNumberCleanup(void)
118 HeapFree(GetProcessHeap(), 0, ifTable);
121 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
122 AsnInteger32 *pErrorStatus)
124 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
126 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
127 pErrorStatus);
129 switch (bPduType)
131 case SNMP_PDU_GET:
132 case SNMP_PDU_GETNEXT:
133 if ((bPduType == SNMP_PDU_GET &&
134 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
135 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
136 < 0)
138 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
140 copyInt(&pVarBind->value, &numIfs);
141 if (bPduType == SNMP_PDU_GETNEXT)
142 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
143 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
145 else
147 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
148 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
149 * need to set it here.
152 break;
153 case SNMP_PDU_SET:
154 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
155 break;
156 default:
157 FIXME("0x%02x: unsupported PDU type\n", bPduType);
158 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
160 return TRUE;
163 static void copyOperStatus(AsnAny *value, void *src)
165 value->asnType = ASN_INTEGER;
166 /* The IPHlpApi definition of operational status differs from the MIB2 one,
167 * so map it to the MIB2 value.
169 switch (*(DWORD *)src)
171 case MIB_IF_OPER_STATUS_OPERATIONAL:
172 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
173 break;
174 case MIB_IF_OPER_STATUS_CONNECTING:
175 case MIB_IF_OPER_STATUS_CONNECTED:
176 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
177 break;
178 default:
179 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
183 /* Given an OID and a base OID that it must begin with, finds the item and
184 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
185 * foo, returns item 1 and instance 2.
186 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
187 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
188 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
189 * instance, or item 1, instance 1 if either is missing.
191 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
192 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
194 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
196 switch (bPduType)
198 case SNMP_PDU_GETNEXT:
199 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
201 *item = 1;
202 *instance = 1;
204 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
206 if (oid->idLength == base->idLength ||
207 oid->idLength == base->idLength + 1)
209 /* Either the table or an item within the table is specified,
210 * but the instance is not. Get the first instance.
212 *instance = 1;
213 if (oid->idLength == base->idLength + 1)
214 *item = oid->ids[base->idLength];
215 else
216 *item = 1;
218 else
220 *item = oid->ids[base->idLength];
221 *instance = oid->ids[base->idLength + 1] + 1;
224 else
225 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
226 break;
227 default:
228 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
230 if (oid->idLength == base->idLength ||
231 oid->idLength == base->idLength + 1)
233 /* Either the table or an item within the table is specified,
234 * but the instance is not.
236 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
238 else
240 *item = oid->ids[base->idLength];
241 *instance = oid->ids[base->idLength + 1];
244 else
245 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
247 return ret;
250 /* Given an OID and a base OID that it must begin with, finds the item from the
251 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
252 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
253 * SNMP_ERRORSTATUS_NOSUCHNAME.
254 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
255 * 1 if the item is missing.
257 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
258 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
260 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
262 switch (bPduType)
264 case SNMP_PDU_GETNEXT:
265 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
266 *item = 1;
267 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
269 if (oid->idLength == base->idLength)
271 /* The item is missing, assume the first item */
272 *item = 1;
274 else
275 *item = oid->ids[base->idLength] + 1;
277 else
278 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
279 break;
280 default:
281 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
283 if (oid->idLength == base->idLength)
285 /* The item is missing */
286 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
288 else
290 *item = oid->ids[base->idLength];
291 if (!*item)
292 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
295 else
296 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
298 return ret;
301 struct GenericTable
303 DWORD numEntries;
304 BYTE entries[1];
307 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
309 assert(oid && oid->idLength >= 4);
310 /* Map the IDs to an IP address in little-endian order */
311 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
312 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
315 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
316 typedef int (*compareFunc)(const void *key, const void *value);
318 static UINT findValueInTable(AsnObjectIdentifier *oid,
319 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
320 compareFunc compare)
322 UINT index = 0;
323 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
325 if (key)
327 void *value;
329 makeKey(oid, key);
330 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
331 compare);
332 if (value)
333 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize
334 + 1;
335 HeapFree(GetProcessHeap(), 0, key);
337 return index;
340 /* Given an OID and a base OID that it must begin with, finds the item and
341 * element of the table whose value matches the instance from the OID.
342 * The OID is converted to a key with the function makeKey, and compared
343 * against entries in the table with the function compare.
344 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
345 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
346 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
347 * instance, or item 1, instance 1 if either is missing.
349 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
350 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
351 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
352 compareFunc compare, UINT *item, UINT *instance)
354 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
356 if (!table)
357 return SNMP_ERRORSTATUS_NOSUCHNAME;
359 switch (bPduType)
361 case SNMP_PDU_GETNEXT:
362 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
364 /* Return the first item and instance from the table */
365 *item = 1;
366 *instance = 1;
368 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
369 oid->idLength < base->idLength + instanceLen + 1)
371 /* Either the table or an item is specified, but the instance is
372 * not.
374 *instance = 1;
375 if (oid->idLength >= base->idLength + 1)
377 *item = oid->ids[base->idLength];
378 if (!*item)
379 *item = 1;
381 else
382 *item = 1;
384 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
385 oid->idLength == base->idLength + instanceLen + 1)
387 *item = oid->ids[base->idLength];
388 if (!*item)
390 *instance = 1;
391 *item = 1;
393 else
395 AsnObjectIdentifier ipOid = { instanceLen,
396 oid->ids + base->idLength + 1 };
398 *instance = findValueInTable(&ipOid, table, tableEntrySize,
399 makeKey, compare) + 1;
400 if (*instance > table->numEntries)
401 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
404 else
405 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
406 break;
407 default:
408 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
409 oid->idLength == base->idLength + instanceLen + 1)
411 *item = oid->ids[base->idLength];
412 if (!*item)
413 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
414 else
416 AsnObjectIdentifier ipOid = { instanceLen,
417 oid->ids + base->idLength + 1 };
419 *instance = findValueInTable(&ipOid, table, tableEntrySize,
420 makeKey, compare);
421 if (!*instance)
422 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
425 else
426 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
428 return ret;
431 static void setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
432 UINT item)
434 UINT id;
435 AsnObjectIdentifier oid;
437 SnmpUtilOidCpy(dst, base);
438 oid.idLength = 1;
439 oid.ids = &id;
440 id = item;
441 SnmpUtilOidAppend(dst, &oid);
444 static void setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
445 AsnObjectIdentifier *base, UINT item, DWORD addr)
447 UINT id;
448 BYTE *ptr;
449 AsnObjectIdentifier oid;
451 setOidWithItem(dst, base, item);
452 oid.idLength = 1;
453 oid.ids = &id;
454 for (ptr = (BYTE *)&addr; ptr < (BYTE *)&addr + sizeof(DWORD); ptr++)
456 id = *ptr;
457 SnmpUtilOidAppend(dst, &oid);
461 static void setOidWithItemAndInteger(AsnObjectIdentifier *dst,
462 AsnObjectIdentifier *base, UINT item, UINT instance)
464 AsnObjectIdentifier oid;
466 setOidWithItem(dst, base, item);
467 oid.idLength = 1;
468 oid.ids = &instance;
469 SnmpUtilOidAppend(dst, &oid);
472 static struct structToAsnValue mib2IfEntryMap[] = {
473 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
474 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
475 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
476 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
477 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
478 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
479 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
480 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
481 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
482 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
483 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
484 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
485 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
486 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
487 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
488 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
489 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
490 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
491 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
492 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
493 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
496 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
498 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
499 AsnInteger32 *pErrorStatus)
501 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
503 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
504 pErrorStatus);
506 switch (bPduType)
508 case SNMP_PDU_GET:
509 case SNMP_PDU_GETNEXT:
510 if (!ifTable)
512 /* There is no interface present, so let the caller deal
513 * with finding the successor.
515 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
517 else
519 UINT tableIndex = 0, item = 0;
521 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
522 &entryOid, bPduType, &item, &tableIndex);
523 if (!*pErrorStatus)
525 assert(tableIndex);
526 assert(item);
527 if (tableIndex > ifTable->dwNumEntries)
528 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
529 else
531 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
532 DEFINE_SIZEOF(mib2IfEntryMap),
533 &ifTable->table[tableIndex - 1], item, bPduType,
534 pVarBind);
535 if (bPduType == SNMP_PDU_GETNEXT)
536 setOidWithItemAndInteger(&pVarBind->name, &entryOid,
537 item, tableIndex);
541 break;
542 case SNMP_PDU_SET:
543 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
544 break;
545 default:
546 FIXME("0x%02x: unsupported PDU type\n", bPduType);
547 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
549 return TRUE;
552 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
553 static MIB_IPSTATS ipStats;
555 static void mib2IpStatsInit(void)
557 GetIpStatistics(&ipStats);
560 static struct structToAsnValue mib2IpMap[] = {
561 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
562 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
563 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
564 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
565 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
566 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
567 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
568 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
569 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
570 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
571 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
572 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
573 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
574 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
575 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
576 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
577 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
578 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
579 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
580 { 0, NULL }, /* 20: not used, IP addr table */
581 { 0, NULL }, /* 21: not used, route table */
582 { 0, NULL }, /* 22: not used, net to media (ARP) table */
583 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
586 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
587 AsnInteger32 *pErrorStatus)
589 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
590 UINT item = 0;
592 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
593 pErrorStatus);
595 switch (bPduType)
597 case SNMP_PDU_GET:
598 case SNMP_PDU_GETNEXT:
599 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
600 &item);
601 if (!*pErrorStatus)
603 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
604 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
605 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
606 setOidWithItem(&pVarBind->name, &myOid, item);
608 break;
609 case SNMP_PDU_SET:
610 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
611 break;
612 default:
613 FIXME("0x%02x: unsupported PDU type\n", bPduType);
614 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
616 return TRUE;
619 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
620 static PMIB_IPADDRTABLE ipAddrTable;
622 static struct structToAsnValue mib2IpAddrMap[] = {
623 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
624 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
625 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
626 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
627 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
630 static void mib2IpAddrInit(void)
632 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
634 if (ret == ERROR_INSUFFICIENT_BUFFER)
636 ipAddrTable = HeapAlloc(GetProcessHeap(), 0, size);
637 if (ipAddrTable)
638 GetIpAddrTable(ipAddrTable, &size, TRUE);
642 static void mib2IpAddrCleanup(void)
644 HeapFree(GetProcessHeap(), 0, ipAddrTable);
647 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
649 MIB_IPADDRROW *row = dst;
651 row->dwAddr = oidToIpAddr(oid);
654 static int compareIpAddrRow(const void *a, const void *b)
656 const MIB_IPADDRROW *key = a, *value = b;
658 return key->dwAddr - value->dwAddr;
661 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
662 AsnInteger32 *pErrorStatus)
664 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
665 UINT tableIndex = 0, item = 0;
667 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
668 pErrorStatus);
670 switch (bPduType)
672 case SNMP_PDU_GET:
673 case SNMP_PDU_GETNEXT:
674 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
675 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
676 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
677 &tableIndex);
678 if (!*pErrorStatus)
680 assert(tableIndex);
681 assert(item);
682 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
683 DEFINE_SIZEOF(mib2IpAddrMap),
684 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
685 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
686 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
687 ipAddrTable->table[tableIndex - 1].dwAddr);
689 break;
690 case SNMP_PDU_SET:
691 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
692 break;
693 default:
694 FIXME("0x%02x: unsupported PDU type\n", bPduType);
695 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
697 return TRUE;
700 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
701 static PMIB_IPFORWARDTABLE ipRouteTable;
703 static struct structToAsnValue mib2IpRouteMap[] = {
704 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
705 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
706 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
707 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
708 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
709 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
710 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
711 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
712 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
713 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
714 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
715 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
718 static void mib2IpRouteInit(void)
720 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
722 if (ret == ERROR_INSUFFICIENT_BUFFER)
724 ipRouteTable = HeapAlloc(GetProcessHeap(), 0, size);
725 if (ipRouteTable)
726 GetIpForwardTable(ipRouteTable, &size, TRUE);
730 static void mib2IpRouteCleanup(void)
732 HeapFree(GetProcessHeap(), 0, ipRouteTable);
735 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
737 MIB_IPFORWARDROW *row = dst;
739 row->dwForwardDest = oidToIpAddr(oid);
742 static int compareIpForwardRow(const void *a, const void *b)
744 const MIB_IPFORWARDROW *key = a, *value = b;
746 return key->dwForwardDest - value->dwForwardDest;
749 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
750 AsnInteger32 *pErrorStatus)
752 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
753 UINT tableIndex = 0, item = 0;
755 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
756 pErrorStatus);
758 switch (bPduType)
760 case SNMP_PDU_GET:
761 case SNMP_PDU_GETNEXT:
762 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
763 &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable,
764 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
765 &item, &tableIndex);
766 if (!*pErrorStatus)
768 assert(tableIndex);
769 assert(item);
770 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
771 DEFINE_SIZEOF(mib2IpRouteMap),
772 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
773 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
774 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
775 ipRouteTable->table[tableIndex - 1].dwForwardDest);
777 break;
778 case SNMP_PDU_SET:
779 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
780 break;
781 default:
782 FIXME("0x%02x: unsupported PDU type\n", bPduType);
783 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
785 return TRUE;
788 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
789 static PMIB_IPNETTABLE ipNetTable;
791 static struct structToAsnValue mib2IpNetMap[] = {
792 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
793 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyLengthPrecededString },
794 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
795 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
798 static void mib2IpNetInit(void)
800 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
802 if (ret == ERROR_INSUFFICIENT_BUFFER)
804 ipNetTable = HeapAlloc(GetProcessHeap(), 0, size);
805 if (ipNetTable)
806 GetIpNetTable(ipNetTable, &size, FALSE);
810 static void mib2IpNetCleanup(void)
812 HeapFree(GetProcessHeap(), 0, ipNetTable);
815 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
816 AsnInteger32 *pErrorStatus)
818 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
820 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
821 pErrorStatus);
823 switch (bPduType)
825 case SNMP_PDU_GET:
826 case SNMP_PDU_GETNEXT:
827 if (!ipNetTable)
828 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
829 else
831 UINT tableIndex = 0, item = 0;
833 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
834 &myOid, bPduType, &item, &tableIndex);
835 if (!*pErrorStatus)
837 assert(tableIndex);
838 assert(item);
839 if (tableIndex > ipNetTable->dwNumEntries)
840 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
841 else
843 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
844 DEFINE_SIZEOF(mib2IpNetMap),
845 &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
846 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
847 setOidWithItemAndInteger(&pVarBind->name, &myOid, item,
848 tableIndex);
852 break;
853 case SNMP_PDU_SET:
854 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
855 break;
856 default:
857 FIXME("0x%02x: unsupported PDU type\n", bPduType);
858 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
860 return TRUE;
863 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
864 static MIB_ICMP icmpStats;
866 static void mib2IcmpInit(void)
868 GetIcmpStatistics(&icmpStats);
871 static struct structToAsnValue mib2IcmpMap[] = {
872 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
873 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
874 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
875 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
876 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
877 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
878 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
879 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
880 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
881 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
882 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
883 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
884 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
885 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
886 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
887 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
888 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
889 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
890 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
891 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
892 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
893 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
894 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
895 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
896 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
897 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
900 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
901 AsnInteger32 *pErrorStatus)
903 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
904 UINT item = 0;
906 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
907 pErrorStatus);
909 switch (bPduType)
911 case SNMP_PDU_GET:
912 case SNMP_PDU_GETNEXT:
913 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
914 &item);
915 if (!*pErrorStatus)
917 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
918 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
919 pVarBind);
920 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
921 setOidWithItem(&pVarBind->name, &myOid, item);
923 break;
924 case SNMP_PDU_SET:
925 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
926 break;
927 default:
928 FIXME("0x%02x: unsupported PDU type\n", bPduType);
929 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
931 return TRUE;
934 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
935 static MIB_TCPSTATS tcpStats;
937 static void mib2TcpInit(void)
939 GetTcpStatistics(&tcpStats);
942 static struct structToAsnValue mib2TcpMap[] = {
943 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
944 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
945 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
946 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
947 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
948 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
949 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
950 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
951 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
952 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
953 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
954 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
955 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
956 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
957 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
960 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
961 AsnInteger32 *pErrorStatus)
963 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
964 UINT item = 0;
966 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
967 pErrorStatus);
969 switch (bPduType)
971 case SNMP_PDU_GET:
972 case SNMP_PDU_GETNEXT:
973 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
974 &item);
975 if (!*pErrorStatus)
977 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
978 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
979 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
980 setOidWithItem(&pVarBind->name, &myOid, item);
982 break;
983 case SNMP_PDU_SET:
984 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
985 break;
986 default:
987 FIXME("0x%02x: unsupported PDU type\n", bPduType);
988 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
990 return TRUE;
993 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
994 static MIB_UDPSTATS udpStats;
996 static void mib2UdpInit(void)
998 GetUdpStatistics(&udpStats);
1001 static struct structToAsnValue mib2UdpMap[] = {
1002 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1003 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1004 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1005 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1008 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1009 AsnInteger32 *pErrorStatus)
1011 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1012 UINT item;
1014 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1015 pErrorStatus);
1017 switch (bPduType)
1019 case SNMP_PDU_GET:
1020 case SNMP_PDU_GETNEXT:
1021 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1022 &item);
1023 if (!*pErrorStatus)
1025 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1026 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
1027 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1028 setOidWithItem(&pVarBind->name, &myOid, item);
1030 break;
1031 case SNMP_PDU_SET:
1032 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1033 break;
1034 default:
1035 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1036 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1038 return TRUE;
1041 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
1042 static PMIB_UDPTABLE udpTable;
1044 static void mib2UdpEntryInit(void)
1046 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
1048 if (ret == ERROR_INSUFFICIENT_BUFFER)
1050 udpTable = HeapAlloc(GetProcessHeap(), 0, size);
1051 if (udpTable)
1052 GetUdpTable(udpTable, &size, TRUE);
1056 static void mib2UdpEntryCleanup(void)
1058 HeapFree(GetProcessHeap(), 0, udpTable);
1061 static struct structToAsnValue mib2UdpEntryMap[] = {
1062 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
1063 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
1066 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
1068 MIB_UDPROW *row = dst;
1070 assert(oid && oid->idLength >= 5);
1071 row->dwLocalAddr = oidToIpAddr(oid);
1072 row->dwLocalPort = oid->ids[4];
1075 static int compareUdpRow(const void *a, const void *b)
1077 const MIB_UDPROW *key = a, *value = b;
1078 int ret;
1080 ret = key->dwLocalAddr - value->dwLocalAddr;
1081 if (ret == 0)
1082 ret = key->dwLocalPort - value->dwLocalPort;
1083 return ret;
1086 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1087 AsnInteger32 *pErrorStatus)
1089 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
1091 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1092 pErrorStatus);
1094 switch (bPduType)
1096 case SNMP_PDU_GET:
1097 case SNMP_PDU_GETNEXT:
1098 if (!udpTable)
1099 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1100 else
1102 UINT tableIndex = 0, item = 0;
1104 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
1105 5, bPduType, (struct GenericTable *)udpTable,
1106 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
1107 &tableIndex);
1108 if (!*pErrorStatus)
1110 assert(tableIndex);
1111 assert(item);
1112 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
1113 DEFINE_SIZEOF(mib2UdpEntryMap),
1114 &udpTable->table[tableIndex - 1], item, bPduType, pVarBind);
1115 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1117 AsnObjectIdentifier oid;
1119 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
1120 udpTable->table[tableIndex - 1].dwLocalAddr);
1121 oid.idLength = 1;
1122 oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
1123 SnmpUtilOidAppend(&pVarBind->name, &oid);
1127 break;
1128 case SNMP_PDU_SET:
1129 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1130 break;
1131 default:
1132 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1133 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1135 return TRUE;
1138 /* This list MUST BE lexicographically sorted */
1139 static struct mibImplementation supportedIDs[] = {
1140 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
1141 mib2IfNumberCleanup },
1142 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
1143 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
1144 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
1145 mib2IpAddrCleanup },
1146 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
1147 mib2IpRouteCleanup },
1148 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
1149 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
1150 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
1151 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
1152 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
1153 mib2UdpEntryCleanup },
1155 static UINT minSupportedIDLength;
1157 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1158 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1160 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1161 UINT i;
1163 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1164 pFirstSupportedRegion);
1166 minSupportedIDLength = UINT_MAX;
1167 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1169 if (supportedIDs[i].init)
1170 supportedIDs[i].init();
1171 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1172 minSupportedIDLength = supportedIDs[i].name.idLength;
1174 *phSubagentTrapEvent = NULL;
1175 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1176 return TRUE;
1179 static void cleanup(void)
1181 UINT i;
1183 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1184 if (supportedIDs[i].cleanup)
1185 supportedIDs[i].cleanup();
1188 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1189 UINT *matchingIndex)
1191 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
1192 struct mibImplementation *impl = NULL;
1193 AsnObjectIdentifier oid1 = { idLength, ids};
1195 if (!idLength)
1196 return NULL;
1197 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
1198 i = (indexLow + indexHigh) / 2)
1200 INT cmp;
1202 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
1203 if (!cmp)
1205 impl = &supportedIDs[i];
1206 *matchingIndex = i;
1208 else if (cmp > 0)
1209 indexLow = i + 1;
1210 else
1211 indexHigh = i - 1;
1213 return impl;
1216 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1217 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1219 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1220 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1221 UINT i;
1223 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1224 pErrorStatus, pErrorIndex);
1226 for (i = 0; !error && i < pVarBindList->len; i++)
1228 /* Ignore any OIDs not in MIB2 */
1229 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1230 mib2oid.idLength))
1232 struct mibImplementation *impl = NULL;
1233 UINT len, matchingIndex = 0;
1235 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1236 /* Search for an implementation matching as many octets as possible
1238 for (len = pVarBindList->list[i].name.idLength;
1239 len >= minSupportedIDLength && !impl; len--)
1240 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1241 &matchingIndex);
1242 if (impl && impl->query)
1243 impl->query(bPduType, &pVarBindList->list[i], &error);
1244 else
1245 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1246 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1247 bPduType == SNMP_PDU_GETNEXT)
1249 /* GetNext is special: it finds the successor to the given OID,
1250 * so we have to continue until an implementation handles the
1251 * query or we exhaust the table of supported OIDs.
1253 for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1254 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1255 matchingIndex++)
1257 error = SNMP_ERRORSTATUS_NOERROR;
1258 impl = &supportedIDs[matchingIndex];
1259 if (impl->query)
1260 impl->query(bPduType, &pVarBindList->list[i], &error);
1261 else
1262 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1264 /* If the query still isn't resolved, set the OID to the
1265 * successor to the last entry in the table.
1267 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1269 SnmpUtilOidFree(&pVarBindList->list[i].name);
1270 SnmpUtilOidCpy(&pVarBindList->list[i].name,
1271 &supportedIDs[matchingIndex - 1].name);
1272 pVarBindList->list[i].name.ids[
1273 pVarBindList->list[i].name.idLength - 1] += 1;
1276 if (error)
1277 errorIndex = i + 1;
1280 *pErrorStatus = error;
1281 *pErrorIndex = errorIndex;
1282 return TRUE;
1285 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1287 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1289 switch (fdwReason)
1291 case DLL_PROCESS_ATTACH:
1292 DisableThreadLibraryCalls(hinstDLL);
1293 break;
1294 case DLL_PROCESS_DETACH:
1295 cleanup();
1296 break;
1297 default:
1298 break;
1301 return TRUE;