MIB.C
/*++ 
 
Copyright (c) 1997  Microsoft Corporation 
 
Module Name: 
 
    sample\ip\mib.c 
 
Abstract: 
    MIB Functions exported by the Sample Routing Protocol DLL and related code 
 
Revision History: 
 
 
--*/ 
 
#include "sampinc.h" 
 
 
 
DWORD 
LocateInterface( 
    DWORD               dwQueryType, 
    PPROTO_MIB_QUERY    pQuery, 
    ULONG               ulNumIndices, 
    PPROTO_MIB_RESPONSE pResponse, 
    PDWORD              pdwOutputSize 
    ); 
 
 
// 
// As mentioned in saminfo.h we do not support Creates, Sets or Deletes 
// 
 
 
DWORD 
APIENTRY 
MibCreate( 
    IN DWORD dwInputSize, 
    IN PVOID pInputData 
    ) 
/*++ 
  Routine Description 
     
   
  Arguments 
 
 
  Return Value 
      NO_ERROR 
 
--*/ 
{ 
    // 
    // Not supported 
    // 
     
    return NO_ERROR; 
} 
 
 
DWORD 
APIENTRY 
MibDelete( 
    IN DWORD dwInputSize, 
    IN PVOID pInputData 
    ) 
/*++ 
  Routine Description 
 
   
  Arguments 
 
 
  Return Value 
      NO_ERROR 
 
--*/ 
{ 
    // 
    // Not supported 
    // 
     
    return NO_ERROR; 
} 
 
DWORD 
APIENTRY 
MibSet( 
    IN DWORD dwInputSize, 
    IN PVOID pInputData 
    ) 
/*++ 
  Routine Description 
 
   
  Arguments 
 
 
  Return Value 
      NO_ERROR 
 
--*/ 
{ 
    // 
    // Not supported 
    // 
     
    return NO_ERROR; 
} 
 
DWORD 
APIENTRY 
MibGet( 
    IN     DWORD  dwInputSize, 
    IN     PVOID  pInputData, 
    IN OUT PDWORD pdwOutputSize, 
       OUT PVOID  pOutputData 
    ) 
/*++ 
  Routine Description 
      Called by an admin (SNMP) utility.  It actually passes through the 
      IP Router Manager, but all that does is demux the call to the 
      desired routing protocol 
      We verify the parameters and return the information if we can 
       
  Arguments 
 
 
  Return Value 
      ERROR_INSUFFICIENT_BUFFER 
      ERROR_INVALID_PARAMETER 
      ERROR_NO_DATA 
      ERROR_NO_MORE_ITEMS 
      ERROR_INVALID_INDEX 
      NO_ERROR 
 
--*/ 
{ 
    PPROTO_MIB_QUERY    pQuery; 
    PPROTO_MIB_RESPONSE pResponse; 
    ULONG               ulNumIndices; 
    DWORD               dwResult; 
     
     
    EnterProtocolApi(); 
 
    TraceEnter("MibGet"); 
 
    if(dwInputSize < sizeof(DWORD)) 
    { 
        // 
        // Need atleas the OID to do the get 
        // 
 
        TraceLeave("MibGet"); 
 
        ExitProtocolApi(); 
         
        return ERROR_INVALID_PARAMETER; 
    } 
 
    // 
    // The input to the function is the query 
    // 
     
    pQuery      = (PPROTO_MIB_QUERY)pInputData; 
    pResponse   = (PPROTO_MIB_RESPONSE)pOutputData; 
     
    // 
    // It would be really bad if someone messed the sizes up 
    // 
     
    ASSERT(dwInputSize%sizeof(DWORD) == 0); 
     
    ulNumIndices = NUM_INDICES(dwInputSize); 
 
    dwResult = NO_ERROR; 
     
    switch(pQuery->dwOid) 
    { 
        case PROTO_MIB_GLOBAL_ID: 
        { 
            // 
            // The output size needed is the PROTO_MIB_RESPONSE + just enough for 
            // the structure we need. We dont need space for the whole union 
            // 
             
            if(*pdwOutputSize < FIELD_OFFSET(PROTO_MIB_RESPONSE, mgGlobal) + sizeof(PROTO_MIB_GLOBAL)) 
            { 
                *pdwOutputSize = FIELD_OFFSET(PROTO_MIB_RESPONSE, mgGlobal) + sizeof(PROTO_MIB_GLOBAL); 
                 
                dwResult = ERROR_INSUFFICIENT_BUFFER; 
 
                break; 
            } 
 
            *pdwOutputSize = FIELD_OFFSET(PROTO_MIB_RESPONSE, mgGlobal) + sizeof(PROTO_MIB_GLOBAL); 
             
            pResponse->dwOid = PROTO_MIB_GLOBAL_ID; 
 
            EnterCriticalSection(&g_csGlobalInfoLock); 
             
            pResponse->mgGlobal.dwLogLevel = g_dwLogLevel; 
 
            LeaveCriticalSection(&g_csGlobalInfoLock); 
             
            break; 
        } 
        case PROTO_MIB_INTF_ID: 
        { 
            EnterCriticalSection(&g_csIfListLock); 
 
            dwResult = LocateInterface(QUERY_TYPE_GET, 
                                       pQuery, 
                                       ulNumIndices, 
                                       pResponse, 
                                       pdwOutputSize); 
             
 
            LeaveCriticalSection(&g_csIfListLock); 
             
            break; 
        } 
        default: 
        { 
            dwResult = ERROR_INVALID_PARAMETER; 
 
            break; 
        } 
    } 
 
    TraceLeave("MibGet"); 
 
    ExitProtocolApi(); 
         
    return dwResult; 
} 
 
 
DWORD 
APIENTRY 
MibGetFirst( 
    IN     DWORD  dwInputSize, 
    IN     PVOID  pInputData, 
    IN OUT PDWORD pdwOutputSize, 
       OUT PVOID  pOutputData 
    ) 
