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;
}