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);
35 static void copyInt(AsnAny *value, void *src)
37 value->asnType = ASN_INTEGER;
38 value->asnValue.number = *(DWORD *)src;
41 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
45 strValue.asnType = type;
46 strValue.asnValue.string.stream = str;
47 strValue.asnValue.string.length = len;
48 strValue.asnValue.string.dynamic = TRUE;
49 SnmpUtilAsnAnyCpy(value, &strValue);
52 static void copyLengthPrecededString(AsnAny *value, void *src)
54 DWORD len = *(DWORD *)src;
56 setStringValue(value, ASN_OCTETSTRING, len, (BYTE *)src + sizeof(DWORD));
59 typedef void (*copyValueFunc)(AsnAny *value, void *src);
61 struct structToAsnValue
67 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
68 UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
70 /* OIDs are 1-based */
72 return SNMP_ERRORSTATUS_NOSUCHNAME;
75 return SNMP_ERRORSTATUS_NOSUCHNAME;
77 return SNMP_ERRORSTATUS_NOSUCHNAME;
78 map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
79 return SNMP_ERRORSTATUS_NOERROR;
82 static void copyIpAddr(AsnAny *value, void *src)
84 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
87 static UINT mib2[] = { 1,3,6,1,2,1 };
88 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
90 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
91 AsnInteger32 *pErrorStatus);
93 struct mibImplementation
95 AsnObjectIdentifier name;
98 void (*cleanup)(void);
101 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
102 static PMIB_IFTABLE ifTable;
104 static void mib2IfNumberInit(void)
106 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
108 if (ret == ERROR_INSUFFICIENT_BUFFER)
110 MIB_IFTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
113 if (!GetIfTable(table, &size, FALSE)) ifTable = table;
114 else HeapFree(GetProcessHeap(), 0, table );
119 static void mib2IfNumberCleanup(void)
121 HeapFree(GetProcessHeap(), 0, ifTable);
124 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
125 AsnInteger32 *pErrorStatus)
127 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
130 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
136 case SNMP_PDU_GETNEXT:
137 if ((bPduType == SNMP_PDU_GET &&
138 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
139 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
142 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
144 copyInt(&pVarBind->value, &numIfs);
145 if (bPduType == SNMP_PDU_GETNEXT)
146 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
147 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
151 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
152 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
153 * need to set it here.
158 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
162 FIXME("0x%02x: unsupported PDU type\n", bPduType);
163 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
168 static void copyOperStatus(AsnAny *value, void *src)
170 value->asnType = ASN_INTEGER;
171 /* The IPHlpApi definition of operational status differs from the MIB2 one,
172 * so map it to the MIB2 value.
174 switch (*(DWORD *)src)
176 case MIB_IF_OPER_STATUS_OPERATIONAL:
177 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
179 case MIB_IF_OPER_STATUS_CONNECTING:
180 case MIB_IF_OPER_STATUS_CONNECTED:
181 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
184 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
188 /* Given an OID and a base OID that it must begin with, finds the item and
189 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
190 * foo, returns item 1 and instance 2.
191 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
192 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
193 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
194 * instance, or item 1, instance 1 if either is missing.
196 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
197 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
199 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
203 case SNMP_PDU_GETNEXT:
204 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
209 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
211 if (oid->idLength == base->idLength ||
212 oid->idLength == base->idLength + 1)
214 /* Either the table or an item within the table is specified,
215 * but the instance is not. Get the first instance.
218 if (oid->idLength == base->idLength + 1)
219 *item = oid->ids[base->idLength];
225 *item = oid->ids[base->idLength];
226 *instance = oid->ids[base->idLength + 1] + 1;
230 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
233 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
235 if (oid->idLength == base->idLength ||
236 oid->idLength == base->idLength + 1)
238 /* Either the table or an item within the table is specified,
239 * but the instance is not.
241 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
245 *item = oid->ids[base->idLength];
246 *instance = oid->ids[base->idLength + 1];
250 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
255 /* Given an OID and a base OID that it must begin with, finds the item from the
256 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
257 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
258 * SNMP_ERRORSTATUS_NOSUCHNAME.
259 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
260 * 1 if the item is missing.
262 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
263 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
265 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
269 case SNMP_PDU_GETNEXT:
270 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
272 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
274 if (oid->idLength == base->idLength)
276 /* The item is missing, assume the first item */
280 *item = oid->ids[base->idLength] + 1;
283 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
286 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
288 if (oid->idLength == base->idLength)
290 /* The item is missing */
291 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
295 *item = oid->ids[base->idLength];
297 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
301 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
312 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
314 assert(oid && oid->idLength >= 4);
315 /* Map the IDs to an IP address in little-endian order */
316 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
317 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
320 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
321 typedef int (*compareFunc)(const void *key, const void *value);
323 static UINT findValueInTable(AsnObjectIdentifier *oid,
324 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
328 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
335 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
338 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize
340 HeapFree(GetProcessHeap(), 0, key);
345 /* Given an OID and a base OID that it must begin with, finds the item and
346 * element of the table whose value matches the instance from the OID.
347 * The OID is converted to a key with the function makeKey, and compared
348 * against entries in the table with the function compare.
349 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
350 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
351 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
352 * instance, or item 1, instance 1 if either is missing.
354 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
355 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
356 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
357 compareFunc compare, UINT *item, UINT *instance)
359 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
362 return SNMP_ERRORSTATUS_NOSUCHNAME;
366 case SNMP_PDU_GETNEXT:
367 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
369 /* Return the first item and instance from the table */
373 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
374 oid->idLength < base->idLength + instanceLen + 1)
376 /* Either the table or an item is specified, but the instance is
380 if (oid->idLength >= base->idLength + 1)
382 *item = oid->ids[base->idLength];
389 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
390 oid->idLength == base->idLength + instanceLen + 1)
392 *item = oid->ids[base->idLength];
400 AsnObjectIdentifier ipOid = { instanceLen,
401 oid->ids + base->idLength + 1 };
403 *instance = findValueInTable(&ipOid, table, tableEntrySize,
404 makeKey, compare) + 1;
405 if (*instance > table->numEntries)
406 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
410 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
413 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
414 oid->idLength == base->idLength + instanceLen + 1)
416 *item = oid->ids[base->idLength];
418 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
421 AsnObjectIdentifier ipOid = { instanceLen,
422 oid->ids + base->idLength + 1 };
424 *instance = findValueInTable(&ipOid, table, tableEntrySize,
427 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
431 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
436 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
440 AsnObjectIdentifier oid;
443 ret = SnmpUtilOidCpy(dst, base);
449 ret = SnmpUtilOidAppend(dst, &oid);
454 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
455 AsnObjectIdentifier *base, UINT item, DWORD addr)
459 AsnObjectIdentifier oid;
462 ret = setOidWithItem(dst, base, item);
467 for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
471 ret = SnmpUtilOidAppend(dst, &oid);
477 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
478 AsnObjectIdentifier *base, UINT item, UINT instance)
480 AsnObjectIdentifier oid;
483 ret = setOidWithItem(dst, base, item);
488 ret = SnmpUtilOidAppend(dst, &oid);
493 static struct structToAsnValue mib2IfEntryMap[] = {
494 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
495 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
496 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
497 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
498 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
499 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
500 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
501 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
502 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
503 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
504 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
505 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
506 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
507 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
508 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
509 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
510 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
511 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
512 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
513 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
514 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
517 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
519 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
520 AsnInteger32 *pErrorStatus)
522 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
525 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
531 case SNMP_PDU_GETNEXT:
534 /* There is no interface present, so let the caller deal
535 * with finding the successor.
537 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
541 UINT tableIndex = 0, item = 0;
543 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
544 &entryOid, bPduType, &item, &tableIndex);
549 if (tableIndex > ifTable->dwNumEntries)
550 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
553 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
554 DEFINE_SIZEOF(mib2IfEntryMap),
555 &ifTable->table[tableIndex - 1], item, bPduType,
557 if (bPduType == SNMP_PDU_GETNEXT)
558 ret = setOidWithItemAndInteger(&pVarBind->name,
559 &entryOid, item, tableIndex);
565 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
569 FIXME("0x%02x: unsupported PDU type\n", bPduType);
570 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
575 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
576 static MIB_IPSTATS ipStats;
578 static void mib2IpStatsInit(void)
580 GetIpStatistics(&ipStats);
583 static struct structToAsnValue mib2IpMap[] = {
584 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
585 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
586 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
587 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
588 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
589 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
590 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
591 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
592 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
593 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
594 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
595 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
596 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
597 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
598 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
599 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
600 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
601 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
602 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
603 { 0, NULL }, /* 20: not used, IP addr table */
604 { 0, NULL }, /* 21: not used, route table */
605 { 0, NULL }, /* 22: not used, net to media (ARP) table */
606 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
609 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
610 AsnInteger32 *pErrorStatus)
612 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
616 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
622 case SNMP_PDU_GETNEXT:
623 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
627 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
628 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
629 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
630 ret = setOidWithItem(&pVarBind->name, &myOid, item);
634 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
638 FIXME("0x%02x: unsupported PDU type\n", bPduType);
639 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
644 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
645 static PMIB_IPADDRTABLE ipAddrTable;
647 static struct structToAsnValue mib2IpAddrMap[] = {
648 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
649 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
650 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
651 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
652 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
655 static void mib2IpAddrInit(void)
657 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
659 if (ret == ERROR_INSUFFICIENT_BUFFER)
661 MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
664 if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table;
665 else HeapFree(GetProcessHeap(), 0, table );
670 static void mib2IpAddrCleanup(void)
672 HeapFree(GetProcessHeap(), 0, ipAddrTable);
675 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
677 MIB_IPADDRROW *row = dst;
679 row->dwAddr = oidToIpAddr(oid);
682 static int compareIpAddrRow(const void *a, const void *b)
684 const MIB_IPADDRROW *key = a, *value = b;
686 return key->dwAddr - value->dwAddr;
689 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
690 AsnInteger32 *pErrorStatus)
692 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
693 UINT tableIndex = 0, item = 0;
696 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
702 case SNMP_PDU_GETNEXT:
703 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
704 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
705 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
711 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
712 DEFINE_SIZEOF(mib2IpAddrMap),
713 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
714 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
715 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
716 ipAddrTable->table[tableIndex - 1].dwAddr);
720 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
724 FIXME("0x%02x: unsupported PDU type\n", bPduType);
725 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
730 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
731 static PMIB_IPFORWARDTABLE ipRouteTable;
733 static struct structToAsnValue mib2IpRouteMap[] = {
734 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
735 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
736 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
737 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
738 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
739 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
740 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
741 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
742 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
743 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
744 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
745 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
748 static void mib2IpRouteInit(void)
750 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
752 if (ret == ERROR_INSUFFICIENT_BUFFER)
754 MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
757 if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table;
758 else HeapFree(GetProcessHeap(), 0, table );
763 static void mib2IpRouteCleanup(void)
765 HeapFree(GetProcessHeap(), 0, ipRouteTable);
768 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
770 MIB_IPFORWARDROW *row = dst;
772 row->dwForwardDest = oidToIpAddr(oid);
775 static int compareIpForwardRow(const void *a, const void *b)
777 const MIB_IPFORWARDROW *key = a, *value = b;
779 return key->dwForwardDest - value->dwForwardDest;
782 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
783 AsnInteger32 *pErrorStatus)
785 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
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 *)ipRouteTable,
798 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
804 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
805 DEFINE_SIZEOF(mib2IpRouteMap),
806 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
807 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
808 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
809 ipRouteTable->table[tableIndex - 1].dwForwardDest);
813 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
817 FIXME("0x%02x: unsupported PDU type\n", bPduType);
818 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
823 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
824 static PMIB_IPNETTABLE ipNetTable;
826 static struct structToAsnValue mib2IpNetMap[] = {
827 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
828 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyLengthPrecededString },
829 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
830 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
833 static void mib2IpNetInit(void)
835 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
837 if (ret == ERROR_INSUFFICIENT_BUFFER)
839 MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
842 if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table;
843 else HeapFree(GetProcessHeap(), 0, table );
848 static void mib2IpNetCleanup(void)
850 HeapFree(GetProcessHeap(), 0, ipNetTable);
853 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
854 AsnInteger32 *pErrorStatus)
856 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
859 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
865 case SNMP_PDU_GETNEXT:
867 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
870 UINT tableIndex = 0, item = 0;
872 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
873 &myOid, bPduType, &item, &tableIndex);
878 if (tableIndex > ipNetTable->dwNumEntries)
879 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
882 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
883 DEFINE_SIZEOF(mib2IpNetMap),
884 &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
885 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
886 ret = setOidWithItemAndInteger(&pVarBind->name, &myOid,
893 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
897 FIXME("0x%02x: unsupported PDU type\n", bPduType);
898 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
903 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
904 static MIB_ICMP icmpStats;
906 static void mib2IcmpInit(void)
908 GetIcmpStatistics(&icmpStats);
911 static struct structToAsnValue mib2IcmpMap[] = {
912 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
913 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
914 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
915 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
916 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
917 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
918 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
919 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
920 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
921 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
922 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
923 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
924 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
925 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
926 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
927 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
928 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
929 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
930 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
931 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
932 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
933 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
934 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
935 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
936 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
937 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
940 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
941 AsnInteger32 *pErrorStatus)
943 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
947 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
953 case SNMP_PDU_GETNEXT:
954 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
958 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
959 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
961 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
962 ret = setOidWithItem(&pVarBind->name, &myOid, item);
966 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
970 FIXME("0x%02x: unsupported PDU type\n", bPduType);
971 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
976 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
977 static MIB_TCPSTATS tcpStats;
979 static void mib2TcpInit(void)
981 GetTcpStatistics(&tcpStats);
984 static struct structToAsnValue mib2TcpMap[] = {
985 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
986 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
987 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
988 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
989 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
990 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
991 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
992 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
993 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
994 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
995 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
996 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
997 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
998 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
999 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
1002 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1003 AsnInteger32 *pErrorStatus)
1005 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
1009 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1015 case SNMP_PDU_GETNEXT:
1016 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1020 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
1021 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
1022 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1023 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1027 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1031 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1032 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1037 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
1038 static MIB_UDPSTATS udpStats;
1040 static void mib2UdpInit(void)
1042 GetUdpStatistics(&udpStats);
1045 static struct structToAsnValue mib2UdpMap[] = {
1046 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1047 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1048 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1049 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1052 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1053 AsnInteger32 *pErrorStatus)
1055 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1059 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1065 case SNMP_PDU_GETNEXT:
1066 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1070 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1071 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
1072 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1073 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1077 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1081 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1082 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1087 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
1088 static PMIB_UDPTABLE udpTable;
1090 static void mib2UdpEntryInit(void)
1092 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
1094 if (ret == ERROR_INSUFFICIENT_BUFFER)
1096 MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
1099 if (!GetUdpTable(table, &size, TRUE)) udpTable = table;
1100 else HeapFree(GetProcessHeap(), 0, table);
1105 static void mib2UdpEntryCleanup(void)
1107 HeapFree(GetProcessHeap(), 0, udpTable);
1110 static struct structToAsnValue mib2UdpEntryMap[] = {
1111 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
1112 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
1115 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
1117 MIB_UDPROW *row = dst;
1119 assert(oid && oid->idLength >= 5);
1120 row->dwLocalAddr = oidToIpAddr(oid);
1121 row->dwLocalPort = oid->ids[4];
1124 static int compareUdpRow(const void *a, const void *b)
1126 const MIB_UDPROW *key = a, *value = b;
1129 ret = key->dwLocalAddr - value->dwLocalAddr;
1131 ret = key->dwLocalPort - value->dwLocalPort;
1135 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1136 AsnInteger32 *pErrorStatus)
1138 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
1141 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1147 case SNMP_PDU_GETNEXT:
1149 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1152 UINT tableIndex = 0, item = 0;
1154 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
1155 5, bPduType, (struct GenericTable *)udpTable,
1156 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
1162 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
1163 DEFINE_SIZEOF(mib2UdpEntryMap),
1164 &udpTable->table[tableIndex - 1], item, bPduType, pVarBind);
1165 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1167 AsnObjectIdentifier oid;
1169 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
1170 udpTable->table[tableIndex - 1].dwLocalAddr);
1174 oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
1175 ret = SnmpUtilOidAppend(&pVarBind->name, &oid);
1182 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1186 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1187 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1192 /* This list MUST BE lexicographically sorted */
1193 static struct mibImplementation supportedIDs[] = {
1194 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
1195 mib2IfNumberCleanup },
1196 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
1197 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
1198 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
1199 mib2IpAddrCleanup },
1200 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
1201 mib2IpRouteCleanup },
1202 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
1203 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
1204 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
1205 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
1206 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
1207 mib2UdpEntryCleanup },
1209 static UINT minSupportedIDLength;
1211 /*****************************************************************************
1212 * SnmpExtensionInit [INETMIB1.@]
1214 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1215 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1217 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1220 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1221 pFirstSupportedRegion);
1223 minSupportedIDLength = UINT_MAX;
1224 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1226 if (supportedIDs[i].init)
1227 supportedIDs[i].init();
1228 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1229 minSupportedIDLength = supportedIDs[i].name.idLength;
1231 *phSubagentTrapEvent = NULL;
1232 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1236 static void cleanup(void)
1240 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1241 if (supportedIDs[i].cleanup)
1242 supportedIDs[i].cleanup();
1245 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1246 UINT *matchingIndex)
1248 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
1249 struct mibImplementation *impl = NULL;
1250 AsnObjectIdentifier oid1 = { idLength, ids};
1254 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
1255 i = (indexLow + indexHigh) / 2)
1259 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
1262 impl = &supportedIDs[i];
1273 /*****************************************************************************
1274 * SnmpExtensionQuery [INETMIB1.@]
1276 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1277 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1279 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1280 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1283 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1284 pErrorStatus, pErrorIndex);
1286 for (i = 0; !error && i < pVarBindList->len; i++)
1288 /* Ignore any OIDs not in MIB2 */
1289 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1292 struct mibImplementation *impl = NULL;
1293 UINT len, matchingIndex = 0;
1295 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1296 /* Search for an implementation matching as many octets as possible
1298 for (len = pVarBindList->list[i].name.idLength;
1299 len >= minSupportedIDLength && !impl; len--)
1300 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1302 if (impl && impl->query)
1303 impl->query(bPduType, &pVarBindList->list[i], &error);
1305 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1306 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1307 bPduType == SNMP_PDU_GETNEXT)
1309 /* GetNext is special: it finds the successor to the given OID,
1310 * so we have to continue until an implementation handles the
1311 * query or we exhaust the table of supported OIDs.
1313 for (; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1314 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1317 error = SNMP_ERRORSTATUS_NOERROR;
1318 impl = &supportedIDs[matchingIndex];
1320 impl->query(bPduType, &pVarBindList->list[i], &error);
1322 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1324 /* If the query still isn't resolved, set the OID to the
1325 * successor to the last entry in the table.
1327 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1329 SnmpUtilOidFree(&pVarBindList->list[i].name);
1330 SnmpUtilOidCpy(&pVarBindList->list[i].name,
1331 &supportedIDs[matchingIndex - 1].name);
1332 pVarBindList->list[i].name.ids[
1333 pVarBindList->list[i].name.idLength - 1] += 1;
1340 *pErrorStatus = error;
1341 *pErrorIndex = errorIndex;
1345 /*****************************************************************************
1346 * DllMain [INETMIB1.@]
1348 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1350 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1354 case DLL_PROCESS_ATTACH:
1355 DisableThreadLibraryCalls(hinstDLL);
1357 case DLL_PROCESS_DETACH: