ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

main.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 2008 Juan Lang
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00017  */
00018 
00019 #include "config.h"
00020 #include <assert.h>
00021 #include <stdarg.h>
00022 #include <stdlib.h>
00023 #include <limits.h>
00024 
00025 #define NONAMELESSUNION
00026 
00027 #include "windef.h"
00028 #include "winbase.h"
00029 #include "snmp.h"
00030 #include "iphlpapi.h"
00031 #include "wine/debug.h"
00032 
00033 WINE_DEFAULT_DEBUG_CHANNEL(inetmib1);
00034 
00038 static DWORD copyInt(AsnAny *value, void *src)
00039 {
00040     value->asnType = ASN_INTEGER;
00041     value->asnValue.number = *(DWORD *)src;
00042     return SNMP_ERRORSTATUS_NOERROR;
00043 }
00044 
00045 static void setStringValue(AsnAny *value, BYTE type, DWORD len, BYTE *str)
00046 {
00047     AsnAny strValue;
00048 
00049     strValue.asnType = type;
00050     strValue.asnValue.string.stream = str;
00051     strValue.asnValue.string.length = len;
00052     strValue.asnValue.string.dynamic = FALSE;
00053     SnmpUtilAsnAnyCpy(value, &strValue);
00054 }
00055 
00056 typedef DWORD (*copyValueFunc)(AsnAny *value, void *src);
00057 
00058 struct structToAsnValue
00059 {
00060     size_t        offset;
00061     copyValueFunc copy;
00062 };
00063 
00064 static AsnInteger32 mapStructEntryToValue(struct structToAsnValue *map,
00065     UINT mapLen, void *record, UINT id, SnmpVarBind *pVarBind)
00066 {
00067     /* OIDs are 1-based */
00068     if (!id)
00069         return SNMP_ERRORSTATUS_NOSUCHNAME;
00070     --id;
00071     if (id >= mapLen)
00072         return SNMP_ERRORSTATUS_NOSUCHNAME;
00073     if (!map[id].copy)
00074         return SNMP_ERRORSTATUS_NOSUCHNAME;
00075     return map[id].copy(&pVarBind->value, (BYTE *)record + map[id].offset);
00076 }
00077 
00078 static DWORD copyIpAddr(AsnAny *value, void *src)
00079 {
00080     setStringValue(value, ASN_IPADDRESS, sizeof(DWORD), src);
00081     return SNMP_ERRORSTATUS_NOERROR;
00082 }
00083 
00084 static UINT mib2[] = { 1,3,6,1,2,1 };
00085 static UINT mib2System[] = { 1,3,6,1,2,1,1 };
00086 
00087 typedef BOOL (*varqueryfunc)(BYTE bPduType, SnmpVarBind *pVarBind,
00088     AsnInteger32 *pErrorStatus);
00089 
00090 struct mibImplementation
00091 {
00092     AsnObjectIdentifier name;
00093     void              (*init)(void);
00094     varqueryfunc        query;
00095     void              (*cleanup)(void);
00096 };
00097 
00098 static UINT mib2IfNumber[] = { 1,3,6,1,2,1,2,1 };
00099 static PMIB_IFTABLE ifTable;
00100 
00101 static void mib2IfNumberInit(void)
00102 {
00103     DWORD size = 0, ret = GetIfTable(NULL, &size, FALSE);
00104 
00105     if (ret == ERROR_INSUFFICIENT_BUFFER)
00106     {
00107         MIB_IFTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
00108         if (table)
00109         {
00110             if (!GetIfTable(table, &size, FALSE)) ifTable = table;
00111             else HeapFree(GetProcessHeap(), 0, table );
00112         }
00113     }
00114 }
00115 
00116 static void mib2IfNumberCleanup(void)
00117 {
00118     HeapFree(GetProcessHeap(), 0, ifTable);
00119 }
00120 
00121 static BOOL mib2IfNumberQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00122     AsnInteger32 *pErrorStatus)
00123 {
00124     AsnObjectIdentifier numberOid = DEFINE_OID(mib2IfNumber);
00125     BOOL ret = TRUE;
00126 
00127     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00128         pErrorStatus);
00129 
00130     switch (bPduType)
00131     {
00132     case SNMP_PDU_GET:
00133     case SNMP_PDU_GETNEXT:
00134         if ((bPduType == SNMP_PDU_GET &&
00135             !SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength))
00136             || SnmpUtilOidNCmp(&pVarBind->name, &numberOid, numberOid.idLength)
00137             < 0)
00138         {
00139             DWORD numIfs = ifTable ? ifTable->dwNumEntries : 0;
00140 
00141             copyInt(&pVarBind->value, &numIfs);
00142             if (bPduType == SNMP_PDU_GETNEXT)
00143             {
00144                 SnmpUtilOidFree(&pVarBind->name);
00145                 SnmpUtilOidCpy(&pVarBind->name, &numberOid);
00146             }
00147             *pErrorStatus = SNMP_ERRORSTATUS_NOERROR;
00148         }
00149         else
00150         {
00151             *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00152             /* Caller deals with OID if bPduType == SNMP_PDU_GETNEXT, so don't
00153              * need to set it here.
00154              */
00155         }
00156         break;
00157     case SNMP_PDU_SET:
00158         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00159         ret = FALSE;
00160         break;
00161     default:
00162         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00163         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00164     }
00165     return ret;
00166 }
00167 
00168 static DWORD copyOperStatus(AsnAny *value, void *src)
00169 {
00170     value->asnType = ASN_INTEGER;
00171     /* The IPHlpApi definition of operational status differs from the MIB2 one,
00172      * so map it to the MIB2 value.
00173      */
00174     switch (*(DWORD *)src)
00175     {
00176     case MIB_IF_OPER_STATUS_OPERATIONAL:
00177         value->asnValue.number = MIB_IF_ADMIN_STATUS_UP;
00178         break;
00179     case MIB_IF_OPER_STATUS_CONNECTING:
00180     case MIB_IF_OPER_STATUS_CONNECTED:
00181         value->asnValue.number = MIB_IF_ADMIN_STATUS_TESTING;
00182         break;
00183     default:
00184         value->asnValue.number = MIB_IF_ADMIN_STATUS_DOWN;
00185     };
00186     return SNMP_ERRORSTATUS_NOERROR;
00187 }
00188 
00189 /* Given an OID and a base OID that it must begin with, finds the item and
00190  * integer instance from the OID.  E.g., given an OID foo.1.2 and a base OID
00191  * foo, returns item 1 and instance 2.
00192  * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
00193  * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
00194  * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
00195  * instance, or item 1, instance 1 if either is missing.
00196  */
00197 static AsnInteger32 getItemAndIntegerInstanceFromOid(AsnObjectIdentifier *oid,
00198     AsnObjectIdentifier *base, BYTE bPduType, UINT *item, UINT *instance)
00199 {
00200     AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
00201 
00202     switch (bPduType)
00203     {
00204     case SNMP_PDU_GETNEXT:
00205         if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
00206         {
00207             *item = 1;
00208             *instance = 1;
00209         }
00210         else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
00211         {
00212             if (oid->idLength == base->idLength ||
00213                 oid->idLength == base->idLength + 1)
00214             {
00215                 /* Either the table or an item within the table is specified,
00216                  * but the instance is not.  Get the first instance.
00217                  */
00218                 *instance = 1;
00219                 if (oid->idLength == base->idLength + 1)
00220                     *item = oid->ids[base->idLength];
00221                 else
00222                     *item = 1;
00223             }
00224             else
00225             {
00226                 *item = oid->ids[base->idLength];
00227                 *instance = oid->ids[base->idLength + 1] + 1;
00228             }
00229         }
00230         else
00231             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00232         break;
00233     default:
00234         if (!SnmpUtilOidNCmp(oid, base, base->idLength))
00235         {
00236             if (oid->idLength == base->idLength ||
00237                 oid->idLength == base->idLength + 1)
00238             {
00239                 /* Either the table or an item within the table is specified,
00240                  * but the instance is not.
00241                  */
00242                 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00243             }
00244             else
00245             {
00246                 *item = oid->ids[base->idLength];
00247                 *instance = oid->ids[base->idLength + 1];
00248             }
00249         }
00250         else
00251             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00252     }
00253     return ret;
00254 }
00255 
00256 /* Given an OID and a base OID that it must begin with, finds the item from the
00257  * OID.  E.g., given an OID foo.1 and a base OID foo, returns item 1.
00258  * If bPduType is not SNMP_PDU_GETNEXT and the item is missing, returns
00259  * SNMP_ERRORSTATUS_NOSUCHNAME.
00260  * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item, or item
00261  * 1 if the item is missing.
00262  */
00263 static AsnInteger32 getItemFromOid(AsnObjectIdentifier *oid,
00264     AsnObjectIdentifier *base, BYTE bPduType, UINT *item)
00265 {
00266     AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
00267 
00268     switch (bPduType)
00269     {
00270     case SNMP_PDU_GETNEXT:
00271         if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
00272             *item = 1;
00273         else if (!SnmpUtilOidNCmp(oid, base, base->idLength))
00274         {
00275             if (oid->idLength == base->idLength)
00276             {
00277                 /* The item is missing, assume the first item */
00278                 *item = 1;
00279             }
00280             else
00281                 *item = oid->ids[base->idLength] + 1;
00282         }
00283         else
00284             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00285         break;
00286     default:
00287         if (!SnmpUtilOidNCmp(oid, base, base->idLength))
00288         {
00289             if (oid->idLength == base->idLength)
00290             {
00291                 /* The item is missing */
00292                 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00293             }
00294             else
00295             {
00296                 *item = oid->ids[base->idLength];
00297                 if (!*item)
00298                     ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00299             }
00300         }
00301         else
00302             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00303     }
00304     return ret;
00305 }
00306 
00307 struct GenericTable
00308 {
00309     DWORD numEntries;
00310     BYTE  entries[1];
00311 };
00312 
00313 static DWORD oidToIpAddr(AsnObjectIdentifier *oid)
00314 {
00315     assert(oid && oid->idLength >= 4);
00316     /* Map the IDs to an IP address in little-endian order */
00317     return (BYTE)oid->ids[3] << 24 | (BYTE)oid->ids[2] << 16 |
00318         (BYTE)oid->ids[1] << 8 | (BYTE)oid->ids[0];
00319 }
00320 
00321 typedef void (*oidToKeyFunc)(AsnObjectIdentifier *oid, void *dst);
00322 typedef int (*compareFunc)(const void *key, const void *value);
00323 
00324 /* Finds the first value in the table that matches key.  Returns its 1-based
00325  * index if found, or 0 if not found.
00326  */
00327 static UINT findValueInTable(const void *key,
00328     struct GenericTable *table, size_t tableEntrySize, compareFunc compare)
00329 {
00330     UINT index = 0;
00331     void *value;
00332 
00333     value = bsearch(key, table->entries, table->numEntries, tableEntrySize,
00334         compare);
00335     if (value)
00336         index = ((BYTE *)value - (BYTE *)table->entries) / tableEntrySize + 1;
00337     return index;
00338 }
00339 
00340 /* Finds the first value in the table that matches oid, using makeKey to
00341  * convert the oid to a key for comparison.  Returns the value's 1-based
00342  * index if found, or 0 if not found.
00343  */
00344 static UINT findOidInTable(AsnObjectIdentifier *oid,
00345     struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
00346     compareFunc compare)
00347 {
00348     UINT index = 0;
00349     void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
00350 
00351     if (key)
00352     {
00353         makeKey(oid, key);
00354         index = findValueInTable(key, table, tableEntrySize, compare);
00355         HeapFree(GetProcessHeap(), 0, key);
00356     }
00357     return index;
00358 }
00359 
00360 /* Finds the first successor to the value in the table that does matches oid,
00361  * using makeKey to convert the oid to a key for comparison.  A successor is
00362  * a value that does not match oid, so if multiple entries match an oid, only
00363  * the first will ever be returned using this method.
00364  * Returns the successor's 1-based index if found, or 0 if not found.
00365  */
00366 static UINT findNextOidInTable(AsnObjectIdentifier *oid,
00367     struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
00368     compareFunc compare)
00369 {
00370     UINT index = 0;
00371     void *key = HeapAlloc(GetProcessHeap(), 0, tableEntrySize);
00372 
00373     if (key)
00374     {
00375         makeKey(oid, key);
00376         index = findValueInTable(key, table, tableEntrySize, compare);
00377         if (index == 0)
00378         {
00379             /* Not found in table.  If it's less than the first entry, return
00380              * the first index.  Otherwise just return 0 and let the caller
00381              * handle finding the successor.
00382              */
00383             if (compare(key, table->entries) < 0)
00384                 index = 1;
00385         }
00386         else
00387         {
00388             /* Skip any entries that match the same key.  This enumeration will
00389              * be incomplete, but it's what Windows appears to do if there are
00390              * multiple entries with the same index in a table, and it avoids
00391              * an infinite loop.
00392              */
00393             for (++index; index <= table->numEntries && compare(key,
00394                 &table->entries[tableEntrySize * (index - 1)]) == 0; ++index)
00395                 ;
00396         }
00397         HeapFree(GetProcessHeap(), 0, key);
00398     }
00399     return index;
00400 }
00401 
00402 /* Given an OID and a base OID that it must begin with, finds the item and
00403  * element of the table whose value matches the instance from the OID.
00404  * The OID is converted to a key with the function makeKey, and compared
00405  * against entries in the table with the function compare.
00406  * If bPduType is not SNMP_PDU_GETNEXT and either the item or instance is
00407  * missing, returns SNMP_ERRORSTATUS_NOSUCHNAME.
00408  * If bPduType is SNMP_PDU_GETNEXT, returns the successor to the item and
00409  * instance, or item 1, instance 1 if either is missing.
00410  */
00411 static AsnInteger32 getItemAndInstanceFromTable(AsnObjectIdentifier *oid,
00412     AsnObjectIdentifier *base, UINT instanceLen, BYTE bPduType,
00413     struct GenericTable *table, size_t tableEntrySize, oidToKeyFunc makeKey,
00414     compareFunc compare, UINT *item, UINT *instance)
00415 {
00416     AsnInteger32 ret = SNMP_ERRORSTATUS_NOERROR;
00417 
00418     if (!table)
00419         return SNMP_ERRORSTATUS_NOSUCHNAME;
00420 
00421     switch (bPduType)
00422     {
00423     case SNMP_PDU_GETNEXT:
00424         if (SnmpUtilOidNCmp(oid, base, base->idLength) < 0)
00425         {
00426             /* Return the first item and instance from the table */
00427             *item = 1;
00428             *instance = 1;
00429         }
00430         else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
00431             oid->idLength < base->idLength + instanceLen + 1)
00432         {
00433             /* Either the table or an item is specified, but the instance is
00434              * not.
00435              */
00436             *instance = 1;
00437             if (oid->idLength >= base->idLength + 1)
00438             {
00439                 *item = oid->ids[base->idLength];
00440                 if (!*item)
00441                     *item = 1;
00442             }
00443             else
00444                 *item = 1;
00445         }
00446         else if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
00447             oid->idLength == base->idLength + instanceLen + 1)
00448         {
00449             *item = oid->ids[base->idLength];
00450             if (!*item)
00451             {
00452                 *instance = 1;
00453                 *item = 1;
00454             }
00455             else
00456             {
00457                 AsnObjectIdentifier instanceOid = { instanceLen,
00458                     oid->ids + base->idLength + 1 };
00459 
00460                 *instance = findNextOidInTable(&instanceOid, table,
00461                     tableEntrySize, makeKey, compare);
00462                 if (!*instance || *instance > table->numEntries)
00463                     ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00464             }
00465         }
00466         else
00467             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00468         break;
00469     default:
00470         if (!SnmpUtilOidNCmp(oid, base, base->idLength) &&
00471             oid->idLength == base->idLength + instanceLen + 1)
00472         {
00473             *item = oid->ids[base->idLength];
00474             if (!*item)
00475                 ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00476             else
00477             {
00478                 AsnObjectIdentifier instanceOid = { instanceLen,
00479                     oid->ids + base->idLength + 1 };
00480 
00481                 *instance = findOidInTable(&instanceOid, table, tableEntrySize,
00482                     makeKey, compare);
00483                 if (!*instance)
00484                     ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00485             }
00486         }
00487         else
00488             ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00489     }
00490     return ret;
00491 }
00492 
00493 static INT setOidWithItem(AsnObjectIdentifier *dst, AsnObjectIdentifier *base,
00494     UINT item)
00495 {
00496     UINT id;
00497     AsnObjectIdentifier oid;
00498     INT ret;
00499 
00500     SnmpUtilOidFree(dst);
00501     ret = SnmpUtilOidCpy(dst, base);
00502     if (ret)
00503     {
00504         oid.idLength = 1;
00505         oid.ids = &id;
00506         id = item;
00507         ret = SnmpUtilOidAppend(dst, &oid);
00508     }
00509     return ret;
00510 }
00511 
00512 static INT setOidWithItemAndIpAddr(AsnObjectIdentifier *dst,
00513     AsnObjectIdentifier *base, UINT item, DWORD addr)
00514 {
00515     UINT id;
00516     BYTE *ptr;
00517     AsnObjectIdentifier oid;
00518     INT ret;
00519 
00520     ret = setOidWithItem(dst, base, item);
00521     if (ret)
00522     {
00523         oid.idLength = 1;
00524         oid.ids = &id;
00525         for (ptr = (BYTE *)&addr; ret && ptr < (BYTE *)&addr + sizeof(DWORD);
00526          ptr++)
00527         {
00528             id = *ptr;
00529             ret = SnmpUtilOidAppend(dst, &oid);
00530         }
00531     }
00532     return ret;
00533 }
00534 
00535 static INT setOidWithItemAndInteger(AsnObjectIdentifier *dst,
00536     AsnObjectIdentifier *base, UINT item, UINT instance)
00537 {
00538     AsnObjectIdentifier oid;
00539     INT ret;
00540 
00541     ret = setOidWithItem(dst, base, item);
00542     if (ret)
00543     {
00544         oid.idLength = 1;
00545         oid.ids = &instance;
00546         ret = SnmpUtilOidAppend(dst, &oid);
00547     }
00548     return ret;
00549 }
00550 
00551 static DWORD copyIfRowDescr(AsnAny *value, void *src)
00552 {
00553     PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src -
00554                                   FIELD_OFFSET(MIB_IFROW, dwDescrLen));
00555     DWORD ret;
00556 
00557     if (row->dwDescrLen)
00558     {
00559         setStringValue(value, ASN_OCTETSTRING, row->dwDescrLen, row->bDescr);
00560         ret = SNMP_ERRORSTATUS_NOERROR;
00561     }
00562     else
00563         ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00564     return ret;
00565 }
00566 
00567 static DWORD copyIfRowPhysAddr(AsnAny *value, void *src)
00568 {
00569     PMIB_IFROW row = (PMIB_IFROW)((BYTE *)src -
00570                                   FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen));
00571     DWORD ret;
00572 
00573     if (row->dwPhysAddrLen)
00574     {
00575         setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen,
00576                        row->bPhysAddr);
00577         ret = SNMP_ERRORSTATUS_NOERROR;
00578     }
00579     else
00580         ret = SNMP_ERRORSTATUS_NOSUCHNAME;
00581     return ret;
00582 }
00583 
00584 static struct structToAsnValue mib2IfEntryMap[] = {
00585     { FIELD_OFFSET(MIB_IFROW, dwIndex), copyInt },
00586     { FIELD_OFFSET(MIB_IFROW, dwDescrLen), copyIfRowDescr },
00587     { FIELD_OFFSET(MIB_IFROW, dwType), copyInt },
00588     { FIELD_OFFSET(MIB_IFROW, dwMtu), copyInt },
00589     { FIELD_OFFSET(MIB_IFROW, dwSpeed), copyInt },
00590     { FIELD_OFFSET(MIB_IFROW, dwPhysAddrLen), copyIfRowPhysAddr },
00591     { FIELD_OFFSET(MIB_IFROW, dwAdminStatus), copyInt },
00592     { FIELD_OFFSET(MIB_IFROW, dwOperStatus), copyOperStatus },
00593     { FIELD_OFFSET(MIB_IFROW, dwLastChange), copyInt },
00594     { FIELD_OFFSET(MIB_IFROW, dwInOctets), copyInt },
00595     { FIELD_OFFSET(MIB_IFROW, dwInUcastPkts), copyInt },
00596     { FIELD_OFFSET(MIB_IFROW, dwInNUcastPkts), copyInt },
00597     { FIELD_OFFSET(MIB_IFROW, dwInDiscards), copyInt },
00598     { FIELD_OFFSET(MIB_IFROW, dwInErrors), copyInt },
00599     { FIELD_OFFSET(MIB_IFROW, dwInUnknownProtos), copyInt },
00600     { FIELD_OFFSET(MIB_IFROW, dwOutOctets), copyInt },
00601     { FIELD_OFFSET(MIB_IFROW, dwOutUcastPkts), copyInt },
00602     { FIELD_OFFSET(MIB_IFROW, dwOutNUcastPkts), copyInt },
00603     { FIELD_OFFSET(MIB_IFROW, dwOutDiscards), copyInt },
00604     { FIELD_OFFSET(MIB_IFROW, dwOutErrors), copyInt },
00605     { FIELD_OFFSET(MIB_IFROW, dwOutQLen), copyInt },
00606 };
00607 
00608 static UINT mib2IfEntry[] = { 1,3,6,1,2,1,2,2,1 };
00609 
00610 static BOOL mib2IfEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00611     AsnInteger32 *pErrorStatus)
00612 {
00613     AsnObjectIdentifier entryOid = DEFINE_OID(mib2IfEntry);
00614     BOOL ret = TRUE;
00615 
00616     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00617         pErrorStatus);
00618 
00619     switch (bPduType)
00620     {
00621     case SNMP_PDU_GET:
00622     case SNMP_PDU_GETNEXT:
00623         if (!ifTable)
00624         {
00625             /* There is no interface present, so let the caller deal
00626              * with finding the successor.
00627              */
00628             *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00629         }
00630         else
00631         {
00632             UINT tableIndex = 0, item = 0;
00633 
00634             *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
00635                 &entryOid, bPduType, &item, &tableIndex);
00636             if (!*pErrorStatus)
00637             {
00638                 assert(tableIndex);
00639                 assert(item);
00640                 if (tableIndex > ifTable->dwNumEntries)
00641                     *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00642                 else
00643                 {
00644                     *pErrorStatus = mapStructEntryToValue(mib2IfEntryMap,
00645                         DEFINE_SIZEOF(mib2IfEntryMap),
00646                         &ifTable->table[tableIndex - 1], item,
00647                         pVarBind);
00648                     if (bPduType == SNMP_PDU_GETNEXT)
00649                         ret = setOidWithItemAndInteger(&pVarBind->name,
00650                             &entryOid, item, tableIndex);
00651                 }
00652             }
00653         }
00654         break;
00655     case SNMP_PDU_SET:
00656         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00657         ret = FALSE;
00658         break;
00659     default:
00660         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00661         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00662     }
00663     return ret;
00664 }
00665 
00666 static UINT mib2Ip[] = { 1,3,6,1,2,1,4 };
00667 static MIB_IPSTATS ipStats;
00668 
00669 static void mib2IpStatsInit(void)
00670 {
00671     GetIpStatistics(&ipStats);
00672 }
00673 
00674 static struct structToAsnValue mib2IpMap[] = {
00675     { FIELD_OFFSET(MIB_IPSTATS, dwForwarding), copyInt }, /* 1 */
00676     { FIELD_OFFSET(MIB_IPSTATS, dwDefaultTTL), copyInt }, /* 2 */
00677     { FIELD_OFFSET(MIB_IPSTATS, dwInReceives), copyInt }, /* 3 */
00678     { FIELD_OFFSET(MIB_IPSTATS, dwInHdrErrors), copyInt }, /* 4 */
00679     { FIELD_OFFSET(MIB_IPSTATS, dwInAddrErrors), copyInt }, /* 5 */
00680     { FIELD_OFFSET(MIB_IPSTATS, dwForwDatagrams), copyInt }, /* 6 */
00681     { FIELD_OFFSET(MIB_IPSTATS, dwInUnknownProtos), copyInt }, /* 7 */
00682     { FIELD_OFFSET(MIB_IPSTATS, dwInDiscards), copyInt }, /* 8 */
00683     { FIELD_OFFSET(MIB_IPSTATS, dwInDelivers), copyInt }, /* 9 */
00684     { FIELD_OFFSET(MIB_IPSTATS, dwOutRequests), copyInt }, /* 10 */
00685     { FIELD_OFFSET(MIB_IPSTATS, dwOutDiscards), copyInt }, /* 11 */
00686     { FIELD_OFFSET(MIB_IPSTATS, dwOutNoRoutes), copyInt }, /* 12 */
00687     { FIELD_OFFSET(MIB_IPSTATS, dwReasmTimeout), copyInt }, /* 13 */
00688     { FIELD_OFFSET(MIB_IPSTATS, dwReasmReqds), copyInt }, /* 14 */
00689     { FIELD_OFFSET(MIB_IPSTATS, dwReasmOks), copyInt }, /* 15 */
00690     { FIELD_OFFSET(MIB_IPSTATS, dwReasmFails), copyInt }, /* 16 */
00691     { FIELD_OFFSET(MIB_IPSTATS, dwFragOks), copyInt }, /* 17 */
00692     { FIELD_OFFSET(MIB_IPSTATS, dwFragFails), copyInt }, /* 18 */
00693     { FIELD_OFFSET(MIB_IPSTATS, dwFragCreates), copyInt }, /* 19 */
00694     { 0, NULL }, /* 20: not used, IP addr table */
00695     { 0, NULL }, /* 21: not used, route table */
00696     { 0, NULL }, /* 22: not used, net to media (ARP) table */
00697     { FIELD_OFFSET(MIB_IPSTATS, dwRoutingDiscards), copyInt }, /* 23 */
00698 };
00699 
00700 static BOOL mib2IpStatsQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00701     AsnInteger32 *pErrorStatus)
00702 {
00703     AsnObjectIdentifier myOid = DEFINE_OID(mib2Ip);
00704     UINT item = 0;
00705     BOOL ret = TRUE;
00706 
00707     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00708         pErrorStatus);
00709 
00710     switch (bPduType)
00711     {
00712     case SNMP_PDU_GET:
00713     case SNMP_PDU_GETNEXT:
00714         *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
00715             &item);
00716         if (!*pErrorStatus)
00717         {
00718             *pErrorStatus = mapStructEntryToValue(mib2IpMap,
00719                 DEFINE_SIZEOF(mib2IpMap), &ipStats, item, pVarBind);
00720             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
00721                 ret = setOidWithItem(&pVarBind->name, &myOid, item);
00722         }
00723         break;
00724     case SNMP_PDU_SET:
00725         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00726         ret = FALSE;
00727         break;
00728     default:
00729         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00730         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00731     }
00732     return ret;
00733 }
00734 
00735 static UINT mib2IpAddr[] = { 1,3,6,1,2,1,4,20,1 };
00736 static PMIB_IPADDRTABLE ipAddrTable;
00737 
00738 static struct structToAsnValue mib2IpAddrMap[] = {
00739     { FIELD_OFFSET(MIB_IPADDRROW, dwAddr), copyIpAddr },
00740     { FIELD_OFFSET(MIB_IPADDRROW, dwIndex), copyInt },
00741     { FIELD_OFFSET(MIB_IPADDRROW, dwMask), copyIpAddr },
00742     { FIELD_OFFSET(MIB_IPADDRROW, dwBCastAddr), copyInt },
00743     { FIELD_OFFSET(MIB_IPADDRROW, dwReasmSize), copyInt },
00744 };
00745 
00746 static void mib2IpAddrInit(void)
00747 {
00748     DWORD size = 0, ret = GetIpAddrTable(NULL, &size, TRUE);
00749 
00750     if (ret == ERROR_INSUFFICIENT_BUFFER)
00751     {
00752         MIB_IPADDRTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
00753         if (table)
00754         {
00755             if (!GetIpAddrTable(table, &size, TRUE)) ipAddrTable = table;
00756             else HeapFree(GetProcessHeap(), 0, table );
00757         }
00758     }
00759 }
00760 
00761 static void mib2IpAddrCleanup(void)
00762 {
00763     HeapFree(GetProcessHeap(), 0, ipAddrTable);
00764 }
00765 
00766 static void oidToIpAddrRow(AsnObjectIdentifier *oid, void *dst)
00767 {
00768     MIB_IPADDRROW *row = dst;
00769 
00770     row->dwAddr = oidToIpAddr(oid);
00771 }
00772 
00773 static int compareIpAddrRow(const void *a, const void *b)
00774 {
00775     const MIB_IPADDRROW *key = a, *value = b;
00776 
00777     return key->dwAddr - value->dwAddr;
00778 }
00779 
00780 static BOOL mib2IpAddrQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00781     AsnInteger32 *pErrorStatus)
00782 {
00783     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpAddr);
00784     UINT tableIndex = 0, item = 0;
00785     BOOL ret = TRUE;
00786 
00787     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00788         pErrorStatus);
00789 
00790     switch (bPduType)
00791     {
00792     case SNMP_PDU_GET:
00793     case SNMP_PDU_GETNEXT:
00794         *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
00795             &myOid, 4, bPduType, (struct GenericTable *)ipAddrTable,
00796             sizeof(MIB_IPADDRROW), oidToIpAddrRow, compareIpAddrRow, &item,
00797             &tableIndex);
00798         if (!*pErrorStatus)
00799         {
00800             assert(tableIndex);
00801             assert(item);
00802             *pErrorStatus = mapStructEntryToValue(mib2IpAddrMap,
00803                 DEFINE_SIZEOF(mib2IpAddrMap),
00804                 &ipAddrTable->table[tableIndex - 1], item, pVarBind);
00805             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
00806                 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
00807                     ipAddrTable->table[tableIndex - 1].dwAddr);
00808         }
00809         break;
00810     case SNMP_PDU_SET:
00811         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00812         ret = FALSE;
00813         break;
00814     default:
00815         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00816         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00817     }
00818     return ret;
00819 }
00820 
00821 static UINT mib2IpRoute[] = { 1,3,6,1,2,1,4,21,1 };
00822 static PMIB_IPFORWARDTABLE ipRouteTable;
00823 
00824 static struct structToAsnValue mib2IpRouteMap[] = {
00825     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardDest), copyIpAddr },
00826     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardIfIndex), copyInt },
00827     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric1), copyInt },
00828     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric2), copyInt },
00829     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric3), copyInt },
00830     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric4), copyInt },
00831     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardNextHop), copyIpAddr },
00832     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardType), copyInt },
00833     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardProto), copyInt },
00834     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardAge), copyInt },
00835     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMask), copyIpAddr },
00836     { FIELD_OFFSET(MIB_IPFORWARDROW, dwForwardMetric5), copyInt },
00837 };
00838 
00839 static void mib2IpRouteInit(void)
00840 {
00841     DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE);
00842 
00843     if (ret == ERROR_INSUFFICIENT_BUFFER)
00844     {
00845         MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
00846         if (table)
00847         {
00848             if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table;
00849             else HeapFree(GetProcessHeap(), 0, table );
00850         }
00851     }
00852 }
00853 
00854 static void mib2IpRouteCleanup(void)
00855 {
00856     HeapFree(GetProcessHeap(), 0, ipRouteTable);
00857 }
00858 
00859 static void oidToIpForwardRow(AsnObjectIdentifier *oid, void *dst)
00860 {
00861     MIB_IPFORWARDROW *row = dst;
00862 
00863     row->dwForwardDest = oidToIpAddr(oid);
00864 }
00865 
00866 static int compareIpForwardRow(const void *a, const void *b)
00867 {
00868     const MIB_IPFORWARDROW *key = a, *value = b;
00869 
00870     return key->dwForwardDest - value->dwForwardDest;
00871 }
00872 
00873 static BOOL mib2IpRouteQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00874     AsnInteger32 *pErrorStatus)
00875 {
00876     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpRoute);
00877     UINT tableIndex = 0, item = 0;
00878     BOOL ret = TRUE;
00879 
00880     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00881         pErrorStatus);
00882 
00883     switch (bPduType)
00884     {
00885     case SNMP_PDU_GET:
00886     case SNMP_PDU_GETNEXT:
00887         *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name,
00888             &myOid, 4, bPduType, (struct GenericTable *)ipRouteTable,
00889             sizeof(MIB_IPFORWARDROW), oidToIpForwardRow, compareIpForwardRow,
00890             &item, &tableIndex);
00891         if (!*pErrorStatus)
00892         {
00893             assert(tableIndex);
00894             assert(item);
00895             *pErrorStatus = mapStructEntryToValue(mib2IpRouteMap,
00896                 DEFINE_SIZEOF(mib2IpRouteMap),
00897                 &ipRouteTable->table[tableIndex - 1], item, pVarBind);
00898             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
00899                 ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
00900                     ipRouteTable->table[tableIndex - 1].dwForwardDest);
00901         }
00902         break;
00903     case SNMP_PDU_SET:
00904         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00905         ret = FALSE;
00906         break;
00907     default:
00908         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00909         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00910     }
00911     return ret;
00912 }
00913 
00914 static UINT mib2IpNet[] = { 1,3,6,1,2,1,4,22,1 };
00915 static PMIB_IPNETTABLE ipNetTable;
00916 
00917 static DWORD copyIpNetPhysAddr(AsnAny *value, void *src)
00918 {
00919     PMIB_IPNETROW row = (PMIB_IPNETROW)((BYTE *)src - FIELD_OFFSET(MIB_IPNETROW,
00920                                         dwPhysAddrLen));
00921 
00922     setStringValue(value, ASN_OCTETSTRING, row->dwPhysAddrLen, row->bPhysAddr);
00923     return SNMP_ERRORSTATUS_NOERROR;
00924 }
00925 
00926 static struct structToAsnValue mib2IpNetMap[] = {
00927     { FIELD_OFFSET(MIB_IPNETROW, dwIndex), copyInt },
00928     { FIELD_OFFSET(MIB_IPNETROW, dwPhysAddrLen), copyIpNetPhysAddr },
00929     { FIELD_OFFSET(MIB_IPNETROW, dwAddr), copyIpAddr },
00930     { FIELD_OFFSET(MIB_IPNETROW, dwType), copyInt },
00931 };
00932 
00933 static void mib2IpNetInit(void)
00934 {
00935     DWORD size = 0, ret = GetIpNetTable(NULL, &size, FALSE);
00936 
00937     if (ret == ERROR_INSUFFICIENT_BUFFER)
00938     {
00939         MIB_IPNETTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
00940         if (table)
00941         {
00942             if (!GetIpNetTable(table, &size, FALSE)) ipNetTable = table;
00943             else HeapFree(GetProcessHeap(), 0, table );
00944         }
00945     }
00946 }
00947 
00948 static void mib2IpNetCleanup(void)
00949 {
00950     HeapFree(GetProcessHeap(), 0, ipNetTable);
00951 }
00952 
00953 static BOOL mib2IpNetQuery(BYTE bPduType, SnmpVarBind *pVarBind,
00954     AsnInteger32 *pErrorStatus)
00955 {
00956     AsnObjectIdentifier myOid = DEFINE_OID(mib2IpNet);
00957     BOOL ret = TRUE;
00958 
00959     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
00960         pErrorStatus);
00961 
00962     switch (bPduType)
00963     {
00964     case SNMP_PDU_GET:
00965     case SNMP_PDU_GETNEXT:
00966         if (!ipNetTable)
00967             *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00968         else
00969         {
00970             UINT tableIndex = 0, item = 0;
00971 
00972             *pErrorStatus = getItemAndIntegerInstanceFromOid(&pVarBind->name,
00973                 &myOid, bPduType, &item, &tableIndex);
00974             if (!*pErrorStatus)
00975             {
00976                 assert(tableIndex);
00977                 assert(item);
00978                 if (tableIndex > ipNetTable->dwNumEntries)
00979                     *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00980                 else
00981                 {
00982                     *pErrorStatus = mapStructEntryToValue(mib2IpNetMap,
00983                         DEFINE_SIZEOF(mib2IpNetMap),
00984                         &ipNetTable[tableIndex - 1], item, pVarBind);
00985                     if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
00986                         ret = setOidWithItemAndInteger(&pVarBind->name, &myOid,
00987                             item, tableIndex);
00988                 }
00989             }
00990         }
00991         break;
00992     case SNMP_PDU_SET:
00993         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
00994         ret = FALSE;
00995         break;
00996     default:
00997         FIXME("0x%02x: unsupported PDU type\n", bPduType);
00998         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
00999     }
01000     return ret;
01001 }
01002 
01003 static UINT mib2Icmp[] = { 1,3,6,1,2,1,5 };
01004 static MIB_ICMP icmpStats;
01005 
01006 static void mib2IcmpInit(void)
01007 {
01008     GetIcmpStatistics(&icmpStats);
01009 }
01010 
01011 static struct structToAsnValue mib2IcmpMap[] = {
01012     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwMsgs), copyInt },
01013     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwErrors), copyInt },
01014     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwDestUnreachs), copyInt },
01015     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimeExcds), copyInt },
01016     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwParmProbs), copyInt },
01017     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwSrcQuenchs), copyInt },
01018     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwRedirects), copyInt },
01019     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchos), copyInt },
01020     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwEchoReps), copyInt },
01021     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestamps), copyInt },
01022     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwTimestampReps), copyInt },
01023     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMasks), copyInt },
01024     { FIELD_OFFSET(MIBICMPINFO, icmpInStats.dwAddrMaskReps), copyInt },
01025     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwMsgs), copyInt },
01026     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwErrors), copyInt },
01027     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwDestUnreachs), copyInt },
01028     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimeExcds), copyInt },
01029     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwParmProbs), copyInt },
01030     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwSrcQuenchs), copyInt },
01031     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwRedirects), copyInt },
01032     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchos), copyInt },
01033     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwEchoReps), copyInt },
01034     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestamps), copyInt },
01035     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwTimestampReps), copyInt },
01036     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMasks), copyInt },
01037     { FIELD_OFFSET(MIBICMPINFO, icmpOutStats.dwAddrMaskReps), copyInt },
01038 };
01039 
01040 static BOOL mib2IcmpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
01041     AsnInteger32 *pErrorStatus)
01042 {
01043     AsnObjectIdentifier myOid = DEFINE_OID(mib2Icmp);
01044     UINT item = 0;
01045     BOOL ret = TRUE;
01046 
01047     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
01048         pErrorStatus);
01049 
01050     switch (bPduType)
01051     {
01052     case SNMP_PDU_GET:
01053     case SNMP_PDU_GETNEXT:
01054         *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
01055             &item);
01056         if (!*pErrorStatus)
01057         {
01058             *pErrorStatus = mapStructEntryToValue(mib2IcmpMap,
01059                 DEFINE_SIZEOF(mib2IcmpMap), &icmpStats, item,
01060                 pVarBind);
01061             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
01062                 ret = setOidWithItem(&pVarBind->name, &myOid, item);
01063         }
01064         break;
01065     case SNMP_PDU_SET:
01066         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
01067         ret = FALSE;
01068         break;
01069     default:
01070         FIXME("0x%02x: unsupported PDU type\n", bPduType);
01071         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
01072     }
01073     return ret;
01074 }
01075 
01076 static UINT mib2Tcp[] = { 1,3,6,1,2,1,6 };
01077 static MIB_TCPSTATS tcpStats;
01078 
01079 static void mib2TcpInit(void)
01080 {
01081     GetTcpStatistics(&tcpStats);
01082 }
01083 
01084 static struct structToAsnValue mib2TcpMap[] = {
01085     { FIELD_OFFSET(MIB_TCPSTATS, dwRtoAlgorithm), copyInt },
01086     { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMin), copyInt },
01087     { FIELD_OFFSET(MIB_TCPSTATS, dwRtoMax), copyInt },
01088     { FIELD_OFFSET(MIB_TCPSTATS, dwMaxConn), copyInt },
01089     { FIELD_OFFSET(MIB_TCPSTATS, dwActiveOpens), copyInt },
01090     { FIELD_OFFSET(MIB_TCPSTATS, dwPassiveOpens), copyInt },
01091     { FIELD_OFFSET(MIB_TCPSTATS, dwAttemptFails), copyInt },
01092     { FIELD_OFFSET(MIB_TCPSTATS, dwEstabResets), copyInt },
01093     { FIELD_OFFSET(MIB_TCPSTATS, dwCurrEstab), copyInt },
01094     { FIELD_OFFSET(MIB_TCPSTATS, dwInSegs), copyInt },
01095     { FIELD_OFFSET(MIB_TCPSTATS, dwOutSegs), copyInt },
01096     { FIELD_OFFSET(MIB_TCPSTATS, dwRetransSegs), copyInt },
01097     { FIELD_OFFSET(MIB_TCPSTATS, dwInErrs), copyInt },
01098     { FIELD_OFFSET(MIB_TCPSTATS, dwOutRsts), copyInt },
01099     { FIELD_OFFSET(MIB_TCPSTATS, dwNumConns), copyInt },
01100 };
01101 
01102 static BOOL mib2TcpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
01103     AsnInteger32 *pErrorStatus)
01104 {
01105     AsnObjectIdentifier myOid = DEFINE_OID(mib2Tcp);
01106     UINT item = 0;
01107     BOOL ret = TRUE;
01108 
01109     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
01110         pErrorStatus);
01111 
01112     switch (bPduType)
01113     {
01114     case SNMP_PDU_GET:
01115     case SNMP_PDU_GETNEXT:
01116         *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
01117             &item);
01118         if (!*pErrorStatus)
01119         {
01120             *pErrorStatus = mapStructEntryToValue(mib2TcpMap,
01121                 DEFINE_SIZEOF(mib2TcpMap), &tcpStats, item, pVarBind);
01122             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
01123                 ret = setOidWithItem(&pVarBind->name, &myOid, item);
01124         }
01125         break;
01126     case SNMP_PDU_SET:
01127         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
01128         ret = FALSE;
01129         break;
01130     default:
01131         FIXME("0x%02x: unsupported PDU type\n", bPduType);
01132         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
01133     }
01134     return ret;
01135 }
01136 
01137 static UINT mib2Udp[] = { 1,3,6,1,2,1,7 };
01138 static MIB_UDPSTATS udpStats;
01139 
01140 static void mib2UdpInit(void)
01141 {
01142     GetUdpStatistics(&udpStats);
01143 }
01144 
01145 static struct structToAsnValue mib2UdpMap[] = {
01146     { FIELD_OFFSET(MIB_UDPSTATS, dwInDatagrams), copyInt },
01147     { FIELD_OFFSET(MIB_UDPSTATS, dwNoPorts), copyInt },
01148     { FIELD_OFFSET(MIB_UDPSTATS, dwInErrors), copyInt },
01149     { FIELD_OFFSET(MIB_UDPSTATS, dwOutDatagrams), copyInt },
01150 };
01151 
01152 static BOOL mib2UdpQuery(BYTE bPduType, SnmpVarBind *pVarBind,
01153     AsnInteger32 *pErrorStatus)
01154 {
01155     AsnObjectIdentifier myOid = DEFINE_OID(mib2Udp);
01156     UINT item;
01157     BOOL ret = TRUE;
01158 
01159     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
01160         pErrorStatus);
01161 
01162     switch (bPduType)
01163     {
01164     case SNMP_PDU_GET:
01165     case SNMP_PDU_GETNEXT:
01166         *pErrorStatus = getItemFromOid(&pVarBind->name, &myOid, bPduType,
01167             &item);
01168         if (!*pErrorStatus)
01169         {
01170             *pErrorStatus = mapStructEntryToValue(mib2UdpMap,
01171                 DEFINE_SIZEOF(mib2UdpMap), &udpStats, item, pVarBind);
01172             if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
01173                 ret = setOidWithItem(&pVarBind->name, &myOid, item);
01174         }
01175         break;
01176     case SNMP_PDU_SET:
01177         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
01178         ret = FALSE;
01179         break;
01180     default:
01181         FIXME("0x%02x: unsupported PDU type\n", bPduType);
01182         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
01183     }
01184     return ret;
01185 }
01186 
01187 static UINT mib2UdpEntry[] = { 1,3,6,1,2,1,7,5,1 };
01188 static PMIB_UDPTABLE udpTable;
01189 
01190 static void mib2UdpEntryInit(void)
01191 {
01192     DWORD size = 0, ret = GetUdpTable(NULL, &size, TRUE);
01193 
01194     if (ret == ERROR_INSUFFICIENT_BUFFER)
01195     {
01196         MIB_UDPTABLE *table = HeapAlloc(GetProcessHeap(), 0, size);
01197         if (table)
01198         {
01199             if (!GetUdpTable(table, &size, TRUE)) udpTable = table;
01200             else HeapFree(GetProcessHeap(), 0, table);
01201         }
01202     }
01203 }
01204 
01205 static void mib2UdpEntryCleanup(void)
01206 {
01207     HeapFree(GetProcessHeap(), 0, udpTable);
01208 }
01209 
01210 static struct structToAsnValue mib2UdpEntryMap[] = {
01211     { FIELD_OFFSET(MIB_UDPROW, dwLocalAddr), copyIpAddr },
01212     { FIELD_OFFSET(MIB_UDPROW, dwLocalPort), copyInt },
01213 };
01214 
01215 static void oidToUdpRow(AsnObjectIdentifier *oid, void *dst)
01216 {
01217     MIB_UDPROW *row = dst;
01218 
01219     assert(oid && oid->idLength >= 5);
01220     row->dwLocalAddr = oidToIpAddr(oid);
01221     row->dwLocalPort = oid->ids[4];
01222 }
01223 
01224 static int compareUdpRow(const void *a, const void *b)
01225 {
01226     const MIB_UDPROW *key = a, *value = b;
01227     int ret;
01228 
01229     ret = key->dwLocalAddr - value->dwLocalAddr;
01230     if (ret == 0)
01231         ret = key->dwLocalPort - value->dwLocalPort;
01232     return ret;
01233 }
01234 
01235 static BOOL mib2UdpEntryQuery(BYTE bPduType, SnmpVarBind *pVarBind,
01236     AsnInteger32 *pErrorStatus)
01237 {
01238     AsnObjectIdentifier myOid = DEFINE_OID(mib2UdpEntry);
01239     BOOL ret = TRUE;
01240 
01241     TRACE("(0x%02x, %s, %p)\n", bPduType, SnmpUtilOidToA(&pVarBind->name),
01242         pErrorStatus);
01243 
01244     switch (bPduType)
01245     {
01246     case SNMP_PDU_GET:
01247     case SNMP_PDU_GETNEXT:
01248         if (!udpTable)
01249             *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
01250         else
01251         {
01252             UINT tableIndex = 0, item = 0;
01253 
01254             *pErrorStatus = getItemAndInstanceFromTable(&pVarBind->name, &myOid,
01255                 5, bPduType, (struct GenericTable *)udpTable,
01256                 sizeof(MIB_UDPROW), oidToUdpRow, compareUdpRow, &item,
01257                 &tableIndex);
01258             if (!*pErrorStatus)
01259             {
01260                 assert(tableIndex);
01261                 assert(item);
01262                 *pErrorStatus = mapStructEntryToValue(mib2UdpEntryMap,
01263                     DEFINE_SIZEOF(mib2UdpEntryMap),
01264                     &udpTable->table[tableIndex - 1], item, pVarBind);
01265                 if (!*pErrorStatus && bPduType == SNMP_PDU_GETNEXT)
01266                 {
01267                     AsnObjectIdentifier oid;
01268 
01269                     ret = setOidWithItemAndIpAddr(&pVarBind->name, &myOid, item,
01270                         udpTable->table[tableIndex - 1].dwLocalAddr);
01271                     if (ret)
01272                     {
01273                         oid.idLength = 1;
01274                         oid.ids = &udpTable->table[tableIndex - 1].dwLocalPort;
01275                         ret = SnmpUtilOidAppend(&pVarBind->name, &oid);
01276                     }
01277                 }
01278             }
01279         }
01280         break;
01281     case SNMP_PDU_SET:
01282         *pErrorStatus = SNMP_ERRORSTATUS_READONLY;
01283         ret = FALSE;
01284         break;
01285     default:
01286         FIXME("0x%02x: unsupported PDU type\n", bPduType);
01287         *pErrorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
01288     }
01289     return ret;
01290 }
01291 
01292 /* This list MUST BE lexicographically sorted */
01293 static struct mibImplementation supportedIDs[] = {
01294     { DEFINE_OID(mib2IfNumber), mib2IfNumberInit, mib2IfNumberQuery,
01295       mib2IfNumberCleanup },
01296     { DEFINE_OID(mib2IfEntry), NULL, mib2IfEntryQuery, NULL },
01297     { DEFINE_OID(mib2Ip), mib2IpStatsInit, mib2IpStatsQuery, NULL },
01298     { DEFINE_OID(mib2IpAddr), mib2IpAddrInit, mib2IpAddrQuery,
01299       mib2IpAddrCleanup },
01300     { DEFINE_OID(mib2IpRoute), mib2IpRouteInit, mib2IpRouteQuery,
01301       mib2IpRouteCleanup },
01302     { DEFINE_OID(mib2IpNet), mib2IpNetInit, mib2IpNetQuery, mib2IpNetCleanup },
01303     { DEFINE_OID(mib2Icmp), mib2IcmpInit, mib2IcmpQuery, NULL },
01304     { DEFINE_OID(mib2Tcp), mib2TcpInit, mib2TcpQuery, NULL },
01305     { DEFINE_OID(mib2Udp), mib2UdpInit, mib2UdpQuery, NULL },
01306     { DEFINE_OID(mib2UdpEntry), mib2UdpEntryInit, mib2UdpEntryQuery,
01307       mib2UdpEntryCleanup },
01308 };
01309 static UINT minSupportedIDLength;
01310 
01311 /*****************************************************************************
01312  * SnmpExtensionInit [INETMIB1.@]
01313  */
01314 BOOL WINAPI SnmpExtensionInit(DWORD dwUptimeReference,
01315     HANDLE *phSubagentTrapEvent, AsnObjectIdentifier *pFirstSupportedRegion)
01316 {
01317     AsnObjectIdentifier myOid = DEFINE_OID(mib2System);
01318     UINT i;
01319 
01320     TRACE("(%d, %p, %p)\n", dwUptimeReference, phSubagentTrapEvent,
01321         pFirstSupportedRegion);
01322 
01323     minSupportedIDLength = UINT_MAX;
01324     for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
01325     {
01326         if (supportedIDs[i].init)
01327             supportedIDs[i].init();
01328         if (supportedIDs[i].name.idLength < minSupportedIDLength)
01329             minSupportedIDLength = supportedIDs[i].name.idLength;
01330     }
01331     *phSubagentTrapEvent = NULL;
01332     SnmpUtilOidCpy(pFirstSupportedRegion, &myOid);
01333     return TRUE;
01334 }
01335 
01336 static void cleanup(void)
01337 {
01338     UINT i;
01339 
01340     for (i = 0; i < sizeof(supportedIDs) / sizeof(supportedIDs[0]); i++)
01341         if (supportedIDs[i].cleanup)
01342             supportedIDs[i].cleanup();
01343 }
01344 
01345 static struct mibImplementation *findSupportedQuery(UINT *ids, UINT idLength,
01346     UINT *matchingIndex)
01347 {
01348     int indexHigh = DEFINE_SIZEOF(supportedIDs) - 1, indexLow = 0;
01349     AsnObjectIdentifier oid1 = { idLength, ids};
01350 
01351     if (!idLength)
01352         return NULL;
01353 
01354     while (indexLow <= indexHigh)
01355     {
01356         INT cmp, i = (indexLow + indexHigh) / 2;
01357         if (!(cmp = SnmpUtilOidNCmp(&oid1, &supportedIDs[i].name, idLength)))
01358         {
01359             *matchingIndex = i;
01360             return &supportedIDs[i];
01361         }
01362         if (cmp > 0)
01363             indexLow = i + 1;
01364         else
01365             indexHigh = i - 1;
01366     }
01367     return NULL;
01368 }
01369 
01370 /*****************************************************************************
01371  * SnmpExtensionQuery [INETMIB1.@]
01372  */
01373 BOOL WINAPI SnmpExtensionQuery(BYTE bPduType, SnmpVarBindList *pVarBindList,
01374     AsnInteger32 *pErrorStatus, AsnInteger32 *pErrorIndex)
01375 {
01376     AsnObjectIdentifier mib2oid = DEFINE_OID(mib2);
01377     AsnInteger32 error = SNMP_ERRORSTATUS_NOERROR, errorIndex = 0;
01378     UINT i;
01379     BOOL ret = TRUE;
01380 
01381     TRACE("(0x%02x, %p, %p, %p)\n", bPduType, pVarBindList,
01382         pErrorStatus, pErrorIndex);
01383 
01384     for (i = 0; !error && i < pVarBindList->len; i++)
01385     {
01386         /* Ignore any OIDs not in MIB2 */
01387         if (!SnmpUtilOidNCmp(&pVarBindList->list[i].name, &mib2oid,
01388             mib2oid.idLength))
01389         {
01390             struct mibImplementation *impl = NULL;
01391             UINT len, matchingIndex = 0;
01392 
01393             TRACE("%s\n", SnmpUtilOidToA(&pVarBindList->list[i].name));
01394             /* Search for an implementation matching as many octets as possible
01395              */
01396             for (len = pVarBindList->list[i].name.idLength;
01397                 len >= minSupportedIDLength && !impl; len--)
01398                 impl = findSupportedQuery(pVarBindList->list[i].name.ids, len,
01399                     &matchingIndex);
01400             if (impl && impl->query)
01401                 ret = impl->query(bPduType, &pVarBindList->list[i], &error);
01402             else
01403                 error = SNMP_ERRORSTATUS_NOSUCHNAME;
01404             if (error == SNMP_ERRORSTATUS_NOSUCHNAME &&
01405                 bPduType == SNMP_PDU_GETNEXT)
01406             {
01407                 /* GetNext is special: it finds the successor to the given OID,
01408                  * so we have to continue until an implementation handles the
01409                  * query or we exhaust the table of supported OIDs.
01410                  */
01411                 for (matchingIndex++; error == SNMP_ERRORSTATUS_NOSUCHNAME &&
01412                     matchingIndex < DEFINE_SIZEOF(supportedIDs);
01413                     matchingIndex++)
01414                 {
01415                     error = SNMP_ERRORSTATUS_NOERROR;
01416                     impl = &supportedIDs[matchingIndex];
01417                     if (impl->query)
01418                         ret = impl->query(bPduType, &pVarBindList->list[i],
01419                             &error);
01420                     else
01421                         error = SNMP_ERRORSTATUS_NOSUCHNAME;
01422                 }
01423                 /* If the query still isn't resolved, set the OID to the
01424                  * successor to the last entry in the table.
01425                  */
01426                 if (error == SNMP_ERRORSTATUS_NOSUCHNAME)
01427                 {
01428                     SnmpUtilOidFree(&pVarBindList->list[i].name);
01429                     ret = SnmpUtilOidCpy(&pVarBindList->list[i].name,
01430                         &supportedIDs[matchingIndex - 1].name);
01431                     pVarBindList->list[i].name.ids[
01432                         pVarBindList->list[i].name.idLength - 1] += 1;
01433                 }
01434             }
01435             if (error)
01436                 errorIndex = i + 1;
01437         }
01438     }
01439     *pErrorStatus = error;
01440     *pErrorIndex = errorIndex;
01441     return ret;
01442 }
01443 
01444 /*****************************************************************************
01445  * DllMain [INETMIB1.@]
01446  */
01447 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
01448 {
01449     TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
01450 
01451     switch (fdwReason)
01452     {
01453         case DLL_PROCESS_ATTACH:
01454             DisableThreadLibraryCalls(hinstDLL);
01455             break;
01456         case DLL_PROCESS_DETACH:
01457             cleanup();
01458             break;
01459         default:
01460             break;
01461     }
01462 
01463     return TRUE;
01464 }

Generated on Sat May 26 2012 04:15:43 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.