dpwsockx: Implementation of SPInit
[wine/gsoc_dplay.git] / dlls / inetmib1 / main.c
blobb0ff812dd7ca7d77cecc3aa0c162d398b0eac89c
1 /*
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
19 #include "config.h"
20 #include <assert.h>
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <limits.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "snmp.h"
27 #include "iphlpapi.h"
28 #include "wine/debug.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
32 /**
33 * Utility functions
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)
43 AsnAny strValue;
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
63 size_t offset;
64 copyValueFunc copy;
67 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
68 UINT mapLen, void *record, UINT id, BYTE bPduType, SnmpVarBind *pVarBind)
70 /* OIDs are 1-based */
71 if (!id)
72 return SNMP_ERRORSTATUS_NOSUCHNAME;
73 --id;
74 if (id >= mapLen)
75 return SNMP_ERRORSTATUS_NOSUCHNAME;
76 if (!map[id].copy)
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;
96 void (*init)(void);
97 varqueryfunc query;
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);
111 if (table)
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);
128 BOOL ret = TRUE;
130 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
131 pErrorStatus);
133 switch (bPduType)
135 case SNMP_PDU_GET:
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)
140 < 0)
142 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
144 copyInt(&pVarBind->value, &numIfs);
145 if (bPduType == SNMP_PDU_GETNEXT)
147 SnmpUtilOidFree(&pVarBind->name);
148 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
150 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
152 else
154 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
155 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
156 * need to set it here.
159 break;
160 case SNMP_PDU_SET:
161 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
162 ret = FALSE;
163 break;
164 default:
165 FIXME("0x%02x: unsupported PDU type\n", bPduType);
166 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
168 return ret;
171 static void copyOperStatus(AsnAny *value, void *src)
173 value->asnType = ASN_INTEGER;
174 /* The IPHlpApi definition of operational status differs from the MIB2 one,
175 * so map it to the MIB2 value.
177 switch (*(DWORD *)src)
179 case MIB_IF_OPER_STATUS_OPERATIONAL:
180 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
181 break;
182 case MIB_IF_OPER_STATUS_CONNECTING:
183 case MIB_IF_OPER_STATUS_CONNECTED:
184 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
185 break;
186 default:
187 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
191 /* Given an OID and a base OID that it must begin with, finds the item and
192 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
193 * foo, returns item 1 and instance 2.
194 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
195 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
196 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
197 * instance, or item 1, instance 1 if either is missing.
199 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
200 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
202 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
204 switch (bPduType)
206 case SNMP_PDU_GETNEXT:
207 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
209 *item = 1;
210 *instance = 1;
212 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
214 if (oid->idLength == base->idLength ||
215 oid->idLength == base->idLength + 1)
217 /* Either the table or an item within the table is specified,
218 * but the instance is not. Get the first instance.
220 *instance = 1;
221 if (oid->idLength == base->idLength + 1)
222 *item = oid->ids[base->idLength];
223 else
224 *item = 1;
226 else
228 *item = oid->ids[base->idLength];
229 *instance = oid->ids[base->idLength + 1] + 1;
232 else
233 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
234 break;
235 default:
236 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
238 if (oid->idLength == base->idLength ||
239 oid->idLength == base->idLength + 1)
241 /* Either the table or an item within the table is specified,
242 * but the instance is not.
244 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
246 else
248 *item = oid->ids[base->idLength];
249 *instance = oid->ids[base->idLength + 1];
252 else
253 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
255 return ret;
258 /* Given an OID and a base OID that it must begin with, finds the item from the
259 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
260 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
261 * SNMP_ERRORSTATUS_NOSUCHNAME.
262 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
263 * 1 if the item is missing.
265 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
266 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
268 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
270 switch (bPduType)
272 case SNMP_PDU_GETNEXT:
273 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
274 *item = 1;
275 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
277 if (oid->idLength == base->idLength)
279 /* The item is missing, assume the first item */
280 *item = 1;
282 else
283 *item = oid->ids[base->idLength] + 1;
285 else
286 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
287 break;
288 default:
289 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
291 if (oid->idLength == base->idLength)
293 /* The item is missing */
294 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
296 else
298 *item = oid->ids[base->idLength];
299 if (!*item)
300 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
303 else
304 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
306 return ret;
309 struct GenericTable
311 DWORD numEntries;
312 BYTE entries[1];
315 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
317 assert(oid && oid->idLength >= 4);
318 /* Map the IDs to an IP address in little-endian order */
319 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
320 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
323 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
324 typedef int (*compareFunc)(const void *key, const void *value);
326 /* Finds the first value in the table that matches key. Returns its 1-based
327 * index if found, or 0 if not found.
329 static UINT findValueInTable(const void *key,
330 struct GenericTable *table, size_t tableEntrySize, compareFunc compare)
332 UINT index = 0;
333 void *value;
335 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
336 compare);
337 if (value)
338 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize + 1;
339 return index;
342 /* Finds the first value in the table that matches oid, using makeKey to
343 * convert the oid to a key for comparison. Returns the value's 1-based
344 * index if found, or 0 if not found.
346 static UINT findOidInTable(AsnObjectIdentifier *oid,
347 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
348 compareFunc compare)
350 UINT index = 0;
351 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
353 if (key)
355 makeKey(oid, key);
356 index = findValueInTable(key, table, tableEntrySize, compare);
357 HeapFree(GetProcessHeap(), 0, key);
359 return index;
362 /* Finds the first successor to the value in the table that does matches oid,
363 * using makeKey to convert the oid to a key for comparison. A successor is
364 * a value that does not match oid, so if multiple entries match an oid, only
365 * the first will ever be returned using this method.
366 * Returns the successor's 1-based index if found, or 0 if not found.
368 static UINT findNextOidInTable(AsnObjectIdentifier *oid,
369 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
370 compareFunc compare)
372 UINT index = 0;
373 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
375 if (key)
377 makeKey(oid, key);
378 index = findValueInTable(key, table, tableEntrySize, compare);
379 if (index == 0)
381 /* Not found in table. If it's less than the first entry, return
382 * the first index. Otherwise just return 0 and let the caller
383 * handle finding the successor.
385 if (compare(key, table->entries) < 0)
386 index = 1;
388 else
390 /* Skip any entries that match the same key. This enumeration will
391 * be incomplete, but it's what Windows appears to do if there are
392 * multiple entries with the same index in a table, and it avoids
393 * an infinite loop.
395 for (++index; index <= table->numEntries && compare(key,
396 &table->entries[tableEntrySize * index]) == 0; ++index)
399 HeapFree(GetProcessHeap(), 0, key);
401 return index;
404 /* Given an OID and a base OID that it must begin with, finds the item and
405 * element of the table whose value matches the instance from the OID.
406 * The OID is converted to a key with the function makeKey, and compared
407 * against entries in the table with the function compare.
408 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
409 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
410 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
411 * instance, or item 1, instance 1 if either is missing.
413 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
414 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
415 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
416 compareFunc compare, UINT *item, UINT *instance)
418 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
420 if (!table)
421 return SNMP_ERRORSTATUS_NOSUCHNAME;
423 switch (bPduType)
425 case SNMP_PDU_GETNEXT:
426 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
428 /* Return the first item and instance from the table */
429 *item = 1;
430 *instance = 1;
432 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
433 oid->idLength < base->idLength + instanceLen + 1)
435 /* Either the table or an item is specified, but the instance is
436 * not.
438 *instance = 1;
439 if (oid->idLength >= base->idLength + 1)
441 *item = oid->ids[base->idLength];
442 if (!*item)
443 *item = 1;
445 else
446 *item = 1;
448 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
449 oid->idLength == base->idLength + instanceLen + 1)
451 *item = oid->ids[base->idLength];
452 if (!*item)
454 *instance = 1;
455 *item = 1;
457 else
459 AsnObjectIdentifier instanceOid = { instanceLen,
460 oid->ids + base->idLength + 1 };
462 *instance = findNextOidInTable(&instanceOid, table,
463 tableEntrySize, makeKey, compare);
464 if (!*instance || *instance > table->numEntries)
465 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
468 else
469 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
470 break;
471 default:
472 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
473 oid->idLength == base->idLength + instanceLen + 1)
475 *item = oid->ids[base->idLength];
476 if (!*item)
477 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
478 else
480 AsnObjectIdentifier instanceOid = { instanceLen,
481 oid->ids + base->idLength + 1 };
483 *instance = findOidInTable(&instanceOid, table, tableEntrySize,
484 makeKey, compare);
485 if (!*instance)
486 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
489 else
490 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
492 return ret;
495 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
496 UINT item)
498 UINT id;
499 AsnObjectIdentifier oid;
500 INT ret;
502 SnmpUtilOidFree(dst);
503 ret = SnmpUtilOidCpy(dst, base);
504 if (ret)
506 oid.idLength = 1;
507 oid.ids = &id;
508 id = item;
509 ret = SnmpUtilOidAppend(dst, &oid);
511 return ret;
514 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
515 AsnObjectIdentifier *base, UINT item, DWORD addr)
517 UINT id;
518 BYTE *ptr;
519 AsnObjectIdentifier oid;
520 INT ret;
522 ret = setOidWithItem(dst, base, item);
523 if (ret)
525 oid.idLength = 1;
526 oid.ids = &id;
527 for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
528 ptr++)
530 id = *ptr;
531 ret = SnmpUtilOidAppend(dst, &oid);
534 return ret;
537 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
538 AsnObjectIdentifier *base, UINT item, UINT instance)
540 AsnObjectIdentifier oid;
541 INT ret;
543 ret = setOidWithItem(dst, base, item);
544 if (ret)
546 oid.idLength = 1;
547 oid.ids = &instance;
548 ret = SnmpUtilOidAppend(dst, &oid);
550 return ret;
553 static struct structToAsnValue mib2IfEntryMap[] = {
554 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
555 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyLengthPrecededString },
556 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
557 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
558 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
559 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyLengthPrecededString },
560 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
561 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
562 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
563 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
564 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
565 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
566 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
567 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
568 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
569 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
570 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
571 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
572 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
573 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
574 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
577 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
579 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
580 AsnInteger32 *pErrorStatus)
582 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
583 BOOL ret = TRUE;
585 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
586 pErrorStatus);
588 switch (bPduType)
590 case SNMP_PDU_GET:
591 case SNMP_PDU_GETNEXT:
592 if (!ifTable)
594 /* There is no interface present, so let the caller deal
595 * with finding the successor.
597 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
599 else
601 UINT tableIndex = 0, item = 0;
603 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
604 &entryOid, bPduType, &item, &tableIndex);
605 if (!*pErrorStatus)
607 assert(tableIndex);
608 assert(item);
609 if (tableIndex > ifTable->dwNumEntries)
610 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
611 else
613 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
614 DEFINE_SIZEOF(mib2IfEntryMap),
615 &ifTable->table[tableIndex - 1], item, bPduType,
616 pVarBind);
617 if (bPduType == SNMP_PDU_GETNEXT)
618 ret = setOidWithItemAndInteger(&pVarBind->name,
619 &entryOid, item, tableIndex);
623 break;
624 case SNMP_PDU_SET:
625 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
626 ret = FALSE;
627 break;
628 default:
629 FIXME("0x%02x: unsupported PDU type\n", bPduType);
630 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
632 return ret;
635 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
636 static MIB_IPSTATS ipStats;
638 static void mib2IpStatsInit(void)
640 GetIpStatistics(&ipStats);
643 static struct structToAsnValue mib2IpMap[] = {
644 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
645 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
646 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
647 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
648 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
649 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
650 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
651 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
652 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
653 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
654 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
655 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
656 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
657 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
658 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
659 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
660 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
661 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
662 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
663 { 0, NULL }, /* 20: not used, IP addr table */
664 { 0, NULL }, /* 21: not used, route table */
665 { 0, NULL }, /* 22: not used, net to media (ARP) table */
666 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
669 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
670 AsnInteger32 *pErrorStatus)
672 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
673 UINT item = 0;
674 BOOL ret = TRUE;
676 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
677 pErrorStatus);
679 switch (bPduType)
681 case SNMP_PDU_GET:
682 case SNMP_PDU_GETNEXT:
683 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
684 &item);
685 if (!*pErrorStatus)
687 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
688 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, bPduType, pVarBind);
689 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
690 ret = setOidWithItem(&pVarBind->name, &myOid, item);
692 break;
693 case SNMP_PDU_SET:
694 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
695 ret = FALSE;
696 break;
697 default:
698 FIXME("0x%02x: unsupported PDU type\n", bPduType);
699 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
701 return ret;
704 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
705 static PMIB_IPADDRTABLE ipAddrTable;
707 static struct structToAsnValue mib2IpAddrMap[] = {
708 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
709 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
710 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
711 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
712 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
715 static void mib2IpAddrInit(void)
717 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
719 if (ret == ERROR_INSUFFICIENT_BUFFER)
721 MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
722 if (table)
724 if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table;
725 else HeapFree(GetProcessHeap(), 0, table );
730 static void mib2IpAddrCleanup(void)
732 HeapFree(GetProcessHeap(), 0, ipAddrTable);
735 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
737 MIB_IPADDRROW *row = dst;
739 row->dwAddr = oidToIpAddr(oid);
742 static int compareIpAddrRow(const void *a, const void *b)
744 const MIB_IPADDRROW *key = a, *value = b;
746 return key->dwAddr - value->dwAddr;
749 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
750 AsnInteger32 *pErrorStatus)
752 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
753 UINT tableIndex = 0, item = 0;
754 BOOL ret = TRUE;
756 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
757 pErrorStatus);
759 switch (bPduType)
761 case SNMP_PDU_GET:
762 case SNMP_PDU_GETNEXT:
763 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
764 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
765 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
766 &tableIndex);
767 if (!*pErrorStatus)
769 assert(tableIndex);
770 assert(item);
771 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
772 DEFINE_SIZEOF(mib2IpAddrMap),
773 &ipAddrTable->table[tableIndex - 1], item, bPduType, pVarBind);
774 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
775 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
776 ipAddrTable->table[tableIndex - 1].dwAddr);
778 break;
779 case SNMP_PDU_SET:
780 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
781 ret = FALSE;
782 break;
783 default:
784 FIXME("0x%02x: unsupported PDU type\n", bPduType);
785 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
787 return ret;
790 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
791 static PMIB_IPFORWARDTABLE ipRouteTable;
793 static struct structToAsnValue mib2IpRouteMap[] = {
794 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
795 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
796 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
797 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
798 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
799 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
800 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
801 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
802 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
803 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
804 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
805 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
808 static void mib2IpRouteInit(void)
810 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
812 if (ret == ERROR_INSUFFICIENT_BUFFER)
814 MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
815 if (table)
817 if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table;
818 else HeapFree(GetProcessHeap(), 0, table );
823 static void mib2IpRouteCleanup(void)
825 HeapFree(GetProcessHeap(), 0, ipRouteTable);
828 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
830 MIB_IPFORWARDROW *row = dst;
832 row->dwForwardDest = oidToIpAddr(oid);
835 static int compareIpForwardRow(const void *a, const void *b)
837 const MIB_IPFORWARDROW *key = a, *value = b;
839 return key->dwForwardDest - value->dwForwardDest;
842 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
843 AsnInteger32 *pErrorStatus)
845 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
846 UINT tableIndex = 0, item = 0;
847 BOOL ret = TRUE;
849 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
850 pErrorStatus);
852 switch (bPduType)
854 case SNMP_PDU_GET:
855 case SNMP_PDU_GETNEXT:
856 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
857 &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable,
858 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
859 &item, &tableIndex);
860 if (!*pErrorStatus)
862 assert(tableIndex);
863 assert(item);
864 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
865 DEFINE_SIZEOF(mib2IpRouteMap),
866 &ipRouteTable->table[tableIndex - 1], item, bPduType, pVarBind);
867 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
868 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
869 ipRouteTable->table[tableIndex - 1].dwForwardDest);
871 break;
872 case SNMP_PDU_SET:
873 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
874 ret = FALSE;
875 break;
876 default:
877 FIXME("0x%02x: unsupported PDU type\n", bPduType);
878 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
880 return ret;
883 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
884 static PMIB_IPNETTABLE ipNetTable;
886 static struct structToAsnValue mib2IpNetMap[] = {
887 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
888 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyLengthPrecededString },
889 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
890 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
893 static void mib2IpNetInit(void)
895 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
897 if (ret == ERROR_INSUFFICIENT_BUFFER)
899 MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
900 if (table)
902 if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table;
903 else HeapFree(GetProcessHeap(), 0, table );
908 static void mib2IpNetCleanup(void)
910 HeapFree(GetProcessHeap(), 0, ipNetTable);
913 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
914 AsnInteger32 *pErrorStatus)
916 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
917 BOOL ret = TRUE;
919 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
920 pErrorStatus);
922 switch (bPduType)
924 case SNMP_PDU_GET:
925 case SNMP_PDU_GETNEXT:
926 if (!ipNetTable)
927 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
928 else
930 UINT tableIndex = 0, item = 0;
932 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
933 &myOid, bPduType, &item, &tableIndex);
934 if (!*pErrorStatus)
936 assert(tableIndex);
937 assert(item);
938 if (tableIndex > ipNetTable->dwNumEntries)
939 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
940 else
942 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
943 DEFINE_SIZEOF(mib2IpNetMap),
944 &ipNetTable[tableIndex - 1], item, bPduType, pVarBind);
945 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
946 ret = setOidWithItemAndInteger(&pVarBind->name, &myOid,
947 item, tableIndex);
951 break;
952 case SNMP_PDU_SET:
953 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
954 ret = FALSE;
955 break;
956 default:
957 FIXME("0x%02x: unsupported PDU type\n", bPduType);
958 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
960 return ret;
963 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
964 static MIB_ICMP icmpStats;
966 static void mib2IcmpInit(void)
968 GetIcmpStatistics(&icmpStats);
971 static struct structToAsnValue mib2IcmpMap[] = {
972 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
973 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
974 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
975 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
976 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
977 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
978 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
979 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
980 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
981 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
982 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
983 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
984 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
985 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
986 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
987 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
988 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
989 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
990 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
991 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
992 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
993 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
994 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
995 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
996 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
997 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
1000 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1001 AsnInteger32 *pErrorStatus)
1003 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
1004 UINT item = 0;
1005 BOOL ret = TRUE;
1007 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1008 pErrorStatus);
1010 switch (bPduType)
1012 case SNMP_PDU_GET:
1013 case SNMP_PDU_GETNEXT:
1014 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1015 &item);
1016 if (!*pErrorStatus)
1018 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
1019 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item, bPduType,
1020 pVarBind);
1021 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1022 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1024 break;
1025 case SNMP_PDU_SET:
1026 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1027 ret = FALSE;
1028 break;
1029 default:
1030 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1031 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1033 return ret;
1036 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
1037 static MIB_TCPSTATS tcpStats;
1039 static void mib2TcpInit(void)
1041 GetTcpStatistics(&tcpStats);
1044 static struct structToAsnValue mib2TcpMap[] = {
1045 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
1046 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
1047 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
1048 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
1049 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
1050 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
1051 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
1052 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
1053 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
1054 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
1055 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
1056 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
1057 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
1058 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
1059 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
1062 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1063 AsnInteger32 *pErrorStatus)
1065 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
1066 UINT item = 0;
1067 BOOL ret = TRUE;
1069 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1070 pErrorStatus);
1072 switch (bPduType)
1074 case SNMP_PDU_GET:
1075 case SNMP_PDU_GETNEXT:
1076 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1077 &item);
1078 if (!*pErrorStatus)
1080 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
1081 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, bPduType, pVarBind);
1082 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1083 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1085 break;
1086 case SNMP_PDU_SET:
1087 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1088 ret = FALSE;
1089 break;
1090 default:
1091 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1092 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1094 return ret;
1097 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
1098 static MIB_UDPSTATS udpStats;
1100 static void mib2UdpInit(void)
1102 GetUdpStatistics(&udpStats);
1105 static struct structToAsnValue mib2UdpMap[] = {
1106 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1107 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1108 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1109 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1112 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1113 AsnInteger32 *pErrorStatus)
1115 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1116 UINT item;
1117 BOOL ret = TRUE;
1119 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1120 pErrorStatus);
1122 switch (bPduType)
1124 case SNMP_PDU_GET:
1125 case SNMP_PDU_GETNEXT:
1126 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1127 &item);
1128 if (!*pErrorStatus)
1130 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1131 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, bPduType, pVarBind);
1132 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1133 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1135 break;
1136 case SNMP_PDU_SET:
1137 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1138 ret = FALSE;
1139 break;
1140 default:
1141 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1142 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1144 return ret;
1147 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
1148 static PMIB_UDPTABLE udpTable;
1150 static void mib2UdpEntryInit(void)
1152 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
1154 if (ret == ERROR_INSUFFICIENT_BUFFER)
1156 MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
1157 if (table)
1159 if (!GetUdpTable(table, &size, TRUE)) udpTable = table;
1160 else HeapFree(GetProcessHeap(), 0, table);
1165 static void mib2UdpEntryCleanup(void)
1167 HeapFree(GetProcessHeap(), 0, udpTable);
1170 static struct structToAsnValue mib2UdpEntryMap[] = {
1171 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
1172 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
1175 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
1177 MIB_UDPROW *row = dst;
1179 assert(oid && oid->idLength >= 5);
1180 row->dwLocalAddr = oidToIpAddr(oid);
1181 row->dwLocalPort = oid->ids[4];
1184 static int compareUdpRow(const void *a, const void *b)
1186 const MIB_UDPROW *key = a, *value = b;
1187 int ret;
1189 ret = key->dwLocalAddr - value->dwLocalAddr;
1190 if (ret == 0)
1191 ret = key->dwLocalPort - value->dwLocalPort;
1192 return ret;
1195 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1196 AsnInteger32 *pErrorStatus)
1198 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
1199 BOOL ret = TRUE;
1201 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1202 pErrorStatus);
1204 switch (bPduType)
1206 case SNMP_PDU_GET:
1207 case SNMP_PDU_GETNEXT:
1208 if (!udpTable)
1209 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1210 else
1212 UINT tableIndex = 0, item = 0;
1214 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
1215 5, bPduType, (struct GenericTable *)udpTable,
1216 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
1217 &tableIndex);
1218 if (!*pErrorStatus)
1220 assert(tableIndex);
1221 assert(item);
1222 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
1223 DEFINE_SIZEOF(mib2UdpEntryMap),
1224 &udpTable->table[tableIndex - 1], item, bPduType, pVarBind);
1225 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1227 AsnObjectIdentifier oid;
1229 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
1230 udpTable->table[tableIndex - 1].dwLocalAddr);
1231 if (ret)
1233 oid.idLength = 1;
1234 oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
1235 ret = SnmpUtilOidAppend(&pVarBind->name, &oid);
1240 break;
1241 case SNMP_PDU_SET:
1242 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1243 ret = FALSE;
1244 break;
1245 default:
1246 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1247 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1249 return ret;
1252 /* This list MUST BE lexicographically sorted */
1253 static struct mibImplementation supportedIDs[] = {
1254 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
1255 mib2IfNumberCleanup },
1256 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
1257 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
1258 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
1259 mib2IpAddrCleanup },
1260 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
1261 mib2IpRouteCleanup },
1262 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
1263 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
1264 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
1265 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
1266 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
1267 mib2UdpEntryCleanup },
1269 static UINT minSupportedIDLength;
1271 /*****************************************************************************
1272 * SnmpExtensionInit [INETMIB1.@]
1274 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1275 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1277 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1278 UINT i;
1280 TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1281 pFirstSupportedRegion);
1283 minSupportedIDLength = UINT_MAX;
1284 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1286 if (supportedIDs[i].init)
1287 supportedIDs[i].init();
1288 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1289 minSupportedIDLength = supportedIDs[i].name.idLength;
1291 *phSubagentTrapEvent = NULL;
1292 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1293 return TRUE;
1296 static void cleanup(void)
1298 UINT i;
1300 for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
1301 if (supportedIDs[i].cleanup)
1302 supportedIDs[i].cleanup();
1305 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1306 UINT *matchingIndex)
1308 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0, i;
1309 struct mibImplementation *impl = NULL;
1310 AsnObjectIdentifier oid1 = { idLength, ids};
1312 if (!idLength)
1313 return NULL;
1314 for (i = (indexLow + indexHigh) / 2; !impl && indexLow <= indexHigh;
1315 i = (indexLow + indexHigh) / 2)
1317 INT cmp;
1319 cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength);
1320 if (!cmp)
1322 impl = &supportedIDs[i];
1323 *matchingIndex = i;
1325 else if (cmp > 0)
1326 indexLow = i + 1;
1327 else
1328 indexHigh = i - 1;
1330 return impl;
1333 /*****************************************************************************
1334 * SnmpExtensionQuery [INETMIB1.@]
1336 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1337 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1339 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1340 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1341 UINT i;
1342 BOOL ret = TRUE;
1344 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1345 pErrorStatus, pErrorIndex);
1347 for (i = 0; !error && i < pVarBindList->len; i++)
1349 /* Ignore any OIDs not in MIB2 */
1350 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1351 mib2oid.idLength))
1353 struct mibImplementation *impl = NULL;
1354 UINT len, matchingIndex = 0;
1356 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1357 /* Search for an implementation matching as many octets as possible
1359 for (len = pVarBindList->list[i].name.idLength;
1360 len >= minSupportedIDLength && !impl; len--)
1361 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1362 &matchingIndex);
1363 if (impl && impl->query)
1364 ret = impl->query(bPduType, &pVarBindList->list[i], &error);
1365 else
1366 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1367 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1368 bPduType == SNMP_PDU_GETNEXT)
1370 /* GetNext is special: it finds the successor to the given OID,
1371 * so we have to continue until an implementation handles the
1372 * query or we exhaust the table of supported OIDs.
1374 for (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1375 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1376 matchingIndex++)
1378 error = SNMP_ERRORSTATUS_NOERROR;
1379 impl = &supportedIDs[matchingIndex];
1380 if (impl->query)
1381 ret = impl->query(bPduType, &pVarBindList->list[i],
1382 &error);
1383 else
1384 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1386 /* If the query still isn't resolved, set the OID to the
1387 * successor to the last entry in the table.
1389 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1391 SnmpUtilOidFree(&pVarBindList->list[i].name);
1392 ret = SnmpUtilOidCpy(&pVarBindList->list[i].name,
1393 &supportedIDs[matchingIndex - 1].name);
1394 pVarBindList->list[i].name.ids[
1395 pVarBindList->list[i].name.idLength - 1] += 1;
1398 if (error)
1399 errorIndex = i + 1;
1402 *pErrorStatus = error;
1403 *pErrorIndex = errorIndex;
1404 return ret;
1407 /*****************************************************************************
1408 * DllMain [INETMIB1.@]
1410 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1412 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
1414 switch (fdwReason)
1416 case DLL_PROCESS_ATTACH:
1417 DisableThreadLibraryCalls(hinstDLL);
1418 break;
1419 case DLL_PROCESS_DETACH:
1420 cleanup();
1421 break;
1422 default:
1423 break;
1426 return TRUE;