cmd: DIR command outputs free space for the path.
[wine.git] / dlls / inetmib1 / main.c
blob6a662c2f72a79b802cf5426f9ddde029aa60376f
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 <assert.h>
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <limits.h>
24 #include "windef.h"
25 #include "winbase.h"
26 #include "winsock2.h"
27 #include "snmp.h"
28 #include "iphlpapi.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
33 /**
34 * Utility functions
36 static DWORD copyInt(AsnAny *value, void *src)
38 value->asnType = ASN_INTEGER;
39 value->asnValue.number = *(DWORD *)src;
40 return SNMP_ERRORSTATUS_NOERROR;
43 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
45 AsnAny strValue;
47 strValue.asnType = type;
48 strValue.asnValue.string.stream = str;
49 strValue.asnValue.string.length = len;
50 strValue.asnValue.string.dynamic = FALSE;
51 SnmpUtilAsnAnyCpy(value, &strValue);
54 typedef DWORD (*copyValueFunc)(AsnAny *value, void *src);
56 struct structToAsnValue
58 size_t offset;
59 copyValueFunc copy;
62 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
63 UINT mapLen, void *record, UINT id, SnmpVarBind *pVarBind)
65 /* OIDs are 1-based */
66 if (!id)
67 return SNMP_ERRORSTATUS_NOSUCHNAME;
68 --id;
69 if (id >= mapLen)
70 return SNMP_ERRORSTATUS_NOSUCHNAME;
71 if (!map[id].copy)
72 return SNMP_ERRORSTATUS_NOSUCHNAME;
73 return map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
76 static DWORD copyIpAddr(AsnAny *value, void *src)
78 setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
79 return SNMP_ERRORSTATUS_NOERROR;
82 static UINT mib2[] = { 1,3,6,1,2,1 };
83 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
85 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
86 AsnInteger32 *pErrorStatus);
88 struct mibImplementation
90 AsnObjectIdentifier name;
91 void (*init)(void);
92 varqueryfunc query;
93 void (*cleanup)(void);
96 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
97 static PMIB_IFTABLE ifTable;
99 static void mib2IfNumberInit(void)
101 DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
103 if (ret == ERROR_INSUFFICIENT_BUFFER)
105 MIB_IFTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
106 if (table)
108 if (!GetIfTable(table, &size, FALSE)) ifTable = table;
109 else HeapFree(GetProcessHeap(), 0, table );
114 static void mib2IfNumberCleanup(void)
116 HeapFree(GetProcessHeap(), 0, ifTable);
119 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
120 AsnInteger32 *pErrorStatus)
122 AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
123 BOOL ret = TRUE;
125 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
126 pErrorStatus);
128 switch (bPduType)
130 case SNMP_PDU_GET:
131 case SNMP_PDU_GETNEXT:
132 if ((bPduType == SNMP_PDU_GET &&
133 !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
134 || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
135 < 0)
137 DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
139 copyInt(&pVarBind->value, &numIfs);
140 if (bPduType == SNMP_PDU_GETNEXT)
142 SnmpUtilOidFree(&pVarBind->name);
143 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
145 *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
147 else
149 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
150 /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
151 * need to set it here.
154 break;
155 case SNMP_PDU_SET:
156 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
157 ret = FALSE;
158 break;
159 default:
160 FIXME("0x%02x: unsupported PDU type\n", bPduType);
161 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
163 return ret;
166 static DWORD copyOperStatus(AsnAny *value, void *src)
168 value->asnType = ASN_INTEGER;
169 /* The IPHlpApi definition of operational status differs from the MIB2 one,
170 * so map it to the MIB2 value.
172 switch (*(DWORD *)src)
174 case MIB_IF_OPER_STATUS_OPERATIONAL:
175 value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
176 break;
177 case MIB_IF_OPER_STATUS_CONNECTING:
178 case MIB_IF_OPER_STATUS_CONNECTED:
179 value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
180 break;
181 default:
182 value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
184 return SNMP_ERRORSTATUS_NOERROR;
187 /* Given an OID and a base OID that it must begin with, finds the item and
188 * integer instance from the OID. E.g., given an OID foo.1.2 and a base OID
189 * foo, returns item 1 and instance 2.
190 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
191 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
192 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
193 * instance, or item 1, instance 1 if either is missing.
195 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
196 AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
198 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
200 switch (bPduType)
202 case SNMP_PDU_GETNEXT:
203 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
205 *item = 1;
206 *instance = 1;
208 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
210 if (oid->idLength == base->idLength ||
211 oid->idLength == base->idLength + 1)
213 /* Either the table or an item within the table is specified,
214 * but the instance is not. Get the first instance.
216 *instance = 1;
217 if (oid->idLength == base->idLength + 1)
218 *item = oid->ids[base->idLength];
219 else
220 *item = 1;
222 else
224 *item = oid->ids[base->idLength];
225 *instance = oid->ids[base->idLength + 1] + 1;
228 else
229 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
230 break;
231 default:
232 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
234 if (oid->idLength == base->idLength ||
235 oid->idLength == base->idLength + 1)
237 /* Either the table or an item within the table is specified,
238 * but the instance is not.
240 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
242 else
244 *item = oid->ids[base->idLength];
245 *instance = oid->ids[base->idLength + 1];
248 else
249 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
251 return ret;
254 /* Given an OID and a base OID that it must begin with, finds the item from the
255 * OID. E.g., given an OID foo.1 and a base OID foo, returns item 1.
256 * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
257 * SNMP_ERRORSTATUS_NOSUCHNAME.
258 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
259 * 1 if the item is missing.
261 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
262 AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
264 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
266 switch (bPduType)
268 case SNMP_PDU_GETNEXT:
269 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
270 *item = 1;
271 else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
273 if (oid->idLength == base->idLength)
275 /* The item is missing, assume the first item */
276 *item = 1;
278 else
279 *item = oid->ids[base->idLength] + 1;
281 else
282 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
283 break;
284 default:
285 if (!SnmpUtilOidNCmp(oid, base, base->idLength))
287 if (oid->idLength == base->idLength)
289 /* The item is missing */
290 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
292 else
294 *item = oid->ids[base->idLength];
295 if (!*item)
296 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
299 else
300 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
302 return ret;
305 struct GenericTable
307 DWORD numEntries;
308 BYTE entries[1];
311 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
313 assert(oid && oid->idLength >= 4);
314 /* Map the IDs to an IP address in little-endian order */
315 return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
316 (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
319 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
320 typedef int (__cdecl *compareFunc)(const void *key, const void *value);
322 /* Finds the first value in the table that matches key. Returns its 1-based
323 * index if found, or 0 if not found.
325 static UINT findValueInTable(const void *key,
326 struct GenericTable *table, size_t tableEntrySize, compareFunc compare)
328 UINT index = 0;
329 void *value;
331 value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
332 compare);
333 if (value)
334 index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize + 1;
335 return index;
338 /* Finds the first value in the table that matches oid, using makeKey to
339 * convert the oid to a key for comparison. Returns the value's 1-based
340 * index if found, or 0 if not found.
342 static UINT findOidInTable(AsnObjectIdentifier *oid,
343 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
344 compareFunc compare)
346 UINT index = 0;
347 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
349 if (key)
351 makeKey(oid, key);
352 index = findValueInTable(key, table, tableEntrySize, compare);
353 HeapFree(GetProcessHeap(), 0, key);
355 return index;
358 /* Finds the first successor to the value in the table that does matches oid,
359 * using makeKey to convert the oid to a key for comparison. A successor is
360 * a value that does not match oid, so if multiple entries match an oid, only
361 * the first will ever be returned using this method.
362 * Returns the successor's 1-based index if found, or 0 if not found.
364 static UINT findNextOidInTable(AsnObjectIdentifier *oid,
365 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
366 compareFunc compare)
368 UINT index = 0;
369 void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
371 if (key)
373 makeKey(oid, key);
374 index = findValueInTable(key, table, tableEntrySize, compare);
375 if (index == 0)
377 /* Not found in table. If it's less than the first entry, return
378 * the first index. Otherwise just return 0 and let the caller
379 * handle finding the successor.
381 if (compare(key, table->entries) < 0)
382 index = 1;
384 else
386 /* Skip any entries that match the same key. This enumeration will
387 * be incomplete, but it's what Windows appears to do if there are
388 * multiple entries with the same index in a table, and it avoids
389 * an infinite loop.
391 for (++index; index <= table->numEntries && compare(key,
392 &table->entries[tableEntrySize * (index - 1)]) == 0; ++index)
395 HeapFree(GetProcessHeap(), 0, key);
397 return index;
400 /* Given an OID and a base OID that it must begin with, finds the item and
401 * element of the table whose value matches the instance from the OID.
402 * The OID is converted to a key with the function makeKey, and compared
403 * against entries in the table with the function compare.
404 * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
405 * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
406 * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
407 * instance, or item 1, instance 1 if either is missing.
409 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
410 AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
411 struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
412 compareFunc compare, UINT *item, UINT *instance)
414 AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
416 if (!table)
417 return SNMP_ERRORSTATUS_NOSUCHNAME;
419 switch (bPduType)
421 case SNMP_PDU_GETNEXT:
422 if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
424 /* Return the first item and instance from the table */
425 *item = 1;
426 *instance = 1;
428 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
429 oid->idLength < base->idLength + instanceLen + 1)
431 /* Either the table or an item is specified, but the instance is
432 * not.
434 *instance = 1;
435 if (oid->idLength >= base->idLength + 1)
437 *item = oid->ids[base->idLength];
438 if (!*item)
439 *item = 1;
441 else
442 *item = 1;
444 else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
445 oid->idLength == base->idLength + instanceLen + 1)
447 *item = oid->ids[base->idLength];
448 if (!*item)
450 *instance = 1;
451 *item = 1;
453 else
455 AsnObjectIdentifier instanceOid = { instanceLen,
456 oid->ids + base->idLength + 1 };
458 *instance = findNextOidInTable(&instanceOid, table,
459 tableEntrySize, makeKey, compare);
460 if (!*instance || *instance > table->numEntries)
461 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
464 else
465 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
466 break;
467 default:
468 if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
469 oid->idLength == base->idLength + instanceLen + 1)
471 *item = oid->ids[base->idLength];
472 if (!*item)
473 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
474 else
476 AsnObjectIdentifier instanceOid = { instanceLen,
477 oid->ids + base->idLength + 1 };
479 *instance = findOidInTable(&instanceOid, table, tableEntrySize,
480 makeKey, compare);
481 if (!*instance)
482 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
485 else
486 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
488 return ret;
491 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
492 UINT item)
494 UINT id;
495 AsnObjectIdentifier oid;
496 INT ret;
498 SnmpUtilOidFree(dst);
499 ret = SnmpUtilOidCpy(dst, base);
500 if (ret)
502 oid.idLength = 1;
503 oid.ids = &id;
504 id = item;
505 ret = SnmpUtilOidAppend(dst, &oid);
507 return ret;
510 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
511 AsnObjectIdentifier *base, UINT item, DWORD addr)
513 UINT id;
514 BYTE *ptr;
515 AsnObjectIdentifier oid;
516 INT ret;
518 ret = setOidWithItem(dst, base, item);
519 if (ret)
521 oid.idLength = 1;
522 oid.ids = &id;
523 for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
524 ptr++)
526 id = *ptr;
527 ret = SnmpUtilOidAppend(dst, &oid);
530 return ret;
533 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
534 AsnObjectIdentifier *base, UINT item, UINT instance)
536 AsnObjectIdentifier oid;
537 INT ret;
539 ret = setOidWithItem(dst, base, item);
540 if (ret)
542 oid.idLength = 1;
543 oid.ids = &instance;
544 ret = SnmpUtilOidAppend(dst, &oid);
546 return ret;
549 static DWORD copyIfRowDescr(AsnAny *value, void *src)
551 PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src -
552 FIELD_OFFSET(MIB_IFROW, dwDescrLen));
553 DWORD ret;
555 if (row->dwDescrLen)
557 setStringValue(value, ASN_OCTETSTRING, row->dwDescrLen, row->bDescr);
558 ret = SNMP_ERRORSTATUS_NOERROR;
560 else
561 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
562 return ret;
565 static DWORD copyIfRowPhysAddr(AsnAny *value, void *src)
567 PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src -
568 FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen));
569 DWORD ret;
571 if (row->dwPhysAddrLen)
573 setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen,
574 row->bPhysAddr);
575 ret = SNMP_ERRORSTATUS_NOERROR;
577 else
578 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
579 return ret;
582 static struct structToAsnValue mib2IfEntryMap[] = {
583 { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
584 { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyIfRowDescr },
585 { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
586 { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
587 { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
588 { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyIfRowPhysAddr },
589 { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
590 { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
591 { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
592 { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
593 { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
594 { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
595 { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
596 { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
597 { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
598 { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
599 { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
600 { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
601 { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
602 { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
603 { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
606 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
608 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
609 AsnInteger32 *pErrorStatus)
611 AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
612 BOOL ret = TRUE;
614 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
615 pErrorStatus);
617 switch (bPduType)
619 case SNMP_PDU_GET:
620 case SNMP_PDU_GETNEXT:
621 if (!ifTable)
623 /* There is no interface present, so let the caller deal
624 * with finding the successor.
626 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
628 else
630 UINT tableIndex = 0, item = 0;
632 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
633 &entryOid, bPduType, &item, &tableIndex);
634 if (!*pErrorStatus)
636 assert(tableIndex);
637 assert(item);
638 if (tableIndex > ifTable->dwNumEntries)
639 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
640 else
642 *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
643 DEFINE_SIZEOF(mib2IfEntryMap),
644 &ifTable->table[tableIndex - 1], item,
645 pVarBind);
646 if (bPduType == SNMP_PDU_GETNEXT)
647 ret = setOidWithItemAndInteger(&pVarBind->name,
648 &entryOid, item, tableIndex);
652 break;
653 case SNMP_PDU_SET:
654 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
655 ret = FALSE;
656 break;
657 default:
658 FIXME("0x%02x: unsupported PDU type\n", bPduType);
659 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
661 return ret;
664 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
665 static MIB_IPSTATS ipStats;
667 static void mib2IpStatsInit(void)
669 GetIpStatistics(&ipStats);
672 static struct structToAsnValue mib2IpMap[] = {
673 { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
674 { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
675 { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
676 { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
677 { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
678 { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
679 { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
680 { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
681 { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
682 { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
683 { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
684 { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
685 { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
686 { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
687 { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
688 { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
689 { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
690 { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
691 { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
692 { 0, NULL }, /* 20: not used, IP addr table */
693 { 0, NULL }, /* 21: not used, route table */
694 { 0, NULL }, /* 22: not used, net to media (ARP) table */
695 { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
698 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
699 AsnInteger32 *pErrorStatus)
701 AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
702 UINT item = 0;
703 BOOL ret = TRUE;
705 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
706 pErrorStatus);
708 switch (bPduType)
710 case SNMP_PDU_GET:
711 case SNMP_PDU_GETNEXT:
712 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
713 &item);
714 if (!*pErrorStatus)
716 *pErrorStatus = mapStructEntryToValue(mib2IpMap,
717 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, pVarBind);
718 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
719 ret = setOidWithItem(&pVarBind->name, &myOid, item);
721 break;
722 case SNMP_PDU_SET:
723 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
724 ret = FALSE;
725 break;
726 default:
727 FIXME("0x%02x: unsupported PDU type\n", bPduType);
728 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
730 return ret;
733 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
734 static PMIB_IPADDRTABLE ipAddrTable;
736 static struct structToAsnValue mib2IpAddrMap[] = {
737 { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
738 { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
739 { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
740 { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
741 { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
744 static void mib2IpAddrInit(void)
746 DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
748 if (ret == ERROR_INSUFFICIENT_BUFFER)
750 MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
751 if (table)
753 if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table;
754 else HeapFree(GetProcessHeap(), 0, table );
759 static void mib2IpAddrCleanup(void)
761 HeapFree(GetProcessHeap(), 0, ipAddrTable);
764 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
766 MIB_IPADDRROW *row = dst;
768 row->dwAddr = oidToIpAddr(oid);
771 static int __cdecl DWORD_cmp(DWORD a, DWORD b)
773 return a < b ? -1 : a > b ? 1 : 0; /* a subtraction would overflow */
776 static int __cdecl compareIpAddrRow(const void *a, const void *b)
778 const MIB_IPADDRROW *rowA = a, *rowB = b;
779 return DWORD_cmp(ntohl(rowA->dwAddr), ntohl(rowB->dwAddr));
782 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
783 AsnInteger32 *pErrorStatus)
785 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
786 UINT tableIndex = 0, item = 0;
787 BOOL ret = TRUE;
789 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
790 pErrorStatus);
792 switch (bPduType)
794 case SNMP_PDU_GET:
795 case SNMP_PDU_GETNEXT:
796 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
797 &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
798 sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
799 &tableIndex);
800 if (!*pErrorStatus)
802 assert(tableIndex);
803 assert(item);
804 *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
805 DEFINE_SIZEOF(mib2IpAddrMap),
806 &ipAddrTable->table[tableIndex - 1], item, pVarBind);
807 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
808 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
809 ipAddrTable->table[tableIndex - 1].dwAddr);
811 break;
812 case SNMP_PDU_SET:
813 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
814 ret = FALSE;
815 break;
816 default:
817 FIXME("0x%02x: unsupported PDU type\n", bPduType);
818 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
820 return ret;
823 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
824 static PMIB_IPFORWARDTABLE ipRouteTable;
826 static struct structToAsnValue mib2IpRouteMap[] = {
827 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
828 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
829 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
830 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
831 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
832 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
833 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
834 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
835 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
836 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
837 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
838 { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
841 static void mib2IpRouteInit(void)
843 DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
845 if (ret == ERROR_INSUFFICIENT_BUFFER)
847 MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
848 if (table)
850 if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table;
851 else HeapFree(GetProcessHeap(), 0, table );
856 static void mib2IpRouteCleanup(void)
858 HeapFree(GetProcessHeap(), 0, ipRouteTable);
861 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
863 MIB_IPFORWARDROW *row = dst;
865 row->dwForwardDest = oidToIpAddr(oid);
868 static int __cdecl compareIpForwardRow(const void *a, const void *b)
870 const MIB_IPFORWARDROW *rowA = a, *rowB = b;
871 return DWORD_cmp(ntohl(rowA->dwForwardDest), ntohl(rowB->dwForwardDest));
874 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
875 AsnInteger32 *pErrorStatus)
877 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
878 UINT tableIndex = 0, item = 0;
879 BOOL ret = TRUE;
881 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
882 pErrorStatus);
884 switch (bPduType)
886 case SNMP_PDU_GET:
887 case SNMP_PDU_GETNEXT:
888 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
889 &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable,
890 sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
891 &item, &tableIndex);
892 if (!*pErrorStatus)
894 assert(tableIndex);
895 assert(item);
896 *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
897 DEFINE_SIZEOF(mib2IpRouteMap),
898 &ipRouteTable->table[tableIndex - 1], item, pVarBind);
899 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
900 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
901 ipRouteTable->table[tableIndex - 1].dwForwardDest);
903 break;
904 case SNMP_PDU_SET:
905 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
906 ret = FALSE;
907 break;
908 default:
909 FIXME("0x%02x: unsupported PDU type\n", bPduType);
910 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
912 return ret;
915 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
916 static PMIB_IPNETTABLE ipNetTable;
918 static DWORD copyIpNetPhysAddr(AsnAny *value, void *src)
920 PMIB_IPNETROW row = (PMIB_IPNETROW)((BYTE *)src - FIELD_OFFSET(MIB_IPNETROW,
921 dwPhysAddrLen));
923 setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen, row->bPhysAddr);
924 return SNMP_ERRORSTATUS_NOERROR;
927 static struct structToAsnValue mib2IpNetMap[] = {
928 { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
929 { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyIpNetPhysAddr },
930 { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
931 { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
934 static void mib2IpNetInit(void)
936 DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
938 if (ret == ERROR_INSUFFICIENT_BUFFER)
940 MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
941 if (table)
943 if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table;
944 else HeapFree(GetProcessHeap(), 0, table );
949 static void mib2IpNetCleanup(void)
951 HeapFree(GetProcessHeap(), 0, ipNetTable);
954 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
955 AsnInteger32 *pErrorStatus)
957 AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
958 BOOL ret = TRUE;
960 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
961 pErrorStatus);
963 switch (bPduType)
965 case SNMP_PDU_GET:
966 case SNMP_PDU_GETNEXT:
967 if (!ipNetTable)
968 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
969 else
971 UINT tableIndex = 0, item = 0;
973 *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
974 &myOid, bPduType, &item, &tableIndex);
975 if (!*pErrorStatus)
977 assert(tableIndex);
978 assert(item);
979 if (tableIndex > ipNetTable->dwNumEntries)
980 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
981 else
983 *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
984 DEFINE_SIZEOF(mib2IpNetMap),
985 &ipNetTable[tableIndex - 1], item, pVarBind);
986 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
987 ret = setOidWithItemAndInteger(&pVarBind->name, &myOid,
988 item, tableIndex);
992 break;
993 case SNMP_PDU_SET:
994 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
995 ret = FALSE;
996 break;
997 default:
998 FIXME("0x%02x: unsupported PDU type\n", bPduType);
999 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1001 return ret;
1004 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
1005 static MIB_ICMP icmpStats;
1007 static void mib2IcmpInit(void)
1009 GetIcmpStatistics(&icmpStats);
1012 static struct structToAsnValue mib2IcmpMap[] = {
1013 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
1014 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
1015 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
1016 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
1017 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
1018 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
1019 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
1020 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
1021 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
1022 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
1023 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
1024 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
1025 { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
1026 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
1027 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
1028 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
1029 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
1030 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
1031 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
1032 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
1033 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
1034 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
1035 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
1036 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
1037 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
1038 { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
1041 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1042 AsnInteger32 *pErrorStatus)
1044 AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
1045 UINT item = 0;
1046 BOOL ret = TRUE;
1048 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1049 pErrorStatus);
1051 switch (bPduType)
1053 case SNMP_PDU_GET:
1054 case SNMP_PDU_GETNEXT:
1055 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1056 &item);
1057 if (!*pErrorStatus)
1059 *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
1060 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item,
1061 pVarBind);
1062 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1063 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1065 break;
1066 case SNMP_PDU_SET:
1067 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1068 ret = FALSE;
1069 break;
1070 default:
1071 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1072 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1074 return ret;
1077 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
1078 static MIB_TCPSTATS tcpStats;
1080 static void mib2TcpInit(void)
1082 GetTcpStatistics(&tcpStats);
1085 static struct structToAsnValue mib2TcpMap[] = {
1086 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
1087 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
1088 { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
1089 { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
1090 { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
1091 { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
1092 { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
1093 { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
1094 { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
1095 { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
1096 { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
1097 { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
1098 { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
1099 { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
1100 { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
1103 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1104 AsnInteger32 *pErrorStatus)
1106 AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
1107 UINT item = 0;
1108 BOOL ret = TRUE;
1110 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1111 pErrorStatus);
1113 switch (bPduType)
1115 case SNMP_PDU_GET:
1116 case SNMP_PDU_GETNEXT:
1117 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1118 &item);
1119 if (!*pErrorStatus)
1121 *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
1122 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, pVarBind);
1123 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1124 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1126 break;
1127 case SNMP_PDU_SET:
1128 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1129 ret = FALSE;
1130 break;
1131 default:
1132 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1133 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1135 return ret;
1138 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
1139 static MIB_UDPSTATS udpStats;
1141 static void mib2UdpInit(void)
1143 GetUdpStatistics(&udpStats);
1146 static struct structToAsnValue mib2UdpMap[] = {
1147 { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
1148 { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
1149 { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
1150 { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
1153 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1154 AsnInteger32 *pErrorStatus)
1156 AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
1157 UINT item;
1158 BOOL ret = TRUE;
1160 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1161 pErrorStatus);
1163 switch (bPduType)
1165 case SNMP_PDU_GET:
1166 case SNMP_PDU_GETNEXT:
1167 *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
1168 &item);
1169 if (!*pErrorStatus)
1171 *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
1172 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, pVarBind);
1173 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1174 ret = setOidWithItem(&pVarBind->name, &myOid, item);
1176 break;
1177 case SNMP_PDU_SET:
1178 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1179 ret = FALSE;
1180 break;
1181 default:
1182 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1183 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1185 return ret;
1188 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
1189 static PMIB_UDPTABLE udpTable;
1191 static void mib2UdpEntryInit(void)
1193 DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
1195 if (ret == ERROR_INSUFFICIENT_BUFFER)
1197 MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
1198 if (table)
1200 if (!GetUdpTable(table, &size, TRUE)) udpTable = table;
1201 else HeapFree(GetProcessHeap(), 0, table);
1206 static void mib2UdpEntryCleanup(void)
1208 HeapFree(GetProcessHeap(), 0, udpTable);
1211 static struct structToAsnValue mib2UdpEntryMap[] = {
1212 { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
1213 { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
1216 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
1218 MIB_UDPROW *row = dst;
1220 assert(oid && oid->idLength >= 5);
1221 row->dwLocalAddr = oidToIpAddr(oid);
1222 row->dwLocalPort = htons(oid->ids[4]);
1225 static int __cdecl compareUdpRow(const void *a, const void *b)
1227 const MIB_UDPROW *rowA = a, *rowB = b;
1228 return DWORD_cmp(ntohl(rowA->dwLocalAddr), ntohl(rowB->dwLocalAddr)) ||
1229 ntohs(rowA->dwLocalPort) - ntohs(rowB->dwLocalPort);
1232 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
1233 AsnInteger32 *pErrorStatus)
1235 AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
1236 BOOL ret = TRUE;
1238 TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
1239 pErrorStatus);
1241 switch (bPduType)
1243 case SNMP_PDU_GET:
1244 case SNMP_PDU_GETNEXT:
1245 if (!udpTable)
1246 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1247 else
1249 UINT tableIndex = 0, item = 0;
1251 *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
1252 5, bPduType, (struct GenericTable *)udpTable,
1253 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
1254 &tableIndex);
1255 if (!*pErrorStatus)
1257 assert(tableIndex);
1258 assert(item);
1259 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
1260 DEFINE_SIZEOF(mib2UdpEntryMap),
1261 &udpTable->table[tableIndex - 1], item, pVarBind);
1262 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
1264 AsnObjectIdentifier oid;
1266 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
1267 udpTable->table[tableIndex - 1].dwLocalAddr);
1268 if (ret)
1270 UINT id = ntohs(udpTable->table[tableIndex - 1].dwLocalPort);
1271 oid.idLength = 1;
1272 oid.ids = &id;
1273 ret = SnmpUtilOidAppend(&pVarBind->name, &oid);
1278 break;
1279 case SNMP_PDU_SET:
1280 *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
1281 ret = FALSE;
1282 break;
1283 default:
1284 FIXME("0x%02x: unsupported PDU type\n", bPduType);
1285 *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
1287 return ret;
1290 /* This list MUST BE lexicographically sorted */
1291 static struct mibImplementation supportedIDs[] = {
1292 { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
1293 mib2IfNumberCleanup },
1294 { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
1295 { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
1296 { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
1297 mib2IpAddrCleanup },
1298 { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
1299 mib2IpRouteCleanup },
1300 { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
1301 { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
1302 { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
1303 { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
1304 { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
1305 mib2UdpEntryCleanup },
1307 static UINT minSupportedIDLength;
1309 /*****************************************************************************
1310 * SnmpExtensionInit [INETMIB1.@]
1312 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
1313 HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
1315 AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
1316 UINT i;
1318 TRACE("(%ld, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
1319 pFirstSupportedRegion);
1321 minSupportedIDLength = UINT_MAX;
1322 for (i = 0; i < ARRAY_SIZE(supportedIDs); i++)
1324 if (supportedIDs[i].init)
1325 supportedIDs[i].init();
1326 if (supportedIDs[i].name.idLength < minSupportedIDLength)
1327 minSupportedIDLength = supportedIDs[i].name.idLength;
1329 *phSubagentTrapEvent = NULL;
1330 SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
1331 return TRUE;
1334 static void cleanup(void)
1336 UINT i;
1338 for (i = 0; i < ARRAY_SIZE(supportedIDs); i++)
1339 if (supportedIDs[i].cleanup)
1340 supportedIDs[i].cleanup();
1343 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
1344 UINT *matchingIndex)
1346 int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0;
1347 AsnObjectIdentifier oid1 = { idLength, ids};
1349 if (!idLength)
1350 return NULL;
1352 while (indexLow <= indexHigh)
1354 INT cmp, i = (indexLow + indexHigh) / 2;
1355 if (!(cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength)))
1357 *matchingIndex = i;
1358 return &supportedIDs[i];
1360 if (cmp > 0)
1361 indexLow = i + 1;
1362 else
1363 indexHigh = i - 1;
1365 return NULL;
1368 /*****************************************************************************
1369 * SnmpExtensionQuery [INETMIB1.@]
1371 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
1372 AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
1374 AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
1375 AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
1376 UINT i;
1377 BOOL ret = TRUE;
1379 TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
1380 pErrorStatus, pErrorIndex);
1382 for (i = 0; !error && i < pVarBindList->len; i++)
1384 /* Ignore any OIDs not in MIB2 */
1385 if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
1386 mib2oid.idLength))
1388 struct mibImplementation *impl = NULL;
1389 UINT len, matchingIndex = 0;
1391 TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
1392 /* Search for an implementation matching as many octets as possible
1394 for (len = pVarBindList->list[i].name.idLength;
1395 len >= minSupportedIDLength && !impl; len--)
1396 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
1397 &matchingIndex);
1398 if (impl && impl->query)
1399 ret = impl->query(bPduType, &pVarBindList->list[i], &error);
1400 else
1401 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1402 if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1403 bPduType == SNMP_PDU_GETNEXT)
1405 /* GetNext is special: it finds the successor to the given OID,
1406 * so we have to continue until an implementation handles the
1407 * query or we exhaust the table of supported OIDs.
1409 for (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
1410 matchingIndex < DEFINE_SIZEOF(supportedIDs);
1411 matchingIndex++)
1413 error = SNMP_ERRORSTATUS_NOERROR;
1414 impl = &supportedIDs[matchingIndex];
1415 if (impl->query)
1416 ret = impl->query(bPduType, &pVarBindList->list[i],
1417 &error);
1418 else
1419 error = SNMP_ERRORSTATUS_NOSUCHNAME;
1421 /* If the query still isn't resolved, set the OID to the
1422 * successor to the last entry in the table.
1424 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
1426 SnmpUtilOidFree(&pVarBindList->list[i].name);
1427 ret = SnmpUtilOidCpy(&pVarBindList->list[i].name,
1428 &supportedIDs[matchingIndex - 1].name);
1429 pVarBindList->list[i].name.ids[
1430 pVarBindList->list[i].name.idLength - 1] += 1;
1433 if (error)
1434 errorIndex = i + 1;
1437 *pErrorStatus = error;
1438 *pErrorIndex = errorIndex;
1439 return ret;
1442 /*****************************************************************************
1443 * DllMain [INETMIB1.@]
1445 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
1447 TRACE("(0x%p, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
1449 switch (fdwReason)
1451 case DLL_PROCESS_ATTACH:
1452 DisableThreadLibraryCalls(hinstDLL);
1453 break;
1454 case DLL_PROCESS_DETACH:
1455 if (lpvReserved) break;
1456 cleanup();
1457 break;
1460 return TRUE;