/*++ 
  Routine Description 
 
 
  Locks 
 
 
  Arguments 
 
 
  Return Value 
      NO_ERROR 
 
--*/ 
{ 
    PPROTO_MIB_QUERY    pQuery; 
    PPROTO_MIB_RESPONSE pResponse; 
    ULONG               ulNumIndices; 
    DWORD               dwResult; 
     
     
    EnterProtocolApi(); 
 
    TraceEnter("MibGet"); 
 
    if(dwInputSize < sizeof(DWORD)) 
    { 
        // 
        // Need atleas the OID to do the get 
        // 
 
        TraceLeave("MibGet"); 
 
        ExitProtocolApi(); 
         
        return ERROR_INVALID_PARAMETER; 
    } 
 
    // 
    // The input to the function is the query 
    // 
     
    pQuery      = (PPROTO_MIB_QUERY)pInputData; 
    pResponse   = (PPROTO_MIB_RESPONSE)pOutputData; 
     
    // 
    // It would be really bad if someone messed the sizes up 
    // 
     
    ASSERT(dwInputSize%sizeof(DWORD) == 0); 
     
    ulNumIndices = NUM_INDICES(dwInputSize); 
 
    dwResult = NO_ERROR; 
     
    switch(pQuery->dwOid) 
    { 
        case PROTO_MIB_GLOBAL_ID: 
        { 
            // 
            // Only support GET_FIRST for tables 
            // 
 
            dwResult = ERROR_INVALID_PARAMETER; 
             
            break; 
        } 
        case PROTO_MIB_INTF_ID: 
        { 
            EnterCriticalSection(&g_csIfListLock); 
 
            dwResult = LocateInterface(QUERY_TYPE_GET_FIRST, 
                                       pQuery, 
                                       ulNumIndices, 
                                       pResponse, 
                                       pdwOutputSize); 
             
 
            LeaveCriticalSection(&g_csIfListLock); 
             
            break; 
        } 
    } 
 
    TraceLeave("MibGet"); 
 
    ExitProtocolApi(); 
         
    return dwResult; 
} 
 
 
DWORD 
APIENTRY 
MibGetNext( 
    IN     DWORD  dwInputSize, 
    IN     PVOID  pInputData, 
    IN OUT PDWORD pdwOutputSize, 
       OUT PVOID  pOutputData 
    ) 
