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 void setOidWithItem(AsnObjectIdentifier
*dst
, AsnObjectIdentifier
*base
,
438 AsnObjectIdentifier oid
;
440 SnmpUtilOidCpy(dst
, base
);
444 SnmpUtilOidAppend(dst
, &oid
);
447 static void setOidWithItemAndIpAddr(AsnObjectIdentifier
*dst
,
448 AsnObjectIdentifier
*base
, UINT item
, DWORD addr
)
452 AsnObjectIdentifier oid
;
454 setOidWithItem(dst
, base
, item
);
457 for (ptr
= (BYTE
*)&addr
; ptr
< (BYTE
*)&addr
+ sizeof(DWORD
); ptr
++)
460 SnmpUtilOidAppend(dst
, &oid
);
464 static void setOidWithItemAndInteger(AsnObjectIdentifier
*dst
,
465 AsnObjectIdentifier
*base
, UINT item
, UINT instance
)
467 AsnObjectIdentifier oid
;
469 setOidWithItem(dst
, base
, item
);
472 SnmpUtilOidAppend(dst
, &oid
);
475 static struct structToAsnValue mib2IfEntryMap
[] = {
476 { FIELD_OFFSET(MIB_IFROW
, dwIndex
), copyInt
},
477 { FIELD_OFFSET(MIB_IFROW
, dwDescrLen
), copyLengthPrecededString
},
478 { FIELD_OFFSET(MIB_IFROW
, dwType
), copyInt
},
479 { FIELD_OFFSET(MIB_IFROW
, dwMtu
), copyInt
},
480 { FIELD_OFFSET(MIB_IFROW
, dwSpeed
), copyInt
},
481 { FIELD_OFFSET(MIB_IFROW
, dwPhysAddrLen
), copyLengthPrecededString
},
482 { FIELD_OFFSET(MIB_IFROW
, dwAdminStatus
), copyInt
},
483 { FIELD_OFFSET(MIB_IFROW
, dwOperStatus
), copyOperStatus
},
484 { FIELD_OFFSET(MIB_IFROW
, dwLastChange
), copyInt
},
485 { FIELD_OFFSET(MIB_IFROW
, dwInOctets
), copyInt
},
486 { FIELD_OFFSET(MIB_IFROW
, dwInUcastPkts
), copyInt
},
487 { FIELD_OFFSET(MIB_IFROW
, dwInNUcastPkts
), copyInt
},
488 { FIELD_OFFSET(MIB_IFROW
, dwInDiscards
), copyInt
},
489 { FIELD_OFFSET(MIB_IFROW
, dwInErrors
), copyInt
},
490 { FIELD_OFFSET(MIB_IFROW
, dwInUnknownProtos
), copyInt
},
491 { FIELD_OFFSET(MIB_IFROW
, dwOutOctets
), copyInt
},
492 { FIELD_OFFSET(MIB_IFROW
, dwOutUcastPkts
), copyInt
},
493 { FIELD_OFFSET(MIB_IFROW
, dwOutNUcastPkts
), copyInt
},
494 { FIELD_OFFSET(MIB_IFROW
, dwOutDiscards
), copyInt
},
495 { FIELD_OFFSET(MIB_IFROW
, dwOutErrors
), copyInt
},
496 { FIELD_OFFSET(MIB_IFROW
, dwOutQLen
), copyInt
},
499 static UINT mib2IfEntry
[] = { 1,3,6,1,2,1,2,2,1 };
501 static BOOL
mib2IfEntryQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
502 AsnInteger32
*pErrorStatus
)
504 AsnObjectIdentifier entryOid
= DEFINE_OID(mib2IfEntry
);
506 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
512 case SNMP_PDU_GETNEXT
:
515 /* There is no interface present, so let the caller deal
516 * with finding the successor.
518 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
522 UINT tableIndex
= 0, item
= 0;
524 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
525 &entryOid
, bPduType
, &item
, &tableIndex
);
530 if (tableIndex
> ifTable
->dwNumEntries
)
531 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
534 *pErrorStatus
= mapStructEntryToValue(mib2IfEntryMap
,
535 DEFINE_SIZEOF(mib2IfEntryMap
),
536 &ifTable
->table
[tableIndex
- 1], item
, bPduType
,
538 if (bPduType
== SNMP_PDU_GETNEXT
)
539 setOidWithItemAndInteger(&pVarBind
->name
, &entryOid
,
546 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
549 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
550 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
555 static UINT mib2Ip
[] = { 1,3,6,1,2,1,4 };
556 static MIB_IPSTATS ipStats
;
558 static void mib2IpStatsInit(void)
560 GetIpStatistics(&ipStats
);
563 static struct structToAsnValue mib2IpMap
[] = {
564 { FIELD_OFFSET(MIB_IPSTATS
, dwForwarding
), copyInt
}, /* 1 */
565 { FIELD_OFFSET(MIB_IPSTATS
, dwDefaultTTL
), copyInt
}, /* 2 */
566 { FIELD_OFFSET(MIB_IPSTATS
, dwInReceives
), copyInt
}, /* 3 */
567 { FIELD_OFFSET(MIB_IPSTATS
, dwInHdrErrors
), copyInt
}, /* 4 */
568 { FIELD_OFFSET(MIB_IPSTATS
, dwInAddrErrors
), copyInt
}, /* 5 */
569 { FIELD_OFFSET(MIB_IPSTATS
, dwForwDatagrams
), copyInt
}, /* 6 */
570 { FIELD_OFFSET(MIB_IPSTATS
, dwInUnknownProtos
), copyInt
}, /* 7 */
571 { FIELD_OFFSET(MIB_IPSTATS
, dwInDiscards
), copyInt
}, /* 8 */
572 { FIELD_OFFSET(MIB_IPSTATS
, dwInDelivers
), copyInt
}, /* 9 */
573 { FIELD_OFFSET(MIB_IPSTATS
, dwOutRequests
), copyInt
}, /* 10 */
574 { FIELD_OFFSET(MIB_IPSTATS
, dwOutDiscards
), copyInt
}, /* 11 */
575 { FIELD_OFFSET(MIB_IPSTATS
, dwOutNoRoutes
), copyInt
}, /* 12 */
576 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmTimeout
), copyInt
}, /* 13 */
577 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmReqds
), copyInt
}, /* 14 */
578 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmOks
), copyInt
}, /* 15 */
579 { FIELD_OFFSET(MIB_IPSTATS
, dwReasmFails
), copyInt
}, /* 16 */
580 { FIELD_OFFSET(MIB_IPSTATS
, dwFragOks
), copyInt
}, /* 17 */
581 { FIELD_OFFSET(MIB_IPSTATS
, dwFragFails
), copyInt
}, /* 18 */
582 { FIELD_OFFSET(MIB_IPSTATS
, dwFragCreates
), copyInt
}, /* 19 */
583 { 0, NULL
}, /* 20: not used, IP addr table */
584 { 0, NULL
}, /* 21: not used, route table */
585 { 0, NULL
}, /* 22: not used, net to media (ARP) table */
586 { FIELD_OFFSET(MIB_IPSTATS
, dwRoutingDiscards
), copyInt
}, /* 23 */
589 static BOOL
mib2IpStatsQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
590 AsnInteger32
*pErrorStatus
)
592 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Ip
);
595 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
601 case SNMP_PDU_GETNEXT
:
602 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
606 *pErrorStatus
= mapStructEntryToValue(mib2IpMap
,
607 DEFINE_SIZEOF(mib2IpMap
), &ipStats
, item
, bPduType
, pVarBind
);
608 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
609 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
613 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
616 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
617 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
622 static UINT mib2IpAddr
[] = { 1,3,6,1,2,1,4,20,1 };
623 static PMIB_IPADDRTABLE ipAddrTable
;
625 static struct structToAsnValue mib2IpAddrMap
[] = {
626 { FIELD_OFFSET(MIB_IPADDRROW
, dwAddr
), copyIpAddr
},
627 { FIELD_OFFSET(MIB_IPADDRROW
, dwIndex
), copyInt
},
628 { FIELD_OFFSET(MIB_IPADDRROW
, dwMask
), copyIpAddr
},
629 { FIELD_OFFSET(MIB_IPADDRROW
, dwBCastAddr
), copyInt
},
630 { FIELD_OFFSET(MIB_IPADDRROW
, dwReasmSize
), copyInt
},
633 static void mib2IpAddrInit(void)
635 DWORD size
= 0, ret
= GetIpAddrTable(NULL
, &size
, FALSE
);
637 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
639 ipAddrTable
= HeapAlloc(GetProcessHeap(), 0, size
);
641 GetIpAddrTable(ipAddrTable
, &size
, FALSE
);
645 static BOOL
mib2IpAddrQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
646 AsnInteger32
*pErrorStatus
)
648 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpAddr
);
649 UINT tableIndex
= 0, item
= 0;
651 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
657 case SNMP_PDU_GETNEXT
:
658 *pErrorStatus
= getItemAndIpAddressInstanceFromOid(&pVarBind
->name
,
659 &myOid
, bPduType
, (struct GenericTable
*)ipAddrTable
,
660 sizeof(MIB_IPADDRROW
), FIELD_OFFSET(MIB_IPADDRROW
, dwAddr
), &item
,
666 *pErrorStatus
= mapStructEntryToValue(mib2IpAddrMap
,
667 DEFINE_SIZEOF(mib2IpAddrMap
),
668 &ipAddrTable
->table
[tableIndex
- 1], item
, bPduType
, pVarBind
);
669 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
670 setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
671 ipAddrTable
->table
[tableIndex
- 1].dwAddr
);
675 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
678 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
679 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
684 static UINT mib2IpRoute
[] = { 1,3,6,1,2,1,4,21,1 };
685 static PMIB_IPFORWARDTABLE ipRouteTable
;
687 static struct structToAsnValue mib2IpRouteMap
[] = {
688 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardDest
), copyIpAddr
},
689 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardIfIndex
), copyInt
},
690 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric1
), copyInt
},
691 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric2
), copyInt
},
692 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric3
), copyInt
},
693 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric4
), copyInt
},
694 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardNextHop
), copyIpAddr
},
695 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardType
), copyInt
},
696 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardProto
), copyInt
},
697 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardAge
), copyInt
},
698 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMask
), copyIpAddr
},
699 { FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardMetric5
), copyInt
},
702 static void mib2IpRouteInit(void)
704 DWORD size
= 0, ret
= GetIpForwardTable(NULL
, &size
, FALSE
);
706 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
708 ipRouteTable
= HeapAlloc(GetProcessHeap(), 0, size
);
710 GetIpForwardTable(ipRouteTable
, &size
, FALSE
);
714 static BOOL
mib2IpRouteQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
715 AsnInteger32
*pErrorStatus
)
717 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpRoute
);
718 UINT tableIndex
= 0, item
= 0;
720 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
726 case SNMP_PDU_GETNEXT
:
727 *pErrorStatus
= getItemAndIpAddressInstanceFromOid(&pVarBind
->name
,
728 &myOid
, bPduType
, (struct GenericTable
*)ipRouteTable
,
729 sizeof(MIB_IPFORWARDROW
),
730 FIELD_OFFSET(MIB_IPFORWARDROW
, dwForwardDest
), &item
, &tableIndex
);
735 *pErrorStatus
= mapStructEntryToValue(mib2IpRouteMap
,
736 DEFINE_SIZEOF(mib2IpRouteMap
),
737 &ipRouteTable
->table
[tableIndex
- 1], item
, bPduType
, pVarBind
);
738 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
739 setOidWithItemAndIpAddr(&pVarBind
->name
, &myOid
, item
,
740 ipRouteTable
->table
[tableIndex
- 1].dwForwardDest
);
744 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
747 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
748 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
753 static UINT mib2IpNet
[] = { 1,3,6,1,2,1,4,22,1 };
754 static PMIB_IPNETTABLE ipNetTable
;
756 static struct structToAsnValue mib2IpNetMap
[] = {
757 { FIELD_OFFSET(MIB_IPNETROW
, dwIndex
), copyInt
},
758 { FIELD_OFFSET(MIB_IPNETROW
, dwPhysAddrLen
), copyLengthPrecededString
},
759 { FIELD_OFFSET(MIB_IPNETROW
, dwAddr
), copyIpAddr
},
760 { FIELD_OFFSET(MIB_IPNETROW
, dwType
), copyInt
},
763 static void mib2IpNetInit(void)
765 DWORD size
= 0, ret
= GetIpNetTable(NULL
, &size
, FALSE
);
767 if (ret
== ERROR_INSUFFICIENT_BUFFER
)
769 ipNetTable
= HeapAlloc(GetProcessHeap(), 0, size
);
771 GetIpNetTable(ipNetTable
, &size
, FALSE
);
775 static BOOL
mib2IpNetQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
776 AsnInteger32
*pErrorStatus
)
778 AsnObjectIdentifier myOid
= DEFINE_OID(mib2IpNet
);
780 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
786 case SNMP_PDU_GETNEXT
:
788 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
791 UINT tableIndex
= 0, item
= 0;
793 *pErrorStatus
= getItemAndIntegerInstanceFromOid(&pVarBind
->name
,
794 &myOid
, bPduType
, &item
, &tableIndex
);
799 if (tableIndex
> ipNetTable
->dwNumEntries
)
800 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
803 *pErrorStatus
= mapStructEntryToValue(mib2IpNetMap
,
804 DEFINE_SIZEOF(mib2IpNetMap
),
805 &ipNetTable
[tableIndex
- 1], item
, bPduType
, pVarBind
);
806 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
807 setOidWithItemAndInteger(&pVarBind
->name
, &myOid
, item
,
814 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
817 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
818 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
823 static UINT mib2Icmp
[] = { 1,3,6,1,2,1,5 };
824 static MIB_ICMP icmpStats
;
826 static void mib2IcmpInit(void)
828 GetIcmpStatistics(&icmpStats
);
831 static struct structToAsnValue mib2IcmpMap
[] = {
832 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwMsgs
), copyInt
},
833 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwErrors
), copyInt
},
834 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwDestUnreachs
), copyInt
},
835 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimeExcds
), copyInt
},
836 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwParmProbs
), copyInt
},
837 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwSrcQuenchs
), copyInt
},
838 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwRedirects
), copyInt
},
839 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchos
), copyInt
},
840 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwEchoReps
), copyInt
},
841 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestamps
), copyInt
},
842 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwTimestampReps
), copyInt
},
843 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMasks
), copyInt
},
844 { FIELD_OFFSET(MIBICMPINFO
, icmpInStats
.dwAddrMaskReps
), copyInt
},
845 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwMsgs
), copyInt
},
846 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwErrors
), copyInt
},
847 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwDestUnreachs
), copyInt
},
848 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimeExcds
), copyInt
},
849 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwParmProbs
), copyInt
},
850 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwSrcQuenchs
), copyInt
},
851 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwRedirects
), copyInt
},
852 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchos
), copyInt
},
853 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwEchoReps
), copyInt
},
854 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestamps
), copyInt
},
855 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwTimestampReps
), copyInt
},
856 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMasks
), copyInt
},
857 { FIELD_OFFSET(MIBICMPINFO
, icmpOutStats
.dwAddrMaskReps
), copyInt
},
860 static BOOL
mib2IcmpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
861 AsnInteger32
*pErrorStatus
)
863 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Icmp
);
866 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
872 case SNMP_PDU_GETNEXT
:
873 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
877 *pErrorStatus
= mapStructEntryToValue(mib2IcmpMap
,
878 DEFINE_SIZEOF(mib2IcmpMap
), &icmpStats
, item
, bPduType
,
880 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
881 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
885 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
888 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
889 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
894 static UINT mib2Tcp
[] = { 1,3,6,1,2,1,6 };
895 static MIB_TCPSTATS tcpStats
;
897 static void mib2TcpInit(void)
899 GetTcpStatistics(&tcpStats
);
902 static struct structToAsnValue mib2TcpMap
[] = {
903 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoAlgorithm
), copyInt
},
904 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMin
), copyInt
},
905 { FIELD_OFFSET(MIB_TCPSTATS
, dwRtoMax
), copyInt
},
906 { FIELD_OFFSET(MIB_TCPSTATS
, dwMaxConn
), copyInt
},
907 { FIELD_OFFSET(MIB_TCPSTATS
, dwActiveOpens
), copyInt
},
908 { FIELD_OFFSET(MIB_TCPSTATS
, dwPassiveOpens
), copyInt
},
909 { FIELD_OFFSET(MIB_TCPSTATS
, dwAttemptFails
), copyInt
},
910 { FIELD_OFFSET(MIB_TCPSTATS
, dwEstabResets
), copyInt
},
911 { FIELD_OFFSET(MIB_TCPSTATS
, dwCurrEstab
), copyInt
},
912 { FIELD_OFFSET(MIB_TCPSTATS
, dwInSegs
), copyInt
},
913 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutSegs
), copyInt
},
914 { FIELD_OFFSET(MIB_TCPSTATS
, dwRetransSegs
), copyInt
},
915 { FIELD_OFFSET(MIB_TCPSTATS
, dwInErrs
), copyInt
},
916 { FIELD_OFFSET(MIB_TCPSTATS
, dwOutRsts
), copyInt
},
917 { FIELD_OFFSET(MIB_TCPSTATS
, dwNumConns
), copyInt
},
920 static BOOL
mib2TcpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
921 AsnInteger32
*pErrorStatus
)
923 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Tcp
);
926 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
932 case SNMP_PDU_GETNEXT
:
933 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
937 *pErrorStatus
= mapStructEntryToValue(mib2TcpMap
,
938 DEFINE_SIZEOF(mib2TcpMap
), &tcpStats
, item
, bPduType
, pVarBind
);
939 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
940 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
944 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
947 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
948 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
953 static UINT mib2Udp
[] = { 1,3,6,1,2,1,7 };
954 static MIB_UDPSTATS udpStats
;
956 static void mib2UdpInit(void)
958 GetUdpStatistics(&udpStats
);
961 static struct structToAsnValue mib2UdpMap
[] = {
962 { FIELD_OFFSET(MIB_UDPSTATS
, dwInDatagrams
), copyInt
},
963 { FIELD_OFFSET(MIB_UDPSTATS
, dwNoPorts
), copyInt
},
964 { FIELD_OFFSET(MIB_UDPSTATS
, dwInErrors
), copyInt
},
965 { FIELD_OFFSET(MIB_UDPSTATS
, dwOutDatagrams
), copyInt
},
968 static BOOL
mib2UdpQuery(BYTE bPduType
, SnmpVarBind
*pVarBind
,
969 AsnInteger32
*pErrorStatus
)
971 AsnObjectIdentifier myOid
= DEFINE_OID(mib2Udp
);
974 TRACE("(0x%02x, %s, %p)\n", bPduType
, SnmpUtilOidToA(&pVarBind
->name
),
980 case SNMP_PDU_GETNEXT
:
981 *pErrorStatus
= getItemFromOid(&pVarBind
->name
, &myOid
, bPduType
,
985 *pErrorStatus
= mapStructEntryToValue(mib2UdpMap
,
986 DEFINE_SIZEOF(mib2UdpMap
), &udpStats
, item
, bPduType
, pVarBind
);
987 if (!*pErrorStatus
&& bPduType
== SNMP_PDU_GETNEXT
)
988 setOidWithItem(&pVarBind
->name
, &myOid
, item
);
992 *pErrorStatus
= SNMP_ERRORSTATUS_READONLY
;
995 FIXME("0x%02x: unsupported PDU type\n", bPduType
);
996 *pErrorStatus
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1001 /* This list MUST BE lexicographically sorted */
1002 static struct mibImplementation supportedIDs
[] = {
1003 { DEFINE_OID(mib2IfNumber
), mib2IfNumberInit
, mib2IfNumberQuery
},
1004 { DEFINE_OID(mib2IfEntry
), NULL
, mib2IfEntryQuery
},
1005 { DEFINE_OID(mib2Ip
), mib2IpStatsInit
, mib2IpStatsQuery
},
1006 { DEFINE_OID(mib2IpAddr
), mib2IpAddrInit
, mib2IpAddrQuery
},
1007 { DEFINE_OID(mib2IpRoute
), mib2IpRouteInit
, mib2IpRouteQuery
},
1008 { DEFINE_OID(mib2IpNet
), mib2IpNetInit
, mib2IpNetQuery
},
1009 { DEFINE_OID(mib2Icmp
), mib2IcmpInit
, mib2IcmpQuery
},
1010 { DEFINE_OID(mib2Tcp
), mib2TcpInit
, mib2TcpQuery
},
1011 { DEFINE_OID(mib2Udp
), mib2UdpInit
, mib2UdpQuery
},
1013 static UINT minSupportedIDLength
;
1015 BOOL WINAPI
SnmpExtensionInit(DWORD dwUptimeReference
,
1016 HANDLE
*phSubagentTrapEvent
, AsnObjectIdentifier
*pFirstSupportedRegion
)
1018 AsnObjectIdentifier myOid
= DEFINE_OID(mib2System
);
1021 TRACE("(%d, %p, %p)\n", dwUptimeReference
, phSubagentTrapEvent
,
1022 pFirstSupportedRegion
);
1024 minSupportedIDLength
= UINT_MAX
;
1025 for (i
= 0; i
< sizeof(supportedIDs
) / sizeof(supportedIDs
[0]); i
++)
1027 if (supportedIDs
[i
].init
)
1028 supportedIDs
[i
].init();
1029 if (supportedIDs
[i
].name
.idLength
< minSupportedIDLength
)
1030 minSupportedIDLength
= supportedIDs
[i
].name
.idLength
;
1032 *phSubagentTrapEvent
= NULL
;
1033 SnmpUtilOidCpy(pFirstSupportedRegion
, &myOid
);
1037 static struct mibImplementation
*findSupportedQuery(UINT
*ids
, UINT idLength
,
1038 UINT
*matchingIndex
)
1040 int indexHigh
= DEFINE_SIZEOF(supportedIDs
) - 1, indexLow
= 0, i
;
1041 struct mibImplementation
*impl
= NULL
;
1042 AsnObjectIdentifier oid1
= { idLength
, ids
};
1046 for (i
= (indexLow
+ indexHigh
) / 2; !impl
&& indexLow
<= indexHigh
;
1047 i
= (indexLow
+ indexHigh
) / 2)
1051 cmp
= SnmpUtilOidNCmp(&oid1
, &supportedIDs
[i
].name
, idLength
);
1054 impl
= &supportedIDs
[i
];
1065 BOOL WINAPI
SnmpExtensionQuery(BYTE bPduType
, SnmpVarBindList
*pVarBindList
,
1066 AsnInteger32
*pErrorStatus
, AsnInteger32
*pErrorIndex
)
1068 AsnObjectIdentifier mib2oid
= DEFINE_OID(mib2
);
1069 AsnInteger32 error
= SNMP_ERRORSTATUS_NOERROR
, errorIndex
= 0;
1072 TRACE("(0x%02x, %p, %p, %p)\n", bPduType
, pVarBindList
,
1073 pErrorStatus
, pErrorIndex
);
1075 for (i
= 0; !error
&& i
< pVarBindList
->len
; i
++)
1077 /* Ignore any OIDs not in MIB2 */
1078 if (!SnmpUtilOidNCmp(&pVarBindList
->list
[i
].name
, &mib2oid
,
1081 struct mibImplementation
*impl
= NULL
;
1082 UINT len
, matchingIndex
= 0;
1084 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList
->list
[i
].name
));
1085 /* Search for an implementation matching as many octets as possible
1087 for (len
= pVarBindList
->list
[i
].name
.idLength
;
1088 len
>= minSupportedIDLength
&& !impl
; len
--)
1089 impl
= findSupportedQuery(pVarBindList
->list
[i
].name
.ids
, len
,
1091 if (impl
&& impl
->query
)
1092 impl
->query(bPduType
, &pVarBindList
->list
[i
], &error
);
1094 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1095 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1096 bPduType
== SNMP_PDU_GETNEXT
)
1098 /* GetNext is special: it finds the successor to the given OID,
1099 * so we have to continue until an implementation handles the
1100 * query or we exhaust the table of supported OIDs.
1102 for (; error
== SNMP_ERRORSTATUS_NOSUCHNAME
&&
1103 matchingIndex
< DEFINE_SIZEOF(supportedIDs
);
1106 error
= SNMP_ERRORSTATUS_NOERROR
;
1107 impl
= &supportedIDs
[matchingIndex
];
1109 impl
->query(bPduType
, &pVarBindList
->list
[i
], &error
);
1111 error
= SNMP_ERRORSTATUS_NOSUCHNAME
;
1113 /* If the query still isn't resolved, set the OID to the
1114 * successor to the last entry in the table.
1116 if (error
== SNMP_ERRORSTATUS_NOSUCHNAME
)
1118 SnmpUtilOidFree(&pVarBindList
->list
[i
].name
);
1119 SnmpUtilOidCpy(&pVarBindList
->list
[i
].name
,
1120 &supportedIDs
[matchingIndex
- 1].name
);
1121 pVarBindList
->list
[i
].name
.ids
[
1122 pVarBindList
->list
[i
].name
.idLength
- 1] += 1;
1129 *pErrorStatus
= error
;
1130 *pErrorIndex
= errorIndex
;