inetmib1: Check return values from SnmpUtilOid functions in utility functions.
[wine/multimedia.git] / dlls / inetmib1 / main.c
blob4fdd1dff3cac2fa5b1064c777cd59bcb923be003
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 MIB_IFTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
111 if (table)
113 if (!GetIfTable(table, &size, FALSE)) ifTable = table;
114 else HeapFree(GetProcessHeap(), 0, table );
119 static void mib2IfNumberCleanup(void)
121 HeapFree(GetProcessHeap(), 0, ifTable);
124 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
125 AsnInteger32 *pErrorStatus)
127 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
129 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
130 pErrorStatus);
132 switch (bPduType)
134 case SNMP_PDU_GET:
135 case SNMP_PDU_GETNEXT:
136 if ((bPduType == SNMP_PDU_GET &&
137 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
138 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
139 < 0)
141 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
143 copyInt(&pVarBind->value, &numIfs);
144 if (bPduType == SNMP_PDU_GETNEXT)
145 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
146 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
148 else
150 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
151 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
152 * need to set it here.
155 break;
156 case SNMP_PDU_SET:
157 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
158 break;
159 default:
160 FIXME("0x%02x: unsupported PDU type\n", bPduType);
161 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
163 return TRUE;
166 static void copyOperStatus(AsnAny *value, void *src)
168 value->asnType = ASN_INTEGER;
169 /* The IPHlpApi definition of operational status differs from the MIB2 one,
170 * so map it to the MIB2 value.
172 switch (*(DWORD *)src)
174 case MIB_IF_OPER_STATUS_OPERATIONAL:
175 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
176 break;
177 case MIB_IF_OPER_STATUS_CONNECTING:
178 case MIB_IF_OPER_STATUS_CONNECTED:
179 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
180 break;
181 default:
182 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
186 /* Given an OID and a base OID that it must begin with, finds the item and
187 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
188 * foo, returns item 1 and instance 2.
189 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
190 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
191 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
192 * instance, or item 1, instance 1 if either is missing.
194 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
195 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
197 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
199 switch (bPduType)
201 case SNMP_PDU_GETNEXT:
202 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
204 *item = 1;
205 *instance = 1;
207 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
209 if (oid->idLength == base->idLength ||
210 oid->idLength == base->idLength + 1)
212 /* Either the table or an item within the table is specified,
213 * but the instance is not. Get the first instance.
215 *instance = 1;
216 if (oid->idLength == base->idLength + 1)
217 *item = oid->ids[base->idLength];
218 else
219 *item = 1;
221 else
223 *item = oid->ids[base->idLength];
224 *instance = oid->ids[base->idLength + 1] + 1;
227 else
228 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
229 break;
230 default:
231 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
233 if (oid->idLength == base->idLength ||
234 oid->idLength == base->idLength + 1)
236 /* Either the table or an item within the table is specified,
237 * but the instance is not.
239 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
241 else
243 *item = oid->ids[base->idLength];
244 *instance = oid->ids[base->idLength + 1];
247 else
248 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
250 return ret;
253 /* Given an OID and a base OID that it must begin with, finds the item from the
254 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
255 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
256 * SNMP_ERRORSTATUS_NOSUCHNAME.
257 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
258 * 1 if the item is missing.
260 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
261 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
263 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
265 switch (bPduType)
267 case SNMP_PDU_GETNEXT:
268 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
269 *item = 1;
270 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
272 if (oid->idLength == base->idLength)
274 /* The item is missing, assume the first item */
275 *item = 1;
277 else
278 *item = oid->ids[base->idLength] + 1;
280 else
281 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
282 break;
283 default:
284 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
286 if (oid->idLength == base->idLength)
288 /* The item is missing */
289 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
291 else
293 *item = oid->ids[base->idLength];
294 if (!*item)
295 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
298 else
299 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
301 return ret;
304 struct GenericTable
306 DWORD numEntries;
307 BYTE entries[1];
310 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
312 assert(oid && oid->idLength >= 4);
313 /* Map the IDs to an IP address in little-endian order */
314 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
315 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
318 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
319 typedef int (*compareFunc)(const void *key, const void *value);
321 static UINT findValueInTable(AsnObjectIdentifier *oid,
322 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
323 compareFunc compare)
325 UINT index = 0;
326 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
328 if (key)
330 void *value;
332 makeKey(oid, key);
333 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
334 compare);
335 if (value)
336 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize
337 + 1;
338 HeapFree(GetProcessHeap(), 0, key);
340 return index;
343 /* Given an OID and a base OID that it must begin with, finds the item and
344 * element of the table whose value matches the instance from the OID.
345 * The OID is converted to a key with the function makeKey, and compared
346 * against entries in the table with the function compare.
347 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
348 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
349 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
350 * instance, or item 1, instance 1 if either is missing.
352 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
353 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
354 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
355 compareFunc compare, UINT *item, UINT *instance)
357 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
359 if (!table)
360 return SNMP_ERRORSTATUS_NOSUCHNAME;
362 switch (bPduType)
364 case SNMP_PDU_GETNEXT:
365 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
367 /* Return the first item and instance from the table */
368 *item = 1;
369 *instance = 1;
371 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
372 oid->idLength < base->idLength + instanceLen + 1)
374 /* Either the table or an item is specified, but the instance is
375 * not.
377 *instance = 1;
378 if (oid->idLength >= base->idLength + 1)
380 *item = oid->ids[base->idLength];
381 if (!*item)
382 *item = 1;
384 else
385 *item = 1;
387 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
388 oid->idLength == base->idLength + instanceLen + 1)
390 *item = oid->ids[base->idLength];
391 if (!*item)
393 *instance = 1;
394 *item = 1;
396 else
398 AsnObjectIdentifier ipOid = { instanceLen,
399 oid->ids + base->idLength + 1 };
401 *instance = findValueInTable(&ipOid, table, tableEntrySize,
402 makeKey, compare) + 1;
403 if (*instance > table->numEntries)
404 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
407 else
408 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
409 break;
410 default:
411 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
412 oid->idLength == base->idLength + instanceLen + 1)
414 *item = oid->ids[base->idLength];
415 if (!*item)
416 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
417 else
419 AsnObjectIdentifier ipOid = { instanceLen,
420 oid->ids + base->idLength + 1 };
422 *instance = findValueInTable(&ipOid, table, tableEntrySize,
423 makeKey, compare);
424 if (!*instance)
425 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
428 else
429 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
431 return ret;
434 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
435 UINT item)
437 UINT id;
438 AsnObjectIdentifier oid;
439 INT ret;
441 ret = SnmpUtilOidCpy(dst, base);
442 if (ret)
444 oid.idLength = 1;
445 oid.ids = &id;
446 id = item;
447 ret = SnmpUtilOidAppend(dst, &oid);
449 return ret;
452 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
453 AsnObjectIdentifier *base, UINT item, DWORD addr)
455 UINT id;
456 BYTE *ptr;
457 AsnObjectIdentifier oid;
458 INT ret;
460 ret = setOidWithItem(dst, base, item);
461 if (ret)
463 oid.idLength = 1;
464 oid.ids = &id;
465 for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
466 ptr++)
468 id = *ptr;
469 ret = SnmpUtilOidAppend(dst, &oid);
472 return ret;
475 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
476 AsnObjectIdentifier *base, UINT item, UINT instance)
478 AsnObjectIdentifier oid;
479 INT ret;
481 ret = setOidWithItem(dst, base, item);
482 if (ret)
484 oid.idLength = 1;
485 oid.ids = &instance;
486 ret = SnmpUtilOidAppend(dst, &oid);
488 return ret;
491 static struct structToAsnValue mib2IfEntryMap[] = {
492 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
493 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
494 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
495 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
496 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
497 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
498 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
499 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
500 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
501 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
502 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
503 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
504 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
505 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
506 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
507 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
508 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
509 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
510 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
511 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
512 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
515 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
517 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
518 AsnInteger32 *pErrorStatus)
520 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
522 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
523 pErrorStatus);
525 switch (bPduType)
527 case SNMP_PDU_GET:
528 case SNMP_PDU_GETNEXT:
529 if (!ifTable)
531 /* There is no interface present, so let the caller deal
532 * with finding the successor.
534 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
536 else
538 UINT tableIndex = 0, item = 0;
540 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
541 &entryOid, bPduType, &item, &tableIndex);
542 if (!*pErrorStatus)
544 assert(tableIndex);
545 assert(item);
546 if (tableIndex > ifTable->dwNumEntries)
547 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
548 else
550 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
551 DEFINE_SIZEOF(mib2IfEntryMap),
552 &ifTable->table[tableIndex - 1], item, bPduType,
553 pVarBind);
554 if (bPduType == SNMP_PDU_GETNEXT)
555 setOidWithItemAndInteger(&pVarBind->name, &entryOid,
556 item, tableIndex);
560 break;
561 case SNMP_PDU_SET:
562 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
563 break;
564 default:
565 FIXME("0x%02x: unsupported PDU type\n", bPduType);
566 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
568 return TRUE;
571 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
572 static MIB_IPSTATS ipStats;
574 static void mib2IpStatsInit(void)
576 GetIpStatistics(&ipStats);
579 static struct structToAsnValue mib2IpMap[] = {
580 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
581 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
582 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
583 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
584 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
585 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
586 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
587 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
588 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
589 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
590 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
591 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
592 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
593 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
594 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
595 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
596 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
597 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
598 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
599 { 0, NULL }, /* 20: not used, IP addr table */
600 { 0, NULL }, /* 21: not used, route table */
601 { 0, NULL }, /* 22: not used, net to media (ARP) table */
602 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
605 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
606 AsnInteger32 *pErrorStatus)
608 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
609 UINT item = 0;
611 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
612 pErrorStatus);
614 switch (bPduType)
616 case SNMP_PDU_GET:
617 case SNMP_PDU_GETNEXT:
618 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
619 &item);
620 if (!*pErrorStatus)
622 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
623 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
624 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
625 setOidWithItem(&pVarBind->name, &myOid, item);
627 break;
628 case SNMP_PDU_SET:
629 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
630 break;
631 default:
632 FIXME("0x%02x: unsupported PDU type\n", bPduType);
633 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
635 return TRUE;
638 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
639 static PMIB_IPADDRTABLE ipAddrTable;
641 static struct structToAsnValue mib2IpAddrMap[] = {
642 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
643 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
644 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
645 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
646 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
649 static void mib2IpAddrInit(void)
651 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
653 if (ret == ERROR_INSUFFICIENT_BUFFER)
655 MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
656 if (table)
658 if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table;
659 else HeapFree(GetProcessHeap(), 0, table );
664 static void mib2IpAddrCleanup(void)
666 HeapFree(GetProcessHeap(), 0, ipAddrTable);
669 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
671 MIB_IPADDRROW *row = dst;
673 row->dwAddr = oidToIpAddr(oid);
676 static int compareIpAddrRow(const void *a, const void *b)
678 const MIB_IPADDRROW *key = a, *value = b;
680 return key->dwAddr - value->dwAddr;
683 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
684 AsnInteger32 *pErrorStatus)
686 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
687 UINT tableIndex = 0, item = 0;
689 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
690 pErrorStatus);
692 switch (bPduType)
694 case SNMP_PDU_GET:
695 case SNMP_PDU_GETNEXT:
696 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
697 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
698 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
699 &tableIndex);
700 if (!*pErrorStatus)
702 assert(tableIndex);
703 assert(item);
704 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
705 DEFINE_SIZEOF(mib2IpAddrMap),
706 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
707 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
708 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
709 ipAddrTable->table[tableIndex - 1].dwAddr);
711 break;
712 case SNMP_PDU_SET:
713 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
714 break;
715 default:
716 FIXME("0x%02x: unsupported PDU type\n", bPduType);
717 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
719 return TRUE;
722 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
723 static PMIB_IPFORWARDTABLE ipRouteTable;
725 static struct structToAsnValue mib2IpRouteMap[] = {
726 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
727 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
728 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
729 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
730 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
731 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
732 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
733 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
734 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
735 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
736 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
737 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
740 static void mib2IpRouteInit(void)
742 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
744 if (ret == ERROR_INSUFFICIENT_BUFFER)
746 MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
747 if (table)
749 if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table;
750 else HeapFree(GetProcessHeap(), 0, table );
755 static void mib2IpRouteCleanup(void)
757 HeapFree(GetProcessHeap(), 0, ipRouteTable);
760 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
762 MIB_IPFORWARDROW *row = dst;
764 row->dwForwardDest = oidToIpAddr(oid);
767 static int compareIpForwardRow(const void *a, const void *b)
769 const MIB_IPFORWARDROW *key = a, *value = b;
771 return key->dwForwardDest - value->dwForwardDest;
774 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
775 AsnInteger32 *pErrorStatus)
777 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
778 UINT tableIndex = 0, item = 0;
780 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
781 pErrorStatus);
783 switch (bPduType)
785 case SNMP_PDU_GET:
786 case SNMP_PDU_GETNEXT:
787 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
788 &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable,
789 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
790 &item, &tableIndex);
791 if (!*pErrorStatus)
793 assert(tableIndex);
794 assert(item);
795 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
796 DEFINE_SIZEOF(mib2IpRouteMap),
797 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
798 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
799 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
800 ipRouteTable->table[tableIndex - 1].dwForwardDest);
802 break;
803 case SNMP_PDU_SET:
804 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
805 break;
806 default:
807 FIXME("0x%02x: unsupported PDU type\n", bPduType);
808 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
810 return TRUE;
813 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
814 static PMIB_IPNETTABLE ipNetTable;
816 static struct structToAsnValue mib2IpNetMap[] = {
817 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
818 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyLengthPrecededString },
819 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
820 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
823 static void mib2IpNetInit(void)
825 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
827 if (ret == ERROR_INSUFFICIENT_BUFFER)
829 MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
830 if (table)
832 if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table;
833 else HeapFree(GetProcessHeap(), 0, table );
838 static void mib2IpNetCleanup(void)
840 HeapFree(GetProcessHeap(), 0, ipNetTable);
843 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
844 AsnInteger32 *pErrorStatus)
846 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
848 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
849 pErrorStatus);
851 switch (bPduType)
853 case SNMP_PDU_GET:
854 case SNMP_PDU_GETNEXT:
855 if (!ipNetTable)
856 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
857 else
859 UINT tableIndex = 0, item = 0;
861 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
862 &myOid, bPduType, &item, &tableIndex);
863 if (!*pErrorStatus)
865 assert(tableIndex);
866 assert(item);
867 if (tableIndex > ipNetTable->dwNumEntries)
868 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
869 else
871 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
872 DEFINE_SIZEOF(mib2IpNetMap),
873 &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
874 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
875 setOidWithItemAndInteger(&pVarBind->name, &myOid, item,
876 tableIndex);
880 break;
881 case SNMP_PDU_SET:
882 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
883 break;
884 default:
885 FIXME("0x%02x: unsupported PDU type\n", bPduType);
886 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
888 return TRUE;
891 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
892 static MIB_ICMP icmpStats;
894 static void mib2IcmpInit(void)
896 GetIcmpStatistics(&icmpStats);
899 static struct structToAsnValue mib2IcmpMap[] = {
900 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
901 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
902 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
903 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
904 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
905 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
906 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
907 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
908 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
909 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
910 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
911 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
912 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
913 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
914 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
915 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
916 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
917 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
918 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
919 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
920 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
921 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
922 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
923 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
924 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
925 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
928 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
929 AsnInteger32 *pErrorStatus)
931 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
932 UINT item = 0;
934 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
935 pErrorStatus);
937 switch (bPduType)
939 case SNMP_PDU_GET:
940 case SNMP_PDU_GETNEXT:
941 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
942 &item);
943 if (!*pErrorStatus)
945 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
946 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
947 pVarBind);
948 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
949 setOidWithItem(&pVarBind->name, &myOid, item);
951 break;
952 case SNMP_PDU_SET:
953 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
954 break;
955 default:
956 FIXME("0x%02x: unsupported PDU type\n", bPduType);
957 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
959 return TRUE;
962 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
963 static MIB_TCPSTATS tcpStats;
965 static void mib2TcpInit(void)
967 GetTcpStatistics(&tcpStats);
970 static struct structToAsnValue mib2TcpMap[] = {
971 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
972 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
973 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
974 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
975 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
976 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
977 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
978 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
979 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
980 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
981 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
982 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
983 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
984 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
985 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
988 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
989 AsnInteger32 *pErrorStatus)
991 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
992 UINT item = 0;
994 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
995 pErrorStatus);
997 switch (bPduType)
999 case SNMP_PDU_GET:
1000 case SNMP_PDU_GETNEXT:
1001 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1002 &item);
1003 if (!*pErrorStatus)
1005 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
1006 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
1007 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1008 setOidWithItem(&pVarBind->name, &myOid, item);
1010 break;
1011 case SNMP_PDU_SET:
1012 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1013 break;
1014 default:
1015 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1016 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1018 return TRUE;
1021 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
1022 static MIB_UDPSTATS udpStats;
1024 static void mib2UdpInit(void)
1026 GetUdpStatistics(&udpStats);
1029 static struct structToAsnValue mib2UdpMap[] = {
1030 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1031 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1032 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1033 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1036 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1037 AsnInteger32 *pErrorStatus)
1039 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1040 UINT item;
1042 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1043 pErrorStatus);
1045 switch (bPduType)
1047 case SNMP_PDU_GET:
1048 case SNMP_PDU_GETNEXT:
1049 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1050 &item);
1051 if (!*pErrorStatus)
1053 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1054 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
1055 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1056 setOidWithItem(&pVarBind->name, &myOid, item);
1058 break;
1059 case SNMP_PDU_SET:
1060 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1061 break;
1062 default:
1063 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1064 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1066 return TRUE;
1069 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
1070 static PMIB_UDPTABLE udpTable;
1072 static void mib2UdpEntryInit(void)
1074 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
1076 if (ret == ERROR_INSUFFICIENT_BUFFER)
1078 MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
1079 if (table)
1081 if (!GetUdpTable(table, &size, TRUE)) udpTable = table;
1082 else HeapFree(GetProcessHeap(), 0, table);
1087 static void mib2UdpEntryCleanup(void)
1089 HeapFree(GetProcessHeap(), 0, udpTable);
1092 static struct structToAsnValue mib2UdpEntryMap[] = {
1093 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
1094 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
1097 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
1099 MIB_UDPROW *row = dst;
1101 assert(oid && oid->idLength >= 5);
1102 row->dwLocalAddr = oidToIpAddr(oid);
1103 row->dwLocalPort = oid->ids[4];
1106 static int compareUdpRow(const void *a, const void *b)
1108 const MIB_UDPROW *key = a, *value = b;
1109 int ret;
1111 ret = key->dwLocalAddr - value->dwLocalAddr;
1112 if (ret == 0)
1113 ret = key->dwLocalPort - value->dwLocalPort;
1114 return ret;
1117 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1118 AsnInteger32 *pErrorStatus)
1120 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
1122 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1123 pErrorStatus);
1125 switch (bPduType)
1127 case SNMP_PDU_GET:
1128 case SNMP_PDU_GETNEXT:
1129 if (!udpTable)
1130 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1131 else
1133 UINT tableIndex = 0, item = 0;
1135 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
1136 5, bPduType, (struct GenericTable *)udpTable,
1137 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
1138 &tableIndex);
1139 if (!*pErrorStatus)
1141 assert(tableIndex);
1142 assert(item);
1143 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
1144 DEFINE_SIZEOF(mib2UdpEntryMap),
1145 &udpTable->table[tableIndex - 1], item, bPduType, pVarBind);
1146 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1148 AsnObjectIdentifier oid;
1150 setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
1151 udpTable->table[tableIndex - 1].dwLocalAddr);
1152 oid.idLength = 1;
1153 oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
1154 SnmpUtilOidAppend(&pVarBind->name, &oid);
1158 break;
1159 case SNMP_PDU_SET:
1160 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1161 break;
1162 default:
1163 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1164 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1166 return TRUE;
1169 /* This list MUST BE lexicographically sorted */
1170 static struct mibImplementation supportedIDs[] = {
1171 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
1172 mib2IfNumberCleanup },
1173 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
1174 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
1175 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
1176 mib2IpAddrCleanup },
1177 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
1178 mib2IpRouteCleanup },
1179 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
1180 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
1181 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
1182 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
1183 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
1184 mib2UdpEntryCleanup },
1186 static UINT minSupportedIDLength;
1188 /*****************************************************************************
1189 * SnmpExtensionInit [INETMIB1.@]
1191 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1192 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1194 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1195 UINT i;
1197 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1198 pFirstSupportedRegion);
1200 minSupportedIDLength = UINT_MAX;
1201 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1203 if (supportedIDs[i].init)
1204 supportedIDs[i].init();
1205 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1206 minSupportedIDLength = supportedIDs[i].name.idLength;
1208 *phSubagentTrapEvent = NULL;
1209 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1210 return TRUE;
1213 static void cleanup(void)
1215 UINT i;
1217 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1218 if (supportedIDs[i].cleanup)
1219 supportedIDs[i].cleanup();
1222 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1223 UINT *matchingIndex)
1225 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
1226 struct mibImplementation *impl = NULL;
1227 AsnObjectIdentifier oid1 = { idLength, ids};
1229 if (!idLength)
1230 return NULL;
1231 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
1232 i = (indexLow + indexHigh) / 2)
1234 INT cmp;
1236 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
1237 if (!cmp)
1239 impl = &supportedIDs[i];
1240 *matchingIndex = i;
1242 else if (cmp > 0)
1243 indexLow = i + 1;
1244 else
1245 indexHigh = i - 1;
1247 return impl;
1250 /*****************************************************************************
1251 * SnmpExtensionQuery [INETMIB1.@]
1253 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1254 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1256 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1257 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1258 UINT i;
1260 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1261 pErrorStatus, pErrorIndex);
1263 for (i = 0; !error && i < pVarBindList->len; i++)
1265 /* Ignore any OIDs not in MIB2 */
1266 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1267 mib2oid.idLength))
1269 struct mibImplementation *impl = NULL;
1270 UINT len, matchingIndex = 0;
1272 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1273 /* Search for an implementation matching as many octets as possible
1275 for (len = pVarBindList->list[i].name.idLength;
1276 len >= minSupportedIDLength && !impl; len--)
1277 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1278 &matchingIndex);
1279 if (impl && impl->query)
1280 impl->query(bPduType, &pVarBindList->list[i], &error);
1281 else
1282 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1283 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1284 bPduType == SNMP_PDU_GETNEXT)
1286 /* GetNext is special: it finds the successor to the given OID,
1287 * so we have to continue until an implementation handles the
1288 * query or we exhaust the table of supported OIDs.
1290 for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1291 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1292 matchingIndex++)
1294 error = SNMP_ERRORSTATUS_NOERROR;
1295 impl = &supportedIDs[matchingIndex];
1296 if (impl->query)
1297 impl->query(bPduType, &pVarBindList->list[i], &error);
1298 else
1299 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1301 /* If the query still isn't resolved, set the OID to the
1302 * successor to the last entry in the table.
1304 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1306 SnmpUtilOidFree(&pVarBindList->list[i].name);
1307 SnmpUtilOidCpy(&pVarBindList->list[i].name,
1308 &supportedIDs[matchingIndex - 1].name);
1309 pVarBindList->list[i].name.ids[
1310 pVarBindList->list[i].name.idLength - 1] += 1;
1313 if (error)
1314 errorIndex = i + 1;
1317 *pErrorStatus = error;
1318 *pErrorIndex = errorIndex;
1319 return TRUE;
1322 /*****************************************************************************
1323 * DllMain [INETMIB1.@]
1325 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1327 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1329 switch (fdwReason)
1331 case DLL_PROCESS_ATTACH:
1332 DisableThreadLibraryCalls(hinstDLL);
1333 break;
1334 case DLL_PROCESS_DETACH:
1335 cleanup();
1336 break;
1337 default:
1338 break;
1341 return TRUE;