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
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1
);
36 static DWORD
copyInt(AsnAny
*value
, void *src
)
38 value
->asnType
= ASN_INTEGER
;
39 value
->asnValue
.number
= *(DWORD
*)src
;
40 return SNMP_ERRORSTATUS_NOERROR
;
43 static void setStringValue(AsnAny
*value
, BYTE type
, DWORD len
, BYTE
*str
)
47 strValue
.asnType
= type
;
48 strValue
.asnValue
.string
.stream
= str
;
49 strValue
.asnValue
.string
.length
= len
;
50 strValue
.asnValue
.string
.dynamic
= FALSE
;
51 SnmpUtilAsnAnyCpy(value
, &strValue
);
54 typedef DWORD (*copyValueFunc
)(AsnAny
*value
, void *src
);
56 struct structToAsnValue
62 static AsnInteger32
mapStructEntryToValue(struct structToAsnValue
*map
,
63 UINT mapLen
, void *record
, UINT id
, SnmpVarBind
*pVarBind
)
65 /* OIDs are 1-based */
67 return SNMP_ERRORSTATUS_NOSUCHNAME
;
70 return SNMP_ERRORSTATUS_NOSUCHNAME
;
72 return SNMP_ERRORSTATUS_NOSUCHNAME
;
73 return map
[id
].copy(&pVarBind
->value
, (BYTE
*)record
+ map
[id
].offset
);
76 static DWORD
copyIpAddr(AsnAny
*value
, void *src
)
78 setStringValue(value
, ASN_IPADDRESS
, sizeof(DWORD
), src
);
79 return SNMP_ERRORSTATUS_NOERROR
;
82 static UINT mib2
[] = { 1,3,6,1,2,1 };
83 static UINT mib2System
[] = { 1,3,6,1,2,1,1 };
85 typedef BOOL (*varqueryfunc
)(BYTE bPduType
, SnmpVarBind
*pVarBind
,
86 AsnInteger32
*pErrorStatus
);
88 struct mibImplementation
90 AsnObjectIdentifier name
;
93 void (*cleanup
)(void);
96 static UINT mib2IfNumber
[] = { 1,3,6,1,2,1,2,1 };
97 static PMIB_IFTABLE ifTable
;
99 static void mib2IfNumberInit(void)
101 DWORD size
= 0, ret
= GetIfTable(NULL
, &size
, FALSE
);
103 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
105 MIB_IFTABLE
*table
= HeapAlloc(GetProcessHeap(), 0, size
);
108 if (!GetIfTable(table
, &size
, FALSE
)) ifTable
= table
;
109 else HeapFree(GetProcessHeap(), 0, table
);
114 static void mib2IfNumberCleanup(void)
116 HeapFree(GetProcessHeap(), 0, ifTable
);
119 static BOOL
mib2IfNumberQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
120 AsnInteger32
*pErrorStatus
)
122 AsnObjectIdentifier numberOid
= DEFINE_OID(mib2IfNumber
);
125 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
131 case SNMP_PDU_GETNEXT
:
132 if ((bPduType
== SNMP_PDU_GET
&&
133 !SnmpUtilOidNCmp(&pVarBind
->name
, &numberOid
, numberOid
.idLength
))
134 || SnmpUtilOidNCmp(&pVarBind
->name
, &numberOid
, numberOid
.idLength
)
137 DWORD numIfs
= ifTable
? ifTable
->dwNumEntries
: 0;
139 copyInt(&pVarBind
->value
, &numIfs
);
140 if (bPduType
== SNMP_PDU_GETNEXT
)
142 SnmpUtilOidFree(&pVarBind
->name
);
143 SnmpUtilOidCpy(&pVarBind
->name
, &numberOid
);
145 *pErrorStatus
= SNMP_ERRORSTATUS_NOERROR
;
149 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
150 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
151 * need to set it here.
156 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
160 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
161 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
166 static DWORD
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
;
177 case MIB_IF_OPER_STATUS_CONNECTING
:
178 case MIB_IF_OPER_STATUS_CONNECTED
:
179 value
->asnValue
.number
= MIB_IF_ADMIN_STATUS_TESTING
;
182 value
->asnValue
.number
= MIB_IF_ADMIN_STATUS_DOWN
;
184 return SNMP_ERRORSTATUS_NOERROR
;
187 /* Given an OID and a base OID that it must begin with, finds the item and
188 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
189 * foo, returns item 1 and instance 2.
190 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
191 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
192 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
193 * instance, or item 1, instance 1 if either is missing.
195 static AsnInteger32
getItemAndIntegerInstanceFromOid(AsnObjectIdentifier
*oid
,
196 AsnObjectIdentifier
*base
, BYTE bPduType
, UINT
*item
, UINT
*instance
)
198 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
202 case SNMP_PDU_GETNEXT
:
203 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
208 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
210 if (oid
->idLength
== base
->idLength
||
211 oid
->idLength
== base
->idLength
+ 1)
213 /* Either the table or an item within the table is specified,
214 * but the instance is not. Get the first instance.
217 if (oid
->idLength
== base
->idLength
+ 1)
218 *item
= oid
->ids
[base
->idLength
];
224 *item
= oid
->ids
[base
->idLength
];
225 *instance
= oid
->ids
[base
->idLength
+ 1] + 1;
229 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
232 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
234 if (oid
->idLength
== base
->idLength
||
235 oid
->idLength
== base
->idLength
+ 1)
237 /* Either the table or an item within the table is specified,
238 * but the instance is not.
240 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
244 *item
= oid
->ids
[base
->idLength
];
245 *instance
= oid
->ids
[base
->idLength
+ 1];
249 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
254 /* Given an OID and a base OID that it must begin with, finds the item from the
255 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
256 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
257 * SNMP_ERRORSTATUS_NOSUCHNAME.
258 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
259 * 1 if the item is missing.
261 static AsnInteger32
getItemFromOid(AsnObjectIdentifier
*oid
,
262 AsnObjectIdentifier
*base
, BYTE bPduType
, UINT
*item
)
264 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
268 case SNMP_PDU_GETNEXT
:
269 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
271 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
273 if (oid
->idLength
== base
->idLength
)
275 /* The item is missing, assume the first item */
279 *item
= oid
->ids
[base
->idLength
] + 1;
282 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
285 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
287 if (oid
->idLength
== base
->idLength
)
289 /* The item is missing */
290 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
294 *item
= oid
->ids
[base
->idLength
];
296 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
300 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
311 static DWORD
oidToIpAddr(AsnObjectIdentifier
*oid
)
313 assert(oid
&& oid
->idLength
>= 4);
314 /* Map the IDs to an IP address in little-endian order */
315 return (BYTE
)oid
->ids
[3] << 24 | (BYTE
)oid
->ids
[2] << 16 |
316 (BYTE
)oid
->ids
[1] << 8 | (BYTE
)oid
->ids
[0];
319 typedef void (*oidToKeyFunc
)(AsnObjectIdentifier
*oid
, void *dst
);
320 typedef int (__cdecl
*compareFunc
)(const void *key
, const void *value
);
322 /* Finds the first value in the table that matches key. Returns its 1-based
323 * index if found, or 0 if not found.
325 static UINT
findValueInTable(const void *key
,
326 struct GenericTable
*table
, size_t tableEntrySize
, compareFunc compare
)
331 value
= bsearch(key
, table
->entries
, table
->numEntries
, tableEntrySize
,
334 index
= ((BYTE
*)value
- (BYTE
*)table
->entries
) / tableEntrySize
+ 1;
338 /* Finds the first value in the table that matches oid, using makeKey to
339 * convert the oid to a key for comparison. Returns the value's 1-based
340 * index if found, or 0 if not found.
342 static UINT
findOidInTable(AsnObjectIdentifier
*oid
,
343 struct GenericTable
*table
, size_t tableEntrySize
, oidToKeyFunc makeKey
,
347 void *key
= HeapAlloc(GetProcessHeap(), 0, tableEntrySize
);
352 index
= findValueInTable(key
, table
, tableEntrySize
, compare
);
353 HeapFree(GetProcessHeap(), 0, key
);
358 /* Finds the first successor to the value in the table that does matches oid,
359 * using makeKey to convert the oid to a key for comparison. A successor is
360 * a value that does not match oid, so if multiple entries match an oid, only
361 * the first will ever be returned using this method.
362 * Returns the successor's 1-based index if found, or 0 if not found.
364 static UINT
findNextOidInTable(AsnObjectIdentifier
*oid
,
365 struct GenericTable
*table
, size_t tableEntrySize
, oidToKeyFunc makeKey
,
369 void *key
= HeapAlloc(GetProcessHeap(), 0, tableEntrySize
);
374 index
= findValueInTable(key
, table
, tableEntrySize
, compare
);
377 /* Not found in table. If it's less than the first entry, return
378 * the first index. Otherwise just return 0 and let the caller
379 * handle finding the successor.
381 if (compare(key
, table
->entries
) < 0)
386 /* Skip any entries that match the same key. This enumeration will
387 * be incomplete, but it's what Windows appears to do if there are
388 * multiple entries with the same index in a table, and it avoids
391 for (++index
; index
<= table
->numEntries
&& compare(key
,
392 &table
->entries
[tableEntrySize
* (index
- 1)]) == 0; ++index
)
395 HeapFree(GetProcessHeap(), 0, key
);
400 /* Given an OID and a base OID that it must begin with, finds the item and
401 * element of the table whose value matches the instance from the OID.
402 * The OID is converted to a key with the function makeKey, and compared
403 * against entries in the table with the function compare.
404 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
405 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
406 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
407 * instance, or item 1, instance 1 if either is missing.
409 static AsnInteger32
getItemAndInstanceFromTable(AsnObjectIdentifier
*oid
,
410 AsnObjectIdentifier
*base
, UINT instanceLen
, BYTE bPduType
,
411 struct GenericTable
*table
, size_t tableEntrySize
, oidToKeyFunc makeKey
,
412 compareFunc compare
, UINT
*item
, UINT
*instance
)
414 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
417 return SNMP_ERRORSTATUS_NOSUCHNAME
;
421 case SNMP_PDU_GETNEXT
:
422 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
424 /* Return the first item and instance from the table */
428 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
429 oid
->idLength
< base
->idLength
+ instanceLen
+ 1)
431 /* Either the table or an item is specified, but the instance is
435 if (oid
->idLength
>= base
->idLength
+ 1)
437 *item
= oid
->ids
[base
->idLength
];
444 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
445 oid
->idLength
== base
->idLength
+ instanceLen
+ 1)
447 *item
= oid
->ids
[base
->idLength
];
455 AsnObjectIdentifier instanceOid
= { instanceLen
,
456 oid
->ids
+ base
->idLength
+ 1 };
458 *instance
= findNextOidInTable(&instanceOid
, table
,
459 tableEntrySize
, makeKey
, compare
);
460 if (!*instance
|| *instance
> table
->numEntries
)
461 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
465 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
468 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
469 oid
->idLength
== base
->idLength
+ instanceLen
+ 1)
471 *item
= oid
->ids
[base
->idLength
];
473 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
476 AsnObjectIdentifier instanceOid
= { instanceLen
,
477 oid
->ids
+ base
->idLength
+ 1 };
479 *instance
= findOidInTable(&instanceOid
, table
, tableEntrySize
,
482 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
486 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
491 static INT
setOidWithItem(AsnObjectIdentifier
*dst
, AsnObjectIdentifier
*base
,
495 AsnObjectIdentifier oid
;
498 SnmpUtilOidFree(dst
);
499 ret
= SnmpUtilOidCpy(dst
, base
);
505 ret
= SnmpUtilOidAppend(dst
, &oid
);
510 static INT
setOidWithItemAndIpAddr(AsnObjectIdentifier
*dst
,
511 AsnObjectIdentifier
*base
, UINT item
, DWORD addr
)
515 AsnObjectIdentifier oid
;
518 ret
= setOidWithItem(dst
, base
, item
);
523 for (ptr
= (BYTE
*)&addr
; ret
&& ptr
< (BYTE
*)&addr
+ sizeof(DWORD
);
527 ret
= SnmpUtilOidAppend(dst
, &oid
);
533 static INT
setOidWithItemAndInteger(AsnObjectIdentifier
*dst
,
534 AsnObjectIdentifier
*base
, UINT item
, UINT instance
)
536 AsnObjectIdentifier oid
;
539 ret
= setOidWithItem(dst
, base
, item
);
544 ret
= SnmpUtilOidAppend(dst
, &oid
);
549 static DWORD
copyIfRowDescr(AsnAny
*value
, void *src
)
551 PMIB_IFROW row
= (PMIB_IFROW
)((BYTE
*)src
-
552 FIELD_OFFSET(MIB_IFROW
, dwDescrLen
));
557 setStringValue(value
, ASN_OCTETSTRING
, row
->dwDescrLen
, row
->bDescr
);
558 ret
= SNMP_ERRORSTATUS_NOERROR
;
561 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
565 static DWORD
copyIfRowPhysAddr(AsnAny
*value
, void *src
)
567 PMIB_IFROW row
= (PMIB_IFROW
)((BYTE
*)src
-
568 FIELD_OFFSET(MIB_IFROW
, dwPhysAddrLen
));
571 if (row
->dwPhysAddrLen
)
573 setStringValue(value
, ASN_OCTETSTRING
, row
->dwPhysAddrLen
,
575 ret
= SNMP_ERRORSTATUS_NOERROR
;
578 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
582 static struct structToAsnValue mib2IfEntryMap
[] = {
583 { FIELD_OFFSET(MIB_IFROW
, dwIndex
), copyInt
},
584 { FIELD_OFFSET(MIB_IFROW
, dwDescrLen
), copyIfRowDescr
},
585 { FIELD_OFFSET(MIB_IFROW
, dwType
), copyInt
},
586 { FIELD_OFFSET(MIB_IFROW
, dwMtu
), copyInt
},
587 { FIELD_OFFSET(MIB_IFROW
, dwSpeed
), copyInt
},
588 { FIELD_OFFSET(MIB_IFROW
, dwPhysAddrLen
), copyIfRowPhysAddr
},
589 { FIELD_OFFSET(MIB_IFROW
, dwAdminStatus
), copyInt
},
590 { FIELD_OFFSET(MIB_IFROW
, dwOperStatus
), copyOperStatus
},
591 { FIELD_OFFSET(MIB_IFROW
, dwLastChange
), copyInt
},
592 { FIELD_OFFSET(MIB_IFROW
, dwInOctets
), copyInt
},
593 { FIELD_OFFSET(MIB_IFROW
, dwInUcastPkts
), copyInt
},
594 { FIELD_OFFSET(MIB_IFROW
, dwInNUcastPkts
), copyInt
},
595 { FIELD_OFFSET(MIB_IFROW
, dwInDiscards
), copyInt
},
596 { FIELD_OFFSET(MIB_IFROW
, dwInErrors
), copyInt
},
597 { FIELD_OFFSET(MIB_IFROW
, dwInUnknownProtos
), copyInt
},
598 { FIELD_OFFSET(MIB_IFROW
, dwOutOctets
), copyInt
},
599 { FIELD_OFFSET(MIB_IFROW
, dwOutUcastPkts
), copyInt
},
600 { FIELD_OFFSET(MIB_IFROW
, dwOutNUcastPkts
), copyInt
},
601 { FIELD_OFFSET(MIB_IFROW
, dwOutDiscards
), copyInt
},
602 { FIELD_OFFSET(MIB_IFROW
, dwOutErrors
), copyInt
},
603 { FIELD_OFFSET(MIB_IFROW
, dwOutQLen
), copyInt
},
606 static UINT mib2IfEntry
[] = { 1,3,6,1,2,1,2,2,1 };
608 static BOOL
mib2IfEntryQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
609 AsnInteger32
*pErrorStatus
)
611 AsnObjectIdentifier entryOid
= DEFINE_OID(mib2IfEntry
);
614 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
620 case SNMP_PDU_GETNEXT
:
623 /* There is no interface present, so let the caller deal
624 * with finding the successor.
626 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
630 UINT tableIndex
= 0, item
= 0;
632 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
633 &entryOid
, bPduType
, &item
, &tableIndex
);
638 if (tableIndex
> ifTable
->dwNumEntries
)
639 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
642 *pErrorStatus
= mapStructEntryToValue(mib2IfEntryMap
,
643 DEFINE_SIZEOF(mib2IfEntryMap
),
644 &ifTable
->table
[tableIndex
- 1], item
,
646 if (bPduType
== SNMP_PDU_GETNEXT
)
647 ret
= setOidWithItemAndInteger(&pVarBind
->name
,
648 &entryOid
, item
, tableIndex
);
654 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
658 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
659 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
664 static UINT mib2Ip
[] = { 1,3,6,1,2,1,4 };
665 static MIB_IPSTATS ipStats
;
667 static void mib2IpStatsInit(void)
669 GetIpStatistics(&ipStats
);
672 static struct structToAsnValue mib2IpMap
[] = {
673 { FIELD_OFFSET(MIB_IPSTATS
, dwForwarding
), copyInt
}, /* 1 */
674 { FIELD_OFFSET(MIB_IPSTATS
, dwDefaultTTL
), copyInt
}, /* 2 */
675 { FIELD_OFFSET(MIB_IPSTATS
, dwInReceives
), copyInt
}, /* 3 */
676 { FIELD_OFFSET(MIB_IPSTATS
, dwInHdrErrors
), copyInt
}, /* 4 */
677 { FIELD_OFFSET(MIB_IPSTATS
, dwInAddrErrors
), copyInt
}, /* 5 */
678 { FIELD_OFFSET(MIB_IPSTATS
, dwForwDatagrams
), copyInt
}, /* 6 */
679 { FIELD_OFFSET(MIB_IPSTATS
, dwInUnknownProtos
), copyInt
}, /* 7 */
680 { FIELD_OFFSET(MIB_IPSTATS
, dwInDiscards
), copyInt
}, /* 8 */
681 { FIELD_OFFSET(MIB_IPSTATS
, dwInDelivers
), copyInt
}, /* 9 */
682 { FIELD_OFFSET(MIB_IPSTATS
, dwOutRequests
), copyInt
}, /* 10 */
683 { FIELD_OFFSET(MIB_IPSTATS
, dwOutDiscards
), copyInt
}, /* 11 */
684 { FIELD_OFFSET(MIB_IPSTATS
, dwOutNoRoutes
), copyInt
}, /* 12 */
685 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmTimeout
), copyInt
}, /* 13 */
686 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmReqds
), copyInt
}, /* 14 */
687 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmOks
), copyInt
}, /* 15 */
688 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmFails
), copyInt
}, /* 16 */
689 { FIELD_OFFSET(MIB_IPSTATS
, dwFragOks
), copyInt
}, /* 17 */
690 { FIELD_OFFSET(MIB_IPSTATS
, dwFragFails
), copyInt
}, /* 18 */
691 { FIELD_OFFSET(MIB_IPSTATS
, dwFragCreates
), copyInt
}, /* 19 */
692 { 0, NULL
}, /* 20: not used, IP addr table */
693 { 0, NULL
}, /* 21: not used, route table */
694 { 0, NULL
}, /* 22: not used, net to media (ARP) table */
695 { FIELD_OFFSET(MIB_IPSTATS
, dwRoutingDiscards
), copyInt
}, /* 23 */
698 static BOOL
mib2IpStatsQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
699 AsnInteger32
*pErrorStatus
)
701 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Ip
);
705 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
711 case SNMP_PDU_GETNEXT
:
712 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
716 *pErrorStatus
= mapStructEntryToValue(mib2IpMap
,
717 DEFINE_SIZEOF(mib2IpMap
), &ipStats
, item
, pVarBind
);
718 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
719 ret
= setOidWithItem(&pVarBind
->name
, &myOid
, item
);
723 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
727 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
728 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
733 static UINT mib2IpAddr
[] = { 1,3,6,1,2,1,4,20,1 };
734 static PMIB_IPADDRTABLE ipAddrTable
;
736 static struct structToAsnValue mib2IpAddrMap
[] = {
737 { FIELD_OFFSET(MIB_IPADDRROW
, dwAddr
), copyIpAddr
},
738 { FIELD_OFFSET(MIB_IPADDRROW
, dwIndex
), copyInt
},
739 { FIELD_OFFSET(MIB_IPADDRROW
, dwMask
), copyIpAddr
},
740 { FIELD_OFFSET(MIB_IPADDRROW
, dwBCastAddr
), copyInt
},
741 { FIELD_OFFSET(MIB_IPADDRROW
, dwReasmSize
), copyInt
},
744 static void mib2IpAddrInit(void)
746 DWORD size
= 0, ret
= GetIpAddrTable(NULL
, &size
, TRUE
);
748 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
750 MIB_IPADDRTABLE
*table
= HeapAlloc(GetProcessHeap(), 0, size
);
753 if (!GetIpAddrTable(table
, &size
, TRUE
)) ipAddrTable
= table
;
754 else HeapFree(GetProcessHeap(), 0, table
);
759 static void mib2IpAddrCleanup(void)
761 HeapFree(GetProcessHeap(), 0, ipAddrTable
);
764 static void oidToIpAddrRow(AsnObjectIdentifier
*oid
, void *dst
)
766 MIB_IPADDRROW
*row
= dst
;
768 row
->dwAddr
= oidToIpAddr(oid
);
771 static int __cdecl
DWORD_cmp(DWORD a
, DWORD b
)
773 return a
< b
? -1 : a
> b
? 1 : 0; /* a subtraction would overflow */
776 static int __cdecl
compareIpAddrRow(const void *a
, const void *b
)
778 const MIB_IPADDRROW
*rowA
= a
, *rowB
= b
;
779 return DWORD_cmp(ntohl(rowA
->dwAddr
), ntohl(rowB
->dwAddr
));
782 static BOOL
mib2IpAddrQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
783 AsnInteger32
*pErrorStatus
)
785 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpAddr
);
786 UINT tableIndex
= 0, item
= 0;
789 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
795 case SNMP_PDU_GETNEXT
:
796 *pErrorStatus
= getItemAndInstanceFromTable(&pVarBind
->name
,
797 &myOid
, 4, bPduType
, (struct GenericTable
*)ipAddrTable
,
798 sizeof(MIB_IPADDRROW
), oidToIpAddrRow
, compareIpAddrRow
, &item
,
804 *pErrorStatus
= mapStructEntryToValue(mib2IpAddrMap
,
805 DEFINE_SIZEOF(mib2IpAddrMap
),
806 &ipAddrTable
->table
[tableIndex
- 1], item
, pVarBind
);
807 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
808 ret
= setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
809 ipAddrTable
->table
[tableIndex
- 1].dwAddr
);
813 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
817 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
818 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
823 static UINT mib2IpRoute
[] = { 1,3,6,1,2,1,4,21,1 };
824 static PMIB_IPFORWARDTABLE ipRouteTable
;
826 static struct structToAsnValue mib2IpRouteMap
[] = {
827 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardDest
), copyIpAddr
},
828 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardIfIndex
), copyInt
},
829 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric1
), copyInt
},
830 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric2
), copyInt
},
831 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric3
), copyInt
},
832 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric4
), copyInt
},
833 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardNextHop
), copyIpAddr
},
834 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardType
), copyInt
},
835 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardProto
), copyInt
},
836 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardAge
), copyInt
},
837 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMask
), copyIpAddr
},
838 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric5
), copyInt
},
841 static void mib2IpRouteInit(void)
843 DWORD size
= 0, ret
= GetIpForwardTable(NULL
, &size
, TRUE
);
845 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
847 MIB_IPFORWARDTABLE
*table
= HeapAlloc(GetProcessHeap(), 0, size
);
850 if (!GetIpForwardTable(table
, &size
, TRUE
)) ipRouteTable
= table
;
851 else HeapFree(GetProcessHeap(), 0, table
);
856 static void mib2IpRouteCleanup(void)
858 HeapFree(GetProcessHeap(), 0, ipRouteTable
);
861 static void oidToIpForwardRow(AsnObjectIdentifier
*oid
, void *dst
)
863 MIB_IPFORWARDROW
*row
= dst
;
865 row
->dwForwardDest
= oidToIpAddr(oid
);
868 static int __cdecl
compareIpForwardRow(const void *a
, const void *b
)
870 const MIB_IPFORWARDROW
*rowA
= a
, *rowB
= b
;
871 return DWORD_cmp(ntohl(rowA
->dwForwardDest
), ntohl(rowB
->dwForwardDest
));
874 static BOOL
mib2IpRouteQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
875 AsnInteger32
*pErrorStatus
)
877 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpRoute
);
878 UINT tableIndex
= 0, item
= 0;
881 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
887 case SNMP_PDU_GETNEXT
:
888 *pErrorStatus
= getItemAndInstanceFromTable(&pVarBind
->name
,
889 &myOid
, 4, bPduType
, (struct GenericTable
*)ipRouteTable
,
890 sizeof(MIB_IPFORWARDROW
), oidToIpForwardRow
, compareIpForwardRow
,
896 *pErrorStatus
= mapStructEntryToValue(mib2IpRouteMap
,
897 DEFINE_SIZEOF(mib2IpRouteMap
),
898 &ipRouteTable
->table
[tableIndex
- 1], item
, pVarBind
);
899 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
900 ret
= setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
901 ipRouteTable
->table
[tableIndex
- 1].dwForwardDest
);
905 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
909 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
910 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
915 static UINT mib2IpNet
[] = { 1,3,6,1,2,1,4,22,1 };
916 static PMIB_IPNETTABLE ipNetTable
;
918 static DWORD
copyIpNetPhysAddr(AsnAny
*value
, void *src
)
920 PMIB_IPNETROW row
= (PMIB_IPNETROW
)((BYTE
*)src
- FIELD_OFFSET(MIB_IPNETROW
,
923 setStringValue(value
, ASN_OCTETSTRING
, row
->dwPhysAddrLen
, row
->bPhysAddr
);
924 return SNMP_ERRORSTATUS_NOERROR
;
927 static struct structToAsnValue mib2IpNetMap
[] = {
928 { FIELD_OFFSET(MIB_IPNETROW
, dwIndex
), copyInt
},
929 { FIELD_OFFSET(MIB_IPNETROW
, dwPhysAddrLen
), copyIpNetPhysAddr
},
930 { FIELD_OFFSET(MIB_IPNETROW
, dwAddr
), copyIpAddr
},
931 { FIELD_OFFSET(MIB_IPNETROW
, dwType
), copyInt
},
934 static void mib2IpNetInit(void)
936 DWORD size
= 0, ret
= GetIpNetTable(NULL
, &size
, FALSE
);
938 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
940 MIB_IPNETTABLE
*table
= HeapAlloc(GetProcessHeap(), 0, size
);
943 if (!GetIpNetTable(table
, &size
, FALSE
)) ipNetTable
= table
;
944 else HeapFree(GetProcessHeap(), 0, table
);
949 static void mib2IpNetCleanup(void)
951 HeapFree(GetProcessHeap(), 0, ipNetTable
);
954 static BOOL
mib2IpNetQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
955 AsnInteger32
*pErrorStatus
)
957 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpNet
);
960 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
966 case SNMP_PDU_GETNEXT
:
968 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
971 UINT tableIndex
= 0, item
= 0;
973 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
974 &myOid
, bPduType
, &item
, &tableIndex
);
979 if (tableIndex
> ipNetTable
->dwNumEntries
)
980 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
983 *pErrorStatus
= mapStructEntryToValue(mib2IpNetMap
,
984 DEFINE_SIZEOF(mib2IpNetMap
),
985 &ipNetTable
[tableIndex
- 1], item
, pVarBind
);
986 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
987 ret
= setOidWithItemAndInteger(&pVarBind
->name
, &myOid
,
994 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
998 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
999 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1004 static UINT mib2Icmp
[] = { 1,3,6,1,2,1,5 };
1005 static MIB_ICMP icmpStats
;
1007 static void mib2IcmpInit(void)
1009 GetIcmpStatistics(&icmpStats
);
1012 static struct structToAsnValue mib2IcmpMap
[] = {
1013 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwMsgs
), copyInt
},
1014 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwErrors
), copyInt
},
1015 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwDestUnreachs
), copyInt
},
1016 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimeExcds
), copyInt
},
1017 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwParmProbs
), copyInt
},
1018 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwSrcQuenchs
), copyInt
},
1019 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwRedirects
), copyInt
},
1020 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchos
), copyInt
},
1021 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchoReps
), copyInt
},
1022 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestamps
), copyInt
},
1023 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestampReps
), copyInt
},
1024 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMasks
), copyInt
},
1025 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMaskReps
), copyInt
},
1026 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwMsgs
), copyInt
},
1027 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwErrors
), copyInt
},
1028 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwDestUnreachs
), copyInt
},
1029 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimeExcds
), copyInt
},
1030 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwParmProbs
), copyInt
},
1031 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwSrcQuenchs
), copyInt
},
1032 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwRedirects
), copyInt
},
1033 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchos
), copyInt
},
1034 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchoReps
), copyInt
},
1035 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestamps
), copyInt
},
1036 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestampReps
), copyInt
},
1037 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMasks
), copyInt
},
1038 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMaskReps
), copyInt
},
1041 static BOOL
mib2IcmpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
1042 AsnInteger32
*pErrorStatus
)
1044 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Icmp
);
1048 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
1054 case SNMP_PDU_GETNEXT
:
1055 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
1059 *pErrorStatus
= mapStructEntryToValue(mib2IcmpMap
,
1060 DEFINE_SIZEOF(mib2IcmpMap
), &icmpStats
, item
,
1062 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
1063 ret
= setOidWithItem(&pVarBind
->name
, &myOid
, item
);
1067 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
1071 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
1072 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1077 static UINT mib2Tcp
[] = { 1,3,6,1,2,1,6 };
1078 static MIB_TCPSTATS tcpStats
;
1080 static void mib2TcpInit(void)
1082 GetTcpStatistics(&tcpStats
);
1085 static struct structToAsnValue mib2TcpMap
[] = {
1086 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoAlgorithm
), copyInt
},
1087 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMin
), copyInt
},
1088 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMax
), copyInt
},
1089 { FIELD_OFFSET(MIB_TCPSTATS
, dwMaxConn
), copyInt
},
1090 { FIELD_OFFSET(MIB_TCPSTATS
, dwActiveOpens
), copyInt
},
1091 { FIELD_OFFSET(MIB_TCPSTATS
, dwPassiveOpens
), copyInt
},
1092 { FIELD_OFFSET(MIB_TCPSTATS
, dwAttemptFails
), copyInt
},
1093 { FIELD_OFFSET(MIB_TCPSTATS
, dwEstabResets
), copyInt
},
1094 { FIELD_OFFSET(MIB_TCPSTATS
, dwCurrEstab
), copyInt
},
1095 { FIELD_OFFSET(MIB_TCPSTATS
, dwInSegs
), copyInt
},
1096 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutSegs
), copyInt
},
1097 { FIELD_OFFSET(MIB_TCPSTATS
, dwRetransSegs
), copyInt
},
1098 { FIELD_OFFSET(MIB_TCPSTATS
, dwInErrs
), copyInt
},
1099 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutRsts
), copyInt
},
1100 { FIELD_OFFSET(MIB_TCPSTATS
, dwNumConns
), copyInt
},
1103 static BOOL
mib2TcpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
1104 AsnInteger32
*pErrorStatus
)
1106 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Tcp
);
1110 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
1116 case SNMP_PDU_GETNEXT
:
1117 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
1121 *pErrorStatus
= mapStructEntryToValue(mib2TcpMap
,
1122 DEFINE_SIZEOF(mib2TcpMap
), &tcpStats
, item
, pVarBind
);
1123 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
1124 ret
= setOidWithItem(&pVarBind
->name
, &myOid
, item
);
1128 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
1132 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
1133 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1138 static UINT mib2Udp
[] = { 1,3,6,1,2,1,7 };
1139 static MIB_UDPSTATS udpStats
;
1141 static void mib2UdpInit(void)
1143 GetUdpStatistics(&udpStats
);
1146 static struct structToAsnValue mib2UdpMap
[] = {
1147 { FIELD_OFFSET(MIB_UDPSTATS
, dwInDatagrams
), copyInt
},
1148 { FIELD_OFFSET(MIB_UDPSTATS
, dwNoPorts
), copyInt
},
1149 { FIELD_OFFSET(MIB_UDPSTATS
, dwInErrors
), copyInt
},
1150 { FIELD_OFFSET(MIB_UDPSTATS
, dwOutDatagrams
), copyInt
},
1153 static BOOL
mib2UdpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
1154 AsnInteger32
*pErrorStatus
)
1156 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Udp
);
1160 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
1166 case SNMP_PDU_GETNEXT
:
1167 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
1171 *pErrorStatus
= mapStructEntryToValue(mib2UdpMap
,
1172 DEFINE_SIZEOF(mib2UdpMap
), &udpStats
, item
, pVarBind
);
1173 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
1174 ret
= setOidWithItem(&pVarBind
->name
, &myOid
, item
);
1178 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
1182 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
1183 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1188 static UINT mib2UdpEntry
[] = { 1,3,6,1,2,1,7,5,1 };
1189 static PMIB_UDPTABLE udpTable
;
1191 static void mib2UdpEntryInit(void)
1193 DWORD size
= 0, ret
= GetUdpTable(NULL
, &size
, TRUE
);
1195 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
1197 MIB_UDPTABLE
*table
= HeapAlloc(GetProcessHeap(), 0, size
);
1200 if (!GetUdpTable(table
, &size
, TRUE
)) udpTable
= table
;
1201 else HeapFree(GetProcessHeap(), 0, table
);
1206 static void mib2UdpEntryCleanup(void)
1208 HeapFree(GetProcessHeap(), 0, udpTable
);
1211 static struct structToAsnValue mib2UdpEntryMap
[] = {
1212 { FIELD_OFFSET(MIB_UDPROW
, dwLocalAddr
), copyIpAddr
},
1213 { FIELD_OFFSET(MIB_UDPROW
, dwLocalPort
), copyInt
},
1216 static void oidToUdpRow(AsnObjectIdentifier
*oid
, void *dst
)
1218 MIB_UDPROW
*row
= dst
;
1220 assert(oid
&& oid
->idLength
>= 5);
1221 row
->dwLocalAddr
= oidToIpAddr(oid
);
1222 row
->dwLocalPort
= htons(oid
->ids
[4]);
1225 static int __cdecl
compareUdpRow(const void *a
, const void *b
)
1227 const MIB_UDPROW
*rowA
= a
, *rowB
= b
;
1228 return DWORD_cmp(ntohl(rowA
->dwLocalAddr
), ntohl(rowB
->dwLocalAddr
)) ||
1229 ntohs(rowA
->dwLocalPort
) - ntohs(rowB
->dwLocalPort
);
1232 static BOOL
mib2UdpEntryQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
1233 AsnInteger32
*pErrorStatus
)
1235 AsnObjectIdentifier myOid
= DEFINE_OID(mib2UdpEntry
);
1238 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
1244 case SNMP_PDU_GETNEXT
:
1246 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1249 UINT tableIndex
= 0, item
= 0;
1251 *pErrorStatus
= getItemAndInstanceFromTable(&pVarBind
->name
, &myOid
,
1252 5, bPduType
, (struct GenericTable
*)udpTable
,
1253 sizeof(MIB_UDPROW
), oidToUdpRow
, compareUdpRow
, &item
,
1259 *pErrorStatus
= mapStructEntryToValue(mib2UdpEntryMap
,
1260 DEFINE_SIZEOF(mib2UdpEntryMap
),
1261 &udpTable
->table
[tableIndex
- 1], item
, pVarBind
);
1262 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
1264 AsnObjectIdentifier oid
;
1266 ret
= setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
1267 udpTable
->table
[tableIndex
- 1].dwLocalAddr
);
1270 UINT id
= ntohs(udpTable
->table
[tableIndex
- 1].dwLocalPort
);
1273 ret
= SnmpUtilOidAppend(&pVarBind
->name
, &oid
);
1280 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
1284 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
1285 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1290 /* This list MUST BE lexicographically sorted */
1291 static struct mibImplementation supportedIDs
[] = {
1292 { DEFINE_OID(mib2IfNumber
), mib2IfNumberInit
, mib2IfNumberQuery
,
1293 mib2IfNumberCleanup
},
1294 { DEFINE_OID(mib2IfEntry
), NULL
, mib2IfEntryQuery
, NULL
},
1295 { DEFINE_OID(mib2Ip
), mib2IpStatsInit
, mib2IpStatsQuery
, NULL
},
1296 { DEFINE_OID(mib2IpAddr
), mib2IpAddrInit
, mib2IpAddrQuery
,
1297 mib2IpAddrCleanup
},
1298 { DEFINE_OID(mib2IpRoute
), mib2IpRouteInit
, mib2IpRouteQuery
,
1299 mib2IpRouteCleanup
},
1300 { DEFINE_OID(mib2IpNet
), mib2IpNetInit
, mib2IpNetQuery
, mib2IpNetCleanup
},
1301 { DEFINE_OID(mib2Icmp
), mib2IcmpInit
, mib2IcmpQuery
, NULL
},
1302 { DEFINE_OID(mib2Tcp
), mib2TcpInit
, mib2TcpQuery
, NULL
},
1303 { DEFINE_OID(mib2Udp
), mib2UdpInit
, mib2UdpQuery
, NULL
},
1304 { DEFINE_OID(mib2UdpEntry
), mib2UdpEntryInit
, mib2UdpEntryQuery
,
1305 mib2UdpEntryCleanup
},
1307 static UINT minSupportedIDLength
;
1309 /*****************************************************************************
1310 * SnmpExtensionInit [INETMIB1.@]
1312 BOOL WINAPI
SnmpExtensionInit(DWORD dwUptimeReference
,
1313 HANDLE
*phSubagentTrapEvent
, AsnObjectIdentifier
*pFirstSupportedRegion
)
1315 AsnObjectIdentifier myOid
= DEFINE_OID(mib2System
);
1318 TRACE("(%ld, %p, %p)\n", dwUptimeReference
, phSubagentTrapEvent
,
1319 pFirstSupportedRegion
);
1321 minSupportedIDLength
= UINT_MAX
;
1322 for (i
= 0; i
< ARRAY_SIZE(supportedIDs
); i
++)
1324 if (supportedIDs
[i
].init
)
1325 supportedIDs
[i
].init();
1326 if (supportedIDs
[i
].name
.idLength
< minSupportedIDLength
)
1327 minSupportedIDLength
= supportedIDs
[i
].name
.idLength
;
1329 *phSubagentTrapEvent
= NULL
;
1330 SnmpUtilOidCpy(pFirstSupportedRegion
, &myOid
);
1334 static void cleanup(void)
1338 for (i
= 0; i
< ARRAY_SIZE(supportedIDs
); i
++)
1339 if (supportedIDs
[i
].cleanup
)
1340 supportedIDs
[i
].cleanup();
1343 static struct mibImplementation
*findSupportedQuery(UINT
*ids
, UINT idLength
,
1344 UINT
*matchingIndex
)
1346 int indexHigh
= DEFINE_SIZEOF(supportedIDs
) - 1, indexLow
= 0;
1347 AsnObjectIdentifier oid1
= { idLength
, ids
};
1352 while (indexLow
<= indexHigh
)
1354 INT cmp
, i
= (indexLow
+ indexHigh
) / 2;
1355 if (!(cmp
= SnmpUtilOidNCmp(&oid1
, &supportedIDs
[i
].name
, idLength
)))
1358 return &supportedIDs
[i
];
1368 /*****************************************************************************
1369 * SnmpExtensionQuery [INETMIB1.@]
1371 BOOL WINAPI
SnmpExtensionQuery(BYTE bPduType
, SnmpVarBindList
*pVarBindList
,
1372 AsnInteger32
*pErrorStatus
, AsnInteger32
*pErrorIndex
)
1374 AsnObjectIdentifier mib2oid
= DEFINE_OID(mib2
);
1375 AsnInteger32 error
= SNMP_ERRORSTATUS_NOERROR
, errorIndex
= 0;
1379 TRACE("(0x%02x, %p, %p, %p)\n", bPduType
, pVarBindList
,
1380 pErrorStatus
, pErrorIndex
);
1382 for (i
= 0; !error
&& i
< pVarBindList
->len
; i
++)
1384 /* Ignore any OIDs not in MIB2 */
1385 if (!SnmpUtilOidNCmp(&pVarBindList
->list
[i
].name
, &mib2oid
,
1388 struct mibImplementation
*impl
= NULL
;
1389 UINT len
, matchingIndex
= 0;
1391 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList
->list
[i
].name
));
1392 /* Search for an implementation matching as many octets as possible
1394 for (len
= pVarBindList
->list
[i
].name
.idLength
;
1395 len
>= minSupportedIDLength
&& !impl
; len
--)
1396 impl
= findSupportedQuery(pVarBindList
->list
[i
].name
.ids
, len
,
1398 if (impl
&& impl
->query
)
1399 ret
= impl
->query(bPduType
, &pVarBindList
->list
[i
], &error
);
1401 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1402 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1403 bPduType
== SNMP_PDU_GETNEXT
)
1405 /* GetNext is special: it finds the successor to the given OID,
1406 * so we have to continue until an implementation handles the
1407 * query or we exhaust the table of supported OIDs.
1409 for (matchingIndex
++; error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1410 matchingIndex
< DEFINE_SIZEOF(supportedIDs
);
1413 error
= SNMP_ERRORSTATUS_NOERROR
;
1414 impl
= &supportedIDs
[matchingIndex
];
1416 ret
= impl
->query(bPduType
, &pVarBindList
->list
[i
],
1419 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1421 /* If the query still isn't resolved, set the OID to the
1422 * successor to the last entry in the table.
1424 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
)
1426 SnmpUtilOidFree(&pVarBindList
->list
[i
].name
);
1427 ret
= SnmpUtilOidCpy(&pVarBindList
->list
[i
].name
,
1428 &supportedIDs
[matchingIndex
- 1].name
);
1429 pVarBindList
->list
[i
].name
.ids
[
1430 pVarBindList
->list
[i
].name
.idLength
- 1] += 1;
1437 *pErrorStatus
= error
;
1438 *pErrorIndex
= errorIndex
;
1442 /*****************************************************************************
1443 * DllMain [INETMIB1.@]
1445 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
1447 TRACE("(0x%p, %ld, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
1451 case DLL_PROCESS_ATTACH
:
1452 DisableThreadLibraryCalls(hinstDLL
);
1454 case DLL_PROCESS_DETACH
:
1455 if (lpvReserved
) break;