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
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
31 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
33 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
37 case DLL_WINE_PREATTACH:
38 return FALSE; /* prefer native version */
39 case DLL_PROCESS_ATTACH:
40 DisableThreadLibraryCalls(hinstDLL);
42 case DLL_PROCESS_DETACH:
54 static void copyInt(AsnAny *value, void *src)
56 value->asnType = ASN_INTEGER;
57 value->asnValue.number = *(DWORD *)src;
60 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
64 strValue.asnType = type;
65 strValue.asnValue.string.stream = str;
66 strValue.asnValue.string.length = len;
67 strValue.asnValue.string.dynamic = TRUE;
68 SnmpUtilAsnAnyCpy(value, &strValue);
71 static void copyLengthPrecededString(AsnAny *value, void *src)
73 DWORD len = *(DWORD *)src;
75 setStringValue(value, ASN_OCTETSTRING, len, (BYTE *)src + sizeof(DWORD));
78 typedef void (*copyValueFunc)(AsnAny *value, void *src);
80 struct structToAsnValue
86 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
87 UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
89 /* OIDs are 1-based */
91 return SNMP_ERRORSTATUS_NOSUCHNAME;
94 return SNMP_ERRORSTATUS_NOSUCHNAME;
96 return SNMP_ERRORSTATUS_NOSUCHNAME;
97 map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
98 return SNMP_ERRORSTATUS_NOERROR;
101 static void copyIpAddr(AsnAny *value, void *src)
103 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
106 static UINT mib2[] = { 1,3,6,1,2,1 };
107 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
109 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
110 AsnInteger32 *pErrorStatus);
112 struct mibImplementation
114 AsnObjectIdentifier name;
119 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
120 static PMIB_IFTABLE ifTable;
122 static void mib2IfNumberInit(void)
124 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
126 if (ret == ERROR_INSUFFICIENT_BUFFER)
128 ifTable = HeapAlloc(GetProcessHeap(), 0, size);
130 GetIfTable(ifTable, &size, FALSE);
134 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
135 AsnInteger32 *pErrorStatus)
137 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
139 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
145 case SNMP_PDU_GETNEXT:
146 if ((bPduType == SNMP_PDU_GET &&
147 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
148 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
151 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
153 copyInt(&pVarBind->value, &numIfs);
154 if (bPduType == SNMP_PDU_GETNEXT)
155 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
156 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
160 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
161 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
162 * need to set it here.
167 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
170 FIXME("0x%02x: unsupported PDU type\n", bPduType);
171 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
176 static void copyOperStatus(AsnAny *value, void *src)
178 value->asnType = ASN_INTEGER;
179 /* The IPHlpApi definition of operational status differs from the MIB2 one,
180 * so map it to the MIB2 value.
182 switch (*(DWORD *)src)
184 case MIB_IF_OPER_STATUS_OPERATIONAL:
185 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
187 case MIB_IF_OPER_STATUS_CONNECTING:
188 case MIB_IF_OPER_STATUS_CONNECTED:
189 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
192 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
196 /* Given an OID and a base OID that it must begin with, finds the item and
197 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
198 * foo, returns item 1 and instance 2.
199 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
200 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
201 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
202 * instance, or item 1, instance 1 if either is missing.
204 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
205 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
207 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
211 case SNMP_PDU_GETNEXT:
212 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
217 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
219 if (oid->idLength == base->idLength ||
220 oid->idLength == base->idLength + 1)
222 /* Either the table or an item within the table is specified,
223 * but the instance is not. Get the first instance.
226 if (oid->idLength == base->idLength + 1)
227 *item = oid->ids[base->idLength];
233 *item = oid->ids[base->idLength];
234 *instance = oid->ids[base->idLength + 1] + 1;
238 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
241 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
243 if (oid->idLength == base->idLength ||
244 oid->idLength == base->idLength + 1)
246 /* Either the table or an item within the table is specified,
247 * but the instance is not.
249 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
253 *item = oid->ids[base->idLength];
254 *instance = oid->ids[base->idLength + 1];
258 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
263 /* Given an OID and a base OID that it must begin with, finds the item from the
264 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
265 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
266 * SNMP_ERRORSTATUS_NOSUCHNAME.
267 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
268 * 1 if the item is missing.
270 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
271 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
273 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
277 case SNMP_PDU_GETNEXT:
278 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
280 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
282 if (oid->idLength == base->idLength)
284 /* The item is missing, assume the first item */
288 *item = oid->ids[base->idLength] + 1;
291 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
294 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
296 if (oid->idLength == base->idLength)
298 /* The item is missing */
299 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
303 *item = oid->ids[base->idLength];
305 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
309 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
320 /* Finds the index in table whose IP address (at offset addressOffset within the
321 * entry) matches that given the OID, which is assumed to have at least 4 IDs.
323 static UINT findOIDIPAddressInTable(AsnObjectIdentifier *oid,
324 struct GenericTable *table, size_t tableEntrySize, size_t addressOffset)
329 /* Map the IDs to an IP address in little-endian order */
330 addr = (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
331 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
332 /* Find the item whose address matches */
333 for (i = 0; !index && i < table->numEntries; i++)
336 *(DWORD *)(table->entries + i * tableEntrySize + addressOffset);
338 if (addr == tableAddr)
344 /* Given an OID and a base OID that it must begin with, finds the item and
345 * element of the table whose IP address matches the instance from the OID.
346 * E.g., given an OID foo.1.2.3.4.5 and a base OID foo, returns item 1 and the
347 * index of the entry in the table whose IP address is 2.3.4.5.
348 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
349 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
350 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
351 * instance, or item 1, instance 1 if either is missing.
353 static AsnInteger32 getItemAndIpAddressInstanceFromOid(AsnObjectIdentifier *oid,
354 AsnObjectIdentifier *base, BYTE bPduType, struct GenericTable *table,
355 size_t tableEntrySize, size_t addressOffset, UINT *item, UINT *instance)
357 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
360 return SNMP_ERRORSTATUS_NOSUCHNAME;
364 case SNMP_PDU_GETNEXT:
365 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
367 /* Return the first item and instance from the table */
371 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
372 oid->idLength < base->idLength + 5)
374 /* Either the table or an item is specified, but the instance is
378 if (oid->idLength >= base->idLength + 1)
380 *item = oid->ids[base->idLength];
387 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
388 oid->idLength == base->idLength + 5)
390 *item = oid->ids[base->idLength];
398 AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
401 *instance = findOIDIPAddressInTable(&ipOid, table,
402 tableEntrySize, addressOffset) + 1;
403 if (*instance > table->numEntries)
404 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
408 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
411 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
412 oid->idLength == base->idLength + 5)
414 *item = oid->ids[base->idLength];
416 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
419 AsnObjectIdentifier ipOid = { 4, oid->ids + base->idLength + 1
422 *instance = findOIDIPAddressInTable(&ipOid, table,
423 tableEntrySize, addressOffset);
425 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
429 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
434 static struct structToAsnValue mib2IfEntryMap[] = {
435 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
436 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
437 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
438 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
439 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
440 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
441 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
442 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
443 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
444 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
445 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
446 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
447 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
448 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
449 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
450 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
451 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
452 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
453 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
454 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
455 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
458 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
460 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
461 AsnInteger32 *pErrorStatus)
463 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
465 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
471 case SNMP_PDU_GETNEXT:
474 /* There is no interface present, so let the caller deal
475 * with finding the successor.
477 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
481 UINT tableIndex = 0, item = 0;
483 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
484 &entryOid, bPduType, &item, &tableIndex);
489 if (tableIndex > ifTable->dwNumEntries)
490 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
493 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
494 DEFINE_SIZEOF(mib2IfEntryMap),
495 &ifTable->table[tableIndex - 1], item, bPduType,
497 if (bPduType == SNMP_PDU_GETNEXT)
499 AsnObjectIdentifier oid;
501 SnmpUtilOidCpy(&pVarBind->name, &entryOid);
504 SnmpUtilOidAppend(&pVarBind->name, &oid);
505 /* According to RFC1158, the value of the interface
506 * index must vary between 1 and ifNumber (the number
507 * of interfaces), so use the 1-based table index
508 * directly, rather than assuming that IPHlpApi's
509 * dwIndex will have the correct range.
512 oid.ids = &tableIndex;
513 SnmpUtilOidAppend(&pVarBind->name, &oid);
520 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
523 FIXME("0x%02x: unsupported PDU type\n", bPduType);
524 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
529 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
530 static MIB_IPSTATS ipStats;
532 static void mib2IpStatsInit(void)
534 GetIpStatistics(&ipStats);
537 static struct structToAsnValue mib2IpMap[] = {
538 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
539 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
540 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
541 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
542 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
543 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
544 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
545 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
546 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
547 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
548 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
549 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
550 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
551 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
552 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
553 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
554 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
555 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
556 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
557 { 0, NULL }, /* 20: not used, IP addr table */
558 { 0, NULL }, /* 21: not used, route table */
559 { 0, NULL }, /* 22: not used, net to media (ARP) table */
560 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
563 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
564 AsnInteger32 *pErrorStatus)
566 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
569 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
575 case SNMP_PDU_GETNEXT:
576 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
580 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
581 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
582 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
584 AsnObjectIdentifier oid;
586 SnmpUtilOidCpy(&pVarBind->name, &myOid);
589 SnmpUtilOidAppend(&pVarBind->name, &oid);
594 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
597 FIXME("0x%02x: unsupported PDU type\n", bPduType);
598 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
603 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
604 static PMIB_IPADDRTABLE ipAddrTable;
606 static struct structToAsnValue mib2IpAddrMap[] = {
607 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
608 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
609 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
610 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
611 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
614 static void mib2IpAddrInit(void)
616 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, FALSE);
618 if (ret == ERROR_INSUFFICIENT_BUFFER)
620 ipAddrTable = HeapAlloc(GetProcessHeap(), 0, size);
622 GetIpAddrTable(ipAddrTable, &size, FALSE);
626 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
627 AsnInteger32 *pErrorStatus)
629 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
630 UINT tableIndex = 0, item = 0;
632 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
638 case SNMP_PDU_GETNEXT:
639 *pErrorStatus = getItemAndIpAddressInstanceFromOid(&pVarBind->name,
640 &myOid, bPduType, (struct GenericTable *)ipAddrTable,
641 sizeof(MIB_IPADDRROW), FIELD_OFFSET(MIB_IPADDRROW, dwAddr), &item,
647 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
648 DEFINE_SIZEOF(mib2IpAddrMap),
649 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
650 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
654 AsnObjectIdentifier oid;
656 SnmpUtilOidCpy(&pVarBind->name, &myOid);
660 SnmpUtilOidAppend(&pVarBind->name, &oid);
661 for (ptr = (BYTE *)&ipAddrTable->table[tableIndex - 1].dwAddr;
662 ptr < (BYTE *)&ipAddrTable->table[tableIndex - 1].dwAddr +
663 sizeof(DWORD); ptr++)
666 SnmpUtilOidAppend(&pVarBind->name, &oid);
672 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
675 FIXME("0x%02x: unsupported PDU type\n", bPduType);
676 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
681 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
682 static MIB_ICMP icmpStats;
684 static void mib2IcmpInit(void)
686 GetIcmpStatistics(&icmpStats);
689 static struct structToAsnValue mib2IcmpMap[] = {
690 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
691 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
692 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
693 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
694 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
695 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
696 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
697 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
698 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
699 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
700 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
701 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
702 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
703 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
704 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
705 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
706 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
707 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
708 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
709 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
710 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
711 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
712 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
713 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
714 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
715 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
718 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
719 AsnInteger32 *pErrorStatus)
721 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
724 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
730 case SNMP_PDU_GETNEXT:
731 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
735 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
736 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
740 AsnObjectIdentifier oid;
742 SnmpUtilOidCpy(&pVarBind->name, &myOid);
745 SnmpUtilOidAppend(&pVarBind->name, &oid);
750 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
753 FIXME("0x%02x: unsupported PDU type\n", bPduType);
754 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
759 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
760 static MIB_TCPSTATS tcpStats;
762 static void mib2TcpInit(void)
764 GetTcpStatistics(&tcpStats);
767 static struct structToAsnValue mib2TcpMap[] = {
768 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
769 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
770 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
771 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
772 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
773 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
774 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
775 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
776 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
777 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
778 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
779 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
780 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
781 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
782 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
785 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
786 AsnInteger32 *pErrorStatus)
788 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
791 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
797 case SNMP_PDU_GETNEXT:
798 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
802 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
803 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
804 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
806 AsnObjectIdentifier oid;
808 SnmpUtilOidCpy(&pVarBind->name, &myOid);
811 SnmpUtilOidAppend(&pVarBind->name, &oid);
816 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
819 FIXME("0x%02x: unsupported PDU type\n", bPduType);
820 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
825 /* This list MUST BE lexicographically sorted */
826 static struct mibImplementation supportedIDs[] = {
827 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery },
828 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery },
829 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery },
830 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery },
831 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery },
832 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery },
834 static UINT minSupportedIDLength;
836 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
837 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
839 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
842 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
843 pFirstSupportedRegion);
845 minSupportedIDLength = UINT_MAX;
846 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
848 if (supportedIDs[i].init)
849 supportedIDs[i].init();
850 if (supportedIDs[i].name.idLength < minSupportedIDLength)
851 minSupportedIDLength = supportedIDs[i].name.idLength;
853 *phSubagentTrapEvent = NULL;
854 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
858 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
861 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
862 struct mibImplementation *impl = NULL;
863 AsnObjectIdentifier oid1 = { idLength, ids};
867 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
868 i = (indexLow + indexHigh) / 2)
872 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
875 impl = &supportedIDs[i];
886 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
887 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
889 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
890 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
893 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
894 pErrorStatus, pErrorIndex);
896 for (i = 0; !error && i < pVarBindList->len; i++)
898 /* Ignore any OIDs not in MIB2 */
899 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
902 struct mibImplementation *impl = NULL;
903 UINT len, matchingIndex = 0;
905 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
906 /* Search for an implementation matching as many octets as possible
908 for (len = pVarBindList->list[i].name.idLength;
909 len >= minSupportedIDLength && !impl; len--)
910 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
912 if (impl && impl->query)
913 impl->query(bPduType, &pVarBindList->list[i], &error);
915 error = SNMP_ERRORSTATUS_NOSUCHNAME;
916 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
917 bPduType == SNMP_PDU_GETNEXT)
919 /* GetNext is special: it finds the successor to the given OID,
920 * so we have to continue until an implementation handles the
921 * query or we exhaust the table of supported OIDs.
923 for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
924 matchingIndex < DEFINE_SIZEOF(supportedIDs);
927 error = SNMP_ERRORSTATUS_NOERROR;
928 impl = &supportedIDs[matchingIndex];
930 impl->query(bPduType, &pVarBindList->list[i], &error);
932 error = SNMP_ERRORSTATUS_NOSUCHNAME;
934 /* If the query still isn't resolved, set the OID to the
935 * successor to the last entry in the table.
937 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
939 SnmpUtilOidFree(&pVarBindList->list[i].name);
940 SnmpUtilOidCpy(&pVarBindList->list[i].name,
941 &supportedIDs[matchingIndex - 1].name);
942 pVarBindList->list[i].name.ids[
943 pVarBindList->list[i].name.idLength - 1] += 1;
950 *pErrorStatus = error;
951 *pErrorIndex = errorIndex;