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
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1
);
32 BOOL WINAPI
DllMain(HINSTANCE hinstDLL
, DWORD fdwReason
, LPVOID lpvReserved
)
34 TRACE("(0x%p, %d, %p)\n", hinstDLL
, fdwReason
, lpvReserved
);
38 case DLL_WINE_PREATTACH
:
39 return FALSE
; /* prefer native version */
40 case DLL_PROCESS_ATTACH
:
41 DisableThreadLibraryCalls(hinstDLL
);
43 case DLL_PROCESS_DETACH
:
55 static void copyInt(AsnAny
*value
, void *src
)
57 value
->asnType
= ASN_INTEGER
;
58 value
->asnValue
.number
= *(DWORD
*)src
;
61 static void setStringValue(AsnAny
*value
, BYTE type
, DWORD len
, BYTE
*str
)
65 strValue
.asnType
= type
;
66 strValue
.asnValue
.string
.stream
= str
;
67 strValue
.asnValue
.string
.length
= len
;
68 strValue
.asnValue
.string
.dynamic
= TRUE
;
69 SnmpUtilAsnAnyCpy(value
, &strValue
);
72 static void copyLengthPrecededString(AsnAny
*value
, void *src
)
74 DWORD len
= *(DWORD
*)src
;
76 setStringValue(value
, ASN_OCTETSTRING
, len
, (BYTE
*)src
+ sizeof(DWORD
));
79 typedef void (*copyValueFunc
)(AsnAny
*value
, void *src
);
81 struct structToAsnValue
87 static AsnInteger32
mapStructEntryToValue(struct structToAsnValue
*map
,
88 UINT mapLen
, void *record
, UINT id
, BYTE bPduType
, SnmpVarBind
*pVarBind
)
90 /* OIDs are 1-based */
92 return SNMP_ERRORSTATUS_NOSUCHNAME
;
95 return SNMP_ERRORSTATUS_NOSUCHNAME
;
97 return SNMP_ERRORSTATUS_NOSUCHNAME
;
98 map
[id
].copy(&pVarBind
->value
, (BYTE
*)record
+ map
[id
].offset
);
99 return SNMP_ERRORSTATUS_NOERROR
;
102 static void copyIpAddr(AsnAny
*value
, void *src
)
104 setStringValue(value
, ASN_IPADDRESS
, sizeof(DWORD
), src
);
107 static UINT mib2
[] = { 1,3,6,1,2,1 };
108 static UINT mib2System
[] = { 1,3,6,1,2,1,1 };
110 typedef BOOL (*varqueryfunc
)(BYTE bPduType
, SnmpVarBind
*pVarBind
,
111 AsnInteger32
*pErrorStatus
);
113 struct mibImplementation
115 AsnObjectIdentifier name
;
120 static UINT mib2IfNumber
[] = { 1,3,6,1,2,1,2,1 };
121 static PMIB_IFTABLE ifTable
;
123 static void mib2IfNumberInit(void)
125 DWORD size
= 0, ret
= GetIfTable(NULL
, &size
, FALSE
);
127 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
129 ifTable
= HeapAlloc(GetProcessHeap(), 0, size
);
131 GetIfTable(ifTable
, &size
, FALSE
);
135 static BOOL
mib2IfNumberQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
136 AsnInteger32
*pErrorStatus
)
138 AsnObjectIdentifier numberOid
= DEFINE_OID(mib2IfNumber
);
140 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
146 case SNMP_PDU_GETNEXT
:
147 if ((bPduType
== SNMP_PDU_GET
&&
148 !SnmpUtilOidNCmp(&pVarBind
->name
, &numberOid
, numberOid
.idLength
))
149 || SnmpUtilOidNCmp(&pVarBind
->name
, &numberOid
, numberOid
.idLength
)
152 DWORD numIfs
= ifTable
? ifTable
->dwNumEntries
: 0;
154 copyInt(&pVarBind
->value
, &numIfs
);
155 if (bPduType
== SNMP_PDU_GETNEXT
)
156 SnmpUtilOidCpy(&pVarBind
->name
, &numberOid
);
157 *pErrorStatus
= SNMP_ERRORSTATUS_NOERROR
;
161 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
162 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
163 * need to set it here.
168 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
171 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
172 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
177 static void copyOperStatus(AsnAny
*value
, void *src
)
179 value
->asnType
= ASN_INTEGER
;
180 /* The IPHlpApi definition of operational status differs from the MIB2 one,
181 * so map it to the MIB2 value.
183 switch (*(DWORD
*)src
)
185 case MIB_IF_OPER_STATUS_OPERATIONAL
:
186 value
->asnValue
.number
= MIB_IF_ADMIN_STATUS_UP
;
188 case MIB_IF_OPER_STATUS_CONNECTING
:
189 case MIB_IF_OPER_STATUS_CONNECTED
:
190 value
->asnValue
.number
= MIB_IF_ADMIN_STATUS_TESTING
;
193 value
->asnValue
.number
= MIB_IF_ADMIN_STATUS_DOWN
;
197 /* Given an OID and a base OID that it must begin with, finds the item and
198 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
199 * foo, returns item 1 and instance 2.
200 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
201 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
202 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
203 * instance, or item 1, instance 1 if either is missing.
205 static AsnInteger32
getItemAndIntegerInstanceFromOid(AsnObjectIdentifier
*oid
,
206 AsnObjectIdentifier
*base
, BYTE bPduType
, UINT
*item
, UINT
*instance
)
208 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
212 case SNMP_PDU_GETNEXT
:
213 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
218 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
220 if (oid
->idLength
== base
->idLength
||
221 oid
->idLength
== base
->idLength
+ 1)
223 /* Either the table or an item within the table is specified,
224 * but the instance is not. Get the first instance.
227 if (oid
->idLength
== base
->idLength
+ 1)
228 *item
= oid
->ids
[base
->idLength
];
234 *item
= oid
->ids
[base
->idLength
];
235 *instance
= oid
->ids
[base
->idLength
+ 1] + 1;
239 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
242 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
244 if (oid
->idLength
== base
->idLength
||
245 oid
->idLength
== base
->idLength
+ 1)
247 /* Either the table or an item within the table is specified,
248 * but the instance is not.
250 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
254 *item
= oid
->ids
[base
->idLength
];
255 *instance
= oid
->ids
[base
->idLength
+ 1];
259 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
264 /* Given an OID and a base OID that it must begin with, finds the item from the
265 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
266 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
267 * SNMP_ERRORSTATUS_NOSUCHNAME.
268 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
269 * 1 if the item is missing.
271 static AsnInteger32
getItemFromOid(AsnObjectIdentifier
*oid
,
272 AsnObjectIdentifier
*base
, BYTE bPduType
, UINT
*item
)
274 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
278 case SNMP_PDU_GETNEXT
:
279 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
281 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
283 if (oid
->idLength
== base
->idLength
)
285 /* The item is missing, assume the first item */
289 *item
= oid
->ids
[base
->idLength
] + 1;
292 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
295 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
))
297 if (oid
->idLength
== base
->idLength
)
299 /* The item is missing */
300 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
304 *item
= oid
->ids
[base
->idLength
];
306 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
310 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
321 static DWORD
oidToIpAddr(AsnObjectIdentifier
*oid
)
323 assert(oid
&& oid
->idLength
>= 4);
324 /* Map the IDs to an IP address in little-endian order */
325 return (BYTE
)oid
->ids
[3] << 24 | (BYTE
)oid
->ids
[2] << 16 |
326 (BYTE
)oid
->ids
[1] << 8 | (BYTE
)oid
->ids
[0];
329 typedef void (*oidToKeyFunc
)(AsnObjectIdentifier
*oid
, void *dst
);
330 typedef int (*compareFunc
)(const void *key
, const void *value
);
332 static UINT
findValueInTable(AsnObjectIdentifier
*oid
,
333 struct GenericTable
*table
, size_t tableEntrySize
, oidToKeyFunc makeKey
,
337 void *key
= HeapAlloc(GetProcessHeap(), 0, tableEntrySize
);
344 value
= bsearch(key
, table
->entries
, table
->numEntries
, tableEntrySize
,
347 index
= ((BYTE
*)value
- (BYTE
*)table
->entries
) / tableEntrySize
349 HeapFree(GetProcessHeap(), 0, key
);
354 /* Given an OID and a base OID that it must begin with, finds the item and
355 * element of the table whose IP address matches the instance from the OID.
356 * E.g., given an OID foo.1.2.3.4.5 and a base OID foo, returns item 1 and the
357 * index of the entry in the table whose IP address is 2.3.4.5.
358 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
359 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
360 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
361 * instance, or item 1, instance 1 if either is missing.
363 static AsnInteger32
getItemAndIpAddressInstanceFromOid(AsnObjectIdentifier
*oid
,
364 AsnObjectIdentifier
*base
, BYTE bPduType
, struct GenericTable
*table
,
365 size_t tableEntrySize
, oidToKeyFunc makeKey
, compareFunc compare
,
366 UINT
*item
, UINT
*instance
)
368 AsnInteger32 ret
= SNMP_ERRORSTATUS_NOERROR
;
371 return SNMP_ERRORSTATUS_NOSUCHNAME
;
375 case SNMP_PDU_GETNEXT
:
376 if (SnmpUtilOidNCmp(oid
, base
, base
->idLength
) < 0)
378 /* Return the first item and instance from the table */
382 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
383 oid
->idLength
< base
->idLength
+ 5)
385 /* Either the table or an item is specified, but the instance is
389 if (oid
->idLength
>= base
->idLength
+ 1)
391 *item
= oid
->ids
[base
->idLength
];
398 else if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
399 oid
->idLength
== base
->idLength
+ 5)
401 *item
= oid
->ids
[base
->idLength
];
409 AsnObjectIdentifier ipOid
= { 4, oid
->ids
+ base
->idLength
+ 1
412 *instance
= findValueInTable(&ipOid
, table
, tableEntrySize
,
413 makeKey
, compare
) + 1;
414 if (*instance
> table
->numEntries
)
415 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
419 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
422 if (!SnmpUtilOidNCmp(oid
, base
, base
->idLength
) &&
423 oid
->idLength
== base
->idLength
+ 5)
425 *item
= oid
->ids
[base
->idLength
];
427 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
430 AsnObjectIdentifier ipOid
= { 4, oid
->ids
+ base
->idLength
+ 1
433 *instance
= findValueInTable(&ipOid
, table
, tableEntrySize
,
436 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
440 ret
= SNMP_ERRORSTATUS_NOSUCHNAME
;
445 static void setOidWithItem(AsnObjectIdentifier
*dst
, AsnObjectIdentifier
*base
,
449 AsnObjectIdentifier oid
;
451 SnmpUtilOidCpy(dst
, base
);
455 SnmpUtilOidAppend(dst
, &oid
);
458 static void setOidWithItemAndIpAddr(AsnObjectIdentifier
*dst
,
459 AsnObjectIdentifier
*base
, UINT item
, DWORD addr
)
463 AsnObjectIdentifier oid
;
465 setOidWithItem(dst
, base
, item
);
468 for (ptr
= (BYTE
*)&addr
; ptr
< (BYTE
*)&addr
+ sizeof(DWORD
); ptr
++)
471 SnmpUtilOidAppend(dst
, &oid
);
475 static void setOidWithItemAndInteger(AsnObjectIdentifier
*dst
,
476 AsnObjectIdentifier
*base
, UINT item
, UINT instance
)
478 AsnObjectIdentifier oid
;
480 setOidWithItem(dst
, base
, item
);
483 SnmpUtilOidAppend(dst
, &oid
);
486 static struct structToAsnValue mib2IfEntryMap
[] = {
487 { FIELD_OFFSET(MIB_IFROW
, dwIndex
), copyInt
},
488 { FIELD_OFFSET(MIB_IFROW
, dwDescrLen
), copyLengthPrecededString
},
489 { FIELD_OFFSET(MIB_IFROW
, dwType
), copyInt
},
490 { FIELD_OFFSET(MIB_IFROW
, dwMtu
), copyInt
},
491 { FIELD_OFFSET(MIB_IFROW
, dwSpeed
), copyInt
},
492 { FIELD_OFFSET(MIB_IFROW
, dwPhysAddrLen
), copyLengthPrecededString
},
493 { FIELD_OFFSET(MIB_IFROW
, dwAdminStatus
), copyInt
},
494 { FIELD_OFFSET(MIB_IFROW
, dwOperStatus
), copyOperStatus
},
495 { FIELD_OFFSET(MIB_IFROW
, dwLastChange
), copyInt
},
496 { FIELD_OFFSET(MIB_IFROW
, dwInOctets
), copyInt
},
497 { FIELD_OFFSET(MIB_IFROW
, dwInUcastPkts
), copyInt
},
498 { FIELD_OFFSET(MIB_IFROW
, dwInNUcastPkts
), copyInt
},
499 { FIELD_OFFSET(MIB_IFROW
, dwInDiscards
), copyInt
},
500 { FIELD_OFFSET(MIB_IFROW
, dwInErrors
), copyInt
},
501 { FIELD_OFFSET(MIB_IFROW
, dwInUnknownProtos
), copyInt
},
502 { FIELD_OFFSET(MIB_IFROW
, dwOutOctets
), copyInt
},
503 { FIELD_OFFSET(MIB_IFROW
, dwOutUcastPkts
), copyInt
},
504 { FIELD_OFFSET(MIB_IFROW
, dwOutNUcastPkts
), copyInt
},
505 { FIELD_OFFSET(MIB_IFROW
, dwOutDiscards
), copyInt
},
506 { FIELD_OFFSET(MIB_IFROW
, dwOutErrors
), copyInt
},
507 { FIELD_OFFSET(MIB_IFROW
, dwOutQLen
), copyInt
},
510 static UINT mib2IfEntry
[] = { 1,3,6,1,2,1,2,2,1 };
512 static BOOL
mib2IfEntryQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
513 AsnInteger32
*pErrorStatus
)
515 AsnObjectIdentifier entryOid
= DEFINE_OID(mib2IfEntry
);
517 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
523 case SNMP_PDU_GETNEXT
:
526 /* There is no interface present, so let the caller deal
527 * with finding the successor.
529 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
533 UINT tableIndex
= 0, item
= 0;
535 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
536 &entryOid
, bPduType
, &item
, &tableIndex
);
541 if (tableIndex
> ifTable
->dwNumEntries
)
542 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
545 *pErrorStatus
= mapStructEntryToValue(mib2IfEntryMap
,
546 DEFINE_SIZEOF(mib2IfEntryMap
),
547 &ifTable
->table
[tableIndex
- 1], item
, bPduType
,
549 if (bPduType
== SNMP_PDU_GETNEXT
)
550 setOidWithItemAndInteger(&pVarBind
->name
, &entryOid
,
557 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
560 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
561 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
566 static UINT mib2Ip
[] = { 1,3,6,1,2,1,4 };
567 static MIB_IPSTATS ipStats
;
569 static void mib2IpStatsInit(void)
571 GetIpStatistics(&ipStats
);
574 static struct structToAsnValue mib2IpMap
[] = {
575 { FIELD_OFFSET(MIB_IPSTATS
, dwForwarding
), copyInt
}, /* 1 */
576 { FIELD_OFFSET(MIB_IPSTATS
, dwDefaultTTL
), copyInt
}, /* 2 */
577 { FIELD_OFFSET(MIB_IPSTATS
, dwInReceives
), copyInt
}, /* 3 */
578 { FIELD_OFFSET(MIB_IPSTATS
, dwInHdrErrors
), copyInt
}, /* 4 */
579 { FIELD_OFFSET(MIB_IPSTATS
, dwInAddrErrors
), copyInt
}, /* 5 */
580 { FIELD_OFFSET(MIB_IPSTATS
, dwForwDatagrams
), copyInt
}, /* 6 */
581 { FIELD_OFFSET(MIB_IPSTATS
, dwInUnknownProtos
), copyInt
}, /* 7 */
582 { FIELD_OFFSET(MIB_IPSTATS
, dwInDiscards
), copyInt
}, /* 8 */
583 { FIELD_OFFSET(MIB_IPSTATS
, dwInDelivers
), copyInt
}, /* 9 */
584 { FIELD_OFFSET(MIB_IPSTATS
, dwOutRequests
), copyInt
}, /* 10 */
585 { FIELD_OFFSET(MIB_IPSTATS
, dwOutDiscards
), copyInt
}, /* 11 */
586 { FIELD_OFFSET(MIB_IPSTATS
, dwOutNoRoutes
), copyInt
}, /* 12 */
587 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmTimeout
), copyInt
}, /* 13 */
588 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmReqds
), copyInt
}, /* 14 */
589 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmOks
), copyInt
}, /* 15 */
590 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmFails
), copyInt
}, /* 16 */
591 { FIELD_OFFSET(MIB_IPSTATS
, dwFragOks
), copyInt
}, /* 17 */
592 { FIELD_OFFSET(MIB_IPSTATS
, dwFragFails
), copyInt
}, /* 18 */
593 { FIELD_OFFSET(MIB_IPSTATS
, dwFragCreates
), copyInt
}, /* 19 */
594 { 0, NULL
}, /* 20: not used, IP addr table */
595 { 0, NULL
}, /* 21: not used, route table */
596 { 0, NULL
}, /* 22: not used, net to media (ARP) table */
597 { FIELD_OFFSET(MIB_IPSTATS
, dwRoutingDiscards
), copyInt
}, /* 23 */
600 static BOOL
mib2IpStatsQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
601 AsnInteger32
*pErrorStatus
)
603 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Ip
);
606 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
612 case SNMP_PDU_GETNEXT
:
613 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
617 *pErrorStatus
= mapStructEntryToValue(mib2IpMap
,
618 DEFINE_SIZEOF(mib2IpMap
), &ipStats
, item
, bPduType
, pVarBind
);
619 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
620 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
624 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
627 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
628 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
633 static UINT mib2IpAddr
[] = { 1,3,6,1,2,1,4,20,1 };
634 static PMIB_IPADDRTABLE ipAddrTable
;
636 static struct structToAsnValue mib2IpAddrMap
[] = {
637 { FIELD_OFFSET(MIB_IPADDRROW
, dwAddr
), copyIpAddr
},
638 { FIELD_OFFSET(MIB_IPADDRROW
, dwIndex
), copyInt
},
639 { FIELD_OFFSET(MIB_IPADDRROW
, dwMask
), copyIpAddr
},
640 { FIELD_OFFSET(MIB_IPADDRROW
, dwBCastAddr
), copyInt
},
641 { FIELD_OFFSET(MIB_IPADDRROW
, dwReasmSize
), copyInt
},
644 static void mib2IpAddrInit(void)
646 DWORD size
= 0, ret
= GetIpAddrTable(NULL
, &size
, TRUE
);
648 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
650 ipAddrTable
= HeapAlloc(GetProcessHeap(), 0, size
);
652 GetIpAddrTable(ipAddrTable
, &size
, TRUE
);
656 static void oidToIpAddrRow(AsnObjectIdentifier
*oid
, void *dst
)
658 MIB_IPADDRROW
*row
= dst
;
660 row
->dwAddr
= oidToIpAddr(oid
);
663 static int compareIpAddrRow(const void *a
, const void *b
)
665 const MIB_IPADDRROW
*key
= a
, *value
= b
;
667 return key
->dwAddr
- value
->dwAddr
;
670 static BOOL
mib2IpAddrQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
671 AsnInteger32
*pErrorStatus
)
673 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpAddr
);
674 UINT tableIndex
= 0, item
= 0;
676 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
682 case SNMP_PDU_GETNEXT
:
683 *pErrorStatus
= getItemAndIpAddressInstanceFromOid(&pVarBind
->name
,
684 &myOid
, bPduType
, (struct GenericTable
*)ipAddrTable
,
685 sizeof(MIB_IPADDRROW
), oidToIpAddrRow
, compareIpAddrRow
, &item
,
691 *pErrorStatus
= mapStructEntryToValue(mib2IpAddrMap
,
692 DEFINE_SIZEOF(mib2IpAddrMap
),
693 &ipAddrTable
->table
[tableIndex
- 1], item
, bPduType
, pVarBind
);
694 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
695 setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
696 ipAddrTable
->table
[tableIndex
- 1].dwAddr
);
700 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
703 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
704 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
709 static UINT mib2IpRoute
[] = { 1,3,6,1,2,1,4,21,1 };
710 static PMIB_IPFORWARDTABLE ipRouteTable
;
712 static struct structToAsnValue mib2IpRouteMap
[] = {
713 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardDest
), copyIpAddr
},
714 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardIfIndex
), copyInt
},
715 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric1
), copyInt
},
716 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric2
), copyInt
},
717 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric3
), copyInt
},
718 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric4
), copyInt
},
719 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardNextHop
), copyIpAddr
},
720 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardType
), copyInt
},
721 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardProto
), copyInt
},
722 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardAge
), copyInt
},
723 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMask
), copyIpAddr
},
724 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric5
), copyInt
},
727 static void mib2IpRouteInit(void)
729 DWORD size
= 0, ret
= GetIpForwardTable(NULL
, &size
, TRUE
);
731 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
733 ipRouteTable
= HeapAlloc(GetProcessHeap(), 0, size
);
735 GetIpForwardTable(ipRouteTable
, &size
, TRUE
);
739 static void oidToIpForwardRow(AsnObjectIdentifier
*oid
, void *dst
)
741 MIB_IPFORWARDROW
*row
= dst
;
743 row
->dwForwardDest
= oidToIpAddr(oid
);
746 static int compareIpForwardRow(const void *a
, const void *b
)
748 const MIB_IPFORWARDROW
*key
= a
, *value
= b
;
750 return key
->dwForwardDest
- value
->dwForwardDest
;
753 static BOOL
mib2IpRouteQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
754 AsnInteger32
*pErrorStatus
)
756 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpRoute
);
757 UINT tableIndex
= 0, item
= 0;
759 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
765 case SNMP_PDU_GETNEXT
:
766 *pErrorStatus
= getItemAndIpAddressInstanceFromOid(&pVarBind
->name
,
767 &myOid
, bPduType
, (struct GenericTable
*)ipRouteTable
,
768 sizeof(MIB_IPFORWARDROW
), oidToIpForwardRow
, compareIpForwardRow
,
774 *pErrorStatus
= mapStructEntryToValue(mib2IpRouteMap
,
775 DEFINE_SIZEOF(mib2IpRouteMap
),
776 &ipRouteTable
->table
[tableIndex
- 1], item
, bPduType
, pVarBind
);
777 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
778 setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
779 ipRouteTable
->table
[tableIndex
- 1].dwForwardDest
);
783 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
786 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
787 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
792 static UINT mib2IpNet
[] = { 1,3,6,1,2,1,4,22,1 };
793 static PMIB_IPNETTABLE ipNetTable
;
795 static struct structToAsnValue mib2IpNetMap
[] = {
796 { FIELD_OFFSET(MIB_IPNETROW
, dwIndex
), copyInt
},
797 { FIELD_OFFSET(MIB_IPNETROW
, dwPhysAddrLen
), copyLengthPrecededString
},
798 { FIELD_OFFSET(MIB_IPNETROW
, dwAddr
), copyIpAddr
},
799 { FIELD_OFFSET(MIB_IPNETROW
, dwType
), copyInt
},
802 static void mib2IpNetInit(void)
804 DWORD size
= 0, ret
= GetIpNetTable(NULL
, &size
, FALSE
);
806 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
808 ipNetTable
= HeapAlloc(GetProcessHeap(), 0, size
);
810 GetIpNetTable(ipNetTable
, &size
, FALSE
);
814 static BOOL
mib2IpNetQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
815 AsnInteger32
*pErrorStatus
)
817 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpNet
);
819 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
825 case SNMP_PDU_GETNEXT
:
827 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
830 UINT tableIndex
= 0, item
= 0;
832 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
833 &myOid
, bPduType
, &item
, &tableIndex
);
838 if (tableIndex
> ipNetTable
->dwNumEntries
)
839 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
842 *pErrorStatus
= mapStructEntryToValue(mib2IpNetMap
,
843 DEFINE_SIZEOF(mib2IpNetMap
),
844 &ipNetTable
[tableIndex
- 1], item
, bPduType
, pVarBind
);
845 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
846 setOidWithItemAndInteger(&pVarBind
->name
, &myOid
, item
,
853 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
856 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
857 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
862 static UINT mib2Icmp
[] = { 1,3,6,1,2,1,5 };
863 static MIB_ICMP icmpStats
;
865 static void mib2IcmpInit(void)
867 GetIcmpStatistics(&icmpStats
);
870 static struct structToAsnValue mib2IcmpMap
[] = {
871 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwMsgs
), copyInt
},
872 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwErrors
), copyInt
},
873 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwDestUnreachs
), copyInt
},
874 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimeExcds
), copyInt
},
875 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwParmProbs
), copyInt
},
876 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwSrcQuenchs
), copyInt
},
877 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwRedirects
), copyInt
},
878 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchos
), copyInt
},
879 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchoReps
), copyInt
},
880 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestamps
), copyInt
},
881 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestampReps
), copyInt
},
882 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMasks
), copyInt
},
883 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMaskReps
), copyInt
},
884 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwMsgs
), copyInt
},
885 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwErrors
), copyInt
},
886 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwDestUnreachs
), copyInt
},
887 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimeExcds
), copyInt
},
888 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwParmProbs
), copyInt
},
889 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwSrcQuenchs
), copyInt
},
890 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwRedirects
), copyInt
},
891 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchos
), copyInt
},
892 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchoReps
), copyInt
},
893 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestamps
), copyInt
},
894 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestampReps
), copyInt
},
895 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMasks
), copyInt
},
896 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMaskReps
), copyInt
},
899 static BOOL
mib2IcmpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
900 AsnInteger32
*pErrorStatus
)
902 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Icmp
);
905 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
911 case SNMP_PDU_GETNEXT
:
912 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
916 *pErrorStatus
= mapStructEntryToValue(mib2IcmpMap
,
917 DEFINE_SIZEOF(mib2IcmpMap
), &icmpStats
, item
, bPduType
,
919 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
920 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
924 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
927 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
928 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
933 static UINT mib2Tcp
[] = { 1,3,6,1,2,1,6 };
934 static MIB_TCPSTATS tcpStats
;
936 static void mib2TcpInit(void)
938 GetTcpStatistics(&tcpStats
);
941 static struct structToAsnValue mib2TcpMap
[] = {
942 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoAlgorithm
), copyInt
},
943 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMin
), copyInt
},
944 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMax
), copyInt
},
945 { FIELD_OFFSET(MIB_TCPSTATS
, dwMaxConn
), copyInt
},
946 { FIELD_OFFSET(MIB_TCPSTATS
, dwActiveOpens
), copyInt
},
947 { FIELD_OFFSET(MIB_TCPSTATS
, dwPassiveOpens
), copyInt
},
948 { FIELD_OFFSET(MIB_TCPSTATS
, dwAttemptFails
), copyInt
},
949 { FIELD_OFFSET(MIB_TCPSTATS
, dwEstabResets
), copyInt
},
950 { FIELD_OFFSET(MIB_TCPSTATS
, dwCurrEstab
), copyInt
},
951 { FIELD_OFFSET(MIB_TCPSTATS
, dwInSegs
), copyInt
},
952 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutSegs
), copyInt
},
953 { FIELD_OFFSET(MIB_TCPSTATS
, dwRetransSegs
), copyInt
},
954 { FIELD_OFFSET(MIB_TCPSTATS
, dwInErrs
), copyInt
},
955 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutRsts
), copyInt
},
956 { FIELD_OFFSET(MIB_TCPSTATS
, dwNumConns
), copyInt
},
959 static BOOL
mib2TcpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
960 AsnInteger32
*pErrorStatus
)
962 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Tcp
);
965 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
971 case SNMP_PDU_GETNEXT
:
972 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
976 *pErrorStatus
= mapStructEntryToValue(mib2TcpMap
,
977 DEFINE_SIZEOF(mib2TcpMap
), &tcpStats
, item
, bPduType
, pVarBind
);
978 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
979 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
983 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
986 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
987 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
992 static UINT mib2Udp
[] = { 1,3,6,1,2,1,7 };
993 static MIB_UDPSTATS udpStats
;
995 static void mib2UdpInit(void)
997 GetUdpStatistics(&udpStats
);
1000 static struct structToAsnValue mib2UdpMap
[] = {
1001 { FIELD_OFFSET(MIB_UDPSTATS
, dwInDatagrams
), copyInt
},
1002 { FIELD_OFFSET(MIB_UDPSTATS
, dwNoPorts
), copyInt
},
1003 { FIELD_OFFSET(MIB_UDPSTATS
, dwInErrors
), copyInt
},
1004 { FIELD_OFFSET(MIB_UDPSTATS
, dwOutDatagrams
), copyInt
},
1007 static BOOL
mib2UdpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
1008 AsnInteger32
*pErrorStatus
)
1010 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Udp
);
1013 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
1019 case SNMP_PDU_GETNEXT
:
1020 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
1024 *pErrorStatus
= mapStructEntryToValue(mib2UdpMap
,
1025 DEFINE_SIZEOF(mib2UdpMap
), &udpStats
, item
, bPduType
, pVarBind
);
1026 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
1027 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
1031 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
1034 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
1035 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1040 /* This list MUST BE lexicographically sorted */
1041 static struct mibImplementation supportedIDs
[] = {
1042 { DEFINE_OID(mib2IfNumber
), mib2IfNumberInit
, mib2IfNumberQuery
},
1043 { DEFINE_OID(mib2IfEntry
), NULL
, mib2IfEntryQuery
},
1044 { DEFINE_OID(mib2Ip
), mib2IpStatsInit
, mib2IpStatsQuery
},
1045 { DEFINE_OID(mib2IpAddr
), mib2IpAddrInit
, mib2IpAddrQuery
},
1046 { DEFINE_OID(mib2IpRoute
), mib2IpRouteInit
, mib2IpRouteQuery
},
1047 { DEFINE_OID(mib2IpNet
), mib2IpNetInit
, mib2IpNetQuery
},
1048 { DEFINE_OID(mib2Icmp
), mib2IcmpInit
, mib2IcmpQuery
},
1049 { DEFINE_OID(mib2Tcp
), mib2TcpInit
, mib2TcpQuery
},
1050 { DEFINE_OID(mib2Udp
), mib2UdpInit
, mib2UdpQuery
},
1052 static UINT minSupportedIDLength
;
1054 BOOL WINAPI
SnmpExtensionInit(DWORD dwUptimeReference
,
1055 HANDLE
*phSubagentTrapEvent
, AsnObjectIdentifier
*pFirstSupportedRegion
)
1057 AsnObjectIdentifier myOid
= DEFINE_OID(mib2System
);
1060 TRACE("(%d, %p, %p)\n", dwUptimeReference
, phSubagentTrapEvent
,
1061 pFirstSupportedRegion
);
1063 minSupportedIDLength
= UINT_MAX
;
1064 for (i
= 0; i
< sizeof(supportedIDs
) / sizeof(supportedIDs
[0]); i
++)
1066 if (supportedIDs
[i
].init
)
1067 supportedIDs
[i
].init();
1068 if (supportedIDs
[i
].name
.idLength
< minSupportedIDLength
)
1069 minSupportedIDLength
= supportedIDs
[i
].name
.idLength
;
1071 *phSubagentTrapEvent
= NULL
;
1072 SnmpUtilOidCpy(pFirstSupportedRegion
, &myOid
);
1076 static struct mibImplementation
*findSupportedQuery(UINT
*ids
, UINT idLength
,
1077 UINT
*matchingIndex
)
1079 int indexHigh
= DEFINE_SIZEOF(supportedIDs
) - 1, indexLow
= 0, i
;
1080 struct mibImplementation
*impl
= NULL
;
1081 AsnObjectIdentifier oid1
= { idLength
, ids
};
1085 for (i
= (indexLow
+ indexHigh
) / 2; !impl
&& indexLow
<= indexHigh
;
1086 i
= (indexLow
+ indexHigh
) / 2)
1090 cmp
= SnmpUtilOidNCmp(&oid1
, &supportedIDs
[i
].name
, idLength
);
1093 impl
= &supportedIDs
[i
];
1104 BOOL WINAPI
SnmpExtensionQuery(BYTE bPduType
, SnmpVarBindList
*pVarBindList
,
1105 AsnInteger32
*pErrorStatus
, AsnInteger32
*pErrorIndex
)
1107 AsnObjectIdentifier mib2oid
= DEFINE_OID(mib2
);
1108 AsnInteger32 error
= SNMP_ERRORSTATUS_NOERROR
, errorIndex
= 0;
1111 TRACE("(0x%02x, %p, %p, %p)\n", bPduType
, pVarBindList
,
1112 pErrorStatus
, pErrorIndex
);
1114 for (i
= 0; !error
&& i
< pVarBindList
->len
; i
++)
1116 /* Ignore any OIDs not in MIB2 */
1117 if (!SnmpUtilOidNCmp(&pVarBindList
->list
[i
].name
, &mib2oid
,
1120 struct mibImplementation
*impl
= NULL
;
1121 UINT len
, matchingIndex
= 0;
1123 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList
->list
[i
].name
));
1124 /* Search for an implementation matching as many octets as possible
1126 for (len
= pVarBindList
->list
[i
].name
.idLength
;
1127 len
>= minSupportedIDLength
&& !impl
; len
--)
1128 impl
= findSupportedQuery(pVarBindList
->list
[i
].name
.ids
, len
,
1130 if (impl
&& impl
->query
)
1131 impl
->query(bPduType
, &pVarBindList
->list
[i
], &error
);
1133 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1134 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1135 bPduType
== SNMP_PDU_GETNEXT
)
1137 /* GetNext is special: it finds the successor to the given OID,
1138 * so we have to continue until an implementation handles the
1139 * query or we exhaust the table of supported OIDs.
1141 for (; error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1142 matchingIndex
< DEFINE_SIZEOF(supportedIDs
);
1145 error
= SNMP_ERRORSTATUS_NOERROR
;
1146 impl
= &supportedIDs
[matchingIndex
];
1148 impl
->query(bPduType
, &pVarBindList
->list
[i
], &error
);
1150 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1152 /* If the query still isn't resolved, set the OID to the
1153 * successor to the last entry in the table.
1155 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
)
1157 SnmpUtilOidFree(&pVarBindList
->list
[i
].name
);
1158 SnmpUtilOidCpy(&pVarBindList
->list
[i
].name
,
1159 &supportedIDs
[matchingIndex
- 1].name
);
1160 pVarBindList
->list
[i
].name
.ids
[
1161 pVarBindList
->list
[i
].name
.idLength
- 1] += 1;
1168 *pErrorStatus
= error
;
1169 *pErrorIndex
= errorIndex
;