/*++ 
  Routine Description 
 
 
  Locks 
 
 
  Arguments 
 
 
  Return Value 
      NO_ERROR 
 
--*/ 
{ 
    PPROTO_MIB_QUERY    pQuery; 
    PPROTO_MIB_RESPONSE pResponse; 
    ULONG               ulNumIndices; 
    DWORD               dwResult; 
     
     
    EnterProtocolApi(); 
 
    TraceEnter("MibGet"); 
 
    if(dwInputSize < sizeof(DWORD)) 
    { 
        // 
        // Need atleas the OID to do the get 
        // 
 
        TraceLeave("MibGet"); 
 
        ExitProtocolApi(); 
         
        return ERROR_INVALID_PARAMETER; 
    } 
 
    // 
    // The input to the function is the query 
    // 
     
    pQuery      = (PPROTO_MIB_QUERY)pInputData; 
    pResponse   = (PPROTO_MIB_RESPONSE)pOutputData; 
     
    // 
    // It would be really bad if someone messed the sizes up 
    // 
     
    ASSERT(dwInputSize%sizeof(DWORD) == 0); 
     
    ulNumIndices = NUM_INDICES(dwInputSize); 
 
    dwResult = NO_ERROR; 
     
    switch(pQuery->dwOid) 
    { 
        case PROTO_MIB_GLOBAL_ID: 
        { 
            // 
            // Only support GET_NEXT for tables 
            // 
 
            dwResult = ERROR_INVALID_PARAMETER; 
             
            break; 
        } 
        case PROTO_MIB_INTF_ID: 
        { 
            EnterCriticalSection(&g_csIfListLock); 
 
            dwResult = LocateInterface(QUERY_TYPE_GET_FIRST, 
                                       pQuery, 
                                       ulNumIndices, 
                                       pResponse, 
                                       pdwOutputSize); 
             
 
            LeaveCriticalSection(&g_csIfListLock); 
             
            break; 
        } 
    } 
 
    TraceLeave("MibGet"); 
 
    ExitProtocolApi(); 
         
    return dwResult; 
} 
 
DWORD 
LocateInterface( 
    DWORD               dwQueryType, 
    PPROTO_MIB_QUERY    pQuery, 
    ULONG               ulNumIndices, 
    PPROTO_MIB_RESPONSE pResponse, 
    PDWORD              pdwOutputSize 
    ) 
/*++ 
  Routine Description 
      This locates the correct interface for the MIB query 
 
  Locks 
      The IF List lock should be held 
 
  Arguments 
      dwQueryType 
      pQuery 
      ulNumIndices 
      pResponse 
      pdwOutputSize 
 
  Return Value 
      ERROR_NO_DATA             If there are no interfaces 
      ERROR_INVALID_PARAMETER   If the index is bad 
      ERROR_INVALID_INDEX       If the index does not exist 
      ERROR_NO_MORE_ITEMS       If there are no more interfaces. Unlike SNMP 
                                we dont walk to the next variable. This keeps 
                                our code easy, and doesnt take away any functionality 
                                since the NT SNMP agent will try the next variable 
                                automatically on getting this error 
      NO_ERROR 
 
--*/ 
{ 
    PNT_IF          pIf, pRetIf; 
    PINTRNL_IF      pBind; 
    BOOL            bModified,bNext; 
    PLIST_ENTRY     pleNode; 
    DWORD           dwResult,dwIndex,i; 
    PPROTO_MIB_INTF pMibIf; 
     
    TraceEnter("LocateInterface"); 
     
    if(IsListEmpty(&g_leIfListHead)) 
    { 
        TraceLeave("LocateInterface"); 
 
        return ERROR_NO_DATA; 
    } 
 
     
    if((ulNumIndices < 1) && (dwQueryType == QUERY_TYPE_GET)) 
    { 
        // 
        // For a get we need the index 
        // 
 
        TraceLeave("LocateInterface"); 
         
        return ERROR_INVALID_PARAMETER; 
    } 
 
    if(dwQueryType == QUERY_TYPE_GET_FIRST) 
    { 
        // 
        // Since the list is ordered 
        // 
 
        pIf = CONTAINING_RECORD(g_leIfListHead.Flink, NT_IF, leNtIfLink); 
         
        if(*pdwOutputSize < FIELD_OFFSET(PROTO_MIB_RESPONSE,miIntf) + 
                             SIZEOF_MIB_INTF_INFO(pIf->ulNumBindings)) 
        { 
             
            *pdwOutputSize = FIELD_OFFSET(PROTO_MIB_RESPONSE,miIntf) +  
                SIZEOF_MIB_INTF_INFO(pIf->ulNumBindings); 
 
            TraceLeave("LocateInterface"); 
         
            return ERROR_INSUFFICIENT_BUFFER; 
        } 
    } 
 
    // 
    // Now a little magic to figure out which interface to return. 
    // We initialize the index to 0. If we have not gotten an index we 
    // set th bModified to TRUE, meaning the index has been initialized 
    // and we have not actually got a 0. 
    // 
     
    if(ulNumIndices > 0) 
    { 
        dwIndex     = pQuery->rgdwIndex[0]; 
        bModified   = FALSE; 
    } 
    else 
    { 
        dwIndex     = 0; 
        bModified   = TRUE; 
    } 
 
    // 
    // Now we will take the next interface if the query type is GET_NEXT 
    // and the index was not modified. Otherwise we will pick the interface 
    // == dwIndex 
    // 
 
    bNext = ((dwQueryType == QUERY_TYPE_GET_NEXT) && (bModified == FALSE)); 
 
    pRetIf   = NULL; 
    dwResult = ERROR_NO_MORE_ITEMS; 
     
    for(pleNode  = g_leIfListHead.Flink; 
        pleNode != &g_leIfListHead; 
        pleNode  = pleNode->Flink) 
    { 
        pIf = CONTAINING_RECORD(pleNode, 
                                NT_IF, 
                                leNtIfLink); 
 
        if((dwIndex == pIf->dwNtIndex) && !bNext) 
        { 
            // 
            // Found an if with matchin index and we were not 
            // meant to get the "next" one 
            // 
 
            pRetIf = pIf; 
 
            break; 
        } 
 
        if(dwIndex < pIf->dwNtIndex) 
        { 
            if(dwQueryType == QUERY_TYPE_GET_NEXT) 
            { 
                // 
                // Found the first one greater than the given 
                // and the query type is GET_NEXT 
                // 
 
                pRetIf = pIf; 
                 
                break; 
            } 
            else 
            { 
                // 
                // We were meant to get an exact match but 
                // since the list is ordered, we wont find it now 
                // 
 
                dwResult = ERROR_INVALID_INDEX; 
            } 
        } 
    }    
 
    if(pRetIf != NULL) 
    { 
        // 
        // So we did find an interface 
        // 
 
        if(*pdwOutputSize < FIELD_OFFSET(PROTO_MIB_RESPONSE,miIntf) + 
                             SIZEOF_MIB_INTF_INFO(pRetIf->ulNumBindings)) 
        { 
             
            *pdwOutputSize = FIELD_OFFSET(PROTO_MIB_RESPONSE,miIntf) +  
                SIZEOF_MIB_INTF_INFO(pRetIf->ulNumBindings); 
 
            dwResult = ERROR_INSUFFICIENT_BUFFER; 
        } 
        else 
        { 
            // 
            // So we found the interface AND have the space 
            // 
 
            *pdwOutputSize = FIELD_OFFSET(PROTO_MIB_RESPONSE,miIntf) +  
                SIZEOF_MIB_INTF_INFO(pRetIf->ulNumBindings); 
 
            pResponse->dwOid = PROTO_MIB_INTF_ID; 
 
            pMibIf = (PPROTO_MIB_INTF)(&(pResponse->miIntf)); 
             
            pMibIf->dwIfIndex     = pRetIf->dwNtIndex; 
            pMibIf->ulNumAddress  = pRetIf->ulNumBindings; 
             
            for(pleNode  = pRetIf->leInternalIfHead.Flink, i = 0; 
                pleNode != &pIf->leInternalIfHead; 
                pleNode  = pleNode->Flink, i++) 
            { 
                pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink); 
 
                pMibIf->rgmbBindInfo[i].dwAddress = pBind->dwAddress; 
                pMibIf->rgmbBindInfo[i].dwMask    = pBind->dwMask; 
                pMibIf->rgmbBindInfo[i].bEnabled  = pBind->bEnabled; 
            } 
 
            ASSERT(i == pRetIf->ulNumBindings); 
 
            dwResult = NO_ERROR; 
        } 
    } 
     
    TraceLeave("LocateInterface"); 
 
    return dwResult; 
}